diff --git a/C7/C7.sln.DotSettings b/C7/C7.sln.DotSettings
new file mode 100644
index 00000000..b8373783
--- /dev/null
+++ b/C7/C7.sln.DotSettings
@@ -0,0 +1,4 @@
+
+ True
+ True
+ True
\ No newline at end of file
diff --git a/C7/Game.cs b/C7/Game.cs
index 3035ecef..12132806 100644
--- a/C7/Game.cs
+++ b/C7/Game.cs
@@ -113,12 +113,12 @@ public override void _Ready() {
// Set initial camera location. If the UI controller has any cities, focus on their capital. Otherwise, focus on their
// starting settler.
- if (controller.cities.Count > 0) {
- City capital = controller.cities.Find(c => c.IsCapital());
+ if (controller.Cities.Count > 0) {
+ City capital = controller.Cities.Find(c => c.IsCapital());
if (capital != null)
mapView.centerCameraOnTile(capital.location);
} else {
- MapUnit startingSettler = controller.units.Find(u => u.unitType.actions.Contains(C7Action.UnitBuildCity));
+ MapUnit startingSettler = controller.Units.Find(u => u.unitType.actions.Contains(C7Action.UnitBuildCity));
if (startingSettler != null)
mapView.centerCameraOnTile(startingSettler.location);
}
@@ -155,7 +155,7 @@ public void processEngineMessages(GameData gameData) {
switch (msg) {
case MsgStartUnitAnimation mSUA:
MapUnit unit = gameData.GetUnit(mSUA.unitID);
- if (unit != null && (controller.tileKnowledge.isTileKnown(unit.location) || controller.tileKnowledge.isTileKnown(unit.previousLocation))) {
+ if (unit != null && (controller.TileKnowledge.isTileKnown(unit.location) || controller.TileKnowledge.isTileKnown(unit.previousLocation))) {
// TODO: This needs to be extended so that the player is shown when AIs found cities, when they move units
// (optionally, depending on preferences) and generalized so that modders can specify whether custom
// animations should be shown to the player.
@@ -173,7 +173,7 @@ public void processEngineMessages(GameData gameData) {
int x, y;
gameData.map.tileIndexToCoords(mSEA.tileIndex, out x, out y);
Tile tile = gameData.map.tileAt(x, y);
- if (tile != Tile.NONE && controller.tileKnowledge.isTileKnown(tile))
+ if (tile != Tile.NONE && controller.TileKnowledge.isTileKnown(tile))
animTracker.startAnimation(tile, mSEA.effect, mSEA.completionEvent, mSEA.ending);
else {
if (mSEA.completionEvent != null)
@@ -193,9 +193,9 @@ public void processEngineMessages(GameData gameData) {
// handling cases like 1 city elimination, regicide, settlers that
// are still alive, etc.
if (mCD.city.owner.RemainingCities() == 0) {
- popupOverlay.ShowPopup(new CivilizationDestroyed(mCD.city.owner.civilization), PopupOverlay.PopupCategory.Advisor);
- for (int i = 0; i < mCD.city.owner.units.Count; ++i) {
- MapUnitExtensions.disband(mCD.city.owner.units[i]);
+ popupOverlay.ShowPopup(new CivilizationDestroyed(mCD.city.owner.Civilization), PopupOverlay.PopupCategory.Advisor);
+ for (int i = 0; i < mCD.city.owner.Units.Count; ++i) {
+ MapUnitExtensions.disband(mCD.city.owner.Units[i]);
}
}
break;
@@ -213,7 +213,7 @@ public void processEngineMessages(GameData gameData) {
// F6 is the science advisor.
// TODO: Move the F* key strings to a set of constants/enum.
EmitSignal(SignalName.ShowSpecificAdvisor, "F6");
- Tech tech = gameData.techs.Find(x => x.id == gameData.GetHumanPlayers()[0].currentlyResearchedTech);
+ Tech tech = gameData.techs.Find(x => x.id == gameData.GetHumanPlayers()[0].CurrentlyResearchedTech);
// TODO: calculate research speed.
EmitSignal(SignalName.UpdateTechProgress, tech.Name, -1);
@@ -287,7 +287,7 @@ public override void _Process(double delta) {
// If "location" is not already near the center of the screen, moves the camera to bring it into view.
public void ensureLocationIsInView(Tile location) {
- if (controller.tileKnowledge.isTileKnown(location) && location != Tile.NONE) {
+ if (controller.TileKnowledge.isTileKnown(location) && location != Tile.NONE) {
Vector2 relativeScreenLocation = mapView.screenLocationOfTile(location, true) / mapView.getVisibleAreaSize();
if (relativeScreenLocation.DistanceTo(new Vector2((float)0.5, (float)0.5)) > 0.30)
mapView.centerCameraOnTile(location);
@@ -342,7 +342,7 @@ private void OnPlayerStartTurn() {
int turnNumber = TurnHandling.GetTurnNumber();
Player player = gameDataAccess.gameData.GetHumanPlayers()[0];
- EmitSignal(SignalName.TurnStarted, turnNumber, player.gold, /*goldPerTurn=*/0);
+ EmitSignal(SignalName.TurnStarted, turnNumber, player.Gold, /*goldPerTurn=*/0);
CurrentState = GameState.PlayerTurn;
GetNextAutoselectedUnit(gameDataAccess.gameData);
@@ -510,12 +510,12 @@ public override void _UnhandledInput(InputEvent @event) {
gameDataAccess.gameData.observerMode = !gameDataAccess.gameData.observerMode;
if (gameDataAccess.gameData.observerMode) {
foreach (Player player in gameDataAccess.gameData.players) {
- player.isHuman = false;
+ player.IsHuman = false;
}
} else {
foreach (Player player in gameDataAccess.gameData.players) {
- if (player.id == EngineStorage.uiControllerID) {
- player.isHuman = true;
+ if (player.Id == EngineStorage.uiControllerID) {
+ player.IsHuman = true;
}
}
}
diff --git a/C7/Map/BorderLayer.cs b/C7/Map/BorderLayer.cs
index b88394fc..3562bc3b 100644
--- a/C7/Map/BorderLayer.cs
+++ b/C7/Map/BorderLayer.cs
@@ -75,7 +75,7 @@ public override void drawObject(LooseView looseView, GameData gameData, Tile til
{ TileDirection.SOUTHEAST, 6 }
};
- Color borderColor = Util.LoadColor(tile.owner.colorIndex);
+ Color borderColor = Util.LoadColor(tile.owner.ColorIndex);
foreach (var entry in directionToTextureIdx) {
if (tile.neighbors[entry.Key].owner != tile.owner) {
diff --git a/C7/Map/CityLabelScene.cs b/C7/Map/CityLabelScene.cs
index 4c3fbae7..8eed6698 100644
--- a/C7/Map/CityLabelScene.cs
+++ b/C7/Map/CityLabelScene.cs
@@ -154,7 +154,7 @@ private Image CreateLabelBackground(int cityLabelWidth, City city, int textAreaW
Image labelImage = Image.Create(cityLabelWidth, CITY_LABEL_HEIGHT, false, Image.Format.Rgba8);
labelImage.Fill(Color.Color8(0, 0, 0, 0));
byte transparencyLevel = 192; //25%
- Color civColor = Util.LoadColor(city.owner.colorIndex);
+ Color civColor = Util.LoadColor(city.owner.ColorIndex);
civColor = new Color(civColor, transparencyLevel);
Color civColorDarker = Color.Color8(0, 0, 138, transparencyLevel); //todo: automate the darker() function. maybe less transparency?
Color topRowGrey = Color.Color8(32, 32, 32, transparencyLevel);
diff --git a/C7/Map/FogOfWarLayer.cs b/C7/Map/FogOfWarLayer.cs
index eb88eab9..bcf7816a 100644
--- a/C7/Map/FogOfWarLayer.cs
+++ b/C7/Map/FogOfWarLayer.cs
@@ -16,7 +16,7 @@ public FogOfWarLayer() {
public override void drawObject(LooseView looseView, GameData gameData, Tile tile, Vector2 tileCenter) {
Rect2 screenTarget = new Rect2(tileCenter - tileSize / 2, tileSize);
- TileKnowledge tileKnowledge = gameData.GetHumanPlayers()[0].tileKnowledge;
+ TileKnowledge tileKnowledge = gameData.GetHumanPlayers()[0].TileKnowledge;
//N.B. FogOfWar.pcx handles both totally unknown and fogged tiles, indexed in the same file.
//Hence the trinary math rather than the more commonplace binary.
if (!tileKnowledge.isTileKnown(tile)) {
diff --git a/C7/Map/UnitLayer.cs b/C7/Map/UnitLayer.cs
index 1a45fa9e..53160570 100644
--- a/C7/Map/UnitLayer.cs
+++ b/C7/Map/UnitLayer.cs
@@ -149,7 +149,7 @@ public void drawUnitAnimFrame(LooseView looseView, MapUnit unit, MapUnit.Appeara
Vector2 position = tileCenter + animOffset - new Vector2(0, inst.FrameSize(animName).Y / 4);
inst.SetPosition(position);
- Color civColor = Util.LoadColor(unit.owner.colorIndex);
+ Color civColor = Util.LoadColor(unit.owner.ColorIndex);
int nextFrame = inst.GetNextFrameByProgress(animName, appearance.progress);
inst.material.SetShaderParameter("tintColor", new Vector3(civColor.R, civColor.G, civColor.B));
diff --git a/C7/MapView.cs b/C7/MapView.cs
index 7cd29b72..1c0a9bfb 100644
--- a/C7/MapView.cs
+++ b/C7/MapView.cs
@@ -517,7 +517,7 @@ private static bool IsTileKnown(Tile tile, UIGameDataAccess gameDataAccess) {
if (gameDataAccess.gameData.observerMode) {
return true;
}
- return tile != Tile.NONE && gameDataAccess.gameData.GetHumanPlayers()[0].tileKnowledge.isTileKnown(tile);
+ return tile != Tile.NONE && gameDataAccess.gameData.GetHumanPlayers()[0].TileKnowledge.isTileKnown(tile);
}
}
diff --git a/C7/UIElements/Advisors/ScienceAdvisor.cs b/C7/UIElements/Advisors/ScienceAdvisor.cs
index 44a89635..f1e2b7f5 100644
--- a/C7/UIElements/Advisors/ScienceAdvisor.cs
+++ b/C7/UIElements/Advisors/ScienceAdvisor.cs
@@ -65,28 +65,28 @@ void DrawTechTree() {
using (UIGameDataAccess gameDataAccess = new()) {
List techs = gameDataAccess.gameData.techs;
Player player = gameDataAccess.gameData.GetHumanPlayers()[0];
- HashSet knownTechs = player.knownTechs;
+ HashSet knownTechs = player.KnownTechs;
// Set the tech background based on the player's era.
- if (player.eraCivilopediaName == "ERAS_Ancient_Times") {
+ if (player.EraCivilopediaName == "ERAS_Ancient_Times") {
this.Texture = AncientBackground;
- } else if (player.eraCivilopediaName == "ERAS_Middle_Ages") {
+ } else if (player.EraCivilopediaName == "ERAS_Middle_Ages") {
this.Texture = MiddleBackground;
- } else if (player.eraCivilopediaName == "ERAS_Industrial_Age") {
+ } else if (player.EraCivilopediaName == "ERAS_Industrial_Age") {
this.Texture = IndustrialBackground;
- } else if (player.eraCivilopediaName == "ERAS_Modern_Era") {
+ } else if (player.EraCivilopediaName == "ERAS_Modern_Era") {
this.Texture = ModernBackground;
}
foreach (Tech tech in techs) {
- if (tech.EraCivilopediaName != player.eraCivilopediaName) {
+ if (tech.EraCivilopediaName != player.EraCivilopediaName) {
continue;
}
TechBox.TechState techState = TechBox.TechState.kBlocked;
if (knownTechs.Contains(tech.id)) {
techState = TechBox.TechState.kKnown;
- } else if (player.currentlyResearchedTech == tech.id) {
+ } else if (player.CurrentlyResearchedTech == tech.id) {
techState = TechBox.TechState.kInProgress;
} else {
bool prereqsKnown = true;
diff --git a/C7/UIElements/Popups/CivilizationDestroyed.cs b/C7/UIElements/Popups/CivilizationDestroyed.cs
index c04f1ca0..4adc2e81 100644
--- a/C7/UIElements/Popups/CivilizationDestroyed.cs
+++ b/C7/UIElements/Popups/CivilizationDestroyed.cs
@@ -10,7 +10,7 @@ public partial class CivilizationDestroyed : Popup {
public CivilizationDestroyed(Civilization civ) {
alignment = BoxContainer.AlignmentMode.End;
margins = new Margins(right: 10);
- civNoun = civ.noun;
+ civNoun = civ.Noun;
}
public override void _Ready() {
diff --git a/C7/UIElements/RightClickMenu.cs b/C7/UIElements/RightClickMenu.cs
index 301bde77..faabf1f8 100644
--- a/C7/UIElements/RightClickMenu.cs
+++ b/C7/UIElements/RightClickMenu.cs
@@ -128,8 +128,8 @@ public void ResetItems(Tile tile, Dictionary uiUpdatedUnitStates = nul
RemoveAll();
int fortifiedCount = 0;
- List playerUnits = tile.unitsOnTile.FindAll(unit => unit.owner.id == game.controller.id);
- List nonPlayerUnits = tile.unitsOnTile.FindAll(unit => unit.owner.id != game.controller.id);
+ List playerUnits = tile.unitsOnTile.FindAll(unit => unit.owner.Id == game.controller.Id);
+ List nonPlayerUnits = tile.unitsOnTile.FindAll(unit => unit.owner.Id != game.controller.Id);
foreach (MapUnit unit in playerUnits) {
bool isFortified = isUnitFortified(unit, uiUpdatedUnitStates);
@@ -159,15 +159,15 @@ public void ResetItems(Tile tile, Dictionary uiUpdatedUnitStates = nul
if (nonPlayerUnits.Count > 0) {
if (tile.cityAtTile == null) {
foreach (MapUnit unit in nonPlayerUnits) {
- AddItem($"{unit.owner.civilization.noun} {unit.Describe()}", null);
+ AddItem($"{unit.owner.Civilization.Noun} {unit.Describe()}", null);
}
- AddItem($"Contact {nonPlayerUnits[0].owner.civilization.name}", null);
+ AddItem($"Contact {nonPlayerUnits[0].owner.Civilization.Name}", null);
} else {
// TODO: This isn't necessarily the top unit, get that code to an accessible
// location and then use it here.
MapUnit unit = nonPlayerUnits[0];
- AddItem($"{unit.owner.civilization.noun} {unit.Describe()}", null);
- AddItem($"Contact {unit.owner.civilization.name}", null);
+ AddItem($"{unit.owner.Civilization.Noun} {unit.Describe()}", null);
+ AddItem($"Contact {unit.owner.Civilization.Name}", null);
}
}
}
diff --git a/C7Engine/AI/BarbarianAI.cs b/C7Engine/AI/BarbarianAI.cs
index 27a7b353..0086a83e 100644
--- a/C7Engine/AI/BarbarianAI.cs
+++ b/C7Engine/AI/BarbarianAI.cs
@@ -12,14 +12,14 @@ public class BarbarianAI {
private ILogger log = Log.ForContext();
public void PlayTurn(Player player, GameData gameData) {
- if (!player.isBarbarians) {
+ if (!player.IsBarbarians) {
throw new System.Exception("Barbarian AI can only play barbarian players");
}
// Copy unit list into temporary array so we can remove units while iterating.
// TODO: We also need to handle units spawned during the loop, e.g. leaders, armies, enslaved units. This is not so much an
// issue for the barbs but will be for similar loops elsewhere in the AI logic.
- foreach (MapUnit unit in player.units.ToArray()) {
+ foreach (MapUnit unit in player.Units.ToArray()) {
if (UnitIsFreeToMove(unit)) {
while (unit.movementPoints.canMove) {
//Move randomly
diff --git a/C7Engine/AI/CityProductionAI.cs b/C7Engine/AI/CityProductionAI.cs
index e77d3a91..980cc5c4 100644
--- a/C7Engine/AI/CityProductionAI.cs
+++ b/C7Engine/AI/CityProductionAI.cs
@@ -29,7 +29,7 @@ public class CityProductionAI {
* get hung up on knowing exactly how it should be done the road.
*/
public static IProducible GetNextItemToBeProduced(City city, IProducible lastProduced) {
- List priorities = city.owner.strategicPriorityData;
+ List priorities = city.owner.StrategicPriorityData;
IEnumerable unitPrototypes = city.ListProductionOptions();
log.Information($"Choosing what to produce next in {city.name}");
diff --git a/C7Engine/AI/PlayerAI.cs b/C7Engine/AI/PlayerAI.cs
index d7fc0273..05a51900 100644
--- a/C7Engine/AI/PlayerAI.cs
+++ b/C7Engine/AI/PlayerAI.cs
@@ -8,32 +8,38 @@
using C7Engine.AI.StrategicAI;
using C7Engine.AI.UnitAI;
using Serilog;
+// ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
+// ReSharper disable InvertIf
+// ReSharper disable ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
+// ReSharper disable CheckNamespace
namespace C7Engine {
- public class PlayerAI {
- private static ILogger log = Log.ForContext();
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class PlayerAi {
+ // ReSharper disable once InconsistentNaming
+ private static readonly ILogger log = Log.ForContext();
public static void PlayTurn(Player player, Random rng) {
- if (player.isHuman || player.isBarbarians) {
+ if (player.IsHuman || player.IsBarbarians) {
return;
}
- log.Information("-> Begin " + player.civilization.cityNames[0] + " turn");
+ log.Information("-> Begin " + player.Civilization.CityNames[0] + " turn");
- if (player.turnsUntilPriorityReevaluation == 0) {
+ if (player.TurnsUntilPriorityReevaluation == 0) {
log.Information("Re-evaluating strategic priorities for " + player);
List priorities = StrategicPriorityArbitrator.Arbitrate(player);
- player.strategicPriorityData.Clear();
+ player.StrategicPriorityData.Clear();
foreach (StrategicPriority priority in priorities) {
- player.strategicPriorityData.Add(priority);
+ player.StrategicPriorityData.Add(priority);
}
- player.turnsUntilPriorityReevaluation = 15 + GameData.rng.Next(10);
- log.Information(player.turnsUntilPriorityReevaluation + " turns until next re-evaluation");
+ player.TurnsUntilPriorityReevaluation = 15 + GameData.rng.Next(10);
+ log.Information(player.TurnsUntilPriorityReevaluation + " turns until next re-evaluation");
} else {
- player.turnsUntilPriorityReevaluation--;
+ player.TurnsUntilPriorityReevaluation--;
}
//Do things with units. Copy into an array first to avoid collection-was-modified exception
- foreach (MapUnit unit in player.units.ToArray()) {
+ foreach (MapUnit unit in player.Units.ToArray()) {
//For each unit, if there's already an AI task assigned, it will attempt to complete its goal.
//It may fail due to conditions having changed since that goal was assigned; in that case it will
//get a new task to try to complete.
@@ -43,10 +49,10 @@ public static void PlayTurn(Player player, Random rng) {
int maxAttempts = 2; //safety valve so we don't freeze the UI if SetAIForUnit returns something that fails
while (!unitDone) {
if (unit.currentAIData == null || attempts > 0) {
- SetAIForUnit(unit, player);
+ SetAiForUnit(unit, player);
}
- UnitAI artificialIntelligence = getAIForUnitStrategy(unit.currentAIData);
+ UnitAI artificialIntelligence = GetAiForUnitStrategy(unit.currentAIData);
unitDone = artificialIntelligence.PlayTurn(player, unit);
attempts++;
@@ -56,60 +62,56 @@ public static void PlayTurn(Player player, Random rng) {
}
}
- player.tileKnowledge.AddTilesToKnown(unit.location);
+ player.TileKnowledge.AddTilesToKnown(unit.location);
}
}
- public static void SetAIForUnit(MapUnit unit, Player player) {
+ public static void SetAiForUnit(MapUnit unit, Player player) {
//figure out an AI behavior
//TODO: Use strategies, not names
if (unit.unitType.name == "Settler") {
- SettlerAIData settlerAiData = new SettlerAIData();
- settlerAiData.goal = SettlerAIData.SettlerGoal.BUILD_CITY;
+ SettlerAiData settlerAiData = new() { Goal = SettlerAiData.SettlerGoal.BuildCity };
//If it's the starting settler, have it settle in place. Otherwise, use an AI to find a location.
- if (player.cities.Count == 0 && unit.location.cityAtTile == null) {
- settlerAiData.destination = unit.location;
- log.Information("No cities yet! Set AI for unit to settler AI with destination of " + settlerAiData.destination);
+ if (player.Cities.Count == 0 && unit.location.cityAtTile == null) {
+ settlerAiData.Destination = unit.location;
+ log.Information("No cities yet! Set AI for unit to settler AI with destination of " + settlerAiData.Destination);
} else {
- settlerAiData.destination = SettlerLocationAI.findSettlerLocation(unit.location, player);
- if (settlerAiData.destination == Tile.NONE) {
+ settlerAiData.Destination = SettlerLocationAi.FindSettlerLocation(unit.location, player);
+ if (settlerAiData.Destination == Tile.NONE) {
//This is possible if all tiles within 4 tiles of a city are either not land, or already claimed
//by another colonist. Longer-term, the AI shouldn't be building settlers if that is the case,
//but right now we'll just spike the football to stop the clock and avoid building immediately next to another city.
- settlerAiData.goal = SettlerAIData.SettlerGoal.JOIN_CITY;
+ settlerAiData.Goal = SettlerAiData.SettlerGoal.JoinCity;
log.Information("Set AI for unit to JOIN_CITY due to lack of locations to settle");
} else {
PathingAlgorithm algorithm = PathingAlgorithmChooser.GetAlgorithm(unit.IsLandUnit());
- settlerAiData.pathToDestination = algorithm.PathFrom(unit.location, settlerAiData.destination);
- log.Information("Set AI for unit to BUILD_CITY with destination of " + settlerAiData.destination);
+ settlerAiData.PathToDestination = algorithm.PathFrom(unit.location, settlerAiData.Destination);
+ log.Information("Set AI for unit to BUILD_CITY with destination of " + settlerAiData.Destination);
}
}
unit.currentAIData = settlerAiData;
} else if (unit.location.cityAtTile != null && unit.location.unitsOnTile.Count(u => u.unitType.defense > 0 && u != unit) == 0) {
- DefenderAIData ai = new DefenderAIData();
- ai.goal = DefenderAIData.DefenderGoal.DEFEND_CITY;
- ai.destination = unit.location;
+ DefenderAIData ai = new() {
+ goal = DefenderAIData.DefenderGoal.DEFEND_CITY, destination = unit.location
+ };
log.Information("Set defender AI for " + unit + " with destination of " + ai.destination);
unit.currentAIData = ai;
} else if (UnitCanAttackNearbyBarbCamp(unit, player)) {
log.Information("Set unit " + unit + " to take out barb camp");
} else if (unit.unitType.name == "Catapult") {
//For now tell catapults to sit tight. It's getting really annoying watching them pointlessly bombard barb camps forever
- DefenderAIData ai = new DefenderAIData();
- ai.goal = DefenderAIData.DefenderGoal.DEFEND_CITY;
- ai.destination = unit.location;
+ DefenderAIData ai = new() {
+ goal = DefenderAIData.DefenderGoal.DEFEND_CITY, destination = unit.location
+ };
log.Information("Set defender AI for " + unit + " with destination of " + ai.destination);
unit.currentAIData = ai;
} else {
-
if (unit.unitType.categories.Contains("Sea")) {
- ExplorerAIData ai = new ExplorerAIData();
- ai.type = ExplorerAIData.ExplorationType.COASTLINE;
+ ExplorerAIData ai = new() { type = ExplorerAIData.ExplorationType.COASTLINE };
unit.currentAIData = ai;
log.Information("Set coastline exploration AI for " + unit);
} else if (unit.location.unitsOnTile.Exists((x) => x.unitType.categories.Contains("Sea"))) {
- ExplorerAIData ai = new ExplorerAIData();
- ai.type = ExplorerAIData.ExplorationType.ON_A_BOAT;
+ ExplorerAIData ai = new() { type = ExplorerAIData.ExplorationType.ON_A_BOAT };
unit.currentAIData = ai;
//TODO: Actually put the unit on the boat
log.Information("Set ON_A_BOAT exploration AI for " + unit);
@@ -117,19 +119,18 @@ public static void SetAIForUnit(MapUnit unit, Player player) {
//Isn't a Settler. If there's a city at the location, it's defended. No boats involved. What's our priority?
//If there is land to explore, we'll try to explore it.
//Long-term TODO: Should only send tiles on this landmass.
- KeyValuePair tileToExplore = ExplorerAI.FindTopScoringTileForExploration(player, player.tileKnowledge.AllKnownTiles().Where(t => t.IsLand()), ExplorerAIData.ExplorationType.RANDOM);
+ KeyValuePair tileToExplore = ExplorerAI.FindTopScoringTileForExploration(player, player.TileKnowledge.AllKnownTiles().Where(t => t.IsLand()), ExplorerAIData.ExplorationType.RANDOM);
if (tileToExplore.Value > 0) {
ExplorerAIData ai = new ExplorerAIData();
//What type of exploration should we do?
int nearbyExplorers = 0;
- foreach (MapUnit mapUnit in player.units) {
- if (mapUnit.currentAIData is ExplorerAIData explorerAI) {
- if (explorerAI.type == ExplorerAIData.ExplorationType.NEAR_CITIES) {
- nearbyExplorers++;
- }
+ foreach (MapUnit mapUnit in player.Units) {
+ if (mapUnit.currentAIData is ExplorerAIData { type: ExplorerAIData.ExplorationType.NEAR_CITIES }) {
+ nearbyExplorers++;
}
}
- if (nearbyExplorers < (player.cities.Count + 1)) {
+ // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
+ if (nearbyExplorers < (player.Cities.Count + 1)) {
ai.type = ExplorerAIData.ExplorationType.NEAR_CITIES;
} else {
ai.type = ExplorerAIData.ExplorationType.RANDOM;
@@ -148,20 +149,21 @@ public static void SetAIForUnit(MapUnit unit, Player player) {
//resources. I expect we'll have some sort of arbiter that decides between competing priorities, with each being given a score as to how important
//they are, including a weight by how far away the task is. But this will evolve gradually over a long time)
+ // ReSharper disable once GrammarMistakeInComment
//As of today (4/7/2022), let's tackle just one of those - adequate defense of cities. The AI is really good at losing cities to barbs right now,
//and that's a problem.
City nearestCityToDefend = FindNearbyCityToDefend(unit, player);
- DefenderAIData newUnitAIData = new DefenderAIData();
- newUnitAIData.destination = nearestCityToDefend.location;
- newUnitAIData.goal = DefenderAIData.DefenderGoal.DEFEND_CITY;
+ DefenderAIData newUnitAiData = new() {
+ destination = nearestCityToDefend.location, goal = DefenderAIData.DefenderGoal.DEFEND_CITY
+ };
PathingAlgorithm algorithm = PathingAlgorithmChooser.GetAlgorithm(unit.IsLandUnit());
- newUnitAIData.pathToDestination = algorithm.PathFrom(unit.location, newUnitAIData.destination);
+ newUnitAiData.pathToDestination = algorithm.PathFrom(unit.location, newUnitAiData.destination);
log.Information($"Unit {unit} tasked with defending {nearestCityToDefend.name}");
- unit.currentAIData = newUnitAIData;
+ unit.currentAIData = newUnitAiData;
}
}
}
@@ -172,7 +174,7 @@ private static bool UnitCanAttackNearbyBarbCamp(MapUnit unit, Player player) {
return false;
}
- List reachableBarbCampsTiles = player.tileKnowledge.AllKnownTiles()
+ List reachableBarbCampsTiles = player.TileKnowledge.AllKnownTiles()
.Where(t => unit.CanEnterTile(t, true) && t.hasBarbarianCamp).ToList();
Tile closestBarbCamp = Tile.NONE;
@@ -186,11 +188,11 @@ private static bool UnitCanAttackNearbyBarbCamp(MapUnit unit, Player player) {
}
if (closestBarbDistance <= 3) {
- CombatAIData caid = new CombatAIData();
+ CombatAIData combatAiData = new CombatAIData();
PathingAlgorithm algorithm = PathingAlgorithmChooser.GetAlgorithm(unit.IsLandUnit());
- caid.path = algorithm.PathFrom(unit.location, closestBarbCamp);
- unit.currentAIData = caid;
+ combatAiData.path = algorithm.PathFrom(unit.location, closestBarbCamp);
+ unit.currentAIData = combatAiData;
return true;
}
return false;
@@ -207,9 +209,9 @@ private static bool UnitCanAttackNearbyBarbCamp(MapUnit unit, Player player) {
*/
private static City FindNearbyCityToDefend(MapUnit unit, Player player) {
int minDefenders = int.MaxValue;
- //TODO: Just being there doesn't mean a unit is a defender.
+ // TODO: Just being there doesn't mean a unit is a defender.
List citiesWithFewestDefenders = new List();
- foreach (City c in player.cities) {
+ foreach (City c in player.Cities) {
if (c.location.unitsOnTile.Count < minDefenders) {
minDefenders = c.location.unitsOnTile.Count;
citiesWithFewestDefenders.Clear();
@@ -241,14 +243,14 @@ private static City FindNearbyCityToDefend(MapUnit unit, Player player) {
* too, for example, and one AIData class might be able to call up multiple types of AIs.
* It also likely will become mod-supporting someday, but we can't add everything on day one.
**/
- public static UnitAI getAIForUnitStrategy(UnitAIData aiData) {
- if (aiData is SettlerAIData sai) {
+ private static UnitAI GetAiForUnitStrategy(UnitAIData aiData) {
+ if (aiData is SettlerAiData) {
return new SettlerAI();
- } else if (aiData is DefenderAIData dai) {
+ } else if (aiData is DefenderAIData) {
return new DefenderAI();
- } else if (aiData is ExplorerAIData eai) {
+ } else if (aiData is ExplorerAIData) {
return new ExplorerAI();
- } else if (aiData is CombatAIData cai) {
+ } else if (aiData is CombatAIData) {
return new CombatAI();
}
throw new Exception("AI data not recognized" + aiData);
diff --git a/C7Engine/AI/StrategicAI/ExpansionPriority.cs b/C7Engine/AI/StrategicAI/ExpansionPriority.cs
index 7741e19b..709ba28c 100644
--- a/C7Engine/AI/StrategicAI/ExpansionPriority.cs
+++ b/C7Engine/AI/StrategicAI/ExpansionPriority.cs
@@ -19,7 +19,7 @@ public ExpansionPriority() {
}
public override void CalculateWeightAndMetadata(Player player) {
- if (player.cities.Count < 2) {
+ if (player.Cities.Count < 2) {
this.calculatedWeight = 1000;
} else {
int score = UtilityCalculations.CalculateAvailableLandScore(player);
diff --git a/C7Engine/AI/StrategicAI/UtilityCalculations.cs b/C7Engine/AI/StrategicAI/UtilityCalculations.cs
index 781b317d..a3874b67 100644
--- a/C7Engine/AI/StrategicAI/UtilityCalculations.cs
+++ b/C7Engine/AI/StrategicAI/UtilityCalculations.cs
@@ -10,15 +10,15 @@ namespace C7Engine.AI.StrategicAI {
///
public class UtilityCalculations {
- private static readonly int POSSIBLE_CITY_LOCATION_SCORE = 2; //how much weight to give to each possible city location
- private static readonly int TILE_SCORE_DIVIDER = 10; //how much to divide each location's tile score by
+ private static readonly int PossibleCityLocationScore = 2; //how much weight to give to each possible city location
+ private static readonly int TileScoreDivider = 10; //how much to divide each location's tile score by
public static int CalculateAvailableLandScore(Player player) {
//Figure out if there's land to settle, and how much
- Dictionary possibleLocations = SettlerLocationAI.GetScoredSettlerCandidates(player.cities[0].location, player);
- int score = possibleLocations.Count * POSSIBLE_CITY_LOCATION_SCORE;
+ Dictionary possibleLocations = SettlerLocationAi.GetScoredSettlerCandidates(player.Cities[0].location, player);
+ int score = possibleLocations.Count * PossibleCityLocationScore;
foreach (int i in possibleLocations.Values) {
- score += i / TILE_SCORE_DIVIDER;
+ score += i / TileScoreDivider;
}
return score;
}
diff --git a/C7Engine/AI/StrategicAI/WarPriority.cs b/C7Engine/AI/StrategicAI/WarPriority.cs
index 6e5bc082..0011486f 100644
--- a/C7Engine/AI/StrategicAI/WarPriority.cs
+++ b/C7Engine/AI/StrategicAI/WarPriority.cs
@@ -25,7 +25,7 @@ public WarPriority() {
///
///
public override void CalculateWeightAndMetadata(Player player) {
- if (player.cities.Count < 2) {
+ if (player.Cities.Count < 2) {
this.calculatedWeight = 0;
} else {
int landScore = UtilityCalculations.CalculateAvailableLandScore(player);
@@ -42,7 +42,7 @@ public override void CalculateWeightAndMetadata(Player player) {
int rnd = GameData.rng.Next(opponentCount);
if (rnd == 0) {
//Let's fight this nation!
- properties["opponent"] = nation.id.ToString();
+ properties["opponent"] = nation.Id.ToString();
calculatedWeight = TEMP_WAR_PRIORITY_WEIGHT;
} else {
opponentCount--; //guarantees we'll eventually get an opponent selected
diff --git a/C7Engine/AI/UnitAI/ExplorerAI.cs b/C7Engine/AI/UnitAI/ExplorerAI.cs
index bbfb8b0b..080b2b95 100644
--- a/C7Engine/AI/UnitAI/ExplorerAI.cs
+++ b/C7Engine/AI/UnitAI/ExplorerAI.cs
@@ -70,7 +70,7 @@ private static bool FindPathToNewExplorationArea(Player player, ExplorerAIData e
Stopwatch watch = new Stopwatch();
watch.Start();
List validExplorerTiles = new List();
- foreach (Tile t in player.tileKnowledge.AllKnownTiles()
+ foreach (Tile t in player.TileKnowledge.AllKnownTiles()
.Where(t => unit.CanEnterTile(t, false) && t.cityAtTile == null && numUnknownNeighboringTiles(player, t) > 0)) {
validExplorerTiles.Add(t);
}
@@ -145,7 +145,7 @@ public static KeyValuePair FindTopScoringTileForExploration(Player
explorationScore[t] = 0;
}
int distanceToNearestCity = int.MaxValue;
- foreach (City c in player.cities) {
+ foreach (City c in player.Cities) {
int distance = t.distanceTo(c.location);
if (distance < distanceToNearestCity) {
distanceToNearestCity = distance;
@@ -169,11 +169,11 @@ private static int numUnknownNeighboringTiles(Player player, Tile t) {
}
//Calculate whether it, and its neighbors are in known tiles.
int discoverableTiles = 0;
- if (!player.tileKnowledge.isTileKnown(t)) {
+ if (!player.TileKnowledge.isTileKnown(t)) {
discoverableTiles++;
}
foreach (Tile n in t.neighbors.Values) {
- if (!player.tileKnowledge.isTileKnown(n)) {
+ if (!player.TileKnowledge.isTileKnown(n)) {
discoverableTiles++;
}
}
diff --git a/C7Engine/AI/UnitAI/SettlerAI.cs b/C7Engine/AI/UnitAI/SettlerAI.cs
index 27933e6a..6047ce15 100644
--- a/C7Engine/AI/UnitAI/SettlerAI.cs
+++ b/C7Engine/AI/UnitAI/SettlerAI.cs
@@ -1,5 +1,4 @@
using System;
-using C7Engine.Pathing;
using C7GameData;
using C7GameData.AIData;
using Serilog;
@@ -10,15 +9,15 @@ public class SettlerAI : UnitAI {
private ILogger log = Log.ForContext();
public bool PlayTurn(Player player, MapUnit unit) {
- SettlerAIData settlerAi = (SettlerAIData)unit.currentAIData;
+ SettlerAiData settlerAi = (SettlerAiData)unit.currentAIData;
start:
- switch (settlerAi.goal) {
- case SettlerAIData.SettlerGoal.BUILD_CITY:
- if (IsInvalidCityLocation(settlerAi.destination)) {
- log.Information("Seeking new destination for settler " + unit.id + "headed to " + settlerAi.destination);
- PlayerAI.SetAIForUnit(unit, player);
+ switch (settlerAi.Goal) {
+ case SettlerAiData.SettlerGoal.BuildCity:
+ if (IsInvalidCityLocation(settlerAi.Destination)) {
+ log.Information("Seeking new destination for settler " + unit.id + "headed to " + settlerAi.Destination);
+ PlayerAi.SetAiForUnit(unit, player);
//Make sure we're using the new settler AI going forward, including this turn
- settlerAi = (SettlerAIData)unit.currentAIData;
+ settlerAi = (SettlerAiData)unit.currentAIData;
//Re-process since the unit's goal may have changed.
//TODO: In theory in the future, it might even have a non-settler AI. Maybe we should instead return false,
//and have the PlayerAI re-kick the unit based on a possibly different AI class?
@@ -26,20 +25,20 @@ public bool PlayTurn(Player player, MapUnit unit) {
//very well become a Defender or Attacker if there's no exploration left, for example.
goto start;
}
- if (unit.location == settlerAi.destination) {
+ if (unit.location == settlerAi.Destination) {
log.Information("Building city with " + unit);
//TODO: This should use a message, and the message handler should cause the disbanding to happen.
- CityInteractions.BuildCity(unit.location.xCoordinate, unit.location.yCoordinate, player.id, unit.owner.GetNextCityName());
+ CityInteractions.BuildCity(unit.location.xCoordinate, unit.location.yCoordinate, player.Id, unit.owner.GetNextCityName());
unit.disband();
} else {
//If the settler has no destination, then disband rather than crash later.
- if (settlerAi.destination == Tile.NONE) {
+ if (settlerAi.Destination == Tile.NONE) {
log.Information("Disbanding settler " + unit.id + " with no valid destination");
unit.disband();
return false;
}
try {
- Tile nextTile = settlerAi.pathToDestination.Next();
+ Tile nextTile = settlerAi.PathToDestination.Next();
unit.move(unit.location.directionTo(nextTile));
} catch (Exception ex) {
//This occurs when on the previous turn, a settler tries to move to the next location on its path, but cannot, due to another
@@ -50,7 +49,7 @@ public bool PlayTurn(Player player, MapUnit unit) {
}
}
break;
- case SettlerAIData.SettlerGoal.JOIN_CITY:
+ case SettlerAiData.SettlerGoal.JoinCity:
if (unit.location.cityAtTile != null) {
//TODO: Actually join the city. Haven't added that action.
//For now, just get rid of the unit. Sorry, bro.
@@ -62,7 +61,7 @@ public bool PlayTurn(Player player, MapUnit unit) {
}
break;
default:
- log.Warning("Unknown strategy of " + settlerAi.goal + " for unit");
+ log.Warning("Unknown strategy of " + settlerAi.Goal + " for unit");
break;
}
return true;
diff --git a/C7Engine/AI/UnitAI/SettlerLocationAI.cs b/C7Engine/AI/UnitAI/SettlerLocationAI.cs
index 43e05848..66857e1a 100644
--- a/C7Engine/AI/UnitAI/SettlerLocationAI.cs
+++ b/C7Engine/AI/UnitAI/SettlerLocationAI.cs
@@ -1,54 +1,46 @@
-using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using C7GameData;
using System.Linq;
using C7GameData.AIData;
using Serilog;
+// ReSharper disable ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
+// ReSharper disable CheckNamespace
namespace C7Engine {
- public class SettlerLocationAI {
- private static ILogger log = Log.ForContext();
-
- //Eventually, there should be different weights based on whether the AI already
- //has the resource or not (more important to secure ones that they don't have).
- //But since we don't have trade networks yet, for now there's only one value.
- static int STRATEGIC_RESOURCE_BONUS = 20;
- static int LUXURY_RESOURCE_BONUS = 15;
+ public class SettlerLocationAi {
+ private static readonly ILogger Log = Serilog.Log.ForContext();
//Figures out where to plant Settlers
- public static Tile findSettlerLocation(Tile start, Player player) {
- Dictionary scores = GetScoredSettlerCandidates(start, player);
+ public static Tile FindSettlerLocation(Tile start, Player player) {
+ Dictionary scores = GetScoredSettlerCandidates(start, player);
if (scores.Count == 0 || scores.Values.Max() <= 0) {
return Tile.NONE; //nowhere to settle
}
- IOrderedEnumerable > orderedScores = scores.OrderByDescending(t => t.Value);
- log.Debug("Top city location candidates from " + start + ":");
+ IOrderedEnumerable > orderedScores = scores.OrderByDescending(t => t.Value);
+ Log.Debug("Top city location candidates from " + start + ":");
Tile returnValue = null;
- foreach (KeyValuePair kvp in orderedScores.Take(5)) {
- if (returnValue == null) {
- returnValue = kvp.Key;
- }
+ foreach (KeyValuePair kvp in orderedScores.Take(5)) {
+ returnValue ??= kvp.Key;
if (kvp.Value > 0) {
- log.Debug(" Tile " + kvp.Key + " scored " + kvp.Value);
+ Log.Debug(" Tile " + kvp.Key + " scored " + kvp.Value);
}
}
return returnValue;
}
- public static Dictionary GetScoredSettlerCandidates(Tile start, Player player) {
- List playerUnits = player.units;
- IEnumerable candidates = player.tileKnowledge.AllKnownTiles().Where(t => !IsInvalidCityLocation(t));
- Dictionary scores = AssignTileScores(start, player, candidates, playerUnits.FindAll(u => u.unitType.name == "Settler"));
+ public static Dictionary GetScoredSettlerCandidates(Tile start, Player player) {
+ List playerUnits = player.Units;
+ IEnumerable candidates = player.TileKnowledge.AllKnownTiles().Where(t => !IsInvalidCityLocation(t));
+ Dictionary scores = AssignTileScores(start, player, candidates, playerUnits.FindAll(u => u.unitType.name == "Settler"));
return scores;
}
- private static Dictionary AssignTileScores(Tile startTile, Player player, IEnumerable candidates, List playerSettlers) {
- Dictionary scores = new Dictionary();
+ private static Dictionary AssignTileScores(Tile startTile, Player player, IEnumerable candidates, List playerSettlers) {
+ Dictionary scores = new();
candidates = candidates.Where(t => !SettlerAlreadyMovingTowardsTile(t, playerSettlers) && t.IsAllowCities());
foreach (Tile t in candidates) {
- int score = GetTileYieldScore(t, player);
+ float score = GetTileYieldScore(t, player);
//For simplicity's sake, I'm only going to look at immediate neighbors here, but
//a lot more things should be considered over time.
foreach (Tile nt in t.neighbors.Values) {
@@ -58,17 +50,17 @@ private static Dictionary AssignTileScores(Tile startTile, Player pla
//Prefer hills for defense, and coast for boats and such.
if (t.baseTerrainType.Key == "hills") {
- score += 10;
+ score += player.Civilization.Adjustments.HillsBonus;
}
if (t.NeighborsWater()) {
- score += 10;
+ score += player.Civilization.Adjustments.WaterBonus;
}
//Lower scores if they are far away
- int preDistanceScore = score;
+ float preDistanceScore = score;
int distance = startTile.distanceTo(t);
- if (distance > 4) {
- score -= distance * 2;
+ if (distance > player.Civilization.Adjustments.DistancePenaltyRadius) {
+ score += player.Civilization.Adjustments.DistancePenalty(distance);
}
//Distance can never lower score beyond 1; the AI will always try to settle those worthless tundras.
//(This could actually be modified in the future, but for now is also a safety rail)
@@ -80,37 +72,42 @@ private static Dictionary AssignTileScores(Tile startTile, Player pla
}
return scores;
}
- private static int GetTileYieldScore(Tile t, Player owner) {
- int score = t.foodYield(owner) * 5;
- score += t.productionYield(owner) * 3;
- score += t.commerceYield(owner) * 2;
- if (t.Resource.Category == ResourceCategory.STRATEGIC) {
- score += STRATEGIC_RESOURCE_BONUS;
- } else if (t.Resource.Category == ResourceCategory.LUXURY) {
- score += LUXURY_RESOURCE_BONUS;
+ private static float GetTileYieldScore(Tile t, Player owner) {
+ float score = owner.Civilization.Adjustments.FoodYieldBonus(t.foodYield(owner));
+ score += owner.Civilization.Adjustments.ProductionYieldBonus(t.productionYield(owner));
+ score += owner.Civilization.Adjustments.CommerceYieldBonus(t.commerceYield(owner));
+ switch (t.Resource.Category)
+ {
+ case ResourceCategory.STRATEGIC:
+ // TODO: increase bonus if this civ doesn't have this strategic resource yet
+ score += owner.Civilization.Adjustments.StrategicResourceBonus;
+ break;
+ case ResourceCategory.LUXURY:
+ score += owner.Civilization.Adjustments.LuxuryResourceBonus;
+ break;
}
return score;
}
- public static bool IsInvalidCityLocation(Tile tile) {
+ private static bool IsInvalidCityLocation(Tile tile) {
if (tile.HasCity) {
- log.Verbose("Tile " + tile + " is invalid due to existing city of " + tile.cityAtTile.name);
+ Log.Verbose("Tile " + tile + " is invalid due to existing city of " + tile.cityAtTile.name);
return true;
}
foreach (Tile neighbor in tile.neighbors.Values) {
if (neighbor.HasCity) {
- log.Verbose("Tile " + tile + " is invalid due to neighboring city of " + neighbor.cityAtTile.name);
+ Log.Verbose("Tile " + tile + " is invalid due to neighboring city of " + neighbor.cityAtTile.name);
return true;
}
foreach (Tile neighborOfNeighbor in neighbor.neighbors.Values) {
if (neighborOfNeighbor.HasCity) {
- log.Verbose("Tile " + tile + " is invalid due to nearby city of " + neighborOfNeighbor.cityAtTile.name);
+ Log.Verbose("Tile " + tile + " is invalid due to nearby city of " + neighborOfNeighbor.cityAtTile.name);
return true;
}
}
}
- log.Debug("Tile " + tile + " is a valid city location ");
+ Log.Debug("Tile " + tile + " is a valid city location ");
return false;
}
@@ -123,16 +120,17 @@ public static bool IsInvalidCityLocation(Tile tile) {
/// The tile under consideration for a future city.
/// The settlers owned by the AI considering building a city.
///
- public static bool SettlerAlreadyMovingTowardsTile(Tile tile, List playerSettlers) {
+ private static bool SettlerAlreadyMovingTowardsTile(Tile tile, List playerSettlers) {
foreach (MapUnit otherSettler in playerSettlers) {
- if (otherSettler.currentAIData is SettlerAIData otherSettlerAI) {
- if (otherSettlerAI.destination == tile) {
+ // ReSharper disable once InvertIf
+ if (otherSettler.currentAIData is SettlerAiData otherSettlerAi) {
+ if (otherSettlerAi.Destination == tile) {
return true;
}
- if (otherSettlerAI.destination.GetLandNeighbors().Exists(innerRingTile => innerRingTile == tile)) {
+ if (otherSettlerAi.Destination.GetLandNeighbors().Exists(innerRingTile => innerRingTile == tile)) {
return true;
}
- foreach (Tile innerRingTile in otherSettlerAI.destination.GetLandNeighbors()) {
+ foreach (Tile innerRingTile in otherSettlerAi.Destination.GetLandNeighbors()) {
if (innerRingTile.GetLandNeighbors().Exists(outerRingTile => outerRingTile == tile)) {
return true;
}
diff --git a/C7Engine/EntryPoints/CityInteractions.cs b/C7Engine/EntryPoints/CityInteractions.cs
index d188f064..3fe63917 100644
--- a/C7Engine/EntryPoints/CityInteractions.cs
+++ b/C7Engine/EntryPoints/CityInteractions.cs
@@ -13,11 +13,11 @@ public static void BuildCity(int x, int y, ID playerID, string name) {
CityResident firstResident = new CityResident();
CityTileAssignmentAI.AssignNewCitizenToTile(newCity, firstResident);
newCity.SetItemBeingProduced(CityProductionAI.GetNextItemToBeProduced(newCity, null));
- if (owner.cities.Count == 0) {
+ if (owner.Cities.Count == 0) {
newCity.capital = true;
}
gameData.cities.Add(newCity);
- owner.cities.Add(newCity);
+ owner.Cities.Add(newCity);
tileWithNewCity.cityAtTile = newCity;
// Cities are treated as though they have a road, but if
@@ -32,7 +32,7 @@ public static void DestroyCity(int x, int y) {
Tile tile = EngineStorage.gameData.map.tileAt(x, y);
tile.DisbandNonDefendingUnits();
tile.cityAtTile.RemoveAllCitizens();
- tile.cityAtTile.owner.cities.Remove(tile.cityAtTile);
+ tile.cityAtTile.owner.Cities.Remove(tile.cityAtTile);
EngineStorage.gameData.cities.Remove(tile.cityAtTile);
new MsgCityDestroyed(tile.cityAtTile).send();
tile.cityAtTile = null;
diff --git a/C7Engine/EntryPoints/CreateGame.cs b/C7Engine/EntryPoints/CreateGame.cs
index dcb80abb..62738dfa 100644
--- a/C7Engine/EntryPoints/CreateGame.cs
+++ b/C7Engine/EntryPoints/CreateGame.cs
@@ -28,12 +28,12 @@ public static Player createGame(string loadFilePath, string defaultBicPath, Func
// members containing numerous references to eachother, but with SaveGame, each entity is
// only defined once in the save file, and references to it are stored as IDs making it easy
// to generate and modify valid save files.
- Player humanPlayer = gameData.players.Any(p => p.isHuman) switch {
- true => gameData.players.Find(p => p.isHuman),
+ Player humanPlayer = gameData.players.Any(p => p.IsHuman) switch {
+ true => gameData.players.Find(p => p.IsHuman),
false => throw new Exception($"{loadFilePath} does not contain a human player"),
};
- EngineStorage.uiControllerID = humanPlayer.id;
+ EngineStorage.uiControllerID = humanPlayer.Id;
TurnHandling.OnBeginTurn(); // Call for the first turn
TurnHandling.AdvanceTurn();
diff --git a/C7Engine/EntryPoints/MessageToEngine.cs b/C7Engine/EntryPoints/MessageToEngine.cs
index 82c5b022..16830004 100644
--- a/C7Engine/EntryPoints/MessageToEngine.cs
+++ b/C7Engine/EntryPoints/MessageToEngine.cs
@@ -134,7 +134,7 @@ public MsgChooseResearch(ID techId) {
public override void process() {
Player player = EngineStorage.gameData.GetHumanPlayers()[0];
- if (player.currentlyResearchedTech == techId) {
+ if (player.CurrentlyResearchedTech == techId) {
return;
}
Tech requestedTech = EngineStorage.gameData.techs.Find(t => t.id == techId);
@@ -143,13 +143,13 @@ public override void process() {
//
// TODO: do a topological sort to allow a queue of techs to study.
foreach (Tech prereq in requestedTech.Prerequisites) {
- if (!player.knownTechs.Contains(prereq.id)) {
+ if (!player.KnownTechs.Contains(prereq.id)) {
return;
}
}
// Start researching this tech and update the UI.
- player.currentlyResearchedTech = requestedTech.id;
+ player.CurrentlyResearchedTech = requestedTech.id;
new MsgUpdateUiAfterTechSelection().send();
}
}
@@ -161,14 +161,14 @@ public class MsgEndTurn : MessageToEngine {
public override void process() {
Player controller = EngineStorage.gameData.GetPlayer(EngineStorage.uiControllerID);
- foreach (MapUnit unit in controller.units) {
+ foreach (MapUnit unit in controller.Units) {
log.Debug($"{unit}, path length: {unit.path?.PathLength() ?? 0}");
if (unit.path?.PathLength() > 0) {
unit.moveAlongPath();
}
}
- controller.hasPlayedThisTurn = true;
+ controller.HasPlayedThisTurn = true;
TurnHandling.AdvanceTurn();
}
}
diff --git a/C7Engine/EntryPoints/TurnHandling.cs b/C7Engine/EntryPoints/TurnHandling.cs
index e76b2986..7e500ee2 100644
--- a/C7Engine/EntryPoints/TurnHandling.cs
+++ b/C7Engine/EntryPoints/TurnHandling.cs
@@ -16,7 +16,7 @@ internal static void OnBeginTurn() {
mapUnit.OnBeginTurn();
foreach (Player player in gameData.players) {
- player.hasPlayedThisTurn = false;
+ player.HasPlayedThisTurn = false;
}
}
@@ -56,22 +56,22 @@ internal static void AdvanceTurn() {
/// true when it is time for the human to take control again
private static bool PlayPlayerTurns(GameData gameData, bool firstTurn) {
foreach (Player player in gameData.players) {
- if ((!player.hasPlayedThisTurn) &&
+ if ((!player.HasPlayedThisTurn) &&
!(firstTurn && player.SitsOutFirstTurn())) {
- if (player.isBarbarians) {
+ if (player.IsBarbarians) {
//Call the barbarian AI
//TODO: The AIs should be stored somewhere on the game state as some of them will store state (plans,
//strategy, etc.) For now, we only have a random AI, so that will be in a future commit
new BarbarianAI().PlayTurn(player, gameData);
- player.hasPlayedThisTurn = true;
- } else if (!player.isHuman) {
- PlayerAI.PlayTurn(player, GameData.rng);
- player.hasPlayedThisTurn = true;
- } else if (player.id != EngineStorage.uiControllerID) {
- player.hasPlayedThisTurn = true;
+ player.HasPlayedThisTurn = true;
+ } else if (!player.IsHuman) {
+ PlayerAi.PlayTurn(player, GameData.rng);
+ player.HasPlayedThisTurn = true;
+ } else if (player.Id != EngineStorage.uiControllerID) {
+ player.HasPlayedThisTurn = true;
}
//Human player check. Let the human see what's going on even if they are in observer mode.
- if (player.id == EngineStorage.uiControllerID) {
+ if (player.Id == EngineStorage.uiControllerID) {
new MsgStartTurn().send();
return true;
}
@@ -81,7 +81,7 @@ private static bool PlayPlayerTurns(GameData gameData, bool firstTurn) {
}
private static void SpawnBarbarians(GameData gameData) {
//Generate new barbarian units.
- Player barbPlayer = gameData.players.Find(player => player.isBarbarians);
+ Player barbPlayer = gameData.players.Find(player => player.IsBarbarians);
foreach (Tile tile in gameData.map.barbarianCamps) {
//7% chance of a new barbarian. Probably should scale based on barbarian activity.
int result = GameData.rng.Next(100);
@@ -98,7 +98,7 @@ private static void SpawnBarbarians(GameData gameData) {
tile.unitsOnTile.Add(newUnit);
gameData.mapUnits.Add(newUnit);
- barbPlayer.units.Add(newUnit);
+ barbPlayer.Units.Add(newUnit);
log.Debug("New barbarian added at " + tile);
} else if (tile.NeighborsWater() && result < 6) {
MapUnit newUnit = new MapUnit(gameData.ids.CreateID(gameData.barbarianInfo.barbarianSeaUnit.name));
@@ -112,7 +112,7 @@ private static void SpawnBarbarians(GameData gameData) {
tile.unitsOnTile.Add(newUnit);
gameData.mapUnits.Add(newUnit);
- barbPlayer.units.Add(newUnit);
+ barbPlayer.Units.Add(newUnit);
log.Debug("New barbarian galley added at " + tile);
}
}
@@ -127,7 +127,7 @@ private static void HandleCityResults(GameData gameData) {
int newSize = city.size;
if (newSize > initialSize) {
CityResident newResident = new CityResident();
- newResident.nationality = city.owner.civilization;
+ newResident.nationality = city.owner.Civilization;
CityTileAssignmentAI.AssignNewCitizenToTile(city, newResident);
} else if (newSize < initialSize) {
int diff = initialSize - newSize;
@@ -160,7 +160,7 @@ private static void HandleCityResults(GameData gameData) {
city.SetItemBeingProduced(CityProductionAI.GetNextItemToBeProduced(city, producedItem));
}
- city.owner.gold += city.CurrentCommerceYield();
+ city.owner.Gold += city.CurrentCommerceYield();
}
}
diff --git a/C7Engine/EntryPoints/UnitInteractions.cs b/C7Engine/EntryPoints/UnitInteractions.cs
index 40fa0df1..6ff78853 100644
--- a/C7Engine/EntryPoints/UnitInteractions.cs
+++ b/C7Engine/EntryPoints/UnitInteractions.cs
@@ -11,11 +11,11 @@ public class UnitInteractions {
private static ILogger log = Log.ForContext();
public static MapUnit getNextSelectedUnit(GameData gameData) {
- foreach (Player player in gameData.players.Where(p => p.isHuman)) {
+ foreach (Player player in gameData.players.Where(p => p.IsHuman)) {
//TODO: Should pass in a player GUID instead of checking for human
//This current limits us to one human player, although it's better
//than the old limit of one non-barbarian player.
- foreach (MapUnit unit in player.units.Where(u => u.movementPoints.canMove && !u.IsBusy())) {
+ foreach (MapUnit unit in player.Units.Where(u => u.movementPoints.canMove && !u.IsBusy())) {
if (!waitQueue.Contains(unit)) {
return unit;
}
diff --git a/C7Engine/MapUnitExtensions.cs b/C7Engine/MapUnitExtensions.cs
index d9f2e106..454fb6cf 100644
--- a/C7Engine/MapUnitExtensions.cs
+++ b/C7Engine/MapUnitExtensions.cs
@@ -94,7 +94,7 @@ public static bool HasPriorityAsDefender(this MapUnit unit, MapUnit otherDefende
public static void RollToPromote(this MapUnit unit, MapUnit opponent, bool waitForAnimation) {
double promotionChance = unit.experienceLevel.promotionChance;
- if (opponent.owner.isBarbarians)
+ if (opponent.owner.IsBarbarians)
promotionChance /= 2.0;
// TODO: Double promotionChance if unit is owned by a militaristic civ
@@ -274,10 +274,10 @@ public static void OnBeginTurn(this MapUnit unit) {
public static void OnEnterTile(this MapUnit unit, Tile tile) {
//Add to player knowledge of tiles
- unit.owner.tileKnowledge.AddTilesToKnown(tile);
+ unit.owner.TileKnowledge.AddTilesToKnown(tile);
// Disperse barb camp
- if (tile.hasBarbarianCamp && (!unit.owner.isBarbarians)) {
+ if (tile.hasBarbarianCamp && (!unit.owner.IsBarbarians)) {
tile.DisbandNonDefendingUnits();
EngineStorage.gameData.map.barbarianCamps.Remove(tile);
tile.hasBarbarianCamp = false;
@@ -404,8 +404,8 @@ public static void disband(this MapUnit unit) {
unit.location.unitsOnTile.Remove(unit);
gameData.mapUnits.Remove(unit);
foreach (Player player in gameData.players) {
- if (player.units.Contains(unit)) {
- player.units.Remove(unit);
+ if (player.Units.Contains(unit)) {
+ player.Units.Remove(unit);
}
}
}
@@ -430,7 +430,7 @@ public static void buildCity(this MapUnit unit, string cityName) {
// TODO: Need to check somewhere that this unit is allowed to build a city on its current tile. Either do that here or in every caller
// (probably best to just do it here).
- CityInteractions.BuildCity(unit.location.xCoordinate, unit.location.yCoordinate, unit.owner.id, cityName);
+ CityInteractions.BuildCity(unit.location.xCoordinate, unit.location.yCoordinate, unit.owner.Id, cityName);
// TODO: Should directly delete the unit instead of disbanding it. Disbanding in a city will eventually award shields, which we
// obviously don't want to do here.
diff --git a/C7GameData/AIData/SettlerAIData.cs b/C7GameData/AIData/SettlerAIData.cs
index 98cc7cae..fc247c25 100644
--- a/C7GameData/AIData/SettlerAIData.cs
+++ b/C7GameData/AIData/SettlerAIData.cs
@@ -16,20 +16,20 @@ namespace C7GameData.AIData
* I'm also unsure of how much the logic of figuring out what to do should be in these
* classes, versus higher-level ones.
*/
- public class SettlerAIData : UnitAIData
+ public class SettlerAiData : UnitAIData
{
public enum SettlerGoal
{
- BUILD_CITY,
- JOIN_CITY
+ BuildCity,
+ JoinCity
}
- public SettlerGoal goal;
- public Tile destination;
- public TilePath pathToDestination;
+ public SettlerGoal Goal;
+ public Tile Destination;
+ public TilePath PathToDestination;
public override string ToString()
{
- return goal + " at " + destination;
+ return Goal + " at " + Destination;
}
}
}
diff --git a/C7GameData/Civilization.cs b/C7GameData/Civilization.cs
index 67b17db0..98cc3df5 100644
--- a/C7GameData/Civilization.cs
+++ b/C7GameData/Civilization.cs
@@ -1,5 +1,5 @@
+using System;
using System.Collections.Generic;
-using System.Text.Json.Serialization;
namespace C7GameData {
/**
@@ -12,21 +12,47 @@ public enum Gender {
}
public class Civilization {
- public Civilization() { }
-
+ public Civilization() {}
+ // ReSharper disable once UnusedMember.Global
public Civilization(string name) {
- this.name = name;
+ Name = name;
}
- public string name;
-
+ public string Name;
// `noun` is "Americans" for "America", or "Spanish" for "Spain", etc.
- public string noun;
- public string leader;
- public int colorIndex;
- public Gender leaderGender;
- public List cityNames = new List();
-
+ public string Noun;
+ // ReSharper disable once NotAccessedField.Global
+ public string Leader;
+ public int ColorIndex;
+ // ReSharper disable once NotAccessedField.Global
+ public Gender LeaderGender;
+ // ReSharper disable once FieldCanBeMadeReadOnly.Global
+ public List CityNames = new();
// The IDs of all the techs that this civ starts with.
- public HashSet startingTechs = new();
+ // ReSharper disable once FieldCanBeMadeReadOnly.Global
+ public HashSet StartingTechs = new();
+
+ public class SettlerTileAdjustments {
+ private const int DefaultDistancePenaltyRadius = 4;
+ private const float DefaultCommerceYieldBonus = 2;
+ private const float DefaultDistancePenalty = -2;
+ private const float DefaultFoodYieldBonus = 5;
+ private const float DefaultHillsBonus = 10;
+ private const float DefaultLuxuryResourceBonus = 15;
+ private const float DefaultProductionYieldBonus = 3;
+ private const float DefaultStrategicResourceBonus = 20;
+ private const float DefaultWaterBonus = 10;
+
+ public int DistancePenaltyRadius = DefaultDistancePenaltyRadius;
+ public Func CommerceYieldBonus = yield => yield * DefaultCommerceYieldBonus;
+ public Func DistancePenalty = distance => distance * DefaultDistancePenalty;
+ public Func FoodYieldBonus = yield => yield * DefaultFoodYieldBonus;
+ public float HillsBonus = DefaultHillsBonus;
+ public float LuxuryResourceBonus = DefaultLuxuryResourceBonus;
+ public Func ProductionYieldBonus = yield => yield * DefaultProductionYieldBonus;
+ public float StrategicResourceBonus = DefaultStrategicResourceBonus;
+ public float WaterBonus = DefaultWaterBonus;
+ }
+ // ReSharper disable once FieldCanBeMadeReadOnly.Global
+ public SettlerTileAdjustments Adjustments = new();
}
}
diff --git a/C7GameData/GameData.cs b/C7GameData/GameData.cs
index 35592bcc..63e1f211 100644
--- a/C7GameData/GameData.cs
+++ b/C7GameData/GameData.cs
@@ -54,7 +54,7 @@ public GameData() {
}
public List GetHumanPlayers() {
- return players.FindAll(p => p.isHuman);
+ return players.FindAll(p => p.IsHuman);
}
public MapUnit GetUnit(ID id) {
@@ -62,7 +62,7 @@ public MapUnit GetUnit(ID id) {
}
public Player GetPlayer(ID id) {
- return players.Find(p => p.id == id);
+ return players.Find(p => p.Id == id);
}
public ExperienceLevel GetExperienceLevelAfter(ExperienceLevel experienceLevel) {
diff --git a/C7GameData/ImportCiv3.cs b/C7GameData/ImportCiv3.cs
index 8750e9ee..758645ab 100644
--- a/C7GameData/ImportCiv3.cs
+++ b/C7GameData/ImportCiv3.cs
@@ -334,14 +334,14 @@ private void ImportRaces() {
int i = 0;
foreach (RACE race in theBiq.Race) {
Civilization civ = new Civilization{
- name = race.Name,
- noun = race.Noun,
- leader = race.LeaderName,
- leaderGender = race.LeaderGender == 0 ? Gender.Male : Gender.Female,
- colorIndex = race.DefaultColor,
+ Name = race.Name,
+ Noun = race.Noun,
+ Leader = race.LeaderName,
+ LeaderGender = race.LeaderGender == 0 ? Gender.Male : Gender.Female,
+ ColorIndex = race.DefaultColor,
};
foreach (RACE_City city in theBiq.RaceCityName[i]) {
- civ.cityNames.Add(city.Name);
+ civ.CityNames.Add(city.Name);
}
save.Civilizations.Add(civ);
i++;
@@ -425,10 +425,10 @@ private void ImportSavLeaders() {
private SavePlayer MakeSavePlayerFromCiv(Civilization civ, bool isBarbarian, bool isHuman, int cityNameIndex, string era) {
return new SavePlayer {
id = ids.CreateID("player"),
- colorIndex = civ.colorIndex,
+ colorIndex = civ.ColorIndex,
barbarian = isBarbarian,
human = isHuman,
- civilization = civ.name,
+ civilization = civ.Name,
hasPlayedCurrentTurn = false, // TODO: find how this information is stored in a .sav
cityNameIndex = cityNameIndex,
eraCivilopediaName = era,
@@ -715,25 +715,25 @@ private void ImportTechs() {
RACE race = theBiq.Race[i];
if (race.FreeTech1 > -1) {
- sc.startingTechs.Add(save.Techs[race.FreeTech1].id);
+ sc.StartingTechs.Add(save.Techs[race.FreeTech1].id);
}
if (race.FreeTech2 > -1) {
- sc.startingTechs.Add(save.Techs[race.FreeTech2].id);
+ sc.StartingTechs.Add(save.Techs[race.FreeTech2].id);
}
if (race.FreeTech3 > -1) {
- sc.startingTechs.Add(save.Techs[race.FreeTech3].id);
+ sc.StartingTechs.Add(save.Techs[race.FreeTech3].id);
}
if (race.FreeTech4 > -1) {
- sc.startingTechs.Add(save.Techs[race.FreeTech4].id);
+ sc.StartingTechs.Add(save.Techs[race.FreeTech4].id);
}
// Remove any invalid starting techs. Some scenarios like
// Fall of Rome give starting techs without giving all of the
// prereqs, so they should be ignored.
- sc.startingTechs.RemoveWhere(t => {
+ sc.StartingTechs.RemoveWhere(t => {
SaveTech st = save.Techs.Find(x => x.id == t);
foreach (ID prereqId in st.Prerequisites) {
- if (!sc.startingTechs.Contains(prereqId)) {
+ if (!sc.StartingTechs.Contains(prereqId)) {
return true;
}
}
diff --git a/C7GameData/Player.cs b/C7GameData/Player.cs
index 4430b73c..92494cd5 100644
--- a/C7GameData/Player.cs
+++ b/C7GameData/Player.cs
@@ -1,52 +1,55 @@
using System.Collections.Generic;
using System.Linq;
using C7Engine.AI.StrategicAI;
+// ReSharper disable ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
namespace C7GameData {
public class Player {
- public ID id { get; internal set; }
- public int colorIndex;
- public bool isBarbarians = false;
- //TODO: Refactor front-end so it sends player GUID with requests.
- //We should allow multiple humans, this is a temporary measure.
- public bool isHuman = false;
- public bool hasPlayedThisTurn = false;
-
- public Civilization civilization;
- internal int cityNameIndex = 0;
-
- public List units = new List();
- public List cities = new List();
- public TileKnowledge tileKnowledge = new TileKnowledge();
+ // ReSharper disable once PropertyCanBeMadeInitOnly.Global
+ public ID Id { get; internal set; }
+ public int ColorIndex;
+ public bool IsBarbarians = false;
+ // TODO: Refactor front-end so it sends player GUID with requests.
+ // We should allow multiple humans, this is a temporary measure.
+ public bool IsHuman = false;
+ public bool HasPlayedThisTurn = false;
+
+ public Civilization Civilization;
+ internal int CityNameIndex;
+
+ public List Units = new();
+ public List Cities = new();
+ public TileKnowledge TileKnowledge = new();
//Ordered list of priority data. First is most important.
- public List strategicPriorityData = new List();
+ // ReSharper disable once FieldCanBeMadeReadOnly.Global
+ public List StrategicPriorityData = new();
// The list of techs known by this player.
- public HashSet knownTechs = new();
+ public HashSet KnownTechs = new();
// The tech the player is currently researching.
- public ID currentlyResearchedTech;
+ public ID CurrentlyResearchedTech;
// The civilopedia name of the era this player is in.
//
// The civilopedia name is what is used for art lookups, not the actual
// name.
- public string eraCivilopediaName;
+ public string EraCivilopediaName;
- public int turnsUntilPriorityReevaluation = 0;
+ public int TurnsUntilPriorityReevaluation = 0;
// The amount of gold this player has.
- public int gold = 0;
+ public int Gold = 0;
public void AddUnit(MapUnit unit) {
- this.units.Add(unit);
+ Units.Add(unit);
}
public string GetNextCityName() {
- string name = civilization.cityNames[cityNameIndex % civilization.cityNames.Count];
- int bonusLoops = cityNameIndex / civilization.cityNames.Count;
+ string name = Civilization.CityNames[CityNameIndex % Civilization.CityNames.Count];
+ int bonusLoops = CityNameIndex / Civilization.CityNames.Count;
if (bonusLoops % 2 == 1) {
name = "New " + name;
}
@@ -54,20 +57,18 @@ public string GetNextCityName() {
if (suffix > 1) {
name = name + " " + suffix; //e.g. for bonusLoops = 2, we'll have "Athens 2"
}
- cityNameIndex++;
+ CityNameIndex++;
return name;
}
- public Player() { }
-
public bool IsAtPeaceWith(Player other) {
- // Right now it's a free-for-all but eventually we'll implement peace treaties and alliances
+ // Right now it's a free-for-all, but eventually we'll implement peace treaties and alliances
return other == this;
}
public bool SitsOutFirstTurn() {
// TODO: Scenarios can also specify that certain players sit out the first turn. E.g. WW2 in the Pacific
- return isBarbarians;
+ return IsBarbarians;
}
// Once we have technologies, not all resources will be known at the start.
@@ -80,7 +81,7 @@ public bool KnowsAboutResource(Resource resource) {
public int RemainingCities() {
int result = 0;
- foreach (City city in cities) {
+ foreach (City city in Cities) {
// Destroyed cities have a size of zero.
if (city.size > 0) {
++result;
@@ -90,9 +91,7 @@ public int RemainingCities() {
}
public override string ToString() {
- if (civilization != null)
- return civilization.cityNames.First();
- return "";
+ return Civilization != null ? Civilization.CityNames.First() : "";
}
}
diff --git a/C7GameData/Save/SaveCity.cs b/C7GameData/Save/SaveCity.cs
index 571bfdf6..bea6af39 100644
--- a/C7GameData/Save/SaveCity.cs
+++ b/C7GameData/Save/SaveCity.cs
@@ -23,7 +23,7 @@ public SaveCity() { }
public SaveCity(City city) {
id = city.id;
- owner = city.owner.id;
+ owner = city.owner.Id;
capital = city.capital;
location = new TileLocation(city.location);
name = city.name;
@@ -34,7 +34,7 @@ public SaveCity(City city) {
foodNeededToGrow = city.foodNeededToGrow;
residents = city.residents.ConvertAll(resident => {
return new SaveCityResident {
- nationality = resident.nationality?.name,
+ nationality = resident.nationality?.Name,
tileWorked = new TileLocation(resident.tileWorked),
};
});
@@ -44,7 +44,7 @@ public City ToCity(GameMap gameMap, List players, List un
City city = new City{
id = id,
location = gameMap.tileAt(location.x, location.y),
- owner = players.Find(p => p.id == owner),
+ owner = players.Find(p => p.Id == owner),
name = name,
size = size,
itemBeingProduced = unitPrototypes.Find(proto => proto.name == producible),
@@ -55,7 +55,7 @@ public City ToCity(GameMap gameMap, List players, List un
residents = residents.ConvertAll(resident =>{
return new CityResident{
tileWorked = gameMap.tileAt(resident.tileWorked.x, resident.tileWorked.y),
- nationality = civilizations.Find(civ => civ.name == resident.nationality),
+ nationality = civilizations.Find(civ => civ.Name == resident.nationality),
};
}),
};
diff --git a/C7GameData/Save/SaveGame.cs b/C7GameData/Save/SaveGame.cs
index a4fbdbad..30a8b30a 100644
--- a/C7GameData/Save/SaveGame.cs
+++ b/C7GameData/Save/SaveGame.cs
@@ -106,7 +106,7 @@ public GameData ToGameData() {
// once unit owners are known, players can reference units
data.players.ForEach(player => {
- player.units = data.mapUnits.Where(unit => unit.owner.id == player.id).ToList(); ;
+ player.Units = data.mapUnits.Where(unit => unit.owner.Id == player.Id).ToList(); ;
});
// cities require game map for location and players for city owner
@@ -114,7 +114,7 @@ public GameData ToGameData() {
// Once cities are known, players can reference cities.
data.players.ForEach(player => {
- player.cities = data.cities.Where(city => city.owner.id == player.id).ToList(); ;
+ player.Cities = data.cities.Where(city => city.owner.Id == player.Id).ToList(); ;
});
foreach (City city in data.cities) {
diff --git a/C7GameData/Save/SavePlayer.cs b/C7GameData/Save/SavePlayer.cs
index 771ad8c9..54e45989 100644
--- a/C7GameData/Save/SavePlayer.cs
+++ b/C7GameData/Save/SavePlayer.cs
@@ -33,25 +33,25 @@ public class SavePlayer {
public Player ToPlayer(GameMap map, List civilizations) {
Player player = new Player{
- id = id,
- isBarbarians = barbarian,
- isHuman = human,
- hasPlayedThisTurn = hasPlayedCurrentTurn,
- colorIndex = colorIndex,
- civilization = civilization is not null ? civilizations.Find(civ => civ.name == civilization) : null,
- cityNameIndex = cityNameIndex,
- tileKnowledge = new TileKnowledge(),
- knownTechs = knownTechs,
- currentlyResearchedTech = currentlyResearchedTech,
- eraCivilopediaName = eraCivilopediaName,
- gold = gold,
+ Id = id,
+ IsBarbarians = barbarian,
+ IsHuman = human,
+ HasPlayedThisTurn = hasPlayedCurrentTurn,
+ ColorIndex = colorIndex,
+ Civilization = civilization is not null ? civilizations.Find(civ => civ.Name == civilization) : null,
+ CityNameIndex = cityNameIndex,
+ TileKnowledge = new TileKnowledge(),
+ KnownTechs = knownTechs,
+ CurrentlyResearchedTech = currentlyResearchedTech,
+ EraCivilopediaName = eraCivilopediaName,
+ Gold = gold,
};
foreach (TileLocation tile in tileKnowledge) {
- player.tileKnowledge.AddTileToKnown(map.tileAt(tile.x, tile.y));
+ player.TileKnowledge.AddTileToKnown(map.tileAt(tile.x, tile.y));
}
- foreach (ID techId in player.civilization.startingTechs) {
- if (!player.knownTechs.Contains(techId)) {
- player.knownTechs.Add(techId);
+ foreach (ID techId in player.Civilization.StartingTechs) {
+ if (!player.KnownTechs.Contains(techId)) {
+ player.KnownTechs.Add(techId);
}
}
return player;
@@ -60,21 +60,21 @@ public Player ToPlayer(GameMap map, List civilizations) {
public SavePlayer() { }
public SavePlayer(Player player) {
- id = player.id;
- colorIndex = player.colorIndex;
- barbarian = player.isBarbarians;
- human = player.isHuman;
- hasPlayedCurrentTurn = player.hasPlayedThisTurn;
- civilization = player.civilization?.name;
+ id = player.Id;
+ colorIndex = player.ColorIndex;
+ barbarian = player.IsBarbarians;
+ human = player.IsHuman;
+ hasPlayedCurrentTurn = player.HasPlayedThisTurn;
+ civilization = player.Civilization?.Name;
// TODO: this should be computed by looking at cities defined in the save
// so that adding cities in the save structure doesn't require updating this value
- cityNameIndex = player.cityNameIndex;
- tileKnowledge = player.tileKnowledge.AllKnownTiles().ConvertAll(tile => new TileLocation(tile));
- turnsUntilPriorityReevaluation = player.turnsUntilPriorityReevaluation;
- knownTechs = player.knownTechs;
- currentlyResearchedTech = player.currentlyResearchedTech;
- eraCivilopediaName = player.eraCivilopediaName;
- gold = player.gold;
+ cityNameIndex = player.CityNameIndex;
+ tileKnowledge = player.TileKnowledge.AllKnownTiles().ConvertAll(tile => new TileLocation(tile));
+ turnsUntilPriorityReevaluation = player.TurnsUntilPriorityReevaluation;
+ knownTechs = player.KnownTechs;
+ currentlyResearchedTech = player.CurrentlyResearchedTech;
+ eraCivilopediaName = player.EraCivilopediaName;
+ gold = player.Gold;
}
}
}
diff --git a/C7GameData/Save/SaveUnit.cs b/C7GameData/Save/SaveUnit.cs
index 3543a141..803aea66 100644
--- a/C7GameData/Save/SaveUnit.cs
+++ b/C7GameData/Save/SaveUnit.cs
@@ -20,7 +20,7 @@ public SaveUnit() { }
public SaveUnit(MapUnit unit, GameMap map) {
id = unit.id;
prototype = unit.unitType.name;
- owner = unit.owner.id;
+ owner = unit.owner.Id;
if (unit.previousLocation is not null) {
previousLocation = new TileLocation(unit.previousLocation);
}
@@ -41,7 +41,7 @@ public MapUnit ToMapUnit(List prototypes, List e
unitType = prototypes.Find(p => p.name == prototype),
experienceLevelKey = experience,
experienceLevel = experienceLevels.Find(el => el.key == experience),
- owner = players.Find(player => player.id == owner),
+ owner = players.Find(player => player.Id == owner),
location = map.tileAt(currentLocation.x, currentLocation.y),
previousLocation = currentLocation.x == - 1 ? Tile.NONE : map.tileAt(previousLocation.x, previousLocation.y),
hitPointsRemaining = hitPointsRemaining,
diff --git a/C7GameDataTests/SaveTest.cs b/C7GameDataTests/SaveTest.cs
index 86f59f46..9bdbb8ce 100644
--- a/C7GameDataTests/SaveTest.cs
+++ b/C7GameDataTests/SaveTest.cs
@@ -200,26 +200,26 @@ public void CheckScenariosInCiv3Subfolder(string subfolder) {
foreach (Player player in gd.players) {
int settlerCount = 0;
int totalUnitCount = 0;
- foreach (MapUnit mu in player.units) {
+ foreach (MapUnit mu in player.Units) {
++totalUnitCount;
if (mu.unitType.name == "Settler") {
++settlerCount;
}
}
- int cityCount = player.cities.Count;
+ int cityCount = player.Cities.Count;
- Console.WriteLine(name + " : " + player.civilization.name + " has " +
+ Console.WriteLine(name + " : " + player.Civilization.Name + " has " +
settlerCount + " settlers, " +
cityCount + " cities, " +
totalUnitCount + " units, and is " +
- (player.isHuman ? "" : "not ") +
+ (player.IsHuman ? "" : "not ") +
"the human player");
// The human player should always have either a city or a settler.
- if (player.isHuman) {
+ if (player.IsHuman) {
Assert.True(cityCount + settlerCount > 0,
- name + " : " + player.civilization.name);
+ name + " : " + player.Civilization.Name);
}
}