Unit enemy spawnpoint camping

This commit is contained in:
Anuken
2019-09-20 23:09:11 -04:00
parent 025386af53
commit dda1f18f67
14 changed files with 1581 additions and 1500 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Before

Width:  |  Height:  |  Size: 95 B

After

Width:  |  Height:  |  Size: 95 B

View File

@@ -577,8 +577,8 @@ category.general.name = General
category.view.name = View category.view.name = View
category.multiplayer.name = Multiplayer category.multiplayer.name = Multiplayer
command.attack = Attack command.attack = Attack
command.rally = Rally
command.retreat = Retreat command.retreat = Retreat
command.patrol = Patrol
keybind.gridMode.name = Block Select keybind.gridMode.name = Block Select
keybind.gridModeShift.name = Category Select keybind.gridModeShift.name = Category Select
keybind.press = Press a key... keybind.press = Press a key...
@@ -854,6 +854,8 @@ block.solar-panel.name = Solar Panel
block.solar-panel-large.name = Large Solar Panel block.solar-panel-large.name = Large Solar Panel
block.oil-extractor.name = Oil Extractor block.oil-extractor.name = Oil Extractor
block.command-center.name = Command Center block.command-center.name = Command Center
block.rally-point.name = Rally Point
block.rally-point.description = A marker for units to group up around. Requires issuing the 'Rally' command on the command center to use.
block.draug-factory.name = Draug Miner Drone Factory block.draug-factory.name = Draug Miner Drone Factory
block.spirit-factory.name = Spirit Repair Drone Factory block.spirit-factory.name = Spirit Repair Drone Factory
block.phantom-factory.name = Phantom Builder Drone Factory block.phantom-factory.name = Phantom Builder Drone Factory

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 723 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

After

Width:  |  Height:  |  Size: 677 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 KiB

After

Width:  |  Height:  |  Size: 587 KiB

View File

