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;
import io.anuke.arc.Events;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.type.TileEntity;
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.Teams.TeamData;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.arc.function.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*;
/** Class used for indexing special target blocks for AI. */
@SuppressWarnings("unchecked")
public class BlockIndexer{
/** Size of one ore quadrant. */
private final static int oreQuadrantSize = 20;
/** Size of one structure quadrant. */
private final static int structQuadrantSize = 12;
/** Size of one quadrant. */
private final static int quadrantSize = 16;
/** Set of all ores that are being scanned. */
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
structQuadrants = new GridBits[Team.all.length];
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++){
@ -94,7 +91,7 @@ public class BlockIndexer{
for(int x = 0; x < quadWidth(); x++){
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;
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 ry = Math.max((int)((y - range) / tilesize / structQuadrantSize), 0); ry <= (int)((y + range) / tilesize / structQuadrantSize) && ry < quadHeight(); ry++){
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 / quadrantSize), 0); ry <= (int)((y + range) / tilesize / quadrantSize) && ry < quadHeight(); ry++){
if(!getQuad(team, rx, ry)) continue;
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){
for(int tx = rx * quadrantSize; tx < (rx + 1) * quadrantSize && tx < world.width(); tx++){
for(int ty = ry * quadrantSize; ty < (ry + 1) * quadrantSize && ty < world.height(); ty++){
Tile other = world.ltile(tx, ty);
if(other == null) continue;
@ -196,7 +193,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 #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}.
*/
public ObjectSet<Tile> getOrePositions(Item item){
@ -205,12 +202,12 @@ public class BlockIndexer{
/** Find the closest ore block relative to a position. */
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;
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 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 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 - quadrantSize / 2); y < tile.y + quadrantSize / 2 && y < world.height(); y++){
Tile res = world.tile(x, y);
if(res.block() == Blocks.air && res.drop() == item){
return res;
@ -222,8 +219,7 @@ public class BlockIndexer{
}
private void process(Tile tile){
if(tile.block().flags.size() > 0 &&
tile.getTeam() != Team.none){
if(tile.block().flags.size() > 0 && tile.getTeam() != Team.none){
ObjectSet<Tile>[] map = getFlagged(tile.getTeam());
for(BlockFlag flag : tile.block().flags){
@ -239,16 +235,16 @@ public class BlockIndexer{
if(ores == null) return;
int quadrantX = tile.x / oreQuadrantSize;
int quadrantY = tile.y / oreQuadrantSize;
int quadrantX = tile.x / quadrantSize;
int quadrantY = tile.y / quadrantSize;
itemSet.clear();
Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1));
Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1),
Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
//find all items that this quadrant contains
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++){
for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
Tile result = world.tile(x, y);
if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue;
@ -273,8 +269,8 @@ public class BlockIndexer{
if(structQuadrants == null) return;
//this quadrant is now 'dirty', re-scan the whole thing
int quadrantX = tile.x / structQuadrantSize;
int quadrantY = tile.y / structQuadrantSize;
int quadrantX = tile.x / quadrantSize;
int quadrantY = tile.y / quadrantSize;
int index = quadrantX + quadrantY * quadWidth();
for(Team team : Team.all){
@ -289,8 +285,8 @@ public class BlockIndexer{
structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY, false);
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++){
for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
Tile result = world.ltile(x, y);
//when a targetable block is found, mark this quadrant as occupied and stop searching
if(result.entity != null && result.getTeam() == data.team){
@ -307,11 +303,11 @@ public class BlockIndexer{
}
private int quadWidth(){
return Mathf.ceil(world.width() / (float)structQuadrantSize);
return Mathf.ceil(world.width() / (float)quadrantSize);
}
private int quadHeight(){
return Mathf.ceil(world.height() / (float)structQuadrantSize);
return Mathf.ceil(world.height() / (float)quadrantSize);
}
private void scanOres(){
@ -324,8 +320,8 @@ public class BlockIndexer{
for(int x = 0; x < world.width(); x++){
for(int y = 0; y < world.height(); y++){
int qx = (x / oreQuadrantSize);
int qy = (y / oreQuadrantSize);
int qx = (x / quadrantSize);
int qy = (y / quadrantSize);
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){
ores.get(tile.drop()).add(world.tile(
//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(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)));
Mathf.clamp(qx * quadrantSize + quadrantSize / 2, 0, world.width() - 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);
}}).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){
return;
}

View File

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

View File

@ -74,6 +74,10 @@ public class Map implements Comparable<Map>{
return tags.get("othercore", "true").equals("true");
}
public boolean attribute(MapAttribute attr){
return tags.getBool(attr.name());
}
public String 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{
/** 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. */
private Array<Map> maps = new Array<>();
/** Serializer for meta. */