diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 6226dbae5d..b3ff2389c2 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1350,17 +1350,20 @@ public class Blocks implements ContentList{ requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); size = 3; itemCapacity = 1000; + group = BlockGroup.storage; }}; container = new StorageBlock("container"){{ requirements(Category.effect, with(Items.titanium, 100)); size = 2; itemCapacity = 300; + group = BlockGroup.storage; }}; unloader = new Unloader("unloader"){{ requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30)); speed = 6f; + group = BlockGroup.transportation; }}; //endregion diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index bd4d57c771..e748310b8a 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -85,7 +85,7 @@ public abstract class BulletType extends Content{ public float fragAngle = 0f; public int fragBullets = 9; public float fragVelocityMin = 0.2f, fragVelocityMax = 1f, fragLifeMin = 1f, fragLifeMax = 1f; - public BulletType fragBullet = null; + public @Nullable BulletType fragBullet = null; public Color hitColor = Color.white; public Color trailColor = Pal.missileYellowBack; diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 540392c743..bf4236ce53 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -849,6 +849,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } + /** + * Called when a block is placed over some other blocks. This seq will always have at least one item. + * Should load some previous state, if necessary. */ + public void overwrote(Seq previous){ + + } + public void onRemoved(){ } diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index c7b07fe401..7fe708ce7d 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -198,6 +198,8 @@ public class Block extends UnlockableContent{ public boolean instantTransfer = false; /** Whether you can rotate this block with Keybind rotateplaced + Scroll Wheel. */ public boolean quickRotate = true; + /** Main subclass. Non-anonymous. */ + public @Nullable Class subclass; public Prov buildType = null; //initialized later public ObjectMap, Cons2> configurations = new ObjectMap<>(); @@ -371,7 +373,7 @@ public class Block extends UnlockableContent{ public boolean canReplace(Block other){ if(other.alwaysReplace) return true; - return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && size == other.size; + return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && (size == other.size || (size >= other.size && subclass != null && subclass == other.subclass)); } /** @return a possible replacement for this block when placed in a line by the player. */ @@ -590,6 +592,8 @@ public class Block extends UnlockableContent{ current = current.getSuperclass(); } + subclass = current; + while(buildType == null && Block.class.isAssignableFrom(current)){ //first class that is subclass of Building Class type = Structs.find(current.getDeclaredClasses(), t -> Building.class.isAssignableFrom(t) && !t.isInterface()); diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 15c7decbcf..070ddab553 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -3,18 +3,21 @@ package mindustry.world; import arc.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.gen.*; import mindustry.world.blocks.*; import mindustry.world.blocks.ConstructBlock.*; import static mindustry.Vars.*; public class Build{ + private static final IntSet tmp = new IntSet(); @Remote(called = Loc.server) public static void beginBreak(Team team, int x, int y){ @@ -36,7 +39,8 @@ public class Build{ tile.setBlock(sub, team, rotation); tile.bc().setDeconstruct(previous); - tile.build.health(tile.build.maxHealth() * prevPercent); + tile.build.health = tile.build.maxHealth * prevPercent; + Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true))); } @@ -55,11 +59,23 @@ public class Build{ Block previous = tile.block(); Block sub = ConstructBlock.get(result.size); + Seq prevBuild = new Seq<>(9); result.beforePlaceBegan(tile, previous); + tmp.clear(); + + tile.getLinkedTilesAs(result, t -> { + if(t.build != null && t.build.team == team && tmp.add(t.build.id)){ + prevBuild.add(t.build); + } + }); tile.setBlock(sub, team, rotation); - tile.bc().setConstruct(previous.size == sub.size ? previous : Blocks.air, result); + + ConstructBuild build = tile.bc(); + + build.setConstruct(previous.size == sub.size ? previous : Blocks.air, result); + build.prevBuild = prevBuild; result.placeBegan(tile, previous); @@ -110,7 +126,9 @@ public class Build{ for(int dy = 0; dy < type.size; dy++){ int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y; + Tile check = world.tile(wx, wy); + if( check == null || //nothing there (check.floor().isDeep() && !type.floating && !type.requiresWater && !type.placeableLiquid) || //deep water diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index a8893088f8..978d91fe58 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -389,19 +389,27 @@ public class Tile implements Position, QuadTreeObject, Displayable{ */ public Seq getLinkedTilesAs(Block block, Seq tmpArray){ tmpArray.clear(); + getLinkedTilesAs(block, tmpArray::add); + return tmpArray; + } + + /** + * Returns the list of all tiles linked to this multiblock if it were this block. + * The result contains all linked tiles, including this tile itself. + */ + public void getLinkedTilesAs(Block block, Cons tmpArray){ 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++){ Tile other = world.tile(x + dx + offsetx, y + dy + offsety); - if(other != null) tmpArray.add(other); + if(other != null) tmpArray.get(other); } } }else{ - tmpArray.add(this); + tmpArray.get(this); } - return tmpArray; } public Rect getHitbox(Rect rect){ diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index d6bb877be8..3cd0b5ec0f 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -5,6 +5,7 @@ import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; import arc.util.io.*; @@ -62,6 +63,7 @@ public class ConstructBlock extends Block{ if(tile == null) return; float healthf = tile.build == null ? 1f : tile.build.healthf(); + Seq prev = tile.build instanceof ConstructBuild ? ((ConstructBuild)tile.build).prevBuild : null; tile.setBlock(block, team, rotation); @@ -71,6 +73,10 @@ public class ConstructBlock extends Block{ if(config != null){ tile.build.configured(builder, config); } + + if(prev != null && prev.size > 0){ + tile.build.overwrote(prev); + } } //last builder was this local client player, call placed() @@ -126,6 +132,7 @@ public class ConstructBlock extends Block{ * If there is no recipe for this block, as is the case with rocks, 'previous' is used. */ public @Nullable Block cblock; + public @Nullable Seq prevBuild; public float progress = 0; public float buildCost; diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index 351ab3b773..f6f347aba3 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -146,6 +146,20 @@ public class Conveyor extends Block implements Autotiler{ } } + @Override + public void overwrote(Seq builds){ + if(builds.first() instanceof ConveyorBuild build){ + ids = build.ids.clone(); + xs = build.xs.clone(); + ys = build.ys.clone(); + len = build.len; + clogHeat = build.clogHeat; + lastInserted = build.lastInserted; + mid = build.mid; + minitem = build.minitem; + } + } + @Override public boolean shouldIdleSound(){ return clogHeat <= 0.5f ; @@ -161,11 +175,9 @@ public class Conveyor extends Block implements Autotiler{ blendscly = bits[2]; blending = bits[4]; - if(front() != null && front() != null){ - next = front(); - nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null; - aligned = nextc != null && rotation == next.rotation; - } + next = front(); + nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null; + aligned = nextc != null && rotation == next.rotation; } @Override @@ -220,7 +232,7 @@ public class Conveyor extends Block implements Autotiler{ if(ys[i] > 0.5 && i > 0) mid = i - 1; xs[i] = Mathf.approachDelta(xs[i], 0, speed*2); - if(ys[i] >= 1f && moveForward(ids[i])){ + if(ys[i] >= 1f && pass(ids[i])){ //align X position if passing forwards if(aligned){ nextc.xs[nextc.lastInserted] = xs[i]; @@ -242,6 +254,14 @@ public class Conveyor extends Block implements Autotiler{ noSleep(); } + public boolean pass(Item item) { + if(next != null && next.team == team && next.acceptItem(this, item)){ + next.handleItem(this, item); + return true; + } + return false; + } + @Override public int removeStack(Item item, int amount){ noSleep(); @@ -346,6 +366,9 @@ public class Conveyor extends Block implements Autotiler{ ys[i] = y; } } + + //this updates some state + updateTile(); } diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java index 009cc8fbfe..ce77b978df 100644 --- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.distribution; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; @@ -14,6 +15,7 @@ import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; import mindustry.world.blocks.*; +import mindustry.world.blocks.distribution.Conveyor.*; import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -220,6 +222,16 @@ public class StackConveyor extends Block implements Autotiler{ } } + @Override + public void overwrote(Seq builds){ + if(builds.first() instanceof ConveyorBuild build){ + Item item = build.items.first(); + if(item != null){ + handleStack(item, build.items.get(itemCapacity), null); + } + } + } + @Override public boolean shouldIdleSound(){ return false; // has no moving parts; diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java index d556f584f5..fb70751c18 100644 --- a/core/src/mindustry/world/blocks/power/Battery.java +++ b/core/src/mindustry/world/blocks/power/Battery.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.power; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.math.*; import arc.struct.*; import mindustry.annotations.Annotations.*; import mindustry.gen.*; @@ -31,5 +32,15 @@ public class Battery extends PowerDistributor{ Draw.rect(topRegion, x, y); } + + @Override + public void overwrote(Seq previous){ + for(Building other : previous){ + if(other.power != null && other.block.consumes.hasPower() && other.block.consumes.getPower().buffered){ + float amount = other.block.consumes.getPower().capacity * other.power.status; + power.status = Mathf.clamp(power.status + amount / block.consumes.getPower().capacity); + } + } + } } } diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 0aca99a0b6..29059a25c7 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -1,5 +1,6 @@ package mindustry.world.blocks.storage; +import arc.struct.*; import arc.util.ArcAnnotate.*; import mindustry.gen.*; import mindustry.type.*; @@ -40,6 +41,18 @@ public abstract class StorageBlock extends Block{ } } + @Override + public void overwrote(Seq previous){ + for(Building other : previous){ + if(other.items != null){ + items.addAll(other.items); + } + } + + //ensure item counts are not too high + items.each((i, a) -> items.set(i, Math.min(a, itemCapacity))); + } + @Override public boolean canPickup(){ return linkedCore == null; diff --git a/core/src/mindustry/world/meta/BlockGroup.java b/core/src/mindustry/world/meta/BlockGroup.java index 24e8166990..2b3434ccfb 100644 --- a/core/src/mindustry/world/meta/BlockGroup.java +++ b/core/src/mindustry/world/meta/BlockGroup.java @@ -1,5 +1,5 @@ package mindustry.world.meta; public enum BlockGroup{ - none, walls, turrets, transportation, power, liquids, drills + none, walls, turrets, transportation, power, liquids, drills, storage } diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index 7b3e4033ea..a293942592 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -180,6 +180,7 @@ public class ItemModule extends BlockModule{ return total > 0; } + @Nullable public Item first(){ for(int i = 0; i < items.length; i++){ if(items[i] > 0){ @@ -189,6 +190,7 @@ public class ItemModule extends BlockModule{ return null; } + @Nullable public Item take(){ for(int i = 0; i < items.length; i++){ int index = (i + takeRotation); @@ -204,6 +206,7 @@ public class ItemModule extends BlockModule{ } /** Begins a speculative take operation. This returns the item that would be returned by #take(), but does not change state. */ + @Nullable public Item beginTake(){ for(int i = 0; i < items.length; i++){ int index = (i + takeRotation);