/// <summary> /// returns true if 10% armor damage was incurred or any structure damage /// </summary> /// <param name="attackSequence"></param> /// <returns></returns> private static bool SufficientDamageWasDone(AttackDirector.AttackSequence attackSequence) { if (attackSequence == null) { return(false); } var id = attackSequence.chosenTarget.GUID; if (!attackSequence.GetAttackDidDamage(id)) { LogDebug("No damage"); return(false); } var previousArmor = Patches.mechArmorBeforeAttack; var previousStructure = Patches.mechStructureBeforeAttack; LogDebug($"Damage >>> A: {attackSequence.GetArmorDamageDealt(id):#.###}" + $" S: {attackSequence.GetStructureDamageDealt(id):#.###}" + $" ({(attackSequence.GetArmorDamageDealt(id) + attackSequence.GetStructureDamageDealt(id)) / (previousArmor + previousStructure) * 100:#.##}%) H: {Patches.heatDamage}"); if (attackSequence.GetStructureDamageDealt(id) >= modSettings.MinimumStructureDamageRequired) { LogDebug("Structure damage requires panic save"); return(true); } float heatTaken = 0; if (attackSequence.chosenTarget is Mech defender) { heatTaken = defender.CurrentHeat - Patches.mechHeatBeforeAttack; // LogDebug($"B {Patches.mechHeatBeforeAttack} A {defender.CurrentHeat}"); LogDebug($"Took {Patches.heatDamage} heat"); } LogDebug($"attackSequence.GetArmorDamageDealt(id) {attackSequence.GetArmorDamageDealt(id)}\nattackSequence.GetStructureDamageDealt(id) {attackSequence.GetStructureDamageDealt(id)}\nPatches.heatDamage * modSettings.HeatDamageModifier {Patches.heatDamage * modSettings.HeatDamageModifier}"); if (attackSequence.GetArmorDamageDealt(id) + attackSequence.GetStructureDamageDealt(id) + Patches.heatDamage * modSettings.HeatDamageModifier / (previousArmor + previousStructure) + 100 <= modSettings.MinimumDamagePercentageRequired) { LogDebug("Not enough damage"); return(false); } LogDebug("Total damage requires a panic save"); return(true); }
// returns true if enough damage was inflicted to trigger a panic save private static bool SufficientDamageWasDone(AttackDirector.AttackSequence attackSequence) { if (attackSequence == null) { return(false); } var id = attackSequence.chosenTarget.GUID; if (!attackSequence.GetAttackDidDamage(id)) { LogReport("No damage"); return(false); } var previousArmor = AttackStackSequence_OnAttackBegin_Patch.armorBeforeAttack; var previousStructure = AttackStackSequence_OnAttackBegin_Patch.structureBeforeAttack; var armorDamage = attackSequence.GetArmorDamageDealt(id); var structureDamage = attackSequence.GetStructureDamageDealt(id); var percentDamageDone = (attackSequence.GetArmorDamageDealt(id) + attackSequence.GetStructureDamageDealt(id)) / (previousArmor + previousStructure) * 100; damageWithHeatDamage = percentDamageDone + Mech_AddExternalHeat_Patch.heatDamage * modSettings.HeatDamageFactor; // have to check structure here AFTER armor, despite it being the priority, because we need to set the global LogReport($"Damage >>> A: {armorDamage:F3} S: {structureDamage:F3} ({percentDamageDone:F2}%) H: {Mech_AddExternalHeat_Patch.heatDamage}"); if (attackSequence.chosenTarget is Mech && attackSequence.GetStructureDamageDealt(id) >= modSettings.MinimumMechStructureDamageRequired || modSettings.VehiclesCanPanic && attackSequence.chosenTarget is Vehicle && attackSequence.GetStructureDamageDealt(id) >= modSettings.MinimumVehicleStructureDamageRequired) { LogReport("Structure damage requires panic save"); return(true); } if (damageWithHeatDamage <= modSettings.MinimumDamagePercentageRequired) { LogReport("Not enough damage"); Mech_AddExternalHeat_Patch.heatDamage = 0; return(false); } LogReport("Total damage requires a panic save"); return(true); }
// returns true if enough damage was inflicted to trigger a panic save private static bool SufficientDamageWasDone(AttackDirector.AttackSequence attackSequence) { if (attackSequence == null) { return(false); } var id = attackSequence.chosenTarget.GUID; if (!attackSequence.GetAttackDidDamage(id)) { LogReport("No damage"); return(false); } // Account for melee attacks so separate panics are not triggered. if (attackSequence.isMelee && MechMeleeSequence_FireWeapons_Patch.meleeHasSupportWeapons) { initialArmorMelee = AttackStackSequence_OnAttackBegin_Patch.armorBeforeAttack; initialStructureMelee = AttackStackSequence_OnAttackBegin_Patch.structureBeforeAttack; armorDamageMelee = attackSequence.GetArmorDamageDealt(id); structureDamageMelee = attackSequence.GetStructureDamageDealt(id); hadMeleeAttack = true; LogReport("Stashing melee damage for support weapon firing"); return(false); } var previousArmor = AttackStackSequence_OnAttackBegin_Patch.armorBeforeAttack; var previousStructure = AttackStackSequence_OnAttackBegin_Patch.structureBeforeAttack; if (hadMeleeAttack) { LogReport("Adding stashed melee damage"); previousArmor = initialArmorMelee; previousStructure = initialStructureMelee; } else { armorDamageMelee = 0; structureDamageMelee = 0; } var armorDamage = attackSequence.GetArmorDamageDealt(id) + armorDamageMelee; var structureDamage = attackSequence.GetStructureDamageDealt(id) + structureDamageMelee; var heatDamage = Mech_AddExternalHeat_Patch.heatDamage * modSettings.HeatDamageFactor; // used in SavingThrows.cs damageIncludingHeatDamage = armorDamage + structureDamage + heatDamage; var percentDamageDone = damageIncludingHeatDamage / (previousArmor + previousStructure) * 100; // clear melee values initialArmorMelee = 0; initialStructureMelee = 0; armorDamageMelee = 0; structureDamageMelee = 0; hadMeleeAttack = false; // have to check structure here AFTER armor, despite it being the priority, because we need to set the global LogReport($"Damage >>> A: {armorDamage:F3} S: {structureDamage:F3} ({percentDamageDone:F2}%) H: {Mech_AddExternalHeat_Patch.heatDamage}"); if (modSettings.AlwaysPanic) { LogReport("AlwaysPanic"); return(true); } if (attackSequence.chosenTarget is Mech && attackSequence.GetStructureDamageDealt(id) > modSettings.MinimumMechStructureDamageRequired || modSettings.VehiclesCanPanic && attackSequence.chosenTarget is Vehicle && attackSequence.GetStructureDamageDealt(id) > modSettings.MinimumVehicleStructureDamageRequired) { LogReport("Structure damage requires panic save"); return(true); } if (percentDamageDone <= modSettings.MinimumDamagePercentageRequired) { LogReport("Not enough damage"); Mech_AddExternalHeat_Patch.heatDamage = 0; return(false); } LogReport("Total damage requires a panic save"); return(true); }
static void Postfix(AbstractActor __instance, string sourceID, int sequenceID, int stackItemID, AttackDirection attackDirection) { try { AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(sequenceID); if (attackSequence != null && attackSequence.GetAttackDidDamage(__instance.GUID)) { List <Effect> list = __instance.Combat.EffectManager.GetAllEffectsTargeting(__instance).FindAll((Effect x) => x.EffectData.targetingData.effectTriggerType == EffectTriggerType.OnDamaged); for (int i = 0; i < list.Count; i++) { list[i].OnEffectTakeDamage(attackSequence.attacker, __instance); } if (attackSequence.isMelee) { int value = attackSequence.attacker.StatCollection.GetValue <int>("MeleeHitPushBackPhases"); if (value > 0) { for (int j = 0; j < value; j++) { __instance.ForceUnitOnePhaseDown(sourceID, stackItemID, false); } } } } int evasivePipsCurrent = __instance.EvasivePipsCurrent; var settings = PermanentEvasion.Settings; float totalDamageReceived = 1; if (attackSequence.GetAttackDidDamage(__instance.GUID)) { totalDamageReceived += attackSequence.GetArmorDamageDealt(__instance.GUID) + attackSequence.GetStructureDamageDealt(__instance.GUID); if ((totalDamageReceived > settings.MinDamageForEvasionStrip) && settings.AllowHitStrip) { __instance.ConsumeEvasivePip(true); Fields.LoosePip = false; } else if (Fields.LoosePip) { __instance.ConsumeEvasivePip(true); Fields.LoosePip = false; } } else if (Fields.LoosePip) { __instance.ConsumeEvasivePip(true); Fields.LoosePip = false; } int evasivePipsCurrent2 = __instance.EvasivePipsCurrent; if (evasivePipsCurrent2 < evasivePipsCurrent && (totalDamageReceived > settings.MinDamageForEvasionStrip) && settings.AllowHitStrip && !__instance.IsDead && !__instance.IsFlaggedForDeath) { __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "HIT: -1 EVASION", FloatieMessage.MessageNature.Debuff)); } else if (evasivePipsCurrent2 < evasivePipsCurrent && !__instance.IsDead && !__instance.IsFlaggedForDeath) { __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "-1 EVASION", FloatieMessage.MessageNature.Debuff)); } else if (evasivePipsCurrent2 > 0 && Fields.KeptPip && !__instance.IsDead && !__instance.IsFlaggedForDeath) { __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "EVASION KEPT", FloatieMessage.MessageNature.Buff)); Fields.KeptPip = false; } } catch (Exception e) { Logger.Error(e); } }