package Roguelike.DungeonGeneration;
import Roguelike.Global;
import Roguelike.Save.SaveLevel;
import Roguelike.Tiles.Point;
import Roguelike.Util.EnumBitflag;
import Roguelike.Util.ImageUtils;
import com.badlogic.gdx.utils.Array;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Random;
/**
* Created by Philip on 24-Feb-16.
*/
public class StaticLevelGenerator extends AbstractDungeonGenerator
{
// ----------------------------------------------------------------------
public StaticLevelGenerator()
{}
// ----------------------------------------------------------------------
@Override
public void setup( SaveLevel level, DungeonFileParser dfp )
{
this.saveLevel = level;
this.dfp = dfp;
width = dfp.minWidth;
height = dfp.minHeight;
ran = new Random( level.seed );
}
// ----------------------------------------------------------------------
@Override
public boolean generate()
{
if ( generationIndex == 0 )
{
selectRooms();
generationIndex++;
generationText = "Filling Grid";
}
else if ( generationIndex == 1 )
{
toBePlaced.addAll( requiredRooms );
fillGridBase();
generationIndex++;
generationText = "Finding Rooms";
}
else if ( generationIndex == 2 )
{
findRoomLocations();
generationIndex++;
generationText = "Placing Rooms";
}
else if ( generationIndex == 3 )
{
placeRooms();
generationIndex++;
generationText = "Placing factions";
}
else if ( generationIndex == 4 )
{
placeFactions();
generationIndex++;
generationText = "Marking Rooms";
}
else if ( generationIndex == 5 )
{
markRooms();
generationIndex++;
generationText = "Flattening Level";
}
else if ( generationIndex == 6 )
{
level = createLevel( grid, dfp.getSymbol( '#' ) );
generationIndex++;
generationText = "Completed";
}
percent = (int) ( ( 100.0f / 7.0f ) * generationIndex );
if ( generationIndex < 7 )
{
return false;
}
else
{
return true;
}
}
// ----------------------------------------------------------------------
private void fillGridBase()
{
width = dfp.roomDef.length;
height = dfp.roomDef[0].length;
grid = new Symbol[width][height];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
grid[x][y] = dfp.getSymbol( dfp.roomDef[x][y] );
grid[x][y].resolveExtends( dfp.sharedSymbolMap );
}
}
}
// ----------------------------------------------------------------------
private void findRoomLocations()
{
for (int x = 0; x < width; x++)
{
for ( int y = 0; y < height; y++ )
{
if (grid[x][y].metaValue != null && grid[x][y].metaValue.equalsIgnoreCase( "roomseed" ))
{
boolean skip = false;
for (RoomLocationData data : roomLocations)
{
if (x >= data.x && x <= data.x+data.width && y >= data.y && y <= data.y+data.height)
{
skip = true;
break;
}
}
if (skip)
{
continue;
}
// find the room
roomLocations.add( findRoom( x, y ) );
}
}
}
}
// ----------------------------------------------------------------------
private RoomLocationData findRoom(int sx, int sy)
{
Point min = new Point(sx, sy);
Point max = new Point(sx, sy);
boolean minxCollided = false;
boolean minyCollided = false;
boolean maxxCollided = false;
boolean maxyCollided = false;
while (true)
{
if (!minxCollided)
{
min.x--;
//walking along (minx,miny) to (minx,maxy) is there a collison
for ( int i = 0; i < (max.y - min.y)+1; i++ )
{
int y = min.y + i;
Symbol symbol = grid[ min.x ][ y ];
if ( symbol.metaValue == null || !symbol.metaValue.equalsIgnoreCase( "roomseed" ) )
{
min.x++;
minxCollided = true;
break;
}
}
}
if (!minyCollided)
{
min.y--;
//walking along (minx,miny) to (maxx,miny) is there a collison
for ( int i = 0; i < (max.x - min.x)+1; i++ )
{
int x = min.x + i;
Symbol symbol = grid[ x ][ min.y ];
if ( symbol.metaValue == null || !symbol.metaValue.equalsIgnoreCase( "roomseed" ) )
{
min.y++;
minyCollided = true;
break;
}
}
}
if (!maxxCollided)
{
max.x++;
//walking along (maxx,miny) to (maxx,maxy) is there a collison
for ( int i = 0; i < (max.y - min.y)+1; i++ )
{
int y = min.y + i;
Symbol symbol = grid[ max.x ][ y ];
if ( symbol.metaValue == null || !symbol.metaValue.equalsIgnoreCase( "roomseed" ) )
{
max.x--;
maxxCollided = true;
break;
}
}
}
if (!maxyCollided)
{
max.y++;
//walking along (minx,maxy) to (maxx,maxy) is there a collison
for ( int i = 0; i < (max.x - min.x)+1; i++ )
{
int x = min.x + i;
Symbol symbol = grid[ x ][ max.y ];
if ( symbol.metaValue == null || !symbol.metaValue.equalsIgnoreCase( "roomseed" ) )
{
max.y--;
maxyCollided = true;
break;
}
}
}
if (minxCollided && maxxCollided && minyCollided && maxyCollided)
{
break;
}
}
RoomLocationData data = new RoomLocationData();
data.x = min.x;
data.y = min.y;
data.width = (max.x - min.x)+1;
data.height = (max.y - min.y)+1;
return data;
}
// ----------------------------------------------------------------------
private void placeRooms()
{
Array<RoomPlacementData> placementDatas = new Array<RoomPlacementData>( );
for (Room room : requiredRooms)
{
RoomPlacementData data = new RoomPlacementData();
data.room = room;
for (RoomLocationData locationData : roomLocations)
{
if (room.width <= locationData.width && room.height <= locationData.height)
{
data.validLocations.add( locationData );
}
else if (room.height <= locationData.width && room.width <= locationData.height)
{
data.validLocations.add( locationData );
}
}
placementDatas.add( data );
}
while (placementDatas.size > 0)
{
// sort
placementDatas.sort( new Comparator<RoomPlacementData>() {
@Override
public int compare( RoomPlacementData o1, RoomPlacementData o2 )
{
return o1.validLocations.size - o2.validLocations.size;
}
} );
// remove first
RoomPlacementData data = placementDatas.removeIndex( 0 );
if (data.validLocations.size == 0)
{
throw new RuntimeException( "Could not find space for room!" );
}
// place
RoomLocationData location = data.validLocations.get( ran.nextInt( data.validLocations.size ) );
// rotate / flip if neccesary
boolean fits = false;
boolean rotate = false;
boolean flipVert = false;
boolean flipHori = false;
boolean fitsVertical = location.width <= width && location.height <= height;
boolean fitsHorizontal = location.height <= width && location.width <= height;
if ( data.room.roomData.lockRotation )
{
if ( fitsVertical )
{
fits = true;
flipVert = true;
if ( ran.nextBoolean() )
{
flipHori = true;
}
}
}
else
{
if ( fitsVertical || fitsHorizontal )
{
fits = true;
// randomly flip
if ( ran.nextBoolean() )
{
flipVert = true;
}
if ( ran.nextBoolean() )
{
flipHori = true;
}
// if it fits on both directions, randomly pick one
if ( fitsVertical && fitsHorizontal )
{
if ( ran.nextBoolean() )
{
rotate = true;
}
}
else if ( fitsHorizontal )
{
rotate = true;
}
}
}
// If it fits then place the room and rotate/flip as neccesary
if ( fits )
{
if ( flipVert )
{
data.room.flipVertical();
}
if ( flipHori )
{
data.room.flipHorizontal();
}
if ( rotate )
{
data.room.rotate();
}
if ( flipVert && rotate )
{
data.room.orientation = Global.Direction.WEST;
}
else if ( flipVert )
{
data.room.orientation = Global.Direction.SOUTH;
}
else if ( rotate )
{
data.room.orientation = Global.Direction.EAST;
}
else
{
data.room.orientation = Global.Direction.NORTH;
}
}
// setup pos
data.room.x = location.x;
data.room.y = location.y;
//remove this room from all children
for (RoomPlacementData odata : placementDatas)
{
odata.validLocations.removeValue( location, true );
}
roomLocations.removeValue( location, true );
placedRooms.add( data.room );
}
// Fill rest with faction stuff
for (RoomLocationData location : roomLocations)
{
Room room = new Room();
room.x = location.x;
room.y = location.y;
room.width = location.width;
room.height = location.height;
room.roomContents = new Symbol[room.width][room.height];
for ( int rx = 0; rx < room.width; rx++ )
{
for ( int ry = 0; ry < room.height; ry++ )
{
room.roomContents[rx][ry] = grid[room.x+rx][room.y+ry];
}
}
placedRooms.add( room );
}
}
// ----------------------------------------------------------------------
protected void markRooms()
{
for ( Room room : placedRooms )
{
for ( int x = 0; x < room.width; x++ )
{
for ( int y = 0; y < room.height; y++ )
{
Symbol symbol = room.roomContents[x][y];
symbol.containingRoom = room;
grid[room.x+x][room.y+y] = symbol;
}
}
}
}
// ----------------------------------------------------------------------
public static final EnumBitflag<Global.Passability> GeneratorPassability = new EnumBitflag<Global.Passability>( Global.Passability.WALK );
// ----------------------------------------------------------------------
Array<RoomLocationData> roomLocations = new Array<RoomLocationData>( );
// ----------------------------------------------------------------------
private Symbol[][] grid;
// ----------------------------------------------------------------------
private class RoomLocationData
{
public int x;
public int y;
public int width;
public int height;
}
// ----------------------------------------------------------------------
private class RoomPlacementData
{
public Room room;
public Array<RoomLocationData> validLocations = new Array<RoomLocationData>( );
}
}