Пример #1
0
 // PlayerEncounter.SacrificeTroops
 public static void SacrificeTroops(float ratio, MapEventSide side, MapEvent mapEvent)
 {
     // side.MakeReadyForSimulation();
     foreach (PartyBase party in side.Parties)
     {
         SacrificeTroopsWithRatio(party.MobileParty, ratio);
     }
 }
Пример #2
0
        public static float GetPartyContributionRate(this MapEventSide instance, PartyBase partyBase)
        {
            var totalContribution = instance.CalculateTotalContribution();

            if (totalContribution == 0)
            {
                return(0f);
            }

            var partyContribution = instance.PartyRecs.FirstOrDefault(p => p.Party == partyBase)?.ContributionToBattle ?? 0;

            return((float)partyContribution / (float)totalContribution);
        }
        // MapEventSide.ApplySimulationDamageToSelectedTroop
        public static bool ApplySimulationDamageToSelectedTroop(MapEventSide side,
                                                                CharacterObject strikedTroop,
                                                                PartyBase strikedTroopParty,
                                                                UniqueTroopDescriptor strikedTroopDescriptor,
                                                                int selectedSimulationTroopIndex,
                                                                List <UniqueTroopDescriptor> strikedTroopList,
                                                                PartyAttackComposition attack,
                                                                DamageTypes damageType,
                                                                PartyBase strikerParty,
                                                                MapEventState mapEventState,
                                                                IBattleObserver battleObserver,
                                                                out float damage)
        {
            bool IsFinishingStrike = mapEventState.ApplyDamageToPartyTroop(attack, strikedTroopParty, strikedTroop, out damage);

            if (IsFinishingStrike)
            {
                if (strikedTroop.IsHero)
                {
                    battleObserver?.TroopNumberChanged(side.MissionSide, (IBattleCombatant)strikedTroopParty, (BasicCharacterObject)strikedTroop, -1, 0, 1, 0, 0, 0);
                }
                else
                {
                    float survivalChance = Campaign.Current.Models.PartyHealingModel.GetSurvivalChance(strikedTroopParty, strikedTroop, damageType, strikerParty);
                    if (MBRandom.RandomFloat < survivalChance)
                    {
                        side.OnTroopWounded(strikedTroopDescriptor);
                        battleObserver?.TroopNumberChanged(side.MissionSide, (IBattleCombatant)strikedTroopParty, (BasicCharacterObject)strikedTroop, -1, 0, 1, 0, 0, 0);
                        if (strikedTroopParty.MobileParty != null)
                        {
                            SkillLevelingManager.OnSurgeryApplied(strikedTroopParty.MobileParty, 1f);
                        }
                    }
                    else
                    {
                        side.OnTroopKilled(strikedTroopDescriptor);
                        battleObserver?.TroopNumberChanged(side.MissionSide, (IBattleCombatant)strikedTroopParty, (BasicCharacterObject)strikedTroop, -1, 1, 0, 0, 0, 0);
                        if (strikedTroopParty.MobileParty != null)
                        {
                            SkillLevelingManager.OnSurgeryApplied(strikedTroopParty.MobileParty, 0.5f);
                        }
                    }
                }

                // side.RemoveSelectedTroopFromSimulationList();
                RemoveSelectedTroopFromSimulationList(side, selectedSimulationTroopIndex, strikedTroopList);
            }
            return(IsFinishingStrike);
        }
        private static bool StrikeOnce(MapEvent mapEvent,
                                       IBattleObserver battleObserver,
                                       MapEventSide strikerSide,
                                       MapEventSide strikedSide,
                                       PartyAttackComposition attack,
                                       out float totalDamageDone)
        {
            int strikerNumber = strikerSide.NumRemainingSimulationTroops;
            int strikedNumber = strikedSide.NumRemainingSimulationTroops;

            totalDamageDone = 0;
            if (strikerNumber == 0 || strikedNumber == 0)
            {
                return(true);
            }

            MapEventState mapEventState  = MapEventState.GetMapEventState(mapEvent);
            bool          finishedAnyone = false;

            for (int index = strikedNumber - 1; index >= 0; index--)
            {
                UniqueTroopDescriptor strikerTroopDescriptor = strikerSide.SelectRandomSimulationTroop();
                CharacterObject       strikerTroop           = strikerSide.GetAllocatedTroop(strikerTroopDescriptor);
                PartyBase             strikerTroopParty      = strikerSide.GetAllocatedTroopParty(strikerTroopDescriptor);

                UniqueTroopDescriptor strikedTroopDescriptor = MapEventSideHelper.SelectSimulationTroopAtIndex(strikedSide, index, out List <UniqueTroopDescriptor> strikedTroopList);
                CharacterObject       strikedTroop           = strikedSide.GetAllocatedTroop(strikedTroopDescriptor);
                PartyBase             strikedTroopParty      = strikedSide.GetAllocatedTroopParty(strikedTroopDescriptor);

                // MapEvents.GetSimulatedDamage and CombatSimulationModel.SimulateHit
                if (mapEvent.IsPlayerSimulation && strikedTroopParty == PartyBase.MainParty)
                {
                    float damageMultiplier = Campaign.Current.Models.DifficultyModel.GetPlayerTroopsReceivedDamageMultiplier();
                    attack *= damageMultiplier;
                }
                DamageTypes damageType = (double)MBRandom.RandomFloat < 0.15 ? DamageTypes.Blunt : DamageTypes.Cut;

                bool isFinishingStrike = MapEventSideHelper.ApplySimulationDamageToSelectedTroop(
                    strikedSide, strikedTroop, strikedTroopParty, strikedTroopDescriptor, index, strikedTroopList,
                    attack, damageType, strikerTroopParty, mapEventState, battleObserver, out float damage);
                totalDamageDone += damage;

                strikerSide.ApplySimulatedHitRewardToSelectedTroop(strikedTroop, 0, isFinishingStrike);
                finishedAnyone = finishedAnyone || isFinishingStrike;
            }

            return(finishedAnyone);
        }
 public static float RecalculateStrengthOfSide(MapEventSide side, MapEventState mapEventState)
 {
     if (!SubModule.Settings.Battle_SendAllTroops)
     {
         return(side.RecalculateStrengthOfSide());
     }
     else
     {
         float totalStrength = 0f;
         foreach (var party in side.Parties)
         {
             totalStrength += mapEventState.GetPartyStrength(party);
         }
         return(totalStrength);
     }
 }
        public static UniqueTroopDescriptor SelectSimulationTroopAtIndex(MapEventSide side, int index, out List <UniqueTroopDescriptor> simulationTroopList)
        {
            // side._selectedSimulationTroopIndex = index;
            MapEventSide__selectedSimulationTroopIndex.SetValue(side, index);

            // side._selectedSimulationTroopDescriptor = side._simulationTroopList[index];
            simulationTroopList = (List <UniqueTroopDescriptor>)MapEventSide__simulationTroopList.GetValue(side);
            UniqueTroopDescriptor selectedSimulationTroopDescriptor = simulationTroopList[index];

            MapEventSide__selectedSimulationTroopDescriptor.SetValue(side, selectedSimulationTroopDescriptor);

            // side._selectedSimulationTroop = side.GetAllocatedTroop(side._selectedSimulationTroopDescriptor);
            MapEventSide__selectedSimulationTroop.SetValue(side, side.GetAllocatedTroop(selectedSimulationTroopDescriptor));

            return(selectedSimulationTroopDescriptor);
        }
