code:
package com.lilithsthrone.world;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;

import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Vector2i;
import com.lilithsthrone.world.places.GenericPlace;
import javafx.concurrent.Task;

/**
 * @since 0.1.0
 * @version 0.3.1
 * @author Innoxia
 */
public class Generation extends Task<Boolean> {

	private boolean debug = false;

	public Generation() {
	}

	@Override
	public Boolean call() {
		int maxSize = WorldType.values().length;
		int count = 0;

		for(WorldType wt : WorldType.values()) {
			if(debug) {
				System.out.println(wt);
			}
			worldGeneration(wt);
			count++;
			updateProgress(count, maxSize);
		}

		return true;
	}

	public void worldGeneration(WorldType worldType) {
//		System.out.println(worldType);
		if(worldType.isUsesFile()) {
			try {
				BufferedImage img = ImageIO.read((getClass().getResource(worldType.getFileLocation())));

				World world = new World(img.getWidth(), img.getHeight(), null, worldType);
				Main.game.getWorlds().put(worldType, world);

				if(debug)
					System.out.println(worldType.getName()+" Start-File 1");

				Cell[][] grid = new Cell[img.getWidth()][img.getHeight()];

				for (int i = 0; i < img.getWidth(); i++) {
					for (int j = 0; j < img.getHeight(); j++) {
						grid[i][j] = new Cell(worldType, new Vector2i(i, j));
						if(worldType.isRevealedOnStart()) {
							grid[i][j].setDiscovered(true);
							grid[i][j].setTravelledTo(true);

						} else if(worldType.isDiscoveredOnStart()) {
							grid[i][j].setDiscovered(true);
						}
					}
				}

				if(debug)
					System.out.println(worldType.getName()+" Start-File 2");

				for(int w = 0 ; w < img.getWidth(); w++) {
					for(int h = 0 ; h < img.getHeight(); h++) {
						grid[w][img.getHeight()-1-h].setPlace(new GenericPlace(worldType.getPlacesMap().get(new Color(img.getRGB(w, h)))), true);
					}
				}

				if(debug)
					System.out.println(worldType.getName()+" Start-File 3");

				world.setGrid(grid);

			} catch (IOException e) {
				e.printStackTrace();
			}

		} else {

			if(debug)
				System.out.println(worldType.getName()+" Start 1");

			int width = worldType.getWorldSize();
			int height = worldType.getWorldSize();

			if(debug)
				System.out.println(worldType.getName()+" Start 2  [width:"+width+"] [height:"+height+"]");

			// Create new world of this type:
			World w = new World(width * 2 - 1, height * 2 - 1, null, worldType);

			Main.game.getWorlds().put(w.getWorldType(), w);

			if(debug)
				System.out.println(worldType.getName()+" Start 3");

			// Initialize grid:
			Cell[][] grid = new Cell[width][height];

			if(debug)
				System.out.println(worldType.getName()+" Start 4");

			for (int i = 0; i < width; i++) {
				for (int j = 0; j < height; j++) {
					grid[i][j] = new Cell(worldType, new Vector2i(i, j));
					if(worldType.isRevealedOnStart()) {
						grid[i][j].setDiscovered(true);
						grid[i][j].setTraveledTo(true);
					}
				}
			}

			if(debug)
				System.out.println(worldType.getName()+" Init finished");

			// Put blocks in alternating checkerboard of 4 squares:
			/*
			 * C = chance for 1 block in the 2x2 square . = never a block here
			 * C|C|.|.|C|C
			 * C|C|.|.|C|C
			 * .|.|C|C|.|.
			 * .|.|C|C|.|.
			 * C|C|.|.|C|C
			 * C|C|.|.|C|C
			 *
			 * This will stop any impassable areas being created
			 */
			boolean[][] visited = new boolean[width][height];
			int x = 0, y = 0;
			List<Vector2i> dangerousPlaces = new ArrayList<>();
			for (int i = 0; i < width / 2; i++) {
				for (int j = 0; j < height / 2; j++) {
					if ((i + j) % 2 == 0) {
						switch (rnd.nextInt(4)) {
						case 0:
							x = 0;
							y = 0;
							break;
						case 1:
							x = 0;
							y = 1;
							break;
						case 2:
							x = 1;
							y = 0;
							break;
						case 3:
							x = 0;
							y = 1;
							break;
						}
						visited[i * 2 + x][j * 2 + y] = true;
						grid[i * 2 + x][j * 2 + y].setBlocked(true);
						if (worldType.getCutOffZone() != null) {
							grid[i * 2 + x][j * 2 + y].setPlace(new GenericPlace(worldType.getCutOffZone()), true);
							dangerousPlaces.add(new Vector2i(i * 2 + x, j * 2 + y));
						}
					}
				}
			}

			if(debug)
				System.out.println(worldType.getName()+" Break 1");

			int coreX = 0, coreY = 0;

			if(debug)
				System.out.println(worldType.getName()+" Break 2");

			// Set exits:
			for(PlaceType pt : worldType.getPlaces()){
				if(pt.getBearing()!=null){
					// To get a little bit of spread, use quadrants of map to place exits.
					int quadrant = 1;

					// Don't place exits in corners.
					do {
						if (pt.getBearing() == Bearing.NORTH) {
							coreY = height - 1;

							if (quadrant == 1) {
								coreX = rnd.nextInt(width / 2 - 1) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else {
								coreX = (width / 2) + rnd.nextInt(width / 2 - 1);

								if (!grid[coreX][coreY].isBlocked())
									quadrant = 1;
							}

						} else if (pt.getBearing() == Bearing.EAST) {
							coreX = width - 1;

							if (quadrant == 1) {
								coreY = rnd.nextInt(height / 2 - 1) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else {
								coreY = (height / 2) + rnd.nextInt(height / 2 - 1);

								if (!grid[coreX][coreY].isBlocked())
									quadrant = 1;
							}

						} else if (pt.getBearing() == Bearing.SOUTH) {
							coreY = 0;

							if (quadrant == 1) {
								coreX = rnd.nextInt(width / 2 - 1) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else {
								coreX = (width / 2) + rnd.nextInt(width / 2 - 1);

								if (!grid[coreX][coreY].isBlocked())
									quadrant = 1;
							}

						} else if (pt.getBearing() == Bearing.WEST) {
							coreX = 0;

							if (quadrant == 1) {
								coreY = rnd.nextInt(height / 2 - 1) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else {
								coreY = (height / 2) + rnd.nextInt(height / 2 - 1);

								if (!grid[coreX][coreY].isBlocked())
									quadrant = 1;
							}

						} else {
							// If no bearing, the entrance can't be on a map edge:

							if (quadrant == 1) {
								coreX = rnd.nextInt((width - 2) / 2) + 1;
								coreY = rnd.nextInt((height - 2) / 2) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else if (quadrant == 2) {
								coreX = (width - 2) / 2 + rnd.nextInt((width - 2) / 2) + 1;
								coreY = rnd.nextInt((height - 2) / 2) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else if (quadrant == 3) {
								coreX = rnd.nextInt((width - 2) / 2) + 1;
								coreY = (height - 2) / 2 + rnd.nextInt((height - 2) / 2) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant++;
							} else {
								coreX = (width - 2) / 2 + rnd.nextInt((width - 2) / 2) + 1;
								coreY = (height - 2) / 2 + rnd.nextInt((height - 2) / 2) + 1;

								if (!grid[coreX][coreY].isBlocked())
									quadrant = 1;
							}
						}
					} while (grid[coreX][coreY].isBlocked());

					grid[coreX][coreY].setBlocked(false);
					visited[coreX][coreY] = false;
					grid[coreX][coreY].setPlace(new GenericPlace(pt), true);

					if (pt.getBearing() == Bearing.NORTH)
						grid[coreX][coreY].setNorthAccess(true);
					else if (pt.getBearing() == Bearing.EAST)
						grid[coreX][coreY].setEastAccess(true);
					else if (pt.getBearing() == Bearing.SOUTH)
						grid[coreX][coreY].setSouthAccess(true);
					else if (pt.getBearing() == Bearing.WEST)
						grid[coreX][coreY].setWestAccess(true);
				}
			}

			if(debug)
				System.out.println(worldType.getName()+" Break 3");

			// Add places:
			int quadrant = 1;
			List<PlaceType> places = new ArrayList<>();
			for (PlaceType p : worldType.getPlaces()) {
				if(p.getBearing()==null && p.getParentAlignment()==null)
					places.add(p);
			}
			Collections.shuffle(places);

			for (PlaceType p : places) {
				do {
					coreX = rnd.nextInt(width);
					coreY = rnd.nextInt(height);
					if (quadrant == 1) {
						coreX = rnd.nextInt(width / 2);
						coreY = rnd.nextInt(height / 2);
					} else if (quadrant == 2) {
						coreX = width / 2 + rnd.nextInt(width / 2);
						coreY = rnd.nextInt(height / 2);
					} else if (quadrant == 3) {
						coreX = rnd.nextInt(width / 2);
						coreY = height / 2 + rnd.nextInt(height / 2);
					} else {
						coreX = width / 2 + rnd.nextInt(width / 2);
						coreY = height / 2 + rnd.nextInt(height / 2);
					}
				} while (grid[coreX][coreY].isBlocked() || grid[coreX][coreY].getPlace().getPlaceType() != worldType.getStandardPlace());

				quadrant++;
				if (quadrant > 4)
					quadrant = 1;

				grid[coreX][coreY].setPlace(new GenericPlace(p), true);

			}

			// Add cuttOffZone places:
			if (worldType.getDangerousPlaces() != null)
				for (PlaceType p : worldType.getDangerousPlaces()) {
					Vector2i vTemp = dangerousPlaces.get(Util.random.nextInt(dangerousPlaces.size()));

					grid[vTemp.getX()][vTemp.getY()].setPlace(new GenericPlace(p), true);

					dangerousPlaces.remove(vTemp);
				}

			Cell[][] finalGrid = generateMap(width / 2, height / 2, grid, visited);

			if(debug)
				System.out.println(worldType.getName()+" Break 4");

			// Expand the generated grid:

			Cell[][] expandedGrid = new Cell[width * 2 - 1][height * 2 - 1];
			for (int i = 0; i < width * 2 - 1; i++)
				for (int j = 0; j < height * 2 - 1; j++)
					expandedGrid[i][j] = new Cell(worldType, new Vector2i(i, j));

			for (int i = 0; i < width * 2 - 1; i++)
				for (int j = 0; j < height * 2 - 1; j++) {
					if (i % 2 == 0 && j % 2 == 0) {
						if (finalGrid[i / 2][j / 2].getPlace().getPlaceType() != worldType.getStandardPlace()) {
							expandedGrid[i][j].setPlace(finalGrid[i / 2][j / 2].getPlace(), true);
						}
					} else if (i % 2 == 0) {
						if (finalGrid[i / 2][j / 2].isNorthAccess())
							expandedGrid[i][j].setSouthAccess(true);
						if (finalGrid[i / 2][(j + 1) / 2].isSouthAccess())
							expandedGrid[i][j].setNorthAccess(true);
						if (!finalGrid[i / 2][j / 2].isNorthAccess() && !finalGrid[i / 2][(j + 1) / 2].isSouthAccess()) {
							expandedGrid[i][j].setPlace(new GenericPlace(worldType.getCutOffZone()), true);
						}

					} else if (j % 2 == 0) {
						if (finalGrid[i / 2][j / 2].isEastAccess())
							expandedGrid[i][j].setWestAccess(true);
						if (finalGrid[(i + 1) / 2][j / 2].isWestAccess())
							expandedGrid[i][j].setEastAccess(true);
						if (!finalGrid[i / 2][j / 2].isEastAccess() && !finalGrid[(i + 1) / 2][j / 2].isWestAccess()) {
							expandedGrid[i][j].setPlace(new GenericPlace(worldType.getCutOffZone()), true);
						}

					} else {
						if (Math.random() > 0.8) {
							expandedGrid[i][j].setPlace(new GenericPlace(worldType.getCutOffZone()), true);
						} else {
							expandedGrid[i][j].setPlace(new GenericPlace(PlaceType.GENERIC_IMPASSABLE), true);
						}
					}

				}

//			printMaze(expandedGrid);

			w.setGrid(expandedGrid);
		}
	}

	// start point for generation
	public Cell[][] generateMap(int x, int y, Cell[][] grid, boolean[][] visited) {
		Random rnd = new Random();

		if (Math.random() >= 0.5) {
			visited[x][y] = true;
		}

		int width = grid.length;
		int height = grid[0].length;

		// Check each surrounding cell to see if it's been visited. If it has,
		// skip over it. If it hasn't, break the wall to it:
		// y+2
		// x-2 ORIGIN x+2
		// y-2

		// randomize this order:
		int[] direction = { 1, 2, 3, 4 };
		for (int i = direction.length - 1; i > 0; i--) {
			int index = rnd.nextInt(i + 1);
			// Simple swap
			int a = direction[index];
			direction[index] = direction[i];
			direction[i] = a;
		}

		for (Integer index : direction) {
			switch (index) {
			case 1: // West
				if (x - 1 >= 0 && y >= 0 && y <= height - 1)
					if (!visited[x - 1][y] && !grid[x - 1][y].isBlocked()) {
						grid[x][y].setWestAccess(true);
						grid[x - 1][y].setEastAccess(true);
						generateMap(x - 1, y, grid, visited);
					}
				break;

			case 2: // East
				if (x + 1 <= width - 1 && y >= 0 && y <= height - 1)
					if (!visited[x + 1][y] && !grid[x + 1][y].isBlocked()) {
						grid[x][y].setEastAccess(true);
						grid[x + 1][y].setWestAccess(true);
						generateMap(x + 1, y, grid, visited);
					}
				break;

			case 3: // South
				if (y - 1 >= 0 && x >= 0 && x <= width - 1)
					if (!visited[x][y - 1] && !grid[x][y - 1].isBlocked()) {
						grid[x][y].setSouthAccess(true);
						grid[x][y - 1].setNorthAccess(true);
						generateMap(x, y - 1, grid, visited);
					}
				break;

			case 4: // North
				if (y + 1 <= height - 1 && x >= 0 && x <= width - 1)
					if (!visited[x][y + 1] && !grid[x][y + 1].isBlocked()) {
						grid[x][y].setNorthAccess(true);
						grid[x][y + 1].setSouthAccess(true);
						generateMap(x, y + 1, grid, visited);
					}
				break;
			}
		}

		return grid;
	}

	/*
	 * Take in grid where important places need to go
	 * Take in important places list
	 * Randomly place places into grid
	 * Generate new grid with IMPASSABLE padding - place important places at regular intervals
	 * Start from middle and explore grid until visited all original places, changing IMPASSABLE to generic path or dangerous path as you go
	 * cannot explore into corners
	 */

	public static Cell[][] generateTestMap(WorldType worldType, int x, int y, Cell[][] grid, int padding) {
		int paddedCellSize = 2*padding+1;

		Cell[][] paddedGrid = new Cell[(grid.length*paddedCellSize)-(2*padding)][(grid[0].length*paddedCellSize)-(2*padding)];

		for(int i=0; i<paddedGrid.length;i++) {
			for(int j=0; j<paddedGrid[0].length;j++) {
				if(i%paddedCellSize==0 && j%paddedCellSize==0) {
					paddedGrid[i][j] = grid[i/paddedCellSize][j/paddedCellSize];
				} else {
					paddedGrid[i][j] = new Cell(worldType, new Vector2i(i, j));
					paddedGrid[i][j].setPlace(new GenericPlace(PlaceType.GENERIC_IMPASSABLE), true);
				}
			}
		}
		int totalMajorPlaces = grid.length*grid[0].length;
		List<Vector2i> discoveredMajorPlaces = new ArrayList<>();
		return recursiveGenerateTestMap(worldType, (paddedGrid.length/2)+1, (paddedGrid[0].length/2)+1, paddedGrid, totalMajorPlaces, discoveredMajorPlaces);
	}

	private static Cell[][] recursiveGenerateTestMap(WorldType worldType, int x, int y, Cell[][] grid, int totalMajorPlaces, List<Vector2i> discoveredMajorPlaces) {
		if(totalMajorPlaces == discoveredMajorPlaces.size()) {
			return grid;
		}

		Random rnd = new Random();

		int width = grid.length;
		int height = grid[0].length;

		// randomize this order:
		int[] direction = { 1, 2, 3, 4 };
		for (int i = direction.length - 1; i > 0; i--) {
			int index = rnd.nextInt(i + 1);
			// Simple swap
			int a = direction[index];
			direction[index] = direction[i];
			direction[i] = a;
		}

		for (Integer index : direction) {
			switch (index) {
				case 1: // West
					if (x - 1 >= 0 && y >= 0 && y <= height - 1) {
						if (!isCorner(x - 1, y, grid) && grid[x - 1][y].getPlace().getPlaceType()==PlaceType.GENERIC_IMPASSABLE) {
							grid[x - 1][y].setPlace(new GenericPlace(worldType.getStandardPlace()), true);
							recursiveGenerateTestMap(worldType, x - 1, y, grid, totalMajorPlaces, discoveredMajorPlaces);

						} else if(grid[x - 1][y].getPlace().getPlaceType()!=worldType.getStandardPlace()) {
							if(!discoveredMajorPlaces.contains(new Vector2i(x-1, y))) {
								discoveredMajorPlaces.add(new Vector2i(x-1, y));
								recursiveGenerateTestMap(worldType, x - 1, y, grid, totalMajorPlaces, discoveredMajorPlaces);
							}
						}
					}
					break;

				case 2: // East
					if (x + 1 <= width - 1 && y >= 0 && y <= height - 1) {
						if (!isCorner(x + 1, y, grid) &&grid[x + 1][y].getPlace().getPlaceType()==PlaceType.GENERIC_IMPASSABLE) {
							grid[x + 1][y].setPlace(new GenericPlace(worldType.getStandardPlace()), true);
							recursiveGenerateTestMap(worldType, x + 1, y, grid, totalMajorPlaces, discoveredMajorPlaces);

						} else if(grid[x + 1][y].getPlace().getPlaceType()!=worldType.getStandardPlace()) {
							if(!discoveredMajorPlaces.contains(new Vector2i(x+1, y))) {
								discoveredMajorPlaces.add(new Vector2i(x+1, y));
								recursiveGenerateTestMap(worldType, x + 1, y, grid, totalMajorPlaces, discoveredMajorPlaces);
							}
						}
					}
					break;

				case 3: // South
					if (y - 1 >= 0 && x >= 0 && x <= width - 1) {
						if (!isCorner(x, y-1, grid) &&grid[x][y - 1].getPlace().getPlaceType()==PlaceType.GENERIC_IMPASSABLE) {
							grid[x][y - 1].setPlace(new GenericPlace(worldType.getStandardPlace()), true);
							recursiveGenerateTestMap(worldType, x, y - 1, grid, totalMajorPlaces, discoveredMajorPlaces);

						} else if(grid[x][y-1].getPlace().getPlaceType()!=worldType.getStandardPlace()) {
							if(!discoveredMajorPlaces.contains(new Vector2i(x, y-1))) {
								discoveredMajorPlaces.add(new Vector2i(x, y-1));
								recursiveGenerateTestMap(worldType, x, y-1, grid, totalMajorPlaces, discoveredMajorPlaces);
							}
						}
					}
					break;

				case 4: // North
					if (y + 1 <= height - 1 && x >= 0 && x <= width - 1) {
						if (!isCorner(x, y+1, grid) &&grid[x][y + 1].getPlace().getPlaceType()==PlaceType.GENERIC_IMPASSABLE) {
							grid[x][y + 1].setPlace(new GenericPlace(worldType.getStandardPlace()), true);
							recursiveGenerateTestMap(worldType, x, y + 1, grid, totalMajorPlaces, discoveredMajorPlaces);

						} else if(grid[x][y+1].getPlace().getPlaceType()!=worldType.getStandardPlace()) {
							if(!discoveredMajorPlaces.contains(new Vector2i(x, y+1))) {
								discoveredMajorPlaces.add(new Vector2i(x, y+1));
								recursiveGenerateTestMap(worldType, x, y+1, grid, totalMajorPlaces, discoveredMajorPlaces);
							}
						}
					}
					break;
			}
		}
		System.out.println(discoveredMajorPlaces.size());
		return grid;
	}

	private static boolean isCorner(int x, int y, Cell[][] grid) {
		int x1[] = new int[] {-1, 0, 1, 1, 1, 0, -1, -1};
		int y1[] = new int[] {1, 1, 1, 0, -1, -1, -1, 0};

		int count=0;
		for(int i=0;i<8;i++) {
			if(x+x1[i]>0 && x+x1[i]<grid.length
				&& y+y1[i]>0 && y+y1[i]<grid[0].length
					&& grid[x+x1[i]][y+y1[i]].getPlace().getPlaceType()!=PlaceType.GENERIC_IMPASSABLE) {
				count++;
			} else {
				count = 0;
			}
			if(count==3) {
				return true;
			}
		}
		return false;
	}

	public static void printMaze(WorldType worldType, Cell[][] maze) {
		StringBuilder lineOneBuffer = new StringBuilder("");
		for (int y = maze[0].length - 1; y >= 0; y--) {
			for (int x = 0; x < maze.length; x++) {
				if (maze[x][y].getPlace().getPlaceType() == PlaceType.GENERIC_IMPASSABLE) {
					lineOneBuffer.append('#');
				} else if (maze[x][y].getPlace().getPlaceType() == worldType.getStandardPlace()) {
					lineOneBuffer.append('-');
				} else {
					lineOneBuffer.append('*');
				}
			}

			System.out.println(lineOneBuffer.toString());
			lineOneBuffer = new StringBuilder("");
		}
	}

}


code:
package com.lilithsthrone.world;

import java.time.Month;

/**
 * @since 0.1.96
 * @version 0.1.96
 * @author Innoxia
 */
public enum Season {

	SPRING("spring"),
	SUMMER("summer"),
	AUTUMN("autumn"),
	WINTER("winter");

	private String name;

	private Season(String name) {
		this.name = name;
	}

	public static Season getSeasonFromMonth(Month month) {
		switch(month) {
			case DECEMBER: case JANUARY: case FEBRUARY:
				return Season.WINTER;

			case MARCH: case APRIL: case MAY:
				return Season.SPRING;

			case JUNE: case JULY: case AUGUST:
				return Season.SUMMER;

			case SEPTEMBER: case OCTOBER: case NOVEMBER:
				return Season.AUTUMN;
		}

		return Season.SUMMER;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

repo_name: klorpa/Pedo

license: unknown


code:
package com.lilithsthrone.world;

/**
 * @since 0.3.5
 * @version 0.3.5
 * @author Innoxia
 */
public enum TeleportPermissions {

	NONE(false, false),

	INCOMING_ONLY(true, false),

	OUTGOING_ONLY(false, true),

	BOTH(true, true);

	private boolean incoming;
	private boolean outgoing;

	private TeleportPermissions(boolean incoming, boolean outgoing) {
		this.incoming = incoming;
		this.outgoing = outgoing;
	}

	public boolean isIncoming() {
		return incoming;
	}

	public boolean isOutgoing() {
		return outgoing;
	}

}


code:
package com.lilithsthrone.world;

import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.0
 * @version 0.1.96
 * @author Innoxia
 */
public enum Weather {

	CLOUD("cloudy", Colour.GENERIC_GOOD),

	CLEAR("clear", Colour.GENERIC_GOOD),

	RAIN("raining", Colour.GENERIC_BAD),

	SNOW("snowing", Colour.GENERIC_BAD),

	MAGIC_STORM_GATHERING("stormy sky", Colour.GENERIC_ARCANE),

	MAGIC_STORM("arcane storm", Colour.GENERIC_ARCANE);

	private String name;
	private Colour colour;

	private Weather(String name, Colour colour) {
		this.name = name;
		this.colour = colour;
	}

	public String getName() {
		return name;
	}

	public Colour getColour() {
		return colour;
	}
}


code:
package com.lilithsthrone.world;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.lilithsthrone.game.character.CharacterUtils;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.Vector2i;
import com.lilithsthrone.utils.XMLSaving;
import com.lilithsthrone.world.places.AbstractPlaceType;
import com.lilithsthrone.world.places.PlaceType;
import com.lilithsthrone.world.places.PlaceUpgrade;

/**
 * @since 0.1.0
 * @version 0.3
 * @author Innoxia
 */
public class World implements XMLSaving {

	public final int WORLD_WIDTH;
	public final int WORLD_HEIGHT;
	public static final int CELL_SIZE = 64;

	private Cell[][] grid;
	private WorldType worldType;

	public World(int worldWidth, int worldHeight, Cell[][] grid, WorldType worldType) {
		WORLD_WIDTH = worldWidth;
		WORLD_HEIGHT = worldHeight;

		this.grid = grid;
		this.worldType = worldType;
	}

	@Override
	public Element saveAsXML(Element parentElement, Document doc) {
		Element element = doc.createElement("world");
		parentElement.appendChild(element);

		CharacterUtils.addAttribute(doc, element, "worldType", this.getWorldType().toString());
		CharacterUtils.addAttribute(doc, element, "width", String.valueOf(this.WORLD_WIDTH));
		CharacterUtils.addAttribute(doc, element, "height", String.valueOf(this.WORLD_HEIGHT));

		Element innerElement = doc.createElement("grid");
		element.appendChild(innerElement);
		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(!grid[i][j].getPlace().getPlaceType().equals(PlaceType.GENERIC_IMPASSABLE)) {
					grid[i][j].saveAsXML(innerElement, doc);
				}
			}
		}

		return element;
	}

	public static World loadFromXML(Element parentElement, Document doc) {
		WorldType type = WorldType.EMPTY;
		String worldType = parentElement.getAttribute("worldType");
		if(worldType.equals("SEWERS")) {
			type = WorldType.SUBMISSION;
		} else {
			type = WorldType.valueOf(worldType);
		}

		int width = Integer.valueOf(parentElement.getAttribute("width"));
		int height = Integer.valueOf(parentElement.getAttribute("height"));
		Cell[][] newGrid = new Cell[width][height];
		for(int i=0;i<width;i++) {
			for(int j=0;j<height;j++) {
				newGrid[i][j] = new Cell(type, new Vector2i(i, j));
				newGrid[i][j].getPlace().setPlaceType(PlaceType.GENERIC_IMPASSABLE);
			}
		}

		NodeList cells = ((Element) parentElement.getElementsByTagName("grid").item(0)).getElementsByTagName("cell");
		for(int i = 0; i < cells.getLength(); i++){
			Element e = (Element) cells.item(i);

			Cell c = Cell.loadFromXML(e, doc, type);
			newGrid[c.getLocation().getX()][c.getLocation().getY()] = c;
		}

		return new World(width, height, newGrid, type);
	}

	public Cell getCell(int i, int j) {
		if(i<0 || j<0 || i >= WORLD_WIDTH || j >= WORLD_HEIGHT) {
			return null;
		}
		return grid[i][j];
	}

	public Cell getCell(Vector2i vec) {
		try {
			return grid[vec.getX()][vec.getY()];
		} catch(Exception ex) {
			System.err.println("Error in WorldType: "+this.getWorldType());
			throw ex;
		}
	}

	/**
	 * @param place The AbstractPlaceType to find a Cell of.
	 * @return A Cell of the PlaceType defined by the argument 'place'. If there are multiple Cells with the same PlaceType, the first one that is found is returned.
	 */
	public Cell getCell(AbstractPlaceType place) {
		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place)) {
					return grid[i][j];
				}
			}
		}
		return null;
	}

	/**
	 * @param place The AbstractPlaceType to find all Cells of.
	 * @return A List of Cells of the PlaceType defined by the argument 'place'.
	 */
	public List<Cell> getCells(AbstractPlaceType place) {
		List<Cell> cellsFound = new ArrayList<>();

		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place)) {
					cellsFound.add(grid[i][j]);
				}
			}
		}

		return cellsFound;
	}

	/**
	 * @param place The PlaceUpgrade to find all Cells of.
	 * @return A List of Cells which have the specified upgrade.
	 */
	public List<Cell> getCells(PlaceUpgrade placeUpgrade) {
		List<Cell> cellsFound = new ArrayList<>();

		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceUpgrades().contains(placeUpgrade)) {
					cellsFound.add(grid[i][j]);
				}
			}
		}

		return cellsFound;
	}

	public Cell getClosestCell(Vector2i location, AbstractPlaceType place) {
		float distance = 10000f;
		Cell closestCell = null;
		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place)) {
					float newDistance = Vector2i.getDistance(location, grid[i][j].getLocation());
					if(newDistance < distance) {
						closestCell = grid[i][j];
						distance = newDistance;
					}
				}
			}
		}
		return closestCell;
	}

	/**
	 * @param place The PlaceType to find a Cell of.
	 * @return A random, unoccupied Cell of the PlaceType defined by the argument 'place'. If there are no unoccupied Cells with this PlaceType, a random occupied one is returned instead.
	 */
	public Cell getRandomUnoccupiedCell(AbstractPlaceType place) {
		List<Cell> cells = new ArrayList<>();
		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place) && Main.game.getCharactersPresent(grid[i][j]).isEmpty()) {
					cells.add(grid[i][j]);
				}
			}
		}
		if(cells.isEmpty()) {
//			if(Main.DEBUG) {
//				System.err.println("World.getRandomUnoccupiedCell() - No unoccupied cells found, occupied one returned instead.");
//			}
			return getRandomCell(place);
		}
		return cells.get(Util.random.nextInt(cells.size()));
	}

	/**
	 * @param place The PlaceType to find a Cell of.
	 * @return A Cell of the PlaceType defined by the argument 'place'. If there are multiple Cells with the same PlaceType, a random one is returned.
	 */
	public Cell getRandomCell(AbstractPlaceType place) {
		List<Cell> corridorCells = new ArrayList<>();
		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place)) {
					corridorCells.add(grid[i][j]);
				}
			}
		}
		if(corridorCells.isEmpty()) {
			return null;
		}

		return corridorCells.get(Util.random.nextInt(corridorCells.size()));
	}

	public Cell getNearestCell(AbstractPlaceType place, Vector2i startLocation) {
		Cell nearestCell = null;
		float closestDistance = 10000f;

		for(int i=0; i<grid.length; i++) {
			for(int j=0; j<grid[0].length; j++) {
				if(grid[i][j].getPlace().getPlaceType().equals(place)) {
					float distance = (float) Math.sqrt(Math.pow(Math.abs(i-startLocation.getX()), 2) + Math.pow(Math.abs(j-startLocation.getY()), 2));
					if(distance < closestDistance) {
						nearestCell = grid[i][j];
						closestDistance = distance;
					}
				}
			}
		}

		return nearestCell;
	}

	public Cell[][] getCellGrid() {
		return grid;
	}

	public WorldType getWorldType() {
		return worldType;
	}

	public void setCellType(WorldType cellType) {
		this.worldType = cellType;
	}

	public Cell[][] getGrid() {
		return grid;
	}

	public void setGrid(Cell[][] grid) {
		this.grid = grid;
	}
}


