// PlayerEncounter.SacrificeTroops public static void SacrificeTroops(float ratio, MapEventSide side, MapEvent mapEvent) { // side.MakeReadyForSimulation(); foreach (PartyBase party in side.Parties) { SacrificeTroopsWithRatio(party.MobileParty, ratio); } }
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); }
// 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); }
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); } }
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"); }
public static int CalculateTotalContribution(this MapEventSide instance) => instance.PartyRecs .Where(mapEventParty => mapEventParty.Party.MemberRoster.Count > 0) .Sum(mapEventParty => mapEventParty.ContributionToBattle);
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); }
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); }