// 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);
        }
Beispiel #3
0
 public void SetObserver(IBattleObserver observer)
 {
     this.BattleObserver = observer;
 }
Beispiel #4
0
 public void registerObserver(IBattleObserver observer)
 {
     this.observer = observer;
 }
Beispiel #5
0
 public void start()
 {
     observer             = null;
     pokemonBattleManager = new PokemonBattleManager();
     state = BattleState.Inactive;
 }
Beispiel #6
0
 /// <summary>
 /// Remove an observer that no longer wants to be notified about events
 /// </summary>
 /// <param name="battleObserver"></param>
 public void UnSubscribe(IBattleObserver battleObserver)
 {
     observers.Remove(battleObserver);
 }
Beispiel #7
0
 /// <summary>
 /// Adds an observer that wants to be notified about events
 /// </summary>
 /// <param name="battleObserver"></param>
 public void Subscribe(IBattleObserver battleObserver)
 {
     observers.Add(battleObserver);
 }
Beispiel #8
0
 /// <summary>
 /// Remove an observer that no longer wants to be notified about events
 /// </summary>
 /// <param name="battleObserver"></param>
 public void UnSubscribe(IBattleObserver battleObserver)
 {
     observers.Remove(battleObserver);
 }
Beispiel #9
0
 /// <summary>
 /// Adds an observer that wants to be notified about events
 /// </summary>
 /// <param name="battleObserver"></param>
 public void Subscribe(IBattleObserver battleObserver)
 {
     observers.Add(battleObserver);
 }
        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);
        }