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}!")); }
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}!")); }
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()); }
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; } }
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())); } }
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); }
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; } }
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); }