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);
                }
            }
        }
Пример #3
0
        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;
        }