public TownGenerator(int width, int height, String name, int wiggle, double radius, double treeDensity, OverworldCell overworldCell, Quinoa quinoa)
 {
     header = new RegionHeader(name);
     region = new Region(width, height);
     header.setRegion(region);
     header.setName(NameMaker.makeTrivialPlaceName());
     this.wiggle = wiggle;
     this.radius = radius;
     this.treeDensity = treeDensity;
     this.quinoa = quinoa;
     this.overworldCell = overworldCell;
 }
        public RegionMap()
        {
            regions = new Dictionary<String, RegionHeader>();
            currentRegionID = "";
            overworldWidth = Quinoa.OVERWORLD_WIDTH;
            overworldHeight = Quinoa.OVERWORLD_HEIGHT;
            overworldCells = new OverworldCell[overworldWidth,overworldHeight];

            for(int x=0; x < overworldWidth; x++)
            {
                for(int y=0; y < overworldHeight; y++)
                {
                    overworldCells[x,y] = new OverworldCell();
                }
            }
        }
 /**
  * @param overworldCells the overworldCells to set
  */
 public void setOverworldCells(OverworldCell[,] overworldCells)
 {
     this.overworldCells = overworldCells;
 }
        public override void generate(Quinoa quinoa)
        {
            //Fill the overworld cell array
            int owWidth = quinoa.getMap().getOverworldWidth();
            int owHeight = quinoa.getMap().getOverworldHeight();
            OverworldCell[,] owc = quinoa.getMap().getOverworldCells();
            for(int x=0; x < owWidth; x++)
            {
                for(int y=0; y < owHeight; y++)
                {
                    owc[x,y] = new OverworldCell();
                }
            }

            //choose a random spot to be town, set as cross
            int townX = owWidth / 2 + ((int)(RandomNumber.RandomDouble() * 3) - 1);
            int townY = owHeight / 2 + ((int)(RandomNumber.RandomDouble() * 3) - 1);
            owc[townX,townY].cellType = CellType.MAIN_TOWN;
            owc[townX,townY].nExit = true;
            owc[townX,townY].eExit = true;
            owc[townX,townY].sExit = true;
            owc[townX,townY].wExit = true;

            //generate paths recursively
            this.addPathBranch(townX-1, townY, owWidth, owHeight, owc, 0, 2, 7);
            this.addPathBranch(townX+1, townY, owWidth, owHeight, owc, 0, 2, 7);
            this.addPathBranch(townX, townY-1, owWidth, owHeight, owc, 0, 2, 7);
            this.addPathBranch(townX, townY+1, owWidth, owHeight, owc, 0, 2, 7);

            //generate regions for each overworld cell
            for(int x=0; x < owWidth; x++)
            {
                for(int y=0; y < owHeight; y++)
                {
                    if(owc[x,y].cellType == CellType.MAIN_TOWN)
                    {
                        TownGenerator townGen = new TownGenerator(100, 100, "main", 3, 0.75, 0.01, owc[x,y], quinoa);
                        townGen.generate();
                        owc[x,y].header = townGen.header;
                        townGen.header.storeRegion(true);
                        this.addCaveBranch(townGen.header, 14, 14, 3 + (int)(RandomNumber.RandomDouble() * 3), quinoa);
                        quinoa.getMap().addRegionHeader(owc[x,y].header);
                    }
                    else if(owc[x,y].cellType == CellType.TOWN)
                    {
                        TownGenerator townGen = new TownGenerator(100, 100, "town" + RandomNumber.RandomUUID().ToString(), 3, 0.75, 0.01, owc[x,y], quinoa);
                        townGen.generate();
                        owc[x,y].header = townGen.header;
                        townGen.header.storeRegion(true);
                        quinoa.getMap().addRegionHeader(owc[x,y].header);
                    }
                    else if(owc[x,y].cellType == CellType.FOREST)
                    {
                        String forestName = "forest" + RandomNumber.RandomUUID().ToString();

                        int depthCount = 0;
                        int depthTotal = 0;
                        if(owc[x,y].nExit)
                        {
                            depthCount++;
                            depthTotal = depthTotal + owc[x,y-1].depth;
                        }
                        if(owc[x,y].eExit)
                        {
                            depthCount++;
                            depthTotal = depthTotal + owc[x + 1,y].depth;
                        }
                        if(owc[x,y].sExit)
                        {
                            depthCount++;
                            depthTotal = depthTotal + owc[x,y+1].depth;
                        }
                        if(owc[x,y].wExit)
                        {
                            depthCount++;
                            depthTotal = depthTotal + owc[x-1,y].depth;
                        }

                        depthTotal = depthTotal + owc[x,y].depth;
                        depthCount = depthCount + 1;

                        double treeDensity = 0.01 + ((depthTotal / depthCount) * 0.02);
                        if(treeDensity > 0.55)
                        {
                            treeDensity = 0.55;
                        }
                        ForestGenerator forGen = new ForestGenerator(100, 100, forestName, treeDensity, quinoa);
                        double waterDensity = 0.15 + (RandomNumber.RandomDouble() * 0.35);
                        if(waterDensity > 0.65)
                        {
                            waterDensity = 0.65;
                        }
                        forGen.addWater(waterDensity, 4);
                        forGen.generate(owc[x,y].nExit, owc[x,y].eExit, owc[x,y].sExit, owc[x,y].wExit);
                        forGen.addSprings();
                        forGen.header.setName("Forest");
                        owc[x,y].header = forGen.header;

                        //add cave branches if only one exit is present
                        int exitCount = 0;
                        if(owc[x,y].nExit) {exitCount++;}
                        if(owc[x,y].eExit) {exitCount++;}
                        if(owc[x,y].sExit) {exitCount++;}
                        if(owc[x,y].wExit) {exitCount++;}
                        if(exitCount == 1 && RandomNumber.RandomDouble() < 0.50)
                        {
                            this.addCaveBranch(owc[x,y].header, owc[x,y].header.getRegion().getWidth() / 2, owc[x,y].header.getRegion().getHeight() / 2, 2 + (int)(RandomNumber.RandomDouble() * (depthTotal / depthCount)), quinoa);
                        }

                        forGen.header.storeRegion(true);
                        quinoa.getMap().addRegionHeader(owc[x,y].header);
                    }
                }
            }

            //connect exits
            for(int x=0; x < owWidth; x++)
            {
                for(int y=0; y < owHeight; y++)
                {
                    if(owc[x,y].header != null)
                    {
                        if(owc[x,y].nExit && y > 0)
                        {
                            this.connectExits(owc[x,y], owc[x,y-1], Direction.N);
                        }
                        if(owc[x,y].sExit && y < owHeight-1)
                        {
                            this.connectExits(owc[x,y], owc[x,y+1], Direction.S);
                        }
                        if(owc[x,y].eExit && x < owWidth-1)
                        {
                            this.connectExits(owc[x,y], owc[x+1,y], Direction.E);
                        }
                        if(owc[x,y].wExit && x > 0)
                        {
                            this.connectExits(owc[x,y], owc[x-1,y], Direction.W);
                        }
                    }
                }
            }

            //place the brother
            this.placeBrother(quinoa);

            this.initializePlayer(quinoa);
        }
        public void connectExits(OverworldCell owc1, OverworldCell owc2, Direction exitDirection)
        {
            int exitX = 0;
            int exitY = 0;
            int dX = 0;
            int dY = 0;

            owc1.header.recallRegion();
            owc2.header.recallRegion();

            switch(exitDirection)
            {
                case Direction.N:
                exitX = (int)(owc1.header.getRegion().getWidth() / 2);
                exitY = 0;
                dX = (int)(owc2.header.getRegion().getWidth() / 2);
                dY = owc2.header.getRegion().getHeight() - 2;
                owc1.header.getExits().Add(new RegionExit(exitX, exitY,dX,dY,owc2.header.getId(), ExitDecorator.NONE));
                break;

                case Direction.E:
                exitX = owc1.header.getRegion().getWidth() - 1;
                exitY = (owc1.header.getRegion().getHeight() / 2);
                dX = 1;
                dY = (owc2.header.getRegion().getHeight() / 2);
                owc1.header.getExits().Add(new RegionExit(exitX, exitY,dX,dY,owc2.header.getId(), ExitDecorator.NONE));
                break;

                case Direction.S:
                exitX = (int)(owc1.header.getRegion().getWidth() / 2);
                exitY = owc1.header.getRegion().getHeight() - 1;
                dX = (int)(owc2.header.getRegion().getWidth() / 2);
                dY = 1;
                owc1.header.getExits().Add(new RegionExit(exitX, exitY,dX,dY,owc2.header.getId(), ExitDecorator.NONE));
                break;

                case Direction.W:
                exitX = 0;
                exitY = (owc1.header.getRegion().getHeight() / 2);
                dX = owc2.header.getRegion().getWidth() - 2;
                dY = (owc2.header.getRegion().getHeight() / 2);
                owc1.header.getExits().Add(new RegionExit(exitX, exitY,dX,dY,owc2.header.getId(), ExitDecorator.NONE));
                break;
            }

            owc1.header.storeRegion(true);
            owc2.header.storeRegion(true);
        }
        public void addPathBranch(int x, int y, int width, int height, OverworldCell[,] owc, int depth, int branchCountdown, int townCounter)
        {
            int townCountdown = townCounter;

            if(owc[x,y].cellType != CellType.NULL)
            {
                return;
            }
            else
            {
                //figure out vital connections
                owc[x,y].cellType = CellType.FOREST;
                owc[x,y].depth = depth;
                if(y > 0 && owc[x,y-1].sExit)
                {
                    owc[x,y].nExit = true;
                }

                if(y < height-1 && owc[x,y+1].nExit)
                {
                    owc[x,y].sExit = true;
                }

                if(x > 0 && owc[x-1,y].eExit)
                {
                    owc[x,y].wExit = true;
                }

                if(x < width-1 && owc[x+1,y].wExit)
                {
                    owc[x,y].eExit = true;
                }

                //randomly try different directions
                //try to lower amount of branching by only allowing up to two exit follows
                int exitCount = 0;
                if(owc[x,y].nExit)
                {
                    exitCount++;
                }
                if(owc[x,y].eExit)
                {
                    exitCount++;
                }
                if(owc[x,y].sExit)
                {
                    exitCount++;
                }
                if(owc[x,y].wExit)
                {
                    exitCount++;
                }

                if(townCountdown == 0)
                {
                    owc[x,y].cellType = CellType.TOWN;
                    townCountdown = 6 + (int)(RandomNumber.RandomDouble() * 3);
                }

                branchCountdown = branchCountdown - 1;
                int branchMax = 2 + (int)(RandomNumber.RandomDouble() * 4);
                if(branchCountdown > 0)
                {
                    if(owc[x,y].nExit && y < height - 1)
                    {
                        owc[x,y].sExit = true;
                        owc[x,y+1].nExit = true;
                        this.addPathBranch(x, y+1, width, height, owc, depth + 1, branchCountdown - 1, townCountdown - 1);
                    }
                    else if(owc[x,y].sExit && y > 0)
                    {
                        owc[x,y].nExit = true;
                        owc[x,y-1].sExit = true;
                        this.addPathBranch(x, y-1, width, height, owc, depth + 1, branchCountdown - 1, townCountdown - 1);
                    }

                    if(owc[x,y].eExit && x > 0)
                    {
                        owc[x,y].wExit = true;
                        owc[x-1,y].eExit = true;
                        this.addPathBranch(x-1, y, width, height, owc, depth + 1, branchCountdown - 1, townCountdown - 1);
                    }
                    else if(owc[x,y].wExit && x < width - 1)
                    {
                        owc[x,y].eExit = true;
                        owc[x+1,y].wExit = true;
                        this.addPathBranch(x+1, y, width, height, owc, depth + 1, branchCountdown - 1, townCountdown - 1);
                    }

                }
                else
                {
                    //branch off in any direction
                    int exitCutoff = 2;
                    double branchChance = 0.35;

                    if(exitCount < exitCutoff && y > 0 && owc[x,y].nExit == false && RandomNumber.RandomDouble() < branchChance)
                    {
                        owc[x,y].nExit = true;
                        owc[x,y-1].sExit = true;
                        this.addPathBranch(x, y-1, width, height, owc, depth + 1, branchMax, townCountdown - 1);
                    }

                    if(exitCount < exitCutoff && y < height-1 && owc[x,y].sExit == false && RandomNumber.RandomDouble() < branchChance)
                    {
                        owc[x,y].sExit = true;
                        owc[x,y+1].nExit = true;
                        this.addPathBranch(x, y+1, width, height, owc, depth + 1, branchMax, townCountdown - 1);
                    }

                    if(exitCount < exitCutoff && x > 0 && owc[x,y].wExit == false && RandomNumber.RandomDouble() < branchChance)
                    {
                        owc[x,y].wExit = true;
                        owc[x - 1,y].eExit = true;
                        this.addPathBranch(x - 1, y, width, height, owc, depth + 1, branchMax, townCountdown - 1);
                    }

                    if(exitCount < exitCutoff && x < width-1 && owc[x,y].eExit == false && RandomNumber.RandomDouble() < branchChance)
                    {
                        owc[x,y].eExit = true;
                        owc[x + 1,y].wExit = true;
                        this.addPathBranch(x + 1, y, width, height, owc, depth + 1, branchMax, townCountdown - 1);
                    }
                }
            }
        }