static void Prefix(MechDFASequence __instance) { (MeleeAttack meleeAttack, Weapon fakeWeapon)seqState = ModState.GetMeleeSequenceState(__instance.SequenceGUID); if (seqState.meleeAttack != null && seqState.meleeAttack.AttackerInstability != 0) { Mod.MeleeLog.Info?.Write($" -- Adding {seqState.meleeAttack.AttackerInstability} absolute instability to attacker."); __instance.OwningMech.AddAbsoluteInstability(seqState.meleeAttack.AttackerInstability, StabilityChangeSource.Attack, "-1"); } }
static void Postfix(MechDFASequence __instance, List <Weapon> ___requestedWeapons) { // TODO: If this happens before the above... need to grab the selected melee type from state Mod.MeleeLog.Info?.Write($"Setting current melee type to: {MeleeAttackType.DFA} and weapon to: {__instance.OwningMech.DFAWeapon.UIName}"); (MeleeAttack meleeAttack, Weapon fakeWeapon)seqState = ModState.GetMeleeSequenceState(__instance.SequenceGUID); if (seqState.meleeAttack != null) { // Modify the owning mech DFA melee weapon to do the 'first' hit float targetDamage = seqState.meleeAttack.TargetDamageClusters?.Length > 0 ? seqState.meleeAttack.TargetDamageClusters[0] : 0; __instance.OwningMech.DFAWeapon.StatCollection.Set <float>(ModStats.HBS_Weapon_DamagePerShot, targetDamage); __instance.OwningMech.DFAWeapon.StatCollection.Set <float>(ModStats.HBS_Weapon_Instability, 0); Mod.MeleeLog.Info?.Write($"For {CombatantUtils.Label(__instance.OwningMech)} set DFA weapon damage: {targetDamage} and instability: {seqState.meleeAttack.TargetInstability}"); // Cache the attacker's original DFASelfDamage value and set it to zero, so we can apply our own damage ModState.OriginalDFASelfDamage = __instance.OwningMech.StatCollection.GetValue <float>(ModStats.HBS_DFA_Self_Damage); __instance.OwningMech.StatCollection.Set <float>(ModStats.HBS_DFA_Self_Damage, 0f); __instance.OwningMech.StatCollection.Set <bool>(ModStats.HBS_DFA_Causes_Self_Unsteady, false); // Make sure we use the target's damage table ModState.ForceDamageTable = seqState.meleeAttack.TargetTable; // Filter any weapons from requested weapons. This works because BuildMeleeDirectorSequence is called immediately before BuildWeaponDirectorSequence if (Mod.Config.Melee.FilterCanUseInMeleeWeaponsByAttack) { Mod.MeleeLog.Debug?.Write($"Filtering DFA weapons by attack type: {seqState.meleeAttack.Label}"); List <Weapon> allowedWeapons = new List <Weapon>(); foreach (Weapon weapon in ___requestedWeapons) { if (seqState.meleeAttack.IsRangedWeaponAllowed(weapon)) { Mod.MeleeLog.Debug?.Write($" -- Weapon: {weapon.UIName} is allowed by melee type."); allowedWeapons.Add(weapon); } } ___requestedWeapons.Clear(); ___requestedWeapons.AddRange(allowedWeapons); } } }
static void Prefix(MechMeleeSequence __instance) { (MeleeAttack meleeAttack, Weapon fakeWeapon)seqState = ModState.GetMeleeSequenceState(__instance.SequenceGUID); if (seqState.meleeAttack != null && seqState.meleeAttack.AttackerInstability != 0) { Mod.MeleeLog.Info?.Write($" -- Adding {seqState.meleeAttack.AttackerInstability} absolute instability to attacker."); __instance.OwningMech.AddAbsoluteInstability(seqState.meleeAttack.AttackerInstability, StabilityChangeSource.Attack, "-1"); } // Publish a floatie warning of the swarm attack on the target if (ModState.ForceDamageTable == DamageTable.SWARM) { string swarmAttackText = new Text(Mod.LocalizedText.Floaties[ModText.FT_Swarm_Attack]).ToString(); MultiSequence showInfoSequence = new ShowActorInfoSequence(__instance.MeleeTarget, swarmAttackText, FloatieMessage.MessageNature.Debuff, false) { RootSequenceGUID = __instance.SequenceGUID }; SharedState.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(showInfoSequence)); Mod.Log.Info?.Write(" -- published fall sequence."); } }
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; }