Пример #7
0
        // DefaultTroopSacrificeModel.GetNumberOfTroopsSacrificedForTryingToGetAway
        public static int GetNumberOfTroopsSacrificedForTryingToGetAway(
            MapEventSide mapEventSide,
            MapEventSide oppositeSide,
            float powerRatio,
            int ofRegularMembers)
        {
            int             num2 = mapEventSide.CountTroops((Func <FlattenedTroopRosterElement, bool>)(x => x.State == RosterTroopState.Active && !x.Troop.IsHero));
            ExplainedNumber stat = new ExplainedNumber(1f, (StringBuilder)null);

            if (mapEventSide.LeaderParty.Leader != null)
            {
                SkillHelper.AddSkillBonusForCharacter(DefaultSkills.Tactics, DefaultSkillEffects.TacticsTroopSacrificeReduction, mapEventSide.LeaderParty.Leader, ref stat, true);
            }

            int num3 = Math.Max(((double)ofRegularMembers * Math.Pow((double)Math.Min(powerRatio, 3f), 1.29999995231628) * 0.100000001490116 / (2.0 / (2.0 + ((double)stat.ResultNumber - 1.0) * 10.0)) + 5.0).Round(), 1);

            return(num3 <= num2 ? num3 : -1);
        }
        // MapEventSide.RemoveSelectedTroopFromSimulationList
        public static void RemoveSelectedTroopFromSimulationList(MapEventSide side,
                                                                 int selectedSimulationTroopIndex,
                                                                 List <UniqueTroopDescriptor> simulationTroopList)
        {
            // this._simulationTroopList[this._selectedSimulationTroopIndex] = this._simulationTroopList[this._simulationTroopList.Count - 1];
            // this._simulationTroopList.RemoveAt(this._simulationTroopList.Count - 1);
            // int selectedSimulationTroopIndex = (int)MapEventSide__selectedSimulationTroopIndex.GetValue(side);
            // List<UniqueTroopDescriptor> simulationTroopList = (List<UniqueTroopDescriptor>)MapEventSide_PartyAttackComposition_simulationTroopList.GetValue(side);
            simulationTroopList[selectedSimulationTroopIndex] = simulationTroopList[simulationTroopList.Count - 1];
            simulationTroopList.RemoveAt(simulationTroopList.Count - 1);

            // this._selectedSimulationTroopIndex = -1;
            // this._selectedSimulationTroopDescriptor = UniqueTroopDescriptor.Invalid;
            // this._selectedSimulationTroop = (CharacterObject)null;
            MapEventSide__selectedSimulationTroopIndex.SetValue(side, -1);
            MapEventSide__selectedSimulationTroopDescriptor.SetValue(side, UniqueTroopDescriptor.Invalid);
            MapEventSide__selectedSimulationTroop.SetValue(side, (CharacterObject)null);
        }
