Skip to content
Open
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
1 change: 0 additions & 1 deletion .github/workflows/build_dev_version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ jobs:
onlyPrefix: 'ImperatorToCK3-${{ matrix.build }}-dev-${{ env.BRANCH_NAME }}'
- uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
- name: "Setup Dotnet for use with actions"
# don't run on self-hosted Windows
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ jobs:
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
- name: "Check if docs folders exist"
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/spelling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ jobs:
**/*_l_polish.yml
**/*_l_korean.yml
**/*_l_german.yml
ImperatorToCK3/Data_Files/configurables/province_mappings/invictus_to_wtwsms.txt


3 changes: 3 additions & 0 deletions .github/workflows/steam_mod_update_notifier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
check-steam-mod-updates:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Check Steam Workshop mods and notify
shell: bash
env:
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ jobs:
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
- name: "Setup Dotnet for use with actions"
uses: actions/setup-dotnet@v5
Expand All @@ -41,7 +40,6 @@ jobs:
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
- name: "Setup Dotnet for use with actions"
# don't run on self-hosted Windows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ public void ImperatorCountriesGoldCanBeDistributedAmongRulerAndVassals() {
ruler_term={ character=1000 start_date=440.10.1 }
");
var country = Country.Parse(countryReader, 589);

imperatorWorld.Provinces[1].OwnerCountry = country;
imperatorWorld.Provinces[2].OwnerCountry = country;
imperatorWorld.Provinces[3].OwnerCountry = country;
imperatorWorld.Provinces[4].OwnerCountry = country;
imperatorWorld.Provinces[5].OwnerCountry = country;
imperatorWorld.Provinces[6].OwnerCountry = country;

Assert.Equal(200, country.Currencies.Gold);
imperatorWorld.Countries.Add(country);
imperatorWorld.Characters.LinkCountries(imperatorWorld.Countries);
Expand Down Expand Up @@ -499,9 +507,9 @@ private static void SetPrivateProperty(object target, string propertyName, objec
var targetType = target.GetType();
var property = targetType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Assert.NotNull(property);
var setter = property!.GetSetMethod(nonPublic: true);
var setter = property.GetSetMethod(nonPublic: true);
Assert.NotNull(setter);
setter!.Invoke(target, new[] { value });
setter.Invoke(target, [value]);
}

private static ImperatorRulerTerm CreateRulerTerm(Date startDate, string governmentId) {
Expand Down
85 changes: 79 additions & 6 deletions ImperatorToCK3.UnitTests/CK3/Titles/LandedTitlesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,22 +235,33 @@ public void GovernorshipsCanBeRecognizedAsCountyLevel() {
var config = new Configuration { ImperatorPath = "TestFiles/LandedTitlesTests/Imperator" };
var imperatorWorld = new TestImperatorWorld(config);

imperatorWorld.Provinces.Add(new Province(1));
imperatorWorld.Provinces.Add(new Province(2));
imperatorWorld.Provinces.Add(new Province(3));
var irProv1 = new Province(1);
var irProv2 = new Province(2);
var irProv3 = new Province(3);
imperatorWorld.Provinces.Add(irProv1);
imperatorWorld.Provinces.Add(irProv2);
imperatorWorld.Provinces.Add(irProv3);

var governor = new ImperatorToCK3.Imperator.Characters.Character(25212);
imperatorWorld.Characters.Add(governor);

var countryReader = new BufferedReader("tag=PRY capital=1");
var country = Country.Parse(countryReader, 589);
irProv1.OwnerCountry = country;
irProv2.OwnerCountry = country;
irProv3.OwnerCountry = country;
country.RegisterProvince(irProv1);
country.RegisterProvince(irProv2);
country.RegisterProvince(irProv3);
imperatorWorld.Countries.Add(country);

imperatorWorld.Areas.LoadAreas(imperatorWorld.ModFS, imperatorWorld.Provinces);
var irRegionMapper = new ImperatorRegionMapper(imperatorWorld.Areas, irMapData);
irRegionMapper.LoadRegions(imperatorWorld.ModFS, new ColorFactory());
Assert.True(irRegionMapper.RegionNameIsValid("galatia_area"));
Assert.True(irRegionMapper.RegionNameIsValid("galatia_region"));
Assert.True(irRegionMapper.ProvinceIsInRegion(2, "galatia_region"));
Assert.True(irRegionMapper.ProvinceIsInRegion(3, "galatia_region"));
var ck3RegionMapper = new CK3RegionMapper();

var reader = new BufferedReader(
Expand Down Expand Up @@ -335,14 +346,14 @@ public void GovernorshipsCanBeRecognizedAsCountyLevel() {
title => Assert.Equal("d_IRTOCK3_PRY", title.Id)
);

var provinces = new ProvinceCollection(ck3ModFS);
var ck3Provinces = new ProvinceCollection(ck3ModFS);
var ck3MapData = new MapData(ck3ModFS);
ck3MapData.ProvinceDefinitions.Add(new(1));
ck3MapData.ProvinceDefinitions.Add(new(2));
ck3MapData.ProvinceDefinitions.Add(new(3));
provinces.ImportImperatorProvinces(imperatorWorld, ck3MapData, titles, cultureMapper, religionMapper, provinceMapper, conversionDate, config);
ck3Provinces.ImportImperatorProvinces(imperatorWorld, ck3MapData, titles, cultureMapper, religionMapper, provinceMapper, conversionDate, config);
// Country 589 is imported as duchy-level title, so its governorship of galatia_region will be county level.
titles.ImportImperatorGovernorships(imperatorWorld, provinces, tagTitleMapper, irLocDB, ck3LocDB, config, provinceMapper, definiteFormMapper, irRegionMapper, coaMapper, countyLevelGovernorships);
titles.ImportImperatorGovernorships(imperatorWorld, ck3Provinces, tagTitleMapper, irLocDB, ck3LocDB, config, provinceMapper, definiteFormMapper, irRegionMapper, coaMapper, countyLevelGovernorships);

Assert.Collection(titles,
title => Assert.Equal("c_county1", title.Id),
Expand Down Expand Up @@ -610,6 +621,68 @@ public void TitlesCanBeExpandedInOtherFiles() {
Assert.Equal("c_karakorum", mongoliaKingdom.CapitalCountyId);
}

[Fact]
public void KingdomUsesNextDominantHeritageWhenMostDominantOneCannotProvideEmpire() {
var date = new Date(867, 1, 1);
var titles = new Title.LandedTitles();
titles.LoadTitles(new BufferedReader(
"e_mongolia = { }\n" +
"k_test = {\n" +
"\td_test = {\n" +
"\t\tc_county1 = { b_barony1 = { province = 1 } }\n" +
"\t\tc_county2 = { b_barony2 = { province = 2 } }\n" +
"\t\tc_county3 = { b_barony3 = { province = 3 } }\n" +
"\t}\n" +
"}\n" +
"k_xia = {\n" +
"\td_xia = {\n" +
"\t\tc_xia_county = { b_xia_barony = { province = 4 } }\n" +
"\t}\n" +
"}\n"
), colorFactory);

var cultureCollection = new TestCK3CultureCollection();
cultureCollection.GenerateTestCulture("han", "heritage_chinese");
cultureCollection.GenerateTestCulture("mongol", "heritage_mongolic");

var characters = new CharacterCollection();
var hanHolder1 = new Character("1", "Han Holder 1", new Date(800, 1, 1), characters);
hanHolder1.SetCultureId("han", null);
characters.Add(hanHolder1);

var hanHolder2 = new Character("2", "Han Holder 2", new Date(801, 1, 1), characters);
hanHolder2.SetCultureId("han", null);
characters.Add(hanHolder2);

var mongolHolder = new Character("3", "Mongol Holder", new Date(802, 1, 1), characters);
mongolHolder.SetCultureId("mongol", null);
characters.Add(mongolHolder);

titles["c_county1"].SetHolder(hanHolder1, date);
titles["c_county2"].SetHolder(hanHolder2, date);
titles["c_county3"].SetHolder(mongolHolder, date);
titles["c_xia_county"].SetHolder(mongolHolder, date);

var heritageMapPath = Path.Combine("configurables", "heritage_empires_map.txt");
var originalHeritageMap = File.Exists(heritageMapPath) ? File.ReadAllText(heritageMapPath) : null;
Directory.CreateDirectory("configurables");
File.WriteAllText(heritageMapPath,
"heritage_chinese = none\n" +
"heritage_mongolic = e_mongolia\n");

try {
titles.SetDeJureKingdomsAndAbove(date, cultureCollection, characters, new MapData(ck3ModFS), new CK3RegionMapper(), new TestCK3LocDB());

Assert.Equal("e_mongolia", titles["k_test"].DeJureLiege?.Id);
} finally {
if (originalHeritageMap is null) {
File.Delete(heritageMapPath);
} else {
File.WriteAllText(heritageMapPath, originalHeritageMap);
}
}
}

[Fact]
public void RemoveBreaksAllLinks() {
var landedTitles = new Title.LandedTitles();
Expand Down
30 changes: 19 additions & 11 deletions ImperatorToCK3/CK3/Titles/LandedTitles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
return newTitle;
}

internal Title Add(
private Title Add(
string id,
Governorship governorship,
Country country,
Expand Down Expand Up @@ -778,6 +778,11 @@
// add new ones from Imperator governorships.
var counter = 0;
foreach (var governorship in governorships) {
// Don't import if the governorship has no I:R provinces.
if (governorship.GetIRProvinceCount(irWorld.Provinces) == 0) {
continue;
}

ImportImperatorGovernorship(
governorship,
this,
Expand Down Expand Up @@ -819,7 +824,8 @@

var id = DetermineId(governorship, titles, irProvinces, ck3Provinces, imperatorRegionMapper, tagTitleMapper, provinceMapper);
if (id is null) {
Logger.Warn($"Cannot convert {governorship.Region.Id} of country {country.Id}");
Logger.Warn($"Cannot convert {governorship.Region.Id} of country {country.Id}. " +
$"I:R provinces: {string.Join(", ", governorship.GetIRProvinces(irProvinces).Select(p => p.Id))}");
return;
}

Expand Down Expand Up @@ -861,54 +867,54 @@
}
}

public void ImportImperatorHoldings(ProvinceCollection ck3Provinces, Imperator.Characters.CharacterCollection irCharacters, Date conversionDate) {
Logger.Info("Importing Imperator holdings...");
var counter = 0;

var highLevelTitlesThatHaveHolders = this
.Where(t => t.Rank >= TitleRank.duchy && t.GetHolderId(conversionDate) != "0")
.ToImmutableList();
var highLevelTitleCapitalBaronyIds = highLevelTitlesThatHaveHolders
.Select(t=>t.CapitalCounty?.CapitalBaronyId ?? t.CapitalBaronyId)
.ToImmutableHashSet();

// Dukes and above should be excluded from having their holdings converted.
// Otherwise, governors with holdings would own parts of other governorships.
var dukeAndAboveIds = highLevelTitlesThatHaveHolders
.Where(t => t.Rank >= TitleRank.duchy)
.Select(t => t.GetHolderId(conversionDate))
.ToImmutableHashSet();

// We exclude baronies that are capitals of duchies and above.
var eligibleBaronies = this
.Where(t => t.Rank == TitleRank.barony)
.Where(b => !highLevelTitleCapitalBaronyIds.Contains(b.Id))
.ToArray();

var countyCapitalBaronies = eligibleBaronies
.Where(b => b.DeJureLiege?.CapitalBaronyId == b.Id)
.OrderBy(b => b.Id)
.ToArray();

var nonCapitalBaronies = eligibleBaronies.Except(countyCapitalBaronies).OrderBy(b => b.Id).ToArray();

// In CK3, a county holder shouldn't own baronies in counties that are not their own.
// This dictionary tracks what counties are held by what characters.
Dictionary<string, HashSet<string>> countiesPerCharacter = []; // characterId -> countyIds

// Evaluate all capital baronies first (we want to distribute counties first, then baronies).
foreach (var barony in countyCapitalBaronies) {
var ck3Province = GetBaronyProvince(barony);
if (ck3Province is null) {
continue;
}

// Skip none holdings and temple holdings.
if (ck3Province.GetHoldingType(conversionDate) is "church_holding" or "none") {
continue;
}

var irProvince = ck3Province.PrimaryImperatorProvince; // TODO: when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces

Check warning on line 917 in ImperatorToCK3/CK3/Titles/LandedTitles.cs

View workflow job for this annotation

GitHub Actions / test_and_check_coverage

TODO when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)

Check warning on line 917 in ImperatorToCK3/CK3/Titles/LandedTitles.cs

View workflow job for this annotation

GitHub Actions / test (macos-14)

TODO when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)
var ck3Owner = GetEligibleCK3OwnerForImperatorProvince(irProvince);
if (ck3Owner is null) {
continue;
Expand Down Expand Up @@ -962,7 +968,7 @@
continue;
}

var irProvince = ck3Province.PrimaryImperatorProvince; // TODO: when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces

Check warning on line 971 in ImperatorToCK3/CK3/Titles/LandedTitles.cs

View workflow job for this annotation

GitHub Actions / test_and_check_coverage

TODO when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)

Check warning on line 971 in ImperatorToCK3/CK3/Titles/LandedTitles.cs

View workflow job for this annotation

GitHub Actions / test (macos-14)

TODO when the holding owner of the primary I:R province is not able to hold the CK3 equivalent, also check the holding owners from secondary source provinces (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)
var ck3Owner = GetEligibleCK3OwnerForImperatorProvince(irProvince);
if (ck3Owner is null) {
continue;
Expand Down Expand Up @@ -1388,21 +1394,23 @@
}
kingdomToDominantHeritagesDict[kingdom.Id] = dominantHeritages;

var dominantHeritage = dominantHeritages[0];

if (heritageToEmpireDict.TryGetValue(dominantHeritage.Id, out var empire)) {
if (empire is null) {
// The heritage is not supposed to have an empire.
continue;
foreach (var dominantHeritage in dominantHeritages) {
if (heritageToEmpireDict.TryGetValue(dominantHeritage.Id, out var empire)) {
if (empire is null) {
// The heritage is not supposed to have an empire, try the next dominant heritage.
continue;
}
kingdom.DeJureLiege = empire;
break;
}
kingdom.DeJureLiege = empire;
} else {
// Create new de jure empire based on heritage.

// Create new de jure empire based on the first usable heritage.
var heritageEmpire = CreateEmpireForHeritage(dominantHeritage, ck3Cultures, ck3LocDB);
removableEmpireIds.Add(heritageEmpire.Id);

kingdom.DeJureLiege = heritageEmpire;
heritageToEmpireDict[dominantHeritage.Id] = heritageEmpire;
break;
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion ImperatorToCK3/CK3/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@
private void LoadCorrectProvinceMappingsFile(Imperator.World irWorld, Configuration config) {
// Terra Indomita mappings should be used if either TI or Antiquitas is detected.
bool irHasTI = config.TerraIndomitaDetected;

bool ck3HasRajasOfAsia = config.RajasOfAsiaEnabled;
bool ck3HasAEP = config.AsiaExpansionProjectEnabled;

Expand All @@ -562,6 +562,8 @@
mappingsToUse = "terra_indomita_to_aep";
} else if (irHasTI) {
mappingsToUse = "terra_indomita_to_vanilla_ck3";
} else if (config.WhenTheWorldStoppedMakingSenseEnabled) {
mappingsToUse = "invictus_to_wtwsms";
} else if (config is {InvictusDetected: true, Invictus1_7Detected: true}) {
mappingsToUse = "invictus_1_7_to_vanilla_ck3";
} else if (config.InvictusDetected) {
Expand Down Expand Up @@ -603,93 +605,93 @@
}
}

private void OverwriteCountiesHistory(CountryCollection irCountries, List<Governorship> governorships, List<KeyValuePair<Country, Dependency?>> countyLevelCountries, List<Governorship> countyLevelGovernorships, Imperator.Characters.CharacterCollection impCharacters, Imperator.Provinces.ProvinceCollection irProvinces, Date conversionDate) {
Logger.Info("Overwriting counties' history...");
FrozenSet<Governorship> governorshipsSet = governorships.ToFrozenSet();
FrozenSet<Governorship> countyLevelGovernorshipsSet = countyLevelGovernorships.ToFrozenSet();

foreach (var county in LandedTitles.Counties) {
if (county.NobleFamily == true) {
continue;
}
if (county.CapitalBaronyProvinceId is null) {
Logger.Warn($"County {county} has no capital barony province!");
continue;
}
ulong capitalBaronyProvId = (ulong)county.CapitalBaronyProvinceId;
if (capitalBaronyProvId == 0) {
// title's capital province has an invalid ID (0 is not a valid province in CK3)
Logger.Warn($"County {county} has invalid capital barony province!");
continue;
}

if (!Provinces.ContainsKey(capitalBaronyProvId)) {
Logger.Warn($"Capital barony province not found: {capitalBaronyProvId}");
continue;
}

var ck3CapitalBaronyProvince = Provinces[capitalBaronyProvId];
var irProvince = ck3CapitalBaronyProvince.PrimaryImperatorProvince;
// If the county capital's primary I:R province has no owner,
// try to use other source provinces.
// If this fails, try using source provinces of other baronies.
if (irProvince?.OwnerCountry is null) {
foreach (var secondarySourceProv in ck3CapitalBaronyProvince.SecondaryImperatorProvinces) {
if (secondarySourceProv.OwnerCountry is null) {
continue;
}

irProvince = secondarySourceProv;
Logger.Debug($"Using secondary source province {secondarySourceProv.Id} of capital barony" +
$"province {capitalBaronyProvId} for history of county {county.Id}!");
}
}
if (irProvince?.OwnerCountry is null) {
foreach (var barony in county.DeJureVassals) {
var baronyCk3ProvId = barony.ProvinceId;
if (baronyCk3ProvId is null) {
continue;
}
var primarySourceProvForBarony = Provinces[baronyCk3ProvId.Value].PrimaryImperatorProvince;
if (primarySourceProvForBarony?.OwnerCountry is null) {
continue;
}

irProvince = primarySourceProvForBarony;
Logger.Debug($"Using province {baronyCk3ProvId.Value} of barony {barony.Id} instead of" +
$"capital barony province {capitalBaronyProvId} for history of county {county.Id}!");
break;
}
}
if (irProvince?.OwnerCountry is null) {
foreach (var barony in county.DeJureVassals) {
var baronyCk3ProvId = barony.ProvinceId;
if (baronyCk3ProvId is null) {
continue;
}

var secondaryProvWithOwner = Provinces[baronyCk3ProvId.Value].SecondaryImperatorProvinces
.FirstOrDefault(p => p.OwnerCountry is not null);
if (secondaryProvWithOwner is null) {
continue;
}

irProvince = secondaryProvWithOwner;
Logger.Debug($"Using province {baronyCk3ProvId.Value} of barony {barony.Id} instead of" +
$"capital barony province {capitalBaronyProvId} for history of county {county.Id}!");
break;
}
}

if (irProvince is null) { // probably outside of Imperator map
continue;
}

OverwriteCountyHistory(county, irProvince, irCountries, countyLevelCountries, governorshipsSet, countyLevelGovernorshipsSet, impCharacters, irProvinces, conversionDate);
}
Logger.IncrementProgress();
}

Check notice on line 694 in ImperatorToCK3/CK3/World.cs

View check run for this annotation

codefactor.io / CodeFactor

ImperatorToCK3/CK3/World.cs#L608-L694

Complex Method
private void OverwriteCountyHistory(Title county, Imperator.Provinces.Province irProvince, CountryCollection irCountries,
List<KeyValuePair<Country, Dependency?>> countyLevelCountries, FrozenSet<Governorship> governorshipsSet, FrozenSet<Governorship> countyLevelGovernorshipsSet,
Imperator.Characters.CharacterCollection irCharacters, Imperator.Provinces.ProvinceCollection irProvinces, Date conversionDate) {
Expand Down Expand Up @@ -1186,178 +1188,178 @@
}
}

private void GenerateFillerHoldersForUnownedLands(Imperator.Provinces.ProvinceCollection irProvinces, CultureCollection cultures, Configuration config) {
Logger.Info("Generating filler holders for unowned lands...");
var date = config.CK3BookmarkDate;
List<Title> unheldCounties = [];
foreach (var county in LandedTitles.Counties) {
if (county.NobleFamily == true) {
continue;
}

// If the county's provinces are have no owners in Imperator,
// // generate a filler holder even if a valid vanilla holder exists.
// This fixes stuff like a vanilla Tang China in one county.
var irProvIds = county.CountyProvinceIds
.SelectMany(id => provinceMapper.GetImperatorProvinceNumbers(id)).ToArray();
if (irProvIds.Length > 0 && irProvIds.All(p => !irProvinces.TryGetValue(p, out var irProv) || irProv.OwnerCountry is null)) {
Logger.Debug($"Adding {county.Id} to unheld counties because all its provinces are mapped to I:R wastelands.");
unheldCounties.Add(county);
continue;
}

var holderId = county.GetHolderId(date);
if (holderId == "0") {
unheldCounties.Add(county);
} else if (Characters.TryGetValue(holderId, out var holder)) {
if (holder.DeathDate is not null && holder.DeathDate <= date) {
Logger.Debug($"Adding {county.Id} to unheld counties because holder {holderId} is dead.");
unheldCounties.Add(county);
}
}
}

var duchyIdToHolderDict = new Dictionary<string, Character>();

foreach (var county in unheldCounties) {
if (config.FillerDukes) {
var duchy = county.DeJureLiege;
if (duchy is not null && duchy.Rank == TitleRank.duchy) {
if (duchyIdToHolderDict.TryGetValue(duchy.Id, out var duchyHolder)) {
county.SetHolder(duchyHolder, date);
continue;
}
}
}

var candidateProvinces = new OrderedSet<Province>();
if (county.CapitalBaronyProvinceId is not null) {
// Give priority to capital province.
if (Provinces.TryGetValue(county.CapitalBaronyProvinceId.Value, out var capitalProvince)) {
candidateProvinces.Add(capitalProvince);
}
}

var allCountyProvinces = county.CountyProvinceIds
.Select(id => Provinces.TryGetValue(id, out var province) ? province : null)
.Where(p => p is not null)
.Select(p => p!);
candidateProvinces.UnionWith(allCountyProvinces);

int pseudoRandomSeed;
if (candidateProvinces.Count != 0) {
pseudoRandomSeed = (int)candidateProvinces.First().Id;
} else {
// Use county ID for seed if no province is available.
pseudoRandomSeed = county.Id.Aggregate(0, (current, c) => current + c);
}

// Determine culture of the holder.
var culture = candidateProvinces
.Select(p => p.GetCulture(date, cultures))
.FirstOrDefault(c => c is not null);
if (culture is null) {
Logger.Debug($"Trying to use de jure duchy for culture of holder for {county.Id}...");
var deJureDuchy = county.DeJureLiege;
if (deJureDuchy is not null) {
culture = Provinces
.Where(p => deJureDuchy.DuchyContainsProvince(p.Id))
.Select(p => p.GetCulture(date, cultures))
.FirstOrDefault(c => c is not null);
}
if (culture is null && deJureDuchy?.DeJureLiege is not null) {
Logger.Debug($"Trying to use de jure kingdom for culture of holder for {county.Id}...");
var deJureKingdom = deJureDuchy.DeJureLiege;
culture = Provinces
.Where(p => deJureKingdom.KingdomContainsProvince(p.Id))
.Select(p => p.GetCulture(date, cultures))
.FirstOrDefault(c => c is not null);
}
if (culture is null) {
Logger.Warn($"Found no fitting culture for generated holder of {county.Id}, " +
"using first culture from database!");
culture = cultures.First();
}
}

// Determine faith of the holder.
var faithId = candidateProvinces
.Select(p => p.GetFaithId(date))
.FirstOrDefault(f => f is not null);
if (faithId is null) {
Logger.Debug($"Trying to use de jure duchy for faith of holder for {county.Id}...");
var deJureDuchy = county.DeJureLiege;
if (deJureDuchy is not null) {
faithId = Provinces
.Where(p => deJureDuchy.DuchyContainsProvince(p.Id))
.Select(p => p.GetFaithId(date))
.FirstOrDefault(f => f is not null);
}
if (faithId is null && deJureDuchy?.DeJureLiege is not null) {
Logger.Debug($"Trying to use de jure kingdom for faith of holder for {county.Id}...");
var deJureKingdom = deJureDuchy.DeJureLiege;
faithId = Provinces
.Where(p => deJureKingdom.KingdomContainsProvince(p.Id))
.Select(p => p.GetFaithId(date))
.FirstOrDefault(f => f is not null);
}
if (faithId is null) {
Logger.Warn($"Found no fitting faith for generated holder of {county.Id}, " +
"using first faith from database!");
faithId = Religions.Faiths.First().Id;
}
}

bool female = false;
string name;
var maleNames = culture.MaleNames.ToImmutableList();
if (maleNames.Count > 0) {
name = maleNames[pseudoRandomSeed % maleNames.Count];
} else { // Generate a female if no male name is available.
female = true;
var femaleNames = culture.FemaleNames.ToImmutableList();
name = femaleNames[pseudoRandomSeed % femaleNames.Count];
}
int age = 18 + (pseudoRandomSeed % 60);
var holder = new Character($"IRToCK3_{county.Id}_holder", name, date, Characters) {
FromImperator = true,
Female = female,
BirthDate = date.ChangeByYears(-age)
};
holder.SetFaithId(faithId, null);
holder.SetCultureId(culture.Id, null);
holder.History.AddFieldValue(holder.BirthDate, "effects", "effect", "{ set_variable = irtock3_uncolonized_filler }");
Characters.AddOrReplace(holder);

var countyHoldingTypes = county.CountyProvinceIds
.Select(id => Provinces.TryGetValue(id, out var province) ? province : null)
.Where(p => p is not null)
.Select(p => p!.GetHoldingType(date))
.Where(t => t is not null)
.Select(t => t!)
.ToFrozenSet();
string government = countyHoldingTypes.Contains("castle_holding")
? "feudal_government"
: "tribal_government";

county.SetHolder(holder, date);
if (config.FillerDukes) {
var duchy = county.DeJureLiege;
if (duchy is null || duchy.Rank != TitleRank.duchy) {
continue;
}

duchy.SetHolder(holder, date);
duchy.SetGovernment(government, date);
duchy.SetDeFactoLiege(newLiege: null, date);
duchyIdToHolderDict[duchy.Id] = holder;
} else {
county.SetGovernment(government, date);
}
county.SetDeFactoLiege(newLiege: null, date);
}
}

Check warning on line 1362 in ImperatorToCK3/CK3/World.cs

View check run for this annotation

codefactor.io / CodeFactor

ImperatorToCK3/CK3/World.cs#L1191-L1362

Very Complex Method
private void DetermineCK3Dlcs(Configuration config) {
var dlcFolderPath = Path.Join(config.CK3Path, "game/dlc");
if (!Directory.Exists(dlcFolderPath)) {
Expand Down
1 change: 0 additions & 1 deletion ImperatorToCK3/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using ImperatorToCK3.CommonUtils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1704,6 +1704,8 @@ irtock3_form_prefecture_magna_taprobana_decision = {
}
}


{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# irtock3_rome_empire_division_insulae_remotae: "Insulae Remotae"
irtock3_form_prefecture_insulae_remotae_decision = {
picture = {
Expand Down Expand Up @@ -1845,6 +1847,7 @@ irtock3_form_prefecture_insulae_solis_decision = {
irtock3_form_roman_prefecture_effect = { REGION = irtock3_rome_empire_division_insulae_solis }
}
}
{% endunless %}

# irtock3_rome_empire_division_septentrionalis_deserti: "Septentrionalis Deserti"
irtock3_form_prefecture_septentrionalis_deserti_decision = {
Expand Down Expand Up @@ -1917,6 +1920,7 @@ irtock3_form_prefecture_septentrionalis_deserti_decision = {
}
}

{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# irtock3_rome_empire_division_serica_ultima: "Serica Ultima"
irtock3_form_prefecture_serica_ultima_decision = {
picture = {
Expand Down Expand Up @@ -2342,3 +2346,4 @@ irtock3_form_prefecture_serica_deserti_decision = {
irtock3_form_roman_prefecture_effect = { REGION = irtock3_rome_empire_division_serica_deserti }
}
}
{% endunless %}
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ IRToCK3_game_start_onaction_effects = {
REGION = irtock3_rome_empire_division_imoan_montem
EMPIRE = e_tibet
}
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Insulae Remotae
irtock3_gamestart_add_title_to_prefecture_region_effect = {
REGION = irtock3_rome_empire_division_insulae_remotae
Expand All @@ -275,11 +276,13 @@ IRToCK3_game_start_onaction_effects = {
REGION = irtock3_rome_empire_division_insulae_solis
EMPIRE = e_japan
}
{% endunless %}
# Septentrionalis Deserti
irtock3_gamestart_add_title_to_prefecture_region_effect = {
REGION = irtock3_rome_empire_division_septentrionalis_deserti
EMPIRE = e_mongolia
}
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Serica Meridiana
irtock3_gamestart_add_title_to_prefecture_region_effect = {
REGION = irtock3_rome_empire_division_serica_meridiana
Expand All @@ -305,6 +308,7 @@ IRToCK3_game_start_onaction_effects = {
REGION = irtock3_rome_empire_division_serica_deserti
EMPIRE = e_yongliang
}
{% endunless %}

## If a hegemony Rome title exists at game start, need to make sure it's de jure empires are properly setup as Praetorian Prefectures
if = {
Expand Down Expand Up @@ -364,12 +368,15 @@ IRToCK3_game_start_onaction_effects = {
irtock3_setup_roman_prefectures_game_start = { REGION = india_extra_gangem }
# Magna Taprobana
irtock3_setup_roman_prefectures_game_start = { REGION = magna_taprobana }
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Insulae Remotae
irtock3_setup_roman_prefectures_game_start = { REGION = insulae_remotae }
# Insulae Solis
irtock3_setup_roman_prefectures_game_start = { REGION = insulae_solis }
{% endunless %}
# Septentrionalis Deserti
irtock3_setup_roman_prefectures_game_start = { REGION = septentrionalis_deserti }
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Serica Ultima
irtock3_setup_roman_prefectures_game_start = { REGION = serica_ultima }
# Serica Meridiana
Expand All @@ -383,6 +390,7 @@ IRToCK3_game_start_onaction_effects = {
# Serica Deserti
irtock3_setup_roman_prefectures_game_start = { REGION = serica_deserti }
}
{% endunless %}

## If anyone holds the Rome hegemony titles at game start, they should have the Augustus trait and naming flag, and their vassals should get flags so their titles are properly named as well
if = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,12 +347,15 @@ split_byzantine_empire_effect = {
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_india_extra_gangem }
# Magna Taprobana
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_magna_taprobana }
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Insulae Remotae
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_insulae_remotae }
# Insulae Solis
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_insulae_solis }
{% endunless %}
# Septentrionalis Deserti
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_septentrionalis_deserti }
{% unless wtwsms %} # WtWSMS doesn't have playable East Asia yet.
# Serica Ultima
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_serica_ultima }
# Serica Meridiana
Expand All @@ -365,6 +368,7 @@ split_byzantine_empire_effect = {
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_serica_septentrionalis }
# Serica Deserti
irtock3_split_rome_empire_region_effect = { REGION = irtock3_rome_empire_division_serica_deserti }
{% endunless %}

# Leftover titles
## If a kingdom title under these empires is somehow split enough across multiple regions, it might not get put under one of the above prefectures, so need to check those
Expand Down
Loading
Loading