Fixed drones being idiots / Added another PvP map

This commit is contained in:
Anuken
2019-07-24 21:25:33 -04:00
parent 859591cea5
commit c9bd253960
8 changed files with 78 additions and 50 deletions

Binary file not shown.

BIN
core/assets/maps/veins.msav Normal file

Binary file not shown.

View File

@@ -1,29 +1,26 @@
package io.anuke.mindustry.ai; package io.anuke.mindustry.ai;
import io.anuke.arc.Events; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.function.Predicate; import io.anuke.arc.function.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.Geometry; import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.game.Teams.TeamData; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.meta.*;
import io.anuke.mindustry.world.meta.BlockFlag;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
/** Class used for indexing special target blocks for AI. */ /** Class used for indexing special target blocks for AI. */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class BlockIndexer{ public class BlockIndexer{
/** Size of one ore quadrant. */ /** Size of one quadrant. */
private final static int oreQuadrantSize = 20; private final static int quadrantSize = 16;
/** Size of one structure quadrant. */
private final static int structQuadrantSize = 12;
/** Set of all ores that are being scanned. */ /** Set of all ores that are being scanned. */
private final ObjectSet<Item> scanOres = ObjectSet.with(Item.getAllOres().toArray(Item.class)); private final ObjectSet<Item> scanOres = ObjectSet.with(Item.getAllOres().toArray(Item.class));
@@ -75,7 +72,7 @@ public class BlockIndexer{
//create bitset for each team type that contains each quadrant //create bitset for each team type that contains each quadrant
structQuadrants = new GridBits[Team.all.length]; structQuadrants = new GridBits[Team.all.length];
for(int i = 0; i < Team.all.length; i++){ for(int i = 0; i < Team.all.length; i++){
structQuadrants[i] = new GridBits(Mathf.ceil(world.width() / (float)structQuadrantSize), Mathf.ceil(world.height() / (float)structQuadrantSize)); structQuadrants[i] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize));
} }
for(int x = 0; x < world.width(); x++){ for(int x = 0; x < world.width(); x++){
@@ -94,7 +91,7 @@ public class BlockIndexer{
for(int x = 0; x < quadWidth(); x++){ for(int x = 0; x < quadWidth(); x++){
for(int y = 0; y < quadHeight(); y++){ for(int y = 0; y < quadHeight(); y++){
updateQuadrant(world.tile(x * structQuadrantSize, y * structQuadrantSize)); updateQuadrant(world.tile(x * quadrantSize, y * quadrantSize));
} }
} }
@@ -164,13 +161,13 @@ public class BlockIndexer{
TileEntity closest = null; TileEntity closest = null;
float dst = 0; float dst = 0;
for(int rx = Math.max((int)((x - range) / tilesize / structQuadrantSize), 0); rx <= (int)((x + range) / tilesize / structQuadrantSize) && rx < quadWidth(); rx++){ for(int rx = Math.max((int)((x - range) / tilesize / quadrantSize), 0); rx <= (int)((x + range) / tilesize / quadrantSize) && rx < quadWidth(); rx++){
for(int ry = Math.max((int)((y - range) / tilesize / structQuadrantSize), 0); ry <= (int)((y + range) / tilesize / structQuadrantSize) && ry < quadHeight(); ry++){ for(int ry = Math.max((int)((y - range) / tilesize / quadrantSize), 0); ry <= (int)((y + range) / tilesize / quadrantSize) && ry < quadHeight(); ry++){
if(!getQuad(team, rx, ry)) continue; if(!getQuad(team, rx, ry)) continue;
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){ for(int tx = rx * quadrantSize; tx < (rx + 1) * quadrantSize && tx < world.width(); tx++){
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){ for(int ty = ry * quadrantSize; ty < (ry + 1) * quadrantSize && ty < world.height(); ty++){
Tile other = world.ltile(tx, ty); Tile other = world.ltile(tx, ty);
if(other == null) continue; if(other == null) continue;
@@ -196,7 +193,7 @@ public class BlockIndexer{
/** /**
* Returns a set of tiles that have ores of the specified type nearby. * 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, * 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 #oreQuadrantSize} / 2 blocks of it. * each tile will at least have an ore within {@link #quadrantSize} / 2 blocks of it.
* Only specific ore types are scanned. See {@link #scanOres}. * Only specific ore types are scanned. See {@link #scanOres}.
*/ */
public ObjectSet<Tile> getOrePositions(Item item){ public ObjectSet<Tile> getOrePositions(Item item){
@@ -205,12 +202,12 @@ public class BlockIndexer{
/** Find the closest ore block relative to a position. */ /** Find the closest ore block relative to a position. */
public Tile findClosestOre(float xp, float yp, Item item){ public Tile findClosestOre(float xp, float yp, Item item){
Tile tile = Geometry.findClosest(xp, yp, world.indexer.getOrePositions(item)); Tile tile = Geometry.findClosest(xp, yp, getOrePositions(item));
if(tile == null) return null; if(tile == null) return null;
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){ for(int x = Math.max(0, tile.x - quadrantSize / 2); x < tile.x + quadrantSize / 2 && x < world.width(); x++){
for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){ for(int y = Math.max(0, tile.y - quadrantSize / 2); y < tile.y + quadrantSize / 2 && y < world.height(); y++){
Tile res = world.tile(x, y); Tile res = world.tile(x, y);
if(res.block() == Blocks.air && res.drop() == item){ if(res.block() == Blocks.air && res.drop() == item){
return res; return res;
@@ -222,8 +219,7 @@ public class BlockIndexer{
} }
private void process(Tile tile){ private void process(Tile tile){
if(tile.block().flags.size() > 0 && if(tile.block().flags.size() > 0 && tile.getTeam() != Team.none){
tile.getTeam() != Team.none){
ObjectSet<Tile>[] map = getFlagged(tile.getTeam()); ObjectSet<Tile>[] map = getFlagged(tile.getTeam());
for(BlockFlag flag : tile.block().flags){ for(BlockFlag flag : tile.block().flags){
@@ -239,16 +235,16 @@ public class BlockIndexer{
if(ores == null) return; if(ores == null) return;
int quadrantX = tile.x / oreQuadrantSize; int quadrantX = tile.x / quadrantSize;
int quadrantY = tile.y / oreQuadrantSize; int quadrantY = tile.y / quadrantSize;
itemSet.clear(); itemSet.clear();
Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1), Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1),
Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)); Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
//find all items that this quadrant contains //find all items that this quadrant contains
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){ for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){ for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
Tile result = world.tile(x, y); Tile result = world.tile(x, y);
if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue; if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue;
@@ -273,8 +269,8 @@ public class BlockIndexer{
if(structQuadrants == null) return; if(structQuadrants == null) return;
//this quadrant is now 'dirty', re-scan the whole thing //this quadrant is now 'dirty', re-scan the whole thing
int quadrantX = tile.x / structQuadrantSize; int quadrantX = tile.x / quadrantSize;
int quadrantY = tile.y / structQuadrantSize; int quadrantY = tile.y / quadrantSize;
int index = quadrantX + quadrantY * quadWidth(); int index = quadrantX + quadrantY * quadWidth();
for(Team team : Team.all){ for(Team team : Team.all){
@@ -289,8 +285,8 @@ public class BlockIndexer{
structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY, false); structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY, false);
outer: outer:
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){ for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){ for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
Tile result = world.ltile(x, y); Tile result = world.ltile(x, y);
//when a targetable block is found, mark this quadrant as occupied and stop searching //when a targetable block is found, mark this quadrant as occupied and stop searching
if(result.entity != null && result.getTeam() == data.team){ if(result.entity != null && result.getTeam() == data.team){
@@ -307,11 +303,11 @@ public class BlockIndexer{
} }
private int quadWidth(){ private int quadWidth(){
return Mathf.ceil(world.width() / (float)structQuadrantSize); return Mathf.ceil(world.width() / (float)quadrantSize);
} }
private int quadHeight(){ private int quadHeight(){
return Mathf.ceil(world.height() / (float)structQuadrantSize); return Mathf.ceil(world.height() / (float)quadrantSize);
} }
private void scanOres(){ private void scanOres(){
@@ -324,8 +320,8 @@ public class BlockIndexer{
for(int x = 0; x < world.width(); x++){ for(int x = 0; x < world.width(); x++){
for(int y = 0; y < world.height(); y++){ for(int y = 0; y < world.height(); y++){
int qx = (x / oreQuadrantSize); int qx = (x / quadrantSize);
int qy = (y / oreQuadrantSize); int qy = (y / quadrantSize);
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
@@ -333,8 +329,8 @@ public class BlockIndexer{
if(tile.drop() != null && scanOres.contains(tile.drop()) && tile.block() == Blocks.air){ if(tile.drop() != null && scanOres.contains(tile.drop()) && tile.block() == Blocks.air){
ores.get(tile.drop()).add(world.tile( ores.get(tile.drop()).add(world.tile(
//make sure to clamp quadrant middle position, since it might go off bounds //make sure to clamp quadrant middle position, since it might go off bounds
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1), Mathf.clamp(qx * quadrantSize + quadrantSize / 2, 0, world.width() - 1),
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1))); Mathf.clamp(qy * quadrantSize + quadrantSize / 2, 0, world.height() - 1)));
} }
} }
} }

View File

@@ -101,7 +101,7 @@ public class MapGenerateDialog extends FloatingDialog{
}}); }});
visible(() -> generating && !updateEditorOnChange); visible(() -> generating && !updateEditorOnChange);
}}).size(mobile ? 300f : 400f).padRight(10); }}).size(mobile ? 300f : 400f).padRight(10);
t.pane(p -> filterTable = p).width(300f).marginRight(6).update(pane -> { t.pane(p -> filterTable = p.marginRight(6)).width(300f).update(pane -> {
if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){ if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){
return; return;
} }

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.entities.type; package io.anuke.mindustry.entities.type;
import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.*;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.g2d.TextureRegion;
@@ -86,7 +85,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
return type.typeID; return type.typeID;
} }
public Tile getSpawner(){ public @Nullable Tile getSpawner(){
return world.tile(spawner); return world.tile(spawner);
} }

View File

@@ -74,6 +74,10 @@ public class Map implements Comparable<Map>{
return tags.get("othercore", "true").equals("true"); return tags.get("othercore", "true").equals("true");
} }
public boolean attribute(MapAttribute attr){
return tags.getBool(attr.name());
}
public String author(){ public String author(){
return tag("author"); return tag("author");
} }

View File

@@ -0,0 +1,29 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import static io.anuke.mindustry.Vars.*;
/** Defines a specific type of attribute for a map, usually whether or not it supports a certain type of mode.*/
public enum MapAttribute{
/** Whether a map has a player spawnpoint in it.*/
spawnpoint(teams -> teams.contains(defaultTeam.ordinal())),
/** Whether a map has a wave team core to attack.*/
attack(teams -> teams.contains(waveTeam.ordinal())),
/** Whether this map supports PvP.*/
pvp(teams -> teams.size > 1);
private final Predicate<IntSet> validator;
public static final MapAttribute[] all = values();
MapAttribute(Predicate<IntSet> set){
this.validator = set;
}
//todo also take into account enemy spawnpoints
public boolean validate(IntSet teams){
return validator.test(teams);
}
}

View File

@@ -20,7 +20,7 @@ import static io.anuke.mindustry.Vars.*;
public class Maps implements Disposable{ public class Maps implements Disposable{
/** List of all built-in maps. Filenames only. */ /** List of all built-in maps. Filenames only. */
private static String[] defaultMapNames = {"fortress", "labyrinth", "islands", "tendrils", "caldera", "glacier"}; private static String[] defaultMapNames = {"fortress", "labyrinth", "islands", "tendrils", "caldera", "glacier", "vein"};
/** All maps stored in an ordered array. */ /** All maps stored in an ordered array. */
private Array<Map> maps = new Array<>(); private Array<Map> maps = new Array<>();
/** Serializer for meta. */ /** Serializer for meta. */