Пример #9
0
            private static void Postfix(MapEventSide __instance, PartyBase party, Hero __state)
            {
                if (__state == null ||
                    party?.MobileParty == null ||
                    !IsBM(party.MobileParty) ||
                    party.PrisonRoster != null &&
                    party.PrisonRoster.Contains(Hero.MainHero.CharacterObject))
                {
                    return;
                }

                if (party.MemberRoster?.TotalHealthyCount == 0 ||
                    party.MemberRoster?.TotalHealthyCount < Globals.Settings.MinPartySize &&
                    party.PrisonRoster?.Count < Globals.Settings.MinPartySize &&
                    __instance.Casualties > party.MemberRoster?.TotalHealthyCount * 2)
                {
                    Mod.Log($">>> Dispersing {party.Name} of {party.MemberRoster.TotalHealthyCount}+{party.MemberRoster.TotalWounded}w+{party.PrisonRoster?.Count}p");
                    __state.KillHero();
                    Trash(party.MobileParty);
                }
            }
Пример #10
0
        private List <Troop> PrepareTroopsForSide(MapEventSide mapEventSide, int amount, bool isAttacker)
        {
            var troopList      = Troop.GetTroopList(mapEventSide);
            var counter        = 0;
            var selectedTroops = new List <Troop>();

            foreach (var descriptor in troopList)
            {
                var chance = amount / (troopList.Count - counter);
                if (chance > MBRandom.RandomFloat)
                {
                    amount--;
                    var character = mapEventSide.GetAllocatedTroop(descriptor);
                    selectedTroops.Add(new Troop(descriptor, character, isAttacker));
                }
                if (amount == 0)
                {
                    break;
                }
                counter++;
            }

            return(selectedTroops);
        }
 internal static void RemoveSelectedTroopFromSimulationList(this MapEventSide __instance)
 {
     throw new NotImplementedException("Reverse patch didn't work");
 }
Пример #12
0
 public static int CalculateTotalContribution(this MapEventSide instance) => instance.PartyRecs
 .Where(mapEventParty => mapEventParty.Party.MemberRoster.Count > 0)
 .Sum(mapEventParty => mapEventParty.ContributionToBattle);
