public static void Prefix(MechFallSequence __instance) { Mod.Log.Trace?.Write("MFS:OnComplete - entered."); int damagePointsTT = (int)Math.Ceiling(__instance.OwningMech.tonnage / 10f); Mod.Log.Debug?.Write($"Actor: {CombatantUtils.Label(__instance.OwningMech)} will suffer {damagePointsTT} TT damage points."); // Check for any pilot skill damage reduction float damageReduction = 1.0f - __instance.OwningMech.PilotCheckMod(Mod.Config.Piloting.DFAReductionMulti); float reducedDamage = (float)Math.Max(0f, Math.Floor(damageReduction * damagePointsTT)); Mod.Log.Debug?.Write($" Reducing TT fall damage from: {damagePointsTT} by {damageReduction:P1} to {reducedDamage}"); List <float> locationDamage = new List <float>(); while (damagePointsTT >= 5) { locationDamage.Add(5 * Mod.Config.Piloting.FallingDamagePerTenTons); damagePointsTT -= 5; } if (damagePointsTT > 0) { locationDamage.Add(damagePointsTT * Mod.Config.Piloting.FallingDamagePerTenTons); } Mod.Log.Info?.Write($"FALLING DAMAGE: TT damage: {damagePointsTT} => {damagePointsTT * Mod.Config.Piloting.FallingDamagePerTenTons} falling damage to actor: {CombatantUtils.Label(__instance.OwningMech)}"); try { (Weapon melee, Weapon dfa)fakeWeapons = ModState.GetFakedWeapons(__instance.OwningMech); AttackHelper.CreateImaginaryAttack(__instance.OwningMech, fakeWeapons.melee, __instance.OwningMech, __instance.SequenceGUID, locationDamage.ToArray(), DamageType.KnockdownSelf, MeleeAttackType.NotSet); } catch (Exception e) { Mod.Log.Error?.Write(e, "FAILED TO APPLY FALL DAMAGE"); } }
static void Prefix(MechDFASequence __instance, MessageCenterMessage message, AttackStackSequence ___meleeSequence) { Mod.Log.Trace?.Write("MMS:OMC entered."); AttackCompleteMessage attackCompleteMessage = message as AttackCompleteMessage; Mod.MeleeLog.Info?.Write($"== Resolving cluster damage, instability, and unsteady on DFA attacker: {CombatantUtils.Label(__instance.OwningMech)} and " + $"target: {CombatantUtils.Label(__instance.DFATarget)}."); (MeleeAttack meleeAttack, Weapon fakeWeapon)seqState = ModState.GetMeleeSequenceState(__instance.SequenceGUID); if (attackCompleteMessage.stackItemUID == ___meleeSequence.SequenceGUID && seqState.meleeAttack != null) { // Check to see if the target was hit bool targetWasHit = false; foreach (AttackDirector.AttackSequence attackSequence in ___meleeSequence.directorSequences) { if (!attackSequence.attackCompletelyMissed) { targetWasHit = true; Mod.MeleeLog.Info?.Write($" -- AttackSequence: {attackSequence.stackItemUID} hit the target."); } else { Mod.MeleeLog.Info?.Write($" -- AttackSequence: {attackSequence.stackItemUID} missed the target."); } } if (__instance.OwningMech.isHasStability() && !__instance.OwningMech.IsOrWillBeProne) { // Attacker stability and unsteady - always applies as we're always a mech if ((targetWasHit && seqState.meleeAttack.UnsteadyAttackerOnHit) || (!targetWasHit && seqState.meleeAttack.UnsteadyAttackerOnMiss)) { Mod.MeleeLog.Info?.Write(" -- Forcing attacker to become unsteady from attack!"); __instance.OwningMech.DumpEvasion(); } } // Attacker cluster damage if (targetWasHit && !__instance.OwningMech.IsDead) { // Make sure we use the attackers's damage table ModState.ForceDamageTable = seqState.meleeAttack.AttackerTable; if (seqState.meleeAttack.AttackerDamageClusters.Length > 0) { try { Mod.MeleeLog.Info?.Write($" -- Applying {seqState.meleeAttack.AttackerDamageClusters.Sum()} damage to attacker as {seqState.meleeAttack.AttackerDamageClusters.Length} clusters."); AttackHelper.CreateImaginaryAttack(__instance.OwningMech, seqState.fakeWeapon, __instance.OwningMech, __instance.SequenceGUID, seqState.meleeAttack.AttackerDamageClusters, DamageType.Melee, MeleeAttackType.Kick); } catch (Exception e) { Mod.Log.Error?.Write(e, "FAILED TO APPLY DFA DAMAGE TO ATTACKER"); } } } if (targetWasHit) { // Target mech stability and unsteady if (__instance.DFATarget is Mech targetMech && targetMech.isHasStability() && !targetMech.IsProne) { if (seqState.meleeAttack.TargetInstability != 0) { Mod.MeleeLog.Info?.Write($" -- Adding {seqState.meleeAttack.TargetInstability} absolute instability to target."); targetMech.AddAbsoluteInstability(seqState.meleeAttack.TargetInstability, StabilityChangeSource.Attack, "-1"); } if (seqState.meleeAttack.OnTargetMechHitForceUnsteady) { Mod.MeleeLog.Info?.Write(" -- Forcing target to become unsteady from attack!"); targetMech.DumpEvasion(); } } // Target vehicle evasion damage if (__instance.DFATarget is Vehicle || __instance.DFATarget.FakeVehicle() || __instance.DFATarget.NavalUnit()) { AbstractActor targetActor = __instance.DFATarget as AbstractActor; if (seqState.meleeAttack.OnTargetVehicleHitEvasionPipsRemoved != 0 && targetActor.EvasivePipsCurrent > 0) { Mod.MeleeLog.Info?.Write($" -- Removing {seqState.meleeAttack.OnTargetVehicleHitEvasionPipsRemoved} from target vehicle."); int modifiedPips = targetActor.EvasivePipsCurrent - seqState.meleeAttack.OnTargetVehicleHitEvasionPipsRemoved; if (modifiedPips < 0) { modifiedPips = 0; } targetActor.EvasivePipsCurrent = modifiedPips; SharedState.Combat.MessageCenter.PublishMessage(new EvasiveChangedMessage(targetActor.GUID, targetActor.EvasivePipsCurrent)); } } // Target cluster damage - first attack was applied through melee weapon if (seqState.meleeAttack.TargetDamageClusters.Length > 1 && !__instance.DFATarget.IsDead) { try { // Make sure we use the attackers's damage table ModState.ForceDamageTable = seqState.meleeAttack.TargetTable; // The target already got hit by the first cluster as the weapon damage. Only add the additional hits float[] clusterDamage = seqState.meleeAttack.TargetDamageClusters.SubArray(1, seqState.meleeAttack.TargetDamageClusters.Length); Mod.MeleeLog.Info?.Write($" -- Applying {clusterDamage.Sum()} damage to target as {clusterDamage.Length} clusters."); AttackHelper.CreateImaginaryAttack(__instance.OwningMech, seqState.fakeWeapon, __instance.DFATarget, __instance.SequenceGUID, clusterDamage, DamageType.Melee, MeleeAttackType.DFA); } catch (Exception e) { Mod.Log.Error?.Write(e, "FAILED TO APPLY DFA DAMAGE TO TARGET"); } } } Mod.MeleeLog.Info?.Write($"== Done."); } // Restore the attacker's DFA damage __instance.OwningMech.StatCollection.Set <float>(ModStats.HBS_DFA_Self_Damage, ModState.OriginalDFASelfDamage); __instance.OwningMech.StatCollection.Set <bool>(ModStats.HBS_DFA_Causes_Self_Unsteady, true); // Reset melee state ModState.ForceDamageTable = DamageTable.NONE; ModState.OriginalDFASelfDamage = 0f; }