package domain;
import static core.Script.callfunction;
import static core.Script.current_map;
import java.awt.Color;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import core.Script;
import core.TileObject;
public class MapDynamic extends MapAbstract implements Map {
private VImage[] layers;
private String mapName;
private HashMap<Integer, TileObject> pixelMappings; // map a pixel color to a TileObject
private int scaleFactor = 1;
private HashMap<String, Integer[]> autoTileMappings;
private boolean autoTiling;
public MapDynamic(String strFilename) {
this(Script.load(strFilename));
}
public MapDynamic(URL properties) {
Properties mapProperties = new Properties();
try {
this.scaleFactor = 1;
mapProperties.load(properties.openStream());
this.renderstring = mapProperties.getProperty("RenderString");
this.startX = Integer.parseInt(mapProperties.getProperty("StartX"));
this.startY = Integer.parseInt(mapProperties.getProperty("StartY"));
String strTileset = mapProperties.getProperty("Tileset");
this.tileset = new Vsp(Script.load(strTileset));
// Load Layers as VImages
String strLayers[] = mapProperties.getProperty("Layers").split(",");
this.layers = new VImage[strLayers.length];
for(int i=0; i<layers.length; i++) {
layers[i] = new VImage(Script.load(strLayers[i].trim()));
}
this.pixelMappings = new HashMap<Integer, TileObject>();
String[] strMappings = mapProperties.getProperty("Tile.Mappings").split(",");
String strAutoTiles[] = null;
String strAutotiling = mapProperties.getProperty("Autotiling.tiles");
if(strAutotiling!=null) {
this.autoTiling = true;
strAutoTiles = strAutotiling.split(",");
}
// Associates each pixel color to a tile object from the given tileset
for(String strPixelName: strMappings) {
String strMapping = mapProperties.getProperty("Tile.PixelColor." + strPixelName.trim());
String strColors[] = strMapping.split(",");
String strIdx[] = mapProperties.getProperty("Tile.TilesetIdx." + strPixelName.trim()).split(",");
Integer[] tileIdx = new Integer[strIdx.length];
if(Math.sqrt(tileIdx.length) > scaleFactor) {
//scaleFactor = (int) Math.sqrt(tileIdx.length);
}
for(int i=0; i<tileIdx.length;i++) {
tileIdx[i] = Integer.parseInt(strIdx[i].trim());
}
TileObject tileObj = new TileObject();
tileObj.tiles = tileIdx;
tileObj.name = strPixelName.trim();
// Finds primeTerrain TileObject
String primeTerrain = mapProperties.getProperty("Tile.PrimeTerrain." + strPixelName.trim());
if(primeTerrain != null) {
for(TileObject to: pixelMappings.values()) {
if(to.name.equals(primeTerrain)) {
tileObj.primeTerrain = to;
break;
}
}
}
//tileObj.primeTerrain = primeTerrain != null ? primeTerrain.trim() : strPixelName.trim();
for(String s: strAutoTiles) {
if(s.trim().equals(strPixelName.trim())) {
tileObj.autotiling = true;
}
}
pixelMappings.put(new Color(Integer.parseInt(strColors[0].trim()),
Integer.parseInt(strColors[1].trim()),
Integer.parseInt(strColors[2].trim())).getRGB(), tileObj);
}
/* Auto-tiling */
if(this.autoTiling == true) {
autoTileMappings = new HashMap();
for(int i=0; i<strAutoTiles.length; i++) {
for(int j=0; j<strAutoTiles.length; j++) {
if(i==j)
continue;
String in = strAutoTiles[i].trim();
String out = strAutoTiles[j].trim();
String autoTiling = mapProperties.getProperty("Autotiling." + in + "." + out);
System.out.println("Autotiling." + in + "." + out);
if(autoTiling!=null) {
String strTiles[] = autoTiling.split(",");
Integer intTiles[] = new Integer[strTiles.length];
for(int k=0; k<strTiles.length;k++) {
intTiles[k] = Integer.parseInt(strTiles[k].trim());
}
autoTileMappings.put(in+"/"+out, intTiles);
Integer[] revIntTiles = new Integer[intTiles.length];
for(int p=0;p<intTiles.length;p++) {
revIntTiles[p] = intTiles[intTiles.length-p-1];
}
autoTileMappings.put(out+"/"+in, revIntTiles);
}
}
}
scaleFactor *=2;
}
for(TileObject t: pixelMappings.values()) {
System.out.println(t);
}
for(String s: autoTileMappings.keySet()) {
System.out.println(s + ": " + Arrays.toString(autoTileMappings.get(s)));
}
this.startX*=scaleFactor;
this.startY*=scaleFactor;
current_map = this;
callfunction("mapinit");
} catch (IOException e) {
e.printStackTrace();
}
}
public String getMapname() {
return "Dynamic map: " + getFilename();
}
public int getWidth() {
if(layers!=null && layers[0]!=null) {
return layers[0].width * scaleFactor;
}
return 0;
}
public int getHeight() {
if(layers!=null && layers[0]!=null) {
return layers[0].height * scaleFactor;
}
return 0;
}
int NULL_TILE = 0;
public int gettile(int x, int y, int l) {
if(x<0 || y<0 || x >= this.getWidth() || y >= this.getHeight()) {
return 0;
}
if(layers[l] != null) {
if(autoTiling && l==0) { // terrain
//TileObject tobj = pixelMappings.get(layers[l].getImage().getRGB(x/scaleFactor, y/scaleFactor));
//if(tobj!=null) {
//String strTile = tobj.name;
//}
if(x%2==0 && y%2==0) { // Central tile
return getDirectTileFrom(x, y, x, y, l);
}
else if (x%2==1 && y%2==0) { // Horizontal Neighbors
TileObject c1 = getTileObjectFrom(x-1, y, l);
TileObject c2 = getTileObjectFrom(x+1, y, l);
if(c1==c2) {
return getDirectTileFrom(x-1, y, l);
} else {
return (getAutoTile(c1, c2, c1, c2));
}
}
else if (x%2==0 && y%2==1) { // Vertical Neighbors
TileObject c1 = getTileObjectFrom(x, y-1, l);
TileObject c2 = getTileObjectFrom(x, y+1, l);
if(c1==c2) {
return getDirectTileFrom(x, y-1, l);
} else {
return (getAutoTile(c1, c1, c2, c2));
}
}
else { // All Directions Neighbors
TileObject c1 = getTileObjectFrom(x-1, y-1, l);
TileObject c2 = getTileObjectFrom(x+1, y-1, l);
TileObject c3 = getTileObjectFrom(x-1, y+1, l);
TileObject c4 = getTileObjectFrom(x+1, y+1, l);
if(c1==c2 && c2==c3 && c3==c4) {
return getDirectTileFrom(x-1, y-1, l);
} else {
return (getAutoTile(c1, c2, c3, c4));
}
}
//return NULL_TILE;
}
// Not using autotiling, or if it's using, Even X and Even Y
return getDirectTileFrom(x, y, x, y, l);
}
return 0;
}
// Combines 4 tiles to return 1 frontier tile
private int getAutoTile(TileObject c1, TileObject c2, TileObject c3, TileObject c4) {
if(c1==null || c2==null || c3==null || c4==null){
System.err.println("Tile not found");
return NULL_TILE;
}
// Tile becomes the primeTerrain, if it exists
c1 = c1.primeTerrain==null ? c1 : c1.primeTerrain;
c2 = c2.primeTerrain==null ? c2 : c2.primeTerrain;
c3 = c3.primeTerrain==null ? c3 : c3.primeTerrain;
c4 = c4.primeTerrain==null ? c4 : c4.primeTerrain;
int count = 1;
if(c1!=c2) count++;
if(c3!=c1 && c3!=c2) count++;
if(c4!=c1 && c4!=c2 && c4!=c3) count++;
//If primeTerrain is equal (ex: grass/grass), return it (ex: grass)
if(count==1)
return c1.tiles[0];
TileObject minTO = null, maxTO = null;
if(count==2) {
minTO = c1.min(c2.min(c3.min(c4)));
maxTO = c1.max(c2.max(c3.max(c4)));
}
else if(count==3 || count==4) {
//System.out.println("BE" + c1 + " " + c2 + " " + c3 + " " + c4);
if(c1.name.equals("water")) minTO = c1;
else if(c2.name.equals("water")) minTO = c2;
else if(c3.name.equals("water")) minTO = c3;
else if(c4.name.equals("water")) minTO = c4;
if(minTO !=null) { // has water
maxTO = c1;
if(minTO == maxTO) maxTO = c2;
if(minTO == maxTO) maxTO = c3;
if(minTO == maxTO) maxTO = c4;
} else { // does not have water
minTO = c1;
maxTO = c2;
if(minTO == maxTO) maxTO = c3;
if(minTO == maxTO) maxTO = c4;
}
// All tiles become minTO or maxTO
if(c1 != minTO && c1!=maxTO) c1=maxTO;
if(c2 != minTO && c2!=maxTO) c2=maxTO;
if(c3 != minTO && c3!=maxTO) c3=maxTO;
if(c4 != minTO && c4!=maxTO) c4=maxTO;
// Swap minTO and maxTO, for correct Autotiling ordering
if(minTO.tiles[0] > maxTO.tiles[0]) {
TileObject temp = minTO;
minTO = maxTO;
maxTO = temp;
}
//System.out.println("AF" + c1 + " " + c2 + " " + c3 + " " + c4);
//return NULL_TILE;
}
int result = NULL_TILE;
int b1 = c1.equals(minTO) ? 0: 1;
int b2 = c2.equals(minTO) ? 0: 1;
int b3 = c3.equals(minTO) ? 0: 1;
int b4 = c4.equals(minTO) ? 0: 1;
try {
result = autoTileMappings.get(minTO.name + "/" + maxTO.name)[b1 + b2*2 + b3*4 + b4*8];
}catch(Exception e) {
System.out.println(minTO + " " + maxTO);
}
return result;
}
private TileObject getTileObjectFrom(int x, int y, int l) {
TileObject to = pixelMappings.get(layers[l].getImage().getRGB(x/scaleFactor, y/scaleFactor));
if(to==null) {
System.err.println(layers[l].getImage().getRGB(x/scaleFactor, y/scaleFactor));
Color c = new Color(layers[l].getImage().getRGB(x/scaleFactor, y/scaleFactor));
System.out.println(c.getRed() + "," + c.getGreen() + ","+c.getBlue());
}
return to;
}
private int getDirectTileFrom(int x, int y, int l) {
return getDirectTileFrom(x,y,x,y,l);
}
private int getDirectTileFrom(int x, int y, int mappingx, int mappingy, int l) {
TileObject tobj = pixelMappings.get(layers[l].getImage().getRGB(mappingx/scaleFactor, mappingy/scaleFactor));
if(tobj!=null) {
if(tobj.tiles.length==1)
return tobj.tiles[0];
else if(tobj.tiles.length==4) {
return tobj.tiles[2*(y%2==0?0:1) + (x%2==0?0:1)];
}
}
return 0;
}
public void settile(int x, int y, int i, int z) {
if(layers[i] != null) {
layers[i].getImage().setRGB(x * scaleFactor, y * scaleFactor, z);
}
}
public boolean getobs(int x, int y) {
if(x<0 || y<0 || x >= this.getWidth() || y >= this.getHeight())
return true;
//if(getDirectTileFrom(x, y, 0)==3) {//water
//return true;
//}
return false;
}
public void setobs(int x, int y, int t) {
// TODO Auto-generated method stub
}
public boolean getobspixel(int x, int y) {
if(x<0 || y<0 || x>>4 >= this.getWidth() || y>>4 >= this.getHeight())
return true;
//if(getDirectTileFrom(x>>4, y>>4, 0)==3) {//water
//return true;
//}
return false;
}
public String getFilename() {
return mapName;
}
public Entity[] getEntities() {
return null;
}
public String getRenderstring() {
return this.renderstring;
}
public void setRenderstring(String string) {
this.renderstring = string;
}
public int getzone(int x, int y) {
return layers[1].getImage().getRGB(x/scaleFactor, y/scaleFactor)==-3670016 ? 1 : 0;
//return 0;
}
public void setzone(int x, int y, int z) {
// TODO Auto-generated method stub
}
public String getScriptZone(int zone) {
if(zone==1)
return "city";
return null;
}
public int getPercentZone(int zone) {
// TODO Auto-generated method stub
return 255;
}
public int getMethodZone(int zone) {
// TODO Auto-generated method stub
return 1;
}
public int getNumLayers() {
return layers.length;
}
public int getLayerLucent(int layer) {
return 0;
}
}