code:
package com.lilithsthrone.world;

import java.awt.Color;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.Util.Value;
import com.lilithsthrone.world.places.AbstractPlaceType;
import com.lilithsthrone.world.places.PlaceType;

/**
 * @since 0.1.0
 * @version 0.3.5.5
 * @author Innoxia
 */
public enum WorldType {

	// Dominion:

	WORLD_MAP("Lilith's Realm",
			Colour.BASE_TAN,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/global/world_map.png",
			null, null, Util.newHashMapOfValues(
					new Value<>(new Color(0x61997e), PlaceType.WORLD_MAP_THICK_JUNGLE), // thick jungle
					new Value<>(new Color(0x81cca8), PlaceType.WORLD_MAP_JUNGLE), // jungle
					new Value<>(new Color(0xb377b0), PlaceType.WORLD_MAP_JUNGLE_CITY), // jungle city

					new Value<>(new Color(0x696969), PlaceType.WORLD_MAP_FOOTHILLS), // foothills
					new Value<>(new Color(0xc1c1c1), PlaceType.WORLD_MAP_MOUNTAINS), // low mountains
					new Value<>(new Color(0xe0e0e0), PlaceType.WORLD_MAP_SNOWY_MOUNTAINS), // snowy mountains

					new Value<>(new Color(0xffffff), PlaceType.WORLD_MAP_SNOWY_VALLEY), // snowy valley
					new Value<>(new Color(0xadffff), PlaceType.WORLD_MAP_GLACIAL_LAKE), // glacial lake

					new Value<>(new Color(0x8500ff), PlaceType.WORLD_MAP_DOMINION), // dominion

					new Value<>(new Color(0xcbf1d5), PlaceType.WORLD_MAP_GRASSLANDS), // wild grasslands
					new Value<>(new Color(0xe2ffd7), PlaceType.WORLD_MAP_FIELDS), // foloi fields
					new Value<>(new Color(0xb4c490), PlaceType.WORLD_MAP_FOREST), // forest
					new Value<>(new Color(0xd544ae), PlaceType.WORLD_MAP_FIELDS_CITY), // Elis

					new Value<>(new Color(0x98c488), PlaceType.WORLD_MAP_YOUKO_FOREST), // shinrin highland

					new Value<>(new Color(0x62e6d3), PlaceType.WORLD_MAP_WILD_RIVER), // dangerous river
					new Value<>(new Color(0xa7fce8), PlaceType.WORLD_MAP_RIVER), // river

					new Value<>(new Color(0xc4fcff), PlaceType.WORLD_MAP_SEA), // endless sea
					new Value<>(new Color(0x8264b0), PlaceType.WORLD_MAP_SEA_CITY), // sea city

					new Value<>(new Color(0xebffc4), PlaceType.WORLD_MAP_ARID_GRASSLAND), // arid grassland
					new Value<>(new Color(0xd3e6b0), PlaceType.WORLD_MAP_ARID_SAVANNAH), // savannah

					new Value<>(new Color(0xffefc4), PlaceType.WORLD_MAP_DESERT), // desert
					new Value<>(new Color(0xffce4a), PlaceType.WORLD_MAP_SAND_DUNES), // sand dunes
					new Value<>(new Color(0xd5445e), PlaceType.WORLD_MAP_DESERT_CITY), // desert city

					new Value<>(new Color(0xff8100), PlaceType.WORLD_MAP_VOLCANO), // volcano
					new Value<>(new Color(0x3b3b3b), PlaceType.WORLD_MAP_LAVA_FLOWS) // lava flows
					)) {
		@Override
		public boolean isDiscoveredOnStart() {
			return true;
		}

	},

