diff --git a/core/assets-raw/sprites/blocks/units/drone-center.png b/core/assets-raw/sprites/blocks/units/drone-center.png new file mode 100644 index 0000000000..4e1478888a Binary files /dev/null and b/core/assets-raw/sprites/blocks/units/drone-center.png differ diff --git a/core/assets-raw/sprites/units/effect-drone.png b/core/assets-raw/sprites/units/effect-drone.png new file mode 100644 index 0000000000..e7e43313d1 Binary files /dev/null and b/core/assets-raw/sprites/units/effect-drone.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 612d00e5bc..87f7fec7cc 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -528,3 +528,5 @@ 63175=carbon-vent|block-carbon-vent-ui 63174=shield-projector|block-shield-projector-ui 63173=beam-link|block-beam-link-ui +63172=drone-center|block-drone-center-ui +63171=effect-drone|unit-effect-drone-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index 1c6082c1b8..81f0eb070c 100644 Binary files a/core/assets/logicids.dat and b/core/assets/logicids.dat differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index b3f2362d99..e6752d0b5b 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -142,6 +142,8 @@ public class Blocks{ //TODO maybe making it 5x5 would be more appropriate, seems kinda cheap. basicAssemblerModule, + droneCenter, + //payloads payloadConveyor, payloadRouter, payloadPropulsionTower, smallDeconstructor, deconstructor, constructor, largeConstructor, payloadLoader, payloadUnloader, @@ -3531,6 +3533,16 @@ public class Blocks{ size = 3; }}; + //TODO setup, sprite, balance... + droneCenter = new DroneCenter("drone-center"){{ + requirements(Category.units, with(Items.graphite, 10)); + + size = 3; + consumes.power(3f); + + droneType = UnitTypes.effectDrone; + }}; + //endregion //region payloads diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 9dc92b446c..c46c3cd63d 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -70,7 +70,7 @@ public class UnitTypes{ public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block; //special tethered (has payload capability, because it's necessary sometimes) - public static @EntityDef({Unitc.class, BuildingTetherc.class, Payloadc.class}) UnitType manifold, assemblyDrone; + public static @EntityDef({Unitc.class, BuildingTetherc.class, Payloadc.class}) UnitType manifold, assemblyDrone, effectDrone; //tank public static @EntityDef({Unitc.class, Tankc.class}) UnitType vanquish, conquer; @@ -3190,7 +3190,7 @@ public class UnitTypes{ mineFloor = false; mineHardnessScaling = false; flying = true; - mineSpeed = 5f; + mineSpeed = 4.5f; mineTier = 4; buildSpeed = 1.1f; drag = 0.08f; @@ -3258,11 +3258,11 @@ public class UnitTypes{ mineFloor = false; mineHardnessScaling = false; flying = true; - mineSpeed = 6f; + mineSpeed = 5f; mineTier = 4; buildSpeed = 1.4f; drag = 0.08f; - speed = 7.2f; + speed = 7.3f; rotateSpeed = 8f; accel = 0.08f; itemCapacity = 110; @@ -3288,7 +3288,7 @@ public class UnitTypes{ beamWidth = 0.7f; repairSpeed = 0.2f; aimDst = 0f; - shootCone = 16f; + shootCone = 40f; fractionRepair = true; mirror = true; @@ -3369,6 +3369,23 @@ public class UnitTypes{ envDisabled = Env.none; }}; + effectDrone = new ErekirUnitType("effect-drone"){{ + flying = true; + drag = 0.08f; + speed = 3f; + drawCell = false; + logicControllable = playerControllable = allowedInPayloads = isCounted = false; + hidden = true; + + engineSize = 0f; + float es = 2.5f, ew = 14.5f / 4f; + + setEnginesMirror( + new UnitEngine(ew, ew, es, 45f), + new UnitEngine(ew, -ew, es, 315f) + ); + }}; + //payloadDrone = new UnitType("payload-drone"){{ //}}; diff --git a/core/src/mindustry/ui/SearchBar.java b/core/src/mindustry/ui/SearchBar.java deleted file mode 100644 index 8185fe746c..0000000000 --- a/core/src/mindustry/ui/SearchBar.java +++ /dev/null @@ -1,6 +0,0 @@ -package mindustry.ui; - -//TODO remove, unlikely to be used anywhere else. -public class SearchBar{ - -} diff --git a/core/src/mindustry/world/blocks/defense/BaseShield.java b/core/src/mindustry/world/blocks/defense/BaseShield.java index 6989525569..455452d9fb 100644 --- a/core/src/mindustry/world/blocks/defense/BaseShield.java +++ b/core/src/mindustry/world/blocks/defense/BaseShield.java @@ -80,12 +80,11 @@ public class BaseShield extends Block{ @Override public void updateTile(){ - broken = efficiency() <= 0.0001f; - smoothRadius = Mathf.lerpDelta(smoothRadius, radius * efficiency(), 0.04f); + smoothRadius = Mathf.lerpDelta(smoothRadius, radius * efficiency(), 0.05f); float rad = radius(); - if(rad > 0 && !broken){ + if(rad > 1){ paramBuild = this; //paramEffect = absorbEffect; Groups.bullet.intersect(x - rad, y - rad, rad * 2f, rad * 2f, bulletConsumer); @@ -94,7 +93,6 @@ public class BaseShield extends Block{ } public float radius(){ - //TODO bad rule? return smoothRadius; } @@ -125,10 +123,9 @@ public class BaseShield extends Block{ }else{ Lines.stroke(1.5f); Draw.alpha(0.09f + Mathf.clamp(0.08f * hit)); - Fill.circle(x, y, radius); + Fill.poly(x, y, sides, radius); Draw.alpha(1f); - //TODO - Lines.poly(x, y, 60, radius); + Lines.poly(x, y, sides, radius); Draw.reset(); } } diff --git a/core/src/mindustry/world/blocks/units/DroneCenter.java b/core/src/mindustry/world/blocks/units/DroneCenter.java new file mode 100644 index 0000000000..ab83c588de --- /dev/null +++ b/core/src/mindustry/world/blocks/units/DroneCenter.java @@ -0,0 +1,168 @@ +package mindustry.world.blocks.units; + +import arc.graphics.g2d.*; +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import arc.util.io.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.entities.units.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.type.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class DroneCenter extends Block{ + public int unitsSpawned = 4; + public UnitType droneType; + public StatusEffect status = StatusEffects.overdrive; + public float droneConstructTime = 60f * 3f; + public float statusDuration = 60f * 2f; + public float droneRange = 50f; + + public DroneCenter(String name){ + super(name); + + update = solid = true; + configurable = true; + } + + @Override + public void init(){ + super.init(); + + droneType.defaultController = EffectDroneAI::new; + } + + public class DroneCenterBuild extends Building{ + protected IntSeq readUnits = new IntSeq(); + protected int readTarget = -1; + + public Seq units = new Seq<>(); + public @Nullable Unit target; + public float droneProgress, droneWarmup, totalDroneProgress; + + @Override + public void updateTile(){ + if(!readUnits.isEmpty()){ + units.clear(); + readUnits.each(i -> { + var unit = Groups.unit.getByID(i); + if(unit != null){ + units.add(unit); + } + }); + readUnits.clear(); + } + + units.removeAll(u -> !u.isAdded() || u.dead); + + droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < unitsSpawned ? efficiency() : 0f, 0.1f); + totalDroneProgress += droneWarmup * Time.delta; + + if(readTarget != 0){ + target = Groups.unit.getByID(readTarget); + readTarget = 0; + } + + //TODO better effects? + if(units.size < unitsSpawned && (droneProgress += edelta() / droneConstructTime) >= 1f){ + var unit = droneType.create(team); + if(unit instanceof BuildingTetherc bt){ + bt.building(this); + } + unit.set(x, y); + unit.rotation = 90f; + unit.add(); + + Fx.spawn.at(unit); + units.add(unit); + droneProgress = 0f; + } + + if(target != null && !target.isValid()){ + target = null; + } + + //TODO no autotarget, bad + if(target == null){ + target = Units.closest(team, x, y, u -> !u.spawnedByCore && u.type != droneType); + } + } + + @Override + public void drawConfigure(){ + Drawf.square(x, y, tile.block().size * tilesize / 2f + 1f + Mathf.absin(Time.time, 4f, 1f)); + + if(target != null){ + Drawf.square(target.x, target.y, target.hitSize * 0.8f); + } + } + + @Override + public void draw(){ + super.draw(); + + //TODO draw more stuff + + if(droneWarmup > 0){ + Draw.draw(Layer.blockOver + 0.2f, () -> { + Drawf.construct(this, droneType.fullIcon, Pal.accent, 0f, droneProgress, droneWarmup, totalDroneProgress, 14f); + }); + } + } + + @Override + public void write(Writes write){ + super.write(write); + + write.i(target == null ? -1 : target.id); + + write.s(units.size); + for(var unit : units){ + write.i(unit.id); + } + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); + + readTarget = read.i(); + + int count = read.s(); + readUnits.clear(); + for(int i = 0; i < count; i++){ + readUnits.add(read.i()); + } + } + } + + public static class EffectDroneAI extends AIController{ + //TODO non static? + + @Override + public void updateUnit(){ + if(!(unit instanceof BuildingTetherc tether)) return; + if(!(tether.building() instanceof DroneCenterBuild build)) return; + if(build.target == null) return; + + DroneCenter block = (DroneCenter)build.block; + + target = build.target; + + //TODO what angle? + moveTo(target, build.target.hitSize / 1.8f + block.droneRange - 10f); + + unit.lookAt(target); + + //TODO low power? status effects may not be the best way to do this... + if(unit.within(target, block.droneRange + build.target.hitSize)){ + build.target.apply(block.status, block.statusDuration); + } + } + } +}