Пример #1
0
        public void CheckDestroyed()
        {
            if (DestroyTurn != -1 || !IsDestroyed)
            {
                return;
            }
            if (IsHuman)
            {
                // TODO: Move Game Over code here
                return;
            }

            ICivilization destroyCivilization = Game.CurrentPlayer.Civilization;

            if (destroyCivilization == Civilization)
            {
                destroyCivilization = Game.GetPlayer(0).Civilization;
            }

            GameTask.Insert(Message.Advisor(Advisor.Defense, false, Civilization.Name, "civilization", "destroyed", $"by {destroyCivilization.NamePlural}!"));
        }
Пример #2
0
        private void PlayerDestroyed(object sender, EventArgs args)
        {
            Player player = (sender as Player);

            ICivilization destroyed   = player.Civilization;
            ICivilization destroyedBy = Game.CurrentPlayer.Civilization;

            if (destroyedBy == destroyed)
            {
                destroyedBy = Game.GetPlayer(0).Civilization;
            }

            _replayData.Add(new ReplayData.CivilizationDestroyed(_gameTurn, destroyed.Id, destroyedBy.Id));

            if (player.IsHuman)
            {
                // TODO: Move Game Over code here
                return;
            }

            GameTask.Insert(Message.Advisor(Advisor.Defense, false, destroyed.Name, "civilization", "destroyed", $"by {destroyedBy.NamePlural}!"));
        }
Пример #3
0
        public void Generate(int landMass = 1, int temperature = 1, int climate = 1, int age = 1)
        {
            if (Ready || _tiles != null)
            {
                Log("ERROR: Map is already load{0}/generat{0}", (Ready ? "ed" : "ing"));
                return;
            }

            if (Settings.Instance.CustomMapSize)
            {
                CustomMapSize customMapSize = new CustomMapSize();
                customMapSize.Closed += (s, a) =>
                {
                    Size mapSize = (s as CustomMapSize).MapSize;
                    _width  = mapSize.Width;
                    _height = mapSize.Height;

                    _landMass    = landMass;
                    _temperature = temperature;
                    _climate     = climate;
                    _age         = age;

                    Task.Run(() => GenerateThread());
                };

                GameTask.Insert(Show.Screen(customMapSize));
                return;
            }

            _landMass    = landMass;
            _temperature = temperature;
            _climate     = climate;
            _age         = age;

            Task.Run(() => GenerateThread());
        }
