Merged Unit & Builder components / Cleanup

This commit is contained in:
Anuken
2020-11-17 19:40:18 -05:00
parent 8280166485
commit 527be41e32
38 changed files with 152 additions and 125 deletions

View File

@@ -1,10 +1,13 @@
#Maps entity names to IDs. Autogenerated. #Maps entity names to IDs. Autogenerated.
alpha=0 alpha=0
arkyid=29
atrax=1 atrax=1
beta=30
block=2 block=2
corvus=24 corvus=24
flare=3 flare=3
gamma=31
mace=4 mace=4
mega=5 mega=5
mindustry.entities.comp.BuildingComp=6 mindustry.entities.comp.BuildingComp=6
@@ -26,6 +29,8 @@ oct=26
poly=18 poly=18
pulsar=19 pulsar=19
quad=23 quad=23
quasar=32
risso=20 risso=20
spiroct=21 spiroct=21
toxopid=33
vela=25 vela=25

View File

@@ -0,0 +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:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +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:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +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:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:4,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:4,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:4,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +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:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:4,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:3,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +1 @@
{version:4,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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -0,0 +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:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}

View File

@@ -1279,6 +1279,7 @@ liquid.slag.description = Refined in separators into constituent metals, or spra
liquid.oil.description = Used in advanced material production and as incendiary ammunition. liquid.oil.description = Used in advanced material production and as incendiary ammunition.
liquid.cryofluid.description = Used as coolant in reactors, turrets and factories. liquid.cryofluid.description = Used as coolant in reactors, turrets and factories.
block.resupply-point.description = Resupplies nearby units with copper ammunition. Not compatible with units that require battery power.
block.armored-conveyor.description = Moves items forward. Does not accept inputs from the sides. block.armored-conveyor.description = Moves items forward. Does not accept inputs from the sides.
block.illuminator.description = Emits light. block.illuminator.description = Emits light.
block.message.description = Stores a message for communication between allies. block.message.description = Stores a message for communication between allies.

View File