@@ -7,7 +7,6 @@ import io.anuke.arc.function.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.async.*; import io.anuke.arc.util.async.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
@@ -39,6 +38,7 @@ public class Pathfinder implements Runnable{
Events.on(WorldLoadEvent.class, event -> { Events.on(WorldLoadEvent.class, event -> {
stop(); stop();
//reset and update internal tile array
tiles = new int[world.width()][world.height()]; tiles = new int[world.width()][world.height()];
pathMap = new PathData[Team.all.length][PathTarget.all.length]; pathMap = new PathData[Team.all.length][PathTarget.all.length];
created = new GridBits(Team.all.length, PathTarget.all.length); created = new GridBits(Team.all.length, PathTarget.all.length);
@@ -50,9 +50,14 @@ public class Pathfinder implements Runnable{
} }
} }
//special preset which may help speed things up; this is optional
preloadPath(waveTeam, PathTarget.enemyCores);
start(); start();
}); });
Events.on(ResetEvent.class, event -> stop());
Events.on(TileChangeEvent.class, event -> updateTile(event.tile)); Events.on(TileChangeEvent.class, event -> updateTile(event.tile));
} }
@@ -84,12 +89,13 @@ public class Pathfinder implements Runnable{
int x = tile.x, y = tile.y; int x = tile.x, y = tile.y;
tiles[x][y] = packed; tiles[x][y] = packed;
//can't iterate through array so use the map, which should not lead to problems
for(PathData[] arr : pathMap){ for(PathData[] arr : pathMap){
for(PathData path : arr){ for(PathData path : arr){
if(path != null){ if(path != null){
synchronized(path.targets){ synchronized(path.targets){
path.targets.clear(); path.targets.clear();
path.target.getTargets(tile.getTeam(), path.targets); path.target.getTargets(path.team, path.targets);
} }
} }
} }
@@ -97,7 +103,7 @@ public class Pathfinder implements Runnable{
queue.post(() -> { queue.post(() -> {
for(PathData data : list){ for(PathData data : list){
updateTargets(data, x, y, packed); updateTargets(data, x, y);
} }
}); });
} }
@@ -106,7 +112,7 @@ public class Pathfinder implements Runnable{
@Override @Override
public void run(){ public void run(){
while(true){ while(true){
if(net.client() || state.is(State.menu)) return; if(net.client()) return;
queue.run(); queue.run();
@@ -126,7 +132,7 @@ public class Pathfinder implements Runnable{
/** Gets next tile to travel to. Main thread only. */ /** Gets next tile to travel to. Main thread only. */
public Tile getTargetTile(Tile tile, Team team, PathTarget target){ public Tile getTargetTile(Tile tile, Team team, PathTarget target){
if(tile == null) return tile; if(tile == null) return null;
PathData data = pathMap[team.ordinal()][target.ordinal()]; PathData data = pathMap[team.ordinal()][target.ordinal()];
@@ -136,7 +142,7 @@ public class Pathfinder implements Runnable{
created.set(team.ordinal(), target.ordinal()); created.set(team.ordinal(), target.ordinal());
//grab targets since this is run on main thread //grab targets since this is run on main thread
IntArray targets = target.getTargets(team, new IntArray()); IntArray targets = target.getTargets(team, new IntArray());
queue.post(() -> createFor(team, target, targets)); queue.post(() -> createPath(team, target, targets));
} }
return tile; return tile;
} }
@@ -174,7 +180,7 @@ public class Pathfinder implements Runnable{
* Clears the frontier, increments the search and sets up all flow sources. * Clears the frontier, increments the search and sets up all flow sources.
* This only occurs for active teams. * This only occurs for active teams.
*/ */
private void updateTargets(PathData path, int x, int y, int tile){ private void updateTargets(PathData path, int x, int y){
if(!Structs.inBounds(x, y, path.weights)) return; if(!Structs.inBounds(x, y, path.weights)) return;
if(path.weights[x][y] == 0){ if(path.weights[x][y] == 0){
@@ -207,9 +213,13 @@ public class Pathfinder implements Runnable{
} }
} }
private void preloadPath(Team team, PathTarget target){
updateFrontier(createPath(team, target, target.getTargets(team, new IntArray())), -1);
}
/** Created a new flowfield that aims to get to a certain target for a certain team. /** Created a new flowfield that aims to get to a certain target for a certain team.
* Pathfinding thread only. */ * Pathfinding thread only. */
private void createFor(Team team, PathTarget target, IntArray targets){ private PathData createPath(Team team, PathTarget target, IntArray targets){
PathData path = new PathData(team, target, world.width(), world.height()); PathData path = new PathData(team, target, world.width(), world.height());
list.add(path); list.add(path);
@@ -234,6 +244,8 @@ public class Pathfinder implements Runnable{
path.weights[Pos.x(pos)][Pos.y(pos)] = 0; path.weights[Pos.x(pos)][Pos.y(pos)] = 0;
path.frontier.addFirst(pos); path.frontier.addFirst(pos);
} }
return path;
} }
/** Update the frontier for a path. Pathfinding thread only. */ /** Update the frontier for a path. Pathfinding thread only. */
@@ -274,6 +286,13 @@ public class Pathfinder implements Runnable{
for(Tile other : indexer.getEnemy(team, BlockFlag.core)){ for(Tile other : indexer.getEnemy(team, BlockFlag.core)){
out.add(other.pos()); out.add(other.pos());
} }
//spawn points are also enemies.
if(state.rules.waves && team == defaultTeam){
for(Tile other : spawner.getGroundSpawns()){
out.add(other.pos());
}
}
}), }),
rallyPoints((team, out) -> { rallyPoints((team, out) -> {
for(Tile other : indexer.getAllied(team, BlockFlag.rally)){ for(Tile other : indexer.getAllied(team, BlockFlag.rally)){

View File

@@ -75,7 +75,7 @@ public class Blocks implements ContentList{
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
//units //units
commandCenter, draugFactory, spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, crawlerFactory, titanFactory, commandCenter, rallyPoint, draugFactory, spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, crawlerFactory, titanFactory,
fortressFactory, repairPoint, fortressFactory, repairPoint,
//upgrades //upgrades
@@ -1650,6 +1650,12 @@ public class Blocks implements ContentList{
health = size * size * 55; health = size * size * 55;
}}; }};
rallyPoint = new RallyPoint("rally-point"){{
requirements(Category.units, ItemStack.with(Items.lead, 100, Items.silicon, 100, Items.graphite, 50));
size = 2;
health = size * size * 85;
}};
wraithFactory = new UnitFactory("wraith-factory"){{ wraithFactory = new UnitFactory("wraith-factory"){{
requirements(Category.units, ItemStack.with(Items.titanium, 30, Items.lead, 40, Items.silicon, 45)); requirements(Category.units, ItemStack.with(Items.titanium, 30, Items.lead, 40, Items.silicon, 45));
type = UnitTypes.wraith; type = UnitTypes.wraith;

View File

@@ -174,8 +174,15 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
} }
} }
public TileEntity getClosestEnemyCore(){ public Tile getClosest(BlockFlag flag){
return Geometry.findClosest(x, y, indexer.getAllied(team, flag));
}
public Tile getClosestSpawner(){
return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns());
}
public TileEntity getClosestEnemyCore(){
for(Team enemy : Vars.state.teams.enemiesOf(team)){ for(Team enemy : Vars.state.teams.enemiesOf(team)){
Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores); Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores);
if(tile != null){ if(tile != null){

View File

@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.bullet.*;
import io.anuke.mindustry.entities.units.*; import io.anuke.mindustry.entities.units.*;
@@ -35,13 +36,15 @@ public abstract class FlyingUnit extends BaseUnit{
if(target == null) targetClosestEnemyFlag(BlockFlag.producer); if(target == null) targetClosestEnemyFlag(BlockFlag.producer);
if(target == null) targetClosestEnemyFlag(BlockFlag.turret); if(target == null) targetClosestEnemyFlag(BlockFlag.turret);
if(target == null){
setState(patrol);
}
} }
if(target != null){ if(target == null){
target = getSpawner();
}
if(target == getSpawner() && getSpawner() != null){
circle(80f + Mathf.randomSeed(id) * 120);
}else if(target != null){
attack(type.attackLength); attack(type.attackLength);
if((Angles.near(angleTo(target), rotation, type.shootCone) || getWeapon().ignoreRotation) //bombers and such don't care about rotation if((Angles.near(angleTo(target), rotation, type.shootCone) || getWeapon().ignoreRotation) //bombers and such don't care about rotation
@@ -64,22 +67,24 @@ public abstract class FlyingUnit extends BaseUnit{
getWeapon().update(FlyingUnit.this, to.x, to.y); getWeapon().update(FlyingUnit.this, to.x, to.y);
} }
} }
}else{
target = getClosestSpawner();
moveTo(Vars.state.rules.dropZoneRadius + 80f);
} }
} }
}, },
patrol = new UnitState(){ rally = new UnitState(){
public void update(){ public void update(){
if(retarget()){ if(retarget()){
targetClosestAllyFlag(BlockFlag.rally);
targetClosest(); targetClosest();
targetClosestEnemyFlag(BlockFlag.core);
if(target != null && !Units.invalidateTarget(target, team, x, y)){ if(target != null && !Units.invalidateTarget(target, team, x, y)){
setState(attack); setState(attack);
return; return;
} }
target = getSpawner(); if(target == null) target = getSpawner();
if(target == null) target = getClosestCore();
} }
if(target != null){ if(target != null){
@@ -109,7 +114,7 @@ public abstract class FlyingUnit extends BaseUnit{
public void onCommand(UnitCommand command){ public void onCommand(UnitCommand command){
state.set(command == UnitCommand.retreat ? retreat : state.set(command == UnitCommand.retreat ? retreat :
command == UnitCommand.attack ? attack : command == UnitCommand.attack ? attack :
command == UnitCommand.patrol ? patrol : command == UnitCommand.rally ? rally :
null); null);
} }

View File

@@ -14,6 +14,7 @@ import io.anuke.mindustry.game.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -35,31 +36,30 @@ public abstract class GroundUnit extends BaseUnit{
TileEntity core = getClosestEnemyCore(); TileEntity core = getClosestEnemyCore();
if(core == null){ if(core == null){
setState(patrol); Tile closestSpawn = getClosestSpawner();
return; if(closestSpawn == null || !withinDst(closestSpawn, Vars.state.rules.dropZoneRadius + 75f)){
} moveToCore(PathTarget.enemyCores);
}
}else{
float dst = dst(core); float dst = dst(core);
if(dst < getWeapon().bullet.range() / 1.1f){ if(dst < getWeapon().bullet.range() / 1.1f){
target = core; target = core;
} }
if(dst > getWeapon().bullet.range() * 0.5f){ if(dst > getWeapon().bullet.range() * 0.5f){
moveToCore(); moveToCore(PathTarget.enemyCores);
}
} }
} }
}, },
patrol = new UnitState(){ rally = new UnitState(){
public void update(){ public void update(){
TileEntity target = getClosestCore(); Tile target = getClosest(BlockFlag.rally);
if(target != null){ if(target != null && dst(target) > 100f){
if(dst(target) > 400f){ moveToCore(PathTarget.rallyPoints);
moveAwayFromCore();
}else if(!(!Units.invalidateTarget(GroundUnit.this.target, GroundUnit.this) && dst(GroundUnit.this.target) < getWeapon().bullet.range())){
patrol();
}
} }
} }
}, },
@@ -77,7 +77,7 @@ public abstract class GroundUnit extends BaseUnit{
public void onCommand(UnitCommand command){ public void onCommand(UnitCommand command){
state.set(command == UnitCommand.retreat ? retreat : state.set(command == UnitCommand.retreat ? retreat :
command == UnitCommand.attack ? attack : command == UnitCommand.attack ? attack :
command == UnitCommand.patrol ? patrol : command == UnitCommand.rally ? rally :
null); null);
} }
@@ -221,10 +221,10 @@ public abstract class GroundUnit extends BaseUnit{
velocity.add(vec); velocity.add(vec);
} }
protected void moveToCore(){ protected void moveToCore(PathTarget path){
Tile tile = world.tileWorld(x, y); Tile tile = world.tileWorld(x, y);
if(tile == null) return; if(tile == null) return;
Tile targetTile = pathfinder.getTargetTile(tile, team, PathTarget.enemyCores); Tile targetTile = pathfinder.getTargetTile(tile, team, path);
if(tile == targetTile) return; if(tile == targetTile) return;

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.units;
import io.anuke.arc.*; import io.anuke.arc.*;
public enum UnitCommand{ public enum UnitCommand{
attack, retreat, patrol; attack, retreat, rally;
private final String localized; private final String localized;
public static final UnitCommand[] all = values(); public static final UnitCommand[] all = values();