Пример #4
0
        private static void BarbarianMove(IUnit unit)
        {
            switch (unit.Class)
            {
            case UnitClass.Water:
            {
                if (!unit.Tile.Units.Any(x => x.Class == UnitClass.Land))
                {
                    Game.DisbandUnit(unit);
                    return;
                }

                for (int i = 0; i < 1000; i++)
                {
                    if (unit.Tile.GetBorderTiles().Any(x => !x.IsOcean))
                    {
                        if (Game.GetCities().Any(x => x.Owner != 0))
                        {
                            City nearestCity = Game.GetCities().Where(x => x.Owner != 0).OrderBy(x => Common.DistanceToTile(x.X, x.Y, unit.X, unit.Y)).ThenBy(x => x.Player == Human ? 0 : 1).First();
                            if (nearestCity.Player == Human && Human.Visible(unit.Tile))
                            {
                                GameTask.Insert(Message.Advisor(Advisor.Defense, false, "Barbarian raiding party", $"lands near {nearestCity.Name}!", "Citizens are alarmed."));
                            }
                        }

                        foreach (IUnit landUnit in unit.Tile.Units.Where(x => x.Class == UnitClass.Land && x.Sentry))
                        {
                            landUnit.Sentry = false;
                        }
                        unit.SkipTurn();
                        continue;
                    }

                    if (unit.Goto.IsEmpty)
                    {
                        if (!Game.GetCities().Any(x => x.Owner != 0))
                        {
                            Game.DisbandUnit(unit);
                        }

                        City nearestCity = Game.GetCities().Where(x => x.Owner != 0).OrderBy(x => Common.DistanceToTile(x.X, x.Y, unit.X, unit.Y)).First();
                        if (Common.DistanceToTile(unit.X, unit.Y, nearestCity.X, nearestCity.Y) > 10)
                        {
                            Game.DisbandUnit(unit);
                        }
                        unit.Goto = new Point(nearestCity.X, nearestCity.Y);
                        continue;
                    }

                    if (!unit.Goto.IsEmpty)
                    {
                        int     distance = unit.Tile.DistanceTo(unit.Goto);
                        ITile[] tiles    = unit.MoveTargets.OrderBy(x => x.DistanceTo(unit.Goto)).ThenBy(x => x.Movement).ToArray();
                        if (tiles.Length == 0 || tiles[0].DistanceTo(unit.Goto) > distance)
                        {
                            // No valid tile to move to, cancel goto
                            unit.Goto = Point.Empty;
                            continue;
                        }
                        else if (tiles[0].DistanceTo(unit.Goto) == distance)
                        {
                            // Distance is unchanged, 50% chance to cancel goto
                            if (Common.Random.Next(0, 100) < 50)
                            {
                                unit.Goto = Point.Empty;
                                continue;
                            }
                        }

                        if (!unit.MoveTo(tiles[0].X - unit.X, tiles[0].Y - unit.Y))
                        {
                            unit.Goto = Point.Empty;
                            unit.SkipTurn();
                            return;
                        }
                    }

                    unit.SkipTurn();
                    return;
                }
            }
                return;

            case UnitClass.Land:
            {
                ITile[] tiles = unit.Tile.GetBorderTiles().Where(t => !((unit.Tile.IsOcean || unit is Diplomat) && t.City != null) && !t.IsOcean && t.Units.Any(u => u.Owner != 0)).ToArray();
                if (tiles.Length == 0)
                {
                    // No adjecent units found
                    if (Common.Random.Next(10) < 7)
                    {
                        for (int i = 0; i < 1000; i++)
                        {
                            int relX = Common.Random.Next(-1, 2);
                            int relY = Common.Random.Next(-1, 2);
                            if (relX == 0 && relY == 0)
                            {
                                continue;
                            }
                            if (unit.Tile[relX, relY] is Ocean)
                            {
                                continue;
                            }
                            if (unit is Diplomat && unit.Tile[relX, relY].City != null)
                            {
                                continue;
                            }
                            if (unit.Tile.IsOcean && unit.Tile[relX, relY].City != null)
                            {
                                continue;
                            }
                            unit.MoveTo(relX, relY);
                            return;
                        }
                    }
                    Game.DisbandUnit(unit);
                    return;
                }
                else
                {
                    ITile moveTo = tiles[Common.Random.Next(tiles.Length)];
                    int   relX   = moveTo.X - unit.X;
                    int   relY   = moveTo.Y - unit.Y;
                    while (relX < -1)
                    {
                        relX += 80;
                    }
                    while (relX > 1)
                    {
                        relX -= 80;
                    }
                    if (unit is Diplomat && unit.Tile.City != null)
                    {
                        return;
                    }

                    unit.MoveTo(relX, relY);
                }
            }
                return;

            default:
                Game.DisbandUnit(unit);
                return;
            }
        }
