diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index 3523d2732b..3011879492 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -1,6 +1,93 @@ package io.anuke.mindustry.ai; +import com.badlogic.gdx.utils.IntMap; +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.ObjectSet; +import io.anuke.mindustry.game.EventType.TileChangeEvent; +import io.anuke.mindustry.game.EventType.WorldLoadEvent; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.flags.BlockFlag; +import io.anuke.ucore.core.Events; +import io.anuke.ucore.util.EnumSet; + +import static io.anuke.mindustry.Vars.state; +import static io.anuke.mindustry.Vars.world; + /**Class used for indexing special target blocks for AI. - * TODO implement this class*/ + * TODO maybe use Arrays instead of ObjectSets?*/ public class BlockIndexer { + /**Maps teams to a map of flagged tiles by type.*/ + private ObjectMap> enemyMap = new ObjectMap<>(); + /**Maps teams to a map of flagged tiles by type.*/ + private ObjectMap> allyMap = new ObjectMap<>(); + /**Maps tile positions to their last known tile index data.*/ + private IntMap typeMap = new IntMap<>(); + /**Empty array used for returning.*/ + private ObjectSet emptyArray = new ObjectSet<>(); + + public BlockIndexer(){ + Events.on(TileChangeEvent.class, tile -> { + if(typeMap.get(tile.packedPosition()) != null){ + TileIndex index = typeMap.get(tile.packedPosition()); + for(BlockFlag flag : index.flags){ + getMap(index.team).get(flag).remove(tile); + } + } + process(tile); + }); + + Events.on(WorldLoadEvent.class, () -> { + enemyMap.clear(); + allyMap.clear(); + typeMap.clear(); + for(int x = 0; x < world.width(); x ++){ + for (int y = 0; y < world.height(); y++) { + process(world.tile(x, y)); + } + } + }); + } + + public ObjectSet getAllied(Team team, BlockFlag type){ + return (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray); + } + + public ObjectSet getEnemy(Team team, BlockFlag type){ + return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray); + } + + private void process(Tile tile){ + if(tile.block().flags != null){ + ObjectMap> map = getMap(tile.getTeam()); + + for(BlockFlag flag : tile.block().flags){ + + ObjectSet arr = map.get(flag); + if(arr == null){ + arr = new ObjectSet<>(); + map.put(flag, arr); + } + + arr.add(tile); + + map.put(flag, arr); + } + typeMap.put(tile.packedPosition(), new TileIndex(tile.block().flags, tile.getTeam())); + } + } + + private ObjectMap> getMap(Team team){ + return state.teams.get(team).ally ? allyMap : enemyMap; + } + + private class TileIndex{ + public final EnumSet flags; + public final Team team; + + public TileIndex(EnumSet flags, Team team) { + this.flags = flags; + this.team = team; + } + } } diff --git a/core/src/io/anuke/mindustry/content/fx/UnitFx.java b/core/src/io/anuke/mindustry/content/fx/UnitFx.java index 92664c373a..ca1459bc63 100644 --- a/core/src/io/anuke/mindustry/content/fx/UnitFx.java +++ b/core/src/io/anuke/mindustry/content/fx/UnitFx.java @@ -13,7 +13,7 @@ public class UnitFx { vtolHover = new Effect(40f, e -> { float len = e.finpow()*10f; float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f); - Draw.color(Palette.lightFlame); + Draw.color(Palette.lightFlame, Palette.lightOrange, e.fin()); Fill.circle(e.x + Angles.trnsx(ang, len), e.y + Angles.trnsy(ang, len), 2f * e.fout()); Draw.reset(); }); diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index 37a6d1f22c..fc8ee5f6d8 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -22,6 +22,7 @@ import io.anuke.mindustry.entities.effect.GroundEffectEntity; import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect; import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.game.TeamInfo.TeamData; import io.anuke.mindustry.graphics.BlockRenderer; import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.graphics.MinimapRenderer; @@ -519,8 +520,8 @@ public class Renderer extends RendererModule{ } if((!debug || showUI) && Settings.getBool("healthbars")){ - for(EntityGroup group : unitGroups){ - for(Unit e : group.all()){ + for(TeamData ally : state.teams.getTeams(true)){ + for(Unit e : unitGroups[ally.team.ordinal()].all()){ drawStats(e); } } diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index d9aa794cd5..d50a5f2e7b 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.ai.BlockIndexer; import io.anuke.mindustry.ai.Pathfinder; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.game.EventType.TileChangeEvent; @@ -28,6 +29,7 @@ public class World extends Module{ private Map currentMap; private Tile[][] tiles; private Pathfinder pathfinder = new Pathfinder(); + private BlockIndexer indexer = new BlockIndexer(); private Maps maps = new Maps(); private Array tempTiles = new Array<>(); @@ -46,6 +48,10 @@ public class World extends Module{ return maps; } + public BlockIndexer indexer() { + return indexer; + } + public Pathfinder pathfinder(){ return pathfinder; } diff --git a/core/src/io/anuke/mindustry/entities/Unit.java b/core/src/io/anuke/mindustry/entities/Unit.java index ec86539f62..39d06c305b 100644 --- a/core/src/io/anuke/mindustry/entities/Unit.java +++ b/core/src/io/anuke/mindustry/entities/Unit.java @@ -56,6 +56,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity { stream.writeShort((short)health); stream.writeByte(status.current().id); stream.writeFloat(status.getTime()); + inventory.write(stream); } @Override @@ -67,6 +68,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity { byte effect = stream.readByte(); float etime = stream.readFloat(); + this.inventory.read(stream); this.team = Team.values()[team]; this.health = health; this.x = x; @@ -125,7 +127,10 @@ public abstract class Unit extends SyncEntity implements SerializableEntity { damage(health + 1, false); } + float px = x, py = y; move(velocity.x / getMass() * floor.speedMultiplier * Timers.delta(), velocity.y / getMass() * floor.speedMultiplier * Timers.delta()); + if(Math.abs(px - x) <= 0.0001f) velocity.x = 0f; + if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f; } velocity.scl(Mathf.clamp(1f-drag* floor.dragMultiplier* Timers.delta())); diff --git a/core/src/io/anuke/mindustry/entities/UnitInventory.java b/core/src/io/anuke/mindustry/entities/UnitInventory.java index 67ffb9bf8b..2690fc6adc 100644 --- a/core/src/io/anuke/mindustry/entities/UnitInventory.java +++ b/core/src/io/anuke/mindustry/entities/UnitInventory.java @@ -1,7 +1,14 @@ package io.anuke.mindustry.entities; import com.badlogic.gdx.utils.Array; -import io.anuke.mindustry.resource.*; +import io.anuke.mindustry.resource.AmmoEntry; +import io.anuke.mindustry.resource.AmmoType; +import io.anuke.mindustry.resource.Item; +import io.anuke.mindustry.resource.ItemStack; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; public class UnitInventory { private Array ammos = new Array<>(); @@ -14,6 +21,33 @@ public class UnitInventory { this.ammoCapacity = ammoCapacity; } + public void write(DataOutputStream stream) throws IOException { + stream.writeInt(item == null ? 0 : item.amount); + stream.writeByte(item == null ? 0 : item.item.id); + stream.writeInt(totalAmmo); + stream.writeByte(ammos.size); + for(int i = 0; i < ammos.size; i ++){ + stream.writeByte(ammos.get(i).type.id); + stream.writeInt(ammos.get(i).amount); + } + } + + public void read(DataInputStream stream) throws IOException { + int iamount = stream.readInt(); + byte iid = stream.readByte(); + this.totalAmmo = stream.readInt(); + byte ammoa = stream.readByte(); + for(int i = 0; i < ammoa; i ++){ + byte aid = stream.readByte(); + int am = stream.readInt(); + ammos.add(new AmmoEntry(AmmoType.getByID(aid), am)); + } + + if(iamount != 0){ + item = new ItemStack(Item.getByID(iid), iamount); + } + } + public AmmoType getAmmo() { return ammos.size == 0 ? null : ammos.peek().type; } diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index 6edb24f2b2..bc4ed0b6cd 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -4,9 +4,11 @@ import io.anuke.mindustry.ai.OptimizedPathFinder; import io.anuke.mindustry.ai.SmoothGraphPath; import io.anuke.mindustry.entities.Bullet; import io.anuke.mindustry.entities.BulletType; +import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.resource.Item; +import io.anuke.mindustry.world.flags.BlockFlag; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.entities.Entity; @@ -25,6 +27,7 @@ public class BaseUnit extends Unit{ public UnitType type; public Timer timer = new Timer(5); public float walkTime = 0f; + public StateMachine state = new StateMachine(); public Entity target; protected OptimizedPathFinder finder; @@ -46,7 +49,12 @@ public class BaseUnit extends Unit{ public void effectAt(Effect effect, float rotation, float dx, float dy){ Effects.effect(effect, x + Angles.trnsx(rotation, dx, dy), - y + Angles.trnsy(rotation, dx, dy), Mathf.atan2(dx, dy)); + y + Angles.trnsy(rotation, dx, dy), Mathf.atan2(dx, dy) + rotation); + } + + public boolean targetHasFlag(BlockFlag flag){ + return target instanceof TileEntity && + ((TileEntity)target).tile.block().flags.contains(flag); } @Override @@ -129,6 +137,7 @@ public class BaseUnit extends Unit{ hitbox.solid = true; hitbox.setSize(type.hitsize); hitboxTile.setSize(type.hitsizeTile); + state.set(this, type.getStartState()); if(!isFlying()){ finder = new OptimizedPathFinder(); diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java index 4735c8706e..55d0b0aab6 100644 --- a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java @@ -1,16 +1,9 @@ package io.anuke.mindustry.entities.units; import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.ObjectSet; import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.game.TeamInfo.TeamData; -import io.anuke.mindustry.resource.AmmoType; -import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; -import static io.anuke.mindustry.Vars.state; - public class FlyingUnitType extends UnitType { protected static Vector2 vec = new Vector2(); @@ -29,11 +22,7 @@ public class FlyingUnitType extends UnitType { super.update(unit); unit.rotation = unit.velocity.angle(); - - if(unit.velocity.len() > 0.2f && unit.timer.get(timerBoost, 2f)){ - //Effects.effect(UnitFx.vtolHover, unit.x + Angles.trnsx(unit.rotation + 180f, boosterLength), - // unit.y + Angles.trnsy(unit.rotation + 180f, boosterLength)); - } + unit.state.update(unit); } @Override @@ -47,51 +36,6 @@ public class FlyingUnitType extends UnitType { @Override public void behavior(BaseUnit unit) { - vec.set(unit.target.x - unit.x, unit.target.y - unit.y); - float len = vec.len(); - - float circleLength = 40f; - - if(vec.len() < circleLength){ - vec.rotate((circleLength-vec.len())/circleLength * 180f); - } - - vec.setLength(speed * Timers.delta()); - - unit.velocity.add(vec); //TODO clamp it so it doesn't glitch out at low fps - - if(unit.inventory.hasAmmo() && unit.timer.get(timerReload, reload) && len < range){ - AmmoType ammo = unit.inventory.getAmmo(); - unit.inventory.useAmmo(); - - shoot(unit, ammo, unit.rotation, 4f); - } - } - - @Override - public void updateTargeting(BaseUnit unit) { - if(!unit.timer.get(timerTarget, 20)) return; - - ObjectSet teams = state.teams.enemyDataOf(unit.team); - - Tile closest = null; - float cdist = 0f; - - for(TeamData data : teams){ - for(Tile tile : data.cores){ - float dist = Vector2.dst(unit.x, unit.y, tile.drawx(), tile.drawy()); - if(closest == null || dist < cdist){ - closest = tile; - cdist = dist; - } - } - } - - if(closest != null){ - unit.target = closest.entity; - }else{ - unit.target = null; - } } } diff --git a/core/src/io/anuke/mindustry/entities/units/StateMachine.java b/core/src/io/anuke/mindustry/entities/units/StateMachine.java new file mode 100644 index 0000000000..e12c44fe0b --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/units/StateMachine.java @@ -0,0 +1,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 set(BaseUnit unit, UnitState next){ + if(state != null) state.exited(unit); + this.state = next; + if(next != null) next.entered(unit); + } +} diff --git a/core/src/io/anuke/mindustry/entities/units/UnitState.java b/core/src/io/anuke/mindustry/entities/units/UnitState.java new file mode 100644 index 0000000000..fa00d52053 --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/units/UnitState.java @@ -0,0 +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){} +} diff --git a/core/src/io/anuke/mindustry/entities/units/UnitType.java b/core/src/io/anuke/mindustry/entities/units/UnitType.java index 4b63e6b62f..8f5d47755b 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitType.java @@ -5,7 +5,6 @@ import com.badlogic.gdx.utils.ObjectMap; import io.anuke.mindustry.content.fx.ExplosionFx; import io.anuke.mindustry.entities.Bullet; import io.anuke.mindustry.entities.Unit; -import io.anuke.mindustry.entities.Units; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.resource.AmmoType; @@ -59,6 +58,10 @@ public abstract class UnitType { public abstract void draw(BaseUnit unit); + public UnitState getStartState(){ + return null; + } + public void drawUnder(BaseUnit unit){} public boolean isFlying(){ @@ -94,10 +97,6 @@ public abstract class UnitType { if(unit.target == null || (unit.target instanceof Unit && ((Unit)unit.target).isDead())){ unit.target = null; } - - if(unit.timer.get(timerTarget, 20)){ - unit.target = Units.getClosestEnemy(unit.team, unit.x, unit.y, range, e -> true); - } } public void shoot(BaseUnit unit, AmmoType type, float rotation, float translation){ 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 659fbb9456..216db280e4 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java @@ -1,26 +1,49 @@ 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; 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.mindustry.resource.AmmoType; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.flags.BlockFlag; 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 static io.anuke.mindustry.Vars.world; + public class Vtol extends FlyingUnitType { public Vtol(){ super("vtol"); setAmmo(AmmoTypes.basicIron); + speed = 0.3f; + maxVelocity = 2f; } @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(); + /* for(int i : Mathf.signs) { float rotation = unit.rotation - 90; @@ -32,16 +55,14 @@ public class Vtol extends FlyingUnitType { Draw.rect("vtol-flame", unit.x + Angles.trnsx(rotation, dx, dy), - unit.y + Angles.trnsy(rotation, dx, dy), Mathf.atan2(dx, dy)); + unit.y + Angles.trnsy(rotation, dx, dy), Mathf.atan2(dx, dy) + rotation); Draw.rect("vtol-flame", unit.x + Angles.trnsx(rotation, dx2, dy2), - unit.y + Angles.trnsy(rotation, dx2, dy2), Mathf.atan2(dx2, dy2)); + unit.y + Angles.trnsy(rotation, dx2, dy2), Mathf.atan2(dx2, dy2) + rotation); Draw.color(); - } - - + }*/ } @Override @@ -50,8 +71,8 @@ public class Vtol extends FlyingUnitType { Draw.rect(name, unit.x, unit.y, unit.rotation - 90); for(int i : Mathf.signs){ - Draw.rect(name + "-booster-1", unit.x + i, unit.y, 12*i, 12, unit.rotation - 90); - Draw.rect(name + "-booster-2", unit.x + i, unit.y, 12*i, 12, unit.rotation - 90); + 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.alpha(1f); @@ -61,14 +82,103 @@ public class Vtol extends FlyingUnitType { public void update(BaseUnit unit) { super.update(unit); - unit.x += Mathf.sin(Timers.time() + unit.id*999, 25f, 0.07f); - unit.y += Mathf.cos(Timers.time() + unit.id*999, 25f, 0.07f); - unit.rotation += Mathf.sin(Timers.time() + unit.id*99, 10f, 8f); + unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.07f); + unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.07f); + + 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 void behavior(BaseUnit unit) { - //super.behavior(unit); - + public UnitState getStartState(){ + return resupply; } + + void circle(BaseUnit unit, float circleLength){ + vec.set(unit.target.x - unit.x, unit.target.y - unit.y); + + if(vec.len() < circleLength){ + vec.rotate((circleLength-vec.len())/circleLength * 180f); + } + + vec.setLength(speed * Timers.delta()); + + unit.velocity.add(vec); + } + + void attack(BaseUnit unit, float circleLength){ + vec.set(unit.target.x - unit.x, unit.target.y - 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.4f)); + } + + 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)){ + if(unit.timer.get(timerTarget, 20)) { + Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.resupplyPoint)); + if (target != null) unit.target = target.entity; + } + }else{ + circle(unit, 20f); + } + } + }, + attack = new UnitState(){ + public void entered(BaseUnit unit) { + unit.target = null; + } + + public void update(BaseUnit unit) { + + 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 -> true); + if(closest != null){ + unit.target = closest; + }else { + Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getEnemy(unit.team, BlockFlag.resupplyPoint)); + if (target != null) unit.target = target.entity; + } + } + }else{ + attack(unit, 150f); + + if (unit.timer.get(timerReload, 7) && Mathf.angNear(unit.angleTo(unit.target), unit.rotation, 16f) + && unit.distanceTo(unit.target) < unit.inventory.getAmmo().getRange()) { + AmmoType ammo = unit.inventory.getAmmo(); + unit.inventory.useAmmo(); + + shoot(unit, ammo, unit.rotation, 4f); + } + } + } + }; + } diff --git a/core/src/io/anuke/mindustry/resource/AmmoType.java b/core/src/io/anuke/mindustry/resource/AmmoType.java index 4a6f6b13ed..eeb2aeec92 100644 --- a/core/src/io/anuke/mindustry/resource/AmmoType.java +++ b/core/src/io/anuke/mindustry/resource/AmmoType.java @@ -53,6 +53,10 @@ public class AmmoType { this.quantityMultiplier = multiplier; } + public float getRange(){ + return bullet.speed * bullet.lifetime; + } + public static Array getAllTypes() { return allTypes; } diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index d735a6a494..5040b030d0 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -20,12 +20,14 @@ import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.resource.ItemStack; import io.anuke.mindustry.resource.Liquid; +import io.anuke.mindustry.world.flags.BlockFlag; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Hue; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Bundles; +import io.anuke.ucore.util.EnumSet; import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; @@ -105,6 +107,8 @@ public class Block extends BaseBlock { public BlockBars bars = new BlockBars(); /**List of block stats.*/ public BlockStats stats = new BlockStats(); + /**List of block flags. Used for AI indexing.*/ + public EnumSet flags; /**Whether to automatically set the entity to 'sleeping' when created.*/ public boolean autoSleep; diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index b72868923d..6ce6ccd81b 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -11,12 +11,13 @@ import io.anuke.mindustry.world.blocks.types.modules.LiquidModule; import io.anuke.mindustry.world.blocks.types.modules.PowerModule; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.util.Bits; +import io.anuke.ucore.util.Position; import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class Tile{ +public class Tile implements Position{ public static final Object tileSetLock = new Object(); /**Block ID data.*/ @@ -300,6 +301,7 @@ public class Tile{ } public void changed(){ + synchronized (tileSetLock) { if (entity != null) { entity.remove(); @@ -323,6 +325,16 @@ public class Tile{ world.notifyChanged(this); } + @Override + public float getX() { + return drawx(); + } + + @Override + public float getY() { + return drawy(); + } + @Override public String toString(){ Block block = block(); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java index 4913caf420..441222ef2d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java @@ -5,13 +5,16 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.types.PowerBlock; +import io.anuke.mindustry.world.flags.BlockFlag; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.util.EnumSet; public class PowerGenerator extends PowerBlock { public PowerGenerator(String name) { super(name); baseExplosiveness = 5f; + flags = EnumSet.of(BlockFlag.producer); } protected void distributePower(Tile tile){ diff --git a/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java index d3efa1c6ca..3f32059744 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java @@ -6,8 +6,10 @@ import io.anuke.mindustry.entities.effect.ItemTransferEffect; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.flags.BlockFlag; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; +import io.anuke.ucore.util.EnumSet; import static io.anuke.mindustry.Vars.state; @@ -28,6 +30,7 @@ public class CoreBlock extends StorageBlock { size = 3; hasItems = true; itemCapacity = 2000; + flags = EnumSet.of(BlockFlag.resupplyPoint); } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java b/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java index aaa98a189d..5c2508a984 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java @@ -6,6 +6,8 @@ import io.anuke.mindustry.entities.effect.ItemTransferEffect; import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.flags.BlockFlag; +import io.anuke.ucore.util.EnumSet; public class ResupplyPoint extends Block{ private static Rectangle rect = new Rectangle(); @@ -19,6 +21,7 @@ public class ResupplyPoint extends Block{ super(name); update = true; solid = true; + flags = EnumSet.of(BlockFlag.resupplyPoint); } @Override diff --git a/core/src/io/anuke/mindustry/world/flags/BlockFlag.java b/core/src/io/anuke/mindustry/world/flags/BlockFlag.java new file mode 100644 index 0000000000..eb8712a692 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/flags/BlockFlag.java @@ -0,0 +1,5 @@ +package io.anuke.mindustry.world.flags; + +public enum BlockFlag { + resupplyPoint, producer +}