	DOMINION("Dominion",
			Colour.BASE_PURPLE,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/dominion.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.DOMINION_PLAZA, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x808080), PlaceType.DOMINION_STREET),
					new Value<>(new Color(0x404040), PlaceType.DOMINION_BOULEVARD),
					new Value<>(new Color(0x808000), PlaceType.DOMINION_EXIT_TO_SUBMISSION),

					new Value<>(new Color(0xc10000), PlaceType.DOMINION_BACK_ALLEYS),
					new Value<>(new Color(0x5b0000), PlaceType.DOMINION_DARK_ALLEYS),
					new Value<>(new Color(0x40b4ff), PlaceType.DOMINION_ALLEYS_CANAL_CROSSING),

					new Value<>(new Color(0x0080ff), PlaceType.DOMINION_CANAL),
					new Value<>(new Color(0x004080), PlaceType.DOMINION_CANAL_END),

					new Value<>(new Color(0x000000), PlaceType.DOMINION_DEMON_HOME_GATE),
					new Value<>(new Color(0xff80ff), PlaceType.DOMINION_DEMON_HOME),
					new Value<>(new Color(0xff9100), PlaceType.DOMINION_DEMON_HOME_ARTHUR),
					new Value<>(new Color(0x8000ff), PlaceType.DOMINION_CITY_HALL),
					new Value<>(new Color(0xff00ff), PlaceType.DOMINION_LILITHS_TOWER),

					new Value<>(new Color(0x8080ff), PlaceType.DOMINION_EXIT_WEST),
					new Value<>(new Color(0xff4a00), PlaceType.DOMINION_EXIT_NORTH),
					new Value<>(new Color(0x008040), PlaceType.DOMINION_EXIT_EAST),
					new Value<>(new Color(0xffff80), PlaceType.DOMINION_EXIT_SOUTH),

					new Value<>(new Color(0x008080), PlaceType.DOMINION_STREET_HARPY_NESTS),
					new Value<>(new Color(0x00ff80), PlaceType.DOMINION_HARPY_NESTS_ENTRANCE),

					new Value<>(new Color(0x004000), PlaceType.DOMINION_PLAZA),
					new Value<>(new Color(0x00ffff), PlaceType.DOMINION_AUNTS_HOME),
					new Value<>(new Color(0xffff00), PlaceType.DOMINION_SHOPPING_ARCADE),
					new Value<>(new Color(0x0000ff), PlaceType.DOMINION_ENFORCER_HQ),
					new Value<>(new Color(0x000080), PlaceType.DOMINION_NIGHTLIFE_DISTRICT),
					new Value<>(new Color(0xff0000), PlaceType.DOMINION_SLAVER_ALLEY),
					new Value<>(new Color(0x4bff00), PlaceType.DOMINION_PARK),
					new Value<>(new Color(0xff4000), PlaceType.DOMINION_RED_LIGHT_DISTRICT)

					)),

	// Empty:
	EMPTY("City",
			Colour.BASE_BROWN,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/empty.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.GENERIC_EMPTY_TILE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0xff0000), PlaceType.GENERIC_EMPTY_TILE),
					new Value<>(new Color(0xffff00), PlaceType.GENERIC_HOLDING_CELL),
					new Value<>(new Color(0x0080ff), PlaceType.GENERIC_MUSEUM))),

	MUSEUM("Museum",
			Colour.BASE_BROWN,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/prologue/museum.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.MUSEUM_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0xff0000), PlaceType.MUSEUM_ENTRANCE),
					new Value<>(new Color(0x8000ff), PlaceType.MUSEUM_CROWDS),
					new Value<>(new Color(0x0080ff), PlaceType.MUSEUM_OFFICE),
					new Value<>(new Color(0xffff00), PlaceType.MUSEUM_STAGE),
					new Value<>(new Color(0xff8000), PlaceType.MUSEUM_ROOM),
					new Value<>(new Color(0x00ff00), PlaceType.MUSEUM_STAIRS),
					new Value<>(new Color(0x808080), PlaceType.MUSEUM_LOBBY))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	MUSEUM_LOST("Museum",
			Colour.BASE_BROWN,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/prologue/museum_lost.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.MUSEUM_MIRROR, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0xff8000), PlaceType.MUSEUM_ROOM),
					new Value<>(new Color(0x00ff00), PlaceType.MUSEUM_MIRROR),
					new Value<>(new Color(0x808080), PlaceType.MUSEUM_CORRIDOR))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	LILAYAS_HOUSE_GROUND_FLOOR("Lilaya's Home GF",
			Colour.BASE_BLUE_LIGHT,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/lilayasHome/lilayas_home_ground_floor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.LILAYA_HOME_ENTRANCE_HALL, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.LILAYA_HOME_CORRIDOR),
					new Value<>(new Color(0xff0000), PlaceType.LILAYA_HOME_ENTRANCE_HALL),
					new Value<>(new Color(0x008000), PlaceType.LILAYA_HOME_GARDEN),
					new Value<>(new Color(0xff8000), PlaceType.LILAYA_HOME_LAB),
					new Value<>(new Color(0xffff00), PlaceType.LILAYA_HOME_BIRTHING_ROOM),
					new Value<>(new Color(0xff80ff), PlaceType.LILAYA_HOME_KITCHEN),
					new Value<>(new Color(0x00ffff), PlaceType.LILAYA_HOME_LIBRARY),
					new Value<>(new Color(0x8000ff), PlaceType.LILAYA_HOME_FOUNTAIN),
					new Value<>(new Color(0xff0080), PlaceType.LILAYA_HOME_ROOM_GARDEN_GROUND_FLOOR),
					new Value<>(new Color(0xff00ff), PlaceType.LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR),
					new Value<>(new Color(0x00ff00), PlaceType.LILAYA_HOME_STAIR_UP))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	LILAYAS_HOUSE_FIRST_FLOOR("Lilaya's Home 1F",
			Colour.BASE_BLUE_LIGHT,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/lilayasHome/lilayas_home_first_floor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.LILAYA_HOME_STAIR_DOWN, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.LILAYA_HOME_CORRIDOR),
					new Value<>(new Color(0xff00ff), PlaceType.LILAYA_HOME_ROOM_WINDOW_FIRST_FLOOR),
					new Value<>(new Color(0xff0080), PlaceType.LILAYA_HOME_ROOM_GARDEN_FIRST_FLOOR),
					new Value<>(new Color(0xff80ff), PlaceType.LILAYA_HOME_ROOM_LILAYA),
					new Value<>(new Color(0x0080ff), PlaceType.LILAYA_HOME_ROOM_ROSE),
					new Value<>(new Color(0x00ffff), PlaceType.LILAYA_HOME_ROOM_PLAYER),
					new Value<>(new Color(0xff0000), PlaceType.LILAYA_HOME_STAIR_DOWN))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	ZARANIX_HOUSE_FIRST_FLOOR("Zaranix's Home 1F",
			Colour.BASE_CRIMSON,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/dominion/zaranixHome/first_floor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.ZARANIX_FF_STAIRS, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.ZARANIX_FF_CORRIDOR),
					new Value<>(new Color(0x00ff00), PlaceType.ZARANIX_FF_STAIRS),
					new Value<>(new Color(0xff80ff), PlaceType.ZARANIX_FF_OFFICE),
					new Value<>(new Color(0xff00ff), PlaceType.ZARANIX_FF_ROOM),
					new Value<>(new Color(0x8000ff), PlaceType.ZARANIX_FF_MAID))),

	ZARANIX_HOUSE_GROUND_FLOOR("Zaranix's Home GF",
			Colour.BASE_CRIMSON,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/dominion/zaranixHome/ground_floor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.ZARANIX_GF_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.ZARANIX_GF_CORRIDOR),
					new Value<>(new Color(0x00ff00), PlaceType.ZARANIX_GF_STAIRS),
					new Value<>(new Color(0xff0000), PlaceType.ZARANIX_GF_ENTRANCE),
					new Value<>(new Color(0xffff00), PlaceType.ZARANIX_GF_LOUNGE),
					new Value<>(new Color(0xff00ff), PlaceType.ZARANIX_GF_ROOM),
					new Value<>(new Color(0x8000ff), PlaceType.ZARANIX_GF_MAID),
					new Value<>(new Color(0x00ffff), PlaceType.ZARANIX_GF_GARDEN_ROOM),
					new Value<>(new Color(0x008000), PlaceType.ZARANIX_GF_GARDEN),
					new Value<>(new Color(0xff8000), PlaceType.ZARANIX_GF_GARDEN_ENTRY))),

	HARPY_NEST("Harpy Nests",
			Colour.BASE_CRIMSON,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/harpyNests/harpyNests.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.HARPY_NESTS_ENTRANCE_ENFORCER_POST, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x808080), PlaceType.HARPY_NESTS_WALKWAYS),
					new Value<>(new Color(0x404040), PlaceType.HARPY_NESTS_WALKWAYS_BRIDGE),

					new Value<>(new Color(0x00ff80), PlaceType.HARPY_NESTS_ENTRANCE_ENFORCER_POST),
					new Value<>(new Color(0xff0000), PlaceType.HARPY_NESTS_HARPY_NEST_RED),
					new Value<>(new Color(0xff00ff), PlaceType.HARPY_NESTS_HARPY_NEST_PINK),
					new Value<>(new Color(0xffff00), PlaceType.HARPY_NESTS_HARPY_NEST_YELLOW),
					new Value<>(new Color(0xff9100), PlaceType.HARPY_NESTS_ALEXAS_NEST))),

	SLAVER_ALLEY("Slaver Alley",
			Colour.BASE_RED,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/slaverAlley/slaverAlley.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.SLAVER_ALLEY_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.SLAVER_ALLEY_PATH),
					new Value<>(new Color(0xff0000), PlaceType.SLAVER_ALLEY_ENTRANCE),

					new Value<>(new Color(0xff80ff), PlaceType.SLAVER_ALLEY_STALL_FEMALES),
					new Value<>(new Color(0x0080ff), PlaceType.SLAVER_ALLEY_STALL_MALES),

					new Value<>(new Color(0xff8000), PlaceType.SLAVER_ALLEY_STALL_ANAL),
					new Value<>(new Color(0xff00ff), PlaceType.SLAVER_ALLEY_STALL_VAGINAL),
					new Value<>(new Color(0xff8080), PlaceType.SLAVER_ALLEY_STALL_ORAL),
					new Value<>(new Color(0x404040), PlaceType.SLAVER_ALLEY_STATUE),

					new Value<>(new Color(0x21bfc5), PlaceType.SLAVER_ALLEY_MARKET_STALL_EXCLUSIVE),
					new Value<>(new Color(0x004080), PlaceType.SLAVER_ALLEY_MARKET_STALL_BULK),
					new Value<>(new Color(0x008080), PlaceType.SLAVER_ALLEY_CAFE),

					new Value<>(new Color(0x0000ff), PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION),
					new Value<>(new Color(0xff0080), PlaceType.SLAVER_ALLEY_SCARLETTS_SHOP),

					new Value<>(new Color(0xffff00), PlaceType.SLAVER_ALLEY_AUCTIONING_BLOCK),
					new Value<>(new Color(0x00ff00), PlaceType.SLAVER_ALLEY_PUBLIC_STOCKS))),

	SHOPPING_ARCADE("Shopping Arcade",
			Colour.BASE_YELLOW,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/shoppingArcade/shoppingArcade.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.SHOPPING_ARCADE_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.SHOPPING_ARCADE_PATH),
					new Value<>(new Color(0xff0000), PlaceType.SHOPPING_ARCADE_ENTRANCE),
					new Value<>(new Color(0x00ffff), PlaceType.SHOPPING_ARCADE_RALPHS_SHOP),
					new Value<>(new Color(0xffff00), PlaceType.SHOPPING_ARCADE_NYANS_SHOP),
					new Value<>(new Color(0x0080ff), PlaceType.SHOPPING_ARCADE_VICKYS_SHOP),
					new Value<>(new Color(0x8000ff), PlaceType.SHOPPING_ARCADE_PIXS_GYM),
					new Value<>(new Color(0xff8000), PlaceType.SHOPPING_ARCADE_KATES_SHOP),
					new Value<>(new Color(0xff00ff), PlaceType.SHOPPING_ARCADE_GENERIC_SHOP),
					new Value<>(new Color(0x008000), PlaceType.SHOPPING_ARCADE_ASHLEYS_SHOP),
					new Value<>(new Color(0x00ff00), PlaceType.SHOPPING_ARCADE_SUPPLIER_DEPOT)
					)){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	SUPPLIER_DEN("Supplier Depot",
			Colour.BASE_CRIMSON,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/dominion/shoppingArcade/supplierDen.png",
			PlaceType.WORLD_MAP_DOMINION,
			PlaceType.SUPPLIER_DEPOT_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.SUPPLIER_DEPOT_CORRIDOR),
					new Value<>(new Color(0xff0000), PlaceType.SUPPLIER_DEPOT_ENTRANCE),
					new Value<>(new Color(0xff00ff), PlaceType.SUPPLIER_DEPOT_STORAGE_ROOM),
					new Value<>(new Color(0x00ff00), PlaceType.SUPPLIER_DEPOT_OFFICE))),

	ENFORCER_HQ("Enforcer HQ",
			Colour.BASE_BLUE,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/dominion/enforcerHQ/enforcerHQ.png",
			PlaceType.WORLD_MAP_DOMINION,
			PlaceType.ENFORCER_HQ_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.ENFORCER_HQ_CORRIDOR),
					new Value<>(new Color(0xb9b9b9), PlaceType.ENFORCER_HQ_CELLS_CORRIDOR),

					new Value<>(new Color(0xff0000), PlaceType.ENFORCER_HQ_ENTRANCE),
					new Value<>(new Color(0x8000ff), PlaceType.ENFORCER_HQ_WAITING_AREA),
					new Value<>(new Color(0x0080ff), PlaceType.ENFORCER_HQ_RECEPTION_DESK),

					new Value<>(new Color(0xffff00), PlaceType.ENFORCER_HQ_GUARDED_DOOR),
					new Value<>(new Color(0xff0080), PlaceType.ENFORCER_HQ_LOCKED_DOOR),

					new Value<>(new Color(0xff8000), PlaceType.ENFORCER_HQ_BRAXS_OFFICE),
					new Value<>(new Color(0x00ffff), PlaceType.ENFORCER_HQ_OFFICE),
					new Value<>(new Color(0xff8080), PlaceType.ENFORCER_HQ_CELLS_OFFICE),
					new Value<>(new Color(0x3b3b3b), PlaceType.ENFORCER_HQ_CELL)
					)),

	ENFORCER_WAREHOUSE("SWORD Warehouse",
			Colour.BASE_BLUE,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/dominion/enforcerWarehouse/enforcerWarehouse.png",
			PlaceType.WORLD_MAP_DOMINION,
			PlaceType.ENFORCER_WAREHOUSE_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0xff0000), PlaceType.ENFORCER_WAREHOUSE_ENTRANCE),
					new Value<>(new Color(0x808080), PlaceType.ENFORCER_WAREHOUSE_CORRIDOR),
					new Value<>(new Color(0xff8080), PlaceType.ENFORCER_WAREHOUSE_CLAIRE_WARNING),

					new Value<>(new Color(0x404040), PlaceType.ENFORCER_WAREHOUSE_ENCLOSURE),
					new Value<>(new Color(0x00ff00), PlaceType.ENFORCER_WAREHOUSE_ENCLOSURE_TELEPORT_PADS),
					new Value<>(new Color(0x00ffff), PlaceType.ENFORCER_WAREHOUSE_ENCLOSURE_TELEPORT_SHELVING),

					new Value<>(new Color(0xff0080), PlaceType.ENFORCER_WAREHOUSE_ENFORCER_GUARD_POST),

					new Value<>(new Color(0xff8000), PlaceType.ENFORCER_WAREHOUSE_CRATES),
					new Value<>(new Color(0xffff00), PlaceType.ENFORCER_WAREHOUSE_CRATES_ARK),
					new Value<>(new Color(0xff00ff), PlaceType.ENFORCER_WAREHOUSE_CRATES_LUST_WEAPON),
					new Value<>(new Color(0x8000ff), PlaceType.ENFORCER_WAREHOUSE_CRATES_SPELL_BOOK)

					)),

	CITY_HALL("City Hall",
			Colour.BASE_PURPLE,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/dominion/cityHall/city_hall.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.CITY_HALL_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.CITY_HALL_CORRIDOR),
					new Value<>(new Color(0xff0000), PlaceType.CITY_HALL_ENTRANCE),
					new Value<>(new Color(0xffff00), PlaceType.CITY_HALL_INFORMATION_DESK),
					new Value<>(new Color(0x8000ff), PlaceType.CITY_HALL_WAITING_AREA),
					new Value<>(new Color(0xff8000), PlaceType.CITY_HALL_OFFICE),
					new Value<>(new Color(0x00ff00), PlaceType.CITY_HALL_STAIRS),
					new Value<>(new Color(0xff0080), PlaceType.CITY_HALL_BUREAU_OF_DEMOGRAPHICS),
					new Value<>(new Color(0xff00ff), PlaceType.CITY_HALL_ARCHIVES),
					new Value<>(new Color(0xffff80), PlaceType.CITY_HALL_BUREAU_OF_PROPERTY_RIGHTS_AND_COMMERCE))),

	ANGELS_KISS_GROUND_FLOOR("Angel's Kiss GF",
			Colour.BASE_MAGENTA,
			1,
			false,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/angelsKiss/angelsKissGroundFloor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.ANGELS_KISS_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.ANGELS_KISS_CORRIDOR),
					new Value<>(new Color(0x00ff00), PlaceType.ANGELS_KISS_ENTRANCE),
					new Value<>(new Color(0xff0000), PlaceType.ANGELS_KISS_STAIRCASE_UP),
					new Value<>(new Color(0x00ffff), PlaceType.ANGELS_KISS_OFFICE),
					new Value<>(new Color(0xff00ff), PlaceType.ANGELS_KISS_BEDROOM))),

	ANGELS_KISS_FIRST_FLOOR("Angel's Kiss 1F",
			Colour.BASE_MAGENTA,
			1,
			false,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/dominion/angelsKiss/angelsKissFirstFloor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.ANGELS_KISS_STAIRCASE_DOWN, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.ANGELS_KISS_CORRIDOR),
					new Value<>(new Color(0xff0000), PlaceType.ANGELS_KISS_STAIRCASE_DOWN),
					new Value<>(new Color(0xff00ff), PlaceType.ANGELS_KISS_BEDROOM),
					new Value<>(new Color(0xffff00), PlaceType.ANGELS_KISS_BEDROOM_BUNNY),
					new Value<>(new Color(0xff8000), PlaceType.ANGELS_KISS_BEDROOM_LOPPY))),

	NIGHTLIFE_CLUB("The Watering Hole",
			Colour.BASE_BLUE,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/dominion/nightLife/wateringHole.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.WATERING_HOLE_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x00ff00), PlaceType.WATERING_HOLE_ENTRANCE),

					new Value<>(new Color(0x808080), PlaceType.WATERING_HOLE_MAIN_AREA),

					new Value<>(new Color(0x0080ff), PlaceType.WATERING_HOLE_SEATING_AREA),
					new Value<>(new Color(0xff00ff), PlaceType.WATERING_HOLE_VIP_AREA),
					new Value<>(new Color(0xff8000), PlaceType.WATERING_HOLE_BAR),
					new Value<>(new Color(0xffff00), PlaceType.WATERING_HOLE_DANCE_FLOOR),
					new Value<>(new Color(0xff0000), PlaceType.WATERING_HOLE_TOILETS)
					)){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	DADDYS_APARTMENT("Daddy's apartment",
			Colour.RACE_DEMON,
			1,
			false,
			TeleportPermissions.NONE,
			"/com/lilithsthrone/res/map/dominion/daddy/apartment.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.DOMINION_DEMON_HOME_DADDY, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x00ff00), PlaceType.DADDY_APARTMENT_ENTRANCE),
					new Value<>(new Color(0xffff00), PlaceType.DADDY_APARTMENT_LOUNGE),
					new Value<>(new Color(0x00ffff), PlaceType.DADDY_APARTMENT_KITCHEN),
					new Value<>(new Color(0xff00ff), PlaceType.DADDY_APARTMENT_BEDROOM)
					)){
		@Override
		public String getName() {
			return UtilText.parse("[daddy.NamePos] apartment");
		}
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	// Other:

	SUBMISSION("Submission",
			Colour.BASE_GREEN,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/submission/submission.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.SUBMISSION_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x808000), PlaceType.SUBMISSION_ENTRANCE),

					new Value<>(new Color(0x808080), PlaceType.SUBMISSION_WALKWAYS),
					new Value<>(new Color(0xc10000), PlaceType.SUBMISSION_TUNNELS),

					new Value<>(new Color(0x008080), PlaceType.SUBMISSION_BAT_CAVERNS),
					new Value<>(new Color(0xff9100), PlaceType.SUBMISSION_RAT_WARREN),
					new Value<>(new Color(0xffff00), PlaceType.SUBMISSION_GAMBLING_DEN),

					new Value<>(new Color(0xff00ff), PlaceType.SUBMISSION_LILIN_PALACE),
					new Value<>(new Color(0x000000), PlaceType.SUBMISSION_LILIN_PALACE_GATE),
					new Value<>(new Color(0x404040), PlaceType.SUBMISSION_LILIN_PALACE_CAVERN),

					new Value<>(new Color(0x004fc9), PlaceType.SUBMISSION_IMP_FORTRESS_ALPHA),
					new Value<>(new Color(0x658cc9), PlaceType.SUBMISSION_IMP_TUNNELS_ALPHA),

					new Value<>(new Color(0x6928c9), PlaceType.SUBMISSION_IMP_FORTRESS_DEMON),
					new Value<>(new Color(0x8d65c9), PlaceType.SUBMISSION_IMP_TUNNELS_DEMON),

					new Value<>(new Color(0xa228c9), PlaceType.SUBMISSION_IMP_FORTRESS_FEMALES),
					new Value<>(new Color(0xb065c9), PlaceType.SUBMISSION_IMP_TUNNELS_FEMALES),

					new Value<>(new Color(0x0096c9), PlaceType.SUBMISSION_IMP_FORTRESS_MALES),
					new Value<>(new Color(0x65b0c9), PlaceType.SUBMISSION_IMP_TUNNELS_MALES)
					)),

	LYSSIETH_PALACE("Lyssieth's Palace",
			Colour.BASE_PURPLE,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/lyssiethsPalace/groundFloor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.LYSSIETH_PALACE_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.LYSSIETH_PALACE_CORRIDOR),
					new Value<>(new Color(0x404040), PlaceType.LYSSIETH_PALACE_WINDOWS),

					new Value<>(new Color(0x00ff00), PlaceType.LYSSIETH_PALACE_ENTRANCE),
					new Value<>(new Color(0xff80ff), PlaceType.LYSSIETH_PALACE_ROOM),
					new Value<>(new Color(0xff8000), PlaceType.LYSSIETH_PALACE_HALL),
					new Value<>(new Color(0x8000ff), PlaceType.LYSSIETH_PALACE_OFFICE),
					new Value<>(new Color(0xff0080), PlaceType.LYSSIETH_PALACE_SIREN_OFFICE),

					new Value<>(new Color(0xff0000), PlaceType.LYSSIETH_PALACE_STAIRS_1),
					new Value<>(new Color(0x0000ff), PlaceType.LYSSIETH_PALACE_STAIRS_2)

					)),

	IMP_FORTRESS_ALPHA("Imp Fortress A",
			Colour.BASE_CRIMSON,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/impFortress/fortress1Map.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.FORTRESS_ALPHA_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.FORTRESS_ALPHA_COURTYARD),
					new Value<>(new Color(0x00ff00), PlaceType.FORTRESS_ALPHA_ENTRANCE),
					new Value<>(new Color(0xff8000), PlaceType.FORTRESS_ALPHA_KEEP))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	IMP_FORTRESS_DEMON("Imp Citadel",
			Colour.BASE_PURPLE,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/impFortress/fortress2Map.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.FORTRESS_DEMON_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.FORTRESS_DEMON_COURTYARD),
					new Value<>(new Color(0x00ff00), PlaceType.FORTRESS_DEMON_ENTRANCE),
					new Value<>(new Color(0x65b0c9), PlaceType.FORTRESS_DEMON_WELL),
					new Value<>(new Color(0xff8000), PlaceType.FORTRESS_DEMON_KEEP),
					new Value<>(new Color(0x8000ff), PlaceType.FORTRESS_DEMON_CELLS),

					new Value<>(new Color(0x80ff00), PlaceType.FORTRESS_LAB),

					new Value<>(new Color(0xff00ff), PlaceType.FORTRESS_DEMON_TREASURY))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	IMP_FORTRESS_FEMALES("Imp Fortress F",
			Colour.BASE_PINK,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/impFortress/fortress3Map.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.FORTRESS_FEMALES_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.FORTRESS_FEMALES_COURTYARD),
					new Value<>(new Color(0x00ff00), PlaceType.FORTRESS_FEMALES_ENTRANCE),
					new Value<>(new Color(0xff8000), PlaceType.FORTRESS_FEMALES_KEEP))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	IMP_FORTRESS_MALES("Imp Fortress M",
			Colour.BASE_BLUE,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/impFortress/fortress4Map.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.FORTRESS_MALES_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.FORTRESS_MALES_COURTYARD),
					new Value<>(new Color(0x00ff00), PlaceType.FORTRESS_MALES_ENTRANCE),
					new Value<>(new Color(0xff8000), PlaceType.FORTRESS_MALES_KEEP))){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	BAT_CAVERNS("Bat Caverns",
			Colour.BASE_BLACK,
			1,
			true,
			TeleportPermissions.BOTH,
			"/com/lilithsthrone/res/map/submission/batCaverns/batCaverns.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.BAT_CAVERN_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x00ff00), PlaceType.BAT_CAVERN_ENTRANCE),

					new Value<>(new Color(0x008080), PlaceType.BAT_CAVERN_DARK),
					new Value<>(new Color(0x808080), PlaceType.BAT_CAVERN_LIGHT),

					new Value<>(new Color(0x0080ff), PlaceType.BAT_CAVERN_RIVER),
					new Value<>(new Color(0x40b4ff), PlaceType.BAT_CAVERN_RIVER_CROSSING),
					new Value<>(new Color(0x004080), PlaceType.BAT_CAVERN_RIVER_END),

					new Value<>(new Color(0xff80ff), PlaceType.BAT_CAVERN_SLIME_QUEEN_LAIR))),

	SLIME_QUEENS_LAIR_GROUND_FLOOR("Slime Queen's Tower GF",
			Colour.BASE_PINK,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/slimeQueensLair/slimeQueensLairGroundFloor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.SLIME_QUEENS_LAIR_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x808080), PlaceType.SLIME_QUEENS_LAIR_CORRIDOR),

					new Value<>(new Color(0x00ff00), PlaceType.SLIME_QUEENS_LAIR_ENTRANCE),
					new Value<>(new Color(0xff0000), PlaceType.SLIME_QUEENS_LAIR_STAIRS_UP),

					new Value<>(new Color(0xff8000), PlaceType.SLIME_QUEENS_LAIR_STORAGE_VATS),
					new Value<>(new Color(0x40b4ff), PlaceType.SLIME_QUEENS_LAIR_ROOM),

					new Value<>(new Color(0xff80ff), PlaceType.SLIME_QUEENS_LAIR_ENTRANCE_GUARDS),

					new Value<>(new Color(0xffff00), PlaceType.SLIME_QUEENS_LAIR_SLIME_QUEEN))),

	SLIME_QUEENS_LAIR_FIRST_FLOOR("Slime Queen's Tower 1F",
			Colour.BASE_PINK,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/slimeQueensLair/slimeQueensLairFirstFloor.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.SLIME_QUEENS_LAIR_STAIRS_DOWN, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),

					new Value<>(new Color(0x808080), PlaceType.SLIME_QUEENS_LAIR_CORRIDOR),

					new Value<>(new Color(0x00ff00), PlaceType.SLIME_QUEENS_LAIR_STAIRS_DOWN),

					new Value<>(new Color(0x40b4ff), PlaceType.SLIME_QUEENS_LAIR_ROOM),

					new Value<>(new Color(0xff00ff), PlaceType.SLIME_QUEENS_LAIR_ROYAL_GUARD),
					new Value<>(new Color(0xffff00), PlaceType.SLIME_QUEENS_LAIR_SLIME_QUEEN))),

	GAMBLING_DEN("Gambling Den",
			Colour.BASE_GOLD,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/gamblingDen/gamblingDen.png",
			PlaceType.WORLD_MAP_DOMINION, PlaceType.GAMBLING_DEN_ENTRANCE, Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.GAMBLING_DEN_CORRIDOR),

					new Value<>(new Color(0x00ff00), PlaceType.GAMBLING_DEN_ENTRANCE),

					new Value<>(new Color(0x4bb1d0), PlaceType.GAMBLING_DEN_OFFICE),

					new Value<>(new Color(0xffff00), PlaceType.GAMBLING_DEN_TRADER),

					new Value<>(new Color(0x0080ff), PlaceType.GAMBLING_DEN_GAMBLING),

					new Value<>(new Color(0xff80ff), PlaceType.GAMBLING_DEN_PREGNANCY),
					new Value<>(new Color(0xff00ff), PlaceType.GAMBLING_DEN_FUTA_PREGNANCY),
					new Value<>(new Color(0xff8000), PlaceType.GAMBLING_DEN_PREGNANCY_ROULETTE)
					)){
		@Override
		public boolean isRevealedOnStart() {
			return true;
		}
	},

	RAT_WARRENS("Rat Warrens",
			Colour.BASE_BROWN,
			1,
			false,
			TeleportPermissions.OUTGOING_ONLY,
			"/com/lilithsthrone/res/map/submission/ratWarrens/ratWarrens.png",
			PlaceType.WORLD_MAP_DOMINION,
			PlaceType.RAT_WARRENS_ENTRANCE,
			Util.newHashMapOfValues(
					new Value<>(new Color(0xFFFFFF), PlaceType.GENERIC_IMPASSABLE),
					new Value<>(new Color(0x808080), PlaceType.RAT_WARRENS_CORRIDOR_LEFT),
					new Value<>(new Color(0xb9b9b9), PlaceType.RAT_WARRENS_CORRIDOR),
					new Value<>(new Color(0x3b3b3b), PlaceType.RAT_WARRENS_CORRIDOR_RIGHT),
					new Value<>(new Color(0x00ff00), PlaceType.RAT_WARRENS_ENTRANCE),

					new Value<>(new Color(0x00ffff), PlaceType.RAT_WARRENS_CHECKPOINT_LEFT),
					new Value<>(new Color(0x80ffff), PlaceType.RAT_WARRENS_CHECKPOINT_RIGHT),

					new Value<>(new Color(0xff8080), PlaceType.RAT_WARRENS_DORMITORY_LEFT),
					new Value<>(new Color(0xff8000), PlaceType.RAT_WARRENS_DORMITORY_RIGHT),

					new Value<>(new Color(0x0000ff), PlaceType.RAT_WARRENS_DICE_DEN),
					new Value<>(new Color(0xffff00), PlaceType.RAT_WARRENS_MILKING_ROOM),
					new Value<>(new Color(0x8000ff), PlaceType.RAT_WARRENS_VENGARS_HALL),
					new Value<>(new Color(0x800080), PlaceType.RAT_WARRENS_VENGARS_BEDROOM)

					)),
	;

	private final String name;
	private final String fileLocation;
	private Colour colour;
	private int worldSize;
	private int timeToTransition;

	private boolean loiteringEnabled;

	private int tileSetRowNumber;
	private int moveCost;
	private AbstractPlaceType standardPlace;
	private AbstractPlaceType cutOffZone;
	private List<AbstractPlaceType> places;
	private List<AbstractPlaceType> dangerousPlaces;

	private TeleportPermissions teleportPermissions;

	private boolean usesFile;
	private AbstractPlaceType globalMapLocation;
	private AbstractPlaceType entryFromGlobalMapLocation;
	private Map<Color, AbstractPlaceType> placesMap;

	// For randomly generating maps:
	WorldType(int worldSize,
			String name,
			Colour colour,
			int timeToTransition,
			boolean loiteringEnabled,
			AbstractPlaceType globalMapLocation,
			AbstractPlaceType entryFromGlobalMapLocation,
			AbstractPlaceType standardPlace,
			AbstractPlaceType cutOffZone,
			List<AbstractPlaceType> places,
			List<AbstractPlaceType> dangerousPlaces) {
		this.worldSize=worldSize;

		this.name = name;
		this.colour = colour;
		this.timeToTransition=timeToTransition;
		this.moveCost = 5;

		this.standardPlace = standardPlace;
		this.cutOffZone = cutOffZone;

		this.globalMapLocation = globalMapLocation;
		this.entryFromGlobalMapLocation = entryFromGlobalMapLocation;

		this.places = places;
		this.dangerousPlaces = dangerousPlaces;

		this.loiteringEnabled = loiteringEnabled;

		fileLocation = null;
		usesFile = false;

		this.teleportPermissions = TeleportPermissions.NONE;
	}

	WorldType(String name,
			Colour colour,
			int timeToTransition,
			boolean loiteringEnabled,
			TeleportPermissions teleportPermissions,
			String fileLocation,
			AbstractPlaceType globalMapLocation,
			AbstractPlaceType entryFromGlobalMapLocation,
			Map<Color, AbstractPlaceType> placesMap) {
		this.name = name;
		this.colour = colour;
		this.timeToTransition=timeToTransition;
		moveCost = 5;

		standardPlace = null;
		cutOffZone = null;

		this.globalMapLocation = globalMapLocation;
		this.entryFromGlobalMapLocation = entryFromGlobalMapLocation;

		places = null;
		dangerousPlaces = null;

		this.loiteringEnabled = loiteringEnabled;

		this.teleportPermissions = teleportPermissions;

		this.fileLocation = fileLocation;
		usesFile = true;
		this.placesMap=placesMap;
	}

	public int getTileSetRowNumber() {
		return tileSetRowNumber;
	}

	public String getName() {
		return name;
	}

	public Colour getColour() {
		return colour;
	}

	public int getTimeToTransition() {
		return timeToTransition;
	}

	public int getMoveCost() {
		return moveCost;
	}

	public boolean isLoiteringEnabled() {
		return loiteringEnabled;
	}

	/**
	 * Reveals all tiles as though the player knows about them, but has not travelled to them. Behaviour may be overridden by isRevealedOnStart().
	 */
	public boolean isDiscoveredOnStart() {
		return false;
	}

	/**
	 * Reveals all tiles as though the player has already travelled to them.
	 */
	public boolean isRevealedOnStart() {
		return false;
	}

	public AbstractPlaceType getStandardPlace() {
		return standardPlace;
	}

	public AbstractPlaceType getCutOffZone() {
		return cutOffZone;
	}

	public List<AbstractPlaceType> getPlaces() {
		return places;
	}

	public List<AbstractPlaceType> getDangerousPlaces() {
		return dangerousPlaces;
	}

	public AbstractPlaceType getGlobalMapLocation() {
		return globalMapLocation;
	}

	public AbstractPlaceType getEntryFromGlobalMapLocation() {
		return entryFromGlobalMapLocation;
	}

	public String getFileLocation() {
		return fileLocation;
	}

	public boolean isUsesFile() {
		return usesFile;
	}

	public Map<Color, AbstractPlaceType> getPlacesMap() {
		return placesMap;
	}

	public int getWorldSize() {
		return worldSize;
	}

	public TeleportPermissions getTeleportPermissions() {
		return teleportPermissions;
	}

}


