From 6bbbd5ab01ea3ce2083b65028d2ec321f4aec823 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 7 Feb 2022 10:58:22 -0500 Subject: [PATCH] Fixed disappearing blocks / Unit tech tree entries --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/content/Blocks.java | 6 +- .../src/mindustry/content/ErekirTechTree.java | 27 +++++++++ core/src/mindustry/content/UnitTypes.java | 6 +- core/src/mindustry/entities/EntityGroup.java | 14 ++++- core/src/mindustry/entities/Units.java | 16 +++++ core/src/mindustry/type/UnitType.java | 19 ++++++ .../world/blocks/payloads/PayloadBlock.java | 2 +- .../world/blocks/payloads/PayloadLoader.java | 60 +++++++++++++++++-- .../mindustry/world/blocks/power/Battery.java | 2 +- .../world/blocks/units/UnitAssembler.java | 17 ++++-- 11 files changed, 149 insertions(+), 21 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index aca308463d..e095a1acb4 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -837,6 +837,7 @@ bar.heatamount = Heat: {0} bar.heatpercent = Heat: {0} ({1}%) bar.power = Power bar.progress = Build Progress +bar.loadprogress = Progress bar.launchcooldown = Launch Cooldown bar.input = Input bar.output = Output diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index c7e9f2c7fe..365a40f76f 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3470,8 +3470,8 @@ public class Blocks{ tankAssembler = new UnitAssembler("tank-assembler"){{ requirements(Category.units, with(Items.graphite, 600, Items.beryllium, 600, Items.oxide, 200, Items.tungsten, 500)); size = 5; - plans.add(new AssemblerUnitPlan(UnitTypes.vanquish, 60f * 10f, BlockStack.list(Blocks.tungstenWallLarge, 5, Blocks.duct, 2))); - consumes.power(2f); + plans.add(new AssemblerUnitPlan(UnitTypes.vanquish, 60f * 10f, BlockStack.list(Blocks.tungstenWallLarge, 6, Blocks.duct, 14, Blocks.cliffCrusher, 10))); + consumes.power(3f); areaSize = 13; //TODO unit production is rarely continuous, can be double @@ -3480,7 +3480,7 @@ public class Blocks{ //TODO requirements shipAssembler = new UnitAssembler("ship-assembler"){{ - requirements(Category.units, with(Items.graphite, 600, Items.beryllium, 600, Items.oxide, 200, Items.tungsten, 500)); + requirements(Category.units, with(Items.beryllium, 700, Items.oxide, 150, Items.tungsten, 500, Items.silicon, 800)); size = 5; plans.add(new AssemblerUnitPlan(UnitTypes.quell, 60f * 4f, BlockStack.list(Blocks.tungstenWallLarge, 5, Blocks.plasmaBore, 2))); consumes.power(2f); diff --git a/core/src/mindustry/content/ErekirTechTree.java b/core/src/mindustry/content/ErekirTechTree.java index 7de78f2c9a..b190c19db8 100644 --- a/core/src/mindustry/content/ErekirTechTree.java +++ b/core/src/mindustry/content/ErekirTechTree.java @@ -21,6 +21,9 @@ public class ErekirTechTree{ costMultipliers.put(Items.thorium, 9); costMultipliers.put(Items.graphite, 9); + //TODO remove + Objective tmpNever = new Research(Items.fissileMatter); + //TODO gate behind capture Planets.erekir.techTree = nodeRoot("erekir", coreBastion, true, () -> { @@ -202,6 +205,30 @@ public class ErekirTechTree{ }); }); + node(tankAssembler, Seq.with(new OnSector(four), new Research(constructor), new Research(slagCentrifuge), new Research(Liquids.gallium)), () -> { + node(UnitTypes.vanquish, () -> { + node(UnitTypes.conquer, Seq.with(tmpNever), () -> { + + }); + }); + + node(shipAssembler, Seq.with(tmpNever), () -> { + node(UnitTypes.quell, () -> { + node(UnitTypes.disrupt, Seq.with(tmpNever), () -> { + + }); + }); + + node(mechAssembler, () -> { + node(UnitTypes.bulwark, () -> { + node(UnitTypes.krepost, Seq.with(tmpNever), () -> { + + }); + }); + }); + }); + }); + //TODO more sectors node(onset, () -> { node(aware, Seq.with(new SectorComplete(onset), new Research(ductRouter)), () -> { diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 24ec257ec4..017120a74a 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -2737,7 +2737,7 @@ public class UnitTypes{ velocityRnd = 0.33f; heatColor = Color.red; - bullet = new MissileBulletType(4.2f, 34){{ + bullet = new MissileBulletType(4.2f, 40){{ homingPower = 0.2f; weaveMag = 4; weaveScale = 4; @@ -2745,7 +2745,7 @@ public class UnitTypes{ //TODO better shootEffect = Fx.shootBig2; smokeEffect = Fx.shootSmokeTitan; - splashDamage = 40f; + splashDamage = 50f; splashDamageRadius = 30f; frontColor = Color.white; hitSound = Sounds.none; @@ -2918,7 +2918,7 @@ public class UnitTypes{ y = 5 / 4f; rotate = true; rotateSpeed = 2f; - reload = 70f; + reload = 60f; layerOffset = -0.001f; recoil = 1f; rotationLimit = 60f; diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index d3cf9bd32b..b7a16e21b2 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -32,7 +32,7 @@ public class EntityGroup implements Iterable{ /** Makes sure the next ID counter is higher than this number, so future entities cannot possibly use this ID. */ public static void checkNextId(int id){ - lastId = id + 1; + lastId = Math.max(lastId, id + 1); } public EntityGroup(Class type, boolean spatial, boolean mapping){ @@ -47,6 +47,18 @@ public class EntityGroup implements Iterable{ } } + /** @return entities with colliding IDs, or an empty array. */ + public Seq checkIDCollisions(){ + Seq out = new Seq<>(); + IntSet ints = new IntSet(); + each(u -> { + if(!ints.add(u.id())){ + out.add(u); + } + }); + return out; + } + public void sort(Comparator comp){ array.sort(comp); } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 17ffc49d56..551b724ea4 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -173,6 +173,22 @@ public class Units{ return boolResult; } + public static boolean anyEntities(float x, float y, float width, float height, Boolf check){ + boolResult = false; + + nearby(x, y, width, height, unit -> { + if(boolResult) return; + if(check.get(unit)){ + unit.hitboxTile(hitrect); + + if(hitrect.overlaps(aeX, aeY, aeW, aeH)){ + boolResult = true; + } + } + }); + return boolResult; + } + /** Returns the nearest damaged tile. */ public static Building findDamagedTile(Team team, float x, float y){ return indexer.getDamaged(team).min(b -> b.dst2(x, y)); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index f4db78b718..e93701345a 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -682,6 +682,7 @@ public class UnitType extends UnlockableContent{ /** @return item requirements based on reconstructors or factories found; returns previous unit in array if provided */ public @Nullable ItemStack[] getRequirements(@Nullable UnitType[] prevReturn, @Nullable float[] timeReturn){ + //find reconstructor var rec = (Reconstructor)content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this)); if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){ @@ -693,6 +694,7 @@ public class UnitType extends UnlockableContent{ } return ci.items; }else{ + //find a factory var factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this)); if(factory != null){ @@ -701,6 +703,23 @@ public class UnitType extends UnlockableContent{ timeReturn[0] = plan.time; } return plan.requirements; + }else{ + //find an assembler + var assembler = (UnitAssembler)content.blocks().find(u -> u instanceof UnitAssembler a && a.plans.contains(p -> p.unit == this)); + if(assembler != null){ + var plan = assembler.plans.find(p -> p.unit == this); + + if(timeReturn != null){ + timeReturn[0] = plan.time; + } + ItemSeq reqs = new ItemSeq(); + for(var bstack : plan.requirements){ + for(var stack : bstack.block.requirements){ + reqs.add(stack.item, stack.amount * bstack.amount); + } + } + return reqs.toArray(); + } } } return null; diff --git a/core/src/mindustry/world/blocks/payloads/PayloadBlock.java b/core/src/mindustry/world/blocks/payloads/PayloadBlock.java index f1e1869061..520b0bd78f 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadBlock.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadBlock.java @@ -166,7 +166,7 @@ public class PayloadBlock extends Block{ if(rotate){ payRotation = Angles.moveToward(payRotation, rotate ? rotdeg() : 90f, payloadRotateSpeed * edelta()); } - payVector.approach(Vec2.ZERO, payloadSpeed * delta()); + payVector.approach(Vec2.ZERO, payloadSpeed * edelta()); return hasArrived(); } diff --git a/core/src/mindustry/world/blocks/payloads/PayloadLoader.java b/core/src/mindustry/world/blocks/payloads/PayloadLoader.java index 11156138c3..a96b62c98b 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadLoader.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadLoader.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.payloads; import arc.*; import arc.graphics.g2d.*; +import arc.math.*; import arc.util.*; import arc.util.io.*; import mindustry.entities.units.*; @@ -19,12 +20,17 @@ public class PayloadLoader extends PayloadBlock{ public int itemsLoaded = 8; public float liquidsLoaded = 40f; public int maxBlockSize = 3; + public float maxPowerConsumption = 40f; + + //initialized in init(), do not touch + protected float basePowerUse = 0f; public PayloadLoader(String name){ super(name); hasItems = true; hasLiquids = true; + hasPower = true; itemCapacity = 100; liquidCapacity = 100f; update = true; @@ -47,7 +53,9 @@ public class PayloadLoader extends PayloadBlock{ public void setBars(){ super.setBars(); - bars.add("progress", (PayloadLoaderBuild entity) -> new Bar(() -> Core.bundle.format("bar.items", entity.payload == null ? 0 : entity.payload.build.items.total()), () -> Pal.items, entity::fraction)); + bars.add("progress", (PayloadLoaderBuild build) -> new Bar(() -> + Core.bundle.format(build.payload != null && build.payload.block().hasItems ? "bar.items" : "bar.loadprogress", + build.payload == null || !build.payload.block().hasItems ? 0 : build.payload.build.items.total()), () -> Pal.items, build::fraction)); } @Override @@ -58,6 +66,14 @@ public class PayloadLoader extends PayloadBlock{ Draw.rect(topRegion, plan.drawx(), plan.drawy()); } + @Override + public void init(){ + basePowerUse = consumes.hasPower() ? consumes.getPower().usage : 0f; + consumes.powerDynamic((PayloadLoaderBuild loader) -> loader.hasBattery() && !loader.exporting ? maxPowerConsumption + basePowerUse : basePowerUse); + + super.init(); + } + public class PayloadLoaderBuild extends PayloadBlockBuild{ public boolean exporting = false; @@ -65,9 +81,14 @@ public class PayloadLoader extends PayloadBlock{ public boolean acceptPayload(Building source, Payload payload){ return super.acceptPayload(source, payload) && payload.fits(maxBlockSize) && - payload instanceof BuildPayload build && - ((build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize) || - build.build.block().hasLiquids && build.block().liquidCapacity >= 10f); + payload instanceof BuildPayload build && ( + //item container + (build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize) || + //liquid container + (build.build.block().hasLiquids && build.block().liquidCapacity >= 10f) || + //battery + (build.build.block.consumes.hasPower() && build.build.block.consumes.getPower().buffered) + ); } @Override @@ -150,18 +171,45 @@ public class PayloadLoader extends PayloadBlock{ liquids.remove(liq, flow); } } + + //load up power + if(hasBattery()){ + //base power input that in raw units + float powerInput = power.status * (basePowerUse + maxPowerConsumption); + //how much is actually usable + float availableInput = Math.max(powerInput - basePowerUse, 0f); + + //charge the battery + float cap = payload.block().consumes.getPower().capacity; + payload.build.power.status += availableInput / cap * Time.delta; + + //export if full + if(payload.build.power.status >= 1f){ + exporting = true; + payload.build.power.status = Mathf.clamp(payload.build.power.status); + } + } } } public float fraction(){ - return payload == null ? 0f : payload.build.items.total() / (float)payload.build.block.itemCapacity; + return payload == null ? 0f : + payload.build.items != null ? payload.build.items.total() / (float)payload.build.block.itemCapacity : + payload.build.liquids != null ? payload.build.liquids.currentAmount() / payload.block().liquidCapacity : + hasBattery() ? payload.build.power.status : + 0f; } public boolean shouldExport(){ return payload != null && ( exporting || (payload.block().hasLiquids && liquids.currentAmount() >= 0.1f && payload.build.liquids.currentAmount() >= payload.block().liquidCapacity - 0.001f) || - (payload.block().hasItems && items.any() && payload.block().separateItemCapacity && content.items().contains(i -> payload.build.items.get(i) >= payload.block().itemCapacity))); + (payload.block().hasItems && items.any() && payload.block().separateItemCapacity && content.items().contains(i -> payload.build.items.get(i) >= payload.block().itemCapacity)) || + (hasBattery() && payload.build.power.status >= 0.999999999f)); + } + + public boolean hasBattery(){ + return payload != null && payload.block().hasPower && payload.block().consumes.getPower().buffered; } @Override diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java index 8a6011cd32..c4e46167f4 100644 --- a/core/src/mindustry/world/blocks/power/Battery.java +++ b/core/src/mindustry/world/blocks/power/Battery.java @@ -30,7 +30,7 @@ public class Battery extends PowerDistributor{ @Override public void draw(){ Draw.color(emptyLightColor, fullLightColor, power.status); - Fill.square(x, y, tilesize * size / 2f - 1); + Fill.square(x, y, (tilesize * size / 2f - 1) * Draw.xscl); Draw.color(); Draw.rect(topRegion, x, y); diff --git a/core/src/mindustry/world/blocks/units/UnitAssembler.java b/core/src/mindustry/world/blocks/units/UnitAssembler.java index f4fa881c9f..45b9cc969e 100644 --- a/core/src/mindustry/world/blocks/units/UnitAssembler.java +++ b/core/src/mindustry/world/blocks/units/UnitAssembler.java @@ -172,7 +172,7 @@ public class UnitAssembler extends PayloadBlock{ public Seq units = new Seq<>(); public Seq modules = new Seq<>(); public BlockSeq blocks = new BlockSeq(); - public float progress, warmup, droneWarmup, powerWarmup; + public float progress, warmup, droneWarmup, powerWarmup, sameTypeWarmup; public float invalidWarmup = 0f; public int currentTier = 0; public boolean wasOccupied = false; @@ -318,10 +318,12 @@ public class UnitAssembler extends PayloadBlock{ ai.targetAngle = i * 90f + 45f + 180f; } - wasOccupied = checkSolid(spawn); + wasOccupied = checkSolid(spawn, false); + boolean visualOccupied = checkSolid(spawn, true); float eff = (units.count(u -> ((AssemblerAI)u.controller()).inPosition()) / (float)dronesCreated); - invalidWarmup = Mathf.lerpDelta(invalidWarmup, wasOccupied ? 1f : 0f, 0.1f); + sameTypeWarmup = Mathf.lerpDelta(sameTypeWarmup, wasOccupied && !visualOccupied ? 0f : 1f, 0.1f); + invalidWarmup = Mathf.lerpDelta(invalidWarmup, visualOccupied ? 1f : 0f, 0.1f); var plan = plan(); @@ -401,7 +403,7 @@ public class UnitAssembler extends PayloadBlock{ //draw unit silhouette Draw.mixcol(Tmp.c1.set(Pal.accent).lerp(Pal.remove, invalidWarmup), 1f); - Draw.alpha(powerWarmup); + Draw.alpha(Math.min(powerWarmup, sameTypeWarmup)); Draw.rect(plan.unit.fullIcon, spawn.x, spawn.y); //build beams do not draw when invalid @@ -442,9 +444,12 @@ public class UnitAssembler extends PayloadBlock{ Draw.reset(); } - public boolean checkSolid(Vec2 v){ + public boolean checkSolid(Vec2 v, boolean same){ var output = unit(); - return !output.flying && (collisions.overlapsTile(Tmp.r1.setCentered(v.x, v.y, output.hitSize), EntityCollisions::solid) || Units.anyEntities(v.x, v.y, output.hitSize * 1.4f)); + //TODO CHECK TO MAKE SURE IT'S NOT THE SAME UNIT + float hsize = output.hitSize * 1.4f; + return !output.flying && (collisions.overlapsTile(Tmp.r1.setCentered(v.x, v.y, output.hitSize), EntityCollisions::solid) || + (!same ? Units.anyEntities(v.x, v.y, hsize) : Units.anyEntities(v.x - hsize/2f, v.y - hsize/2f, hsize, hsize, u -> u.type != output && u.isGrounded()))); } /** @return true if this block is ready to produce units, e.g. requirements met */