public void AutoArrangeAnimals(IServerSocket serverSocket, AnimalManager animalManager, bool triggerChoice, bool discardExcess, bool isBreeding)
        {
            //Entry room holds 2 of same type
            //Pasture holds 2 of same type
            //Large pasture holds 4 of same time
            //Stable on pasture doubles capacity
            //Stable on meadow holds 1 animal

            //Ore/Ruby mine -> 1 donkey each
            //Stable on forest holds 1 pig
            //Dogs go anywhere... but preferably on meadow/pasture
            //dog(s) on meadow holds dogs+1 sheep OR meadow capacity
            //dog(s) on pasture holder dogs+1 sheep OR pasture capacity

            //other areas exist as 'blocks'
            //dogs can cause these to be variable... there will be P*D combinations, where
            //P = number of meadows/pastures, D = number of dogs
            //maybe just do these if we have excess sheep... which will be allocated last anyway.

            List<AnimalHolder> animalsHolders = new List<AnimalHolder>();

            //add starting tile
            AnimalHolder startingTile = new AnimalHolder();
            startingTile.TileType = TileTypes.StartingTile;
            startingTile.genericCapacity = 2;
            startingTile.position = new Vector2(0f, 0f);
            startingTile.isCave = true;
            animalsHolders.Add(startingTile);

            //add single fenced areas
            List<Vector2> smallFencedAreas = GetMatchingForestTileSpaces(TileTypes.SmallFence);
            foreach (Vector2 smallPasture in smallFencedAreas)
            {
                AnimalHolder pasture = new AnimalHolder();
                pasture.TileType = TileTypes.SmallFence;
                pasture.isCave = false;
                pasture.genericCapacity = 2;
                pasture.position = smallPasture;
                if (StableSpaces[(int)smallPasture.x, (int)smallPasture.y] == TileTypes.Stable)
                    pasture.genericCapacity = pasture.genericCapacity*2;
                animalsHolders.Add(pasture);
            }

            //add double fenced areas
            for(int i=0; i< _doubleFencedPastures.Count; i+=2)
            {
                AnimalHolder pasture = new AnimalHolder();
                pasture.TileType = TileTypes.BigFence1;
                pasture.isCave = false;
                pasture.genericCapacity = 4;
                pasture.position = _doubleFencedPastures[i];
                if (StableSpaces[(int)_doubleFencedPastures[i].x, (int)_doubleFencedPastures[i].y] == TileTypes.Stable)
                    pasture.genericCapacity = pasture.genericCapacity * 2;
                if (StableSpaces[(int)_doubleFencedPastures[i+1].x, (int)_doubleFencedPastures[i+1].y] == TileTypes.Stable)
                    pasture.genericCapacity = pasture.genericCapacity * 2;
                animalsHolders.Add(pasture);
            }

            //add meadows with stables
            List<Vector2> meadows = GetMatchingForestTileSpaces(TileTypes.Clearing);
            foreach (Vector2 meadow in meadows)
            {
                AnimalHolder clearing = new AnimalHolder();
                clearing.TileType = TileTypes.Clearing;
                clearing.isCave = false;
                clearing.genericCapacity = 0;
                clearing.position = meadow;
                if (StableSpaces[(int)meadow.x, (int)meadow.y] == TileTypes.Stable)
                    clearing.genericCapacity = 1;
                animalsHolders.Add(clearing);
            }

            //add forests with stables
            List<Vector2> forestPositions = GetMatchingForestTileSpaces(null);
            foreach (Vector2 position in forestPositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = null;
                holder.isCave = false;
                holder.genericCapacity = 0;
                holder.position = position;
                if (StableSpaces[(int)position.x, (int)position.y] == TileTypes.Stable)
                    holder.pigCapacity = 1;
                animalsHolders.Add(holder);
            }

            //add ore mines
            List<Vector2> oreMinePositions = GetMatchingCaveTileSpaces(TileTypes.OreMine);
            foreach (Vector2 position in oreMinePositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = TileTypes.OreMine;
                holder.isCave = true;
                holder.donkeyCapacity = 1;
                holder.position = position;
                animalsHolders.Add(holder);
            }

            //add ruby mines
            List<Vector2> rubyMinePositions = GetMatchingCaveTileSpaces(TileTypes.RubyMine);
            foreach (Vector2 position in rubyMinePositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = TileTypes.RubyMine;
                holder.isCave = true;
                holder.donkeyCapacity = 1;
                holder.position = position;
                animalsHolders.Add(holder);
            }

            //add special buildings
            List<Vector2> mixedDwellingPositions = GetMatchingCaveTileSpaces(BuildingTypes.MixedDwelling);
            foreach (Vector2 position in mixedDwellingPositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = BuildingTypes.MixedDwelling;
                holder.isCave = true;
                holder.genericCapacity = 2;
                holder.position = position;
                animalsHolders.Add(holder);
            }
            List<Vector2> breakfastRoomPositions = GetMatchingCaveTileSpaces(BuildingTypes.BreakfastRoom);
            foreach (Vector2 position in breakfastRoomPositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = BuildingTypes.BreakfastRoom;
                holder.isCave = true;
                holder.cowCapacity = 3;
                holder.position = position;
                animalsHolders.Add(holder);
            }
            List<Vector2> cuddleRoomPositions = GetMatchingCaveTileSpaces(BuildingTypes.CuddleRoom);
            foreach (Vector2 position in cuddleRoomPositions)
            {
                AnimalHolder holder = new AnimalHolder();
                holder.TileType = BuildingTypes.CuddleRoom;
                holder.isCave = true;
                holder.sheepCapacity = _player.GetDwarfStatus().Count;
                holder.position = position;
                animalsHolders.Add(holder);
            }

            //add whatever the dogs are doing

            int cowsToAllocate = animalManager.Cows;
            int pigsToAllocate = animalManager.Pigs;
            int donkeysToAllocate = animalManager.Donkeys;
            int sheepToAllocate = animalManager.Sheep;
            int dogsToAllocate = animalManager.Dogs;

            //Dogs spread between meadows as evenly as possible
            //sheepWatched = Math.Min(dogs, meadows)*2
            //if dogs > meadows
            //sheepWatched += dogs-meadows
            //e.g, 5 dogs 2 meadows --> 7 sheep
            //---> possible exception for stabled meadow... assign dogs to this last (generic capacity 1)
            //
            //If no meadows, dogs cluster in lowest capacity pasture to maximise extra sheep capacity
            //
            //If no pastures, dogs can live in the home dwelling or near the house or something
            //
            //When filling areas, do not assign sheep/generic areas until after all sheep only areas.
            //Then assign sheep only if there are MORE sheep than generic capacity (ie, extra space will get used)
            //Otherwise, treat as normal

            //ASSIGN DOGS
            if (dogsToAllocate > 0)
            {
                if (animalsHolders.Count(x => x.TileType == TileTypes.Clearing) > 0)
                {
                    List<AnimalHolder> clearings = animalsHolders.Where(x => x.TileType == TileTypes.Clearing).OrderBy(x => x.genericCapacity).ToList();
                    while (dogsToAllocate > 0)
                    {
                        foreach (AnimalHolder clearing in clearings)
                        {
                            clearing.AddDog(ref dogsToAllocate);
                        }
                    }
                }
                else if (animalsHolders.Count(x => x.TileType == TileTypes.SmallFence || x.TileType == TileTypes.BigFence1) > 0)
                {
                    AnimalHolder smallestCapacity = animalsHolders.Where(x => x.TileType == TileTypes.SmallFence || x.TileType == TileTypes.BigFence1).OrderBy(x => x.genericCapacity).First();
                    smallestCapacity.FillAnimals(ResourceTypes.Dogs, ref dogsToAllocate);
                }
                else
                {
                    //put them in the house
                    AnimalHolder tile = animalsHolders.First(x => x.TileType == TileTypes.StartingTile);
                    tile.FillAnimals(ResourceTypes.Dogs, ref dogsToAllocate);
                }
            }

            //FIRST PASS - areas only for specific animals

            while (cowsToAllocate > 0)
            {
                //first find spaces that only hold cows
                List<AnimalHolder> cowHolders = animalsHolders.FindAll(x => x.IsUnfilledCowHolder);
                if (cowHolders.Count > 0)
                {
                    cowHolders[0].FillAnimals(ResourceTypes.Cows, ref cowsToAllocate);
                    continue;
                }

                //nowhere to put them!
                break;
            }

            while (pigsToAllocate > 0)
            {
                //first find spaces that only hold pigs
                List<AnimalHolder> pigHolders = animalsHolders.FindAll(x => x.IsUnfilledPigHolder);
                if (pigHolders.Count > 0)
                {
                    pigHolders[0].FillAnimals(ResourceTypes.Pigs, ref pigsToAllocate);
                    continue;
                }

                //nowhere to put them!
                break;
            }

            while (donkeysToAllocate > 0)
            {
                //first find spaces that only hold donkeys
                List<AnimalHolder> donkeyHolders = animalsHolders.FindAll(x => x.IsUnfilledDonkeyHolder);
                if (donkeyHolders.Count > 0)
                {
                    donkeyHolders[0].FillAnimals(ResourceTypes.Donkeys, ref donkeysToAllocate);
                    continue;
                }

                //nowhere to put them!
                break;
            }

            //When filling areas, do not assign sheep & generic areas until after all sheep only areas.
            //Then assign sheep only if there are MORE sheep than generic capacity (ie, extra space will get used)
            while (sheepToAllocate > 0)
            {
                //first find spaces that ONLY hold sheep
                List<AnimalHolder> sheepHolders = animalsHolders.FindAll(x => x.IsUnfilledSheepHolder && x.genericCapacity ==0);
                if (sheepHolders.Count > 0)
                {
                    sheepHolders[0].FillAnimals(ResourceTypes.Sheep, ref sheepToAllocate);
                    continue;
                }

                //then places that will get more sheep assigned than generic capacity
                sheepHolders = animalsHolders.FindAll(x => x.IsUnfilledSheepHolder && sheepToAllocate > x.genericCapacity);
                if (sheepHolders.Count > 0)
                {
                    sheepHolders[0].FillAnimals(ResourceTypes.Sheep, ref sheepToAllocate);
                    continue;
                }

                //other places get assigned as normal
                break;
            }

            //SECOND PASS - take group with most animals, put in biggest pen. Repeat.
            bool fillMade = true;
            while (fillMade)
            {
                int maxAnimals = new[] {cowsToAllocate, pigsToAllocate, donkeysToAllocate, sheepToAllocate}.Max();
                fillMade = false;

                if (cowsToAllocate > 0 && cowsToAllocate == maxAnimals)
                {
                    //find the space that holds most cows, and put them there
                    List<AnimalHolder> primaryHolders =
                        animalsHolders.FindAll(x => x.RemainingCowCapacity > 0).OrderByDescending(x => x.RemainingCowCapacity)
                        .ToList();
                    if (primaryHolders.Count > 0)
                    {
                        primaryHolders[0].FillAnimals(ResourceTypes.Cows, ref cowsToAllocate);
                        fillMade = true;
                    }
                }
                else if (pigsToAllocate > 0 && pigsToAllocate == maxAnimals)
                {
                    //find the space that holds most cows, and put them there
                    List<AnimalHolder> primaryHolders =
                        animalsHolders.FindAll(x => x.RemainingPigCapacity > 0).OrderByDescending(x => x.RemainingPigCapacity)
                        .ToList();
                    if (primaryHolders.Count > 0)
                    {
                        primaryHolders[0].FillAnimals(ResourceTypes.Pigs, ref pigsToAllocate);
                        fillMade = true;
                    }
                }
                else if (donkeysToAllocate > 0 && donkeysToAllocate == maxAnimals)
                {
                    //find the space that holds most cows, and put them there
                    List<AnimalHolder> primaryHolders =
                        animalsHolders.FindAll(x => x.RemainingDonkeyCapacity > 0).OrderByDescending(x => x.RemainingDonkeyCapacity)
                        .ToList();
                    if (primaryHolders.Count > 0)
                    {
                        primaryHolders[0].FillAnimals(ResourceTypes.Donkeys, ref donkeysToAllocate);
                        fillMade = true;
                    }
                }
                else if (sheepToAllocate > 0 && sheepToAllocate == maxAnimals)
                {
                    //find the space that holds most cows, and put them there
                    List<AnimalHolder> primaryHolders =
                        animalsHolders.FindAll(x => x.RemainingSheepCapacity > 0).OrderByDescending(x => x.RemainingSheepCapacity)
                        .ToList();
                    if (primaryHolders.Count > 0)
                    {
                        primaryHolders[0].FillAnimals(ResourceTypes.Sheep, ref sheepToAllocate);
                        fillMade = true;
                    }
                }
            }

            //now draw it to the screen
            foreach (AnimalHolder holder in animalsHolders)
            {
                serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Dogs, 0);
                serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Sheep, 0);
                serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Donkeys, 0);
                serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Pigs, 0);
                serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Cows, 0);

                if (holder.GetDogs() > 0)
                    serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Dogs, holder.GetDogs());
                if (holder.GetSheep() > 0)
                    serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Sheep, holder.GetSheep());
                if (holder.GetDonkeys() > 0)
                    serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Donkeys, holder.GetDonkeys());
                if (holder.GetPigs() > 0)
                    serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Pigs, holder.GetPigs());
                if (holder.GetCows() > 0)
                    serverSocket.SetTileAnimals(holder.position, holder.isCave, ResourceTypes.Cows, holder.GetCows());
            }

            //did we have leftovers? if so, need to warn the player
            ArrangeAnimalsTriggered = false;
            if (cowsToAllocate + pigsToAllocate + donkeysToAllocate + sheepToAllocate == 0)
                return;

            ArrangeAnimalsTriggered = true;

            if (discardExcess)
            {
                //do not trigger the normal checks with this, use aninal manager to avoid
                animalManager.Cows -= cowsToAllocate;
                animalManager.Pigs -= pigsToAllocate;
                animalManager.Donkeys -= donkeysToAllocate;
                animalManager.Sheep -= sheepToAllocate;
            }

            if (!triggerChoice)
                return;

            string result = "Unassigned animals: ";
            if (cowsToAllocate > 0)
                result += cowsToAllocate + " cows, ";
            if (pigsToAllocate > 0)
                result += pigsToAllocate + " pigs, ";
            if (donkeysToAllocate > 0)
                result += donkeysToAllocate + " donkeys, ";
            if (sheepToAllocate > 0)
                result += sheepToAllocate + " sheep, ";

            List<string> options = new List<string>();
            options.Add(DiscardActions.DiscardAllUnassignedAnimals);

            //are we in the breeding phase?
            if (isBreeding)
            {
                if (animalManager.Cows > 0)
                    options.Add(DiscardActions.DiscardCow);
                if (animalManager.Pigs > 0)
                    options.Add(DiscardActions.DiscardPig);
                if (animalManager.Donkeys > 0)
                    options.Add(DiscardActions.DiscardDonkey);
                if (animalManager.Sheep > 0)
                    options.Add(DiscardActions.DiscardSheep);
            }
            else
            {
                if (HasTile(BuildingTypes.SlaughteringCave))
                {
                    if (animalManager.Cows > 0)
                        options.Add(FoodActions.SlaughteringCaveConvertCow);
                    if (animalManager.Pigs > 0)
                        options.Add(FoodActions.SlaughteringCaveConvertPig);
                    if (animalManager.Donkeys > 1)
                        options.Add(FoodActions.SlaughteringCaveConvertDonkeyPair);
                    if (animalManager.Donkeys > 0)
                        options.Add(FoodActions.SlaughteringCaveConvertDonkey);
                    if (animalManager.Sheep > 0)
                        options.Add(FoodActions.SlaughteringCaveConvertSheep);
                }
                else
                {
                    if (animalManager.Cows > 0)
                        options.Add(FoodActions.ConvertCow);
                    if (animalManager.Pigs > 0)
                        options.Add(FoodActions.ConvertPig);
                    if (animalManager.Donkeys > 1)
                        options.Add(FoodActions.ConvertDonkeyPair);
                    if (animalManager.Donkeys > 0)
                        options.Add(FoodActions.ConvertDonkey);
                    if (animalManager.Sheep > 0)
                        options.Add(FoodActions.ConvertSheep);
                }
            }

            serverSocket.GetPlayerChoice("playerID", "Allocate Animals", result, options);
        }