-
-
Notifications
You must be signed in to change notification settings - Fork 22
[WIP] Conversion of treasures into artifacts #2474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2a9c5de
8a94f8c
cbb0a7c
9df6d97
afc0b03
dbd0191
7560bec
df01650
21ec47b
dd5918b
e620a07
12efe22
355f41d
f2b309b
752e40a
2c9ec4c
f5d6e69
87643a3
ba2e6bd
a48fcc7
5e723f5
6428179
d93481c
a87e690
27a2f22
4b7e56e
dc475f7
66d459b
ef63015
47d3a7b
963f956
1f93e77
ae90d51
0927725
2e83362
c57b830
e948774
d09a420
81a5e71
b8d8a98
eddb1f3
1d65d8a
0a49785
eee2bcd
68ce469
c8fac68
ad20a9d
4e49056
5890daa
e251464
51f5436
2a6612e
0bce016
e9a0f94
73e4bf8
7bd91f8
8dd5f48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,15 +2,20 @@ | |
using commonItems.Collections; | ||
using commonItems.Localization; | ||
using ImperatorToCK3.CK3.Armies; | ||
using ImperatorToCK3.CK3.Modifiers; | ||
using ImperatorToCK3.CK3.Cultures; | ||
using ImperatorToCK3.CK3.Dynasties; | ||
using ImperatorToCK3.CK3.Titles; | ||
using ImperatorToCK3.CommonUtils; | ||
using ImperatorToCK3.CommonUtils.Map; | ||
using ImperatorToCK3.Imperator.Armies; | ||
using ImperatorToCK3.Imperator.Provinces; | ||
using ImperatorToCK3.Imperator.Religions; | ||
using ImperatorToCK3.Imperator.Characters; | ||
using ImperatorToCK3.Mappers.Artifact; | ||
using ImperatorToCK3.Mappers.Culture; | ||
using ImperatorToCK3.Mappers.DeathReason; | ||
using ImperatorToCK3.Mappers.Modifier; | ||
using ImperatorToCK3.Mappers.Nickname; | ||
using ImperatorToCK3.Mappers.Province; | ||
using ImperatorToCK3.Mappers.Religion; | ||
|
@@ -184,41 +189,41 @@ | |
} | ||
} | ||
|
||
private void LinkMothersAndFathers() { | ||
var motherCounter = 0; | ||
var fatherCounter = 0; | ||
foreach (var ck3Character in this) { | ||
// make links between Imperator characters | ||
if (ck3Character.ImperatorCharacter is null) { | ||
// imperatorRegnal characters do not have ImperatorCharacter | ||
continue; | ||
} | ||
var irMotherCharacter = ck3Character.ImperatorCharacter.Mother; | ||
if (irMotherCharacter is not null) { | ||
var ck3MotherCharacter = irMotherCharacter.CK3Character; | ||
if (ck3MotherCharacter is not null) { | ||
ck3Character.Mother = ck3MotherCharacter; | ||
++motherCounter; | ||
} else { | ||
Logger.Warn($"Imperator mother {irMotherCharacter.Id} has no CK3 character!"); | ||
} | ||
} | ||
|
||
// make links between Imperator characters | ||
var irFatherCharacter = ck3Character.ImperatorCharacter.Father; | ||
if (irFatherCharacter is not null) { | ||
var ck3FatherCharacter = irFatherCharacter.CK3Character; | ||
if (ck3FatherCharacter is not null) { | ||
ck3Character.Father = ck3FatherCharacter; | ||
++fatherCounter; | ||
} else { | ||
Logger.Warn($"Imperator father {irFatherCharacter.Id} has no CK3 character!"); | ||
} | ||
} | ||
} | ||
Logger.Info($"{motherCounter} mothers and {fatherCounter} fathers linked in CK3."); | ||
} | ||
|
||
private void LinkSpouses(Date conversionDate) { | ||
var spouseCounter = 0; | ||
foreach (var ck3Character in this) { | ||
|
@@ -383,54 +388,54 @@ | |
Logger.IncrementProgress(); | ||
} | ||
|
||
private void SetCharacterCastes(CultureCollection cultures, Date ck3BookmarkDate) { | ||
var casteSystemCultureIds = cultures | ||
.Where(c => c.TraditionIds.Contains("tradition_caste_system")) | ||
.Select(c => c.Id) | ||
.ToFrozenSet(); | ||
var learningEducationTraits = new[]{"education_learning_1", "education_learning_2", "education_learning_3", "education_learning_4"}; | ||
|
||
foreach (var character in this.OrderBy(c => c.BirthDate)) { | ||
if (character.ImperatorCharacter is null) { | ||
continue; | ||
} | ||
|
||
var cultureId = character.GetCultureId(ck3BookmarkDate); | ||
if (cultureId is null || !casteSystemCultureIds.Contains(cultureId)) { | ||
continue; | ||
} | ||
|
||
// The caste is hereditary. | ||
var father = character.Father; | ||
if (father is not null) { | ||
var foundTrait = GetCasteTraitFromParent(father); | ||
if (foundTrait is not null) { | ||
character.AddBaseTrait(foundTrait); | ||
continue; | ||
} | ||
} | ||
var mother = character.Mother; | ||
if (mother is not null) { | ||
var foundTrait = GetCasteTraitFromParent(mother); | ||
if (foundTrait is not null) { | ||
character.AddBaseTrait(foundTrait); | ||
continue; | ||
} | ||
} | ||
|
||
// Try to set caste based on character's traits. | ||
var traitIds = character.BaseTraits.ToFrozenSet(); | ||
character.AddBaseTrait(traitIds.Intersect(learningEducationTraits).Any() ? "brahmin" : "kshatriya"); | ||
} | ||
return; | ||
|
||
static string? GetCasteTraitFromParent(Character parentCharacter) { | ||
var casteTraits = new[]{"brahmin", "kshatriya", "vaishya", "shudra"}; | ||
var parentTraitIds = parentCharacter.BaseTraits.ToFrozenSet(); | ||
return casteTraits.Intersect(parentTraitIds).FirstOrDefault(); | ||
} | ||
} | ||
|
||
public void LoadCharacterIDsToPreserve(Date ck3BookmarkDate) { | ||
Logger.Debug("Loading IDs of CK3 characters to preserve..."); | ||
|
||
|
@@ -469,93 +474,93 @@ | |
parser.ParseFile(configurablePath); | ||
} | ||
|
||
public void PurgeUnneededCharacters(Title.LandedTitles titles, DynastyCollection dynasties, HouseCollection houses, Date ck3BookmarkDate) { | ||
Logger.Info("Purging unneeded characters..."); | ||
|
||
// Characters from CK3 that hold titles at the bookmark date should be kept. | ||
var currentTitleHolderIds = titles.GetHolderIdsForAllTitlesExceptNobleFamilyTitles(ck3BookmarkDate); | ||
var landedCharacters = this | ||
.Where(character => currentTitleHolderIds.Contains(character.Id)) | ||
.ToArray(); | ||
var charactersToCheck = this.Except(landedCharacters); | ||
|
||
// Characters from I:R that held or hold titles should be kept. | ||
var allTitleHolderIds = titles.GetAllHolderIds(); | ||
var imperatorTitleHolders = this | ||
.Where(character => character.FromImperator && allTitleHolderIds.Contains(character.Id)) | ||
.ToArray(); | ||
charactersToCheck = charactersToCheck.Except(imperatorTitleHolders); | ||
|
||
// Don't purge animation_test characters. | ||
charactersToCheck = charactersToCheck | ||
.Where(c => !c.Id.StartsWith("animation_test_")); | ||
|
||
// Keep alive Imperator characters. | ||
charactersToCheck = charactersToCheck | ||
.Where(c => c is not {FromImperator: true, ImperatorCharacter.IsDead: false}); | ||
|
||
// Make some exceptions for characters referenced in game's script files. | ||
charactersToCheck = charactersToCheck | ||
.Where(character => !character.IsNonRemovable) | ||
.ToArray(); | ||
|
||
// I:R members of landed dynasties will be preserved, unless dead and childless. | ||
var dynastyIdsOfLandedCharacters = landedCharacters | ||
.Select(character => character.GetDynastyId(ck3BookmarkDate)) | ||
.Distinct() | ||
.Where(id => id is not null) | ||
.ToFrozenSet(); | ||
|
||
var i = 0; | ||
var charactersToRemove = new List<Character>(); | ||
var parentIdsCache = new HashSet<string>(); | ||
do { | ||
Logger.Debug($"Beginning iteration {i} of characters purge..."); | ||
charactersToRemove.Clear(); | ||
parentIdsCache.Clear(); | ||
++i; | ||
|
||
// Build cache of all parent IDs. | ||
foreach (var character in this) { | ||
var motherId = character.MotherId; | ||
if (motherId is not null) { | ||
parentIdsCache.Add(motherId); | ||
} | ||
|
||
var fatherId = character.FatherId; | ||
if (fatherId is not null) { | ||
parentIdsCache.Add(fatherId); | ||
} | ||
} | ||
|
||
// See who can be removed. | ||
foreach (var character in charactersToCheck) { | ||
// Is the character from Imperator and do they belong to a dynasty that holds or held titles? | ||
if (character.FromImperator && dynastyIdsOfLandedCharacters.Contains(character.GetDynastyId(ck3BookmarkDate))) { | ||
// Is the character dead and childless? Purge. | ||
if (!parentIdsCache.Contains(character.Id)) { | ||
charactersToRemove.Add(character); | ||
} | ||
|
||
continue; | ||
} | ||
|
||
charactersToRemove.Add(character); | ||
} | ||
|
||
BulkRemove(charactersToRemove.ConvertAll(c => c.Id)); | ||
|
||
Logger.Debug($"\tPurged {charactersToRemove.Count} unneeded characters in iteration {i}."); | ||
charactersToCheck = charactersToCheck.Except(charactersToRemove).ToArray(); | ||
} while(charactersToRemove.Count > 0); | ||
|
||
// At this point we probably have many dynasties with no characters left. | ||
// Let's purge them. | ||
houses.PurgeUnneededHouses(this, ck3BookmarkDate); | ||
dynasties.PurgeUnneededDynasties(this, houses, ck3BookmarkDate); | ||
dynasties.FlattenDynastiesWithNoFounders(this, houses, ck3BookmarkDate); | ||
} | ||
|
||
public void RemoveEmployerIdFromLandedCharacters(Title.LandedTitles titles, Date conversionDate) { | ||
Logger.Info("Removing employer id from landed characters..."); | ||
var landedCharacterIds = titles.GetHolderIdsForAllTitlesExceptNobleFamilyTitles(conversionDate); | ||
|
@@ -662,155 +667,344 @@ | |
Logger.IncrementProgress(); | ||
} | ||
|
||
public void ImportArtifacts( | ||
ProvinceCollection irProvinces, | ||
ProvinceMapper provinceMapper, | ||
Title.LandedTitles titles, | ||
TreasureManager treasureManager, | ||
ModifierMapper modifierMapper, | ||
ModifierCollection ck3Modifiers, | ||
LocDB irLocDB, | ||
CK3LocDB ck3LocDB, | ||
Date date | ||
) { | ||
Logger.Info("Importing Imperator artifacts..."); | ||
var ck3CharacterIdToTreasureIdsListDict = new Dictionary<string, IList<ulong>>(); | ||
|
||
foreach (var irProvince in irProvinces) { | ||
var ck3Provinces = provinceMapper.GetCK3ProvinceNumbers(irProvince.Id); | ||
if (ck3Provinces.Count == 0) { | ||
continue; | ||
} | ||
var primaryCK3ProvinceId = ck3Provinces.First(); | ||
|
||
string? ownerId = null; | ||
|
||
var barony = titles.GetBaronyForProvince(primaryCK3ProvinceId); | ||
if (barony is null) { | ||
Logger.Warn($"Can't find barony for province {primaryCK3ProvinceId}!"); | ||
continue; | ||
} | ||
var baronyHolderId = barony.GetHolderId(date); | ||
if (baronyHolderId != "0") { | ||
ownerId = baronyHolderId; | ||
} else { | ||
var county = titles.GetCountyForProvince(primaryCK3ProvinceId); | ||
if (county is null) { | ||
Logger.Warn($"Can't find county for province {primaryCK3ProvinceId}!"); | ||
continue; | ||
} | ||
var countyHolderId = county.GetHolderId(date); | ||
if (countyHolderId != "0") { | ||
ownerId = countyHolderId; | ||
} | ||
} | ||
|
||
if (ownerId is null) { | ||
Logger.Warn($"Can't find owner for province {primaryCK3ProvinceId}!"); | ||
continue; | ||
} | ||
|
||
if (ck3CharacterIdToTreasureIdsListDict.TryGetValue(ownerId, out var artifactList)) { | ||
artifactList.AddRange(irProvince.TreasureIds); | ||
} else { | ||
ck3CharacterIdToTreasureIdsListDict[ownerId] = irProvince.TreasureIds.ToList(); | ||
} | ||
} | ||
// TODO: also import artifacts not assigned to holy sites (search for treasures={ 225 226 } in save) | ||
Check warning on line 724 in ImperatorToCK3/CK3/Characters/CharacterCollection.cs
|
||
|
||
// TODO: check if needed: Create visuals for artifacts. | ||
Check warning on line 726 in ImperatorToCK3/CK3/Characters/CharacterCollection.cs
|
||
/*var treasureIconNames = treasureManager | ||
.Select(t => t.IconName) | ||
.Distinct() | ||
.ToList(); | ||
foreach (var iconName in treasureIconNames) { | ||
throw new NotImplementedException(); | ||
// example: | ||
// icon: artefact_icons_unique_artifact_cheese | ||
// asset entity: ep1_western_pouch_basic_01_a_entity | ||
// mesh: ep1_western_pouch_basic_01_a_mesh | ||
}*/ | ||
|
||
var visualsMapper = new ArtifactMapper("configurables/artifact_map.txt"); | ||
|
||
var charactersFromImperator = this.Where(c => c.FromImperator).ToList(); | ||
foreach (var character in charactersFromImperator) { | ||
if (!ck3CharacterIdToTreasureIdsListDict.TryGetValue(character.Id, out var irArtifactIds)) { | ||
continue; | ||
} | ||
|
||
// TODO: try to use create_artifact_sculpture_babr_e_bayan_effect as base | ||
Check warning on line 747 in ImperatorToCK3/CK3/Characters/CharacterCollection.cs
|
||
foreach (var irArtifactId in irArtifactIds) { | ||
var irArtifact = treasureManager[irArtifactId]; | ||
ImportArtifact(character, irArtifact, modifierMapper, ck3Modifiers, visualsMapper, irLocDB, ck3LocDB, date); | ||
} | ||
|
||
|
||
|
||
/* | ||
* # Create the artifact | ||
create_artifact = { | ||
name = artifact_sculpture_armor_babr_name | ||
description = artifact_sculpture_armor_babr | ||
type = sculpture | ||
template = babr_template | ||
visuals = sculpture_babr_e_bayan | ||
wealth = scope:wealth | ||
quality = scope:quality | ||
history = { | ||
type = created_before_history | ||
} | ||
modifier = babr_e_bayan_modifier | ||
save_scope_as = newly_created_artifact | ||
decaying = yes | ||
} | ||
|
||
scope:newly_created_artifact = { | ||
set_variable = { name = historical_unique_artifact value = yes } | ||
set_variable = babr_e_bayan | ||
save_scope_as = epic | ||
} | ||
*/ | ||
} | ||
|
||
Logger.IncrementProgress(); | ||
} | ||
|
||
private void ImportArtifact(Character character, Treasure irArtifact, ModifierMapper modifierMapper, ModifierCollection ck3Modifiers, ArtifactMapper artifactMapper, LocDB irLocDB, CK3LocDB ck3LocDB, Date date) { | ||
var visualAndType = artifactMapper.GetVisualAndType(irArtifact.Key, irArtifact.IconName); | ||
if (visualAndType is null) { | ||
Logger.Warn($"Can't find a match for I:R artifact key {irArtifact.Key} and icon {irArtifact.IconName}!"); | ||
return; | ||
} | ||
var (ck3Visual, ck3Type) = visualAndType.Value; | ||
|
||
var ck3ArtifactName = $"IRToCK3_artifact_{irArtifact.Key}_{irArtifact.Id}"; | ||
var irNameLoc = irLocDB.GetLocBlockForKey(irArtifact.Key); | ||
if (irNameLoc is null) { | ||
Logger.Warn($"Can't find name loc for artifact {irArtifact.Key}!"); | ||
} else { | ||
var artifactNameLocBlock = ck3LocDB.GetOrCreateLocBlock(ck3ArtifactName); | ||
artifactNameLocBlock.CopyFrom(irNameLoc); | ||
} | ||
|
||
var ck3DescKey = $"{ck3ArtifactName}_desc"; | ||
var irDescLoc = irLocDB.GetLocBlockForKey(irArtifact.Key + "_desc"); | ||
if (irDescLoc is null) { | ||
Logger.Warn($"Can't find description loc for artifact {irArtifact.Key}!"); | ||
} else { | ||
var descLocBlock = ck3LocDB.GetOrCreateLocBlock(ck3DescKey); | ||
descLocBlock.CopyFrom(irDescLoc); | ||
} | ||
|
||
var artifactScope = $"newly_created_artifact_{irArtifact.Id}"; | ||
|
||
var ck3ModifierEffects = new Dictionary<string, double>(); | ||
foreach (var (irEffect, irEffectValue) in irArtifact.StateModifiers) { | ||
var match = modifierMapper.Match(irEffect, irEffectValue); | ||
if (match is null) { | ||
Logger.Warn($"Can't find CK3 modifier for Imperator modifier {irEffect}!"); | ||
continue; | ||
} | ||
ck3ModifierEffects[match.Value.Key] = match.Value.Value; | ||
} | ||
foreach (var (irEffect, irEffectValue) in irArtifact.CharacterModifiers) { | ||
var match = modifierMapper.Match(irEffect, irEffectValue); | ||
if (match is null) { | ||
Logger.Warn($"Can't find CK3 modifier for Imperator modifier {irEffect}!"); | ||
continue; | ||
} | ||
ck3ModifierEffects[match.Value.Key] = match.Value.Value; | ||
} | ||
var ck3ModifierId = $"{ck3ArtifactName}_modifier"; | ||
ck3Modifiers.Add(new Modifier(ck3ModifierId, ck3ModifierEffects)); | ||
|
||
string createArtifactEffect = $$""" | ||
set_artifact_rarity_illustrious = yes | ||
create_artifact = { | ||
name = {{ ck3ArtifactName }} | ||
description = {{ ck3DescKey }} | ||
type = {{ ck3Type }} | ||
# template = babr_template # TODO: check if needed | ||
visuals = {{ ck3Visual }} | ||
wealth = scope:wealth | ||
quality = scope:quality | ||
history = { | ||
type = created_before_history | ||
} | ||
modifier = {{ ck3ModifierId }} | ||
save_scope_as = {{ artifactScope }} | ||
decaying = yes | ||
} | ||
scope:{{ artifactScope }} = { | ||
set_variable = { | ||
name = historical_unique_artifact | ||
value = yes | ||
} | ||
} | ||
"""; | ||
character.History.AddFieldValue(date, "effects", "effect", createArtifactEffect); | ||
} | ||
|
||
public void GenerateSuccessorsForOldCharacters(Title.LandedTitles titles, CultureCollection cultures, Date irSaveDate, Date ck3BookmarkDate, ulong randomSeed) { | ||
Logger.Info("Generating successors for old characters..."); | ||
|
||
var oldCharacters = this | ||
.Where(c => c.BirthDate < ck3BookmarkDate && c.DeathDate is null && ck3BookmarkDate.DiffInYears(c.BirthDate) > 60).ToArray(); | ||
|
||
var titleHolderIds = titles.GetHolderIdsForAllTitlesExceptNobleFamilyTitles(ck3BookmarkDate); | ||
|
||
var oldTitleHolders = oldCharacters | ||
.Where(c => titleHolderIds.Contains(c.Id)) | ||
.ToArray(); | ||
|
||
// For characters that don't hold any titles, just set up a death date. | ||
var randomForCharactersWithoutTitles = new Random((int)randomSeed); | ||
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); | ||
} | ||
|
||
ConcurrentDictionary<string, Title[]> titlesByHolderId = new(titles | ||
.Select(t => new {Title = t, HolderId = t.GetHolderId(ck3BookmarkDate)}) | ||
.Where(t => t.HolderId != "0") | ||
.GroupBy(t => t.HolderId) | ||
.ToDictionary(g => g.Key, g => g.Select(t => t.Title).ToArray())); | ||
|
||
ConcurrentDictionary<string, string[]> cultureIdToMaleNames = new(cultures | ||
.ToDictionary(c => c.Id, c => c.MaleNames.ToArray())); | ||
|
||
// For title holders, generate successors and add them to title history. | ||
Parallel.ForEach(oldTitleHolders, oldCharacter => { | ||
// Get all titles held by the character. | ||
var heldTitles = titlesByHolderId[oldCharacter.Id]; | ||
string? dynastyId = oldCharacter.GetDynastyId(ck3BookmarkDate); | ||
string? dynastyHouseId = oldCharacter.GetDynastyHouseId(ck3BookmarkDate); | ||
string? faithId = oldCharacter.GetFaithId(ck3BookmarkDate); | ||
string? cultureId = oldCharacter.GetCultureId(ck3BookmarkDate); | ||
string[] maleNames; | ||
if (cultureId is not null) { | ||
maleNames = cultureIdToMaleNames[cultureId]; | ||
} else { | ||
Logger.Warn($"Failed to find male names for successors of {oldCharacter.Id}."); | ||
maleNames = ["Alexander"]; | ||
} | ||
|
||
var randomSeedForCharacter = randomSeed ^ (oldCharacter.ImperatorCharacter?.Id ?? 0); | ||
var random = new Random((int)randomSeedForCharacter); | ||
|
||
int successorCount = 0; | ||
Character currentCharacter = oldCharacter; | ||
Date currentCharacterBirthDate = currentCharacter.BirthDate; | ||
while (ck3BookmarkDate.DiffInYears(currentCharacterBirthDate) >= 90) { | ||
// If the character has living male children, the oldest one will be the successor. | ||
var successorAndBirthDate = currentCharacter.Children | ||
.Where(c => c is {Female: false, DeathDate: null}) | ||
.Select(c => new { Character = c, c.BirthDate }) | ||
.OrderBy(x => x.BirthDate) | ||
.FirstOrDefault(); | ||
|
||
Character successor; | ||
Date currentCharacterDeathDate; | ||
Date successorBirthDate; | ||
if (successorAndBirthDate is not null) { | ||
successor = successorAndBirthDate.Character; | ||
successorBirthDate = successorAndBirthDate.BirthDate; | ||
|
||
// Roll a dice to determine how much longer the character will live. | ||
// But make sure the successor is at least 16 years old when the old character dies. | ||
var successorAgeAtBookmarkDate = ck3BookmarkDate.DiffInYears(successorBirthDate); | ||
var yearsUntilSuccessorBecomesAnAdult = Math.Max(16 - successorAgeAtBookmarkDate, 0); | ||
|
||
var yearsToLive = random.Next((int)Math.Ceiling(yearsUntilSuccessorBecomesAnAdult), 25); | ||
int currentCharacterAge = random.Next(30 + yearsToLive, 80); | ||
currentCharacterDeathDate = currentCharacterBirthDate.ChangeByYears(currentCharacterAge); | ||
// Needs to be after the save date. | ||
if (currentCharacterDeathDate <= irSaveDate) { | ||
currentCharacterDeathDate = irSaveDate.ChangeByDays(1); | ||
} | ||
} else { | ||
// We don't want all the generated successors on the map to have the same birth date. | ||
var yearsUntilHeir = random.Next(1, 5); | ||
|
||
// Make the old character live until the heir is at least 16 years old. | ||
var successorAge = random.Next(yearsUntilHeir + 16, 30); | ||
int currentCharacterAge = random.Next(30 + successorAge, 80); | ||
currentCharacterDeathDate = currentCharacterBirthDate.ChangeByYears(currentCharacterAge); | ||
if (currentCharacterDeathDate <= irSaveDate) { | ||
currentCharacterDeathDate = irSaveDate.ChangeByDays(1); | ||
} | ||
|
||
// Generate a new successor. | ||
string id = $"irtock3_{oldCharacter.Id}_successor_{successorCount}"; | ||
string firstName = maleNames[random.Next(0, maleNames.Length)]; | ||
|
||
successorBirthDate = currentCharacterDeathDate.ChangeByYears(-successorAge); | ||
successor = new Character(id, firstName, successorBirthDate, this) {FromImperator = true}; | ||
Add(successor); | ||
if (currentCharacter.Female) { | ||
successor.Mother = currentCharacter; | ||
} else { | ||
successor.Father = currentCharacter; | ||
} | ||
if (cultureId is not null) { | ||
successor.SetCultureId(cultureId, null); | ||
} | ||
if (faithId is not null) { | ||
successor.SetFaithId(faithId, null); | ||
} | ||
if (dynastyId is not null) { | ||
successor.SetDynastyId(dynastyId, null); | ||
} | ||
if (dynastyHouseId is not null) { | ||
successor.SetDynastyHouseId(dynastyHouseId, null); | ||
} | ||
} | ||
|
||
currentCharacter.DeathDate = currentCharacterDeathDate; | ||
// On the old character death date, the successor should inherit all titles. | ||
foreach (var heldTitle in heldTitles) { | ||
heldTitle.SetHolder(successor, currentCharacterDeathDate); | ||
} | ||
|
||
// Move to the successor and repeat the process. | ||
currentCharacter = successor; | ||
currentCharacterBirthDate = successorBirthDate; | ||
++successorCount; | ||
} | ||
|
||
// 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; | ||
}); | ||
} | ||
|
||
internal void ConvertImperatorCharacterDNA(DNAFactory dnaFactory) { | ||
Logger.Info("Converting Imperator character DNA to CK3..."); | ||
foreach (var character in this) { | ||
if (character.ImperatorCharacter is null) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using commonItems.Collections; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace ImperatorToCK3.CK3.Modifiers; | ||
|
||
public class Modifier : IIdentifiable<string> { | ||
public string Id { get; } | ||
private readonly Dictionary<string, double> effects = new(); | ||
|
||
public Modifier(string id, IDictionary<string, double> effects) { | ||
Id = id; | ||
this.effects = new Dictionary<string, double>(effects); | ||
} | ||
|
||
public override string ToString() { | ||
var output = new StringBuilder(); | ||
output.AppendLine($"{Id} = {{"); | ||
foreach (var effect in effects) { | ||
output.AppendLine($"\t{effect.Key} = {effect.Value}"); | ||
} | ||
output.AppendLine("}"); | ||
return output.ToString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using commonItems.Collections; | ||
using System.Text; | ||
|
||
namespace ImperatorToCK3.CK3.Modifiers; | ||
|
||
public class ModifierCollection : IdObjectCollection<string, Modifier> { | ||
public override string ToString() { | ||
var output = new StringBuilder(); | ||
foreach (var modifier in this) { | ||
output.AppendLine(modifier.ToString()); | ||
} | ||
return output.ToString(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[misspell] reported by reviewdog 🐶
"artefact" is a misspelling of "artifact"