mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-25 10:25:42 +07:00
Fixed drones being idiots / Added another PvP map
This commit is contained in:
parent
859591cea5
commit
c9bd253960
Binary file not shown.
BIN
core/assets/maps/veins.msav
Normal file
BIN
core/assets/maps/veins.msav
Normal file
Binary file not shown.
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
29
core/src/io/anuke/mindustry/maps/MapAttribute.java
Normal file
29
core/src/io/anuke/mindustry/maps/MapAttribute.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user