Пример #13
0
        public void CalculateRelation(MapEvent m)
        {
            if (Hero.MainHero != null && Hero.MainHero.IsAlive)
            {
                if (m.IsFieldBattle || m.IsSiege || m.IsSiegeOutside)
                {
                    if (m.PlayerSide.ToString().Equals("Defender") || m.PlayerSide.ToString().Equals("Attacker"))
                    {
                        MapEventSide sidePlayer = GetPlayerEventSide(m);
                        MapEventSide sideEnemy  = GetEnemyEventSide(m);
                        if (sidePlayer != null && sideEnemy != null)
                        {
                            List <PartyBase> allyHeroesB  = new List <PartyBase>(sidePlayer.PartiesOnThisSide.ToList <PartyBase>());
                            List <PartyBase> enemyHeroesB = new List <PartyBase>(sideEnemy.PartiesOnThisSide.ToList <PartyBase>());
                            if (allyHeroesB != null && enemyHeroesB != null)
                            {
                                int              totalMenAlly           = sidePlayer.TroopCount + sidePlayer.Casualties;
                                int              totalMenEnemy          = sideEnemy.TroopCount + sideEnemy.Casualties;
                                int              casualtiesAlly         = sidePlayer.Casualties;
                                int              casualtiesEnemy        = sideEnemy.Casualties;
                                int              involvedMen            = totalMenAlly + totalMenEnemy;
                                float            playerContributionRate = sidePlayer.GetPlayerPartyContributionRate();
                                List <PartyBase> allyHeroes             = new List <PartyBase>(ConfigureParties(allyHeroesB));
                                List <PartyBase> enemyHeroes            = new List <PartyBase>(ConfigureParties(enemyHeroesB));

                                if (allyHeroes != null && enemyHeroes != null && allyHeroes.Count > 0 && enemyHeroes.Count > 0)
                                {
                                    if (totalMenAlly >= FTRConfig.newInstance.FTRInitialize.MinimumAlly && totalMenEnemy >= FTRConfig.newInstance.FTRInitialize.MinimumEnemy)
                                    {
                                        if (sidePlayer.Equals(m.Winner))
                                        {
                                            bool lostBattle = false;
                                            if (totalMenAlly >= totalMenEnemy)
                                            {
                                                if ((totalMenAlly / totalMenEnemy) <= 1.2 && (totalMenAlly - totalMenEnemy) <= 80)
                                                {
                                                    if (casualtiesEnemy > casualtiesAlly)
                                                    {
                                                        double c1       = 2 + playerContributionRate * 1.3;
                                                        double calcrel  = Math.Round(c1, 0, MidpointRounding.AwayFromZero);
                                                        int    rel      = (int)calcrel;
                                                        double relMulti = rel * FTRConfig.newInstance.FTRInitialize.GainMultiplier;
                                                        rel = (int)Math.Round(relMulti, 0, MidpointRounding.AwayFromZero);
                                                        RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                    }
                                                    else
                                                    {
                                                        double c2       = 1.25 + playerContributionRate * 1.3;
                                                        double calcrel  = Math.Round(c2, 0, MidpointRounding.AwayFromZero);
                                                        int    rel      = (int)calcrel;
                                                        double relMulti = rel * FTRConfig.newInstance.FTRInitialize.GainMultiplier;
                                                        rel = (int)Math.Round(relMulti, 0, MidpointRounding.AwayFromZero);
                                                        RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                    }
                                                }
                                                else
                                                {
                                                    if (casualtiesEnemy > casualtiesAlly)
                                                    {
                                                        double c3       = 1.1 + playerContributionRate * 1.3;
                                                        double calcrel  = Math.Round(c3, 0, MidpointRounding.AwayFromZero);
                                                        int    rel      = (int)calcrel;
                                                        double relMulti = rel * FTRConfig.newInstance.FTRInitialize.GainMultiplier;
                                                        rel = (int)Math.Round(relMulti, 0, MidpointRounding.AwayFromZero);
                                                        RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                    }
                                                    else
                                                    {
                                                        RelationshipSelector(1, allyHeroes, enemyHeroes, lostBattle);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                if ((totalMenEnemy / totalMenAlly) >= 1.2 && (totalMenEnemy - totalMenAlly) > 60)
                                                {
                                                    double t        = totalMenEnemy / totalMenAlly;
                                                    double c4       = 2.4 + t + (playerContributionRate * 1.3);
                                                    double calcrel  = Math.Round(c4, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = (int)calcrel;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.GainMultiplier;
                                                    rel = (int)Math.Round(relMulti, 0, MidpointRounding.AwayFromZero);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                                else
                                                {
                                                    double c5       = 2.25 + (playerContributionRate * 1.3);
                                                    double calcrel  = Math.Round(c5, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = (int)calcrel;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.GainMultiplier;
                                                    rel = (int)Math.Round(relMulti, 0, MidpointRounding.AwayFromZero);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                            }
                                        }
                                        if (sidePlayer != m.Winner && sidePlayer.LeaderParty.Equals(PartyBase.MainParty) && FTRConfig.newInstance.FTRInitialize.EnableRelationshipLoss == true)
                                        {
                                            bool lostBattle = true;
                                            if (totalMenAlly >= totalMenEnemy)
                                            {
                                                if (casualtiesAlly <= casualtiesEnemy)
                                                {
                                                    double c6 = playerContributionRate * 1.3;
                                                    c6 = Math.Round(c6, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = -2 + (int)c6;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.LossMultiplier;
                                                    rel = (int)Math.Ceiling(relMulti);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                                else
                                                {
                                                    double c7 = (casualtiesAlly - casualtiesEnemy) / 50;
                                                    c7 = Math.Ceiling(c7);
                                                    double calcrel = playerContributionRate * 1.3;
                                                    calcrel = Math.Round(calcrel, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = -2 - (int)c7 + (int)calcrel;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.LossMultiplier;
                                                    rel = (int)Math.Ceiling(relMulti);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                            }
                                            else
                                            {
                                                if (casualtiesAlly > casualtiesEnemy)
                                                {
                                                    double t1 = (totalMenEnemy - totalMenAlly) / 50;
                                                    double c8 = (casualtiesAlly - casualtiesEnemy) / 50;
                                                    t1 = Math.Ceiling(t1);
                                                    c8 = Math.Ceiling(c8);
                                                    double calcrel = playerContributionRate * 1.3;
                                                    calcrel = Math.Round(calcrel, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = -4 - (int)t1 - (int)c8 + (int)calcrel;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.LossMultiplier;
                                                    rel = (int)Math.Ceiling(relMulti);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                                else
                                                {
                                                    double t2 = (totalMenEnemy - totalMenAlly) / 25;
                                                    t2 = Math.Ceiling(t2);
                                                    double calcrel = playerContributionRate * 1.3;
                                                    calcrel = Math.Round(calcrel, 0, MidpointRounding.AwayFromZero);
                                                    int    rel      = -4 - (int)t2 + (int)calcrel;
                                                    double relMulti = rel * FTRConfig.newInstance.FTRInitialize.LossMultiplier;
                                                    rel = (int)Math.Ceiling(relMulti);
                                                    RelationshipSelector(rel, allyHeroes, enemyHeroes, lostBattle);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public static bool Prefix(ref bool __result,
                                  MapEvent __instance,
                                  float strikerAdvantage)
        {
            MapEventSide    attackerSide   = __instance.AttackerSide;
            MapEventSide    defenderSide   = __instance.DefenderSide;
            MapEventState   mapEventState  = MapEventState.GetMapEventState(__instance);
            IBattleObserver battleObserver = (IBattleObserver)MapEvent_BattleObserver.GetValue(__instance);

            int attackerNumber = attackerSide.NumRemainingSimulationTroops;
            int defenderNumber = defenderSide.NumRemainingSimulationTroops;

            float strengthOfNumber;

            if (mapEventState.IsSiege)
            {
                strengthOfNumber = SubModule.Settings.Battle_SendAllTroops_SiegeStrengthOfNumber;
                //if (SubModule.Settings.Battle_SendAllTroops_DetailedCombatModel)
                //{
                //    if (mapEventState.GateBreached)
                //    {
                //        strengthOfNumber = (SubModule.Settings.Battle_SendAllTroops_SiegeStrengthOfNumber
                //            + SubModule.Settings.Battle_SendAllTroops_StrengthOfNumber) / 2;
                //    }
                //    else
                //    {
                //        strengthOfNumber = SubModule.Settings.Battle_SendAllTroops_SiegeStrengthOfNumber;
                //    }
                //}
                //else
                //{
                //    strengthOfNumber = SubModule.Settings.Battle_SendAllTroops_SiegeStrengthOfNumber;
                //}
            }
            else
            {
                strengthOfNumber = SubModule.Settings.Battle_SendAllTroops_StrengthOfNumber;
            }
            float battleSpeedMultiplier = DamageMultiplier;

            if (strengthOfNumber != 0.6f)
            {
                // Normalized battle speed to that of 0.6
                double biggerPartyNumber = Math.Max(attackerNumber, defenderNumber);
                battleSpeedMultiplier *= (float)Math.Pow(biggerPartyNumber, 0.6 - strengthOfNumber);
            }

            float attackerNumberPenalty = (float)Math.Pow((double)attackerNumber, strengthOfNumber - 1.0);
            float defenderNumberPenalty = (float)Math.Pow((double)defenderNumber, strengthOfNumber - 1.0);

            PartyAttackComposition attackerTotalAttack = new PartyAttackComposition();
            PartyAttackComposition defenderTotalAttack = new PartyAttackComposition();

            foreach (var party in attackerSide.Parties)
            {
                attackerTotalAttack += mapEventState.MakePartyAttack(party, battleSpeedMultiplier * attackerNumberPenalty / RangedAverageDamagePerHit);
            }
            foreach (var party in defenderSide.Parties)
            {
                defenderTotalAttack += mapEventState.MakePartyAttack(party, battleSpeedMultiplier * defenderNumberPenalty / RangedAverageDamagePerHit);
            }

            float attackerAdvantage = BattleAdvantageModel.PartyBattleAdvantage(attackerSide.LeaderParty);
            float defenderAdvantage = BattleAdvantageModel.PartyBattleAdvantage(defenderSide.LeaderParty);

            PartyAttackComposition attackerDistributedAttack = attackerTotalAttack
                                                               * (battleSpeedMultiplier * attackerNumberPenalty * attackerAdvantage * mapEventState.SettlementPenalty / defenderNumber);
            PartyAttackComposition defenderDistributedAttack = defenderTotalAttack
                                                               * (battleSpeedMultiplier * defenderNumberPenalty * defenderAdvantage / attackerNumber);

            bool finishedAnyone = false;

            finishedAnyone |= StrikeOnce(__instance, battleObserver, attackerSide, defenderSide, attackerDistributedAttack, out float attackerTotalDamageDone);
            finishedAnyone |= StrikeOnce(__instance, battleObserver, defenderSide, attackerSide, defenderDistributedAttack, out float defenderTotalDamageDone);

            // Distribute XP among all living
            int AttackerAverageDamageDone = (int)Math.Round(Math.Min(attackerTotalDamageDone / attackerNumber, 1));

            try
            {
                for (int index = 0; index < attackerSide.NumRemainingSimulationTroops; index++)
                {
                    MapEventSideHelper.SelectSimulationTroopAtIndex(attackerSide, index, out _);
                    attackerSide.ApplySimulatedHitRewardToSelectedTroop(null, AttackerAverageDamageDone, false);
                }
                int DefenderAverageDamageDone = (int)Math.Round(Math.Min(defenderTotalDamageDone / defenderNumber, 1));
                for (int index = 0; index < attackerSide.NumRemainingSimulationTroops; index++)
                {
                    MapEventSideHelper.SelectSimulationTroopAtIndex(attackerSide, index, out _);
                    attackerSide.ApplySimulatedHitRewardToSelectedTroop(null, DefenderAverageDamageDone, false);
                }
            }
            catch (NullReferenceException)
            {
                // CombatXpModel.GetXpFromHit is changed by other mod and not accepting attackedTroop == null
            }

            __result = finishedAnyone;

            return(false);
        }
Пример #15
0
        public static bool Prefix(ref bool __result, MapEvent __instance, int ____mapEventUpdateCount)
        {
            if (____mapEventUpdateCount <= 1)
            {
                __result = false;
                return(false);
            }

            bool AttackerRunaway = false;
            bool DefenderRunaway = false;

            // __instance.SimulateBattleSetup();
            MapEventSide attackerSide          = __instance.AttackerSide;
            MapEventSide defenderSide          = __instance.DefenderSide;
            float        attackerTotalStrength = attackerSide.RecalculateStrengthOfSide();
            float        defenderTotalStrength = defenderSide.RecalculateStrengthOfSide();

            if (__instance.IsSiegeAssault)
            {
                attackerTotalStrength *= 0.6666667f;
            }
            float powerRatio = defenderTotalStrength / attackerTotalStrength;

            if (__instance.AttackerSide.LeaderParty.LeaderHero == null)
            {
                AttackerRunaway = false;
            }
            else
            {
                // Attacker Runaway
                if (powerRatio > 1.2)
                {
                    float baseChance = (powerRatio - 1.2f) * 1.5f * SubModule.Settings.Strategy_LearnToQuit_RetreatChance;
                    float bonus      = -(float)__instance.AttackerSide.LeaderParty.LeaderHero.GetTraitLevel(DefaultTraits.Valor) * 0.2f;
                    AttackerRunaway = MBRandom.RandomFloat < baseChance + bonus;
                }
            }
            if (AttackerRunaway)
            {
                if (SubModule.Settings.Strategy_LearnToQuit_Verbose)
                {
                    Dictionary <string, TextObject> attributes = new Dictionary <string, TextObject>
                    {
                        { "ATTACKER", __instance.AttackerSide.LeaderParty.Name },
                        { "DEFENDER", __instance.DefenderSide.LeaderParty.Name },
                    };
                    TextObject information = new TextObject("{=dJhAtk}{ATTACKER} withdrew from battle against {DEFENDER}.", attributes);
                    InformationManager.DisplayMessage(new InformationMessage(information.ToString()));
                }

                __result = true;
                return(false);
            }

            float sacrificeRatio = 0f;

            if (__instance.DefenderSide.LeaderParty.LeaderHero == null)
            {
                DefenderRunaway = false;
            }
            else
            {
                // Defender Runaway
                if (powerRatio <= 0.8f)
                {
                    int ofRegularMembers = 0;
                    foreach (PartyBase party in __instance.DefenderSide.Parties)
                    {
                        ofRegularMembers += party.NumberOfRegularMembers;
                    }
                    int forTryingToGetAway = TroopSacrificeModel.GetNumberOfTroopsSacrificedForTryingToGetAway(__instance.DefenderSide, __instance.AttackerSide, 1 / powerRatio, ofRegularMembers);
                    if (forTryingToGetAway < 0 || ofRegularMembers < forTryingToGetAway)
                    {
                        // Not enough man
                        DefenderRunaway = false;
                    }
                    else
                    {
                        sacrificeRatio = (float)forTryingToGetAway / (float)ofRegularMembers;
                        float baseChance = (1f - 1.25f * powerRatio) * 1.5f * SubModule.Settings.Strategy_LearnToQuit_RetreatChance;
                        float bonus      = -(float)__instance.DefenderSide.LeaderParty.LeaderHero.GetTraitLevel(DefaultTraits.Valor) * 0.2f;
                        DefenderRunaway = MBRandom.RandomFloat < baseChance + bonus;
                    }
                }
            }
            if (DefenderRunaway)
            {
                MapEventCustomMembers.DefendersRanAway[__instance.Id] = true;
                if (SubModule.Settings.Strategy_LearnToQuit_Verbose)
                {
                    Dictionary <string, TextObject> attributes = new Dictionary <string, TextObject>
                    {
                        { "ATTACKER", __instance.AttackerSide.LeaderParty.Name },
                        { "DEFENDER", __instance.DefenderSide.LeaderParty.Name },
                    };
                    TextObject information = new TextObject("{=LLIPq6}{DEFENDER} was forced to retreat against {ATTACKER}.", attributes);
                    InformationManager.DisplayMessage(new InformationMessage(information.ToString()));
                }
                TroopSacrificeModel.SacrificeTroops(sacrificeRatio, __instance.DefenderSide, __instance);

                __result = true;
                return(false);
            }

            __result = false;
            return(false);
        }
 internal static Dictionary <UniqueTroopDescriptor, MapEventParty> GetAllocatedTroops(MapEventSide mapEventSide) => _allocatedTroops(mapEventSide);
 internal static IBattleObserver GetBattleObserver(MapEventSide mapEventSide) => (IBattleObserver)_battleObserverPropertyGetter.GetValue(mapEventSide);
        internal static bool Prefix(ref bool __result, ref MapEventSide __instance, ref CharacterObject ____selectedSimulationTroop, ref UniqueTroopDescriptor ____selectedSimulationTroopDescriptor, int damage, DamageTypes damageType, out int troopState, PartyBase strikerParty)
        {
            if (strikerParty.MapEvent != null && SimulationModel.IsValidEventType(strikerParty.MapEvent.EventType))
            {
                if (SimulationsPool.TryGetSimulationModel(strikerParty.MapEvent.Id, out var simulationModel))
                {
                    SimulationTroopState simulationTroopState = SimulationTroopState.Alive;
                    __result = false;

                    // try to find the attacked troop in our model. Id doesn't exist call vanilla method
                    var troopId = ____selectedSimulationTroop.Id;
                    var troop   = simulationModel.Parties[(int)__instance.MissionSide].Troops.Find(t => t.CharacterObject.Id == troopId);
                    if (troop == null)
                    {
                        troopState = (int)simulationTroopState;
                        return(true);
                    }

                    var battleObserver  = MapEventSideAccessTools.GetBattleObserver(__instance);
                    var allocatedTroops = MapEventSideAccessTools.GetAllocatedTroops(__instance);

                    // troop is a Hero logic
                    if (____selectedSimulationTroop.IsHero)
                    {
                        __instance.AddHeroDamage(____selectedSimulationTroop.HeroObject, damage);
                        if (____selectedSimulationTroop.HeroObject.IsWounded)
                        {
                            __result             = true;
                            simulationTroopState = SimulationTroopState.Wounded;
                            if (battleObserver != null)
                            {
                                battleObserver.TroopNumberChanged(__instance.MissionSide, __instance.GetAllocatedTroopParty(____selectedSimulationTroopDescriptor), ____selectedSimulationTroop, -1, 0, 1, 0, 0, 0);
                            }
                        }
                    }
                    // regular logic
                    else if (troop.ApplyDamage(damage))
                    {
                        PartyBase party          = allocatedTroops[____selectedSimulationTroopDescriptor].Party;
                        float     survivalChance = Campaign.Current.Models.PartyHealingModel.GetSurvivalChance(party, ____selectedSimulationTroop, damageType, strikerParty);

                        if (MBRandom.RandomFloat < survivalChance)
                        {
                            __instance.OnTroopWounded(____selectedSimulationTroopDescriptor);
                            simulationTroopState = SimulationTroopState.Wounded;
                            if (battleObserver != null)
                            {
                                battleObserver.TroopNumberChanged(__instance.MissionSide, __instance.GetAllocatedTroopParty(____selectedSimulationTroopDescriptor), ____selectedSimulationTroop, -1, 0, 1, 0, 0, 0);
                            }
                            SkillLevelingManager.OnSurgeryApplied(party.MobileParty, 1f);
                        }
                        else
                        {
                            __instance.OnTroopKilled(____selectedSimulationTroopDescriptor);
                            simulationTroopState = SimulationTroopState.Kille;

                            if (battleObserver != null)
                            {
                                battleObserver.TroopNumberChanged(__instance.MissionSide, __instance.GetAllocatedTroopParty(____selectedSimulationTroopDescriptor), ____selectedSimulationTroop, -1, 1, 0, 0, 0, 0);
                            }
                            SkillLevelingManager.OnSurgeryApplied(party.MobileParty, 0.5f);
                        }
                        __result = true;
                    }

                    if (__result)
                    {
                        __instance.RemoveSelectedTroopFromSimulationList();
                    }

                    troopState = (int)simulationTroopState;
                    return(false);
                }
            }
            troopState = 1;
            return(true);
        }