88using ImperatorToCK3 . CK3 . Provinces ;
99using ImperatorToCK3 . CK3 . Titles ;
1010using ImperatorToCK3 . CommonUtils . Map ;
11+ using ImperatorToCK3 . CK3 . Dynasties ;
1112using ImperatorToCK3 . Imperator . Countries ;
1213using ImperatorToCK3 . Imperator . Diplomacy ;
1314using ImperatorToCK3 . Imperator . Geography ;
3031using Xunit ;
3132using System ;
3233using System . IO ;
34+ using System . Globalization ;
35+ using System . Reflection ;
36+ using System . Text . RegularExpressions ;
37+ using ImperatorRulerTerm = ImperatorToCK3 . Imperator . Countries . RulerTerm ;
3338
3439namespace ImperatorToCK3 . UnitTests . CK3 . Characters ;
3540
@@ -208,6 +213,31 @@ public void OnlyEarlyPregnanciesAreImportedFromImperator() {
208213 ck3Characters [ "imperator4" ] . Pregnancies . Should ( ) . BeEmpty ( ) ;
209214 }
210215
216+ [ Fact ]
217+ public void RemoveInvalidDynastiesFromHistory_FiltersCorrectly ( ) {
218+ var cc = new CharacterCollection ( ) ;
219+ var date = new Date ( 1 , 1 , 1 , AUC : true ) ;
220+ var char1 = new Character ( "c1" , "one" , date , cc ) { FromImperator = false } ;
221+ char1 . History . Fields [ "dynasty" ] . InitialEntries . Add ( new KeyValuePair < string , object > ( "dynasty" , "valid" ) ) ;
222+ char1 . History . Fields [ "dynasty" ] . InitialEntries . Add ( new KeyValuePair < string , object > ( "dynasty" , "" ) ) ;
223+ char1 . History . Fields [ "dynasty" ] . InitialEntries . Add ( new KeyValuePair < string , object > ( "dynasty" , "invalid" ) ) ;
224+ cc . AddOrReplace ( char1 ) ;
225+
226+ var char2 = new Character ( "c2" , "two" , date , cc ) { FromImperator = true } ;
227+ char2 . History . Fields [ "dynasty" ] . InitialEntries . Add ( new KeyValuePair < string , object > ( "dynasty" , "valid" ) ) ;
228+ cc . AddOrReplace ( char2 ) ;
229+
230+ var dyns = new DynastyCollection ( ) ;
231+ dyns . AddOrReplace ( new Dynasty ( "valid" , new BufferedReader ( "" ) ) ) ;
232+
233+ cc . RemoveInvalidDynastiesFromHistory ( dyns ) ;
234+
235+ var entries = char1 . History . Fields [ "dynasty" ] . InitialEntries . Select ( kvp => kvp . Value . ToString ( ) ) . ToList ( ) ;
236+ entries . Should ( ) . Equal ( new [ ] { "valid" } ) ;
237+ var entries2 = char2 . History . Fields [ "dynasty" ] . InitialEntries . Select ( kvp => kvp . Value . ToString ( ) ) . ToList ( ) ;
238+ entries2 . Should ( ) . Equal ( new [ ] { "valid" } ) ;
239+ }
240+
211241 [ Fact ]
212242 public void ImperatorCountriesGoldCanBeDistributedAmongRulerAndVassals ( ) {
213243 var conversionDate = new Date ( 470 , 2 , 1 , AUC : true ) ;
@@ -415,4 +445,75 @@ public void ImperatorCharacterNamesCanBeOverriddenByConfigurable() {
415445 // Clean up.
416446 File . Delete ( overridesFilePath ) ;
417447 }
448+
449+ [ Fact ]
450+ public void ChineseDynasticCycleVariablesAreCorrectlyCalculatedForChineseEmpireCountryRulers ( ) {
451+ Date ck3BookmarkDate = new ( 810 , 1 , 1 ) ;
452+ Date irEndDate = new ( 780 , 1 , 1 ) ;
453+
454+ var characters = new CharacterCollection ( ) ;
455+ var holder = new Character ( "imperator_han_emperor" , "Han Emperor" , new Date ( 760 , 1 , 1 ) , characters ) {
456+ FromImperator = true
457+ } ;
458+ characters . Add ( holder ) ;
459+
460+ var landedTitles = new Title . LandedTitles ( ) ;
461+ var celestialEmpire = landedTitles . Add ( "e_chinese_empire" ) ;
462+ celestialEmpire . SetHolder ( holder , ck3BookmarkDate ) ;
463+
464+ var imperatorCountry = new Country ( 1 ) { Tag = "HAN" } ;
465+ SetPrivateProperty ( imperatorCountry , nameof ( Country . Government ) , "chinese_empire" ) ;
466+ imperatorCountry . TotalPowerBase = 60f ;
467+ imperatorCountry . NonLoyalPowerBase = 15f ;
468+
469+ var precedingNonChineseStartDate = new Date ( 700 , 3 , 1 ) ;
470+ var earliestChineseStartDate = new Date ( 720 , 6 , 1 ) ;
471+ var laterChineseStartDate = new Date ( 760 , 2 , 1 ) ;
472+
473+ imperatorCountry . RulerTerms . Add ( CreateRulerTerm ( precedingNonChineseStartDate , "tribal" ) ) ;
474+ imperatorCountry . RulerTerms . Add ( CreateRulerTerm ( earliestChineseStartDate , "chinese_empire" ) ) ;
475+ imperatorCountry . RulerTerms . Add ( CreateRulerTerm ( laterChineseStartDate , "chinese_empire" ) ) ;
476+
477+ imperatorCountry . CK3Title = celestialEmpire ;
478+ SetPrivateProperty ( celestialEmpire , nameof ( Title . ImperatorCountry ) , imperatorCountry ) ;
479+
480+ characters . CalculateChineseDynasticCycleVariables ( landedTitles , irEndDate , ck3BookmarkDate ) ;
481+
482+ var effectsField = holder . History . Fields [ "effects" ] ;
483+ var effectEntry = Assert . Single ( effectsField . DateToEntriesDict ) ;
484+ Assert . Equal ( ck3BookmarkDate , effectEntry . Key ) ;
485+ var effectString = Assert . IsType < StringOfItem > ( Assert . Single ( effectEntry . Value ) . Value ) . ToString ( ) ;
486+
487+ var expectedYearsWithGovernment = ck3BookmarkDate . DiffInYears ( earliestChineseStartDate ) + ( earliestChineseStartDate . DiffInYears ( precedingNonChineseStartDate ) / 2 ) ;
488+ var expectedUnrest = imperatorCountry . NonLoyalPowerBase / imperatorCountry . TotalPowerBase ;
489+ var effectLines = effectString . Split ( new [ ] { "\r \n " , "\n " } , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) ;
490+ var yearsLine = Assert . Single ( effectLines , line => line . Contains ( "years_with_government" , StringComparison . Ordinal ) ) ;
491+ var yearsValue = ExtractVariableValue ( yearsLine ) ;
492+ Assert . Equal ( expectedYearsWithGovernment , yearsValue , precision : 5 ) ;
493+ var unrestLine = Assert . Single ( effectLines , line => line . Contains ( "imperator_unrest" , StringComparison . Ordinal ) ) ;
494+ var unrestValue = ExtractVariableValue ( unrestLine ) ;
495+ Assert . Equal ( expectedUnrest , unrestValue , precision : 5 ) ;
496+ }
497+
498+ private static void SetPrivateProperty ( object target , string propertyName , object ? value ) {
499+ var targetType = target . GetType ( ) ;
500+ var property = targetType . GetProperty ( propertyName , BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) ;
501+ Assert . NotNull ( property ) ;
502+ var setter = property ! . GetSetMethod ( nonPublic : true ) ;
503+ Assert . NotNull ( setter ) ;
504+ setter ! . Invoke ( target , new [ ] { value } ) ;
505+ }
506+
507+ private static ImperatorRulerTerm CreateRulerTerm ( Date startDate , string governmentId ) {
508+ var term = new ImperatorRulerTerm ( ) ;
509+ SetPrivateProperty ( term , nameof ( ImperatorRulerTerm . StartDate ) , startDate ) ;
510+ SetPrivateProperty ( term , nameof ( ImperatorRulerTerm . Government ) , governmentId ) ;
511+ return term ;
512+ }
513+
514+ private static double ExtractVariableValue ( string line ) {
515+ var match = Regex . Match ( line , "value\\ s*=\\ s*(?<value>[-+]?[0-9]*\\ .?[0-9]+)" ) ;
516+ Assert . True ( match . Success , $ "Could not parse value from line '{ line } '.") ;
517+ return double . Parse ( match . Groups [ "value" ] . Value , CultureInfo . InvariantCulture ) ;
518+ }
418519}
0 commit comments