Skip to content

Commit

Permalink
Make country rank conversion configurable through `configurables/coun…
Browse files Browse the repository at this point in the history
…try_rank_map.txt` (#1834) #minor
  • Loading branch information
IhateTrains authored Mar 12, 2024
1 parent d17b4a3 commit 7ce613f
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 71 deletions.
5 changes: 4 additions & 1 deletion ImperatorToCK3.UnitTests/CK3/Titles/TitleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ private class TitleBuilder {
private readonly Title.LandedTitles landedTitles = new();
private ProvinceMapper provinceMapper = new();
private CoaMapper coaMapper = new(irModFS);
private TagTitleMapper tagTitleMapper = new("TestFiles/configurables/title_map.txt", "TestFiles/configurables/governorMappings.txt");
private TagTitleMapper tagTitleMapper = new(
"TestFiles/configurables/title_map.txt",
"TestFiles/configurables/governorMappings.txt",
"TestFiles/configurables/country_rank_map.txt");
private GovernmentMapper governmentMapper = new(ck3GovernmentIds: Array.Empty<string>());
private SuccessionLawMapper successionLawMapper = new("TestFiles/configurables/succession_law_map.txt");
private DefiniteFormMapper definiteFormMapper = new("TestFiles/configurables/definite_form_names.txt");
Expand Down
44 changes: 33 additions & 11 deletions ImperatorToCK3.UnitTests/Mappers/TagTitle/TagTitleMapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class TagTitleMapperTests {
private readonly ImperatorRegionMapper irRegionMapper = new(Areas);
private const string tagTitleMappingsPath = "TestFiles/configurables/title_map.txt";
private const string governorshipTitleMappingsPath = "TestFiles/configurables/governorMappings.txt";
private const string rankMappingsPath = "TestFiles/configurables/country_rank_map.txt";
private static readonly CultureCollection cultures;
private static readonly ColorFactory ColorFactory = new();

Expand All @@ -51,7 +52,7 @@ public TagTitleMapperTests() {

[Fact]
public void TitleCanBeMatchedFromTag() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath); // reads title_map.txt from TestFiles
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath); // reads title_map.txt from TestFiles
var country = Country.Parse(new BufferedReader("tag=CRT"), 1);
for (ulong i = 1; i < 200; ++i) { // makes the country a major power
var province = new ImperatorToCK3.Imperator.Provinces.Province(i);
Expand All @@ -63,7 +64,7 @@ public void TitleCanBeMatchedFromTag() {
}
[Fact]
public void TitleCanBeMatchedFromGovernorship() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath); // reads title_map.txt from TestFiles
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath); // reads title_map.txt from TestFiles
const ulong romeId = 1;
mapper.RegisterCountry(romeId, "e_roman_empire");

Expand Down Expand Up @@ -104,7 +105,7 @@ public void TitleCanBeMatchedFromGovernorship() {

[Fact]
public void TitleCanBeMatchedByRanklessLink() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath); // reads title_map.txt from TestFiles
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath); // reads title_map.txt from TestFiles
var country = Country.Parse(new BufferedReader("tag=RAN"), 1);
for (ulong i = 1; i < 200; ++i) { // makes the country a major power
var province = new ImperatorToCK3.Imperator.Provinces.Province(i);
Expand All @@ -117,7 +118,7 @@ public void TitleCanBeMatchedByRanklessLink() {

[Fact]
public void TitleCanBeGeneratedFromTag() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
var rom = Country.Parse(new BufferedReader("tag=ROM"), 1);
for (ulong i = 0; i < 20; ++i) { // makes the country a local power
rom.RegisterProvince(new ImperatorToCK3.Imperator.Provinces.Province(i));
Expand All @@ -135,7 +136,7 @@ public void TitleCanBeGeneratedFromTag() {
}
[Fact]
public void TitleCanBeGeneratedFromGovernorship() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
const ulong romeId = 1;
const ulong dreId = 2;
mapper.RegisterCountry(romeId, "e_roman_empire");
Expand Down Expand Up @@ -184,7 +185,7 @@ public void TitleCanBeGeneratedFromGovernorship() {

[Fact]
public void GetTitleForTagReturnsNullOnEmptyTag() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
var country = Country.Parse(new BufferedReader(string.Empty), 1);
Assert.Empty(country.Tag);
var match = mapper.GetTitleForTag(country, "", maxTitleRank: TitleRank.empire);
Expand All @@ -201,7 +202,7 @@ public void GetTitleGovernorshipTagReturnsNullOnCountryWithNoCK3Title() {
var irProvinces = new ImperatorToCK3.Imperator.Provinces.ProvinceCollection();
var provMapper = new ProvinceMapper();

var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
var country = new Country(1);
var countries = new CountryCollection {country};
var apuliaGovReader = new BufferedReader("who=1 governorship=apulia_region");
Expand All @@ -214,7 +215,7 @@ public void GetTitleGovernorshipTagReturnsNullOnCountryWithNoCK3Title() {

[Fact]
public void TagCanBeRegistered() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
const ulong borId = 1;
mapper.RegisterCountry(borId, "e_boredom");
var country = Country.Parse(new BufferedReader("tag=BOR"), borId);
Expand All @@ -228,7 +229,7 @@ public void TagCanBeRegistered() {
}
[Fact]
public void GovernorshipCanBeRegistered() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
const ulong borId = 1;
mapper.RegisterCountry(borId, "e_roman_empire");

Expand Down Expand Up @@ -272,19 +273,21 @@ public void GovernorshipCanBeRegistered() {

[Fact]
public void GetCK3TitleRankReturnsCorrectRank() {
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath);
var mapper = new TagTitleMapper(tagTitleMappingsPath, governorshipTitleMappingsPath, rankMappingsPath);
var tag1 = Country.Parse(new BufferedReader("tag=TEST_TAG1"), 1);
for (ulong i = 1; i < 20; ++i) { // makes the country a local power
var province = new ImperatorToCK3.Imperator.Provinces.Province(i);
tag1.RegisterProvince(province);
}
// Should be an empire because of the name containing "Empire".
Assert.Equal('e', mapper.GetTitleForTag(tag1, "Test Empire", maxTitleRank: TitleRank.empire)![0]);

var tag2 = Country.Parse(new BufferedReader("tag=TEST_TAG2"), 2);
for (ulong i = 1; i < 2; ++i) { // makes the country a city state
var province = new ImperatorToCK3.Imperator.Provinces.Province(i);
tag2.RegisterProvince(province);
}
// Should be a kingdom because of the name containing "Kingdom".
Assert.Equal('k', mapper.GetTitleForTag(tag2, "Test Kingdom", maxTitleRank: TitleRank.empire)![0]);

var tag3 = Country.Parse(new BufferedReader("tag=TEST_TAG3"), 3); // migrant horde
Expand Down Expand Up @@ -323,6 +326,25 @@ public void GetCK3TitleRankReturnsCorrectRank() {
var province = new ImperatorToCK3.Imperator.Provinces.Province(i);
tag8.RegisterProvince(province);
}
Assert.Equal('e', mapper.GetTitleForTag(tag8)![0]);
Assert.Equal('e', mapper.GetTitleForTag(tag8, "Testonia", maxTitleRank: TitleRank.empire)![0]);

// Rank can be overridden by name containing "Duchy", "Principality" or "Dukedom".
var tag9 = Country.Parse(new BufferedReader("tag=TEST_TAG9"), 9);
for (ulong i = 1; i < 501; ++i) { // makes the country a great power
tag9.RegisterProvince(new(i));
}
Assert.Equal('d', mapper.GetTitleForTag(tag9, "Test Duchy", maxTitleRank: TitleRank.empire)![0]);

var tag10 = Country.Parse(new BufferedReader("tag=TEST_TAG10"), 10);
for (ulong i = 1; i < 501; ++i) { // makes the country a great power
tag10.RegisterProvince(new(i));
}
Assert.Equal('d', mapper.GetTitleForTag(tag10, "Test Principality", maxTitleRank: TitleRank.empire)![0]);

var tag11 = Country.Parse(new BufferedReader("tag=TEST_TAG11"), 11);
for (ulong i = 1; i < 501; ++i) { // makes the country a great power
tag11.RegisterProvince(new(i));
}
Assert.Equal('d', mapper.GetTitleForTag(tag11, "Test Dukedom", maxTitleRank: TitleRank.empire)![0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ namespace ImperatorToCK3.UnitTests.Mappers.TagTitle;

[Collection("Sequential")]
[CollectionDefinition("Sequential", DisableParallelization = true)]
public class MappingTests {
public class TitleMappingTests {
[Fact]
public void SimpleTagMatch() {
var reader = new BufferedReader("{ ck3 = e_roman_empire ir = ROM }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Equal("e_roman_empire", match);
Expand All @@ -32,7 +32,7 @@ public void SimpleTagMatch() {
[Fact]
public void SimpleTagMatchFailsOnWrongTag() {
var reader = new BufferedReader("{ ck3 = e_roman_empire ir = REM }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Null(match);
Expand All @@ -41,7 +41,7 @@ public void SimpleTagMatchFailsOnWrongTag() {
[Fact]
public void SimpleTagMatchFailsOnNoTag() {
var reader = new BufferedReader("{ ck3 = e_roman_empire }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Null(match);
Expand All @@ -50,7 +50,7 @@ public void SimpleTagMatchFailsOnNoTag() {
[Fact]
public void TagRankMatch() {
var reader = new BufferedReader("{ ck3 = e_roman_empire ir = ROM rank = e }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Equal("e_roman_empire", match);
Expand All @@ -59,7 +59,7 @@ public void TagRankMatch() {
[Fact]
public void TagRankMatchFailsOnWrongRank() {
var reader = new BufferedReader("{ ck3 = e_roman_empire ir = ROM rank = k }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Null(match);
Expand All @@ -68,7 +68,7 @@ public void TagRankMatchFailsOnWrongRank() {
[Fact]
public void TagRankMatchSucceedsOnNoRank() {
var reader = new BufferedReader("{ ck3 = e_roman_empire ir = ROM }");
var mapping = Mapping.Parse(reader);
var mapping = TitleMapping.Parse(reader);
var match = mapping.RankMatch("ROM", TitleRank.empire, maxTitleRank: TitleRank.empire);

Assert.Equal("e_roman_empire", match);
Expand Down Expand Up @@ -131,7 +131,7 @@ public void GovernorshipToDeJureDuchyMappingFailsIfDuchyIsNot60PercentControlled
Assert.Contains(duchyId, titles.GetDeJureDuchies().Select(d => d.Id));

var mappingReader = new BufferedReader($"{{ ck3={duchyId} ir={irRegionId} rank=d }}");
var mapping = Mapping.Parse(mappingReader);
var mapping = TitleMapping.Parse(mappingReader);

// Governorship holds 0/3 provinces in the duchy, so it should not be mapped to the duchy.
irGovernorship.GetIRProvinces(irProvinces).Should().BeEmpty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Some words specific to empires, kingdoms and duchies override the mappings based on rank.
empire_keywords = { "empire" "imperium" }
kingdom_keywords = { "kingdom" "regnum" }
duchy_keywords = { "duchy" "principality" "dukedom" "ducatus" }

# Every Imperator country rank should be mapped to CK3 title rank.
# d - duchy, k - kingdom, e - empire
# Mapping to county and barony level is not supported.

# A mapping can contain optional required_territories field.
# Use it if you want to base the CK3 rank on the number of owned I:R territories.

# First matching mapping is used.

link = { ir=migrant_horde ck3=d }
link = { ir=city_power ck3=d }
link = { ir=local_power ck3=k }
link = { ir=regional_power ck3=k }
link = { ir=major_power required_territories=300 ck3=e }
link = { ir=major_power ck3=k }
link = { ir=great_power ck3=e }
2 changes: 0 additions & 2 deletions ImperatorToCK3/CK3/Titles/Title.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@

namespace ImperatorToCK3.CK3.Titles;

public enum TitleRank { barony, county, duchy, kingdom, empire }

[SerializationByProperties]
public sealed partial class Title : IPDXSerializable, IIdentifiable<string> {
public override string ToString() {
Expand Down
3 changes: 3 additions & 0 deletions ImperatorToCK3/CK3/Titles/TitleRank.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace ImperatorToCK3.CK3.Titles;

public enum TitleRank { barony, county, duchy, kingdom, empire }
16 changes: 16 additions & 0 deletions ImperatorToCK3/CK3/Titles/TitleRankUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace ImperatorToCK3.CK3.Titles;

public static class TitleRankUtils {
public static TitleRank CharToTitleRank(char c) {
return c switch {
'e' => TitleRank.empire,
'k' => TitleRank.kingdom,
'd' => TitleRank.duchy,
'c' => TitleRank.county,
'b' => TitleRank.barony,
_ => throw new ArgumentOutOfRangeException(nameof(c))
};
}
}
3 changes: 2 additions & 1 deletion ImperatorToCK3/CK3/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,8 @@ private void GenerateFillerHoldersForUnownedLands(CultureCollection cultures, Co
private readonly SuccessionLawMapper successionLawMapper = new(Path.Combine("configurables", "succession_law_map.txt"));
private readonly TagTitleMapper tagTitleMapper = new(
tagTitleMappingsPath: Path.Combine("configurables", "title_map.txt"),
governorshipTitleMappingsPath: Path.Combine("configurables", "governorMappings.txt")
governorshipTitleMappingsPath: Path.Combine("configurables", "governorMappings.txt"),
rankMappingsPath: "configurables/country_rank_map.txt"
);
private readonly UnitTypeMapper unitTypeMapper = new("configurables/unit_types_map.txt");
private readonly CK3RegionMapper ck3RegionMapper;
Expand Down
21 changes: 21 additions & 0 deletions ImperatorToCK3/Data_Files/configurables/country_rank_map.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Some words specific to empires, kingdoms and duchies override the mappings based on rank.
empire_keywords = { "empire" "imperium" }
kingdom_keywords = { "kingdom" "regnum" }
duchy_keywords = { "duchy" "principality" "dukedom" "ducatus" }

# Every Imperator country rank should be mapped to CK3 title rank.
# d - duchy, k - kingdom, e - empire
# Mapping to county and barony level is not supported.

# A mapping can contain optional required_territories field.
# Use it if you want to base the CK3 rank on the number of owned I:R territories.

# First matching mapping is used.

link = { ir=migrant_horde ck3=d }
link = { ir=city_power ck3=d }
link = { ir=local_power ck3=k }
link = { ir=regional_power ck3=k }
link = { ir=major_power required_territories=300 ck3=e }
link = { ir=major_power ck3=k }
link = { ir=great_power ck3=e }
2 changes: 1 addition & 1 deletion ImperatorToCK3/ImperatorToCK3.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PGCG.commonItems" Version="11.3.0" />
<PackageReference Include="PGCG.commonItems" Version="11.4.0" />
<PackageReference Include="PGCG.commonItems.SourceGenerators" Version="1.0.5" />
<PackageReference Include="Polly" Version="8.3.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
Expand Down
31 changes: 31 additions & 0 deletions ImperatorToCK3/Mappers/TagTitle/RankMapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using commonItems;
using ImperatorToCK3.CK3.Titles;

namespace ImperatorToCK3.Mappers.TagTitle;

public class RankMapping {
public RankMapping(BufferedReader mappingReader) {
var parser = new Parser();
parser.RegisterKeyword("ir", reader => irRank = reader.GetString());
parser.RegisterKeyword("required_territories", reader => requiredTerritories = reader.GetInt());
parser.RegisterKeyword("ck3", reader => ck3Rank = TitleRankUtils.CharToTitleRank(reader.GetChar()));
parser.IgnoreAndLogUnregisteredItems();
parser.ParseStream(mappingReader);
}

public TitleRank? Match(string imperatorRank, int territoriesCount) {
if (irRank is not null && imperatorRank != irRank) {
return null;
}

if (requiredTerritories > 0 && territoriesCount < requiredTerritories) {
return null;
}

return ck3Rank;
}

private string? irRank;
private int requiredTerritories = 0;
private TitleRank? ck3Rank;
}
Loading

0 comments on commit 7ce613f

Please sign in to comment.