diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 916e57ef4d..bfc54e1b9a 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -63,7 +63,7 @@ public class Vars{ //whether turrets have infinite ammo (only with debug) public static boolean infiniteAmmo = true; //whether to show paths of enemies - public static boolean showPaths = true; + public static boolean showPaths = false; //if false, player is always hidden public static boolean showPlayer = true; //whether to hide ui, only on debug diff --git a/core/src/io/anuke/mindustry/content/UnitTypes.java b/core/src/io/anuke/mindustry/content/UnitTypes.java index b4f4bc8bfe..d74d592d71 100644 --- a/core/src/io/anuke/mindustry/content/UnitTypes.java +++ b/core/src/io/anuke/mindustry/content/UnitTypes.java @@ -11,8 +11,29 @@ public class UnitTypes implements ContentList { @Override public void load() { - drone = new Drone(); - scout = new Scout(); - vtol = new Vtol(); + drone = new UnitType("drone", team -> new Drone(drone, team)){{ + isFlying = true; + drag = 0.01f; + speed = 0.2f; + maxVelocity = 0.8f; + range = 50f; + }}; + + scout = new UnitType("scout", team -> new Scout(scout, team)){{ + maxVelocity = 1.1f; + speed = 0.1f; + drag = 0.4f; + range = 40f; + setAmmo(AmmoTypes.bulletIron); + }}; + + vtol = new UnitType("vtol", team -> new Vtol(vtol, team)){{ + speed = 0.3f; + maxVelocity = 2f; + drag = 0.01f; + isFlying = true; + reload = 7; + setAmmo(AmmoTypes.bulletIron); + }}; } } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index fcec340265..b4eb06a9fb 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -82,7 +82,7 @@ public class Logic extends Module { //TODO spawn enemies for(int i = 0; i < 10; i ++){ - BaseUnit unit = new BaseUnit(UnitTypes.vtol, Team.red); + BaseUnit unit = UnitTypes.vtol.create(Team.red); Vector2 offset = new Vector2().setToRandomDirection().scl(world.width()/2f*tilesize).add(world.width()/2f*tilesize, world.height()/2f*tilesize); unit.inventory.addAmmo(AmmoTypes.bulletIron); unit.inventory.setInfiniteAmmo(true); diff --git a/core/src/io/anuke/mindustry/entities/BlockBuilder.java b/core/src/io/anuke/mindustry/entities/BlockBuilder.java index 69e8040281..fca3f3f1d2 100644 --- a/core/src/io/anuke/mindustry/entities/BlockBuilder.java +++ b/core/src/io/anuke/mindustry/entities/BlockBuilder.java @@ -6,6 +6,7 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.entities.effect.ItemTransfer; +import io.anuke.mindustry.game.EventType.BlockBuildEvent; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Recipe; @@ -14,6 +15,7 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.types.BuildBlock; import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity; import io.anuke.ucore.core.Effects; +import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Fill; @@ -26,8 +28,7 @@ import io.anuke.ucore.util.Translator; import java.util.Arrays; -import static io.anuke.mindustry.Vars.tilesize; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; /**Interface for units that build, break or mine things.*/ public interface BlockBuilder { @@ -140,6 +141,9 @@ public interface BlockBuilder { if(Build.validPlace(unit.team, current.x, current.y, current.recipe.result, current.rotation)){ //if it's valid, place it Build.placeBlock(unit.team, current.x, current.y, current.recipe, current.rotation); + + //fire place event. + threads.run(() -> Events.fire(BlockBuildEvent.class, unit.team, world.tile(current.x, current.y))); }else{ //otherwise, skip it getPlaceQueue().removeFirst(); diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index f377a88dd5..939b00b3c0 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -69,8 +69,7 @@ public class Player extends Unit implements BlockBuilder { public Player(){ hitbox.setSize(5); hitboxTile.setSize(4f); - - maxhealth = 200; + heal(); } @@ -78,6 +77,10 @@ public class Player extends Unit implements BlockBuilder { //region unit and event overrides, utility methods + @Override + public float getMaxHealth() { + return 200; + } @Override public Tile getMineTile() { diff --git a/core/src/io/anuke/mindustry/entities/Unit.java b/core/src/io/anuke/mindustry/entities/Unit.java index 77babec970..ccef21cb87 100644 --- a/core/src/io/anuke/mindustry/entities/Unit.java +++ b/core/src/io/anuke/mindustry/entities/Unit.java @@ -41,7 +41,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar @Override public boolean collides(SolidEntity other){ - return other instanceof io.anuke.mindustry.entities.bullet.Bullet && state.teams.areEnemies((((Bullet) other).team), team); + return other instanceof Bullet && state.teams.areEnemies((((Bullet) other).team), team); } @Override diff --git a/core/src/io/anuke/mindustry/entities/UnitInventory.java b/core/src/io/anuke/mindustry/entities/UnitInventory.java index b3338dcf11..4b6358f1a1 100644 --- a/core/src/io/anuke/mindustry/entities/UnitInventory.java +++ b/core/src/io/anuke/mindustry/entities/UnitInventory.java @@ -22,6 +22,10 @@ public class UnitInventory { this.ammoCapacity = ammoCapacity; } + public boolean isInfiniteAmmo() { + return infiniteAmmo; + } + public void setInfiniteAmmo(boolean infinite){ infiniteAmmo = infinite; } @@ -29,6 +33,7 @@ public class UnitInventory { public void write(DataOutputStream stream) throws IOException { stream.writeInt(item == null ? 0 : item.amount); stream.writeByte(item == null ? 0 : item.item.id); + stream.writeBoolean(infiniteAmmo); stream.writeInt(totalAmmo); stream.writeByte(ammos.size); for(int i = 0; i < ammos.size; i ++){ @@ -40,6 +45,7 @@ public class UnitInventory { public void read(DataInputStream stream) throws IOException { int iamount = stream.readInt(); byte iid = stream.readByte(); + infiniteAmmo = stream.readBoolean(); this.totalAmmo = stream.readInt(); byte ammoa = stream.readByte(); for(int i = 0; i < ammoa; i ++){ diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index 3ab6e3cee0..ddd0547df0 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -1,16 +1,22 @@ package io.anuke.mindustry.entities.units; +import io.anuke.mindustry.content.fx.ExplosionFx; import io.anuke.mindustry.entities.Targetable; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.type.AmmoType; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.BlockFlag; +import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; +import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Timer; @@ -19,14 +25,19 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; -import static io.anuke.mindustry.Vars.unitGroups; +import static io.anuke.mindustry.Vars.*; -public class BaseUnit extends Unit{ - public UnitType type; - public Timer timer = new Timer(5); - public float walkTime = 0f; - public StateMachine state = new StateMachine(); - public Targetable target; +public abstract class BaseUnit extends Unit{ + private static int timerIndex = 0; + + protected static final int timerTarget = timerIndex++; + protected static final int timerBoost = timerIndex++; + protected static final int timerReload = timerIndex++; + + protected UnitType type; + protected Timer timer = new Timer(5); + protected StateMachine state = new StateMachine(); + protected Targetable target; public BaseUnit(UnitType type, Team team){ this.type = type; @@ -52,15 +63,51 @@ public class BaseUnit extends Unit{ } public void setState(UnitState state){ - this.state.set(this, state); + this.state.set(state); } public void retarget(Runnable run){ - if(timer.get(UnitType.timerTarget, 20)){ + if(timer.get(timerTarget, 20)){ run.run(); } } + /**Only runs when the unit has a target.*/ + public void behavior(){ + + } + + public void updateTargeting(){ + if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).team == team)) + || (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){ + target = null; + } + } + + public void shoot(AmmoType type, float rotation, float translation){ + Bullet.create(type.bullet, this, + x + Angles.trnsx(rotation, translation), + y + Angles.trnsy(rotation, translation), rotation); + Effects.effect(type.shootEffect, x + Angles.trnsx(rotation, translation), + y + Angles.trnsy(rotation, translation), rotation, this); + Effects.effect(type.smokeEffect, x + Angles.trnsx(rotation, translation), + y + Angles.trnsy(rotation, translation), rotation, this); + } + + public void targetClosestAllyFlag(BlockFlag flag){ + Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag)); + if (target != null) this.target = target.entity; + } + + public UnitState getStartState(){ + return null; + } + + @Override + public float getMaxHealth() { + return type.health; + } + @Override public float getArmor() { return type.armor; @@ -99,22 +146,41 @@ public class BaseUnit extends Unit{ @Override public void update(){ - type.update(this); + if(hitTime > 0){ + hitTime -= Timers.delta(); + } + + if(hitTime < 0) hitTime = 0; + + if(Net.client()){ + interpolate(); + return; + } + + updateTargeting(); + + state.update(); + updateVelocityStatus(type.drag, type.maxVelocity); + + if(target != null) behavior(); + + x = Mathf.clamp(x, 0, world.width() * tilesize); + y = Mathf.clamp(y, 0, world.height() * tilesize); } @Override public void drawSmooth(){ - type.draw(this); + } @Override public void drawUnder(){ - type.drawUnder(this); + } @Override public void drawOver(){ - type.drawOver(this); + } @Override @@ -130,27 +196,29 @@ public class BaseUnit extends Unit{ @Override public void onDeath(){ super.onDeath(); - type.onDeath(this); + + Effects.effect(ExplosionFx.explosion, this); + Effects.shake(2f, 2f, this); + + remove(); } @Override public void onRemoteDeath(){ - type.onRemoteDeath(this); + onDeath(); } @Override public void removed(){ - type.removed(this); + } @Override public void added(){ - maxhealth = type.health; - hitbox.solid = !isFlying(); hitbox.setSize(type.hitsize); hitboxTile.setSize(type.hitsizeTile); - state.set(this, type.getStartState()); + state.set(getStartState()); heal(); } diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java new file mode 100644 index 0000000000..8a01024877 --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java @@ -0,0 +1,168 @@ +package io.anuke.mindustry.entities.units; + +import io.anuke.mindustry.entities.Unit; +import io.anuke.mindustry.entities.Units; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.graphics.Palette; +import io.anuke.mindustry.graphics.Trail; +import io.anuke.mindustry.type.AmmoType; +import io.anuke.mindustry.world.BlockFlag; +import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Geometry; +import io.anuke.ucore.util.Mathf; +import io.anuke.ucore.util.Translator; + +import static io.anuke.mindustry.Vars.world; + +public class FlyingUnit extends BaseUnit { + protected static Translator vec = new Translator(); + protected static float maxAim = 30f; + protected static float wobblyness = 0.6f; + + protected Trail trail = new Trail(16); + + public FlyingUnit(UnitType type, Team team) { + super(type, team); + } + + @Override + public void update() { + super.update(); + + rotation = velocity.angle(); + trail.update(x + Angles.trnsx(rotation + 180f, 6f) + Mathf.range(wobblyness), + y + Angles.trnsy(rotation + 180f, 6f) + Mathf.range(wobblyness)); + } + + @Override + public void drawSmooth() { + Draw.alpha(hitTime / hitDuration); + + Draw.rect(type.name, x, y, rotation - 90); + + Draw.alpha(1f); + } + + @Override + public void drawOver() { + trail.draw(Palette.lighterOrange, Palette.lightishOrange, 5f); + } + + @Override + public void behavior() { + if(health <= health * type.retreatPercent && + Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ + setState(retreat); + } + } + + + @Override + public UnitState getStartState(){ + return attack; + } + + protected void circle(float circleLength){ + vec.set(target.getX() - x, target.getY() - y); + + if(vec.len() < circleLength){ + vec.rotate((circleLength-vec.len())/circleLength * 180f); + } + + vec.setLength(type.speed * Timers.delta()); + + velocity.add(vec); + } + + protected void attack(float circleLength){ + vec.set(target.getX() - x, target.getY() - y); + + float ang = angleTo(target); + float diff = Angles.angleDist(ang, rotation); + + if(diff > 100f && vec.len() < circleLength){ + vec.setAngle(velocity.angle()); + }else{ + vec.setAngle(Mathf.slerpDelta(velocity.angle(), vec.angle(), 0.44f)); + } + + vec.setLength(type.speed*Timers.delta()); + + velocity.add(vec); + } + + public final UnitState + + resupply = new UnitState(){ + public void entered() { + target = null; + } + + public void update() { + if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ + state.set(attack); + }else if(!targetHasFlag(BlockFlag.resupplyPoint)){ + retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint)); + }else{ + circle(20f); + } + } + }, + attack = new UnitState(){ + public void entered() { + target = null; + } + + public void update() { + if(Units.invalidateTarget(target, team, x, y)){ + target = null; + } + + if(!inventory.hasAmmo()) { + state.set(resupply); + }else if (target == null){ + if(timer.get(timerTarget, 20)) { + Unit closest = Units.getClosestEnemy(team, x, y, + inventory.getAmmo().getRange(), other -> distanceTo(other) < 60f); + if(closest != null){ + target = closest; + }else { + Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, BlockFlag.target)); + if (target != null) FlyingUnit.this.target = target.entity; + } + } + }else{ + attack(150f); + + if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f) + && distanceTo(target) < inventory.getAmmo().getRange()) { + AmmoType ammo = inventory.getAmmo(); + inventory.useAmmo(); + + shoot(ammo, Angles.moveToward(rotation, angleTo(target), maxAim), 4f); + } + } + } + }, + retreat = new UnitState() { + public void entered() { + target = null; + } + + public void update() { + if(health >= health){ + state.set(attack); + }else if(!targetHasFlag(BlockFlag.repair)){ + retarget(() -> { + Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)); + if (target != null) FlyingUnit.this.target = target.entity; + }); + }else{ + circle(20f); + } + } + }; +} diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java deleted file mode 100644 index 5171505297..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java +++ /dev/null @@ -1,160 +0,0 @@ -package io.anuke.mindustry.entities.units; - -import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.entities.Units; -import io.anuke.mindustry.type.AmmoType; -import io.anuke.mindustry.world.BlockFlag; -import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.core.Timers; -import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.Angles; -import io.anuke.ucore.util.Geometry; -import io.anuke.ucore.util.Mathf; -import io.anuke.ucore.util.Translator; - -import static io.anuke.mindustry.Vars.world; - -public class FlyingUnitType extends UnitType { - protected static Translator vec = new Translator(); - - protected float maxAim = 30f; - - public FlyingUnitType(String name) { - super(name); - speed = 0.2f; - maxVelocity = 2f; - drag = 0.01f; - isFlying = true; - } - - @Override - public void update(BaseUnit unit) { - super.update(unit); - - unit.rotation = unit.velocity.angle(); - } - - @Override - public void draw(BaseUnit unit) { - Draw.alpha(unit.hitTime / Unit.hitDuration); - - Draw.rect(name, unit.x, unit.y, unit.rotation - 90); - - Draw.alpha(1f); - } - - @Override - public void behavior(BaseUnit unit) { - if(unit.health <= health * retreatPercent && - Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)) != null){ - unit.setState(retreat); - } - } - - - @Override - public UnitState getStartState(){ - return attack; - } - - protected void circle(BaseUnit unit, float circleLength){ - vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y); - - if(vec.len() < circleLength){ - vec.rotate((circleLength-vec.len())/circleLength * 180f); - } - - vec.setLength(speed * Timers.delta()); - - unit.velocity.add(vec); - } - - protected void attack(BaseUnit unit, float circleLength){ - vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y); - - float ang = unit.angleTo(unit.target); - float diff = Angles.angleDist(ang, unit.rotation); - - if(diff > 100f && vec.len() < circleLength){ - vec.setAngle(unit.velocity.angle()); - }else{ - vec.setAngle(Mathf.slerpDelta(unit.velocity.angle(), vec.angle(), 0.44f)); - } - - vec.setLength(speed*Timers.delta()); - - unit.velocity.add(vec); - } - - public final UnitState - - resupply = new UnitState(){ - public void entered(BaseUnit unit) { - unit.target = null; - } - - public void update(BaseUnit unit) { - if(unit.inventory.totalAmmo() + 10 >= unit.inventory.ammoCapacity()){ - unit.state.set(unit, attack); - }else if(!unit.targetHasFlag(BlockFlag.resupplyPoint)){ - unit.retarget(() -> targetClosestAllyFlag(unit, BlockFlag.resupplyPoint)); - }else{ - circle(unit, 20f); - } - } - }, - attack = new UnitState(){ - public void entered(BaseUnit unit) { - unit.target = null; - } - - public void update(BaseUnit unit) { - if(Units.invalidateTarget(unit.target, unit.team, unit.x, unit.y)){ - unit.target = null; - } - - if(!unit.inventory.hasAmmo()) { - unit.state.set(unit, resupply); - }else if (unit.target == null){ - if(unit.timer.get(timerTarget, 20)) { - Unit closest = Units.getClosestEnemy(unit.team, unit.x, unit.y, - unit.inventory.getAmmo().getRange(), other -> other.distanceTo(unit) < 60f); - if(closest != null){ - unit.target = closest; - }else { - Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getEnemy(unit.team, BlockFlag.target)); - if (target != null) unit.target = target.entity; - } - } - }else{ - attack(unit, 150f); - - if (unit.timer.get(timerReload, reload) && Mathf.angNear(unit.angleTo(unit.target), unit.rotation, 13f) - && unit.distanceTo(unit.target) < unit.inventory.getAmmo().getRange()) { - AmmoType ammo = unit.inventory.getAmmo(); - unit.inventory.useAmmo(); - - shoot(unit, ammo, Angles.moveToward(unit.rotation, unit.angleTo(unit.target), maxAim), 4f); - } - } - } - }, - retreat = new UnitState() { - public void entered(BaseUnit unit) { - unit.target = null; - } - - public void update(BaseUnit unit) { - if(unit.health >= health){ - unit.state.set(unit, attack); - }else if(!unit.targetHasFlag(BlockFlag.repair)){ - if(unit.timer.get(timerTarget, 20)) { - Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)); - if (target != null) unit.target = target.entity; - } - }else{ - circle(unit, 20f); - } - } - }; -} diff --git a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java index 2927fdacad..a55fbb06aa 100644 --- a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java @@ -1,8 +1,10 @@ package io.anuke.mindustry.entities.units; import com.badlogic.gdx.graphics.Color; +import io.anuke.mindustry.Vars; import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.entities.Units; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.type.AmmoType; import io.anuke.mindustry.world.BlockFlag; import io.anuke.mindustry.world.Tile; @@ -15,20 +17,16 @@ import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Translator; -import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; -public abstract class GroundUnitType extends UnitType{ +public abstract class GroundUnitType extends BaseUnit { protected static Translator vec = new Translator(); + protected static float maxAim = 30f; - protected float maxAim = 30f; + protected float walkTime; - public GroundUnitType(String name) { - super(name); - maxVelocity = 1.1f; - speed = 0.1f; - drag = 0.4f; - range = 40f; + public GroundUnitType(UnitType type, Team team) { + super(type, team); } @Override @@ -37,158 +35,158 @@ public abstract class GroundUnitType extends UnitType{ } @Override - public void update(BaseUnit unit) { - super.update(unit); + public void update() { + super.update(); - if(!unit.velocity.isZero(0.0001f) && (unit.target == null - || (unit.inventory.hasAmmo() && unit.distanceTo(unit.target) > unit.inventory.getAmmo().getRange()))){ - unit.rotation = unit.velocity.angle(); + if(!velocity.isZero(0.0001f) && (target == null + || (inventory.hasAmmo() && distanceTo(target) > inventory.getAmmo().getRange()))){ + rotation = velocity.angle(); } } @Override - public void draw(BaseUnit unit) { - Draw.alpha(unit.hitTime / Unit.hitDuration); + public void drawSmooth() { + Draw.alpha(hitTime / hitDuration); - float walktime = unit.walkTime; + float walktime = walkTime; float ft = Mathf.sin(walktime, 6f, 2f); - Floor floor = unit.getFloorOn(); + Floor floor = getFloorOn(); if(floor.liquid){ Draw.tint(Hue.mix(Color.WHITE, floor.liquidColor, 0.5f)); } for (int i : Mathf.signs) { - Draw.rect(name + "-leg", - unit.x + Angles.trnsx(unit.baseRotation, ft * i), - unit.y + Angles.trnsy(unit.baseRotation, ft * i), - 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), unit.baseRotation - 90); + Draw.rect(type.name + "-leg", + x + Angles.trnsx(baseRotation, ft * i), + y + Angles.trnsy(baseRotation, ft * i), + 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90); } if(floor.liquid) { - Draw.tint(Color.WHITE, floor.liquidColor, unit.drownTime * 0.4f); + Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f); }else { Draw.tint(Color.WHITE); } - Draw.rect(name + "-base", unit.x, unit.y, unit.baseRotation- 90); + Draw.rect(type.name + "-base", x, y, baseRotation- 90); - Draw.rect(name, unit.x, unit.y, unit.rotation -90); + Draw.rect(type.name, x, y, rotation -90); Draw.alpha(1f); } @Override - public void behavior(BaseUnit unit) { - if(unit.health <= health * retreatPercent){ - unit.setState(retreat); + public void behavior() { + if(health <= health * type.retreatPercent && !inventory.isInfiniteAmmo()){ + setState(retreat); } } @Override - public void updateTargeting(BaseUnit unit) { - super.updateTargeting(unit); + public void updateTargeting() { + super.updateTargeting(); - if(Units.invalidateTarget(unit.target, unit)){ - unit.target = null; + if(Units.invalidateTarget(target, this)){ + target = null; } } - protected void moveToCore(BaseUnit unit){ - Tile tile = world.tileWorld(unit.x, unit.y); - Tile targetTile = world.pathfinder().getTargetTile(unit.team, tile); + protected void moveToCore(){ + Tile tile = world.tileWorld(x, y); + Tile targetTile = world.pathfinder().getTargetTile(team, tile); if(tile == targetTile) return; - vec.trns(unit.baseRotation, speed); + vec.trns(baseRotation, type.speed); - unit.baseRotation = Mathf.slerpDelta(unit.baseRotation, unit.angleTo(targetTile), 0.05f); - unit.walkTime += Timers.delta(); - unit.velocity.add(vec); + baseRotation = Mathf.slerpDelta(baseRotation, angleTo(targetTile), 0.05f); + walkTime += Timers.delta(); + velocity.add(vec); } - protected void moveAwayFromCore(BaseUnit unit){ - Tile tile = world.tileWorld(unit.x, unit.y); - Tile targetTile = world.pathfinder().getTargetTile(state.teams.enemiesOf(unit.team).first(), tile); + protected void moveAwayFromCore(){ + Tile tile = world.tileWorld(x, y); + Tile targetTile = world.pathfinder().getTargetTile(Vars.state.teams.enemiesOf(team).first(), tile); if(tile == targetTile) return; - vec.trns(unit.baseRotation, speed); + vec.trns(baseRotation, type.speed); - unit.baseRotation = Mathf.slerpDelta(unit.baseRotation, unit.angleTo(targetTile), 0.05f); - unit.walkTime += Timers.delta(); - unit.velocity.add(vec); + baseRotation = Mathf.slerpDelta(baseRotation, angleTo(targetTile), 0.05f); + walkTime += Timers.delta(); + velocity.add(vec); } public final UnitState resupply = new UnitState(){ - public void entered(BaseUnit unit) { - unit.target = null; + public void entered() { + target = null; } - public void update(BaseUnit unit) { - Tile tile = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.resupplyPoint)); + public void update() { + Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint)); - if (tile != null && unit.distanceTo(tile) > 40) { - moveAwayFromCore(unit); + if (tile != null && distanceTo(tile) > 40) { + moveAwayFromCore(); } //TODO move toward resupply point - if(unit.inventory.totalAmmo() + 10 >= unit.inventory.ammoCapacity()){ - unit.state.set(unit, attack); + if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ + state.set(attack); } } }, attack = new UnitState(){ - public void entered(BaseUnit unit) { - unit.target = null; + public void entered() { + target = null; } - public void update(BaseUnit unit) { - unit.retarget(() -> { - Unit closest = Units.getClosestEnemy(unit.team, unit.x, unit.y, unit.inventory.getAmmo().getRange(), other -> true); + public void update() { + retarget(() -> { + Unit closest = Units.getClosestEnemy(team, x, y, inventory.getAmmo().getRange(), other -> true); if(closest != null){ - unit.target = closest; + target = closest; }else { - Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getEnemy(unit.team, BlockFlag.target)); - if (target != null) unit.target = target.entity; + Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, BlockFlag.target)); + if (target != null) GroundUnitType.this.target = target.entity; } }); - if(!unit.inventory.hasAmmo()) { - unit.state.set(unit, resupply); + if(!inventory.hasAmmo()) { + state.set(resupply); }else{ - if(unit.distanceTo(unit.target) > unit.inventory.getAmmo().getRange() * 0.7f){ - moveToCore(unit); + if(distanceTo(target) > inventory.getAmmo().getRange() * 0.7f){ + moveToCore(); }else{ - unit.rotate(unit.angleTo(unit.target)); + rotate(angleTo(target)); } - if (unit.timer.get(timerReload, reload) && Mathf.angNear(unit.angleTo(unit.target), unit.rotation, 13f) - && unit.distanceTo(unit.target) < unit.inventory.getAmmo().getRange()) { - AmmoType ammo = unit.inventory.getAmmo(); - unit.inventory.useAmmo(); - unit.rotate(unit.angleTo(unit.target)); + if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f) + && distanceTo(target) < inventory.getAmmo().getRange()) { + AmmoType ammo = inventory.getAmmo(); + inventory.useAmmo(); + rotate(angleTo(target)); - shoot(unit, ammo, Angles.moveToward(unit.rotation, unit.angleTo(unit.target), maxAim), 4f); + shoot(ammo, Angles.moveToward(rotation, angleTo(target), maxAim), 4f); } } } }, retreat = new UnitState() { - public void entered(BaseUnit unit) { - unit.target = null; + public void entered() { + target = null; } - public void update(BaseUnit unit) { - if(unit.health >= health){ - unit.state.set(unit, attack); + public void update() { + if(health >= health){ + state.set(attack); } - moveAwayFromCore(unit); + moveAwayFromCore(); } }; } diff --git a/core/src/io/anuke/mindustry/entities/units/StateMachine.java b/core/src/io/anuke/mindustry/entities/units/StateMachine.java index 156ff35c7c..082f7d114f 100644 --- a/core/src/io/anuke/mindustry/entities/units/StateMachine.java +++ b/core/src/io/anuke/mindustry/entities/units/StateMachine.java @@ -3,15 +3,15 @@ package io.anuke.mindustry.entities.units; public class StateMachine { private UnitState state; - public void update(BaseUnit unit){ - if(state != null) state.update(unit); + public void update(){ + if(state != null) state.update(); } - public void set(BaseUnit unit, UnitState next){ + public void set( UnitState next){ if(next == state) return; - if(state != null) state.exited(unit); + if(state != null) state.exited(); this.state = next; - if(next != null) next.entered(unit); + if(next != null) next.entered(); } public boolean is(UnitState state){ diff --git a/core/src/io/anuke/mindustry/entities/units/UnitState.java b/core/src/io/anuke/mindustry/entities/units/UnitState.java index fa00d52053..c11ce3aa8b 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitState.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitState.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.entities.units; public interface UnitState { - default void entered(BaseUnit unit){} - default void exited(BaseUnit unit){} - default void update(BaseUnit unit){} + default void entered(){} + default void exited(){} + default void update(){} } diff --git a/core/src/io/anuke/mindustry/entities/units/UnitType.java b/core/src/io/anuke/mindustry/entities/units/UnitType.java index 8a2e8fba7b..9b021caedd 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitType.java @@ -2,146 +2,55 @@ package io.anuke.mindustry.entities.units; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.ObjectMap; -import io.anuke.mindustry.content.fx.ExplosionFx; -import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.entities.bullet.Bullet; -import io.anuke.mindustry.net.Net; -import io.anuke.mindustry.net.NetEvents; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.type.AmmoType; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.world.BlockFlag; -import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.core.Effects; -import io.anuke.ucore.core.Timers; -import io.anuke.ucore.util.Angles; -import io.anuke.ucore.util.Geometry; -import io.anuke.ucore.util.Mathf; -import static io.anuke.mindustry.Vars.tilesize; -import static io.anuke.mindustry.Vars.world; - -public abstract class UnitType { +public class UnitType { private static byte lastid = 0; private static Array types = new Array<>(); - private static int timerIndex = 0; - - protected static final int timerTarget = timerIndex++; - protected static final int timerBoost = timerIndex++; - protected static final int timerReload = timerIndex++; + protected final UnitCreator creator; public final String name; public final byte id; - protected float health = 60; - protected float hitsize = 5f; - protected float hitsizeTile = 4f; - protected float speed = 0.4f; - protected float range = 160; - protected float rotatespeed = 0.1f; - protected float baseRotateSpeed = 0.1f; - protected float mass = 1f; - protected boolean isFlying; - protected float drag = 0.1f; - protected float maxVelocity = 5f; - protected float reload = 40f; - protected float retreatPercent = 0.2f; - protected float armor = 0f; - protected ObjectMap ammo = new ObjectMap<>(); + public float health = 60; + public float hitsize = 5f; + public float hitsizeTile = 4f; + public float speed = 0.4f; + public float range = 160; + public float rotatespeed = 0.1f; + public float baseRotateSpeed = 0.1f; + public float mass = 1f; + public boolean isFlying; + public float drag = 0.1f; + public float maxVelocity = 5f; + public float reload = 40f; + public float retreatPercent = 0.2f; + public float armor = 0f; + public ObjectMap ammo = new ObjectMap<>(); - public UnitType(String name){ + public UnitType(String name, UnitCreator creator){ this.id = lastid++; this.name = name; + this.creator = creator; + types.add(this); } + public BaseUnit create(Team team){ + return creator.create(team); + } + protected void setAmmo(AmmoType... types){ for(AmmoType type : types){ ammo.put(type.item, type); } } - public abstract void draw(BaseUnit unit); - - public void drawUnder(BaseUnit unit){} - - public void drawOver(BaseUnit unit){} - - public UnitState getStartState(){ - return null; - } - - public boolean isFlying(){ - return isFlying; - } - - public void update(BaseUnit unit){ - if(unit.hitTime > 0){ - unit.hitTime -= Timers.delta(); - } - - if(unit.hitTime < 0) unit.hitTime = 0; - - if(Net.client()){ - unit.interpolate(); - return; - } - - updateTargeting(unit); - - unit.state.update(unit); - unit.updateVelocityStatus(drag, maxVelocity); - - if(unit.target != null) behavior(unit); - - unit.x = Mathf.clamp(unit.x, 0, world.width() * tilesize); - unit.y = Mathf.clamp(unit.y, 0, world.height() * tilesize); - } - - /**Only runs when the unit has a target.*/ - public abstract void behavior(BaseUnit unit); - - public void updateTargeting(BaseUnit unit){ - if(unit.target == null || (unit.target instanceof Unit && (unit.target.isDead() || ((Unit)unit.target).team == unit.team)) - || (unit.target instanceof TileEntity && ((TileEntity) unit.target).tile.entity == null)){ - unit.target = null; - } - } - - public void shoot(BaseUnit unit, AmmoType type, float rotation, float translation){ - Bullet.create(type.bullet, unit, - unit.x + Angles.trnsx(rotation, translation), - unit.y + Angles.trnsy(rotation, translation), rotation); - Effects.effect(type.shootEffect, unit.x + Angles.trnsx(rotation, translation), - unit.y + Angles.trnsy(rotation, translation), rotation, unit); - Effects.effect(type.smokeEffect, unit.x + Angles.trnsx(rotation, translation), - unit.y + Angles.trnsy(rotation, translation), rotation, unit); - } - - public void targetClosestAllyFlag(BaseUnit unit, BlockFlag flag){ - Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, flag)); - if (target != null) unit.target = target.entity; - } - - public void onDeath(BaseUnit unit){ - //TODO other things, such as enemies? - Effects.effect(ExplosionFx.explosion, unit); - Effects.shake(2f, 2f, unit); - - if(Net.server()){ - NetEvents.handleUnitDeath(unit); - } - - unit.remove(); - } - - public void onRemoteDeath(BaseUnit unit){ - onDeath(unit); - } - - public void removed(BaseUnit unit){ - //TODO + public interface UnitCreator{ + BaseUnit create(Team team); } public static UnitType getByID(byte id){ diff --git a/core/src/io/anuke/mindustry/entities/units/types/Brute.java b/core/src/io/anuke/mindustry/entities/units/types/Brute.java deleted file mode 100644 index 2dafd845f6..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/types/Brute.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.anuke.mindustry.entities.units.types; - -import io.anuke.mindustry.content.AmmoTypes; -import io.anuke.mindustry.entities.units.GroundUnitType; - -public class Brute extends GroundUnitType { - - public Brute(String name) { - super(name); - setAmmo(AmmoTypes.bulletIron); - } - -} diff --git a/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java b/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java deleted file mode 100644 index 50c8e36d1f..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.anuke.mindustry.entities.units.types; - -import io.anuke.mindustry.content.AmmoTypes; -import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.entities.units.BaseUnit; -import io.anuke.mindustry.entities.units.FlyingUnitType; -import io.anuke.mindustry.entities.units.UnitState; -import io.anuke.mindustry.graphics.Palette; -import io.anuke.ucore.core.Timers; -import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.Angles; -import io.anuke.ucore.util.Mathf; - -public class Cruiser extends FlyingUnitType { - - - public Cruiser(){ - super("vtol"); - setAmmo(AmmoTypes.bulletIron); - speed = 0.2f; - maxVelocity = 1.4f; - health = 300f; - } - - @Override - public void drawUnder(BaseUnit unit) { - float rotation = unit.rotation - 90; - float scl = 0.6f + Mathf.absin(Timers.time(), 1f, 0.3f); - float dy = -6f*scl; - - Draw.color(Palette.lighterOrange, Palette.lightFlame, Mathf.absin(Timers.time(), 3f, 0.7f)); - - Draw.rect("vtol-flame", - unit.x + Angles.trnsx(rotation, 0, dy), - unit.y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation); - - Draw.color(); - } - - @Override - public void draw(BaseUnit unit) { - Draw.alpha(unit.hitTime / Unit.hitDuration); - - Draw.rect(name, unit.x, unit.y, unit.rotation - 90); - - Draw.alpha(1f); - } - - @Override - public void update(BaseUnit unit) { - super.update(unit); - - unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.06f); - unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.06f); - - if(unit.velocity.len() <= 0.2f){ - unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 8f); - } - - if(unit.timer.get(timerBoost, 2)){ - // unit.effectAt(UnitFx.vtolHover, unit.rotation + 180f, 4f, 0); - } - } - - @Override - public UnitState getStartState(){ - return resupply; - } -} diff --git a/core/src/io/anuke/mindustry/entities/units/types/Drone.java b/core/src/io/anuke/mindustry/entities/units/types/Drone.java index f69ea2d972..e74ffa9146 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Drone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Drone.java @@ -1,58 +1,117 @@ package io.anuke.mindustry.entities.units.types; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.utils.Queue; +import io.anuke.mindustry.entities.BlockBuilder; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.Units; import io.anuke.mindustry.entities.units.BaseUnit; -import io.anuke.mindustry.entities.units.FlyingUnitType; +import io.anuke.mindustry.entities.units.FlyingUnit; import io.anuke.mindustry.entities.units.UnitState; +import io.anuke.mindustry.entities.units.UnitType; +import io.anuke.mindustry.game.EventType.BlockBuildEvent; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.world.BlockFlag; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.blocks.types.BuildBlock; +import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity; +import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Shapes; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Mathf; +import static io.anuke.mindustry.Vars.unitGroups; import static io.anuke.mindustry.Vars.world; -public class Drone extends FlyingUnitType { - protected float healSpeed = 0.1f; - protected float discoverRange = 120f; +public class Drone extends FlyingUnit implements BlockBuilder{ + protected static float healSpeed = 0.1f; + protected static float discoverRange = 120f; + protected static boolean initialized; - public Drone() { - super("drone"); - speed = 0.2f; - maxVelocity = 0.8f; - range = 50f; + protected Tile mineTile; + protected Queue placeQueue = new Queue<>(); + + private static void initEvents(){ + Events.on(BlockBuildEvent.class, (team, tile) -> { + EntityGroup group = unitGroups[team.ordinal()]; + + if(!(tile.entity instanceof BuildEntity)) return; + BuildEntity entity = tile.entity(); + + for(BaseUnit unit : group.all()){ + if(unit instanceof Drone){ + ((Drone) unit).notifyPlaced(entity); + } + } + }); + } + + public Drone(UnitType type, Team team) { + super(type, team); + + if(!initialized){ + initEvents(); + initialized = true; + } + } + + private void notifyPlaced(BuildEntity entity){ + float timeToBuild = entity.recipe.cost; + float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0); + + if(dist / type.maxVelocity < timeToBuild * 0.9f){ + target = entity; + setState(build); + } } @Override - public void update(BaseUnit unit) { - float rot = unit.rotation; - super.update(unit); - unit.rotation = rot; + public Queue getPlaceQueue() { + return placeQueue; + } - if(unit.target != null && unit.state.is(repair)){ - unit.rotation = Mathf.slerpDelta(rot, unit.angleTo(unit.target), 0.3f); + @Override + public Tile getMineTile() { + return mineTile; + } + + @Override + public void setMineTile(Tile tile) { + this.mineTile = tile; + } + + @Override + public void update() { + float rot = rotation; + super.update(); + rotation = rot; + + if(target != null && state.is(repair)){ + rotation = Mathf.slerpDelta(rot, angleTo(target), 0.3f); }else{ - unit.rotation = Mathf.slerpDelta(rot, unit.velocity.angle(), 0.3f); + rotation = Mathf.slerpDelta(rot, velocity.angle(), 0.3f); } - unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.07f); - unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.07f); + x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f); + y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f); - if(unit.velocity.len() <= 0.2f && !(unit.state.is(repair) && unit.target != null)){ - unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 5f); + if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){ + rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f); } + + updateBuilding(this); } @Override - public void behavior(BaseUnit unit) { - if(unit.health <= health * retreatPercent && - Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)) != null){ - unit.setState(retreat); + public void behavior() { + if(health <= health * type.retreatPercent && + Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ + setState(retreat); } } @@ -62,60 +121,86 @@ public class Drone extends FlyingUnitType { } @Override - public void drawOver(BaseUnit unit) { - if(unit.target instanceof TileEntity && unit.state.is(repair)){ + public void drawOver() { + trail.draw(Palette.lighterOrange, Palette.lightishOrange, 3f); + + if(target instanceof TileEntity && state.is(repair)){ float len = 5f; Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f)); Shapes.laser("beam", "beam-end", - unit.x + Angles.trnsx(unit.rotation, len), - unit.y + Angles.trnsy(unit.rotation, len), - unit.target.getX(), unit.target.getY()); + x + Angles.trnsx(rotation, len), + y + Angles.trnsy(rotation, len), + target.getX(), target.getY()); Draw.color(); } + + drawBuilding(this); + } + + @Override + public float drawSize() { + return isBuilding() ? placeDistance*2f : 30f; } public final UnitState + build = new UnitState(){ + + public void update() { + BuildEntity entity = (BuildEntity)target; + + if(entity.progress() < 1f && entity.tile.block() instanceof BuildBlock){ //building is valid + if(!isBuilding() && distanceTo(target) < placeDistance * 0.9f){ //within distance, begin placing + getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.recipe)); + } + + circle(placeDistance * 0.7f); + }else{ //building isn't valid + setState(repair); + } + } + }, + repair = new UnitState(){ - public void entered(BaseUnit unit) { - unit.target = null; + public void entered() { + target = null; } - public void update(BaseUnit unit) { - if(unit.target != null && (((TileEntity)unit.target).health >= ((TileEntity)unit.target).tile.block().health - || unit.target.distanceTo(unit) > discoverRange)){ - unit.target = null; + public void update() { + if(target != null && (((TileEntity)target).health >= ((TileEntity)target).tile.block().health + || target.distanceTo(Drone.this) > discoverRange)){ + target = null; } - if (unit.target == null) { - if (unit.timer.get(timerTarget, 20)) { - unit.target = Units.findAllyTile(unit.team, unit.x, unit.y, discoverRange, - tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health); - } - }else if(unit.target.distanceTo(unit) > range){ - circle(unit, range); + if (target == null) { + retarget(() -> { + target = Units.findAllyTile(team, x, y, discoverRange, + tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health); + }); + }else if(target.distanceTo(Drone.this) > type.range){ + circle(type.range); }else{ - TileEntity entity = (TileEntity) unit.target; + TileEntity entity = (TileEntity) target; entity.health += healSpeed * Timers.delta(); entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health); } } }, retreat = new UnitState() { - public void entered(BaseUnit unit) { - unit.target = null; + public void entered() { + target = null; } - public void update(BaseUnit unit) { - if(unit.health >= health){ - unit.state.set(unit, attack); - }else if(!unit.targetHasFlag(BlockFlag.repair)){ - if(unit.timer.get(timerTarget, 20)) { - Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)); - if (target != null) unit.target = target.entity; + public void update() { + if(health >= health){ + state.set(attack); + }else if(!targetHasFlag(BlockFlag.repair)){ + if(timer.get(timerTarget, 20)) { + Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)); + if (target != null) Drone.this.target = target.entity; } }else{ - circle(unit, 40f); + circle(40f); } } }; diff --git a/core/src/io/anuke/mindustry/entities/units/types/Eradicator.java b/core/src/io/anuke/mindustry/entities/units/types/Eradicator.java deleted file mode 100644 index 3dce0d6ae5..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/types/Eradicator.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.units.types; - -public class Eradicator { -} diff --git a/core/src/io/anuke/mindustry/entities/units/types/Reaper.java b/core/src/io/anuke/mindustry/entities/units/types/Reaper.java deleted file mode 100644 index c76b31e5c7..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/types/Reaper.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.anuke.mindustry.entities.units.types; - -import io.anuke.mindustry.entities.units.FlyingUnitType; - -public class Reaper extends FlyingUnitType { - - public Reaper(String name) { - super(name); - } -} diff --git a/core/src/io/anuke/mindustry/entities/units/types/Scout.java b/core/src/io/anuke/mindustry/entities/units/types/Scout.java index 8b179e29cd..93b5b39702 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Scout.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Scout.java @@ -1,12 +1,12 @@ package io.anuke.mindustry.entities.units.types; -import io.anuke.mindustry.content.AmmoTypes; import io.anuke.mindustry.entities.units.GroundUnitType; +import io.anuke.mindustry.entities.units.UnitType; +import io.anuke.mindustry.game.Team; public class Scout extends GroundUnitType { - public Scout(){ - super("scout"); - setAmmo(AmmoTypes.bulletIron); + public Scout(UnitType type, Team team) { + super(type, team); } } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Sheller.java b/core/src/io/anuke/mindustry/entities/units/types/Sheller.java deleted file mode 100644 index 747415eda3..0000000000 --- a/core/src/io/anuke/mindustry/entities/units/types/Sheller.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.units.types; - -public class Sheller { -} diff --git a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java index 848f256d34..3dd96c63ed 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java @@ -1,67 +1,62 @@ package io.anuke.mindustry.entities.units.types; -import io.anuke.mindustry.content.AmmoTypes; import io.anuke.mindustry.content.fx.UnitFx; -import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.entities.units.BaseUnit; -import io.anuke.mindustry.entities.units.FlyingUnitType; +import io.anuke.mindustry.entities.units.FlyingUnit; +import io.anuke.mindustry.entities.units.UnitType; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.graphics.Palette; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class Vtol extends FlyingUnitType { +public class Vtol extends FlyingUnit { - public Vtol(){ - super("vtol"); - setAmmo(AmmoTypes.bulletIron); - speed = 0.3f; - maxVelocity = 2f; - reload = 7; + public Vtol(UnitType type, Team team) { + super(type, team); } @Override - public void drawUnder(BaseUnit unit) { - float rotation = unit.rotation - 90; + public void drawUnder() { + float rotation = this.rotation - 90; float scl = 0.6f + Mathf.absin(Timers.time(), 1f, 0.3f); float dy = -6f*scl; Draw.color(Palette.lighterOrange, Palette.lightFlame, Mathf.absin(Timers.time(), 3f, 0.7f)); Draw.rect("vtol-flame", - unit.x + Angles.trnsx(rotation, 0, dy), - unit.y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation); + x + Angles.trnsx(rotation, 0, dy), + y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation); Draw.color(); } @Override - public void draw(BaseUnit unit) { - Draw.alpha(unit.hitTime / Unit.hitDuration); + public void drawSmooth() { + Draw.alpha(hitTime / hitDuration); - Draw.rect(name, unit.x, unit.y, unit.rotation - 90); + Draw.rect(type.name, x, y, rotation - 90); for(int i : Mathf.signs){ - Draw.rect(name + "-booster-1", unit.x, unit.y, 12*i, 12, unit.rotation - 90); - Draw.rect(name + "-booster-2", unit.x, unit.y, 12*i, 12, unit.rotation - 90); + Draw.rect(type.name + "-booster-1", x, y, 12*i, 12, rotation - 90); + Draw.rect(type.name + "-booster-2", x, y, 12*i, 12, rotation - 90); } Draw.alpha(1f); } @Override - public void update(BaseUnit unit) { - super.update(unit); + public void update() { + super.update(); - unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.07f); - unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.07f); + x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f); + y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f); - if(unit.velocity.len() <= 0.2f){ - unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 8f); + if(velocity.len() <= 0.2f){ + rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f); } - if(unit.timer.get(timerBoost, 2)){ - unit.effectAt(UnitFx.vtolHover, unit.rotation + 180f, 4f, 0); + if(timer.get(timerBoost, 2)){ + effectAt(UnitFx.vtolHover, rotation + 180f, 4f, 0); } } diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index 5f5a7c0bdc..0814d1d286 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -50,5 +50,9 @@ public class EventType { public interface UnlockEvent extends Event{ void handle(Content content); } + + public interface BlockBuildEvent extends Event{ + void handle(Team team, Tile tile); + } } diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index 7f737a6623..9edb109a48 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -189,7 +189,7 @@ public class OverlayRenderer { } drawEncloser(x, y - 8f, 2f); - drawBar(Color.SCARLET, x, y - 8f, unit.health / unit.maxhealth); + drawBar(Color.SCARLET, x, y - 8f, unit.healthfrac()); drawBar(Color.valueOf("32cf6d"), x, y - 9f, unit.inventory.totalAmmo() / (float) unit.inventory.ammoCapacity()); } diff --git a/core/src/io/anuke/mindustry/type/Item.java b/core/src/io/anuke/mindustry/type/Item.java index 49b714a8a2..6de074bc8a 100644 --- a/core/src/io/anuke/mindustry/type/Item.java +++ b/core/src/io/anuke/mindustry/type/Item.java @@ -32,7 +32,7 @@ public class Item implements Comparable, Content{ public Color flameColor = Palette.darkFlame.cpy(); /**base material cost of this item, used for calculating place times * 1 cost = 1 tick added to build time*/ - public float cost = 1f; + public float cost = 3f; public Item(String name, Color color) { this.id = items.size; diff --git a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java index 23f6edd3ed..b3208b3753 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java @@ -4,10 +4,9 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import io.anuke.mindustry.content.UnitTypes; import io.anuke.mindustry.content.bullets.TurretBullets; -import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.entities.units.BaseUnit; +import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.net.Net; import io.anuke.ucore.core.Timers; @@ -70,9 +69,9 @@ public class DebugFragment implements Fragment { row(); new button("death", () -> player.damage(99999, false)); row(); - new button("spawnf", () -> new BaseUnit(UnitTypes.drone, player.team).set(player.x, player.y).add()); + new button("spawnf", () -> UnitTypes.drone.create(player.team).set(player.x, player.y).add()); row(); - new button("spawng", () -> new BaseUnit(UnitTypes.scout, player.team).set(player.x, player.y).add()); + new button("spawng", () -> UnitTypes.scout.create(player.team).set(player.x, player.y).add()); row(); }}.end(); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/power/NuclearReactor.java b/core/src/io/anuke/mindustry/world/blocks/types/power/NuclearReactor.java index 675aa6ecab..76e0fa0a21 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/power/NuclearReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/power/NuclearReactor.java @@ -47,6 +47,7 @@ public class NuclearReactor extends LiquidBurnerGenerator { itemCapacity = 30; liquidCapacity = 50; powerCapacity = 80f; + hasItems = true; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java b/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java index 284a6f99d7..02d03d86b1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java @@ -75,7 +75,7 @@ public class RepairPoint extends Block{ RepairPointEntity entity = tile.entity(); if(entity.target != null && (entity.target.isDead() || entity.target.distanceTo(tile) > repairRadius || - entity.target.health >= entity.target.maxhealth)){ + entity.target.health >= entity.target.getMaxHealth())){ entity.target = null; }else if(entity.target != null){ entity.target.health += repairSpeed * Timers.delta() * entity.strength; @@ -95,7 +95,7 @@ public class RepairPoint extends Block{ if(entity.timer.get(timerTarget, 20)) { rect.setSize(repairRadius * 2).setCenter(tile.drawx(), tile.drawy()); entity.target = Units.getClosest(tile.getTeam(), tile.drawx(), tile.drawy(), repairRadius, - unit -> unit.health < unit.maxhealth); + unit -> unit.health < unit.getMaxHealth()); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/types/units/UnitFactory.java b/core/src/io/anuke/mindustry/world/blocks/types/units/UnitFactory.java index 518c4837a9..dc1f0596cb 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/units/UnitFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/units/UnitFactory.java @@ -51,7 +51,7 @@ public class UnitFactory extends Block { @Override public boolean isSolidFor(Tile tile) { UnitFactoryEntity entity = tile.entity(); - return type.isFlying() || !entity.open; + return type.isFlying || !entity.open; } @Override @@ -114,7 +114,7 @@ public class UnitFactory extends Block { if(entity.openCountdown > Timers.delta()){ entity.openCountdown -= Timers.delta(); }else{ - if(type.isFlying() || !anyEntities(tile)) { + if(type.isFlying || !anyEntities(tile)) { entity.open = false; entity.openCountdown = -1; }else{ @@ -141,7 +141,7 @@ public class UnitFactory extends Block { Effects.shake(2f, 3f, entity); Effects.effect(BlockFx.producesmoke, tile.drawx(), tile.drawy()); - BaseUnit unit = new BaseUnit(type, tile.getTeam()); + BaseUnit unit = type.create(tile.getTeam()); unit.set(tile.drawx(), tile.drawy()).add(); unit.velocity.y = launchVelocity; });