private static void conversation_set_up_safe_passage_barter_on_consequence(DialogueParams param) { BarterManager instance = BarterManager.Instance; Hero oneToOneConversationHero = Hero.OneToOneConversationHero; PartyBase mainParty = PartyBase.MainParty; PartyBase otherParty = MobileParty.ConversationParty?.Party; BarterManager.BarterContextInitializer initContext = new BarterManager.BarterContextInitializer(BarterManager.Instance.InitializeSafePassageBarterContext); int persuasionCostReduction = 0; bool isAIBarter = false; if (Hero.OneToOneConversationHero == null) { Barterable[] array = new Barterable[1]; array[0] = new SafePassageBarterable(null, Hero.MainHero, otherParty, PartyBase.MainParty); instance.StartBarterOffer(Hero.MainHero, oneToOneConversationHero, mainParty, otherParty, null, initContext, persuasionCostReduction, isAIBarter, array); } else { Barterable[] array = new Barterable[2]; array[0] = new SafePassageBarterable(oneToOneConversationHero, Hero.MainHero, otherParty, PartyBase.MainParty); array[1] = new NoAttackBarterable(Hero.MainHero, oneToOneConversationHero, mainParty, otherParty, CampaignTime.Days(5f)); instance.StartBarterOffer(Hero.MainHero, oneToOneConversationHero, mainParty, otherParty, null, initContext, persuasionCostReduction, isAIBarter, array); } }
/// <summary> /// Show an text popup listing Hero current loans. /// </summary> private void ShowLoans() { string text = ""; foreach (var loan in BankAccount.Loans) { text += $"~ Loan took on {CampaignTime.Days(loan.Date)} for <b>{loan.Amount}</b><img src=\"Icons\\Coin@2x\">\n"; text += (loan.Remaining == loan.Total) ? $"Daily payments will start on {CampaignTime.Days(loan.PaymentsStartDate)}\n" : $"Daily payments started on {CampaignTime.Days(loan.PaymentsStartDate)}\n"; text += $"Daily payments will end on {CampaignTime.Days(loan.PaymentsEndDate)}\n"; text += $"Daily payments: <b>{loan.Payments * -1}</b><img src=\"Icons\\Coin@2x\">\n"; text += $"Remaining to pay: <b>{loan.Remaining}</b><img src=\"Icons\\Coin@2x\">\n"; text += $" \n"; text += $" \n"; } InformationManager.ShowInquiry(new InquiryData( titleText: $"Your current loans.", text: text, isAffirmativeOptionShown: true, isNegativeOptionShown: false, affirmativeText: "Ok", negativeText: "Back", affirmativeAction: new Action(() => { }), negativeAction: new Action(() => { }) ), true); }
private void OnDailyTick() { bool adultAafEnabled = Main.Settings !.AdultAgeFactor > 1.02f; bool childAafEnabled = Main.Settings !.ChildAgeFactor > 1.02f; if (CampaignOptions.IsLifeDeathCycleDisabled) { return; } PeriodicDeathProbabilityUpdate(adultAafEnabled); /* Send childhood growth stage transition events & perform AAF if enabled */ // Subtract 1 for the daily tick's implicitly-aged day & the rest is // explicit, incremental age to add. var adultAgeDelta = CampaignTime.Days(Main.Settings.AdultAgeFactor - 1f); var childAgeDelta = CampaignTime.Days(Main.Settings.ChildAgeFactor - 1f); var oneDay = CampaignTime.Days(1f); foreach (var hero in Hero.All) { if (!hero.IsAlive) { continue; } // When calculating the prevAge, we must take care to include the day // which the daily tick implicitly aged us since we last did this, or // else we could miss age transitions. Ergo, prevAge is the age we // were as if we were one day younger than our current BirthDay. int prevAge = (int)(hero.BirthDay + oneDay).ElapsedYearsUntilNow; if (adultAafEnabled && !hero.IsChild) { hero.SetBirthDay(hero.BirthDay - adultAgeDelta); } else if (childAafEnabled && hero.IsChild) { hero.SetBirthDay(hero.BirthDay - childAgeDelta); } hero.CharacterObject.Age = hero.Age; // And our new age, if different. int newAge = (int)hero.Age; // Did a relevant transition in age(s) occur? if (newAge > prevAge && prevAge < adultAge && !hero.IsTemplate) { ProcessAgeTransition(hero, prevAge, newAge); } } }
private static bool GetRandomBirthDayForAge(float age, ref CampaignTime __result) { var now = CampaignTime.Now; float birthYear = now.GetYear - age; float randDayOfYear = MBRandom.RandomFloatRanged(1, Main.TimeParam.DayPerYear); if (randDayOfYear > now.GetDayOfYear) { --birthYear; } __result = CampaignTime.Years(birthYear) + CampaignTime.Days(randDayOfYear); return(false); }
private void SetStoryVisibleTimeoutIfNeeded(QuestBase quest) { if (!IsFirstStoryPhase() || !quest.IsSpecialQuest || !quest.IsOngoing) { return; } // set visible timeout to be when vanilla would have (silently) timed // out the quest, minus a day to make very sure the quest doesn't // somehow trigger vanilla's silent timeout too early. CampaignTime newDueTime = FirstPhase.Instance.FirstPhaseStartTime + CampaignTime.Years(FirstPhaseTimeLimitInYears) - CampaignTime.Days(1); if (quest.QuestDueTime != newDueTime) { quest.ChangeQuestDueTime(newDueTime); ShowNotification(new TextObject("{=QuestTimeRemainingUpdated}Quest time remaining was updated."), "event:/ui/notification/quest_update"); } }
private static void Postfix(PregnancyCampaignBehavior __instance) { CampaignEvents.DailyTickEvent.AddNonSerializedListener(__instance, () => { var pregnancies = AccessTools.Field(typeof(PregnancyCampaignBehavior), "_heroPregnancies") .GetValue(__instance) as IReadOnlyList <object>; float timeShiftDays = 1 * LifeIsShortConfig.Instance.AgeMultiplier - 1; if (timeShiftDays > 0) { foreach (var pregnancy in pregnancies) { var dateField = pregnancy.GetType().GetField("DueDate"); var date = (CampaignTime)dateField.GetValue(pregnancy); var newDate = CampaignTime.Days((float)date.ToDays - timeShiftDays); dateField.SetValue(pregnancy, newDate); } } }); }
private void AdjustPregnanciesOnLoad(List <string> trace) { if (!Main.Settings !.EnablePregnancyTweaks || !Main.Settings.AdjustPregnancyDueDates || (SavedValues.PregnancyDuration == default && !WasVanilla)) { return; } var pregnancyModel = Campaign.Current.Models.PregnancyModel; var newDuration = pregnancyModel.PregnancyDurationInDays; var ourDuration = Main.Settings.ScaledPregnancyDuration * Main.TimeParam.DayPerYear; var oldDuration = WasVanilla ? VanillaPregnancyDuration : SavedValues.PregnancyDuration; // Check whether our pregnancy duration is actually in force (i.e., no interference from other mods). if (!Util.NearEqual(ourDuration, newDuration)) { trace.Add($"WARNING: {Main.Name}'s pregnancy duration setting has no effect due to at least " + "one other mod overriding the pregnancy model in a conflicting manner."); trace.Add($"Type of pregnancy model: {pregnancyModel.GetType().AssemblyQualifiedName}"); } // Don't bother if the effective old and new durations barely differ if at all. if (Util.NearEqual(oldDuration, newDuration, 1e-3f)) { return; } trace.Add("\nAuto-adjusting in-progress pregnancy due dates due to change in pregnancy duration...\n"); var dueDateDelta = newDuration - oldDuration; trace.Add($"Prior pregnancy duration (days): {oldDuration:F2}"); trace.Add($"Current pregnancy duration (days): {newDuration:F2}"); trace.Add($"Pregnancy due dates will change by {dueDateDelta:F2} days."); // We need to iterate over the global List<PregnancyCampaignBehavior.Pregnancy> (Pregnancy is a private // nested class) stored in that behavior's private instance field _heroPregnancies. We'll then need to // access the Pregnancy.DueDate, a private instance field, for all of those. So let's do some reflection. var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; var pregListFI = typeof(PregnancyCampaignBehavior).GetField("_heroPregnancies", bindingFlags); if (pregListFI is null) { trace.Add($"Could not resolve {typeof(PregnancyCampaignBehavior).FullName}._heroPregnancies field! Aborting."); return; } var pregT = typeof(PregnancyCampaignBehavior).GetNestedType("Pregnancy", bindingFlags); if (pregT is null) { trace.Add($"Could not resolve {typeof(PregnancyCampaignBehavior).FullName}.Pregnancy type! Aborting."); return; } var pregDueDateFI = pregT.GetField("DueDate", bindingFlags); if (pregDueDateFI is null) { trace.Add($"Could not resolve {pregT.FullName}.DueDate field! Aborting."); return; } // OK, done setting up reflection info. Start by grabbing the instance of the behavior (gee, a public API!): var pregBehavior = GetCampaignBehavior <PregnancyCampaignBehavior>(); if (pregBehavior is null) { trace.Add($"Could not find campaign behavior {typeof(PregnancyCampaignBehavior).FullName}! Aborting."); return; } if (pregListFI.GetValue(pregBehavior) is not IReadOnlyList <object> pregList) { trace.Add($"Could not access {pregListFI.Name} as IReadOnlyList<object>! Aborting."); return; } if (pregList.Count == 0) { trace.Add("No pregnancies are in-progress. Aborting."); return; } var dueDateDeltaCT = CampaignTime.Days(dueDateDelta); uint nPregs = 0; foreach (var preg in pregList) { var dueDateCT = (CampaignTime)pregDueDateFI.GetValue(preg); pregDueDateFI.SetValue(preg, dueDateCT + dueDateDeltaCT); ++nPregs; } trace.Add($"Adjusted {nPregs} in-progress pregnancies."); }
public void Import(Hero character, bool updateAppearance) { string filename = GetSaveName(character); bool isPlayer = Helper.CharacterHasTraitDeveloper(character); int? year = null, season = null, day = null, hour = null; long? remaining = null; int? mercy = null, valor = null, honor = null, generosity = null, calculating = null; string culture = null; foreach (var keyValuePair in Helper.ReadFile(filename)) { var key = keyValuePair.Key; var value = keyValuePair.Value; // Parse try { // Birthday if (key.Equals("Year")) { year = Convert.ToInt32(value); } else if (key.Equals("Season")) { season = Convert.ToInt32(value); } else if (key.Equals("Day")) { day = Convert.ToInt32(value); } else if (key.Equals("Hour")) { hour = Convert.ToInt32(value); } else if (key.Equals("RemainingTicks")) { remaining = Convert.ToInt64(value); } // Culture else if (key.Equals("Culture")) { culture = value; } // Traits // if the character is the player (who has a trait developer), read the XP else if (isPlayer) { if (key.Equals("MercyXP")) { mercy = Convert.ToInt32(value); } else if (key.Equals("ValorXP")) { valor = Convert.ToInt32(value); } else if (key.Equals("HonorXP")) { honor = Convert.ToInt32(value); } else if (key.Equals("GenerosityXP")) { generosity = Convert.ToInt32(value); } else if (key.Equals("CalculatingXP")) { calculating = Convert.ToInt32(value); } } else { // The character doesn't not have a trait developer (non-player). Directly read the traits. if (key.Equals("Mercy")) { mercy = Convert.ToInt32(value); } else if (key.Equals("Valor")) { valor = Convert.ToInt32(value); } else if (key.Equals("Honor")) { honor = Convert.ToInt32(value); } else if (key.Equals("Generosity")) { generosity = Convert.ToInt32(value); } else if (key.Equals("Calculating")) { calculating = Convert.ToInt32(value); } } } catch { Helper.ShowAndLog($"Failed to parse {key} for {character}"); return; } } bool readBirthdaySuccess = false; bool readCultureSuccess = false; bool readTraitsSuccess = false; // Read Birthday if (year.HasValue && season.HasValue && day.HasValue && hour.HasValue && remaining.HasValue) { var b = CampaignTime.Years(year.Value) + CampaignTime.Seasons(season.Value) + CampaignTime.Days(day.Value) + CampaignTime.Hours(hour.Value); long newTicks = b.GetTicks(); newTicks += remaining.Value; var newBirthDay = Helper.CreateCampaignTime(newTicks); character.BirthDay = newBirthDay; // Update character model if (updateAppearance) { var dps = character.BodyProperties.DynamicProperties; dps.Age = character.Age; typeof(BodyProperties) .GetField("_dynamicBodyProperties", BindingFlags.Instance | BindingFlags.NonPublic) .SetValue(character.BodyProperties, dps); } readBirthdaySuccess = true; } // Read Culture if (culture != null) { CultureCode c; if (Enum.TryParse(culture, true, out c) == false) { c = CultureCode.Invalid; } if (c != CultureCode.Invalid) { var heroOfThisCulture = Hero.FindFirst((h) => h.Culture.GetCultureCode() == c); if (heroOfThisCulture != null) { character.CharacterObject.Culture = heroOfThisCulture.CharacterObject.Culture; if (character.Clan.Leader == character) { character.Clan.Culture = character.CharacterObject.Culture; // Clan culture changes too } readCultureSuccess = true; } else { //Helper.ShowAndLog($"{character.Name}'s culture not imported: Can't set to culture \"{c.ToString()}\"!"); } } else { //Helper.ShowAndLog($"{character.Name}'s culture not imported: Invalid culture \"{culture}\"!"); } } else { //Helper.ShowAndLog($"{character.Name}'s culture not imported: culture value is empty!"); } // Read Traits if (mercy.HasValue && valor.HasValue && honor.HasValue && generosity.HasValue && calculating.HasValue) { if (isPlayer) { var ptd = Campaign.Current.PlayerTraitDeveloper; var deltaMercy = mercy.Value - ptd.GetPropertyValue(DefaultTraits.Mercy); var deltaValor = valor.Value - ptd.GetPropertyValue(DefaultTraits.Valor); var deltaHonor = honor.Value - ptd.GetPropertyValue(DefaultTraits.Honor); var deltaGenerosity = generosity.Value - ptd.GetPropertyValue(DefaultTraits.Generosity); var deltaCalculating = calculating.Value - ptd.GetPropertyValue(DefaultTraits.Calculating); if (deltaMercy != 0) { ptd.AddTraitXp(DefaultTraits.Mercy, deltaMercy); } if (deltaValor != 0) { ptd.AddTraitXp(DefaultTraits.Valor, deltaValor); } if (deltaHonor != 0) { ptd.AddTraitXp(DefaultTraits.Honor, deltaHonor); } if (deltaGenerosity != 0) { ptd.AddTraitXp(DefaultTraits.Generosity, deltaGenerosity); } if (deltaCalculating != 0) { ptd.AddTraitXp(DefaultTraits.Calculating, deltaCalculating); } } else { // It will clamp to min max value in SetTraitLevel() character.SetTraitLevel(DefaultTraits.Mercy, mercy.Value); character.SetTraitLevel(DefaultTraits.Valor, valor.Value); character.SetTraitLevel(DefaultTraits.Honor, honor.Value); character.SetTraitLevel(DefaultTraits.Generosity, generosity.Value); character.SetTraitLevel(DefaultTraits.Calculating, calculating.Value); } readTraitsSuccess = true; } string msg = $"Imported {character.Name}'s "; if (readBirthdaySuccess && readCultureSuccess && readTraitsSuccess) { msg += "birthday, culture and traits."; } else if (readBirthdaySuccess && readCultureSuccess && !readTraitsSuccess) { msg += "birthday and culture."; } else if (readBirthdaySuccess && !readCultureSuccess && readTraitsSuccess) { msg += "birthday and traits."; } else if (!readBirthdaySuccess && readCultureSuccess && readTraitsSuccess) { msg += "culture and traits."; } else if (readBirthdaySuccess && !readCultureSuccess && !readTraitsSuccess) { msg += "birthday."; } else if (!readBirthdaySuccess && readCultureSuccess && !readTraitsSuccess) { msg += "culture."; } else if (!readBirthdaySuccess && !readCultureSuccess && readTraitsSuccess) { msg += "traits."; } else { msg = null; } if (msg != null) { Helper.ShowAndLog(msg + $" Appearance {(updateAppearance ? string.Empty : "not")} updated.", new Color(0, 1, 0)); } }
public void Export(Hero character) { StringBuilder sb = new StringBuilder(); sb.AppendLine("//Lines started with // are comments."); sb.AppendLine(string.Empty); sb.AppendLine("//Readme:"); sb.AppendLine("//Season ranges from 0 to 3. Spring is 0 and Autumn is 2, for example."); sb.AppendLine("//Day starts with 0. So if your birthday is Summer 11, Day should be 10."); sb.AppendLine("//Use the field \"FormattedBirthday\" to check what your birthday is, after export."); sb.AppendLine("//If you want to modify RemainingTicks, remember there are 10000 ticks per game second."); sb.AppendLine("//Traits range from -2 to 2."); sb.AppendLine(Environment.NewLine); sb.AppendLine($"//{character.Name}'s birthday:"); sb.AppendLine($"Year={character.BirthDay.GetYear}"); sb.AppendLine($"Season={character.BirthDay.GetSeasonOfYear}"); sb.AppendLine($"Day={character.BirthDay.GetDayOfSeason}"); sb.AppendLine($"Hour={character.BirthDay.GetHourOfDay}"); // Get remaining ticks so we don't lose any milliseconds. var b = CampaignTime.Years(character.BirthDay.GetYear) + CampaignTime.Seasons(character.BirthDay.GetSeasonOfYear) + CampaignTime.Days(character.BirthDay.GetDayOfSeason) + CampaignTime.Hours(character.BirthDay.GetHourOfDay); sb.AppendLine($"RemainingTicks={(character.BirthDay - b).GetTicks()}"); sb.AppendLine(Environment.NewLine); // Culture sb.AppendLine("//Culture:"); sb.AppendLine($"Culture={character.Culture.GetName()}"); sb.AppendLine(Environment.NewLine); // Is this character the player? bool isPlayer = Helper.CharacterHasTraitDeveloper(character); // Traits string traitPromptStr = isPlayer ? " (Read only. Modify Trait XP to change traits)" : string.Empty; sb.AppendLine($"//Traits{traitPromptStr}:"); var traits = character.GetHeroTraits(); sb.AppendLine($"Mercy={traits.Mercy}"); sb.AppendLine($"Valor={traits.Valor}"); sb.AppendLine($"Honor={traits.Honor}"); sb.AppendLine($"Generosity={traits.Generosity}"); sb.AppendLine($"Calculating={traits.Calculating}"); sb.AppendLine(Environment.NewLine); // Trait XP if (isPlayer) { sb.AppendLine("//Trait XP:"); sb.AppendLine($"MercyXP={Campaign.Current.PlayerTraitDeveloper.GetPropertyValue(DefaultTraits.Mercy)}"); sb.AppendLine($"ValorXP={Campaign.Current.PlayerTraitDeveloper.GetPropertyValue(DefaultTraits.Valor)}"); sb.AppendLine($"HonorXP={Campaign.Current.PlayerTraitDeveloper.GetPropertyValue(DefaultTraits.Honor)}"); sb.AppendLine($"GenerosityXP={Campaign.Current.PlayerTraitDeveloper.GetPropertyValue(DefaultTraits.Generosity)}"); sb.AppendLine($"CalculatingXP={Campaign.Current.PlayerTraitDeveloper.GetPropertyValue(DefaultTraits.Calculating)}"); sb.AppendLine(Environment.NewLine); } // Output. sb.AppendLine("//Don't modify this field as it will not be read."); sb.AppendLine($"FormattedBirthday={character.BirthDay.ToString()}"); for (int i = DefaultTraits.Mercy.MinValue; i <= DefaultTraits.Mercy.MaxValue; ++i) { sb.AppendLine($"MercyXPRequired{i}={Campaign.Current.Models.CharacterDevelopmentModel.GetTraitXpRequiredForTraitLevel(DefaultTraits.Mercy, i)}"); } for (int i = DefaultTraits.Valor.MinValue; i <= DefaultTraits.Valor.MaxValue; ++i) { sb.AppendLine($"ValorXPRequired{i}={Campaign.Current.Models.CharacterDevelopmentModel.GetTraitXpRequiredForTraitLevel(DefaultTraits.Valor, i)}"); } for (int i = DefaultTraits.Honor.MinValue; i <= DefaultTraits.Honor.MaxValue; ++i) { sb.AppendLine($"HonorXPRequired{i}={Campaign.Current.Models.CharacterDevelopmentModel.GetTraitXpRequiredForTraitLevel(DefaultTraits.Honor, i)}"); } for (int i = DefaultTraits.Generosity.MinValue; i <= DefaultTraits.Generosity.MaxValue; ++i) { sb.AppendLine($"GenerosityXPRequired{i}={Campaign.Current.Models.CharacterDevelopmentModel.GetTraitXpRequiredForTraitLevel(DefaultTraits.Generosity, i)}"); } for (int i = DefaultTraits.Calculating.MinValue; i <= DefaultTraits.Calculating.MaxValue; ++i) { sb.AppendLine($"CalculatingXPRequired{i}={Campaign.Current.Models.CharacterDevelopmentModel.GetTraitXpRequiredForTraitLevel(DefaultTraits.Calculating, i)}"); } File.WriteAllText(this.GetSaveName(character), sb.ToString()); Helper.ShowAndLog($"Exported {character.Name}'s birthday, culture and traits."); }
private static void TimeShift(Hero hero, float timeShiftDays) { hero.BirthDay = CampaignTime.Days((float)hero.BirthDay.ToDays - timeShiftDays); }
private void OnDailyTick() { bool aafEnabled = !Util.NearEqual(Main.Settings !.AgeFactor, 1f, 1e-2); /* Update Hero Death Probabilities */ int daysElapsed = (int)Campaign.Current.CampaignStartTime.ElapsedDaysUntilNow; int updatePeriod = !aafEnabled ? Main.TimeParam.DayPerYear : (int)(Main.TimeParam.DayPerYear / Main.Settings.AgeFactor); if (updatePeriod <= 0) { updatePeriod = 1; } // Globally update death probabilities every year of accumulated age if (daysElapsed % updatePeriod == 0) { UpdateHeroDeathProbabilities !(); } /* Send childhood growth stage transition events & perform AAF if enabled */ // Subtract 1 for the daily tick's implicitly-aged day & the rest is // explicit, incremental age to add. var birthDayDelta = CampaignTime.Days(Main.Settings.AgeFactor - 1f); // And this is just hoisted. var oneDay = CampaignTime.Days(1f); foreach (var hero in Hero.All) { if (hero.IsDead) { continue; } // When calculating the prevAge, we must take care to include the day // which the daily tick implicitly aged us since we last did this, or // else we could miss age transitions. Ergo, prevAge is the age we // were as if we were one day younger than our current BirthDay. int prevAge = (int)(hero.BirthDay + oneDay).ElapsedYearsUntilNow; if (aafEnabled) { hero.BirthDay -= birthDayDelta; hero.CharacterObject.Age = hero.Age; } // And our new age, if different. int newAge = (int)hero.Age; // Did a relevant transition in age(s) occur? if (newAge > prevAge && prevAge < adultAge && !hero.IsTemplate) { // Loop over the aged years (extremely aggressive Days Per Season + AAF // could make it multiple), and thus we need to be able to handle the // possibility of multiple growth stage events needing to be fired. for (int age = prevAge + 1; age <= Math.Min(newAge, adultAge); ++age) { // Replacement for EducationCampaignBehavior.OnDailyTick() // // On e1.5.5, they've disabled the EducationCampaignBehavior, but I'm going to // continue calling DoEducation so long as the child isn't yet of age, because // that seems at worst harmless. What crashes (and not in e1.5.5 because they // removed all of the behavior's event listeners, which is what we'll do for // our e1.5.4 version) is when their OnHeroComesOfAge event listener runs. if (hero.Clan == Clan.PlayerClan && GetChildAgeState(age) != ChildAgeState.Invalid) { DoEducation !(hero); // WTF is this doing after the DoEducation call? Magic, or TaleWorlds f*****g up? new TextObject("{=Z5qYQV08}Your kin has reached the age of {CHILD.AGE} and needs your guidance on " + "{?CHILD.GENDER}her{?}his{\\?} development.", null) .SetCharacterProperties("CHILD", hero.CharacterObject, null, false); } // This replaces AgingCampaignBehavior.OnDailyTick's campaign event triggers: if (age == childAge) { OnHeroGrowsOutOfInfancy(hero); } if (age == teenAge) { OnHeroReachesTeenAge(hero); } if (age == adultAge && !hero.IsActive) { OnHeroComesOfAge(hero); } } } } }
private void OnDailyTickClan(Clan clan) { if (!SeparatismConfig.Settings.AnarchyRebellionsEnabled) { return; } var clanFiefsAmount = clan.GetFiefsAmount(); if (clanFiefsAmount < SeparatismConfig.Settings.CriticalAmountOfFiefsPerSingleClan) { return; } var anarchySettlements = clan.Settlements.Where(x => x.IsTown && CampaignTime.Hours(x.LastVisitTimeOfOwner) + CampaignTime.Days(SeparatismConfig.Settings.NumberOfDaysAfterOwnerVisitToKeepOrder) < CampaignTime.Now).ToArray(); if (anarchySettlements.Length == 0) { return; } var availableClans = Clan.All.ReadyToGo().ToArray(); foreach (var settlement in anarchySettlements.OrderByDescending(x => x.Position2D.Distance(clan.FactionMidPoint))) { var newRulerClan = availableClans .Where(x => x.Culture == settlement.Culture) .OrderByDescending(x => x.TotalStrength) .FirstOrDefault(); var rebelRightNow = SeparatismConfig.Settings.DailyAnarchyRebellionChance >= 1 || (MBRandom.RandomFloat <= SeparatismConfig.Settings.DailyAnarchyRebellionChance); if (newRulerClan != null && rebelRightNow) { var rebelSettlements = new List <Settlement>(); rebelSettlements.Add(settlement); int bonusSettlements = (SeparatismConfig.Settings.BonusRebelFiefForHighTierClan && newRulerClan.Tier > 4) ? 1 : 0; if (bonusSettlements > 0) { var neighborClanFiefs = new Queue <Settlement>(Settlement .FindSettlementsAroundPosition(settlement.Position2D, 50, x => x.OwnerClan == clan) .Where(x => x.IsCastle) .Except(rebelSettlements) .OrderBy(x => x.Position2D.Distance(settlement.Position2D))); while (bonusSettlements > 0 && neighborClanFiefs.Count > 0) { var nextFief = neighborClanFiefs.Dequeue(); if (nextFief.Culture == settlement.Culture) { rebelSettlements.Add(nextFief); bonusSettlements--; } } } var rebelKingdom = GoRebelKingdom(newRulerClan, rebelSettlements); var textObject = new TextObject("{=Separatism_Anarchy_Rebel}People of {Settlement} have broken from {Kingdom} to call {Ruler} on rulership and found the {RebelKingdom}.", null); textObject.SetTextVariable("Settlement", settlement.Name); textObject.SetTextVariable("Kingdom", clan.Kingdom.Name); textObject.SetTextVariable("Ruler", newRulerClan.Leader.Name); textObject.SetTextVariable("RebelKingdom", rebelKingdom.Name); GameLog.Warn(textObject.ToString()); return; } } }