code:
package com.lilithsthrone.world.places;

import java.io.IOException;
import java.io.InputStream;

import com.lilithsthrone.game.dialogue.DialogueNode;
import com.lilithsthrone.game.dialogue.encounters.Encounter;
import com.lilithsthrone.utils.SvgUtil;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.world.WorldType;

/**
 * @since 0.3.1
 * @version 0.3.1
 * @author Innoxia
 */
public abstract class AbstractGlobalPlaceType extends AbstractPlaceType {

	public AbstractGlobalPlaceType(String name,
			String SVGPath,
			String tooltipDescription,
			String colourString,
			DialogueNode dialogue,
			Encounter encounterType,
			String virginityLossDescription) {
		this(name, tooltipDescription, SVGPath, colourString, null, dialogue, encounterType, virginityLossDescription);
	}

	public AbstractGlobalPlaceType(String name,
			String tooltipDescription,
			String SVGPath,
			String colourString,
			String backgroundColourString,
			DialogueNode dialogue,
			Encounter encounterType,
			String virginityLossDescription) {
		super(name, tooltipDescription, null, null, dialogue, encounterType, virginityLossDescription);

		this.name = name;

		this.colourString = colourString;

		if(backgroundColourString==null) {
			this.backgroundColourString = colourString;
		} else {
			this.backgroundColourString = backgroundColourString;
		}

		this.encounterType = encounterType;
		this.virginityLossDescription = virginityLossDescription;
		this.dialogue = dialogue;

		this.globalMapTile = true;

		if(SVGPath!=null) {
			try {
				InputStream is = this.getClass().getResourceAsStream("/com/lilithsthrone/res/map/" + SVGPath + ".svg");
				if(is==null) {
					System.err.println("Error! PlaceType icon file does not exist (Trying to read from '"+SVGPath+"')! (Code 1)");
				}
				String s = Util.inputStreamToString(is);

				try {
					s = SvgUtil.colourReplacement("placeColour"+colourReplacementId, colourString, s);
					colourReplacementId++;
				} catch(Exception ex) {
					System.err.println(SVGPath+" error!");
				}

				SVGString = s;

				is.close();

			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} else {
			SVGString = null;
		}
	}

	@Override
	public AbstractGlobalPlaceType initDangerous() {
		this.dangerous = true;
		return this;
	}

	@Override
	public AbstractGlobalPlaceType initItemsPersistInTile() {
		this.itemsDisappear = false;
		return this;
	}

	public abstract WorldType getGlobalLinkedWorldType();
}


code:
package com.lilithsthrone.world.places;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.lilithsthrone.game.dialogue.DialogueNode;
import com.lilithsthrone.game.dialogue.encounters.Encounter;
import com.lilithsthrone.game.inventory.CharacterInventory;
import com.lilithsthrone.utils.BaseColour;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.SvgUtil;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.world.Bearing;
import com.lilithsthrone.world.EntranceType;
import com.lilithsthrone.world.TeleportPermissions;
import com.lilithsthrone.world.Weather;
import com.lilithsthrone.world.WorldType;

/**
 * @since 0.3.1
 * @version 0.3.1
 * @author Innoxia
 */
public class AbstractPlaceType {

