Skip to content

Minor tweaks to importing I:R characters and families #2561

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

Merged
merged 1 commit into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions ImperatorToCK3/CK3/Characters/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,174 +359,178 @@
}
}

internal Character(
Imperator.Characters.Character impCharacter,
CharacterCollection characters,
ReligionMapper religionMapper,
CultureMapper cultureMapper,
TraitMapper traitMapper,
NicknameMapper nicknameMapper,
LocDB irLocDB,
CK3LocDB ck3LocDB,
MapData irMapData,
ProvinceMapper provinceMapper, // used to determine ck3 province for religion mapper
DeathReasonMapper deathReasonMapper,
DNAFactory dnaFactory,
Date dateOnConversion,
Configuration config,
ISet<string> unlocalizedImperatorNames
) {
this.characters = characters;

ImperatorCharacter = impCharacter;
ImperatorCharacter.CK3Character = this;
Id = "imperator" + ImperatorCharacter.Id;
FromImperator = true;

if (!string.IsNullOrEmpty(ImperatorCharacter.CustomName)) {
var loc = ImperatorCharacter.CustomName;
var locKey = CommonFunctions.NormalizeUTF8Path(loc.FoldToASCII().Replace(' ', '_'));
var name = $"IRTOCK3_CUSTOM_NAME_{locKey}";
SetName(name, null);

var ck3NameLocBlock = ck3LocDB.GetOrCreateLocBlock(name);
foreach (var language in ConverterGlobals.SupportedLanguages) {
ck3NameLocBlock[language] = loc;
}
} else {
var nameLoc = ImperatorCharacter.Name;
var name = nameLoc.Replace(' ', '_');
SetName(name, null);
if (!string.IsNullOrEmpty(name)) {
var ck3NameLocBlock = ck3LocDB.GetOrCreateLocBlock(name);
var matchedLocBlock = irLocDB.GetLocBlockForKey(name);
if (matchedLocBlock is not null) {
ck3NameLocBlock.CopyFrom(matchedLocBlock);
} else { // fallback: use unlocalized name as displayed name
unlocalizedImperatorNames.Add(name);
ck3NameLocBlock[ConverterGlobals.PrimaryLanguage] = nameLoc;
}
}
}

Female = ImperatorCharacter.Female;

// Determine valid (not dropped in province mappings) "source I:R province" and "source CK3 province"
// to be used by religion mapper. Don't give up without a fight.
ulong? irProvinceId = ImperatorCharacter.GetSourceLandProvince(irMapData);

var impProvForProvinceMapper = irProvinceId;
if ((!impProvForProvinceMapper.HasValue || provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper.Value).Count == 0) && ImperatorCharacter.Father is not null) {
impProvForProvinceMapper = ImperatorCharacter.Father.ProvinceId;
var irProvIdForProvMapper = irProvinceId;
if (IsImperatorProvIdInvalidForCharacterSource(irProvIdForProvMapper, provinceMapper) && ImperatorCharacter.Father is not null) {
irProvIdForProvMapper = ImperatorCharacter.Father.ProvinceId;
}
if ((!impProvForProvinceMapper.HasValue || provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper.Value).Count == 0) && ImperatorCharacter.Mother is not null) {
impProvForProvinceMapper = ImperatorCharacter.Mother.ProvinceId;
if (IsImperatorProvIdInvalidForCharacterSource(irProvIdForProvMapper, provinceMapper) && ImperatorCharacter.Mother is not null) {
irProvIdForProvMapper = ImperatorCharacter.Mother.ProvinceId;
}
if ((!impProvForProvinceMapper.HasValue || provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper.Value).Count == 0) && ImperatorCharacter.Spouses.Count > 0) {
if (IsImperatorProvIdInvalidForCharacterSource(irProvIdForProvMapper, provinceMapper) && ImperatorCharacter.Spouses.Count > 0) {
var firstSpouse = ImperatorCharacter.Spouses.First().Value;
impProvForProvinceMapper = firstSpouse.ProvinceId;
irProvIdForProvMapper = firstSpouse.ProvinceId;
}

var ck3ProvinceNumbers = impProvForProvinceMapper.HasValue ? provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper.Value) : [];
var ck3ProvinceNumbers = irProvIdForProvMapper.HasValue ? provinceMapper.GetCK3ProvinceNumbers(irProvIdForProvMapper.Value) : [];
ulong? ck3ProvinceId = ck3ProvinceNumbers.Count > 0 ? ck3ProvinceNumbers[0] : null;

var cultureMatch = cultureMapper.Match(
ImperatorCharacter.Culture,
ck3ProvinceId,
irProvinceId,
ImperatorCharacter.Country?.HistoricalTag
);
if (cultureMatch is null) {
Logger.Warn($"Could not determine CK3 culture for Imperator character {ImperatorCharacter.Id}" +
$" with culture {ImperatorCharacter.Culture}!");
} else {
SetCultureId(cultureMatch, null);
}

