diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a0841b523b..50fa001df5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Create a report to help fix an issue. title: '' -labels: '' +labels: bug assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..e1d9fecf05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Feature request + url: https://github.com/Anuken/Mindustry-Suggestions/issues/new/choose + about: Do not make a new issue for feature requests! Instead, post it in suggestions repository. + - name: Question + url: https://discord.com/invite/mindustry + about: Questions about the game should be asked in the Discord, not in the issue tracker. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 7a08062e1d..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Feature request -about: Do not make a new issue for feature requests! Instead, post in the suggestions - repository. See the README. -title: '' -labels: invalid -assignees: '' - ---- - -**Do not make a new issue for feature requests!** Instead, post it in suggestions repository: https://github.com/Anuken/Mindustry-Suggestions/issues/new/choose diff --git a/.gitignore b/.gitignore index e9a73fdffd..1a50ef27f2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ logs/ /desktop/mindustry-saves/ /desktop/mindustry-maps/ /desktop/gifexport/ +/gifs/ /core/lib/ /ios/assets/ /core/assets-raw/sprites/generated/ @@ -28,7 +29,6 @@ core/assets/saves/ /core/assets/saves/ steam_appid.txt /test_files/ -/annotations/build/ /android/assets/mindustry-maps/ /android/assets/mindustry-saves/ /core/assets/gifexport/ @@ -40,12 +40,9 @@ steam_appid.txt ios/robovm.properties packr-out/ config/ -changelog *.gif -/core/assets/saves/ -/out/ -/core/assets-raw/fontgen/out/ +/core/assets/basepartnames version.properties .attach_* diff --git a/.travis.yml b/.travis.yml index d680769ec2..9c63be80eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ dist: xenial android: components: - android-29 - - build-tools-29.0.2 + - build-tools-29.0.3 script: - git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50f94d22f6..c79ce649fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ This means: Import [this style file](.github/Mindustry-CodeStyle-IJ.xml) into IntelliJ to get correct formatting when developing Mindustry. #### Do not use incompatible Java features (java.util.function, java.awt). -Android [does not support](https://developer.android.com/studio/write/java8-support#supported_features) many of Java 8's features, such as the packages `java.util.function`, `java.util.stream` or `forEach` in collections. Do not use these in your code. +Android and RoboVM (iOS) do not support many of Java 8's features, such as the packages `java.util.function`, `java.util.stream` or `forEach` in collections. Do not use these in your code. If you need to use functional interfaces, use the ones in `arc.func`, which are more or less the same with different naming schemes. The same applies to any class *outside* of the standard `java.[n]io` / `java.net` / `java.util` packages: Most of them are not supported. diff --git a/android/build.gradle b/android/build.gradle index b83b64c15a..412ed1c441 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,8 @@ buildscript{ } dependencies{ + //IMPORTANT NOTICE: any version of the plugin after 3.4.1 will break builds for every API level < 24, perhaps even higher. + //it appears abstract methods don't get desugared properly (if at all) classpath 'com.android.tools.build:gradle:3.4.1' } } diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index 7996c2c93a..4d41e46cb4 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -1,6 +1,7 @@ package mindustry.android; import android.*; +import android.annotation.*; import android.app.*; import android.content.*; import android.content.pm.*; diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java index 4cf17621ef..f3fb569aff 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java @@ -196,14 +196,14 @@ public class EntityProcess extends BaseProcessor{ //skip double classes if(usedNames.containsKey(name)){ - extraNames.getOr(usedNames.get(name), ObjectSet::new).add(type.name()); + extraNames.get(usedNames.get(name), ObjectSet::new).add(type.name()); continue; } usedNames.put(name, type); - extraNames.getOr(type, ObjectSet::new).add(name); + extraNames.get(type, ObjectSet::new).add(name); if(!type.isType()){ - extraNames.getOr(type, ObjectSet::new).add(type.name()); + extraNames.get(type, ObjectSet::new).add(type.name()); } TypeSpec.Builder builder = TypeSpec.classBuilder(name).addModifiers(Modifier.PUBLIC); @@ -222,6 +222,8 @@ public class EntityProcess extends BaseProcessor{ Array syncedFields = new Array<>(); Array allFields = new Array<>(); + boolean isSync = components.contains(s -> s.name().contains("Sync")); + //add all components for(Stype comp : components){ @@ -257,7 +259,7 @@ public class EntityProcess extends BaseProcessor{ allFields.add(f); //add extra sync fields - if(f.has(SyncField.class)){ + if(f.has(SyncField.class) && isSync){ if(!f.tname().toString().equals("float")) err("All SyncFields must be of type float", f); syncedFields.add(f); @@ -277,7 +279,7 @@ public class EntityProcess extends BaseProcessor{ //get all utility methods from components for(Smethod elem : comp.methods()){ - methods.getOr(elem.toString(), Array::new).add(elem); + methods.get(elem.toString(), Array::new).add(elem); } } @@ -552,8 +554,8 @@ public class EntityProcess extends BaseProcessor{ idStore.addStatement("idMap[$L] = $L::new", def.classID, def.name); extraNames.get(def.base).each(extra -> { idStore.addStatement("nameMap.put($S, $L::new)", extra, def.name); - if(!camelToKebab(extra).equals(extra)){ - idStore.addStatement("nameMap.put($S, $L::new)", camelToKebab(extra), def.name); + if(!Strings.camelToKebab(extra).equals(extra)){ + idStore.addStatement("nameMap.put($S, $L::new)", Strings.camelToKebab(extra), def.name); } }); @@ -749,22 +751,6 @@ public class EntityProcess extends BaseProcessor{ return comps.toString("", s -> s.name().replace("Comp", "")) + "Entity"; } - static String camelToKebab(String s){ - StringBuilder result = new StringBuilder(s.length() + 1); - - for(int i = 0; i < s.length(); i++){ - char c = s.charAt(i); - if(i > 0 && Character.isUpperCase(s.charAt(i))){ - result.append('-'); - } - - result.append(Character.toLowerCase(c)); - - } - - return result.toString(); - } - boolean isComponent(Stype type){ return type.annotation(Component.class) != null; } diff --git a/annotations/src/main/java/mindustry/annotations/misc/LoadRegionProcessor.java b/annotations/src/main/java/mindustry/annotations/misc/LoadRegionProcessor.java index 6703b92a16..6923dc2149 100644 --- a/annotations/src/main/java/mindustry/annotations/misc/LoadRegionProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/misc/LoadRegionProcessor.java @@ -30,7 +30,7 @@ public class LoadRegionProcessor extends BaseProcessor{ err("@LoadRegion field must be public", field); } - fieldMap.getOr(field.enclosingType(), Array::new).add(field); + fieldMap.get(field.enclosingType(), Array::new).add(field); } for(Entry> entry : fieldMap){ diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 5f5e95830e..35bd0b348c 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -12,9 +12,11 @@ mindustry.entities.comp.PlayerComp=8 mindustry.entities.comp.PuddleComp=9 mindustry.entities.comp.TileComp=10 mindustry.type.Weather.WeatherComp=11 -mindustry.world.blocks.storage.LaunchPad.LaunchPayloadComp=12 +mindustry.world.blocks.campaign.CoreLauncher.LaunchCoreComp=20 +mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=12 oculon=13 phantom=14 +tau=19 titan=15 trident=18 vanguard=16 diff --git a/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnitEntity/0.json b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnitEntity/0.json new file mode 100644 index 0000000000..dcf10887d1 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnitEntity/0.json @@ -0,0 +1 @@ +{fields:[{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:mineTile,type:mindustry.world.Tile,size:-1},{name:requests,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.Array,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/LaunchCoreEntity/0.json b/annotations/src/main/resources/revisions/LaunchCoreEntity/0.json new file mode 100644 index 0000000000..6fed0fac7f --- /dev/null +++ b/annotations/src/main/resources/revisions/LaunchCoreEntity/0.json @@ -0,0 +1 @@ +{fields:[{name:lifetime,type:float,size:4},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{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/LaunchCoreEntity/1.json b/annotations/src/main/resources/revisions/LaunchCoreEntity/1.json new file mode 100644 index 0000000000..4575c931f1 --- /dev/null +++ b/annotations/src/main/resources/revisions/LaunchCoreEntity/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:block,type:mindustry.world.Block,size:-1},{name:lifetime,type:float,size:4},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{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/LaunchCoreEntity/2.json b/annotations/src/main/resources/revisions/LaunchCoreEntity/2.json new file mode 100644 index 0000000000..0030ee7afd --- /dev/null +++ b/annotations/src/main/resources/revisions/LaunchCoreEntity/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:block,type:mindustry.world.Block,size:-1},{name:lifetime,type:float,size:4},{name:time,type:float,size:4},{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/TrailUnitEntity/0.json b/annotations/src/main/resources/revisions/TrailUnitEntity/0.json new file mode 100644 index 0000000000..ea9b0f0abe --- /dev/null +++ b/annotations/src/main/resources/revisions/TrailUnitEntity/0.json @@ -0,0 +1 @@ +{fields:[{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: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.Array,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/build.gradle b/build.gradle index 7fee921c61..2e66aff6e0 100644 --- a/build.gradle +++ b/build.gradle @@ -106,6 +106,7 @@ allprojects{ output += other.name.substring("bundle".length() + 1, other.name.lastIndexOf('.')) + "\n" } new File(project(':core').projectDir, 'assets/locales').text = output + new File(project(':core').projectDir, 'assets/basepartnames').text = new File(project(':core').projectDir, 'assets/baseparts/').list().join("\n") } writeVersion = { diff --git a/core/assets-raw/sprites/blocks/campaign/core-silo.png b/core/assets-raw/sprites/blocks/campaign/core-silo.png new file mode 100644 index 0000000000..dbb0b6d70c Binary files /dev/null and b/core/assets-raw/sprites/blocks/campaign/core-silo.png differ diff --git a/core/assets-raw/sprites/blocks/campaign/data-processor.png b/core/assets-raw/sprites/blocks/campaign/data-processor.png new file mode 100644 index 0000000000..6383dcfbe2 Binary files /dev/null and b/core/assets-raw/sprites/blocks/campaign/data-processor.png differ diff --git a/core/assets-raw/sprites/blocks/storage/launch-pad-large.png b/core/assets-raw/sprites/blocks/campaign/launch-pad-large.png similarity index 100% rename from core/assets-raw/sprites/blocks/storage/launch-pad-large.png rename to core/assets-raw/sprites/blocks/campaign/launch-pad-large.png diff --git a/core/assets-raw/sprites/blocks/storage/launch-pad-light.png b/core/assets-raw/sprites/blocks/campaign/launch-pad-light.png similarity index 100% rename from core/assets-raw/sprites/blocks/storage/launch-pad-light.png rename to core/assets-raw/sprites/blocks/campaign/launch-pad-light.png diff --git a/core/assets-raw/sprites/blocks/storage/launch-pad.png b/core/assets-raw/sprites/blocks/campaign/launch-pad.png similarity index 100% rename from core/assets-raw/sprites/blocks/storage/launch-pad.png rename to core/assets-raw/sprites/blocks/campaign/launch-pad.png diff --git a/core/assets-raw/sprites/blocks/storage/launchpod.png b/core/assets-raw/sprites/blocks/campaign/launchpod.png similarity index 100% rename from core/assets-raw/sprites/blocks/storage/launchpod.png rename to core/assets-raw/sprites/blocks/campaign/launchpod.png diff --git a/core/assets-raw/sprites/blocks/defense/large-overdrive-projector-top.png b/core/assets-raw/sprites/blocks/defense/large-overdrive-projector-top.png new file mode 100644 index 0000000000..4daa23ba53 Binary files /dev/null and b/core/assets-raw/sprites/blocks/defense/large-overdrive-projector-top.png differ diff --git a/core/assets-raw/sprites/blocks/defense/large-overdrive-projector.png b/core/assets-raw/sprites/blocks/defense/large-overdrive-projector.png new file mode 100644 index 0000000000..61515689d0 Binary files /dev/null and b/core/assets-raw/sprites/blocks/defense/large-overdrive-projector.png differ diff --git a/core/assets-raw/sprites/blocks/defense/segment.png b/core/assets-raw/sprites/blocks/defense/segment.png new file mode 100644 index 0000000000..57bd53d61d Binary files /dev/null and b/core/assets-raw/sprites/blocks/defense/segment.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/payload-router-edge.png b/core/assets-raw/sprites/blocks/distribution/payload-router-edge.png new file mode 100644 index 0000000000..c8335d4008 Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/payload-router-edge.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/payload-router-icon.png b/core/assets-raw/sprites/blocks/distribution/payload-router-icon.png new file mode 100644 index 0000000000..9d40f86518 Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/payload-router-icon.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/payload-router-over.png b/core/assets-raw/sprites/blocks/distribution/payload-router-over.png new file mode 100644 index 0000000000..52195b27a1 Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/payload-router-over.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/payload-router-top.png b/core/assets-raw/sprites/blocks/distribution/payload-router-top.png new file mode 100644 index 0000000000..8ecc636e9e Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/payload-router-top.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/payload-router.png b/core/assets-raw/sprites/blocks/distribution/payload-router.png new file mode 100644 index 0000000000..8c363b7435 Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/payload-router.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png deleted file mode 100644 index c49ac209e8..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png deleted file mode 100644 index d2896d5c7b..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png deleted file mode 100644 index 3a619260dd..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png deleted file mode 100644 index e673a4c6cf..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-5.png b/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-5.png deleted file mode 100644 index 2abf35998c..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-5.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-6.png b/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-6.png deleted file mode 100644 index cb31db8fd3..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/plated-conduit-top-6.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png deleted file mode 100644 index ff795df1fc..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png deleted file mode 100644 index f4e6379a31..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/power/solar-panel-large.png b/core/assets-raw/sprites/blocks/power/solar-panel-large.png index a5e37542f1..d520d3cbf5 100644 Binary files a/core/assets-raw/sprites/blocks/power/solar-panel-large.png and b/core/assets-raw/sprites/blocks/power/solar-panel-large.png differ diff --git a/core/assets-raw/sprites/blocks/power/solar-panel.png b/core/assets-raw/sprites/blocks/power/solar-panel.png index 9b2dfab795..9b960682a0 100644 Binary files a/core/assets-raw/sprites/blocks/power/solar-panel.png and b/core/assets-raw/sprites/blocks/power/solar-panel.png differ diff --git a/core/assets-raw/sprites/blocks/power/thorium-reactor-center.png b/core/assets-raw/sprites/blocks/power/thorium-reactor-top.png similarity index 100% rename from core/assets-raw/sprites/blocks/power/thorium-reactor-center.png rename to core/assets-raw/sprites/blocks/power/thorium-reactor-top.png diff --git a/core/assets-raw/sprites/blocks/production/block-launcher.png b/core/assets-raw/sprites/blocks/production/block-launcher.png deleted file mode 100644 index fa98a78ba4..0000000000 Binary files a/core/assets-raw/sprites/blocks/production/block-launcher.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/production/cryofluidmixer-bottom.png b/core/assets-raw/sprites/blocks/production/cryofluidmixer-bottom.png index f4d8646c0e..b9bc65af45 100644 Binary files a/core/assets-raw/sprites/blocks/production/cryofluidmixer-bottom.png and b/core/assets-raw/sprites/blocks/production/cryofluidmixer-bottom.png differ diff --git a/core/assets-raw/sprites/blocks/production/disassembler-liquid.png b/core/assets-raw/sprites/blocks/production/disassembler-liquid.png new file mode 100644 index 0000000000..88006fc498 Binary files /dev/null and b/core/assets-raw/sprites/blocks/production/disassembler-liquid.png differ diff --git a/core/assets-raw/sprites/blocks/production/disassembler-spinner.png b/core/assets-raw/sprites/blocks/production/disassembler-spinner.png new file mode 100644 index 0000000000..8a7c2bd606 Binary files /dev/null and b/core/assets-raw/sprites/blocks/production/disassembler-spinner.png differ diff --git a/core/assets-raw/sprites/blocks/production/disassembler.png b/core/assets-raw/sprites/blocks/production/disassembler.png new file mode 100644 index 0000000000..7dbfcb1474 Binary files /dev/null and b/core/assets-raw/sprites/blocks/production/disassembler.png differ diff --git a/core/assets-raw/sprites/blocks/production/graphite-press.png b/core/assets-raw/sprites/blocks/production/graphite-press.png index 37e6e3138a..c72febdb35 100644 Binary files a/core/assets-raw/sprites/blocks/production/graphite-press.png and b/core/assets-raw/sprites/blocks/production/graphite-press.png differ diff --git a/core/assets-raw/sprites/blocks/production/kiln.png b/core/assets-raw/sprites/blocks/production/kiln.png index a115501b61..d3aaec4ff6 100644 Binary files a/core/assets-raw/sprites/blocks/production/kiln.png and b/core/assets-raw/sprites/blocks/production/kiln.png differ diff --git a/core/assets-raw/sprites/blocks/production/silicon-crucible-top.png b/core/assets-raw/sprites/blocks/production/silicon-crucible-top.png new file mode 100644 index 0000000000..36cc10b089 Binary files /dev/null and b/core/assets-raw/sprites/blocks/production/silicon-crucible-top.png differ diff --git a/core/assets-raw/sprites/blocks/production/silicon-crucible.png b/core/assets-raw/sprites/blocks/production/silicon-crucible.png new file mode 100644 index 0000000000..9e0f352606 Binary files /dev/null and b/core/assets-raw/sprites/blocks/production/silicon-crucible.png differ diff --git a/core/assets-raw/sprites/blocks/production/silicon-smelter.png b/core/assets-raw/sprites/blocks/production/silicon-smelter.png index cbf1a9de5f..510deee463 100644 Binary files a/core/assets-raw/sprites/blocks/production/silicon-smelter.png and b/core/assets-raw/sprites/blocks/production/silicon-smelter.png differ diff --git a/core/assets-raw/sprites/units/cix-foot.png b/core/assets-raw/sprites/units/cix-foot.png index d198d789df..1e0d2bfcb7 100644 Binary files a/core/assets-raw/sprites/units/cix-foot.png and b/core/assets-raw/sprites/units/cix-foot.png differ diff --git a/core/assets-raw/sprites/units/cix-joint-base.png b/core/assets-raw/sprites/units/cix-joint-base.png new file mode 100644 index 0000000000..eb11ec2914 Binary files /dev/null and b/core/assets-raw/sprites/units/cix-joint-base.png differ diff --git a/core/assets-raw/sprites/units/cix-leg-base.png b/core/assets-raw/sprites/units/cix-leg-base.png index 17781d6781..6401faf7ee 100644 Binary files a/core/assets-raw/sprites/units/cix-leg-base.png and b/core/assets-raw/sprites/units/cix-leg-base.png differ diff --git a/core/assets-raw/sprites/units/cix-leg.png b/core/assets-raw/sprites/units/cix-leg.png index 4857465b32..3855a7a3b1 100644 Binary files a/core/assets-raw/sprites/units/cix-leg.png and b/core/assets-raw/sprites/units/cix-leg.png differ diff --git a/core/assets-raw/sprites/units/cix-old.png b/core/assets-raw/sprites/units/cix-old.png new file mode 100644 index 0000000000..7996cd3aa4 Binary files /dev/null and b/core/assets-raw/sprites/units/cix-old.png differ diff --git a/core/assets-raw/sprites/units/cix.png b/core/assets-raw/sprites/units/cix.png index 7996cd3aa4..5500e743df 100644 Binary files a/core/assets-raw/sprites/units/cix.png and b/core/assets-raw/sprites/units/cix.png differ diff --git a/core/assets-raw/sprites/units/eruptor-foot.png b/core/assets-raw/sprites/units/eruptor-foot.png new file mode 100644 index 0000000000..cb2348f903 Binary files /dev/null and b/core/assets-raw/sprites/units/eruptor-foot.png differ diff --git a/core/assets-raw/sprites/units/cix-joint.png b/core/assets-raw/sprites/units/eruptor-joint.png similarity index 100% rename from core/assets-raw/sprites/units/cix-joint.png rename to core/assets-raw/sprites/units/eruptor-joint.png diff --git a/core/assets-raw/sprites/units/eruptor-leg-base.png b/core/assets-raw/sprites/units/eruptor-leg-base.png new file mode 100644 index 0000000000..df93d2d320 Binary files /dev/null and b/core/assets-raw/sprites/units/eruptor-leg-base.png differ diff --git a/core/assets-raw/sprites/units/eruptor-leg.png b/core/assets-raw/sprites/units/eruptor-leg.png index 20bec1a51e..b4ffb9cb8d 100644 Binary files a/core/assets-raw/sprites/units/eruptor-leg.png and b/core/assets-raw/sprites/units/eruptor-leg.png differ diff --git a/core/assets-raw/sprites/units/lich-cell.png b/core/assets-raw/sprites/units/lich-cell.png index 1d320304b0..85c7517229 100644 Binary files a/core/assets-raw/sprites/units/lich-cell.png and b/core/assets-raw/sprites/units/lich-cell.png differ diff --git a/core/assets-raw/sprites/units/lich.png b/core/assets-raw/sprites/units/lich.png index d6048cfa25..10af20cfb9 100644 Binary files a/core/assets-raw/sprites/units/lich.png and b/core/assets-raw/sprites/units/lich.png differ diff --git a/core/assets-raw/sprites/units/reaper.png b/core/assets-raw/sprites/units/reaper.png index ab6175801b..a85075830f 100644 Binary files a/core/assets-raw/sprites/units/reaper.png and b/core/assets-raw/sprites/units/reaper.png differ diff --git a/core/assets-raw/sprites/units/revenant-cell.png b/core/assets-raw/sprites/units/revenant-cell.png index 2bf4ee9866..852af58904 100644 Binary files a/core/assets-raw/sprites/units/revenant-cell.png and b/core/assets-raw/sprites/units/revenant-cell.png differ diff --git a/core/assets-raw/sprites/units/revenant.png b/core/assets-raw/sprites/units/revenant.png index 0355715192..469d949c41 100644 Binary files a/core/assets-raw/sprites/units/revenant.png and b/core/assets-raw/sprites/units/revenant.png differ diff --git a/core/assets-raw/sprites/weapons/revenant-missiles.png b/core/assets-raw/sprites/weapons/revenant-missiles.png index 6aaac4c6d7..bc7dd1f0a5 100644 Binary files a/core/assets-raw/sprites/weapons/revenant-missiles.png and b/core/assets-raw/sprites/weapons/revenant-missiles.png differ diff --git a/core/assets/baseparts/1591368647700.msch b/core/assets/baseparts/1591368647700.msch new file mode 100644 index 0000000000..4235369db1 --- /dev/null +++ b/core/assets/baseparts/1591368647700.msch @@ -0,0 +1,2 @@ +mschx- + EUB>ć}aZՍv 9$|&Lj{(N}|J."̱QvG5}}5yG[Be. "ꒁSIPƊaΙ -hY +zd:hAM \ No newline at end of file diff --git a/core/assets/baseparts/1591368707268.msch b/core/assets/baseparts/1591368707268.msch new file mode 100644 index 0000000000..ee88f4b397 --- /dev/null +++ b/core/assets/baseparts/1591368707268.msch @@ -0,0 +1,2 @@ +mschx%L + <*A>ħ}kC+VߟYIrw%`<0or!%lq1+\M3܎PWk,UK0o}.aeF%uKAwB*?X=V"5~[ \ No newline at end of file diff --git a/core/assets/baseparts/1591369683871.msch b/core/assets/baseparts/1591369683871.msch new file mode 100644 index 0000000000..6a03cd7f4e Binary files /dev/null and b/core/assets/baseparts/1591369683871.msch differ diff --git a/core/assets/baseparts/1591369726023.msch b/core/assets/baseparts/1591369726023.msch new file mode 100644 index 0000000000..eb87221260 Binary files /dev/null and b/core/assets/baseparts/1591369726023.msch differ diff --git a/core/assets/baseparts/1591378058396.msch b/core/assets/baseparts/1591378058396.msch new file mode 100644 index 0000000000..4d1b6b91aa Binary files /dev/null and b/core/assets/baseparts/1591378058396.msch differ diff --git a/core/assets/baseparts/1591380533871.msch b/core/assets/baseparts/1591380533871.msch new file mode 100644 index 0000000000..aa42280794 --- /dev/null +++ b/core/assets/baseparts/1591380533871.msch @@ -0,0 +1,2 @@ +mschx%] GD4>jō5A0@xKfgi~Ts@Ka=(l]=JtbS\ />ct7'Vqwql1ؕ'*»IAA52Z4 +uQIZ%~jZ zz]'fa苡/U\, \ No newline at end of file diff --git a/core/assets/baseparts/1591380739339.msch b/core/assets/baseparts/1591380739339.msch new file mode 100644 index 0000000000..e7a245e2d7 --- /dev/null +++ b/core/assets/baseparts/1591380739339.msch @@ -0,0 +1,2 @@ +mschxA +!^r7|q]A|?c(h1excqʏ,,͝5MQ'SZq-Y@8:L"o@4' \ No newline at end of file diff --git a/core/assets/baseparts/1591381320600.msch b/core/assets/baseparts/1591381320600.msch new file mode 100644 index 0000000000..9ec53eaf98 --- /dev/null +++ b/core/assets/baseparts/1591381320600.msch @@ -0,0 +1,2 @@ +mschxE +0 `{>TA *g@.Ơ=on)v쎣 AlM,S&Ns/jO1!q` K,&[R(O6 E * ?ʻ.>hRSɖ-TQBTP5PA( \ No newline at end of file diff --git a/core/assets/baseparts/1591385128968.msch b/core/assets/baseparts/1591385128968.msch new file mode 100644 index 0000000000..d6ae616c4f --- /dev/null +++ b/core/assets/baseparts/1591385128968.msch @@ -0,0 +1 @@ +mschx-kn0్]$mZgP!/.S~Y ; >> :ĥoԧ ~i(1&T ͜ש[\X}Xb%ē@^HIG;vZ+V_pAF6BR;9Wr&r%o$QEoUk"-H?| \ No newline at end of file diff --git a/core/assets/baseparts/1591385266195.msch b/core/assets/baseparts/1591385266195.msch new file mode 100644 index 0000000000..4611adddfa --- /dev/null +++ b/core/assets/baseparts/1591385266195.msch @@ -0,0 +1 @@ +mschxMa0 LDBsp)ŐF&숳si+NP As6rhnvԮJPg,88v0 kDc  )2g o~kxEFESDSɾ&'JeeU/!u4u0@}wO< \ No newline at end of file diff --git a/core/assets/baseparts/1591385293703.msch b/core/assets/baseparts/1591385293703.msch new file mode 100644 index 0000000000..d48006b7be --- /dev/null +++ b/core/assets/baseparts/1591385293703.msch @@ -0,0 +1,2 @@ +mschx%A +0 'VKB ~eKjǗJ HbwV,0py/%ARym{mɄ-ռFU%O]v>9"S(H~)X_dKaYDݹ(Sim;VI^e0s-@ uVxz?k \ No newline at end of file diff --git a/core/assets/baseparts/1591389561116.msch b/core/assets/baseparts/1591389561116.msch new file mode 100644 index 0000000000..667b021f4a --- /dev/null +++ b/core/assets/baseparts/1591389561116.msch @@ -0,0 +1,3 @@ +mschx=Љn0 `pKKco>Tш!Է_*c'C~ +cCsLU;O35cl06 .a m3]Z֜Ur[n#Ry ^ b1Cp58/ ߃J2nd;#gs(p(pZd0 +)ЄdvFpU]`- .$Y+; . \ No newline at end of file diff --git a/core/assets/baseparts/1591389593326.msch b/core/assets/baseparts/1591389593326.msch new file mode 100644 index 0000000000..57264dcc72 --- /dev/null +++ b/core/assets/baseparts/1591389593326.msch @@ -0,0 +1 @@ +mschx=] GIo7eIjMo_I3; n֯vyi6C>2-k/C7DXvt!BGBӱ r*^55RSkJ3%r6\b8p#FQ,Z[FG8i UCe? clear = Clear banned = [scarlet]Banned +unplaceable.sectorcaptured = [scarlet]Requires captured sector yes = Yes no = No info.title = Info @@ -785,8 +784,6 @@ rules.unitdrops = Unit Drops rules.unitbuildspeedmultiplier = Unit Production Speed Multiplier rules.unithealthmultiplier = Unit Health Multiplier rules.blockhealthmultiplier = Block Health Multiplier -rules.playerhealthmultiplier = Player Health Multiplier -rules.playerdamagemultiplier = Player Damage Multiplier rules.unitdamagemultiplier = Unit Damage Multiplier rules.enemycorebuildradius = Enemy Core No-Build Radius:[lightgray] (tiles) rules.wavespacing = Wave Spacing:[lightgray] (sec) @@ -796,12 +793,11 @@ rules.deconstructrefundmultiplier = Deconstruct Refund Multiplier rules.waitForWaveToEnd = Waves Wait for Enemies rules.dropzoneradius = Drop Zone Radius:[lightgray] (tiles) rules.title.waves = Waves -rules.title.respawns = Respawns rules.title.resourcesbuilding = Resources & Building -rules.title.player = Players rules.title.enemy = Enemies rules.title.unit = Units rules.title.experimental = Experimental +rules.title.environment = Environment rules.lighting = Lighting rules.ambientlight = Ambient Light rules.solarpowermultiplier = Solar Power Multiplier diff --git a/core/assets/contributors b/core/assets/contributors index ba93d0b0ab..60cc9cc286 100644 --- a/core/assets/contributors +++ b/core/assets/contributors @@ -88,3 +88,4 @@ Alicila Daniel Dusek DeltaNedas GioIacca9 +SnakkiZXZ \ No newline at end of file diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 9ef0993f06..5a569f86d6 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -235,3 +235,10 @@ 63509=basic-reconstructor|block-basic-reconstructor-medium 63508=block-loader|block-block-loader-medium 63507=block-unloader|block-block-unloader-medium +63506=core-silo|block-core-silo-medium +63505=data-processor|block-data-processor-medium +63504=payload-router|block-payload-router-medium +63503=silicon-crucible|block-silicon-crucible-medium +63502=segment|block-segment-medium +63501=large-overdrive-projector|block-large-overdrive-projector-medium +63500=disassembler|block-disassembler-medium diff --git a/core/assets/maps/groundZero.msav b/core/assets/maps/groundZero.msav index 078b1a0caf..4e6900b4c3 100644 Binary files a/core/assets/maps/groundZero.msav and b/core/assets/maps/groundZero.msav differ diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 813f18a16c..b8acc336b9 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -24,70 +24,72 @@ const extend = function(classType, params){ const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) Call = Packages.mindustry.gen.Call -importPackage(Packages.mindustry.game) -importPackage(Packages.arc.func) -importPackage(Packages.mindustry.entities) +importPackage(Packages.mindustry.graphics.g3d) +importPackage(Packages.mindustry.ctype) importPackage(Packages.mindustry.gen) -importPackage(Packages.mindustry.core) -importPackage(Packages.mindustry.world.blocks.storage) -importPackage(Packages.mindustry.ui.dialogs) -importPackage(Packages.arc.scene.ui) -importPackage(Packages.mindustry.world.blocks.defense.turrets) -importPackage(Packages.mindustry.world.blocks.distribution) -importPackage(Packages.mindustry.ui) -importPackage(Packages.mindustry.content) -importPackage(Packages.mindustry.world.blocks.liquid) -importPackage(Packages.arc.struct) -importPackage(Packages.arc.scene.ui.layout) -importPackage(Packages.mindustry.world.modules) -importPackage(Packages.arc.util) -importPackage(Packages.arc.graphics) -importPackage(Packages.mindustry.entities.def) -importPackage(Packages.mindustry.maps.generators) importPackage(Packages.arc.scene.actions) -importPackage(Packages.mindustry.graphics) -importPackage(Packages.mindustry.entities.bullet) -importPackage(Packages.mindustry.world.blocks.legacy) -importPackage(Packages.mindustry.world.blocks.experimental) importPackage(Packages.mindustry.editor) +importPackage(Packages.mindustry.type) +importPackage(Packages.arc.scene.ui) +importPackage(Packages.arc.math.geom) +importPackage(Packages.mindustry.game) +importPackage(Packages.mindustry.maps.filters) +importPackage(Packages.arc.struct) +importPackage(Packages.arc.scene.style) +importPackage(Packages.mindustry.ui.dialogs) +importPackage(Packages.mindustry.entities.comp) +importPackage(Packages.mindustry.world.blocks.defense.turrets) +importPackage(Packages.mindustry.async) +importPackage(Packages.mindustry.world.blocks.distribution) +importPackage(Packages.mindustry.world.blocks.environment) +importPackage(Packages.mindustry.world.blocks.campaign) +importPackage(Packages.mindustry.world.blocks.liquid) +importPackage(Packages.mindustry.ui) +importPackage(Packages.mindustry.world.blocks.production) +importPackage(Packages.mindustry.ai) +importPackage(Packages.mindustry.world.blocks.defense) +importPackage(Packages.mindustry.world.meta) +importPackage(Packages.mindustry.world.blocks.legacy) +importPackage(Packages.mindustry.world.blocks.units) +importPackage(Packages.arc.graphics) +importPackage(Packages.arc.func) +importPackage(Packages.mindustry.content) importPackage(Packages.mindustry.world.blocks.power) -importPackage(Packages.mindustry.ui.layout) +importPackage(Packages.mindustry.world.blocks) +importPackage(Packages.arc.scene.event) +importPackage(Packages.mindustry.logic) +importPackage(Packages.arc.math) +importPackage(Packages.mindustry.world) +importPackage(Packages.mindustry.maps) +importPackage(Packages.mindustry.maps.generators) +importPackage(Packages.mindustry.world.meta.values) +importPackage(Packages.mindustry.entities) +importPackage(Packages.arc.util) +importPackage(Packages.mindustry.graphics) +importPackage(Packages.mindustry.world.modules) importPackage(Packages.mindustry.world.blocks.sandbox) importPackage(Packages.mindustry.input) -importPackage(Packages.mindustry.world.consumers) -importPackage(Packages.mindustry.ui.fragments) -importPackage(Packages.mindustry.ai.formations) -importPackage(Packages.mindustry.type) -importPackage(Packages.mindustry.world.blocks.production) -importPackage(Packages.arc.scene.event) -importPackage(Packages.arc.math) -importPackage(Packages.arc.scene.utils) -importPackage(Packages.mindustry.world.blocks.defense) -importPackage(Packages.mindustry.graphics.g3d) -importPackage(Packages.mindustry.world.meta) -importPackage(Packages.mindustry.world.blocks.payloads) -importPackage(Packages.mindustry.world) -importPackage(Packages.mindustry.async) -importPackage(Packages.arc.scene.style) -importPackage(Packages.mindustry.world.blocks) -importPackage(Packages.arc.math.geom) -importPackage(Packages.mindustry.ai) -importPackage(Packages.mindustry.maps.filters) -importPackage(Packages.arc.graphics.g2d) -importPackage(Packages.mindustry.ai.formations.patterns) -importPackage(Packages.mindustry.world.blocks.environment) -importPackage(Packages.mindustry) importPackage(Packages.mindustry.entities.units) -importPackage(Packages.mindustry.ctype) +importPackage(Packages.arc.scene.ui.layout) importPackage(Packages.mindustry.ai.types) -importPackage(Packages.mindustry.maps) -importPackage(Packages.mindustry.world.meta.values) -importPackage(Packages.mindustry.world.producers) -importPackage(Packages.mindustry.world.blocks.units) +importPackage(Packages.mindustry.ai.formations.patterns) +importPackage(Packages.arc.scene.utils) +importPackage(Packages.mindustry.ai.formations) +importPackage(Packages.mindustry.ui.fragments) +importPackage(Packages.mindustry.world.blocks.experimental) +importPackage(Packages.mindustry.world.blocks.storage) +importPackage(Packages.mindustry.audio) +importPackage(Packages.mindustry.ui.layout) +importPackage(Packages.mindustry.entities.bullet) +importPackage(Packages.mindustry.world.consumers) +importPackage(Packages.mindustry.core) importPackage(Packages.arc.scene) -importPackage(Packages.mindustry.maps.planet) +importPackage(Packages.mindustry) importPackage(Packages.arc) -importPackage(Packages.mindustry.world.blocks.logic) +importPackage(Packages.mindustry.world.blocks.payloads) +importPackage(Packages.mindustry.world.producers) +importPackage(Packages.arc.graphics.g2d) +importPackage(Packages.mindustry.maps.planet) const PlayerIpUnbanEvent = Packages.mindustry.game.EventType.PlayerIpUnbanEvent const PlayerIpBanEvent = Packages.mindustry.game.EventType.PlayerIpBanEvent const PlayerUnbanEvent = Packages.mindustry.game.EventType.PlayerUnbanEvent @@ -95,8 +97,7 @@ const PlayerBanEvent = Packages.mindustry.game.EventType.PlayerBanEvent const PlayerLeave = Packages.mindustry.game.EventType.PlayerLeave const PlayerConnect = Packages.mindustry.game.EventType.PlayerConnect const PlayerJoin = Packages.mindustry.game.EventType.PlayerJoin -const MechChangeEvent = Packages.mindustry.game.EventType.MechChangeEvent -const ResizeEvent = Packages.mindustry.game.EventType.ResizeEvent +const UnitChangeEvent = Packages.mindustry.game.EventType.UnitChangeEvent const UnitCreateEvent = Packages.mindustry.game.EventType.UnitCreateEvent const UnitDestroyEvent = Packages.mindustry.game.EventType.UnitDestroyEvent const BlockDestroyEvent = Packages.mindustry.game.EventType.BlockDestroyEvent @@ -107,12 +108,19 @@ const ResearchEvent = Packages.mindustry.game.EventType.ResearchEvent const UnlockEvent = Packages.mindustry.game.EventType.UnlockEvent const StateChangeEvent = Packages.mindustry.game.EventType.StateChangeEvent const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent -const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent const TapConfigEvent = Packages.mindustry.game.EventType.TapConfigEvent const TapEvent = Packages.mindustry.game.EventType.TapEvent const DepositEvent = Packages.mindustry.game.EventType.DepositEvent const WithdrawEvent = Packages.mindustry.game.EventType.WithdrawEvent +const SectorCaptureEvent = Packages.mindustry.game.EventType.SectorCaptureEvent +const ZoneConfigureCompleteEvent = Packages.mindustry.game.EventType.ZoneConfigureCompleteEvent +const ZoneRequireCompleteEvent = Packages.mindustry.game.EventType.ZoneRequireCompleteEvent +const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent +const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent +const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent +const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent +const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent @@ -123,17 +131,13 @@ const PlayEvent = Packages.mindustry.game.EventType.PlayEvent const DisposeEvent = Packages.mindustry.game.EventType.DisposeEvent const ContentReloadEvent = Packages.mindustry.game.EventType.ContentReloadEvent const ServerLoadEvent = Packages.mindustry.game.EventType.ServerLoadEvent -const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent const ClientCreateEvent = Packages.mindustry.game.EventType.ClientCreateEvent const SaveLoadEvent = Packages.mindustry.game.EventType.SaveLoadEvent -const ZoneConfigureCompleteEvent = Packages.mindustry.game.EventType.ZoneConfigureCompleteEvent -const ZoneRequireCompleteEvent = Packages.mindustry.game.EventType.ZoneRequireCompleteEvent -const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent -const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent const MapPublishEvent = Packages.mindustry.game.EventType.MapPublishEvent const MapMakeEvent = Packages.mindustry.game.EventType.MapMakeEvent -const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent +const ResizeEvent = Packages.mindustry.game.EventType.ResizeEvent const LaunchEvent = Packages.mindustry.game.EventType.LaunchEvent const LoseEvent = Packages.mindustry.game.EventType.LoseEvent const WinEvent = Packages.mindustry.game.EventType.WinEvent +const TurnEvent = Packages.mindustry.game.EventType.TurnEvent const Trigger = Packages.mindustry.game.EventType.Trigger diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png index 32e579d0db..43a89d0603 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/sprites.atlas b/core/assets/sprites/sprites.atlas index 46c804012d..dfc92d4789 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -4,156 +4,212 @@ size: 2048,2048 format: RGBA8888 filter: Nearest,Nearest repeat: none +core-silo + rotate: false + xy: 1, 679 + size: 160, 160 + orig: 160, 160 + offset: 0, 0 + index: -1 +data-processor + rotate: false + xy: 1803, 1301 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +launch-pad + rotate: false + xy: 1194, 1105 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +launch-pad-large + rotate: false + xy: 1628, 1627 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +launch-pad-light + rotate: false + xy: 1292, 1105 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +launchpod + rotate: false + xy: 1981, 1983 + size: 66, 64 + orig: 66, 64 + offset: 0, 0 + index: -1 force-projector rotate: false - xy: 489, 484 + xy: 1782, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 force-projector-top rotate: false - xy: 489, 386 + xy: 1880, 1203 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +large-overdrive-projector + rotate: false + xy: 1684, 1105 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +large-overdrive-projector-top + rotate: false + xy: 1782, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mend-projector rotate: false - xy: 1799, 1073 + xy: 565, 653 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mend-projector-top rotate: false - xy: 1865, 1073 + xy: 565, 587 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender rotate: false - xy: 1197, 433 + xy: 1375, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mender-top rotate: false - xy: 1231, 467 + xy: 1409, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overdrive-projector rotate: false - xy: 1733, 1007 + xy: 565, 455 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overdrive-projector-top rotate: false - xy: 1799, 1007 + xy: 557, 389 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shock-mine rotate: false - xy: 1435, 501 + xy: 1545, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-loader rotate: false - xy: 884, 1278 + xy: 1133, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-unloader rotate: false - xy: 1493, 1399 + xy: 1819, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 bridge-arrow rotate: false - xy: 917, 137 + xy: 1683, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor rotate: false - xy: 1027, 621 + xy: 1747, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-bridge rotate: false - xy: 1027, 587 + xy: 1679, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-end rotate: false - xy: 1027, 553 + xy: 1713, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 center rotate: false - xy: 1027, 519 + xy: 1747, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-0 rotate: false - xy: 951, 1104 + xy: 2015, 1417 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-armored-conveyor-full rotate: false - xy: 951, 1104 + xy: 2015, 1417 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-1 rotate: false - xy: 925, 613 + xy: 1888, 1629 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-2 rotate: false - xy: 967, 655 + xy: 499, 421 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-3 rotate: false - xy: 1009, 697 + xy: 557, 91 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-0 rotate: false - xy: 1051, 739 + xy: 1513, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -167,1708 +223,1708 @@ armored-conveyor-1-1 index: -1 armored-conveyor-1-2 rotate: false - xy: 925, 579 + xy: 485, 820 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-3 rotate: false - xy: 1085, 739 + xy: 1922, 1629 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-0 rotate: false - xy: 925, 545 + xy: 1547, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-1 rotate: false - xy: 1119, 739 + xy: 1581, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-2 rotate: false - xy: 925, 511 + xy: 1615, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-3 rotate: false - xy: 1153, 739 + xy: 1649, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-0 rotate: false - xy: 925, 477 + xy: 1711, 1889 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-1 rotate: false - xy: 1187, 739 + xy: 1811, 1759 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-2 rotate: false - xy: 925, 443 + xy: 1845, 1759 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-3 rotate: false - xy: 1221, 739 + xy: 989, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-0 rotate: false - xy: 925, 409 + xy: 519, 817 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-1 rotate: false - xy: 1255, 739 + xy: 989, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-2 rotate: false - xy: 925, 375 + xy: 1023, 45 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-3 rotate: false - xy: 1289, 739 + xy: 1023, 11 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-1 rotate: false - xy: 1019, 179 + xy: 1819, 557 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-2 rotate: false - xy: 985, 111 + xy: 1781, 523 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-3 rotate: false - xy: 1019, 145 + xy: 1815, 523 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-0 rotate: false - xy: 1019, 111 + xy: 1781, 489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-1 rotate: false - xy: 1069, 663 + xy: 1815, 489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-2 rotate: false - xy: 1061, 629 + xy: 1849, 523 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-3 rotate: false - xy: 1061, 595 + xy: 1849, 489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-0 rotate: false - xy: 1061, 561 + xy: 1137, 536 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-1 rotate: false - xy: 1061, 527 + xy: 1137, 502 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-2 rotate: false - xy: 1061, 493 + xy: 1171, 536 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-3 rotate: false - xy: 1061, 459 + xy: 1137, 468 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-0 rotate: false - xy: 1061, 425 + xy: 1171, 502 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-1 rotate: false - xy: 1061, 391 + xy: 1171, 468 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-2 rotate: false - xy: 1061, 357 + xy: 1137, 434 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-3 rotate: false - xy: 1061, 323 + xy: 1171, 434 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-0 rotate: false - xy: 1103, 671 + xy: 1137, 400 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-1 rotate: false - xy: 1137, 671 + xy: 1137, 366 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-2 rotate: false - xy: 1171, 671 + xy: 1171, 400 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-3 rotate: false - xy: 1205, 671 + xy: 1137, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor rotate: false - xy: 1333, 535 + xy: 1375, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor-0 rotate: false - xy: 1367, 569 + xy: 1409, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor-1 rotate: false - xy: 1401, 603 + xy: 1443, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor-2 rotate: false - xy: 1435, 637 + xy: 1307, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor-edge rotate: false - xy: 1163, 331 + xy: 1341, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-conveyor-stack rotate: false - xy: 1197, 365 + xy: 1375, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-1 rotate: false - xy: 1503, 501 + xy: 1511, 287 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-2 rotate: false - xy: 1537, 535 + xy: 1545, 321 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-3 rotate: false - xy: 1367, 331 + xy: 1579, 355 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-0 rotate: false - xy: 1401, 365 + xy: 1613, 389 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-1 rotate: false - xy: 1435, 399 + xy: 1477, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-2 rotate: false - xy: 1469, 433 + xy: 1511, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-3 rotate: false - xy: 1503, 467 + xy: 1545, 287 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-0 rotate: false - xy: 1537, 501 + xy: 1579, 321 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-1 rotate: false - xy: 1401, 331 + xy: 1613, 355 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-2 rotate: false - xy: 1435, 365 + xy: 1477, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-3 rotate: false - xy: 1469, 399 + xy: 1511, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-0 rotate: false - xy: 1503, 433 + xy: 1545, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-1 rotate: false - xy: 1537, 467 + xy: 1579, 287 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-2 rotate: false - xy: 1435, 331 + xy: 1613, 321 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-3 rotate: false - xy: 1469, 365 + xy: 1477, 151 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-0 rotate: false - xy: 1503, 399 + xy: 1511, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-1 rotate: false - xy: 1537, 433 + xy: 1545, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-2 rotate: false - xy: 1469, 331 + xy: 1579, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-3 rotate: false - xy: 1503, 365 + xy: 1613, 287 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cross rotate: false - xy: 1545, 671 + xy: 1137, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 distributor rotate: false - xy: 1535, 1103 + xy: 491, 84 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 inverted-sorter rotate: false - xy: 1095, 629 + xy: 1205, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction rotate: false - xy: 1231, 569 + xy: 1239, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-conveyor rotate: false - xy: 587, 288 + xy: 1015, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-conveyor-edge rotate: false - xy: 587, 190 + xy: 1113, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-conveyor-top rotate: false - xy: 587, 92 + xy: 1113, 909 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +payload-router-top + rotate: false + xy: 1113, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-driver-base rotate: false - xy: 685, 680 + xy: 1211, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 overflow-gate rotate: false - xy: 1299, 535 + xy: 1239, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +payload-router + rotate: false + xy: 1309, 811 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +payload-router-edge + rotate: false + xy: 1407, 1007 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +payload-router-over + rotate: false + xy: 1407, 909 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 phase-conveyor rotate: false - xy: 1163, 365 + xy: 1409, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-arrow rotate: false - xy: 1197, 399 + xy: 1443, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-bridge rotate: false - xy: 1231, 433 + xy: 1273, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-end rotate: false - xy: 1265, 467 + xy: 1307, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 router rotate: false - xy: 1367, 467 + xy: 1409, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sorter rotate: false - xy: 1503, 569 + xy: 1477, 355 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 underflow-gate rotate: false - xy: 1537, 365 + xy: 1579, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-drill rotate: false - xy: 323, 1072 + xy: 526, 1275 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rim rotate: false - xy: 526, 1275 + xy: 656, 1312 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rotator rotate: false - xy: 656, 1312 + xy: 863, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-top rotate: false - xy: 863, 1757 + xy: 993, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 drill-top rotate: false - xy: 819, 1064 + xy: 623, 790 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-liquid rotate: false - xy: 819, 1064 + xy: 623, 790 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill rotate: false - xy: 293, 124 + xy: 1880, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rim rotate: false - xy: 391, 106 + xy: 900, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rotator rotate: false - xy: 489, 92 + xy: 998, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-top rotate: false - xy: 285, 26 + xy: 1096, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill rotate: false - xy: 1799, 1139 + xy: 499, 521 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-rotator rotate: false - xy: 1865, 1139 + xy: 499, 455 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-top rotate: false - xy: 1733, 1073 + xy: 565, 719 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 oil-extractor rotate: false - xy: 685, 386 + xy: 917, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-liquid rotate: false - xy: 685, 288 + xy: 1015, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-rotator rotate: false - xy: 685, 190 + xy: 1113, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-top rotate: false - xy: 685, 92 + xy: 1211, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 pneumatic-drill rotate: false - xy: 1017, 971 + xy: 623, 191 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-rotator rotate: false - xy: 1149, 1037 + xy: 623, 125 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-top rotate: false - xy: 1017, 905 + xy: 615, 59 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor rotate: false - xy: 1215, 773 + xy: 895, 745 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-liquid rotate: false - xy: 1281, 773 + xy: 961, 745 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-rotator rotate: false - xy: 1347, 773 + xy: 895, 679 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-top rotate: false - xy: 1413, 773 + xy: 1027, 745 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border rotate: false - xy: 1459, 739 + xy: 275, 27 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-middle rotate: false - xy: 993, 519 + xy: 1407, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-select rotate: false - xy: 1485, 705 + xy: 1645, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-liquid rotate: false - xy: 985, 281 + xy: 1821, 659 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message rotate: false - xy: 1265, 501 + xy: 1443, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 place-arrow rotate: false - xy: 1003, 1301 + xy: 1505, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 bridge-conduit rotate: false - xy: 951, 171 + xy: 1717, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-arrow rotate: false - xy: 951, 137 + xy: 1751, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-arrow rotate: false - xy: 951, 137 + xy: 1751, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-bridge rotate: false - xy: 917, 103 + xy: 1679, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-end rotate: false - xy: 951, 103 + xy: 1713, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom rotate: false - xy: 1027, 417 + xy: 1822, 727 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-0 rotate: false - xy: 1027, 383 + xy: 1787, 693 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-1 rotate: false - xy: 1027, 349 + xy: 1821, 693 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-2 rotate: false - xy: 993, 315 + xy: 1787, 659 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-3 rotate: false - xy: 993, 315 + xy: 1787, 659 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-4 rotate: false - xy: 993, 315 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -conduit-bottom-6 - rotate: false - xy: 993, 315 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -conduit-bottom-5 - rotate: false - xy: 1027, 315 + xy: 1787, 659 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-0 rotate: false - xy: 985, 247 + xy: 1785, 625 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-1 rotate: false - xy: 1019, 281 + xy: 1785, 591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-2 rotate: false - xy: 985, 213 + xy: 1819, 625 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-3 rotate: false - xy: 1019, 247 + xy: 1819, 591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-3 rotate: false - xy: 1019, 247 + xy: 1819, 591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-4 rotate: false - xy: 985, 179 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -conduit-top-5 - rotate: false - xy: 1019, 213 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -conduit-top-6 - rotate: false - xy: 985, 145 + xy: 1785, 557 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-junction rotate: false - xy: 1129, 433 + xy: 1341, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-overflow-gate rotate: false - xy: 1231, 535 + xy: 1443, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-overflow-gate-top rotate: false - xy: 1265, 569 + xy: 1205, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-bottom rotate: false - xy: 1299, 603 + xy: 1239, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-liquid rotate: false - xy: 1333, 637 + xy: 1273, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-top rotate: false - xy: 1129, 399 + xy: 1307, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-bottom rotate: false - xy: 587, 582 + xy: 917, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-liquid rotate: false - xy: 587, 484 + xy: 917, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-top rotate: false - xy: 587, 386 + xy: 1015, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-pump rotate: false - xy: 1367, 637 + xy: 1273, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mechanical-pump-liquid rotate: false - xy: 1129, 365 + xy: 1307, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump-liquid rotate: false - xy: 1129, 365 + xy: 1307, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-pump-liquid rotate: false - xy: 1129, 365 + xy: 1307, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit rotate: false - xy: 1333, 569 + xy: 1273, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-arrow rotate: false - xy: 1367, 603 + xy: 1307, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-bridge rotate: false - xy: 1401, 637 + xy: 1341, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-end rotate: false - xy: 1129, 331 + xy: 1375, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-cap rotate: false - xy: 1265, 433 + xy: 1443, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-0 rotate: false - xy: 1299, 467 + xy: 1341, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-1 rotate: false - xy: 1333, 501 + xy: 1375, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-2 rotate: false - xy: 1367, 535 + xy: 1409, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-3 rotate: false - xy: 1401, 569 + xy: 1443, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-4 rotate: false - xy: 1435, 603 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -plated-conduit-top-5 - rotate: false - xy: 1469, 637 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -plated-conduit-top-6 - rotate: false - xy: 1197, 331 + xy: 1375, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-0 rotate: false - xy: 1333, 467 + xy: 1443, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-1 rotate: false - xy: 1367, 501 + xy: 1443, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-2 rotate: false - xy: 1401, 535 + xy: 1205, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-4 rotate: false - xy: 1435, 569 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -pulse-conduit-top-5 - rotate: false - xy: 1469, 603 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -pulse-conduit-top-6 - rotate: false - xy: 1503, 637 + xy: 1239, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump rotate: false - xy: 1149, 971 + xy: 697, 722 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-pump rotate: false - xy: 1591, 1301 + xy: 1701, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 battery rotate: false - xy: 1323, 739 + xy: 1057, 45 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large rotate: false - xy: 721, 998 + xy: 623, 856 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 battery-large-top rotate: false - xy: 721, 900 + xy: 721, 952 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 battery-top rotate: false - xy: 1357, 739 + xy: 1057, 11 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator rotate: false - xy: 1027, 485 + xy: 1159, 27 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator-top rotate: false - xy: 1027, 451 + xy: 1788, 727 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 differential-generator rotate: false - xy: 391, 692 + xy: 1901, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-liquid rotate: false - xy: 391, 594 + xy: 900, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-top rotate: false - xy: 391, 496 + xy: 998, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 diode rotate: false - xy: 1053, 281 + xy: 1171, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 diode-arrow rotate: false - xy: 1053, 247 + xy: 1171, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator rotate: false - xy: 985, 77 + xy: 1883, 489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-top rotate: false - xy: 1019, 77 + xy: 1205, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor rotate: false - xy: 163, 191 + xy: 807, 1474 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-bottom rotate: false - xy: 155, 61 + xy: 937, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-light rotate: false - xy: 807, 1474 + xy: 1067, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-0 rotate: false - xy: 937, 1497 + xy: 1197, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-1 rotate: false - xy: 1067, 1497 + xy: 1327, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-2 rotate: false - xy: 1197, 1497 + xy: 1457, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-3 rotate: false - xy: 1327, 1497 + xy: 1587, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 power-node rotate: false - xy: 1231, 365 + xy: 1409, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large rotate: false - xy: 1083, 971 + xy: 681, 59 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source rotate: false - xy: 1265, 399 + xy: 1443, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void rotate: false - xy: 1299, 433 + xy: 1409, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator rotate: false - xy: 1281, 1037 + xy: 631, 590 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rtg-generator-top rotate: false - xy: 1401, 501 + xy: 1443, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel rotate: false - xy: 1469, 535 + xy: 1613, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large rotate: false - xy: 1493, 1301 + xy: 1603, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 surge-tower rotate: false - xy: 1083, 839 + xy: 755, 128 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-generator rotate: false - xy: 1281, 839 + xy: 829, 656 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-reactor rotate: false - xy: 1689, 1337 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 -thorium-reactor-center - rotate: false - xy: 1787, 1337 + xy: 1799, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-lights rotate: false - xy: 1885, 1337 + xy: 1701, 811 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +thorium-reactor-top + rotate: false + xy: 1799, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 turbine-generator rotate: false - xy: 1017, 773 + xy: 821, 194 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-top rotate: false - xy: 1083, 773 + xy: 821, 128 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 alloy-smelter rotate: false - xy: 525, 876 + xy: 525, 949 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 alloy-smelter-top rotate: false - xy: 623, 986 + xy: 623, 954 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-mixer rotate: false - xy: 1983, 1369 + xy: 293, 394 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 -block-launcher - rotate: false - xy: 786, 1278 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 coal-centrifuge rotate: false - xy: 1586, 1235 + xy: 367, 414 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-bottom rotate: false - xy: 1007, 1103 + xy: 359, 84 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-liquid rotate: false - xy: 1073, 1103 + xy: 425, 84 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-top rotate: false - xy: 1139, 1103 + xy: 351, 18 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator rotate: false - xy: 1205, 1103 + xy: 417, 18 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-middle rotate: false - xy: 1271, 1103 + xy: 491, 348 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-top rotate: false - xy: 1337, 1103 + xy: 491, 282 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +disassembler + rotate: false + xy: 1096, 1203 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +disassembler-liquid + rotate: false + xy: 1194, 1203 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +disassembler-spinner + rotate: false + xy: 1292, 1203 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 graphite-press rotate: false - xy: 885, 1006 + xy: 755, 788 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 incinerator rotate: false - xy: 1053, 77 + xy: 1239, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source rotate: false - xy: 1197, 603 + xy: 1375, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void rotate: false - xy: 1197, 535 + xy: 1205, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln rotate: false - xy: 885, 940 + xy: 821, 788 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 kiln-top rotate: false - xy: 819, 866 + xy: 499, 719 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter-top rotate: false - xy: 819, 866 + xy: 499, 719 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 liquid-source rotate: false - xy: 1231, 501 + xy: 1409, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-void rotate: false - xy: 1265, 535 + xy: 1443, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 melter rotate: false - xy: 1163, 399 + xy: 1341, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press rotate: false - xy: 685, 582 + xy: 1309, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phase-weaver rotate: false - xy: 721, 834 + xy: 557, 257 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-bottom rotate: false - xy: 951, 1037 + xy: 557, 191 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-weave rotate: false - xy: 1017, 1037 + xy: 557, 125 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor rotate: false - xy: 951, 971 + xy: 623, 389 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor-top rotate: false - xy: 1083, 1037 + xy: 623, 323 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pulverizer rotate: false - xy: 1231, 331 + xy: 1273, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-rotator rotate: false - xy: 1265, 365 + xy: 1307, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer rotate: false - xy: 1215, 1037 + xy: 631, 722 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator rotate: false - xy: 1347, 905 + xy: 763, 458 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-liquid rotate: false - xy: 1413, 971 + xy: 689, 392 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-spinner rotate: false - xy: 1545, 1037 + xy: 689, 326 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +silicon-crucible + rotate: false + xy: 1603, 909 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +silicon-crucible-top + rotate: false + xy: 1701, 1007 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 silicon-smelter rotate: false - xy: 1413, 905 + xy: 755, 392 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press rotate: false - xy: 1479, 971 + xy: 689, 260 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame0 rotate: false - xy: 1479, 905 + xy: 755, 326 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame1 rotate: false - xy: 1545, 971 + xy: 689, 194 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame2 rotate: false - xy: 1545, 905 + xy: 755, 260 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-liquid rotate: false - xy: 951, 839 + xy: 689, 128 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-top rotate: false - xy: 1017, 839 + xy: 755, 194 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rock1 rotate: false - xy: 1977, 699 + xy: 987, 163 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rock2 rotate: false - xy: 1977, 649 + xy: 1037, 379 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sand-boulder1 rotate: false - xy: 1435, 535 + xy: 1477, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-boulder2 rotate: false - xy: 1469, 569 + xy: 1511, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-boulder1 rotate: false - xy: 1367, 433 + xy: 1477, 389 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-boulder2 rotate: false - xy: 1401, 467 + xy: 1511, 423 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snowrock1 rotate: false - xy: 1943, 955 + xy: 1037, 229 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock2 rotate: false - xy: 1993, 1005 + xy: 1037, 179 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-cluster1 rotate: false - xy: 925, 647 + xy: 1387, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-cluster2 rotate: false - xy: 967, 689 + xy: 1429, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-cluster3 rotate: false - xy: 1009, 731 + xy: 1471, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 @@ -1889,14 +1945,14 @@ white-tree-dead index: -1 container rotate: false - xy: 1073, 1169 + xy: 359, 348 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 core-foundation rotate: false - xy: 1513, 1793 + xy: 1498, 1627 size: 128, 128 orig: 128, 128 offset: 0, 0 @@ -1910,476 +1966,448 @@ core-nucleus index: -1 core-shard rotate: false - xy: 1591, 1399 + xy: 1917, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 -launch-pad - rotate: false - xy: 383, 8 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 -launch-pad-large - rotate: false - xy: 1457, 1497 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -launch-pad-light - rotate: false - xy: 587, 680 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 -launchpod - rotate: false - xy: 873, 1138 - size: 66, 64 - orig: 66, 64 - offset: 0, 0 - index: -1 unloader rotate: false - xy: 1537, 331 + xy: 1613, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-center rotate: false - xy: 1579, 671 + xy: 1545, 151 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault rotate: false - xy: 1689, 1239 + xy: 1799, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 arc-heat rotate: false - xy: 1652, 1267 + xy: 2015, 1451 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-1 rotate: false - xy: 1391, 739 + xy: 1091, 45 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-2 rotate: false - xy: 941, 1138 + xy: 293, 328 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-3 rotate: false - xy: 1717, 1435 + xy: 721, 854 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-4 rotate: false - xy: 993, 1757 + xy: 1123, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 hail-heat rotate: false - xy: 833, 197 + xy: 1999, 1307 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 lancer-heat rotate: false - xy: 1733, 1139 + xy: 499, 587 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 meltdown-heat rotate: false - xy: 1628, 1663 + xy: 1773, 1793 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple-heat rotate: false - xy: 1199, 1301 + xy: 1505, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salvo-heat rotate: false - xy: 1215, 971 + xy: 697, 656 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-left rotate: false - xy: 1347, 1037 + xy: 631, 524 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-right rotate: false - xy: 1215, 905 + xy: 763, 656 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-heat rotate: false - xy: 1537, 637 + xy: 1545, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wave-liquid rotate: false - xy: 1545, 773 + xy: 961, 679 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 air-factory rotate: false - xy: 525, 974 + xy: 525, 1047 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 basic-reconstructor rotate: false - xy: 623, 888 + xy: 525, 851 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-forge rotate: false - xy: 623, 888 + xy: 525, 851 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 command-center rotate: false - xy: 1007, 1169 + xy: 433, 414 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory rotate: false - xy: 1403, 1103 + xy: 491, 216 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory-top rotate: false - xy: 1469, 1103 + xy: 491, 150 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 factory-in rotate: false - xy: 391, 204 + xy: 1488, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 factory-out rotate: false - xy: 489, 680 + xy: 1586, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 factory-top rotate: false - xy: 489, 582 + xy: 1684, 1203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ground-factory rotate: false - xy: 489, 190 + xy: 1586, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 naval-factory rotate: false - xy: 685, 484 + xy: 1309, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rally-point rotate: false - xy: 1083, 905 + xy: 631, 656 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-base rotate: false - xy: 1333, 433 + xy: 1375, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory rotate: false - xy: 1758, 1663 + xy: 1903, 1793 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 revenant-factory-top rotate: false - xy: 1888, 1663 + xy: 1717, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 copper-wall rotate: false - xy: 1239, 671 + xy: 1171, 366 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large rotate: false - xy: 1139, 1169 + xy: 359, 282 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door rotate: false - xy: 1053, 213 + xy: 1853, 625 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large rotate: false - xy: 1601, 1103 + xy: 483, 18 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-large-open rotate: false - xy: 1667, 1107 + xy: 549, 18 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-open rotate: false - xy: 1053, 179 + xy: 1853, 591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall rotate: false - xy: 1299, 501 + xy: 1341, 245 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large rotate: false - xy: 1865, 1007 + xy: 557, 323 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-wall rotate: false - xy: 1231, 399 + xy: 1409, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-large rotate: false - xy: 951, 905 + xy: 623, 257 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-gigantic rotate: false - xy: 1587, 1497 + xy: 1758, 1627 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-huge2 rotate: false - xy: 1297, 1301 + xy: 1603, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge3 rotate: false - xy: 1395, 1301 + xy: 1505, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-large1 rotate: false - xy: 1413, 1037 + xy: 631, 458 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large2 rotate: false - xy: 1281, 905 + xy: 763, 590 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large3 rotate: false - xy: 1347, 971 + xy: 697, 524 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large4 rotate: false - xy: 1479, 1037 + xy: 763, 524 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall2 rotate: false - xy: 1265, 331 + xy: 1477, 423 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall3 rotate: false - xy: 1299, 365 + xy: 1511, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall4 rotate: false - xy: 1333, 399 + xy: 1579, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall5 rotate: false - xy: 1333, 399 + xy: 1579, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall rotate: false - xy: 1435, 433 + xy: 1613, 423 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large rotate: false - xy: 1149, 839 + xy: 747, 62 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-wall rotate: false - xy: 1469, 467 + xy: 1477, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large rotate: false - xy: 1347, 839 + xy: 829, 590 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thruster rotate: false - xy: 1847, 1533 + xy: 1847, 1497 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 titanium-wall rotate: false - xy: 1537, 399 + xy: 1511, 151 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large rotate: false - xy: 951, 773 + xy: 821, 260 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 bullet rotate: false - xy: 1611, 1049 + xy: 1680, 757 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 bullet-back rotate: false - xy: 1727, 837 + xy: 1734, 757 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 casing rotate: false - xy: 409, 792 + xy: 2033, 1399 size: 8, 16 orig: 8, 16 offset: 0, 0 @@ -2393,7 +2421,7 @@ circle-end index: -1 circle-mid rotate: false - xy: 1121, 122 + xy: 1647, 254 size: 1, 199 orig: 1, 199 offset: 0, 0 @@ -2407,63 +2435,63 @@ circle-shadow index: -1 error rotate: false - xy: 783, 284 + xy: 879, 75 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 laser rotate: false - xy: 848, 1757 + xy: 1673, 475 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 laser-end rotate: false - xy: 844, 1204 + xy: 293, 608 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 minelaser rotate: false - xy: 854, 1757 + xy: 848, 1757 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 minelaser-end rotate: false - xy: 799, 1130 + xy: 293, 534 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 missile rotate: false - xy: 2011, 1501 + xy: 937, 125 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 missile-back rotate: false - xy: 2011, 1463 + xy: 979, 75 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 particle rotate: false - xy: 967, 731 + xy: 1345, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 scale_marker rotate: false - xy: 770, 1198 + xy: 149, 61 size: 4, 4 orig: 4, 4 offset: 0, 0 @@ -2477,546 +2505,567 @@ shell index: -1 shell-back rotate: false - xy: 616, 1237 + xy: 485, 854 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 transfer rotate: false - xy: 285, 141 + xy: 995, 413 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 transfer-arrow rotate: false - xy: 1503, 331 + xy: 1545, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 white rotate: false - xy: 1712, 1658 + xy: 623, 785 size: 3, 3 orig: 3, 3 offset: 0, 0 index: -1 arc rotate: false - xy: 1733, 1205 + xy: 2015, 1485 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-arc-full rotate: false - xy: 1425, 739 + xy: 1091, 11 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-drill-full rotate: false - xy: 1123, 1757 + xy: 1253, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-char-full rotate: false - xy: 1493, 739 + xy: 309, 30 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliffs-full rotate: false - xy: 1527, 739 + xy: 1169, 570 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conduit-full rotate: false - xy: 1561, 739 + xy: 1129, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conveyor-full rotate: false - xy: 925, 341 + xy: 1129, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-0 rotate: false - xy: 925, 341 + xy: 1129, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-craters-full rotate: false - xy: 1563, 1759 + xy: 1125, 27 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cryofluidmixer-full rotate: false - xy: 1977, 1597 + xy: 293, 262 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-cultivator-full rotate: false - xy: 743, 26 + xy: 293, 196 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-cyclone-full rotate: false - xy: 1815, 1435 + xy: 819, 952 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-dark-metal-full rotate: false - xy: 1678, 1629 + xy: 1513, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-full rotate: false - xy: 616, 1203 + xy: 1547, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dunerocks-full rotate: false - xy: 959, 613 + xy: 1581, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-duo-full rotate: false - xy: 959, 579 + xy: 1615, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-fuse-full rotate: false - xy: 1913, 1435 + xy: 819, 854 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-grass-full rotate: false - xy: 959, 545 + xy: 1649, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hail-full rotate: false - xy: 959, 511 + xy: 1103, 553 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-holostone-full rotate: false - xy: 959, 477 + xy: 1103, 519 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hotrock-full rotate: false - xy: 959, 443 + xy: 1103, 485 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-full rotate: false - xy: 959, 409 + xy: 1103, 451 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-snow-full rotate: false - xy: 959, 375 + xy: 1203, 570 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-icerocks-full rotate: false - xy: 959, 341 + xy: 1237, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ignarock-full rotate: false - xy: 1001, 655 + xy: 1271, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-impact-reactor-full rotate: false - xy: 1253, 1757 + xy: 1383, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-lancer-full rotate: false - xy: 1787, 1205 + xy: 367, 744 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-laser-drill-full rotate: false - xy: 807, 1376 + xy: 937, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-liquid-router-full rotate: false - xy: 993, 621 + xy: 1305, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-tank-full rotate: false - xy: 905, 1376 + xy: 1035, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-magmarock-full rotate: false - xy: 993, 587 + xy: 1339, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mass-conveyor-full rotate: false - xy: 1003, 1399 + xy: 1231, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-conveyor-icon rotate: false - xy: 1003, 1399 + xy: 1231, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-mass-driver-full rotate: false - xy: 1101, 1399 + xy: 1329, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-mechanical-drill-full rotate: false - xy: 1853, 1205 + xy: 367, 678 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-meltdown-full rotate: false - xy: 1383, 1757 + xy: 1513, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-metal-floor-damaged-full rotate: false - xy: 993, 553 + xy: 1373, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-moss-full rotate: false - xy: 993, 485 + xy: 1441, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-oil-extractor-full rotate: false - xy: 1199, 1399 + xy: 1427, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-ore-coal-full rotate: false - xy: 993, 451 + xy: 1475, 585 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-copper-full rotate: false - xy: 993, 417 + xy: 1237, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-lead-full rotate: false - xy: 993, 383 + xy: 1271, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-scrap-full rotate: false - xy: 993, 349 + xy: 1305, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-thorium-full rotate: false - xy: 1043, 697 + xy: 1339, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-titanium-full rotate: false - xy: 1035, 663 + xy: 1373, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +block-payload-router-full + rotate: false + xy: 1525, 1399 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +payload-router-icon + rotate: false + xy: 1525, 1399 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 block-pebbles-full rotate: false - xy: 1077, 705 + xy: 1407, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-weaver-full rotate: false - xy: 992, 1235 + xy: 367, 612 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-plated-conduit-full rotate: false - xy: 1111, 705 + xy: 1441, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pneumatic-drill-full rotate: false - xy: 1058, 1235 + xy: 367, 546 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-pulse-conduit-full rotate: false - xy: 1145, 705 + xy: 1475, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulverizer-full rotate: false - xy: 1179, 705 + xy: 1509, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-repair-point-full rotate: false - xy: 1213, 705 + xy: 1543, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ripple-full rotate: false - xy: 1297, 1399 + xy: 1623, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-rock-full rotate: false - xy: 1835, 899 + xy: 839, 12 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rocks-full rotate: false - xy: 1247, 705 + xy: 1577, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-saltrocks-full rotate: false - xy: 1281, 705 + xy: 1611, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salvo-full rotate: false - xy: 1124, 1235 + xy: 367, 480 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-sand-boulder-full rotate: false - xy: 1315, 705 + xy: 1645, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-full rotate: false - xy: 1349, 705 + xy: 1509, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sandrocks-full rotate: false - xy: 1383, 705 + xy: 1543, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scatter-full rotate: false - xy: 1190, 1235 + xy: 433, 744 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-scorch-full rotate: false - xy: 1417, 705 + xy: 1577, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-full rotate: false - xy: 1451, 705 + xy: 1611, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall1 rotate: false - xy: 1451, 705 + xy: 1611, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-huge-full rotate: false - xy: 1395, 1399 + xy: 1721, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge1 rotate: false - xy: 1395, 1399 + xy: 1721, 1399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-scrap-wall-large-full rotate: false - xy: 1256, 1235 + xy: 433, 678 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +block-segment-full + rotate: false + xy: 433, 612 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-shale-boulder-full rotate: false - xy: 1519, 705 + xy: 1888, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-full rotate: false - xy: 1553, 705 + xy: 1922, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shalerocks-full rotate: false - xy: 917, 307 + xy: 1685, 673 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shrubs-full rotate: false - xy: 917, 273 + xy: 1719, 673 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-full rotate: false - xy: 951, 307 + xy: 1753, 673 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snowrock-full rotate: false - xy: 1727, 737 + xy: 1987, 1069 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snowrocks-full rotate: false - xy: 917, 239 + xy: 1683, 639 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -3030,1309 +3079,1316 @@ block-spectre-full index: -1 block-spore-cluster-full rotate: false - xy: 833, 281 + xy: 107, 25 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-moss-full rotate: false - xy: 951, 273 + xy: 1683, 605 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-press-full rotate: false - xy: 1322, 1235 + xy: 433, 546 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-sporerocks-full rotate: false - xy: 917, 205 + xy: 1717, 639 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-stone-full rotate: false - xy: 951, 239 + xy: 1717, 605 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-swarmer-full rotate: false - xy: 1388, 1235 + xy: 433, 480 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-tendrils-full rotate: false - xy: 917, 171 + xy: 1751, 639 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-conveyor-full rotate: false - xy: 951, 205 + xy: 1751, 605 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-0 rotate: false - xy: 951, 205 + xy: 1751, 605 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-water-extractor-full rotate: false - xy: 1454, 1235 + xy: 1978, 1235 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-wave-full rotate: false - xy: 1520, 1235 + xy: 1978, 1169 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-1-0 rotate: false - xy: 1273, 671 + xy: 1137, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-1 rotate: false - xy: 1307, 671 + xy: 1171, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-2 rotate: false - xy: 1341, 671 + xy: 1137, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-3 rotate: false - xy: 1375, 671 + xy: 1171, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-4 rotate: false - xy: 1409, 671 + xy: 1137, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-5 rotate: false - xy: 1443, 671 + xy: 1171, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-6 rotate: false - xy: 1477, 671 + xy: 1137, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-7 rotate: false - xy: 1511, 671 + xy: 1171, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-2-0 rotate: false - xy: 1205, 1169 + xy: 425, 348 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-1 rotate: false - xy: 1271, 1169 + xy: 359, 216 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-2 rotate: false - xy: 1337, 1169 + xy: 425, 282 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-3 rotate: false - xy: 1403, 1169 + xy: 425, 216 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-4 rotate: false - xy: 1469, 1169 + xy: 359, 150 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-5 rotate: false - xy: 1535, 1169 + xy: 425, 150 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-6 rotate: false - xy: 1601, 1169 + xy: 293, 130 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-7 rotate: false - xy: 1667, 1173 + xy: 285, 64 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-3-0 rotate: false - xy: 321, 810 + xy: 921, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-1 rotate: false - xy: 419, 790 + xy: 1019, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-2 rotate: false - xy: 517, 778 + xy: 1117, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-3 rotate: false - xy: 293, 712 + xy: 1215, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-4 rotate: false - xy: 293, 614 + xy: 1313, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-5 rotate: false - xy: 293, 516 + xy: 1411, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-6 rotate: false - xy: 293, 418 + xy: 1509, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-7 rotate: false - xy: 293, 320 + xy: 1607, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-4-0 rotate: false - xy: 1643, 1793 + xy: 526, 1145 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-1 rotate: false - xy: 1773, 1793 + xy: 656, 1182 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-2 rotate: false - xy: 453, 1072 + xy: 163, 711 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-3 rotate: false - xy: 1903, 1793 + xy: 163, 581 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-4 rotate: false - xy: 163, 711 + xy: 163, 451 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-5 rotate: false - xy: 163, 581 + xy: 163, 321 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-6 rotate: false - xy: 163, 451 + xy: 163, 191 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-7 rotate: false - xy: 163, 321 + xy: 155, 61 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-5-0 rotate: false - xy: 1, 679 + xy: 645, 1442 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-1 rotate: false - xy: 645, 1442 + xy: 1025, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-2 rotate: false - xy: 1025, 1887 + xy: 1, 517 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-3 rotate: false - xy: 1, 517 + xy: 1187, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-4 rotate: false - xy: 1187, 1887 + xy: 1, 355 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-5 rotate: false - xy: 1, 355 + xy: 1349, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-6 rotate: false - xy: 1349, 1887 + xy: 1, 193 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-7 rotate: false - xy: 1, 193 + xy: 1511, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cyclone rotate: false - xy: 293, 222 + xy: 1705, 1301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 duo rotate: false - xy: 1053, 145 + xy: 1853, 557 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 fuse rotate: false - xy: 489, 288 + xy: 1488, 1105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 hail rotate: false - xy: 1053, 111 + xy: 1883, 523 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-blast-compound-large rotate: false - xy: 833, 155 + xy: 1169, 604 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-blast-compound-medium rotate: false - xy: 1095, 561 + xy: 1205, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-blast-compound-small rotate: false - xy: 783, 92 + xy: 1477, 525 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-blast-compound-tiny rotate: false - xy: 267, 43 + xy: 2015, 1399 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-blast-compound-xlarge rotate: false - xy: 1931, 1155 + xy: 1135, 696 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-coal-large rotate: false - xy: 833, 113 + xy: 477, 1118 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-coal-medium rotate: false - xy: 1095, 493 + xy: 1307, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-small rotate: false - xy: 925, 782 + xy: 1125, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-coal-tiny rotate: false - xy: 267, 25 + xy: 848, 1609 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-coal-xlarge rotate: false - xy: 1931, 1105 + xy: 1185, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-copper-large rotate: false - xy: 875, 281 + xy: 477, 1076 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-copper-medium rotate: false - xy: 1095, 425 + xy: 1239, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-small rotate: false - xy: 1983, 1343 + xy: 1151, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-copper-tiny rotate: false - xy: 2031, 837 + xy: 786, 1424 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-copper-xlarge rotate: false - xy: 1931, 1055 + xy: 1235, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-graphite-large rotate: false - xy: 875, 239 + xy: 1219, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-graphite-medium rotate: false - xy: 1095, 357 + xy: 1341, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-small rotate: false - xy: 2019, 1229 + xy: 1177, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-graphite-tiny rotate: false - xy: 2031, 819 + xy: 900, 1342 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-graphite-xlarge rotate: false - xy: 1981, 1155 + xy: 1285, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-lead-large rotate: false - xy: 875, 197 + xy: 1261, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-lead-medium rotate: false - xy: 1087, 289 + xy: 1239, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-small rotate: false - xy: 787, 874 + xy: 275, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-lead-tiny rotate: false - xy: 2031, 801 + xy: 367, 812 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-lead-xlarge rotate: false - xy: 1981, 1105 + xy: 1335, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-metaglass-large rotate: false - xy: 875, 155 + xy: 1303, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-metaglass-medium rotate: false - xy: 1087, 221 + xy: 1307, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-small rotate: false - xy: 787, 848 + xy: 301, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-metaglass-tiny rotate: false - xy: 848, 1609 + xy: 385, 812 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-metaglass-xlarge rotate: false - xy: 1981, 1055 + xy: 1385, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-phase-fabric-large rotate: false - xy: 875, 113 + xy: 1345, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-phase-fabric-medium rotate: false - xy: 1087, 153 + xy: 1205, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-small rotate: false - xy: 813, 790 + xy: 623, 1119 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-phase-fabric-tiny rotate: false - xy: 786, 1424 + xy: 107, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-phase-fabric-xlarge rotate: false - xy: 813, 816 + xy: 1435, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-plastanium-large rotate: false - xy: 883, 766 + xy: 1387, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-plastanium-medium rotate: false - xy: 1087, 85 + xy: 1273, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-small rotate: false - xy: 2011, 1437 + xy: 887, 828 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-plastanium-tiny rotate: false - xy: 937, 1479 + xy: 1977, 1501 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-plastanium-xlarge rotate: false - xy: 1785, 849 + xy: 1485, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-pyratite-large rotate: false - xy: 883, 724 + xy: 1429, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-pyratite-medium rotate: false - xy: 1129, 603 + xy: 1341, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-small rotate: false - xy: 1652, 1241 + xy: 291, 856 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-pyratite-tiny rotate: false - xy: 391, 792 + xy: 533, 437 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-pyratite-xlarge rotate: false - xy: 1835, 849 + xy: 1535, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-sand-large rotate: false - xy: 883, 682 + xy: 1471, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-sand-medium rotate: false - xy: 1129, 569 + xy: 1205, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-small rotate: false - xy: 291, 856 + xy: 293, 830 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-sand-tiny rotate: false - xy: 481, 8 + xy: 591, 107 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-sand-xlarge rotate: false - xy: 1885, 899 + xy: 1585, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-scrap-large rotate: false - xy: 883, 640 + xy: 1513, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-scrap-medium rotate: false - xy: 1197, 637 + xy: 1273, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-small rotate: false - xy: 1597, 1767 + xy: 1956, 749 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-scrap-tiny rotate: false - xy: 982, 1358 + xy: 1956, 1645 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-scrap-xlarge rotate: false - xy: 1885, 849 + xy: 1635, 703 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-silicon-large rotate: false - xy: 883, 598 + xy: 1555, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-silicon-medium rotate: false - xy: 1163, 569 + xy: 1341, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-small rotate: false - xy: 1571, 645 + xy: 1856, 735 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-silicon-tiny rotate: false - xy: 799, 1112 + xy: 1956, 1627 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-silicon-xlarge rotate: false - xy: 1781, 799 + xy: 1685, 707 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-spore-pod-large rotate: false - xy: 883, 556 + xy: 1597, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-spore-pod-medium rotate: false - xy: 1129, 501 + xy: 1205, 279 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-small rotate: false - xy: 1689, 1443 + xy: 1137, 136 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-spore-pod-tiny rotate: false - xy: 809, 100 + xy: 1103, 433 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-spore-pod-xlarge rotate: false - xy: 1831, 799 + xy: 1735, 707 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-surge-alloy-large rotate: false - xy: 883, 514 + xy: 1639, 661 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-surge-alloy-medium rotate: false - xy: 1197, 569 + xy: 1273, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-small rotate: false - xy: 2009, 1343 + xy: 1163, 136 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-surge-alloy-tiny rotate: false - xy: 863, 848 + xy: 1205, 552 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-surge-alloy-xlarge rotate: false - xy: 1881, 799 + xy: 953, 563 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-thorium-large rotate: false - xy: 883, 472 + xy: 149, 19 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-thorium-medium rotate: false - xy: 1265, 637 + xy: 1341, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-small rotate: false - xy: 1571, 619 + xy: 1647, 499 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-thorium-tiny rotate: false - xy: 1767, 1221 + xy: 623, 1075 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-thorium-xlarge rotate: false - xy: 1777, 749 + xy: 953, 513 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-titanium-large rotate: false - xy: 883, 430 + xy: 191, 19 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-titanium-medium rotate: false - xy: 1163, 501 + xy: 1409, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-small rotate: false - xy: 1571, 593 + xy: 1579, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-titanium-tiny rotate: false - xy: 985, 1120 + xy: 1647, 455 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-titanium-xlarge rotate: false - xy: 1777, 699 + xy: 953, 463 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lancer rotate: false - xy: 885, 874 + xy: 499, 653 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 liquid-cryofluid-large rotate: false - xy: 883, 388 + xy: 233, 19 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-cryofluid-medium rotate: false - xy: 1299, 637 + xy: 1307, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-small rotate: false - xy: 1571, 567 + xy: 1613, 227 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-cryofluid-tiny rotate: false - xy: 883, 328 + xy: 866, 1609 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-cryofluid-xlarge rotate: false - xy: 1827, 649 + xy: 937, 163 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-oil-large rotate: false - xy: 883, 346 + xy: 1219, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-oil-medium rotate: false - xy: 1197, 501 + xy: 1409, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-small rotate: false - xy: 1571, 541 + xy: 623, 1093 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-oil-tiny rotate: false - xy: 2019, 1211 + xy: 786, 1406 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-oil-xlarge rotate: false - xy: 1877, 649 + xy: 1019, 579 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-slag-large rotate: false - xy: 925, 731 + xy: 1261, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-slag-medium rotate: false - xy: 1197, 467 + xy: 1375, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-small rotate: false - xy: 1571, 515 + xy: 1647, 473 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-slag-tiny rotate: false - xy: 839, 798 + xy: 900, 1324 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-slag-xlarge rotate: false - xy: 1727, 637 + xy: 1003, 529 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-water-large rotate: false - xy: 925, 689 + xy: 1303, 619 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-water-medium rotate: false - xy: 1333, 603 + xy: 1239, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-small rotate: false - xy: 1571, 489 + xy: 1579, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-water-tiny rotate: false - xy: 1571, 471 + xy: 125, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-water-xlarge rotate: false - xy: 1777, 599 + xy: 1003, 479 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mass-driver rotate: false - xy: 615, 778 + xy: 1211, 1007 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 meltdown rotate: false - xy: 1498, 1627 + xy: 1643, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 repair-point rotate: false - xy: 1299, 399 + xy: 1341, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ripple rotate: false - xy: 1101, 1301 + xy: 1407, 811 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salvo rotate: false - xy: 1149, 905 + xy: 763, 722 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scatter rotate: false - xy: 1281, 971 + xy: 697, 590 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch rotate: false - xy: 1503, 603 + xy: 1477, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +segment + rotate: false + xy: 697, 458 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 spectre rotate: false - xy: 1717, 1533 + xy: 1888, 1663 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 splash-0 rotate: false - xy: 1537, 603 + xy: 1511, 389 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-1 rotate: false - xy: 1299, 331 + xy: 1545, 423 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-10 rotate: false - xy: 1367, 365 + xy: 1545, 355 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-11 rotate: false - xy: 1401, 399 + xy: 1579, 389 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-2 rotate: false - xy: 1333, 365 + xy: 1579, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-3 rotate: false - xy: 1367, 399 + xy: 1477, 321 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-4 rotate: false - xy: 1401, 433 + xy: 1511, 355 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-5 rotate: false - xy: 1435, 467 + xy: 1545, 389 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-6 rotate: false - xy: 1469, 501 + xy: 1579, 423 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-7 rotate: false - xy: 1503, 535 + xy: 1613, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-8 rotate: false - xy: 1537, 569 + xy: 1477, 287 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 splash-9 rotate: false - xy: 1333, 331 + xy: 1511, 321 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 swarmer rotate: false - xy: 1215, 839 + xy: 829, 722 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unit-alpha-full rotate: false - xy: 1985, 855 + xy: 1087, 179 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-cix-full rotate: false - xy: 481, 26 - size: 88, 64 - orig: 88, 64 + xy: 656, 1052 + size: 128, 128 + orig: 128, 128 offset: 0, 0 index: -1 unit-crawler-full rotate: false - xy: 1981, 805 + xy: 1037, 129 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-dagger-full rotate: false - xy: 833, 723 + xy: 1087, 129 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-draug-full rotate: false - xy: 833, 673 + xy: 979, 113 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-eruptor-full rotate: false - xy: 571, 26 + xy: 1897, 775 size: 88, 64 orig: 88, 64 offset: 0, 0 index: -1 unit-fortress-full rotate: false - xy: 423, 888 + xy: 423, 994 size: 100, 80 orig: 100, 80 offset: 0, 0 index: -1 unit-ghoul-full rotate: false - xy: 918, 1204 + xy: 293, 460 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 unit-oculon-full rotate: false - xy: 1973, 1925 + xy: 1978, 1119 size: 58, 48 orig: 58, 48 offset: 0, 0 index: -1 unit-phantom-full rotate: false - xy: 1727, 891 + xy: 1564, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 @@ -4344,198 +4400,205 @@ unit-reaper-full orig: 320, 320 offset: 0, 0 index: -1 +unit-revenant-full + rotate: false + xy: 786, 1132 + size: 112, 112 + orig: 112, 112 + offset: 0, 0 + index: -1 unit-spirit-full rotate: false - xy: 833, 623 + xy: 1069, 637 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-tau-full rotate: false - xy: 1785, 949 + xy: 1622, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 unit-titan-full rotate: false - xy: 1149, 773 + xy: 813, 62 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unit-trident-full rotate: false - xy: 697, 1096 + xy: 423, 892 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 unit-vanguard-full rotate: false - xy: 833, 573 + xy: 1069, 587 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-wraith-full rotate: false - xy: 833, 523 + xy: 1029, 79 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wave rotate: false - xy: 1479, 773 + xy: 895, 613 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 item-blast-compound rotate: false - xy: 1095, 595 + xy: 1273, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal rotate: false - xy: 1095, 527 + xy: 1239, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper rotate: false - xy: 1095, 459 + xy: 1205, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite rotate: false - xy: 1095, 391 + xy: 1273, 483 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead rotate: false - xy: 1095, 323 + xy: 1205, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass rotate: false - xy: 1087, 255 + xy: 1273, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric rotate: false - xy: 1087, 187 + xy: 1375, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium rotate: false - xy: 1087, 119 + xy: 1239, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite rotate: false - xy: 1129, 637 + xy: 1307, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand rotate: false - xy: 1163, 637 + xy: 1409, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap rotate: false - xy: 1163, 603 + xy: 1239, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon rotate: false - xy: 1129, 535 + xy: 1307, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod rotate: false - xy: 1231, 637 + xy: 1443, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy rotate: false - xy: 1163, 535 + xy: 1239, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium rotate: false - xy: 1231, 603 + xy: 1307, 381 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium rotate: false - xy: 1129, 467 + xy: 1375, 449 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid rotate: false - xy: 1265, 603 + xy: 1273, 313 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil rotate: false - xy: 1163, 467 + xy: 1375, 415 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag rotate: false - xy: 1163, 433 + xy: 1341, 347 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water rotate: false - xy: 1299, 569 + xy: 1205, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blank rotate: false - xy: 219, 841 + xy: 631, 455 size: 1, 1 orig: 1, 1 offset: 0, 0 @@ -4549,21 +4612,21 @@ circle index: -1 shape-3 rotate: false - xy: 1611, 976 + xy: 1093, 746 size: 63, 63 orig: 63, 63 offset: 0, 0 index: -1 alpha rotate: false - xy: 1676, 991 + xy: 1999, 1349 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 alpha-cell rotate: false - xy: 1785, 899 + xy: 1788, 761 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -4575,6 +4638,13 @@ chaos-array orig: 128, 128 offset: 0, 0 index: -1 +cix + rotate: false + xy: 978, 1627 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 chaos-array-base rotate: false xy: 1108, 1627 @@ -4596,268 +4666,289 @@ chaos-array-leg orig: 128, 128 offset: 0, 0 index: -1 -cix - rotate: false - xy: 1, 1 - size: 88, 64 - orig: 88, 64 - offset: 0, 0 - index: -1 cix-cell rotate: false - xy: 526, 1209 + xy: 1897, 1039 size: 88, 64 orig: 88, 64 offset: 0, 0 index: -1 cix-foot rotate: false - xy: 833, 239 - size: 40, 40 - orig: 40, 40 + xy: 1977, 1591 + size: 70, 70 + orig: 70, 70 offset: 0, 0 index: -1 -cix-joint +cix-joint-base rotate: false - xy: 1689, 1469 - size: 26, 26 - orig: 26, 26 + xy: 1977, 1519 + size: 70, 70 + orig: 70, 70 offset: 0, 0 index: -1 cix-leg rotate: false - xy: 1513, 1765 - size: 48, 26 - orig: 48, 26 + xy: 615, 1 + size: 56, 56 + orig: 56, 56 offset: 0, 0 index: -1 cix-leg-base rotate: false - xy: 1628, 1635 - size: 48, 26 - orig: 48, 26 + xy: 1, 1 + size: 104, 64 + orig: 104, 64 + offset: 0, 0 + index: -1 +cix-old + rotate: false + xy: 1897, 973 + size: 88, 64 + orig: 88, 64 offset: 0, 0 index: -1 crawler rotate: false - xy: 1727, 687 + xy: 1987, 1019 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-base rotate: false - xy: 713, 784 + xy: 1987, 969 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-cell rotate: false - xy: 1893, 957 + xy: 1987, 919 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-leg rotate: false - xy: 763, 784 + xy: 1987, 869 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger rotate: false - xy: 783, 734 + xy: 1987, 819 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-base rotate: false - xy: 783, 684 + xy: 1987, 769 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-leg rotate: false - xy: 783, 634 + xy: 895, 425 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta rotate: false - xy: 783, 584 + xy: 887, 375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-base rotate: false - xy: 783, 534 + xy: 887, 325 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-cell rotate: false - xy: 783, 484 + xy: 887, 275 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-leg rotate: false - xy: 783, 434 + xy: 887, 225 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 draug rotate: false - xy: 783, 384 + xy: 887, 175 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 draug-cell rotate: false - xy: 783, 334 + xy: 887, 125 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 eradicator rotate: false - xy: 1511, 1923 + xy: 1, 67 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-base rotate: false - xy: 1, 67 + xy: 1673, 1923 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-cell rotate: false - xy: 1665, 1923 + xy: 1827, 1923 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-leg rotate: false - xy: 1819, 1923 + xy: 323, 1076 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eruptor rotate: false - xy: 1787, 1271 + xy: 1897, 907 size: 88, 64 orig: 88, 64 offset: 0, 0 index: -1 eruptor-base rotate: false - xy: 819, 998 + xy: 557, 785 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 eruptor-cell rotate: false - xy: 1877, 1271 + xy: 1897, 841 size: 88, 64 orig: 88, 64 offset: 0, 0 index: -1 +eruptor-foot + rotate: false + xy: 477, 1160 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +eruptor-joint + rotate: false + xy: 1745, 1895 + size: 26, 26 + orig: 26, 26 + offset: 0, 0 + index: -1 eruptor-leg rotate: false - xy: 819, 932 - size: 64, 64 - orig: 64, 64 + xy: 1673, 1895 + size: 36, 26 + orig: 36, 26 + offset: 0, 0 + index: -1 +eruptor-leg-base + rotate: false + xy: 1773, 1765 + size: 36, 26 + orig: 36, 26 offset: 0, 0 index: -1 fortress rotate: false - xy: 321, 990 + xy: 786, 1050 size: 100, 80 orig: 100, 80 offset: 0, 0 index: -1 fortress-base rotate: false - xy: 885, 1072 + xy: 689, 788 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-cell rotate: false - xy: 321, 908 + xy: 321, 994 size: 100, 80 orig: 100, 80 offset: 0, 0 index: -1 fortress-leg rotate: false - xy: 661, 30 + xy: 321, 830 size: 80, 60 orig: 80, 60 offset: 0, 0 index: -1 ghoul rotate: false - xy: 1973, 1975 + xy: 293, 756 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 ghoul-cell rotate: false - xy: 770, 1204 + xy: 293, 682 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 glaive rotate: false - xy: 1977, 1539 + xy: 673, 1 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 glaive-cell rotate: false - xy: 1611, 780 + xy: 731, 1 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 javelin rotate: false - xy: 1827, 749 + xy: 945, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 javelin-cell rotate: false - xy: 1827, 699 + xy: 937, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 javelin-shield rotate: false - xy: 1877, 749 + xy: 937, 313 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -4878,84 +4969,84 @@ lich-cell index: -1 oculon rotate: false - xy: 91, 17 + xy: 1981, 1933 size: 58, 48 orig: 58, 48 offset: 0, 0 index: -1 oculon-base rotate: false - xy: 1927, 749 + xy: 1053, 429 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 oculon-cell rotate: false - xy: 1927, 699 + xy: 987, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 oculon-leg rotate: false - xy: 1927, 649 + xy: 987, 313 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 omega rotate: false - xy: 1967, 1255 + xy: 403, 810 size: 80, 80 orig: 80, 80 offset: 0, 0 index: -1 omega-armor rotate: false - xy: 1667, 1041 + xy: 565, 521 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 omega-base rotate: false - xy: 151, 3 + xy: 961, 621 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 omega-cell rotate: false - xy: 209, 3 + xy: 1027, 687 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 omega-leg rotate: false - xy: 1669, 918 + xy: 1158, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 phantom rotate: false - xy: 1669, 860 + xy: 1216, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 phantom-cell rotate: false - xy: 1669, 802 + xy: 1274, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 power-cell rotate: false - xy: 1669, 744 + xy: 1332, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 @@ -4976,252 +5067,252 @@ reaper-cell index: -1 revenant rotate: false - xy: 656, 1198 + xy: 807, 1360 size: 112, 112 orig: 112, 112 offset: 0, 0 index: -1 revenant-cell rotate: false - xy: 583, 1084 + xy: 786, 1246 size: 112, 112 orig: 112, 112 offset: 0, 0 index: -1 spirit rotate: false - xy: 1993, 955 + xy: 1087, 379 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spirit-cell rotate: false - xy: 1935, 905 + xy: 1087, 329 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tau rotate: false - xy: 1611, 722 + xy: 1390, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 tau-base rotate: false - xy: 1935, 855 + xy: 1087, 279 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tau-cell rotate: false - xy: 1669, 686 + xy: 1448, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 tau-leg rotate: false - xy: 1985, 905 + xy: 1087, 229 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titan rotate: false - xy: 1413, 839 + xy: 829, 524 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-base rotate: false - xy: 1479, 839 + xy: 829, 458 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-cell rotate: false - xy: 1545, 839 + xy: 821, 392 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-leg rotate: false - xy: 885, 808 + xy: 821, 326 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident rotate: false - xy: 423, 970 + xy: 321, 892 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 trident-cell rotate: false - xy: 1727, 949 + xy: 1506, 753 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 vanguard rotate: false - xy: 833, 473 + xy: 1079, 79 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 vanguard-cell rotate: false - xy: 833, 423 + xy: 1119, 645 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wraith rotate: false - xy: 833, 323 + xy: 1169, 646 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 artillery rotate: false - xy: 1843, 949 + xy: 789, 4 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 beam-weapon rotate: false - xy: 1727, 787 + xy: 1838, 761 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 chaos rotate: false - xy: 1611, 838 + xy: 895, 475 size: 56, 136 orig: 56, 136 offset: 0, 0 index: -1 eradication rotate: false - xy: 391, 302 + xy: 1390, 1107 size: 96, 192 orig: 96, 192 offset: 0, 0 index: -1 eruption rotate: false - xy: 783, 226 + xy: 889, 17 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 flakgun rotate: false - xy: 783, 176 + xy: 929, 75 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 flamethrower rotate: false - xy: 783, 118 + xy: 939, 17 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 heal-weapon rotate: false - xy: 1919, 1205 + xy: 1019, 629 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 heal-weapon-mount rotate: false - xy: 1969, 1205 + xy: 1085, 695 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 large-weapon rotate: false - xy: 1877, 699 + xy: 937, 263 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lich-missiles rotate: false - xy: 1777, 649 + xy: 937, 213 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 missiles rotate: false - xy: 1827, 599 + xy: 1053, 529 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 missiles-mount rotate: false - xy: 1877, 599 + xy: 1053, 479 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mount-weapon rotate: false - xy: 1931, 799 + xy: 1003, 429 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 reaper-weapon rotate: false - xy: 1927, 599 + xy: 987, 263 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 revenant-missiles rotate: false - xy: 1977, 749 + xy: 987, 213 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 small-basic-weapon rotate: false - xy: 1977, 599 + xy: 1037, 329 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 small-weapon rotate: false - xy: 1943, 1005 + xy: 1037, 279 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 weapon rotate: false - xy: 833, 373 + xy: 1119, 595 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -6885,2029 +6976,2071 @@ water-edge index: -1 sprites4.png -size: 2048,512 +size: 2048,1024 format: RGBA8888 filter: Nearest,Nearest repeat: none alloy-smelter-icon-editor rotate: false - xy: 905, 275 + xy: 875, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 arc-icon-editor rotate: false - xy: 2015, 469 + xy: 1077, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-icon-editor rotate: false - xy: 2015, 435 + xy: 1111, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 basic-reconstructor-icon-editor rotate: false - xy: 1035, 405 + xy: 973, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-forge-icon-editor rotate: false - xy: 1035, 405 + xy: 973, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 battery-icon-editor rotate: false - xy: 2015, 401 + xy: 1145, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large-icon-editor rotate: false - xy: 1133, 405 + xy: 1071, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-drill-icon-editor rotate: false - xy: 645, 373 + xy: 323, 715 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-mixer-icon-editor rotate: false - xy: 1395, 339 + xy: 1, 5 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border-editor rotate: false - xy: 1655, 239 + xy: 1179, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-launcher-icon-editor - rotate: false - xy: 1231, 405 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 block-loader-icon-editor rotate: false - xy: 1329, 405 + xy: 1169, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-unloader-icon-editor rotate: false - xy: 1427, 405 + xy: 1267, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 bridge-conduit-icon-editor rotate: false - xy: 1689, 239 + xy: 1213, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-icon-editor rotate: false - xy: 1723, 239 + xy: 1247, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char-icon-editor rotate: false - xy: 1757, 239 + xy: 1281, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char1 rotate: false - xy: 1757, 239 + xy: 1281, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 clear-editor rotate: false - xy: 645, 240 + xy: 293, 360 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 cliff-icon-editor rotate: false - xy: 1791, 239 + xy: 1315, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cliffs-icon-editor rotate: false - xy: 1825, 239 + xy: 1349, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal-centrifuge-icon-editor rotate: false - xy: 1461, 339 + xy: 1953, 941 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 combustion-generator-icon-editor rotate: false - xy: 1859, 239 + xy: 1383, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-icon-editor rotate: false - xy: 1893, 239 + xy: 1417, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 container-icon-editor rotate: false - xy: 1527, 339 + xy: 747, 517 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 conveyor-icon-editor rotate: false - xy: 1927, 239 + xy: 1451, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-icon-editor rotate: false - xy: 945, 45 + xy: 1485, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large-icon-editor rotate: false - xy: 1593, 339 + xy: 67, 5 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 core-foundation-icon-editor rotate: false - xy: 163, 51 + xy: 485, 877 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-nucleus-icon-editor rotate: false - xy: 1, 19 + xy: 323, 845 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-shard-icon-editor rotate: false - xy: 1525, 405 + xy: 1365, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 +core-silo-icon-editor + rotate: false + xy: 1, 201 + size: 160, 160 + orig: 160, 160 + offset: 0, 0 + index: -1 craters-icon-editor rotate: false - xy: 979, 45 + xy: 1519, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-craters1 rotate: false - xy: 979, 45 + xy: 1519, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cryofluidmixer-icon-editor rotate: false - xy: 1659, 339 + xy: 421, 387 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-icon-editor rotate: false - xy: 1725, 339 + xy: 487, 387 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cyclone-icon-editor rotate: false - xy: 1623, 405 + xy: 1463, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-metal-icon-editor rotate: false - xy: 1109, 75 + xy: 1553, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-icon-editor rotate: false - xy: 1143, 75 + xy: 1587, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-1 rotate: false - xy: 1143, 75 + xy: 1587, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-icon-editor rotate: false - xy: 1177, 75 + xy: 1621, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-2 rotate: false - xy: 1177, 75 + xy: 1621, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-icon-editor rotate: false - xy: 1211, 75 + xy: 1655, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-3 rotate: false - xy: 1211, 75 + xy: 1655, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-icon-editor rotate: false - xy: 1245, 75 + xy: 1689, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-4 rotate: false - xy: 1245, 75 + xy: 1689, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-icon-editor rotate: false - xy: 1279, 75 + xy: 1723, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-5 rotate: false - xy: 1279, 75 + xy: 1723, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-icon-editor rotate: false - xy: 1313, 75 + xy: 1757, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-6 rotate: false - xy: 1313, 75 + xy: 1757, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-icon-editor rotate: false - xy: 163, 17 + xy: 1791, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand1 rotate: false - xy: 163, 17 + xy: 1791, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-icon-editor rotate: false - xy: 197, 17 + xy: 1825, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-icon-editor rotate: false - xy: 231, 17 + xy: 1859, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +data-processor-icon-editor + rotate: false + xy: 1561, 909 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 deepwater-icon-editor rotate: false - xy: 265, 17 + xy: 1893, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-deepwater rotate: false - xy: 265, 17 + xy: 1893, 809 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 differential-generator-icon-editor rotate: false - xy: 1721, 405 + xy: 1659, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 diode-icon-editor rotate: false - xy: 299, 17 + xy: 1953, 907 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +disassembler-icon-editor + rotate: false + xy: 1757, 909 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 distributor-icon-editor rotate: false - xy: 1791, 339 + xy: 553, 419 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-icon-editor rotate: false - xy: 333, 17 + xy: 813, 549 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large-icon-editor rotate: false - xy: 1857, 339 + xy: 619, 419 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dunerocks-icon-editor rotate: false - xy: 367, 17 + xy: 553, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo-icon-editor rotate: false - xy: 401, 17 + xy: 587, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char2 rotate: false - xy: 435, 17 + xy: 621, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char3 rotate: false - xy: 469, 17 + xy: 655, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-clear rotate: false - xy: 905, 263 + xy: 485, 865 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 editor-craters2 rotate: false - xy: 503, 17 + xy: 689, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-craters3 rotate: false - xy: 1373, 107 + xy: 977, 709 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-tainted-water1 rotate: false - xy: 1505, 139 + xy: 391, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-tainted-water2 rotate: false - xy: 1539, 139 + xy: 391, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-tainted-water3 rotate: false - xy: 1573, 139 + xy: 361, 225 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-water1 rotate: false - xy: 1961, 239 + xy: 361, 191 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-water2 rotate: false - xy: 1607, 147 + xy: 133, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-water3 rotate: false - xy: 1655, 205 + xy: 167, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand2 rotate: false - xy: 1407, 107 + xy: 1987, 907 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand3 rotate: false - xy: 1441, 107 + xy: 813, 515 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass1 rotate: false - xy: 1689, 205 + xy: 201, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-icon-editor rotate: false - xy: 1689, 205 + xy: 201, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass2 rotate: false - xy: 1723, 205 + xy: 235, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass3 rotate: false - xy: 1757, 205 + xy: 269, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone1 rotate: false - xy: 1791, 205 + xy: 723, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 holostone-icon-editor rotate: false - xy: 1791, 205 + xy: 723, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone2 rotate: false - xy: 1825, 205 + xy: 303, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone3 rotate: false - xy: 1859, 205 + xy: 847, 561 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock1 rotate: false - xy: 1893, 205 + xy: 847, 527 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock-icon-editor rotate: false - xy: 1893, 205 + xy: 847, 527 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock2 rotate: false - xy: 1927, 205 + xy: 961, 675 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock3 rotate: false - xy: 1961, 205 + xy: 895, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow1 rotate: false - xy: 1749, 171 + xy: 1179, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow-icon-editor rotate: false - xy: 1749, 171 + xy: 1179, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow2 rotate: false - xy: 1783, 171 + xy: 1213, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow3 rotate: false - xy: 1817, 171 + xy: 1247, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice1 rotate: false - xy: 1647, 171 + xy: 1077, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-icon-editor rotate: false - xy: 1647, 171 + xy: 1077, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice2 rotate: false - xy: 1681, 171 + xy: 1111, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice3 rotate: false - xy: 1715, 171 + xy: 1145, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock1 rotate: false - xy: 1851, 171 + xy: 1281, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ignarock-icon-editor rotate: false - xy: 1851, 171 + xy: 1281, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock2 rotate: false - xy: 1885, 171 + xy: 1315, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock3 rotate: false - xy: 1919, 171 + xy: 1349, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock1 rotate: false - xy: 1953, 171 + xy: 1383, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock-icon-editor rotate: false - xy: 1953, 171 + xy: 1383, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock2 rotate: false - xy: 1641, 137 + xy: 1417, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock3 rotate: false - xy: 1675, 137 + xy: 1451, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor rotate: false - xy: 1709, 137 + xy: 1485, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-icon-editor rotate: false - xy: 1709, 137 + xy: 1485, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-2 rotate: false - xy: 1743, 137 + xy: 1519, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-icon-editor rotate: false - xy: 1743, 137 + xy: 1519, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-3 rotate: false - xy: 1777, 137 + xy: 1553, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-icon-editor rotate: false - xy: 1777, 137 + xy: 1553, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-5 rotate: false - xy: 1811, 137 + xy: 1587, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-icon-editor rotate: false - xy: 1811, 137 + xy: 1587, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged1 rotate: false - xy: 1845, 137 + xy: 1621, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged-icon-editor rotate: false - xy: 1845, 137 + xy: 1621, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged2 rotate: false - xy: 1879, 137 + xy: 1655, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged3 rotate: false - xy: 1913, 137 + xy: 1689, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss1 rotate: false - xy: 1947, 137 + xy: 1723, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss-icon-editor rotate: false - xy: 1947, 137 + xy: 1723, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss2 rotate: false - xy: 1607, 113 + xy: 1757, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss3 rotate: false - xy: 1641, 103 + xy: 1791, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal1 rotate: false - xy: 1675, 103 + xy: 1825, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal2 rotate: false - xy: 1709, 103 + xy: 1859, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal3 rotate: false - xy: 1743, 103 + xy: 1893, 775 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper1 rotate: false - xy: 1777, 103 + xy: 1011, 709 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper2 rotate: false - xy: 1811, 103 + xy: 995, 675 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper3 rotate: false - xy: 1845, 103 + xy: 895, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead1 rotate: false - xy: 1879, 103 + xy: 881, 543 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead2 rotate: false - xy: 1913, 103 + xy: 929, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead3 rotate: false - xy: 1947, 103 + xy: 929, 593 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap1 rotate: false - xy: 1989, 367 + xy: 963, 641 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap2 rotate: false - xy: 1989, 333 + xy: 963, 607 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap3 rotate: false - xy: 1989, 299 + xy: 997, 641 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium1 rotate: false - xy: 1987, 171 + xy: 997, 607 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium2 rotate: false - xy: 1981, 137 + xy: 1029, 675 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium3 rotate: false - xy: 2015, 137 + xy: 1031, 641 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium1 rotate: false - xy: 1981, 103 + xy: 1031, 607 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium2 rotate: false - xy: 2015, 103 + xy: 1069, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium3 rotate: false - xy: 1347, 73 + xy: 1103, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles1 rotate: false - xy: 1381, 73 + xy: 1137, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles2 rotate: false - xy: 1415, 73 + xy: 1171, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles3 rotate: false - xy: 1449, 73 + xy: 1205, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-salt rotate: false - xy: 1013, 43 + xy: 1239, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-icon-editor rotate: false - xy: 1013, 43 + xy: 1239, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand-water1 rotate: false - xy: 1149, 41 + xy: 1375, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand-water2 rotate: false - xy: 1183, 41 + xy: 1409, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand-water3 rotate: false - xy: 1217, 41 + xy: 1443, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand1 rotate: false - xy: 1047, 43 + xy: 1273, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-icon-editor rotate: false - xy: 1047, 43 + xy: 1273, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand2 rotate: false - xy: 1081, 41 + xy: 1307, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand3 rotate: false - xy: 1115, 41 + xy: 1341, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale1 rotate: false - xy: 1251, 41 + xy: 1477, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-icon-editor rotate: false - xy: 1251, 41 + xy: 1477, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale2 rotate: false - xy: 1285, 41 + xy: 1511, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale3 rotate: false - xy: 1319, 39 + xy: 1545, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-slag rotate: false - xy: 1353, 39 + xy: 1579, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag-icon-editor rotate: false - xy: 1353, 39 + xy: 1579, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow1 rotate: false - xy: 1387, 39 + xy: 1613, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow2 rotate: false - xy: 1421, 39 + xy: 1647, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow3 rotate: false - xy: 1455, 39 + xy: 1681, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spawn rotate: false - xy: 1995, 265 + xy: 1715, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss1 rotate: false - xy: 1995, 231 + xy: 1749, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-icon-editor rotate: false - xy: 1995, 231 + xy: 1749, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss2 rotate: false - xy: 619, 13 + xy: 1783, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss3 rotate: false - xy: 653, 13 + xy: 1817, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone1 rotate: false - xy: 687, 13 + xy: 1851, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-icon-editor rotate: false - xy: 687, 13 + xy: 1851, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone2 rotate: false - xy: 721, 13 + xy: 1885, 741 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone3 rotate: false - xy: 755, 13 + xy: 881, 509 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tainted-water rotate: false - xy: 789, 13 + xy: 847, 493 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-icon-editor rotate: false - xy: 789, 13 + xy: 847, 493 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tar rotate: false - xy: 823, 13 + xy: 929, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-editor rotate: false - xy: 823, 13 + xy: 929, 559 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils1 rotate: false - xy: 857, 13 + xy: 963, 573 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils2 rotate: false - xy: 891, 13 + xy: 997, 573 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils3 rotate: false - xy: 925, 11 + xy: 1031, 573 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-water rotate: false - xy: 959, 11 + xy: 915, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-editor rotate: false - xy: 959, 11 + xy: 915, 525 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 force-projector-icon-editor rotate: false - xy: 1819, 405 + xy: 1855, 909 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fuse-icon-editor rotate: false - xy: 1917, 405 + xy: 323, 357 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 graphite-press-icon-editor rotate: false - xy: 1923, 339 + xy: 685, 419 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 hail-icon-editor rotate: false - xy: 993, 9 + xy: 881, 475 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icerocks-icon-editor rotate: false - xy: 1027, 9 + xy: 915, 491 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-icon-editor rotate: false - xy: 1061, 7 + xy: 915, 457 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor-icon-editor rotate: false - xy: 645, 243 + xy: 1, 71 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 incinerator-icon-editor rotate: false - xy: 1095, 7 + xy: 963, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 inverted-sorter-icon-editor rotate: false - xy: 1129, 7 + xy: 997, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-editor rotate: false - xy: 1163, 7 + xy: 1031, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-editor rotate: false - xy: 1197, 7 + xy: 949, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction-icon-editor rotate: false - xy: 1231, 7 + xy: 949, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln-icon-editor rotate: false - xy: 1043, 209 + xy: 163, 167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 lancer-icon-editor rotate: false - xy: 1043, 143 + xy: 229, 167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +large-overdrive-projector-icon-editor + rotate: false + xy: 293, 259 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 laser-drill-icon-editor rotate: false - xy: 553, 83 + xy: 453, 747 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-icon-editor rotate: false - xy: 651, 145 + xy: 453, 649 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-large-icon-editor rotate: false - xy: 775, 373 + xy: 163, 233 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 liquid-junction-icon-editor rotate: false - xy: 1265, 7 + xy: 983, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-editor rotate: false - xy: 1299, 5 + xy: 983, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-editor rotate: false - xy: 1333, 5 + xy: 1017, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-icon-editor rotate: false - xy: 749, 145 + xy: 453, 551 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-void-icon-editor rotate: false - xy: 1367, 5 + xy: 1017, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-conveyor-icon-editor rotate: false - xy: 651, 47 + xy: 453, 453 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-driver-icon-editor rotate: false - xy: 749, 47 + xy: 551, 779 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill-icon-editor rotate: false - xy: 1043, 77 + xy: 295, 193 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-pump-icon-editor rotate: false - xy: 1401, 5 + xy: 949, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 meltdown-icon-editor rotate: false - xy: 293, 51 + xy: 323, 585 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 melter-icon-editor rotate: false - xy: 1435, 5 + xy: 983, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mend-projector-icon-editor rotate: false - xy: 1109, 241 + xy: 131, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender-icon-editor rotate: false - xy: 1469, 5 + xy: 1017, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message-icon-editor rotate: false - xy: 1503, 105 + xy: 1051, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press-icon-editor rotate: false - xy: 847, 145 + xy: 551, 681 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-icon-editor rotate: false - xy: 847, 47 + xy: 649, 779 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 overdrive-projector-icon-editor rotate: false - xy: 1109, 175 + xy: 197, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overflow-gate-icon-editor rotate: false - xy: 1537, 105 + xy: 1051, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +payload-router-icon-editor + rotate: false + xy: 551, 583 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 pebbles-icon-editor rotate: false - xy: 1571, 105 + xy: 1051, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-icon-editor rotate: false - xy: 1605, 79 + xy: 1931, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-editor rotate: false - xy: 1639, 69 + xy: 1965, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-editor rotate: false - xy: 1673, 69 + xy: 1931, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large-icon-editor rotate: false - xy: 1175, 241 + xy: 133, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-icon-editor rotate: false - xy: 1109, 109 + xy: 199, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pine-icon-editor rotate: false - xy: 1505, 223 + xy: 977, 793 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 plastanium-compressor-icon-editor rotate: false - xy: 1175, 175 + xy: 263, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-conveyor-icon-editor rotate: false - xy: 1707, 69 + xy: 1965, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-icon-editor rotate: false - xy: 1741, 69 + xy: 1927, 805 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-large-icon-editor rotate: false - xy: 1241, 241 + xy: 265, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plated-conduit-icon-editor rotate: false - xy: 1775, 69 + xy: 1961, 805 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pneumatic-drill-icon-editor rotate: false - xy: 1175, 109 + xy: 875, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-node-icon-editor rotate: false - xy: 1809, 69 + xy: 1927, 771 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large-icon-editor rotate: false - xy: 1241, 175 + xy: 941, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source-icon-editor rotate: false - xy: 1843, 69 + xy: 1961, 771 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-editor rotate: false - xy: 1877, 69 + xy: 1999, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-editor rotate: false - xy: 1911, 69 + xy: 1999, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-editor rotate: false - xy: 1945, 69 + xy: 1995, 805 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer-icon-editor rotate: false - xy: 1307, 241 + xy: 1007, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-icon-editor rotate: false - xy: 1979, 69 + xy: 1995, 771 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ripple-icon-editor rotate: false - xy: 1003, 275 + xy: 649, 681 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rock-icon-editor rotate: false - xy: 1505, 173 + xy: 845, 595 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rocks-icon-editor rotate: false - xy: 2013, 69 + xy: 1919, 737 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump-icon-editor rotate: false - xy: 1241, 109 + xy: 1073, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 router-icon-editor rotate: false - xy: 1503, 71 + xy: 1953, 737 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator-icon-editor rotate: false - xy: 1307, 175 + xy: 1139, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 saltrocks-icon-editor rotate: false - xy: 1537, 71 + xy: 1987, 737 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salvo-icon-editor rotate: false - xy: 1307, 109 + xy: 1205, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-boulder-icon-editor rotate: false - xy: 1571, 71 + xy: 425, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-editor rotate: false - xy: 1605, 45 + xy: 425, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sandrocks-icon-editor rotate: false - xy: 1639, 35 + xy: 459, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scatter-icon-editor rotate: false - xy: 553, 17 + xy: 1271, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-icon-editor rotate: false - xy: 1673, 35 + xy: 459, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-editor rotate: false - xy: 775, 243 + xy: 615, 877 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-huge-icon-editor rotate: false - xy: 945, 177 + xy: 747, 779 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-icon-editor rotate: false - xy: 1707, 35 + xy: 493, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-large-icon-editor rotate: false - xy: 1395, 273 + xy: 1337, 843 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +segment-icon-editor + rotate: false + xy: 1403, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-icon-editor rotate: false - xy: 1461, 273 + xy: 1469, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-boulder-icon-editor rotate: false - xy: 1741, 35 + xy: 493, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shalerocks-icon-editor rotate: false - xy: 1775, 35 + xy: 425, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-editor rotate: false - xy: 1809, 35 + xy: 459, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-editor rotate: false - xy: 1843, 35 + xy: 493, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +silicon-crucible-icon-editor + rotate: false + xy: 551, 485 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 silicon-smelter-icon-editor rotate: false - xy: 1527, 273 + xy: 1535, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 snow-icon-editor rotate: false - xy: 1877, 35 + xy: 527, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-pine-icon-editor rotate: false - xy: 1555, 223 + xy: 911, 661 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock-icon-editor rotate: false - xy: 1555, 173 + xy: 977, 743 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrocks-icon-editor rotate: false - xy: 1911, 35 + xy: 527, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-editor rotate: false - xy: 1945, 35 + xy: 561, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large-icon-editor rotate: false - xy: 945, 79 + xy: 649, 583 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sorter-icon-editor rotate: false - xy: 1979, 35 + xy: 561, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-editor rotate: false - xy: 2013, 35 + xy: 595, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre-icon-editor rotate: false - xy: 905, 373 + xy: 323, 455 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spore-cluster-icon-editor rotate: false - xy: 1605, 181 + xy: 1027, 751 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-pine-icon-editor rotate: false - xy: 1605, 223 + xy: 1027, 793 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-press-icon-editor rotate: false - xy: 1593, 273 + xy: 1601, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sporerocks-icon-editor rotate: false - xy: 1503, 37 + xy: 595, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-tower-icon-editor rotate: false - xy: 1659, 273 + xy: 1667, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-wall-icon-editor rotate: false - xy: 1537, 37 + xy: 629, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large-icon-editor rotate: false - xy: 1725, 273 + xy: 1733, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 swarmer-icon-editor rotate: false - xy: 1791, 273 + xy: 1799, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tendrils-icon-editor rotate: false - xy: 1571, 37 + xy: 629, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-generator-icon-editor rotate: false - xy: 1857, 273 + xy: 1865, 843 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-pump-icon-editor rotate: false - xy: 1101, 307 + xy: 747, 681 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-icon-editor rotate: false - xy: 1199, 307 + xy: 649, 485 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-wall-icon-editor rotate: false - xy: 1503, 3 + xy: 663, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large-icon-editor rotate: false - xy: 1923, 273 + xy: 845, 777 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thruster-icon-editor rotate: false - xy: 423, 51 + xy: 745, 877 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 titanium-conveyor-icon-editor rotate: false - xy: 1537, 3 + xy: 663, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-editor rotate: false - xy: 1571, 3 + xy: 697, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large-icon-editor rotate: false - xy: 1373, 207 + xy: 845, 711 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-icon-editor rotate: false - xy: 1373, 141 + xy: 911, 777 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 underflow-gate-icon-editor rotate: false - xy: 1605, 11 + xy: 697, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-icon-editor rotate: false - xy: 1639, 1 + xy: 527, 283 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault-icon-editor rotate: false - xy: 1297, 307 + xy: 747, 583 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 water-extractor-icon-editor rotate: false - xy: 1439, 207 + xy: 845, 645 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wave-icon-editor rotate: false - xy: 1439, 141 + xy: 911, 711 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 white-tree-dead-icon-editor rotate: false - xy: 1, 181 + xy: 1, 685 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 white-tree-icon-editor rotate: false - xy: 323, 181 + xy: 1, 363 size: 320, 320 orig: 320, 320 offset: 0, 0 @@ -8927,7 +9060,7 @@ alpha-bg index: -1 bar rotate: false - xy: 1457, 670 + xy: 1318, 646 size: 27, 36 split: 9, 9, 9, 9 orig: 27, 36 @@ -8935,7 +9068,7 @@ bar index: -1 bar-top rotate: false - xy: 1428, 670 + xy: 1289, 638 size: 27, 36 split: 9, 10, 9, 10 orig: 27, 36 @@ -8950,7 +9083,7 @@ block-alloy-smelter-large index: -1 block-alloy-smelter-medium rotate: false - xy: 845, 899 + xy: 881, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -8985,14 +9118,14 @@ block-arc-large index: -1 block-arc-medium rotate: false - xy: 879, 899 + xy: 881, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-arc-small rotate: false - xy: 38, 2 + xy: 80, 2 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -9013,28 +9146,28 @@ block-arc-xlarge index: -1 block-armored-conveyor-large rotate: false - xy: 551, 574 + xy: 601, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-armored-conveyor-medium rotate: false - xy: 913, 899 + xy: 915, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-armored-conveyor-small rotate: false - xy: 887, 499 + xy: 963, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-armored-conveyor-tiny rotate: false - xy: 949, 593 + xy: 337, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9048,42 +9181,42 @@ block-armored-conveyor-xlarge index: -1 block-basic-reconstructor-large rotate: false - xy: 351, 324 + xy: 351, 274 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-forge-large rotate: false - xy: 351, 324 + xy: 351, 274 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-basic-reconstructor-medium rotate: false - xy: 947, 912 + xy: 881, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-forge-medium rotate: false - xy: 947, 912 + xy: 881, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-basic-reconstructor-small rotate: false - xy: 1486, 682 + xy: 1289, 612 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-forge-small rotate: false - xy: 1486, 682 + xy: 1289, 612 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -9118,28 +9251,28 @@ block-block-forge-xlarge index: -1 block-battery-large rotate: false - xy: 401, 374 + xy: 401, 324 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-large rotate: false - xy: 451, 424 + xy: 451, 374 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-medium rotate: false - xy: 981, 912 + xy: 949, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-large-small rotate: false - xy: 978, 648 + xy: 1376, 658 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -9160,21 +9293,21 @@ block-battery-large-xlarge index: -1 block-battery-medium rotate: false - xy: 1015, 912 + xy: 915, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-small rotate: false - xy: 64, 2 + xy: 1376, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-battery-tiny rotate: false - xy: 761, 598 + xy: 929, 459 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9188,28 +9321,28 @@ block-battery-xlarge index: -1 block-blast-drill-large rotate: false - xy: 501, 474 + xy: 501, 424 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-drill-medium rotate: false - xy: 1049, 912 + xy: 983, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-drill-small rotate: false - xy: 913, 499 + xy: 106, 2 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-drill-tiny rotate: false - xy: 1987, 957 + xy: 132, 10 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9223,28 +9356,28 @@ block-blast-drill-xlarge index: -1 block-blast-mixer-large rotate: false - xy: 551, 532 + xy: 551, 474 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-mixer-medium rotate: false - xy: 1083, 912 + xy: 949, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-mixer-small rotate: false - xy: 1512, 682 + xy: 989, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-mixer-tiny rotate: false - xy: 921, 455 + xy: 1145, 425 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9256,630 +9389,630 @@ block-blast-mixer-xlarge orig: 48, 48 offset: 0, 0 index: -1 -block-block-launcher-large - rotate: false - xy: 593, 574 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-block-launcher-medium - rotate: false - xy: 1117, 912 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-block-launcher-small - rotate: false - xy: 1004, 648 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-block-launcher-tiny - rotate: false - xy: 1777, 715 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-block-launcher-xlarge - rotate: false - xy: 259, 769 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 block-block-loader-large rotate: false - xy: 351, 282 + xy: 601, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-loader-medium rotate: false - xy: 1151, 912 + xy: 915, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-loader-small rotate: false - xy: 978, 622 + xy: 1015, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-loader-tiny rotate: false - xy: 1803, 741 + xy: 2026, 609 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-block-loader-xlarge rotate: false - xy: 1, 378 + xy: 259, 769 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-block-unloader-large rotate: false - xy: 593, 532 + xy: 643, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-unloader-medium rotate: false - xy: 1185, 912 + xy: 1017, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-unloader-small rotate: false - xy: 90, 2 + xy: 1041, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-unloader-tiny rotate: false - xy: 1829, 767 + xy: 1901, 520 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-block-unloader-xlarge rotate: false - xy: 51, 428 + xy: 1, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-bridge-conduit-large rotate: false - xy: 635, 574 + xy: 351, 232 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conduit-medium rotate: false - xy: 1219, 912 + xy: 983, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conduit-small rotate: false - xy: 1538, 682 + xy: 1067, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conduit-tiny rotate: false - xy: 1855, 793 + xy: 1927, 551 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-bridge-conduit-xlarge rotate: false - xy: 181, 558 + xy: 51, 428 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-bridge-conveyor-large rotate: false - xy: 351, 240 + xy: 643, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conveyor-medium rotate: false - xy: 1253, 912 + xy: 949, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conveyor-small rotate: false - xy: 1030, 648 + xy: 1093, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conveyor-tiny rotate: false - xy: 1907, 829 + xy: 1953, 588 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-bridge-conveyor-xlarge rotate: false - xy: 259, 719 + xy: 181, 558 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-char-large rotate: false - xy: 635, 532 + xy: 685, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-char-medium rotate: false - xy: 1287, 912 + xy: 1051, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-char-small rotate: false - xy: 1004, 622 + xy: 1119, 417 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-char-tiny rotate: false - xy: 1933, 860 + xy: 309, 680 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-char-xlarge rotate: false - xy: 1, 328 + xy: 259, 719 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-cliff-large rotate: false - xy: 677, 574 + xy: 351, 190 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cliff-medium rotate: false - xy: 1321, 912 + xy: 1017, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliff-small rotate: false - xy: 116, 2 + xy: 1402, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cliff-tiny rotate: false - xy: 309, 680 + xy: 331, 580 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-cliff-xlarge rotate: false - xy: 51, 378 + xy: 1, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-cliffs-large rotate: false - xy: 351, 198 + xy: 685, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cliffs-medium rotate: false - xy: 1355, 912 + xy: 983, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliffs-small rotate: false - xy: 1564, 682 + xy: 1428, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cliffs-tiny rotate: false - xy: 331, 580 + xy: 1953, 570 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-cliffs-xlarge rotate: false - xy: 259, 669 + xy: 51, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-coal-centrifuge-large rotate: false - xy: 677, 532 + xy: 727, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-coal-centrifuge-medium rotate: false - xy: 1389, 912 + xy: 1085, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-coal-centrifuge-small rotate: false - xy: 1056, 648 + xy: 1454, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-coal-centrifuge-tiny rotate: false - xy: 761, 580 + xy: 1971, 588 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-coal-centrifuge-xlarge rotate: false - xy: 1, 278 + xy: 259, 669 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-combustion-generator-large rotate: false - xy: 719, 574 + xy: 351, 148 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-combustion-generator-medium rotate: false - xy: 1423, 912 + xy: 1051, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-combustion-generator-small rotate: false - xy: 1030, 622 + xy: 1480, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-combustion-generator-tiny rotate: false - xy: 939, 455 + xy: 1971, 570 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-combustion-generator-xlarge rotate: false - xy: 51, 328 + xy: 1, 278 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-conduit-large rotate: false - xy: 351, 156 + xy: 727, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conduit-medium rotate: false - xy: 1457, 912 + xy: 1017, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conduit-small rotate: false - xy: 1590, 682 + xy: 1506, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conduit-tiny rotate: false - xy: 1971, 923 + xy: 2027, 813 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-conduit-xlarge rotate: false - xy: 1, 228 + xy: 51, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-container-large rotate: false - xy: 719, 532 + xy: 351, 106 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-container-medium rotate: false - xy: 1491, 912 + xy: 1119, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-container-small rotate: false - xy: 1082, 648 + xy: 1532, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-container-tiny rotate: false - xy: 957, 455 + xy: 2027, 795 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-container-xlarge rotate: false - xy: 51, 278 + xy: 1, 228 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-conveyor-large rotate: false - xy: 351, 114 + xy: 351, 64 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conveyor-medium rotate: false - xy: 1525, 912 + xy: 1153, 660 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conveyor-small rotate: false - xy: 1056, 622 + xy: 1558, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conveyor-tiny rotate: false - xy: 1989, 939 + xy: 2027, 777 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-conveyor-xlarge rotate: false - xy: 1, 178 + xy: 51, 278 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-copper-wall-large rotate: false - xy: 351, 72 + xy: 351, 22 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-large rotate: false - xy: 351, 30 + xy: 769, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-medium rotate: false - xy: 1559, 912 + xy: 1085, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-large-small rotate: false - xy: 1616, 682 + xy: 1584, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-large-tiny rotate: false - xy: 1989, 921 + xy: 355, 4 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-copper-wall-large-xlarge rotate: false - xy: 51, 228 + xy: 1, 178 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-copper-wall-medium rotate: false - xy: 1593, 912 + xy: 1051, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-small rotate: false - xy: 1108, 648 + xy: 1610, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-tiny rotate: false - xy: 2007, 923 + xy: 373, 4 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-copper-wall-xlarge rotate: false - xy: 1, 128 + xy: 51, 228 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-core-foundation-large rotate: false - xy: 761, 536 + xy: 811, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-foundation-medium rotate: false - xy: 1627, 912 + xy: 1119, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-foundation-small rotate: false - xy: 1082, 622 + xy: 1636, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-foundation-tiny rotate: false - xy: 2025, 923 + xy: 391, 4 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-core-foundation-xlarge rotate: false - xy: 51, 178 + xy: 1, 128 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-core-nucleus-large rotate: false - xy: 803, 536 + xy: 853, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-nucleus-medium rotate: false - xy: 1661, 912 + xy: 1153, 626 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-nucleus-small rotate: false - xy: 1642, 682 + xy: 1662, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-nucleus-tiny rotate: false - xy: 955, 437 + xy: 409, 4 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-core-nucleus-xlarge rotate: false - xy: 1, 78 + xy: 51, 178 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-core-shard-large rotate: false - xy: 845, 536 + xy: 601, 490 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-shard-medium rotate: false - xy: 1695, 912 + xy: 1085, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-shard-small rotate: false - xy: 1134, 648 + xy: 1688, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-shard-tiny rotate: false - xy: 955, 419 + xy: 1927, 533 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-core-shard-xlarge + rotate: false + xy: 1, 78 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-core-silo-large + rotate: false + xy: 643, 490 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-core-silo-medium + rotate: false + xy: 1119, 579 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-core-silo-small + rotate: false + xy: 1714, 632 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-core-silo-tiny + rotate: false + xy: 1355, 510 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-core-silo-xlarge rotate: false xy: 51, 128 size: 48, 48 @@ -9888,28 +10021,28 @@ block-core-shard-xlarge index: -1 block-craters-large rotate: false - xy: 551, 490 + xy: 685, 490 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-craters-medium rotate: false - xy: 1729, 912 + xy: 1153, 592 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-craters-small rotate: false - xy: 1108, 622 + xy: 1740, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-craters-tiny rotate: false - xy: 1933, 842 + xy: 1373, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9923,28 +10056,28 @@ block-craters-xlarge index: -1 block-cryofluidmixer-large rotate: false - xy: 593, 490 + xy: 727, 490 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cryofluidmixer-medium rotate: false - xy: 1783, 941 + xy: 895, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cryofluidmixer-small rotate: false - xy: 1668, 682 + xy: 1766, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cryofluidmixer-tiny rotate: false - xy: 1959, 897 + xy: 1391, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9958,28 +10091,28 @@ block-cryofluidmixer-xlarge index: -1 block-cultivator-large rotate: false - xy: 635, 490 + xy: 769, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cultivator-medium rotate: false - xy: 1817, 941 + xy: 929, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cultivator-small rotate: false - xy: 1160, 648 + xy: 1792, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cultivator-tiny rotate: false - xy: 1959, 879 + xy: 1409, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9993,28 +10126,28 @@ block-cultivator-xlarge index: -1 block-cyclone-large rotate: false - xy: 677, 490 + xy: 811, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cyclone-medium rotate: false - xy: 1851, 941 + xy: 963, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cyclone-small rotate: false - xy: 1134, 622 + xy: 1818, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cyclone-tiny rotate: false - xy: 955, 575 + xy: 1427, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10028,28 +10161,28 @@ block-cyclone-xlarge index: -1 block-dark-metal-large rotate: false - xy: 719, 490 + xy: 853, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-metal-medium rotate: false - xy: 1885, 941 + xy: 997, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-metal-small rotate: false - xy: 1694, 682 + xy: 1844, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-metal-tiny rotate: false - xy: 955, 557 + xy: 1445, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10063,28 +10196,28 @@ block-dark-metal-xlarge index: -1 block-dark-panel-1-large rotate: false - xy: 761, 494 + xy: 393, 274 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-1-medium rotate: false - xy: 1919, 941 + xy: 895, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-1-small rotate: false - xy: 1186, 648 + xy: 1870, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-1-tiny rotate: false - xy: 955, 539 + xy: 1463, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10098,28 +10231,28 @@ block-dark-panel-1-xlarge index: -1 block-dark-panel-2-large rotate: false - xy: 803, 494 + xy: 393, 232 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-2-medium rotate: false - xy: 1953, 941 + xy: 929, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-2-small rotate: false - xy: 1160, 622 + xy: 1896, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-2-tiny rotate: false - xy: 1881, 803 + xy: 1481, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10133,28 +10266,28 @@ block-dark-panel-2-xlarge index: -1 block-dark-panel-3-large rotate: false - xy: 845, 494 + xy: 393, 190 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-3-medium rotate: false - xy: 859, 865 + xy: 963, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-3-small rotate: false - xy: 1720, 682 + xy: 1922, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-3-tiny rotate: false - xy: 973, 578 + xy: 1499, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10168,28 +10301,28 @@ block-dark-panel-3-xlarge index: -1 block-dark-panel-4-large rotate: false - xy: 393, 324 + xy: 393, 148 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-4-medium rotate: false - xy: 859, 831 + xy: 997, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-4-small rotate: false - xy: 1212, 648 + xy: 1948, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-4-tiny rotate: false - xy: 991, 578 + xy: 1517, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10203,28 +10336,28 @@ block-dark-panel-4-xlarge index: -1 block-dark-panel-5-large rotate: false - xy: 393, 282 + xy: 393, 106 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-5-medium rotate: false - xy: 893, 865 + xy: 1031, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-5-small rotate: false - xy: 1186, 622 + xy: 1974, 632 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-5-tiny rotate: false - xy: 973, 560 + xy: 1535, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10238,28 +10371,28 @@ block-dark-panel-5-xlarge index: -1 block-dark-panel-6-large rotate: false - xy: 393, 240 + xy: 393, 64 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-6-medium rotate: false - xy: 859, 797 + xy: 1031, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-6-small rotate: false - xy: 1746, 682 + xy: 997, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-6-tiny rotate: false - xy: 1009, 578 + xy: 1553, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10273,49 +10406,49 @@ block-dark-panel-6-xlarge index: -1 block-darksand-large rotate: false - xy: 393, 198 + xy: 393, 22 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-medium rotate: false - xy: 893, 831 + xy: 1065, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-small rotate: false - xy: 1238, 648 + xy: 997, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-large rotate: false - xy: 393, 156 + xy: 443, 324 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-tainted-water-medium rotate: false - xy: 859, 763 + xy: 1065, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-tainted-water-small rotate: false - xy: 1212, 622 + xy: 1023, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-tiny rotate: false - xy: 973, 542 + xy: 1571, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10329,35 +10462,35 @@ block-darksand-tainted-water-xlarge index: -1 block-darksand-tiny rotate: false - xy: 991, 560 + xy: 1589, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-darksand-water-large rotate: false - xy: 393, 114 + xy: 435, 282 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-water-medium rotate: false - xy: 893, 797 + xy: 1099, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-water-small rotate: false - xy: 1264, 648 + xy: 997, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-water-tiny rotate: false - xy: 1027, 578 + xy: 1607, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -10376,5259 +10509,5469 @@ block-darksand-xlarge orig: 48, 48 offset: 0, 0 index: -1 -block-deepwater-large +block-data-processor-large rotate: false - xy: 393, 72 + xy: 435, 240 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-deepwater-medium +block-data-processor-medium rotate: false - xy: 859, 729 + xy: 1099, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-deepwater-small +block-data-processor-small rotate: false - xy: 1238, 622 + xy: 1023, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-deepwater-tiny +block-data-processor-tiny rotate: false - xy: 991, 542 + xy: 1625, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-deepwater-xlarge +block-data-processor-xlarge rotate: false xy: 1407, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-differential-generator-large +block-deepwater-large rotate: false - xy: 393, 30 + xy: 435, 198 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-differential-generator-medium +block-deepwater-medium rotate: false - xy: 893, 763 + xy: 1133, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-differential-generator-small +block-deepwater-small rotate: false - xy: 1290, 648 + xy: 1049, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-differential-generator-tiny +block-deepwater-tiny rotate: false - xy: 1009, 560 + xy: 1643, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-differential-generator-xlarge +block-deepwater-xlarge rotate: false xy: 1457, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-diode-large +block-differential-generator-large rotate: false - xy: 443, 374 + xy: 435, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-diode-medium +block-differential-generator-medium rotate: false - xy: 859, 695 + xy: 1133, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-diode-small +block-differential-generator-small rotate: false - xy: 1264, 622 + xy: 1023, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-diode-tiny +block-differential-generator-tiny rotate: false - xy: 1045, 578 + xy: 1661, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-diode-xlarge +block-differential-generator-xlarge rotate: false xy: 1507, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-distributor-large +block-diode-large rotate: false - xy: 435, 332 + xy: 435, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-distributor-medium +block-diode-medium rotate: false - xy: 893, 729 + xy: 1979, 899 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-distributor-small +block-diode-small rotate: false - xy: 1290, 622 + xy: 1049, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-distributor-tiny +block-diode-tiny rotate: false - xy: 1027, 560 + xy: 1679, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-distributor-xlarge +block-diode-xlarge rotate: false xy: 1557, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-door-large +block-disassembler-large rotate: false - xy: 435, 290 + xy: 435, 72 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-door-large-large +block-disassembler-medium rotate: false - xy: 435, 248 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-door-large-medium - rotate: false - xy: 893, 695 + xy: 2013, 907 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-door-large-small +block-disassembler-small rotate: false - xy: 519, 2 + xy: 1075, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-door-large-tiny +block-disassembler-tiny rotate: false - xy: 1009, 542 + xy: 1697, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-door-large-xlarge +block-disassembler-xlarge rotate: false xy: 1607, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-door-medium +block-distributor-large rotate: false - xy: 927, 865 + xy: 435, 30 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-distributor-medium + rotate: false + xy: 929, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-door-small +block-distributor-small rotate: false - xy: 545, 2 + xy: 1049, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-door-tiny +block-distributor-tiny rotate: false - xy: 1063, 578 + xy: 1715, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-door-xlarge +block-distributor-xlarge rotate: false xy: 1657, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dunerocks-large +block-door-large rotate: false - xy: 435, 206 + xy: 493, 374 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dunerocks-medium +block-door-large-large rotate: false - xy: 927, 831 + xy: 485, 332 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-door-large-medium + rotate: false + xy: 963, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dunerocks-small +block-door-large-small rotate: false - xy: 571, 2 + xy: 1075, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dunerocks-tiny +block-door-large-tiny rotate: false - xy: 1045, 560 + xy: 1733, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dunerocks-xlarge +block-door-large-xlarge rotate: false xy: 1707, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-duo-large +block-door-medium rotate: false - xy: 435, 164 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-duo-medium - rotate: false - xy: 927, 797 + xy: 997, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-duo-small +block-door-small rotate: false - xy: 597, 2 + xy: 1101, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-duo-tiny +block-door-tiny rotate: false - xy: 1027, 542 + xy: 1751, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-duo-xlarge +block-door-xlarge rotate: false xy: 1757, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-force-projector-large +block-dunerocks-large rotate: false - xy: 435, 122 + xy: 543, 424 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-force-projector-medium +block-dunerocks-medium rotate: false - xy: 927, 763 + xy: 1031, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-force-projector-small +block-dunerocks-small rotate: false - xy: 623, 2 + xy: 1075, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-force-projector-tiny +block-dunerocks-tiny rotate: false - xy: 1081, 578 + xy: 1769, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-force-projector-xlarge +block-dunerocks-xlarge rotate: false xy: 1807, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-fuse-large +block-duo-large rotate: false - xy: 435, 80 + xy: 535, 382 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-fuse-medium +block-duo-medium rotate: false - xy: 927, 729 + xy: 1065, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-fuse-small +block-duo-small rotate: false - xy: 649, 2 + xy: 1101, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-fuse-tiny +block-duo-tiny rotate: false - xy: 1063, 560 + xy: 1787, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-fuse-xlarge +block-duo-xlarge rotate: false xy: 1857, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-graphite-press-large +block-force-projector-large rotate: false - xy: 435, 38 + xy: 593, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-graphite-press-medium +block-force-projector-medium rotate: false - xy: 927, 695 + xy: 1099, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-graphite-press-small +block-force-projector-small rotate: false - xy: 675, 2 + xy: 1101, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-graphite-press-tiny +block-force-projector-tiny rotate: false - xy: 1045, 542 + xy: 1805, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-graphite-press-xlarge +block-force-projector-xlarge rotate: false xy: 1907, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-grass-large +block-fuse-large rotate: false - xy: 493, 424 + xy: 635, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-grass-medium +block-fuse-medium rotate: false - xy: 961, 878 + xy: 1133, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-grass-small +block-fuse-small rotate: false - xy: 701, 2 + xy: 1127, 391 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-grass-tiny +block-fuse-tiny rotate: false - xy: 1099, 578 + xy: 1823, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-grass-xlarge +block-fuse-xlarge rotate: false xy: 1957, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-hail-large +block-graphite-press-large rotate: false - xy: 485, 382 + xy: 677, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-hail-medium +block-graphite-press-medium rotate: false - xy: 995, 878 + xy: 1279, 786 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-hail-small +block-graphite-press-small rotate: false - xy: 727, 2 + xy: 1127, 365 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-hail-tiny +block-graphite-press-tiny rotate: false - xy: 1081, 560 + xy: 1841, 510 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-hail-xlarge +block-graphite-press-xlarge rotate: false xy: 345, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-holostone-large +block-grass-large rotate: false - xy: 543, 448 + xy: 719, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-holostone-medium +block-grass-medium rotate: false - xy: 961, 844 + xy: 1313, 786 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-holostone-small +block-grass-small rotate: false - xy: 753, 2 + xy: 1127, 339 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-holostone-tiny +block-grass-tiny rotate: false - xy: 1063, 542 + xy: 1352, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-holostone-xlarge +block-grass-xlarge rotate: false xy: 395, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-hotrock-large +block-hail-large rotate: false - xy: 585, 448 + xy: 585, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-hotrock-medium +block-hail-medium rotate: false - xy: 1029, 878 + xy: 1237, 744 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-hotrock-small +block-hail-small rotate: false - xy: 779, 2 + xy: 1235, 412 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-hotrock-tiny +block-hail-tiny rotate: false - xy: 1117, 578 + xy: 1352, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-hotrock-xlarge +block-hail-xlarge rotate: false xy: 445, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ice-large +block-holostone-large rotate: false - xy: 627, 448 + xy: 627, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-ice-medium +block-holostone-medium rotate: false - xy: 995, 844 + xy: 1195, 702 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-ice-small +block-holostone-small rotate: false - xy: 805, 2 + xy: 1007, 313 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-ice-snow-large +block-holostone-tiny rotate: false - xy: 669, 448 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ice-snow-medium - rotate: false - xy: 961, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ice-snow-small - rotate: false - xy: 831, 2 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ice-snow-tiny - rotate: false - xy: 1099, 560 + xy: 1370, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ice-snow-xlarge +block-holostone-xlarge rotate: false xy: 495, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ice-tiny +block-hotrock-large rotate: false - xy: 1081, 542 + xy: 669, 406 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-hotrock-medium + rotate: false + xy: 1363, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-hotrock-small + rotate: false + xy: 1033, 313 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-hotrock-tiny + rotate: false + xy: 1352, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ice-xlarge +block-hotrock-xlarge rotate: false xy: 545, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-icerocks-large +block-ice-large rotate: false - xy: 711, 448 + xy: 711, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-icerocks-medium +block-ice-medium rotate: false - xy: 1063, 878 + xy: 1397, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-icerocks-small +block-ice-small rotate: false - xy: 857, 2 + xy: 1059, 313 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-icerocks-tiny +block-ice-snow-large rotate: false - xy: 1135, 578 + xy: 577, 364 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ice-snow-medium + rotate: false + xy: 1431, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ice-snow-small + rotate: false + xy: 1085, 313 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ice-snow-tiny + rotate: false + xy: 1370, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-icerocks-xlarge +block-ice-snow-xlarge rotate: false xy: 595, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ignarock-large +block-ice-tiny rotate: false - xy: 535, 406 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ignarock-medium - rotate: false - xy: 1029, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ignarock-small - rotate: false - xy: 939, 499 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ignarock-tiny - rotate: false - xy: 1117, 560 + xy: 1388, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ignarock-xlarge +block-ice-xlarge rotate: false xy: 645, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-illuminator-large +block-icerocks-large rotate: false - xy: 577, 406 + xy: 619, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-illuminator-medium +block-icerocks-medium rotate: false - xy: 995, 810 + xy: 1465, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-illuminator-small +block-icerocks-small rotate: false - xy: 921, 473 + xy: 1111, 313 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-illuminator-tiny +block-icerocks-tiny rotate: false - xy: 1099, 542 + xy: 1352, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-illuminator-xlarge +block-icerocks-xlarge rotate: false xy: 695, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-impact-reactor-large +block-ignarock-large rotate: false - xy: 619, 406 + xy: 661, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-impact-reactor-medium +block-ignarock-medium rotate: false - xy: 961, 776 + xy: 1499, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-impact-reactor-small +block-ignarock-small rotate: false - xy: 947, 473 + xy: 1007, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-impact-reactor-tiny +block-ignarock-tiny rotate: false - xy: 1153, 578 + xy: 1370, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-impact-reactor-xlarge +block-ignarock-xlarge rotate: false xy: 101, 478 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-incinerator-large +block-illuminator-large rotate: false - xy: 661, 406 + xy: 703, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-incinerator-medium +block-illuminator-medium rotate: false - xy: 1097, 878 + xy: 1533, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-incinerator-small +block-illuminator-small rotate: false - xy: 883, 2 + xy: 1033, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-incinerator-tiny +block-illuminator-tiny rotate: false - xy: 1135, 560 + xy: 1388, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-incinerator-xlarge +block-illuminator-xlarge rotate: false xy: 101, 428 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-inverted-sorter-large +block-impact-reactor-large rotate: false - xy: 703, 406 + xy: 535, 340 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-inverted-sorter-medium +block-impact-reactor-medium rotate: false - xy: 1063, 844 + xy: 1567, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-inverted-sorter-small +block-impact-reactor-small rotate: false - xy: 909, 6 + xy: 1059, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-inverted-sorter-tiny +block-impact-reactor-tiny rotate: false - xy: 1117, 542 + xy: 1406, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-inverted-sorter-xlarge +block-impact-reactor-xlarge rotate: false xy: 101, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-item-source-large +block-incinerator-large rotate: false - xy: 527, 364 + xy: 577, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-item-source-medium +block-incinerator-medium rotate: false - xy: 1029, 810 + xy: 1601, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-item-source-small +block-incinerator-small rotate: false - xy: 935, 6 + xy: 1085, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-item-source-tiny +block-incinerator-tiny rotate: false - xy: 1171, 578 + xy: 1352, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-item-source-xlarge +block-incinerator-xlarge rotate: false xy: 101, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-item-void-large +block-inverted-sorter-large rotate: false - xy: 569, 364 + xy: 619, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-item-void-medium +block-inverted-sorter-medium rotate: false - xy: 995, 776 + xy: 1635, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-item-void-small +block-inverted-sorter-small rotate: false - xy: 961, 6 + xy: 1111, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-item-void-tiny +block-inverted-sorter-tiny rotate: false - xy: 1153, 560 + xy: 1370, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-item-void-xlarge +block-inverted-sorter-xlarge rotate: false xy: 101, 278 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-junction-large +block-item-source-large rotate: false - xy: 611, 364 + xy: 661, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-junction-medium +block-item-source-medium rotate: false - xy: 961, 742 + xy: 1669, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-junction-small +block-item-source-small rotate: false - xy: 987, 6 + xy: 1137, 313 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-junction-tiny +block-item-source-tiny rotate: false - xy: 1135, 542 + xy: 1388, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-junction-xlarge +block-item-source-xlarge rotate: false xy: 101, 228 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-kiln-large +block-item-void-large rotate: false - xy: 653, 364 + xy: 703, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-kiln-medium +block-item-void-medium rotate: false - xy: 1131, 878 + xy: 1703, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-kiln-small +block-item-void-small rotate: false - xy: 1486, 656 + xy: 1137, 287 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-kiln-tiny +block-item-void-tiny rotate: false - xy: 1189, 578 + xy: 1406, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-kiln-xlarge +block-item-void-xlarge rotate: false xy: 101, 178 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-lancer-large +block-junction-large rotate: false - xy: 695, 364 + xy: 761, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-lancer-medium +block-junction-medium rotate: false - xy: 1097, 844 + xy: 1737, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-lancer-small +block-junction-small rotate: false - xy: 1512, 656 + xy: 1376, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-lancer-tiny +block-junction-tiny rotate: false - xy: 1171, 560 + xy: 1424, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-lancer-xlarge +block-junction-xlarge rotate: false xy: 101, 128 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-laser-drill-large +block-kiln-large rotate: false - xy: 485, 340 + xy: 753, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-laser-drill-medium +block-kiln-medium rotate: false - xy: 1063, 810 + xy: 1771, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-laser-drill-small +block-kiln-small rotate: false - xy: 1538, 656 + xy: 1402, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-laser-drill-tiny +block-kiln-tiny rotate: false - xy: 1153, 542 + xy: 1352, 402 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-laser-drill-xlarge +block-kiln-xlarge rotate: false xy: 101, 78 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-launch-pad-large +block-lancer-large rotate: false - xy: 477, 298 + xy: 745, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-launch-pad-large-large +block-lancer-medium rotate: false - xy: 477, 256 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-launch-pad-large-medium - rotate: false - xy: 1029, 776 + xy: 1805, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-launch-pad-large-small +block-lancer-small rotate: false - xy: 1564, 656 + xy: 1428, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-launch-pad-large-tiny +block-lancer-tiny rotate: false - xy: 1207, 578 + xy: 1370, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-launch-pad-large-xlarge +block-lancer-xlarge rotate: false xy: 101, 28 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-launch-pad-medium +block-large-overdrive-projector-large rotate: false - xy: 995, 742 + xy: 745, 322 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-large-overdrive-projector-medium + rotate: false + xy: 1839, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-launch-pad-small +block-large-overdrive-projector-small rotate: false - xy: 1590, 656 + xy: 1454, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-launch-pad-tiny +block-large-overdrive-projector-tiny rotate: false - xy: 1189, 560 + xy: 1388, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-launch-pad-xlarge +block-large-overdrive-projector-xlarge rotate: false xy: 231, 608 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-liquid-junction-large +block-laser-drill-large rotate: false - xy: 477, 214 + xy: 803, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-liquid-junction-medium +block-laser-drill-medium rotate: false - xy: 961, 708 + xy: 1873, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-liquid-junction-small +block-laser-drill-small rotate: false - xy: 1616, 656 + xy: 1480, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-liquid-junction-tiny +block-laser-drill-tiny rotate: false - xy: 1171, 542 + xy: 1406, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-liquid-junction-xlarge +block-laser-drill-xlarge rotate: false xy: 231, 558 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-liquid-router-large +block-launch-pad-large rotate: false - xy: 477, 172 + xy: 845, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-liquid-router-medium +block-launch-pad-large-large rotate: false - xy: 1165, 878 + xy: 477, 282 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-launch-pad-large-medium + rotate: false + xy: 1907, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-liquid-router-small +block-launch-pad-large-small rotate: false - xy: 1642, 656 + xy: 1506, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-liquid-router-tiny +block-launch-pad-large-tiny rotate: false - xy: 1225, 578 + xy: 1424, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-liquid-router-xlarge +block-launch-pad-large-xlarge rotate: false xy: 745, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-liquid-source-large +block-launch-pad-medium rotate: false - xy: 477, 130 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-liquid-source-medium - rotate: false - xy: 1131, 844 + xy: 1941, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-liquid-source-small +block-launch-pad-small rotate: false - xy: 1668, 656 + xy: 1532, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-liquid-source-tiny +block-launch-pad-tiny rotate: false - xy: 1207, 560 + xy: 1442, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-liquid-source-xlarge +block-launch-pad-xlarge rotate: false xy: 151, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-liquid-tank-large +block-liquid-junction-large rotate: false - xy: 477, 88 + xy: 477, 240 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-liquid-tank-medium +block-liquid-junction-medium rotate: false - xy: 1097, 810 + xy: 963, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-liquid-tank-small +block-liquid-junction-small rotate: false - xy: 1694, 656 + xy: 1558, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-liquid-tank-tiny +block-liquid-junction-tiny rotate: false - xy: 1189, 542 + xy: 1370, 402 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-liquid-tank-xlarge +block-liquid-junction-xlarge rotate: false xy: 151, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-liquid-void-large +block-liquid-router-large rotate: false - xy: 477, 46 + xy: 477, 198 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-liquid-void-medium +block-liquid-router-medium rotate: false - xy: 1063, 776 + xy: 997, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-liquid-void-small +block-liquid-router-small rotate: false - xy: 1720, 656 + xy: 1584, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-liquid-void-tiny +block-liquid-router-tiny rotate: false - xy: 1243, 578 + xy: 1388, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-liquid-void-xlarge +block-liquid-router-xlarge rotate: false xy: 201, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-magmarock-large +block-liquid-source-large rotate: false - xy: 527, 322 + xy: 477, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-magmarock-medium +block-liquid-source-medium rotate: false - xy: 1029, 742 + xy: 1031, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-magmarock-small +block-liquid-source-small rotate: false - xy: 1746, 656 + xy: 1610, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-magmarock-tiny +block-liquid-source-tiny rotate: false - xy: 1225, 560 + xy: 1406, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-magmarock-xlarge +block-liquid-source-xlarge rotate: false xy: 151, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mass-conveyor-large +block-liquid-tank-large rotate: false - xy: 569, 322 + xy: 477, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mass-conveyor-medium +block-liquid-tank-medium rotate: false - xy: 995, 708 + xy: 1065, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mass-conveyor-small +block-liquid-tank-small rotate: false - xy: 978, 596 + xy: 1636, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mass-conveyor-tiny +block-liquid-tank-tiny rotate: false - xy: 1207, 542 + xy: 1424, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mass-conveyor-xlarge +block-liquid-tank-xlarge rotate: false xy: 201, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mass-driver-large +block-liquid-void-large rotate: false - xy: 611, 322 + xy: 477, 72 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mass-driver-medium +block-liquid-void-medium rotate: false - xy: 1199, 878 + xy: 1099, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mass-driver-small +block-liquid-void-small rotate: false - xy: 1004, 596 + xy: 1662, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mass-driver-tiny +block-liquid-void-tiny rotate: false - xy: 1261, 578 + xy: 1442, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mass-driver-xlarge +block-liquid-void-xlarge rotate: false xy: 151, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mechanical-drill-large +block-magmarock-large rotate: false - xy: 653, 322 + xy: 477, 30 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mechanical-drill-medium +block-magmarock-medium rotate: false - xy: 1165, 844 + xy: 1133, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mechanical-drill-small +block-magmarock-small rotate: false - xy: 1030, 596 + xy: 1688, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mechanical-drill-tiny +block-magmarock-tiny rotate: false - xy: 1243, 560 + xy: 1460, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mechanical-drill-xlarge +block-magmarock-xlarge rotate: false xy: 201, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mechanical-pump-large +block-mass-conveyor-large rotate: false - xy: 695, 322 + xy: 795, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mechanical-pump-medium +block-mass-conveyor-medium rotate: false - xy: 1131, 810 + xy: 1979, 865 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mechanical-pump-small +block-mass-conveyor-small rotate: false - xy: 1056, 596 + xy: 1714, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mechanical-pump-tiny +block-mass-conveyor-tiny rotate: false - xy: 1225, 542 + xy: 1388, 402 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mechanical-pump-xlarge +block-mass-conveyor-xlarge rotate: false xy: 151, 308 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-meltdown-large +block-mass-driver-large rotate: false - xy: 519, 280 + xy: 787, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-meltdown-medium +block-mass-driver-medium rotate: false - xy: 1097, 776 + xy: 2013, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-meltdown-small +block-mass-driver-small rotate: false - xy: 1082, 596 + xy: 1740, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-meltdown-tiny +block-mass-driver-tiny rotate: false - xy: 1279, 578 + xy: 1406, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-meltdown-xlarge +block-mass-driver-xlarge rotate: false xy: 201, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-melter-large +block-mechanical-drill-large rotate: false - xy: 519, 238 + xy: 787, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-melter-medium +block-mechanical-drill-medium rotate: false - xy: 1063, 742 + xy: 1975, 831 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-melter-small +block-mechanical-drill-small rotate: false - xy: 1108, 596 + xy: 1766, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-melter-tiny +block-mechanical-drill-tiny rotate: false - xy: 1261, 560 + xy: 1424, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-melter-xlarge +block-mechanical-drill-xlarge rotate: false xy: 151, 258 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mend-projector-large +block-mechanical-pump-large rotate: false - xy: 561, 280 + xy: 837, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mend-projector-medium +block-mechanical-pump-medium rotate: false - xy: 1029, 708 + xy: 1347, 786 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mend-projector-small +block-mechanical-pump-small rotate: false - xy: 1134, 596 + xy: 1792, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mend-projector-tiny +block-mechanical-pump-tiny rotate: false - xy: 1243, 542 + xy: 1442, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mend-projector-xlarge +block-mechanical-pump-xlarge rotate: false xy: 201, 308 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-mender-large +block-meltdown-large rotate: false - xy: 519, 196 + xy: 887, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-mender-medium +block-meltdown-medium rotate: false - xy: 1233, 878 + xy: 1381, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-mender-small +block-meltdown-small rotate: false - xy: 1160, 596 + xy: 1818, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-mender-tiny +block-meltdown-tiny rotate: false - xy: 1297, 578 + xy: 1460, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-mender-xlarge +block-meltdown-xlarge rotate: false xy: 151, 208 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-message-large +block-melter-large rotate: false - xy: 561, 238 + xy: 879, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-message-medium +block-melter-medium rotate: false - xy: 1199, 844 + xy: 1415, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-message-small +block-melter-small rotate: false - xy: 1186, 596 + xy: 1844, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-message-tiny +block-melter-tiny rotate: false - xy: 1279, 560 + xy: 1478, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-message-xlarge +block-melter-xlarge rotate: false xy: 201, 258 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-metal-floor-2-large +block-mend-projector-large rotate: false - xy: 603, 280 + xy: 829, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-metal-floor-2-medium +block-mend-projector-medium rotate: false - xy: 1165, 810 + xy: 1449, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-metal-floor-2-small +block-mend-projector-small rotate: false - xy: 1212, 596 + xy: 1870, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-metal-floor-2-tiny +block-mend-projector-tiny rotate: false - xy: 1261, 542 + xy: 1406, 402 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-metal-floor-2-xlarge +block-mend-projector-xlarge rotate: false xy: 151, 158 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-metal-floor-3-large +block-mender-large rotate: false - xy: 519, 154 + xy: 829, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-metal-floor-3-medium +block-mender-medium rotate: false - xy: 1131, 776 + xy: 1483, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-metal-floor-3-small +block-mender-small rotate: false - xy: 1238, 596 + xy: 1896, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-metal-floor-3-tiny +block-mender-tiny rotate: false - xy: 1297, 560 + xy: 1424, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-metal-floor-3-xlarge +block-mender-xlarge rotate: false xy: 201, 208 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-metal-floor-5-large +block-message-large rotate: false - xy: 561, 196 + xy: 871, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-metal-floor-5-medium +block-message-medium rotate: false - xy: 1097, 742 + xy: 1517, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-metal-floor-5-small +block-message-small rotate: false - xy: 1264, 596 + xy: 1922, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-metal-floor-5-tiny +block-message-tiny rotate: false - xy: 1279, 542 + xy: 1442, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-metal-floor-5-xlarge +block-message-xlarge rotate: false xy: 151, 108 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-metal-floor-damaged-large +block-metal-floor-2-large rotate: false - xy: 603, 238 + xy: 871, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-metal-floor-damaged-medium +block-metal-floor-2-medium rotate: false - xy: 1063, 708 + xy: 1551, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-metal-floor-damaged-small +block-metal-floor-2-small rotate: false - xy: 1290, 596 + xy: 1948, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-metal-floor-damaged-tiny +block-metal-floor-2-tiny rotate: false - xy: 1297, 542 + xy: 1460, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-metal-floor-damaged-xlarge +block-metal-floor-2-xlarge rotate: false xy: 201, 158 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-metal-floor-large +block-metal-floor-3-large rotate: false - xy: 645, 280 + xy: 921, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-metal-floor-medium +block-metal-floor-3-medium rotate: false - xy: 1267, 878 + xy: 1585, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-metal-floor-small +block-metal-floor-3-small rotate: false - xy: 1013, 6 + xy: 1974, 606 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-metal-floor-tiny +block-metal-floor-3-tiny rotate: false - xy: 1315, 572 + xy: 1478, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-metal-floor-xlarge +block-metal-floor-3-xlarge rotate: false xy: 151, 58 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-moss-large +block-metal-floor-5-large rotate: false - xy: 519, 112 + xy: 913, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-moss-medium +block-metal-floor-5-medium rotate: false - xy: 1233, 844 + xy: 1619, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-moss-small +block-metal-floor-5-small rotate: false - xy: 1316, 642 + xy: 1318, 620 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-moss-tiny +block-metal-floor-5-tiny rotate: false - xy: 1315, 554 + xy: 1496, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-moss-xlarge +block-metal-floor-5-xlarge rotate: false xy: 201, 108 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-multi-press-large +block-metal-floor-damaged-large rotate: false - xy: 561, 154 + xy: 913, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-multi-press-medium +block-metal-floor-damaged-medium rotate: false - xy: 1199, 810 + xy: 1653, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-multi-press-small +block-metal-floor-damaged-small rotate: false - xy: 1316, 616 + xy: 1303, 586 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-multi-press-tiny +block-metal-floor-damaged-tiny rotate: false - xy: 1333, 572 + xy: 1424, 402 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-multi-press-xlarge +block-metal-floor-damaged-xlarge rotate: false xy: 201, 58 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-oil-extractor-large +block-metal-floor-large rotate: false - xy: 603, 196 + xy: 955, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-oil-extractor-medium +block-metal-floor-medium rotate: false - xy: 1165, 776 + xy: 1687, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-oil-extractor-small +block-metal-floor-small rotate: false - xy: 1342, 642 + xy: 1303, 560 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-oil-extractor-tiny +block-metal-floor-tiny rotate: false - xy: 1333, 554 + xy: 1442, 420 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-oil-extractor-xlarge +block-metal-floor-xlarge rotate: false xy: 251, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ore-coal-large +block-moss-large rotate: false - xy: 645, 238 + xy: 955, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-ore-coal-medium +block-moss-medium rotate: false - xy: 1131, 742 + xy: 1721, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-ore-coal-small +block-moss-small rotate: false - xy: 1342, 616 + xy: 1303, 534 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-ore-coal-tiny +block-moss-tiny rotate: false - xy: 1351, 572 + xy: 1460, 438 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ore-coal-xlarge +block-moss-xlarge rotate: false xy: 251, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ore-copper-large - rotate: false - xy: 687, 280 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ore-copper-medium - rotate: false - xy: 1097, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ore-copper-small - rotate: false - xy: 1368, 642 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ore-copper-tiny - rotate: false - xy: 1351, 554 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ore-copper-xlarge - rotate: false - xy: 251, 408 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-ore-lead-large - rotate: false - xy: 519, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ore-lead-medium - rotate: false - xy: 1301, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ore-lead-small - rotate: false - xy: 1368, 616 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ore-lead-tiny - rotate: false - xy: 1369, 572 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ore-lead-xlarge - rotate: false - xy: 251, 358 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-ore-scrap-large - rotate: false - xy: 561, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ore-scrap-medium - rotate: false - xy: 1267, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ore-scrap-small - rotate: false - xy: 1394, 642 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ore-scrap-tiny - rotate: false - xy: 1369, 554 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ore-scrap-xlarge - rotate: false - xy: 251, 308 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-ore-thorium-large - rotate: false - xy: 603, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ore-thorium-medium - rotate: false - xy: 1233, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ore-thorium-small - rotate: false - xy: 1394, 616 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ore-thorium-tiny - rotate: false - xy: 1387, 572 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ore-thorium-xlarge - rotate: false - xy: 251, 258 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-ore-titanium-large - rotate: false - xy: 645, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ore-titanium-medium - rotate: false - xy: 1199, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ore-titanium-small - rotate: false - xy: 1316, 590 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ore-titanium-tiny - rotate: false - xy: 1387, 554 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ore-titanium-xlarge - rotate: false - xy: 251, 208 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-overdrive-projector-large - rotate: false - xy: 687, 238 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-overdrive-projector-medium - rotate: false - xy: 1165, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-overdrive-projector-small - rotate: false - xy: 1342, 590 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-overdrive-projector-tiny - rotate: false - xy: 1405, 572 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-overdrive-projector-xlarge - rotate: false - xy: 251, 158 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-overflow-gate-large - rotate: false - xy: 561, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-overflow-gate-medium - rotate: false - xy: 1131, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-overflow-gate-small - rotate: false - xy: 1368, 590 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-overflow-gate-tiny - rotate: false - xy: 1405, 554 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-overflow-gate-xlarge - rotate: false - xy: 251, 108 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pebbles-large - rotate: false - xy: 603, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pebbles-medium - rotate: false - xy: 1335, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pebbles-small - rotate: false - xy: 1394, 590 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pebbles-tiny - rotate: false - xy: 1423, 572 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pebbles-xlarge - rotate: false - xy: 251, 58 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-phase-conduit-large - rotate: false - xy: 645, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-phase-conduit-medium - rotate: false - xy: 1301, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-phase-conduit-small - rotate: false - xy: 1420, 642 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-phase-conduit-tiny - rotate: false - xy: 1423, 554 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-phase-conduit-xlarge - rotate: false - xy: 151, 8 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-phase-conveyor-large - rotate: false - xy: 687, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-phase-conveyor-medium - rotate: false - xy: 1267, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-phase-conveyor-small - rotate: false - xy: 1420, 616 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-phase-conveyor-tiny - rotate: false - xy: 1315, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-phase-conveyor-xlarge - rotate: false - xy: 201, 8 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-phase-wall-large - rotate: false - xy: 603, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-phase-wall-large-large - rotate: false - xy: 645, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-phase-wall-large-medium - rotate: false - xy: 1233, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-phase-wall-large-small - rotate: false - xy: 1420, 590 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-phase-wall-large-tiny - rotate: false - xy: 1333, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-phase-wall-large-xlarge - rotate: false - xy: 251, 8 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-phase-wall-medium - rotate: false - xy: 1199, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-phase-wall-small - rotate: false - xy: 1446, 644 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-phase-wall-tiny - rotate: false - xy: 1351, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-phase-wall-xlarge - rotate: false - xy: 281, 619 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-phase-weaver-large - rotate: false - xy: 687, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-phase-weaver-medium - rotate: false - xy: 1165, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-phase-weaver-small - rotate: false - xy: 1446, 618 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-phase-weaver-tiny - rotate: false - xy: 1369, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-phase-weaver-xlarge - rotate: false - xy: 281, 569 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pine-large - rotate: false - xy: 645, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pine-medium - rotate: false - xy: 1369, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pine-small - rotate: false - xy: 1446, 592 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pine-tiny - rotate: false - xy: 1387, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pine-xlarge - rotate: false - xy: 301, 519 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-plastanium-compressor-large - rotate: false - xy: 687, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-plastanium-compressor-medium - rotate: false - xy: 1335, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-plastanium-compressor-small - rotate: false - xy: 1472, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-plastanium-compressor-tiny - rotate: false - xy: 1405, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-plastanium-compressor-xlarge - rotate: false - xy: 301, 469 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-plastanium-conveyor-large - rotate: false - xy: 687, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-plastanium-conveyor-medium - rotate: false - xy: 1301, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-plastanium-conveyor-small - rotate: false - xy: 1472, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-plastanium-conveyor-tiny - rotate: false - xy: 1423, 536 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-plastanium-conveyor-xlarge - rotate: false - xy: 301, 419 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-plastanium-wall-large - rotate: false - xy: 519, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-plastanium-wall-large-large - rotate: false - xy: 561, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-plastanium-wall-large-medium - rotate: false - xy: 1267, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-plastanium-wall-large-small - rotate: false - xy: 1498, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-plastanium-wall-large-tiny - rotate: false - xy: 1441, 548 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-plastanium-wall-large-xlarge - rotate: false - xy: 301, 369 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-plastanium-wall-medium - rotate: false - xy: 1233, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-plastanium-wall-small - rotate: false - xy: 1498, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-plastanium-wall-tiny - rotate: false - xy: 1441, 530 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-plastanium-wall-xlarge - rotate: false - xy: 301, 319 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-plated-conduit-large - rotate: false - xy: 603, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-plated-conduit-medium - rotate: false - xy: 1199, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-plated-conduit-small - rotate: false - xy: 1524, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-plated-conduit-tiny - rotate: false - xy: 1795, 715 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-plated-conduit-xlarge - rotate: false - xy: 301, 269 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pneumatic-drill-large - rotate: false - xy: 645, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pneumatic-drill-medium - rotate: false - xy: 1403, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pneumatic-drill-small - rotate: false - xy: 1524, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pneumatic-drill-tiny - rotate: false - xy: 1821, 741 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pneumatic-drill-xlarge - rotate: false - xy: 301, 219 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-power-node-large - rotate: false - xy: 687, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-power-node-large-large - rotate: false - xy: 477, 4 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-power-node-large-medium - rotate: false - xy: 1369, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-power-node-large-small - rotate: false - xy: 1550, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-power-node-large-tiny - rotate: false - xy: 1813, 723 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-power-node-large-xlarge - rotate: false - xy: 301, 169 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-power-node-medium - rotate: false - xy: 1335, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-power-node-small - rotate: false - xy: 1550, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-power-node-tiny - rotate: false - xy: 1847, 767 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-power-node-xlarge - rotate: false - xy: 301, 119 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-power-source-large - rotate: false - xy: 753, 448 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-power-source-medium - rotate: false - xy: 1301, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-power-source-small - rotate: false - xy: 1576, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-power-source-tiny - rotate: false - xy: 1839, 749 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-power-source-xlarge - rotate: false - xy: 301, 69 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-power-void-large - rotate: false - xy: 745, 406 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-power-void-medium - rotate: false - xy: 1267, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-power-void-small - rotate: false - xy: 1576, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-power-void-tiny - rotate: false - xy: 1907, 811 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-power-void-xlarge - rotate: false - xy: 301, 19 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pulse-conduit-large - rotate: false - xy: 737, 364 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pulse-conduit-medium - rotate: false - xy: 1233, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pulse-conduit-small - rotate: false - xy: 1602, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pulse-conduit-tiny - rotate: false - xy: 1925, 824 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pulse-conduit-xlarge - rotate: false - xy: 795, 878 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pulverizer-large - rotate: false - xy: 737, 322 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pulverizer-medium - rotate: false - xy: 1437, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pulverizer-small - rotate: false - xy: 1602, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pulverizer-tiny - rotate: false - xy: 1925, 806 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pulverizer-xlarge - rotate: false - xy: 309, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-pyratite-mixer-large - rotate: false - xy: 729, 280 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-pyratite-mixer-medium - rotate: false - xy: 1403, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-pyratite-mixer-small - rotate: false - xy: 1628, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-pyratite-mixer-tiny - rotate: false - xy: 1951, 860 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-pyratite-mixer-xlarge - rotate: false - xy: 309, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-repair-point-large - rotate: false - xy: 729, 238 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-repair-point-medium - rotate: false - xy: 1369, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-repair-point-small - rotate: false - xy: 1628, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-repair-point-tiny - rotate: false - xy: 1951, 842 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-repair-point-xlarge - rotate: false - xy: 359, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-ripple-large - rotate: false - xy: 729, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ripple-medium - rotate: false - xy: 1335, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ripple-small - rotate: false - xy: 1654, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ripple-tiny - rotate: false - xy: 1943, 824 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-ripple-xlarge - rotate: false - xy: 309, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-rock-large - rotate: false - xy: 729, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-rock-medium - rotate: false - xy: 1301, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-rock-small - rotate: false - xy: 1654, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-rock-tiny - rotate: false - xy: 1943, 806 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-rock-xlarge - rotate: false - xy: 359, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-rocks-large - rotate: false - xy: 729, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-rocks-medium - rotate: false - xy: 1267, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-rocks-small - rotate: false - xy: 1680, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-rocks-tiny - rotate: false - xy: 1813, 705 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-rocks-xlarge - rotate: false - xy: 409, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-rotary-pump-large - rotate: false - xy: 729, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-rotary-pump-medium - rotate: false - xy: 1471, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-rotary-pump-small - rotate: false - xy: 1680, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-rotary-pump-tiny - rotate: false - xy: 1831, 723 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-rotary-pump-xlarge - rotate: false - xy: 359, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-router-large - rotate: false - xy: 729, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-router-medium - rotate: false - xy: 1437, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-router-small - rotate: false - xy: 1706, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-router-tiny - rotate: false - xy: 1831, 705 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-router-xlarge - rotate: false - xy: 409, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-rtg-generator-large - rotate: false - xy: 795, 452 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-rtg-generator-medium - rotate: false - xy: 1403, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-rtg-generator-small - rotate: false - xy: 1706, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-rtg-generator-tiny - rotate: false - xy: 1857, 749 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-rtg-generator-xlarge - rotate: false - xy: 459, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-salt-large - rotate: false - xy: 837, 452 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-salt-medium - rotate: false - xy: 1369, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-salt-small - rotate: false - xy: 1732, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-salt-tiny - rotate: false - xy: 1849, 731 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-salt-xlarge - rotate: false - xy: 409, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-saltrocks-large - rotate: false - xy: 787, 406 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-saltrocks-medium - rotate: false - xy: 1335, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-saltrocks-small - rotate: false - xy: 1732, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-saltrocks-tiny - rotate: false - xy: 1849, 713 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-saltrocks-xlarge - rotate: false - xy: 459, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-salvo-large - rotate: false - xy: 779, 364 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-salvo-medium - rotate: false - xy: 1301, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-salvo-small - rotate: false - xy: 1758, 630 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-salvo-tiny - rotate: false - xy: 1961, 824 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-salvo-xlarge - rotate: false - xy: 509, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sand-boulder-large - rotate: false - xy: 779, 322 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sand-boulder-medium - rotate: false - xy: 1505, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sand-boulder-small - rotate: false - xy: 1758, 604 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sand-boulder-tiny - rotate: false - xy: 1961, 806 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sand-boulder-xlarge - rotate: false - xy: 459, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sand-large - rotate: false - xy: 771, 280 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sand-medium - rotate: false - xy: 1471, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sand-small - rotate: false - xy: 1472, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sand-tiny - rotate: false - xy: 1867, 731 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sand-water-large - rotate: false - xy: 771, 238 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sand-water-medium - rotate: false - xy: 1437, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sand-water-small - rotate: false - xy: 1498, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sand-water-tiny - rotate: false - xy: 1867, 713 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sand-water-xlarge - rotate: false - xy: 509, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sand-xlarge - rotate: false - xy: 559, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sandrocks-large - rotate: false - xy: 771, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sandrocks-medium - rotate: false - xy: 1403, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sandrocks-small - rotate: false - xy: 1524, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sandrocks-tiny - rotate: false - xy: 1849, 695 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sandrocks-xlarge - rotate: false - xy: 509, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scatter-large - rotate: false - xy: 771, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scatter-medium - rotate: false - xy: 1369, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scatter-small - rotate: false - xy: 1550, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scatter-tiny - rotate: false - xy: 1867, 695 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scatter-xlarge - rotate: false - xy: 559, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scorch-large - rotate: false - xy: 771, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scorch-medium - rotate: false - xy: 1335, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scorch-small - rotate: false - xy: 1576, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scorch-tiny - rotate: false - xy: 1777, 697 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scorch-xlarge - rotate: false - xy: 609, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scrap-wall-gigantic-large - rotate: false - xy: 771, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scrap-wall-gigantic-medium - rotate: false - xy: 1539, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scrap-wall-gigantic-small - rotate: false - xy: 1602, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scrap-wall-gigantic-tiny - rotate: false - xy: 1795, 697 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scrap-wall-gigantic-xlarge - rotate: false - xy: 559, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scrap-wall-huge-large - rotate: false - xy: 771, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scrap-wall-huge-medium - rotate: false - xy: 1505, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scrap-wall-huge-small - rotate: false - xy: 1628, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scrap-wall-huge-tiny - rotate: false - xy: 1772, 679 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scrap-wall-huge-xlarge - rotate: false - xy: 609, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scrap-wall-large - rotate: false - xy: 829, 410 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scrap-wall-large-large - rotate: false - xy: 879, 452 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-scrap-wall-large-medium - rotate: false - xy: 1471, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scrap-wall-large-small - rotate: false - xy: 1654, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scrap-wall-large-tiny - rotate: false - xy: 1772, 661 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scrap-wall-large-xlarge - rotate: false - xy: 659, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-scrap-wall-medium - rotate: false - xy: 1437, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-scrap-wall-small - rotate: false - xy: 1680, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-scrap-wall-tiny - rotate: false - xy: 1790, 679 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-scrap-wall-xlarge - rotate: false - xy: 609, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-separator-large - rotate: false - xy: 871, 410 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-separator-medium - rotate: false - xy: 1403, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-separator-small - rotate: false - xy: 1706, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-separator-tiny - rotate: false - xy: 1790, 661 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-separator-xlarge - rotate: false - xy: 659, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-shale-boulder-large - rotate: false - xy: 821, 364 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-shale-boulder-medium - rotate: false - xy: 1369, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-shale-boulder-small - rotate: false - xy: 1732, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-shale-boulder-tiny - rotate: false - xy: 1784, 643 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-shale-boulder-xlarge - rotate: false - xy: 709, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-shale-large - rotate: false - xy: 821, 322 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-shale-medium - rotate: false - xy: 1573, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-shale-small - rotate: false - xy: 1758, 578 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-shale-tiny - rotate: false - xy: 1784, 625 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-shale-xlarge - rotate: false - xy: 659, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-shalerocks-large - rotate: false - xy: 813, 280 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-shalerocks-medium - rotate: false - xy: 1539, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-shalerocks-small - rotate: false - xy: 1446, 566 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-shalerocks-tiny - rotate: false - xy: 1784, 607 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-shalerocks-xlarge - rotate: false - xy: 709, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-shock-mine-large - rotate: false - xy: 813, 238 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-shock-mine-medium - rotate: false - xy: 1505, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-shock-mine-small - rotate: false - xy: 1472, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-shock-mine-tiny - rotate: false - xy: 1784, 589 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-shock-mine-xlarge - rotate: false - xy: 709, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-shrubs-large - rotate: false - xy: 813, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-shrubs-medium - rotate: false - xy: 1471, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-shrubs-small - rotate: false - xy: 1498, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-shrubs-tiny - rotate: false - xy: 1784, 571 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-shrubs-xlarge - rotate: false - xy: 759, 816 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-silicon-smelter-large - rotate: false - xy: 813, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-silicon-smelter-medium - rotate: false - xy: 1437, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-silicon-smelter-small - rotate: false - xy: 1524, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-silicon-smelter-tiny - rotate: false - xy: 1784, 553 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-silicon-smelter-xlarge - rotate: false - xy: 759, 766 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-slag-large - rotate: false - xy: 813, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-slag-medium - rotate: false - xy: 1403, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-slag-small - rotate: false - xy: 1550, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-slag-tiny - rotate: false - xy: 1813, 687 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-slag-xlarge - rotate: false - xy: 759, 716 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-snow-large - rotate: false - xy: 813, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-snow-medium - rotate: false - xy: 1607, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-snow-pine-large - rotate: false - xy: 813, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-snow-pine-medium - rotate: false - xy: 1573, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-snow-pine-small - rotate: false - xy: 1576, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-snow-pine-tiny - rotate: false - xy: 1831, 687 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-snow-pine-xlarge - rotate: false - xy: 809, 828 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-snow-small - rotate: false - xy: 1602, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-snow-tiny - rotate: false - xy: 1808, 669 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-snow-xlarge - rotate: false - xy: 809, 778 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-snowrock-large - rotate: false - xy: 863, 368 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-snowrock-medium - rotate: false - xy: 1539, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-snowrock-small - rotate: false - xy: 1628, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-snowrock-tiny - rotate: false - xy: 1826, 669 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-snowrock-xlarge - rotate: false - xy: 809, 728 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-snowrocks-large - rotate: false - xy: 863, 326 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-snowrocks-medium - rotate: false - xy: 1505, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-snowrocks-small - rotate: false - xy: 1654, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-snowrocks-tiny - rotate: false - xy: 1849, 677 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-snowrocks-xlarge - rotate: false - xy: 809, 678 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-solar-panel-large - rotate: false - xy: 913, 410 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-solar-panel-large-large - rotate: false - xy: 905, 368 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-solar-panel-large-medium - rotate: false - xy: 1471, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-solar-panel-large-small - rotate: false - xy: 1680, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-solar-panel-large-tiny - rotate: false - xy: 1867, 677 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-solar-panel-large-xlarge - rotate: false - xy: 331, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-solar-panel-medium - rotate: false - xy: 1437, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-solar-panel-small - rotate: false - xy: 1706, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-solar-panel-tiny - rotate: false - xy: 1808, 651 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-solar-panel-xlarge - rotate: false - xy: 331, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sorter-large - rotate: false - xy: 905, 326 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sorter-medium - rotate: false - xy: 1641, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sorter-small - rotate: false - xy: 1732, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sorter-tiny - rotate: false - xy: 1826, 651 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sorter-xlarge - rotate: false - xy: 381, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spawn-large - rotate: false - xy: 855, 280 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spawn-medium - rotate: false - xy: 1607, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spawn-small - rotate: false - xy: 1758, 552 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spawn-tiny - rotate: false - xy: 1844, 659 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spawn-xlarge - rotate: false - xy: 381, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spectre-large - rotate: false - xy: 855, 238 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spectre-medium - rotate: false - xy: 1573, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spectre-small - rotate: false - xy: 1763, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spectre-tiny - rotate: false - xy: 1862, 659 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spectre-xlarge - rotate: false - xy: 431, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spore-cluster-large - rotate: false - xy: 855, 196 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spore-cluster-medium - rotate: false - xy: 1539, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spore-cluster-small - rotate: false - xy: 1789, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spore-cluster-tiny - rotate: false - xy: 1802, 633 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spore-cluster-xlarge - rotate: false - xy: 431, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spore-moss-large - rotate: false - xy: 855, 154 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spore-moss-medium - rotate: false - xy: 1505, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spore-moss-small - rotate: false - xy: 1815, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spore-moss-tiny - rotate: false - xy: 1802, 615 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spore-moss-xlarge - rotate: false - xy: 481, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spore-pine-large - rotate: false - xy: 855, 112 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spore-pine-medium - rotate: false - xy: 1471, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spore-pine-small - rotate: false - xy: 1841, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spore-pine-tiny - rotate: false - xy: 1820, 633 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spore-pine-xlarge - rotate: false - xy: 481, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-spore-press-large - rotate: false - xy: 855, 70 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-spore-press-medium - rotate: false - xy: 1675, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-spore-press-small - rotate: false - xy: 1867, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-spore-press-tiny - rotate: false - xy: 1802, 597 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-spore-press-xlarge - rotate: false - xy: 531, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-sporerocks-large - rotate: false - xy: 855, 28 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-sporerocks-medium - rotate: false - xy: 1641, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-sporerocks-small - rotate: false - xy: 1893, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-sporerocks-tiny - rotate: false - xy: 1820, 615 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-sporerocks-xlarge - rotate: false - xy: 531, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-stone-large - rotate: false - xy: 897, 284 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-stone-medium - rotate: false - xy: 1607, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-stone-small - rotate: false - xy: 1919, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-stone-tiny - rotate: false - xy: 1802, 579 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-stone-xlarge - rotate: false - xy: 581, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-surge-tower-large - rotate: false - xy: 897, 242 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-tower-medium - rotate: false - xy: 1573, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-surge-tower-small - rotate: false - xy: 1945, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-surge-tower-tiny - rotate: false - xy: 1820, 597 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-surge-tower-xlarge - rotate: false - xy: 581, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-surge-wall-large - rotate: false - xy: 897, 200 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-wall-large-large - rotate: false - xy: 897, 158 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-wall-large-medium - rotate: false - xy: 1539, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-surge-wall-large-small - rotate: false - xy: 1777, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-surge-wall-large-tiny - rotate: false - xy: 1802, 561 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-surge-wall-large-xlarge - rotate: false - xy: 631, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-surge-wall-medium - rotate: false - xy: 1505, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-surge-wall-small - rotate: false - xy: 1777, 863 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-surge-wall-tiny - rotate: false - xy: 1820, 579 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-surge-wall-xlarge - rotate: false - xy: 631, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-swarmer-large - rotate: false - xy: 897, 116 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-swarmer-medium - rotate: false - xy: 1709, 878 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-swarmer-small - rotate: false - xy: 1803, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-swarmer-tiny - rotate: false - xy: 1820, 561 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-swarmer-xlarge - rotate: false - xy: 681, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-tainted-water-large - rotate: false - xy: 897, 74 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-tainted-water-medium - rotate: false - xy: 1675, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-tainted-water-small - rotate: false - xy: 1777, 837 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-tainted-water-tiny - rotate: false - xy: 1844, 641 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-tainted-water-xlarge - rotate: false - xy: 681, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-tar-large - rotate: false - xy: 897, 32 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-tar-medium - rotate: false - xy: 1641, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-tar-small - rotate: false - xy: 1803, 863 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-tar-tiny - rotate: false - xy: 1862, 641 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-tar-xlarge - rotate: false - xy: 731, 666 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-tendrils-large - rotate: false - xy: 947, 368 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-tendrils-medium - rotate: false - xy: 1607, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-tendrils-small - rotate: false - xy: 1829, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-tendrils-tiny - rotate: false - xy: 1838, 623 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-tendrils-xlarge - rotate: false - xy: 731, 616 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thermal-generator-large - rotate: false - xy: 947, 326 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thermal-generator-medium - rotate: false - xy: 1573, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thermal-generator-small - rotate: false - xy: 1777, 811 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thermal-generator-tiny - rotate: false - xy: 1838, 605 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thermal-generator-xlarge - rotate: false - xy: 781, 628 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thermal-pump-large - rotate: false - xy: 939, 284 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thermal-pump-medium - rotate: false - xy: 1539, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thermal-pump-small - rotate: false - xy: 1803, 837 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thermal-pump-tiny - rotate: false - xy: 1856, 623 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thermal-pump-xlarge - rotate: false - xy: 831, 628 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thorium-reactor-large - rotate: false - xy: 939, 242 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thorium-reactor-medium - rotate: false - xy: 1709, 844 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thorium-reactor-small - rotate: false - xy: 1829, 863 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thorium-reactor-tiny - rotate: false - xy: 1838, 587 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thorium-reactor-xlarge - rotate: false - xy: 781, 578 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thorium-wall-large - rotate: false - xy: 939, 200 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thorium-wall-large-large - rotate: false - xy: 939, 158 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thorium-wall-large-medium - rotate: false - xy: 1675, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thorium-wall-large-small - rotate: false - xy: 1855, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thorium-wall-large-tiny - rotate: false - xy: 1856, 605 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thorium-wall-large-xlarge - rotate: false - xy: 831, 578 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thorium-wall-medium - rotate: false - xy: 1641, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thorium-wall-small - rotate: false - xy: 1777, 785 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thorium-wall-tiny - rotate: false - xy: 1838, 569 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thorium-wall-xlarge - rotate: false - xy: 351, 566 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-thruster-large - rotate: false - xy: 939, 116 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thruster-medium - rotate: false - xy: 1607, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-thruster-small - rotate: false - xy: 1803, 811 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-thruster-tiny - rotate: false - xy: 1856, 587 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-thruster-xlarge - rotate: false - xy: 351, 516 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-titanium-conveyor-large - rotate: false - xy: 939, 74 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-titanium-conveyor-medium - rotate: false - xy: 1573, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-titanium-conveyor-small - rotate: false - xy: 1829, 837 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-titanium-conveyor-tiny - rotate: false - xy: 1856, 569 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-titanium-conveyor-xlarge - rotate: false - xy: 401, 566 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-titanium-wall-large - rotate: false - xy: 939, 32 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-titanium-wall-large-large - rotate: false - xy: 981, 284 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-titanium-wall-large-medium - rotate: false - xy: 1709, 810 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-titanium-wall-large-small - rotate: false - xy: 1855, 863 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-titanium-wall-large-tiny - rotate: false - xy: 1802, 543 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-titanium-wall-large-xlarge - rotate: false - xy: 351, 466 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-titanium-wall-medium - rotate: false - xy: 1675, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-titanium-wall-small - rotate: false - xy: 1881, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-titanium-wall-tiny - rotate: false - xy: 1820, 543 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-titanium-wall-xlarge - rotate: false - xy: 401, 516 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-turbine-generator-large - rotate: false - xy: 981, 242 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-turbine-generator-medium - rotate: false - xy: 1641, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-turbine-generator-small - rotate: false - xy: 1777, 759 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-turbine-generator-tiny - rotate: false - xy: 1838, 551 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-turbine-generator-xlarge - rotate: false - xy: 451, 566 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-underflow-gate-large - rotate: false - xy: 981, 200 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-underflow-gate-medium - rotate: false - xy: 1607, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-underflow-gate-small - rotate: false - xy: 1803, 785 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-underflow-gate-tiny - rotate: false - xy: 1856, 551 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-underflow-gate-xlarge - rotate: false - xy: 351, 416 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-unloader-large - rotate: false - xy: 981, 158 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-unloader-medium - rotate: false - xy: 1709, 776 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-unloader-small - rotate: false - xy: 1829, 811 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-unloader-tiny - rotate: false - xy: 1784, 535 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-unloader-xlarge - rotate: false - xy: 401, 466 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-vault-large - rotate: false - xy: 981, 116 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-vault-medium - rotate: false - xy: 1675, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-vault-small - rotate: false - xy: 1855, 837 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-vault-tiny - rotate: false - xy: 1838, 533 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-vault-xlarge - rotate: false - xy: 451, 516 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-water-extractor-large - rotate: false - xy: 981, 74 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-water-extractor-medium - rotate: false - xy: 1641, 708 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-water-extractor-small - rotate: false - xy: 1881, 863 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-water-extractor-tiny - rotate: false - xy: 1856, 533 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-water-extractor-xlarge - rotate: false - xy: 501, 566 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-water-large - rotate: false - xy: 981, 32 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-water-medium - rotate: false - xy: 1709, 742 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-water-small - rotate: false - xy: 1907, 889 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-water-tiny - rotate: false - xy: 1802, 525 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-water-xlarge - rotate: false - xy: 351, 366 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-wave-large +block-multi-press-large rotate: false xy: 821, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-wave-medium +block-multi-press-medium rotate: false - xy: 1675, 708 + xy: 1755, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-wave-small +block-multi-press-small rotate: false - xy: 1777, 733 + xy: 1300, 508 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-wave-tiny +block-multi-press-tiny rotate: false - xy: 1820, 525 + xy: 1478, 456 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-wave-xlarge +block-multi-press-xlarge rotate: false - xy: 401, 416 + xy: 251, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-dead-large +block-oil-extractor-large rotate: false xy: 863, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-dead-medium +block-oil-extractor-medium rotate: false - xy: 1709, 708 + xy: 1789, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-dead-small +block-oil-extractor-small rotate: false - xy: 1803, 759 + xy: 1300, 482 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-dead-tiny +block-oil-extractor-tiny rotate: false - xy: 1838, 515 + xy: 1496, 474 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-dead-xlarge +block-oil-extractor-xlarge rotate: false - xy: 451, 466 + xy: 251, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-large +block-ore-coal-large rotate: false xy: 905, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-medium +block-ore-coal-medium rotate: false - xy: 1743, 878 + xy: 1823, 794 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-small +block-ore-coal-small rotate: false - xy: 1829, 785 + xy: 1300, 456 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-tiny +block-ore-coal-tiny rotate: false - xy: 1856, 515 + xy: 1514, 492 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-xlarge +block-ore-coal-xlarge + rotate: false + xy: 251, 308 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ore-copper-large + rotate: false + xy: 947, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ore-copper-medium + rotate: false + xy: 1857, 794 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ore-copper-small + rotate: false + xy: 1300, 430 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ore-copper-tiny + rotate: false + xy: 1442, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ore-copper-xlarge + rotate: false + xy: 251, 258 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ore-lead-large + rotate: false + xy: 989, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ore-lead-medium + rotate: false + xy: 1891, 794 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ore-lead-small + rotate: false + xy: 1300, 404 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ore-lead-tiny + rotate: false + xy: 1460, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ore-lead-xlarge + rotate: false + xy: 251, 208 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ore-scrap-large + rotate: false + xy: 1031, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ore-scrap-medium + rotate: false + xy: 1925, 794 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ore-scrap-small + rotate: false + xy: 1153, 396 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ore-scrap-tiny + rotate: false + xy: 1478, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ore-scrap-xlarge + rotate: false + xy: 251, 158 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ore-thorium-large + rotate: false + xy: 1073, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ore-thorium-medium + rotate: false + xy: 1959, 794 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ore-thorium-small + rotate: false + xy: 1179, 396 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ore-thorium-tiny + rotate: false + xy: 1496, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ore-thorium-xlarge + rotate: false + xy: 251, 108 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ore-titanium-large + rotate: false + xy: 1115, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ore-titanium-medium + rotate: false + xy: 1993, 797 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ore-titanium-small + rotate: false + xy: 1153, 370 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ore-titanium-tiny + rotate: false + xy: 1514, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ore-titanium-xlarge + rotate: false + xy: 251, 58 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-overdrive-projector-large + rotate: false + xy: 1157, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-overdrive-projector-medium + rotate: false + xy: 2009, 831 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-overdrive-projector-small + rotate: false + xy: 1205, 396 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-overdrive-projector-tiny + rotate: false + xy: 1532, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-overdrive-projector-xlarge + rotate: false + xy: 151, 8 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-overflow-gate-large + rotate: false + xy: 1199, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-overflow-gate-medium + rotate: false + xy: 1381, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-overflow-gate-small + rotate: false + xy: 1153, 344 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-overflow-gate-tiny + rotate: false + xy: 1460, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-overflow-gate-xlarge + rotate: false + xy: 201, 8 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-payload-router-large + rotate: false + xy: 1241, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-payload-router-medium + rotate: false + xy: 1415, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-payload-router-small + rotate: false + xy: 1179, 370 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-payload-router-tiny + rotate: false + xy: 1478, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-payload-router-xlarge + rotate: false + xy: 251, 8 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pebbles-large + rotate: false + xy: 1283, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pebbles-medium + rotate: false + xy: 1449, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pebbles-small + rotate: false + xy: 1179, 344 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pebbles-tiny + rotate: false + xy: 1496, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pebbles-xlarge + rotate: false + xy: 281, 619 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-phase-conduit-large + rotate: false + xy: 1325, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-phase-conduit-medium + rotate: false + xy: 1483, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-phase-conduit-small + rotate: false + xy: 1205, 370 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-phase-conduit-tiny + rotate: false + xy: 1514, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-phase-conduit-xlarge + rotate: false + xy: 281, 569 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-phase-conveyor-large + rotate: false + xy: 1367, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-phase-conveyor-medium + rotate: false + xy: 1517, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-phase-conveyor-small + rotate: false + xy: 1205, 344 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-phase-conveyor-tiny + rotate: false + xy: 1532, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-phase-conveyor-xlarge + rotate: false + xy: 301, 519 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-phase-wall-large + rotate: false + xy: 1409, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-phase-wall-large-large + rotate: false + xy: 1451, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-phase-wall-large-medium + rotate: false + xy: 1551, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-phase-wall-large-small + rotate: false + xy: 1231, 386 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-phase-wall-large-tiny + rotate: false + xy: 1550, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-phase-wall-large-xlarge + rotate: false + xy: 301, 469 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-phase-wall-medium + rotate: false + xy: 1585, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-phase-wall-small + rotate: false + xy: 1231, 360 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-phase-wall-tiny + rotate: false + xy: 1478, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-phase-wall-xlarge + rotate: false + xy: 301, 419 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-phase-weaver-large + rotate: false + xy: 1493, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-phase-weaver-medium + rotate: false + xy: 1619, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-phase-weaver-small + rotate: false + xy: 1163, 318 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-phase-weaver-tiny + rotate: false + xy: 1496, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-phase-weaver-xlarge + rotate: false + xy: 301, 369 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pine-large + rotate: false + xy: 1535, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pine-medium + rotate: false + xy: 1653, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pine-small + rotate: false + xy: 1163, 292 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pine-tiny + rotate: false + xy: 1514, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pine-xlarge + rotate: false + xy: 301, 319 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-plastanium-compressor-large + rotate: false + xy: 1577, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-plastanium-compressor-medium + rotate: false + xy: 1687, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-plastanium-compressor-small + rotate: false + xy: 1189, 318 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-plastanium-compressor-tiny + rotate: false + xy: 1532, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-plastanium-compressor-xlarge + rotate: false + xy: 301, 269 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-plastanium-conveyor-large + rotate: false + xy: 1619, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-plastanium-conveyor-medium + rotate: false + xy: 1721, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-plastanium-conveyor-small + rotate: false + xy: 1189, 292 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-plastanium-conveyor-tiny + rotate: false + xy: 1550, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-plastanium-conveyor-xlarge + rotate: false + xy: 301, 219 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-plastanium-wall-large + rotate: false + xy: 1661, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-plastanium-wall-large-large + rotate: false + xy: 1703, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-plastanium-wall-large-medium + rotate: false + xy: 1755, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-plastanium-wall-large-small + rotate: false + xy: 1231, 334 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-plastanium-wall-large-tiny + rotate: false + xy: 1568, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-plastanium-wall-large-xlarge + rotate: false + xy: 301, 169 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-plastanium-wall-medium + rotate: false + xy: 1789, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-plastanium-wall-small + rotate: false + xy: 1215, 308 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-plastanium-wall-tiny + rotate: false + xy: 1496, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-plastanium-wall-xlarge + rotate: false + xy: 301, 119 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-plated-conduit-large + rotate: false + xy: 1745, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-plated-conduit-medium + rotate: false + xy: 1823, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-plated-conduit-small + rotate: false + xy: 1215, 282 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-plated-conduit-tiny + rotate: false + xy: 1514, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-plated-conduit-xlarge + rotate: false + xy: 301, 69 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pneumatic-drill-large + rotate: false + xy: 1787, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pneumatic-drill-medium + rotate: false + xy: 1857, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pneumatic-drill-small + rotate: false + xy: 1241, 308 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pneumatic-drill-tiny + rotate: false + xy: 1532, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pneumatic-drill-xlarge + rotate: false + xy: 301, 19 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-power-node-large + rotate: false + xy: 1829, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-power-node-large-large + rotate: false + xy: 1871, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-power-node-large-medium + rotate: false + xy: 1891, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-power-node-large-small + rotate: false + xy: 1241, 282 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-power-node-large-tiny + rotate: false + xy: 1550, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-power-node-large-xlarge + rotate: false + xy: 795, 878 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-power-node-medium + rotate: false + xy: 1925, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-power-node-small + rotate: false + xy: 1329, 594 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-power-node-tiny + rotate: false + xy: 1568, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-power-node-xlarge + rotate: false + xy: 309, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-power-source-large + rotate: false + xy: 1913, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-power-source-medium + rotate: false + xy: 1959, 760 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-power-source-small + rotate: false + xy: 1329, 568 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-power-source-tiny + rotate: false + xy: 1586, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-power-source-xlarge + rotate: false + xy: 309, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-power-void-large + rotate: false + xy: 1955, 933 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-power-void-medium + rotate: false + xy: 1993, 763 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-power-void-small + rotate: false + xy: 1329, 542 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-power-void-tiny + rotate: false + xy: 1514, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-power-void-xlarge + rotate: false + xy: 359, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pulse-conduit-large + rotate: false + xy: 845, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pulse-conduit-medium + rotate: false + xy: 1167, 558 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pulse-conduit-small + rotate: false + xy: 1329, 516 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pulse-conduit-tiny + rotate: false + xy: 1532, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pulse-conduit-xlarge + rotate: false + xy: 309, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pulverizer-large + rotate: false + xy: 887, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pulverizer-medium + rotate: false + xy: 1167, 524 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pulverizer-small + rotate: false + xy: 1326, 490 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pulverizer-tiny + rotate: false + xy: 1550, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pulverizer-xlarge + rotate: false + xy: 359, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-pyratite-mixer-large + rotate: false + xy: 929, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-pyratite-mixer-medium + rotate: false + xy: 1167, 490 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-pyratite-mixer-small + rotate: false + xy: 1326, 464 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-pyratite-mixer-tiny + rotate: false + xy: 1568, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-pyratite-mixer-xlarge + rotate: false + xy: 409, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-repair-point-large + rotate: false + xy: 971, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-repair-point-medium + rotate: false + xy: 1167, 456 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-repair-point-small + rotate: false + xy: 1326, 438 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-repair-point-tiny + rotate: false + xy: 1586, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-repair-point-xlarge + rotate: false + xy: 359, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-ripple-large + rotate: false + xy: 1013, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ripple-medium + rotate: false + xy: 1167, 422 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ripple-small + rotate: false + xy: 1326, 412 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ripple-tiny + rotate: false + xy: 1604, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-ripple-xlarge + rotate: false + xy: 409, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-rock-large + rotate: false + xy: 1055, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-rock-medium + rotate: false + xy: 871, 292 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-rock-small + rotate: false + xy: 1326, 386 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-rock-tiny + rotate: false + xy: 1532, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-rock-xlarge + rotate: false + xy: 459, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-rocks-large + rotate: false + xy: 1097, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-rocks-medium + rotate: false + xy: 905, 292 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-rocks-small + rotate: false + xy: 2000, 601 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-rocks-tiny + rotate: false + xy: 1550, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-rocks-xlarge + rotate: false + xy: 409, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-rotary-pump-large + rotate: false + xy: 1139, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-rotary-pump-medium + rotate: false + xy: 939, 292 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-rotary-pump-small + rotate: false + xy: 1163, 266 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-rotary-pump-tiny + rotate: false + xy: 1568, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-rotary-pump-xlarge + rotate: false + xy: 459, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-router-large + rotate: false + xy: 1181, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-router-medium + rotate: false + xy: 973, 292 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-router-small + rotate: false + xy: 1189, 266 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-router-tiny + rotate: false + xy: 1586, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-router-xlarge + rotate: false + xy: 509, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-rtg-generator-large + rotate: false + xy: 1223, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-rtg-generator-medium + rotate: false + xy: 1233, 710 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-rtg-generator-small + rotate: false + xy: 1215, 256 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-rtg-generator-tiny + rotate: false + xy: 1604, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-rtg-generator-xlarge + rotate: false + xy: 459, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-salt-large + rotate: false + xy: 1265, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-salt-medium + rotate: false + xy: 1275, 752 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-salt-small + rotate: false + xy: 1241, 256 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-salt-tiny + rotate: false + xy: 1622, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-salt-xlarge + rotate: false + xy: 509, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-saltrocks-large + rotate: false + xy: 1307, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-saltrocks-medium + rotate: false + xy: 1309, 752 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-saltrocks-small + rotate: false + xy: 1355, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-saltrocks-tiny + rotate: false + xy: 1550, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-saltrocks-xlarge + rotate: false + xy: 559, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-salvo-large + rotate: false + xy: 1349, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-salvo-medium + rotate: false + xy: 1343, 752 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-salvo-small + rotate: false + xy: 1355, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-salvo-tiny + rotate: false + xy: 1568, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-salvo-xlarge + rotate: false + xy: 509, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sand-boulder-large + rotate: false + xy: 1391, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sand-boulder-medium + rotate: false + xy: 1187, 660 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sand-boulder-small + rotate: false + xy: 1381, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sand-boulder-tiny + rotate: false + xy: 1586, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sand-boulder-xlarge + rotate: false + xy: 559, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sand-large + rotate: false + xy: 1433, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sand-medium + rotate: false + xy: 1187, 626 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sand-small + rotate: false + xy: 1355, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sand-tiny + rotate: false + xy: 1604, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sand-water-large + rotate: false + xy: 1475, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sand-water-medium + rotate: false + xy: 1187, 592 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sand-water-small + rotate: false + xy: 1381, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sand-water-tiny + rotate: false + xy: 1622, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sand-water-xlarge + rotate: false + xy: 609, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sand-xlarge + rotate: false + xy: 559, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sandrocks-large + rotate: false + xy: 1517, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sandrocks-medium + rotate: false + xy: 1201, 558 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sandrocks-small + rotate: false + xy: 1407, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sandrocks-tiny + rotate: false + xy: 1640, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sandrocks-xlarge + rotate: false + xy: 609, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scatter-large + rotate: false + xy: 1559, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scatter-medium + rotate: false + xy: 1201, 524 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scatter-small + rotate: false + xy: 1381, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scatter-tiny + rotate: false + xy: 1568, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scatter-xlarge + rotate: false + xy: 659, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scorch-large + rotate: false + xy: 1601, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scorch-medium + rotate: false + xy: 1201, 490 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scorch-small + rotate: false + xy: 1407, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scorch-tiny + rotate: false + xy: 1586, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scorch-xlarge + rotate: false + xy: 609, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scrap-wall-gigantic-large + rotate: false + xy: 1643, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scrap-wall-gigantic-medium + rotate: false + xy: 1201, 456 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scrap-wall-gigantic-small + rotate: false + xy: 1433, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scrap-wall-gigantic-tiny + rotate: false + xy: 1604, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scrap-wall-gigantic-xlarge + rotate: false + xy: 659, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scrap-wall-huge-large + rotate: false + xy: 1685, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scrap-wall-huge-medium + rotate: false + xy: 1201, 422 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scrap-wall-huge-small + rotate: false + xy: 1407, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scrap-wall-huge-tiny + rotate: false + xy: 1622, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scrap-wall-huge-xlarge + rotate: false + xy: 709, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scrap-wall-large + rotate: false + xy: 1727, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scrap-wall-large-large + rotate: false + xy: 1769, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-scrap-wall-large-medium + rotate: false + xy: 1267, 710 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scrap-wall-large-small + rotate: false + xy: 1433, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scrap-wall-large-tiny + rotate: false + xy: 1640, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scrap-wall-large-xlarge + rotate: false + xy: 659, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-scrap-wall-medium + rotate: false + xy: 1301, 718 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-scrap-wall-small + rotate: false + xy: 1459, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-scrap-wall-tiny + rotate: false + xy: 1658, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-scrap-wall-xlarge + rotate: false + xy: 709, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-segment-large + rotate: false + xy: 1811, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-segment-medium + rotate: false + xy: 1335, 718 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-segment-small + rotate: false + xy: 1433, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-segment-tiny + rotate: false + xy: 1586, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-segment-xlarge + rotate: false + xy: 709, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-separator-large + rotate: false + xy: 1853, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-separator-medium + rotate: false + xy: 1301, 684 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-separator-small + rotate: false + xy: 1459, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-separator-tiny + rotate: false + xy: 1604, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-separator-xlarge + rotate: false + xy: 759, 816 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-shale-boulder-large + rotate: false + xy: 1895, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-shale-boulder-medium + rotate: false + xy: 1335, 684 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-shale-boulder-small + rotate: false + xy: 1485, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-shale-boulder-tiny + rotate: false + xy: 1622, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-shale-boulder-xlarge + rotate: false + xy: 759, 766 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-shale-large + rotate: false + xy: 1937, 891 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-shale-medium + rotate: false + xy: 1369, 718 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-shale-small + rotate: false + xy: 1459, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-shale-tiny + rotate: false + xy: 1640, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-shale-xlarge + rotate: false + xy: 759, 716 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-shalerocks-large + rotate: false + xy: 859, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-shalerocks-medium + rotate: false + xy: 1369, 684 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-shalerocks-small + rotate: false + xy: 1485, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-shalerocks-tiny + rotate: false + xy: 1658, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-shalerocks-xlarge + rotate: false + xy: 809, 828 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-shock-mine-large + rotate: false + xy: 859, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-shock-mine-medium + rotate: false + xy: 1403, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-shock-mine-small + rotate: false + xy: 1511, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-shock-mine-tiny + rotate: false + xy: 1676, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-shock-mine-xlarge + rotate: false + xy: 809, 778 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-shrubs-large + rotate: false + xy: 901, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-shrubs-medium + rotate: false + xy: 1403, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-shrubs-small + rotate: false + xy: 1485, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-shrubs-tiny + rotate: false + xy: 1604, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-shrubs-xlarge + rotate: false + xy: 809, 728 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-silicon-crucible-large + rotate: false + xy: 859, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-silicon-crucible-medium + rotate: false + xy: 1437, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-silicon-crucible-small + rotate: false + xy: 1511, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-silicon-crucible-tiny + rotate: false + xy: 1622, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-silicon-crucible-xlarge + rotate: false + xy: 809, 678 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-silicon-smelter-large + rotate: false + xy: 943, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-silicon-smelter-medium + rotate: false + xy: 1437, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-silicon-smelter-small + rotate: false + xy: 1537, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-silicon-smelter-tiny + rotate: false + xy: 1640, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-silicon-smelter-xlarge + rotate: false + xy: 331, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-slag-large + rotate: false + xy: 901, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-slag-medium + rotate: false + xy: 1471, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-slag-small + rotate: false + xy: 1511, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-slag-tiny + rotate: false + xy: 1658, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-slag-xlarge + rotate: false + xy: 331, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-snow-large + rotate: false + xy: 859, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-snow-medium + rotate: false + xy: 1471, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-snow-pine-large + rotate: false + xy: 985, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-snow-pine-medium + rotate: false + xy: 1505, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-snow-pine-small + rotate: false + xy: 1537, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-snow-pine-tiny + rotate: false + xy: 1676, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-snow-pine-xlarge + rotate: false + xy: 381, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-snow-small + rotate: false + xy: 1563, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-snow-tiny + rotate: false + xy: 1694, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-snow-xlarge + rotate: false + xy: 381, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-snowrock-large + rotate: false + xy: 943, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-snowrock-medium + rotate: false + xy: 1505, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-snowrock-small + rotate: false + xy: 1537, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-snowrock-tiny + rotate: false + xy: 1622, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-snowrock-xlarge + rotate: false + xy: 431, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-snowrocks-large + rotate: false + xy: 901, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-snowrocks-medium + rotate: false + xy: 1539, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-snowrocks-small + rotate: false + xy: 1563, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-snowrocks-tiny + rotate: false + xy: 1640, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-snowrocks-xlarge + rotate: false + xy: 431, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-solar-panel-large + rotate: false + xy: 859, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-solar-panel-large-large + rotate: false + xy: 1027, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-solar-panel-large-medium + rotate: false + xy: 1539, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-solar-panel-large-small + rotate: false + xy: 1589, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-solar-panel-large-tiny + rotate: false + xy: 1658, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-solar-panel-large-xlarge + rotate: false + xy: 481, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-solar-panel-medium + rotate: false + xy: 1573, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-solar-panel-small + rotate: false + xy: 1563, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-solar-panel-tiny + rotate: false + xy: 1676, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-solar-panel-xlarge + rotate: false + xy: 481, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sorter-large + rotate: false + xy: 985, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sorter-medium + rotate: false + xy: 1573, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sorter-small + rotate: false + xy: 1589, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sorter-tiny + rotate: false + xy: 1694, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sorter-xlarge + rotate: false + xy: 531, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spawn-large + rotate: false + xy: 943, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spawn-medium + rotate: false + xy: 1607, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spawn-small + rotate: false + xy: 1615, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spawn-tiny + rotate: false + xy: 1712, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spawn-xlarge + rotate: false + xy: 531, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spectre-large + rotate: false + xy: 901, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spectre-medium + rotate: false + xy: 1607, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spectre-small + rotate: false + xy: 1589, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spectre-tiny + rotate: false + xy: 1640, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spectre-xlarge + rotate: false + xy: 581, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spore-cluster-large + rotate: false + xy: 1069, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spore-cluster-medium + rotate: false + xy: 1641, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spore-cluster-small + rotate: false + xy: 1615, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spore-cluster-tiny + rotate: false + xy: 1658, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spore-cluster-xlarge + rotate: false + xy: 581, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spore-moss-large + rotate: false + xy: 1027, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spore-moss-medium + rotate: false + xy: 1641, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spore-moss-small + rotate: false + xy: 1641, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spore-moss-tiny + rotate: false + xy: 1676, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spore-moss-xlarge + rotate: false + xy: 631, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spore-pine-large + rotate: false + xy: 985, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spore-pine-medium + rotate: false + xy: 1675, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spore-pine-small + rotate: false + xy: 1615, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spore-pine-tiny + rotate: false + xy: 1694, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spore-pine-xlarge + rotate: false + xy: 631, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-spore-press-large + rotate: false + xy: 943, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-spore-press-medium + rotate: false + xy: 1675, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-spore-press-small + rotate: false + xy: 1641, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-spore-press-tiny + rotate: false + xy: 1712, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-spore-press-xlarge + rotate: false + xy: 681, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-sporerocks-large + rotate: false + xy: 901, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-sporerocks-medium + rotate: false + xy: 1709, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-sporerocks-small + rotate: false + xy: 1667, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-sporerocks-tiny + rotate: false + xy: 1730, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-sporerocks-xlarge + rotate: false + xy: 681, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-stone-large + rotate: false + xy: 1111, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-stone-medium + rotate: false + xy: 1709, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-stone-small + rotate: false + xy: 1641, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-stone-tiny + rotate: false + xy: 1658, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-stone-xlarge + rotate: false + xy: 731, 666 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-surge-tower-large + rotate: false + xy: 1069, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-tower-medium + rotate: false + xy: 1743, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-surge-tower-small + rotate: false + xy: 1667, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-surge-tower-tiny + rotate: false + xy: 1676, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-surge-tower-xlarge + rotate: false + xy: 731, 616 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-surge-wall-large + rotate: false + xy: 1027, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-large + rotate: false + xy: 985, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-medium + rotate: false + xy: 1743, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-surge-wall-large-small + rotate: false + xy: 1693, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-surge-wall-large-tiny + rotate: false + xy: 1694, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-surge-wall-large-xlarge + rotate: false + xy: 781, 628 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-surge-wall-medium + rotate: false + xy: 1777, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-surge-wall-small + rotate: false + xy: 1667, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-surge-wall-tiny + rotate: false + xy: 1712, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-surge-wall-xlarge + rotate: false + xy: 831, 628 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-swarmer-large + rotate: false + xy: 943, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-swarmer-medium + rotate: false + xy: 1777, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-swarmer-small + rotate: false + xy: 1693, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-swarmer-tiny + rotate: false + xy: 1730, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-swarmer-xlarge + rotate: false + xy: 781, 578 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-tainted-water-large + rotate: false + xy: 1153, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-tainted-water-medium + rotate: false + xy: 1811, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-tainted-water-small + rotate: false + xy: 1719, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-tainted-water-tiny + rotate: false + xy: 1748, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-tainted-water-xlarge + rotate: false + xy: 831, 578 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-tar-large + rotate: false + xy: 1111, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-tar-medium + rotate: false + xy: 1811, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-tar-small + rotate: false + xy: 1693, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-tar-tiny + rotate: false + xy: 1676, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-tar-xlarge + rotate: false + xy: 351, 566 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-tendrils-large + rotate: false + xy: 1069, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-tendrils-medium + rotate: false + xy: 1845, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-tendrils-small + rotate: false + xy: 1719, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-tendrils-tiny + rotate: false + xy: 1694, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-tendrils-xlarge + rotate: false + xy: 351, 516 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thermal-generator-large + rotate: false + xy: 1027, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thermal-generator-medium + rotate: false + xy: 1845, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thermal-generator-small + rotate: false + xy: 1745, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thermal-generator-tiny + rotate: false + xy: 1712, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thermal-generator-xlarge + rotate: false + xy: 401, 566 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thermal-pump-large + rotate: false + xy: 985, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thermal-pump-medium + rotate: false + xy: 1879, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thermal-pump-small + rotate: false + xy: 1719, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thermal-pump-tiny + rotate: false + xy: 1730, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thermal-pump-xlarge + rotate: false + xy: 351, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thorium-reactor-large + rotate: false + xy: 1195, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-reactor-medium + rotate: false + xy: 1879, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thorium-reactor-small + rotate: false + xy: 1745, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thorium-reactor-tiny + rotate: false + xy: 1748, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thorium-reactor-xlarge + rotate: false + xy: 401, 516 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thorium-wall-large + rotate: false + xy: 1153, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-large + rotate: false + xy: 1111, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-medium + rotate: false + xy: 1913, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thorium-wall-large-small + rotate: false + xy: 1771, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thorium-wall-large-tiny + rotate: false + xy: 1766, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thorium-wall-large-xlarge + rotate: false + xy: 451, 566 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thorium-wall-medium + rotate: false + xy: 1913, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thorium-wall-small + rotate: false + xy: 1745, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thorium-wall-tiny + rotate: false + xy: 1694, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thorium-wall-xlarge + rotate: false + xy: 351, 416 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-thruster-large + rotate: false + xy: 1069, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thruster-medium + rotate: false + xy: 1947, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-thruster-small + rotate: false + xy: 1771, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-thruster-tiny + rotate: false + xy: 1712, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-thruster-xlarge + rotate: false + xy: 401, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-titanium-conveyor-large + rotate: false + xy: 1027, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-conveyor-medium + rotate: false + xy: 1947, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-titanium-conveyor-small + rotate: false + xy: 1797, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-titanium-conveyor-tiny + rotate: false + xy: 1730, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-titanium-conveyor-xlarge + rotate: false + xy: 451, 516 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-titanium-wall-large + rotate: false + xy: 1237, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-large + rotate: false + xy: 1195, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-medium + rotate: false + xy: 1981, 726 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-titanium-wall-large-small + rotate: false + xy: 1771, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-titanium-wall-large-tiny + rotate: false + xy: 1748, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-titanium-wall-large-xlarge + rotate: false + xy: 501, 566 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-titanium-wall-medium + rotate: false + xy: 2015, 729 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-titanium-wall-small + rotate: false + xy: 1797, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-titanium-wall-tiny + rotate: false + xy: 1766, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-titanium-wall-xlarge + rotate: false + xy: 351, 366 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-turbine-generator-large + rotate: false + xy: 1153, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-turbine-generator-medium + rotate: false + xy: 2015, 695 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-turbine-generator-small + rotate: false + xy: 1823, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-turbine-generator-tiny + rotate: false + xy: 1784, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-turbine-generator-xlarge + rotate: false + xy: 401, 416 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-underflow-gate-large + rotate: false + xy: 1111, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-underflow-gate-medium + rotate: false + xy: 1981, 692 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-underflow-gate-small + rotate: false + xy: 1797, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-underflow-gate-tiny + rotate: false + xy: 1712, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-underflow-gate-xlarge + rotate: false + xy: 451, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-unloader-large + rotate: false + xy: 1069, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-unloader-medium + rotate: false + xy: 2015, 661 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-unloader-small + rotate: false + xy: 1823, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-unloader-tiny + rotate: false + xy: 1730, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-unloader-xlarge rotate: false xy: 501, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 +block-vault-large + rotate: false + xy: 1279, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-vault-medium + rotate: false + xy: 1403, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-vault-small + rotate: false + xy: 1849, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-vault-tiny + rotate: false + xy: 1748, 438 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-vault-xlarge + rotate: false + xy: 551, 566 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-water-extractor-large + rotate: false + xy: 1237, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-water-extractor-medium + rotate: false + xy: 1437, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-water-extractor-small + rotate: false + xy: 1823, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-water-extractor-tiny + rotate: false + xy: 1766, 456 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-water-extractor-xlarge + rotate: false + xy: 351, 316 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-water-large + rotate: false + xy: 1195, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-water-medium + rotate: false + xy: 1471, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-water-small + rotate: false + xy: 1849, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-water-tiny + rotate: false + xy: 1784, 474 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-water-xlarge + rotate: false + xy: 401, 366 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-wave-large + rotate: false + xy: 1153, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-wave-medium + rotate: false + xy: 1505, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-wave-small + rotate: false + xy: 1875, 580 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-wave-tiny + rotate: false + xy: 1802, 492 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-wave-xlarge + rotate: false + xy: 451, 416 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-white-tree-dead-large + rotate: false + xy: 1111, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-white-tree-dead-medium + rotate: false + xy: 1539, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-white-tree-dead-small + rotate: false + xy: 1849, 528 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-white-tree-dead-tiny + rotate: false + xy: 1730, 402 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-white-tree-dead-xlarge + rotate: false + xy: 501, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-white-tree-large + rotate: false + xy: 1321, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-white-tree-medium + rotate: false + xy: 1573, 658 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-white-tree-small + rotate: false + xy: 1875, 554 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-white-tree-tiny + rotate: false + xy: 1748, 420 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-white-tree-xlarge + rotate: false + xy: 551, 516 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 button rotate: false - xy: 1479, 946 + xy: 1667, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15636,7 +15979,7 @@ button index: -1 button-disabled rotate: false - xy: 351, 1 + xy: 435, 1 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15644,7 +15987,7 @@ button-disabled index: -1 button-down rotate: false - xy: 389, 1 + xy: 473, 1 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15652,7 +15995,7 @@ button-down index: -1 button-edge-1 rotate: false - xy: 947, 946 + xy: 511, 1 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15660,7 +16003,7 @@ button-edge-1 index: -1 button-edge-2 rotate: false - xy: 985, 946 + xy: 1279, 820 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15668,7 +16011,7 @@ button-edge-2 index: -1 button-edge-3 rotate: false - xy: 1023, 946 + xy: 1237, 778 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15676,7 +16019,7 @@ button-edge-3 index: -1 button-edge-4 rotate: false - xy: 1061, 946 + xy: 1195, 736 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15684,7 +16027,7 @@ button-edge-4 index: -1 button-edge-over-4 rotate: false - xy: 1099, 946 + xy: 1153, 694 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15692,7 +16035,7 @@ button-edge-over-4 index: -1 button-over rotate: false - xy: 1137, 946 + xy: 1363, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15700,7 +16043,7 @@ button-over index: -1 button-red rotate: false - xy: 1175, 946 + xy: 1317, 820 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15708,7 +16051,7 @@ button-red index: -1 button-right rotate: false - xy: 1289, 946 + xy: 1477, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15716,7 +16059,7 @@ button-right index: -1 button-right-down rotate: false - xy: 1213, 946 + xy: 1401, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15724,7 +16067,7 @@ button-right-down index: -1 button-right-over rotate: false - xy: 1251, 946 + xy: 1439, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15732,7 +16075,7 @@ button-right-over index: -1 button-select rotate: false - xy: 1855, 811 + xy: 1901, 580 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 @@ -15740,7 +16083,7 @@ button-select index: -1 button-square rotate: false - xy: 1403, 946 + xy: 1591, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15748,7 +16091,7 @@ button-square index: -1 button-square-down rotate: false - xy: 1327, 946 + xy: 1515, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15756,7 +16099,7 @@ button-square-down index: -1 button-square-over rotate: false - xy: 1365, 946 + xy: 1553, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15764,7 +16107,7 @@ button-square-over index: -1 button-trans rotate: false - xy: 1441, 946 + xy: 1629, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15772,42 +16115,42 @@ button-trans index: -1 check-disabled rotate: false - xy: 1743, 844 + xy: 1607, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-off rotate: false - xy: 1743, 810 + xy: 1641, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on rotate: false - xy: 1743, 776 + xy: 1675, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-disabled rotate: false - xy: 1743, 742 + xy: 1709, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-over rotate: false - xy: 1743, 708 + xy: 1743, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-over rotate: false - xy: 881, 661 + xy: 1777, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -15828,7 +16171,7 @@ crater index: -1 cursor rotate: false - xy: 881, 587 + xy: 259, 663 size: 4, 4 orig: 4, 4 offset: 0, 0 @@ -15842,7 +16185,7 @@ discord-banner index: -1 flat-down-base rotate: false - xy: 1517, 946 + xy: 1705, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -15857,7 +16200,7 @@ info-banner index: -1 inventory rotate: false - xy: 1881, 821 + xy: 1875, 512 size: 24, 40 split: 10, 10, 10, 14 orig: 24, 40 @@ -15865,140 +16208,140 @@ inventory index: -1 item-blast-compound-icon rotate: false - xy: 881, 627 + xy: 1811, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-icon rotate: false - xy: 915, 661 + xy: 1845, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-icon rotate: false - xy: 881, 593 + xy: 1879, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-icon rotate: false - xy: 915, 627 + xy: 1913, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-icon rotate: false - xy: 915, 593 + xy: 1947, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-icon rotate: false - xy: 887, 559 + xy: 1981, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-icon rotate: false - xy: 887, 525 + xy: 2015, 627 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-icon rotate: false - xy: 921, 559 + xy: 1229, 676 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-icon rotate: false - xy: 921, 525 + xy: 1263, 676 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-icon rotate: false - xy: 961, 674 + xy: 1221, 642 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-icon rotate: false - xy: 995, 674 + xy: 1221, 608 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-icon rotate: false - xy: 1029, 674 + xy: 1255, 642 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-icon rotate: false - xy: 1063, 674 + xy: 1255, 608 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-icon rotate: false - xy: 1097, 674 + xy: 1235, 574 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-icon rotate: false - xy: 1131, 674 + xy: 1235, 540 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-icon rotate: false - xy: 1165, 674 + xy: 1235, 506 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-icon rotate: false - xy: 1199, 674 + xy: 1235, 472 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-icon rotate: false - xy: 1233, 674 + xy: 1235, 438 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-icon rotate: false - xy: 1267, 674 + xy: 1269, 574 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-icon rotate: false - xy: 1301, 674 + xy: 1269, 540 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -16019,7 +16362,7 @@ nomap index: -1 pane rotate: false - xy: 1593, 946 + xy: 1781, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16027,7 +16370,7 @@ pane index: -1 pane-2 rotate: false - xy: 1555, 946 + xy: 1743, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16035,7 +16378,7 @@ pane-2 index: -1 scroll rotate: false - xy: 1933, 878 + xy: 1927, 569 size: 24, 35 split: 10, 10, 6, 5 orig: 24, 35 @@ -16043,7 +16386,7 @@ scroll index: -1 scroll-horizontal rotate: false - xy: 1, 2 + xy: 43, 2 size: 35, 24 split: 6, 5, 10, 10 orig: 35, 24 @@ -16051,21 +16394,21 @@ scroll-horizontal index: -1 scroll-knob-horizontal-black rotate: false - xy: 435, 12 + xy: 1, 2 size: 40, 24 orig: 40, 24 offset: 0, 0 index: -1 scroll-knob-vertical-black rotate: false - xy: 1907, 847 + xy: 1901, 538 size: 24, 40 orig: 24, 40 offset: 0, 0 index: -1 scroll-knob-vertical-thin rotate: false - xy: 1874, 599 + xy: 1766, 414 size: 12, 40 orig: 12, 40 offset: 0, 0 @@ -16079,28 +16422,28 @@ selection index: -1 slider rotate: false - xy: 131, 528 + xy: 1315, 628 size: 1, 8 orig: 1, 8 offset: 0, 0 index: -1 slider-knob rotate: false - xy: 1335, 668 + xy: 1269, 500 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-down rotate: false - xy: 1366, 668 + xy: 1269, 460 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-over rotate: false - xy: 1397, 668 + xy: 1269, 420 size: 29, 38 orig: 29, 38 offset: 0, 0 @@ -16114,7 +16457,7 @@ slider-vertical index: -1 underline rotate: false - xy: 1745, 946 + xy: 1933, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16122,7 +16465,7 @@ underline index: -1 underline-2 rotate: false - xy: 1631, 946 + xy: 1819, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16130,7 +16473,7 @@ underline-2 index: -1 underline-disabled rotate: false - xy: 1669, 946 + xy: 1857, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16138,7 +16481,7 @@ underline-disabled index: -1 underline-red rotate: false - xy: 1707, 946 + xy: 1895, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16153,7 +16496,7 @@ whiteui index: -1 window-empty rotate: false - xy: 949, 611 + xy: 1347, 621 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 e5e469d684..6ca4632feb 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 f530d80d91..c8ab971458 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/assets/sprites/sprites4.png b/core/assets/sprites/sprites4.png index 5965272be8..87b18413db 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 124f3c4695..dc4b0cf89e 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 56f1bb9f35..31a9e191bd 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -65,18 +65,14 @@ public class Vars implements Loadable{ public static final Array defaultServers = Array.with(); /** maximum distance between mine and core that supports automatic transferring */ public static final float mineTransferRange = 220f; - /** whether to enable editing of units in the editor */ - public static final boolean enableUnitEditing = false; /** max chat message length */ public static final int maxTextLength = 150; /** max player name length in bytes */ public static final int maxNameLength = 40; - /** displayed item size when ingame, TODO remove. */ + /** displayed item size when ingame. */ public static final float itemSize = 5f; - /** extra padding around the world; units outside this bound will begin to self-destruct. */ - public static final float worldBounds = 100f; - /** units outside of this bound will simply die instantly */ - public static final float finalWorldBounds = worldBounds + 500; + /** units outside of this bound will die instantly */ + public static final float finalWorldBounds = 500; /** mining range for manual miners */ public static final float miningRange = 70f; /** range for building */ @@ -85,6 +81,8 @@ public class Vars implements Loadable{ public static final float turnDuration = 5 * Time.toMinutes; /** min armor fraction damage; e.g. 0.05 = at least 5% damage */ public static final float minArmorDamage = 0.05f; + /** launch animation duration */ + public static final float launchDuration = 140f; /** tile used in certain situations, instead of null */ public static Tile emptyTile; /** for map generator dialog */ @@ -180,6 +178,7 @@ public class Vars implements Loadable{ public static BeControl becontrol; public static AsyncCore asyncCore; public static TeamIndexProcess teamIndex; + public static BaseRegistry bases; public static Universe universe; public static World world; @@ -252,6 +251,7 @@ public class Vars implements Loadable{ spawner = new WaveSpawner(); indexer = new BlockIndexer(); pathfinder = new Pathfinder(); + bases = new BaseRegistry(); state = new GameState(); data = new GlobalData(); diff --git a/core/src/mindustry/ai/Astar.java b/core/src/mindustry/ai/Astar.java new file mode 100644 index 0000000000..1499be5ce5 --- /dev/null +++ b/core/src/mindustry/ai/Astar.java @@ -0,0 +1,97 @@ +package mindustry.ai; + +import arc.func.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.world.*; + +import static mindustry.Vars.world; + +public class Astar{ + public static final DistanceHeuristic manhattan = (x1, y1, x2, y2) -> Math.abs(x1 - x2) + Math.abs(y1 - y2); + + private static final Array out = new Array<>(); + private static final PQueue queue = new PQueue<>(200 * 200 / 4, (a, b) -> 0); + private static final IntFloatMap costs = new IntFloatMap(); + private static byte[][] rotations; + + public static Array pathfind(Tile from, Tile to, TileHueristic th, Boolf passable){ + return pathfind(from.x, from.y, to.x, to.y, th, manhattan, passable); + } + + public static Array pathfind(int startX, int startY, int endX, int endY, TileHueristic th, Boolf passable){ + return pathfind(startX, startY, endX, endY, th, manhattan, passable); + } + + public static Array pathfind(int startX, int startY, int endX, int endY, TileHueristic th, DistanceHeuristic dh, Boolf passable){ + Tiles tiles = world.tiles; + + Tile start = tiles.getn(startX, startY); + Tile end = tiles.getn(endX, endY); + + GridBits closed = new GridBits(tiles.width, tiles.height); + + costs.clear(); + queue.clear(); + queue.comparator = Structs.comparingFloat(a -> costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y)); + queue.add(start); + if(rotations == null || rotations.length != world.width() || rotations[0].length != world.height()){ + rotations = new byte[world.width()][world.height()]; + } + + boolean found = false; + while(!queue.empty()){ + Tile next = queue.poll(); + float baseCost = costs.get(next.pos(), 0f); + if(next == end){ + found = true; + break; + } + closed.set(next.x, next.y); + for(Point2 point : Geometry.d4){ + int newx = next.x + point.x, newy = next.y + point.y; + if(Structs.inBounds(newx, newy, tiles.width, tiles.height)){ + Tile child = tiles.getn(newx, newy); + if(passable.get(child)){ + float newCost = th.cost(next, child) + baseCost; + if(!closed.get(child.x, child.y)){ + closed.set(child.x, child.y); + rotations[child.x][child.y] = child.relativeTo(next.x, next.y); + costs.put(child.pos(), newCost); + queue.add(child); + } + } + } + } + } + + out.clear(); + + if(!found) return out; + + Tile current = end; + while(current != start){ + out.add(current); + + byte rot = rotations[current.x][current.y]; + current = tiles.getn(current.x + Geometry.d4x[rot], current.y + Geometry.d4y[rot]); + } + + out.reverse(); + + return out; + } + + public interface DistanceHeuristic{ + float cost(int x1, int y1, int x2, int y2); + } + + public interface TileHueristic{ + float cost(Tile tile); + + default float cost(Tile from, Tile tile){ + return cost(tile); + } + } +} diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java new file mode 100644 index 0000000000..466a3fad95 --- /dev/null +++ b/core/src/mindustry/ai/BaseAI.java @@ -0,0 +1,164 @@ +package mindustry.ai; + +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.*; +import mindustry.ai.BaseRegistry.*; +import mindustry.content.*; +import mindustry.game.*; +import mindustry.game.Schematic.*; +import mindustry.game.Teams.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.defense.*; +import mindustry.world.blocks.production.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.*; + +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 float emptyChance = 0.01f; + + private static int correct = 0, incorrect = 0; + + private int lastX, lastY, lastW, lastH; + private boolean triedWalls; + + TeamData data; + Interval timer = new Interval(); + + public BaseAI(TeamData data){ + this.data = data; + } + + public void update(){ + + //only schedule when there's something to build. + if(data.blocks.isEmpty() && timer.get(step)){ + if(!triedWalls){ + tryWalls(); + triedWalls = true; + } + + for(int i = 0; i < attempts; i++){ + int range = 150; + CoreEntity core = data.cores.random(); + + Tmp.v1.rnd(Mathf.random(range)); + int wx = (int)(core.tileX() + Tmp.v1.x), wy = (int)(core.tileY() + Tmp.v1.y); + Tile tile = world.tiles.getc(wx, wy); + + Array parts = null; + + //pick a completely random base part, and place it a random location + //((yes, very intelligent)) + if(tile.drop() != null && Vars.bases.forResource(tile.drop()).any()){ + parts = Vars.bases.forResource(tile.drop()); + }else if(Mathf.chance(emptyChance)){ + parts = Vars.bases.parts; + } + + if(parts != null){ + BasePart part = parts.random(); + if(tryPlace(part, tile.x, tile.y)){ + break; + } + } + } + } + } + + boolean tryPlace(BasePart part, int x, int y){ + int rotation = Mathf.range(2); + axis.set((int)(part.schematic.width / 2f), (int)(part.schematic.height / 2f)); + Schematic result = Schematics.rotate(part.schematic, rotation); + int rotdeg = rotation*90; + rotator.set(part.centerX, part.centerY).rotateAround(axis, rotdeg); + //bottom left schematic corner + int cx = x - (int)rotator.x; + int cy = y - (int)rotator.y; + + //chekc valid placeability + for(Stile tile : result.tiles){ + int realX = tile.x + cx, realY = tile.y + cy; + if(!Build.validPlace(tile.block, data.team, realX, realY, tile.rotation)){ + return false; + } + } + + //make sure at least X% of resource requirements are met + correct = incorrect = 0; + + if(part.required instanceof Item){ + for(Stile tile : result.tiles){ + if(tile.block instanceof Drill){ + + tile.block.iterateTaken(tile.x + cx, tile.y + cy, (ex, ey) -> { + Tile res = world.rawTile(ex, ey); + if(res.drop() == part.required){ + correct ++; + }else{ + incorrect ++; + } + }); + } + } + } + + //fail if not enough fit requirements + if((float)correct / incorrect < correctPercent){ + return false; + } + + //queue it + for(Stile tile : result.tiles){ + data.blocks.add(new BlockPlan(cx + tile.x, cy + tile.y, tile.rotation, tile.block.id, tile.config)); + } + + lastX = cx - 1; + lastY = cy - 1; + lastW = result.width + 2; + lastH = result.height + 2; + + triedWalls = false; + + return true; + } + + void tryWalls(){ + Block wall = Blocks.copperWall; + Tile spawn = state.rules.defaultTeam.core() != null ? state.rules.defaultTeam.core().tile : data.team.core().tile; + + for(int wx = lastX; wx <= lastX + lastW; wx++){ + for(int wy = lastY; wy <= lastY + lastH; wy++){ + Tile tile = world.tile(wx, wy); + + if(tile == null || !tile.block().alwaysReplace) continue; + + boolean any = false; + + for(Point2 p : Geometry.d8){ + if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(tile)) > 70){ + continue; + } + + Tile o = world.tile(tile.x + p.x, tile.y + p.y); + if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){ + any = true; + break; + } + } + + if(any && Build.validPlace(wall, data.team, tile.x, tile.y, 0)){ + data.blocks.add(new BlockPlan(tile.x, tile.y, (short)0, wall.id, null)); + } + } + } + } +} diff --git a/core/src/mindustry/ai/BaseRegistry.java b/core/src/mindustry/ai/BaseRegistry.java new file mode 100644 index 0000000000..88ceb86635 --- /dev/null +++ b/core/src/mindustry/ai/BaseRegistry.java @@ -0,0 +1,121 @@ +package mindustry.ai; + +import arc.*; +import arc.struct.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.ctype.*; +import mindustry.game.*; +import mindustry.game.Schematic.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.production.*; +import mindustry.world.blocks.sandbox.*; +import mindustry.world.blocks.storage.*; +import mindustry.world.meta.*; + +import java.io.*; + +import static mindustry.Vars.tilesize; + +public class BaseRegistry{ + public Array cores = new Array<>(); + public Array parts = new Array<>(); + public ObjectMap> reqParts = new ObjectMap<>(); + + public Array forResource(Content item){ + return reqParts.get(item, Array::new); + } + + public void load(){ + cores.clear(); + parts.clear(); + reqParts.clear(); + + String[] names = Core.files.internal("basepartnames").readString().split("\n"); + + for(String name : names){ + try{ + Schematic schem = Schematics.read(Core.files.internal("baseparts/" + name)); + + BasePart part = new BasePart(schem); + Tmp.v1.setZero(); + int drills = 0; + + for(Stile tile : schem.tiles){ + //keep track of core type + if(tile.block instanceof CoreBlock){ + part.core = tile.block; + } + + //save the required resource based on item source - multiple sources are not allowed + if(tile.block instanceof ItemSource){ + Item config = (Item)tile.config; + if(config != null) part.required = config; + } + + //same for liquids - this is not used yet + if(tile.block instanceof LiquidSource){ + Liquid config = (Liquid)tile.config; + if(config != null) part.required = config; + } + + //calculate averages + if(tile.block instanceof Drill || tile.block instanceof Pump){ + Tmp.v1.add(tile.x*tilesize + tile.block.offset(), tile.y*tilesize + tile.block.offset()); + drills ++; + } + } + schem.tiles.removeAll(s -> s.block.buildVisibility == BuildVisibility.sandboxOnly); + + part.tier = schem.tiles.sumf(s -> s.block.buildCost / s.block.buildCostMultiplier); + + if(part.core != null){ + cores.add(part); + }else if(part.required == null){ + parts.add(part); + } + + if(drills > 0){ + Tmp.v1.scl(1f / drills).scl(1f / tilesize); + part.centerX = (int)Tmp.v1.x; + part.centerY = (int)Tmp.v1.y; + }else{ + part.centerX = part.schematic.width/2; + part.centerY = part.schematic.height/2; + } + + if(part.required != null) reqParts.get(part.required, Array::new).add(part); + + }catch(IOException e){ + throw new RuntimeException(e); + } + } + + cores.sort(Structs.comps(Structs.comparingFloat(b -> b.core.health), Structs.comparingFloat(b -> b.tier))); + parts.sort(); + reqParts.each((key, arr) -> arr.sort()); + } + + public static class BasePart implements Comparable{ + public final Schematic schematic; + + //offsets for drills + public int centerX, centerY; + + public @Nullable Content required; + public @Nullable Block core; + + //total build cost + public float tier; + + public BasePart(Schematic schematic){ + this.schematic = schematic; + } + + @Override + public int compareTo(BasePart other){ + return Float.compare(tier, other.tier); + } + } +} diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 0ba659e460..1560263ee8 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -34,15 +34,15 @@ public class BlockIndexer{ /** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */ private GridBits[] structQuadrants; /** Stores all damaged tile entities by team. */ - private TileArray[] damagedTiles = new TileArray[Team.all().length]; + private TileArray[] damagedTiles = new TileArray[Team.all.length]; /** All ores available on this map. */ private ObjectSet allOres = new ObjectSet<>(); /** Stores teams that are present here as tiles. */ private Array activeTeams = new Array<>(); /** Maps teams to a map of flagged tiles by flag. */ - private TileArray[][] flagMap = new TileArray[Team.all().length][BlockFlag.all.length]; + private TileArray[][] flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; /** Max units by team. */ - private int[] unitCaps = new int[Team.all().length]; + private int[] unitCaps = new int[Team.all.length]; /** Maps tile positions to their last known tile index data. */ private IntMap typeMap = new IntMap<>(); /** Empty set used for returning. */ @@ -69,9 +69,9 @@ public class BlockIndexer{ Events.on(WorldLoadEvent.class, event -> { scanOres.clear(); scanOres.addAll(Item.getAllOres()); - damagedTiles = new TileArray[Team.all().length]; - flagMap = new TileArray[Team.all().length][BlockFlag.all.length]; - unitCaps = new int[Team.all().length]; + damagedTiles = new TileArray[Team.all.length]; + flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; + unitCaps = new int[Team.all.length]; for(int i = 0; i < flagMap.length; i++){ for(int j = 0; j < BlockFlag.all.length; j++){ @@ -84,7 +84,7 @@ public class BlockIndexer{ ores = null; //create bitset for each team type that contains each quadrant - structQuadrants = new GridBits[Team.all().length]; + structQuadrants = new GridBits[Team.all.length]; for(Tile tile : world.tiles){ process(tile); @@ -175,7 +175,6 @@ public class BlockIndexer{ int ty = world.toTile(wy); int tileRange = (int)(range / tilesize + 1); - intSet.clear(); boolean any = false; for(int x = -tileRange + tx; x <= tileRange + tx; x++){ @@ -186,10 +185,9 @@ public class BlockIndexer{ if(other == null) continue; - if(other.team() == team && !intSet.contains(other.pos()) && pred.get(other)){ + if(other.team() == team && pred.get(other) && intSet.add(other.pos())){ cons.get(other); any = true; - intSet.add(other.pos()); } } } diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 5f3e2ce40b..06550d602c 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -17,23 +17,27 @@ import mindustry.world.meta.*; import static mindustry.Vars.*; public class Pathfinder implements Runnable{ - private static final long maxUpdate = Time.millisToNanos(4); + private static final long maxUpdate = Time.millisToNanos(6); private static final int updateFPS = 60; private static final int updateInterval = 1000 / updateFPS; private static final int impassable = -1; + private static final int fieldTimeout = 1000 * 60 * 2; /** tile data, see PathTileStruct */ private int[][] tiles; - /** unordered array of path data for iteration only. DO NOT iterate ot access this in the main thread. */ - private Array list = new Array<>(); - /** Maps teams + flags to a valid path to get to that flag for that team. */ - private PathData[][] pathMap = new PathData[Team.all().length][PathTarget.all.length]; - /** Grid map of created path data that should not be queued again. */ - private GridBits created = new GridBits(Team.all().length, PathTarget.all.length); + /** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */ + private Array threadList = new Array<>(), mainList = new Array<>(); + /** Maps team ID and target to to a flowfield.*/ + private ObjectMap[] fieldMap = new ObjectMap[Team.all.length]; + /** Used field maps. */ + private ObjectSet[] fieldMapUsed = new ObjectSet[Team.all.length]; /** handles task scheduling on the update thread. */ private TaskQueue queue = new TaskQueue(); - /** current pathfinding thread */ + /** Stores path target for a position. Main thread only.*/ + private ObjectMap targetCache = new ObjectMap<>(); + /** Current pathfinding thread */ private @Nullable Thread thread; + private IntArray tmpArray = new IntArray(); public Pathfinder(){ Events.on(WorldLoadEvent.class, event -> { @@ -41,16 +45,18 @@ public class Pathfinder implements Runnable{ //reset and update internal tile array tiles = new int[world.width()][world.height()]; - pathMap = new PathData[Team.all().length][PathTarget.all.length]; - created = new GridBits(Team.all().length, PathTarget.all.length); - list = new Array<>(); + fieldMap = new ObjectMap[Team.all.length]; + fieldMapUsed = new ObjectSet[Team.all.length]; + targetCache = new ObjectMap<>(); + threadList = new Array<>(); + mainList = new Array<>(); for(Tile tile : world.tiles){ tiles[tile.x][tile.y] = packTile(tile); } //special preset which may help speed things up; this is optional - preloadPath(state.rules.waveTeam, PathTarget.enemyCores); + preloadPath(state.rules.waveTeam, FlagTarget.enemyCores); start(); }); @@ -62,7 +68,7 @@ public class Pathfinder implements Runnable{ /** Packs a tile into its internal representation. */ private int packTile(Tile tile){ - return PathTile.get(tile.cost, tile.getTeamID(), !tile.solid() && tile.floor().drownTime <= 0f); + return PathTile.get(tile.cost, tile.getTeamID(), !tile.solid() && tile.floor().drownTime <= 0f, !tile.solid() && tile.floor().isLiquid); } /** Starts or restarts the pathfinding thread. */ @@ -80,12 +86,13 @@ public class Pathfinder implements Runnable{ queue.clear(); } - public int debugValue(Team team, int x, int y){ - if(pathMap[team.id][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; - } + //public int debugValue(Team team, int x, int y){ + // if(pathMap[team.id][FlagTarget.enemyCores.ordinal()] == null) return 0; + // return pathMap[team.id][FlagTarget.enemyCores.ordinal()].weights[x][y]; + //} - /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ + /** Update a tile in the internal pathfinding grid. + * Causes a complete pathfinding reclaculation. Main thread only. */ public void updateTile(Tile tile){ if(net.client()) return; @@ -98,19 +105,17 @@ public class Pathfinder implements Runnable{ }); //can't iterate through array so use the map, which should not lead to problems - for(PathData[] arr : pathMap){ - for(PathData path : arr){ - if(path != null){ - synchronized(path.targets){ - path.targets.clear(); - path.target.getTargets(path.team, path.targets); - } + for(Flowfield path : mainList){ + if(path != null){ + synchronized(path.targets){ + path.targets.clear(); + path.target.getPositions(path.team, path.targets); } } } queue.post(() -> { - for(PathData data : list){ + for(Flowfield data : threadList){ updateTargets(data, x, y); } }); @@ -126,8 +131,31 @@ public class Pathfinder implements Runnable{ queue.run(); //total update time no longer than maxUpdate - for(PathData data : list){ - updateFrontier(data, maxUpdate / list.size); + for(Flowfield data : threadList){ + updateFrontier(data, maxUpdate / threadList.size); + + //remove flowfields that have 'timed out' so they can be garbage collected and no longer waste space + if(data.target.refreshRate() > 0 && Time.timeSinceMillis(data.lastUpdateTime) > fieldTimeout){ + //make sure it doesn't get removed twice + data.lastUpdateTime = Time.millis(); + + Team team = data.team; + + Core.app.post(() -> { + //remove its used state + if(fieldMap[team.uid] != null){ + fieldMap[team.uid].remove(data.target); + fieldMapUsed[team.uid].remove(data.target); + } + //remove from main thread list + mainList.remove(data); + }); + + queue.post(() -> { + //remove from this thread list with a delay + threadList.remove(data); + }); + } } try{ @@ -142,23 +170,50 @@ public class Pathfinder implements Runnable{ } } + public Tile getTargetTile(Tile tile, Team team, Position target){ + return getTargetTile(tile, team, getTarget(target)); + } + /** Gets next tile to travel to. Main thread only. */ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[team.id][target.ordinal()]; + if(fieldMap[team.uid] == null){ + fieldMap[team.uid] = new ObjectMap<>(); + fieldMapUsed[team.uid] = new ObjectSet<>(); + } + + Flowfield data = fieldMap[team.uid].get(target); if(data == null){ //if this combination is not found, create it on request - if(!created.get(team.id, target.ordinal())){ - created.set(team.id, target.ordinal()); + if(fieldMapUsed[team.uid].add(target)){ //grab targets since this is run on main thread - IntArray targets = target.getTargets(team, new IntArray()); + IntArray targets = target.getPositions(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); } return tile; } + //if refresh rate is positive, queue a refresh + if(target.refreshRate() > 0 && Time.timeSinceMillis(data.lastUpdateTime) > target.refreshRate()){ + data.lastUpdateTime = Time.millis(); + + tmpArray.clear(); + data.target.getPositions(data.team, tmpArray); + + synchronized(data.targets){ + //make sure the position actually changed + if(!(data.targets.size == 1 && tmpArray.size == 1 && data.targets.first() == tmpArray.first())){ + data.targets.clear(); + data.target.getPositions(data.team, data.targets); + + //queue an update + queue.post(() -> updateTargets(data)); + } + } + } + int[][] values = data.weights; int value = values[tile.x][tile.y]; @@ -182,6 +237,10 @@ public class Pathfinder implements Runnable{ return current; } + private PathTarget getTarget(Position position){ + return targetCache.get(position, () -> new PositionTarget(position)); + } + /** @return whether a tile can be passed through by this team. Pathfinding thread only. */ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; @@ -192,7 +251,7 @@ public class Pathfinder implements Runnable{ * Clears the frontier, increments the search and sets up all flow sources. * This only occurs for active teams. */ - private void updateTargets(PathData path, int x, int y){ + private void updateTargets(Flowfield path, int x, int y){ if(!Structs.inBounds(x, y, path.weights)) return; if(path.weights[x][y] == 0){ @@ -208,10 +267,18 @@ public class Pathfinder implements Runnable{ path.weights[x][y] = impassable; } - //increment search, clear frontier - path.search++; + //clear frontier to prevent contamination path.frontier.clear(); + updateTargets(path); + } + + /** Increments the search and sets up flow sources. Does not change the frontier. */ + private void updateTargets(Flowfield path){ + + //increment search, but do not clear the frontier + path.search++; + synchronized(path.targets){ //add targets for(int i = 0; i < path.targets.size; i++){ @@ -219,25 +286,33 @@ public class Pathfinder implements Runnable{ int tx = Point2.x(pos), ty = Point2.y(pos); path.weights[tx][ty] = 0; - path.searches[tx][ty] = (short)path.search; + path.searches[tx][ty] = path.search; path.frontier.addFirst(pos); } } } private void preloadPath(Team team, PathTarget target){ - updateFrontier(createPath(team, target, target.getTargets(team, new IntArray())), -1); + updateFrontier(createPath(team, target, target.getPositions(team, new IntArray())), -1); } /** * Created a new flowfield that aims to get to a certain target for a certain team. * Pathfinding thread only. */ - private PathData createPath(Team team, PathTarget target, IntArray targets){ - PathData path = new PathData(team, target, world.width(), world.height()); + private Flowfield createPath(Team team, PathTarget target, IntArray targets){ + Flowfield path = new Flowfield(team, target, world.width(), world.height()); + path.lastUpdateTime = Time.millis(); - list.add(path); - pathMap[team.id][target.ordinal()] = path; + threadList.add(path); + + //add to main thread's list of paths + Core.app.post(() -> { + mainList.add(path); + if(fieldMap[team.uid] != null){ + fieldMap[team.uid].put(target, path); + } + }); //grab targets from passed array synchronized(path.targets){ @@ -263,7 +338,7 @@ public class Pathfinder implements Runnable{ } /** Update the frontier for a path. Pathfinding thread only. */ - private void updateFrontier(PathData path, long nsToRun){ + private void updateFrontier(Flowfield path, long nsToRun){ long start = Time.nanos(); while(path.frontier.size > 0 && (nsToRun < 0 || Time.timeSinceNanos(start) <= nsToRun)){ @@ -295,7 +370,7 @@ public class Pathfinder implements Runnable{ } /** A path target defines a set of targets for a path. */ - public enum PathTarget{ + public enum FlagTarget implements PathTarget{ enemyCores((team, out) -> { for(Tile other : indexer.getEnemy(team, BlockFlag.core)){ out.add(other.pos()); @@ -314,23 +389,54 @@ public class Pathfinder implements Runnable{ } }); - public static final PathTarget[] all = values(); + public static final FlagTarget[] all = values(); private final Cons2 targeter; - PathTarget(Cons2 targeter){ + FlagTarget(Cons2 targeter){ this.targeter = targeter; } - /** Get targets. This must run on the main thread. */ - public IntArray getTargets(Team team, IntArray out){ + @Override + public IntArray getPositions(Team team, IntArray out){ targeter.get(team, out); return out; } + + @Override + public int refreshRate(){ + return 0; + } + } + + public static class PositionTarget implements PathTarget{ + public final Position position; + + public PositionTarget(Position position){ + this.position = position; + } + + @Override + public IntArray getPositions(Team team, IntArray out){ + out.add(Point2.pack(world.toTile(position.getX()), world.toTile(position.getY()))); + return out; + } + + @Override + public int refreshRate(){ + return 900; + } + } + + public interface PathTarget{ + /** Gets targets to pathfind towards. This must run on the main thread. */ + IntArray getPositions(Team team, IntArray out); + /** Refresh rate in milliseconds. Return any number <= 0 to disable. */ + int refreshRate(); } /** Data for a specific flow field to some set of destinations. */ - static class PathData{ + static class Flowfield{ /** Team this path is for. */ final Team team; /** Flag that is being targeted. */ @@ -338,20 +444,22 @@ public class Pathfinder implements Runnable{ /** costs of getting to a specific tile */ final int[][] weights; /** search IDs of each position - the highest, most recent search is prioritized and overwritten */ - final short[][] searches; + final int[][] searches; /** search frontier, these are Pos objects */ final IntQueue frontier = new IntQueue(); /** all target positions; these positions have a cost of 0, and must be synchronized on! */ final IntArray targets = new IntArray(); /** current search ID */ int search = 1; + /** last updated time */ + long lastUpdateTime; - PathData(Team team, PathTarget target, int width, int height){ + Flowfield(Team team, PathTarget target, int width, int height){ this.team = team; this.target = target; this.weights = new int[width][height]; - this.searches = new short[width][height]; + this.searches = new int[width][height]; this.frontier.ensureCapacity((width + height) * 3); } } @@ -363,9 +471,9 @@ public class Pathfinder implements Runnable{ short cost; //team of block, if applicable (0 by default) byte team; - //type of target; TODO remove - //byte type; //whether it's viable to pass this block boolean passable; + //whether it's viable to pass this block through water + boolean passableWater; } } diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java new file mode 100644 index 0000000000..4fd4667c58 --- /dev/null +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -0,0 +1,83 @@ +package mindustry.ai.types; + +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.entities.units.*; +import mindustry.game.Teams.*; +import mindustry.gen.*; +import mindustry.world.*; +import mindustry.world.blocks.BuildBlock.*; + +import static mindustry.Vars.*; + +public class BuilderAI extends AIController{ + + @Override + public void update(){ + Builderc builder = (Builderc)unit; + + if(builder.moving()){ + builder.lookAt(builder.vel().angle()); + } + + //approach request if building + if(builder.buildRequest() != null){ + BuildRequest req = builder.buildRequest(); + + boolean valid = + (req.tile().entity instanceof BuildEntity && req.tile().ent().cblock == req.block) || + (req.breaking ? + Build.validBreak(unit.team(), req.x, req.y) : + Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation)); + + if(valid){ + //move toward the request + moveTo(req.tile(), buildingRange - 20f); + }else{ + //discard invalid request + builder.requests().removeFirst(); + } + }else{ + //find new request + if(!unit.team().data().blocks.isEmpty()){ + Queue blocks = unit.team().data().blocks; + BlockPlan block = blocks.first(); + + //check if it's already been placed + if(world.tile(block.x, block.y) != null && world.tile(block.x, block.y).block().id == block.block){ + blocks.removeFirst(); + }else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid. + //add build request. + BuildRequest req = new BuildRequest(block.x, block.y, block.rotation, content.block(block.block)); + if(block.config != null){ + req.configure(block.config); + } + builder.addBuild(req); + }else{ + //shift head of queue to tail, try something else next time + blocks.removeFirst(); + blocks.addLast(block); + } + }else{ + //TODO implement AI base building + } + } + } + + protected void moveTo(Position target, float circleLength){ + vec.set(target).sub(unit); + + float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f); + + vec.setLength(unit.type().speed * Time.delta() * length); + if(length < -0.5f){ + vec.rotate(180f); + }else if(length < 0){ + vec.setZero(); + } + + unit.moveAt(vec); + } +} diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index ee52aa3bae..faf2a543bd 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -11,7 +11,7 @@ public class FlyingAI extends AIController{ @Override public void update(){ - if(!unit.vel().isZero(0.01f)){ + if(unit.moving()){ unit.rotation(unit.vel().angle()); } @@ -46,6 +46,8 @@ public class FlyingAI extends AIController{ unit.controlWeapons(shoot, shoot); } + //TODO clean up + protected void circle(float circleLength){ circle(circleLength, unit.type().speed); } diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index b2096ac315..49367ae12f 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -1,6 +1,8 @@ package mindustry.ai.types; import arc.math.geom.*; +import arc.util.ArcAnnotate.*; +import mindustry.*; import mindustry.ai.formations.*; import mindustry.entities.units.*; import mindustry.gen.*; @@ -9,7 +11,7 @@ public class FormationAI extends AIController implements FormationMember{ public Unitc leader; private Vec3 target = new Vec3(); - private Formation formation; + private @Nullable Formation formation; public FormationAI(Unitc leader, Formation formation){ this.leader = leader; @@ -23,19 +25,37 @@ public class FormationAI extends AIController implements FormationMember{ @Override public void update(){ + if(leader.dead()){ + unit.resetController(); + return; + } + unit.controlWeapons(leader.isRotate(), leader.isShooting()); // unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed)); if(leader.isShooting()){ unit.aimLook(leader.aimX(), leader.aimY()); }else{ - - unit.lookAt(leader.rotation()); - if(!unit.vel().isZero(0.001f)){ - // unit.lookAt(unit.vel().angle()); + if(!unit.moving()){ + unit.lookAt(unit.vel().angle()); + }else{ + unit.lookAt(leader.rotation()); } } - unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed)); + Vec2 realtarget = vec.set(target); + + if(unit.isGrounded() && Vars.world.raycast(unit.tileX(), unit.tileY(), leader.tileX(), leader.tileY(), Vars.world::solid)){ + realtarget.set(Vars.pathfinder.getTargetTile(unit.tileOn(), unit.team(), leader)); + } + + unit.moveAt(realtarget.sub(unit).limit(unit.type().speed)); + } + + @Override + public void removed(Unitc unit){ + if(formation != null){ + formation.removeMember(this); + } } @Override diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index 3d29310640..b32f431682 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -1,6 +1,5 @@ package mindustry.ai.types; -import arc.util.*; import mindustry.ai.Pathfinder.*; import mindustry.entities.*; import mindustry.entities.units.*; @@ -17,11 +16,6 @@ public class GroundAI extends AIController{ if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){ target = null; - - //TODO this is hacky, cleanup - if(unit instanceof Mechc && unit.moving()){ - unit.lookAt(((Mechc)unit).baseRotation()); - } } if(retarget()){ @@ -31,14 +25,12 @@ public class GroundAI extends AIController{ Tilec core = unit.closestEnemyCore(); if(core != null){ - float dst = unit.dst(core); - - if(dst < unit.range() / 1.1f){ + if(unit.within(core,unit.range() / 1.1f)){ target = core; } - if(dst > unit.range() * 0.5f){ - moveToCore(PathTarget.enemyCores); + if(!unit.within(core, unit.range() * 0.5f)){ + moveToCore(FlagTarget.enemyCores); } } @@ -51,19 +43,21 @@ public class GroundAI extends AIController{ if(unit.type().hasWeapons()){ unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed)); } + }else if(unit.moving()){ + unit.lookAt(unit.vel().angle()); } unit.controlWeapons(rotate, shoot); } - protected void moveToCore(PathTarget path){ + protected void moveToCore(FlagTarget path){ Tile tile = unit.tileOn(); if(tile == null) return; Tile targetTile = pathfinder.getTargetTile(tile, unit.team(), path); if(tile == targetTile) return; - unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed * Time.delta())); + unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed)); } protected void moveAwayFromCore(){ @@ -86,11 +80,11 @@ public class GroundAI extends AIController{ Tile tile = unit.tileOn(); if(tile == null) return; - Tile targetTile = pathfinder.getTargetTile(tile, enemy, PathTarget.enemyCores); + Tile targetTile = pathfinder.getTargetTile(tile, enemy, FlagTarget.enemyCores); Tilec core = unit.closestCore(); if(tile == targetTile || core == null || unit.within(core, 120f)) return; - unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed * Time.delta())); + unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed)); } } diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java new file mode 100644 index 0000000000..d56baec2e5 --- /dev/null +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -0,0 +1,70 @@ +package mindustry.ai.types; + +import mindustry.*; +import mindustry.ai.Pathfinder.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.world.*; + +public class SuicideAI extends GroundAI{ + static boolean blockedByBlock; + + @Override + public void update(){ + + if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){ + target = null; + } + + if(retarget()){ + targetClosest(); + } + + Tilec core = unit.closestEnemyCore(); + + boolean rotate = false, shoot = false; + + if(!Units.invalidateTarget(target, unit, unit.range())){ + rotate = true; + shoot = unit.within(target, unit.type().weapons.first().bullet.range() + + (target instanceof Tilec ? ((Tilec)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)); + } + + 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.entity == target) return false; + if(tile != null && tile.entity != null && tile.entity.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; + } + + if(!blocked){ + //move towards target directly + unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed)); + } + + }else{ + if(core != null){ + moveToCore(FlagTarget.enemyCores); + } + + if(unit.moving()) unit.lookAt(unit.vel().angle()); + } + + unit.controlWeapons(rotate, shoot); + } +} diff --git a/core/src/mindustry/async/TeamIndexProcess.java b/core/src/mindustry/async/TeamIndexProcess.java index e691c50ee6..2b5c0043a6 100644 --- a/core/src/mindustry/async/TeamIndexProcess.java +++ b/core/src/mindustry/async/TeamIndexProcess.java @@ -9,8 +9,8 @@ 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 QuadTree[] trees = new QuadTree[Team.all.length]; + private int[] counts = new int[Team.all.length]; public QuadTree tree(Team team){ if(trees[team.uid] == null) trees[team.uid] = new QuadTree<>(Vars.world.getQuadBounds(new Rect())); @@ -28,14 +28,14 @@ public class TeamIndexProcess implements AsyncProcess{ @Override public void reset(){ - counts = new int[Team.all().length]; - trees = new QuadTree[Team.all().length]; + counts = new int[Team.all.length]; + trees = new QuadTree[Team.all.length]; } @Override public void begin(){ - for(Team team : Team.all()){ + for(Team team : Team.all){ if(trees[team.uid] != null){ trees[team.uid].clear(); } diff --git a/core/src/mindustry/audio/LoopControl.java b/core/src/mindustry/audio/LoopControl.java index 6ed4035ef1..1b102ab0a4 100644 --- a/core/src/mindustry/audio/LoopControl.java +++ b/core/src/mindustry/audio/LoopControl.java @@ -16,7 +16,7 @@ public class LoopControl{ float baseVol = sound.calcFalloff(pos.getX(), pos.getY()); float vol = baseVol * volume; - SoundData data = sounds.getOr(sound, SoundData::new); + SoundData data = sounds.get(sound, SoundData::new); data.volume += vol; data.volume = Mathf.clamp(data.volume, 0f, 1f); data.total += baseVol; diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index e216ce0e01..532dcd6c7b 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -14,6 +14,7 @@ import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; +import mindustry.world.blocks.campaign.*; import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.turrets.*; import mindustry.world.blocks.distribution.*; @@ -44,20 +45,20 @@ public class Blocks implements ContentList{ oreCopper, oreLead, oreScrap, oreCoal, oreTitanium, oreThorium, //crafting - siliconSmelter, kiln, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer, - melter, separator, sporePress, pulverizer, incinerator, coalCentrifuge, + siliconSmelter, siliconCrucible, kiln, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer, + melter, separator, disassembler, sporePress, pulverizer, incinerator, coalCentrifuge, //sandbox powerSource, powerVoid, itemSource, itemVoid, liquidSource, liquidVoid, message, illuminator, //defense copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge, - phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine, + phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, largeOverdriveProjector, forceProjector, shockMine, scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet //transport conveyor, titaniumConveyor, plastaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, - overflowGate, underflowGate, massDriver, massConveyor, + overflowGate, underflowGate, massDriver, payloadConveyor, payloadRouter, //liquid mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, platedConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit, @@ -70,17 +71,19 @@ public class Blocks implements ContentList{ mechanicalDrill, pneumaticDrill, laserDrill, blastDrill, waterExtractor, oilExtractor, cultivator, //storage - coreShard, coreFoundation, coreNucleus, vault, container, unloader, launchPad, launchPadLarge, + coreShard, coreFoundation, coreNucleus, vault, container, unloader, //turrets - duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, + duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, segment, //units groundFactory, airFactory, navalFactory, basicReconstructor, repairPoint, - //misc experimental + //campaign + launchPad, launchPadLarge, coreSilo, dataProcessor, - blockForge, blockLauncher, blockLoader, blockUnloader; + //misc experimental + blockForge, blockLoader, blockUnloader; @Override public void load(){ @@ -482,6 +485,22 @@ public class Blocks implements ContentList{ consumes.power(0.50f); }}; + siliconCrucible = new AttributeSmelter("silicon-crucible"){{ + requirements(Category.crafting, ItemStack.with(Items.titanium, 120, Items.metaglass, 80, Items.plastanium, 35, Items.silicon, 60)); + craftEffect = Fx.smeltsmoke; + outputItem = new ItemStack(Items.silicon, 5); + craftTime = 140f; + size = 3; + hasPower = true; + hasLiquids = false; + flameColor = Color.valueOf("ffef99"); + itemCapacity = 30; + boostScale = 0.15f; + + consumes.items(new ItemStack(Items.coal, 3), new ItemStack(Items.sand, 6), new ItemStack(Items.pyratite, 1)); + consumes.power(4f); + }}; + kiln = new GenericSmelter("kiln"){{ requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.graphite, 30, Items.lead, 30)); craftEffect = Fx.smeltsmoke; @@ -655,6 +674,24 @@ public class Blocks implements ContentList{ consumes.liquid(Liquids.slag, 0.07f); }}; + disassembler = new Separator("disassembler"){{ + requirements(Category.crafting, ItemStack.with(Items.graphite, 140, Items.titanium, 100, Items.silicon, 150, Items.surgealloy, 70)); + results = ItemStack.with( + Items.sand, 4, + Items.graphite, 2, + Items.titanium, 2, + Items.thorium, 1 + ); + hasPower = true; + craftTime = 15f; + size = 3; + itemCapacity = 20; + + consumes.power(4f); + consumes.item(Items.scrap); + consumes.liquid(Liquids.slag, 0.12f); + }}; + sporePress = new GenericCrafter("spore-press"){{ requirements(Category.crafting, ItemStack.with(Items.lead, 35, Items.silicon, 30)); liquidCapacity = 60f; @@ -758,6 +795,7 @@ public class Blocks implements ContentList{ requirements(Category.defense, ItemStack.with(Items.plastanium, 5, Items.metaglass, 2)); health = 190 * wallHealthMultiplier; insulated = true; + absorbLasers = true; }}; plastaniumWallLarge = new Wall("plastanium-wall-large"){{ @@ -765,6 +803,7 @@ public class Blocks implements ContentList{ health = 190 * wallHealthMultiplier * 4; size = 2; insulated = true; + absorbLasers = true; }}; thoriumWall = new Wall("thorium-wall"){{ @@ -875,6 +914,18 @@ public class Blocks implements ContentList{ consumes.item(Items.phasefabric).boost(); }}; + //TODO better name + largeOverdriveProjector = new OverdriveProjector("large-overdrive-projector"){{ + requirements(Category.effect, ItemStack.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(ItemStack.with(Items.phasefabric, 1, Items.silicon, 1)); + }}; + forceProjector = new ForceProjector("force-projector"){{ requirements(Category.effect, ItemStack.with(Items.lead, 100, Items.titanium, 75, Items.silicon, 125)); size = 3; @@ -987,7 +1038,11 @@ public class Blocks implements ContentList{ consumes.power(1.75f); }}; - massConveyor = new PayloadConveyor("mass-conveyor"){{ + payloadConveyor = new PayloadConveyor("mass-conveyor"){{ + requirements(Category.distribution, ItemStack.with(Items.copper, 1)); + }}; + + payloadRouter = new PayloadRouter("payload-router"){{ requirements(Category.distribution, ItemStack.with(Items.copper, 1)); }}; @@ -1141,8 +1196,8 @@ public class Blocks implements ContentList{ rtgGenerator = new DecayGenerator("rtg-generator"){{ requirements(Category.power, ItemStack.with(Items.lead, 100, Items.silicon, 75, Items.phasefabric, 25, Items.plastanium, 75, Items.thorium, 50)); size = 2; - powerProduction = 3f; - itemDuration = 440f; + powerProduction = 4f; + itemDuration = 500f; }}; solarPanel = new SolarGenerator("solar-panel"){{ @@ -1315,25 +1370,6 @@ public class Blocks implements ContentList{ speed = 7f; }}; - launchPad = new LaunchPad("launch-pad"){{ - requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150)); - size = 3; - itemCapacity = 100; - launchTime = 60f * 20; - hasPower = true; - consumes.power(4f); - }}; - - launchPadLarge = new LaunchPad("launch-pad-large"){{ - requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.titanium, 200, Items.silicon, 150, Items.lead, 250, Items.plastanium, 75)); - size = 4; - itemCapacity = 300; - launchTime = 60f * 35; - hasPower = true; - consumes.power(6f); - }}; - - //endregion //region turrets @@ -1359,7 +1395,7 @@ public class Blocks implements ContentList{ rotatespeed = 10f; }}; - scatter = new BurstTurret("scatter"){{ + scatter = new ItemTurret("scatter"){{ requirements(Category.turret, ItemStack.with(Items.copper, 85, Items.lead, 45)); ammo( Items.scrap, Bullets.flakScrap, @@ -1399,13 +1435,14 @@ public class Blocks implements ContentList{ shootSound = Sounds.flame; }}; - hail = new ArtilleryTurret("hail"){{ + hail = new ItemTurret("hail"){{ requirements(Category.turret, ItemStack.with(Items.copper, 40, Items.graphite, 17)); ammo( Items.graphite, Bullets.artilleryDense, Items.silicon, Bullets.artilleryHoming, Items.pyratite, Bullets.artilleryIncendiary ); + targetAir = false; reloadTime = 60f; recoilAmount = 2f; range = 230f; @@ -1423,11 +1460,13 @@ public class Blocks implements ContentList{ Liquids.cryofluid, Bullets.cryoShot, Liquids.oil, Bullets.oilShot ); + targetAir = false; size = 2; recoilAmount = 0f; reloadTime = 2f; inaccuracy = 5f; shootCone = 50f; + liquidCapacity = 10f; shootEffect = Fx.shootLiquid; range = 110f; health = 250 * size * size; @@ -1447,7 +1486,7 @@ public class Blocks implements ContentList{ powerUse = 2.5f; shootShake = 2f; shootEffect = Fx.lancerLaserShoot; - smokeEffect = Fx.lancerLaserShootSmoke; + smokeEffect = Fx.none; chargeEffect = Fx.lancerLaserCharge; chargeBeginEffect = Fx.lancerLaserChargeBegin; heatColor = Color.red; @@ -1474,25 +1513,25 @@ public class Blocks implements ContentList{ shootSound = Sounds.spark; }}; - swarmer = new BurstTurret("swarmer"){{ + swarmer = new ItemTurret("swarmer"){{ requirements(Category.turret, ItemStack.with(Items.graphite, 35, Items.titanium, 35, Items.plastanium, 45, Items.silicon, 30)); ammo( Items.blastCompound, Bullets.missileExplosive, Items.pyratite, Bullets.missileIncendiary, Items.surgealloy, Bullets.missileSurge ); - reloadTime = 40f; + reloadTime = 30f; shots = 4; burstSpacing = 5; inaccuracy = 10f; - range = 185f; + range = 190f; xRand = 6f; size = 2; health = 300 * size * size; shootSound = Sounds.missile; }}; - salvo = new BurstTurret("salvo"){{ + salvo = new ItemTurret("salvo"){{ requirements(Category.turret, ItemStack.with(Items.copper, 105, Items.graphite, 95, Items.titanium, 60)); ammo( Items.copper, Bullets.standardCopper, @@ -1509,7 +1548,7 @@ public class Blocks implements ContentList{ ammoEjectBack = 3f; cooldown = 0.03f; recoilAmount = 3f; - shootShake = 2f; + shootShake = 1f; burstSpacing = 3f; shots = 4; ammoUseEffect = Fx.shellEjectBig; @@ -1570,7 +1609,7 @@ public class Blocks implements ContentList{ }); }}; - ripple = new ArtilleryTurret("ripple"){{ + ripple = new ItemTurret("ripple"){{ requirements(Category.turret, ItemStack.with(Items.copper, 150, Items.graphite, 135, Items.titanium, 60)); ammo( Items.graphite, Bullets.artilleryDense, @@ -1579,6 +1618,8 @@ public class Blocks implements ContentList{ Items.blastCompound, Bullets.artilleryExplosive, Items.plastanium, Bullets.artilleryPlastic ); + + targetAir = false; size = 3; shots = 4; inaccuracy = 12f; @@ -1591,6 +1632,7 @@ public class Blocks implements ContentList{ recoilAmount = 6f; shootShake = 2f; range = 290f; + minRange = 50f; health = 130 * size * size; shootSound = Sounds.artillery; @@ -1652,7 +1694,7 @@ public class Blocks implements ContentList{ size = 4; shootShake = 2f; range = 190f; - reloadTime = 80f; + reloadTime = 90f; firingMoveFract = 0.5f; shootDuration = 220f; powerUse = 14f; @@ -1664,6 +1706,18 @@ public class Blocks implements ContentList{ consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.5f)).update(false); }}; + segment = new PointDefenseTurret("segment"){{ + requirements(Category.turret, ItemStack.with(Items.silicon, 80, Items.thorium, 80, Items.surgealloy, 50)); + + hasPower = true; + consumes.power(3f); + size = 2; + shootLength = 5f; + bulletDamage = 12f; + reloadTime = 25f; + health = 190 * size * size; + }}; + //endregion //region units @@ -1711,6 +1765,12 @@ public class Blocks implements ContentList{ itemCapacity = 30; constructTime = 60f * 5f; + + upgrades = new UnitType[][]{ + {UnitTypes.dagger, UnitTypes.titan}, + {UnitTypes.crawler, UnitTypes.eruptor}, + {UnitTypes.wraith, UnitTypes.ghoul}, + }; }}; repairPoint = new RepairPoint("repair-point"){{ @@ -1773,6 +1833,41 @@ public class Blocks implements ContentList{ new LegacyCommandCenter("legacy-command-center"); //endregion + //region campaign + + launchPad = new LaunchPad("launch-pad"){{ + requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150)); + size = 3; + itemCapacity = 100; + launchTime = 60f * 20; + hasPower = true; + consumes.power(4f); + }}; + + launchPadLarge = new LaunchPad("launch-pad-large"){{ + requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.titanium, 200, Items.silicon, 150, Items.lead, 250, Items.plastanium, 75)); + size = 4; + itemCapacity = 300; + launchTime = 60f * 35; + hasPower = true; + consumes.power(6f); + }}; + + coreSilo = new CoreLauncher("core-silo"){{ + requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150)); + size = 5; + itemCapacity = 500; + + consumes.items(ItemStack.with(Items.copper, 500)); + }}; + + dataProcessor = new ResearchBlock("data-processor"){{ + requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150)); + + size = 3; + }}; + + //endregion campaign //region experimental blockForge = new BlockForge("block-forge"){{ @@ -1782,13 +1877,6 @@ public class Blocks implements ContentList{ size = 3; }}; - blockLauncher = new BlockLauncher("block-launcher"){{ - requirements(Category.production, BuildVisibility.debugOnly, ItemStack.with(Items.thorium, 100)); - size = 3; - hasPower = true; - consumes.power(2f); - }}; - blockLoader = new BlockLoader("block-loader"){{ requirements(Category.production, BuildVisibility.debugOnly, ItemStack.with(Items.thorium, 100)); hasPower = true; diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index 1d0e8d7207..946fb926e0 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -17,26 +17,26 @@ public class Bullets implements ContentList{ public static BulletType //artillery - artilleryDense, artilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, artilleryUnit, + artilleryDense, artilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, //flak flakScrap, flakLead, flakPlastic, flakExplosive, flakSurge, flakGlass, glassFrag, //missiles - missileExplosive, missileIncendiary, missileSurge, missileJavelin, missileSwarm, missileRevenant, + missileExplosive, missileIncendiary, missileSurge, missileJavelin, missileSwarm, //standard standardCopper, standardDense, standardThorium, standardHoming, standardIncendiary, standardMechSmall, standardGlaive, standardDenseBig, standardThoriumBig, standardIncendiaryBig, //electric - lancerLaser, meltdownLaser, lightning, arc, damageLightning, + lancerLaser, meltdownLaser, arc, damageLightning, //liquid waterShot, cryoShot, slagShot, oilShot, //environment, misc. - fireball, basicFlame, pyraFlame, driverBolt, healBullet, healBulletBig, frag, eruptorShot, + fireball, basicFlame, pyraFlame, driverBolt, healBullet, healBulletBig, frag, //bombs bombExplosive, bombIncendiary, bombOil; @@ -86,6 +86,8 @@ public class Bullets implements ContentList{ collidesTiles = false; splashDamageRadius = 25f; splashDamage = 33f; + reloadMultiplier = 1.2f; + ammoMultiplier = 3f; homingPower = 0.08f; homingRange = 50f; }}; @@ -97,7 +99,7 @@ public class Bullets implements ContentList{ bulletWidth = bulletHeight = 13f; collidesTiles = false; splashDamageRadius = 25f; - splashDamage = 30f; + splashDamage = 35f; status = StatusEffects.burning; frontColor = Pal.lightishOrange; backColor = Pal.lightOrange; @@ -120,19 +122,6 @@ public class Bullets implements ContentList{ statusDuration = 60f; }}; - artilleryUnit = new ArtilleryBulletType(2f, 8, "shell"){{ - hitEffect = Fx.blastExplosion; - knockback = 0.8f; - lifetime = 90f; - bulletWidth = bulletHeight = 14f; - collides = true; - collidesTiles = true; - splashDamageRadius = 20f; - splashDamage = 38f; - backColor = Pal.bulletYellowBack; - frontColor = Pal.bulletYellow; - }}; - glassFrag = new BasicBulletType(3f, 5, "bullet"){{ bulletWidth = 5f; bulletHeight = 12f; @@ -202,10 +191,10 @@ public class Bullets implements ContentList{ }}; flakSurge = new FlakBulletType(4.5f, 13){{ - splashDamage = 40f; + splashDamage = 45f; splashDamageRadius = 40f; - lightining = 2; - lightningLength = 12; + lightning = 2; + lightningLength = 7; shootEffect = Fx.shootBig; }}; @@ -233,24 +222,24 @@ public class Bullets implements ContentList{ bulletShrink = 0f; drag = -0.01f; homingPower = 0.08f; - splashDamageRadius = 10f; - splashDamage = 10f; + splashDamageRadius = 20f; + splashDamage = 20f; lifetime = 160f; hitEffect = Fx.blastExplosion; status = StatusEffects.burning; }}; - missileSurge = new MissileBulletType(4.4f, 15, "bullet"){{ + missileSurge = new MissileBulletType(4.4f, 20, "bullet"){{ bulletWidth = 8f; bulletHeight = 8f; bulletShrink = 0f; drag = -0.01f; - splashDamageRadius = 30f; - splashDamage = 22f; + splashDamageRadius = 28f; + splashDamage = 40f; lifetime = 150f; hitEffect = Fx.blastExplosion; despawnEffect = Fx.blastExplosion; - lightining = 2; + lightning = 2; lightningLength = 14; }}; @@ -291,25 +280,6 @@ public class Bullets implements ContentList{ weaveMag = 2f; }}; - missileRevenant = new MissileBulletType(2.7f, 12, "missile"){{ - bulletWidth = 8f; - bulletHeight = 8f; - bulletShrink = 0f; - drag = -0.003f; - homingRange = 60f; - keepVelocity = false; - splashDamageRadius = 25f; - splashDamage = 10f; - lifetime = 60f; - trailColor = Pal.unitBack; - backColor = Pal.unitBack; - frontColor = Pal.unitFront; - hitEffect = Fx.blastExplosion; - despawnEffect = Fx.blastExplosion; - weaveScale = 6f; - weaveMag = 1f; - }}; - standardCopper = new BasicBulletType(2.5f, 9, "bullet"){{ bulletWidth = 7f; bulletHeight = 9f; @@ -336,11 +306,11 @@ public class Bullets implements ContentList{ lifetime = 60f; }}; - standardHoming = new BasicBulletType(3f, 9, "bullet"){{ + standardHoming = new BasicBulletType(3f, 12, "bullet"){{ bulletWidth = 7f; bulletHeight = 9f; homingPower = 0.08f; - reloadMultiplier = 1.4f; + reloadMultiplier = 1.5f; ammoMultiplier = 5; lifetime = 60f; }}; @@ -372,19 +342,19 @@ public class Bullets implements ContentList{ despawnEffect = Fx.hitBulletSmall; }}; - standardDenseBig = new BasicBulletType(7f, 44, "bullet"){{ + standardDenseBig = new BasicBulletType(7f, 55, "bullet"){{ bulletWidth = 15f; bulletHeight = 21f; shootEffect = Fx.shootBig; }}; - standardThoriumBig = new BasicBulletType(8f, 67, "bullet"){{ + standardThoriumBig = new BasicBulletType(8f, 80, "bullet"){{ bulletWidth = 16f; bulletHeight = 23f; shootEffect = Fx.shootBig; }}; - standardIncendiaryBig = new BasicBulletType(7f, 44, "bullet"){{ + standardIncendiaryBig = new BasicBulletType(7f, 60, "bullet"){{ bulletWidth = 16f; bulletHeight = 21f; frontColor = Pal.lightishOrange; @@ -399,6 +369,7 @@ public class Bullets implements ContentList{ despawnEffect = Fx.none; status = StatusEffects.shocked; statusDuration = 10f; + hittable = false; }}; healBullet = new HealBulletType(5.2f, 13){{ @@ -412,9 +383,8 @@ public class Bullets implements ContentList{ fireball = new BulletType(1f, 4){ { pierce = true; - hitTiles = false; - collides = false; collidesTiles = false; + collides = false; drag = 0.03f; hitEffect = despawnEffect = Fx.none; } @@ -463,6 +433,7 @@ public class Bullets implements ContentList{ despawnEffect = Fx.none; status = StatusEffects.burning; keepVelocity = false; + hittable = false; } @Override @@ -487,6 +458,7 @@ public class Bullets implements ContentList{ hitEffect = Fx.hitFlameSmall; despawnEffect = Fx.none; status = StatusEffects.burning; + hittable = false; } @Override @@ -503,59 +475,15 @@ public class Bullets implements ContentList{ drawSize = 400f; }}; - meltdownLaser = new BulletType(0.001f, 70){ - Color tmpColor = new Color(); - Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white}; - float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; - float[] strokes = {2f, 1.5f, 1f, 0.3f}; - float[] lenscales = {1f, 1.12f, 1.15f, 1.17f}; - float length = 220f; + meltdownLaser = new ContinuousLaserBulletType(70){{ + length = 220f; + hitEffect = Fx.hitMeltdown; + drawSize = 420f; - { - hitEffect = Fx.hitMeltdown; - despawnEffect = Fx.none; - hitSize = 4; - drawSize = 420f; - lifetime = 16f; - pierce = true; - } - - @Override - public void update(Bulletc b){ - if(b.timer(1, 5f)){ - Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length, true); - } - Effects.shake(1f, 1f, b.x(), b.y()); - } - - @Override - public void hit(Bulletc b, float hitx, float hity){ - hitEffect.at(hitx, hity, colors[2]); - if(Mathf.chance(0.4)){ - Fires.create(world.tileWorld(hitx + Mathf.range(5f), hity + Mathf.range(5f))); - } - } - - @Override - public void draw(Bulletc b){ - float baseLen = (length) * b.fout(); - - Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen); - for(int s = 0; s < colors.length; s++){ - Draw.color(tmpColor.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f))); - for(int i = 0; i < tscales.length; i++){ - Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f); - Lines.stroke((9f + Mathf.absin(Time.time(), 0.8f, 1.5f)) * b.fout() * strokes[s] * tscales[i]); - Lines.lineAngle(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], CapStyle.none); - } - } - - Tmp.v1.trns(b.rotation(), baseLen * 1.1f); - - Drawf.light(b.x(), b.y(), b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, 40, Color.orange, 0.7f); - Draw.reset(); - } - }; + incendChance = 0.4f; + incendSpread = 5f; + incendAmount = 1; + }}; waterShot = new LiquidBulletType(Liquids.water){{ knockback = 0.7f; @@ -570,42 +498,10 @@ public class Bullets implements ContentList{ drag = 0.03f; }}; - eruptorShot = new LiquidBulletType(Liquids.slag){{ - damage = 2; - speed = 2.1f; - drag = 0.02f; - shootEffect = Fx.shootSmall; - }}; - oilShot = new LiquidBulletType(Liquids.oil){{ drag = 0.03f; }}; - lightning = new BulletType(0.001f, 12f){ - { - lifetime = 1f; - shootEffect = Fx.hitLancer; - smokeEffect = Fx.none; - despawnEffect = Fx.none; - hitEffect = Fx.hitLancer; - keepVelocity = false; - } - - @Override - public float range(){ - return 70f; - } - - @Override - public void draw(Bulletc b){ - } - - @Override - public void init(Bulletc b){ - Lightning.create(b.team(), Pal.lancerLaser, damage * (b.owner().isLocal() ? state.rules.playerDamageMultiplier : 1f), b.x(), b.y(), b.rotation(), 30); - } - }; - arc = new LightningBulletType(){{ damage = 21; lightningLength = 25; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 1a5b6621da..7af54291dc 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -12,13 +12,12 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; -import mindustry.world.*; -import mindustry.world.blocks.experimental.BlockLauncher.*; +import static arc.graphics.g2d.Draw.rect; import static arc.graphics.g2d.Draw.*; import static arc.graphics.g2d.Lines.*; import static arc.math.Angles.*; -import static mindustry.Vars.*; +import static mindustry.Vars.tilesize; public class Fx{ public static final Effect @@ -103,18 +102,21 @@ public class Fx{ Fill.circle(x, y, e.fslope() * 1.5f * size); }), - blockTransfer = new Effect(25f, e -> { - if(!(e.data instanceof LaunchedBlock)) return; + pointBeam = new Effect(25f, e -> { + if(!(e.data instanceof Position)) return; - LaunchedBlock l = e.data(); + Position pos = e.data(); - Block block = l.block; - Position to = Tmp.v3.set(l.x * tilesize, l.y * tilesize).add(block.offset(), block.offset()); + Draw.color(e.color); + Draw.alpha(e.fout()); + Lines.stroke(1.5f); + Lines.line(e.x, e.y, pos.getX(), pos.getY()); + }), - Tmp.v1.set(e.x, e.y).interpolate(Tmp.v2.set(to), e.fin(), Interp.linear); - float x = Tmp.v1.x, y = Tmp.v1.y; - - Draw.rect(block.icon(Cicon.full), x, y); + pointHit = new Effect(8f, e -> { + color(Color.white, e.color, e.fin()); + stroke(e.fout() * 1f + 0.2f); + Lines.circle(e.x, e.y, e.fin() * 6f); }), lightning = new Effect(10f, 500f, e -> { @@ -123,10 +125,10 @@ public class Fx{ stroke(3f * e.fout()); color(e.color, Color.white, e.fin()); - beginLine(); - linePoint(e.x, e.y); + beginLine(); lines.each(Lines::linePoint); + linePoint(e.x, e.y); endLine(); int i = 0; @@ -180,6 +182,12 @@ public class Fx{ Fill.circle(e.x, e.y, (1f + 6f * e.rotation) - e.fin()*2f); }), + rocketSmokeLarge = new Effect(220, e -> { + color(Color.gray); + alpha(Mathf.clamp(e.fout()*1.6f - Interp.pow3In.apply(e.rotation)*1.2f)); + Fill.circle(e.x, e.y, (1f + 6f * e.rotation * 1.3f) - e.fin()*2f); + }), + magmasmoke = new Effect(110, e -> { color(Color.gray); Fill.circle(e.x, e.y, e.fslope() * 6f); @@ -876,8 +884,9 @@ public class Fx{ lancerLaserShootSmoke = new Effect(26f, e -> { color(Color.white); + float length = e.data == null ? 70f : (Float)e.data; - randLenVectors(e.id, 7, 70f, e.rotation, 0f, (x, y) -> { + randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> { lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); }); @@ -909,6 +918,16 @@ public class Fx{ }), + sparkShoot = new Effect(12f, e -> { + color(Color.white, e.color, e.fin()); + stroke(e.fout() * 1.2f + 0.6f); + + randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 3f, (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 5f + 0.5f); + }); + + }), + lightningShoot = new Effect(12f, e -> { color(Color.white, Pal.lancerLaser, e.fin()); stroke(e.fout() * 1.2f + 0.5f); diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java index 314c8b0666..0cb848f6c8 100644 --- a/core/src/mindustry/content/TechTree.java +++ b/core/src/mindustry/content/TechTree.java @@ -2,6 +2,7 @@ package mindustry.content; import arc.math.*; import arc.struct.*; +import arc.util.ArcAnnotate.*; import mindustry.ctype.*; import mindustry.game.Objectives.*; import mindustry.type.*; @@ -314,15 +315,17 @@ public class TechTree implements ContentList{ public static class TechNode{ private static TechNode context; + /** Depth in tech tree. */ + public int depth; /** Requirement node. */ - public TechNode parent; + public @Nullable TechNode parent; /** Content to be researched. */ public UnlockableContent content; /** Item requirements for this content. */ public ItemStack[] requirements; /** Extra objectives needed to research this. TODO implement */ public Objective[] objectives = {}; - /** Turns required to research this content. */ + /** Research turns required to research this content. */ public int turns = 3; //TODO keep track of turns that have been used so far /** Nodes that depend on this node. */ public final Array children = new Array<>(); @@ -335,6 +338,7 @@ public class TechTree implements ContentList{ this.parent = ccontext; this.content = content; this.requirements = requirements; + this.depth = parent == null ? 0 : parent.depth + 1; context = this; children.run(); diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index b126884840..3f6f8a869f 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -3,6 +3,7 @@ package mindustry.content; import arc.graphics.*; import arc.math.*; import arc.struct.*; +import mindustry.ai.types.*; import mindustry.annotations.Annotations.*; import mindustry.ctype.*; import mindustry.entities.bullet.*; @@ -13,13 +14,16 @@ import mindustry.type.*; public class UnitTypes implements ContentList{ //ground - public static @EntityDef({Unitc.class, Mechc.class}) UnitType titan, dagger, crawler, fortress, eruptor, chaosArray, eradicator; + public static @EntityDef({Unitc.class, Mechc.class}) UnitType titan, dagger, crawler, fortress, chaosArray, eradicator; //ground + builder - public static @EntityDef({Unitc.class, Mechc.class, Builderc.class}) UnitType oculon, tau; + public static @EntityDef({Unitc.class, Mechc.class, Builderc.class}) UnitType tau; + + //ground + builder + miner + commander + public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType oculon; //legs - public static @EntityDef({Unitc.class, Legsc.class}) UnitType cix; + public static @EntityDef({Unitc.class, Legsc.class}) UnitType cix, eruptor; //air public static @EntityDef({Unitc.class}) UnitType wraith, reaper, ghoul, revenant, lich; @@ -72,33 +76,7 @@ public class UnitTypes implements ContentList{ }}); }}; - cix = new UnitType("cix"){{ - drag = 0.1f; - speed = 0.8f; - hitsize = 9f; - health = 140; - - legCount = 6; - rotateShooting = false; - - for(boolean b : Mathf.booleans){ - weapons.add( - new Weapon("missiles-mount"){{ - reload = 20f; - x = 4f * Mathf.sign(b); - rotate = true; - mirror = false; - flipSprite = !b; - shake = 1f; - bullet = Bullets.missileSwarm; - }}); - } - }}; - titan = new UnitType("titan"){{ - dagger.upgrade = this; - tier = 2; - speed = 0.4f; hitsize = 9f; range = 10f; @@ -117,28 +95,6 @@ public class UnitTypes implements ContentList{ }}); }}; - crawler = new UnitType("crawler"){{ - speed = 0.65f; - hitsize = 8f; - health = 120; - sway = 0.25f; - weapons.add(new Weapon(){{ - reload = 12f; - shootCone = 180f; - ejectEffect = Fx.none; - shootSound = Sounds.explosion; - bullet = new BombBulletType(2f, 3f, "clear"){{ - hitEffect = Fx.pulverize; - lifetime = 30f; - speed = 1.1f; - splashDamageRadius = 55f; - instantDisappear = true; - splashDamage = 30f; - killShooter = true; - }}; - }}); - }}; - tau = new UnitType("tau"){{ itemCapacity = 60; canBoost = true; @@ -190,9 +146,6 @@ public class UnitTypes implements ContentList{ }; fortress = new UnitType("fortress"){{ - titan.upgrade = this; - tier = 3; - speed = 0.38f; hitsize = 13f; rotateSpeed = 3f; @@ -206,15 +159,50 @@ public class UnitTypes implements ContentList{ recoil = 4f; shake = 2f; ejectEffect = Fx.shellEjectMedium; - bullet = Bullets.artilleryUnit; shootSound = Sounds.artillery; + bullet = new ArtilleryBulletType(2f, 8, "shell"){{ + hitEffect = Fx.blastExplosion; + knockback = 0.8f; + lifetime = 110f; + bulletWidth = bulletHeight = 14f; + collides = true; + collidesTiles = true; + splashDamageRadius = 20f; + splashDamage = 38f; + backColor = Pal.bulletYellowBack; + frontColor = Pal.bulletYellow; + }}; + }}); + }}; + + crawler = new UnitType("crawler"){{ + defaultController = SuicideAI::new; + + speed = 0.8f; + hitsize = 8f; + health = 140; + sway = 0.25f; + range = 40f; + + weapons.add(new Weapon(){{ + reload = 12f; + shootCone = 180f; + ejectEffect = Fx.none; + shootSound = Sounds.explosion; + bullet = new BombBulletType(0f, 0f, "clear"){{ + hitEffect = Fx.pulverize; + lifetime = 10f; + speed = 1f; + splashDamageRadius = 55f; + instantDisappear = true; + splashDamage = 30f; + killShooter = true; + hittable = false; + }}; }}); }}; eruptor = new UnitType("eruptor"){{ - crawler.upgrade = this; - tier = 2; - speed = 0.4f; drag = 0.4f; hitsize = 10f; @@ -222,18 +210,59 @@ public class UnitTypes implements ContentList{ targetAir = false; health = 600; immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); + legCount = 4; + legLength = 9f; + legTrns = 2f; + legMoveSpace = 1.4f; + weapons.add(new Weapon("eruption"){{ shootY = 3f; reload = 10f; alternate = true; ejectEffect = Fx.none; - bullet = Bullets.eruptorShot; recoil = 1f; x = 7f; shootSound = Sounds.flame; + + bullet = new LiquidBulletType(Liquids.slag){{ + damage = 11; + speed = 2.3f; + drag = 0.02f; + shootEffect = Fx.shootSmall; + }}; }}); }}; + cix = new UnitType("cix"){{ + drag = 0.1f; + speed = 0.4f; + hitsize = 9f; + health = 140; + baseElevation = 0.51f; + + legCount = 6; + legMoveSpace = 0.9f; + legLength = 34f; + rotateShooting = false; + legExtension = -15; + legBaseOffset = 8f; + landShake = 2f; + legSpeed = 0.1f; + + for(boolean b : Mathf.booleans){ + weapons.add( + new Weapon("missiles-mount"){{ + reload = 20f; + x = 4f * Mathf.sign(b); + rotate = true; + mirror = false; + flipSprite = !b; + shake = 1f; + bullet = Bullets.missileSwarm; + }}); + } + }}; + wraith = new UnitType("wraith"){{ speed = 3f; accel = 0.08f; @@ -255,9 +284,6 @@ public class UnitTypes implements ContentList{ }}; ghoul = new UnitType("ghoul"){{ - wraith.upgrade = this; - tier = 2; - health = 220; speed = 2f; accel = 0.08f; @@ -282,6 +308,51 @@ public class UnitTypes implements ContentList{ }}); }}; + revenant = new UnitType("revenant"){{ + health = 220; + speed = 1.9f; + accel = 0.04f; + drag = 0.016f; + flying = true; + range = 140f; + hitsize = 18f; + lowAltitude = true; + + engineOffset = 12f; + engineSize = 3f; + + for(boolean b : Mathf.booleans){ + weapons.add( + new Weapon("revenant-missiles"){{ + reload = 70f; + x = 7f * Mathf.sign(b); + rotate = true; + mirror = false; + flipSprite = !b; + shake = 1f; + + bullet = new MissileBulletType(2.7f, 12, "missile"){{ + bulletWidth = 8f; + bulletHeight = 8f; + bulletShrink = 0f; + drag = -0.003f; + homingRange = 60f; + keepVelocity = false; + splashDamageRadius = 25f; + splashDamage = 10f; + lifetime = 60f; + trailColor = Pal.unitBack; + backColor = Pal.unitBack; + frontColor = Pal.unitFront; + hitEffect = Fx.blastExplosion; + despawnEffect = Fx.blastExplosion; + weaveScale = 6f; + weaveMag = 1f; + }}; + }}); + } + }}; + reaper = new UnitType("reaper"){{ speed = 1.1f; accel = 0.02f; @@ -370,18 +441,27 @@ public class UnitTypes implements ContentList{ hitsize = 8f; weapons.add(new Weapon("small-basic-weapon"){{ - reload = 25f; + reload = 15f; x = -1f; y = -1f; shootX = 3.5f; alternate = true; - ejectEffect = Fx.none; - //TODO use different ammo - bullet = Bullets.standardCopper; + + bullet = new BasicBulletType(2.5f, 9){{ + bulletWidth = 7f; + bulletHeight = 9f; + lifetime = 60f; + shootEffect = Fx.shootSmall; + smokeEffect = Fx.shootSmallSmoke; + tileDamageMultiplier = 0.15f; + ammoMultiplier = 2; + }}; }}); }}; phantom = new UnitType("phantom"){{ + defaultController = BuilderAI::new; + flying = true; drag = 0.05f; speed = 3f; @@ -396,8 +476,6 @@ public class UnitTypes implements ContentList{ }}; oculon = new UnitType("oculon"){{ - tier = 2; - drillTier = -1; speed = 0.6f; hitsize = 9f; @@ -429,8 +507,6 @@ public class UnitTypes implements ContentList{ }}; trident = new UnitType("trident"){{ - //wraith.upgrade = this; - tier = 3; health = 500; speed = 2f; @@ -517,37 +593,6 @@ public class UnitTypes implements ContentList{ }}); }}; - revenant = new UnitType("revenant", HoverUnit::new){{ - health = 1000; - mass = 5f; - hitsize = 20f; - speed = 0.1f; - maxVelocity = 1f; - drag = 0.01f; - range = 80f; - shootCone = 40f; - flying = true; - //rotateWeapons = true; - engineOffset = 12f; - engineSize = 3f; - rotatespeed = 0.01f; - attackLength = 90f; - baseRotateSpeed = 0.06f; - weapons.add(new Weapon("revenant-missiles"){{ - length = 3f; - reload = 70f; - width = 10f; - shots = 2; - inaccuracy = 2f; - alternate = true; - ejectEffect = Fx.none; - velocityRnd = 0.2f; - spacing = 1f; - shootSound = Sounds.missile; - bullet = Bullets.missileRevenant; - }}); - }}; - lich = new UnitType("lich", HoverUnit::new){{ health = 6000; mass = 20f; @@ -622,47 +667,6 @@ public class UnitTypes implements ContentList{ shootSound = Sounds.shootBig; }}); }}; - - - /* - vanguard = new UnitType("vanguard-ship"){ - float healRange = 60f; - float healReload = 200f; - float healPercent = 10f; - - { - flying = true; - drillTier = 1; - mineSpeed = 4f; - speed = 0.49f; - drag = 0.09f; - health = 200f; - weaponOffsetX = -1; - engineSize = 2.3f; - weaponOffsetY = -1; - engineColor = Pal.lightTrail; - cellTrnsY = 1f; - buildSpeed = 1.2f; - weapons.add(new Weapon("vanguard-gun"){{ - length = 1.5f; - reload = 30f; - alternate = true; - inaccuracy = 6f; - velocityRnd = 0.1f; - ejectEffect = Fx.none; - bullet = new HealBulletType(){{ - healPercent = 3f; - backColor = engineColor; - homingPower = 20f; - bulletHeight = 4f; - bulletWidth = 1.5f; - damage = 3f; - speed = 4f; - lifetime = 40f; - shootEffect = Fx.shootHealYellow; - smokeEffect = hitEffect = despawnEffect = Fx.hitYellowLaser; - }}); - }}; } @Override @@ -683,46 +687,6 @@ public class UnitTypes implements ContentList{ } }; - "alpha "= new UnitType("alpha-mech", false){ - { - drillTier = -1; - speed = 0.5f; - boostSpeed = 0.95f; - itemCapacity = 15; - mass = 0.9f; - health = 150f; - buildSpeed = 0.9f; - weaponOffsetX = 1; - weaponOffsetY = -1; - engineColor = Pal.heal; - - weapons.add(new Weapon("shockgun"){{ - shake = 2f; - length = 0.5f; - reload = 70f; - alternate = true; - recoil = 4f; - width = 5f; - shootSound = Sounds.laser; - - bullet = new LaserBulletType(){{ - damage = 20f; - recoil = 1f; - sideAngle = 45f; - sideWidth = 1f; - sideLength = 70f; - colors = new Color[]{Pal.heal.cpy().a(0.4f), Pal.heal, Color.white}; - }}); - }}; - } - - @Override - public void update(Playerc player){ - player.heal(Time.delta() * 0.09f); - } - - }; - delta = new UnitType("delta-mech", false){ { drillPower = 1; @@ -989,48 +953,6 @@ public class UnitTypes implements ContentList{ } }; - trident = new UnitType("trident-ship"){ - { - flying = true; - drillPower = 2; - speed = 0.15f; - drag = 0.034f; - mass = 2.5f; - turnCursor = false; - health = 250f; - itemCapacity = 30; - engineColor = Color.valueOf("84f491"); - cellTrnsY = 1f; - buildSpeed = 2.5f; - weapons.add(new Weapon("bomber"){{ - length = 0f; - width = 2f; - reload = 25f; - shots = 2; - shotDelay = 1f; - shots = 8; - alternate = true; - ejectEffect = Fx.none; - velocityRnd = 1f; - inaccuracy = 20f; - ignoreRotation = true; - bullet = new BombBulletType(16f, 25f, "shell"){{ - bulletWidth = 10f; - bulletHeight = 14f; - hitEffect = Fx.flakExplosion; - shootEffect = Fx.none; - smokeEffect = Fx.none; - shootSound = Sounds.artillery; - }}); - }}; - } - - @Override - public boolean canShoot(Playerc player){ - return player.vel().len() > 1.2f; - } - }; - glaive = new UnitType("glaive-ship"){ { flying = true; @@ -1054,8 +976,6 @@ public class UnitTypes implements ContentList{ shootSound = Sounds.shootSnap; }}; } - }; - - starter = vanguard;*/ + };*/ } } diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java index d0b2a137d8..2fc40aa169 100644 --- a/core/src/mindustry/content/Weathers.java +++ b/core/src/mindustry/content/Weathers.java @@ -62,7 +62,7 @@ public class Weathers implements ContentList{ }; rain = new Weather("rain"){ - float yspeed = 7f, xspeed = 2f, padding = 16f, size = 40f, density = 1200f; + float yspeed = 5f, xspeed = 1.5f, padding = 16f, size = 40f, density = 1200f; TextureRegion[] splashes = new TextureRegion[12]; @Override diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index 81b1605e0d..e0adf6f89a 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -136,6 +136,9 @@ public class ContentLoader{ Block block = block(i); block.mapColor.rgba8888(color); + //partial alpha colors indicate a square sprite + block.squareSprite = block.mapColor.a > 0.5f; + block.mapColor.a = 1f; block.hasColor = true; } } diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index db2e4686e2..51ab59a460 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -23,6 +23,8 @@ public class GameState{ public Rules rules = new Rules(); /** Statistics for this save/game. Displayed after game over. */ public Stats stats = new Stats(); + /** Sector information. Only valid in the campaign. */ + public SectorInfo secinfo = new SectorInfo(); /** Team data. Gets reset every new game. */ public Teams teams = new Teams(); /** Number of enemies in the game; only used clientside in servers. */ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 502d3f2571..871979bcaf 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -65,23 +65,23 @@ public class Logic implements ApplicationListener{ //remove existing blocks that have been placed here. //painful O(n) iteration + copy - for(int i = 0; i < data.brokenBlocks.size; i++){ - BrokenBlock b = data.brokenBlocks.get(i); + 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.brokenBlocks.removeIndex(i); + data.blocks.removeIndex(i); break; } } - data.brokenBlocks.addFirst(new BrokenBlock(tile.x, tile.y, tile.rotation(), block.id, tile.entity.config())); + data.blocks.addFirst(new BlockPlan(tile.x, tile.y, tile.rotation(), block.id, tile.entity.config())); }); Events.on(BlockBuildEndEvent.class, event -> { if(!event.breaking){ TeamData data = state.teams.get(event.team); - Iterator it = data.brokenBlocks.iterator(); + Iterator it = data.blocks.iterator(); while(it.hasNext()){ - BrokenBlock b = it.next(); + BlockPlan b = it.next(); Block block = content.block(b.block); if(event.tile.block().bounds(event.tile.x, event.tile.y, Tmp.r1).overlaps(block.bounds(b.x, b.y, Tmp.r2))){ it.remove(); @@ -90,7 +90,7 @@ public class Logic implements ApplicationListener{ } }); - Events.on(LaunchItemEvent.class, e -> state.stats.handleItemExport(e.stack)); + Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack)); //when loading a 'damaged' sector, propagate the damage Events.on(WorldLoadEvent.class, e -> { @@ -100,13 +100,14 @@ public class Logic implements ApplicationListener{ } }); - //TODO this should be in the same place as launch handling code + //TODO dying takes up a turn (?) + /* Events.on(GameOverEvent.class, e -> { //simulate a turn on a normal non-launch gameover if(state.isCampaign() && !state.launched){ universe.runTurn(); } - }); + });*/ //disable new waves after the boss spawns Events.on(WaveEvent.class, e -> { @@ -269,11 +270,9 @@ public class Logic implements ApplicationListener{ //save over the data w/o the cores sector.save.save(); - //TODO mark sector as not containing any cores //run a turn, since launching takes up a turn universe.runTurn(); - //TODO needs extra damage to prevent player from landing immediately afterwards sector.setTurnsPassed(sector.getTurnsPassed() + 3); Events.fire(new LaunchEvent()); @@ -300,7 +299,7 @@ public class Logic implements ApplicationListener{ } if(!state.isPaused()){ - state.stats.update(); + state.secinfo.update(); if(state.isCampaign()){ universe.update(); @@ -310,6 +309,20 @@ public class Logic implements ApplicationListener{ //weather is serverside if(!net.client()){ updateWeather(); + + for(TeamData data : state.teams.getActive()){ + if(data.hasAI() && data.hasCore()){ + data.ai.update(); + } + + //TODO this is terrible + //fills enemy core with resources + if(state.rules.enemyInfiniteResources && state.rules.waves && data.team == state.rules.waveTeam && data.hasCore()){ + for(Item item : content.items()){ + data.core().items.set(item, data.core().block.itemCapacity); + } + } + } } if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 7aa36a7981..8117bedd62 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -130,11 +130,11 @@ public class NetClient implements ApplicationListener{ } public void addPacketHandler(String type, Cons handler){ - customPacketHandlers.getOr(type, Array::new).add(handler); + customPacketHandlers.get(type, Array::new).add(handler); } public Array> getPacketHandlers(String type){ - return customPacketHandlers.getOr(type, Array::new); + return customPacketHandlers.get(type, Array::new); } @Remote(targets = Loc.server, variants = Variant.both) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index a38321807c..6c3f51e803 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -393,7 +393,7 @@ public class NetServer implements ApplicationListener{ }else if(found.team() != player.team()){ player.sendMessage("[scarlet]Only players on your team can be kicked."); }else{ - Timekeeper vtime = cooldowns.getOr(player.uuid(), () -> new Timekeeper(voteCooldown)); + Timekeeper vtime = cooldowns.get(player.uuid(), () -> new Timekeeper(voteCooldown)); if(!vtime.get()){ player.sendMessage("[scarlet]You must wait " + voteCooldown/60 + " minutes between votekicks."); @@ -481,11 +481,11 @@ public class NetServer implements ApplicationListener{ } public void addPacketHandler(String type, Cons2 handler){ - customPacketHandlers.getOr(type, Array::new).add(handler); + customPacketHandlers.get(type, Array::new).add(handler); } public Array> getPacketHandlers(String type){ - return customPacketHandlers.getOr(type, Array::new); + return customPacketHandlers.get(type, Array::new); } public static void onDisconnect(Playerc player, String reason){ @@ -641,6 +641,7 @@ public class NetServer implements ApplicationListener{ //now, put the new position, rotation and baserotation into the buffer so it can be read if(unit instanceof Mechc) fbuffer.put(baseRotation); //base rotation is optional + fbuffer.put(unit.elevation()); fbuffer.put(rotation); //rotation is always there fbuffer.put(newx); fbuffer.put(newy); @@ -861,7 +862,7 @@ public class NetServer implements ApplicationListener{ StringBuilder result = new StringBuilder(); int curChar = 0; - while(curChar < name.length() && result.toString().getBytes().length < maxNameLength){ + while(curChar < name.length() && result.toString().getBytes(Strings.utf8).length < maxNameLength){ result.append(name.charAt(curChar++)); } return result.toString(); diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 501e72789f..612131cf0e 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -13,6 +13,7 @@ import mindustry.content.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.graphics.g3d.*; import mindustry.ui.*; import static arc.Core.*; @@ -24,6 +25,7 @@ public class Renderer implements ApplicationListener{ public final OverlayRenderer overlays = new OverlayRenderer(); public final LightRenderer lights = new LightRenderer(); public final Pixelator pixelator = new Pixelator(); + public PlanetRenderer planets; public FrameBuffer effectBuffer = new FrameBuffer(); private Bloom bloom; @@ -47,6 +49,8 @@ public class Renderer implements ApplicationListener{ @Override public void init(){ + planets = new PlanetRenderer(); + if(settings.getBool("bloom")){ setupBloom(); } @@ -96,6 +100,7 @@ public class Renderer implements ApplicationListener{ minimap.dispose(); effectBuffer.dispose(); blocks.dispose(); + planets.dispose(); if(bloom != null){ bloom.dispose(); bloom = null; @@ -126,7 +131,6 @@ public class Renderer implements ApplicationListener{ bloom = null; } bloom = new Bloom(true); - bloom.setClearColor(0f, 0f, 0f, 0f); }catch(Throwable e){ e.printStackTrace(); settings.put("bloom", false); @@ -186,7 +190,6 @@ public class Renderer implements ApplicationListener{ graphics.clear(clearColor); Draw.reset(); - //TODO 'animated water' is a bad name for this setting if(Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")){ effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); } @@ -285,7 +288,7 @@ public class Renderer implements ApplicationListener{ } public void scaleCamera(float amount){ - targetscale += amount; + targetscale *= (amount / 4) + 1; clampScale(); } diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 6af7345412..00dc23c333 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -235,6 +235,11 @@ public class World{ } }); + //postgenerate for bases + if(sector.preset == null){ + sector.planet.generator.postGenerate(tiles); + } + //reset rules setSectorRules(sector); @@ -349,6 +354,35 @@ public class World{ } } + public boolean raycast(int x0f, int y0f, int x1, int y1, Raycaster cons){ + int x0 = x0f; + int y0 = y0f; + int dx = Math.abs(x1 - x0); + int dy = Math.abs(y1 - y0); + + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + + int err = dx - dy; + int e2; + while(true){ + + if(cons.accept(x0, y0)) return true; + if(x0 == x1 && y0 == y1) return false; + + e2 = 2 * err; + if(e2 > -dy){ + err = err - dy; + x0 = x0 + sx; + } + + if(e2 < dx){ + err = err + dx; + y0 = y0 + sy; + } + } + } + public void addDarkness(Tiles tiles){ byte[] dark = new byte[tiles.width * tiles.height]; byte[] writeBuffer = new byte[tiles.width * tiles.height]; diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index caf059ee67..01881c8b64 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -62,11 +62,6 @@ public abstract class UnlockableContent extends MappableContent{ return false; } - /** Override to make content always unlocked. */ - public boolean alwaysUnlocked(){ - return alwaysUnlocked; - } - public final boolean unlocked(){ return Vars.data.isUnlocked(this); } diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 6e9ceeb640..b408cde898 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -39,7 +39,7 @@ public class MapEditor{ loading = true; createTiles(width, height); - renderer.resize(width(), height()); + renderer.resize(width, height); loading = false; } diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 0b15e9cbaa..96792a7cc2 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -272,8 +272,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ editor.getTags().put("rules", JsonIO.write(state.rules)); editor.getTags().remove("width"); editor.getTags().remove("height"); - //TODO unkill player - //player.dead = true; + + player.clearUnit(); Map returned = null; @@ -529,7 +529,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ int i = 0; - for(Team team : Team.base()){ + for(Team team : Team.baseTeams){ ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglePartiali); button.margin(4f); button.getImageCell().grow(); diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index e8b1a05973..90bb2ed4a2 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -37,6 +37,8 @@ public class MapRenderer implements Disposable{ } public void resize(int width, int height){ + updates.clear(); + delayedUpdates.clear(); if(chunks != null){ for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 65f13e0c1b..26516d8ecb 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -13,6 +13,7 @@ import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.type.*; import mindustry.world.*; import static mindustry.Vars.*; @@ -173,9 +174,37 @@ public class Damage{ } /** Damages all entities and blocks in a radius that are enemies of the team. */ - public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){ + public static void damage(Team team, float x, float y, float radius, float damage, boolean air, boolean ground){ + damage(team, x, y, radius, damage, false, air, ground); + } + + /** Applies a status effect to all enemy units in a range. */ + public static void status(Team team, float x, float y, float radius, StatusEffect effect, float duration, boolean air, boolean ground){ Cons cons = entity -> { - if(entity.team() == team || entity.dst(x, y) > radius){ + if(entity.team() == team || !entity.within(x, y, radius) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){ + return; + } + + entity.apply(effect, duration); + }; + + rect.setSize(radius * 2).setCenter(x, y); + if(team != null){ + Units.nearbyEnemies(team, rect, cons); + }else{ + Units.nearby(rect, cons); + } + } + + /** Damages all entities and blocks in a radius that are enemies of the team. */ + public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){ + damage(team, x, y, radius, damage, complete, true, true); + } + + /** Damages all entities and blocks in a radius that are enemies of the team. */ + public static void damage(Team team, float x, float y, float radius, float damage, boolean complete, boolean air, boolean ground){ + Cons cons = entity -> { + if(entity.team() == team || !entity.within(x, y, radius) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){ return; } float amount = calculateDamage(x, y, entity.getX(), entity.getY(), radius, damage); @@ -207,47 +236,53 @@ public class Damage{ } } - public static void tileDamage(Team team, int startx, int starty, int radius, float baseDamage){ - bits.clear(); - propagation.clear(); - int bitOffset = bits.width() / 2; + public static void tileDamage(Team team, int startx, int starty, int baseRadius, float baseDamage){ + //tile damage is posted, so that destroying a block that causes a chain explosion will run in the next frame + //this prevents recursive damage calls from messing up temporary variables + Core.app.post(() -> { - propagation.addFirst(PropCell.get((byte)0, (byte)0, (short)baseDamage)); - //clamp radius to fit bits - radius = Math.min(radius, bits.width() / 2); + bits.clear(); + propagation.clear(); + int bitOffset = bits.width() / 2; - while(!propagation.isEmpty()){ - int prop = propagation.removeLast(); - int x = PropCell.x(prop); - int y = PropCell.y(prop); - int damage = PropCell.damage(prop); - //manhattan distance used for calculating falloff, results in a diamond pattern - int dst = Math.abs(x) + Math.abs(y); + propagation.addFirst(PropCell.get((byte)0, (byte)0, (short)baseDamage)); + //clamp radius to fit bits + int radius = Math.min(baseRadius, bits.width() / 2); - int scaledDamage = (int)(damage * (1f - (float)dst / radius)); + while(!propagation.isEmpty()){ + int prop = propagation.removeLast(); + int x = PropCell.x(prop); + int y = PropCell.y(prop); + int damage = PropCell.damage(prop); + //manhattan distance used for calculating falloff, results in a diamond pattern + int dst = Math.abs(x) + Math.abs(y); - bits.set(bitOffset + x, bitOffset + y); - Tilec tile = world.ent(startx + x, starty + y); + int scaledDamage = (int)(damage * (1f - (float)dst / radius)); - if(scaledDamage <= 0 || tile == null) continue; + bits.set(bitOffset + x, bitOffset + y); + Tile tile = world.tile(startx + x, starty + y); - //apply damage to entity if needed - if(tile.team() != team){ - int health = (int)tile.health(); - if(tile.health() > 0){ - tile.damage(scaledDamage); - scaledDamage -= health; + if(scaledDamage <= 0 || tile == null) continue; - if(scaledDamage <= 0) continue; + //apply damage to entity if needed + if(tile.entity != null && tile.team() != team){ + int health = (int)tile.entity.health(); + if(tile.entity.health() > 0){ + tile.entity.damage(scaledDamage); + scaledDamage -= health; + + if(scaledDamage <= 0) continue; + } + } + + for(Point2 p : Geometry.d4){ + if(!bits.get(bitOffset + x + p.x, bitOffset + y + p.y)){ + propagation.addFirst(PropCell.get((byte)(x + p.x), (byte)(y + p.y), (short)scaledDamage)); + } } } + }); - for(Point2 p : Geometry.d4){ - if(!bits.get(bitOffset + x + p.x, bitOffset + y + p.y)){ - propagation.addFirst(PropCell.get((byte)(x + p.x), (byte)(y + p.y), (short)scaledDamage)); - } - } - } } private static void completeDamage(Team team, float x, float y, float radius, float damage){ diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java index 9422f1008d..c0cd8aab85 100644 --- a/core/src/mindustry/entities/Lightning.java +++ b/core/src/mindustry/entities/Lightning.java @@ -11,7 +11,6 @@ import mindustry.world.*; import static mindustry.Vars.*; -//TODO move into a different class public class Lightning{ private static final Rand random = new Rand(); private static final Rect rect = new Rect(); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 14b2638006..e6c4559b0e 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -149,7 +149,6 @@ public class Units{ result = null; cdist = 0f; - //TODO optimize for(Unitc e : Groups.unit){ if(!predicate.get(e) || e.team() != team) continue; diff --git a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java index 6e43b53cee..1894b4c911 100644 --- a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java @@ -14,6 +14,7 @@ public class ArtilleryBulletType extends BasicBulletType{ collidesTiles = false; collides = false; collidesAir = false; + scaleVelocity = true; hitShake = 1f; hitSound = Sounds.explosion; } diff --git a/core/src/mindustry/entities/bullet/BasicBulletType.java b/core/src/mindustry/entities/bullet/BasicBulletType.java index f4edaf3924..0fc8fe05c9 100644 --- a/core/src/mindustry/entities/bullet/BasicBulletType.java +++ b/core/src/mindustry/entities/bullet/BasicBulletType.java @@ -22,6 +22,11 @@ public class BasicBulletType extends BulletType{ this.bulletSprite = bulletSprite; } + + public BasicBulletType(float speed, float damage){ + this(speed, damage, "bullet"); + } + /** For mods. */ public BasicBulletType(){ this(1f, 1f, "bullet"); diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 5c1fc43c4b..14b33712b5 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -1,6 +1,7 @@ package mindustry.entities.bullet; import arc.audio.*; +import arc.graphics.*; import arc.math.*; import arc.util.ArcAnnotate.*; import arc.util.*; @@ -35,6 +36,8 @@ public abstract class BulletType extends Content{ public float ammoMultiplier = 2f; /** Multiplied by turret reload speed to get final shoot speed. */ public float reloadMultiplier = 1f; + /** Multiplier of how much base damage is done to tiles. */ + public float tileDamageMultiplier = 1f; /** Recoil from shooter entities. */ public float recoil; /** Whether to kill the shooter when this is shot. For suicide bombers. */ @@ -45,8 +48,6 @@ public abstract class BulletType extends Content{ public float splashDamage = 0f; /** Knockback in velocity. */ public float knockback; - /** Whether this bullet hits tiles. */ - public boolean hitTiles = true; /** Status effect applied on hit. */ public StatusEffect status = StatusEffects.none; /** Intensity of applied status effect in terms of duration. */ @@ -61,6 +62,10 @@ public abstract class BulletType extends Content{ public boolean collides = true; /** Whether velocity is inherited from the shooter. */ public boolean keepVelocity = true; + /** Whether to scale velocity to disappear at the target position. Used for artillery. */ + public boolean scaleVelocity; + /** Whether this bullet can be hit by point defense. */ + public boolean hittable = true; //additional effects @@ -68,6 +73,7 @@ public abstract class BulletType extends Content{ public int fragBullets = 9; public float fragVelocityMin = 0.2f, fragVelocityMax = 1f; public BulletType fragBullet = null; + public Color hitColor = Color.white; /** Use a negative value to disable splash damage. */ public float splashDamageRadius = -1f; @@ -78,12 +84,13 @@ public abstract class BulletType extends Content{ public float homingPower = 0f; public float homingRange = 50f; - public int lightining; + public int lightning; public int lightningLength = 5; + /** Use a negative value to use default bullet damage. */ + public float lightningDamage = -1; public float weaveScale = 1f; public float weaveMag = -1f; - public float hitShake = 0f; public BulletType(float speed, float damage){ @@ -112,7 +119,7 @@ public abstract class BulletType extends Content{ } public void hit(Bulletc b, float x, float y){ - hitEffect.at(x, y, b.rotation()); + hitEffect.at(x, y, b.rotation(), hitColor); hitSound.at(b); Effects.shake(hitShake, hitShake, b); @@ -130,7 +137,15 @@ public abstract class BulletType extends Content{ } if(splashDamageRadius > 0){ - Damage.damage(b.team(), x, y, splashDamageRadius, splashDamage * b.damageMultiplier()); + Damage.damage(b.team(), x, y, splashDamageRadius, splashDamage * b.damageMultiplier(), collidesAir, collidesGround); + + if(status != StatusEffects.none){ + Damage.status(b.team(), x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround); + } + } + + for(int i = 0; i < lightning; i++){ + Lightning.create(b.team(), Pal.surge, lightningDamage < 0 ? damage : lightningDamage, b.getX(), b.getY(), Mathf.random(360f), lightningLength); } } @@ -138,13 +153,9 @@ public abstract class BulletType extends Content{ despawnEffect.at(b.getX(), b.getY(), b.rotation()); hitSound.at(b); - if(fragBullet != null || splashDamageRadius > 0){ + if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){ hit(b); } - - for(int i = 0; i < lightining; i++){ - Lightning.create(b.team(), Pal.surge, damage, b.getX(), b.getY(), Mathf.random(360f), lightningLength); - } } public void draw(Bulletc b){ diff --git a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java new file mode 100644 index 0000000000..5332453b78 --- /dev/null +++ b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java @@ -0,0 +1,85 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; + +public class ContinuousLaserBulletType extends BulletType{ + public float length = 220f; + public float shake = 1f; + public Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white}; + public float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; + public float[] strokes = {2f, 1.5f, 1f, 0.3f}; + public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f}; + + public ContinuousLaserBulletType(float damage){ + super(0.001f, damage); + + hitEffect = Fx.hitMeltdown; + despawnEffect = Fx.none; + hitSize = 4; + drawSize = 420f; + lifetime = 16f; + pierce = true; + hittable = false; + hitColor = colors[2]; + } + + protected ContinuousLaserBulletType(){ + this(0); + } + + @Override + public float range(){ + return length; + } + + @Override + public void update(Bulletc b){ + //TODO possible laser absorption from blocks + + //damage every 5 ticks + if(b.timer(1, 5f)){ + Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length, true); + } + + if(shake > 0){ + Effects.shake(shake, shake, b); + } + } + + /* + @Override + public void hit(Bulletc b, float hitx, float hity){ + hitEffect.at(hitx, hity, colors[2]); + if(Mathf.chance(0.4)){ + Fires.create(world.tileWorld(hitx + Mathf.range(5f), hity + Mathf.range(5f))); + } + }*/ + + @Override + public void draw(Bulletc b){ + float baseLen = length * b.fout(); + + Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen); + for(int s = 0; s < colors.length; s++){ + Draw.color(Tmp.c1.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f))); + for(int i = 0; i < tscales.length; i++){ + Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f); + Lines.stroke((9f + Mathf.absin(Time.time(), 0.8f, 1.5f)) * b.fout() * strokes[s] * tscales[i]); + Lines.lineAngle(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], CapStyle.none); + } + } + + Tmp.v1.trns(b.rotation(), baseLen * 1.1f); + + Drawf.light(b.x(), b.y(), b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, 40, Color.orange, 0.7f); + Draw.reset(); + } + +} diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java index cbd33ac951..a9c683299d 100644 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ b/core/src/mindustry/entities/bullet/HealBulletType.java @@ -20,6 +20,7 @@ public class HealBulletType extends BulletType{ hitEffect = Fx.hitLaser; despawnEffect = Fx.hitLaser; collidesTeam = true; + hittable = false; } public HealBulletType(){ diff --git a/core/src/mindustry/entities/bullet/LaserBulletType.java b/core/src/mindustry/entities/bullet/LaserBulletType.java index 352d6fc5b8..606d0a3f1c 100644 --- a/core/src/mindustry/entities/bullet/LaserBulletType.java +++ b/core/src/mindustry/entities/bullet/LaserBulletType.java @@ -8,9 +8,15 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.world.*; + +import static mindustry.Vars.world; public class LaserBulletType extends BulletType{ + protected static Tile furthest; + protected Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; + protected Effect laserEffect = Fx.lancerLaserShootSmoke; protected float length = 160f; protected float width = 15f; protected float lengthFalloff = 0.5f; @@ -24,10 +30,11 @@ public class LaserBulletType extends BulletType{ hitEffect = Fx.hitLancer; despawnEffect = Fx.none; shootEffect = Fx.hitLancer; - smokeEffect = Fx.lancerLaserShootSmoke; + smokeEffect = Fx.none; hitSize = 4; lifetime = 16f; pierce = true; + hittable = false; } public LaserBulletType(){ @@ -41,13 +48,27 @@ public class LaserBulletType extends BulletType{ @Override public void init(Bulletc b){ - Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length); + Tmp.v1.trns(b.rotation(), length); + + furthest = null; + + 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); + + float resultLength = furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length; + + Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), resultLength); + if(furthest != null) b.data(resultLength); + + laserEffect.at(b.x(), b.y(), b.rotation(), resultLength * 0.75f); } @Override public void draw(Bulletc b){ + float realLength = b.data() == null ? length : (Float)b.data(); + float f = Mathf.curve(b.fin(), 0f, 0.2f); - float baseLen = length * f; + float baseLen = realLength * f; float cwidth = width; float compound = 1f; diff --git a/core/src/mindustry/entities/bullet/LightningBulletType.java b/core/src/mindustry/entities/bullet/LightningBulletType.java index 36beb5a092..4ca0f1d2c2 100644 --- a/core/src/mindustry/entities/bullet/LightningBulletType.java +++ b/core/src/mindustry/entities/bullet/LightningBulletType.java @@ -17,6 +17,12 @@ public class LightningBulletType extends BulletType{ despawnEffect = Fx.none; hitEffect = Fx.hitLancer; keepVelocity = false; + hittable = false; + } + + @Override + public float range(){ + return lightningLength * 2.33f; } @Override diff --git a/core/src/mindustry/entities/bullet/LiquidBulletType.java b/core/src/mindustry/entities/bullet/LiquidBulletType.java index 4a7ddf1718..835c8a4d32 100644 --- a/core/src/mindustry/entities/bullet/LiquidBulletType.java +++ b/core/src/mindustry/entities/bullet/LiquidBulletType.java @@ -30,7 +30,7 @@ public class LiquidBulletType extends BulletType{ hitEffect = Fx.hitLiquid; smokeEffect = Fx.none; shootEffect = Fx.none; - drag = 0.009f; + drag = 0.001f; knockback = 0.55f; } @@ -61,7 +61,14 @@ public class LiquidBulletType extends BulletType{ public void draw(Bulletc b){ Draw.color(liquid.color, Color.white, b.fout() / 100f); - Fill.circle(b.x(), b.y(), 0.5f + b.fout() * 2.5f); + Fill.circle(b.x(), b.y(), 3f); + } + + @Override + public void despawned(Bulletc b){ + super.despawned(b); + + hit(b, b.x(), b.y()); } @Override diff --git a/core/src/mindustry/entities/comp/BlockUnitComp.java b/core/src/mindustry/entities/comp/BlockUnitComp.java index 32827c36ec..3af40d00f8 100644 --- a/core/src/mindustry/entities/comp/BlockUnitComp.java +++ b/core/src/mindustry/entities/comp/BlockUnitComp.java @@ -18,10 +18,17 @@ abstract class BlockUnitComp implements Unitc{ //sets up block stats maxHealth(tile.block().health); health(tile.health()); - hitSize(tile.block().size * tilesize); + hitSize(tile.block().size * tilesize * 0.7f); set(tile); } + @Override + public void update(){ + if(tile != null){ + team = tile.team(); + } + } + @Replace public void kill(){ tile.kill(); @@ -37,6 +44,11 @@ abstract class BlockUnitComp implements Unitc{ return tile == null || tile.dead(); } + @Replace + public boolean isValid(){ + return tile != null && tile.isValid(); + } + @Replace public void team(Team team){ if(tile != null && this.team != team){ diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index e939794b17..003536df39 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -80,11 +80,11 @@ abstract class BuilderComp implements Unitc{ } if(!(tile.block() instanceof BuildBlock)){ - if(!current.initialized && !current.breaking && Build.validPlace(team(), current.x, current.y, current.block, current.rotation)){ + if(!current.initialized && !current.breaking && Build.validPlace(current.block, team(), current.x, current.y, current.rotation)){ boolean hasAll = !Structs.contains(current.block.requirements, i -> !core.items().has(i.item)); if(hasAll || state.rules.infiniteResources){ - Build.beginPlace(team(), current.x, current.y, current.block, current.rotation); + Build.beginPlace(current.block, team(), current.x, current.y, current.rotation); }else{ current.stuck = true; } @@ -138,7 +138,7 @@ abstract class BuilderComp implements Unitc{ control.input.drawBreaking(request); }else{ request.block.drawRequest(request, control.input.allRequests(), - Build.validPlace(team(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request)); + Build.validPlace(request.block, team(), request.x, request.y, request.rotation) || control.input.requestMatches(request)); } } diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index 14b8075146..909dde051f 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -107,7 +107,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw public void update(){ type.update(this); - if(type.hitTiles){ + if(type.collidesTiles){ world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> { Tilec tile = world.ent(x, y); diff --git a/core/src/mindustry/entities/comp/HealthComp.java b/core/src/mindustry/entities/comp/HealthComp.java index 5840b7f23a..d906adb714 100644 --- a/core/src/mindustry/entities/comp/HealthComp.java +++ b/core/src/mindustry/entities/comp/HealthComp.java @@ -2,7 +2,6 @@ package mindustry.entities.comp; import arc.math.*; import arc.util.*; -import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.gen.*; @@ -53,7 +52,7 @@ abstract class HealthComp implements Entityc{ /** Damage and pierce armor. */ void damagePierce(float amount, boolean withEffect){ if(this instanceof Shieldc){ - damage(amount / Math.max(1f - ((Shieldc)this).armor(), Vars.minArmorDamage), withEffect); + damage(amount + ((Shieldc)this).armor(), withEffect); }else{ damage(amount, withEffect); } diff --git a/core/src/mindustry/entities/comp/LegsComp.java b/core/src/mindustry/entities/comp/LegsComp.java index e494e32b27..4791739786 100644 --- a/core/src/mindustry/entities/comp/LegsComp.java +++ b/core/src/mindustry/entities/comp/LegsComp.java @@ -11,22 +11,24 @@ import mindustry.type.*; import mindustry.world.blocks.environment.*; @Component -abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ - @Import float x, y, elevation; +abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc, ElevationMovec{ + @Import float x, y; @Import UnitType type; transient Leg[] legs = {}; transient float totalLength; transient int lastGroup; + transient float baseRotation; @Override public void update(){ - //keep elevation halfway - elevation = 0.5f; + if(Mathf.dst(deltaX(), deltaY()) > 0.001f){ + baseRotation = Mathf.slerpDelta(baseRotation, Mathf.angle(deltaX(), deltaY()), 0.1f); + } + float rot = baseRotation; int count = type.legCount; float legLength = type.legLength; - float rotation = vel().angle(); //set up initial leg positions if(legs.length != type.legCount){ @@ -37,8 +39,8 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ for(int i = 0; i < legs.length; i++){ Leg l = new Leg(); - l.joint.trns(i * spacing + rotation, legLength/2f).add(x, y); - l.base.trns(i * spacing + rotation, legLength).add(x, y); + l.joint.trns(i * spacing + rot, legLength/2f + type.legBaseOffset).add(x, y); + l.base.trns(i * spacing + rot, legLength + type.legBaseOffset).add(x, y); legs[i] = l; } @@ -46,7 +48,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ float moveSpeed = type.legSpeed; int div = Math.max(legs.length / 2, 2); - float moveSpace = legLength / 1.6f / (div / 2f); + float moveSpace = legLength / 1.6f / (div / 2f) * type.legMoveSpace; totalLength += Mathf.dst(deltaX(), deltaY()); @@ -78,16 +80,19 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ float movespace = 360f / legs.length / 4f; float trns = vel().len() * 12.5f * div/1.5f * type.legTrns; - Tmp.v4.trns(rotation, trns); + //rotation + offset vector + Tmp.v4.trns(rot, trns); for(int i = 0; i < legs.length; i++){ - float dstRot = rotation + 360f / legs.length * i + (360f / legs.length / 2f); - float rot2 = Angles.moveToward(dstRot, rotation + (Angles.angleDist(dstRot, rotation) < 90f ? 180f : 0), movespace); + float dstRot = legAngle(rot, i); + float rot2 = Angles.moveToward(dstRot, rot + (Angles.angleDist(dstRot, rot) < 90f ? 180f : 0), movespace); Leg l = legs[i]; - Tmp.v1.trns(dstRot, legLength).add(x, y).add(Tmp.v4); - Tmp.v2.trns(rot2, legLength / 2f).add(x, y).add(Tmp.v4); + //leg destination + Tmp.v1.trns(dstRot, legLength + type.legBaseOffset).add(x, y).add(Tmp.v4); + //join destination + Tmp.v2.trns(rot2, legLength / 2f + type.legBaseOffset).add(x, y).add(Tmp.v4); if(i % div == group){ l.base.lerpDelta(Tmp.v1, moveSpeed); @@ -98,8 +103,19 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ } } - @Override - public void add(){ - elevation = 0.5f; + /** @return outwards facing angle of leg at the specified index. */ + float legAngle(float rotation, int index){ + return rotation + 360f / legs.length * index + (360f / legs.length / 2f); } + + /* + @Replace + public boolean isGrounded(){ + return true; + } + + @Replace + public boolean isFlying(){ + return false; + }*/ } diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 5b16b58905..3a02a6ae25 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -50,6 +50,15 @@ abstract class PayloadComp implements Posc, Rotc{ } boolean tryDropPayload(Payload payload){ + Tile on = tileOn(); + + //drop off payload on an acceptor if possible + if(on != null && on.entity != null && on.entity.acceptPayload(on.entity, payload)){ + Fx.unitDrop.at(on.entity); + on.entity.handlePayload(on.entity, payload); + return true; + } + if(payload instanceof BlockPayload){ return dropBlock((BlockPayload)payload); }else if(payload instanceof UnitPayload){ @@ -81,7 +90,7 @@ abstract class PayloadComp implements Posc, Rotc{ Tilec tile = payload.entity; int tx = Vars.world.toTile(x - tile.block().offset()), ty = Vars.world.toTile(y - tile.block().offset()); Tile on = Vars.world.tile(tx, ty); - if(on != null && Build.validPlace(tile.team(), tx, ty, tile.block(), tile.rotation())){ + if(on != null && Build.validPlace(tile.block(), tile.team(), tx, ty, tile.rotation())){ int rot = (int)((rotation() + 45f) / 90f) % 4; payload.place(on, rot); diff --git a/core/src/mindustry/entities/comp/PlayerComp.java b/core/src/mindustry/entities/comp/PlayerComp.java index d6944f6192..99248a0d14 100644 --- a/core/src/mindustry/entities/comp/PlayerComp.java +++ b/core/src/mindustry/entities/comp/PlayerComp.java @@ -12,6 +12,7 @@ import mindustry.annotations.Annotations.*; import mindustry.core.*; import mindustry.entities.units.*; import mindustry.game.*; +import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.Administration.*; @@ -79,7 +80,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra @Override public void update(){ - if(unit.dead()){ + if(!unit.isValid()){ clearUnit(); } @@ -143,10 +144,12 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra unit.team(team); unit.controller(this); } + + Events.fire(new UnitChangeEvent((Playerc)this, unit)); } boolean dead(){ - return unit.isNull(); + return unit.isNull() || !unit.isValid(); } String uuid(){ diff --git a/core/src/mindustry/entities/comp/ShieldComp.java b/core/src/mindustry/entities/comp/ShieldComp.java index 0d1257b02a..204efff128 100644 --- a/core/src/mindustry/entities/comp/ShieldComp.java +++ b/core/src/mindustry/entities/comp/ShieldComp.java @@ -23,7 +23,8 @@ abstract class ShieldComp implements Healthc, Posc{ @Override public void damage(float amount){ //apply armor - amount *= Math.max(1f - armor, minArmorDamage); + //TODO balancing of armor stats & minArmorDamage + amount = Math.max(amount - armor, minArmorDamage * amount); hitTime = 1f; diff --git a/core/src/mindustry/entities/comp/TileComp.java b/core/src/mindustry/entities/comp/TileComp.java index 327f05ee03..039469162e 100644 --- a/core/src/mindustry/entities/comp/TileComp.java +++ b/core/src/mindustry/entities/comp/TileComp.java @@ -188,6 +188,12 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree } } + /** Called clientside when the client taps a block to config. + * @return whether the configuration UI should be shown. */ + public boolean configTapped(){ + return true; + } + public void applyBoost(float intensity, float duration){ timeScale = Math.max(timeScale, intensity); timeScaleDuration = Math.max(timeScaleDuration, duration); @@ -221,25 +227,28 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree return tile.absoluteRelativeTo(cx, cy); } - public @Nullable Tile frontLarge(){ - int trns = block.size/2 + 1; - return tile.getNearby(Geometry.d4(rotation()).x * trns, Geometry.d4(rotation()).y * trns); - } - + /** Multiblock front. */ public @Nullable Tilec front(){ - return nearby((rotation() + 4) % 4); - } - - public @Nullable Tilec right(){ - return nearby((rotation() + 3) % 4); + int trns = block.size/2 + 1; + return nearby(Geometry.d4(rotation()).x * trns, Geometry.d4(rotation()).y * trns); } + /** Multiblock back. */ public @Nullable Tilec back(){ - return nearby((rotation() + 2) % 4); + int trns = block.size/2 + 1; + return nearby(Geometry.d4(rotation() + 2).x * trns, Geometry.d4(rotation() + 2).y * trns); } + /** Multiblock left. */ public @Nullable Tilec left(){ - return nearby((rotation() + 1) % 4); + int trns = block.size/2 + 1; + return nearby(Geometry.d4(rotation() + 1).x * trns, Geometry.d4(rotation() + 1).y * trns); + } + + /** Multiblock right. */ + public @Nullable Tilec right(){ + int trns = block.size/2 + 1; + return nearby(Geometry.d4(rotation() + 3).x * trns, Geometry.d4(rotation() + 3).y * trns); } public int pos(){ @@ -529,6 +538,11 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree return this; } + /** Tries to take the payload. Returns null if no payload is present. */ + public @Nullable Payload takePayload(){ + return null; + } + /** * Tries to put this item into a nearby container, if there are no available * containers, it gets added to the block's inventory. @@ -981,7 +995,7 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree /** Returns whether or not a hand cursor should be shown over this block. */ public Cursor getCursor(){ - return block.configurable ? SystemCursor.hand : SystemCursor.arrow; + return block.configurable && tile.team() == player.team() ? SystemCursor.hand : SystemCursor.arrow; } /** @@ -1023,7 +1037,7 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree } public void collision(Bulletc other){ - damage(other.damage()); + damage(other.damage() * other.type().tileDamageMultiplier); } public void removeFromProximity(){ diff --git a/core/src/mindustry/entities/comp/TrailComp.java b/core/src/mindustry/entities/comp/TrailComp.java index 7ef07d03a2..0109661a7c 100644 --- a/core/src/mindustry/entities/comp/TrailComp.java +++ b/core/src/mindustry/entities/comp/TrailComp.java @@ -1,9 +1,24 @@ package mindustry.entities.comp; +import arc.math.*; import mindustry.annotations.Annotations.*; +import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.type.*; @Component -abstract class TrailComp{ +abstract class TrailComp implements Unitc{ + @Import UnitType type; + @Import float x, y, rotation; + transient Trail trail = new Trail(); + + @Override + public void update(){ + float scale = elevation(); + float offset = type.engineOffset/2f + type.engineOffset/2f*scale; + + float cx = x + Angles.trnsx(rotation + 180, offset), cy = y + Angles.trnsy(rotation + 180, offset); + trail.update(cx, cy); + } } diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 22429d0767..bdc4e15ce4 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -21,7 +21,7 @@ import static mindustry.Vars.*; @Component abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc{ - @Import float x, y, rotation, elevation, maxHealth; + @Import float x, y, rotation, elevation, maxHealth, drag, armor; private UnitController controller; private UnitType type; @@ -71,6 +71,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return controller; } + public void resetController(){ + controller(type.createController()); + } + @Override public void set(UnitType def, UnitController controller){ type(type); @@ -81,13 +85,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I public void type(UnitType type){ this.type = type; this.maxHealth = type.health; + this.drag = type.drag; + this.elevation = type.flying ? 1f : type.baseElevation; + this.armor = type.armor; + heal(); - drag(type.drag); hitSize(type.hitsize); controller(type.createController()); setupWeapons(type); - - elevation = type.flying ? 1f : 0f; } @Override @@ -125,6 +130,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override public void remove(){ teamIndex.updateCount(team(), -1); + controller.removed(this); } @Override diff --git a/core/src/mindustry/entities/comp/VelComp.java b/core/src/mindustry/entities/comp/VelComp.java index c6869f3204..6e3a31c76b 100644 --- a/core/src/mindustry/entities/comp/VelComp.java +++ b/core/src/mindustry/entities/comp/VelComp.java @@ -22,7 +22,7 @@ abstract class VelComp implements Posc{ } boolean moving(){ - return !vel.isZero(0.001f); + return !vel.isZero(0.01f); } void move(float cx, float cy){ diff --git a/core/src/mindustry/entities/comp/WeaponsComp.java b/core/src/mindustry/entities/comp/WeaponsComp.java index 217f16505d..03bb238722 100644 --- a/core/src/mindustry/entities/comp/WeaponsComp.java +++ b/core/src/mindustry/entities/comp/WeaponsComp.java @@ -37,7 +37,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{ void setupWeapons(UnitType def){ mounts = new WeaponMount[def.weapons.size]; - range = 0f; + range = def.range; for(int i = 0; i < mounts.length; i++){ mounts[i] = new WeaponMount(def.weapons.get(i)); range = Math.max(range, def.weapons.get(i).bullet.range()); @@ -110,7 +110,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{ shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX * i, weapon.shootY); float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY) + (this.rotation - angleTo(mount.aimX, mount.aimY)); - shoot(weapon, shootX, shootY, shootAngle, -i); + shoot(weapon, shootX, shootY, mount.aimX, mount.aimY, shootAngle, -i); } if(mount.weapon.mirror) mount.side = !mount.side; @@ -120,23 +120,24 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{ } } - private void shoot(Weapon weapon, float x, float y, float rotation, int side){ + private void shoot(Weapon weapon, float x, float y, float aimX, float aimY, float rotation, int side){ float baseX = this.x, baseY = this.y; 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 > 0.01f){ Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { - Time.run(sequenceNum * weapon.shotDelay, () -> bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy))); + Time.run(sequenceNum * weapon.shotDelay, () -> bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy), lifeScl)); sequenceNum++; }); }else{ - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy))); + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy), lifeScl)); } - BulletType ammo = weapon.bullet; - Tmp.v1.trns(rotation + 180f, ammo.recoil); if(this instanceof Velc){ @@ -153,8 +154,8 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{ ammo.smokeEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? this : null); } - private void bullet(Weapon weapon, float x, float y, float angle){ + private void bullet(Weapon weapon, float x, float y, float angle, float lifescl){ Tmp.v1.trns(angle, 3f); - weapon.bullet.create(this, team(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd)); + weapon.bullet.create(this, team(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd), lifescl); } } diff --git a/core/src/mindustry/entities/units/UnitController.java b/core/src/mindustry/entities/units/UnitController.java index 5fb8ac9136..03b5d1b989 100644 --- a/core/src/mindustry/entities/units/UnitController.java +++ b/core/src/mindustry/entities/units/UnitController.java @@ -15,6 +15,10 @@ public interface UnitController{ } + default void removed(Unitc unit){ + + } + default boolean isBeingControlled(Unitc player){ return false; } diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 86d4d58992..cad55d7931 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -289,14 +289,13 @@ public class EventType{ } } - //TODO rename - public static class MechChangeEvent{ + public static class UnitChangeEvent{ public final Playerc player; - public final UnitType mech; + public final Unitc unit; - public MechChangeEvent(Playerc player, UnitType mech){ + public UnitChangeEvent(Playerc player, Unitc unit){ this.player = player; - this.mech = mech; + this.unit = unit; } } diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index f202daaec8..55bd7e0249 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -19,14 +19,14 @@ public enum Gamemode{ }), attack(rules -> { rules.attackMode = true; + rules.waves = true; + rules.waveTimer = true; }, map -> map.teams.contains(state.rules.waveTeam.id)), pvp(rules -> { rules.pvp = true; rules.enemyCoreBuildRadius = 600f; rules.buildCostMultiplier = 1f; rules.buildSpeedMultiplier = 1f; - rules.playerDamageMultiplier = 0.33f; - rules.playerHealthMultiplier = 0.5f; rules.unitBuildSpeedMultiplier = 2f; rules.unitHealthMultiplier = 3f; rules.attackMode = true; diff --git a/core/src/mindustry/game/GlobalData.java b/core/src/mindustry/game/GlobalData.java index f20e46a2f4..a10e91486b 100644 --- a/core/src/mindustry/game/GlobalData.java +++ b/core/src/mindustry/game/GlobalData.java @@ -128,7 +128,7 @@ public class GlobalData{ /** Returns whether or not this piece of content is unlocked yet. */ public boolean isUnlocked(UnlockableContent content){ - return content.alwaysUnlocked() || unlocked.contains(content.name); + return content.alwaysUnlocked || unlocked.contains(content.name); } /** @@ -137,7 +137,7 @@ public class GlobalData{ * Results are not saved until you call {@link #save()}. */ public void unlockContent(UnlockableContent content){ - if(content.alwaysUnlocked()) return; + if(content.alwaysUnlocked) return; //fire unlock event so other classes can use it if(unlocked.add(content.name)){ diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 9b7bd5ba33..a4f2921eb3 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -14,7 +14,7 @@ import mindustry.world.*; * Does not store game state, just configuration. */ public class Rules{ - /** Whether the player has infinite resources. */ + /** Whether the player team has infinite resources. */ public boolean infiniteResources; /** Whether the waves come automatically on a timer. If not, waves come when the play button is pressed. */ public boolean waveTimer = true; @@ -22,6 +22,8 @@ public class Rules{ public boolean waves; /** Whether the enemy AI has infinite resources in most of their buildings and turrets. */ public boolean enemyCheat; + /** Whether the enemy AI has infinite resources in their core only. TODO remove */ + public boolean enemyInfiniteResources = true; /** Whether the game objective is PvP. Note that this enables automatic hosting. */ public boolean pvp; /** Whether reactors can explode and damage other blocks. */ @@ -30,15 +32,11 @@ public class Rules{ public float unitBuildSpeedMultiplier = 1f; /** How much health units start with. */ public float unitHealthMultiplier = 1f; - /** How much health players start with. */ - public float playerHealthMultiplier = 1f; /** How much health blocks start with. */ public float blockHealthMultiplier = 1f; - /** How much damage player mechs deal. */ - public float playerDamageMultiplier = 1f; /** How much damage any other units deal. */ public float unitDamageMultiplier = 1f; - /** Multiplier for buildings for the player. */ + /** Multiplier for buildings resource cost. */ public float buildCostMultiplier = 1f; /** Multiplier for building speed. */ public float buildSpeedMultiplier = 1f; @@ -73,6 +71,8 @@ public class Rules{ /** Whether to draw shadows of blocks at map edges and static blocks. * Do not change unless you know exactly what you are doing.*/ public boolean drawDarkness = true; + /** EXPERIMENTAL building AI. TODO remove */ + public boolean buildAI = true; /** Starting items put in cores */ public Array loadout = Array.with(ItemStack.with(Items.copper, 100)); /** Weather events that occur here. */ diff --git a/core/src/mindustry/game/Saves.java b/core/src/mindustry/game/Saves.java index 30fb17af67..8c521c534f 100644 --- a/core/src/mindustry/game/Saves.java +++ b/core/src/mindustry/game/Saves.java @@ -242,10 +242,6 @@ public class Saves{ return isSector(); } - public ObjectFloatMap getProductionRates(){ - return meta.exportRates; - } - public String getPlayTime(){ return Strings.formatMillis(current == this ? totalPlaytime : meta.timePlayed); } diff --git a/core/src/mindustry/game/Schematic.java b/core/src/mindustry/game/Schematic.java index eeeda0fbd7..f573c8d029 100644 --- a/core/src/mindustry/game/Schematic.java +++ b/core/src/mindustry/game/Schematic.java @@ -1,10 +1,11 @@ package mindustry.game; +import arc.files.*; import arc.struct.*; import arc.struct.IntIntMap.*; -import arc.files.*; import arc.util.ArcAnnotate.*; import mindustry.*; +import mindustry.content.*; import mindustry.mod.Mods.*; import mindustry.type.*; import mindustry.world.*; @@ -125,5 +126,23 @@ public class Schematic implements Publishable, Comparable{ this.config = config; this.rotation = rotation; } + + //pooling only + public Stile(){ + block = Blocks.air; + } + + public Stile set(Stile other){ + block = other.block; + x = other.x; + y = other.y; + config = other.config; + rotation = other.rotation; + return this; + } + + public Stile copy(){ + return new Stile(block, x, y, config, rotation); + } } } diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 7c1374dad0..4d74a13dae 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -6,12 +6,14 @@ import arc.files.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.graphics.gl.*; +import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; import arc.util.io.*; import arc.util.io.Streams.*; +import arc.util.pooling.*; import arc.util.serialization.*; import mindustry.*; import mindustry.content.*; @@ -38,6 +40,8 @@ import static mindustry.Vars.*; /** Handles schematics.*/ public class Schematics implements Loadable{ + private static final Schematic tmpSchem = new Schematic(new Array<>(), new StringMap(), 0, 0); + private static final Schematic tmpSchem2 = new Schematic(new Array<>(), new StringMap(), 0, 0); public static final String base64Header = "bXNjaAB"; private static final byte[] header = {'m', 's', 'c', 'h'}; @@ -106,6 +110,9 @@ public class Schematics implements Loadable{ if(shadowBuffer == null){ Core.app.post(() -> shadowBuffer = new FrameBuffer(maxSchematicSize + padding + 8, maxSchematicSize + padding + 8)); } + + //load base schematics + bases.load(); } public void overwrite(Schematic target, Schematic newSchematic){ @@ -372,14 +379,18 @@ public class Schematics implements Loadable{ } public static void placeLoadout(Schematic schem, int x, int y){ + placeLoadout(schem, x, y, state.rules.defaultTeam, Blocks.oreCopper); + } + + public static void placeLoadout(Schematic schem, int x, int y, Team team, Block resource){ Stile coreTile = schem.tiles.find(s -> s.block instanceof CoreBlock); - if(coreTile == null) throw new IllegalArgumentException("Schematic has no core tile. Exiting."); + if(coreTile == null) throw new IllegalArgumentException("Loadout schematic has no core tile!"); int ox = x - coreTile.x, oy = y - coreTile.y; schem.tiles.each(st -> { Tile tile = world.tile(st.x + ox, st.y + oy); if(tile == null) return; - tile.setBlock(st.block, state.rules.defaultTeam, 0); + tile.setBlock(st.block, team, 0); tile.rotation(st.rotation); Object config = st.config; @@ -388,7 +399,23 @@ public class Schematics implements Loadable{ } if(st.block instanceof Drill){ - tile.getLinkedTiles(t -> t.setOverlay(Blocks.oreCopper)); + tile.getLinkedTiles(t -> t.setOverlay(resource)); + } + }); + } + + public static void place(Schematic schem, int x, int y, Team team){ + int ox = x - schem.width/2, oy = y - schem.height/2; + schem.tiles.each(st -> { + Tile tile = world.tile(st.x + ox, st.y + oy); + if(tile == null) return; + + tile.setBlock(st.block, team, 0); + tile.rotation(st.rotation); + + Object config = st.config; + if(tile.entity != null){ + tile.entity.configureAny(config); } }); } @@ -503,5 +530,69 @@ public class Schematics implements Loadable{ return null; } + //endregion + //region misc utility + + /** @return a temporary schematic representing the input rotated 90 degrees counterclockwise N times. */ + public static Schematic rotate(Schematic input, int times){ + if(times == 0) return input; + + boolean sign = times > 0; + for(int i = 0; i < Math.abs(times); i++){ + input = rotated(input, sign); + } + return input; + } + + private static Schematic rotated(Schematic input, boolean counter){ + int direction = Mathf.sign(counter); + Schematic schem = input == tmpSchem ? tmpSchem2 : tmpSchem2; + schem.width = input.width; + schem.height = input.height; + Pools.freeAll(schem.tiles); + schem.tiles.clear(); + for(Stile tile : input.tiles){ + schem.tiles.add(Pools.obtain(Stile.class, Stile::new).set(tile)); + } + + int ox = schem.width/2, oy = schem.height/2; + + schem.tiles.each(req -> { + req.config = BuildRequest.pointConfig(req.config, p -> { + int cx = p.x, cy = p.y; + int lx = cx; + + if(direction >= 0){ + cx = -cy; + cy = lx; + }else{ + cx = cy; + cy = -lx; + } + p.set(cx, cy); + }); + + //rotate actual request, centered on its multiblock position + float wx = (req.x - ox) * tilesize + req.block.offset(), wy = (req.y - oy) * tilesize + req.block.offset(); + float x = wx; + if(direction >= 0){ + wx = -wy; + wy = x; + }else{ + 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.rotation = (byte)Mathf.mod(req.rotation + direction, 4); + }); + + //assign flipped values, since it's rotated + schem.width = input.height; + schem.height = input.width; + + return schem; + } + //endregion } diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java new file mode 100644 index 0000000000..7361acdad7 --- /dev/null +++ b/core/src/mindustry/game/SectorInfo.java @@ -0,0 +1,124 @@ +package mindustry.game; + +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; +import mindustry.world.modules.*; + +import static mindustry.Vars.*; + +public class SectorInfo{ + /** export window size in seconds */ + private static final int exportWindow = 60; + /** refresh period of export in ticks */ + private static final float refreshPeriod = 60; + /** Export statistics. */ + public ObjectMap export = new ObjectMap<>(); + /** Items stored in all cores. */ + public ObjectIntMap coreItems = new ObjectIntMap<>(); + /** The best available core type. */ + public Block bestCoreType = Blocks.air; + /** Max storage capacity. */ + public int storageCapacity = 0; + /** Whether a core is available here. */ + public boolean hasCore = true; + + /** Counter refresh state. */ + private transient Interval time = new Interval(); + /** Core item storage to prevent spoofing. */ + private transient int[] lastCoreItems; + + /** Updates export statistics. */ + public void handleItemExport(ItemStack stack){ + handleItemExport(stack.item, stack.amount); + } + + /** Updates export statistics. */ + public void handleItemExport(Item item, int amount){ + export.get(item, ExportStat::new).counter += amount; + } + + /** Subtracts from export statistics. */ + public void handleItemImport(Item item, int amount){ + export.get(item, ExportStat::new).counter -= amount; + } + + public float getExport(Item item){ + return export.get(item, ExportStat::new).mean; + } + + /** Prepare data for writing to a save. */ + public void prepare(){ + //update core items + coreItems.clear(); + + CoreEntity entity = state.rules.defaultTeam.core(); + + if(entity != null){ + ItemModule items = entity.items; + for(int i = 0; i < items.length(); i++){ + coreItems.put(content.item(i), items.get(i)); + } + } + + hasCore = entity != null; + bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block; + storageCapacity = entity != null ? entity.storageCapacity : 0; + } + + /** Update averages of various stats. */ + public void update(){ + //create last stored core items + if(lastCoreItems == null){ + lastCoreItems = new int[content.items().size]; + updateCoreDeltas(); + } + + //refresh throughput + if(time.get(refreshPeriod)){ + CoreEntity ent = state.rules.defaultTeam.core(); + + export.each((item, stat) -> { + //initialize stat after loading + if(!stat.loaded){ + stat.means.fill(stat.mean); + 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.counter = 0; + stat.mean = stat.means.rawMean(); + }); + + updateCoreDeltas(); + } + } + + private void updateCoreDeltas(){ + CoreEntity ent = state.rules.defaultTeam.core(); + for(int i = 0; i < lastCoreItems.length; i++){ + lastCoreItems[i] = ent == null ? 0 : ent.items.get(i); + } + } + + public ObjectFloatMap exportRates(){ + ObjectFloatMap map = new ObjectFloatMap<>(); + export.each((item, value) -> map.put(item, value.mean)); + return map; + } + + public static class ExportStat{ + public transient float counter; + public transient WindowedMean means = new WindowedMean(exportWindow); + public transient boolean loaded; + public float mean; + } +} diff --git a/core/src/mindustry/game/Stats.java b/core/src/mindustry/game/Stats.java index fcc388ea74..01744a7537 100644 --- a/core/src/mindustry/game/Stats.java +++ b/core/src/mindustry/game/Stats.java @@ -2,18 +2,11 @@ package mindustry.game; import arc.math.*; import arc.struct.*; -import arc.util.*; import mindustry.type.*; -import mindustry.world.blocks.storage.CoreBlock.*; - -import static mindustry.Vars.*; +//TODO more stats: +//- units constructed public class Stats{ - /** export window size in seconds */ - private static final int exportWindow = 60; - /** refresh period of export in ticks */ - private static final float refreshPeriod = 60; - /** Total items delivered to global resoure counter. Campaign only. */ public ObjectIntMap itemsDelivered = new ObjectIntMap<>(); /** Enemy (red team) units destroyed. */ @@ -28,76 +21,6 @@ public class Stats{ public int buildingsDeconstructed; /** Friendly buildings destroyed. */ public int buildingsDestroyed; - /** Export statistics. */ - public ObjectMap export = new ObjectMap<>(); - - /** Counter refresh state. */ - private transient Interval time = new Interval(); - /** Core item storage to prevent spoofing. */ - private transient int[] lastCoreItems; - - /** Updates export statistics. */ - public void handleItemExport(ItemStack stack){ - handleItemExport(stack.item, stack.amount); - } - - /** Updates export statistics. */ - public void handleItemExport(Item item, int amount){ - export.getOr(item, ExportStat::new).counter += amount; - } - - /** Subtracts from export statistics. */ - public void handleItemImport(Item item, int amount){ - export.getOr(item, ExportStat::new).counter -= amount; - } - - public float getExport(Item item){ - return export.getOr(item, ExportStat::new).mean; - } - - public void update(){ - //create last stored core items - if(lastCoreItems == null){ - lastCoreItems = new int[content.items().size]; - updateCoreDeltas(); - } - - //refresh throughput - if(time.get(refreshPeriod)){ - CoreEntity ent = state.rules.defaultTeam.core(); - - export.each((item, stat) -> { - //initialize stat after loading - if(!stat.loaded){ - stat.means.fill(stat.mean); - 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.counter = 0; - stat.mean = stat.means.rawMean(); - }); - - updateCoreDeltas(); - } - } - - private void updateCoreDeltas(){ - CoreEntity ent = state.rules.defaultTeam.core(); - for(int i = 0; i < lastCoreItems.length; i++){ - lastCoreItems[i] = ent == null ? 0 : ent.items.get(i); - } - } - - public ObjectFloatMap exportRates(){ - ObjectFloatMap map = new ObjectFloatMap<>(); - export.each((item, value) -> map.put(item, value.mean)); - return map; - } public RankResult calculateRank(Sector zone, boolean launched){ float score = 0; @@ -145,15 +68,7 @@ public class Stats{ } } - public enum Rank{ F, D, C, B, A, S, SS } - - public static class ExportStat{ - public transient float counter; - public transient WindowedMean means = new WindowedMean(exportWindow); - public transient boolean loaded; - public float mean; - } } diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index ba2565ea92..f49fea7494 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -19,9 +19,9 @@ public class Team implements Comparable{ public String name; /** All 256 registered teams. */ - private static final Team[] all = new Team[256]; + public static final Team[] all = new Team[256]; /** The 6 base teams used in the editor. */ - private static final Team[] baseTeams = new Team[6]; + public static final Team[] baseTeams = new Team[6]; public final static Team derelict = new Team(0, "derelict", Color.valueOf("4d4e58")), @@ -44,16 +44,6 @@ public class Team implements Comparable{ return all[((byte)id) & 0xff]; } - /** @return the 6 base team colors. */ - public static Team[] base(){ - return baseTeams; - } - - /** @return all the teams - do not use this for lookup! */ - public static Team[] all(){ - return all; - } - protected Team(int id, String name, Color color){ this.name = name; this.color = color; diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 04e6792dee..60a534d9a8 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -5,6 +5,7 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; +import mindustry.ai.*; import mindustry.gen.*; import mindustry.world.blocks.storage.CoreBlock.*; @@ -147,10 +148,12 @@ public class Teams{ public final Array cores = new Array<>(); public final Array enemies = new Array<>(); public final Team team; - public Queue brokenBlocks = new Queue<>(); + public final BaseAI ai; + public Queue blocks = new Queue<>(); public TeamData(Team team){ this.team = team; + this.ai = new BaseAI(this); } public boolean active(){ @@ -169,6 +172,11 @@ public class Teams{ return cores.isEmpty() ? null : cores.first(); } + /** @return whether this team is controlled by the AI and builds bases. */ + public boolean hasAI(){ + return state.rules.attackMode && team == state.rules.waveTeam && state.rules.buildAI; + } + @Override public String toString(){ return "TeamData{" + @@ -180,13 +188,13 @@ public class Teams{ /** Represents a block made by this team that was destroyed somewhere on the map. * This does not include deconstructed blocks.*/ - public static class BrokenBlock{ + public static class BlockPlan{ public final short x, y, rotation, block; public final Object config; - public BrokenBlock(short x, short y, short rotation, short block, Object config){ - this.x = x; - this.y = y; + public BlockPlan(int x, int y, short rotation, short block, Object config){ + this.x = (short)x; + this.y = (short)y; this.rotation = rotation; this.block = block; this.config = config; diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java index ed7ca1ba2c..ce5a2813db 100644 --- a/core/src/mindustry/game/Universe.java +++ b/core/src/mindustry/game/Universe.java @@ -2,11 +2,12 @@ package mindustry.game; import arc.*; import arc.math.*; -import arc.struct.ObjectFloatMap.*; +import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.content.*; import mindustry.game.EventType.*; +import mindustry.game.SectorInfo.*; import mindustry.io.*; import mindustry.type.*; @@ -80,9 +81,9 @@ public class Universe{ if(sector.hasBase() && !sector.isBeingPlayed()){ SaveMeta meta = sector.save.meta; - for(Entry entry : meta.exportRates){ + for(ObjectMap.Entry entry : meta.secinfo.export){ //total is calculated by items/sec (value) * turn duration in seconds - int total = (int)(entry.value * turnDuration / 60f); + int total = (int)(entry.value.mean * turnDuration / 60f); exports[entry.key.id] += total; } diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 3957ea04d4..1a91d796fe 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -120,7 +120,7 @@ public class BlockRenderer implements Disposable{ } if(brokenFade > 0.001f){ - for(BrokenBlock block : state.teams.get(player.team()).brokenBlocks){ + for(BlockPlan block : state.teams.get(player.team()).blocks){ Block b = content.block(block.block); if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue; diff --git a/core/src/mindustry/graphics/CubemapMesh.java b/core/src/mindustry/graphics/CubemapMesh.java index d0901670dd..f9bfb4e15c 100644 --- a/core/src/mindustry/graphics/CubemapMesh.java +++ b/core/src/mindustry/graphics/CubemapMesh.java @@ -54,8 +54,8 @@ public class CubemapMesh implements Disposable{ }; private final Mesh mesh; - private final Cubemap map; private final Shader shader; + private Cubemap map; public CubemapMesh(Cubemap map){ this.map = map; @@ -69,6 +69,10 @@ public class CubemapMesh implements Disposable{ shader = new Shader(Core.files.internal("shaders/cubemap.vert"), Core.files.internal("shaders/cubemap.frag")); } + public void setCubemap(Cubemap map){ + this.map = map; + } + public void render(Mat3D projection){ map.bind(); shader.bind(); diff --git a/core/src/mindustry/graphics/Drawf.java b/core/src/mindustry/graphics/Drawf.java index 658df5c128..61795a5e2c 100644 --- a/core/src/mindustry/graphics/Drawf.java +++ b/core/src/mindustry/graphics/Drawf.java @@ -5,11 +5,10 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; -import arc.util.ArcAnnotate.*; import arc.util.*; import mindustry.*; +import mindustry.ctype.*; import mindustry.gen.*; -import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; @@ -184,9 +183,11 @@ public class Drawf{ Draw.rect(Core.atlas.find("shape-3"), x, y - oy + length / 2f, width, length, width / 2f, oy, rotation - 90); } - public static void construct(Tilec t, UnitType unit, float rotation, float progress, float speed, float time){ - TextureRegion region = unit.icon(Cicon.full); + public static void construct(Tilec t, UnlockableContent content, float rotation, float progress, float speed, float time){ + construct(t, content.icon(Cicon.full), rotation, progress, speed, time); + } + public static void construct(Tilec t, TextureRegion region, float rotation, float progress, float speed, float time){ Shaders.build.region = region; Shaders.build.progress = progress; Shaders.build.color.set(Pal.accent); @@ -204,64 +205,4 @@ public class Drawf{ Draw.reset(); } - - public static void respawn(Tilec tile, float heat, float progress, float time, UnitType to, @Nullable Playerc player){ - float x = tile.x(), y = tile.y(); - progress = Mathf.clamp(progress); - - Draw.color(Pal.darkMetal); - Lines.stroke(2f * heat); - Fill.poly(x, y, 4, 10f * heat); - - Draw.reset(); - if(player != null){ - TextureRegion region = to.icon(Cicon.full); - - Draw.color(0f, 0f, 0f, 0.4f * progress); - Draw.rect("circle-shadow", x, y, region.getWidth() / 3f, region.getWidth() / 3f); - Draw.color(); - - Shaders.build.region = region; - Shaders.build.progress = progress; - Shaders.build.color.set(Pal.accent); - Shaders.build.time = -time / 10f; - - Draw.shader(Shaders.build, true); - Draw.rect(region, x, y); - Draw.shader(); - - Draw.color(Pal.accentBack); - - float pos = Mathf.sin(time, 6f, 8f); - - Lines.lineAngleCenter(x + pos, y, 90, 16f - Math.abs(pos) * 2f); - - Draw.reset(); - } - - Lines.stroke(2f * heat); - - Draw.color(Pal.accentBack); - Lines.poly(x, y, 4, 8f * heat); - - float oy = -7f, len = 6f * heat; - Lines.stroke(5f); - Draw.color(Pal.darkMetal); - Lines.line(x - len, y + oy, x + len, y + oy, CapStyle.none); - for(int i : Mathf.signs){ - Fill.tri(x + len * i, y + oy - Lines.getStroke()/2f, x + len * i, y + oy + Lines.getStroke()/2f, x + (len + Lines.getStroke() * heat) * i, y + oy); - } - - Lines.stroke(3f); - Draw.color(Pal.accent); - Lines.line(x - len, y + oy, x - len + len*2 * progress, y + oy, CapStyle.none); - for(int i : Mathf.signs){ - Fill.tri(x + len * i, y + oy - Lines.getStroke()/2f, x + len * i, y + oy + Lines.getStroke()/2f, x + (len + Lines.getStroke() * heat) * i, y + oy); - } - Draw.reset(); - - if(Vars.net.active() && player != null){ - tile.block().drawPlaceText(player.name(), tile.tileX(), tile.tileY() - (Math.max((tile.block().size-1)/2, 0)), true); - } - } } diff --git a/core/src/mindustry/graphics/Layer.java b/core/src/mindustry/graphics/Layer.java index ed1aab9726..5736aa19da 100644 --- a/core/src/mindustry/graphics/Layer.java +++ b/core/src/mindustry/graphics/Layer.java @@ -17,6 +17,9 @@ public class Layer{ //things such as spent casings or rubble debris = 20, + //stuff under blocks, like connections of conveyors/conduits + blockUnder = 29.5f, + //base block layer - most blocks go here block = 30, diff --git a/core/src/mindustry/graphics/Pixelator.java b/core/src/mindustry/graphics/Pixelator.java index ea976e2e9f..67dc58dd7d 100644 --- a/core/src/mindustry/graphics/Pixelator.java +++ b/core/src/mindustry/graphics/Pixelator.java @@ -26,8 +26,6 @@ public class Pixelator implements Disposable{ camera.width = (int)camera.width; camera.height = (int)camera.height; - graphics.clear(0f, 0f, 0f, 1f); - px = Core.camera.position.x; py = Core.camera.position.y; Core.camera.position.set((int)px + ((int)(camera.width) % 2 == 0 ? 0 : 0.5f), (int)py + ((int)(camera.height) % 2 == 0 ? 0 : 0.5f)); @@ -37,7 +35,7 @@ public class Pixelator implements Disposable{ buffer.resize(w, h); - buffer.begin(); + buffer.begin(Color.clear); renderer.draw(); } diff --git a/core/src/mindustry/graphics/Shaders.java b/core/src/mindustry/graphics/Shaders.java index 8e99d156a7..0e46e83d60 100644 --- a/core/src/mindustry/graphics/Shaders.java +++ b/core/src/mindustry/graphics/Shaders.java @@ -87,6 +87,8 @@ public class Shaders{ @Override public void apply(){ + camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, renderer.planets.planet.getRotation()); + setUniformf("u_lightdir", lightDir); setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b); setUniformf("u_camdir", camDir); diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java new file mode 100644 index 0000000000..e148254139 --- /dev/null +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -0,0 +1,311 @@ +package mindustry.graphics.g3d; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.graphics.g3d.*; +import arc.graphics.gl.*; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.graphics.*; +import mindustry.graphics.g3d.PlanetGrid.*; +import mindustry.type.*; + +public class PlanetRenderer implements Disposable{ + public static final float outlineRad = 1.17f, camLength = 4f; + public static final Color + outlineColor = Pal.accent.cpy().a(1f), + hoverColor = Pal.accent.cpy().a(0.5f), + borderColor = Pal.accent.cpy().a(0.3f), + shadowColor = new Color(0, 0, 0, 0.7f); + + private static final Array points = new Array<>(); + 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(); + /** The sun/main planet of the solar system from which everything is rendered. */ + public final Planet solarSystem = Planets.sun; + /** Planet being looked at. */ + public Planet planet = Planets.starter; + /** Camera used for rendering. */ + public Camera3D cam = new Camera3D(); + /** Raw vertex batch. */ + public final VertexBatch3D batch = new VertexBatch3D(10000, false, true, 0); + + 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; + + private 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); + + //seed: 8kmfuix03fw + private final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); + + public PlanetRenderer(){ + camPos.set(0, 0f, camLength); + projector.setScaling(1f / 150f); + cam.fov = 60f; + } + + /** Render the entire planet scene to the screen. */ + public void render(PlanetInterfaceRenderer irenderer){ + this.irenderer = irenderer; + + Draw.flush(); + Gl.clear(Gl.depthBufferBit); + Gl.enable(Gl.depthTest); + Gl.depthMask(true); + + Gl.enable(Gl.cullFace); + Gl.cullFace(Gl.back); + + //lock to up vector so it doesn't get confusing + cam.up.set(Vec3.Y); + + cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); + camPos.setLength(planet.radius * camLength + (zoom-1f) * planet.radius * 2); + cam.position.set(planet.position).add(camPos); + cam.lookAt(planet.position); + cam.update(); + + projector.proj(cam.combined); + batch.proj(cam.combined); + + beginBloom(); + + skybox.render(cam.combined); + + renderPlanet(solarSystem); + + endBloom(); + + Gl.enable(Gl.blend); + + irenderer.renderProjections(); + + Gl.disable(Gl.cullFace); + Gl.disable(Gl.depthTest); + + cam.update(); + } + + private void beginBloom(){ + bloom.resize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4); + bloom.capture(); + } + + private void endBloom(){ + bloom.render(); + } + + private void renderPlanet(Planet planet){ + //render planet at offsetted position in the world + planet.mesh.render(cam.combined, planet.getTransform(mat)); + + renderOrbit(planet); + + if(planet.isLandable() && planet == this.planet){ + renderSectors(planet); + } + + if(planet.parent != null && planet.hasAtmosphere && Core.settings.getBool("atmosphere")){ + Blending.additive.apply(); + + Shaders.atmosphere.camera = cam; + Shaders.atmosphere.planet = planet; + Shaders.atmosphere.bind(); + Shaders.atmosphere.apply(); + + atmosphere.render(Shaders.atmosphere, Gl.triangles); + + Blending.normal.apply(); + } + + for(Planet child : planet.children){ + renderPlanet(child); + } + } + + private void renderOrbit(Planet planet){ + if(planet.parent == null) return; + + Vec3 center = planet.parent.position; + float radius = planet.orbitRadius; + int points = (int)(radius * 50); + Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray)); + batch.flush(Gl.lineLoop); + } + + private void renderSectors(Planet planet){ + //apply transformed position + batch.proj().mul(planet.getTransform(mat)); + + irenderer.renderSectors(planet); + + //render sector grid + Mesh mesh = outline(planet.grid.size); + Shader shader = Shaders.planetGrid; + Vec3 tile = planet.intersect(cam.getMouseRay(), outlineRad); + Shaders.planetGrid.mouse.lerp(tile == null ? Vec3.Zero : tile.sub(planet.position).rotate(Vec3.Y, planet.getRotation()), 0.2f); + + shader.bind(); + shader.setUniformMatrix4("u_proj", cam.combined.val); + shader.setUniformMatrix4("u_trans", planet.getTransform(mat).val); + shader.apply(); + mesh.render(shader, Gl.lines); + } + + public void drawArc(Planet planet, Vec3 a, Vec3 b){ + Vec3 avg = Tmp.v31.set(b).add(a).scl(0.5f); + avg.setLength(planet.radius*2f); + + points.clear(); + points.addAll(Tmp.v33.set(b).setLength(outlineRad), Tmp.v31, Tmp.v34.set(a).setLength(outlineRad)); + Tmp.bz3.set(points); + float points = 25; + + for(int i = 0; i < points + 1; i++){ + float f = i / points; + Tmp.c1.set(Pal.accent).lerp(Color.clear, (f+Time.globalTime()/80f)%1f); + batch.color(Tmp.c1); + batch.vertex(Tmp.bz3.valueAt(Tmp.v32, f)); + + } + batch.flush(Gl.lineStrip); + } + + public void drawBorders(Sector sector, Color base){ + Color color = Tmp.c1.set(base).a(base.a + 0.3f + Mathf.absin(Time.globalTime(), 5f, 0.3f)); + + float r1 = 1f; + float r2 = outlineRad + 0.001f; + + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; + + Tmp.v31.set(c.v).setLength(r2); + Tmp.v32.set(next.v).setLength(r2); + Tmp.v33.set(c.v).setLength(r1); + + batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); + + Tmp.v31.set(next.v).setLength(r2); + Tmp.v32.set(next.v).setLength(r1); + Tmp.v33.set(c.v).setLength(r1); + + batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); + } + + if(batch.getNumVertices() >= batch.getMaxVertices() - 6 * 6){ + batch.flush(Gl.triangles); + } + } + + public void drawPlane(Sector sector, Runnable run){ + Draw.batch(projector, () -> { + setPlane(sector); + run.run(); + }); + } + + public void setPlane(Sector sector){ + float rotation = -planet.getRotation(); + float length = 0.01f; + + projector.setPlane( + //origin on sector position + Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(planet.position), + //face up + sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(), + //right vector + Tmp.v31.set(Tmp.v32).rotate(Vec3.Y, -rotation).add(sector.tile.v).rotate(sector.tile.v, 90).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor() + ); + } + + public void fill(Sector sector, Color color, float offset){ + float rr = outlineRad + offset; + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; + batch.tri(Tmp.v31.set(c.v).setLength(rr), Tmp.v32.set(next.v).setLength(rr), Tmp.v33.set(sector.tile.v).setLength(rr), color); + } + } + + public void drawSelection(Sector sector){ + drawSelection(sector, Pal.accent, 0.04f, 0.001f); + } + + public void drawSelection(Sector sector, Color color, float stroke, float length){ + float arad = outlineRad + length; + + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner next = sector.tile.corners[(i + 1) % sector.tile.corners.length]; + Corner curr = sector.tile.corners[i]; + + next.v.scl(arad); + curr.v.scl(arad); + sector.tile.v.scl(arad); + + Tmp.v31.set(curr.v).sub(sector.tile.v).setLength(curr.v.dst(sector.tile.v) - stroke).add(sector.tile.v); + Tmp.v32.set(next.v).sub(sector.tile.v).setLength(next.v.dst(sector.tile.v) - stroke).add(sector.tile.v); + + batch.tri(curr.v, next.v, Tmp.v31, color); + batch.tri(Tmp.v31, next.v, Tmp.v32, color); + + sector.tile.v.scl(1f / arad); + next.v.scl(1f / arad); + curr.v.scl(1f /arad); + } + } + + private Mesh outline(int size){ + if(outlines[size] == null){ + outlines[size] = MeshBuilder.buildHex(new HexMesher(){ + @Override + public float getHeight(Vec3 position){ + return 0; + } + + @Override + public Color getColor(Vec3 position){ + return outlineColor; + } + }, size, true, outlineRad, 0.2f); + } + return outlines[size]; + } + + @Override + public void dispose(){ + skybox.dispose(); + batch.dispose(); + projector.dispose(); + atmosphere.dispose(); + buffer.dispose(); + bloom.dispose(); + for(Mesh m : outlines){ + if(m != null){ + m.dispose(); + } + } + } + + public interface PlanetInterfaceRenderer{ + void renderSectors(Planet planet); + void renderProjections(); + } +} diff --git a/core/src/mindustry/input/Binding.java b/core/src/mindustry/input/Binding.java index 5a4ffcc48a..95508dd300 100644 --- a/core/src/mindustry/input/Binding.java +++ b/core/src/mindustry/input/Binding.java @@ -21,6 +21,8 @@ public enum Binding implements KeyBind{ pickupCargo(KeyCode.leftBracket), dropCargo(KeyCode.rightBracket), + command(KeyCode.g), + clear_building(KeyCode.q), pause_building(KeyCode.e), rotate(new Axis(KeyCode.scroll)), diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index e4a6df80d0..6ae7cfb81c 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -4,7 +4,6 @@ import arc.*; import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; -import arc.input.*; import arc.math.*; import arc.math.geom.*; import arc.scene.*; @@ -14,8 +13,6 @@ import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; import arc.util.*; import mindustry.*; -import mindustry.ai.formations.*; -import mindustry.ai.formations.patterns.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.units.*; @@ -25,6 +22,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.payloads.*; import mindustry.world.meta.*; import static arc.Core.scene; @@ -206,40 +204,15 @@ public class DesktopInput extends InputHandler{ shouldShoot = false; } } - - if(Core.input.keyDown(Binding.respawn) && !player.dead() && !player.unit().spawnedByCore()){ - Call.onUnitClear(player); - controlledType = null; - } - - //TODO this is for debugging, remove later - if(Core.input.keyTap(KeyCode.g) && !player.dead() && player.unit() instanceof Commanderc){ - Commanderc commander = (Commanderc)player.unit(); - - if(commander.isCommanding()){ - commander.clearCommand(); - }else{ - - FormationPattern pattern = new SquareFormation(); - Formation formation = new Formation(new Vec3(player.x(), player.y(), player.unit().rotation()), pattern); - formation.slotAssignmentStrategy = new DistanceAssignmentStrategy(pattern); - - units.clear(); - - Fx.commandSend.at(player); - Units.nearby(player.team(), player.x(), player.y(), 200f, u -> { - if(u.isAI()){ - units.add(u); - } - }); - - commander.command(formation, units); - } - } } if(!player.dead() && !state.isPaused() && !(Core.scene.getKeyboardFocus() instanceof TextField)){ updateMovement(player.unit()); + + if(Core.input.keyDown(Binding.respawn) && !player.unit().spawnedByCore()){ + Call.onUnitClear(player); + controlledType = null; + } } if(Core.input.keyRelease(Binding.select)){ @@ -589,7 +562,7 @@ public class DesktopInput extends InputHandler{ if(aimCursor){ unit.lookAt(mouseAngle); }else{ - if(!unit.vel().isZero(0.01f)){ + if(unit.moving()){ unit.lookAt(unit.vel().angle()); } } @@ -609,6 +582,7 @@ public class DesktopInput extends InputHandler{ isBoosting = Core.input.keyDown(Binding.boost) && !movement.isZero(); player.boosting(isBoosting); + //TODO netsync this if(unit instanceof Payloadc){ Payloadc pay = (Payloadc)unit; @@ -618,8 +592,18 @@ public class DesktopInput extends InputHandler{ pay.pickup(target); }else if(!pay.hasPayload()){ Tilec tile = world.entWorld(pay.x(), pay.y()); - if(tile != null && tile.team() == unit.team() && tile.block().synthetic() && tile.block().buildVisibility != BuildVisibility.hidden && tile.block().size <= 3){ - pay.pickup(tile); + if(tile != null && tile.team() == unit.team() && tile.block().synthetic()){ + //pick up block directly + if(tile.block().buildVisibility != BuildVisibility.hidden && tile.block().size <= 2){ + pay.pickup(tile); + }else{ //pick up block payload + Payload taken = tile.takePayload(); + if(taken != null){ + pay.addPayload(taken); + Fx.unitPickup.at(tile); + } + } + } } } @@ -628,5 +612,12 @@ public class DesktopInput extends InputHandler{ pay.dropLastPayload(); } } + + if(unit instanceof Commanderc){ + + if(Core.input.keyTap(Binding.command)){ + Call.onUnitCommand(player); + } + } } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index b73c65d8d8..3608e399c1 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -14,6 +14,8 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; +import mindustry.ai.formations.*; +import mindustry.ai.formations.patterns.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; @@ -32,6 +34,7 @@ import mindustry.world.*; import mindustry.world.blocks.*; import mindustry.world.blocks.BuildBlock.*; import mindustry.world.blocks.power.*; +import mindustry.world.blocks.storage.CoreBlock.*; import java.util.*; @@ -172,7 +175,12 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(targets = Loc.both, called = Loc.server, forward = true) public static void onUnitControl(Playerc player, @Nullable Unitc unit){ - if(unit == null){ + //clear player unit when they possess a core + if((unit instanceof BlockUnitc && ((BlockUnitc)unit).tile() instanceof CoreEntity)){ + Fx.spawn.at(player); + player.clearUnit(); + player.deathTimer(60f); //for instant respawn + }else if(unit == null){ //just clear the unit (is this used?) player.clearUnit(); //make sure it's AI controlled, so players can't overwrite each other }else if(unit.isAI() && unit.team() == player.team()){ @@ -194,6 +202,36 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ player.deathTimer(60f); //for instant respawn } + @Remote(targets = Loc.both, called = Loc.server, forward = true) + public static void onUnitCommand(Playerc player){ + if(player.dead() || !(player.unit() instanceof Commanderc)) return; + + Commanderc commander = (Commanderc)player.unit(); + + if(commander.isCommanding()){ + commander.clearCommand(); + }else{ + FormationPattern pattern = new SquareFormation(); + Formation formation = new Formation(new Vec3(player.x(), player.y(), player.unit().rotation()), pattern); + formation.slotAssignmentStrategy = new DistanceAssignmentStrategy(pattern); + + units.clear(); + + Fx.commandSend.at(player); + Units.nearby(player.team(), player.x(), player.y(), 200f, u -> { + if(u.isAI()){ + units.add(u); + } + }); + + units.sort(u -> u.dst2(player.unit())); + units.truncate(player.unit().type().commandLimit); + + commander.command(formation, units); + } + + } + public Eachable allRequests(){ return cons -> { for(BuildRequest request : player.builder().requests()) cons.get(request); @@ -469,7 +507,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - for(BrokenBlock req : player.team().data().brokenBlocks){ + for(BlockPlan req : player.team().data().blocks){ Block block = content.block(req.block); if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ drawSelected(req.x, req.y, content.block(req.block), Pal.remove); @@ -591,9 +629,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } //remove blocks to rebuild - Iterator broken = state.teams.get(player.team()).brokenBlocks.iterator(); + Iterator broken = state.teams.get(player.team()).blocks.iterator(); while(broken.hasNext()){ - BrokenBlock req = broken.next(); + BlockPlan req = broken.next(); Block block = content.block(req.block); if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ broken.remove(); @@ -869,7 +907,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return false; } } - return Build.validPlace(player.team(), x, y, type, rotation); + return Build.validPlace(type, player.team(), x, y, rotation); } public boolean validBreak(int x, int y){ diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index ca94abe2ba..16f7261a24 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -241,7 +241,8 @@ public class MobileInput extends InputHandler implements GestureListener{ Boolp schem = () -> lastSchematic != null && !selectRequests.isEmpty(); group.fill(t -> { - t.bottom().left().visible(() -> (player.builder().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); + t.visible(() -> (player.builder().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); + t.bottom().left(); t.button("$cancel", Icon.cancel, () -> { player.builder().clearBuilding(); selectRequests.clear(); @@ -272,25 +273,6 @@ public class MobileInput extends InputHandler implements GestureListener{ }); } - @Override - 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); - } - - @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); - } - - @Override - public boolean isPlacing(){ - return super.isPlacing() && mode == placing; - } - @Override public void drawBottom(){ Lines.stroke(1f); @@ -351,13 +333,11 @@ public class MobileInput extends InputHandler implements GestureListener{ if(mode == placing && block != null){ //draw placing for(int i = 0; i < lineRequests.size; i++){ - BuildRequest req = lineRequests.get(i); - if(i == lineRequests.size - 1 && req.block.rotate){ - drawArrow(block, req.x, req.y, req.rotation); - } - BuildRequest request = lineRequests.get(i); - request.block.drawRequest(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation) && getRequest(req.x, request.y, request.block.size, null) == null); + if(i == lineRequests.size - 1 && request.block.rotate){ + drawArrow(block, request.x, request.y, request.rotation); + } + request.block.drawRequest(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation) && getRequest(request.x, request.y, request.block.size, null) == null); drawSelected(request.x, request.y, request.block, Pal.accent); } }else if(mode == breaking){ @@ -409,7 +389,26 @@ public class MobileInput extends InputHandler implements GestureListener{ } //endregion - //region input events + //region input events, overrides + + @Override + 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); + } + + @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); + } + + @Override + public boolean isPlacing(){ + return super.isPlacing() && mode == placing; + } @Override public boolean isBreaking(){ diff --git a/core/src/mindustry/input/Placement.java b/core/src/mindustry/input/Placement.java index 8a2d9ea499..6c2264d0fe 100644 --- a/core/src/mindustry/input/Placement.java +++ b/core/src/mindustry/input/Placement.java @@ -273,12 +273,4 @@ public class Placement{ return y + (x2 - x > y2 - y ? 0 : i); } } - - public interface DistanceHeuristic{ - float cost(int x1, int y1, int x2, int y2); - } - - public interface TileHueristic{ - float cost(Tile tile, Tile other); - } } diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 095637536d..6b44f56cdb 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -129,7 +129,8 @@ public class JsonIO{ @Override public Block read(Json json, JsonValue jsonData, Class type){ - return Vars.content.getByName(ContentType.block, jsonData.asString()); + Block block = Vars.content.getByName(ContentType.block, jsonData.asString()); + return block == null ? Blocks.air : block; } }); diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index 9478d54bd9..857551860f 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -88,18 +88,18 @@ public abstract class SaveFileReader{ } /** Reads a chunk of some length. Use the runner for reading to catch more descriptive errors. */ - public int readChunk(DataInput input, boolean isByte, IORunner runner) throws IOException{ - int length = isByte ? input.readUnsignedShort() : input.readInt(); + public int readChunk(DataInput input, boolean isShort, IORunner runner) throws IOException{ + int length = isShort ? input.readUnsignedShort() : input.readInt(); runner.accept(input); return length; } - public void skipRegion(DataInput input) throws IOException{ - skipRegion(input, false); + public void skipChunk(DataInput input) throws IOException{ + skipChunk(input, false); } - /** Skip a region completely. */ - public void skipRegion(DataInput input, boolean isByte) throws IOException{ + /** Skip a chunk completely, discarding the bytes. */ + public void skipChunk(DataInput input, boolean isByte) throws IOException{ int length = readChunk(input, isByte, t -> {}); int skipped = input.skipBytes(length); if(length != skipped){ diff --git a/core/src/mindustry/io/SaveMeta.java b/core/src/mindustry/io/SaveMeta.java index a28b1ac6ce..0a3730d8e1 100644 --- a/core/src/mindustry/io/SaveMeta.java +++ b/core/src/mindustry/io/SaveMeta.java @@ -3,7 +3,6 @@ package mindustry.io; import arc.struct.*; import mindustry.game.*; import mindustry.maps.*; -import mindustry.type.*; import static mindustry.Vars.maps; @@ -15,13 +14,12 @@ public class SaveMeta{ public Map map; public int wave; public Rules rules; + public SectorInfo secinfo; public StringMap tags; public String[] mods; - /** These are in items/second. */ - public ObjectFloatMap exportRates; public boolean hasProduction; - public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, ObjectFloatMap exportRates, StringMap tags){ + public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, SectorInfo secinfo, StringMap tags){ this.version = version; this.build = build; this.timestamp = timestamp; @@ -31,8 +29,8 @@ public class SaveMeta{ this.rules = rules; this.tags = tags; this.mods = JsonIO.read(String[].class, tags.get("mods", "[]")); - this.exportRates = exportRates; + this.secinfo = secinfo; - exportRates.each(e -> hasProduction |= e.value > 0.001f); + secinfo.exportRates().each(e -> hasProduction |= e.value > 0.001f); } } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 0635b12ab6..6e17150ca7 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -39,7 +39,7 @@ public abstract class SaveVersion extends SaveFileReader{ map.get("mapname"), map.getInt("wave"), JsonIO.read(Rules.class, map.get("rules", "{}")), - JsonIO.read(Stats.class, map.get("stats", "{}")).exportRates(), + JsonIO.read(SectorInfo.class, map.get("secinfo", "{}")), map ); } @@ -70,6 +70,11 @@ public abstract class SaveVersion extends SaveFileReader{ } public void writeMeta(DataOutput stream, StringMap tags) throws IOException{ + //prepare campaign data for writing + if(state.isCampaign()){ + state.secinfo.prepare(); + } + writeStringMap(stream, StringMap.of( "saved", Time.millis(), "playtime", headless ? 0 : control.saves.getTotalPlaytime(), @@ -78,13 +83,15 @@ 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(), "height", world.height(), "viewpos", Tmp.v1.set(player == null ? Vec2.ZERO : player).toString(), "controlledType", headless || control.input.controlledType == null ? "null" : control.input.controlledType.name, - "nocores", state.rules.defaultTeam.cores().isEmpty() + "nocores", state.rules.defaultTeam.cores().isEmpty(), + "playerteam", player == null ? state.rules.defaultTeam.uid : player.team().uid ).merge(tags)); } @@ -94,6 +101,7 @@ 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.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); lastReadBuild = map.getInt("build", -1); @@ -104,6 +112,10 @@ public abstract class SaveVersion extends SaveFileReader{ player.set(Tmp.v1); control.input.controlledType = content.getByName(ContentType.unit, map.get("controlledType", "")); + Team team = Team.get(map.getInt("playerteam", state.rules.defaultTeam.uid)); + if(!net.client() && team != Team.derelict){ + player.team(team); + } } Map worldmap = maps.byName(map.get("mapname", "\\\\\\")); @@ -145,6 +157,9 @@ public abstract class SaveVersion extends SaveFileReader{ Tile tile = world.rawTile(i % world.width(), i / world.width()); stream.writeShort(tile.blockID()); + //make note of whether there was an entity here + stream.writeBoolean(tile.entity != null); + //only write the entity for multiblocks once - in the center if(tile.entity != null){ if(tile.isCenter()){ @@ -211,8 +226,9 @@ public abstract class SaveVersion extends SaveFileReader{ Tile tile = context.tile(i); if(block == null) block = Blocks.air; boolean isCenter = true; + boolean hadEntity = stream.readBoolean(); - if(block.hasEntity()){ + if(hadEntity){ isCenter = stream.readBoolean(); } @@ -221,15 +237,20 @@ public abstract class SaveVersion extends SaveFileReader{ tile.setBlock(block); } - if(block.hasEntity()){ + if(hadEntity){ if(isCenter){ //only read entity for center blocks - try{ - readChunk(stream, true, in -> { - byte revision = in.readByte(); - tile.entity.readAll(Reads.get(in), revision); - }); - }catch(Throwable e){ - throw new IOException("Failed to read tile entity of block: " + block, e); + if(block.hasEntity()){ + try{ + readChunk(stream, true, in -> { + byte revision = in.readByte(); + tile.entity.readAll(Reads.get(in), revision); + }); + }catch(Throwable e){ + throw new IOException("Failed to read tile entity of block: " + block, e); + } + }else{ + //skip the entity region, as the entity and its IO code are now gone + skipChunk(stream, true); } } }else{ @@ -253,8 +274,8 @@ public abstract class SaveVersion extends SaveFileReader{ stream.writeInt(data.size); for(TeamData team : data){ stream.writeInt(team.team.id); - stream.writeInt(team.brokenBlocks.size); - for(BrokenBlock block : team.brokenBlocks){ + stream.writeInt(team.blocks.size); + for(BlockPlan block : team.blocks){ stream.writeShort(block.x); stream.writeShort(block.y); stream.writeShort(block.rotation); @@ -281,7 +302,7 @@ public abstract class SaveVersion extends SaveFileReader{ TeamData data = team.data(); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ - data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, TypeIO.readObject(Reads.get(stream)))); + data.blocks.addLast(new BlockPlan(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, TypeIO.readObject(Reads.get(stream)))); } } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 5d362e73fc..e5c4103091 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -224,8 +224,11 @@ public class TypeIO{ if(control instanceof Playerc){ write.b(0); write.i(((Playerc)control).id()); - }else{ + }else if(control instanceof FormationAI){ write.b(1); + write.i(((FormationAI)control).leader.id()); + }else{ + write.b(2); } } @@ -237,12 +240,15 @@ public class TypeIO{ //local players will cause problems if assigned, since they may not know they are controlling the unit if(player == null || player.isLocal()) return prev; return player; + }else if(type == 1){ + int id = read.i(); + return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null); }else{ //there are two cases here: //1: prev controller was not a player, carry on //2: prev controller was a player, so replace this controller with *anything else* //...since AI doesn't update clientside it doesn't matter what - return prev instanceof Playerc ? new GroundAI() : prev; + return (!(prev instanceof AIController) || (prev instanceof FormationAI)) ? new GroundAI() : prev; } } diff --git a/core/src/mindustry/io/legacy/LegacySaveVersion.java b/core/src/mindustry/io/legacy/LegacySaveVersion.java index 47f7e26955..4e543c7be6 100644 --- a/core/src/mindustry/io/legacy/LegacySaveVersion.java +++ b/core/src/mindustry/io/legacy/LegacySaveVersion.java @@ -110,7 +110,7 @@ public abstract class LegacySaveVersion extends SaveVersion{ int amount = stream.readInt(); for(int j = 0; j < amount; j++){ //simply skip all the entities - skipRegion(stream, true); + skipChunk(stream, true); } } } diff --git a/core/src/mindustry/io/legacy/Save3.java b/core/src/mindustry/io/legacy/Save3.java index 3924c18b3d..64e7683ff2 100644 --- a/core/src/mindustry/io/legacy/Save3.java +++ b/core/src/mindustry/io/legacy/Save3.java @@ -21,7 +21,7 @@ public class Save3 extends LegacySaveVersion{ TeamData data = team.data(); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ - data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt())); + data.blocks.addLast(new BlockPlan(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt())); } } diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index 922e6e9ef9..98d68b26d4 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -1,49 +1,208 @@ package mindustry.maps.generators; +import arc.func.*; +import arc.math.*; +import arc.math.geom.*; import arc.struct.*; +import mindustry.ai.BaseRegistry.*; +import mindustry.content.*; import mindustry.game.*; +import mindustry.game.Schematic.*; +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 static mindustry.Vars.*; public class BaseGenerator{ + private static final Vec2 axis = new Vec2(), rotator = new Vec2(); + + private final static int range = 180; + + private Tiles tiles; + private Team team; + private ObjectMap ores = new ObjectMap<>(); + private Array cores; public void generate(Tiles tiles, Array cores, Tile spawn, Team team, Sector sector){ + this.tiles = tiles; + this.team = team; + this.cores = cores; + Mathf.random.setSeed(sector.id); - /* - GridBits used = new GridBits(tiles.width, tiles.height); - Queue frontier = new Queue<>(); - for(Tile tile : cores){ - frontier.add(tile); + for(Block block : content.blocks()){ + if(block instanceof OreBlock && block.asFloor().itemDrop != null){ + ores.put(block.asFloor().itemDrop, (OreBlock)block); + } } - int count = 2000; - int total = 0; + float costBudget = 1000; - while(total++ < count){ - Tile tile = frontier.removeFirst(); - for(int i = 0; i < 4; i++){ - int cx = tile.x + Geometry.d4x[i], cy = tile.y + Geometry.d4y[i]; - if(tiles.in(cx, cy) && !used.get(cx, cy)){ - Tile other = tiles.getn(cx, cy); + Array wallsSmall = content.blocks().select(b -> b instanceof Wall && b.size == 1); + Array wallsLarge = content.blocks().select(b -> b instanceof Wall && b.size == 2); - if(!other.solid()){ - frontier.addLast(other); + float bracket = 0.1f; + int wallAngle = 70; //180 for full coverage + double resourceChance = 0.5; + double nonResourceChance = 0.0005; + BasePart coreschem = bases.cores.getFrac(bracket); + + Block wall = wallsSmall.getFrac(bracket), wallLarge = wallsLarge.getFrac(bracket); + + 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); + + //fill core with every type of item (even non-material) + Tilec entity = tile.entity; + for(Item item : content.items()){ + entity.items().add(item, entity.block().itemCapacity); + } + } + + //random schematics + pass(tile -> { + if(!tile.block().alwaysReplace) return; + + if((tile.drop() != null || (tile.floor().liquidDrop != null && Mathf.chance(nonResourceChance * 2))) && Mathf.chance(resourceChance)){ + Array parts = bases.forResource(tile.drop() != null ? tile.drop() : tile.floor().liquidDrop); + if(!parts.isEmpty()){ + tryPlace(parts.random(), tile.x, tile.y); + } + }else if(Mathf.chance(nonResourceChance)){ + tryPlace(bases.parts.random(), tile.x, tile.y); + } + }); + + if(wallAngle > 0){ + + //small walls + pass(tile -> { + if(tile.block().alwaysReplace){ + boolean any = false; + + for(Point2 p : Geometry.d8){ + if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(tile)) > wallAngle){ + continue; + } + + Tile o = tiles.get(tile.x + p.x, tile.y + p.y); + if(o != null && o.team() == team && !(o.block() instanceof Wall)){ + any = true; + break; + } } - used.set(cx, cy); + + if(any){ + tile.setBlock(wall, team); + } + } + }); + + //large walls + pass(curr -> { + int walls = 0; + for(int cx = 0; cx < 2; cx++){ + for(int cy = 0; cy < 2; cy++){ + Tile tile = tiles.get(curr.x + cx, curr.y + cy); + if(tile == null || tile.block().size != 1 || (tile.block() != wall && !tile.block().alwaysReplace)) return; + + if(tile.block() == wall){ + walls ++; + } + } + } + + if(walls >= 3){ + curr.setBlock(wallLarge, team); + } + }); + } + } + + public void postGenerate(){ + for(Tile tile : tiles){ + if(tile.isCenter() && tile.block() instanceof PowerNode){ + tile.entity.placed(); + } + } + } + + void pass(Cons cons){ + Tile core = cores.first(); + core.circle(range, (x, y) -> cons.get(tiles.getn(x, y))); + } + + boolean tryPlace(BasePart part, int x, int y){ + int rotation = Mathf.range(2); + axis.set((int)(part.schematic.width / 2f), (int)(part.schematic.height / 2f)); + Schematic result = Schematics.rotate(part.schematic, rotation); + int rotdeg = rotation*90; + + rotator.set(part.centerX, part.centerY).rotateAround(axis, rotdeg); + //bottom left schematic corner + int cx = x - (int)rotator.x; + int cy = y - (int)rotator.y; + + for(Stile tile : result.tiles){ + int realX = tile.x + cx, realY = tile.y + cy; + if(isTaken(tile.block, realX, realY)){ + return false; + } + } + + if(part.required instanceof 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){ + tiles.getn(ex, ey).setOverlay(ores.get((Item)part.required)); + } + + Tile rand = tiles.getc(ex + Mathf.range(1), ey + Mathf.range(1)); + if(!rand.floor().isLiquid){ + //random ores nearby to make it look more natural + rand.setOverlay(ores.get((Item)part.required)); + } + }); } } } - for(Tile tile : frontier){ - tile.setBlock(Blocks.copperWall, team); + Schematics.place(result, cx + result.width/2, cy + result.height/2, team); + + return true; + } + + boolean isTaken(Block block, int x, int y){ + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + if(overlaps(dx + offsetx + x, dy + offsety + y)){ + return true; + } + } + } + + }else{ + return overlaps(x, y); } - for(Tile tile : cores){ - tile.clearOverlay(); - tile.setBlock(Blocks.coreShard, team); - - }*/ + return false; + } + boolean overlaps(int x, int y){ + Tile tile = 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 f756a149b0..5035662d28 100644 --- a/core/src/mindustry/maps/generators/BasicGenerator.java +++ b/core/src/mindustry/maps/generators/BasicGenerator.java @@ -6,13 +6,14 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.*; +import mindustry.ai.*; +import mindustry.ai.Astar.*; import mindustry.content.*; import mindustry.world.*; import static mindustry.Vars.*; public abstract class BasicGenerator implements WorldGenerator{ - protected static final DistanceHeuristic manhattan = (x1, y1, x2, y2) -> Math.abs(x1 - x2) + Math.abs(y1 - y2); protected static final ShortArray ints1 = new ShortArray(), ints2 = new ShortArray(); protected Rand rand = new Rand(); @@ -313,50 +314,7 @@ public abstract class BasicGenerator implements WorldGenerator{ } public Array pathfind(int startX, int startY, int endX, int endY, TileHueristic th, DistanceHeuristic dh){ - Tile start = tiles.getn(startX, startY); - Tile end = tiles.getn(endX, endY); - GridBits closed = new GridBits(width, height); - IntFloatMap costs = new IntFloatMap(); - PQueue queue = new PQueue<>(tiles.width * tiles.height / 4, Structs.comparingFloat(a -> costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y))); - queue.add(start); - boolean found = false; - while(!queue.empty()){ - Tile next = queue.poll(); - float baseCost = costs.get(next.pos(), 0f); - if(next == end){ - found = true; - break; - } - closed.set(next.x, next.y); - for(Point2 point : Geometry.d4){ - int newx = next.x + point.x, newy = next.y + point.y; - if(Structs.inBounds(newx, newy, width, height) && world.getDarkness(newx, newy) <= 1f){ - Tile child = tiles.getn(newx, newy); - float newCost = th.cost(child) + baseCost; - if(!closed.get(child.x, child.y)){ - closed.set(child.x, child.y); - child.rotation(child.relativeTo(next.x, next.y)); - costs.put(child.pos(), newCost); - queue.add(child); - } - } - } - } - - Array out = new Array<>(); - - if(!found) return out; - - Tile current = end; - while(current != start){ - out.add(current); - Point2 p = Geometry.d4(current.rotation()); - current = tiles.getn(current.x + p.x, current.y + p.y); - } - - out.reverse(); - - return out; + return Astar.pathfind(startX, startY, endX, endY, th, dh, tile -> world.getDarkness(tile.x, tile.y) <= 1f); } public void trimDark(){ @@ -397,12 +355,4 @@ public abstract class BasicGenerator implements WorldGenerator{ } } } - - public interface DistanceHeuristic{ - float cost(int x1, int y1, int x2, int y2); - } - - public interface TileHueristic{ - float cost(Tile tile); - } } diff --git a/core/src/mindustry/maps/generators/WorldGenerator.java b/core/src/mindustry/maps/generators/WorldGenerator.java index c66138096e..71f5c23d34 100644 --- a/core/src/mindustry/maps/generators/WorldGenerator.java +++ b/core/src/mindustry/maps/generators/WorldGenerator.java @@ -4,4 +4,7 @@ import mindustry.world.*; public interface WorldGenerator{ void generate(Tiles tiles); + + /** Do not modify tiles here. This is only for specialized configuration. */ + default void postGenerate(Tiles tiles){} } diff --git a/core/src/mindustry/maps/planet/TODOPlanetGenerator.java b/core/src/mindustry/maps/planet/TODOPlanetGenerator.java index 7558f1a03f..dc838ea5a4 100644 --- a/core/src/mindustry/maps/planet/TODOPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/TODOPlanetGenerator.java @@ -6,6 +6,7 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import arc.util.noise.*; +import mindustry.ai.*; import mindustry.content.*; import mindustry.game.*; import mindustry.maps.generators.*; @@ -16,6 +17,7 @@ import static mindustry.Vars.*; public class TODOPlanetGenerator extends PlanetGenerator{ Simplex noise = new Simplex(); RidgedPerlin rid = new RidgedPerlin(1, 2); + BaseGenerator basegen = new BaseGenerator(); float scl = 5f; float waterOffset = 0.07f; @@ -131,7 +133,7 @@ public class TODOPlanetGenerator extends PlanetGenerator{ connected.add(to); float nscl = rand.random(20f, 60f); int stroke = rand.random(4, 12); - brush(pathfind(x, y, to.x, to.y, tile -> (tile.solid() ? 5f : 0f) + noise(tile.x, tile.y, 1, 1, 1f / nscl) * 60, manhattan), stroke); + brush(pathfind(x, y, to.x, to.y, tile -> (tile.solid() ? 5f : 0f) + noise(tile.x, tile.y, 1, 1, 1f / nscl) * 60, Astar.manhattan), stroke); } } @@ -281,7 +283,7 @@ public class TODOPlanetGenerator extends PlanetGenerator{ Schematics.placeLoadout(Loadouts.advancedShard, spawn.x, spawn.y); if(sector.hasEnemyBase()){ - new BaseGenerator().generate(tiles, enemies.map(r -> tiles.getn(r.x, r.y)), tiles.get(spawn.x, spawn.y), state.rules.waveTeam, sector); + basegen.generate(tiles, enemies.map(r -> tiles.getn(r.x, r.y)), tiles.get(spawn.x, spawn.y), state.rules.waveTeam, sector); state.rules.attackMode = true; } @@ -289,4 +291,8 @@ public class TODOPlanetGenerator extends PlanetGenerator{ state.rules.waves = true; } + @Override + public void postGenerate(Tiles tiles){ + basegen.postGenerate(); + } } diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index 0212607b1a..9961eb8f8c 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -346,7 +346,7 @@ public class Mods implements Loadable{ for(Fi file : folder.list()){ if(file.name().startsWith("bundle") && file.extension().equals("properties")){ String name = file.nameWithoutExtension(); - bundles.getOr(name, Array::new).add(file); + bundles.get(name, Array::new).add(file); } } } @@ -357,7 +357,7 @@ public class Mods implements Loadable{ while(bundle != null){ String str = bundle.getLocale().toString(); String locale = "bundle" + (str.isEmpty() ? "" : "_" + str); - for(Fi file : bundles.getOr(locale, Array::new)){ + for(Fi file : bundles.get(locale, Array::new)){ try{ PropertiesUtils.load(bundle.getProperties(), file.reader()); }catch(Throwable e){ diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index 3559400beb..c25a34fb66 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -17,10 +17,11 @@ import java.net.*; import java.util.regex.*; public class Scripts implements Disposable{ + private final static Object[] emptyObjects = {}; private final Array blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk", "runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system", ".awt", "socket", "classloader", "oracle", "invoke", "arc.events", "java.util.function", "java.util.stream"); - private final Array whitelist = Array.with("mindustry.net", "netserver", "netclient", "com.sun.proxy.$proxy"); + private final Array whitelist = Array.with("mindustry.net", "netserver", "netclient", "com.sun.proxy.$proxy", "mindustry.gen."); private final Context context; private Scriptable scope; private boolean errored; diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index 84c5ee5ed6..6fce3740af 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -1,5 +1,6 @@ package mindustry.net; +import arc.Core; import arc.util.*; import arc.util.io.*; import mindustry.core.*; @@ -72,7 +73,7 @@ public class NetworkIO{ writeString(buffer, name, 100); writeString(buffer, map); - buffer.putInt(Groups.player.size()); + buffer.putInt(Core.settings.getInt("totalPlayers", Groups.player.size())); buffer.putInt(state.wave); buffer.putInt(Version.build); writeString(buffer, Version.type); diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java index e2f9cab47c..c3d13fe62b 100644 --- a/core/src/mindustry/type/Planet.java +++ b/core/src/mindustry/type/Planet.java @@ -45,6 +45,8 @@ public class Planet extends UnlockableContent{ public float orbitTime; /** Time for the planet to perform a full revolution, in seconds. One day. */ public float rotateTime = 24f * 60f; + /** Approx. radius of one sector. */ + 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 the bloom render effect is enabled. */ @@ -80,6 +82,8 @@ public class Planet extends UnlockableContent{ sectors.add(new Sector(this, grid.tiles[i], new SectorData())); } + sectorApproxRadius = sectors.first().tile.v.dst(sectors.first().tile.corners[0].v); + //read data for sectors Fi data = Vars.tree.get("planets/" + name + ".dat"); if(data.exists()){ @@ -96,7 +100,6 @@ public class Planet extends UnlockableContent{ } for(Sector sector : sectors){ - sector.unlocked = true; sector.generate(); } }else{ diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index ca5b4dd183..14baf187f9 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -26,7 +26,6 @@ public class Sector{ public @Nullable SaveSlot save; public @Nullable SectorPreset preset; - public boolean unlocked; /** Sector enemy hostility from 0 to 1 */ public float hostility; @@ -47,7 +46,7 @@ public class Sector{ * Only sectors adjacent to non-wave sectors can be landed on. * TODO also preset sectors*/ public boolean unlocked(){ - return Structs.contains(tile.tiles, p -> planet.getSector(p).isCaptured()) || (preset != null && preset.unlocked()); + return hasBase() || Structs.contains(tile.tiles, p -> planet.getSector(p).isCaptured()) || (preset != null && preset.unlocked()); } /** @return whether the player has a base here. */ diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index a4d27f6f79..9c2e862247 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -32,8 +32,6 @@ public class UnitType extends UnlockableContent{ public boolean flying; public @NonNull Prov constructor; public @NonNull Prov defaultController = () -> !flying ? new GroundAI() : new FlyingAI(); - public @Nullable UnitType upgrade; - public int tier = 1; public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f; public float drag = 0.3f, accel = 0.5f, landShake = 0f; public float health = 200f, range = -1, armor = 0f; @@ -42,9 +40,12 @@ public class UnitType extends UnlockableContent{ public boolean canBoost = false; public float sway = 1f; public int payloadCapacity = 1; + public int commandLimit = 24; + public float baseElevation = 0f; + //TODO document public int legCount = 4; - public float legLength = 24f, legSpeed = 0.1f, legTrns = 1f; + public float legLength = 10f, legSpeed = 0.1f, legTrns = 1f, legBaseOffset = 0f, legMoveSpace = 1f, legExtension = 0; public int itemCapacity = 30; public int drillTier = -1; @@ -62,7 +63,8 @@ public class UnitType extends UnlockableContent{ public Sound deathSound = Sounds.bang; public Array weapons = new Array<>(); - public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, occlusionRegion, jointRegion, footRegion, legBaseRegion; + public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, + occlusionRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion; public UnitType(String name){ super(name); @@ -82,7 +84,6 @@ public class UnitType extends UnlockableContent{ public Unitc create(Team team){ Unitc unit = constructor.get(); unit.team(team); - unit.armor(armor); unit.type(this); return unit; } @@ -118,6 +119,7 @@ public class UnitType extends UnlockableContent{ region = Core.atlas.find(name); legRegion = Core.atlas.find(name + "-leg"); jointRegion = Core.atlas.find(name + "-joint"); + baseJointRegion = Core.atlas.find(name + "-joint-base"); footRegion = Core.atlas.find(name + "-foot"); legBaseRegion = Core.atlas.find(name + "-leg-base", name + "-leg"); baseRegion = Core.atlas.find(name + "-base"); @@ -263,10 +265,6 @@ public class UnitType extends UnlockableContent{ if(unit instanceof Trailc){ Trail trail = ((Trailc)unit).trail(); - - float cx = unit.x() + Angles.trnsx(unit.rotation() + 180, offset), - cy = unit.y() + Angles.trnsy(unit.rotation() + 180, offset); - trail.update(cx, cy); trail.draw(unit.team().color, (engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f) * scale)); } @@ -336,33 +334,52 @@ public class UnitType extends UnlockableContent{ } public void drawLegs(Legsc unit){ + //Draw.z(Layer.groundUnit - 0.02f); + Leg[] legs = unit.legs(); - float ssize = footRegion.getWidth() * Draw.scl * 1.5f; + float rotation = unit.baseRotation(); for(Leg leg : legs){ Drawf.shadow(leg.base.x, leg.base.y, ssize); } + //TODO should be below/above legs + if(baseRegion.found()){ + Draw.rect(baseRegion, unit.x(), unit.y(), rotation); + } + int index = 0; + //TODO figure out layering for(Leg leg : legs){ + float angle = unit.legAngle(rotation, index); boolean flip = index++ >= legs.length/2f; int flips = Mathf.sign(flip); + Vec2 position = legOffset.trns(angle, legBaseOffset).add(unit); + Tmp.v1.set(leg.base).sub(leg.joint).inv().setLength(legExtension); + Draw.color(); Lines.stroke(legRegion.getHeight() * Draw.scl * flips); - Lines.line(legRegion, unit.x(), unit.y(), leg.joint.x, leg.joint.y, CapStyle.none, 0); + Lines.line(legRegion, position.x, position.y, leg.joint.x, leg.joint.y, CapStyle.none, 0); Lines.stroke(legBaseRegion.getHeight() * Draw.scl * flips); - Lines.line(legBaseRegion, leg.joint.x, leg.joint.y, leg.base.x, leg.base.y, CapStyle.none, 0); + Lines.line(legBaseRegion, leg.joint.x + Tmp.v1.x, leg.joint.y + Tmp.v1.y, leg.base.x, leg.base.y, CapStyle.none, 0); - float angle1 = unit.angleTo(leg.joint), angle2 = unit.angleTo(leg.base); + float angle2 = position.angleTo(leg.base); + + if(jointRegion.found()){ + Draw.rect(jointRegion, leg.joint.x, leg.joint.y); + } - Draw.rect(jointRegion, leg.joint.x, leg.joint.y); Draw.rect(footRegion, leg.base.x, leg.base.y, angle2); + + if(baseJointRegion.found()){ + Draw.rect(baseJointRegion, position.x, position.y, rotation); + } } Draw.reset(); diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index a73ab597ef..1dde54513f 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -47,7 +47,7 @@ public class Weapon{ /** delay in ticks between shots */ public float shotDelay = 0; /** The half-radius of the cone in which shooting will start. */ - public float shootCone = 1.5f; + public float shootCone = 5f; /** whether shooter rotation is ignored when shooting. */ public boolean ignoreRotation = false; /** sound used for shooting */ diff --git a/core/src/mindustry/ui/CoreItemsDisplay.java b/core/src/mindustry/ui/CoreItemsDisplay.java new file mode 100644 index 0000000000..11d0511376 --- /dev/null +++ b/core/src/mindustry/ui/CoreItemsDisplay.java @@ -0,0 +1,53 @@ +package mindustry.ui; + +import arc.scene.ui.layout.*; +import arc.struct.*; +import mindustry.*; +import mindustry.gen.*; +import mindustry.type.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.*; + +public class CoreItemsDisplay extends Table{ + private final ObjectSet usedItems = new ObjectSet<>(); + + public CoreItemsDisplay(){ + rebuild(); + } + + public void resetUsed(){ + usedItems.clear(); + } + + void rebuild(){ + clear(); + background(Tex.button); + + update(() -> { + CoreEntity core = Vars.player.team().core(); + + for(Item item : content.items()){ + if(core != null && core.items.get(item) > 0 && usedItems.add(item)){ + rebuild(); + break; + } + } + }); + + int i = 0; + + CoreEntity core = Vars.player.team().core(); + for(Item item : content.items()){ + if(usedItems.contains(item)){ + image(item.icon(Cicon.medium)).padRight(4); + label(() -> core == null ? "0" : ui.formatAmount(core.items.get(item))).padRight(4); + + if(++i % 2 == 0){ + row(); + } + } + } + + } +} diff --git a/core/src/mindustry/ui/dialogs/CustomGameDialog.java b/core/src/mindustry/ui/dialogs/CustomGameDialog.java index e9667270b8..1d7aa2d07b 100644 --- a/core/src/mindustry/ui/dialogs/CustomGameDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomGameDialog.java @@ -38,7 +38,7 @@ public class CustomGameDialog extends BaseDialog{ ScrollPane pane = new ScrollPane(maps); pane.setFadeScrollBars(false); - int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(200)), 1, 8); + int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(210)), 1); float images = 146f; int i = 0; diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index b18e4deb4c..f45850b0fd 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -35,7 +35,7 @@ public class CustomRulesDialog extends BaseDialog{ banDialog.shown(this::rebuildBanned); banDialog.buttons.button("$addall", Icon.add, () -> { - rules.bannedBlocks.addAll(content.blocks().select(Block::isBuildable)); + rules.bannedBlocks.addAll(content.blocks().select(Block::canBeBuilt)); rebuildBanned(); }).size(180, 64f); @@ -88,7 +88,7 @@ public class CustomRulesDialog extends BaseDialog{ dialog.cont.pane(t -> { t.left().margin(14f); int[] i = {0}; - content.blocks().each(b -> !rules.bannedBlocks.contains(b) && b.isBuildable(), b -> { + content.blocks().each(b -> !rules.bannedBlocks.contains(b) && b.canBeBuilt(), b -> { int cols = mobile && Core.graphics.isPortrait() ? 4 : 12; t.button(new TextureRegionDrawable(b.icon(Cicon.medium)), Styles.cleari, () -> { rules.bannedBlocks.add(b); @@ -153,10 +153,6 @@ public class CustomRulesDialog extends BaseDialog{ main.button("$bannedblocks", banDialog::show).left().width(300f); main.row(); - title("$rules.title.player"); - number("$rules.playerhealthmultiplier", f -> rules.playerHealthMultiplier = f, () -> rules.playerHealthMultiplier); - number("$rules.playerdamagemultiplier", f -> rules.playerDamageMultiplier = f, () -> rules.playerDamageMultiplier); - title("$rules.title.unit"); number("$rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier); number("$rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier); @@ -167,7 +163,7 @@ public class CustomRulesDialog extends BaseDialog{ check("$rules.enemyCheat", b -> rules.enemyCheat = b, () -> rules.enemyCheat); number("$rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200)); - title("$rules.title.experimental"); + title("$rules.title.environment"); number("$rules.solarpowermultiplier", f -> rules.solarPowerMultiplier = f, () -> rules.solarPowerMultiplier); check("$rules.lighting", b -> rules.lighting = b, () -> rules.lighting); @@ -181,6 +177,8 @@ public class CustomRulesDialog extends BaseDialog{ b.add("$rules.ambientlight"); }, () -> ui.picker.show(rules.ambientLight, rules.ambientLight::set)).left().width(250f); main.row(); + + //TODO add weather patterns } void number(String text, Floatc cons, Floatp prov){ diff --git a/core/src/mindustry/ui/dialogs/LoadDialog.java b/core/src/mindustry/ui/dialogs/LoadDialog.java index c74580e9a6..9231f1f289 100644 --- a/core/src/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/mindustry/ui/dialogs/LoadDialog.java @@ -31,12 +31,11 @@ public class LoadDialog extends BaseDialog{ super(title); setup(); - shown(() -> { - setup(); - Time.runTask(2f, () -> Core.scene.setScrollFocus(pane)); - }); + shown(this::setup); + onResize(this::setup); addCloseButton(); + addSetup(); } protected void setup(){ @@ -47,16 +46,22 @@ public class LoadDialog extends BaseDialog{ pane.setFadeScrollBars(false); pane.setScrollingDisabled(true, false); - slots.marginRight(24); + slots.marginRight(24).marginLeft(20f); Time.runTask(2f, () -> Core.scene.setScrollFocus(pane)); Array array = control.saves.getSaveSlots(); array.sort((slot, other) -> -Long.compare(slot.getTimestamp(), other.getTimestamp())); + int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(470)), 1); + int i = 0; + boolean any = false; + for(SaveSlot slot : array){ if(slot.isHidden()) continue; + any = true; + TextButton button = new TextButton("", Styles.cleart); button.getLabel().remove(); button.clearChildren(); @@ -97,8 +102,8 @@ public class LoadDialog extends BaseDialog{ String color = "[lightgray]"; TextureRegion def = Core.atlas.find("nomap"); - button.left().add(new BorderImage(def, 4f)).update(i -> { - TextureRegionDrawable draw = (TextureRegionDrawable)i.getDrawable(); + button.left().add(new BorderImage(def, 4f)).update(im -> { + TextureRegionDrawable draw = (TextureRegionDrawable)im.getDrawable(); if(draw.getRegion().getTexture().isDisposed()){ draw.setRegion(def); } @@ -107,7 +112,7 @@ public class LoadDialog extends BaseDialog{ if(draw.getRegion() == def && text != null){ draw.setRegion(new TextureRegion(text)); } - i.setScaling(Scaling.fit); + im.setScaling(Scaling.fit); }).left().size(160f).padRight(6); button.table(meta -> { @@ -128,27 +133,23 @@ public class LoadDialog extends BaseDialog{ modifyButton(button, slot); - slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).row(); + slots.add(button).uniformX().fillX().pad(4).padRight(8f).margin(10f); + + if(++i % maxwidth == 0){ + slots.row(); + } + } + + if(!any){ + slots.button("$save.none", () -> {}).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f); } cont.add(pane); - - addSetup(); } public void addSetup(){ - boolean valids = false; - for(SaveSlot slot : control.saves.getSaveSlots()) if(!slot.isHidden()) valids = true; - if(!valids){ - slots.row(); - slots.button("$save.none", () -> { - }).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f); - } - - slots.row(); - - slots.button("$save.import", Icon.add, () -> { + buttons.button("$save.import", Icon.add, () -> { platform.showFileChooser(true, saveExtension, file -> { if(SaveIO.isSaveValid(file)){ try{ @@ -162,7 +163,7 @@ public class LoadDialog extends BaseDialog{ ui.showErrorMessage("$save.import.invalid"); } }); - }).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); + }).fillX().margin(10f); } public void runLoadSave(SaveSlot slot){ diff --git a/core/src/mindustry/ui/dialogs/MapsDialog.java b/core/src/mindustry/ui/dialogs/MapsDialog.java index 07b7bc5ce7..66d502c8c7 100644 --- a/core/src/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/mindustry/ui/dialogs/MapsDialog.java @@ -3,7 +3,6 @@ package mindustry.ui.dialogs; import arc.*; import arc.graphics.*; import arc.input.*; -import arc.math.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; @@ -80,7 +79,7 @@ public class MapsDialog extends BaseDialog{ //when you attempt to import a save, it will have no name, so generate one - String name = map.tags.getOr("name", () -> { + String name = map.tags.get("name", () -> { String result = "unknown"; int number = 0; while(maps.byName(result + number++) != null); @@ -124,7 +123,7 @@ public class MapsDialog extends BaseDialog{ ScrollPane pane = new ScrollPane(maps); pane.setFadeScrollBars(false); - int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(230)), 1, 8); + int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1); float mapsize = 200f; int i = 0; diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index e0ac76d65c..67fc26b00c 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -93,7 +93,9 @@ public class ModsDialog extends BaseDialog{ t.button("$mod.import.github", Icon.github, bstyle, () -> { dialog.hide(); - ui.showTextInput("$mod.import.github", "", 64, "Anuken/ExampleMod", text -> { + ui.showTextInput("$mod.import.github", "", 64, Core.settings.getString("lastmod", "Anuken/ExampleMod"), text -> { + Core.settings.put("lastmod", text); + ui.loadfrag.show(); Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> { Core.net.httpGet(loc.getHeader("Location"), result -> { diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index cb0f22c3a0..eb8cbe265d 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -3,208 +3,188 @@ package mindustry.ui.dialogs; import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; -import arc.graphics.g3d.*; import arc.graphics.gl.*; import arc.input.*; import arc.math.*; import arc.math.geom.*; import arc.scene.event.*; -import arc.scene.ui.TextButton.*; +import arc.scene.ui.*; import arc.scene.ui.layout.*; -import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; import mindustry.ctype.*; -import mindustry.game.EventType.*; -import mindustry.game.Objectives.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.graphics.g3d.*; -import mindustry.graphics.g3d.PlanetGrid.*; +import mindustry.graphics.g3d.PlanetRenderer.*; import mindustry.type.*; import mindustry.type.Sector.*; import mindustry.ui.*; +import mindustry.world.blocks.campaign.CoreLauncher.*; import static mindustry.Vars.*; +import static mindustry.graphics.g3d.PlanetRenderer.*; +import static mindustry.ui.dialogs.PlanetDialog.Mode.*; -public class PlanetDialog extends BaseDialog{ - private static final Color - outlineColor = Pal.accent.cpy().a(1f), - hoverColor = Pal.accent.cpy().a(0.5f), - borderColor = Pal.accent.cpy().a(0.3f), - shadowColor = new Color(0, 0, 0, 0.7f); - private static final float camLength = 4f; - private static final float outlineRad = 1.16f; - private static final Array points = new Array<>(); +public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ + private final FrameBuffer buffer = new FrameBuffer(2, 2, true); + private final PlanetRenderer planets = renderer.planets; + private final Table stable = new Table().background(Styles.black3); - //the base planet that's being rendered - private final Planet solarSystem = Planets.sun; - - private final Mesh[] outlines = new Mesh[10]; - private final Camera3D cam = new Camera3D(); - private final VertexBatch3D batch = new VertexBatch3D(10000, false, true, 0); - private final PlaneBatch3D projector = new PlaneBatch3D(); - private final Mat3D mat = new Mat3D(); - private final Vec3 camRelative = new Vec3(); - private final ResourcesDialog resources = new ResourcesDialog(); - - private float zoom = 1f, smoothZoom = 1f, selectAlpha = 1f; - private Bloom bloom; - private Planet planet = Planets.starter; - private @Nullable Sector selected, hovered; - private Table stable; - private Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f); - - //seed: 8kmfuix03fw - private CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); + private int launchRange; + private float zoom = 1f, selectAlpha = 1f; + private @Nullable Sector selected, hovered, launchSector; + private CoreLauncherEntity launcher; + private Mode mode = look; public PlanetDialog(){ super("", Styles.fullDialog); - makeBloom(); - - Events.on(DisposeEvent.class, () -> { - skybox.dispose(); - batch.dispose(); - projector.dispose(); - atmosphere.dispose(); - for(Mesh m : outlines){ - if(m != null){ - m.dispose(); - } - } - }); - - Events.on(ResizeEvent.class, e -> { - makeBloom(); - }); - - TextButtonStyle style = Styles.cleart; - float bmargin = 6f; - getCell(buttons).padBottom(-4); buttons.background(Styles.black).defaults().growX().height(64f).pad(0); - //TODO - buttons.button("$back", Icon.left, style, this::hide).margin(bmargin); - buttons.button("Research", Icon.tree, style, () -> ui.tech.show()).margin(bmargin); - //buttons.button("Database", Icon.book, style, () -> ui.database.show()).margin(bmargin); - buttons.button("Resources", Icon.file, style, resources::show).margin(bmargin); - - cam.fov = 60f; - - camRelative.set(0, 0f, camLength); - projector.setScaling(1f / 150f); + keyDown(key -> { + if(key == KeyCode.escape || key == KeyCode.back){ + Core.app.post(this::hide); + } + }); dragged((cx, cy) -> { - float upV = camRelative.angle(Vec3.Y); + Vec3 pos = planets.camPos; + + float upV = pos.angle(Vec3.Y); float xscale = 9f, yscale = 10f; float margin = 1; //scale X speed depending on polar coordinate float speed = 1f - Math.abs(upV - 90) / 90f; - camRelative.rotate(cam.up, cx / xscale * speed); + pos.rotate(planets.cam.up, cx / xscale * speed); //prevent user from scrolling all the way up and glitching it out float amount = cy / yscale; amount = Mathf.clamp(upV + amount, margin, 180f - margin) - upV; - camRelative.rotate(Tmp.v31.set(cam.up).rotate(cam.direction, 90), amount); + pos.rotate(Tmp.v31.set(planets.cam.up).rotate(planets.cam.direction, 90), amount); }); scrolled(value -> { zoom = Mathf.clamp(zoom + value / 10f, 0.5f, 2f); }); - update(() -> { - if(planet.isLandable()){ - hovered = planet.getSector(cam.getMouseRay(), outlineRad); - }else{ - hovered = selected = null; - } - - smoothZoom = Mathf.lerpDelta(smoothZoom, zoom, 0.4f); - selectAlpha = Mathf.lerpDelta(selectAlpha, Mathf.num(smoothZoom < 1.9f), 0.1f); - }); - addListener(new ElementGestureListener(){ @Override public void tap(InputEvent event, float x, float y, int count, KeyCode button){ - selected = hovered != null && hovered.locked() ? null : hovered; + if(hovered != null && (mode == launch ? canLaunch(hovered) && hovered != launchSector : hovered.unlocked())){ + selected = hovered; + } + if(selected != null){ updateSelected(); } } }); - stable = new Table(); - stable.background(Styles.black3); - shown(this::setup); } - void makeBloom(){ - if(bloom != null){ - bloom.dispose(); - bloom = null; + /** show with no limitations, just as a map. */ + @Override + public Dialog show(){ + mode = look; + selected = hovered = launchSector = null; + return super.show(); + } + + public void show(Sector sector, int range, CoreLauncherEntity launcher){ + this.launcher = launcher; + selected = null; + hovered = null; + + //update view to sector + planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation())); + zoom = 1f; + planets.zoom = 2f; + selectAlpha = 0f; + launchRange = range; + launchSector = sector; + + mode = launch; + + super.show(); + } + + boolean canLaunch(Sector sector){ + return mode == launch && sector.tile.v.within(launchSector.tile.v, (launchRange + 0.5f) * planets.planet.sectorApproxRadius*2); + } + + @Override + public void renderSectors(Planet planet){ + + //draw all sector stuff + for(Sector sec : planet.sectors){ + if(selectAlpha > 0.01f){ + if(canLaunch(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); + } + } } - bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false, true){{ - setClearColor(0, 0, 0, 0); - setThreshold(0.8f); - blurPasses = 6; - }}; - } - - void setup(){ - cont.clear(); - titleTable.remove(); - - cont.rect((x, y, w, h) -> render()).grow(); - } - - private void render(){ - Draw.flush(); - Gl.clear(Gl.depthBufferBit); - Gl.enable(Gl.depthTest); - - Gl.enable(Gl.cullFace); - Gl.cullFace(Gl.back); - - //lock to up vector so it doesn't get confusing - cam.up.set(Vec3.Y); - - cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); - camRelative.setLength(planet.radius * camLength + (smoothZoom-1f) * planet.radius * 2); - cam.position.set(planet.position).add(camRelative); - cam.lookAt(planet.position); - cam.update(); - - //TODO hacky - Shaders.planet.camDir.set(cam.direction).rotate(Vec3.Y, planet.getRotation()); - - projector.proj(cam.combined); - batch.proj(cam.combined); - - beginBloom(); - - skybox.render(cam.combined); - - renderPlanet(solarSystem); - - endBloom(); - - Gl.enable(Gl.blend); + if(launchSector != null){ + planets.fill(launchSector, hoverColor, -0.001f); + } + //draw hover border if(hovered != null){ - Draw.batch(projector, () -> { - setPlane(hovered); + planets.fill(hovered, hoverColor, -0.001f); + planets.drawBorders(hovered, borderColor); + } + + //draw selected borders + if(selected != null){ + planets.drawSelection(selected); + planets.drawBorders(selected, borderColor); + } + + planets.batch.flush(Gl.triangles); + + if(mode == launch){ + if(hovered != launchSector && hovered != null && canLaunch(hovered)){ + planets.drawArc(planet, launchSector.tile.v, hovered.tile.v); + } + } + + /* + //TODO render arcs + if(selected != null && selected.preset != null){ + for(Objective o : selected.preset.requirements){ + if(o instanceof SectorObjective){ + SectorPreset preset = ((SectorObjective)o).preset; + planets.drawArc(planet, selected.tile.v, preset.sector.tile.v); + } + } + }*/ + } + + @Override + public void renderProjections(){ + if(hovered != null){ + planets.drawPlane(hovered, () -> { Draw.color(Color.white, Pal.accent, Mathf.absin(5f, 1f)); - TextureRegion icon = hovered.locked() ? Icon.lock.getRegion() : hovered.is(SectorAttribute.naval) ? Liquids.water.icon(Cicon.large) : null; + TextureRegion icon = hovered.locked() && !canLaunch(hovered) ? Icon.lock.getRegion() : hovered.is(SectorAttribute.naval) ? Liquids.water.icon(Cicon.large) : null; if(icon != null){ Draw.rect(icon, 0, 0); @@ -213,201 +193,95 @@ public class PlanetDialog extends BaseDialog{ Draw.reset(); }); } + } - Gl.disable(Gl.cullFace); - Gl.disable(Gl.depthTest); + void setup(){ + zoom = planets.zoom = 1f; + selectAlpha = 1f; + + cont.clear(); + titleTable.remove(); + + cont.rect((x, y, w, h) -> planets.render(this)).grow(); + } + + @Override + public void draw(){ + boolean doBuffer = color.a < 0.99f; + + if(doBuffer){ + buffer.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); + buffer.begin(Color.clear); + } + + super.draw(); + + if(doBuffer){ + buffer.end(); + Draw.color(color); + Draw.rect(Draw.wrap(buffer.getTexture()), Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Core.graphics.getWidth(), -Core.graphics.getHeight()); + Draw.color(); + } + } + + @Override + public void act(float delta){ + super.act(delta); if(selected != null){ addChild(stable); - Vec3 pos = cam.project(Tmp.v31.set(selected.tile.v).setLength(outlineRad).rotate(Vec3.Y, -planet.getRotation()).add(planet.position)); + Vec3 pos = planets.cam.project(Tmp.v31.set(selected.tile.v).setLength(PlanetRenderer.outlineRad).rotate(Vec3.Y, -planets.planet.getRotation()).add(planets.planet.position)); stable.setPosition(pos.x, pos.y, Align.center); stable.toFront(); }else{ stable.remove(); } - cam.update(); - } - - private void beginBloom(){ - bloom.capture(); - } - - private void endBloom(){ - bloom.render(); - } - - private void renderPlanet(Planet planet){ - //render planet at offsetted position in the world - planet.mesh.render(cam.combined, planet.getTransform(mat)); - - renderOrbit(planet); - - if(planet.isLandable() && planet == this.planet){ - renderSectors(planet); - } - - if(planet.parent != null && planet.hasAtmosphere && Core.settings.getBool("atmosphere")){ - Blending.additive.apply(); - - Shaders.atmosphere.camera = cam; - Shaders.atmosphere.planet = planet; - Shaders.atmosphere.bind(); - Shaders.atmosphere.apply(); - - atmosphere.render(Shaders.atmosphere, Gl.triangles); - - Blending.normal.apply(); - } - - for(Planet child : planet.children){ - renderPlanet(child); - } - } - - private void renderOrbit(Planet planet){ - if(planet.parent == null) return; - - Vec3 center = planet.parent.position; - float radius = planet.orbitRadius; - int points = (int)(radius * 50); - Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray)); - batch.flush(Gl.lineLoop); - } - - private void renderSectors(Planet planet){ - //apply transformed position - batch.proj().mul(planet.getTransform(mat)); - - for(Sector sec : planet.sectors){ - - if(selectAlpha > 0.01f){ - if(sec.unlocked()){ - Color color = - sec.hasBase() ? Team.sharded.color : - sec.preset != null ? Team.derelict.color : - sec.hasEnemyBase() ? Team.crux.color : - null; - - if(color != null){ - drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(selectAlpha), 0.026f, -0.001f); - } - }else{ - draw(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, selectAlpha), -0.001f); - } - } - } - - if(hovered != null){ - draw(hovered, hoverColor, -0.001f); - drawBorders(hovered, borderColor); + if(planets.planet.isLandable()){ + hovered = planets.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad); + }else{ + hovered = selected = null; } - if(selected != null){ - drawSelection(selected); - drawBorders(selected, borderColor); - } - - batch.flush(Gl.triangles); - - //render arcs - if(selected != null && selected.preset != null){ - for(Objective o : selected.preset.requirements){ - if(o instanceof SectorObjective){ - SectorPreset preset = ((SectorObjective)o).preset; - drawArc(planet, selected.tile.v, preset.sector.tile.v); - } - } - } - - //render sector grid - Mesh mesh = outline(planet.grid.size); - Shader shader = Shaders.planetGrid; - Vec3 tile = planet.intersect(cam.getMouseRay(), outlineRad); - Shaders.planetGrid.mouse.lerp(tile == null ? Vec3.Zero : tile.sub(planet.position).rotate(Vec3.Y, planet.getRotation()), 0.2f); - - shader.bind(); - shader.setUniformMatrix4("u_proj", cam.combined.val); - shader.setUniformMatrix4("u_trans", planet.getTransform(mat).val); - shader.apply(); - mesh.render(shader, Gl.lines); - } - - private void drawArc(Planet planet, Vec3 a, Vec3 b){ - Vec3 avg = Tmp.v31.set(a).add(b).scl(0.5f); - avg.setLength(planet.radius*2f); - - points.clear(); - points.addAll(Tmp.v33.set(a).setLength(outlineRad), Tmp.v31, Tmp.v34.set(b).setLength(outlineRad)); - Tmp.bz3.set(points); - float points = 25; - - for(int i = 0; i < points + 1; i++){ - float f = i / points; - Tmp.c1.set(Pal.accent).lerp(Color.clear, (f+Time.globalTime()/80f)%1f); - batch.color(Tmp.c1); - batch.vertex(Tmp.bz3.valueAt(Tmp.v32, f)); - - } - batch.flush(Gl.lineStrip); - } - - private void drawBorders(Sector sector, Color base){ - Color color = Tmp.c1.set(base).a(base.a + 0.3f + Mathf.absin(Time.globalTime(), 5f, 0.3f)); - - float r1 = 1f; - float r2 = outlineRad + 0.001f; - - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; - - Tmp.v31.set(c.v).setLength(r2); - Tmp.v32.set(next.v).setLength(r2); - Tmp.v33.set(c.v).setLength(r1); - - batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); - - Tmp.v31.set(next.v).setLength(r2); - Tmp.v32.set(next.v).setLength(r1); - Tmp.v33.set(c.v).setLength(r1); - - batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); - } - - if(batch.getNumVertices() >= batch.getMaxVertices() - 6 * 6){ - batch.flush(Gl.triangles); - } + planets.zoom = Mathf.lerpDelta(planets.zoom, zoom, 0.4f); + selectAlpha = Mathf.lerpDelta(selectAlpha, Mathf.num(planets.zoom < 1.9f), 0.1f); } + //TODO add strings to bundle after prototyping is done private void updateSelected(){ + Sector sector = selected; + + if(sector == null){ + stable.remove(); + return; + } + float x = stable.getX(Align.center), y = stable.getY(Align.center); stable.clear(); stable.background(Styles.black6); - //TODO add strings to bundle after prototyping is done - - stable.add("[accent]" + (selected.preset == null ? selected.id : selected.preset.localizedName)).row(); + stable.add("[accent]" + (sector.preset == null ? sector.id : sector.preset.localizedName)).row(); stable.image().color(Pal.accent).fillX().height(3f).pad(3f).row(); - stable.add(selected.save != null ? selected.save.getPlayTime() : "[lightgray]Unexplored").row(); + stable.add(sector.save != null ? sector.save.getPlayTime() : "[lightgray]Unexplored").row(); stable.add("Resources:").row(); stable.table(t -> { t.left(); int idx = 0; int max = 5; - for(UnlockableContent c : selected.data.resources){ + for(UnlockableContent c : sector.data.resources){ t.image(c.icon(Cicon.small)).padRight(3); if(++idx % max == 0) t.row(); } }).fillX().row(); //production - if(selected.hasBase() && selected.save.meta.hasProduction){ + if(sector.hasBase() && sector.save.meta.hasProduction){ stable.add("Production:").row(); stable.table(t -> { t.left(); - selected.save.meta.exportRates.each(entry -> { + sector.save.meta.secinfo.exportRates().each(entry -> { int total = (int)(entry.value * turnDuration / 60f); if(total > 1){ t.image(entry.key.icon(Cicon.small)).padRight(3); @@ -415,28 +289,71 @@ public class PlanetDialog extends BaseDialog{ t.row(); } }); - }); + }).row(); + } + + //stored resources + if(sector.hasBase() && sector.save.meta.secinfo.coreItems.size > 0){ + stable.add("Stored:").row(); + stable.table(t -> { + t.left(); + + t.table(res -> { + int i = 0; + for(Item item : content.items()){ + int amount = sector.save.meta.secinfo.coreItems.get(item); + if(amount > 0){ + res.image(item.icon(Cicon.small)).padRight(3); + res.add(ui.formatAmount(amount)).color(Color.lightGray); + if(++i % 2 == 0){ + res.row(); + } + } + } + }); + + }).row(); } //display how many turns this sector has been attacked - if(selected.getTurnsPassed() > 0 && selected.hasBase()){ + if(sector.getTurnsPassed() > 0 && sector.hasBase()){ stable.row(); - stable.add("[scarlet]" + Iconc.warning + " " + selected.getTurnsPassed() + "x attacks"); + stable.add("[scarlet]" + Iconc.warning + " " + sector.getTurnsPassed() + "x attacks"); } stable.row(); - stable.button("Launch", Styles.transt, () -> { - if(selected != null){ - if(selected.is(SectorAttribute.naval)){ + if((sector.hasBase() && mode == look) || canLaunch(sector) || sector.preset.alwaysUnlocked){ + stable.button(sector.hasBase() ? "Resume" : "Launch", Styles.transt, () -> { + if(sector.is(SectorAttribute.naval)){ ui.showInfo("You need a naval loadout to launch here."); return; } - control.playSector(selected); + hide(); - } - }).growX().padTop(2f).height(50f).minWidth(170f); + + //save before launch. + if(control.saves.getCurrent() != null && state.isGame()){ + try{ + control.saves.getCurrent().save(); + }catch(Throwable e){ + e.printStackTrace(); + ui.showException("[accent]" + Core.bundle.get("savefail"), e); + } + } + + if(mode == launch){ + launcher.launch(); + zoom = 0.5f; + + ui.hudfrag.showLaunchDirect(); + Time.runTask(launchDuration, () -> control.playSector(sector)); + }else{ + control.playSector(sector); + } + }).growX().padTop(2f).height(50f).minWidth(170f); + } stable.pack(); stable.setPosition(x, y, Align.center); @@ -444,8 +361,8 @@ public class PlanetDialog extends BaseDialog{ stable.update(() -> { if(selected != null){ //fade out UI when not facing selected sector - Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planet.getRotation()).scl(-1f).nor(); - float dot = cam.direction.dot(Tmp.v31); + Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor(); + float dot = planets.cam.direction.dot(Tmp.v31); stable.getColor().a = Math.max(dot, 0f)*2f; if(dot*2f <= -0.1f){ stable.remove(); @@ -457,69 +374,10 @@ public class PlanetDialog extends BaseDialog{ stable.act(0f); } - private void setPlane(Sector sector){ - float rotation = -planet.getRotation(); - float length = 0.01f; - - projector.setPlane( - //origin on sector position - Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(planet.position), - //face up - sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(), - //right vector - Tmp.v31.set(Tmp.v32).rotate(Vec3.Y, -rotation).add(sector.tile.v).rotate(sector.tile.v, 90).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor() - ); - } - - private void draw(Sector sector, Color color, float offset){ - float rr = outlineRad + offset; - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; - batch.tri(Tmp.v31.set(c.v).setLength(rr), Tmp.v32.set(next.v).setLength(rr), Tmp.v33.set(sector.tile.v).setLength(rr), color); - } - } - - private void drawSelection(Sector sector){ - drawSelection(sector, Pal.accent, 0.04f, 0.001f); - } - - private void drawSelection(Sector sector, Color color, float stroke, float length){ - float arad = outlineRad + length; - - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner next = sector.tile.corners[(i + 1) % sector.tile.corners.length]; - Corner curr = sector.tile.corners[i]; - - next.v.scl(arad); - curr.v.scl(arad); - sector.tile.v.scl(arad); - - Tmp.v31.set(curr.v).sub(sector.tile.v).setLength(curr.v.dst(sector.tile.v) - stroke).add(sector.tile.v); - Tmp.v32.set(next.v).sub(sector.tile.v).setLength(next.v.dst(sector.tile.v) - stroke).add(sector.tile.v); - - batch.tri(curr.v, next.v, Tmp.v31, color); - batch.tri(Tmp.v31, next.v, Tmp.v32, color); - - sector.tile.v.scl(1f / arad); - next.v.scl(1f / arad); - curr.v.scl(1f /arad); - } - } - - private Mesh outline(int size){ - if(outlines[size] == null){ - outlines[size] = MeshBuilder.buildHex(new HexMesher(){ - @Override - public float getHeight(Vec3 position){ - return 0; - } - - @Override - public Color getColor(Vec3 position){ - return outlineColor; - } - }, size, true, outlineRad, 0.2f); - } - return outlines[size]; + enum Mode{ + /** Look around for existing sectors. Can only deploy. */ + look, + /** Launch to a new location. */ + launch } } diff --git a/core/src/mindustry/ui/dialogs/SaveDialog.java b/core/src/mindustry/ui/dialogs/SaveDialog.java index b48dd6fe39..9292e2527b 100644 --- a/core/src/mindustry/ui/dialogs/SaveDialog.java +++ b/core/src/mindustry/ui/dialogs/SaveDialog.java @@ -20,16 +20,17 @@ public class SaveDialog extends LoadDialog{ }); } + @Override public void addSetup(){ - slots.row(); - slots.button("$save.new", Icon.add, () -> + + buttons.button("$save.new", Icon.add, () -> ui.showTextInput("$save", "$save.newslot", 30, "", text -> { ui.loadAnd("$saving", () -> { control.saves.addSave(text); Core.app.post(() -> Core.app.post(this::setup)); }); }) - ).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); + ).fillX().margin(10f); } @Override diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index d4f3aa8c9a..3628ff3f14 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -69,19 +69,18 @@ public class SchematicsDialog extends BaseDialog{ }); rebuildPane[0] = () -> { + int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1); + t.clear(); int i = 0; - - if(!schematics.all().contains(s -> search.isEmpty() || s.name().toLowerCase().contains(search.toLowerCase()))){ - t.add("$none"); - } + String regex = "[`~!@#$%^&*()-_=+[{]}|;:'\",<.>/?]"; + String searchString = search.toLowerCase().replaceAll(regex, " "); firstSchematic = null; for(Schematic s : schematics.all()){ - if(!search.isEmpty() && !s.name().toLowerCase().contains(search.toLowerCase())) continue; - if(firstSchematic == null) - firstSchematic = s; + if(!search.isEmpty() && !s.name().toLowerCase().replaceAll(regex, " ").contains(searchString)) continue; + if(firstSchematic == null) firstSchematic = s; Button[] sel = {null}; sel[0] = t.button(b -> { @@ -153,10 +152,14 @@ public class SchematicsDialog extends BaseDialog{ sel[0].getStyle().up = Tex.pane; - if(++i % (mobile ? Core.graphics.isPortrait() ? 2 : 3 : 4) == 0){ + if(++i % maxwidth == 0){ t.row(); } } + + if(firstSchematic == null){ + t.add("$none"); + } }; rebuildPane[0].run(); diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 2a918c4194..cbd6d1cca5 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -103,7 +103,7 @@ public class SettingsMenuDialog extends SettingsDialog{ t.row(); - t.button("$data.export", Icon.download, style, () -> { + t.button("$data.export", Icon.upload, style, () -> { if(ios){ Fi file = Core.files.local("mindustry-data-export.zip"); try{ diff --git a/core/src/mindustry/ui/fragments/BlockConfigFragment.java b/core/src/mindustry/ui/fragments/BlockConfigFragment.java index 4ffa087897..2d1270e036 100644 --- a/core/src/mindustry/ui/fragments/BlockConfigFragment.java +++ b/core/src/mindustry/ui/fragments/BlockConfigFragment.java @@ -43,29 +43,31 @@ public class BlockConfigFragment extends Fragment{ } public void showConfig(Tilec tile){ - configTile = tile; + if(tile.configTapped()){ + configTile = tile; - table.visible(true); - table.clear(); - tile.buildConfiguration(table); - table.pack(); - table.setTransform(true); - table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), - Actions.scaleTo(1f, 1f, 0.07f, Interp.pow3Out)); + table.visible(true); + table.clear(); + tile.buildConfiguration(table); + table.pack(); + table.setTransform(true); + table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), + Actions.scaleTo(1f, 1f, 0.07f, Interp.pow3Out)); - table.update(() -> { - if(configTile != null && configTile.shouldHideConfigure(player)){ - hideConfig(); - return; - } + table.update(() -> { + if(configTile != null && configTile.shouldHideConfigure(player)){ + hideConfig(); + return; + } - table.setOrigin(Align.center); - if(configTile == null || configTile.block() == Blocks.air || !configTile.isValid()){ - hideConfig(); - }else{ - configTile.updateTableAlign(table); - } - }); + table.setOrigin(Align.center); + if(configTile == null || configTile.block() == Blocks.air || !configTile.isValid()){ + hideConfig(); + }else{ + configTile.updateTableAlign(table); + } + }); + } } public boolean hasConfigMouse(){ diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 7cc47d6a71..79c7196693 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -35,6 +35,8 @@ public class HudFragment extends Fragment{ private Table lastUnlockLayout; private boolean shown = true; private float dsize = 47.2f; + //TODO implement + private CoreItemsDisplay coreItems = new CoreItemsDisplay(); private String hudText = ""; private boolean showHudText; @@ -54,6 +56,10 @@ public class HudFragment extends Fragment{ showToast("Sector[accent] captured[]!"); }); + Events.on(ResetEvent.class, e -> { + coreItems.resetUsed(); + }); + //TODO tear this all down //menu at top left parent.fill(cont -> { @@ -183,7 +189,7 @@ public class HudFragment extends Fragment{ t.table(teams -> { teams.left(); int i = 0; - for(Team team : Team.base()){ + for(Team team : Team.baseTeams){ ImageButton button = teams.button(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team)) .size(50f).margin(6f).get(); button.getImageCell().grow(); @@ -326,9 +332,9 @@ public class HudFragment extends Fragment{ c.clearChildren(); for(Item item : content.items()){ - if(state.stats.getExport(item) >= 1){ + if(state.secinfo.getExport(item) >= 1){ c.image(item.icon(Cicon.small)); - c.label(() -> (int)state.stats.getExport(item) + " /s").color(Color.lightGray); + c.label(() -> (int)state.secinfo.getExport(item) + " /s").color(Color.lightGray); c.row(); } } @@ -337,7 +343,7 @@ public class HudFragment extends Fragment{ c.update(() -> { boolean wrong = false; for(Item item : content.items()){ - boolean has = state.stats.getExport(item) >= 1; + boolean has = state.secinfo.getExport(item) >= 1; if(used.get(item.id) != has){ used.set(item.id, has); wrong = true; @@ -503,6 +509,14 @@ public class HudFragment extends Fragment{ } } + public void showLaunchDirect(){ + Image image = new Image(); + image.getColor().a = 0f; + image.setFillParent(true); + image.actions(Actions.fadeIn(launchDuration / 60f, Interp.pow2In), Actions.delay(8f / 60f), Actions.remove()); + Core.scene.add(image); + } + public void showLaunch(){ Image image = new Image(); image.getColor().a = 0f; diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 3d71dcc635..7f5775b2d7 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -227,7 +227,7 @@ public class PlacementFragment extends Fragment{ button.forEach(elem -> elem.setColor(color)); button.setChecked(control.input.block == block); - if(state.rules.bannedBlocks.contains(block)){ + if(!block.isPlaceable()){ button.forEach(elem -> elem.setColor(Color.darkGray)); } }); @@ -324,11 +324,11 @@ public class PlacementFragment extends Fragment{ } }).growX().left().margin(3); - if(state.rules.bannedBlocks.contains(lastDisplay) || !player.isBuilder()){ + if(!lastDisplay.isPlaceable() || !player.isBuilder()){ topTable.row(); topTable.table(b -> { b.image(Icon.cancel).padRight(2).color(Color.scarlet); - b.add(!player.isBuilder() ? "$unit.nobuild" : "$banned").width(190f).wrap(); + b.add(!player.isBuilder() ? "$unit.nobuild" : lastDisplay.unplaceableMessage()).width(190f).wrap(); b.left(); }).padTop(2).left(); } @@ -432,7 +432,7 @@ public class PlacementFragment extends Fragment{ returnArray.sort((b1, b2) -> { int locked = -Boolean.compare(unlocked(b1), unlocked(b2)); if(locked != 0) return locked; - return Boolean.compare(state.rules.bannedBlocks.contains(b1), state.rules.bannedBlocks.contains(b2)); + return Boolean.compare(!b1.isPlaceable(), !b2.isPlaceable()); }); return returnArray; } diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index c16edad296..e706110633 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -45,6 +45,7 @@ public class Block extends UnlockableContent{ public boolean consumesPower = true; public boolean outputsPower = false; public boolean outputsPayload = false; + public boolean outputFacing = true; public boolean acceptsItems = false; public int itemCapacity = 10; @@ -83,6 +84,10 @@ public class Block extends UnlockableContent{ public boolean placeableOn = true; /** whether this block has insulating properties. */ public boolean insulated = false; + /** whether the sprite is a full square. */ + public boolean squareSprite = true; + /** whether this block absorbs laser attacks. */ + public boolean absorbLasers = false; /** tile entity health */ public int health = -1; /** base block explosiveness */ @@ -160,6 +165,8 @@ public class Block extends UnlockableContent{ public float buildCost; /** Whether this block is visible and can currently be built. */ public BuildVisibility buildVisibility = BuildVisibility.hidden; + /** Defines when this block can be placed. */ + public BuildPlaceability buildPlaceability = BuildPlaceability.always; /** Multiplier for speed of building this block. */ public float buildCostMultiplier = 1f; /** Whether this block has instant transfer.*/ @@ -190,7 +197,6 @@ public class Block extends UnlockableContent{ public Block(String name){ super(name); - this.solid = false; initEntity(); } @@ -296,7 +302,7 @@ public class Block extends UnlockableContent{ public void setStats(){ stats.add(BlockStat.size, "@x@", size, size); stats.add(BlockStat.health, health, StatUnit.none); - if(isBuildable()){ + if(canBeBuilt()){ stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds); stats.add(BlockStat.buildCost, new ItemListValue(false, requirements)); } @@ -401,6 +407,23 @@ public class Block extends UnlockableContent{ return (hasItems && itemCapacity > 0); } + /** Iterate through ever grid position taken up by this block. */ + public void iterateTaken(int x, int y, Intc2 placer){ + if(isMultiblock()){ + int offsetx = -(size - 1) / 2; + int offsety = -(size - 1) / 2; + + for(int dx = 0; dx < size; dx++){ + for(int dy = 0; dy < size; dy++){ + placer.get(dx + offsetx + x, dy + offsety + y); + } + } + + }else{ + placer.get(x, y); + } + } + /** Never use outside of the editor! */ public TextureRegion editorIcon(){ if(editorIcon == null) editorIcon = Core.atlas.find(name + "-icon-editor"); @@ -463,6 +486,15 @@ public class Block extends UnlockableContent{ return buildVisibility.visible() && !isHidden(); } + public boolean isPlaceable(){ + return isVisible() && buildPlaceability.placeable() && !state.rules.bannedBlocks.contains(this); + } + + /** @return a message detailing why this block can't be placed. */ + public String unplaceableMessage(){ + return state.rules.bannedBlocks.contains(this) ? Core.bundle.get("banned") : buildPlaceability.message(); + } + public boolean isFloor(){ return this instanceof Floor; } @@ -479,7 +511,7 @@ public class Block extends UnlockableContent{ return id == 0; } - public boolean isBuildable(){ + public boolean canBeBuilt(){ return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly; } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index b66273f9fd..30dc86f5ea 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -42,8 +42,8 @@ public class Build{ /** Places a BuildBlock at this location. */ @Remote(called = Loc.server) - public static void beginPlace(Team team, int x, int y, Block result, int rotation){ - if(!validPlace(team, x, y, result, rotation)){ + public static void beginPlace(Block result, Team team, int x, int y, int rotation){ + if(!validPlace(result, team, x, y, rotation)){ return; } @@ -62,12 +62,9 @@ public class Build{ } /** Returns whether a tile can be placed at this location by this team. */ - public static boolean validPlace(Team team, int x, int y, Block type, int rotation){ - if(type == null || !type.isVisible() || type.isHidden()){ - return false; - } - - if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == state.rules.waveTeam)){ + public static boolean validPlace(Block type, Team team, int x, int y, int rotation){ + //the wave team can build whatever they want as long as it's visible - banned blocks are not applicable + if(type == null || (!type.isPlaceable() && !(state.rules.waves && team == state.rules.waveTeam && type.isVisible()))){ return false; } @@ -94,7 +91,7 @@ public class Build{ } //TODO should water blocks be placeable here? - if(/*!type.requiresWater && */!contactsGround(tile.x, tile.y, type)){ + if(/*!type.requiresWater && */!contactsShallows(tile.x, tile.y, type)){ return false; } @@ -121,7 +118,7 @@ public class Build{ return true; }else{ return tile.interactable(team) - && contactsGround(tile.x, tile.y, type) + && contactsShallows(tile.x, tile.y, type) && (!tile.floor().isDeep() || type.floating || type.requiresWater) && tile.floor().placeableOn && (!type.requiresWater || tile.floor().liquidDrop == Liquids.water) @@ -131,7 +128,22 @@ public class Build{ } } - private static boolean contactsGround(int x, int y, Block block){ + public static boolean contactsGround(int x, int y, Block block){ + if(block.isMultiblock()){ + for(Point2 point : Edges.getEdges(block.size)){ + Tile tile = world.tile(x + point.x, y + point.y); + if(tile != null && !tile.floor().isLiquid) return true; + } + }else{ + for(Point2 point : Geometry.d4){ + Tile tile = world.tile(x + point.x, y + point.y); + if(tile != null && !tile.floor().isLiquid) return true; + } + } + return false; + } + + public static boolean contactsShallows(int x, int y, Block block){ if(block.isMultiblock()){ for(Point2 point : Edges.getInsideEdges(block.size)){ Tile tile = world.tile(x + point.x, y + point.y); diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 6afddc9ae3..545378c23a 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -246,6 +246,15 @@ public class Tile implements Position, QuadTreeObject{ setOverlay(overlay); } + /** Sets the block to air. */ + public void setAir(){ + setBlock(Blocks.air); + } + + public void circle(int radius, Intc2 cons){ + Geometry.circle(x, y, world.width(), world.height(), radius, cons); + } + public void recache(){ if(!headless && !world.isGenerating()){ renderer.blocks.floor.recacheTile(this); @@ -364,7 +373,7 @@ public class Tile implements Position, QuadTreeObject{ } /** - * Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock. + * Returns the list of all tiles linked to this multiblock. * This array contains all linked tiles, including this tile itself. */ public Array getLinkedTiles(Array tmpArray){ @@ -374,7 +383,7 @@ public class Tile implements Position, QuadTreeObject{ } /** - * Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock. + * Returns the list of all tiles linked to this multiblock if it were this block. * This array contains all linked tiles, including this tile itself. */ public Array getLinkedTilesAs(Block block, Array tmpArray){ diff --git a/core/src/mindustry/world/Tiles.java b/core/src/mindustry/world/Tiles.java index a92ac1c1b1..74c784a850 100644 --- a/core/src/mindustry/world/Tiles.java +++ b/core/src/mindustry/world/Tiles.java @@ -1,6 +1,7 @@ package mindustry.world; import arc.func.*; +import arc.math.*; import arc.math.geom.*; import arc.util.ArcAnnotate.*; @@ -54,6 +55,13 @@ public class Tiles implements Iterable{ return array[y*width + x]; } + /** @return a tile at coordinates, clamped. */ + public @NonNull Tile getc(int x, int y){ + x = Mathf.clamp(x, 0, width - 1); + y = Mathf.clamp(y, 0, height - 1); + return array[y*width + x]; + } + /** @return a tile at an iteration index [0, width * height] */ public @NonNull Tile geti(int idx){ return array[idx]; diff --git a/core/src/mindustry/world/blocks/Autotiler.java b/core/src/mindustry/world/blocks/Autotiler.java index ae22eff0ba..bfa4c309e0 100644 --- a/core/src/mindustry/world/blocks/Autotiler.java +++ b/core/src/mindustry/world/blocks/Autotiler.java @@ -1,5 +1,6 @@ package mindustry.world.blocks; +import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.ArcAnnotate.*; @@ -10,12 +11,39 @@ import mindustry.world.*; import java.util.*; +//TODO documentation public interface Autotiler{ + + //holds some static temporary variables, required due to some RoboVM bugs class AutotilerHolder{ - static final int[] blendresult = new int[4]; + static final int[] blendresult = new int[5]; static final BuildRequest[] directionals = new BuildRequest[4]; } + /** slices a texture region: + * mode == 0 -> no slice + * mode == 1 -> bottom + * mode == 2 -> top */ + default TextureRegion sliced(TextureRegion input, int mode){ + return mode == 0 ? input : mode == 1 ? botHalf(input) : topHalf(input); + } + + default TextureRegion topHalf(TextureRegion input){ + TextureRegion region = Tmp.tr1; + region.set(input); + region.setWidth(region.getWidth() / 2); + return region; + } + + default TextureRegion botHalf(TextureRegion input){ + TextureRegion region = Tmp.tr1; + region.set(input); + int width = region.getWidth(); + region.setWidth(width / 2); + region.setX(region.getX() + width); + return region; + } + default @Nullable int[] getTiling(BuildRequest req, Eachable list){ if(req.tile() == null) return null; BuildRequest[] directionals = AutotilerHolder.directionals; @@ -37,6 +65,19 @@ public interface Autotiler{ return buildBlending(req.tile(), req.rotation, directionals, req.worldContext); } + /** + * @return an array of blending values: + * [0]: the type of connection: + * - 0: straight + * - 1: curve (top) + * - 2: straight (bottom) + * - 3: all sides + * - 4: straight (top) + * [1]: X scale + * [2]: Y scale + * [3]: a 4-bit mask with bits 0-3 indicating blend state in that direction (0 being 0 degrees, 1 being 90, etc) + * [4]: same as [3] but only blends with non-square sprites + * */ default int[] buildBlending(Tile tile, int rotation, BuildRequest[] directional, boolean world){ int[] blendresult = AutotilerHolder.blendresult; blendresult[0] = 0; @@ -59,6 +100,15 @@ public interface Autotiler{ } } + blendresult[4] = 0; + + 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)){ + blendresult[4] |= (1 << i); + } + } + return blendresult; } diff --git a/core/src/mindustry/world/blocks/campaign/CoreLauncher.java b/core/src/mindustry/world/blocks/campaign/CoreLauncher.java new file mode 100644 index 0000000000..e61624d757 --- /dev/null +++ b/core/src/mindustry/world/blocks/campaign/CoreLauncher.java @@ -0,0 +1,127 @@ +package mindustry.world.blocks.campaign; + +import arc.Graphics.*; +import arc.Graphics.Cursor.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class CoreLauncher extends Block{ + public int range = 1; + + public CoreLauncher(String name){ + super(name); + + hasItems = true; + configurable = true; + update = true; + //will be enabled when needed (if at all) + //buildPlaceability = BuildPlaceability.sectorCaptured; + } + + public class CoreLauncherEntity extends TileEntity{ + + @Override + public void updateTile(){ + super.updateTile(); + } + + @Override + public boolean configTapped(){ + + if(state.isCampaign() && consValid()){ + Vars.ui.planet.show(state.rules.sector, range, this); + } + return false; + } + + @Override + public Cursor getCursor(){ + return consValid() ? SystemCursor.hand : SystemCursor.arrow; + } + + public void launch(){ + LaunchCorec ent = LaunchCoreEntity.create(); + ent.set(this); + ent.block(Blocks.coreShard); + ent.lifetime(Vars.launchDuration); + ent.add(); + + cons.trigger(); + } + } + + @EntityDef(value = LaunchCorec.class, serialize = false) + @Component + static abstract class LaunchCoreComp implements Drawc, Timedc{ + @Import float x, y; + + transient Interval in = new Interval(); + Block block; + + @Override + public void draw(){ + float alpha = fout(Interp.pow5Out); + float scale = (1f - alpha) * 1.4f + 1f; + float cx = cx(), cy = cy(); + float rotation = fin() * (140f + Mathf.randomSeedRange(id(), 50f)); + + Draw.z(Layer.effect + 0.001f); + + Draw.color(Pal.engine); + + float rad = 0.2f + fslope(); + float rscl = (block.size - 1) * 0.85f; + + Fill.light(cx, cy, 10, 25f * (rad + scale-1f) * rscl, Tmp.c2.set(Pal.engine).a(alpha), Tmp.c1.set(Pal.engine).a(0f)); + + Draw.alpha(alpha); + for(int i = 0; i < 4; i++){ + Drawf.tri(cx, cy, 6f * rscl, 40f * (rad + scale-1f) * rscl, i * 90f + rotation); + } + + Draw.color(); + + Draw.z(Layer.weather - 1); + + TextureRegion region = block.icon(Cicon.full); + float rw = region.getWidth() * Draw.scl * scale, rh = region.getHeight() * Draw.scl * scale; + + Draw.alpha(alpha); + Draw.rect(region, cx, cy, rw, rh, rotation - 45); + + Tmp.v1.trns(225f, fin(Interp.pow3In) * 250f); + + Draw.z(Layer.flyingUnit + 1); + Draw.color(0, 0, 0, 0.22f * alpha); + Draw.rect(region, cx + Tmp.v1.x, cy + Tmp.v1.y, rw, rh, rotation - 45); + + Draw.reset(); + } + + float cx(){ + return x + fin(Interp.pow2In) * (12f + Mathf.randomSeedRange(id() + 3, 4f)); + } + + float cy(){ + return y + fin(Interp.pow5In) * (100f + Mathf.randomSeedRange(id() + 2, 30f)); + } + + @Override + public void update(){ + float r = 4f; + if(in.get(3f - fin()*2f)){ + Fx.rocketSmokeLarge.at(cx() + Mathf.range(r), cy() + Mathf.range(r), fin()); + } + } + } +} diff --git a/core/src/mindustry/world/blocks/storage/LaunchPad.java b/core/src/mindustry/world/blocks/campaign/LaunchPad.java similarity index 99% rename from core/src/mindustry/world/blocks/storage/LaunchPad.java rename to core/src/mindustry/world/blocks/campaign/LaunchPad.java index 592e9b2b47..7dbded1b5c 100644 --- a/core/src/mindustry/world/blocks/storage/LaunchPad.java +++ b/core/src/mindustry/world/blocks/campaign/LaunchPad.java @@ -1,4 +1,4 @@ -package mindustry.world.blocks.storage; +package mindustry.world.blocks.campaign; import arc.*; import arc.graphics.*; diff --git a/core/src/mindustry/world/blocks/production/ResearchBlock.java b/core/src/mindustry/world/blocks/campaign/ResearchBlock.java similarity index 80% rename from core/src/mindustry/world/blocks/production/ResearchBlock.java rename to core/src/mindustry/world/blocks/campaign/ResearchBlock.java index 1d674dfe0a..8f66048fc9 100644 --- a/core/src/mindustry/world/blocks/production/ResearchBlock.java +++ b/core/src/mindustry/world/blocks/campaign/ResearchBlock.java @@ -1,4 +1,4 @@ -package mindustry.world.blocks.production; +package mindustry.world.blocks.campaign; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; @@ -9,6 +9,7 @@ import mindustry.gen.*; import mindustry.world.*; public class ResearchBlock extends Block{ + public float researchSpeed = 1f; public ResearchBlock(String name){ super(name); @@ -20,6 +21,11 @@ public class ResearchBlock extends Block{ configurable = true; } + @Override + public boolean outputsItems(){ + return false; + } + public class ResearchBlockEntity extends TileEntity{ public @Nullable UnlockableContent researching; @@ -33,6 +39,14 @@ public class ResearchBlock extends Block{ } + @Override + public boolean configTapped(){ + //TODO select target + Vars.ui.tech.show(); + + return false; + } + @Override public void write(Writes write){ super.write(write); diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 52223215bb..003d68e781 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -88,7 +88,7 @@ public class ForceProjector extends Block{ @Override public void updateTile(){ - boolean phaseValid = consumes.get(ConsumeType.item).valid(tile.entity); + boolean phaseValid = consumes.get(ConsumeType.item).valid(this); phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(phaseValid), 0.1f); diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index f9fcd08e21..a6f174eaf3 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -23,6 +23,7 @@ public class OverdriveProjector extends Block{ public float speedBoostPhase = 0.75f; public float useTime = 400f; public float phaseRangeBoost = 20f; + public boolean hasBoost = true; public Color baseColor = Color.valueOf("feb380"); public Color phaseColor = Color.valueOf("ffd59e"); @@ -51,9 +52,12 @@ public class OverdriveProjector extends Block{ 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(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); - stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent); + if(hasBoost){ + stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); + stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent); + } } public class OverdriveEntity extends TileEntity{ @@ -71,7 +75,9 @@ public class OverdriveProjector extends Block{ heat = Mathf.lerpDelta(heat, consValid() ? 1f : 0f, 0.08f); charge += heat * Time.delta(); - phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons().optionalValid()), 0.1f); + if(hasBoost){ + phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons().optionalValid()), 0.1f); + } if(timer(timerUse, useTime) && efficiency() > 0){ consume(); @@ -105,8 +111,8 @@ public class OverdriveProjector extends Block{ 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); + Lines.stroke((2f * f + 0.1f) * heat); + 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/PointDefenseTurret.java b/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java new file mode 100644 index 0000000000..9998973ab6 --- /dev/null +++ b/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java @@ -0,0 +1,118 @@ +package mindustry.world.blocks.defense; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.math.geom.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import arc.util.io.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.*; + +import static mindustry.Vars.tilesize; + +public class PointDefenseTurret extends Block{ + public final int timerTarget = timers++; + public float retargetTime = 5f; + + public @Load("block-$size") TextureRegion baseRegion; + + public Color color = Color.white; + public Effect beamEffect = Fx.pointBeam; + 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; + + public PointDefenseTurret(String name){ + super(name); + + outlineIcon = true; + update = true; + } + + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + Drawf.dashCircle(x * tilesize + offset(), y * tilesize + offset(), range, Pal.accent); + } + + @Override + public TextureRegion[] generateIcons(){ + return new TextureRegion[]{Core.atlas.find("block-" + size), Core.atlas.find(name)}; + } + + public class PointDefenseEntity extends TileEntity{ + public float rotation = 90, reload; + public @Nullable Bulletc target; + + @Override + public void updateTile(){ + + //retarget + if(timer(timerTarget, retargetTime)){ + target = Groups.bullet.intersect(x - range, y - range, range*2, range*2).min(b -> b.team() == team || !b.type().hittable ? Float.MAX_VALUE : b.dst2(this)); + } + + //look at target + if(target != null && target.within(this, range) && target.team() != team && target.type().hittable){ + float dest = angleTo(target); + rotation = Angles.moveToward(rotation,dest, rotateSpeed * edelta()); + reload -= edelta(); + + //shoot when possible + if(Angles.within(rotation, dest, shootCone) && reload <= 0f){ + if(target.damage() > bulletDamage){ + target.damage(target.damage() - bulletDamage); + }else{ + target.remove(); + } + + Tmp.v1.trns(rotation, shootLength); + + 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; + } + }else{ + target = null; + } + } + + @Override + public void drawSelect(){ + Drawf.dashCircle(x, y, range, Pal.accent); + } + + @Override + public void draw(){ + Draw.rect(baseRegion, x, y); + Draw.rect(region, x, y, rotation - 90); + } + + @Override + public void write(Writes write){ + super.write(write); + + write.f(rotation); + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); + + rotation = read.f(); + } + } +} diff --git a/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java deleted file mode 100644 index 71044999ce..0000000000 --- a/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java +++ /dev/null @@ -1,41 +0,0 @@ -package mindustry.world.blocks.defense.turrets; - -import arc.math.*; -import mindustry.entities.bullet.*; - -import static mindustry.Vars.tilesize; - -/** - * Artillery turrets have special shooting calculations done to hit targets. - */ -public class ArtilleryTurret extends ItemTurret{ - public float velocityInaccuracy = 0f; - - public ArtilleryTurret(String name){ - super(name); - targetAir = false; - } - - public class ArtilleryTurretEntity extends ItemTurretEntity{ - @Override - protected void shoot(BulletType ammo){ - recoil = recoilAmount; - heat = 1f; - - BulletType type = peekAmmo(); - - tr.trns(rotation, size * tilesize / 2); - - float dst = dst(targetPos.x, targetPos.y); - float maxTraveled = type.lifetime * type.speed; - - for(int i = 0; i < shots; i++){ - ammo.create(tile.entity, team, x + tr.x, y + tr.y, - rotation + Mathf.range(inaccuracy + type.inaccuracy), 1f + Mathf.range(velocityInaccuracy), (dst / maxTraveled)); - } - - effects(); - useAmmo(); - } - } -} diff --git a/core/src/mindustry/world/blocks/defense/turrets/BurstTurret.java b/core/src/mindustry/world/blocks/defense/turrets/BurstTurret.java deleted file mode 100644 index ab2ade3693..0000000000 --- a/core/src/mindustry/world/blocks/defense/turrets/BurstTurret.java +++ /dev/null @@ -1,36 +0,0 @@ -package mindustry.world.blocks.defense.turrets; - -import arc.math.*; -import arc.util.*; -import mindustry.entities.bullet.*; - -import static mindustry.Vars.tilesize; - -public class BurstTurret extends ItemTurret{ - public float burstSpacing = 5; - - public BurstTurret(String name){ - super(name); - } - - public class BurstTurretEntity extends ItemTurretEntity{ - - @Override - protected void shoot(BulletType ammo){ - heat = 1f; - - for(int i = 0; i < shots; i++){ - Time.run(burstSpacing * i, () -> { - if(!(tile.entity instanceof TurretEntity) || !hasAmmo()) return; - - recoil = recoilAmount; - - tr.trns(rotation, size * tilesize / 2, Mathf.range(xRand)); - bullet(ammo, rotation + Mathf.range(inaccuracy)); - effects(); - useAmmo(); - }); - } - } - } -} diff --git a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java index b84a278849..031bca9ebf 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java @@ -9,7 +9,6 @@ import mindustry.entities.bullet.*; import static mindustry.Vars.tilesize; public class ChargeTurret extends PowerTurret{ - public float chargeTime = 30f; public int chargeEffects = 5; public float chargeMaxDelay = 10f; @@ -27,13 +26,13 @@ public class ChargeTurret extends PowerTurret{ public void shoot(BulletType ammo){ useAmmo(); - tr.trns(rotation, size * tilesize / 2); + tr.trns(rotation, size * tilesize / 2f); chargeBeginEffect.at(x + tr.x, y + tr.y, rotation); for(int i = 0; i < chargeEffects; i++){ Time.run(Mathf.random(chargeMaxDelay), () -> { if(!isValid()) return; - tr.trns(rotation, size * tilesize / 2); + tr.trns(rotation, size * tilesize / 2f); chargeEffect.at(x + tr.x, y + tr.y, rotation); }); } @@ -42,7 +41,7 @@ public class ChargeTurret extends PowerTurret{ Time.run(chargeTime, () -> { if(!isValid()) return; - tr.trns(rotation, size * tilesize / 2); + tr.trns(rotation, size * tilesize / 2f); recoil = recoilAmount; heat = 1f; bullet(ammo, rotation + Mathf.range(inaccuracy)); diff --git a/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java b/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java deleted file mode 100644 index 417c6083df..0000000000 --- a/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java +++ /dev/null @@ -1,66 +0,0 @@ -package mindustry.world.blocks.defense.turrets; - -import arc.*; -import arc.math.*; -import arc.util.*; -import mindustry.content.*; -import mindustry.entities.*; -import mindustry.game.EventType.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.consumers.*; -import mindustry.world.meta.*; -import mindustry.world.meta.values.*; - -import static mindustry.Vars.tilesize; - -public class CooledTurret extends Turret{ - /** How much reload is lowered by for each unit of liquid of heat capacity. */ - public float coolantMultiplier = 5f; - public Effect coolEffect = Fx.fuelburn; - - public CooledTurret(String name){ - super(name); - hasLiquids = true; - liquidCapacity = 20f; - - consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.2f)).update(false).boost(); - } - - @Override - public void setStats(){ - super.setStats(); - - stats.add(BlockStat.booster, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id))); - } - - public class CooledTurretEntity extends TurretEntity{ - - @Override - public void handleLiquid(Tilec source, Liquid liquid, float amount){ - if(liquids.currentAmount() <= 0.001f){ - Events.fire(Trigger.turretCool); - } - - super.handleLiquid(source, liquid, amount); - } - - @Override - protected void updateShooting(){ - super.updateShooting(); - - 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)); - } - } - } - -} diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index 5458e02873..4cb155fc99 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -18,7 +18,7 @@ import mindustry.world.meta.values.*; import static mindustry.Vars.*; -public class ItemTurret extends CooledTurret{ +public class ItemTurret extends Turret{ public int maxAmmo = 30; public ObjectMap ammoTypes = new ObjectMap<>(); diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java index 3abe53bcf3..9cb5992bdb 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -44,6 +44,11 @@ public class LaserTurret extends PowerTurret{ Bulletc bullet; float bulletLife; + @Override + protected void updateCooling(){ + //do nothing, cooling is irrelevant here + } + @Override public void updateTile(){ super.updateTile(); diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 48974dcfa5..12b7b08139 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -20,6 +20,7 @@ public class LiquidTurret extends Turret{ public LiquidTurret(String name){ super(name); + acceptCoolant = false; hasLiquids = true; activeSound = Sounds.spray; } diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java index 8fa5368838..7abbfe9924 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -4,7 +4,7 @@ import arc.util.ArcAnnotate.*; import mindustry.entities.bullet.*; import mindustry.world.meta.*; -public class PowerTurret extends CooledTurret{ +public class PowerTurret extends Turret{ public @NonNull BulletType shootType; public float powerUse = 1f; @@ -26,7 +26,7 @@ public class PowerTurret extends CooledTurret{ super.init(); } - public class PowerTurretEntity extends CooledTurretEntity{ + public class PowerTurretEntity extends TurretEntity{ @Override public BulletType useAmmo(){ diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 755a9b74c9..e7ac459f39 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -8,18 +8,22 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; -import arc.util.*; import arc.util.ArcAnnotate.*; +import arc.util.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.bullet.*; +import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; +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.tilesize; @@ -38,6 +42,7 @@ public abstract class Turret extends Block{ public float range = 50f; public float reloadTime = 10f; public float inaccuracy = 0f; + public float velocityInaccuracy = 0f; public int shots = 1; public float spread = 4f; public float recoilAmount = 1f; @@ -47,9 +52,17 @@ public abstract class Turret extends Block{ public float shootCone = 8f; public float shootShake = 0f; public float xRand = 0f; + /** Currently used for artillery only. */ + public float minRange = 0f; + public float burstSpacing = 0; 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; protected Vec2 tr = new Vec2(); protected Vec2 tr2 = new Vec2(); @@ -75,6 +88,7 @@ public abstract class Turret extends Block{ group = BlockGroup.turrets; flags = EnumSet.of(BlockFlag.turret); outlineIcon = true; + liquidCapacity = 20f; } @Override @@ -92,6 +106,20 @@ public abstract class Turret extends Block{ stats.add(BlockStat.shots, 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))); + } + } + + @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 @@ -119,6 +147,7 @@ public abstract class Turret extends Block{ public Vec2 targetPos = new Vec2(); public @NonNull BlockUnitc unit = Nulls.blockUnit; + @Override public void created(){ unit = (BlockUnitc)UnitTypes.block.create(team); unit.tile(this); @@ -196,14 +225,40 @@ public abstract class Turret extends Block{ } } } - } + if(acceptCoolant){ + updateCooling(); + } + } @Override public void drawSelect(){ Drawf.dashCircle(x, y, range, team.color); } + @Override + public void handleLiquid(Tilec source, Liquid liquid, float amount){ + if(acceptCoolant && liquids.currentAmount() <= 0.001f){ + Events.fire(Trigger.turretCool); + } + + 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(); } @@ -232,20 +287,16 @@ public abstract class Turret extends Block{ entry.amount -= ammoPerShot; if(entry.amount == 0) ammo.pop(); totalAmmo -= ammoPerShot; - Time.run(reloadTime / 2f, () -> ejectEffects()); + Time.run(reloadTime / 2f, this::ejectEffects); return entry.type(); } - /** - * Get the ammo type that will be returned if useAmmo is called. - */ + /** @return the ammo type that will be returned if useAmmo is called. */ public BulletType peekAmmo(){ return ammo.peek().type(); } - /** - * Returns whether the turret has ammo. - */ + /** @return whether the turret has ammo. */ public boolean hasAmmo(){ return ammo.size > 0 && ammo.peek().amount >= ammoPerShot; } @@ -266,27 +317,48 @@ public abstract class Turret extends Block{ recoil = recoilAmount; heat = 1f; - if(alternate){ - float i = (shotCounter % shots) - shots/2f + (((shots+1)%2) / 2f); - - tr.trns(rotation - 90, spread * i + Mathf.range(xRand), size * tilesize / 2); - bullet(type, rotation + Mathf.range(inaccuracy)); - }else{ - tr.trns(rotation, size * tilesize / 2f, Mathf.range(xRand)); - + //when burst spacing is enabled, use the burst pattern + if(burstSpacing > 0.0001f){ for(int i = 0; i < shots; i++){ - bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy) + (i - shots / 2f) * spread); + Time.run(burstSpacing * i, () -> { + if(!isValid() || !hasAmmo()) return; + + recoil = recoilAmount; + + tr.trns(rotation, size * tilesize / 2f, Mathf.range(xRand)); + bullet(type, rotation + Mathf.range(inaccuracy)); + effects(); + useAmmo(); + }); } + + }else{ + //otherwise, use the normal shot pattern(s) + + if(alternate){ + float i = (shotCounter % shots) - shots/2f + (((shots+1)%2) / 2f); + + tr.trns(rotation - 90, spread * i + Mathf.range(xRand), size * tilesize / 2f); + bullet(type, rotation + Mathf.range(inaccuracy)); + }else{ + tr.trns(rotation, size * tilesize / 2f, Mathf.range(xRand)); + + for(int i = 0; i < shots; i++){ + bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy) + (i - (int)(shots / 2f)) * spread); + } + } + + shotCounter++; + + effects(); + useAmmo(); } - - shotCounter++; - - effects(); - useAmmo(); } protected void bullet(BulletType type, float angle){ - type.create(this, team, x + tr.x, y + tr.y, angle); + float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, targetPos.x, targetPos.y) / type.range(), minRange / type.range(), range / type.range()) : 1f; + + type.create(this, team, x + tr.x, y + tr.y, angle, 1f + Mathf.range(velocityInaccuracy), lifeScl); } protected void effects(){ diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index ed78f4ba75..a2dae61ea5 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -107,7 +107,7 @@ public class Conveyor extends Block implements Autotiler{ int lastInserted, mid; float minitem = 1; - int blendbits; + int blendbits, blending; int blendsclx, blendscly; float clogHeat = 0f; @@ -116,10 +116,22 @@ public class Conveyor extends Block implements Autotiler{ public void draw(){ byte rotation = tile.rotation(); int frame = clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * timeScale())) % 4) : 0; - Draw.rect(regions[Mathf.clamp(blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], x, y, - tilesize * blendsclx, tilesize * blendscly, rotation * 90); - //TODO is clustering necessary? does it create garbage? + //draw extra conveyors facing this one for non-square tiling purposes + Draw.z(Layer.blockUnder); + for(int i = 0; i < 4; i++){ + if((blending & (1 << i)) != 0){ + int dir = rotation - i; + float rot = i == 0 ? rotation * 90 : (dir)*90; + + Draw.rect(sliced(regions[0][frame], i != 0 ? 1 : 2), x + Geometry.d4x(dir) * tilesize*0.75f, y + Geometry.d4y(dir) * tilesize*0.75f, rot); + } + } + + Draw.z(Layer.block); + + Draw.rect(regions[blendbits][frame], x, y, tilesize * blendsclx, tilesize * blendscly, rotation * 90); + Draw.z(Layer.blockOver); for(int i = 0; i < len; i++){ @@ -128,8 +140,9 @@ public class Conveyor extends Block implements Autotiler{ tr2.trns(rotation * 90, -tilesize / 2f, xs[i] * tilesize / 2f); Draw.rect(item.icon(Cicon.medium), - (tile.x * tilesize + tr1.x * ys[i] + tr2.x), - (tile.y * tilesize + tr1.y * ys[i] + tr2.y), itemSize, itemSize); + (tile.x * tilesize + tr1.x * ys[i] + tr2.x), + (tile.y * tilesize + tr1.y * ys[i] + tr2.y), + itemSize, itemSize); } } @@ -146,6 +159,7 @@ public class Conveyor extends Block implements Autotiler{ blendbits = bits[0]; blendsclx = bits[1]; blendscly = bits[2]; + blending = bits[4]; if(tile.front() != null && tile.front() != null){ next = tile.front(); diff --git a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java index 919b4fc482..a090f0e286 100644 --- a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java @@ -55,6 +55,13 @@ public class PayloadConveyor extends Block{ public boolean blocked; public int step = -1, stepAccepted = -1; + @Override + public Payload takePayload(){ + Payload t = item; + item = null; + return t; + } + @Override public void onProximityUpdate(){ super.onProximityUpdate(); @@ -95,17 +102,27 @@ public class PayloadConveyor extends Block{ //move forward. next.handlePayload(this, item); item = null; + moved(); } }else if(!blocked){ //dump item forward if(item.dump()){ item = null; + moved(); } } } } } + public void moved(){ + + } + + public void drawBottom(){ + super.draw(); + } + @Override public void draw(){ super.draw(); @@ -156,7 +173,8 @@ public class PayloadConveyor extends Block{ @Override public boolean acceptPayload(Tilec source, Payload payload){ - return this.item == null && progress <= 5f; + //accepting payloads from units isn't supported + return this.item == null && progress <= 5f && source != this && payload.fits(); } @Override diff --git a/core/src/mindustry/world/blocks/distribution/PayloadRouter.java b/core/src/mindustry/world/blocks/distribution/PayloadRouter.java new file mode 100644 index 0000000000..e0a721024e --- /dev/null +++ b/core/src/mindustry/world/blocks/distribution/PayloadRouter.java @@ -0,0 +1,71 @@ +package mindustry.world.blocks.distribution; + +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.units.*; +import mindustry.graphics.*; + +public class PayloadRouter extends PayloadConveyor{ + public @Load("@-over") TextureRegion overRegion; + + public PayloadRouter(String name){ + super(name); + + outputsPayload = true; + outputFacing = false; + } + + @Override + public void drawRequestRegion(BuildRequest req, Eachable list){ + super.drawRequestRegion(req, list); + + Draw.rect(overRegion, req.drawx(), req.drawy()); + } + + public class PayloadRouterEntity extends PayloadConveyorEntity{ + public float smoothRot; + + @Override + public void add(){ + super.add(); + smoothRot = rotdeg(); + } + + @Override + public void moved(){ + int rotations = 0; + do{ + tile.rotation((tile.rotation() + 1) % 4); + onProximityUpdate(); + }while((blocked || next == null) && ++rotations < 4); + } + + @Override + public void updateTile(){ + super.updateTile(); + + smoothRot = Mathf.slerpDelta(smoothRot, rotdeg(), 0.2f); + } + + @Override + public void draw(){ + Draw.rect(region, x, y); + + float dst = 0.8f; + + Draw.mixcol(Pal.accent, Math.max((dst - (Math.abs(fract() - 0.5f) * 2)) / dst, 0)); + Draw.rect(topRegion, x, y, smoothRot); + Draw.reset(); + + Draw.rect(overRegion, x, y); + + Draw.z(Layer.blockOver); + + if(item != null){ + item.draw(); + } + } + } +} diff --git a/core/src/mindustry/world/blocks/experimental/BlockForge.java b/core/src/mindustry/world/blocks/experimental/BlockForge.java index 8f05136ceb..22e415e609 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockForge.java +++ b/core/src/mindustry/world/blocks/experimental/BlockForge.java @@ -124,26 +124,7 @@ public class BlockForge extends PayloadAcceptor{ Draw.rect(outRegion, x, y, rotdeg()); if(recipe != null){ - Draw.draw(Layer.blockOver, () -> { - TextureRegion region = recipe.icon(Cicon.full); - - Shaders.build.region = region; - Shaders.build.progress = progress / recipe.buildCost; - Shaders.build.color.set(Pal.accent); - Shaders.build.color.a = heat; - Shaders.build.time = -time / 20f; - - Draw.shader(Shaders.build); - Draw.rect(region, x, y); - Draw.shader(); - - Draw.color(Pal.accent); - Draw.alpha(heat); - - Lines.lineAngleCenter(x + Mathf.sin(time, 20f, Vars.tilesize / 2f * size - 2f), y, 90, size * Vars.tilesize - 4f); - - Draw.reset(); - }); + Draw.draw(Layer.blockOver, () -> Drawf.construct(this, recipe, 0, progress / recipe.buildCost, heat, time)); } drawPayload(); diff --git a/core/src/mindustry/world/blocks/experimental/BlockLauncher.java b/core/src/mindustry/world/blocks/experimental/BlockLauncher.java deleted file mode 100644 index 828ff417a6..0000000000 --- a/core/src/mindustry/world/blocks/experimental/BlockLauncher.java +++ /dev/null @@ -1,89 +0,0 @@ -package mindustry.world.blocks.experimental; - -import arc.math.geom.*; -import arc.struct.*; -import arc.util.*; -import mindustry.content.*; -import mindustry.entities.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.world.*; -import mindustry.world.blocks.payloads.*; -import mindustry.world.blocks.production.*; - -import static mindustry.Vars.*; - -//pointless, will definitely be removed eventually -public class BlockLauncher extends PayloadAcceptor{ - static final IntArray positions = new IntArray(); - - public float range = 150; - - public BlockLauncher(String name){ - super(name); - - update = true; - size = 3; - } - - public class BlockLauncherEntity extends PayloadAcceptorEntity{ - - @Override - public void draw(){ - super.draw(); - - drawPayload(); - } - - @Override - public boolean acceptPayload(Tilec source, Payload payload){ - return this.payload == null && payload instanceof BlockPayload; - } - - @Override - public void updateTile(){ - if(moveInPayload() && efficiency() >= 0.99f){ - Effects.shake(4f, 4f, this); - Fx.producesmoke.at(this); - - positions.clear(); - - Geometry.circle(tileX(), tileY(), world.width(), world.height(), (int)(range / tilesize), (cx, cy) -> { - if(Build.validPlace(team, cx, cy, payload.entity.block(), 0)){ - positions.add(Point2.pack(cx, cy)); - } - }); - - if(positions.isEmpty()) return; - - int pick = positions.random(); - LaunchedBlock launch = new LaunchedBlock(Point2.x(pick), Point2.y(pick), payload.entity.block(), team); - Fx.blockTransfer.at(x, y, 0, launch); - Time.run(Fx.blockTransfer.lifetime, () -> { - float ex = launch.x * tilesize + launch.block.offset(), ey = launch.y * tilesize + launch.block.offset(); - if(Build.validPlace(launch.team, launch.x, launch.y, launch.block, 0)){ - world.tile(launch.x, launch.y).setBlock(launch.block, launch.team); - Fx.placeBlock.at(ex, ey, launch.block.size); - }else{ - Fx.breakBlock.at(ex, ey, launch.block.size); - Fx.explosion.at(ex, ey); - } - }); - payload = null; - } - } - } - - public static class LaunchedBlock{ - public final int x, y; - public final Block block; - public final Team team; - - public LaunchedBlock(int x, int y, Block block, Team team){ - this.x = x; - this.y = y; - this.block = block; - this.team = team; - } - } -} diff --git a/core/src/mindustry/world/blocks/liquid/Conduit.java b/core/src/mindustry/world/blocks/liquid/Conduit.java index 7b5101d2d3..30c28e7a06 100644 --- a/core/src/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/mindustry/world/blocks/liquid/Conduit.java @@ -12,17 +12,20 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.units.*; import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; +import static mindustry.Vars.tilesize; + public class Conduit extends LiquidBlock implements Autotiler{ public final int timerFlow = timers++; public Color botColor = Color.valueOf("565656"); - public @Load(value = "@-top-#", length = 7) TextureRegion[] topRegions; - public @Load(value = "@-bottom-#", length = 7, fallback = "conduit-bottom-#") TextureRegion[] botRegions; + public @Load(value = "@-top-#", length = 5) TextureRegion[] topRegions; + public @Load(value = "@-bottom-#", length = 5, fallback = "conduit-bottom-#") TextureRegion[] botRegions; public float leakResistance = 1.5f; @@ -40,11 +43,13 @@ public class Conduit extends LiquidBlock implements Autotiler{ if(bits == null) return; + Draw.scl(bits[1], bits[2]); Draw.color(botColor); Draw.alpha(0.5f); Draw.rect(botRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90); Draw.color(); Draw.rect(topRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90); + Draw.scl(); } @Override @@ -57,11 +62,6 @@ public class Conduit extends LiquidBlock implements Autotiler{ Mathf.mod(req.tile().rotation() - req.rotation, 2) == 1 ? Blocks.liquidJunction : this; } - @Override - public void transformCase(int num, int[] bits){ - bits[0] = num == 0 ? 3 : num == 1 ? 6 : num == 2 ? 2 : num == 3 ? 4 : num == 4 ? 5 : num == 5 ? 1 : 0; - } - @Override public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){ return otherblock.hasLiquids && otherblock.outputsLiquid && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock); @@ -74,28 +74,51 @@ public class Conduit extends LiquidBlock implements Autotiler{ public class ConduitEntity extends LiquidBlockEntity{ public float smoothLiquid; - int blendbits; + public int blendbits, xscl, yscl, blending; @Override public void draw(){ float rotation = rotdeg(); + int r = rotation(); + //draw extra conduits facing this one for tiling purposes + Draw.z(Layer.blockUnder); + for(int i = 0; i < 4; i++){ + if((blending & (1 << i)) != 0){ + int dir = r - i; + float rot = i == 0 ? rotation : (dir)*90; + drawAt(x + Geometry.d4x(dir) * tilesize*0.75f, y + Geometry.d4y(dir) * tilesize*0.75f, 0, rot, i != 0 ? 1 : 2); + } + } + + Draw.z(Layer.block); + + Draw.scl(xscl, yscl); + drawAt(x, y, blendbits, rotation, 0); + Draw.reset(); + } + + protected void drawAt(float x, float y, int bits, float rotation, int slice){ Draw.color(botColor); - Draw.rect(botRegions[blendbits], x, y, rotation); + Draw.rect(sliced(botRegions[bits], slice), x, y, rotation); Draw.color(liquids.current().color); Draw.alpha(smoothLiquid); - Draw.rect(botRegions[blendbits], x, y, rotation); + Draw.rect(sliced(botRegions[bits], slice), x, y, rotation); Draw.color(); - Draw.rect(topRegions[blendbits], x, y, rotation); + Draw.rect(sliced(topRegions[bits], slice), x, y, rotation); } @Override public void onProximityUpdate(){ super.onProximityUpdate(); - blendbits = buildBlending(tile, rotation(), null, true)[0]; + int[] bits = buildBlending(tile, rotation(), null, true); + blendbits = bits[0]; + xscl = bits[1]; + yscl = bits[2]; + blending = bits[4]; } @Override diff --git a/core/src/mindustry/world/blocks/payloads/BlockPayload.java b/core/src/mindustry/world/blocks/payloads/BlockPayload.java index 3824a90742..f9d72b4e1a 100644 --- a/core/src/mindustry/world/blocks/payloads/BlockPayload.java +++ b/core/src/mindustry/world/blocks/payloads/BlockPayload.java @@ -33,6 +33,11 @@ public class BlockPayload implements Payload{ tile.setBlock(entity.block(), entity.team(), rotation, () -> entity); } + @Override + public boolean fits(){ + return entity.block().size < 3; + } + @Override public void write(Writes write){ write.b(payloadBlock); diff --git a/core/src/mindustry/world/blocks/payloads/Payload.java b/core/src/mindustry/world/blocks/payloads/Payload.java index 02acf2cb09..49be536fd4 100644 --- a/core/src/mindustry/world/blocks/payloads/Payload.java +++ b/core/src/mindustry/world/blocks/payloads/Payload.java @@ -22,6 +22,11 @@ public interface Payload{ return false; } + /** @return whether this payload fits on a standard 3x3 conveyor. */ + default boolean fits(){ + return true; + } + /** writes the payload for saving. */ void write(Writes write); diff --git a/core/src/mindustry/world/blocks/payloads/UnitPayload.java b/core/src/mindustry/world/blocks/payloads/UnitPayload.java index 53e3439c98..fe81f4934a 100644 --- a/core/src/mindustry/world/blocks/payloads/UnitPayload.java +++ b/core/src/mindustry/world/blocks/payloads/UnitPayload.java @@ -1,6 +1,7 @@ package mindustry.world.blocks.payloads; import arc.graphics.g2d.*; +import arc.math.*; import arc.util.io.*; import mindustry.*; import mindustry.gen.*; @@ -14,6 +15,11 @@ public class UnitPayload implements Payload{ this.unit = unit; } + @Override + public boolean fits(){ + return unit.hitSize() <= 16f; + } + @Override public void write(Writes write){ write.b(payloadUnit); @@ -32,6 +38,8 @@ public class UnitPayload implements Payload{ //no client dumping if(Vars.net.client()) return true; + //prevents stacking + unit.vel().add(Mathf.range(0.5f), Mathf.range(0.5f)); unit.add(); return true; diff --git a/core/src/mindustry/world/blocks/power/PowerGraph.java b/core/src/mindustry/world/blocks/power/PowerGraph.java index fa7fbe585e..da360d9343 100644 --- a/core/src/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/mindustry/world/blocks/power/PowerGraph.java @@ -56,8 +56,7 @@ public class PowerGraph{ /** @return multiplier of speed at which resources should be consumed for power generation. */ public float getUsageFraction(){ - //TODO enable it later, or not? - return 1f; //lastUsageFraction; + return 1f; } public float getPowerProduced(){ diff --git a/core/src/mindustry/world/blocks/production/AttributeSmelter.java b/core/src/mindustry/world/blocks/production/AttributeSmelter.java new file mode 100644 index 0000000000..fe44c8652b --- /dev/null +++ b/core/src/mindustry/world/blocks/production/AttributeSmelter.java @@ -0,0 +1,58 @@ +package mindustry.world.blocks.production; + +import arc.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.meta.*; + +/** A smelter that gains efficiency from attribute tiles. */ +public class AttributeSmelter extends GenericSmelter{ + public Attribute attribute = Attribute.heat; + public float baseEfficiency = 1f; + public float boostScale = 1f; + public float maxHeatBoost = 1f; + + public AttributeSmelter(String name){ + super(name); + } + + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + drawPlaceText(Core.bundle.format("bar.efficiency", + (int)((baseEfficiency + Math.min(maxHeatBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)), x, y, valid); + } + + @Override + public void setBars(){ + super.setBars(); + + bars.add("efficiency", entity -> + new Bar(() -> + Core.bundle.format("bar.efficiency", (int)(entity.efficiency() * 100)), + () -> Pal.lightOrange, + entity::efficiency)); + } + + @Override + public void setStats(){ + super.setStats(); + + stats.add(BlockStat.affinities, attribute, boostScale); + } + + public class AttributeSmelterEntity extends SmelterEntity{ + public float attrsum; + + @Override + public float efficiency(){ + return (baseEfficiency + Math.min(maxHeatBoost, boostScale * attrsum)) * super.efficiency(); + } + + @Override + public void placed(){ + super.placed(); + + attrsum = sumAttribute(attribute, tile.x, tile.y); + } + } +} \ No newline at end of file diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index ec5b825d7d..15409f8408 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -280,12 +280,14 @@ public class Drill extends Block{ return; } - if(dominantItems > 0 && progress >= drillTime + hardnessDrillMultiplier * dominantItem.hardness && items.total() < itemCapacity){ + float delay = drillTime + hardnessDrillMultiplier * dominantItem.hardness; + + if(dominantItems > 0 && progress >= delay && items.total() < itemCapacity){ offload(dominantItem); useContent(dominantItem); - index++; - progress = 0f; + index ++; + progress %= delay; drillEffect.at(getX() + Mathf.range(size), getY() + Mathf.range(size), dominantItem.color); } diff --git a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java index 8a6a63b7dc..56a485befe 100644 --- a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java +++ b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java @@ -28,7 +28,8 @@ public class PayloadAcceptor extends Block{ accept.block().size == size && accept.block().outputsPayload && //block must either be facing this one, or not be rotating - ((accept.tileX() + Geometry.d4(accept.rotation()).x * size == tile.tileX() && accept.tileY() + Geometry.d4(accept.rotation()).y * size == tile.tileY()) || !accept.block().rotate); + ((accept.tileX() + Geometry.d4(accept.rotation()).x * size == tile.tileX() && accept.tileY() + Geometry.d4(accept.rotation()).y * size == tile.tileY()) + || !accept.block().rotate || (accept.block().rotate && !accept.block().outputFacing)); } public class PayloadAcceptorEntity extends TileEntity{ @@ -50,6 +51,13 @@ public class PayloadAcceptor extends Block{ updatePayload(); } + @Override + public Payload takePayload(){ + T t = payload; + payload = null; + return t; + } + public void updatePayload(){ if(payload != null){ payload.set(x + payVector.x, y + payVector.y, payRotation); @@ -79,12 +87,12 @@ public class PayloadAcceptor extends Block{ if(payVector.len() >= size * tilesize/2f){ payVector.clamp(-size * tilesize / 2f, size * tilesize / 2f, -size * tilesize / 2f, size * tilesize / 2f); - Tile front = frontLarge(); - if(front != null && front.entity != null && front.block().outputsPayload){ + Tilec front = front(); + if(front != null && front.block().outputsPayload){ if(movePayload(payload)){ payload = null; } - }else if(front != null && !front.solid()){ + }else if(front != null && !front.tile().solid()){ dumpPayload(); } } diff --git a/core/src/mindustry/world/blocks/production/Separator.java b/core/src/mindustry/world/blocks/production/Separator.java index 9fa8efbdc3..1a4c1f0f54 100644 --- a/core/src/mindustry/world/blocks/production/Separator.java +++ b/core/src/mindustry/world/blocks/production/Separator.java @@ -63,7 +63,15 @@ public class Separator extends Block{ @Override public boolean shouldConsume(){ - return items.total() < itemCapacity; + int total = items.total(); + //very inefficient way of allowing separators to ignore input buffer storage + if(consumes.has(ConsumeType.item) && consumes.get(ConsumeType.item) instanceof ConsumeItems){ + ConsumeItems c = consumes.get(ConsumeType.item); + for(ItemStack stack : c.items){ + total -= items.get(stack.item); + } + } + return total < itemCapacity; } @Override @@ -92,7 +100,7 @@ public class Separator extends Block{ } if(progress >= 1f){ - progress = 0f; + progress %= 1f; int sum = 0; for(ItemStack stack : results) sum += stack.amount; @@ -121,6 +129,11 @@ public class Separator extends Block{ } } + @Override + public boolean canDump(Tilec to, Item item){ + return !consumes.itemFilters.get(item.id); + } + @Override public void write(Writes write){ super.write(write); diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 350fb0065c..3d6f59e7a2 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -6,6 +6,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; +import arc.util.ArcAnnotate.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; @@ -15,6 +16,7 @@ import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.*; import mindustry.world.meta.*; import mindustry.world.modules.*; @@ -79,8 +81,21 @@ public class CoreBlock extends StorageBlock{ return false; } - public class CoreEntity extends TileEntity{ - protected int storageCapacity; + public class CoreEntity extends TileEntity implements ControlBlock{ + 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 @NonNull BlockUnitc unit = Nulls.blockUnit; + + @Override + public void created(){ + unit = (BlockUnitc)UnitTypes.block.create(team); + unit.tile(this); + } + + @Override + public Unitc unit(){ + return unit; + } public void requestSpawn(Playerc player){ Call.onPlayerSpawn(tile, player); diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index 0732871627..7670c7f801 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -9,6 +9,7 @@ import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.type.*; import mindustry.ui.*; import mindustry.world.blocks.payloads.*; import mindustry.world.meta.*; @@ -19,8 +20,8 @@ public class Reconstructor extends UnitBlock{ public @Load(value = "@-top", fallback = "factory-top") TextureRegion topRegion; public @Load(value = "@-out", fallback = "factory-out") TextureRegion outRegion; public @Load(value = "@-in", fallback = "factory-in") TextureRegion inRegion; - public int tier = 1; public float constructTime = 60 * 2; + public UnitType[][] upgrades = {}; public Reconstructor(String name){ super(name); @@ -57,8 +58,7 @@ public class Reconstructor extends UnitBlock{ return this.payload == null && relativeTo(source) != rotation() && payload instanceof UnitPayload - && ((UnitPayload)payload).unit.type().upgrade != null - && ((UnitPayload)payload).unit.type().tier == tier; + && hasUpgrade(((UnitPayload)payload).unit.type()); } @Override @@ -79,7 +79,7 @@ public class Reconstructor extends UnitBlock{ Draw.alpha(1f - progress/ constructTime); Draw.rect(payload.unit.type().icon(Cicon.full), x, y, rotdeg() - 90); Draw.reset(); - Drawf.construct(this, payload.unit.type().upgrade, rotdeg() - 90f, progress / constructTime, speedScl, time); + Drawf.construct(this, upgrade(payload.unit.type()), rotdeg() - 90f, progress / constructTime, speedScl, time); }); }else{ Draw.z(Layer.blockOver); @@ -98,7 +98,7 @@ public class Reconstructor extends UnitBlock{ if(payload != null){ //check if offloading - if(payload.unit.type().upgrade == null || payload.unit.type().tier != tier){ + if(!hasUpgrade(payload.unit.type())){ moveOutPayload(); }else{ //update progress if(moveInPayload()){ @@ -109,7 +109,7 @@ public class Reconstructor extends UnitBlock{ //upgrade the unit if(progress >= constructTime){ - payload.unit = payload.unit.type().upgrade.create(payload.unit.team()); + payload.unit = upgrade(payload.unit.type()).create(payload.unit.team()); progress = 0; Effects.shake(2f, 3f, this); Fx.producesmoke.at(this); @@ -124,7 +124,16 @@ public class Reconstructor extends UnitBlock{ } public boolean constructing(){ - return payload != null && payload.unit.type().upgrade != null && payload.unit.type().tier == tier; + return payload != null && hasUpgrade(payload.unit.type()); + } + + public boolean hasUpgrade(UnitType type){ + return upgrade(type) != null; + } + + public UnitType upgrade(UnitType type){ + UnitType[] r = Structs.find(upgrades, arr -> arr[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 5092c25cee..36fa27b435 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -17,7 +17,7 @@ import mindustry.world.meta.*; import static mindustry.Vars.tilesize; public class RepairPoint extends Block{ - private static Rect rect = new Rect(); + private static final Rect rect = new Rect(); public int timerTarget = timers++; diff --git a/core/src/mindustry/world/meta/BlockStats.java b/core/src/mindustry/world/meta/BlockStats.java index de7ac8d5b7..c5f1dc0f5b 100644 --- a/core/src/mindustry/world/meta/BlockStats.java +++ b/core/src/mindustry/world/meta/BlockStats.java @@ -38,9 +38,13 @@ public class BlockStats{ } public void add(BlockStat stat, Attribute attr){ + add(stat, attr, 1f); + } + + public void add(BlockStat stat, Attribute attr, float scale){ for(Block block : Vars.content.blocks()){ if(!block.isFloor() || block.asFloor().attributes.get(attr) == 0) continue; - add(stat, new FloorEfficiencyValue(block.asFloor(), block.asFloor().attributes.get(attr))); + add(stat, new FloorEfficiencyValue(block.asFloor(), block.asFloor().attributes.get(attr) * scale)); } } @@ -55,7 +59,7 @@ public class BlockStats{ map.put(stat.category, new OrderedMap<>()); } - map.get(stat.category).getOr(stat, Array::new).add(value); + map.get(stat.category).get(stat, Array::new).add(value); dirty = true; } diff --git a/core/src/mindustry/world/meta/BuildPlaceability.java b/core/src/mindustry/world/meta/BuildPlaceability.java new file mode 100644 index 0000000000..3799c74207 --- /dev/null +++ b/core/src/mindustry/world/meta/BuildPlaceability.java @@ -0,0 +1,32 @@ +package mindustry.world.meta; + +import arc.*; +import arc.func.*; +import mindustry.*; + +import java.util.*; + +/** + * Like BuildVisiblity, but defines whether a block can be *placed*, with an extra message. + * This is like defining a conditionally banned block. + * */ +public enum BuildPlaceability{ + always(() -> true), + sectorCaptured(() -> Vars.state.rules.sector != null && Vars.state.rules.sector.isCaptured()); + + private final Boolp placeability; + + BuildPlaceability(Boolp placeability){ + this.placeability = placeability; + } + + public boolean placeable(){ + return placeability.get(); + } + + /** @return why this block is banned. */ + public String message(){ + return Core.bundle.get("unplaceable." + name().toLowerCase(Locale.ROOT)); + } + +} diff --git a/core/src/mindustry/world/meta/values/AmmoListValue.java b/core/src/mindustry/world/meta/values/AmmoListValue.java index 8734632cbc..0e9588dfbd 100644 --- a/core/src/mindustry/world/meta/values/AmmoListValue.java +++ b/core/src/mindustry/world/meta/values/AmmoListValue.java @@ -66,7 +66,7 @@ public class AmmoListValue implements StatValue{ sep(bt, "$bullet.homing"); } - if(type.lightining > 0){ + if(type.lightning > 0){ sep(bt, "$bullet.shock"); } diff --git a/desktop/src/mindustry/desktop/steam/SWorkshop.java b/desktop/src/mindustry/desktop/steam/SWorkshop.java index 5acd588f6d..9f064db597 100644 --- a/desktop/src/mindustry/desktop/steam/SWorkshop.java +++ b/desktop/src/mindustry/desktop/steam/SWorkshop.java @@ -51,7 +51,7 @@ public class SWorkshop implements SteamUGCCallback{ } public Array getWorkshopFiles(Class type){ - return workshopFiles.getOr(type, () -> new Array<>(0)); + return workshopFiles.get(type, () -> new Array<>(0)); } /** Publish a new item and submit an update for it. diff --git a/gradle.properties b/gradle.properties index 1652cb9f9d..b326804b67 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=edaf52e6768e0c24cc4598de8105d07a6c66efd8 +archash=35b389b71386e7eb9bcffed7e61f015144fd182f diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index cbdc86a6c0..96ea86692e 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -405,7 +405,7 @@ public class ServerControl implements ApplicationListener{ return; } - Team team = arg.length == 0 ? Team.sharded : Structs.find(Team.all(), t -> t.name.equals(arg[0])); + Team team = arg.length == 0 ? Team.sharded : Structs.find(Team.all, t -> t.name.equals(arg[0])); if(team == null){ err("No team with that name found."); diff --git a/server/src/mindustry/server/ServerLauncher.java b/server/src/mindustry/server/ServerLauncher.java index 760d480fc4..e7146b4db8 100644 --- a/server/src/mindustry/server/ServerLauncher.java +++ b/server/src/mindustry/server/ServerLauncher.java @@ -74,6 +74,8 @@ public class ServerLauncher implements ApplicationListener{ System.exit(1); } + bases.load(); + Core.app.addListener(new ApplicationListener(){public void update(){ asyncCore.begin(); }}); Core.app.addListener(logic = new Logic()); Core.app.addListener(netServer = new NetServer()); diff --git a/servers.json b/servers.json index a11e43f30c..018a57c577 100644 --- a/servers.json +++ b/servers.json @@ -42,10 +42,13 @@ "address": "aamindustry.play.ai" }, { - "address": "mindustry.kr" + "address": "mindustry.atannergaming.com" }, { - "address": "mindustry.atannergaming.com" + "address": "mindustry.atannergaming.com:7000" + }, + { + "address": "mindustry.atannergaming.com:8000" }, { "address": "mindustry.kbni.net.au:6567" @@ -55,5 +58,8 @@ }, { "address": "twsmindustry.24x7.hk" + }, + { + "address": "Chaotic-Neutral.ddns.net:1111" } ] diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 1802564b3f..6cfc6bf7cf 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -554,7 +554,7 @@ public class ApplicationTests{ for(int x = 5; x < tiles.width && i < content.blocks().size; ){ Block block = content.block(i++); - if(block.isBuildable()){ + if(block.canBeBuilt()){ x += block.size; tiles.get(x, 5).setBlock(block); x += block.size; diff --git a/tools/build.gradle b/tools/build.gradle index a187320aab..baa2953413 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -11,7 +11,7 @@ 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 java.util.concurrent.TimeUnit def genFolder = "../core/assets-raw/sprites_out/generated/" def doAntialias = !project.hasProperty("disableAntialias") @@ -33,7 +33,7 @@ def transformColors = { List> list -> //d4816b -transformColors([["6e7080", "989aa4", "b0bac0"], ["bc5452", "ea8878", "feb380"], ["de9458", "f8c266", "ffe18f"], ["feb380", "ea8878", "bc5452"]]) +transformColors([["a387ea", "8a73c6", "5c5e9f"], ["6e7080", "989aa4", "b0bac0"], ["bc5452", "ea8878", "feb380"], ["de9458", "f8c266", "ffe18f"], ["feb380", "ea8878", "bc5452"]]) def antialias = { File file -> if(!doAntialias) return @@ -189,6 +189,17 @@ def scaleImage = { File file -> def tileImage = { File file -> def image = ImageIO.read(file) + for(x in 0..image.width-1){ + for(y in 0..image.height-1){ + if(x > (image.height - 1 - y)){ + def rx = image.height - 1 - y + def ry = x + + image.setRGB(x, y, image.getRGB(rx, image.height - 1 - ry)) + } + } + } + def result = new BufferedImage(image.width * 2, image.height * 2, image.getType()) Graphics2D graphics = result.createGraphics() graphics.drawImage(image, image.width, 0, -image.width, image.height, null) diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 0ca371c8a5..7efaa8ef76 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -32,7 +32,7 @@ public class Generators{ for(int i = 0; i < frames; i++){ float fin = (float)i / (frames); float fout = 1f - fin; - float stroke = 4f * fout; + float stroke = 3.5f * fout; float radius = (size/2f) * fin; Pixmap pixmap = new Pixmap(size, size); @@ -173,6 +173,7 @@ public class Generators{ scaled.save("../ui/block-" + block.name + "-" + icon.name()); } + boolean hasEmpty = false; Color average = new Color(); for(int x = 0; x < image.width; x++){ for(int y = 0; y < image.height; y++){ @@ -180,6 +181,9 @@ public class Generators{ average.r += color.r; average.g += color.g; average.b += color.b; + if(color.a < 0.9f){ + hasEmpty = true; + } } } average.mul(1f / (image.width * image.height)); @@ -188,7 +192,8 @@ public class Generators{ }else{ average.mul(1.1f); } - average.a = 1f; + //encode square sprite in alpha channel + average.a = hasEmpty ? 0.1f : 1f; colors.draw(block.id, 0, average); }catch(IllegalArgumentException e){ Log.info("Skipping &ly'@'", block.name);