Пример #5
0
        public void Disaster()
        {
            List <string> message       = new List <string>();
            bool          humanGetsCity = false;

            if (Player.Cities.Length == 1)
            {
                return;
            }

            if (Size < 5)
            {
                return;
            }

            switch (Common.Random.Next(0, 9))
            {
            case 0:
            {
                // Earthquake
                bool hillsNearby = CityTiles.Any(t => t.Type == Terrain.Hills);
                IList <IBuilding> buildingsOtherThanPalace = Buildings.Where(b => !(b is Palace)).ToList();
                if (!hillsNearby || !buildingsOtherThanPalace.Any())
                {
                    return;
                }

                IBuilding buildingToDestroy = buildingsOtherThanPalace[Common.Random.Next(0, buildingsOtherThanPalace.Count - 1)];
                RemoveBuilding(buildingToDestroy);

                message.Add($"Earthquake in {Name}!");
                message.Add($"{buildingToDestroy} destroyed!");

                break;
            }

            case 1:
            {
                // Plague
                bool hasMedicine     = Player.HasAdvance <Medicine>();
                bool hasAqueduct     = HasBuilding <Aqueduct>();
                bool hasConstruction = Player.Advances.Any(a => a is Construction);

                if (!hasMedicine && !hasAqueduct && hasConstruction)
                {
                    Size = (byte)(Size - Size / 4);

                    message.Add($"Plague in {Name}!");
                    message.Add($"Citizens killed!");
                    message.Add($"Citizens demand AQUEDUCT.");
                }

                break;
            }

            case 2:
            {
                // Flooding
                bool riverNearby  = CityTiles.Any(t => t.Type == Terrain.River);
                bool hasCityWalls = HasBuilding <CityWalls>();
                bool hasMasonry   = Player.HasAdvance <Masonry>();

                if (riverNearby && !hasCityWalls && hasMasonry)
                {
                    Size = (byte)(Size - Size / 4);

                    message.Add($"Flooding in {Name}!");
                    message.Add($"Citizens killed!");
                    message.Add($"Citizens demand CITY WALLS.");
                }
                break;
            }

            case 3:
            {
                // Volcano
                bool mountainNearby      = CityTiles.Any(t => t.Type == Terrain.Mountains);
                bool hasTemple           = HasBuilding <Temple>();
                bool hasCeremonialBurial = Player.HasAdvance <CeremonialBurial>();

                if (mountainNearby && !hasTemple && hasCeremonialBurial)
                {
                    Size = (byte)(Size - Size / 3);

                    message.Add($"Volcano erupts near {Name}!");
                    message.Add($"Citizens killed!");
                    message.Add($"Citizens demand TEMPLE.");
                }

                break;
            }

            case 4:
            {
                // Famine
                bool hasGranary = HasBuilding <Granary>();
                bool hasPottery = Player.HasAdvance <Pottery>();

                if (!hasGranary && hasPottery)
                {
                    Size = (byte)(Size - Size / 3);

                    message.Add($"Famine in {Name}!");
                    message.Add($"Citizens killed!");
                    message.Add($"Citizens demand POTTERY.");
                }

                break;
            }

            case 5:
            {
                // Fire
                IList <IBuilding> buildingsOtherThanPalace = Buildings.Where(b => !(b is Palace)).ToList();
                bool hasAqueduct     = HasBuilding <Aqueduct>();
                bool hasConstruction = Player.HasAdvance <Construction>();

                if (buildingsOtherThanPalace.Any() && !hasAqueduct && hasConstruction)
                {
                    IBuilding buildingToDestroy = buildingsOtherThanPalace[Common.Random.Next(0, buildingsOtherThanPalace.Count - 1)];
                    RemoveBuilding(buildingToDestroy);

                    message.Add($"Fire in {Name}!");
                    message.Add($"{buildingToDestroy.Name} destroyed!");
                    message.Add($"Citizens demand AQUEDUCT.");
                }

                break;
            }

            case 6:
            {
                // Pirates
                bool oceanNearby = CityTiles.Any(t => t.Type == Terrain.Ocean);
                bool hasBarracks = HasBuilding <Barracks>();
                if (oceanNearby && !hasBarracks)
                {
                    Food    = 0;
                    Shields = 0;

                    message.Add($"Pirates plunder {Name}!");
                    message.Add($"Production halted, Food Stolen.!");
                    message.Add($"Citizens demand BARRACKS.");
                }

                break;
            }

            case 7:
            case 8:
            case 9:
                // Riot, scandal, corruption

                string[] disasterTypes    = { "Scandal", "Riot", "Corruption" };
                string   disasterType     = disasterTypes[Common.Random.Next(0, disasterTypes.Length - 1)];
                string   buildingDemanded = "";

                if (HappyCitizens >= UnhappyCitizens)
                {
                    return;
                }

                if (!HasBuilding <Temple>())
                {
                    buildingDemanded = nameof(Temple);
                }
                else if (!HasBuilding <Courthouse>())
                {
                    buildingDemanded = nameof(Courthouse);
                }
                else if (!HasBuilding <MarketPlace>())
                {
                    buildingDemanded = nameof(MarketPlace);
                }
                else if (!HasBuilding <Cathedral>())
                {
                    buildingDemanded = nameof(Cathedral);
                }
                else
                {
                    buildingDemanded = "lower taxes";
                }

                Food    = 0;
                Shields = 0;

                message.Add($"{disasterType} in {Name}");
                message.Add($"Citizens demand {buildingDemanded}");

                if (HasBuilding <Palace>())
                {
                    return;
                }

                if (Player.Cities.Length < 4)
                {
                    return;
                }

                City admired    = null;
                int  mostAppeal = 0;

                foreach (City city in Game.GetCities())
                {
                    if (city == this)
                    {
                        break;
                    }

                    int appeal = ((city.HappyCitizens - city.UnhappyCitizens) * 32) / city.Tile.DistanceTo(this);
                    if (appeal > 4 && appeal > mostAppeal)
                    {
                        admired    = city;
                        mostAppeal = appeal;
                    }
                }

                if (admired != null && admired.Owner != this.Owner)
                {
                    message.Clear();
                    message.Add($"Residents of {Name} admire the prosperity of {admired.Name}");
                    message.Add($"{admired.Name} capture {Name}");

                    Player previousOwner = Game.GetPlayer(this.Owner);

                    Show captureCity = Show.CaptureCity(this);
                    captureCity.Done += (s1, a1) =>
                    {
                        this.Owner = admired.Owner;

                        previousOwner.IsDestroyed();

                        if (Human == admired.Owner)
                        {
                            GameTask.Insert(Tasks.Show.CityManager(this));
                        }
                    };

                    if (Human == admired.Owner)
                    {
                        humanGetsCity = true;
                        GameTask.Insert(captureCity);
                    }
                }

                break;
            }

            if (message.Count > 0 && (Player == Owner || humanGetsCity))
            {
                GameTask.Enqueue(Message.Advisor(Advisor.Domestic, false, message.ToArray()));
            }
        }
