From 42ce901da24cb9c41cb598a47b97e560bea4fcb2 Mon Sep 17 00:00:00 2001 From: SomeonesShade Date: Tue, 1 Sep 2026 08:57:06 +0800 Subject: [PATCH] Balancing Payload Logistics: PMD, Assorted Changes, and Deconstructor Behavioral Changes (#12182) * Payload Changes 3 (final) * Deconstructor Behavior Changes Final * Added full-storage icon * adjustments * removed fontello file * Removed full-storage.png * Tweaked itemBuffer * Update IconConverter.java * Apply suggestion from @Anuken --------- Co-authored-by: EggleEgg <125359838+EggleEgg@users.noreply.github.com> Co-authored-by: Anuken --- core/assets/bundles/bundle.properties | 4 +- core/src/mindustry/content/Blocks.java | 21 ++++--- .../blocks/payloads/PayloadDeconstructor.java | 59 +++++++++++++++---- tools/src/mindustry/tools/IconConverter.java | 25 ++++++-- 4 files changed, 85 insertions(+), 24 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 034e52e9d1..2bd5bf2b00 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -2134,7 +2134,7 @@ block.constructor.description = Fabricates structures up to 2x2 tiles in size. block.large-constructor.name = Large Constructor block.large-constructor.description = Fabricates structures up to 4x4 tiles in size. block.deconstructor.name = Large Deconstructor -block.deconstructor.description = Deconstructs structures and units. Returns 100% of build cost. +block.deconstructor.description = Deconstructs inputted structures and units. Returns 100% of build cost. Holds items into seperate item capacities. block.payload-loader.name = Payload Loader block.payload-loader.description = Load liquids and items into blocks. block.payload-unloader.name = Payload Unloader @@ -2742,7 +2742,7 @@ block.ship-refabricator.description = Upgrades inputted ship units to the second block.mech-refabricator.description = Upgrades inputted mech units to the second tier. block.prime-refabricator.description = Upgrades inputted units to the third tier. block.basic-assembler-module.description = Increases assembler tier when placed next to a construction boundary. Requires power. Can be used as a payload input. -block.small-deconstructor.description = Deconstructs inputted structures and units. Returns 100% of the build cost. +block.small-deconstructor.description = Deconstructs inputted structures and units. Returns 100% of the build cost. Holds items into seperate item capacities. block.reinforced-payload-conveyor.description = Moves payloads forward. block.reinforced-payload-router.description = Distributes payloads into adjacent blocks. Functions as a sorter when a filter is set. block.payload-mass-driver.description = Long-range payload transport structure. Shoots received payloads to linked payload mass drivers. diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 400b77ffbd..a714c9fbb0 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -6622,8 +6622,8 @@ public class Blocks{ requirements(Category.units, with(Items.tungsten, 40, Items.silicon, 50, Items.graphite, 20)); regionSuffix = "-dark"; size = 3; - reload = 130f; - chargeTime = 90f; + reload = 45f; + chargeTime = 70f; range = 700f; maxPayloadSize = 2.5f; fogRadius = 5; @@ -6631,7 +6631,7 @@ public class Blocks{ }}; largePayloadMassDriver = new PayloadMassDriver("large-payload-mass-driver"){{ - requirements(Category.units, with(Items.phaseFabric, 20, Items.tungsten, 200, Items.silicon, 200, Items.graphite, 100, Items.oxide, 30)); + requirements(Category.units, with(Items.phaseFabric, 10, Items.tungsten, 120, Items.silicon, 150, Items.graphite, 60, Items.oxide, 30)); regionSuffix = "-dark"; size = 5; reload = 130f; @@ -6642,21 +6642,28 @@ public class Blocks{ }}; smallDeconstructor = new PayloadDeconstructor("small-deconstructor"){{ - requirements(Category.units, with(Items.beryllium, 100, Items.silicon, 100, Items.oxide, 40, Items.graphite, 80)); + requirements(Category.units, with(Items.beryllium, 70, Items.silicon, 70, Items.oxide, 25, Items.graphite, 50)); regionSuffix = "-dark"; itemCapacity = 100; + itemBuffer = itemCapacity - 20; consumePower(1f); size = 3; deconstructSpeed = 3f; + separateItemCapacity = true; + + //it just looks weird for anything larger + maxPayloadSize = 3; }}; deconstructor = new PayloadDeconstructor("deconstructor"){{ requirements(Category.units, with(Items.beryllium, 250, Items.oxide, 100, Items.silicon, 250, Items.carbide, 50)); regionSuffix = "-dark"; - itemCapacity = 250; + itemCapacity = 320; + itemBuffer = itemCapacity - 20; consumePower(3f); size = 5; deconstructSpeed = 6f; + separateItemCapacity = true; }}; constructor = new Constructor("constructor"){{ @@ -6675,12 +6682,12 @@ public class Blocks{ requirements(Category.units, with(Items.silicon, 150, Items.oxide, 100, Items.tungsten, 200, Items.thorium, 80)); regionSuffix = "-dark"; hasPower = true; - buildSpeed = 0.75f; + buildSpeed = 5f; maxBlockSize = 4; minBlockSize = 3; size = 5; - consumePower(3f); + consumePower(5f); }}; payloadLoader = new PayloadLoader("payload-loader"){{ diff --git a/core/src/mindustry/world/blocks/payloads/PayloadDeconstructor.java b/core/src/mindustry/world/blocks/payloads/PayloadDeconstructor.java index abdc6db2db..a5e7f43006 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadDeconstructor.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadDeconstructor.java @@ -1,5 +1,6 @@ package mindustry.world.blocks.payloads; +import arc.graphics.*; import arc.*; import arc.graphics.g2d.*; import arc.math.*; @@ -19,6 +20,8 @@ public class PayloadDeconstructor extends PayloadBlock{ public float maxPayloadSize = 4; public float deconstructSpeed = 2.5f; public int dumpRate = 4; + /** Any payload with build requirements equalling or exceeding this value is accepted regardless. */ + public int itemBuffer = 0; public PayloadDeconstructor(String name){ super(name); @@ -58,6 +61,8 @@ public class PayloadDeconstructor extends PayloadBlock{ public @Nullable float[] accum; public float progress; public float time, speedScl; + public static final float overlayDuration = 40f; + public float overlayTime = 0; @Override public void draw(){ @@ -90,6 +95,23 @@ public class PayloadDeconstructor extends PayloadBlock{ }); } + //draw warning + if(overlayTime > 0 && deconstructing == null){ + float z = Draw.z(); + Draw.z(Layer.flyingUnitLow + 2f); + var region = Icon.warning.getRegion(); + Draw.color(Color.scarlet); + Draw.alpha(0.8f * Interp.exp5Out.apply(overlayTime)); + + float size = 8f; + Draw.rect(region, this.x, this.y, size, size); + + Draw.reset(); + + overlayTime = Math.max(overlayTime - Time.delta/overlayDuration, 0f); + Draw.z(z); + } + Draw.rect(topRegion, x, y); } @@ -107,9 +129,28 @@ public class PayloadDeconstructor extends PayloadBlock{ @Override public boolean acceptPayload(Building source, Payload payload){ - return deconstructing == null && this.payload == null && super.acceptPayload(source, payload) && payload.requirements().length > 0 && payload.fits(maxPayloadSize); - } + boolean isFull = false; + //source equalling this building means it comes from a unit payenter + if(source != this){ + for(var req : payload.requirements()){ + float realAmount = req.amount * (payload instanceof BuildPayload ? state.rules.buildCostMultiplier : state.rules.unitCost(team)); + if(items.get(req.item) + realAmount >= itemCapacity) isFull = true; + + //if the payload's requirements are too large within the buffer, receive anyway. + if(realAmount >= itemBuffer){ + isFull = false; + break; + } + } + + if(isFull && deconstructing == null){ + overlayTime = 2.5f; + } + } + + return !isFull && deconstructing == null && this.payload == null && super.acceptPayload(source, payload) && payload.requirements().length > 0 && payload.fits(maxPayloadSize); + } @Override public void updateTile(){ super.updateTile(); @@ -132,13 +173,11 @@ public class PayloadDeconstructor extends PayloadBlock{ } //check if there is enough space to get the items for deconstruction - boolean canProgress = items.total() <= itemCapacity; - if(canProgress){ - for(var ac : accum){ - if(ac >= 1f){ - canProgress = false; - break; - } + boolean canProgress = true; + for(var req : reqs){ + if(items.get(req.item) >= itemCapacity){ + canProgress = false; + break; } } @@ -169,7 +208,7 @@ public class PayloadDeconstructor extends PayloadBlock{ //transfer items from accumulation buffer into block inventory when they reach integers for(int i = 0; i < reqs.length; i++){ - int taken = Math.min((int)accum[i], itemCapacity - items.total()); + int taken = Math.min((int)accum[i], itemCapacity - items.get(reqs[i].item)); if(taken > 0){ items.add(reqs[i].item, taken); accum[i] -= taken; diff --git a/tools/src/mindustry/tools/IconConverter.java b/tools/src/mindustry/tools/IconConverter.java index 922cb2b038..36806ba8fb 100644 --- a/tools/src/mindustry/tools/IconConverter.java +++ b/tools/src/mindustry/tools/IconConverter.java @@ -12,11 +12,26 @@ public class IconConverter{ public static void main(String[] __){ /* Process for adding an icon to the font: - 1. Have an SVG ready, possibly created with this tool. - 2. Go to Fontello and load the config.json from core/assets-raw/fontgen/config.json - 3. Drag the SVG in. - 4. Export the config and font file, replace the old config. - 5. Take the font (ttf) from the zip, open it in FontForge, and merge it into font.woff and icon.ttf. Usually, you would do view -> go to (the 0x unicode index). + + //CONVERTING A PNG INTO A SVG + 1. Add your png to core/assets-raw/icons/ + 2. Run gradle tools:pack. This will add the png to icons.properties + 3. If you haven't done it already, download inkscape and add in path enviroment variables your inkscape installation so "inkscape --etc" commands can run + 4. Run gradle tools:icongen. This step will not work if you haven't done step 3 + 5. Locate your icon.svg under core/assets-raw/fontgen/extra/ + 6. Often generated icons cannot be read by fontello correctly ("If image looks not as expected please convert to compound path manually..."), follow the steps in the wiki linked (https://github.com/fontello/fontello/wiki/How-to-use-custom-images#importing-svg-images) + + //ADDING TO FONTS + 1. Go to Fontello and load the config.json from core/assets-raw/fontgen/config.json + 2. Drag the SVG in + 3. Click on your new fontello icon to select it. If selected the icon circle should show a red outline + 4. Export the config and font file ("Download webfont" button), replace the old config + 5. Intall FontForge if you havent done it already + 6. Take the font (.ttf) from the zip, open it in FontForge, and merge it into font.woff (Element -> Merge fonts) inside core/assets/fonts/. You will be prompted whether you want to keep the existing kerning, usually select Yes + 7. Optionally, go view -> go to (the 0x unicode index, or search by name) to check if the icon has been added + 8. Go to file -> generate fonts, uncheck font validation, click generate and replace the old font.woff. Saving the sfd file is not necessary + 9. Repeat steps 6 and 8 for icon.ttf + 10. Done! do note when using icons if they contain any dashes (-) they will be converted into camelcase. So something like foo-bar.svg becomes Icon.fooBar **/ Log.info("Converting icons...");