	protected String name;
	protected String tooltipDescription;
	protected String SVGString;
	protected String colourString;
	protected String backgroundColourString;
	protected BaseColour colour;
	protected Colour backgroundColour;
	protected DialogueNode dialogue;
	protected Encounter encounterType;

	protected boolean globalMapTile;
	protected boolean dangerous;
	protected boolean itemsDisappear;

	protected TeleportPermissions teleportPermissions;

	protected List<Weather> weatherImmunities;
	protected static List<Weather> allWeatherImmunities = new ArrayList<>(Arrays.asList(Weather.values()));

	protected String virginityLossDescription;

	protected static Map<String, String> SVGOverrides = new HashMap<>();

	protected static int colourReplacementId = 0;

	public AbstractPlaceType(String name,
			String tooltipDescription,
			String SVGPath,
			BaseColour colour,
			DialogueNode dialogue,
			Encounter encounterType,
			String virginityLossDescription) {

		this.name = name;
		this.tooltipDescription = tooltipDescription;
		this.colour = colour;
		if(colour != null) {
			this.colourString = colour.toWebHexString();
		}

		this.backgroundColour = Colour.MAP_BACKGROUND;

		this.dialogue = dialogue;
		this.encounterType = encounterType;
		this.weatherImmunities = new ArrayList<>();
		this.virginityLossDescription = virginityLossDescription;

		this.dangerous = false;
		this.itemsDisappear = true;
		this.globalMapTile = false;
		this.teleportPermissions = TeleportPermissions.BOTH;

		if(SVGPath!=null) {
			try {
				InputStream is = this.getClass().getResourceAsStream("/com/lilithsthrone/res/map/" + SVGPath + ".svg");
				if(is==null) {
					System.err.println("Error! PlaceType icon file does not exist (Trying to read from '"+SVGPath+"')! (Code 1)");
				}
				String s = Util.inputStreamToString(is);

				try {
					s = SvgUtil.colourReplacement("placeColour"+colourReplacementId, colour, s);
					colourReplacementId++;
				} catch(Exception ex) {
					System.err.println(SVGPath+" error!");
				}

				SVGString = s;

				is.close();

			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} else {
			SVGString = null;
		}
	}

	public AbstractPlaceType initDangerous() {
		this.dangerous = true;
		if(backgroundColour==Colour.MAP_BACKGROUND) {
			backgroundColour = Colour.MAP_BACKGROUND_DANGEROUS;
		}
		return this;
	}

	public AbstractPlaceType initItemsPersistInTile() {
		this.itemsDisappear = false;
		return this;
	}

	public AbstractPlaceType initMapBackgroundColour(Colour backgroundColour) {
		this.backgroundColour = backgroundColour;
		return this;
	}

	/**
	 * Sets weather immunity to all Weather values.
	 */
	public AbstractPlaceType initWeatherImmune() {
		this.weatherImmunities = allWeatherImmunities;
		return this;
	}

	/**
	 * Define weather immunity for this place.
	 */
	public AbstractPlaceType initWeatherImmune(Weather... weatherImmunities) {
		this.weatherImmunities = new ArrayList<>(Arrays.asList(weatherImmunities));
		return this;
	}

	/**
	 * Define teleport permissions for this tile.
	 * TeleportPermissions are also defined in WorldType, so this will only work in special cases where a world allows teleporting, but not on some tiles (such as Lyssieth's palace in Submission).
	 */
	public AbstractPlaceType initTeleportPermissions(TeleportPermissions teleportPermissions) {
		this.teleportPermissions = teleportPermissions;
		return this;
	}

	public String getName() {
		return name;
	}

	public String getTooltipDescription() {
		return tooltipDescription;
	}

	public String getColourString() {
		if(colour!=null) {
			return colour.toWebHexString();
		} else if(colourString!=null) {
			return colourString;
		}
		return "";
	}

	public Colour getBackgroundColour() throws Exception {
		if(backgroundColourString!=null) { // background colour string is overriding any background set.
			throw new NullPointerException();
		}
		return backgroundColour;
	}

	public String getBackgroundColourString() {
		if(backgroundColourString!=null) {
			return backgroundColourString;
		}
		return backgroundColour.toWebHexString();
	}

	public Encounter getEncounterType() {
		return encounterType;
	}

	public DialogueNode getDialogue(boolean withRandomEncounter) {
		return getDialogue(withRandomEncounter, false);
	}

	public DialogueNode getDialogue(boolean withRandomEncounter, boolean forceEncounter) {
		if (getEncounterType() != null && withRandomEncounter) {
			DialogueNode dn = getEncounterType().getRandomEncounter(forceEncounter);
			if (dn != null) {
				return dn;
			}
		}

		return dialogue;
	}

	public Population getPopulation() {
		return null;
	}

	public boolean isPopulated() {
		return getPopulation()!=null && !getPopulation().getSpecies().isEmpty();
	}

	public boolean isLand() {
		return true;
	}

	public boolean isDangerous() {
		return dangerous;
	}

	public boolean isStormImmune() {
		return weatherImmunities.contains(Weather.MAGIC_STORM);
	}

	public boolean isItemsDisappear() {
		return itemsDisappear;
	}

	protected static String getSVGOverride(String pathName, Colour colour) {
		if(!SVGOverrides.keySet().contains(pathName+colour)) {
			try {
				InputStream is = colour.getClass().getResourceAsStream("/com/lilithsthrone/res/map/" + pathName + ".svg");
				if(is==null) {
					System.err.println("Error! PlaceType icon file does not exist (Trying to read from '"+pathName+"')! (Code 2)");
				}
				String s = Util.inputStreamToString(is);

				try {
					s = SvgUtil.colourReplacement("placeColour"+colourReplacementId, colour, s);
					colourReplacementId++;
				} catch(Exception ex) {
					System.err.println(pathName+" error!");
				}

				SVGOverrides.put(pathName+colour, s);

				is.close();

			} catch (Exception e1) {
				System.err.println("Eeeeeek! PlaceType.getSVGOverride()");
				e1.printStackTrace();
				return "";
			}
		}

		return SVGOverrides.get(pathName+colour);
	}

	public String getSVGString(Set<PlaceUpgrade> upgrades) {
		return SVGString;
	}

	public void applyInventoryInit(CharacterInventory inventory) {

	}

	// For determining where this place should be placed:

	public Bearing getBearing() {
		return null;
	}

	public WorldType getParentWorldType() {
		return null;
	}

	public AbstractPlaceType getParentPlaceType() {
		return null;
	}

	public EntranceType getParentAlignment() {
		return null;
	}

	public String getPlaceNameAppendFormat(int count) {
		return "";
	}

	public boolean isAbleToBeUpgraded() {
		return false;
	}

	public ArrayList<PlaceUpgrade> getStartingPlaceUpgrades() {
		return new ArrayList<>();
	}

	public ArrayList<PlaceUpgrade> getAvailablePlaceUpgrades(Set<PlaceUpgrade> upgrades) {
		return new ArrayList<>();
	}

	public static ArrayList<PlaceUpgrade> getAvailableLilayaRoomPlaceUpgrades(Set<PlaceUpgrade> upgrades) {
		if(upgrades.contains(PlaceUpgrade.LILAYA_GUEST_ROOM)) {
			return PlaceUpgrade.getGuestRoomUpgrades();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_GUEST_ROOM_SUITE)) {
			return PlaceUpgrade.getGuestRoomUpgradesSuite();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM)) {
			return PlaceUpgrade.getSlaveQuartersUpgradesSingle();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM_DOUBLE)) {
			return PlaceUpgrade.getSlaveQuartersUpgradesDouble();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM_QUADRUPLE)) {
			return PlaceUpgrade.getSlaveQuartersUpgradesQuadruple();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_MILKING_ROOM)) {
			return PlaceUpgrade.getMilkingUpgrades();

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_OFFICE)) {
			return PlaceUpgrade.getOfficeUpgrades();
		}

		return PlaceUpgrade.getCoreRoomUpgrades();
	}

	public String getLilayaRoomSVGString(Set<PlaceUpgrade> upgrades) {
		if(upgrades.contains(PlaceUpgrade.LILAYA_GUEST_ROOM)) {
			return getSVGOverride("dominion/lilayasHome/roomGuest", Colour.BASE_GREEN_LIGHT);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_GUEST_ROOM_SUITE)) {
				return getSVGOverride("dominion/lilayasHome/roomGuestSuite", Colour.BASE_GREEN);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM)) {
			return getSVGOverride("dominion/lilayasHome/roomSlave", Colour.BASE_CRIMSON);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_MILKING_ROOM)) {
			return getSVGOverride("dominion/lilayasHome/roomMilking", Colour.BASE_YELLOW_LIGHT);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_OFFICE)) {
			return getSVGOverride("dominion/lilayasHome/roomOffice", Colour.BASE_LILAC);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM_DOUBLE)) {
			return getSVGOverride("dominion/lilayasHome/roomSlaveDouble", Colour.BASE_MAGENTA);

		} else if(upgrades.contains(PlaceUpgrade.LILAYA_SLAVE_ROOM_QUADRUPLE)) {
			return getSVGOverride("dominion/lilayasHome/roomSlaveQuadruple", Colour.BASE_MAGENTA);

		} else {
			return SVGString;
		}
	}

	public String getVirginityLossDescription() {
		return virginityLossDescription;
	}

	public boolean isGlobalMapTile() {
		return globalMapTile;
	}

	/**
	 * TeleportPermissions are also defined in WorldType, so this will only work in special cases where a world allows teleporting, but not on some tiles (such as Lyssieth's palace in Submission).
	 */
	public TeleportPermissions getTeleportPermissions() {
		return teleportPermissions;
	}
}


