gt: 			rwidth = SPECIAL_MIN+ran.nextInt(SPECIAL_VAR);
context: /*******************************************************************************
   * Copyright (c) 2013 Philip Collin.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the GNU Public License v3.0
   * which accompanies this distribution, and is available at
   * http://www.gnu.org/licenses/gpl.html
   * 
   * Contributors:
   *     Philip Collin - initial API and implementation
   ******************************************************************************/
  package com.lyeeedar.Roguelike3D.Game.Level;
  
  import java.awt.Color;
  import java.util.ArrayList;
  import java.util.Random;
  
  import com.lyeeedar.Roguelike3D.Game.Level.AbstractTile.TileType;
  import com.lyeeedar.Roguelike3D.Game.Level.DungeonRoom.RoomType;
  import com.lyeeedar.Roguelike3D.Game.Level.DelaunayTriangulation.*;
  import com.lyeeedar.Roguelike3D.Game.Level.XML.BiomeReader;
  import com.lyeeedar.Utils.Bag;
  
  /**
   * Dungeon generation inspired by: http://forums.tigsource.com/index.php?topic=5174.msg799973#msg799973
   * @author Philip
   *
   */
  public class SerkGenerator implements AbstractGenerator{
  	
  	protected static final int NOISE_PERSISTANCE = 3;
  	protected static final int NOISE_OCTAVES = 5;
  	
  	protected static final int ROOM_PLACE_ATTEMPTS = 150;
  	protected final int ROOM_PLACE_PADDING;
  	protected final int START_MIN;
  	protected final int START_VAR;
  	protected final int END_MIN;
  	protected final int END_VAR;
  	protected final int MAIN_MIN;
  	protected final int MAIN_VAR;
  	protected final int SPECIAL_MIN;
  	protected final int SPECIAL_VAR;
  	protected final int OTHER_MIN;
  	protected final int OTHER_VAR;
  
  	final Bag<DungeonRoom> rooms = new Bag<DungeonRoom>();
  	final AbstractTile[][] tiles;
  	final Random ran = new Random();
  	
  	final int width;
  	final int height;
  	
  	final int up;
  	final int down;
  	
  	public SerkGenerator(AbstractTile[][] tiles, BiomeReader biome, int up, int down)
  	{
  		this.tiles = tiles;
  		this.width = tiles.length;
  		this.height = tiles[0].length;
  		
  		this.up = up;
  		this.down = down;
  		
  		ROOM_PLACE_PADDING = biome.getRoomPadding();
  		START_MIN = biome.getRoomSizeMin(RoomType.START);
  		START_VAR = biome.getRoomSizeVar(RoomType.START);
  		END_MIN = biome.getRoomSizeMin(RoomType.END);
  		END_VAR = biome.getRoomSizeVar(RoomType.END);
  		MAIN_MIN = biome.getRoomSizeMin(RoomType.MAIN);
  		MAIN_VAR = biome.getRoomSizeVar(RoomType.MAIN)+1;
  		SPECIAL_MIN = biome.getRoomSizeMin(RoomType.SPECIAL);
  		SPECIAL_VAR = biome.getRoomSizeVar(RoomType.SPECIAL)+1;
  		OTHER_MIN = biome.getRoomSizeMin(RoomType.OTHER);
  		OTHER_VAR = biome.getRoomSizeVar(RoomType.OTHER)+1;
  	}
  	
  	@Override
  	public Bag<DungeonRoom> generate(BiomeReader biome) {
  		
  		setInfluence();
  		
  		int reps = up;
  
  		for (int i = 0; i < reps; i++) while(!placeRoom(RoomType.START)){}
  		
  		reps = down;
  
  		for (int i = 0; i < reps; i++) while(!placeRoom(RoomType.END)){}
  		
  		reps = biome.getRoomNumberMin(RoomType.MAIN)+ran.nextInt(biome.getRoomNumberVar(RoomType.MAIN));
  		for (int i = 0 ; i < reps; i++)
  		{
  			placeRoom(RoomType.MAIN);
  		}
  		
  		reps = biome.getRoomNumberMin(RoomType.SPECIAL)+ran.nextInt(biome.getRoomNumberVar(RoomType.SPECIAL));
  		for (int i = 0 ; i < reps; i++)
  		{
  			placeRoom(RoomType.SPECIAL);
  		}
  		
  		reps = biome.getRoomNumberMin(RoomType.OTHER)+ran.nextInt(biome.getRoomNumberVar(RoomType.OTHER));
  		for (int i = 0 ; i < reps; i++)
  		{
  			placeRoom(RoomType.OTHER);
  		}
  
  		connectRooms();
  		
  		return rooms;
  	}
  	
  	protected void connectRooms()
  	{
  		ArrayList<Pnt> roomPnts = new ArrayList<Pnt>();
  		
  		for (DungeonRoom dr : rooms)
  		{
  			Pnt p = new Pnt(dr.x+(dr.width/2), dr.y+(dr.height/2));
  			roomPnts.add(p);
  		}
  
  		Triangle initialTriangle = new Triangle(
  				new Pnt(-10000, -10000),
  				new Pnt(10000, -10000),
  				new Pnt(0, 10000));
  		Triangulation dt = new Triangulation(initialTriangle);
  		
  		for (Pnt p : roomPnts)
  		{
  			dt.delaunayPlace(p);
  		}
  		
  		ArrayList<Pnt[]> paths = new ArrayList<Pnt[]>();
  		
  		for (Triangle tri : dt)
  		{
  			calculatePaths(paths, tri);
  		}
  
  		for (Pnt[] p : paths)
  		{
  			AStarPathfind pathFind = new AStarPathfind(tiles, (int)p[0].coord(0), (int)p[0].coord(1), (int)p[1].coord(0), (int)p[1].coord(1));
  			carveCorridor(pathFind.getPath());
  		}
  	}
  	
  	protected void carveCorridor(int[][] path)
  	{
  		boolean room = tiles[path[0][0]][path[0][1]].room;
  		if (!room) System.err.println("Error! Room Linking path did not start in a Room!");
  		
  		AbstractTile t = null;
  		AbstractTile lt = null;
  		for (int[] pos : path)
  		{
  			lt = t;
  			t = tiles[pos[0]][pos[1]];
  			if (!room && t.room)
  			{
  				lt.tileType = TileType.DOOR;
  				t.tileType = TileType.FLOOR;
  			}
  			else if (room && !t.room)
  			{
  				t.tileType =TileType.DOOR;
  			}
  			else
  			{
  				t.tileType = TileType.FLOOR;
  			}
  			t.influence = 0;
  			room = t.room;
  		}
  	}
  	
  	protected void calculatePaths(ArrayList<Pnt[]> paths, Triangle triangle)
  	{
  		Pnt[] vertices = triangle.toArray(new Pnt[0]);
  		
  		int ignore = 0;
          double dist = 0;
          
          dist = Math.pow(2, vertices[0].coord(0)-vertices[1].coord(0))+Math.pow(2, vertices[0].coord(1)-vertices[1].coord(1));
          
          double temp = Math.pow(2, vertices[0].coord(0)-vertices[2].coord(0))+Math.pow(2, vertices[0].coord(1)-vertices[2].coord(1));
          if (dist < temp)
          {
          	dist = temp;
          	ignore = 1;		
          }
          
          temp = Math.pow(2, vertices[1].coord(0)-vertices[2].coord(0))+Math.pow(2, vertices[1].coord(1)-vertices[2].coord(1));
          if (dist < temp)
          {
          	dist = temp;
          	ignore = 2;		
          }
          
          if (ignore != 0 && checkIgnored(vertices[0], vertices[1]) && !checkAdded(vertices[0], vertices[1]))
          {
          	addPath(vertices[0], vertices[1], paths);
          }
          else
          {
          	ignorePnts.add(new Pnt[]{vertices[0], vertices[1]});
          }
          if (ignore != 1 && checkIgnored(vertices[0], vertices[2]) && !checkAdded(vertices[0], vertices[2]))
          {
          	addPath(vertices[0], vertices[2], paths);
          }
          else
          {
          	ignorePnts.add(new Pnt[]{vertices[0], vertices[2]});
          }
          if (ignore != 2 && checkIgnored(vertices[1], vertices[2]) && !checkAdded(vertices[1], vertices[2]))
          {
          	addPath(vertices[1], vertices[2], paths);
          }
          else
          {
          	ignorePnts.add(new Pnt[]{vertices[1], vertices[2]});
          }
  	}
  	
      protected void addPath(Pnt p1, Pnt p2, ArrayList<Pnt[]> paths)
      {
      	if (p1.coord(0) < 0 || p2.coord(0) < 0)
      	{
      		ignorePnts.add(new Pnt[]{p1, p2});
      	}
      	else if (p1.coord(1) < 0 || p2.coord(1) < 0)
      	{
      		ignorePnts.add(new Pnt[]{p1, p2});
      	}
      	else if (p1.coord(0) > 1000 || p2.coord(0) > 1000)
      	{
      		ignorePnts.add(new Pnt[]{p1, p2});
      	}
      	else if (p1.coord(1) > 1000 || p2.coord(1) > 1000)
      	{
      		ignorePnts.add(new Pnt[]{p1, p2});
      	}
      	else
      	{
          	addedPnts.add(new Pnt[]{p1, p2});
          	paths.add(new Pnt[]{p1, p2});
      	}
      }
  	
  	ArrayList<Pnt[]> ignorePnts = new ArrayList<Pnt[]>();
  	ArrayList<Pnt[]> addedPnts = new ArrayList<Pnt[]>();
      
      protected boolean checkIgnored(Pnt p1, Pnt p2)
      {
      	for (Pnt[] p : ignorePnts)
      	{
      		if (p[0].equals(p1) && p[1].equals(p2))
      		{
      			return false;
      		}
      		else if (p[0].equals(p2) && p[1].equals(p1))
      		{
      			return false;
      		}
      	}
      	return true;
      }
      
      protected boolean checkAdded(Pnt p1, Pnt p2)
      {
      	for (Pnt[] p : addedPnts)
      	{
      		if (p[0].equals(p1) && p[1].equals(p2))
      		{
      			return true;
      		}
      		else if (p[0].equals(p2) && p[1].equals(p1))
      		{
      			return true;
      		}
      	}
      	return false;
      }
  
  	protected void setInfluence()
  	{
  		PerlinNoise noise = new PerlinNoise();
  		for (int x = 0; x < width; x++)
  		{
  			for (int y = 0; y < height; y++)
  			{
  				tiles[x][y].influence += noise.PerlinNoise_2D(x, y, NOISE_PERSISTANCE, NOISE_OCTAVES)*50;
  			}
  		}
  	}
  	
  	protected boolean placeRoom(RoomType roomType)
  	{
  		int rwidth = 0;
  		int rheight = 0;
  		int px = 0;
  		int py = 0;
  		
  		if (roomType == RoomType.START)
  		{
  			rwidth = START_MIN+ran.nextInt(START_VAR);
  			rheight = START_MIN+ran.nextInt(START_VAR);
  		}
  		else if (roomType == RoomType.END)
  		{
  			rwidth = END_MIN+ran.nextInt(END_VAR);
  			rheight = END_MIN+ran.nextInt(END_VAR);
  		}
  		else if (roomType == RoomType.MAIN)
  		{
  			rwidth = MAIN_MIN+ran.nextInt(MAIN_VAR);
  			rheight = MAIN_MIN+ran.nextInt(MAIN_VAR);
  		}
  		else if (roomType == RoomType.SPECIAL)
  		{
  