Support for schematic random rotation

This commit is contained in:
Anuken
2020-06-05 13:23:24 -04:00
parent d9e05907af
commit cf02a75846
11 changed files with 180 additions and 48 deletions

View File

@@ -3,8 +3,10 @@ package mindustry.maps.generators;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.pooling.*;
import mindustry.ai.BaseRegistry.*;
import mindustry.content.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.game.Schematic.*;
import mindustry.gen.*;
@@ -17,6 +19,10 @@ import mindustry.world.blocks.production.*;
import static mindustry.Vars.*;
public class BaseGenerator{
private static final Schematic tmpSchem = new Schematic(new Array<>(), new StringMap(), 0, 0);
private static final Schematic tmpSchem2 = new Schematic(new Array<>(), new StringMap(), 0, 0);
private static final Vec2 axis = new Vec2(), rotator = new Vec2();
private Tiles tiles;
private Team team;
private ObjectMap<Item, OreBlock> ores = new ObjectMap<>();
@@ -36,12 +42,12 @@ public class BaseGenerator{
float bracket = 0.1f;
int range = 200;
int wallAngle = 180;
int wallAngle = 70; //180 for full coverage
BasePart coreschem = bases.cores.getFrac(bracket);
Block wall = wallsSmall.getFrac(bracket), wallLarge = wallsLarge.getFrac(bracket);
//TODO random flipping and rotation
//TODO random rotation
for(Tile tile : cores){
tile.clearOverlay();
@@ -67,67 +73,81 @@ public class BaseGenerator{
});
}
//second pass: small walls
for(Tile core : cores){
core.circle(range, (x, y) -> {
Tile tile = tiles.getn(x, y);
if(tile.block().alwaysReplace){
boolean any = false;
if(wallAngle > 0){
//second pass: small walls
for(Tile core : cores){
core.circle(range, (x, y) -> {
Tile tile = tiles.getn(x, y);
if(tile.block().alwaysReplace){
boolean any = false;
for(Point2 p : Geometry.d8){
if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(core)) > wallAngle){
continue;
for(Point2 p : Geometry.d8){
if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(core)) > wallAngle){
continue;
}
Tile o = tiles.get(tile.x + p.x, tile.y + p.y);
if(o != null && o.team() == team && !(o.block() instanceof Wall)){
any = true;
break;
}
}
Tile o = tiles.get(tile.x + p.x, tile.y + p.y);
if(o != null && o.team() == team && !(o.block() instanceof Wall)){
any = true;
break;
if(any){
tile.setBlock(wall, team);
}
}
});
}
//third pass: large walls
for(Tile core : cores){
core.circle(range, (x, y) -> {
int walls = 0;
for(int cx = 0; cx < 2; cx++){
for(int cy = 0; cy < 2; cy++){
Tile tile = tiles.get(x + cx, y + cy);
if(tile == null || tile.block().size != 1 || (tile.block() != wall && !tile.block().alwaysReplace)) return;
if(tile.block() == wall){
walls ++;
}
}
}
if(any){
tile.setBlock(wall, team);
if(walls >= 3){
tiles.getn(x, y).setBlock(wallLarge, team);
}
}
});
}
//third pass: large walls
for(Tile core : cores){
core.circle(range, (x, y) -> {
int walls = 0;
for(int cx = 0; cx < 2; cx++){
for(int cy = 0; cy < 2; cy++){
Tile tile = tiles.get(x + cx, y + cy);
if(tile == null || tile.block().size != 1 || (tile.block() != wall && !tile.block().alwaysReplace)) return;
if(tile.block() == wall){
walls ++;
}
}
}
if(walls >= 3){
tiles.getn(x, y).setBlock(wallLarge, team);
}
});
});
}
}
}
boolean tryPlace(BasePart part, int x, int y){
int cx = x - part.schematic.width/2, cy = y - part.schematic.height/2;
for(int rx = cx; rx <= cx + part.schematic.width; rx++){
for(int ry = cy; ry <= cy + part.schematic.height; ry++){
int rotation = 0;
axis.set((int)(part.schematic.width / 2f), (int)(part.schematic.height / 2f));
Schematic result = rotate(part.schematic, rotation);
rotator.set(part.centerX, part.centerY).rotateAround(axis, rotation * 90);
int cx = x - (int)rotator.x;
int cy = y - (int)rotator.y;
for(int rx = cx; rx <= cx + result.width; rx++){
for(int ry = cy; ry <= cy + result.height; ry++){
Tile tile = tiles.get(rx, ry);
if(tile == null || ((!tile.block().alwaysReplace || world.getDarkness(rx, ry) > 0) && part.occupied.get(rx - cx, ry - cy))){
int ox = rx - cx, oy = ry - cy;
rotator.set(ox, oy).rotateAround(axis, rotation * 90);
ox = (int)rotator.x;
oy = (int)rotator.y;
if(tile == null || ((!tile.block().alwaysReplace || world.getDarkness(rx, ry) > 0) && part.occupied.get(ox, oy))){
return false;
}
}
}
if(part.requiredItem != null){
for(Stile tile : part.schematic.tiles){
for(Stile tile : result.tiles){
if(tile.block instanceof Drill){
tile.block.iterateTaken(tile.x + cx, tile.y + cy, (ex, ey) -> {
tiles.getn(ex, ey).setOverlay(ores.get(part.requiredItem));
@@ -136,8 +156,68 @@ public class BaseGenerator{
}
}
Schematics.place(part.schematic, x, y, team);
Schematics.place(result, cx + result.width/2, cy + result.height/2, team);
return true;
}
Schematic rotate(Schematic input, int times){
if(times == 0) return input;
boolean sign = times < 0;
for(int i = 0; i < Math.abs(times); i++){
input = rotated(input, sign);
}
return input;
}
Schematic rotated(Schematic input, boolean counter){
int direction = Mathf.sign(counter);
Schematic schem = input == tmpSchem ? tmpSchem2 : tmpSchem2;
schem.width = input.width;
schem.height = input.height;
Pools.freeAll(schem.tiles);
schem.tiles.clear();
for(Stile tile : input.tiles){
schem.tiles.add(Pools.obtain(Stile.class, Stile::new).set(tile));
}
int ox = schem.width/2, oy = schem.height/2;
schem.tiles.each(req -> {
req.config = BuildRequest.pointConfig(req.config, p -> {
int cx = p.x, cy = p.y;
int lx = cx;
if(direction >= 0){
cx = -cy;
cy = lx;
}else{
cx = cy;
cy = -lx;
}
p.set(cx, cy);
});
//rotate actual request, centered on its multiblock position
float wx = (req.x - ox) * tilesize + req.block.offset(), wy = (req.y - oy) * tilesize + req.block.offset();
float x = wx;
if(direction >= 0){
wx = -wy;
wy = x;
}else{
wx = wy;
wy = -x;
}
req.x = (short)(world.toTile(wx - req.block.offset()) + ox);
req.y = (short)(world.toTile(wy - req.block.offset()) + oy);
req.rotation = (byte)Mathf.mod(req.rotation + direction, 4);
});
//assign flipped values, since it's rotated
schem.width = input.height;
schem.height = input.width;
return schem;
}
}