code:
package com.lilithsthrone.world.places;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.lilithsthrone.game.Game;
import com.lilithsthrone.game.character.CharacterUtils;
import com.lilithsthrone.game.dialogue.DialogueNode;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.XMLSaving;
import com.lilithsthrone.world.Cell;
import com.lilithsthrone.world.EntranceType;

/**
 * @since 0.1.?
 * @version 0.3
 * @author Innoxia
 */
public class GenericPlace implements XMLSaving {

	private String name;
	private AbstractPlaceType placeType;
	private Set<PlaceUpgrade> placeUpgrades;

	public static Map<AbstractPlaceType, Integer> placeCountMap = new HashMap<>();

	public GenericPlace(AbstractPlaceType placeType) {
		this.placeType=placeType;
		placeUpgrades = new HashSet<>();

		if(placeCountMap.containsKey(placeType)) {
			placeCountMap.put(placeType, placeCountMap.get(placeType)+1);
		} else {
			placeCountMap.put(placeType, 1);
		}

		if(placeType!=null) {
			this.name = placeType.getName() + placeType.getPlaceNameAppendFormat(placeCountMap.get(placeType));
			for(PlaceUpgrade pu : placeType.getStartingPlaceUpgrades()) {
				placeUpgrades.add(pu);
			}
		} else {
			this.name = "-";
		}
	}