Пример #6
0
        public void NewTurn()
        {
            UpdateResources();

            Food += FoodIncome;
            if (Food < 0)
            {
                Food = 0;
                Size--;
                if (Human == Owner)
                {
                    GameTask.Enqueue(Message.Newspaper(this, "Food storage exhausted", $"in {Name}!", "Famine feared."));
                }
                if (Size == 0)
                {
                    return;
                }
            }
            else if (Food > FoodRequired)
            {
                Food -= FoodRequired;

                if (Size == 10 && !_buildings.Any(b => b.Id == (int)Building.Aqueduct))
                {
                    GameTask.Enqueue(Message.Advisor(Advisor.Domestic, false, $"{Name} requires an AQUEDUCT", "for further growth."));
                }
                else
                {
                    Size++;
                }

                if (_buildings.Any(b => (b is Granary)))
                {
                    if (Food < (FoodRequired / 2))
                    {
                        Food = (FoodRequired / 2);
                    }
                }
            }

            if (ShieldIncome < 0)
            {
                int   maxDistance = Units.Max(u => Common.DistanceToTile(X, Y, u.X, u.Y));
                IUnit unit        = Units.Last(u => Common.DistanceToTile(X, Y, u.X, u.Y) == maxDistance);
                if (Human == Owner)
                {
                    Message message = Message.DisbandUnit(this, unit);
                    message.Done += (s, a) => {
                        Game.DisbandUnit(unit);
                    };
                    GameTask.Enqueue(message);
                }
                else
                {
                    Game.DisbandUnit(unit);
                }
            }
            else if (ShieldIncome > 0)
            {
                Shields += ShieldIncome;
            }

            if (Shields >= (int)CurrentProduction.Price * 10)
            {
                if (CurrentProduction is Settlers && Size == 1 && Game.Difficulty == 0)
                {
                    // On Chieftain level, it's not possible to create a Settlers in a city of size 1
                }
                else if (CurrentProduction is IUnit)
                {
                    Shields = 0;
                    IUnit unit = Game.Instance.CreateUnit((CurrentProduction as IUnit).Type, X, Y, Owner);
                    unit.SetHome();
                    unit.Veteran = (_buildings.Any(b => (b is Barracks)));
                    if (CurrentProduction is Settlers)
                    {
                        if (Size == 1 && Player.Cities.Length == 1)
                        {
                            Size++;
                        }
                        if (Size == 1)
                        {
                            unit.SetHome(null);
                        }
                        Size--;
                    }
                    if (Human == Owner && (unit is Settlers || unit is Diplomat || unit is Caravan))
                    {
                        GameTask advisorMessage = Message.Advisor(Advisor.Defense, true, $"{this.Name} builds {unit.Name}.");
                        advisorMessage.Done += (s, a) => GameTask.Insert(Show.CityManager(this));
                        GameTask.Enqueue(advisorMessage);
                    }
                }
                if (CurrentProduction is IBuilding && !_buildings.Any(b => b.Id == (CurrentProduction as IBuilding).Id))
                {
                    Shields = 0;
                    if (CurrentProduction is ISpaceShip)
                    {
                        Message message = Message.Newspaper(this, $"{this.Name} builds", $"{(CurrentProduction as ICivilopedia).Name}.");
                        message.Done += (s, a) => {
                            // TODO: Add space ship component
                            GameTask.Insert(Show.CityManager(this));
                        };
                        GameTask.Enqueue(message);
                    }
                    else if (CurrentProduction is Palace)
                    {
                        foreach (City city in Game.Instance.GetCities().Where(c => c.Owner == Owner))
                        {
                            // Remove palace from all cites.
                            city.RemoveBuilding <Palace>();
                        }
                        if (HasBuilding <Courthouse>())
                        {
                            _buildings.RemoveAll(x => x is Courthouse);
                        }
                        _buildings.Add(CurrentProduction as IBuilding);

                        Message message = Message.Newspaper(this, $"{this.Name} builds", $"{(CurrentProduction as ICivilopedia).Name}.");
                        message.Done += (s, a) => {
                            GameTask advisorMessage = Message.Advisor(Advisor.Foreign, true, $"{Player.TribeName} capital", $"moved to {Name}.");
                            advisorMessage.Done += (s1, a1) => GameTask.Insert(Show.CityManager(this));
                            GameTask.Enqueue(advisorMessage);
                        };
                        GameTask.Enqueue(message);
                    }
                    else
                    {
                        _buildings.Add(CurrentProduction as IBuilding);
                        GameTask.Enqueue(new ImprovementBuilt(this, (CurrentProduction as IBuilding)));
                    }
                }
                if (CurrentProduction is IWonder && !Game.Instance.BuiltWonders.Any(w => w.Id == (CurrentProduction as IWonder).Id))
                {
                    Shields = 0;
                    AddWonder(CurrentProduction as IWonder);
                    GameTask.Enqueue(new ImprovementBuilt(this, (CurrentProduction as IWonder)));
                }
            }

            // TODO: Handle luxuries
            Player.Gold    += Taxes;
            Player.Gold    -= TotalMaintenance;
            Player.Science += Science;
            BuildingSold    = false;
            GameTask.Enqueue(new ProcessScience(Player));

            if (Player == Human)
            {
                return;
            }

            Player.AI.CityProduction(this);
        }