var faithMatch = religionMapper.Match(
ImperatorCharacter.Religion,
GetCultureId(dateOnConversion),
ck3ProvinceId,
irProvinceId,
ImperatorCharacter.HomeCountry?.HistoricalTag,
config
);
if (faithMatch is not null) {
SetFaithId(faithMatch, null);
}

// Determine character attributes.
History.AddFieldValue(null, "diplomacy", "diplomacy", ImperatorCharacter.Attributes.Charisma);
History.AddFieldValue(null, "martial", "martial", ImperatorCharacter.Attributes.Martial);
History.AddFieldValue(null, "stewardship", "stewardship", ImperatorCharacter.Attributes.Finesse);
var intrigue = (ImperatorCharacter.Attributes.Finesse + ImperatorCharacter.Attributes.Charisma) / 2;
History.AddFieldValue(null, "intrigue", "intrigue", intrigue);
History.AddFieldValue(null, "learning", "learning", ImperatorCharacter.Attributes.Zeal);

if (impCharacter.Fertility.HasValue) {
History.AddFieldValue(null, "fertility", "fertility", impCharacter.Fertility.Value);
}

if (impCharacter.Health is not null) {
// In I:R, health is a value between 0 and 100, with 100 being the best.
// In CK3, 0 means near death, ≥ 7 means excellent health.
// https://imperator.paradoxwikis.com/Characters#Secondary
// https://ck3.paradoxwikis.com/Attributes#Health
var ck3Health = impCharacter.Health.Value / 10;
History.AddFieldValue(null, "health", "health", ck3Health);
}

foreach (var traitId in traitMapper.GetCK3TraitsForImperatorTraits(ImperatorCharacter.Traits)) {
AddBaseTrait(traitId);
}

BirthDate = ImperatorCharacter.BirthDate;
DeathDate = ImperatorCharacter.DeathDate;
var impDeathReason = ImperatorCharacter.DeathReason;
if (impDeathReason is not null) {
DeathReason = deathReasonMapper.GetCK3ReasonForImperatorReason(impDeathReason);
}

var nicknameMatch = nicknameMapper.GetCK3NicknameForImperatorNickname(ImperatorCharacter.Nickname);
if (nicknameMatch is not null) {
var nicknameDate = ImperatorCharacter.DeathDate ?? dateOnConversion;
SetNickname(nicknameMatch, nicknameDate);
}

if (ImperatorCharacter.Wealth != 0) {
Gold = ImperatorCharacter.Wealth * config.ImperatorCurrencyRate;
}

// If character is imprisoned, set jailor.
SetJailor();
SetEmployerFromImperator();

void SetJailor() {
if (ImperatorCharacter.PrisonerHome is null) {
return;
}

var prisonCountry = ImperatorCharacter.Country;
if (prisonCountry is null) {
Logger.Warn($"Imperator character {ImperatorCharacter.Id} is imprisoned but has no country!");
} else if (prisonCountry.CK3Title is null) {
Logger.Debug($"Imperator character {ImperatorCharacter.Id}'s prison country does not exist in CK3!");
} else {
jailorId = prisonCountry.CK3Title.GetHolderId(dateOnConversion);
}
}

void SetEmployerFromImperator() {
var prisonerHome = ImperatorCharacter.PrisonerHome;
var homeCountry = ImperatorCharacter.HomeCountry;
if (prisonerHome?.CK3Title is not null) { // is imprisoned
SetEmployerId(prisonerHome.CK3Title.GetHolderId(dateOnConversion), null);
} else if (homeCountry?.CK3Title is not null) {
SetEmployerId(homeCountry.CK3Title.GetHolderId(dateOnConversion), null);
}
}
}


Check notice on line 529 in ImperatorToCK3/CK3/Characters/Character.cs

View check run for this annotation

codefactor.io / CodeFactor

ImperatorToCK3/CK3/Characters/Character.cs#L362-L529

Complex Method
private static bool IsImperatorProvIdInvalidForCharacterSource(ulong? impProvForProvinceMapper, ProvinceMapper provinceMapper) {
return !impProvForProvinceMapper.HasValue || provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper.Value).Count == 0;
}

public void SetCultureId(string cultureId, Date? date) {
History.AddFieldValue(date, "culture", "culture", cultureId);
}
Expand Down
7 changes: 2 additions & 5 deletions ImperatorToCK3/CK3/Dynasties/DynastyCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ public void ImportImperatorFamilies(Imperator.World irWorld, CultureMapper cultu
var imperatorCharacters = irWorld.Characters;
// The collection only holds dynasties converted from Imperator families, as vanilla ones aren't modified.
int importedCount = 0;
Parallel.ForEach(irWorld.Families, family => {
if (family.Minor) {
return;
}

var majorFamilies = irWorld.Families.Where(f => !f.Minor).ToArray();
Parallel.ForEach(majorFamilies, family => {
var newDynasty = new Dynasty(family, imperatorCharacters, irWorld.CulturesDB, cultureMapper, irLocDB, ck3LocDB, date);
AddOrReplace(newDynasty);
Interlocked.Increment(ref importedCount);
Expand Down
Loading