예제 #1
0
 private static void Postfix(MobileParty mobileParty, ref ExplainedNumber __result)
 {
     if (PartyMilitiaMap.ContainsKey(mobileParty))
     {
         __result.AddFactor(SpeedModifier, new TextObject("Bandit Militia"));
     }
 }
예제 #2
0
        internal static IEnumerable <CodeInstruction> CalculateBasePartySpeedPatch(IEnumerable <CodeInstruction> ins)
        {
            // ReSharper disable once EntityNameCapturedOnly.Local
            float SlowBM(MobileParty mobileParty, float input)
            {
                if (PartyMilitiaMap.ContainsKey(mobileParty))
                {
                    return(input * 0.15f);
                }

                return(input);
            }

            var codes = ins.ToListQ();

            for (var index = 0; index < codes.Count; index++)
            {
                if (codes[index].opcode == OpCodes.Call &&
                    codes[index + 1].opcode == OpCodes.Stloc_S &&
                    codes[index + 2].opcode == OpCodes.Ldloca_S &&
                    codes[index + 3].opcode == OpCodes.Ldloc_S)
                {
                    codes.InsertRange(index + 1, new List <CodeInstruction>
                    {
                        new(OpCodes.Dup),
                        new(OpCodes.Ldarg_1),
                        new(OpCodes.Call, AccessTools.Method(typeof(MilitiaPatches), nameof(SlowBM)))
                    });
예제 #3
0
 public Militia(MobileParty mobileParty, TroopRoster party, TroopRoster prisoners)
 {
     Banner    = Banners.GetRandomElement();
     BannerKey = Banner.Serialize();
     Spawn(mobileParty, party, prisoners);
     TrainMilitia();
     PartyMilitiaMap.Add(MobileParty, this);
     LogMilitiaFormed(MobileParty);
 }
예제 #4
0
 internal static void Trash(MobileParty mobileParty)
 {
     Mod.Log("Trashing " + mobileParty.Name);
     PartyMilitiaMap.Remove(mobileParty);
     // added as workaround/fix for issue seen in 1.5.9 where TroopRoster.Count is wrong and TroopRoster.Clear() throws
     Traverse.Create(mobileParty.MemberRoster).Field <int>("_count").Value =
         mobileParty.MemberRoster.GetTroopRoster().Count(x => x.Character != null);
     mobileParty.MemberRoster.UpdateVersion();
     mobileParty.RemoveParty();
 }
예제 #5
0
        private void Spawn(Vec2 position, TroopRoster party, TroopRoster prisoners)
        {
            var partyClan = GetMostPrevalent(party) ?? Clan.BanditFactions.First();

            MobileParty = ModBanditMilitiaPartyComponent.CreateBanditParty(partyClan);
            MobileParty.InitializeMobilePartyAroundPosition(party, prisoners, position, 0);
            PartyMilitiaMap.Add(MobileParty, this);
            PartyImageMap.Add(MobileParty, new ImageIdentifierVM(Banner));
            var leaderHero = MobileParty.MemberRoster.GetTroopRoster().ToListQ()[0].Character.HeroObject;

            MobileParty.PartyComponent.ChangePartyLeader(leaderHero);
            Hero      = MobileParty.LeaderHero;
            Hero.Gold = Convert.ToInt32(MobileParty.Party.TotalStrength * Globals.GoldMap[Globals.Settings.GoldReward.SelectedValue]);
            if (MobileParty.ActualClan.Leader is null)
            {
                MobileParty.ActualClan.SetLeader(Hero);
            }
            if (MobileParty.MemberRoster.GetTroopRoster().Any(t => t.Character.IsMounted))
            {
                var mount = Mounts.GetRandomElement();
                Hero.BattleEquipment[10] = new EquipmentElement(mount);
                if (mount.HorseComponent.Monster.MonsterUsage == "camel")
                {
                    Hero.BattleEquipment[11] = new EquipmentElement(Saddles.Where(saddle =>
                                                                                  saddle.Name.ToString().ToLower().Contains("camel")).ToList().GetRandomElement());
                }
                else
                {
                    Hero.BattleEquipment[11] = new EquipmentElement(Saddles.Where(saddle =>
                                                                                  !saddle.Name.ToString().ToLower().Contains("camel")).ToList().GetRandomElement());
                }
            }

            var getLocalizedText = AccessTools.Method(typeof(MBTextManager), "GetLocalizedText");

            Name = (string)getLocalizedText.Invoke(null, new object[] { $"{Possess(Hero.FirstName.ToString())} Bandit Militia" });
            MobileParty.SetCustomName(new TextObject(Name));
            MobileParty.LeaderHero.StringId    += "Bandit_Militia";
            MobileParty.ShouldJoinPlayerBattles = true;
            var tracker = Globals.MobilePartyTrackerVM?.Trackers?.FirstOrDefault(t => t.TrackedParty == MobileParty);

            if (Globals.Settings.Trackers &&
                tracker is null &&
                MobileParty.MemberRoster.TotalManCount >= Globals.Settings.TrackedSizeMinimum)
            {
                tracker = new MobilePartyTrackItemVM(MobileParty, MapScreen.Instance.MapCamera, null);
                Globals.MobilePartyTrackerVM?.Trackers?.Add(tracker);
            }
예제 #6
0
        private static void OnMilitiaRemoved(PartyBase partyBase)
        {
            if (!IsBM(partyBase.MobileParty))
            {
                return;
            }

            Mod.Log($">>> OnMilitiaRemoved - {partyBase.Name}.");
            if (partyBase.MobileParty.LeaderHero?.CurrentSettlement != null)
            {
                Traverse.Create(HeroesWithoutParty(partyBase.MobileParty.LeaderHero?.CurrentSettlement)).Field <List <Hero> >("_list").Value.Remove(partyBase.MobileParty.LeaderHero);
                Mod.Log($">>> FLUSH OnMilitiaRemoved bandit hero without party - {partyBase.MobileParty.LeaderHero.Name} at {partyBase.MobileParty.LeaderHero?.CurrentSettlement}.");
            }

            PartyMilitiaMap.Remove(partyBase.MobileParty);
        }
예제 #7
0
        private static void FlushBanditMilitias()
        {
            PartyMilitiaMap.Clear();
            var hasLogged       = false;
            var partiesToRemove = MobileParty.All.Where(x => x.StringId.StartsWith("Bandit_Militia")).ToList();

            foreach (var mobileParty in partiesToRemove)
            {
                if (!hasLogged)
                {
                    Mod.Log($">>> FLUSH {partiesToRemove.Count} Bandit Militias", LogLevel.Info);
                    hasLogged = true;
                }

                Trash(mobileParty);
            }
        }
예제 #8
0
 private static void Postfix(MobileParty __instance, MobileParty targetParty, ref bool __result)
 {
     if (__result &&
         !targetParty.IsGarrison &&
         !targetParty.IsMilitia &&
         PartyMilitiaMap.ContainsKey(__instance))
     //Militias.Any(x => x.MobileParty == __instance))
     {
         if (targetParty == MobileParty.MainParty)
         {
             __result = true;
         }
         else
         {
             var party1Strength = __instance.GetTotalStrengthWithFollowers();
             var party2Strength = targetParty.GetTotalStrengthWithFollowers();
             var delta          = (party1Strength - party2Strength) / party1Strength * 100;
             __result = delta <= Globals.Settings.PartyStrengthDeltaPercent;
         }
     }
 }
예제 #9
0
            private static void Postfix()
            {
                Mod.Log("MapScreen.OnInitialize");
                //Mod.Log("Clans:");
                //Clan.All.Do(x => Mod.Log($"Name: {x.Name} MapFaction: {x.MapFaction} Culture: {x.Culture}"));
                //Mod.Log("Bandit Clans:");
                //Clan.BanditFactions.Do(x => Mod.Log($"Name: {x.Name} MapFaction: {x.MapFaction} Culture: {x.Culture}"));
                HeroCreatorCopy.VeteransRespect = PerkObject.All.First(x => x.StringId == "LeadershipVeteransRespect");
                HeroCreatorCopy.Leadership      = SkillObject.All.First(x => x.StringId == "Leadership");
                EquipmentItems.Clear();
                PopulateItems();
                Recruits = CharacterObject.All.Where(x =>
                                                     x.Level == 11 &&
                                                     x.Occupation == Occupation.Soldier &&
                                                     !x.StringId.StartsWith("regular_fighter") &&
                                                     !x.StringId.StartsWith("veteran_borrowed_troop") &&
                                                     !x.StringId.EndsWith("_tier_1") &&
                                                     !x.StringId.Contains("_militia_") &&
                                                     !x.StringId.Equals("sturgian_warrior_son") &&
                                                     !x.StringId.Equals("khuzait_noble_son") &&
                                                     !x.StringId.Equals("imperial_vigla_recruit") &&
                                                     !x.StringId.Equals("battanian_highborn_youth") &&
                                                     !x.StringId.Equals("vlandian_squire") &&
                                                     !x.StringId.Equals("aserai_youth") &&
                                                     !x.StringId.Equals("poacher"));

                // used for armour
                foreach (ItemObject.ItemTypeEnum value in Enum.GetValues(typeof(ItemObject.ItemTypeEnum)))
                {
                    ItemTypes[value] = Items.FindAll(x =>
                                                     x.Type == value && x.Value >= 1000 && x.Value <= Globals.Settings.MaxItemValue * Variance).ToList();
                }

                // front-load
                BanditEquipment.Clear();
                for (var i = 0; i < 500; i++)
                {
                    BanditEquipment.Add(BuildViableEquipmentSet());
                }

                PartyMilitiaMap.Clear();
                Hideouts = Settlement.FindAll(x => x.IsHideout()).ToList();

                var militias = MobileParty.All.Where(x =>
                                                     x != null && x.StringId.StartsWith("Bandit_Militia")).ToList();

                for (var i = 0; i < militias.Count; i++)
                {
                    var militia = militias[i];
                    if (militia.LeaderHero == null)
                    {
                        Mod.Log("Leaderless militia found and removed.");
                        Trash(militia);
                    }
                    else
                    {
                        var recreatedMilitia = new Militia(militia);
                        PartyMilitiaMap.Add(recreatedMilitia.MobileParty, recreatedMilitia);
                    }
                }

                Mod.Log($"Militias: {militias.Count} (registered {PartyMilitiaMap.Count})");
                // 1.5.8 is dropping the militia settlements at some point, I haven't figured out where
                ReHome();
                DailyCalculations();

                // have to patch it late because of its static constructor (type initialization exception)
                Mod.harmony.Patch(
                    AccessTools.Method(typeof(EncounterGameMenuBehavior), "game_menu_encounter_on_init"),
                    new HarmonyMethod(AccessTools.Method(typeof(Helper), nameof(FixMapEventFuckery))));
            }
예제 #10
0
 private static void OnPartyRemoved(PartyBase party)
 {
     PartyMilitiaMap.Remove(party.MobileParty);
 }
예제 #11
0
            private static void Postfix()
            {
                Mod.Log("MapScreen.OnInitialize");
                MinSplitSize = Globals.Settings.MinPartySize * 2;
                EquipmentItems.Clear();
                PopulateItems();
                // 1.7 changed CreateHeroAtOccupation to only fish from this: NotableAndWandererTemplates
                // this has no effect on 1.6.5 since the property doesn't exist
                var characterObjects =
                    CharacterObject.All.Where(x =>
                                              x.Occupation is Occupation.Bandit &&
                                              x.Name.Contains("Boss")).ToList().GetReadOnlyList();

                foreach (var clan in Clan.BanditFactions)
                {
                    Traverse.Create(clan.Culture).Property <IReadOnlyList <CharacterObject> >("NotableAndWandererTemplates").Value = characterObjects;
                }

                var filter = new List <string>
                {
                    "regular_fighter",
                    "veteran_borrowed_troop",
                };

                Recruits = CharacterObject.All.Where(c =>
                                                     c.Level == 11 &&
                                                     c.Occupation == Occupation.Soldier &&
                                                     !filter.Contains(c.StringId) &&
                                                     !c.StringId.EndsWith("_tier_1"));

                // used for armour
                foreach (ItemObject.ItemTypeEnum value in Enum.GetValues(typeof(ItemObject.ItemTypeEnum)))
                {
                    ItemTypes[value] = Items.All.Where(x =>
                                                       x.Type == value && x.Value >= 1000 && x.Value <= Globals.Settings.MaxItemValue).ToList();
                }

                // front-load
                BanditEquipment.Clear();
                for (var i = 0; i < 1000; i++)
                {
                    BanditEquipment.Add(BuildViableEquipmentSet());
                }

                PartyMilitiaMap.Clear();
                Hideouts = Settlement.FindAll(x => x.IsHideout).ToList();

                // considers leaderless militias
                var militias = MobileParty.All.Where(m =>
                                                     m.LeaderHero is not null && m.StringId.StartsWith("Bandit_Militia")).ToList();

                for (var i = 0; i < militias.Count; i++)
                {
                    var militia          = militias[i];
                    var recreatedMilitia = new Militia(militia);
                    SetMilitiaPatrol(recreatedMilitia.MobileParty);
                    PartyMilitiaMap.Add(recreatedMilitia.MobileParty, recreatedMilitia);
                }

                DoPowerCalculations(true);
                FlushMilitiaCharacterObjects();
                // 1.6 is dropping the militia settlements at some point, I haven't figured out where
                ReHome();
                Mod.Log($"Militias: {militias.Count} (registered {PartyMilitiaMap.Count})");
                RunLateManualPatches();
            }
예제 #12
0
 internal static bool IsBM(MobileParty mobileParty)
 {
     return(mobileParty != null &&
            PartyMilitiaMap.ContainsKey(mobileParty));
 }
예제 #13
0
            private static void Postfix()
            {
                try
                {
                    if (Campaign.Current.TimeControlMode == CampaignTimeControlMode.Stop ||
                        Campaign.Current.TimeControlMode == CampaignTimeControlMode.UnstoppableFastForwardForPartyWaitTime ||
                        Campaign.Current.TimeControlMode == CampaignTimeControlMode.FastForwardStop ||
                        Campaign.Current.TimeControlMode == CampaignTimeControlMode.StoppableFastForward ||
                        GlobalMilitiaPower > CalculatedGlobalPowerLimit)
                    {
                        return;
                    }

                    var parties = MobileParty.All.Where(x =>
                                                        x.Party.IsMobile &&
                                                        x.CurrentSettlement == null &&
                                                        !x.IsCurrentlyUsedByAQuest &&
                                                        x.IsBandit).ToList();
                    //T.Restart();
                    for (var index = 0; index < parties.Count; index++)
                    {
                        var mobileParty = parties[index];
                        if (mobileParty.MoveTargetParty != null &&
                            mobileParty.MoveTargetParty.IsBandit ||
                            // Calradia Expanded Kingdoms
                            mobileParty.ToString().Contains("manhunter") ||
                            mobileParty.IsTooBusyToMerge())
                        {
                            continue;
                        }

                        CampaignTime?lastChangeDate = null;
                        if (PartyMilitiaMap.ContainsKey(mobileParty))
                        {
                            lastChangeDate = PartyMilitiaMap[mobileParty].LastMergedOrSplitDate;
                        }

                        if (CampaignTime.Now < lastChangeDate + CampaignTime.Hours(Globals.Settings.CooldownHours))
                        {
                            continue;
                        }

                        var targetParty = MobileParty.FindPartiesAroundPosition(mobileParty.Position2D, FindRadius,
                                                                                x => x != mobileParty && IsValidParty(x) &&
                                                                                x.MemberRoster.TotalManCount + mobileParty.MemberRoster.TotalManCount >= Globals.Settings.MinPartySize)
                                          .ToList().GetRandomElement()?.Party;

                        // "nobody" is a valid answer
                        if (targetParty == null)
                        {
                            continue;
                        }

                        CampaignTime?targetLastChangeDate = null;
                        if (PartyMilitiaMap.ContainsKey(targetParty.MobileParty))
                        {
                            targetLastChangeDate = PartyMilitiaMap[mobileParty].LastMergedOrSplitDate;
                        }

                        if (CampaignTime.Now < targetLastChangeDate + CampaignTime.Hours(Globals.Settings.CooldownHours))
                        {
                            continue;
                        }

                        var militiaTotalCount = mobileParty.MemberRoster.TotalManCount + targetParty.MemberRoster.TotalManCount;
                        if (militiaTotalCount < Globals.Settings.MinPartySize ||
                            militiaTotalCount > CalculatedMaxPartySize ||
                            mobileParty.Party.TotalStrength > CalculatedMaxPartyStrength ||
                            NumMountedTroops(mobileParty.MemberRoster) + NumMountedTroops(targetParty.MemberRoster) > militiaTotalCount / 2)
                        {
                            continue;
                        }

                        if (Campaign.Current.Models.MapDistanceModel.GetDistance(targetParty.MobileParty, mobileParty) > MergeDistance)
                        {
                            Mod.Log($"{mobileParty} seeking > {targetParty.MobileParty}");
                            mobileParty.SetMoveEscortParty(targetParty.MobileParty);
                            //Mod.Log($"SetNavigationModeParty ==> {T.ElapsedTicks / 10000F:F3}ms");

                            if (targetParty.MobileParty.MoveTargetParty != mobileParty)
                            {
                                Mod.Log($"{targetParty.MobileParty} seeking back > {mobileParty}");
                                targetParty.MobileParty.SetMoveEscortParty(mobileParty);
                                //Mod.Log($"SetNavigationModeTargetParty ==> {T.ElapsedTicks / 10000F:F3}ms");
                            }

                            continue;
                        }

                        if (Settlement.FindSettlementsAroundPosition(mobileParty.Position2D, MinDistanceFromHideout, x => x.IsHideout()).Any())
                        {
                            continue;
                        }

                        // create a new party merged from the two
                        var rosters = MergeRosters(mobileParty, targetParty);
                        var militia = new Militia(mobileParty, rosters[0], rosters[1]);
                        militia.MobileParty.SetMovePatrolAroundPoint(militia.MobileParty.Position2D);

                        // teleport new militias near the player
                        if (TestingMode)
                        {
                            // in case a prisoner
                            var party = Hero.MainHero.PartyBelongedTo ?? Hero.MainHero.PartyBelongedToAsPrisoner.MobileParty;
                            militia.MobileParty.Position2D = party.Position2D;
                        }

                        militia.MobileParty.Party.Visuals.SetMapIconAsDirty();
                        Trash(mobileParty);
                        Trash(targetParty.MobileParty);
                        //Mod.Log($">>> Finished all work: {T.ElapsedTicks / 10000F:F3}ms.");
                    }

                    //Mod.Log($"Looped ==> {T.ElapsedTicks / 10000F:F3}ms");
                }
                catch (Exception ex)
                {
                    Mod.Log(ex);
                }
            }