	@Override
	public Element saveAsXML(Element parentElement, Document doc) {
		Element element = doc.createElement("place");
		parentElement.appendChild(element);

		if(!this.getName().equals(this.getPlaceType().getName())) {
			CharacterUtils.addAttribute(doc, element, "name", this.getName());
		}
		CharacterUtils.addAttribute(doc, element, "type", PlaceType.getIdFromPlaceType(this.getPlaceType()));

		if(!this.getPlaceUpgrades().isEmpty()) {
			Element innerElement = doc.createElement("placeUpgrades");
			element.appendChild(innerElement);
			for(PlaceUpgrade upgrade : this.getPlaceUpgrades()) {
				Element e = doc.createElement("upgrade");
				innerElement.appendChild(e);

				CharacterUtils.addAttribute(doc, e, "type", upgrade.toString());
			}
		}
		return element;
	}

	public static GenericPlace loadFromXML(Element parentElement, Document doc, Cell c) {
		String placeType = parentElement.getAttribute("type");

		if(placeType.equals("ZARANIX_FF_BEDROOM")) {
			placeType = "ZARANIX_FF_OFFICE";

		} else if(placeType.equals("LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR_SLAVE")
				|| placeType.equals("LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR_MILKING")) {
			placeType = "LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR";

		} else if(placeType.equals("LILAYA_HOME_ROOM_GARDEN_GROUND_FLOOR_SLAVE")
				|| placeType.equals("LILAYA_HOME_ROOM_GARDEN_GROUND_FLOOR_MILKING")) {
			placeType = "LILAYA_HOME_ROOM_GARDEN_GROUND_FLOOR";

		} else if(placeType.equals("LILAYA_HOME_ROOM_WINDOW_FIRST_FLOOR_SLAVE")
				|| placeType.equals("LILAYA_HOME_ROOM_WINDOW_FIRST_FLOOR_MILKING")) {
			placeType = "LILAYA_HOME_ROOM_WINDOW_FIRST_FLOOR";

		} else if(placeType.equals("LILAYA_HOME_ROOM_GARDEN_FIRST_FLOOR_SLAVE")
				|| placeType.equals("LILAYA_HOME_ROOM_GARDEN_FIRST_FLOOR_MILKING")) {
			placeType = "LILAYA_HOME_ROOM_GARDEN_FIRST_FLOOR";

		}
		else if(placeType.equals("DOMINION_EXIT_TO_JUNGLE")) {
			placeType = "DOMINION_EXIT_EAST";
		}
		else if(placeType.equals("DOMINION_EXIT_TO_DESERT")) {
			placeType = "DOMINION_EXIT_SOUTH";
		}
		else if(placeType.equals("DOMINION_EXIT_TO_FIELDS")) {
			placeType = "DOMINION_EXIT_NORTH";
		}
		else if(placeType.equals("DOMINION_EXIT_TO_SEA")) {
			placeType = "DOMINION_EXIT_WEST";
		}

		GenericPlace place = new GenericPlace(PlaceType.getPlaceTypeFromId(placeType));
		if(!parentElement.getAttribute("name").isEmpty()
				&& (!Main.isVersionOlderThan(Game.loadingVersion, "0.3")
					|| (!place.getPlaceType().equals(PlaceType.DOMINION_EXIT_NORTH)
						&& !place.getPlaceType().equals(PlaceType.DOMINION_EXIT_SOUTH)
						&& !place.getPlaceType().equals(PlaceType.DOMINION_EXIT_EAST)
						&& !place.getPlaceType().equals(PlaceType.DOMINION_EXIT_WEST)))) {
			place.setName(parentElement.getAttribute("name"));
		}

		try {
			if(parentElement.getElementsByTagName("placeUpgrades").getLength()>0 && ((Element) parentElement.getElementsByTagName("placeUpgrades").item(0)).getElementsByTagName("upgrade").getLength()>0) {
				List<PlaceUpgrade> coreUpgrades = new ArrayList<>();
				List<PlaceUpgrade> upgrades = new ArrayList<>();
				for(int i=0; i<((Element) parentElement.getElementsByTagName("placeUpgrades").item(0)).getElementsByTagName("upgrade").getLength(); i++){
					Element e = (Element) ((Element) parentElement.getElementsByTagName("placeUpgrades").item(0)).getElementsByTagName("upgrade").item(i);
					PlaceUpgrade upgrade = PlaceUpgrade.valueOf(e.getAttribute("type"));

					if(upgrade.isCoreRoomUpgrade()) {
						coreUpgrades.add(upgrade);
					} else {
						upgrades.add(upgrade);
					}
				}

				place.getPlaceUpgrades().clear();

				// Add core upgrades first:
				for(PlaceUpgrade coreUpgrade : coreUpgrades) {
					if(coreUpgrade==PlaceUpgrade.LILAYA_EMPTY_ROOM && coreUpgrades.size()>1) {
						continue;
					}
					if(!place.getPlaceUpgrades().contains(coreUpgrade)) {
						if(!place.addPlaceUpgrade(c, coreUpgrade)) { // This line attempts to add the upgrade
							System.err.println("WARNING: Import of GenericPlace ("+place.getPlaceType()+") was unable to add core upgrade: "+coreUpgrade.getName());
						} else {
							break; // There should only be one core upgrade added.
						}
					}
				}
				for(PlaceUpgrade upgrade : upgrades) {
					if(!place.getPlaceUpgrades().contains(upgrade)) {
						if(!place.addPlaceUpgrade(c, upgrade)) { // This line attempts to add the upgrade
							System.err.println("WARNING: Import of GenericPlace ("+place.getPlaceType()+") was unable to add upgrade: "+upgrade.getName());
						}
					}
				}
			}
		} catch(Exception ex) {
			System.err.println("GenericPlace import error 1");
		}

		return place;
	}

