diff --git a/build.gradle b/build.gradle index 4964fa3cfd..f61001f29d 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects{ if(!project.hasProperty("versionType")) versionType = 'official' appName = 'Mindustry' steamworksVersion = '0b86023401880bb5e586bc404bedbaae9b1f1c94' - rhinoVersion = '3c6bbadf73a904eefcc28b6fd8aa742ac575e878' + rhinoVersion = '73a812444ac388ac2d94013b5cadc8f70b7ea027' loadVersionProps = { return new Properties().with{p -> p.load(file('../core/assets/version.properties').newReader()); return p } diff --git a/core/assets-raw/sprites/blocks/units/tank-assembler.png b/core/assets-raw/sprites/blocks/units/tank-assembler.png new file mode 100644 index 0000000000..5bf4b32783 Binary files /dev/null and b/core/assets-raw/sprites/blocks/units/tank-assembler.png differ diff --git a/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png b/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png index 4c21bf939c..d5a14f7432 100644 Binary files a/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png and b/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png differ diff --git a/core/assets-raw/sprites/blocks/walls/tungsten-wall.png b/core/assets-raw/sprites/blocks/walls/tungsten-wall.png index e9c0c18e33..1e57bcea46 100644 Binary files a/core/assets-raw/sprites/blocks/walls/tungsten-wall.png and b/core/assets-raw/sprites/blocks/walls/tungsten-wall.png differ diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index ee0c940a98..e5d28945ab 100644 Binary files a/core/assets/logicids.dat and b/core/assets/logicids.dat differ diff --git a/core/src/mindustry/ai/types/CargoAI.java b/core/src/mindustry/ai/types/CargoAI.java index bc5aca07f6..f9572b9c3f 100644 --- a/core/src/mindustry/ai/types/CargoAI.java +++ b/core/src/mindustry/ai/types/CargoAI.java @@ -29,6 +29,8 @@ public class CargoAI extends AIController{ var build = tether.building(); + if(build.items == null) return; + //empty, approach the loader, even if there's nothing to pick up (units hanging around doing nothing looks bad) if(!unit.hasItem()){ moveTo(build, moveRange, moveSmoothing); diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 7e825d8968..3a9084657c 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3312,10 +3312,13 @@ public class Blocks{ //endregion //region units - erekir + //TODO completely unfinished tankAssembler = new UnitAssembler("tank-assembler"){{ + requirements(Category.units, with(Items.graphite, 10)); size = 3; output = UnitTypes.vanquish; - requirements = BlockStack.list(Blocks.thoriumWallLarge, 4); + droneType = UnitTypes.manifold; + requirements = BlockStack.list(Blocks.thoriumWallLarge, 4, Blocks.duct, 2); }}; //endregion diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 929e6c6496..697e9830d8 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -2691,6 +2691,7 @@ public class UnitTypes{ itemCapacity = 0; commandLimit = 0; hidden = true; + internal = true; }}; manifold = new UnitType("manifold"){{ diff --git a/core/src/mindustry/type/BlockSeq.java b/core/src/mindustry/type/BlockSeq.java new file mode 100644 index 0000000000..e5fc203b6e --- /dev/null +++ b/core/src/mindustry/type/BlockSeq.java @@ -0,0 +1,65 @@ +package mindustry.type; + +import arc.struct.*; +import arc.util.io.*; +import mindustry.*; +import mindustry.world.*; + +public class BlockSeq{ + private ObjectIntMap blocks = new ObjectIntMap<>(); + + public void add(Block block){ + blocks.increment(block); + } + + public void add(Block block, int amount){ + blocks.increment(block, amount); + } + + public void remove(Block block){ + add(block, -1); + } + + public void remove(Block block, int amount){ + add(block, -amount); + } + + public void remove(Seq stacks){ + stacks.each(b -> remove(b.block, b.amount)); + } + + public void clear(){ + blocks.clear(); + } + + public int get(Block block){ + return blocks.get(block); + } + + public boolean contains(Seq stacks){ + return !stacks.contains(b -> get(b.block) < b.amount); + } + + public boolean contains(Block block, int amount){ + return get(block) >= amount; + } + + public boolean contains(BlockStack stack){ + return get(stack.block) >= stack.amount; + } + + public void write(Writes write){ + write.s(blocks.size); + for(var entry : blocks.entries()){ + write.s(entry.key.id); + write.i(entry.value); + } + } + + public void read(Reads read){ + short amount = read.s(); + for(int i = 0; i < amount; i++){ + blocks.put(Vars.content.block(read.s()), read.i()); + } + } +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index f344fadcec..1629be8746 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -156,6 +156,7 @@ public class UnitType extends UnlockableContent{ public boolean singleTarget = false; public boolean forceMultiTarget = false; public boolean hidden = false; + public boolean internal = false; //for crawlers public int segments = 0; diff --git a/core/src/mindustry/ui/ItemImage.java b/core/src/mindustry/ui/ItemImage.java index e0a4ce0b17..e80b8804a5 100644 --- a/core/src/mindustry/ui/ItemImage.java +++ b/core/src/mindustry/ui/ItemImage.java @@ -44,4 +44,8 @@ public class ItemImage extends Stack{ })); } } + + public ItemImage(BlockStack stack){ + this(stack.block.uiIcon, stack.amount); + } } diff --git a/core/src/mindustry/world/blocks/defense/BuildTurret.java b/core/src/mindustry/world/blocks/defense/BuildTurret.java index 53a208df74..aaa1425a97 100644 --- a/core/src/mindustry/world/blocks/defense/BuildTurret.java +++ b/core/src/mindustry/world/blocks/defense/BuildTurret.java @@ -47,6 +47,7 @@ public class BuildTurret extends BaseTurret{ //this is super hacky, but since blocks are initialized before units it does not run into init/concurrent modification issues unitType = new UnitType("turret-unit-" + name){{ hidden = true; + internal = true; speed = 0f; hitSize = 0f; health = 1; diff --git a/core/src/mindustry/world/blocks/distribution/Duct.java b/core/src/mindustry/world/blocks/distribution/Duct.java index cf023c2cc2..229a717fb6 100644 --- a/core/src/mindustry/world/blocks/distribution/Duct.java +++ b/core/src/mindustry/world/blocks/distribution/Duct.java @@ -124,6 +124,11 @@ public class Duct extends Block implements Autotiler{ Draw.reset(); } + @Override + public void payloadDraw(){ + Draw.rect(fullIcon, x, y); + } + protected void drawAt(float x, float y, int bits, float rotation, SliceMode slice){ Draw.z(Layer.blockUnder); Draw.rect(sliced(botRegions[bits], slice), x, y, rotation); diff --git a/core/src/mindustry/world/blocks/units/UnitAssembler.java b/core/src/mindustry/world/blocks/units/UnitAssembler.java index 5617930bda..4cc31aac30 100644 --- a/core/src/mindustry/world/blocks/units/UnitAssembler.java +++ b/core/src/mindustry/world/blocks/units/UnitAssembler.java @@ -1,14 +1,21 @@ package mindustry.world.blocks.units; +import arc.*; +import arc.graphics.g2d.*; +import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.content.*; +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.consumers.*; import static mindustry.Vars.*; @@ -20,13 +27,13 @@ import static mindustry.Vars.*; * 3. * */ public class UnitAssembler extends PayloadBlock{ - public int areaSize = 10; + public int areaSize = 11; public UnitType droneType; public int dronesCreated = 4; //TODO should be different for every tier. public Seq requirements = new Seq<>(); - public UnitType output = UnitTypes.vanquish; + public UnitType output; public UnitAssembler(String name){ super(name); @@ -48,21 +55,62 @@ public class UnitAssembler extends PayloadBlock{ Tmp.r1.x += Geometry.d4x(rotation) * len; Tmp.r1.y += Geometry.d4y(rotation) * len; - //TODO better visuals here? + //TODO better visuals here? dashLine looks bad Drawf.dashRect(valid ? Pal.accent : Pal.remove, Tmp.r1); } + @Override + public void setBars(){ + super.setBars(); + + //TODO progress bar + //bars.add("progress", (UnitAssemblerBuild e) -> new Bar("bar.progress", Pal.ammo, e::fraction)); + + bars.add("units", (UnitAssemblerBuild e) -> + new Bar(() -> + Core.bundle.format("bar.unitcap", + Fonts.getUnicodeStr(output.name), + e.team.data().countType(output), + Units.getStringCap(e.team) + ), + () -> Pal.power, + () -> (float)e.team.data().countType(output) / Units.getCap(e.team) + )); + } + + @Override + public void drawRequestRegion(BuildPlan plan, Eachable list){ + Draw.rect(region, plan.drawx(), plan.drawy()); + //Draw.rect(outRegion, plan.drawx(), plan.drawy(), plan.rotation * 90); + Draw.rect(topRegion, plan.drawx(), plan.drawy()); + } + + @Override + public void init(){ + consumes.add(new ConsumePayloads(requirements, (UnitAssemblerBuild build) -> build.blocks)); + + super.init(); + } + public class UnitAssemblerBuild extends PayloadBlockBuild{ public Seq units = new Seq<>(); + public BlockSeq blocks = new BlockSeq(); - //TODO how should payloads be stored? counts of blocks? intmap? references? - //public Seq payloads = new Seq<>(); + //TODO progress + //TODO how should payloads be stored exactly? counts of blocks? intmap? references? + + public Vec2 getUnitSpawn(){ + float len = tilesize * (areaSize + size)/2f; + float unitX = x + Geometry.d4x(rotation) * len, unitY = y + Geometry.d4y(rotation) * len; + return Tmp.v4.set(unitX, unitY); + } @Override public void updateTile(){ units.removeAll(u -> !u.isAdded() || u.dead); - if(consValid() && units.size < dronesCreated){ + //units annoying, disabled for now + if(false && efficiency() > 0 && units.size < dronesCreated){ //TODO build animation? distribute spawning? var unit = droneType.create(team); if(unit instanceof BuildingTetherc bt){ @@ -76,29 +124,88 @@ public class UnitAssembler extends PayloadBlock{ units.add(unit); } + //TODO units should move stuff into position + + //TODO check if area is occupied + + Vec2 spawn = getUnitSpawn(); + + //check if all requirements are met + if(consValid() & Units.canCreate(team, output)){ + + //TODO ???? should this even be part of a trigger + consume(); + + //TODO actually just goes poof + var unit = output.create(team); + unit.set(spawn.x + Mathf.range(0.001f), spawn.y + Mathf.range(0.001f)); + unit.rotation = 90f; + unit.add(); + + Fx.spawn.at(unit); + + blocks.clear(); + } + //TODO drones need to indicate that they are in position and actually play an animation } + @Override + public void draw(){ + Draw.rect(region, x, y); + //Draw.rect(outRegion, x, y, rotdeg()); + + Draw.z(Layer.blockOver); + + //payRotation = rotdeg(); + //drawPayload(); + + Draw.z(Layer.blockOver + 0.1f); + + Draw.rect(topRegion, x, y); + + Vec2 spawn = getUnitSpawn(); + + //TODO which layer? + Draw.z(Layer.power - 1f); + + Draw.mixcol(Pal.accent, 1f); + Draw.alpha(0.4f + Mathf.absin(10f, 0.2f)); + Draw.rect(output.fullIcon, spawn.x, spawn.y); + Draw.reset(); + } + @Override public void handlePayload(Building source, Payload payload){ //super.handlePayload(source, payload); + blocks.add(((BuildPayload)payload).block()); + //payloads.add((BuildPayload)payload); } @Override public boolean acceptPayload(Building source, Payload payload){ - return payload instanceof BuildPayload bp && requirements.contains(b -> b.block == bp.block()); + return payload instanceof BuildPayload bp && requirements.contains(b -> b.block == bp.block() && blocks.get(bp.block()) < b.amount); } @Override public void write(Writes write){ super.write(write); + + //blocks.write(write); + + //TODO save: + //- unit IDs + //- progress + //- payloads in position (should they have positions?) } @Override public void read(Reads read, byte revision){ super.read(read, revision); + + //blocks.read(read); } } } diff --git a/core/src/mindustry/world/consumers/ConsumeItems.java b/core/src/mindustry/world/consumers/ConsumeItems.java index 90f1c4fd85..fb1e6a7b45 100644 --- a/core/src/mindustry/world/consumers/ConsumeItems.java +++ b/core/src/mindustry/world/consumers/ConsumeItems.java @@ -37,7 +37,7 @@ public class ConsumeItems extends Consume{ int i = 0; for(var stack : items){ c.add(new ReqImage(new ItemImage(stack.item.uiIcon, stack.amount), - () -> build.items != null && build.items.has(stack.item, stack.amount))).padRight(8); + () -> build.items.has(stack.item, stack.amount))).padRight(8); if(++i % 4 == 0) c.row(); } }).left(); diff --git a/core/src/mindustry/world/consumers/ConsumePayloads.java b/core/src/mindustry/world/consumers/ConsumePayloads.java new file mode 100644 index 0000000000..b45cfae90a --- /dev/null +++ b/core/src/mindustry/world/consumers/ConsumePayloads.java @@ -0,0 +1,62 @@ +package mindustry.world.consumers; + +import arc.func.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import mindustry.gen.*; +import mindustry.type.*; +import mindustry.ui.*; +import mindustry.world.meta.*; + +public class ConsumePayloads extends Consume{ + //TODO bad, should be part of Building + dynamic + protected Func inventory; + + public Seq payloads; + + public ConsumePayloads(Seq payloads, Func inventory){ + this.payloads = payloads; + this.inventory = (Func)inventory; + } + + @Override + public boolean valid(Building build){ + return inventory.get(build).contains(payloads); + } + + @Override + public void trigger(Building build){ + inventory.get(build).remove(payloads); + } + + @Override + public void display(Stats stats){ + //TODO + + for(var stack : payloads){ + stats.add(Stat.input, t -> { + t.add(new ItemImage(stack)); + t.add(stack.block.localizedName).padLeft(4).padRight(4); + }); + } + } + + @Override + public void build(Building build, Table table){ + var inv = inventory.get(build); + + table.table(c -> { + int i = 0; + for(var stack : payloads){ + c.add(new ReqImage(new ItemImage(stack.block.uiIcon, stack.amount), + () -> inv.contains(stack.block, stack.amount))).padRight(8); + if(++i % 4 == 0) c.row(); + } + }).left(); + } + + @Override + public ConsumeType type(){ + return ConsumeType.payload; + } +} diff --git a/core/src/mindustry/world/consumers/ConsumeType.java b/core/src/mindustry/world/consumers/ConsumeType.java index 9a68a050cc..d6cd64a735 100644 --- a/core/src/mindustry/world/consumers/ConsumeType.java +++ b/core/src/mindustry/world/consumers/ConsumeType.java @@ -3,5 +3,6 @@ package mindustry.world.consumers; public enum ConsumeType{ item, power, - liquid + liquid, + payload } diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 544b747f02..13acaba85f 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -486,7 +486,7 @@ public class Generators{ }); generate("unit-icons", () -> content.units().each(type -> { - if(type.isHidden()) return; //hidden units don't generate + if(type.internal) return; //internal hidden units don't generate ObjectSet outlined = new ObjectSet<>();