From 80332e37d52a1e385a11507a2aa537fc763aa9cf Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 27 Jun 2020 19:16:39 -0400 Subject: [PATCH] Upgradeable cores --- .../revisions/BuilderMinerTrailUnit/0.json | 1 + core/assets/bundles/bundle.properties | 1 - core/src/mindustry/ai/BlockIndexer.java | 8 +- core/src/mindustry/ai/types/BuilderAI.java | 2 +- core/src/mindustry/ai/types/SuicideAI.java | 4 +- core/src/mindustry/content/Blocks.java | 4 +- core/src/mindustry/content/Fx.java | 6 ++ core/src/mindustry/core/Logic.java | 6 +- core/src/mindustry/core/NetClient.java | 8 +- core/src/mindustry/core/World.java | 14 ++-- core/src/mindustry/editor/EditorTile.java | 12 +-- .../src/mindustry/editor/MapEditorDialog.java | 4 +- core/src/mindustry/entities/Damage.java | 12 +-- core/src/mindustry/entities/Units.java | 2 +- .../mindustry/entities/comp/BuilderComp.java | 12 +-- .../mindustry/entities/comp/BuildingComp.java | 20 ++--- .../src/mindustry/entities/comp/FireComp.java | 4 +- .../mindustry/entities/comp/PayloadComp.java | 6 +- .../mindustry/entities/comp/PuddleComp.java | 2 +- .../mindustry/entities/comp/TrailComp.java | 4 +- .../src/mindustry/entities/comp/UnitComp.java | 4 +- .../entities/units/AIController.java | 4 +- core/src/mindustry/game/Schematic.java | 10 +++ core/src/mindustry/game/Schematics.java | 10 +-- .../src/mindustry/graphics/BlockRenderer.java | 16 ++-- core/src/mindustry/graphics/Trail.java | 3 +- core/src/mindustry/input/DesktopInput.java | 12 +-- core/src/mindustry/input/InputHandler.java | 8 +- core/src/mindustry/input/MobileInput.java | 8 +- core/src/mindustry/io/SaveVersion.java | 10 +-- .../io/legacy/LegacySaveVersion.java | 14 ++-- core/src/mindustry/maps/SectorDamage.java | 10 +-- .../maps/filters/RandomItemFilter.java | 2 +- .../maps/generators/BaseGenerator.java | 6 +- .../maps/generators/FileMapGenerator.java | 2 +- .../maps/planet/TODOPlanetGenerator.java | 4 +- core/src/mindustry/type/UnitType.java | 1 + .../ui/dialogs/SchematicsDialog.java | 21 +++++ .../ui/dialogs/SettingsMenuDialog.java | 1 - .../mindustry/ui/fragments/HudFragment.java | 34 +------- .../ui/fragments/PlacementFragment.java | 6 +- core/src/mindustry/world/Block.java | 15 ++-- core/src/mindustry/world/Build.java | 42 +++++++--- core/src/mindustry/world/CachedTile.java | 6 +- core/src/mindustry/world/Tile.java | 82 +++++++++++-------- .../mindustry/world/blocks/BuildBlock.java | 8 +- .../mindustry/world/blocks/defense/Wall.java | 2 +- .../blocks/defense/turrets/LaserTurret.java | 2 +- .../blocks/defense/turrets/LiquidTurret.java | 2 +- .../world/blocks/distribution/ItemBridge.java | 12 +-- .../world/blocks/distribution/MassDriver.java | 2 +- .../world/blocks/distribution/Sorter.java | 2 +- .../blocks/distribution/StackConveyor.java | 4 +- .../world/blocks/power/PowerNode.java | 4 +- .../world/blocks/storage/CoreBlock.java | 24 +++++- .../world/blocks/storage/Unloader.java | 2 +- .../world/blocks/units/UnitBlock.java | 4 +- .../world/consumers/ConsumePower.java | 2 +- .../src/mindustry/desktop/steam/SStats.java | 3 +- tests/src/test/java/ApplicationTests.java | 70 ++++++++-------- .../java/power/ItemLiquidGeneratorTests.java | 2 +- .../src/test/java/power/PowerTestFixture.java | 9 +- tests/src/test/java/power/PowerTests.java | 38 ++++----- 63 files changed, 365 insertions(+), 290 deletions(-) create mode 100644 annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json diff --git a/annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json b/annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json new file mode 100644 index 0000000000..94f48a7b63 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:int,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 6a3c4a2c68..96cf7fcb1b 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -665,7 +665,6 @@ setting.effects.name = Display Effects setting.destroyedblocks.name = Display Destroyed Blocks setting.blockstatus.name = Display Block Status setting.conveyorpathfinding.name = Conveyor Placement Pathfinding -setting.coreselect.name = Allow Schematic Cores setting.sensitivity.name = Controller Sensitivity setting.saveinterval.name = Save Interval setting.seconds = {0} seconds diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index de46e53050..8f560a4072 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -89,8 +89,8 @@ public class BlockIndexer{ for(Tile tile : world.tiles){ process(tile); - if(tile.entity != null && tile.entity.damaged()){ - notifyTileDamaged(tile.entity); + if(tile.build != null && tile.build.damaged()){ + notifyTileDamaged(tile.build); } if(tile.drop() != null) allOres.add(tile.drop()); @@ -147,7 +147,7 @@ public class BlockIndexer{ TileArray set = damagedTiles[team.id]; for(Tile tile : set){ - if((tile.entity == null || tile.entity.team() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ + if((tile.build == null || tile.build.team() != team || !tile.build.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); } } @@ -380,7 +380,7 @@ public class BlockIndexer{ GridBits bits = structQuadrant(team); //fast-set this quadrant to 'occupied' if the tile just placed is already of this team - if(tile.team() == team && tile.entity != null && tile.block().targetable){ + if(tile.team() == team && tile.build != null && tile.block().targetable){ bits.set(quadrantX, quadrantY); continue; //no need to process futher } diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index b1da5231cf..68953a8d7b 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -27,7 +27,7 @@ public class BuilderAI extends AIController{ BuildPlan req = builder.buildPlan(); boolean valid = - (req.tile().entity instanceof BuildEntity && req.tile().ent().cblock == req.block) || + (req.tile().build instanceof BuildEntity && req.tile().bc().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)); diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index 3ccb620816..57638d7597 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -38,8 +38,8 @@ public class SuicideAI extends GroundAI{ //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()){ + if(tile != null && tile.build == target) return false; + if(tile != null && tile.build != null && tile.build.team() != unit.team()){ blockedByBlock = true; return true; }else{ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 766481cb29..b127ed7407 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1270,7 +1270,7 @@ public class Blocks implements ContentList{ }}; coreFoundation = new CoreBlock("core-foundation"){{ - requirements(Category.effect, BuildVisibility.hidden, with(Items.copper, 3000, Items.lead, 3000, Items.silicon, 2000)); + requirements(Category.effect, with(Items.copper, 3000, Items.lead, 3000, Items.silicon, 2000)); health = 2000; itemCapacity = 9000; @@ -1278,7 +1278,7 @@ public class Blocks implements ContentList{ }}; coreNucleus = new CoreBlock("core-nucleus"){{ - requirements(Category.effect, BuildVisibility.hidden, with(Items.copper, 1000, Items.lead, 1000)); + requirements(Category.effect, with(Items.copper, 1000, Items.lead, 1000)); health = 4000; itemCapacity = 13000; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index d8b11b0da8..e813220290 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -144,6 +144,12 @@ public class Fx{ Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); }), + upgradeCore = new Effect(120f, e -> { + color(Color.white, Pal.accent, e.fin()); + alpha(e.fout()); + Fill.square(e.x, e.y, tilesize / 2f * e.rotation); + }), + placeBlock = new Effect(16, e -> { color(Pal.accent); stroke(3f - e.fin() * 2f); diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index e9f900a162..848749871d 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -38,11 +38,11 @@ public class Logic implements ApplicationListener{ Tile tile = event.tile; Block block = tile.block(); //skip null entities or un-rebuildables, for obvious reasons; also skip client since they can't modify these requests - if(tile.entity == null || !tile.block().rebuildable || net.client()) return; + if(tile.build == null || !tile.block().rebuildable || net.client()) return; if(block instanceof BuildBlock){ - BuildEntity entity = tile.ent(); + BuildEntity entity = tile.bc(); //update block to reflect the fact that something was being constructed if(entity.cblock != null && entity.cblock.synthetic()){ @@ -65,7 +65,7 @@ public class Logic implements ApplicationListener{ } } - data.blocks.addFirst(new BlockPlan(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.build.config())); }); Events.on(BlockBuildEndEvent.class, event -> { diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 1cb5511203..15649dafb5 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -425,11 +425,11 @@ public class NetClient implements ApplicationListener{ for(int i = 0; i < amount; i++){ int pos = input.readInt(); Tile tile = world.tile(pos); - if(tile == null || tile.entity == null){ + if(tile == null || tile.build == null){ Log.warn("Missing entity at @. Skipping block snapshot.", tile); break; } - tile.entity.readAll(Reads.get(input), tile.entity.version()); + tile.build.readAll(Reads.get(input), tile.build.version()); } }catch(Exception e){ e.printStackTrace(); @@ -457,8 +457,8 @@ public class NetClient implements ApplicationListener{ int pos = input.readInt(); Tile tile = world.tile(pos); - if(tile != null && tile.entity != null){ - tile.entity.items.read(Reads.get(input)); + if(tile != null && tile.build != null){ + tile.build.items.read(Reads.get(input)); }else{ new ItemModule().read(Reads.get(input)); } diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 476fd2760a..fb9d5585eb 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -105,7 +105,7 @@ public class World{ public Tile Building(int x, int y){ Tile tile = tiles.get(x, y); if(tile == null) return null; - if(tile.entity != null) return tile.entity.tile(); + if(tile.build != null) return tile.build.tile(); return tile; } @@ -113,14 +113,14 @@ public class World{ public Building ent(int x, int y){ Tile tile = tile(x, y); if(tile == null) return null; - return tile.entity; + return tile.build; } @Nullable public Building ent(int pos){ Tile tile = tile(pos); if(tile == null) return null; - return tile.entity; + return tile.build; } @NonNull @@ -144,8 +144,8 @@ public class World{ private void clearTileEntities(){ for(Tile tile : tiles){ - if(tile != null && tile.entity != null){ - tile.entity.remove(); + if(tile != null && tile.build != null){ + tile.build.remove(); } } } @@ -187,8 +187,8 @@ public class World{ tile.updateOcclusion(); - if(tile.entity != null){ - tile.entity.updateProximity(); + if(tile.build != null){ + tile.build.updateProximity(); } } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 386c46c644..69bfbb21fd 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -115,7 +115,7 @@ public class EditorTile extends Tile{ return; } - entity = null; + build = null; if(block == null) block = Blocks.air; if(floor == null) floor = (Floor)Blocks.air; @@ -123,11 +123,11 @@ public class EditorTile extends Tile{ Block block = block(); if(block.hasEntity()){ - entity = entityprov.get().init(this, team, false); - entity.cons(new ConsumeModule(entity)); - if(block.hasItems) entity.items(new ItemModule()); - if(block.hasLiquids) entity.liquids(new LiquidModule()); - if(block.hasPower) entity.power(new PowerModule()); + build = entityprov.get().init(this, team, false); + build.cons(new ConsumeModule(build)); + if(block.hasItems) build.items(new ItemModule()); + if(block.hasLiquids) build.liquids(new LiquidModule()); + if(block.hasPower) build.power(new PowerModule()); } } diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 562ddf3db4..c62dcfecfd 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -255,8 +255,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ world.endMapLoad(); //add entities so they update. is this really needed? for(Tile tile : world.tiles){ - if(tile.entity != null){ - tile.entity.add(); + if(tile.build != null){ + tile.build.add(); } } player.set(world.width() * tilesize/2f, world.height() * tilesize/2f); diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 05fa5167b6..f488dcbfc4 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -265,10 +265,10 @@ public class Damage{ if(scaledDamage <= 0 || tile == null) 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); + if(tile.build != null && tile.team() != team){ + int health = (int)tile.build.health(); + if(tile.build.health() > 0){ + tile.build.damage(scaledDamage); scaledDamage -= health; if(scaledDamage <= 0) continue; @@ -290,8 +290,8 @@ public class Damage{ for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.entity != null && (team == null ||team.isEnemy(tile.team())) && Mathf.dst(dx, dy) <= trad){ - tile.entity.damage(damage); + if(tile != null && tile.build != null && (team == null ||team.isEnemy(tile.team())) && Mathf.dst(dx, dy) <= trad){ + tile.build.damage(damage); } } } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 3545f21a8f..ea45bbff6f 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -93,7 +93,7 @@ public class Units{ /** Returns the neareset damaged tile. */ public static Building findDamagedTile(Team team, float x, float y){ Tile tile = Geometry.findClosest(x, y, indexer.getDamaged(team)); - return tile == null ? null : tile.entity; + return tile == null ? null : tile.build; } /** Returns the neareset ally tile in a range. */ diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 5aa351fb76..07dca1da8e 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -100,25 +100,25 @@ abstract class BuilderComp implements Unitc{ return; } - if(tile.entity instanceof BuildEntity && !current.initialized){ + if(tile.build instanceof BuildEntity && !current.initialized){ Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, team(), (Builderc)this, current.breaking))); current.initialized = true; } //if there is no core to build with or no build entity, stop building! - if((core == null && !infinite) || !(tile.entity instanceof BuildEntity)){ + if((core == null && !infinite) || !(tile.build instanceof BuildEntity)){ return; } //otherwise, update it. - BuildEntity entity = tile.ent(); + BuildEntity entity = tile.bc(); if(current.breaking){ entity.deconstruct(base(), core, 1f / entity.buildCost * Time.delta() * type().buildSpeed * state.rules.buildSpeedMultiplier); }else{ if(entity.construct(base(), core, 1f / entity.buildCost * Time.delta() * type().buildSpeed * state.rules.buildSpeedMultiplier, current.hasConfig)){ if(current.hasConfig){ - Call.onTileConfig(null, tile.entity, current.config); + Call.onTileConfig(null, tile.build, current.config); } } } @@ -190,8 +190,8 @@ abstract class BuilderComp implements Unitc{ plans.remove(replace); } Tile tile = world.tile(place.x, place.y); - if(tile != null && tile.entity instanceof BuildEntity){ - place.progress = tile.ent().progress; + if(tile != null && tile.build instanceof BuildEntity){ + place.progress = tile.bc().progress; } if(tail){ plans.addLast(place); diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index c7f795901b..c100067e2f 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -400,8 +400,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, int trns = block.size/2 + 1; Tile next = tile.getNearby(Geometry.d4(rotation()).x * trns, Geometry.d4(rotation()).y * trns); - if(next != null && next.entity != null && next.entity.team() == team && next.entity.acceptPayload(base(), todump)){ - next.entity.handlePayload(base(), todump); + if(next != null && next.build != null && next.build.team() == team && next.build.acceptPayload(base(), todump)){ + next.build.handlePayload(base(), todump); return true; } @@ -485,8 +485,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, if(next == null) return 0; - if(next.entity != null){ - return moveLiquid(next.entity, liquid); + if(next.build != null){ + return moveLiquid(next.build, liquid); }else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){ float leakAmount = liquids.get(liquid) / leakResistance; Puddles.deposit(next, tile, liquid, leakAmount); @@ -673,8 +673,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, power.graph.remove(base()); for(int i = 0; i < power.links.size; i++){ Tile other = world.tile(power.links.get(i)); - if(other != null && other.entity != null && other.entity.power != null){ - other.entity.power.links.removeValue(pos()); + if(other != null && other.build != null && other.build.power != null){ + other.build.power.links.removeValue(pos()); } } } @@ -693,7 +693,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(int i = 0; i < power.links.size; i++){ Tile link = world.tile(power.links.get(i)); - if(link != null && link.entity != null && link.entity.power != null) out.add(link.entity); + if(link != null && link.build != null && link.build.power != null) out.add(link.build); } return out; } @@ -803,8 +803,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile))); if(!tempTiles.isEmpty()){ Tile toLink = tempTiles.first(); - if(!toLink.entity.power.links.contains(pos())){ - toLink.entity.configureAny(pos()); + if(!toLink.build.power.links.contains(pos())){ + toLink.build.configureAny(pos()); } } } @@ -1125,7 +1125,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, @Replace @Override public boolean isValid(){ - return tile.entity == base() && !dead(); + return tile.build == base() && !dead(); } @Override diff --git a/core/src/mindustry/entities/comp/FireComp.java b/core/src/mindustry/entities/comp/FireComp.java index a1fc0c5111..74f5199ab6 100644 --- a/core/src/mindustry/entities/comp/FireComp.java +++ b/core/src/mindustry/entities/comp/FireComp.java @@ -49,7 +49,7 @@ abstract class FireComp implements Timedc, Posc, Firec{ return; } - Building entity = tile.entity; + Building entity = tile.build; boolean damage = entity != null; float flammability = baseFlammability + puddleFlammability; @@ -59,7 +59,7 @@ abstract class FireComp implements Timedc, Posc, Firec{ } if(baseFlammability < 0 || block != tile.block()){ - baseFlammability = tile.entity == null ? 0 : tile.entity.getFlammability(); + baseFlammability = tile.build == null ? 0 : tile.build.getFlammability(); block = tile.block(); } diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 1d81f4a198..c655180e30 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -53,9 +53,9 @@ abstract class PayloadComp implements Posc, Rotc{ 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); + if(on != null && on.build != null && on.build.acceptPayload(on.build, payload)){ + Fx.unitDrop.at(on.build); + on.build.handlePayload(on.build, payload); return true; } diff --git a/core/src/mindustry/entities/comp/PuddleComp.java b/core/src/mindustry/entities/comp/PuddleComp.java index 7da22d4b53..61eed49b69 100644 --- a/core/src/mindustry/entities/comp/PuddleComp.java +++ b/core/src/mindustry/entities/comp/PuddleComp.java @@ -80,7 +80,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{ } }); - if(liquid.temperature > 0.7f && (tile.entity != null) && Mathf.chance(0.3 * Time.delta())){ + if(liquid.temperature > 0.7f && (tile.build != null) && Mathf.chance(0.3 * Time.delta())){ Fires.create(tile); } diff --git a/core/src/mindustry/entities/comp/TrailComp.java b/core/src/mindustry/entities/comp/TrailComp.java index 84fffda8a8..420526256d 100644 --- a/core/src/mindustry/entities/comp/TrailComp.java +++ b/core/src/mindustry/entities/comp/TrailComp.java @@ -11,10 +11,12 @@ abstract class TrailComp implements Unitc{ @Import UnitType type; @Import float x, y, rotation; - transient Trail trail = new Trail(4); + transient Trail trail = new Trail(6); @Override public void update(){ + trail.length = type.trailLength; + float scale = elevation(); float offset = type.engineOffset/2f + type.engineOffset/2f*scale; diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index a8f8bf4783..9b17b9dd68 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -181,8 +181,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I if(tile != null && isGrounded()){ //unit block update - if(tile.entity != null){ - tile.entity.unitOn(base()); + if(tile.build != null){ + tile.build.unitOn(base()); } //kill when stuck in wall diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index 3d467a168e..3a9d43e2b2 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -24,12 +24,12 @@ public class AIController implements UnitController{ protected void targetClosestAllyFlag(BlockFlag flag){ Tile target = Geometry.findClosest(unit.x, unit.y, indexer.getAllied(unit.team, flag)); - if(target != null) this.target = target.entity; + if(target != null) this.target = target.build; } protected void targetClosestEnemyFlag(BlockFlag flag){ Tile target = Geometry.findClosest(unit.x, unit.y, indexer.getEnemy(unit.team, flag)); - if(target != null) this.target = target.entity; + if(target != null) this.target = target.build; } protected boolean retarget(){ diff --git a/core/src/mindustry/game/Schematic.java b/core/src/mindustry/game/Schematic.java index a650d0e01e..01088826bb 100644 --- a/core/src/mindustry/game/Schematic.java +++ b/core/src/mindustry/game/Schematic.java @@ -9,7 +9,9 @@ import mindustry.content.*; import mindustry.mod.Mods.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.power.*; import mindustry.world.blocks.storage.*; +import mindustry.world.consumers.*; import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -29,6 +31,14 @@ public class Schematic implements Publishable, Comparable{ this.height = height; } + public float powerProduction(){ + return tiles.sumf(s -> s.block instanceof PowerGenerator ? ((PowerGenerator)s.block).powerProduction : 0f); + } + + public float powerConsumption(){ + return tiles.sumf(s -> s.block.consumes.has(ConsumeType.power) ? s.block.consumes.getPower().usage : 0f); + } + public Seq requirements(){ IntIntMap amounts = new IntIntMap(); diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index cd91ae4aba..c79792728a 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -349,7 +349,7 @@ public class Schematics implements Loadable{ Building tile = world.ent(cx, cy); if(tile != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) - && (tile.block().isVisible() || (tile.block() instanceof CoreBlock && Core.settings.getBool("coreselect")))){ + && (tile.block().isVisible() || (tile.block() instanceof CoreBlock))){ Object config = tile.config(); tiles.add(new Stile(tile.block(), tile.tileX() + offsetX, tile.tileY() + offsetY, config, (byte)tile.rotation())); @@ -388,8 +388,8 @@ public class Schematics implements Loadable{ tile.rotation(st.rotation); Object config = st.config; - if(tile.entity != null){ - tile.entity.configureAny(config); + if(tile.build != null){ + tile.build.configureAny(config); } if(st.block instanceof Drill){ @@ -408,8 +408,8 @@ public class Schematics implements Loadable{ tile.rotation(st.rotation); Object config = st.config; - if(tile.entity != null){ - tile.entity.configureAny(config); + if(tile.build != null){ + tile.build.configureAny(config); } }); } diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 1d72a650cc..5d00e88900 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -192,21 +192,21 @@ public class BlockRenderer implements Disposable{ Tile tile = world.rawTile(x, y); Block block = tile.block(); //link to center - if(tile.entity != null) tile = tile.entity.tile(); + if(tile.build != null) tile = tile.build.tile(); - if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.entity == null || !processedEntities.contains(tile.entity.id()))){ + if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id()))){ if(block.expanded || !expanded){ tileview.add(tile); - if(tile.entity != null) processedEntities.add(tile.entity.id()); + if(tile.build != null) processedEntities.add(tile.build.id()); } //lights are drawn even in the expanded range - if(tile.entity != null){ + if(tile.build != null){ lightview.add(tile); } - if(tile.entity != null && tile.entity.power != null && tile.entity.power.links.size > 0){ - for(Building other : tile.entity.getPowerConnections(outArray2)){ + if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){ + for(Building other : tile.build.getPowerConnections(outArray2)){ if(other.block() instanceof PowerNode){ //TODO need a generic way to render connections! tileview.add(other.tile()); } @@ -229,7 +229,7 @@ public class BlockRenderer implements Disposable{ for(int i = 0; i < tileview.size; i++){ Tile tile = tileview.items[i]; Block block = tile.block(); - Building entity = tile.entity; + Building entity = tile.build; Draw.z(Layer.block); @@ -260,7 +260,7 @@ public class BlockRenderer implements Disposable{ //draw lights for(int i = 0; i < lightview.size; i++){ Tile tile = lightview.items[i]; - Building entity = tile.entity; + Building entity = tile.build; if(entity != null){ entity.drawLight(); diff --git a/core/src/mindustry/graphics/Trail.java b/core/src/mindustry/graphics/Trail.java index f582861174..e48cdda550 100644 --- a/core/src/mindustry/graphics/Trail.java +++ b/core/src/mindustry/graphics/Trail.java @@ -8,7 +8,8 @@ import arc.struct.*; import arc.util.pooling.*; public class Trail{ - private final int length; + public int length; + private final Seq points; private float lastX = -1, lastY = -1; diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index f3c54b591a..04ccf40bec 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -272,8 +272,8 @@ public class DesktopInput extends InputHandler{ Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY()); if(cursor != null){ - if(cursor.entity != null){ - cursorType = cursor.entity.getCursor(); + if(cursor.build != null){ + cursorType = cursor.build.getCursor(); } if(isPlacing() || !selectRequests.isEmpty()){ @@ -292,8 +292,8 @@ public class DesktopInput extends InputHandler{ cursorType = ui.unloadCursor; } - if(cursor.entity != null && cursor.interactable(player.team()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ - Call.rotateBlock(player, cursor.entity, Core.input.axisTap(Binding.rotate) > 0); + if(cursor.build != null && cursor.interactable(player.team()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ + Call.rotateBlock(player, cursor.build, Core.input.axisTap(Binding.rotate) > 0); } } @@ -445,7 +445,7 @@ public class DesktopInput extends InputHandler{ deleting = true; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected.entity) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().plans().size == 0 || !player.builder().isBuilding()) && !droppingItem && + if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().plans().size == 0 || !player.builder().isBuilding()) && !droppingItem && !tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){ isShooting = shouldShoot; } @@ -494,7 +494,7 @@ public class DesktopInput extends InputHandler{ removeSelection(selectX, selectY, cursorX, cursorY); } - tryDropItems(selected == null ? null : selected.entity, Core.input.mouseWorld().x, Core.input.mouseWorld().y); + tryDropItems(selected == null ? null : selected.build, Core.input.mouseWorld().x, Core.input.mouseWorld().y); if(sreq != null){ if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 489aece735..60bfcf2101 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -85,11 +85,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(called = Loc.server, unreliable = true) public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){ - if(tile == null || tile.entity == null || tile.entity.items == null) return; + if(tile == null || tile.build == null || tile.build.items == null) return; for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, tile, () -> {})); } - tile.entity.items.add(item, amount); + tile.build.items.add(item, amount); } public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){ @@ -327,7 +327,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public boolean requestMatches(BuildPlan request){ Tile tile = world.tile(request.x, request.y); - return tile != null && tile.block() instanceof BuildBlock && tile.ent().cblock == request.block; + return tile != null && tile.block() instanceof BuildBlock && tile.bc().cblock == request.block; } public void drawBreaking(int x, int y){ @@ -925,7 +925,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void breakBlock(int x, int y){ Tile tile = world.tile(x, y); //TODO hacky - if(tile != null && tile.entity != null) tile = tile.entity.tile(); + if(tile != null && tile.build != null) tile = tile.build.tile(); player.builder().addBuild(new BuildPlan(tile.x, tile.y)); } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 1b1c301632..df4c3f0935 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -496,9 +496,9 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Tile tile = tileAt(screenX, screenY); - if(tile == null || tile.entity == null) return false; + if(tile == null || tile.build == null) return false; - tryDropItems(tile.entity, Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y); + tryDropItems(tile.build, Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y); } return false; } @@ -542,7 +542,7 @@ public class MobileInput extends InputHandler implements GestureListener{ //ignore off-screen taps if(cursor == null || Core.scene.hasMouse(x, y)) return false; - Tile linked = cursor.entity == null ? cursor : cursor.entity.tile(); + Tile linked = cursor.build == null ? cursor : cursor.build.tile(); checkTargets(worldx, worldy); @@ -555,7 +555,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else if(mode == breaking && validBreak(linked.x,linked.y) && !hasRequest(linked)){ //add to selection queue if it's a valid BREAK position selectRequests.add(new BuildPlan(linked.x, linked.y)); - }else if(!canTapPlayer(worldx, worldy) && !tileTapped(linked.entity)){ + }else if(!canTapPlayer(worldx, worldy) && !tileTapped(linked.build)){ tryBeginMine(cursor); } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 0e106b4c3a..b37f1e0dbe 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -164,15 +164,15 @@ public abstract class SaveVersion extends SaveFileReader{ stream.writeShort(tile.blockID()); //make note of whether there was an entity here - stream.writeBoolean(tile.entity != null); + stream.writeBoolean(tile.build != null); //only write the entity for multiblocks once - in the center - if(tile.entity != null){ + if(tile.build != null){ if(tile.isCenter()){ stream.writeBoolean(true); writeChunk(stream, true, out -> { - out.writeByte(tile.entity.version()); - tile.entity.writeAll(Writes.get(out)); + out.writeByte(tile.build.version()); + tile.build.writeAll(Writes.get(out)); }); }else{ stream.writeBoolean(false); @@ -249,7 +249,7 @@ public abstract class SaveVersion extends SaveFileReader{ try{ readChunk(stream, true, in -> { byte revision = in.readByte(); - tile.entity.readAll(Reads.get(in), revision); + tile.build.readAll(Reads.get(in), revision); }); }catch(Throwable e){ throw new IOException("Failed to read tile entity of block: " + block, e); diff --git a/core/src/mindustry/io/legacy/LegacySaveVersion.java b/core/src/mindustry/io/legacy/LegacySaveVersion.java index cd52d131f4..3af8e1fcb5 100644 --- a/core/src/mindustry/io/legacy/LegacySaveVersion.java +++ b/core/src/mindustry/io/legacy/LegacySaveVersion.java @@ -54,7 +54,7 @@ public abstract class LegacySaveVersion extends SaveVersion{ if(block == null) block = Blocks.air; //occupied by multiblock part - boolean occupied = tile.entity != null && !tile.isCenter() && (tile.entity.block() == block || block == Blocks.air); + boolean occupied = tile.build != null && !tile.isCenter() && (tile.build.block() == block || block == Blocks.air); //do not override occupied cells if(!occupied){ @@ -66,7 +66,7 @@ public abstract class LegacySaveVersion extends SaveVersion{ readChunk(stream, true, in -> { byte version = in.readByte(); //legacy impl of Building#read() - tile.entity.health(stream.readUnsignedShort()); + tile.build.health(stream.readUnsignedShort()); byte packedrot = stream.readByte(); byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot); byte rotation = Pack.rightByte(packedrot); @@ -74,13 +74,13 @@ public abstract class LegacySaveVersion extends SaveVersion{ tile.setTeam(Team.get(team)); tile.rotation(rotation); - if(tile.entity.items != null) tile.entity.items.read(Reads.get(stream)); - if(tile.entity.power != null) tile.entity.power.read(Reads.get(stream)); - if(tile.entity.liquids != null) tile.entity.liquids.read(Reads.get(stream)); - if(tile.entity.cons() != null) tile.entity.cons().read(Reads.get(stream)); + if(tile.build.items != null) tile.build.items.read(Reads.get(stream)); + if(tile.build.power != null) tile.build.power.read(Reads.get(stream)); + if(tile.build.liquids != null) tile.build.liquids.read(Reads.get(stream)); + if(tile.build.cons() != null) tile.build.cons().read(Reads.get(stream)); //read only from subclasses! - tile.entity.read(Reads.get(in), version); + tile.build.read(Reads.get(in), version); }); }catch(Throwable e){ throw new IOException("Failed to read tile entity of block: " + block, e); diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java index 7d923313ef..d595705f84 100644 --- a/core/src/mindustry/maps/SectorDamage.java +++ b/core/src/mindustry/maps/SectorDamage.java @@ -47,16 +47,16 @@ public class SectorDamage{ float resultDamage = currDamage; //damage the tile if it's not friendly - if(other.entity != null && other.team() != state.rules.waveTeam){ - resultDamage -= other.entity.health(); + if(other.build != null && other.team() != state.rules.waveTeam){ + resultDamage -= other.build.health(); if(direct){ - other.entity.damage(currDamage); + other.build.damage(currDamage); }else{ //indirect damage happens at game load time - other.entity.health(other.entity.health() - currDamage); + other.build.health(other.build.health() - currDamage); //remove the block when destroyed - if(other.entity.health() < 0){ + if(other.build.health() < 0){ //rubble currently disabled //if(!other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){ // Effects.rubble(other.entity.x(), other.entity.y(), other.block().size); diff --git a/core/src/mindustry/maps/filters/RandomItemFilter.java b/core/src/mindustry/maps/filters/RandomItemFilter.java index d31c6f40ae..4c9537eca4 100644 --- a/core/src/mindustry/maps/filters/RandomItemFilter.java +++ b/core/src/mindustry/maps/filters/RandomItemFilter.java @@ -21,7 +21,7 @@ public class RandomItemFilter extends GenerateFilter{ if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ for(ItemStack stack : drops){ if(Mathf.chance(chance)){ - tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); + tile.build.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); } } } diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index f5e3516f7e..3d8f11c4c2 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -63,7 +63,7 @@ public class BaseGenerator{ 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) - Building entity = tile.entity; + Building entity = tile.build; for(Item item : content.items()){ entity.items.add(item, entity.block().itemCapacity); } @@ -130,9 +130,11 @@ public class BaseGenerator{ } public void postGenerate(){ + if(tiles == null) return; + for(Tile tile : tiles){ if(tile.isCenter() && tile.block() instanceof PowerNode){ - tile.entity.placed(); + tile.build.placed(); } } } diff --git a/core/src/mindustry/maps/generators/FileMapGenerator.java b/core/src/mindustry/maps/generators/FileMapGenerator.java index 50c89870f2..72daf1aec5 100644 --- a/core/src/mindustry/maps/generators/FileMapGenerator.java +++ b/core/src/mindustry/maps/generators/FileMapGenerator.java @@ -34,7 +34,7 @@ public class FileMapGenerator implements WorldGenerator{ if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock) && state.hasSector()){ for(Content content : state.getSector().data.resources){ if(content instanceof Item && Mathf.chance(0.3)){ - tile.entity.items.add((Item)content, Math.min(Mathf.random(500), tile.block().itemCapacity)); + tile.build.items.add((Item)content, Math.min(Mathf.random(500), tile.block().itemCapacity)); } } } diff --git a/core/src/mindustry/maps/planet/TODOPlanetGenerator.java b/core/src/mindustry/maps/planet/TODOPlanetGenerator.java index a3478e5e7a..35cdb3cc88 100644 --- a/core/src/mindustry/maps/planet/TODOPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/TODOPlanetGenerator.java @@ -293,6 +293,8 @@ public class TODOPlanetGenerator extends PlanetGenerator{ @Override public void postGenerate(Tiles tiles){ - basegen.postGenerate(); + if(sector.hasEnemyBase()){ + basegen.postGenerate(); + } } } diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 24f42fe2b8..3a11ab7f4d 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -64,6 +64,7 @@ public class UnitType extends UnlockableContent{ public Color lightColor = Pal.powerLight; public boolean drawCell = true, drawItems = true; public int parts = 0; + public int trailLength = 5; public ObjectSet immunities = new ObjectSet<>(); public Sound deathSound = Sounds.bang; diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index cef884e13a..ea4f4b4708 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -4,6 +4,7 @@ import arc.*; import arc.graphics.*; import arc.graphics.Texture.*; import arc.graphics.g2d.*; +import arc.math.*; import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.ImageButton.*; @@ -348,6 +349,26 @@ public class SchematicsDialog extends BaseDialog{ } } }); + cont.row(); + float cons = schem.powerConsumption(), prod = schem.powerProduction(); + if(!Mathf.zero(cons) || !Mathf.zero(prod)){ + cont.table(t -> { + + if(!Mathf.zero(prod)){ + t.image(Icon.powerSmall).color(Pal.powerLight).padRight(3); + t.add("+" + Strings.autoFixed(prod, 2)).color(Pal.powerLight).left(); + + if(!Mathf.zero(cons)){ + t.add().width(15); + } + } + + if(!Mathf.zero(cons)){ + t.image(Icon.powerSmall).color(Pal.remove).padRight(3); + t.add("-" + Strings.autoFixed(cons, 2)).color(Pal.remove).left(); + } + }); + } show(); } diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index d215c44a82..e1f77fbd4e 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -238,7 +238,6 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("savecreate", true); game.checkPref("blockreplace", true); game.checkPref("conveyorpathfinding", true); - game.checkPref("coreselect", false); game.checkPref("hints", true); if(!mobile){ game.checkPref("buildautopause", false); diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 6d6693be17..c731f1dcae 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -68,10 +68,7 @@ public class HudFragment extends Fragment{ cont.top().left(); if(mobile){ - - { - Table select = new Table(); - + cont.table(select -> { select.left(); select.defaults().size(dsize).left(); @@ -118,28 +115,7 @@ public class HudFragment extends Fragment{ }); select.image().color(Pal.gray).width(4f).fillY(); - - float size = Scl.scl(dsize); - Seq children = new Seq<>(select.getChildren()); - - //now, you may be wondering, why is this necessary? the answer is, I don't know, but it fixes layout issues somehow - int index = 0; - for(Element elem : children){ - int fi = index++; - parent.addChild(elem); - elem.visible(() -> { - if(fi < 5){ - elem.setSize(size); - }else{ - elem.setSize(Scl.scl(4f), size); - } - elem.setPosition(fi * size, Core.graphics.getHeight(), Align.topLeft); - return true; - }); - } - - cont.add().size(dsize * 5 + 3, dsize).left(); - } + }); cont.row(); cont.image().height(4f).color(Pal.gray).fillX(); @@ -363,10 +339,8 @@ public class HudFragment extends Fragment{ parent.fill(t -> { t.bottom().visible(() -> state.isCampaign() && player.team().core() != null); - t.button("test launch", Icon.warning, () -> { - ui.planet.show(state.getSector(), player.team().core()); - }).width(150f) - .disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements)); //disable core when missing resources for launch + t.button("test launch", Icon.warning, () -> ui.planet.show(state.getSector(), player.team().core())) + .width(150f).disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements)); //disable core when missing resources for launch }); blockfrag.build(parent); diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 5f2bdcd901..671b6d4f8a 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -450,9 +450,9 @@ public class PlacementFragment extends Fragment{ Tile hoverTile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); if(hoverTile != null){ //if the tile has an entity, display it - if(hoverTile.entity != null){ - hoverTile.entity.updateFlow(true); - return hoverTile.entity; + if(hoverTile.build != null){ + hoverTile.build.updateFlow(true); + return hoverTile.build; } //if the tile has a drop, display the drop diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 5aa3ec62a3..25e5b5580d 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -198,8 +198,8 @@ public class Block extends UnlockableContent{ public void drawBase(Tile tile){ //delegates to entity unless it is null - if(tile.entity != null){ - tile.entity.draw(); + if(tile.build != null){ + tile.build.draw(); }else{ Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.rotation * 90 : 0); } @@ -255,11 +255,11 @@ public class Block extends UnlockableContent{ } public TextureRegion getDisplayIcon(Tile tile){ - return tile.entity == null ? icon(Cicon.medium) : tile.entity.getDisplayIcon(); + return tile.build == null ? icon(Cicon.medium) : tile.build.getDisplayIcon(); } public String getDisplayName(Tile tile){ - return tile.entity == null ? localizedName : tile.entity.getDisplayName(); + return tile.build == null ? localizedName : tile.build.getDisplayName(); } /** @return a custom minimap color for this or 0 to use default colors. */ @@ -333,7 +333,7 @@ public class Block extends UnlockableContent{ } public boolean canReplace(Block other){ - return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group; + return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && size == other.size; } /** @return a possible replacement for this block when placed in a line by the player. */ @@ -479,6 +479,11 @@ public class Block extends UnlockableContent{ return isVisible() && buildPlaceability.placeable() && !state.rules.bannedBlocks.contains(this); } + /** Called when building of this block begins. */ + public void placeBegan(Tile tile, Block previous){ + + } + /** @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(); diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 0c9e92707b..d2b10c8e50 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -3,6 +3,7 @@ package mindustry.world; import arc.*; import arc.math.*; import arc.math.geom.*; +import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; @@ -25,8 +26,8 @@ public class Build{ //this should never happen, but it doesn't hurt to check for links float prevPercent = 1f; - if(tile.entity != null){ - prevPercent = tile.entity.healthf(); + if(tile.build != null){ + prevPercent = tile.build.healthf(); } int rotation = tile.rotation(); @@ -34,8 +35,8 @@ public class Build{ Block sub = BuildBlock.get(previous.size); tile.setBlock(sub, team, rotation); - tile.ent().setDeconstruct(previous); - tile.entity.health(tile.entity.maxHealth() * prevPercent); + tile.bc().setDeconstruct(previous); + tile.build.health(tile.build.maxHealth() * prevPercent); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true))); } @@ -56,7 +57,9 @@ public class Build{ Block sub = BuildBlock.get(result.size); tile.setBlock(sub, team, rotation); - tile.ent().setConstruct(previous, result); + tile.bc().setConstruct(previous, result); + + result.placeBegan(tile, previous); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); } @@ -80,14 +83,33 @@ public class Build{ if(tile == null) return false; - //ca check + //campaign darkness check if(world.getDarkness(x, y) >= 3){ return false; } if(type.isMultiblock()){ - if((type.canReplace(tile.block()) || (tile.block instanceof BuildBlock && tile.ent().cblock == type)) && tile.block().size == type.size && type.canPlaceOn(tile, team) && tile.interactable(team)){ - return true; + if((type.canReplace(tile.block()) || (tile.block instanceof BuildBlock && tile.bc().cblock == type)) && + type.canPlaceOn(tile, team) && tile.interactable(team)){ + + //if the block can be replaced but the sizes differ, check all the spaces around the block to make sure it can fit + if(type.size != tile.block().size){ + int offsetx = -(type.size - 1) / 2; + int offsety = -(type.size - 1) / 2; + + //this does not check *all* the conditions for placeability yet + for(int dx = 0; dx < type.size; dx++){ + for(int dy = 0; dy < type.size; dy++){ + int wx = dx + offsetx + x, wy = dy + offsety + y; + + Tile check = world.tile(wx, wy); + if(check == null || (!check.block.alwaysReplace && check.block != tile.block)) return false; + } + } + } + + //make sure that the new block can fit the old one + return type.bounds(x, y, Tmp.r1).grow(0.01f).contains(tile.block.bounds(tile.centerX(), tile.centerY(), Tmp.r2)); } //TODO should water blocks be placeable here? @@ -106,7 +128,7 @@ public class Build{ Tile other = world.tile(x + dx + offsetx, y + dy + offsety); if( other == null || - (other.block() != Blocks.air && !other.block().alwaysReplace) || + !other.block().alwaysReplace || !other.floor().placeableOn || (other.floor().isDeep() && !type.floating && !type.requiresWater) || (type.requiresWater && tile.floor().liquidDrop != Liquids.water) @@ -122,7 +144,7 @@ public class Build{ && (!tile.floor().isDeep() || type.floating || type.requiresWater) && tile.floor().placeableOn && (!type.requiresWater || tile.floor().liquidDrop == Liquids.water) - && (((type.canReplace(tile.block()) || (tile.block instanceof BuildBlock && tile.ent().cblock == type)) + && (((type.canReplace(tile.block()) || (tile.block instanceof BuildBlock && tile.bc().cblock == type)) && !(type == tile.block() && rotation == tile.rotation() && type.rotate)) || tile.block().alwaysReplace || tile.block() == Blocks.air) && tile.block().isMultiblock() == type.isMultiblock() && type.canPlaceOn(tile, team); } diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index 7fab1ad5bd..7f436abac0 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -22,19 +22,19 @@ public class CachedTile extends Tile{ @Override protected void changeEntity(Team team, Prov entityprov){ - entity = null; + build = null; Block block = block(); if(block.hasEntity()){ Building n = entityprov.get(); - n.cons(new ConsumeModule(entity)); + n.cons(new ConsumeModule(build)); n.tile(this); n.block(block); if(block.hasItems) n.items(new ItemModule()); if(block.hasLiquids) n.liquids(new LiquidModule()); if(block.hasPower) n.power(new PowerModule()); - entity = n; + build = n; } } } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index fea2276823..371e522a40 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -24,7 +24,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ /** Tile traversal cost. */ public short cost = 1; /** Tile entity, usually null. */ - public @Nullable Building entity; + public @Nullable Building build; public short x, y; protected @NonNull Block block; protected @NonNull Floor floor; @@ -105,9 +105,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{ return -1; } + /** Convenience method that returns the building of this tile with a cast. + * Method name is shortened to prevent conflict. */ @SuppressWarnings("unchecked") - public T ent(){ - return (T)entity; + public T bc(){ + return (T)build; } public float worldx(){ @@ -148,17 +150,25 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public Team team(){ - return entity == null ? Team.derelict : entity.team(); + return build == null ? Team.derelict : build.team(); } public void setTeam(Team team){ - if(entity != null){ - entity.team(team); + if(build != null){ + build.team(team); } } public boolean isCenter(){ - return entity == null || entity.tile() == this; + return build == null || build.tile() == this; + } + + public int centerX(){ + return build == null ? x : build.tile.x; + } + + public int centerY(){ + return build == null ? y : build.tile.y; } public byte getTeamID(){ @@ -177,15 +187,15 @@ public class Tile implements Position, QuadTreeObject, Displayable{ preChanged(); changeEntity(team, entityprov); - if(entity != null){ - entity.team(team); + if(build != null){ + build.team(team); } //set up multiblock if(block.isMultiblock()){ int offsetx = -(block.size - 1) / 2; int offsety = -(block.size - 1) / 2; - Building entity = this.entity; + Building entity = this.build; Block block = this.block; //two passes: first one clears, second one sets @@ -204,7 +214,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ }else{ //second pass: assign changed data //assign entity and type to blocks, so they act as proxies for this one - other.entity = entity; + other.build = entity; other.block = block; } } @@ -213,7 +223,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } } - this.entity = entity; + this.build = entity; this.block = block; } @@ -235,8 +245,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{ this.overlay = (Floor)Blocks.air; recache(); - if(entity != null){ - entity.onProximityUpdate(); + if(build != null){ + build.onProximityUpdate(); } } @@ -342,7 +352,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public boolean solid(){ - return block.solid || (entity != null && entity.checkSolid()); + return block.solid || (build != null && build.checkSolid()); } public boolean breakable(){ @@ -497,15 +507,15 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } protected void preChanged(){ - if(entity != null){ + if(build != null){ //only call removed() for the center block - this only gets called once. - entity.onRemoved(); - entity.removeFromProximity(); + build.onRemoved(); + build.removeFromProximity(); //remove this tile's dangling entities - if(entity.block().isMultiblock()){ - int cx = entity.tileX(), cy = entity.tileY(); - int size = entity.block.size; + if(build.block().isMultiblock()){ + int cx = build.tileX(), cy = build.tileY(); + int size = build.block.size; int offsetx = -(size - 1) / 2; int offsety = -(size - 1) / 2; for(int dx = 0; dx < size; dx++){ @@ -514,7 +524,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ if(other != null){ //reset entity and block *manually* - thus, preChanged() will not be called anywhere else, for multiblocks if(other != this){ //do not remove own entity so it can be processed in changed() - other.entity = null; + other.build = null; other.block = Blocks.air; //manually call changed event @@ -535,10 +545,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } protected void changeEntity(Team team, Prov entityprov){ - if(entity != null){ - int size = entity.block.size; - entity.remove(); - entity = null; + if(build != null){ + int size = build.block.size; + build.remove(); + build = null; //update edge entities tileSet.clear(); @@ -557,14 +567,14 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } if(block.hasEntity()){ - entity = entityprov.get().init(this, team, block.update); + build = entityprov.get().init(this, team, block.update); } } protected void changed(){ if(!world.isGenerating()){ - if(entity != null){ - entity.updateProximity(); + if(build != null){ + build.updateProximity(); }else{ //since the entity won't update proximity for us, update proximity for all nearby tiles manually for(Point2 p : Geometry.d4){ @@ -609,7 +619,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ @Override public String toString(){ - return floor.name + ":" + block.name + ":" + overlay + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass().getSimpleName())) + ":" + team(); + return floor.name + ":" + block.name + ":" + overlay + "[" + x + "," + y + "] " + "entity=" + (build == null ? "null" : (build.getClass().getSimpleName())) + ":" + team(); } //remote utility methods @@ -632,18 +642,18 @@ public class Tile implements Position, QuadTreeObject, Displayable{ @Remote(called = Loc.server, unreliable = true) public static void onTileDamage(Tile tile, float health){ - if(tile.entity != null){ - tile.entity.health = health; + if(tile.build != null){ + tile.build.health = health; - if(tile.entity.damaged()){ - indexer.notifyTileDamaged(tile.entity); + if(tile.build.damaged()){ + indexer.notifyTileDamaged(tile.build); } } } @Remote(called = Loc.server) public static void onTileDestroyed(Tile tile){ - if(tile.entity == null) return; - tile.entity.killed(); + if(tile.build == null) return; + tile.build.killed(); } } diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index a1361c5942..ab7267ab60 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -59,13 +59,13 @@ public class BuildBlock extends Block{ @Remote(called = Loc.server) public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; - float healthf = tile.entity.healthf(); + float healthf = tile.build.healthf(); tile.setBlock(block, team, rotation); - tile.entity.health(block.health * healthf); + tile.build.health(block.health * healthf); //last builder was this local client player, call placed() if(!headless && builderID == player.unit().id()){ if(!skipConfig){ - tile.entity.playerPlaced(); + tile.build.playerPlaced(); } } Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size); @@ -97,7 +97,7 @@ public class BuildBlock extends Block{ public static void constructed(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ Call.onConstructFinish(tile, block, builderID, rotation, team, skipConfig); - tile.entity.placed(); + tile.build.placed(); Events.fire(new BlockBuildEndEvent(tile, Groups.unit.getByID(builderID), team, false)); if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); diff --git a/core/src/mindustry/world/blocks/defense/Wall.java b/core/src/mindustry/world/blocks/defense/Wall.java index 201d8b51e3..6411640356 100644 --- a/core/src/mindustry/world/blocks/defense/Wall.java +++ b/core/src/mindustry/world/blocks/defense/Wall.java @@ -39,7 +39,7 @@ public class Wall extends Block{ @Override public boolean canReplace(Block other){ - return super.canReplace(other) && health > other.health; + return super.canReplace(other) && health > other.health && size == other.size; } public class WallEntity extends Building{ diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java index 3f8ab62acb..4eee57f8f0 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -101,7 +101,7 @@ public class LaserTurret extends PowerTurret{ @Override protected void bullet(BulletType type, float angle){ - bullet = type.create(tile.entity, team, x + tr.x, y + tr.y, angle); + bullet = type.create(tile.build, team, x + tr.x, y + tr.y, angle); bulletLife = shootDuration; } diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 8e495ebac1..ec54d28e90 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -93,7 +93,7 @@ public class LiquidTurret extends Turret{ shootSound.at(tile); if(shootShake > 0){ - Effects.shake(shootShake, shootShake, tile.entity); + Effects.shake(shootShake, shootShake, tile.build); } recoil = recoilAmount; diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index e3f425ec43..add5bdd595 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -112,7 +112,7 @@ public class ItemBridge extends Block{ return false; } - return (other.block() == tile.block() || (!(tile.block() instanceof ItemBridge) && other.block() == this)) && (other.team() == tile.team() || tile.block() != this) && (!checkDouble || other.ent().link != tile.pos()); + return (other.block() == tile.block() || (!(tile.block() instanceof ItemBridge) && other.block() == this)) && (other.team() == tile.team() || tile.block() != this) && (!checkDouble || other.bc().link != tile.pos()); } public Tile findLink(int x, int y){ @@ -134,7 +134,7 @@ public class ItemBridge extends Block{ public void playerPlaced(){ Tile link = findLink(tile.x, tile.y); if(linkValid(tile, link)){ - link.entity.configure(tile.pos()); + link.build.configure(tile.pos()); } lastPlaced = tile.pos(); @@ -154,7 +154,7 @@ public class ItemBridge extends Block{ private void drawInput(Tile other){ if(!linkValid(tile, other, false)) return; boolean linked = other.pos() == link; - if(!linked && !(other.ent().link == tile.pos())) return; + if(!linked && !(other.bc().link == tile.pos())) return; Tmp.v2.trns(tile.angleTo(other), 2f); float tx = tile.drawx(), ty = tile.drawy(); @@ -227,7 +227,7 @@ public class ItemBridge extends Block{ while(it.hasNext){ int i = it.next(); Tile other = world.tile(i); - if(!linkValid(tile, other, false) || other.ent().link != tile.pos()){ + if(!linkValid(tile, other, false) || other.bc().link != tile.pos()){ it.remove(); } } @@ -245,7 +245,7 @@ public class ItemBridge extends Block{ dump(); uptime = 0f; }else{ - ((ItemBridgeEntity)other.entity).incoming.add(tile.pos()); + ((ItemBridgeEntity)other.build).incoming.add(tile.pos()); if(consValid() && Mathf.zero(1f - efficiency())){ uptime = Mathf.lerpDelta(uptime, 1f, 0.04f); @@ -253,7 +253,7 @@ public class ItemBridge extends Block{ uptime = Mathf.lerpDelta(uptime, 0f, 0.02f); } - updateTransport(other.entity); + updateTransport(other.build); } } diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index cbaf9038de..081a1ba856 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -290,7 +290,7 @@ public class MassDriver extends Block{ protected boolean shooterValid(Tile other){ if(other == null) return true; if(!(other.block() instanceof MassDriver)) return false; - MassDriverEntity entity = other.ent(); + MassDriverEntity entity = other.bc(); return entity.link == tile.pos() && tile.dst(other) <= range; } diff --git a/core/src/mindustry/world/blocks/distribution/Sorter.java b/core/src/mindustry/world/blocks/distribution/Sorter.java index bdaf15d101..4a9e5a5590 100644 --- a/core/src/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/mindustry/world/blocks/distribution/Sorter.java @@ -44,7 +44,7 @@ public class Sorter extends Block{ @Override public int minimapColor(Tile tile){ - return tile.ent().sortItem == null ? 0 : tile.ent().sortItem.color.rgba(); + return tile.bc().sortItem == null ? 0 : tile.bc().sortItem.color.rgba(); } public class SorterEntity extends Building{ diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java index f479765b66..abd62e28bf 100644 --- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java @@ -52,8 +52,8 @@ public class StackConveyor extends Block implements Autotiler{ @Override public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){ - if(tile.entity instanceof StackConveyorEntity){ - int state = ((StackConveyorEntity)tile.entity).state; + if(tile.build instanceof StackConveyorEntity){ + int state = ((StackConveyorEntity)tile.build).state; if(state == stateLoad){ //standard conveyor mode return otherblock.outputsItems() && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock); }else if(state == stateUnload){ //router mode diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 858408f56c..bf74d08c21 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -178,8 +178,8 @@ public class PowerNode extends PowerBlock{ tempTileEnts.clear(); graphs.clear(); - if(tile.entity != null && tile.entity.power != null){ - graphs.add(tile.entity.power.graph); + if(tile.build != null && tile.build.power != null){ + graphs.add(tile.build.power.graph); } Geometry.circle(tile.x, tile.y, (int)(laserRange + 2), (x, y) -> { diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 9b2db5e040..dbfbf3f400 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -10,6 +10,7 @@ import arc.util.ArcAnnotate.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -52,7 +53,7 @@ public class CoreBlock extends StorageBlock{ public static void onPlayerSpawn(Tile tile, Player player){ if(player == null || tile == null) return; - CoreEntity entity = tile.ent(); + CoreEntity entity = tile.bc(); CoreBlock block = (CoreBlock)tile.block(); Fx.spawn.at(entity); @@ -91,6 +92,27 @@ public class CoreBlock extends StorageBlock{ return false; } + @Override + public boolean canReplace(Block other){ + //coreblocks can upgrade smaller cores + return super.canReplace(other) || (other instanceof CoreBlock && size > other.size); + } + + @Override + public boolean canPlaceOn(Tile tile, Team team){ + return canReplace(tile.block()); + } + + @Override + public void placeBegan(Tile tile, Block previous){ + //finish placement immediately when a block is replaced. + if(previous instanceof CoreBlock){ + tile.setBlock(this, tile.team()); + Fx.placeBlock.at(tile, tile.block().size); + Fx.upgradeCore.at(tile, tile.block().size); + } + } + public class CoreEntity extends Building 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 diff --git a/core/src/mindustry/world/blocks/storage/Unloader.java b/core/src/mindustry/world/blocks/storage/Unloader.java index c6e2fb2132..080c5d3627 100644 --- a/core/src/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/mindustry/world/blocks/storage/Unloader.java @@ -82,7 +82,7 @@ public class Unloader extends Block{ @Override public void buildConfiguration(Table table){ - ItemSelection.buildTable(table, content.items(), () -> tile.ent().sortItem, item -> configure(item)); + ItemSelection.buildTable(table, content.items(), () -> tile.bc().sortItem, item -> configure(item)); } @Override diff --git a/core/src/mindustry/world/blocks/units/UnitBlock.java b/core/src/mindustry/world/blocks/units/UnitBlock.java index 6702bcaa58..6056798de3 100644 --- a/core/src/mindustry/world/blocks/units/UnitBlock.java +++ b/core/src/mindustry/world/blocks/units/UnitBlock.java @@ -26,8 +26,8 @@ public class UnitBlock extends PayloadAcceptor{ @Remote(called = Loc.server) public static void onUnitBlockSpawn(Tile tile){ - if(!(tile.entity instanceof UnitBlockEntity)) return; - tile.ent().spawned(); + if(!(tile.build instanceof UnitBlockEntity)) return; + tile.bc().spawned(); } public class UnitBlockEntity extends PayloadAcceptorEntity{ diff --git a/core/src/mindustry/world/consumers/ConsumePower.java b/core/src/mindustry/world/consumers/ConsumePower.java index 5ba9dcf159..557c88469c 100644 --- a/core/src/mindustry/world/consumers/ConsumePower.java +++ b/core/src/mindustry/world/consumers/ConsumePower.java @@ -68,7 +68,7 @@ public class ConsumePower extends Consume{ * @return The amount of power which is requested per tick. */ public float requestedPower(Building entity){ - if(entity.tile().entity == null) return 0f; + if(entity.tile().build == null) return 0f; if(buffered){ return (1f-entity.power.status)*capacity; }else{ diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index 55fed530fa..c77998d4da 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -1,7 +1,6 @@ package mindustry.desktop.steam; import arc.*; -import arc.struct.*; import arc.util.*; import com.codedisaster.steamworks.*; import mindustry.*; @@ -108,7 +107,7 @@ public class SStats implements SteamUserStatsCallback{ if(campaign() && e.unit != null && e.unit.isLocal() && !e.breaking){ SStat.blocksBuilt.add(); - if(e.tile.block() == Blocks.router && e.tile.entity.proximity().contains(t -> t.block() == Blocks.router)){ + if(e.tile.block() == Blocks.router && e.tile.build.proximity().contains(t -> t.block() == Blocks.router)){ chainRouters.complete(); } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 9fd4a55f4b..d7f75b2408 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -134,7 +134,7 @@ public class ApplicationTests{ for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ assertEquals(world.tile(x, y).block(), Blocks.coreShard); - assertEquals(world.tile(x, y).entity, world.tile(bx, by).entity); + assertEquals(world.tile(x, y).build, world.tile(bx, by).build); } } } @@ -143,12 +143,12 @@ public class ApplicationTests{ void blockInventories(){ multiblock(); Tile tile = world.tile(4, 4); - tile.entity.items.add(Items.coal, 5); - tile.entity.items.add(Items.titanium, 50); - assertEquals(tile.entity.items.total(), 55); - tile.entity.items.remove(Items.phasefabric, 10); - tile.entity.items.remove(Items.titanium, 10); - assertEquals(tile.entity.items.total(), 45); + tile.build.items.add(Items.coal, 5); + tile.build.items.add(Items.titanium, 50); + assertEquals(tile.build.items.total(), 55); + tile.build.items.remove(Items.phasefabric, 10); + tile.build.items.remove(Items.titanium, 10); + assertEquals(tile.build.items.total(), 45); } @Test @@ -216,16 +216,16 @@ public class ApplicationTests{ void updateBlocks(int times){ for(Tile tile : world.tiles){ - if(tile.entity != null && tile.isCenter()){ - tile.entity.updateProximity(); + if(tile.build != null && tile.isCenter()){ + tile.build.updateProximity(); } } for(int i = 0; i < times; i++){ Time.update(); for(Tile tile : world.tiles){ - if(tile.entity != null && tile.isCenter()){ - tile.entity.update(); + if(tile.build != null && tile.isCenter()){ + tile.build.update(); } } } @@ -237,14 +237,14 @@ public class ApplicationTests{ state.set(State.playing); world.tile(0, 0).setBlock(Blocks.liquidSource); - world.tile(0, 0).entity.configureAny(Liquids.water); + world.tile(0, 0).build.configureAny(Liquids.water); world.tile(2, 1).setBlock(Blocks.liquidTank); updateBlocks(10); - assertTrue(world.tile(2, 1).entity.liquids.currentAmount() >= 1); - assertTrue(world.tile(2, 1).entity.liquids.current() == Liquids.water); + assertTrue(world.tile(2, 1).build.liquids.currentAmount() >= 1); + assertTrue(world.tile(2, 1).build.liquids.current() == Liquids.water); } @Test @@ -255,7 +255,7 @@ public class ApplicationTests{ Tile source = world.rawTile(0, 0), tank = world.rawTile(1, 4), junction = world.rawTile(0, 1), conduit = world.rawTile(0, 2); source.setBlock(Blocks.liquidSource); - source.entity.configureAny(Liquids.water); + source.build.configureAny(Liquids.water); junction.setBlock(Blocks.liquidJunction); @@ -265,8 +265,8 @@ public class ApplicationTests{ updateBlocks(10); - assertTrue(tank.entity.liquids.currentAmount() >= 1, "Liquid not moved through junction"); - assertTrue(tank.entity.liquids.current() == Liquids.water, "Tank has no water"); + assertTrue(tank.build.liquids.currentAmount() >= 1, "Liquid not moved through junction"); + assertTrue(tank.build.liquids.current() == Liquids.water, "Tank has no water"); } @Test @@ -290,7 +290,7 @@ public class ApplicationTests{ world.tile(0, 0).setBlock(Blocks.conveyor); world.tile(0, 0).rotation(0); - world.tile(0, 0).entity.acceptStack(Items.copper, 1000, null); + world.tile(0, 0).build.acceptStack(Items.copper, 1000, null); } @Test @@ -367,14 +367,14 @@ public class ApplicationTests{ state.set(State.playing); int length = 128; world.tile(0, 0).setBlock(Blocks.itemSource); - world.tile(0, 0).entity.configureAny(Items.copper); + world.tile(0, 0).build.configureAny(Items.copper); - Seq entities = Seq.with(world.tile(0, 0).entity); + Seq entities = Seq.with(world.tile(0, 0).build); for(int i = 0; i < length; i++){ world.tile(i + 1, 0).setBlock(Blocks.conveyor); world.tile(i + 1, 0).rotation(0); - entities.add(world.tile(i + 1, 0).entity); + entities.add(world.tile(i + 1, 0).build); } world.tile(length + 1, 0).setBlock(new Block("___"){{ @@ -501,7 +501,7 @@ public class ApplicationTests{ assertEquals(Blocks.copperWallLarge, world.tile(0, 0).block()); assertEquals(Blocks.air, world.tile(2, 2).block()); assertEquals(Blocks.copperWallLarge, world.tile(1, 1).block()); - assertEquals(world.tile(1, 1).entity, world.tile(0, 0).entity); + assertEquals(world.tile(1, 1).build, world.tile(0, 0).build); } @Test @@ -565,14 +565,14 @@ public class ApplicationTests{ for(int x = 0; x < tiles.width; x++){ for(int y = 0; y < tiles.height; y++){ Tile tile = world.rawTile(x, y); - if(tile.entity != null){ + if(tile.build != null){ try{ - tile.entity.update(); + tile.build.update(); }catch(Throwable t){ fail("Failed to update block '" + tile.block() + "'.", t); } - assertEquals(tile.block(), tile.entity.block()); - assertEquals(tile.block().health, tile.entity.health()); + assertEquals(tile.block(), tile.build.block()); + assertEquals(tile.block().health, tile.build.health()); } } } @@ -584,10 +584,10 @@ public class ApplicationTests{ Tile core = world.tile(5, 5); core.setBlock(Blocks.coreShard, Team.sharded, 0); for(Item item : content.items()){ - core.entity.items.set(item, 3000); + core.build.items.set(item, 3000); } - assertEquals(core.entity, state.teams.get(Team.sharded).core()); + assertEquals(core.build, state.teams.get(Team.sharded).core()); } void depositTest(Block block, Item item){ @@ -595,18 +595,18 @@ public class ApplicationTests{ Tile tile = new Tile(0, 0, Blocks.air, Blocks.air, block); int capacity = tile.block().itemCapacity; - assertNotNull(tile.entity, "Tile should have an entity, but does not: " + tile); + assertNotNull(tile.build, "Tile should have an entity, but does not: " + tile); - int deposited = tile.entity.acceptStack(item, capacity - 1, unit); + int deposited = tile.build.acceptStack(item, capacity - 1, unit); assertEquals(capacity - 1, deposited); - tile.entity.handleStack(item, capacity - 1, unit); - assertEquals(tile.entity.items.get(item), capacity - 1); + tile.build.handleStack(item, capacity - 1, unit); + assertEquals(tile.build.items.get(item), capacity - 1); - int overflow = tile.entity.acceptStack(item, 10, unit); + int overflow = tile.build.acceptStack(item, 10, unit); assertEquals(1, overflow); - tile.entity.handleStack(item, 1, unit); - assertEquals(capacity, tile.entity.items.get(item)); + tile.build.handleStack(item, 1, unit); + assertEquals(capacity, tile.build.items.get(item)); } } diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index 89e730ec63..0896892b8b 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -53,7 +53,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ }; tile = createFakeTile(0, 0, generator); - entity = tile.ent(); + entity = tile.bc(); } /** Tests the consumption and efficiency when being supplied with liquids. */ diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index 5a98ab839d..87177440c0 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -11,7 +11,6 @@ import mindustry.game.*; import mindustry.gen.*; import mindustry.world.*; import mindustry.world.blocks.power.*; -import mindustry.world.modules.*; import org.junit.jupiter.api.*; import static mindustry.Vars.*; @@ -87,21 +86,21 @@ public class PowerTestFixture{ Reflect.set(Tile.class, tile, "floor", Blocks.sand); // Simulate the "changed" method. Calling it through reflections would require half the game to be initialized. - tile.entity = block.newEntity().init(tile, Team.sharded, false); + tile.build = block.newEntity().init(tile, Team.sharded, false); if(block.hasPower){ - tile.entity.power.graph = new PowerGraph(){ + tile.build.power.graph = new PowerGraph(){ //assume there's always something consuming power @Override public float getUsageFraction(){ return 1f; } }; - tile.entity.power.graph.add(tile.entity); + tile.build.power.graph.add(tile.build); } // Assign incredibly high health so the block does not get destroyed on e.g. burning Blast Compound block.health = 100000; - tile.entity.health(100000.0f); + tile.build.health(100000.0f); return tile; }catch(Exception ex){ diff --git a/tests/src/test/java/power/PowerTests.java b/tests/src/test/java/power/PowerTests.java index a25a163853..41f851b804 100644 --- a/tests/src/test/java/power/PowerTests.java +++ b/tests/src/test/java/power/PowerTests.java @@ -54,19 +54,19 @@ public class PowerTests extends PowerTestFixture{ void simulateDirectConsumption(float producedPower, float requiredPower, float expectedSatisfaction, String parameterDescription){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); - producerTile.ent().productionEfficiency = 1f; + producerTile.bc().productionEfficiency = 1f; Tile directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requiredPower)); PowerGraph powerGraph = new PowerGraph(); - powerGraph.add(producerTile.entity); - powerGraph.add(directConsumerTile.entity); + powerGraph.add(producerTile.build); + powerGraph.add(directConsumerTile.build); assertEquals(producedPower * Time.delta(), powerGraph.getPowerProduced(), Mathf.FLOAT_ROUNDING_ERROR); assertEquals(requiredPower * Time.delta(), powerGraph.getPowerNeeded(), Mathf.FLOAT_ROUNDING_ERROR); // Update and check for the expected power status of the consumer powerGraph.update(); - assertEquals(expectedSatisfaction, directConsumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + assertEquals(expectedSatisfaction, directConsumerTile.build.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); } /** @@ -94,24 +94,24 @@ public class PowerTests extends PowerTestFixture{ if(producedPower > 0.0f){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); - producerTile.ent().productionEfficiency = 1f; - powerGraph.add(producerTile.entity); + producerTile.bc().productionEfficiency = 1f; + powerGraph.add(producerTile.build); } Tile directConsumerTile = null; if(requestedPower > 0.0f){ directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requestedPower)); - powerGraph.add(directConsumerTile.entity); + powerGraph.add(directConsumerTile.build); } float maxCapacity = 100f; Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity)); - batteryTile.entity.power.status = initialBatteryCapacity / maxCapacity; + batteryTile.build.power.status = initialBatteryCapacity / maxCapacity; - powerGraph.add(batteryTile.entity); + powerGraph.add(batteryTile.build); powerGraph.update(); - assertEquals(expectedBatteryCapacity / maxCapacity, batteryTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery status did not match"); + assertEquals(expectedBatteryCapacity / maxCapacity, batteryTile.build.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery status did not match"); if(directConsumerTile != null){ - assertEquals(expectedSatisfaction, directConsumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + assertEquals(expectedSatisfaction, directConsumerTile.build.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); } } @@ -119,24 +119,24 @@ public class PowerTests extends PowerTestFixture{ @Test void directConsumptionStopsWithNoPower(){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(10.0f)); - producerTile.ent().productionEfficiency = 1.0f; + producerTile.bc().productionEfficiency = 1.0f; Tile consumerTile = createFakeTile(0, 1, createFakeDirectConsumer(5.0f)); PowerGraph powerGraph = new PowerGraph(); - powerGraph.add(producerTile.entity); - powerGraph.add(consumerTile.entity); + powerGraph.add(producerTile.build); + powerGraph.add(consumerTile.build); powerGraph.update(); - assertEquals(1.0f, consumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR); + assertEquals(1.0f, consumerTile.build.power.status, Mathf.FLOAT_ROUNDING_ERROR); - powerGraph.remove(producerTile.entity); - powerGraph.add(consumerTile.entity); + powerGraph.remove(producerTile.build); + powerGraph.add(consumerTile.build); powerGraph.update(); - assertEquals(0.0f, consumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR); + assertEquals(0.0f, consumerTile.build.power.status, Mathf.FLOAT_ROUNDING_ERROR); if(consumerTile.block().consumes.hasPower()){ ConsumePower consumePower = consumerTile.block().consumes.getPower(); - assertFalse(consumePower.valid(consumerTile.ent())); + assertFalse(consumePower.valid(consumerTile.bc())); } } }