From 33ce877ff185dca992604749d8f589c90967644b Mon Sep 17 00:00:00 2001 From: IhateTrains Date: Fri, 11 Oct 2024 00:47:39 +0100 Subject: [PATCH] Fix some character history entries being set after character death (#2260) #patch --- ImperatorToCK3/CK3/Characters/Character.cs | 3 ++- .../CK3/Characters/CharacterCollection.cs | 14 ++++++++++++ ImperatorToCK3/CK3/Titles/LandedTitles.cs | 8 +++---- ImperatorToCK3/CK3/Titles/Title.cs | 22 +++++++++---------- ImperatorToCK3/CK3/World.cs | 16 +++++++------- .../Outputter/CharacterOutputter.cs | 2 +- ImperatorToCK3/Outputter/WorldOutputter.cs | 2 +- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/ImperatorToCK3/CK3/Characters/Character.cs b/ImperatorToCK3/CK3/Characters/Character.cs index c042bab25..b33762073 100644 --- a/ImperatorToCK3/CK3/Characters/Character.cs +++ b/ImperatorToCK3/CK3/Characters/Character.cs @@ -485,7 +485,8 @@ ISet unlocalizedImperatorNames var nicknameMatch = nicknameMapper.GetCK3NicknameForImperatorNickname(ImperatorCharacter.Nickname); if (nicknameMatch is not null) { - SetNickname(nicknameMatch, dateOnConversion); + var nicknameDate = ImperatorCharacter.DeathDate ?? dateOnConversion; + SetNickname(nicknameMatch, nicknameDate); } if (ImperatorCharacter.Wealth != 0) { diff --git a/ImperatorToCK3/CK3/Characters/CharacterCollection.cs b/ImperatorToCK3/CK3/Characters/CharacterCollection.cs index 9daedab56..42dcb32a4 100644 --- a/ImperatorToCK3/CK3/Characters/CharacterCollection.cs +++ b/ImperatorToCK3/CK3/Characters/CharacterCollection.cs @@ -689,6 +689,16 @@ public void GenerateSuccessorsForOldCharacters(Title.LandedTitles titles, Cultur foreach (var oldCharacter in oldCharacters.Except(oldTitleHolders)) { // Roll a dice to determine how much longer the character will live. var yearsToLive = randomForCharactersWithoutTitles.Next(0, 30); + + // If the character is female and pregnant, make sure she doesn't die before the pregnancy ends. + if (oldCharacter is {Female: true, ImperatorCharacter: not null}) { + var lastPregnancy = oldCharacter.Pregnancies.OrderBy(p => p.BirthDate).LastOrDefault(); + if (lastPregnancy is not null) { + oldCharacter.DeathDate = lastPregnancy.BirthDate.ChangeByYears(yearsToLive); + continue; + } + } + oldCharacter.DeathDate = irSaveDate.ChangeByYears(yearsToLive); } @@ -803,6 +813,10 @@ public void GenerateSuccessorsForOldCharacters(Title.LandedTitles titles, Cultur // After the loop, currentCharacter should represent the successor at bookmark date. // Set his DNA to avoid weird looking character on the bookmark screen in CK3. currentCharacter.DNA = oldCharacter.DNA; + + // Transfer gold to the living successor. + currentCharacter.Gold = oldCharacter.Gold; + oldCharacter.Gold = null; }); } diff --git a/ImperatorToCK3/CK3/Titles/LandedTitles.cs b/ImperatorToCK3/CK3/Titles/LandedTitles.cs index 3ee5cfe23..72e0dc612 100644 --- a/ImperatorToCK3/CK3/Titles/LandedTitles.cs +++ b/ImperatorToCK3/CK3/Titles/LandedTitles.cs @@ -1446,7 +1446,7 @@ private void DistributeExcessDevelopment(Date date) { /// https://ck3.paradoxwikis.com/Council /// https://ck3.paradoxwikis.com/Court#Court_positions /// - public void ImportImperatorGovernmentOffices(ICollection irOfficeJobs, ReligionCollection religionCollection, Date bookmarkDate) { + public void ImportImperatorGovernmentOffices(ICollection irOfficeJobs, ReligionCollection religionCollection, Date irSaveDate) { Logger.Info("Converting government offices..."); var titlesFromImperator = GetCountriesImportedFromImperator(); @@ -1485,7 +1485,7 @@ public void ImportImperatorGovernmentOffices(ICollection irOfficeJobs } // Make sure the ruler actually holds something in CK3. - if (this.All(t => t.GetHolderId(bookmarkDate) != ck3Ruler.Id)) { + if (this.All(t => t.GetHolderId(irSaveDate) != ck3Ruler.Id)) { continue; } @@ -1495,8 +1495,8 @@ public void ImportImperatorGovernmentOffices(ICollection irOfficeJobs } var alreadyEmployedCharacters = new HashSet(); - title.AppointCouncilMembersFromImperator(religionCollection, councilPositionToSourcesDict, convertibleJobs, alreadyEmployedCharacters, ck3Ruler, bookmarkDate); - title.AppointCourtierPositionsFromImperator(courtPositionToSourcesDict, convertibleJobs, alreadyEmployedCharacters, ck3Ruler, bookmarkDate); + title.AppointCouncilMembersFromImperator(religionCollection, councilPositionToSourcesDict, convertibleJobs, alreadyEmployedCharacters, ck3Ruler, irSaveDate); + title.AppointCourtierPositionsFromImperator(courtPositionToSourcesDict, convertibleJobs, alreadyEmployedCharacters, ck3Ruler, irSaveDate); } } diff --git a/ImperatorToCK3/CK3/Titles/Title.cs b/ImperatorToCK3/CK3/Titles/Title.cs index c53a66fa8..3c92f4245 100644 --- a/ImperatorToCK3/CK3/Titles/Title.cs +++ b/ImperatorToCK3/CK3/Titles/Title.cs @@ -1309,7 +1309,7 @@ private void AppointCourtierPositionsFromImperator(Dictionary List convertibleJobs, HashSet alreadyEmployedCharacters, Character ck3Ruler, - Date bookmarkDate) { + Date irSaveDate) { Dictionary heldTitlesPerCharacterCache = []; foreach (var (ck3Position, sources) in courtPositionToSourcesDict) { @@ -1334,7 +1334,7 @@ private void AppointCourtierPositionsFromImperator(Dictionary } if (!heldTitlesPerCharacterCache.ContainsKey(ck3Official.Id)) { - heldTitlesPerCharacterCache[ck3Official.Id] = parentCollection.Count(t => t.GetHolderId(bookmarkDate) == ck3Official.Id); + heldTitlesPerCharacterCache[ck3Official.Id] = parentCollection.Count(t => t.GetHolderId(irSaveDate) == ck3Official.Id); } // A potential courtier must not be a ruler. if (heldTitlesPerCharacterCache[ck3Official.Id] > 0) { @@ -1360,7 +1360,7 @@ private void AppointCourtierPositionsFromImperator(Dictionary } } """); - ck3Ruler.History.AddFieldValue(bookmarkDate, "effects", "effect", courtPositionEffect); + ck3Ruler.History.AddFieldValue(irSaveDate, "effects", "effect", courtPositionEffect); // One character should only hold one CK3 position. convertibleJobs.Remove(job); @@ -1376,7 +1376,7 @@ private void AppointCouncilMembersFromImperator(ReligionCollection religionColle List convertibleJobs, HashSet alreadyEmployedCharacters, Character ck3Ruler, - Date bookmarkDate) { + Date irSaveDate) { Dictionary heldTitlesPerCharacterCache = []; foreach (var (ck3Position, sources) in councilPositionToSourcesDict) { @@ -1401,14 +1401,14 @@ private void AppointCouncilMembersFromImperator(ReligionCollection religionColle } if (!heldTitlesPerCharacterCache.TryGetValue(ck3Official.Id, out int heldTitlesCount)) { - heldTitlesCount = parentCollection.Count(t => t.GetHolderId(bookmarkDate) == ck3Official.Id); + heldTitlesCount = parentCollection.Count(t => t.GetHolderId(irSaveDate) == ck3Official.Id); heldTitlesPerCharacterCache[ck3Official.Id] = heldTitlesCount; } if (ck3Position == "councillor_court_chaplain") { // Court chaplains need to have the same faith as the ruler. - var rulerFaithId = ck3Ruler.GetFaithId(bookmarkDate); - if (rulerFaithId is null || rulerFaithId != ck3Official.GetFaithId(bookmarkDate)) { + var rulerFaithId = ck3Ruler.GetFaithId(irSaveDate); + if (rulerFaithId is null || rulerFaithId != ck3Official.GetFaithId(irSaveDate)) { continue; } @@ -1418,7 +1418,7 @@ private void AppointCouncilMembersFromImperator(ReligionCollection religionColle continue; } if (rulerFaith.HasDoctrine("doctrine_clerical_marriage_disallowed")) { - if (ck3Official.GetSpouseIds(bookmarkDate).Count > 0) { + if (ck3Official.GetSpouseIds(irSaveDate).Count > 0) { continue; } } @@ -1445,7 +1445,7 @@ private void AppointCouncilMembersFromImperator(ReligionCollection religionColle } else if (ck3Position == "councillor_steward" || ck3Position == "councillor_chancellor" || ck3Position == "councillor_marshal") { // Unless they are rulers, stewards, chancellors and marshals need to have the dominant gender of the faith. if (heldTitlesCount == 0) { - var courtFaith = ck3Ruler.GetFaithId(bookmarkDate); + var courtFaith = ck3Ruler.GetFaithId(irSaveDate); if (courtFaith is not null) { var dominantGenderDoctrine = religionCollection.GetFaith(courtFaith)? .GetDoctrineIdForDoctrineCategoryId("doctrine_gender"); @@ -1461,9 +1461,9 @@ private void AppointCouncilMembersFromImperator(ReligionCollection religionColle // We only need to set the employer when the council member is landless. if (heldTitlesCount == 0) { - ck3Official.History.AddFieldValue(bookmarkDate, "employer", "employer", ck3Ruler.Id); + ck3Official.History.AddFieldValue(irSaveDate, "employer", "employer", ck3Ruler.Id); } - ck3Official.History.AddFieldValue(bookmarkDate, "council_position", "give_council_position", ck3Position); + ck3Official.History.AddFieldValue(irSaveDate, "council_position", "give_council_position", ck3Position); // One character should only hold one CK3 position. convertibleJobs.Remove(job); diff --git a/ImperatorToCK3/CK3/World.cs b/ImperatorToCK3/CK3/World.cs index 013466f5a..c49eae54c 100644 --- a/ImperatorToCK3/CK3/World.cs +++ b/ImperatorToCK3/CK3/World.cs @@ -255,7 +255,7 @@ public World(Imperator.World impWorld, Configuration config, Thread? irCoaExtrac deathReasonMapper, dnaFactory, LocDB, - CorrectedDate, + impWorld.EndDate, config ); // Now that we have loaded all characters, we can mark some of them as non-removable. @@ -345,6 +345,12 @@ public World(Imperator.World impWorld, Configuration config, Thread? irCoaExtrac } Dynasties.SetCoasForRulingDynasties(LandedTitles, config.CK3BookmarkDate); + + // If there's a gap between the I:R save date and the CK3 bookmark date, + // generate successors for old I:R characters instead of making them live for centuries. + if (config.CK3BookmarkDate.DiffInYears(impWorld.EndDate) > 1) { + Characters.GenerateSuccessorsForOldCharacters(LandedTitles, Cultures, impWorld.EndDate, config.CK3BookmarkDate, impWorld.RandomSeed); + } Characters.DistributeCountriesGold(LandedTitles, config); Characters.ImportLegions(LandedTitles, impWorld.Units, impWorld.Characters, CorrectedDate, unitTypeMapper, MenAtArmsTypes, provinceMapper, LocDB, config); @@ -359,7 +365,7 @@ public World(Imperator.World impWorld, Configuration config, Thread? irCoaExtrac LandedTitles.CleanUpHistory(Characters, config.CK3BookmarkDate); // Now that the title history is basically done, convert officials as council members and courtiers. - LandedTitles.ImportImperatorGovernmentOffices(impWorld.JobsDB.OfficeJobs, Religions, config.CK3BookmarkDate); + LandedTitles.ImportImperatorGovernmentOffices(impWorld.JobsDB.OfficeJobs, Religions, impWorld.EndDate); // Check if any muslim religion exists in Imperator. Otherwise, remove Islam from the entire CK3 map. var possibleMuslimReligionNames = new List { "muslim", "islam", "sunni", "shiite" }; @@ -371,12 +377,6 @@ public World(Imperator.World impWorld, Configuration config, Thread? irCoaExtrac RemoveIslam(config); } Logger.IncrementProgress(); - - // If there's a gap between the I:R save date and the CK3 bookmark date, - // generate successors for old I:R characters instead of making them live for centuries. - if (config.CK3BookmarkDate.DiffInYears(impWorld.EndDate) > 1) { - Characters.GenerateSuccessorsForOldCharacters(LandedTitles, Cultures, impWorld.EndDate, config.CK3BookmarkDate, impWorld.RandomSeed); - } Parallel.Invoke( () => ImportImperatorWars(impWorld, config.CK3BookmarkDate), diff --git a/ImperatorToCK3/Outputter/CharacterOutputter.cs b/ImperatorToCK3/Outputter/CharacterOutputter.cs index 6b072f9b8..31782a89a 100644 --- a/ImperatorToCK3/Outputter/CharacterOutputter.cs +++ b/ImperatorToCK3/Outputter/CharacterOutputter.cs @@ -29,7 +29,7 @@ public static void WriteCharacter(StringBuilder sb, Character character, Date co string effectStr = gold > 0 ? $"{{ add_gold={gold.ToString("0.00", CultureInfo.InvariantCulture)} }}" : $"{{ remove_long_term_gold={(-gold).ToString("0.00", CultureInfo.InvariantCulture)} }}"; - character.History.AddFieldValue(conversionDate, "effects", "effect", effectStr); + character.History.AddFieldValue(ck3BookmarkDate, "effects", "effect", effectStr); } // Output history. diff --git a/ImperatorToCK3/Outputter/WorldOutputter.cs b/ImperatorToCK3/Outputter/WorldOutputter.cs index 569176c7c..1d2e10e60 100644 --- a/ImperatorToCK3/Outputter/WorldOutputter.cs +++ b/ImperatorToCK3/Outputter/WorldOutputter.cs @@ -31,7 +31,7 @@ public static void OutputWorld(World ck3World, Imperator.World imperatorWorld, C Task.WaitAll( FileTweaker.RemoveUnneededPartsOfFiles(ck3World.ModFS, outputPath, config), - CharactersOutputter.OutputEverything(outputPath, ck3World.Characters, ck3World.CorrectedDate, config.CK3BookmarkDate, ck3World.ModFS), + CharactersOutputter.OutputEverything(outputPath, ck3World.Characters, imperatorWorld.EndDate, config.CK3BookmarkDate, ck3World.ModFS), DynastiesOutputter.OutputDynastiesAndHouses(outputPath, ck3World.Dynasties, ck3World.DynastyHouses), ProvincesOutputter.OutputProvinces(outputPath, ck3World.Provinces, ck3World.LandedTitles),