	@Override
	public boolean equals(Object o) {
		if(o instanceof GenericPlace){
			if(((GenericPlace)o).getPlaceType() == placeType
				&& ((GenericPlace)o).getPlaceUpgrades().equals(placeUpgrades)){
					return true;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + placeType.hashCode();
		result = 31 * result + placeUpgrades.hashCode();
		return result;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getColourString() {
		return placeType.getColourString();
	}

	public DialogueNode getDialogue(boolean withRandomEncounter) {
		return getDialogue(withRandomEncounter, false);
	}

	public DialogueNode getDialogue(boolean withRandomEncounter, boolean forceEncounter) {
		return placeType.getDialogue(withRandomEncounter, forceEncounter);
	}

	public boolean isPopulated() {
		return placeType.isPopulated();
	}

	public boolean isDangerous() {
		return placeType.isDangerous();
	}

	public boolean isStormImmune() {
		return placeType.isStormImmune();
	}

	public boolean isItemsDisappear() {
		return placeType.isItemsDisappear();
	}

	public String getSVGString() {
		return placeType.getSVGString(placeUpgrades);
	}

	// For determining where this place should be placed:

	public AbstractPlaceType getParentPlaceType() {
		return placeType.getParentPlaceType();
	}

	public EntranceType getParentAlignment() {
		return placeType.getParentAlignment();
	}

	public boolean addPlaceUpgrade(Cell c, PlaceUpgrade upgrade) {
		if(placeUpgrades.add(upgrade)) {
			upgrade.applyInstallationEffects(c);
			return true;
		} else {
			return false;
		}
	}

	public boolean removePlaceUpgrade(Cell c, PlaceUpgrade upgrade) {
		if(placeUpgrades.remove(upgrade)) {
			upgrade.applyRemovalEffects(c);
			return true;
		} else {
			return false;
		}
	}

	public boolean isAbleToBeUpgraded() {
		return placeType.isAbleToBeUpgraded();
	}

	public Set<PlaceUpgrade> getPlaceUpgrades() {
		return placeUpgrades;
	}

	public boolean isSlaveCell() {
		for(PlaceUpgrade upgrade : placeUpgrades) {
			if(upgrade.isCoreRoomUpgrade() && upgrade.isSlaverUpgrade()) {
				return true;
			}
		}
		return false;
	}

	public int getCapacity() {
		int c = 0;
		for(PlaceUpgrade pu : placeUpgrades) {
			c+=pu.getCapacity();
		}
		return c;
	}

	public int getUpkeep() {
		int upkeep = 0;
		for(PlaceUpgrade pu : placeUpgrades) {
			upkeep+=pu.getUpkeep();
		}
		if(upkeep<0) {
			return 0;
		}
		return upkeep;
	}

	public float getHourlyAffectionChange() {
		float affectionChange = 0;
		for(PlaceUpgrade pu : placeUpgrades) {
			affectionChange+=pu.getHourlyAffectionGain();
		}
		return affectionChange;
	}

	public float getHourlyObedienceChange() {
		float obedienceChange = 0;
		for(PlaceUpgrade pu : placeUpgrades) {
			obedienceChange+=pu.getHourlyObedienceGain();
		}
		return obedienceChange;
	}

	public AbstractPlaceType getPlaceType() {
		return placeType;
	}

	public void setPlaceType(AbstractPlaceType placeType) {
		this.placeType = placeType;
	}

}