diff --git a/core/assets-raw/sprites/blocks/walls/thorium-wall-large.png b/core/assets-raw/sprites/blocks/walls/thorium-wall-large.png index ef8f313f09..20c23043ac 100644 Binary files a/core/assets-raw/sprites/blocks/walls/thorium-wall-large.png and b/core/assets-raw/sprites/blocks/walls/thorium-wall-large.png differ diff --git a/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png b/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png new file mode 100644 index 0000000000..4c21bf939c Binary files /dev/null and b/core/assets-raw/sprites/blocks/walls/tungsten-wall-large.png differ diff --git a/core/assets-raw/sprites/blocks/walls/tungsten-wall.png b/core/assets-raw/sprites/blocks/walls/tungsten-wall.png new file mode 100644 index 0000000000..e9c0c18e33 Binary files /dev/null and b/core/assets-raw/sprites/blocks/walls/tungsten-wall.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index a00581b2f6..745f318e5b 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -484,3 +484,6 @@ 63222=arkyic-wall|block-arkyic-wall-ui 63221=heat-redirector|block-heat-redirector-ui 63220=vanquish|unit-vanquish-ui +63219=tungsten-wall|block-tungsten-wall-ui +63218=tungsten-wall-large|block-tungsten-wall-large-ui +63217=tank-assembler|block-tank-assembler-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index 0e15c2ddf1..ee0c940a98 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 a6af38a9b2..68c267de10 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -72,7 +72,7 @@ public class Blocks{ powerSource, powerVoid, itemSource, itemVoid, liquidSource, liquidVoid, payloadSource, payloadVoid, illuminator, //defense - copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge, + copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, tungstenWall, tungstenWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge, phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, overdriveDome, forceProjector, shockMine, scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet @@ -128,6 +128,9 @@ public class Blocks{ additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor, repairPoint, repairTurret, + //unit - erekir + tankAssembler, + //payloads //TODO small deconstructor payloadConveyor, payloadRouter, payloadPropulsionTower, smallDeconstructor, deconstructor, constructor, largeConstructor, payloadLoader, payloadUnloader, @@ -1355,6 +1358,19 @@ public class Blocks{ schematicPriority = 10; }}; + tungstenWall = new Wall("tungsten-wall"){{ + requirements(Category.defense, with(Items.tungsten, 6)); + health = 180 * wallHealthMultiplier; + armor = 7f; + }}; + + tungstenWallLarge = new Wall("tungsten-wall-large"){{ + requirements(Category.defense, ItemStack.mult(tungstenWall.requirements, 4)); + health = 180 * wallHealthMultiplier * 4; + armor = 7f; + size = 2; + }}; + thoriumWall = new Wall("thorium-wall"){{ requirements(Category.defense, with(Items.thorium, 6)); health = 200 * wallHealthMultiplier; @@ -3293,6 +3309,15 @@ public class Blocks{ acceptCoolant = true; }}; + //endregion + //region units - erekir + + tankAssembler = new UnitAssembler("tank-assembler"){{ + size = 3; + output = UnitTypes.vanquish; + requirements = BlockStack.list(Blocks.thoriumWallLarge, 4); + }}; + //endregion //region payloads diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index bc2f2a2f53..929e6c6496 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -2446,7 +2446,7 @@ public class UnitTypes{ mirror = false; x = 0f; y = 0; - shadow = 30f; + shadow = 28f; bullet = new BasicBulletType(7f, 50){{ sprite = "missile-large"; @@ -2465,45 +2465,6 @@ public class UnitTypes{ trailLength = 8; hitEffect = despawnEffect = Fx.blastExplosion; }}; - - //TODO better bullet / weapon - /* - bullet = new ArtilleryBulletType(2f, 20, "shell"){{ - hitEffect = Fx.massiveExplosion; - knockback = 0.8f; - lifetime = 100f; - width = height = 14f; - collidesTiles = false; - splashDamageRadius = 60f; - splashDamage = 60f; - backColor = Color.valueOf("feb380"); - frontColor = Color.white; - - width = 9f; - height = 15f; - - status = StatusEffects.blasted; - lightning = 5; - - trailLength = 28; - trailWidth = 4f; - trailEffect = Fx.none; - trailColor = backColor; - - shrinkX = 0.1f; - shrinkY = 0.5f; - - fragBullets = 9; - fragVelocityMin = 0.7f; - fragLifeMin = 0f; - fragBullet = new BasicBulletType(3.5f, 15){{ - width = 7f; - height = 9f; - lifetime = 25f; - backColor = Color.valueOf("feb380"); - frontColor = Color.white; - }}; - }};*/ }}); int i = 0; @@ -2526,7 +2487,7 @@ public class UnitTypes{ hitColor = backColor = trailColor = Color.valueOf("feb380"); frontColor = Color.white; trailWidth = 1.5f; - trailLength = 6; + trailLength = 4; hitEffect = despawnEffect = Fx.hitBulletColor; }}; }}); @@ -2708,9 +2669,6 @@ public class UnitTypes{ height = 12f; shootEffect = Fx.sparkShoot; smokeEffect = Fx.shootBigSmoke; - pierceCap = 2; - pierce = true; - pierceBuilding = true; hitColor = backColor = trailColor = Pal.bulletYellowBack; frontColor = Color.white; trailWidth = 1.5f; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index df2cd699bc..0ab16352f9 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -510,4 +510,9 @@ public class Damage{ float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff); return damage * scaled; } + + /** @return resulting armor calculated based off of damage */ + public static float applyArmor(float damage, float armor){ + return Math.max(damage - armor, minArmorDamage * damage); + } } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index b5afe88109..4c6f90b4b0 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1549,7 +1549,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, if(Mathf.zero(dm)){ damage = health + 1; }else{ - damage /= dm; + damage = Damage.applyArmor(damage, block.armor) / dm; } Call.tileDamage(self(), health - handleDamage(damage)); diff --git a/core/src/mindustry/entities/comp/ShieldComp.java b/core/src/mindustry/entities/comp/ShieldComp.java index aa77d1e8bc..659630ecf0 100644 --- a/core/src/mindustry/entities/comp/ShieldComp.java +++ b/core/src/mindustry/entities/comp/ShieldComp.java @@ -3,11 +3,10 @@ package mindustry.entities.comp; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.entities.*; import mindustry.game.*; import mindustry.gen.*; -import static mindustry.Vars.*; - @Component abstract class ShieldComp implements Healthc, Posc{ @Import float health, hitTime, x, y, healthMultiplier; @@ -24,11 +23,8 @@ abstract class ShieldComp implements Healthc, Posc{ @Replace @Override public void damage(float amount){ - //apply armor - amount = Math.max(amount - armor, minArmorDamage * amount); - amount /= healthMultiplier; - - rawDamage(amount); + //apply armor and scaling effects + rawDamage(Damage.applyArmor(amount, armor) / healthMultiplier); } @Replace diff --git a/core/src/mindustry/entities/comp/TankComp.java b/core/src/mindustry/entities/comp/TankComp.java index 6dfa5d0044..67168e301c 100644 --- a/core/src/mindustry/entities/comp/TankComp.java +++ b/core/src/mindustry/entities/comp/TankComp.java @@ -3,20 +3,24 @@ package mindustry.entities.comp; import arc.math.*; import arc.math.geom.*; import arc.util.*; +import mindustry.*; import mindustry.annotations.Annotations.*; +import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; +import mindustry.world.*; import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; @Component abstract class TankComp implements Posc, Flyingc, Hitboxc, Unitc, ElevationMovec{ - @Import float x, y, hitSize, rotation; + @Import float x, y, hitSize, rotation, speedMultiplier; + @Import boolean hovering; @Import UnitType type; - transient private float treadEffectTime; + transient private float treadEffectTime, lastSlowdown = 1f; transient float treadTime; transient boolean walked; @@ -43,6 +47,22 @@ abstract class TankComp implements Posc, Flyingc, Hitboxc, Unitc, ElevationMovec } } + //calculate overlapping tiles so it slows down when going "over" walls + //TODO is this a necessary mechanic? + int r = Math.max(Math.round(hitSize * 0.6f / tilesize), 1); + + int solids = 0, total = (r*2+1)*(r*2+1); + for(int dx = -r; dx <= r; dx++){ + for(int dy = -r; dy <= r; dy++){ + Tile t = Vars.world.tileWorld(x + dx*tilesize, y + dy*tilesize); + if(t == null || t.solid()){ + solids ++; + } + } + } + + lastSlowdown = Mathf.lerp(1f, type.crawlSlowdown, Mathf.clamp((float)solids / total / type.crawlSlowdownFrac)); + //trigger animation only when walking manually if(walked || net.client()){ float len = deltaLen(); @@ -51,6 +71,14 @@ abstract class TankComp implements Posc, Flyingc, Hitboxc, Unitc, ElevationMovec } } + @Override + @Replace + public float floorSpeedMultiplier(){ + Floor on = isFlying() || hovering ? Blocks.air.asFloor() : floorOn(); + //TODO take into account extra blocks + return on.speedMultiplier * speedMultiplier * lastSlowdown; + } + @Replace @Override public @Nullable Floor drownFloor(){ diff --git a/core/src/mindustry/type/BlockStack.java b/core/src/mindustry/type/BlockStack.java new file mode 100644 index 0000000000..0199bbb9a4 --- /dev/null +++ b/core/src/mindustry/type/BlockStack.java @@ -0,0 +1,56 @@ +package mindustry.type; + +import arc.struct.*; +import mindustry.content.*; +import mindustry.world.*; + +public class BlockStack implements Comparable{ + public Block block = Blocks.router; + public int amount = 1; + + public BlockStack(Block block, int amount){ + this.block = block; + this.amount = amount; + } + + public BlockStack(Block block){ + this.block = block; + } + + public BlockStack(){ + } + + public static BlockStack[] with(Object... items){ + var stacks = new BlockStack[items.length / 2]; + for(int i = 0; i < items.length; i += 2){ + stacks[i / 2] = new BlockStack((Block)items[i], ((Number)items[i + 1]).intValue()); + } + return stacks; + } + + public static Seq list(Object... items){ + Seq stacks = new Seq<>(items.length / 2); + for(int i = 0; i < items.length; i += 2){ + stacks.add(new BlockStack((Block)items[i], ((Number)items[i + 1]).intValue())); + } + return stacks; + } + + @Override + public int compareTo(BlockStack stack){ + return block.compareTo(stack.block); + } + + @Override + public boolean equals(Object o){ + return this == o || (o instanceof BlockStack stack && stack.amount == amount && block == stack.block); + } + + @Override + public String toString(){ + return "BlockStack{" + + "block=" + block + + ", amount=" + amount + + '}'; + } +} diff --git a/core/src/mindustry/type/ItemStack.java b/core/src/mindustry/type/ItemStack.java index ec15207760..253d6d4033 100644 --- a/core/src/mindustry/type/ItemStack.java +++ b/core/src/mindustry/type/ItemStack.java @@ -67,9 +67,7 @@ public class ItemStack implements Comparable{ @Override public boolean equals(Object o){ - if(this == o) return true; - if(!(o instanceof ItemStack stack)) return false; - return amount == stack.amount && item == stack.item; + return this == o || (o instanceof ItemStack stack && stack.amount == amount && item == stack.item); } @Override diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 8064ee77e7..9a1e18e1d5 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -134,6 +134,8 @@ public class Block extends UnlockableContent{ public Attributes attributes = new Attributes(); /** tile entity health */ public int health = -1; + /** damage absorption, similar to unit armor */ + public float armor = 0f; /** base block explosiveness */ public float baseExplosiveness = 0f; /** bullet that this block spawns when destroyed */ @@ -429,6 +431,9 @@ public class Block extends UnlockableContent{ if(synthetic()){ stats.add(Stat.health, health, StatUnit.none); + if(armor > 0){ + stats.add(Stat.armor, armor, StatUnit.none); + } } if(canBeBuilt() && requirements.length > 0){ diff --git a/core/src/mindustry/world/blocks/units/UnitAssembler.java b/core/src/mindustry/world/blocks/units/UnitAssembler.java index 4b5b915ac2..5617930bda 100644 --- a/core/src/mindustry/world/blocks/units/UnitAssembler.java +++ b/core/src/mindustry/world/blocks/units/UnitAssembler.java @@ -3,6 +3,7 @@ package mindustry.world.blocks.units; import arc.math.geom.*; import arc.struct.*; import arc.util.*; +import arc.util.io.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -20,8 +21,12 @@ import static mindustry.Vars.*; * */ public class UnitAssembler extends PayloadBlock{ public int areaSize = 10; - public UnitType unitType; - public int unitsCreated = 4; + public UnitType droneType; + public int dronesCreated = 4; + + //TODO should be different for every tier. + public Seq requirements = new Seq<>(); + public UnitType output = UnitTypes.vanquish; public UnitAssembler(String name){ super(name); @@ -47,17 +52,19 @@ public class UnitAssembler extends PayloadBlock{ Drawf.dashRect(valid ? Pal.accent : Pal.remove, Tmp.r1); } - public class UnitAssemblerBuild extends PayloadBlockBuild{ + public class UnitAssemblerBuild extends PayloadBlockBuild{ public Seq units = new Seq<>(); - public Seq payloads = new Seq<>(); + + //TODO how should payloads be stored? counts of blocks? intmap? references? + //public Seq payloads = new Seq<>(); @Override public void updateTile(){ units.removeAll(u -> !u.isAdded() || u.dead); - if(consValid() && units.size < unitsCreated){ + if(consValid() && units.size < dronesCreated){ //TODO build animation? distribute spawning? - var unit = unitType.create(team); + var unit = droneType.create(team); if(unit instanceof BuildingTetherc bt){ bt.building(this); } @@ -69,12 +76,29 @@ public class UnitAssembler extends PayloadBlock{ units.add(unit); } - //TODO drones need to indicate that they are in position + //TODO drones need to indicate that they are in position and actually play an animation + } + + @Override + public void handlePayload(Building source, Payload payload){ + //super.handlePayload(source, payload); + + //payloads.add((BuildPayload)payload); } @Override public boolean acceptPayload(Building source, Payload payload){ - return super.acceptPayload(source, payload); + return payload instanceof BuildPayload bp && requirements.contains(b -> b.block == bp.block()); + } + + @Override + public void write(Writes write){ + super.write(write); + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); } } }