package engine;
import graphics.model.rails.Rails;
import java.awt.Point;
import java.util.ArrayList;
import org.lwjgl.util.vector.Vector2f;
/**
*
* @author Jari Saaranen <rasaari@gmail.com>
* @author simokr
*/
public class Map {
public static final int mapWidth = 128;
public static final int mapHeight = 128;
/**
* Used to split Rails in to chunks.
* mapWidth & mapHeight must be divisible by this.
*/
public static final int chunkSize = 64;
//constants for differend static map objects
public static final char EMPTY = '.';
public static final char TRACK = '/';
public static final char STATION = '$';
public static final char TREE = 'T';
public static final char VOID = '?';
// direction flags
public static final int EAST = 0;
public static final int SOUTH_EAST = 1;
public static final int SOUTH = 2;
public static final int SOUTH_WEST = 3;
public static final int WEST = 4;
public static final int NORTH_WEST = 5;
public static final int NORTH = 6;
public static final int NORTH_EAST = 7;
//map data
private char[][] data;
private Rails rails;
private ArrayList<Station> stations;
public Map() {
data = new char[mapHeight][mapWidth];
rails = new Rails();
stations = new ArrayList<>();
//initialize map data
for(int rows = 0; rows < mapHeight; rows++) {
for(int cols = 0; cols < mapWidth; cols++) {
this.data[rows][cols] = Map.EMPTY;
}
}
}
/**
* change type of tile in (x,y) location
* @param type
* @param x
* @param y
*/
public void set(char type, int x, int y) {
this.data[y][x] = type;
}
/**
* returns true if map has wanted tile in
* (x, y) location
* @param type
* @param x
* @param y
* @return boolean
*/
public boolean has(char type, int x, int y) {
return (this.data[y][x] == type);
}
public boolean isRideable(int x, int y) {
if(x < 0 || x >= mapWidth || y < 0 ||y >= mapHeight)
return false;
return (this.data[y][x] == Map.TRACK || this.data[y][x] == Map.STATION);
}
/**
* returns type of tile in (x, y) location
* @param x
* @param y
* @return char
*/
public char get(int x, int y) {
if(x < 0 || x >= mapWidth || y < 0 ||y >= mapHeight)
return Map.VOID;
else
return this.data[y][x];
}
/**
* returns whole map as an array.
* @return char[][]
*/
public char[][] getAll() {
return this.data;
}
public void updateRails(){
rails.create(this);
}
public void render() {
rails.render();
}
/**
* returns map data around x and y
* @param x
* @param y
* @return integer array
*/
public int[] scan(int x, int y) {
int[] dirs = new int[8];
dirs[0] = get(x+1, y); // east
dirs[1] = get(x+1, y+1); // south-east
dirs[2] = get(x, y+1); // south
dirs[3] = get(x-1, y+1); // south-west
dirs[4] = get(x-1, y); // west
dirs[5] = get(x-1, y-1); // north-west
dirs[6] = get(x, y-1); // north
dirs[7] = get(x+1, y-1); // north-east
return dirs;
}
public boolean[] scanRideable(int x, int y) {
boolean[] dirs = new boolean[8];
dirs[0] = isRideable(x+1, y); // east
dirs[1] = isRideable(x+1, y+1); // south-east
dirs[2] = isRideable(x, y+1); // south
dirs[3] = isRideable(x-1, y+1); // south-west
dirs[4] = isRideable(x-1, y); // west
dirs[5] = isRideable(x-1, y-1); // north-west
dirs[6] = isRideable(x, y-1); // north
dirs[7] = isRideable(x+1, y-1); // north-east
return dirs;
}
/**
* Finds a piece of track which has other track
* pieces around it in x-axis. Stations are not
* considered as free space.
*
* @param size
* @return
*/
public Vector2f findFreeSpace(int size) {
Vector2f location = new Vector2f(0, 0);
for(int rows = 5; rows < mapHeight-5; rows++) {
for(int cols = 5; cols < mapWidth-5; cols++) {
// current location is valid for use
boolean valid = true;
// figure out if it really is
for(int i = 0; i < size; i++) {
if(get(cols-i, rows) != Map.TRACK)
valid = false;
}
if(valid) {
location.x = cols;
location.y = rows;
return location;
}
}
}
return location;
}
public void initializeStations(){
char[][] map = new char[mapHeight][mapWidth];
for(int rows = 0; rows < mapHeight; rows++) {
System.arraycopy(this.data[rows], 0, map[rows], 0, this.data[rows].length);
}
ArrayList<Station> stations = new ArrayList<>();
for(int rows = 0; rows < mapHeight; rows++) {
for(int cols = 0; cols < mapWidth; cols++) {
if(map[rows][cols] == Map.STATION){
Station station = new Station();
stations.add(station);
this.findStationTiles(station, map, rows, cols);
}
}
}
System.out.println("Station count: "+stations.size());
this.stations = stations;
for (Station station : this.stations) {
// add initial passengers to station
int passengercount = (int) (Math.random()*40);
for(int i = 0; i < passengercount; i++) {
Passenger passenger = new Passenger();
int stationId = (int) (Math.random()*this.stations.size());
while(station.equals(this.stations.get(stationId))) {
stationId = (int) (Math.random()*this.stations.size());
}
passenger.setDestination(station.getCenterPosition(), this.stations.get(stationId));
station.addPassenger(passenger);
}
}
}
public ArrayList<Station> getStations() {
return this.stations;
}
private void findStationTiles(Station station, char[][] map, int y, int x){
if(y < 0 || y >= mapHeight || x < 0 || x >= mapWidth || map[y][x] != Map.STATION)
return;
map[y][x] = Map.EMPTY;
station.addStationTile(new Point(x,y));
int i,j;
for(j = -1; j<2; j++){
for(i = -1; i<2; i++){
this.findStationTiles(station, map, y+j,x+i);
}
}
}
/**
* Finds a Station that has the given tile.
*
* @param tile coordinates of a tile to be checked
* @return Station that has this tile or null
*/
public Station getStationAtTile(Point tile){
for (Station station : this.stations) {
if(station.hasTile(tile))
return station;
}
return null;
}
public void addRandomPassenger() {
int startId = (int) (Math.random()*this.stations.size());
int destinationId = (int) (Math.random()*this.stations.size());
while(destinationId == startId) {
destinationId = (int) (Math.random()*this.stations.size());
}
Passenger passenger = new Passenger();
passenger.setDestination(this.stations.get(startId).getCenterPosition(), this.stations.get(destinationId));
this.stations.get(startId).addPassenger(passenger);
}
public void free(){
rails.free();
}
}