diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index aaa1fe5361..aa911488ca 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.ai; +import com.badlogic.gdx.utils.Bits; import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.ObjectSet; @@ -7,9 +8,10 @@ import io.anuke.mindustry.content.Items; import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.game.TeamInfo.TeamData; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.core.Events; import io.anuke.ucore.util.EnumSet; import io.anuke.ucore.util.Mathf; @@ -18,16 +20,22 @@ import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; //TODO consider using quadtrees for finding specific types of blocks within an area -/**Class used for indexing special target blocks for AI. - * TODO maybe use Arrays instead of ObjectSets?*/ +//TODO maybe use Arrays instead of ObjectSets? +/**Class used for indexing special target blocks for AI.*/ public class BlockIndexer { /**Size of one ore quadrant.*/ - private final static int quadrantSize = 12; + private final static int oreQuadrantSize = 12; + /**Size of one structure quadrant.*/ + private final static int structQuadrantSize = 12; + /**Set of all ores that are being scanned.*/ private final ObjectSet scanOres = ObjectSet.with(Items.iron, Items.coal, Items.lead, Items.thorium, Items.titanium); /**Stores all ore quadtrants on the map.*/ private ObjectMap> ores = new ObjectMap<>(); + /**Tags all quadrants.*/ + private Bits[] structQuadrants; + /**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.*/ @@ -48,6 +56,7 @@ public class BlockIndexer { } } process(tile); + updateQuadrant(tile); }); Events.on(WorldLoadEvent.class, () -> { @@ -55,6 +64,13 @@ public class BlockIndexer { allyMap.clear(); typeMap.clear(); ores.clear(); + + //create bitset for each team type that contains each quadrant + structQuadrants = new Bits[Team.values().length]; + for(int i = 0; i < Team.values().length; i ++){ + structQuadrants[i] = new Bits(Mathf.ceil(world.width() / (float)structQuadrantSize) * Mathf.ceil(world.height() / (float)structQuadrantSize)); + } + for(int x = 0; x < world.width(); x ++){ for (int y = 0; y < world.height(); y++) { process(world.tile(x, y)); @@ -77,7 +93,7 @@ public class BlockIndexer { /**Returns a set of tiles that have ores of the specified type nearby. * While each tile in the set is not guaranteed to have an ore directly on it, - * each tile will at least have an ore within {@link #quadrantSize} / 2 blocks of it. + * each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it. * Only specific ore types are scanned. See {@link #scanOres}.*/ public ObjectSet getOrePositions(Item item){ return ores.get(item, emptyArray); @@ -104,6 +120,36 @@ public class BlockIndexer { } } + private void updateQuadrant(Tile tile){ + //this quadrant is now 'dirty', re-scan the whole thing + int quadrantX = tile.x / structQuadrantSize; + int quadrantY = tile.y / structQuadrantSize; + int index = quadrantX * Mathf.ceil(world.width() / (float)structQuadrantSize) + quadrantY; + + for(TeamData data : state.teams.getTeams()) { + + //fast-set this quadrant to 'occupied' if the tile just placed is already of this team + if(tile.getTeam() == data.team && tile.entity != null){ + structQuadrants[data.team.ordinal()].set(index); + continue; //no need to process futher + } + + structQuadrants[data.team.ordinal()].clear(index); + + outer: + for (int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++) { + for (int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++) { + Tile result = world.tile(x, y); + //when a targetable block is found, mark this quadrant as occupied and stop searching + if(result.entity != null && result.getTeam() == data.team){ + structQuadrants[data.team.ordinal()].set(index); + break outer; + } + } + } + } + } + private ObjectMap> getMap(Team team){ if(!state.teams.has(team)) return emptyMap; return state.teams.get(team).ally ? allyMap : enemyMap; @@ -117,8 +163,8 @@ public class BlockIndexer { for(int x = 0; x < world.width(); x ++){ for (int y = 0; y < world.height(); y++) { - int qx = (x/quadrantSize); - int qy = (y/quadrantSize); + int qx = (x/ oreQuadrantSize); + int qy = (y/ oreQuadrantSize); Tile tile = world.tile(x, y); @@ -126,8 +172,8 @@ public class BlockIndexer { if(tile.floor().drops != null && scanOres.contains(tile.floor().drops.item)){ ores.get(tile.floor().drops.item).add(world.tile( //make sure to clamp quadrant middle position, since it might go off bounds - Mathf.clamp(qx * quadrantSize + quadrantSize/2, 0, world.width() - 1), - Mathf.clamp(qy * quadrantSize + quadrantSize/2, 0, world.height() - 1))); + Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1), + Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1))); } } } diff --git a/core/src/io/anuke/mindustry/ai/SpawnSelector.java b/core/src/io/anuke/mindustry/ai/SpawnSelector.java deleted file mode 100644 index a4ec4d24a9..0000000000 --- a/core/src/io/anuke/mindustry/ai/SpawnSelector.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.anuke.mindustry.ai; - -import io.anuke.mindustry.game.EventType.WorldLoadEvent; -import io.anuke.ucore.core.Events; - -import static io.anuke.mindustry.Vars.world; - -public class SpawnSelector { - private static final int quadsize = 15; - - public SpawnSelector(){ - Events.on(WorldLoadEvent.class, this::reset); - } - - public void calculateSpawn(){ - - for(int x = 0; x < world.width(); x += quadsize){ - for(int y = 0; y < world.height(); y += quadsize){ - //TODO quadrant operations, etc - } - } - } - - private void reset(){ - - } -} diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java new file mode 100644 index 0000000000..80c709ae4c --- /dev/null +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -0,0 +1,93 @@ +package io.anuke.mindustry.ai; + +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.content.AmmoTypes; +import io.anuke.mindustry.content.UnitTypes; +import io.anuke.mindustry.entities.units.BaseUnit; +import io.anuke.mindustry.entities.units.Squad; +import io.anuke.mindustry.game.EventType.WorldLoadEvent; +import io.anuke.mindustry.game.Team; +import io.anuke.ucore.core.Events; +import io.anuke.ucore.util.Mathf; + +import static io.anuke.mindustry.Vars.*; + +public class WaveSpawner { + private static final int quadsize = 15; + + private Array flySpawns = new Array<>(); + private Array groundSpawns = new Array<>(); + + public WaveSpawner(){ + Events.on(WorldLoadEvent.class, this::reset); + } + + public void spawnEnemies(){ + int spawned = 10; + int groundGroups = Math.min(1 + state.wave / 20, 4); + int flyGroups = Math.min(1 + state.wave / 20, 4); + + //add extra groups if necessary + for (int i = 0; i < groundGroups - groundSpawns.size; i++) { + GroundSpawn spawn = new GroundSpawn(); + } + + for (int i = 0; i < flyGroups - flySpawns.size; i++) { + FlyerSpawn spawn = new FlyerSpawn(); + spawn.angle = Mathf.random(360f); + + flySpawns.add(spawn); + } + + for(GroundSpawn spawn : groundSpawns){ + + } + + for(FlyerSpawn spawn : flySpawns){ + Squad squad = new Squad(); + float addition = 40f; + float spread = addition / 1.5f; + + float baseX = world.width() *tilesize/2f + Mathf.sqrwavex(spawn.angle) * (world.width()/2f*tilesize + addition), + baseY = world.height() * tilesize/2f + Mathf.sqrwavey(spawn.angle) * (world.height()/2f*tilesize + addition); + + for(int i = 0; i < spawned; i ++){ + BaseUnit unit = UnitTypes.vtol.create(Team.red); + unit.inventory.addAmmo(AmmoTypes.bulletIron); + unit.setWave(); + unit.setSquad(squad); + unit.set(baseX + Mathf.range(spread), baseY + Mathf.range(spread)); + unit.add(); + } + } + } + + public void calculateSpawn(){ + + for(int x = 0; x < world.width(); x += quadsize){ + for(int y = 0; y < world.height(); y += quadsize){ + //TODO quadrant operations, etc + } + } + } + + private void reset(){ + flySpawns.clear(); + groundSpawns.clear(); + } + + private class FlyerSpawn{ + float angle; + + FlyerSpawn(){ + + } + } + + private class GroundSpawn{ + + GroundSpawn(){ + + } + } +} diff --git a/core/src/io/anuke/mindustry/content/blocks/WeaponBlocks.java b/core/src/io/anuke/mindustry/content/blocks/WeaponBlocks.java index 99f93b4828..94a0480bf7 100644 --- a/core/src/io/anuke/mindustry/content/blocks/WeaponBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/WeaponBlocks.java @@ -31,7 +31,8 @@ public class WeaponBlocks extends BlockList implements ContentList { reload = 60f; restitution = 0.03f; recoil = 1.5f; - burstSpacing = 6f; + burstSpacing = 1f; + inaccuracy = 7f; ammoUseEffect = ShootFx.shellEjectSmall; }}; @@ -47,6 +48,7 @@ public class WeaponBlocks extends BlockList implements ContentList { hail = new ItemTurret("hail") {{ ammoTypes = new AmmoType[]{AmmoTypes.artilleryLead, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary}; + reload = 40f; }}; wave = new LiquidTurret("wave") {{ diff --git a/core/src/io/anuke/mindustry/core/GameState.java b/core/src/io/anuke/mindustry/core/GameState.java index 4abc23acb4..9262c848d1 100644 --- a/core/src/io/anuke/mindustry/core/GameState.java +++ b/core/src/io/anuke/mindustry/core/GameState.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.core; +import io.anuke.mindustry.ai.WaveSpawner; import io.anuke.mindustry.game.Difficulty; import io.anuke.mindustry.game.EventType.StateChangeEvent; import io.anuke.mindustry.game.GameMode; @@ -17,6 +18,7 @@ public class GameState{ public GameMode mode = GameMode.waves; public Difficulty difficulty = Difficulty.normal; public boolean friendlyFire; + public WaveSpawner spawner = new WaveSpawner(); public TeamInfo teams = new TeamInfo(); public void set(State astate){ diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 23227858f7..baa361eaf6 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -1,11 +1,8 @@ package io.anuke.mindustry.core; -import com.badlogic.gdx.math.Vector2; -import io.anuke.mindustry.content.AmmoTypes; -import io.anuke.mindustry.content.UnitTypes; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.entities.units.BaseUnit; +import io.anuke.mindustry.game.EventType.GameOverEvent; import io.anuke.mindustry.game.EventType.PlayEvent; import io.anuke.mindustry.game.EventType.ResetEvent; import io.anuke.mindustry.game.EventType.WaveEvent; @@ -30,8 +27,7 @@ import static io.anuke.mindustry.Vars.*; * Handles game state events. * Does not store any game state itself. * - * This class should not call any outside methods to change state of modules, but instead fire events. - */ + * This class should not call any outside methods to change state of modules, but instead fire events.*/ public class Logic extends Module { public boolean doUpdate = true; @@ -80,17 +76,7 @@ public class Logic extends Module { } public void runWave(){ - - //TODO spawn enemies properly - for(int i = 0; i < 10; i ++){ - 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.setWave(); - unit.set(offset.x, offset.y); - unit.add(); - } - + state.spawner.spawnEnemies(); state.wave ++; state.wavetime = wavespace * state.difficulty.timeScaling; state.extrawavetime = maxwavespace * state.difficulty.maxTimeScaling; @@ -98,6 +84,22 @@ public class Logic extends Module { Events.fire(WaveEvent.class); } + private void checkGameOver(){ + boolean gameOver = true; + + for(TeamData data : state.teams.getTeams(true)){ + if(data.cores.size > 0){ + gameOver = false; + break; + } + } + + if(gameOver && !state.gameOver){ + state.gameOver = true; + Events.fire(GameOverEvent.class); + } + } + @Override public void update(){ if(!doUpdate) return; @@ -110,22 +112,10 @@ public class Logic extends Module { Timers.update(); } - /* - boolean gameOver = true; - - for(TeamData data : state.teams.getTeams(true)){ - if(data.cores.size > 0){ - gameOver = false; - break; - } + if(!debug){ + checkGameOver(); } - if(gameOver && !state.gameOver){ //TODO better gameover state, victory state? - state.gameOver = true; - if(Net.server()) NetEvents.handleGameOver(); - Events.fire(GameOverEvent.class); - }*/ - if(!state.is(State.paused) || Net.active()){ if(!state.mode.disableWaveTimer){ @@ -158,11 +148,12 @@ public class Logic extends Module { if(!group.isEmpty()){ EntityPhysics.collideGroups(bulletGroup, group); + /* for(EntityGroup other : unitGroups){ if(!other.isEmpty()){ EntityPhysics.collideGroups(group, other); } - } + }*/ } } diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index bf958853d7..4ebe91ef01 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -414,6 +414,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait { updateMech(); } + avoidOthers(8f); + float wobblyness = 0.6f; trail.update(x + Angles.trnsx(rotation + 180f, 6f) + Mathf.range(wobblyness), @@ -489,7 +491,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait { velocity.add(movement); - updateVelocityStatus(mech.drag, mech.maxSpeed); + updateVelocityStatus(mech.drag, debug ? speed : mech.maxSpeed); if(!movement.isZero()){ walktime += Timers.delta() * velocity.len()*(1f/0.5f)/speed * getFloorOn().speedMultiplier; diff --git a/core/src/io/anuke/mindustry/entities/TileEntity.java b/core/src/io/anuke/mindustry/entities/TileEntity.java index a1018699d9..1a980c08df 100644 --- a/core/src/io/anuke/mindustry/entities/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/TileEntity.java @@ -31,6 +31,7 @@ import static io.anuke.mindustry.Vars.world; public class TileEntity extends BaseEntity implements TargetTrait { public static final float timeToSleep = 60f*4; //4 seconds to fall asleep + /**This value is only used for debugging.*/ public static int sleepingEntities = 0; public Tile tile; diff --git a/core/src/io/anuke/mindustry/entities/Unit.java b/core/src/io/anuke/mindustry/entities/Unit.java index f9714e315d..1c8e73108e 100644 --- a/core/src/io/anuke/mindustry/entities/Unit.java +++ b/core/src/io/anuke/mindustry/entities/Unit.java @@ -13,12 +13,14 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Floor; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.entities.EntityPhysics; import io.anuke.ucore.entities.impl.DestructibleEntity; import io.anuke.ucore.entities.trait.DamageTrait; import io.anuke.ucore.entities.trait.DrawTrait; import io.anuke.ucore.entities.trait.SolidTrait; import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Mathf; +import io.anuke.ucore.util.Translator; import java.io.DataInput; import java.io.DataOutput; @@ -35,6 +37,8 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ /**Maximum absolute value of a velocity vector component.*/ public static final float maxAbsVelocity = 127f/velocityPercision; + private static final Vector2 moveVector = new Vector2(); + public UnitInventory inventory = new UnitInventory(this); public float rotation; @@ -43,7 +47,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ protected Team team = Team.blue; protected CarryTrait carrier; - protected Vector2 velocity = new Vector2(0f, 0.0001f); + protected Vector2 velocity = new Translator(0f, 0.0001f); protected float hitTime; protected float drownTime; @@ -172,6 +176,16 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ return tile == null ? (Floor) Blocks.air : tile.floor(); } + public void avoidOthers(float avoidRange){ + + EntityPhysics.getNearby(getGroup(), x, y, avoidRange*2f, t -> { + if(t == this || (t instanceof Unit && ((Unit) t).isDead())) return; + float dst = distanceTo(t); + if(dst > avoidRange) return; + velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange)))); + }); + } + /**Updates velocity and status effects.*/ public void updateVelocityStatus(float drag, float maxVelocity){ if(isCarried()){ //carried units do not take into account velocity normally diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index 3c04d3b59d..d672cab2ff 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -10,7 +10,7 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.entities.EntityPhysics; -import io.anuke.ucore.entities.impl.BaseEntity; +import io.anuke.ucore.entities.trait.Entity; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.function.Predicate; import io.anuke.ucore.util.Mathf; @@ -99,9 +99,10 @@ public class Units { return findTile(x, y, range, tile -> state.teams.areEnemies(team, tile.getTeam()) && pred.test(tile)); } + //TODO optimize, spatial caching of tiles /**Returns the neareset tile entity in a range.*/ public static TileEntity findTile(float x, float y, float range, Predicate pred){ - BaseEntity closest = null; + Entity closest = null; float dst = 0; int rad = (int)(range/tilesize)+1; diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index aab6dcf8b0..7c42bb56d7 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.entities.units; +import com.badlogic.gdx.math.Vector2; import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.Remote; import io.anuke.mindustry.content.fx.ExplosionFx; @@ -19,10 +20,7 @@ import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.EntityGroup; -import io.anuke.ucore.util.Angles; -import io.anuke.ucore.util.Geometry; -import io.anuke.ucore.util.Mathf; -import io.anuke.ucore.util.Timer; +import io.anuke.ucore.util.*; import java.io.DataInput; import java.io.DataOutput; @@ -32,6 +30,7 @@ import static io.anuke.mindustry.Vars.*; public abstract class BaseUnit extends Unit{ private static int timerIndex = 0; + private static Vector2 moveVector = new Translator(); protected static final int timerTarget = timerIndex++; protected static final int timerReload = timerIndex++; @@ -39,9 +38,11 @@ public abstract class BaseUnit extends Unit{ protected UnitType type; protected Timer timer = new Timer(5); protected StateMachine state = new StateMachine(); - protected boolean isWave; protected TargetTrait target; + protected boolean isWave; + protected Squad squad; + public BaseUnit(UnitType type, Team team){ this.type = type; this.team = team; @@ -55,6 +56,11 @@ public abstract class BaseUnit extends Unit{ isWave = true; } + public void setSquad(Squad squad) { + this.squad = squad; + squad.units ++; + } + public void rotate(float angle){ rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed); } @@ -186,6 +192,12 @@ public abstract class BaseUnit extends Unit{ return; } + avoidOthers(8f); + + if(squad != null){ + squad.update(); + } + updateTargeting(); state.update(); diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java index 0a5574302b..2b5cb2dcec 100644 --- a/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java @@ -23,7 +23,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ protected static float maxAim = 30f; protected static float wobblyness = 0.6f; - protected Trail trail = new Trail(16); + protected Trail trail = new Trail(8); protected CarriableTrait carrying; public FlyingUnit(UnitType type, Team team) { @@ -79,6 +79,11 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ setState(retreat); } + + if(squad != null){ + squad.direction.add(velocity.x / squad.units, velocity.y / squad.units); + velocity.setAngle(Mathf.slerpDelta(velocity.angle(), squad.direction.angle(), 0.3f)); + } } @Override diff --git a/core/src/io/anuke/mindustry/entities/units/Squad.java b/core/src/io/anuke/mindustry/entities/units/Squad.java new file mode 100644 index 0000000000..41ad5f9d58 --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/units/Squad.java @@ -0,0 +1,22 @@ +package io.anuke.mindustry.entities.units; + +import com.badlogic.gdx.math.Vector2; +import io.anuke.ucore.util.Translator; + +import static io.anuke.mindustry.Vars.threads; + +/**Used to group entities together, for formations and such. + * Usually, squads are used by units spawned in the same wave.*/ +public class Squad { + public Vector2 direction = new Translator(); + public int units; + + private long lastUpdated; + + protected void update(){ + if(threads.getFrameID() != lastUpdated){ + direction.setZero(); + lastUpdated = threads.getFrameID(); + } + } +} diff --git a/core/src/io/anuke/mindustry/game/TeamInfo.java b/core/src/io/anuke/mindustry/game/TeamInfo.java index ee92297f92..b55fe91308 100644 --- a/core/src/io/anuke/mindustry/game/TeamInfo.java +++ b/core/src/io/anuke/mindustry/game/TeamInfo.java @@ -92,8 +92,8 @@ public class TeamInfo { public boolean areEnemies(Team team, Team other){ if(team == other) return false; //fast fail to be more efficient boolean ally = (allyBits & (1 << team.ordinal())) != 0; - boolean ally2 = (enemyBits & (1 << other.ordinal())) != 0; - return (ally == ally2) || !ally; //if it's not in the game, target everything. + boolean enemy = (enemyBits & (1 << other.ordinal())) != 0; + return (ally == enemy) || !ally; //if it's not in the game, target everything. } public class TeamData { diff --git a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java index 3585a93419..5b9b281c75 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java @@ -10,6 +10,7 @@ import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.net.Net; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.scene.Group; import io.anuke.ucore.scene.builders.button; import io.anuke.ucore.scene.builders.label; @@ -46,7 +47,7 @@ public class DebugFragment implements Fragment { new table(){{ visible(() -> debug); - atop().aright(); + abottom().aleft(); new table("pane"){{ defaults().fillX().width(100f); @@ -133,11 +134,20 @@ public class DebugFragment implements Fragment { } public static String debugInfo(){ + int totalUnits = 0; + for(EntityGroup group : unitGroups){ + totalUnits += group.size(); + } + + totalUnits += playerGroup.size(); + StringBuilder result = join( "net.active: " + Net.active(), "net.server: " + Net.server(), "net.client: " + Net.client(), "state: " + state.getState(), + "units: " + totalUnits, + "bullets: " + bulletGroup.size(), Net.client() ? "chat.open: " + ui.chatfrag.chatOpen() + "\n" + "chat.messages: " + ui.chatfrag.getMessagesSize() + "\n" + diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java index 7a30518a25..4a108a9488 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java @@ -56,6 +56,11 @@ public class CoreBlock extends StorageBlock { flags = EnumSet.of(BlockFlag.resupplyPoint, BlockFlag.target); } + @Override + public float handleDamage(Tile tile, float amount) { + return debug ? 0 : amount; + } + @Override public void draw(Tile tile) { CoreEntity entity = tile.entity();