Unit enemy spawnpoint camping
BIN
core/assets-raw/sprites/blocks/units/rally-point.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 95 B After Width: | Height: | Size: 95 B |
@ -577,8 +577,8 @@ category.general.name = General
|
||||
category.view.name = View
|
||||
category.multiplayer.name = Multiplayer
|
||||
command.attack = Attack
|
||||
command.rally = Rally
|
||||
command.retreat = Retreat
|
||||
command.patrol = Patrol
|
||||
keybind.gridMode.name = Block Select
|
||||
keybind.gridModeShift.name = Category Select
|
||||
keybind.press = Press a key...
|
||||
@ -854,6 +854,8 @@ block.solar-panel.name = Solar Panel
|
||||
block.solar-panel-large.name = Large Solar Panel
|
||||
block.oil-extractor.name = Oil Extractor
|
||||
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.spirit-factory.name = Spirit Repair Drone Factory
|
||||
block.phantom-factory.name = Phantom Builder Drone Factory
|
||||
|
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 672 KiB After Width: | Height: | Size: 677 KiB |
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 258 KiB |
Before Width: | Height: | Size: 577 KiB After Width: | Height: | Size: 587 KiB |
@ -7,7 +7,6 @@ import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.async.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
@ -39,6 +38,7 @@ public class Pathfinder implements Runnable{
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
stop();
|
||||
|
||||
//reset and update internal tile array
|
||||
tiles = new int[world.width()][world.height()];
|
||||
pathMap = new PathData[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();
|
||||
});
|
||||
|
||||
Events.on(ResetEvent.class, event -> stop());
|
||||
|
||||
Events.on(TileChangeEvent.class, event -> updateTile(event.tile));
|
||||
}
|
||||
|
||||
@ -84,12 +89,13 @@ public class Pathfinder implements Runnable{
|
||||
int x = tile.x, y = tile.y;
|
||||
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 path : arr){
|
||||
if(path != null){
|
||||
synchronized(path.targets){
|
||||
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(() -> {
|
||||
for(PathData data : list){
|
||||
updateTargets(data, x, y, packed);
|
||||
updateTargets(data, x, y);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -106,7 +112,7 @@ public class Pathfinder implements Runnable{
|
||||
@Override
|
||||
public void run(){
|
||||
while(true){
|
||||
if(net.client() || state.is(State.menu)) return;
|
||||
if(net.client()) return;
|
||||
|
||||
queue.run();
|
||||
|
||||
@ -126,7 +132,7 @@ public class Pathfinder implements Runnable{
|
||||
|
||||
/** Gets next tile to travel to. Main thread only. */
|
||||
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()];
|
||||
|
||||
@ -136,7 +142,7 @@ public class Pathfinder implements Runnable{
|
||||
created.set(team.ordinal(), target.ordinal());
|
||||
//grab targets since this is run on main thread
|
||||
IntArray targets = target.getTargets(team, new IntArray());
|
||||
queue.post(() -> createFor(team, target, targets));
|
||||
queue.post(() -> createPath(team, target, targets));
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
@ -174,7 +180,7 @@ public class Pathfinder implements Runnable{
|
||||
* Clears the frontier, increments the search and sets up all flow sources.
|
||||
* 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(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.
|
||||
* 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());
|
||||
|
||||
list.add(path);
|
||||
@ -234,6 +244,8 @@ public class Pathfinder implements Runnable{
|
||||
path.weights[Pos.x(pos)][Pos.y(pos)] = 0;
|
||||
path.frontier.addFirst(pos);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/** 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)){
|
||||
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) -> {
|
||||
for(Tile other : indexer.getAllied(team, BlockFlag.rally)){
|
||||
|
@ -75,7 +75,7 @@ public class Blocks implements ContentList{
|
||||
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
|
||||
|
||||
//units
|
||||
commandCenter, draugFactory, spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, crawlerFactory, titanFactory,
|
||||
commandCenter, rallyPoint, draugFactory, spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, crawlerFactory, titanFactory,
|
||||
fortressFactory, repairPoint,
|
||||
|
||||
//upgrades
|
||||
@ -1650,6 +1650,12 @@ public class Blocks implements ContentList{
|
||||
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"){{
|
||||
requirements(Category.units, ItemStack.with(Items.titanium, 30, Items.lead, 40, Items.silicon, 45));
|
||||
type = UnitTypes.wraith;
|
||||
|
@ -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)){
|
||||
Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores);
|
||||
if(tile != null){
|
||||
|
@ -5,6 +5,7 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
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.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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
target = getClosestSpawner();
|
||||
moveTo(Vars.state.rules.dropZoneRadius + 80f);
|
||||
}
|
||||
}
|
||||
},
|
||||
patrol = new UnitState(){
|
||||
rally = new UnitState(){
|
||||
public void update(){
|
||||
if(retarget()){
|
||||
targetClosestAllyFlag(BlockFlag.rally);
|
||||
targetClosest();
|
||||
targetClosestEnemyFlag(BlockFlag.core);
|
||||
|
||||
if(target != null && !Units.invalidateTarget(target, team, x, y)){
|
||||
setState(attack);
|
||||
return;
|
||||
}
|
||||
|
||||
target = getSpawner();
|
||||
if(target == null) target = getClosestCore();
|
||||
if(target == null) target = getSpawner();
|
||||
}
|
||||
|
||||
if(target != null){
|
||||
@ -109,7 +114,7 @@ public abstract class FlyingUnit extends BaseUnit{
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.patrol ? patrol :
|
||||
command == UnitCommand.rally ? rally :
|
||||
null);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@ -35,31 +36,30 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
TileEntity core = getClosestEnemyCore();
|
||||
|
||||
if(core == null){
|
||||
setState(patrol);
|
||||
return;
|
||||
}
|
||||
Tile closestSpawn = getClosestSpawner();
|
||||
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){
|
||||
target = core;
|
||||
}
|
||||
if(dst < getWeapon().bullet.range() / 1.1f){
|
||||
target = core;
|
||||
}
|
||||
|
||||
if(dst > getWeapon().bullet.range() * 0.5f){
|
||||
moveToCore();
|
||||
if(dst > getWeapon().bullet.range() * 0.5f){
|
||||
moveToCore(PathTarget.enemyCores);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
patrol = new UnitState(){
|
||||
rally = new UnitState(){
|
||||
public void update(){
|
||||
TileEntity target = getClosestCore();
|
||||
Tile target = getClosest(BlockFlag.rally);
|
||||
|
||||
if(target != null){
|
||||
if(dst(target) > 400f){
|
||||
moveAwayFromCore();
|
||||
}else if(!(!Units.invalidateTarget(GroundUnit.this.target, GroundUnit.this) && dst(GroundUnit.this.target) < getWeapon().bullet.range())){
|
||||
patrol();
|
||||
}
|
||||
if(target != null && dst(target) > 100f){
|
||||
moveToCore(PathTarget.rallyPoints);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -77,7 +77,7 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.patrol ? patrol :
|
||||
command == UnitCommand.rally ? rally :
|
||||
null);
|
||||
}
|
||||
|
||||
@ -221,10 +221,10 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
protected void moveToCore(){
|
||||
protected void moveToCore(PathTarget path){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
if(tile == null) return;
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, team, PathTarget.enemyCores);
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, team, path);
|
||||
|
||||
if(tile == targetTile) return;
|
||||
|
||||
|
@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.units;
|
||||
import io.anuke.arc.*;
|
||||
|
||||
public enum UnitCommand{
|
||||
attack, retreat, patrol;
|
||||
attack, retreat, rally;
|
||||
|
||||
private final String localized;
|
||||
public static final UnitCommand[] all = values();
|
||||
|