Пример #7
0
        private static void BarbarianMoveWater(IUnit unit)
        {
            if (!unit.Tile.Units.Any(x => x.Class == UnitClass.Land))
            {
                Game.DisbandUnit(unit);
                return;
            }

            for (int i = 0; i < 1000; i++)
            {
                if (unit.Tile.GetBorderTiles().Any(x => !x.IsOcean))
                {
                    if (Game.GetCities().Any(x => x.Owner != 0) && unit.Tile.GetBorderTiles().Any(x => !x.IsOcean && !x.Units.Any(u => u.Owner != 0)))
                    {
                        City nearestCity = Game.GetCities().Where(x => x.Owner != 0).OrderBy(x => Common.DistanceToTile(x.X, x.Y, unit.X, unit.Y)).ThenBy(x => x.Player == Human ? 0 : 1).First();
                        if (nearestCity.Player == Human && Human.Visible(unit.Tile))
                        {
                            GameTask.Insert(Message.Advisor(Advisor.Defense, false, "Barbarian raiding party", $"lands near {nearestCity.Name}!", "Citizens are alarmed."));
                        }
                    }

                    foreach (IUnit landUnit in unit.Tile.Units.Where(x => x.Class == UnitClass.Land && x.Sentry))
                    {
                        landUnit.Sentry = false;
                    }
                    if (unit.Tile.Units.Any(x => x.Class == UnitClass.Land && x.MovesLeft > 0))
                    {
                        Game.UnitWait();
                    }
                    else
                    {
                        unit.SkipTurn();
                    }
                    return;
                }

                if (unit.Goto.IsEmpty)
                {
                    if (!Game.GetCities().Any(x => x.Owner != 0 && x.HasBuilding <Palace>()))
                    {
                        Game.DisbandUnit(unit);
                    }

                    City nearestCity = Game.GetCities().Where(x => x.Owner != 0 && x.HasBuilding <Palace>()).OrderBy(x => Common.DistanceToTile(x.X, x.Y, unit.X, unit.Y)).First();
                    if (Common.DistanceToTile(unit.X, unit.Y, nearestCity.X, nearestCity.Y) > 10)
                    {
                        Game.DisbandUnit(unit);
                    }
                    unit.Goto = new Point(nearestCity.X, nearestCity.Y);
                    continue;
                }

                if (!unit.Goto.IsEmpty)
                {
                    int     distance = unit.Tile.DistanceTo(unit.Goto);
                    ITile[] tiles    = unit.MoveTargets.OrderBy(x => x.DistanceTo(unit.Goto)).ThenBy(x => x.Movement).ToArray();
                    if (tiles.Length == 0 || tiles[0].DistanceTo(unit.Goto) > distance)
                    {
                        // No valid tile to move to, cancel goto
                        unit.Goto = Point.Empty;
                        continue;
                    }
                    else if (tiles[0].DistanceTo(unit.Goto) == distance)
                    {
                        // Distance is unchanged, 50% chance to cancel goto
                        if (Common.Random.Next(0, 100) < 50)
                        {
                            unit.Goto = Point.Empty;
                            continue;
                        }
                    }

                    if (!unit.MoveTo(tiles[0].X - unit.X, tiles[0].Y - unit.Y))
                    {
                        unit.Goto = Point.Empty;
                        unit.SkipTurn();
                    }
                    return;
                }

                unit.SkipTurn();
                return;
            }
        }
