public static void build(Region region, int x, int y, Building building)
        {
            switch (building.getBuildingType())
            {
                case BuildingType.BANK:
                    buildByArray(region, x, y, building, bankStruct);
                    break;

                case BuildingType.INN:
                    buildByArray(region, x, y, building, innStruct);
                    building.setLit(false);
                    break;

                case BuildingType.HOUSE:
                    buildByArray(region, x, y, building, houseStruct);
                    break;

                case BuildingType.FOOD_STORE:
                    buildByArray(region, x, y, building, foodStoreStruct);
                    break;

                case BuildingType.TOOL_STORE:
                    buildByArray(region, x, y, building, toolStoreStruct);
                    break;
            }
        }
        public CaveGenerator(int width, int height, String name, double fillPercentage, int smoothness, Quinoa quinoa)
        {
            header = new RegionHeader(name);
            region = new Region(width, height);
            header.setRegion(region);
            entrance = new RegionExit(width / 2, height / 2, 0, 0, "", ExitDecorator.UP_STAIR);
            exit = new RegionExit(width / 2, (height / 2) + 1, 0, 0, "", ExitDecorator.DOWN_STAIR);
            header.getExits().Add(entrance);
            header.getExits().Add(exit);
            region.setLightingModel(LightingModel.CAVE);
            this.quinoa = quinoa;
            this.fillPercentage = fillPercentage;
            this.smoothness = smoothness;

            chambers = new List<Chamber>();

            //fill with solid rock
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    region.setTerrain(x, y, new Terrain());
                    region.getTerrain(x, y).setCode(TerrainCode.ROCK);
                }
            }
        }
                                        248549595, 310686993, 388358742, 485448428, 606810535, 758513168, 948141460, 1185176826, 1481471032, 1851838791}; //times 1.25

        #endregion Fields

        #region Methods

        public static void activate(Monster monster, int x, int y, Region region, Quinoa quinoa)
        {
            if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.HAS_DOOR))
            {
                DoorCode doorCode = (DoorCode)Enum.Parse(typeof(DoorCode), (TerrainManager.getParameter(region.getTerrain(x, y), TerrainParameter.HAS_DOOR)));
                if(doorCode == DoorCode.CLOSED)
                {
                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_DOOR, EnumUtil.EnumName<DoorCode>(DoorCode.OPEN));

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The door opens.");
                    }
                }
                else if(doorCode == DoorCode.OPEN)
                {
                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_DOOR, EnumUtil.EnumName<DoorCode>(DoorCode.CLOSED));

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The door closes.");
                    }
                }
            }
            else if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.HAS_FLOODGATE))
            {
                DoorCode doorCode = (DoorCode)Enum.Parse(typeof(DoorCode), (TerrainManager.getParameter(region.getTerrain(x, y), TerrainParameter.HAS_FLOODGATE)));
                if(doorCode == DoorCode.CLOSED)
                {
                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_FLOODGATE, EnumUtil.EnumName<DoorCode>(DoorCode.OPEN));

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The floodgate opens.");
                    }
                }
                else if(doorCode == DoorCode.OPEN)
                {
                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_FLOODGATE, EnumUtil.EnumName<DoorCode>(DoorCode.CLOSED));

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The floodgate closes.");
                    }
                }
            }
            else
            {
                if(isPlayer(monster))
                {
                    quinoa.getMessageManager().addMessage("Nothing to do there.");
                }
            }
        }
 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 void calculate(Region region)
        {
            width = region.getWidth();
            height = region.getHeight();
            values = new int[width,height];
            calc = new double[width,height];
            lights = new List<Light>();
            lightingModel = region.getLightingModel();

            //Blank out the entire region with base light
            for(int x=0; x < width; x++)
            {
                for(int y=0; y < height; y++)
                {
                    if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.FIRE))
                    {
                        calc[x,y] = ((MAX_LIGHT / 2) * RandomNumber.RandomDouble()) + (MAX_LIGHT / 2);
                        lights.Add(new Light(x,y,calc[x,y]));
                    }
                    else
                    {
                        calc[x,y] = baseLight();
                    }
                }
            }

            //Add lights for appropriate monsters
            calculateMonsterLights();

            //Add lights for appropriate building features
            calculateBuildingFeatureLight();

            //Add lights for items
            calculateItemLights();

            //Propogate light from point sources
            foreach(Light tempLight in lights)
            {
                spreadLight(tempLight.x, tempLight.y, tempLight.intensity, baseLight());
            }

            //Cover buildings if roofs prevent lighting
            calculateBuildingCoverLight();

            //Converate raw values to graded values
            calcToValue();
        }
 public static void addClover(Region region, int cloverCount)
 {
     List<Position> grassTiles = MapGenerator.getTerrainPositions(TerrainCode.GRASS, region, false);
     for(int i=0; i < cloverCount; i++)
     {
         if(grassTiles.Count > 0)
         {
             Position pos = grassTiles[RandomNumber.RandomInteger(grassTiles.Count)];
             Terrain terrain = region.getTerrain(pos.x, pos.y);
             int cloverGrowCount = (int)(RandomNumber.RandomDouble() * (TerrainManager.CLOVER_GROW_COUNT / 4)) + TerrainManager.CLOVER_GROW_COUNT;
             if (!terrain.getParameters().ContainsKey(TerrainParameter.HAS_CLOVER))
             {
                 terrain.getParameters().Add(TerrainParameter.HAS_CLOVER, cloverGrowCount.ToString());
             }
         }
     }
 }
        public ForestGenerator(int width, int height, String name, double treeDensity, Quinoa quinoa)
        {
            header = new RegionHeader(name);
            region = new Region(width, height);
            header.setRegion(region);
            region.setLightingModel(LightingModel.ABOVE_GROUND);
            this.quinoa = quinoa;
            this.treeDensity = treeDensity;

            //fill the forest with grass
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    region.setTerrain(x, y, new Terrain());
                    region.getTerrain(x, y).setCode(TerrainCode.GRASS);
                }
            }
        }
 public static void addTrees(Region region, double treeDensity)
 {
     List<Position> grassTiles = MapGenerator.getTerrainPositions(TerrainCode.GRASS, region, false);
     int treeCount = (int)(grassTiles.Count * treeDensity);
     for(int i=0; i < treeCount; i++)
     {
         if(grassTiles.Count > 0)
         {
             Position pos = grassTiles[RandomNumber.RandomInteger(grassTiles.Count)];
             region.getTerrain(pos.x, pos.y).getParameters().Add(TerrainParameter.HAS_TREE, EnumUtil.EnumName<TreeCode>(TerrainManager.getRandomTree()));
             region.getTerrain(pos.x, pos.y).getParameters().Add(TerrainParameter.DAMAGE, "0");
             grassTiles.Remove(pos);
         }
     }
 }
        public static void step(Terrain terrain, int x, int y, Region region, Quinoa quinoa)
        {
            //moss is destroyed if stepped upon
            if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.HAS_MOSS))
            {
                region.getTerrain(x, y).getParameters().Remove(TerrainParameter.HAS_MOSS);

                if(RandomNumber.RandomDouble() < MOSS_DROP_RATE)
                {
                    Item moss = new Item();
                    moss.itemClass = ItemClass.MOSS;
                    moss.setPosition(x, y);
                    moss.itemState = ItemState.GROUND;
                    region.getItems().Add(moss);
                }
            }
        }
 public static int getMonsterCount(Region region, MonsterCode monsterCode)
 {
     int total = 0;
     foreach(Monster tempMonster in region.getMonsters())
     {
         if(tempMonster.monsterCode == monsterCode)
         {
             total = total + 1;
         }
     }
     return total;
 }
        public static void addGraveyard(int width, int height, int stx, int sty, Region region)
        {
            int treesPlaced = 0;

            region.getTerrain(stx, sty).setCode(TerrainCode.ROCK);
            TerrainManager.removeParameters(region.getTerrain(stx, sty));
            region.getTerrain(stx + width, sty).setCode(TerrainCode.ROCK);
            TerrainManager.removeParameters(region.getTerrain(stx + width, sty));
            region.getTerrain(stx, sty + height).setCode(TerrainCode.ROCK);
            TerrainManager.removeParameters(region.getTerrain(stx, sty + height));
            region.getTerrain(stx + width, sty + height).setCode(TerrainCode.ROCK);
            TerrainManager.removeParameters(region.getTerrain(stx + width, sty + height));

            for(int x=stx; x < stx + width; x++)
            {
                for(int y=sty; y < sty + height; y++)
                {
                    if(x >= 0 && x < region.getWidth()
                    && y >= 0 && y < region.getHeight())
                    {
                        if(x % 2 == 0 && y % 3 == 0)
                        {
                            if(RandomNumber.RandomDouble() < 0.75)
                            {
                                if(RandomNumber.RandomDouble() < 0.01)
                                {
                                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_GRAVE, EnumUtil.EnumName<GraveCode>(GraveCode.SPECIAL));
                                }
                                else
                                {
                                    region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_GRAVE, EnumUtil.EnumName<GraveCode>(GraveCode.NORMAL));
                                }
                            }
                            else
                            {
                                if(region.getTerrain(x, y).getCode() == TerrainCode.GRASS)
                                {
                                    if(RandomNumber.RandomDouble() < 0.25 && treesPlaced < 2)
                                    {
                                        region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_TREE, EnumUtil.EnumName<TreeCode>(TreeCode.APPLE_TREE));
                                        treesPlaced++;
                                    }

                                }
                                else if(region.getTerrain(x, y).getCode() == TerrainCode.STONE_FLOOR)
                                {
                                    if(RandomNumber.RandomDouble() < 0.25 && treesPlaced < 5)
                                    {
                                        region.getTerrain(x, y).getParameters().Add(TerrainParameter.HAS_MOSS, "");
                                        treesPlaced++;
                                    }
                                }
                            }
                        }
                        else
                        {
                            //do nothing
                        }
                    }
                }
            }
        }
        public static void makePath(Region region, bool nExit, bool eExit, bool sExit, bool wExit)
        {
            int pathX = 0;
            int pathY = 0;

            region.getTerrain((int)(region.getWidth() / 2), (int)(region.getHeight() / 2)).setCode(TerrainCode.PATH);
            region.getTerrain((int)(region.getWidth() / 2)-1, (int)(region.getHeight() / 2)).setCode(TerrainCode.PATH);
            region.getTerrain((int)(region.getWidth() / 2)+1, (int)(region.getHeight() / 2)).setCode(TerrainCode.PATH);
            region.getTerrain((int)(region.getWidth() / 2), (int)(region.getHeight() / 2)-1).setCode(TerrainCode.PATH);
            region.getTerrain((int)(region.getWidth() / 2), (int)(region.getHeight() / 2)+1).setCode(TerrainCode.PATH);

            if(nExit)
            {
                pathX = (int)(region.getWidth() / 2);
                for(pathY = 0; pathY < region.getHeight() / 2; pathY++)
                {
                    region.getTerrain(pathX, pathY).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX-1, pathY).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX+1, pathY).setCode(TerrainCode.PATH);
                }
             }

            if(eExit)
            {
                pathY = (int)(region.getWidth() / 2);
                for(pathX = 0; pathX < region.getWidth() / 2; pathX++)
                {
                    region.getTerrain((region.getWidth()/2) + pathX, pathY).setCode(TerrainCode.PATH);
                    region.getTerrain((region.getWidth()/2) + pathX, pathY-1).setCode(TerrainCode.PATH);
                    region.getTerrain((region.getWidth()/2) + pathX, pathY+1).setCode(TerrainCode.PATH);
                }
            }

            if(sExit)
            {
                pathX = (int)(region.getWidth() / 2);
                for(pathY = 0; pathY < region.getHeight() / 2; pathY++)
                {
                    region.getTerrain(pathX, (region.getHeight()/2) + pathY).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX-1, (region.getHeight()/2) + pathY).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX+1, (region.getHeight()/2) + pathY).setCode(TerrainCode.PATH);
                }
             }

            if(wExit)
            {
                pathY = (int)(region.getWidth() / 2);
                for(pathX = 0; pathX < region.getWidth() / 2; pathX++)
                {
                    region.getTerrain(pathX, pathY).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX, pathY-1).setCode(TerrainCode.PATH);
                    region.getTerrain(pathX, pathY+1).setCode(TerrainCode.PATH);
                }
            }
        }
        public static List<Position> getTerrainPositions(TerrainCode code, Region region, bool allowParameters, bool includeEdges)
        {
            int edgeAdjust=0;
            if(!includeEdges)
            {
                edgeAdjust=1;
            }
            List<Position> positions = new List<Position>();
            for(int x=0+edgeAdjust; x < region.getWidth() - (edgeAdjust * 2); x++)
            {
                for(int y=0+edgeAdjust; y < region.getHeight() - (edgeAdjust * 2); y++)
                {
                    if(region.getTerrain(x, y).getCode() == code
                    && ((!allowParameters && region.getTerrain(x, y).getParameters().Count == 0) || allowParameters))
                    {
                        positions.Add(new Position(x,y));
                    }
                }
            }

            return positions;
        }
 public static List<Position> getTerrainPositions(TerrainCode code, Region region, bool allowParameters)
 {
     return MapGenerator.getTerrainPositions(code, region, allowParameters, true);
 }
 public static void addMushroomSpores(Region region, int sporeCount)
 {
     List<Position> grassTiles = MapGenerator.getTerrainPositions(TerrainCode.GRASS, region, false);
     for(int i=0; i < sporeCount; i++)
     {
         if(grassTiles.Count > 0)
         {
             Position pos = grassTiles[RandomNumber.RandomInteger(grassTiles.Count)];
             Terrain terrain = region.getTerrain(pos.x, pos.y);
             MushroomSporeCode msc = EnumUtil.RandomEnumValue<MushroomSporeCode>();
             if(!terrain.getParameters().ContainsKey(TerrainParameter.HAS_MUSHROOM_SPORES))
             {
                 terrain.getParameters().Add(TerrainParameter.HAS_MUSHROOM_SPORES, EnumUtil.EnumName<MushroomSporeCode>(msc));
             }
         }
     }
 }
        public List<Position> findPath(Region region, int maxSearchDistance, Monster mover, int sx, int sy, int tx, int ty)
        {
            //Initialize
                this.region = region;
                nodes = new PathNode[region.getWidth(),region.getHeight()];
                for (int x=0;x<region.getWidth();x++) {
                        for (int y=0;y<region.getHeight();y++) {
                                nodes[x,y] = new PathNode(x,y);
                        }
                }

                // easy first check, if the destination is blocked, we can't get there
                if(!TerrainManager.allowsMonsterToPass(region.getTerrain(tx, ty), mover))
                {
                    return null;
                }

                // initial state for A*. The closed group is empty. Only the starting
                // tile is in the open list and it's cost is zero, i.e. we're already there
                nodes[sx,sy].cost = 0;
                nodes[sx,sy].depth = 0;
                closed.Clear();
                open.clear();
                open.add(nodes[sx,sy]);

                nodes[tx,ty].parent = null;

                // while we haven't found the goal and haven't exceeded our max search depth
                int maxDepth = 0;
                while ((maxDepth < maxSearchDistance) && (open.size() != 0))
                {
                    // pull out the first node in our open list, this is determined to
                    // be the most likely to be the next step based on our heuristic
                    PathNode current = getFirstInOpen();
                    if (current == nodes[tx,ty])
                    {
                            break;
                    }

                    removeFromOpen(current);
                    addToClosed(current);

                    // search through all the neighbours of the current node evaluating
                    // them as next steps
                    for (int x=-1;x<2;x++)
                    {

                        for (int y=-1;y<2;y++)
                        {
                            // not a neighbour, its the current tile
                            if ((x == 0) && (y == 0))
                            {
                                    continue;
                            }

                            // if we're not allowing diaganol movement then only
                            // one of x or y can be set
                            if ((x != 0) && (y != 0))
                            {
                                    continue;
                            }

                            // determine the location of the neighbour and evaluate it
                            int xp = x + current.x;
                            int yp = y + current.y;

                            if (isValidLocation(mover,sx,sy,xp,yp))
                            {
                                    // the cost to get to this node is cost the current plus the movement
                                    // cost to reach this node. Note that the heursitic value is only used
                                    // in the sorted open list
                                    float nextStepCost = current.cost + getMovementCost(mover, current.x, current.y, xp, yp);
                                    PathNode neighbour = nodes[xp,yp];

                                    // if the new cost we've determined for this node is lower than
                                    // it has been previously makes sure the node hasn't been discarded. We've
                                    // determined that there might have been a better path to get to
                                    // this node so it needs to be re-evaluated
                                    if (nextStepCost < neighbour.cost)
                                    {
                                            if (inOpenList(neighbour))
                                            {
                                                    removeFromOpen(neighbour);
                                            }
                                            if (inClosedList(neighbour))
                                            {
                                                    removeFromClosed(neighbour);
                                            }
                                    }

                                    // if the node hasn't already been processed and discarded then
                                    // reset it's cost to our current cost and add it as a next possible
                                    // step (i.e. to the open list)
                                    if (!inOpenList(neighbour) && !(inClosedList(neighbour)))
                                    {
                                            neighbour.cost = nextStepCost;
                                            neighbour.heuristic = getHeuristicCost(mover, xp, yp, tx, ty);
                                            maxDepth = Math.Max(maxDepth, neighbour.setParent(current));
                                            addToOpen(neighbour);
                                    }
                                }
                            }
                        }
            }

            // since we've got an empty open list or we've run out of search
            // there was no path. Just return null
            if (nodes[tx,ty].parent == null)
            {
                return null;
            }

            // At this point we've definitely found a path so we can uses the parent
            // references of the nodes to find out way from the target location back
            // to the start recording the nodes on the way.
            List<Position> path = new List<Position>();
            PathNode target = nodes[tx,ty];
            while (target != nodes[sx,sy])
            {
                Position pos = new Position(target.x, target.y);
                path.Insert(0, pos);
                target = target.parent;
            }
            Position pos2 = new Position(sx, sy);
            path.Insert(0, pos2);

            // thats it, we have our path
            return path;
        }
        public static void buildByArray(Region region, int startX, int startY, Building building, int[,] plan)
        {
            for (int x = 0; x < BuildingManager.getWidth(building.getBuildingType()); x++)
            {
                for (int y = 0; y < BuildingManager.getHeight(building.getBuildingType()); y++)
                {
                    if (x + startX < region.getWidth() && x + startX > 0
                    && y + startY < region.getHeight() && y + startY > 0)
                    {
                        switch (plan[y,x])
                        {
                            case 0:
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_FLOOR);
                                break;

                            case 1:
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_WALL);
                                break;

                            case 9:
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_FLOOR);
                                region.getTerrain(startX + x, startY + y).getParameters().Add(TerrainParameter.HAS_DOOR, Enum.GetName(typeof(DoorCode), DoorCode.CLOSED));
                                building.setDoor(startX + x, startY + y);
                                break;

                            case 8:
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_WALL);
                                region.getTerrain(startX + x, startY + y).getParameters().Add(TerrainParameter.HAS_SIGN, building.getName());
                                break;

                            case 2:
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_FLOOR);
                                Monster newMon = new Monster();
                                switch (building.getBuildingType())
                                {
                                    case BuildingType.BANK:
                                        newMon.monsterCode = MonsterCode.HUMAN;
                                        newMon.role = MonsterRole.BANKER;
                                        break;

                                    case BuildingType.INN:
                                        newMon.monsterCode = MonsterCode.HUMAN;
                                        newMon.role = MonsterRole.NULL;
                                        break;

                                    case BuildingType.FOOD_STORE:
                                        newMon.monsterCode = MonsterCode.HUMAN;
                                        newMon.role = MonsterRole.CHEF;
                                        break;

                                    case BuildingType.TOOL_STORE:
                                        newMon.monsterCode = MonsterCode.HUMAN;
                                        newMon.role = MonsterRole.HANDYMAN;
                                        break;
                                }
                                MonsterActionManager.initialize(newMon);
                                newMon.setPosition(startX + x, startY + y);
                                region.getMonsters().Add(newMon);
                                break;

                            case 3:
                                //Add a bed
                                region.getTerrain(startX + x, startY + y).setCode(TerrainCode.STONE_FLOOR);
                                region.getTerrain(startX + x, startY + y).getParameters().Add(TerrainParameter.HAS_BED, "");
                                break;
                        }
                    }
                }
            }
        }
        public static bool place(Monster monster, Item item, int x, int y, Region region, Quinoa quinoa)
        {
            Terrain terrain = region.getTerrain(x,y);
            switch(item.itemClass)
            {
                case ItemClass.FLOODGATE:
                if(terrain.getCode() == TerrainCode.STREAM_BED)
                {
                    terrain.getParameters().Add(TerrainParameter.HAS_FLOODGATE, EnumUtil.EnumName<DoorCode>(DoorCode.CLOSED));
                    return true;
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("That must be placed in a stream bed.");
                    }
                    return false;
                }

                case ItemClass.BONES:
                if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_GRAVE))
                {
                    GraveCode gc = (GraveCode)Enum.Parse(typeof(GraveCode), TerrainManager.getParameter(terrain, TerrainParameter.HAS_GRAVE));
                    if(gc == GraveCode.BROKEN)
                    {
                        terrain.getParameters().Add(TerrainParameter.HAS_GRAVE, EnumUtil.EnumName<GraveCode>(GraveCode.SPECIAL));
                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("You restore the bones to the grave.");
                        }
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                return false;

                case ItemClass.APPLE:
                if(RandomNumber.RandomDouble() < TerrainManager.APPLE_TREE_FROM_APPLE_CHANCE
                && !TerrainManager.hasParameter(terrain, TerrainParameter.HAS_TREE)
                && !TerrainManager.hasParameter(terrain, TerrainParameter.HAS_SIGN)
                && !TerrainManager.hasParameter(terrain, TerrainParameter.HAS_DOOR)
                && terrain.getCode() == TerrainCode.GRASS)
                {
                    terrain.getParameters().Add(TerrainParameter.HAS_TREE, EnumUtil.EnumName<TreeCode>(TreeCode.APPLE_TREE));

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("An apple tree sprouts!");
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The apple rots...");
                    }
                }
                return true;

                default:
                Item newItem = (Item)item.CopyObject();
                newItem.itemState = ItemState.GROUND;
                newItem.stackSize = 1;
                newItem.refreshID();
                newItem.setPosition(x, y);
                quinoa.getCurrentRegionHeader().getRegion().getItems().Add(newItem);
                return true;
            }
        }
        public static bool setFire(Monster monster, Item item, Region region, int x, int y, Quinoa quinoa)
        {
            if(TerrainManager.flammable(region.getTerrain(x,y), x, y, quinoa))
                {
                    region.getTerrain(x,y).getParameters().Add(TerrainParameter.FIRE, TerrainManager.BASE_FLAME_RATE+"");
                    if(ItemManager.decreaseUse(item))
                    {
                        item.RemoveObject();
                    }

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("Flames burst forth!");
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("That won't catch on fire.");
                    }
                }
                return false;
        }
        public static bool use(Monster monster, Item item, int x, int y, Region region, Quinoa quinoa)
        {
            Terrain terrain = region.getTerrain(x,y);
            switch(item.itemClass)
            {
                case ItemClass.AXE:
                if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.HAS_TREE))
                {
                    TreeCode tc = (TreeCode)Enum.Parse(typeof(TreeCode), TerrainManager.getParameter(region.getTerrain(x, y), TerrainParameter.HAS_TREE));
                    int damage = 0;
                    if(TerrainManager.hasParameter(region.getTerrain(x, y), TerrainParameter.DAMAGE))
                    {
                        damage = Int32.Parse(TerrainManager.getParameter(region.getTerrain(x,y), TerrainParameter.DAMAGE));
                    }
                    damage = damage + 1;

                    if(damage < TerrainManager.maxTreeDamage(tc))
                    {
                        region.getTerrain(x,y).getParameters().Add(TerrainParameter.DAMAGE, damage + "");

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("You chop the " + EnumUtil.EnumName<TreeCode>(tc) + ".");
                        }
                    }
                    else
                    {
                        region.getTerrain(x, y).getParameters().Remove(TerrainParameter.HAS_TREE);
                        region.getTerrain(x, y).getParameters().Remove(TerrainParameter.DAMAGE);
                        Item log = new Item();
                        log.itemClass = ItemClass.LOG;
                        log.itemState = ItemState.GROUND;
                        log.setPosition(x, y);
                        region.getItems().Add(log);

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("The tree falls.");
                        }
                    }
                }
                return false;

                case ItemClass.LANTERN:
                case ItemClass.TORCH:
                return MonsterActionManager.setFire(monster, item, region, x, y, quinoa);

                case ItemClass.ASH:
                //check for mushrooms spores
                if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_MUSHROOM_SPORES))
                {
                    MushroomSporeCode msc = (MushroomSporeCode)Enum.Parse(typeof(MushroomSporeCode), TerrainManager.getParameter(terrain, TerrainParameter.HAS_MUSHROOM_SPORES));

                    if(RandomNumber.RandomDouble() > 0.25)
                    {
                        //Grow a mushroom
                        Item newMushroom = new Item();
                        newMushroom.itemClass = TerrainManager.mushroomSporeToItemClass(msc);
                        ItemManager.initialize(newMushroom);
                        newMushroom.setPosition(x, y);
                        region.getItems().Add(newMushroom);

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("A mushroom sprouts!");
                        }
                    }
                    else
                    {
                        //spread the spore
                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("The spores shimmer..");
                        }
                        quinoa.getActions().spreadSpore(x, y, msc);
                    }

                    //Slight chance to remove the spores
                    if (RandomNumber.RandomDouble() < 0.02)
                    {
                        terrain.getParameters().Remove(TerrainParameter.HAS_MUSHROOM_SPORES);
                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("The spores crumble...");
                        }
                    }

                    return true;
                }

                //check for clover
                if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_CLOVER))
                {
                    int cloverCount = Int32.Parse(TerrainManager.getParameter(terrain, TerrainParameter.HAS_CLOVER));
                    if(cloverCount > 0)
                    {
                        terrain.getParameters().Add(TerrainParameter.HAS_CLOVER, "0");

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("The clover blooms!");
                        }

                        return true;
                    }
                }

                //fertilize existing ground
                switch(terrain.getCode())
                {
                    case TerrainCode.DIRT:
                    terrain.setCode(TerrainCode.FERTILE_LAND);
                    terrain.getParameters().Add(TerrainParameter.GROW_COUNTER, TerrainManager.GRASS_GROW_COUNT+"");
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The ground becomes fertile.");
                    }
                    return true;

                    case TerrainCode.FERTILE_LAND:
                    if(TerrainManager.hasParameter(terrain, TerrainParameter.GROW_COUNTER))
                    {
                        int growCount = Int32.Parse(TerrainManager.getParameter(terrain, TerrainParameter.GROW_COUNTER));
                        growCount = growCount / 2;
                        terrain.getParameters().Add(TerrainParameter.GROW_COUNTER, growCount+"");
                        if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The ground becomes more fertile.");
                    }
                    }
                    return true;

                    default:
                    return false;
                }

                case ItemClass.BUCKET:
                if(terrain.getWater() > 0)
                {
                    int waterLevel = terrain.getWater();
                    if(waterLevel > TerrainManager.DEEP_WATER)
                    {
                        item.itemClass = ItemClass.WATER_BUCKET;
                        terrain.setWater(waterLevel - TerrainManager.DEEP_WATER);
                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("You fill the bucket with water.");
                        }
                    }
                    else
                    {
                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("There's not enough water there.");
                        }
                    }
                }
                return false;

                case ItemClass.WATER_BUCKET:
                int waterValue = ItemManager.WATER_LEVEL_BUCKET_FULL;

                //Turn the item back to a bucket after all uses are gone
                if(ItemManager.decreaseUse(item))
                {
                    item.itemClass = ItemClass.BUCKET;
                }

                //Check for fire extinguishing
                if(TerrainManager.hasParameter(terrain, TerrainParameter.FIRE))
                {
                    terrain.getParameters().Remove(TerrainParameter.FIRE);
                    waterValue = waterValue / 2;

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("The fire is extinguished!");
                    }
                }

                //Add water to the ground
                if(TerrainManager.wetable(terrain, x, y, quinoa))
                {
                    terrain.setWater(terrain.getWater() + waterValue);

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("You splash water around.");
                    }
                }

                return false;

                case ItemClass.SHOVEL:
                if(TerrainManager.diggable(terrain))
                {
                    TerrainManager.dig(terrain, x, y, quinoa);

                    if(isPlayer(monster))
                    {
                        if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_GRAVE))
                        {
                            quinoa.getMessageManager().addMessage("You open the grave.");
                        }
                        else
                        {
                            quinoa.getMessageManager().addMessage("You dig.");
                        }
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("You can't dig there.");
                    }
                }
                return false;

                case ItemClass.PICKAXE:
                if(TerrainManager.mineable(terrain))
                {
                    TerrainManager.mine(terrain, x, y, quinoa);

                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("You mine.");
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("You can't mine there.");
                    }
                }
                return false;

                case ItemClass.CORN_SEED:
                if(terrain.getCode() == TerrainCode.FERTILE_LAND)
                {
                    if(!TerrainManager.hasParameter(terrain, TerrainParameter.HAS_SEED))
                    {
                        terrain.getParameters().Add(TerrainParameter.HAS_SEED, EnumUtil.EnumName<SeedType>(SeedType.CORN));
                        terrain.getParameters().Add(TerrainParameter.GROW_COUNTER,TerrainManager.CORN_GROW_COUNT+"");

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("You sow the corn seed.");
                        }
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("Plant seeds in fertile ground.");
                    }
                }
                return true;

                case ItemClass.PUMPKIN_SEED:
                if(terrain.getCode() == TerrainCode.FERTILE_LAND)
                {
                    if(!TerrainManager.hasParameter(terrain, TerrainParameter.HAS_SEED))
                    {
                        terrain.getParameters().Add(TerrainParameter.HAS_SEED,EnumUtil.EnumName<SeedType>(SeedType.PUMPKIN));
                        terrain.getParameters().Add(TerrainParameter.GROW_COUNTER,TerrainManager.PUMPKIN_GROW_COUNT+"");

                        if(isPlayer(monster))
                        {
                            quinoa.getMessageManager().addMessage("Sow the pumpkin seed.");
                            quinoa.getMessageManager().addMessage("A creeping vine appears.");
                        }
                    }
                }
                else
                {
                    if(isPlayer(monster))
                    {
                        quinoa.getMessageManager().addMessage("Plant seeds in fertile ground.");
                    }
                }
                return true;

                case ItemClass.MOP:
                if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_MOSS))
                {
                    terrain.getParameters().Remove(TerrainParameter.HAS_MOSS);
                }
                if(terrain.getWater() > 0)
                {
                    terrain.setWater(0);
                }
                if(TerrainManager.hasParameter(terrain, TerrainParameter.HAS_MUSHROOM_SPORES))
                {
                    terrain.getParameters().Remove(TerrainParameter.HAS_MUSHROOM_SPORES);
                }
                return false;

                default:
                return false;
            }
        }