diff --git a/annotations/src/main/resources/revisions/AmmoDistributeBuilderCommanderPayloadUnit/1.json b/annotations/src/main/resources/revisions/AmmoDistributeBuilderCommanderPayloadUnit/1.json new file mode 100644 index 0000000000..1e9e8f02c7 --- /dev/null +++ b/annotations/src/main/resources/revisions/AmmoDistributeBuilderCommanderPayloadUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BlockUnitUnit/2.json b/annotations/src/main/resources/revisions/BlockUnitUnit/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/BlockUnitUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/2.json b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/2.json new file mode 100644 index 0000000000..541f5f8c57 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderLegsUnit/2.json b/annotations/src/main/resources/revisions/BuilderLegsUnit/2.json new file mode 100644 index 0000000000..fe5760e693 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderLegsUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/2.json b/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/2.json new file mode 100644 index 0000000000..87371c85dd --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerUnit/2.json b/annotations/src/main/resources/revisions/BuilderMinerUnit/2.json new file mode 100644 index 0000000000..f210a1f05c --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMinerUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderPayloadUnit/2.json b/annotations/src/main/resources/revisions/BuilderPayloadUnit/2.json new file mode 100644 index 0000000000..c0af7d53a9 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderPayloadUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderLegsUnit/2.json b/annotations/src/main/resources/revisions/CommanderLegsUnit/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderLegsUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderMechUnit/2.json b/annotations/src/main/resources/revisions/CommanderMechUnit/2.json new file mode 100644 index 0000000000..7b348dd022 --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderMechUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderUnitWaterMove/2.json b/annotations/src/main/resources/revisions/CommanderUnitWaterMove/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderUnitWaterMove/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/LegsUnit/2.json b/annotations/src/main/resources/revisions/LegsUnit/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/LegsUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MechUnit/2.json b/annotations/src/main/resources/revisions/MechUnit/2.json new file mode 100644 index 0000000000..7b348dd022 --- /dev/null +++ b/annotations/src/main/resources/revisions/MechUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MinerUnit/2.json b/annotations/src/main/resources/revisions/MinerUnit/2.json new file mode 100644 index 0000000000..6a6cc37b39 --- /dev/null +++ b/annotations/src/main/resources/revisions/MinerUnit/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/UnitEntity/2.json b/annotations/src/main/resources/revisions/UnitEntity/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/UnitEntity/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index 5eda85c0fd..157ed2eb9d 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -45,7 +45,7 @@ public class GroundAI extends AIController{ } } - if(unit.type().canBoost && unit.tileOn() != null && !unit.tileOn().solid()){ + if(unit.type().canBoost && !unit.onSolid()){ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f); } diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java index 80ca77b778..df856d6688 100644 --- a/core/src/mindustry/ai/types/LogicAI.java +++ b/core/src/mindustry/ai/types/LogicAI.java @@ -1,11 +1,11 @@ package mindustry.ai.types; +import arc.math.*; import arc.struct.*; import arc.util.*; import mindustry.ai.*; import mindustry.entities.units.*; import mindustry.gen.*; -import mindustry.logic.LExecutor.*; import mindustry.logic.*; import mindustry.world.*; import mindustry.world.meta.*; @@ -20,12 +20,18 @@ public class LogicAI extends AIController{ public LUnitControl control = LUnitControl.stop; public float moveX, moveY, moveRad; - public float itemTimer, controlTimer = logicControlTimeout, targetTimer; + public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer; public Building controller; + public BuildPlan plan = new BuildPlan(); + + //special cache for instruction to store data + public ObjectMap execCache = new ObjectMap<>(); //type of aiming to use public LUnitControl aimControl = LUnitControl.stop; + //whether to use the boost (certain units only) + public boolean boost; //main target set for shootP public Teamc mainTarget; //whether to shoot at all @@ -33,19 +39,18 @@ public class LogicAI extends AIController{ //target shoot positions for manual aiming public PosTeam posTarget = PosTeam.create(); - private ObjectSet radars = new ObjectSet<>(); + private ObjectSet radars = new ObjectSet<>(); @Override protected void updateMovement(){ - if(itemTimer > 0){ - itemTimer -= Time.delta; - } + if(itemTimer > 0) itemTimer -= Time.delta; + if(payTimer > 0) payTimer -= Time.delta; if(targetTimer > 0f){ targetTimer -= Time.delta; }else{ radars.clear(); - targetTimer = 30f; + targetTimer = 40f; } //timeout when not controlled by logic for a while @@ -61,7 +66,7 @@ public class LogicAI extends AIController{ moveTo(Tmp.v1.set(moveX, moveY), 1f, 30f); } case approach -> { - moveTo(Tmp.v1.set(moveX, moveY), moveRad, 1f); + moveTo(Tmp.v1.set(moveX, moveY), moveRad - 8f, 8f); } case pathfind -> { Building core = unit.closestEnemyCore(); @@ -85,6 +90,15 @@ public class LogicAI extends AIController{ } } } + case stop -> { + if(unit instanceof Builderc build){ + build.clearBuilding(); + } + } + } + + if(unit.type().canBoost && !unit.type().flying){ + unit.elevation = Mathf.approachDelta(unit.elevation, Mathf.num(boost || unit.onSolid()), 0.08f); } //look where moving if there's nothing to aim at @@ -97,7 +111,7 @@ public class LogicAI extends AIController{ } } - public boolean checkTargetTimer(RadarI radar){ + public boolean checkTargetTimer(Object radar){ return radars.add(radar); } @@ -114,7 +128,7 @@ public class LogicAI extends AIController{ @Override protected boolean shouldShoot(){ - return shoot; + return shoot && !(unit.type().canBoost && boost); } //always aim for the main target diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index b4b9cd038e..a5327cd6a3 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -287,7 +287,7 @@ public class Blocks implements ContentList{ salt = new Floor("salt"){{ variants = 0; - attributes.set(Attribute.water, -0.25f); + attributes.set(Attribute.water, -0.3f); attributes.set(Attribute.oil, 0.3f); }}; @@ -718,7 +718,7 @@ public class Blocks implements ContentList{ size = 2; hasPower = hasItems = hasLiquids = true; - consumes.liquid(Liquids.oil, 0.09f); + consumes.liquid(Liquids.oil, 0.1f); consumes.power(0.5f); }}; @@ -1119,7 +1119,7 @@ public class Blocks implements ContentList{ requirements(Category.power, with(Items.titanium, 7, Items.lead, 10, Items.silicon, 15, Items.surgealloy, 15)); size = 2; maxNodes = 2; - laserRange = 30f; + laserRange = 40f; }}; diode = new PowerDiode("diode"){{ diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index 9b7e5f8805..514a9d9518 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -379,12 +379,18 @@ public class Bullets implements ContentList{ JsonIO.copy(damageLightning, damageLightningGround); damageLightningGround.collidesAir = false; - healBullet = new HealBulletType(5.2f, 13){{ + healBullet = new LaserBoltBulletType(5.2f, 13){{ healPercent = 3f; + collidesTeam = true; + backColor = Pal.heal; + frontColor = Color.white; }}; - healBulletBig = new HealBulletType(5.2f, 15){{ + healBulletBig = new LaserBoltBulletType(5.2f, 15){{ healPercent = 5.5f; + collidesTeam = true; + backColor = Pal.heal; + frontColor = Color.white; }}; fireball = new BulletType(1f, 4){ diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index a6dd9e2982..2fcb360274 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -293,10 +293,10 @@ public class UnitTypes implements ContentList{ pulsar = new UnitType("pulsar"){{ canBoost = true; - boostMultiplier = 1.5f; - speed = 0.65f; + boostMultiplier = 1.6f; + speed = 0.7f; hitSize = 10f; - health = 320f; + health = 300f; buildSpeed = 0.9f; armor = 4f; @@ -335,7 +335,7 @@ public class UnitTypes implements ContentList{ }}; quasar = new UnitType("quasar"){{ - mineTier = 1; + mineTier = 3; hitSize = 12f; boostMultiplier = 2f; health = 650f; @@ -351,8 +351,7 @@ public class UnitTypes implements ContentList{ speed = 0.4f; hitSize = 10f; - mineTier = 2; - mineSpeed = 7f; + mineSpeed = 6f; drawShields = false; abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6)); @@ -515,7 +514,7 @@ public class UnitTypes implements ContentList{ crawler = new UnitType("crawler"){{ defaultController = SuicideAI::new; - speed = 0.9f; + speed = 0.92f; hitSize = 8f; health = 180; mechSideSway = 0.25f; @@ -1182,8 +1181,13 @@ public class UnitTypes implements ContentList{ keepVelocity = false; shootEffect = Fx.shootHeal; smokeEffect = Fx.hitLaser; + hitEffect = despawnEffect = Fx.hitLaser; frontColor = Color.white; + healPercent = 5.5f; + collidesTeam = true; + backColor = Pal.heal; + frontColor = Color.white; backColor = Pal.heal; trailColor = Pal.heal; }}; @@ -1193,7 +1197,7 @@ public class UnitTypes implements ContentList{ mega = new UnitType("mega"){{ defaultController = RepairAI::new; - mineTier = 2; + mineTier = 3; health = 500; armor = 2f; armor = 5f; @@ -1285,6 +1289,7 @@ public class UnitTypes implements ContentList{ speed = 0.001f; collides = false; + healPercent = 10f; splashDamage = 240f; splashDamageRadius = 115f; }}; diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 8d333fa6ad..71414c3745 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -13,6 +13,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -77,6 +78,8 @@ public abstract class BulletType extends Content{ public boolean backMove = true; /** Bullet range override. */ public float range = -1f; + /** Heal Bullet Percent **/ + public float healPercent = 0f; //additional effects @@ -139,7 +142,7 @@ public abstract class BulletType extends Content{ } public boolean collides(Bullet bullet, Building tile){ - return true; + return healPercent <= 0.001f || tile.team != bullet.team || tile.healthf() < 1f; } public void hitTile(Bullet b, Building tile, float initialHealth){ @@ -147,6 +150,11 @@ public abstract class BulletType extends Content{ Fires.create(tile.tile); } hit(b); + + if(healPercent > 0f && tile.team == b.team && !(tile.block instanceof ConstructBlock)){ + Fx.healBlockFull.at(tile.x, tile.y, tile.block.size, Pal.heal); + tile.heal(healPercent / 100f * tile.maxHealth()); + } } public void hitEntity(Bullet b, Hitboxc other, float initialHealth){ @@ -188,6 +196,13 @@ public abstract class BulletType extends Content{ if(status != StatusEffects.none){ Damage.status(b.team, x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround); } + + if(healPercent > 0f) { + indexer.eachBlock(b.team, x, y, splashDamageRadius, other -> other.damaged(), other -> { + Fx.healBlockFull.at(other.x, other.y, other.block.size, Pal.heal); + other.heal(healPercent / 100f * other.maxHealth()); + }); + } if(status == StatusEffects.burning) { indexer.eachBlock(null, x, y, splashDamageRadius, other -> other.team != b.team, other -> { diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java deleted file mode 100644 index b811790000..0000000000 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ /dev/null @@ -1,55 +0,0 @@ -package mindustry.entities.bullet; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import mindustry.content.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.world.blocks.*; - -public class HealBulletType extends BulletType{ - protected float healPercent = 3f; - protected float height = 7f, width = 2f; - protected Color backColor = Pal.heal, frontColor = Color.white; - - public HealBulletType(float speed, float damage){ - super(speed, damage); - - shootEffect = Fx.shootHeal; - smokeEffect = Fx.hitLaser; - hitEffect = Fx.hitLaser; - despawnEffect = Fx.hitLaser; - collidesTeam = true; - hittable = false; - reflectable = false; - } - - public HealBulletType(){ - this(1f, 1f); - } - - @Override - public boolean collides(Bullet b, Building tile){ - return tile.team != b.team || tile.healthf() < 1f; - } - - @Override - public void draw(Bullet b){ - Draw.color(backColor); - Lines.stroke(width); - Lines.lineAngleCenter(b.x, b.y, b.rotation(), height); - Draw.color(frontColor); - Lines.lineAngleCenter(b.x, b.y, b.rotation(), height / 2f); - Draw.reset(); - } - - @Override - public void hitTile(Bullet b, Building tile, float initialHealth){ - super.hit(b); - - if(tile.team == b.team && !(tile.block instanceof ConstructBlock)){ - Fx.healBlockFull.at(tile.x, tile.y, tile.block.size, Pal.heal); - tile.heal(healPercent / 100f * tile.maxHealth()); - } - } -} diff --git a/core/src/mindustry/entities/bullet/LaserBoltBulletType.java b/core/src/mindustry/entities/bullet/LaserBoltBulletType.java new file mode 100644 index 0000000000..bd1332443f --- /dev/null +++ b/core/src/mindustry/entities/bullet/LaserBoltBulletType.java @@ -0,0 +1,34 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import mindustry.gen.*; +import mindustry.content.*; + +public class LaserBoltBulletType extends BasicBulletType{ + protected float height = 7f, width = 2f; + + public LaserBoltBulletType(float speed, float damage){ + super(speed, damage); + + smokeEffect = Fx.hitLaser; + hitEffect = Fx.hitLaser; + despawnEffect = Fx.hitLaser; + hittable = false; + reflectable = false; + } + + public LaserBoltBulletType(){ + this(1f, 1f); + } + + @Override + public void draw(Bullet b){ + Draw.color(backColor); + Lines.stroke(width); + Lines.lineAngleCenter(b.x, b.y, b.rotation(), height); + Draw.color(frontColor); + Lines.lineAngleCenter(b.x, b.y, b.rotation(), height / 2f); + Draw.reset(); + } +} diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 92a8026708..5a285aca10 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -46,7 +46,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, static final Seq tempTiles = new Seq<>(); static int sleepingEntities = 0; - @Import float x, y, health; + @Import float x, y, health, maxHealth; @Import Team team; transient Tile tile; @@ -1224,7 +1224,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, case y -> y; case team -> team.id; case health -> health; - case maxHealth -> maxHealth(); + case maxHealth -> maxHealth; case efficiency -> efficiency(); case rotation -> rotation; case totalItems -> items == null ? 0 : items.total(); @@ -1238,6 +1238,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored(); case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity(); case enabled -> enabled ? 1 : 0; + case payloadCount -> getPayload() != null ? 1 : 0; default -> 0; }; } @@ -1247,7 +1248,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return switch(sensor){ case type -> block; case firstItem -> items == null ? null : items.first(); - case name -> block.name; + case config -> block.configurations.containsKey(Item.class) || block.configurations.containsKey(Liquid.class) ? config() : null; + case payloadType -> getPayload() instanceof UnitPayload p1 ? p1.unit.type() : getPayload() instanceof BlockPayload p2 ? p2.block() : null; default -> noSensed; }; diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java index 6e11178252..6bac9dbd60 100644 --- a/core/src/mindustry/entities/comp/MinerComp.java +++ b/core/src/mindustry/entities/comp/MinerComp.java @@ -35,6 +35,11 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ return mineTile != null && !(((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding()); } + public boolean validMine(Tile tile){ + return !(tile == null || tile.block() != Blocks.air || !within(tile.worldx(), tile.worldy(), miningRange) + || tile.drop() == null || !canMine(tile.drop())); + } + @Override public void update(){ Building core = closestCore(); @@ -49,8 +54,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ } } - if(mineTile == null || core == null || mineTile.block() != Blocks.air || dst(mineTile.worldx(), mineTile.worldy()) > miningRange - || mineTile.drop() == null || !canMine(mineTile.drop())){ + if(core == null || !validMine(mineTile)){ mineTile = null; mineTimer = 0f; }else if(mining()){ @@ -62,7 +66,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ Fx.pulverizeSmall.at(mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color); } - if(mineTimer >= 50f + item.hardness*10f){ + if(mineTimer >= 50f + item.hardness*15f){ mineTimer = 0; if(within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){ diff --git a/core/src/mindustry/entities/comp/PosComp.java b/core/src/mindustry/entities/comp/PosComp.java index 1c0540eb01..15c665739e 100644 --- a/core/src/mindustry/entities/comp/PosComp.java +++ b/core/src/mindustry/entities/comp/PosComp.java @@ -52,7 +52,7 @@ abstract class PosComp implements Position{ boolean onSolid(){ Tile tile = tileOn(); - return tile != null && tile.solid(); + return tile == null || tile.solid(); } @Nullable diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index b8e0a82ef3..e226edd2ee 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -23,6 +23,7 @@ import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; +import mindustry.world.blocks.payloads.*; import static mindustry.Vars.*; @@ -37,9 +38,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I private UnitController controller; private UnitType type; boolean spawnedByCore; - - //TODO mark as non-transient when done - transient double flag; + double flag; transient Seq abilities = new Seq<>(0); private transient float resupplyTime = Mathf.random(10f); @@ -66,6 +65,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return type.hasWeapons(); } + /** @return speed with boost multipliers factored in. */ + public float realSpeed(){ + return Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation) * type.speed; + } + @Override public float range(){ return type.range; @@ -91,6 +95,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I case shootX -> aimX(); case shootY -> aimY(); case flag -> flag; + case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0; default -> 0; }; } @@ -99,8 +104,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I public Object senseObject(LAccess sensor){ return switch(sensor){ case type -> type; - case name -> controller instanceof Player p ? p.name : type.name; + case name -> controller instanceof Player p ? p.name : null; case firstItem -> stack().amount == 0 ? null : item(); + case payloadType -> self() instanceof Payloadc pay ? + (pay.payloads().isEmpty() ? null : + pay.payloads().peek() instanceof UnitPayload p1 ? p1.unit.type() : + pay.payloads().peek() instanceof BlockPayload p2 ? p2.block() : null) : null; default -> noSensed; }; diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index 7e84a163d6..d235972212 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -187,7 +187,7 @@ public class AIController implements UnitController{ float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f); - vec.setLength(unit.type().speed * length); + vec.setLength(unit.realSpeed() * length); if(length < -0.5f){ vec.rotate(180f); }else if(length < 0){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 868f9a254c..1b6e92caf2 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -159,7 +159,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(target.isAI() && target.isGrounded() && pay.canPickup(target) && target.within(unit, unit.type().hitSize * 2f + target.type().hitSize * 2f)){ - Call.pickedUnitPayload(player, target); + Call.pickedUnitPayload(unit, target); } } @@ -174,57 +174,49 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ && unit.within(tile, tilesize * tile.block.size * 1.2f + tilesize * 5f)){ //pick up block directly if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ - Call.pickedBlockPayload(player, tile, true); + Call.pickedBlockPayload(unit, tile, true); }else{ //pick up block payload Payload current = tile.getPayload(); if(current != null && pay.canPickupPayload(current)){ - Call.pickedBlockPayload(player, tile, false); + Call.pickedBlockPayload(unit, tile, false); } } } } @Remote(targets = Loc.server, called = Loc.server) - public static void pickedUnitPayload(Player player, Unit target){ - if(player == null || target == null || !(player.unit() instanceof Payloadc)){ - if(target != null){ - target.remove(); - } - return; + public static void pickedUnitPayload(Unit unit, Unit target){ + if(target != null && unit instanceof Payloadc pay){ + pay.pickup(target); + }else if(target != null){ + target.remove(); } - - ((Payloadc)player.unit()).pickup(target); } @Remote(targets = Loc.server, called = Loc.server) - public static void pickedBlockPayload(Player player, Building tile, boolean onGround){ - if(player == null || tile == null || !(player.unit() instanceof Payloadc)){ - if(tile != null && onGround){ - Fx.unitPickup.at(tile); - tile.tile.remove(); - } - return; - } - - Unit unit = player.unit(); - Payloadc pay = (Payloadc)unit; - - if(onGround){ - if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ - pay.pickup(tile); - }else{ - Fx.unitPickup.at(tile); - tile.tile.remove(); - } - }else{ - Payload current = tile.getPayload(); - if(current != null && pay.canPickupPayload(current)){ - Payload taken = tile.takePayload(); - if(taken != null){ - pay.addPayload(taken); + public static void pickedBlockPayload(Unit unit, Building tile, boolean onGround){ + if(tile != null && unit instanceof Payloadc pay){ + if(onGround){ + if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ + pay.pickup(tile); + }else{ Fx.unitPickup.at(tile); + tile.tile.remove(); + } + }else{ + Payload current = tile.getPayload(); + if(current != null && pay.canPickupPayload(current)){ + Payload taken = tile.takePayload(); + if(taken != null){ + pay.addPayload(taken); + Fx.unitPickup.at(tile); + } } } + + }else if(tile != null && onGround){ + Fx.unitPickup.at(tile); + tile.tile.remove(); } } @@ -238,19 +230,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Tmp.v1.set(x, y).sub(pay).limit(tilesize * 4f).add(pay); float cx = Tmp.v1.x, cy = Tmp.v1.y; - Call.payloadDropped(player, cx, cy); + Call.payloadDropped(player.unit(), cx, cy); } @Remote(called = Loc.server, targets = Loc.server) - public static void payloadDropped(Player player, float x, float y){ - if(player == null) return; - - Payloadc pay = (Payloadc)player.unit(); - - float prevx = pay.x(), prevy = pay.y(); - pay.set(x, y); - pay.dropLastPayload(); - pay.set(prevx, prevy); + public static void payloadDropped(Unit unit, float x, float y){ + if(unit instanceof Payloadc pay){ + float prevx = pay.x(), prevy = pay.y(); + pay.set(x, y); + pay.dropLastPayload(); + pay.set(prevx, prevy); + } } @Remote(targets = Loc.client, called = Loc.server) diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java index 4cb1563ad7..5dc881a778 100644 --- a/core/src/mindustry/logic/LAccess.java +++ b/core/src/mindustry/logic/LAccess.java @@ -29,6 +29,9 @@ public enum LAccess{ type, flag, name, + config, + payloadCount, + payloadType, //values with parameters are considered controllable enabled("to"), //"to" is standard for single parameter access diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index bd3690110b..e355416427 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -4,6 +4,7 @@ import arc.func.*; import arc.struct.*; import arc.util.*; import mindustry.*; +import mindustry.content.*; import mindustry.gen.*; import mindustry.logic.LExecutor.*; import mindustry.logic.LStatements.*; @@ -51,6 +52,8 @@ public class LAssembler{ } } + putConst("@air", Blocks.air); + for(UnitType type : Vars.content.units()){ putConst("@" + type.name, type); } diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index d92607967b..d1db916be1 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1,5 +1,6 @@ package mindustry.logic; +import arc.math.geom.*; import arc.struct.*; import arc.util.*; import arc.util.noise.*; @@ -14,6 +15,8 @@ import mindustry.world.*; import mindustry.world.blocks.logic.LogicDisplay.*; import mindustry.world.blocks.logic.MemoryBlock.*; import mindustry.world.blocks.logic.MessageBlock.*; +import mindustry.world.blocks.payloads.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -117,6 +120,10 @@ public class LExecutor{ return (int)num(index); } + public void setbool(int index, boolean value){ + setnum(index, value ? 1 : 0); + } + public void setnum(int index, double value){ Var v = vars[index]; if(v.constant) return; @@ -194,8 +201,25 @@ public class LExecutor{ } } - /** Binds the processor to a unit based on some filters. */ + /** Uses a unit to find something that may not be in its range. */ public static class UnitLocateI implements LInstruction{ + public LLocate locate = LLocate.building; + public BlockFlag flag = BlockFlag.core; + public int enemy, ore; + public int outX, outY, outFound; + + public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound){ + this.locate = locate; + this.flag = flag; + this.enemy = enemy; + this.ore = ore; + this.outX = outX; + this.outY = outY; + this.outFound = outFound; + } + + public UnitLocateI(){ + } @Override public void run(LExecutor exec){ @@ -205,8 +229,49 @@ public class LExecutor{ if(unitObj instanceof Unit unit && ai != null){ ai.controlTimer = LogicAI.logicControlTimeout; + Cache cache = (Cache)ai.execCache.get(this, Cache::new); + + if(ai.checkTargetTimer(this)){ + Tile res = null; + boolean build = false; + + switch(locate){ + case ore -> { + if(exec.obj(ore) instanceof Item item){ + res = indexer.findClosestOre(unit.x, unit.y, item); + } + } + case building -> { + res = Geometry.findClosest(unit.x, unit.y, exec.bool(enemy) ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag)); + build = true; + } + case spawn -> { + res = Geometry.findClosest(unit.x, unit.y, Vars.spawner.getSpawns()); + } + } + + if(res != null && (!build || res.build != null)){ + cache.found = true; + //set result if found + exec.setnum(outX, cache.x = build ? res.build.x : res.worldx()); + exec.setnum(outY, cache.y = build ? res.build.y : res.worldy()); + exec.setnum(outFound, 1); + }else{ + cache.found = false; + exec.setnum(outFound, 0); + } + }else{ + exec.setbool(outFound, cache.found); + exec.setnum(outX, cache.x); + exec.setnum(outY, cache.y); + } } } + + static class Cache{ + float x, y; + boolean found; + } } /** Controls the unit based on some parameters. */ @@ -266,6 +331,19 @@ public class LExecutor{ if(type == LUnitControl.approach){ ai.moveRad = exec.numf(p3); } + + //stop mining/building + if(type == LUnitControl.stop){ + if(unit instanceof Minerc miner){ + miner.mineTile(null); + } + if(unit instanceof Builderc build){ + build.clearBuilding(); + } + } + } + case within -> { + exec.setnum(p4, unit.within(exec.numf(p1), exec.numf(p2), exec.numf(p3)) ? 1 : 0); } case pathfind -> { ai.control = type; @@ -281,13 +359,81 @@ public class LExecutor{ ai.mainTarget = exec.obj(p1) instanceof Teamc t ? t : null; ai.shoot = exec.bool(p2); } + case boost -> { + ai.boost = exec.bool(p1); + } case flag -> { unit.flag = exec.num(p1); } case mine -> { Tile tile = world.tileWorld(exec.numf(p1), exec.numf(p2)); if(unit instanceof Minerc miner){ - miner.mineTile(tile); + miner.mineTile(miner.validMine(tile) ? tile : null); + } + } + case payDrop -> { + if(ai.payTimer > 0) return; + + if(unit instanceof Payloadc pay && pay.hasPayload()){ + Call.payloadDropped(unit, unit.x, unit.y); + ai.payTimer = LogicAI.transferDelay; + } + } + case payTake -> { + if(ai.payTimer > 0) return; + + if(unit instanceof Payloadc pay){ + //units + if(exec.bool(p1)){ + Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type().hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f)); + + Call.pickedUnitPayload(unit, result); + }else{ //buildings + Building tile = world.buildWorld(unit.x, unit.y); + + //TODO copy pasted code + if(tile != null && tile.team == unit.team){ + if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ + Call.pickedBlockPayload(unit, tile, true); + }else{ //pick up block payload + Payload current = tile.getPayload(); + if(current != null && pay.canPickupPayload(current)){ + Call.pickedBlockPayload(unit, tile, false); + } + } + } + } + ai.payTimer = LogicAI.transferDelay; + } + } + case build -> { + if(unit instanceof Builderc builder && exec.obj(p3) instanceof Block block){ + int x = world.toTile(exec.numf(p1)), y = world.toTile(exec.numf(p2)); + int rot = exec.numi(p4); + + //reset state of last request when necessary + if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || builder.plans().isEmpty()){ + ai.plan.progress = 0; + ai.plan.initialized = false; + ai.plan.stuck = false; + } + + ai.plan.set(x, y, rot, block); + ai.plan.config = null; + + builder.clearBuilding(); + builder.updateBuilding(true); + builder.addBuild(ai.plan); + } + } + case getBlock -> { + float x = exec.numf(p1), y = exec.numf(p2); + if(unit.within(x, y, unit.range())){ + exec.setobj(p3, null); + }else{ + Tile tile = world.tileWorld(x, y); + Block block = tile == null || !tile.synthetic() ? null : tile.block(); + exec.setobj(p3, block); } } case itemDrop -> { diff --git a/core/src/mindustry/logic/LLocate.java b/core/src/mindustry/logic/LLocate.java new file mode 100644 index 0000000000..679136e74f --- /dev/null +++ b/core/src/mindustry/logic/LLocate.java @@ -0,0 +1,9 @@ +package mindustry.logic; + +public enum LLocate{ + ore, + building, + spawn; + + public static final LLocate[] all = values(); +} diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 10fd77f8d8..a96adaf9d9 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -12,6 +12,7 @@ import mindustry.logic.LCanvas.*; import mindustry.logic.LExecutor.*; import mindustry.type.*; import mindustry.ui.*; +import mindustry.world.meta.*; import static mindustry.world.blocks.logic.LogicDisplay.*; @@ -724,7 +725,7 @@ public class LStatements{ type = "@" + item.name; field.setText(type); hide.run(); - }).size(40f); + }).size(40f).get().resizeImage(Cicon.small.size); if(++c % 6 == 0) i.row(); } @@ -812,4 +813,109 @@ public class LStatements{ return new RadarI(target1, target2, target3, sort, LExecutor.varUnit, builder.var(sortOrder), builder.var(output)); } } + + @RegisterStatement("ulocate") + public static class UnitLocateStatement extends LStatement{ + public LLocate locate = LLocate.building; + public BlockFlag flag = BlockFlag.core; + public String enemy = "true", ore = "@copper"; + public String outX = "outx", outY = "outy", outFound = "found"; + + @Override + public void build(Table table){ + rebuild(table); + } + + void rebuild(Table table){ + table.clearChildren(); + + table.add(" find ").left(); + + table.button(b -> { + b.label(() -> locate.name()); + b.clicked(() -> showSelect(b, LLocate.all, locate, t -> { + locate = t; + rebuild(table); + }, 2, cell -> cell.size(110, 50))); + }, Styles.logict, () -> {}).size(110, 40).color(table.color).left().padLeft(2); + + switch(locate){ + case building -> { + row(table); + table.add(" type ").left(); + table.button(b -> { + b.label(() -> flag.name()); + b.clicked(() -> showSelect(b, BlockFlag.all, flag, t -> flag = t, 2, cell -> cell.size(110, 50))); + }, Styles.logict, () -> {}).size(110, 40).color(table.color).left().padLeft(2); + row(table); + + table.add(" enemy ").left(); + + fields(table, enemy, str -> enemy = str); + + table.row(); + } + + case ore -> { + table.add(" ore ").left(); + table.table(ts -> { + ts.color.set(table.color); + + field(ts, ore, str -> ore = str); + + ts.button(b -> { + b.image(Icon.pencilSmall); + b.clicked(() -> showSelectTable(b, (t, hide) -> { + t.row(); + t.table(i -> { + i.left(); + int c = 0; + for(Item item : Vars.content.items()){ + if(!item.unlockedNow()) continue; + i.button(new TextureRegionDrawable(item.icon(Cicon.small)), Styles.cleari, () -> { + ore = "@" + item.name; + rebuild(table); + hide.run(); + }).size(40f).get().resizeImage(Cicon.small.size); + + if(++c % 6 == 0) i.row(); + } + }).colspan(3).width(240f).left(); + })); + }, Styles.logict, () -> {}).size(40f).padLeft(-2).color(table.color); + }); + + + table.row(); + } + + case spawn -> { + table.row(); + } + } + + table.add(" outX ").left(); + fields(table, outX, str -> outX = str); + + table.add(" outY ").left(); + fields(table, outY, str -> outY = str); + + row(table); + + table.add(" found ").left(); + fields(table, outFound, str -> outFound = str); + + + } + + @Override + public LCategory category(){ + return LCategory.units; + } + + @Override + public LInstruction build(LAssembler builder){ + return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound)); + } + } } diff --git a/core/src/mindustry/logic/LUnitControl.java b/core/src/mindustry/logic/LUnitControl.java index b943e638d5..879578e59b 100644 --- a/core/src/mindustry/logic/LUnitControl.java +++ b/core/src/mindustry/logic/LUnitControl.java @@ -4,13 +4,19 @@ public enum LUnitControl{ stop, move("x", "y"), approach("x", "y", "radius"), + boost("enable"), pathfind(), target("x", "y", "shoot"), targetp("unit", "shoot"), itemDrop("to", "amount"), itemTake("from", "item", "amount"), + payDrop, + payTake("takeUnits"), mine("x", "y"), - flag("value"); + flag("value"), + build("x", "y", "block", "rotation"), + getBlock("x", "y", "result"), + within("x", "y", "radius", "result"); public final String[] params; public static final LUnitControl[] all = values(); diff --git a/core/src/mindustry/type/AmmoTypes.java b/core/src/mindustry/type/AmmoTypes.java index 6b3769b361..5b7c885519 100644 --- a/core/src/mindustry/type/AmmoTypes.java +++ b/core/src/mindustry/type/AmmoTypes.java @@ -41,7 +41,7 @@ public class AmmoTypes implements ContentList{ @Override public void resupply(Unit unit){ float range = unit.hitSize + 60f; - Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerResupply); + Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerRes); if(closest != null && closest.build != null && unit.within(closest.build, range) && closest.build.power != null){ var build = closest.build; diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 0ea8b99c1b..e2ea6adec7 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -235,7 +235,7 @@ public class UnitType extends UnlockableContent{ mechStepParticles = hitSize > 15f; } - canHeal = weapons.contains(w -> w.bullet instanceof HealBulletType); + canHeal = weapons.contains(w -> w.bullet.healPercent > 0f); //add mirrored weapon variants Seq mapped = new Seq<>(); diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java index 03e7d66193..7c1f364b37 100644 --- a/core/src/mindustry/world/blocks/power/Battery.java +++ b/core/src/mindustry/world/blocks/power/Battery.java @@ -20,7 +20,7 @@ public class Battery extends PowerDistributor{ super(name); outputsPower = true; consumesPower = true; - flags = EnumSet.of(BlockFlag.powerResupply); + flags = EnumSet.of(BlockFlag.powerRes); } public class BatteryBuild extends Building{ diff --git a/core/src/mindustry/world/blocks/units/ResupplyPoint.java b/core/src/mindustry/world/blocks/units/ResupplyPoint.java index c6d5e0aa18..2714be2358 100644 --- a/core/src/mindustry/world/blocks/units/ResupplyPoint.java +++ b/core/src/mindustry/world/blocks/units/ResupplyPoint.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.units; import arc.func.*; import arc.graphics.*; +import arc.struct.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.game.*; @@ -9,6 +10,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.AmmoTypes.*; import mindustry.world.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -24,6 +26,7 @@ public class ResupplyPoint extends Block{ super(name); solid = update = true; hasItems = true; + flags = EnumSet.of(BlockFlag.resupply); } @Override diff --git a/core/src/mindustry/world/meta/BlockFlag.java b/core/src/mindustry/world/meta/BlockFlag.java index c818ba642a..5c9bf2e920 100644 --- a/core/src/mindustry/world/meta/BlockFlag.java +++ b/core/src/mindustry/world/meta/BlockFlag.java @@ -13,7 +13,9 @@ public enum BlockFlag{ /** Rally point. */ rally, /** Block that stored power for resupply. */ - powerResupply, + powerRes, + /** Block used for resupply. */ + resupply, /** Any block that boosts unit capacity. */ unitModifier;