Пример #8
0
        public void NewTurn()
        {
            UpdateResources();

            if (IsInDisorder)
            {
                if (Common.Random.Next(20) == 1 && HasBuilding <Buildings.NuclearPlant>() && !Player.HasAdvance <Advances.FusionPower>())
                {
                    // todo: meltdown
                }
                if (WasInDisorder)
                {
                    if (Player == Human)
                    {
                        GameTask.Insert(Message.Advisor(Advisor.Domestic, true, "Civil Disorder in", $"{Name}! Mayor", "flees in panic."));
                    }
                }
                else
                {
                    if (Player == Human)
                    {
                        Show disorderCity = Show.DisorderCity(this);
                        GameTask.Insert(disorderCity);
                    }

                    Log($"City {Name} belonging to {Player.TribeName} has gone into disorder");
                }
                if (WasInDisorder && Player.Government is Advances.Democracy)
                {
                    // todo: Force revolution
                }
                WasInDisorder = true;
            }
            else
            {
                if (WasInDisorder)
                {
                    if (Player == Human)
                    {
                        GameTask.Insert(Message.Advisor(Advisor.Domestic, true, "Order restored", $" in{Name}."));
                    }
                    Log($"City {Name} belonging to {Player.TribeName} is no longer in disorder");
                }
                WasInDisorder = false;
            }
            if (UnhappyCitizens == 0 && HappyCitizens >= ContentCitizens && Size >= 3)
            {
                // we love the president day
                if (Player.Government is Governments.Democracy || Player.Government is Republic)
                {
                    if (Food > 0)
                    {
                        Size++;
                    }
                }
                else
                {
                    // we love the king day
                }
                GameTask.Insert(Show.WeLovePresidentDayCity(this));
            }
            Food += IsInDisorder ? 0 : FoodIncome;

            if (Food < 0)
            {
                Food = 0;
                Size--;
                if (Human == Owner)
                {
                    GameTask.Enqueue(Message.Newspaper(this, "Food storage exhausted", $"in {Name}!", "Famine feared."));
                }
                if (Size == 0)
                {
                    return;
                }
            }
            else if (Food > FoodRequired)
            {
                Food -= FoodRequired;

                if (Size == 10 && !_buildings.Any(b => b.Id == (int)Building.Aqueduct))
                {
                    GameTask.Enqueue(Message.Advisor(Advisor.Domestic, false, $"{Name} requires an AQUEDUCT", "for further growth."));
                }
                else
                {
                    Size++;
                }

                if (_buildings.Any(b => (b is Granary)))
                {
                    if (Food < (FoodRequired / 2))
                    {
                        Food = (FoodRequired / 2);
                    }
                }
            }

            if (ShieldIncome < 0)
            {
                int   maxDistance = Units.Max(u => Common.DistanceToTile(X, Y, u.X, u.Y));
                IUnit unit        = Units.Last(u => Common.DistanceToTile(X, Y, u.X, u.Y) == maxDistance);
                if (Human == Owner)
                {
                    Message message = Message.DisbandUnit(this, unit);
                    message.Done += (s, a) => {
                        Game.DisbandUnit(unit);
                    };
                    GameTask.Enqueue(message);
                }
                else
                {
                    Game.DisbandUnit(unit);
                }
            }
            else if (ShieldIncome > 0)
            {
                Shields += IsInDisorder ? 0 : ShieldIncome;
            }

            if (Shields >= (int)CurrentProduction.Price * 10)
            {
                if (CurrentProduction is Settlers && Size == 1 && Game.Difficulty == 0)
                {
                    // On Chieftain level, it's not possible to create a Settlers in a city of size 1
                }
                else if (CurrentProduction is IUnit)
                {
                    Shields = 0;
                    IUnit unit = Game.Instance.CreateUnit((CurrentProduction as IUnit).Type, X, Y, Owner);
                    unit.SetHome();
                    unit.Veteran = (_buildings.Any(b => (b is Barracks)));
                    if (CurrentProduction is Settlers)
                    {
                        if (Size == 1 && Player.Cities.Length == 1)
                        {
                            Size++;
                        }
                        if (Size == 1)
                        {
                            unit.SetHome(null);
                        }
                        Size--;
                    }
                    if (Human == Owner && (unit is Settlers || unit is Diplomat || unit is Caravan))
                    {
                        GameTask advisorMessage = Message.Advisor(Advisor.Defense, true, $"{this.Name} builds {unit.Name}.");
                        advisorMessage.Done += (s, a) => GameTask.Insert(Show.CityManager(this));
                        GameTask.Enqueue(advisorMessage);
                    }
                }
                if (CurrentProduction is IBuilding && !_buildings.Any(b => b.Id == (CurrentProduction as IBuilding).Id))
                {
                    Shields = 0;
                    if (CurrentProduction is ISpaceShip)
                    {
                        Message message = Message.Newspaper(this, $"{this.Name} builds", $"{(CurrentProduction as ICivilopedia).Name}.");
                        message.Done += (s, a) => {
                            // TODO: Add space ship component
                            GameTask.Insert(Show.CityManager(this));
                        };
                        GameTask.Enqueue(message);
                    }
                    else if (CurrentProduction is Palace)
                    {
                        foreach (City city in Game.Instance.GetCities().Where(c => c.Owner == Owner))
                        {
                            // Remove palace from all cites.
                            city.RemoveBuilding <Palace>();
                        }
                        if (HasBuilding <Courthouse>())
                        {
                            _buildings.RemoveAll(x => x is Courthouse);
                        }
                        _buildings.Add(CurrentProduction as IBuilding);

                        Message message = Message.Newspaper(this, $"{this.Name} builds", $"{(CurrentProduction as ICivilopedia).Name}.");
                        message.Done += (s, a) => {
                            GameTask advisorMessage = Message.Advisor(Advisor.Foreign, true, $"{Player.TribeName} capital", $"moved to {Name}.");
                            advisorMessage.Done += (s1, a1) => GameTask.Insert(Show.CityManager(this));
                            GameTask.Enqueue(advisorMessage);
                        };
                        GameTask.Enqueue(message);
                    }
                    else
                    {
                        _buildings.Add(CurrentProduction as IBuilding);
                        GameTask.Enqueue(new ImprovementBuilt(this, (CurrentProduction as IBuilding)));
                    }
                }
                if (CurrentProduction is IWonder && !Game.Instance.BuiltWonders.Any(w => w.Id == (CurrentProduction as IWonder).Id))
                {
                    Shields = 0;
                    AddWonder(CurrentProduction as IWonder);
                    GameTask.Enqueue(new ImprovementBuilt(this, (CurrentProduction as IWonder)));
                }
            }

            // TODO: Handle luxuries
            Player.Gold    += IsInDisorder ? (short)0 : Taxes;
            Player.Gold    -= TotalMaintenance;
            Player.Science += Science;
            BuildingSold    = false;
            GameTask.Enqueue(new ProcessScience(Player));

            if (Player == Human)
            {
                return;
            }

            Player.AI.CityProduction(this);
        }