@@ -14,21 +14,20 @@ import static mindustry.Vars.*;
public class BuilderAI extends AIController{ public class BuilderAI extends AIController{
float buildRadius = 1500; float buildRadius = 1500;
boolean found = false; boolean found = false;
@Nullable Builderc following; @Nullable Unit following;
@Override @Override
public void updateMovement(){ public void updateMovement(){
Builderc builder = (Builderc)unit;
if(builder.moving()){ if(unit.moving()){
builder.lookAt(builder.vel().angle()); unit.lookAt(unit.vel.angle());
} }
if(target != null && shouldShoot()){ if(target != null && shouldShoot()){
unit.lookAt(target); unit.lookAt(target);
} }
builder.updateBuilding(true); unit.updateBuilding = true;
if(following != null){ if(following != null){
//try to follow and mimic someone //try to follow and mimic someone
@@ -36,18 +35,18 @@ public class BuilderAI extends AIController{
//validate follower //validate follower
if(!following.isValid() || !following.activelyBuilding()){ if(!following.isValid() || !following.activelyBuilding()){
following = null; following = null;
builder.plans().clear(); unit.plans.clear();
return; return;
} }
//set to follower's first build plan, whatever that is //set to follower's first build plan, whatever that is
builder.plans().clear(); unit.plans.clear();
builder.plans().addFirst(following.buildPlan()); unit.plans.addFirst(following.buildPlan());
} }
if(builder.buildPlan() != null){ if(unit.buildPlan() != null){
//approach request if building //approach request if building
BuildPlan req = builder.buildPlan(); BuildPlan req = unit.buildPlan();
boolean valid = boolean valid =
(req.tile().build instanceof ConstructBuild && req.tile().<ConstructBuild>bc().cblock == req.block) || (req.tile().build instanceof ConstructBuild && req.tile().<ConstructBuild>bc().cblock == req.block) ||
@@ -60,7 +59,7 @@ public class BuilderAI extends AIController{
moveTo(req.tile(), buildingRange - 20f); moveTo(req.tile(), buildingRange - 20f);
}else{ }else{
//discard invalid request //discard invalid request
builder.plans().removeFirst(); unit.plans.removeFirst();
} }
}else{ }else{
@@ -71,8 +70,8 @@ public class BuilderAI extends AIController{
Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> { Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> {
if(found) return; if(found) return;
if(u instanceof Builderc b && u != unit && b.activelyBuilding()){ if(u.canBuild() && u != unit && u.activelyBuilding()){
BuildPlan plan = b.buildPlan(); BuildPlan plan = u.buildPlan();
Building build = world.build(plan.x, plan.y); Building build = world.build(plan.x, plan.y);
if(build instanceof ConstructBuild cons){ if(build instanceof ConstructBuild cons){
@@ -80,7 +79,7 @@ public class BuilderAI extends AIController{
//make sure you can reach the request in time //make sure you can reach the request in time
if(dist / unit.speed() < cons.buildCost * 0.9f){ if(dist / unit.speed() < cons.buildCost * 0.9f){
following = b; following = u;
found = true; found = true;
} }
} }
@@ -98,7 +97,7 @@ public class BuilderAI extends AIController{
blocks.removeFirst(); blocks.removeFirst();
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid. }else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid.
//add build request. //add build request.
builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config)); unit.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
//shift build plan to tail so next unit builds something else. //shift build plan to tail so next unit builds something else.
blocks.addLast(blocks.removeFirst()); blocks.addLast(blocks.removeFirst());
}else{ }else{

View File

@@ -59,13 +59,13 @@ public class FormationAI extends AIController implements FormationMember{
unit.moveAt(realtarget.sub(unit).limit(speed)); unit.moveAt(realtarget.sub(unit).limit(speed));
} }
if(unit instanceof Minerc mine && leader instanceof Minerc com){ if(unit.canMine() && leader.canMine()){
if(com.mineTile() != null && mine.validMine(com.mineTile())){ if(leader.mineTile != null && unit.validMine(leader.mineTile)){
mine.mineTile(com.mineTile()); unit.mineTile(leader.mineTile);
CoreBuild core = unit.team.core(); CoreBuild core = unit.team.core();
if(core != null && com.mineTile().drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(com.mineTile().drop())){ if(core != null && leader.mineTile.drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(leader.mineTile.drop())){
if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
@@ -73,13 +73,13 @@ public class FormationAI extends AIController implements FormationMember{
} }
} }
}else{ }else{
mine.mineTile(null); unit.mineTile(null);
} }
} }
if(unit instanceof Builderc build && leader instanceof Builderc com && com.activelyBuilding()){ if(unit.canBuild() && leader.canBuild() && leader.activelyBuilding()){
build.clearBuilding(); unit.clearBuilding();
build.addBuild(com.buildPlan()); leader.addBuild(unit.buildPlan());
} }
} }

View File

@@ -92,9 +92,7 @@ public class LogicAI extends AIController{
} }
} }
case stop -> { case stop -> {
if(unit instanceof Builderc build){ unit.clearBuilding();
build.clearBuilding();
}
} }
} }

View File

@@ -17,21 +17,21 @@ public class MinerAI extends AIController{
protected void updateMovement(){ protected void updateMovement(){
Building core = unit.closestCore(); Building core = unit.closestCore();
if(!(unit instanceof Minerc miner) || core == null) return; if(!(unit.canMine()) || core == null) return;
if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type.range)){ if(unit.mineTile != null && !unit.mineTile.within(unit, unit.type.range)){
miner.mineTile(null); unit.mineTile(null);
} }
if(mining){ if(mining){
if(timer.get(timerTarget2, 60 * 4) || targetItem == null){ if(timer.get(timerTarget2, 60 * 4) || targetItem == null){
targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i)); targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i));
} }
//core full of the target item, do nothing //core full of the target item, do nothing
if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){ if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){
unit.clearItem(); unit.clearItem();
miner.mineTile(null); unit.mineTile(null);
return; return;
} }
@@ -47,7 +47,7 @@ public class MinerAI extends AIController{
moveTo(ore, unit.type.range / 2f, 20f); moveTo(ore, unit.type.range / 2f, 20f);
if(unit.within(ore, unit.type.range)){ if(unit.within(ore, unit.type.range)){
miner.mineTile(ore); unit.mineTile = ore;
} }
if(ore.block() != Blocks.air){ if(ore.block() != Blocks.air){
@@ -56,7 +56,7 @@ public class MinerAI extends AIController{
} }
} }
}else{ }else{
miner.mineTile(null); unit.mineTile = null;
if(unit.stack.amount == 0){ if(unit.stack.amount == 0){
mining = true; mining = true;

View File

@@ -17,11 +17,13 @@ import static mindustry.Vars.*;
public class UnitTypes implements ContentList{ public class UnitTypes implements ContentList{
//region definitions //region definitions
//(the wall of shame - should fix the legacy stuff eventually...)
//mech //mech
public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign;
//mech + builder + miner //mech
public static @EntityDef({Unitc.class, Mechc.class, Builderc.class}) UnitType nova, pulsar, quasar; public static @EntityDef(value = {Unitc.class, Mechc.class}, legacy = true) UnitType nova, pulsar, quasar;
//mech //mech
public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela; public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela;
@@ -29,29 +31,29 @@ public class UnitTypes implements ContentList{
//legs //legs
public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus, atrax; public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus, atrax;
//legs + building //legs
public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid; public static @EntityDef(value = {Unitc.class, Legsc.class}, legacy = true) UnitType spiroct, arkyid, toxopid;
//air (no special traits) //air
public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra; public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra;
//air, legacy mining //air
public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType mono; public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType mono;
//air + building + mining //air
public static @EntityDef({Unitc.class, Builderc.class}) UnitType poly; public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType poly;
//air + building + mining + payload //air + payload
public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType mega; public static @EntityDef({Unitc.class, Payloadc.class}) UnitType mega;
//air + building + payload //air + payload
public static @EntityDef(value = {Unitc.class, Builderc.class, Payloadc.class}, legacy = true) UnitType quad; public static @EntityDef(value = {Unitc.class, Payloadc.class}, legacy = true) UnitType quad;
//air + building + payload //air + payload + ammo distribution
public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; public static @EntityDef({Unitc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct;
//air + building + mining //air
public static @EntityDef({Unitc.class, Builderc.class}) UnitType alpha, beta, gamma; public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType alpha, beta, gamma;
//water //water
public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura; public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura;
@@ -470,7 +472,6 @@ public class UnitTypes implements ContentList{
mineTier = 1; mineTier = 1;
hitSize = 29f; hitSize = 29f;
health = 18000f; health = 18000f;
buildSpeed = 1.7f;
armor = 9f; armor = 9f;
landShake = 1.5f; landShake = 1.5f;
rotateSpeed = 1.5f; rotateSpeed = 1.5f;
@@ -700,6 +701,7 @@ public class UnitTypes implements ContentList{
rippleScale = 2f; rippleScale = 2f;
legSpeed = 0.2f; legSpeed = 0.2f;
ammoType = AmmoTypes.power; ammoType = AmmoTypes.power;
buildSpeed = 1f;
legSplashDamage = 32; legSplashDamage = 32;
legSplashRange = 30; legSplashRange = 30;
@@ -802,6 +804,7 @@ public class UnitTypes implements ContentList{
rippleScale = 3f; rippleScale = 3f;
legSpeed = 0.19f; legSpeed = 0.19f;
ammoType = AmmoTypes.powerHigh; ammoType = AmmoTypes.powerHigh;
buildSpeed = 1f;
legSplashDamage = 80; legSplashDamage = 80;
legSplashRange = 60; legSplashRange = 60;

View File

@@ -571,13 +571,13 @@ public class NetClient implements ApplicationListener{
BuildPlan[] requests = null; BuildPlan[] requests = null;
if(player.isBuilder()){ if(player.isBuilder()){
//limit to 10 to prevent buffer overflows //limit to 10 to prevent buffer overflows
int usedRequests = Math.min(player.builder().plans().size, 10); int usedRequests = Math.min(player.unit().plans().size, 10);
int totalLength = 0; int totalLength = 0;
//prevent buffer overflow by checking config length //prevent buffer overflow by checking config length
for(int i = 0; i < usedRequests; i++){ for(int i = 0; i < usedRequests; i++){
BuildPlan plan = player.builder().plans().get(i); BuildPlan plan = player.unit().plans().get(i);
if(plan.config instanceof byte[] b){ if(plan.config instanceof byte[] b){
int length = b.length; int length = b.length;
totalLength += length; totalLength += length;
@@ -591,7 +591,7 @@ public class NetClient implements ApplicationListener{
requests = new BuildPlan[usedRequests]; requests = new BuildPlan[usedRequests];
for(int i = 0; i < usedRequests; i++){ for(int i = 0; i < usedRequests; i++){
requests[i] = player.builder().plans().get(i); requests[i] = player.unit().plans().get(i);
} }
} }
@@ -607,7 +607,7 @@ public class NetClient implements ApplicationListener{
unit.rotation, unit.rotation,
unit instanceof Mechc m ? m.baseRotation() : 0, unit instanceof Mechc m ? m.baseRotation() : 0,
unit.vel.x, unit.vel.y, unit.vel.x, unit.vel.y,
player.unit().mineTile(), player.unit().mineTile,
player.boosting, player.shooting, ui.chatfrag.shown(), control.input.isBuilding, player.boosting, player.shooting, ui.chatfrag.shown(), control.input.isBuilding,
requests, requests,
Core.camera.position.x, Core.camera.position.y, Core.camera.position.x, Core.camera.position.y,

View File

@@ -600,8 +600,8 @@ public class NetServer implements ApplicationListener{
player.unit().aim(pointerX, pointerY); player.unit().aim(pointerX, pointerY);
if(player.isBuilder()){ if(player.isBuilder()){
player.builder().clearBuilding(); player.unit().clearBuilding();
player.builder().updateBuilding(building); player.unit().updateBuilding(building);
if(requests != null){ if(requests != null){
for(BuildPlan req : requests){ for(BuildPlan req : requests){
@@ -625,7 +625,7 @@ public class NetServer implements ApplicationListener{
con.rejectedRequests.add(req); con.rejectedRequests.add(req);
continue; continue;
} }
player.builder().plans().addLast(req); player.unit().plans().addLast(req);
} }
} }
} }

View File

@@ -13,6 +13,7 @@ import mindustry.entities.units.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.ConstructBlock.*;
@@ -22,17 +23,22 @@ import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@Component @Component
abstract class BuilderComp implements Unitc{ abstract class BuilderComp implements Posc, Teamc, Rotc{
static final Vec2[] vecs = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()}; static final Vec2[] vecs = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()};
@Import float x, y, rotation; @Import float x, y, rotation;
@Import UnitType type;
@SyncLocal Queue<BuildPlan> plans = new Queue<>(1); @SyncLocal Queue<BuildPlan> plans = new Queue<>(1);
@SyncLocal transient boolean updateBuilding = true; @SyncLocal transient boolean updateBuilding = true;
public boolean canBuild(){
return type.buildSpeed > 0;
}
@Override @Override
public void update(){ public void update(){
if(!updateBuilding) return; if(!updateBuilding || !canBuild()) return;
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange;
boolean infinite = state.rules.infiniteResources || team().rules().infiniteResources; boolean infinite = state.rules.infiniteResources || team().rules().infiniteResources;
@@ -102,9 +108,9 @@ abstract class BuilderComp implements Unitc{
ConstructBuild entity = tile.bc(); ConstructBuild entity = tile.bc();
if(current.breaking){ if(current.breaking){
entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier); entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier);
}else{ }else{
entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config); entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier, current.config);
} }
current.stuck = Mathf.equal(current.progress, entity.progress); current.stuck = Mathf.equal(current.progress, entity.progress);
@@ -161,6 +167,8 @@ abstract class BuilderComp implements Unitc{
/** Add another build requests to the queue, if it doesn't exist there yet. */ /** Add another build requests to the queue, if it doesn't exist there yet. */
void addBuild(BuildPlan place, boolean tail){ void addBuild(BuildPlan place, boolean tail){
if(!canBuild()) return;
BuildPlan replace = null; BuildPlan replace = null;
for(BuildPlan request : plans){ for(BuildPlan request : plans){
if(request.x == place.x && request.y == place.y){ if(request.x == place.x && request.y == place.y){
@@ -196,9 +204,8 @@ abstract class BuilderComp implements Unitc{
return plans.size == 0 ? null : plans.first(); return plans.size == 0 ? null : plans.first();
} }
@Override
public void draw(){ public void draw(){
if(!isBuilding() || !updateBuilding) return; if(!isBuilding() || !updateBuilding || !canBuild()) return;
//TODO check correctness //TODO check correctness
Draw.z(Layer.flyingUnit); Draw.z(Layer.flyingUnit);

View File

@@ -1122,7 +1122,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Returns whether or not a hand cursor should be shown over this block. */ /** Returns whether or not a hand cursor should be shown over this block. */
public Cursor getCursor(){ public Cursor getCursor(){
return block.configurable ? SystemCursor.hand : SystemCursor.arrow; return block.configurable && team == player.team() ? SystemCursor.hand : SystemCursor.arrow;
} }
/** /**

View File

@@ -32,7 +32,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{
} }
boolean mining(){ boolean mining(){
return mineTile != null && !(((Object)this) instanceof Builderc b && b.activelyBuilding()); return mineTile != null && !this.<Unit>self().activelyBuilding();
} }
public boolean validMine(Tile tile, boolean checkDst){ public boolean validMine(Tile tile, boolean checkDst){
@@ -44,6 +44,10 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{
return validMine(tile, true); return validMine(tile, true);
} }
public boolean canMine(){
return type.mineSpeed > 0;
}
@Override @Override
public void update(){ public void update(){
Building core = closestCore(); Building core = closestCore();

View File

@@ -48,7 +48,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
transient float textFadeTime; transient float textFadeTime;
public boolean isBuilder(){ public boolean isBuilder(){
return unit instanceof Builderc; return unit.canBuild();
} }
public @Nullable CoreBuild closestCore(){ public @Nullable CoreBuild closestCore(){
@@ -160,10 +160,6 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
return unit; return unit;
} }
public Builderc builder(){
return !(unit instanceof Builderc) ? Nulls.builder : (Builderc)unit;
}
public void unit(Unit unit){ public void unit(Unit unit){
if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead."); if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead.");
if(this.unit == unit) return; if(this.unit == unit) return;

View File

@@ -31,7 +31,7 @@ import mindustry.world.blocks.payloads.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@Component(base = true) @Component(base = true)
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc{ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc, Builderc{
@Import boolean hovering, dead; @Import boolean hovering, dead;
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed;
@@ -88,8 +88,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
/** @return where the unit wants to look at. */ /** @return where the unit wants to look at. */
public float prefRotation(){ public float prefRotation(){
if(this instanceof Builderc builder && builder.activelyBuilding()){ if(activelyBuilding()){
return angleTo(builder.buildPlan()); return angleTo(buildPlan());
}else if(mineTile() != null){ }else if(mineTile() != null){
return angleTo(mineTile()); return angleTo(mineTile());
}else if(moving()){ }else if(moving()){

View File

@@ -28,7 +28,7 @@ public class OverlayRenderer{
if(player.dead()) return; if(player.dead()) return;
if(player.isBuilder()){ if(player.isBuilder()){
player.builder().drawBuildRequests(); player.unit().drawBuildRequests();
} }
input.drawBottom(); input.drawBottom();

View File

@@ -59,7 +59,7 @@ public class DesktopInput extends InputHandler{
group.fill(t -> { group.fill(t -> {
t.bottom(); t.bottom();
t.visible(() -> { t.visible(() -> {
t.color.a = Mathf.lerpDelta(t.color.a, player.builder().isBuilding() ? 1f : 0f, 0.15f); t.color.a = Mathf.lerpDelta(t.color.a, player.unit().isBuilding() ? 1f : 0f, 0.15f);
return ui.hudfrag.shown && Core.settings.getBool("hints") && selectRequests.isEmpty() && t.color.a > 0.01f; return ui.hudfrag.shown && Core.settings.getBool("hints") && selectRequests.isEmpty() && t.color.a > 0.01f;
}); });
@@ -290,7 +290,7 @@ public class DesktopInput extends InputHandler{
cursorType = cursor.build.getCursor(); cursorType = cursor.build.getCursor();
} }
if(isPlacing() || !selectRequests.isEmpty()){ if((isPlacing() && player.isBuilder()) || !selectRequests.isEmpty()){
cursorType = SystemCursor.hand; cursorType = SystemCursor.hand;
} }
@@ -366,7 +366,7 @@ public class DesktopInput extends InputHandler{
int rawCursorX = World.toTile(Core.input.mouseWorld().x), rawCursorY = World.toTile(Core.input.mouseWorld().y); int rawCursorX = World.toTile(Core.input.mouseWorld().x), rawCursorY = World.toTile(Core.input.mouseWorld().y);
// automatically pause building if the current build queue is empty // automatically pause building if the current build queue is empty
if(Core.settings.getBool("buildautopause") && isBuilding && !player.builder().isBuilding()){ if(Core.settings.getBool("buildautopause") && isBuilding && !player.unit().isBuilding()){
isBuilding = false; isBuilding = false;
buildWasAutoPaused = true; buildWasAutoPaused = true;
} }
@@ -388,7 +388,7 @@ public class DesktopInput extends InputHandler{
} }
if(Core.input.keyTap(Binding.clear_building)){ if(Core.input.keyTap(Binding.clear_building)){
player.builder().clearBuilding(); player.unit().clearBuilding();
} }
if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard() && mode != breaking){ if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard() && mode != breaking){
@@ -480,8 +480,8 @@ public class DesktopInput extends InputHandler{
deleting = true; deleting = true;
}else if(selected != null){ }else if(selected != null){
//only begin shooting if there's no cursor event //only begin shooting if there's no cursor event
if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.builder().activelyBuilding() && !droppingItem && if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.unit().activelyBuilding() && !droppingItem &&
!tryBeginMine(selected) && player.unit().mineTile() == null && !Core.scene.hasKeyboard()){ !tryBeginMine(selected) && player.unit().mineTile == null && !Core.scene.hasKeyboard()){
player.shooting = shouldShoot; player.shooting = shouldShoot;
} }
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
@@ -506,7 +506,7 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){ if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){
BuildPlan req = getRequest(cursorX, cursorY); BuildPlan req = getRequest(cursorX, cursorY);
if(req != null && req.breaking){ if(req != null && req.breaking){
player.builder().plans().remove(req); player.unit().plans().remove(req);
} }
}else{ }else{
deleting = false; deleting = false;
@@ -547,7 +547,7 @@ public class DesktopInput extends InputHandler{
if(sreq != null){ if(sreq != null){
if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){ if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){
player.builder().plans().remove(sreq, true); player.unit().plans().remove(sreq, true);
} }
sreq = null; sreq = null;
} }

View File

@@ -169,7 +169,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(variants = Variant.one) @Remote(variants = Variant.one)
public static void removeQueueBlock(int x, int y, boolean breaking){ public static void removeQueueBlock(int x, int y, boolean breaking){
player.builder().removeBuild(x, y, breaking); player.unit().removeBuild(x, y, breaking);
} }
@Remote(targets = Loc.both, called = Loc.server) @Remote(targets = Loc.both, called = Loc.server)
@@ -383,7 +383,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public Eachable<BuildPlan> allRequests(){ public Eachable<BuildPlan> allRequests(){
return cons -> { return cons -> {
for(BuildPlan request : player.builder().plans()) cons.get(request); for(BuildPlan request : player.unit().plans()) cons.get(request);
for(BuildPlan request : selectRequests) cons.get(request); for(BuildPlan request : selectRequests) cons.get(request);
for(BuildPlan request : lineRequests) cons.get(request); for(BuildPlan request : lineRequests) cons.get(request);
}; };
@@ -401,7 +401,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
player.typing = ui.chatfrag.shown(); player.typing = ui.chatfrag.shown();
if(player.isBuilder()){ if(player.isBuilder()){
player.builder().updateBuilding(isBuilding); player.unit().updateBuilding(isBuilding);
} }
if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && player.unit().ammo <= 0){ if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && player.unit().ammo <= 0){
@@ -653,7 +653,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
return r2.overlaps(r1); return r2.overlaps(r1);
}; };
for(BuildPlan req : player.builder().plans()){ for(BuildPlan req : player.unit().plans()){
if(test.get(req)) return req; if(test.get(req)) return req;
} }
@@ -678,7 +678,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Draw.color(Pal.remove); Draw.color(Pal.remove);
Lines.stroke(1f); Lines.stroke(1f);
for(BuildPlan req : player.builder().plans()){ for(BuildPlan req : player.unit().plans()){
if(req.breaking) continue; if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){ if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req); drawBreaking(req);
@@ -740,7 +740,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
for(BuildPlan req : requests){ for(BuildPlan req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
BuildPlan copy = req.copy(); BuildPlan copy = req.copy();
player.builder().addBuild(copy); player.unit().addBuild(copy);
} }
} }
} }
@@ -804,7 +804,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
//remove build requests //remove build requests
Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize);
Iterator<BuildPlan> it = player.builder().plans().iterator(); Iterator<BuildPlan> it = player.unit().plans().iterator();
while(it.hasNext()){ while(it.hasNext()){
BuildPlan req = it.next(); BuildPlan req = it.next();
if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){ if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){
@@ -1044,7 +1044,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
public boolean canShoot(){ public boolean canShoot(){
return block == null && !onConfigurable() && !isDroppingItem() && !player.builder().activelyBuilding() && return block == null && !onConfigurable() && !isDroppingItem() && !player.unit().activelyBuilding() &&
!(player.unit() instanceof Mechc && player.unit().isFlying()); !(player.unit() instanceof Mechc && player.unit().isFlying());
} }
@@ -1090,7 +1090,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
public boolean validPlace(int x, int y, Block type, int rotation, BuildPlan ignore){ public boolean validPlace(int x, int y, Block type, int rotation, BuildPlan ignore){
for(BuildPlan req : player.builder().plans()){ for(BuildPlan req : player.unit().plans()){
if(req != ignore if(req != ignore
&& !req.breaking && !req.breaking
&& req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2)) && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2))
@@ -1108,15 +1108,15 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public void placeBlock(int x, int y, Block block, int rotation){ public void placeBlock(int x, int y, Block block, int rotation){
BuildPlan req = getRequest(x, y); BuildPlan req = getRequest(x, y);
if(req != null){ if(req != null){
player.builder().plans().remove(req); player.unit().plans().remove(req);
} }
player.builder().addBuild(new BuildPlan(x, y, rotation, block, block.nextConfig())); player.unit().addBuild(new BuildPlan(x, y, rotation, block, block.nextConfig()));
} }
public void breakBlock(int x, int y){ public void breakBlock(int x, int y){
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile != null && tile.build != null) tile = tile.build.tile; if(tile != null && tile.build != null) tile = tile.build.tile;
player.builder().addBuild(new BuildPlan(tile.x, tile.y)); player.unit().addBuild(new BuildPlan(tile.x, tile.y));
} }
public void drawArrow(Block block, int x, int y, int rotation){ public void drawArrow(Block block, int x, int y, int rotation){

View File

@@ -114,7 +114,7 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
} }
for(BuildPlan req : player.builder().plans()){ for(BuildPlan req : player.unit().plans()){
Tile other = world.tile(req.x, req.y); Tile other = world.tile(req.x, req.y);
if(other == null || req.breaking) continue; if(other == null || req.breaking) continue;
@@ -219,10 +219,10 @@ public class MobileInput extends InputHandler implements GestureListener{
BuildPlan copy = request.copy(); BuildPlan copy = request.copy();
if(other == null){ if(other == null){
player.builder().addBuild(copy); player.unit().addBuild(copy);
}else if(!other.breaking && other.x == request.x && other.y == request.y && other.block.size == request.block.size){ }else if(!other.breaking && other.x == request.x && other.y == request.y && other.block.size == request.block.size){
player.builder().plans().remove(other); player.unit().plans().remove(other);
player.builder().addBuild(copy); player.unit().addBuild(copy);
} }
} }
@@ -245,10 +245,10 @@ public class MobileInput extends InputHandler implements GestureListener{
Boolp schem = () -> lastSchematic != null && !selectRequests.isEmpty(); Boolp schem = () -> lastSchematic != null && !selectRequests.isEmpty();
group.fill(t -> { group.fill(t -> {
t.visible(() -> (player.builder().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); t.visible(() -> (player.unit().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get());
t.bottom().left(); t.bottom().left();
t.button("@cancel", Icon.cancel, () -> { t.button("@cancel", Icon.cancel, () -> {
player.builder().clearBuilding(); player.unit().clearBuilding();
selectRequests.clear(); selectRequests.clear();
mode = none; mode = none;
block = null; block = null;
@@ -914,7 +914,7 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
//update shooting if not building + not mining //update shooting if not building + not mining
if(!player.builder().isBuilding() && player.unit().mineTile() == null){ if(!player.unit().isBuilding() && player.unit().mineTile == null){
//autofire targeting //autofire targeting
if(manualShooting){ if(manualShooting){

View File

@@ -321,13 +321,8 @@ public class LExecutor{
((LogicAI)unit.controller()).controller = exec.building(varThis); ((LogicAI)unit.controller()).controller = exec.building(varThis);
//clear old state //clear old state
if(unit instanceof Minerc miner){ unit.mineTile = null;
miner.mineTile(null); unit.clearBuilding();
}
if(unit instanceof Builderc builder){
builder.clearBuilding();
}
return (LogicAI)unit.controller(); return (LogicAI)unit.controller();
} }
@@ -357,12 +352,8 @@ public class LExecutor{
//stop mining/building //stop mining/building
if(type == LUnitControl.stop){ if(type == LUnitControl.stop){
if(unit instanceof Minerc miner){ unit.mineTile = null;
miner.mineTile(null); unit.clearBuilding();
}
if(unit instanceof Builderc build){
build.clearBuilding();
}
} }
} }
case within -> { case within -> {
@@ -390,8 +381,8 @@ public class LExecutor{
} }
case mine -> { case mine -> {
Tile tile = world.tileWorld(x1, y1); Tile tile = world.tileWorld(x1, y1);
if(unit instanceof Minerc miner){ if(unit.canMine()){
miner.mineTile(miner.validMine(tile) ? tile : null); unit.mineTile = unit.validMine(tile) ? tile : null;
} }
} }
case payDrop -> { case payDrop -> {
@@ -432,12 +423,12 @@ public class LExecutor{
} }
} }
case build -> { case build -> {
if(unit instanceof Builderc builder && exec.obj(p3) instanceof Block block){ if(unit.canBuild() && exec.obj(p3) instanceof Block block){
int x = World.toTile(x1), y = World.toTile(y1); int x = World.toTile(x1), y = World.toTile(y1);
int rot = exec.numi(p4); int rot = exec.numi(p4);
//reset state of last request when necessary //reset state of last request when necessary
if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || builder.plans().isEmpty()){ if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || unit.plans.isEmpty()){
ai.plan.progress = 0; ai.plan.progress = 0;
ai.plan.initialized = false; ai.plan.initialized = false;
ai.plan.stuck = false; ai.plan.stuck = false;
@@ -446,11 +437,11 @@ public class LExecutor{
ai.plan.set(x, y, rot, block); ai.plan.set(x, y, rot, block);
ai.plan.config = exec.obj(p5) instanceof Content c ? c : null; ai.plan.config = exec.obj(p5) instanceof Content c ? c : null;
builder.clearBuilding(); unit.clearBuilding();
if(ai.plan.tile() != null){ if(ai.plan.tile() != null){
builder.updateBuilding(true); unit.updateBuilding = true;
builder.addBuild(ai.plan); unit.addBuild(ai.plan);
} }
} }
} }

View File

@@ -80,7 +80,7 @@ public class UnitType extends UnlockableContent{
public int ammoCapacity = -1; public int ammoCapacity = -1;
public AmmoType ammoType = AmmoTypes.copper; public AmmoType ammoType = AmmoTypes.copper;
public int mineTier = -1; public int mineTier = -1;
public float buildSpeed = 1f, mineSpeed = 1f; public float buildSpeed = -1f, mineSpeed = 1f;
public Sound mineSound = Sounds.minebeam; public Sound mineSound = Sounds.minebeam;
public float mineSoundVolume = 0.6f; public float mineSoundVolume = 0.6f;
@@ -225,7 +225,7 @@ public class UnitType extends UnlockableContent{
stats.addPercent(Stat.mineSpeed, mineSpeed); stats.addPercent(Stat.mineSpeed, mineSpeed);
stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable)); stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable));
} }
if(inst instanceof Builderc){ if(buildSpeed > 0){
stats.addPercent(Stat.buildSpeed, buildSpeed); stats.addPercent(Stat.buildSpeed, buildSpeed);
} }
if(inst instanceof Payloadc){ if(inst instanceof Payloadc){

View File

@@ -102,7 +102,7 @@ public class PlacementFragment extends Fragment{
Block tryRecipe = tile == null ? null : tile.block instanceof ConstructBlock ? ((ConstructBuild)tile).cblock : tile.block; Block tryRecipe = tile == null ? null : tile.block instanceof ConstructBlock ? ((ConstructBuild)tile).cblock : tile.block;
Object tryConfig = tile == null ? null : tile.config(); Object tryConfig = tile == null ? null : tile.config();
for(BuildPlan req : player.builder().plans()){ for(BuildPlan req : player.unit().plans()){
if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){ if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){
tryRecipe = req.block; tryRecipe = req.block;
tryConfig = req.config; tryConfig = req.config;

View File

@@ -179,7 +179,7 @@ public class ConstructBlock extends Block{
if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){ if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){
control.input.isBuilding = true; control.input.isBuilding = true;
} }
player.builder().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock, lastConfig), false); player.unit().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock, lastConfig), false);
} }
} }

View File

@@ -57,6 +57,7 @@ public interface Payload{
return (T)payload; return (T)payload;
}else if(type == payloadUnit){ }else if(type == payloadUnit){
byte id = read.b(); byte id = read.b();
if(EntityMapping.map(id) == null) throw new RuntimeException("No type with ID " + id + " found.");
Unit unit = (Unit)EntityMapping.map(id).get(); Unit unit = (Unit)EntityMapping.map(id).get();
unit.read(read); unit.read(read);
return (T)new UnitPayload(unit); return (T)new UnitPayload(unit);

View File

@@ -433,6 +433,15 @@ public class ApplicationTests{
assertEquals(256, world.height()); assertEquals(256, world.height());
} }
@Test
void load114Save(){
resetWorld();
SaveIO.load(Core.files.internal("114.msav"));
assertEquals(500, world.width());
assertEquals(500, world.height());
}
@Test @Test
void arrayIterators(){ void arrayIterators(){
Seq<String> arr = Seq.with("a", "b" , "c", "d", "e", "f"); Seq<String> arr = Seq.with("a", "b" , "c", "d", "e", "f");

Binary file not shown.