From 6e890f60780e4b863d07cc171eee6239786b1631 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 23 Jan 2025 18:32:18 -0600 Subject: [PATCH] Properly import known technologies when loading saves/scenarios #392 --- C7GameData/Civilization.cs | 2 +- C7GameData/ImportCiv3.cs | 29 ++++++++++++++++++++++++++++- QueryCiv3/Sav.cs | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/C7GameData/Civilization.cs b/C7GameData/Civilization.cs index 66ecec26..67b17db0 100644 --- a/C7GameData/Civilization.cs +++ b/C7GameData/Civilization.cs @@ -27,6 +27,6 @@ public Civilization(string name) { public List cityNames = new List(); // The IDs of all the techs that this civ starts with. - public List startingTechs = new(); + public HashSet startingTechs = new(); } } diff --git a/C7GameData/ImportCiv3.cs b/C7GameData/ImportCiv3.cs index 1178e036..da246a61 100644 --- a/C7GameData/ImportCiv3.cs +++ b/C7GameData/ImportCiv3.cs @@ -5,7 +5,6 @@ using QueryCiv3; using QueryCiv3.Biq; using C7GameData.Save; -using System.IO; /* This will read a Civ3 sav into C7 native format for immediate use or saving to native JSON save @@ -370,6 +369,13 @@ private void ImportBicLeaders() { // Put the player in the correct starting era. player.eraCivilopediaName = theBiq.Eras[lead.InitialEra].CivilopediaEntry; + // Add the starting techs for scenarios. + if (theBiq.LeadTech != null) { + for (int j = 0; j < theBiq.LeadTech[leadIndex].Length; ++j) { + player.knownTechs.Add(save.Techs[theBiq.LeadTech[leadIndex][j]].id); + } + } + // Mark the first human playable civ as the human player. if (lead.HumanPlayer == 1 && !foundHuman) { player.human = true; @@ -394,9 +400,17 @@ private void ImportSavLeaders() { /*cityNameIndex=*/leader.FoundedCities, /*era=*/theBiq.Eras[leader.Era].CivilopediaEntry); + // TODO: store non-negative values of leader.Researching, // which indexes into save.Techs. + // Record any techs that this player knows. + for (int k = 0; k < savData.KnownTechFlags.Length; ++k) { + if (savData.KnownTechFlags[k][i]) { + player.knownTechs.Add(save.Techs[k].id); + } + } + save.Players.Add(player); i++; } @@ -706,6 +720,19 @@ private void ImportTechs() { if (race.FreeTech4 > -1) { 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 => { + SaveTech st = save.Techs.Find(x => x.id == t); + foreach (ID prereqId in st.Prerequisites) { + if (!sc.startingTechs.Contains(prereqId)) { + return true; + } + } + return false; + }); } } diff --git a/QueryCiv3/Sav.cs b/QueryCiv3/Sav.cs index c0b368e9..daa738a3 100644 --- a/QueryCiv3/Sav.cs +++ b/QueryCiv3/Sav.cs @@ -32,6 +32,7 @@ public unsafe class SavData { public CLNY[] Clny; public int[] CitiesPerContinent; + // Bit k of element i means that civ k knows tech i. public IntBitmap[] KnownTechFlags; public int[] GreatWonderCityIDs; public bool[] GreatWondersBuilt;