Esempio n. 1
0
        static bool Prefix(MechMeleeSequence __instance)
        {
            // allow DFA to knock down target in single hit
            if (Core.ModSettings.AllowSteadyToKnockdownForMelee)
            {
                if (!__instance.MeleeTarget.IsDead)
                {
                    var mech = __instance.MeleeTarget as Mech;
                    Logger.Debug($"opponent stability: {mech.CurrentStability}");
                    var target = __instance.MeleeTarget as AbstractActor;
                    if (target != null)
                    {
                        Logger.Debug($"found target before first check. unsteady? {mech.IsUnsteady} : prone? {mech.IsProne}");
                        target.NeedsInstabilityCheck = true;
                        target.CheckForInstability();
                        Logger.Debug($"found target before second check. unsteady? {mech.IsUnsteady} : prone? {mech.IsProne}");
                        target.NeedsInstabilityCheck = true;
                        target.CheckForInstability();
                        Logger.Debug($"found target after second  check. downed? {mech.IsUnsteady} : prone? {mech.IsProne}");
                        var attacker = __instance.OwningMech;
                        target.HandleKnockdown(__instance.RootSequenceGUID, attacker.GUID, Vector2.one, null);
                    }
                }
            }

            return(true);
        }
 static void Postfix(MechMeleeSequence __instance, bool __result)
 {
     using (var logwriter = File.AppendText(SprintAndPunch.LogPath))
     {
         logwriter?.WriteLine("Default prefix result of ConsumesMovement is {0}.", __result);
         // __result = true;
         Pilot curPilot = __instance.OwningMech.GetPilot();
         if (curPilot != null && curPilot.PassiveAbilities.Count > 0) //.StatCollection.GetValue<int>("MeleeHitPushBackPhases") > 0)
         {
             logwriter?.WriteLine("Found pilot with abilities.");
             bool foundJug = false;
             for (int i = 0; i < curPilot.PassiveAbilities.Count && !foundJug; i++)
             {
                 if (curPilot.PassiveAbilities[i].Def.Description.Id == "AbilityDefGu8")
                 {
                     logwriter?.WriteLine("Should be returning false for ConsumesMovement.");
                     __result = false; //ignore firing cost with juggernaut active:
                                       //__instance.OwningMech.BracedLastRound = true;
                     /// __instance.OwningMech.ApplyInstabilityReduction(StabilityChangeSource.Bracing);
                     foundJug = true;
                     SprintAndPunch.justPunched = foundJug;
                     SprintAndPunch.jugMech     = __instance.OwningMech;
                 }
             }
             if (!foundJug) //assume melee cost like normal
             {
                 logwriter?.WriteLine("Should be returning true for COnsumesMovement.");
                 __result = true;
             }
         }
     }
 }
        public static void Prefix(MechMeleeSequence __instance, ref List <Weapon> ___requestedWeapons)
        {
            if (___requestedWeapons.Count < 1)
            {
                return;
            }

            AbstractActor actor       = __instance.owningActor;
            ICombatant    MeleeTarget = __instance.MeleeTarget;

            bool TargetIsDead            = MeleeTarget.IsDead;
            bool TargetIsFlaggedForDeath = MeleeTarget.IsFlaggedForDeath;

            Logger.Info("[MechMeleeSequence_OnMeleeComplete_PREFIX] TargetIsDead: " + TargetIsDead);
            Logger.Info("[MechMeleeSequence_OnMeleeComplete_PREFIX] TargetIsFlaggedForDeath: " + TargetIsFlaggedForDeath);

            if (TargetIsDead || TargetIsFlaggedForDeath)
            {
                ___requestedWeapons.Clear();
                actor.Combat.MessageCenter.PublishMessage(new FloatieMessage(actor.GUID, actor.GUID, "SUSPENDED SUPPORT WEAPONS", FloatieMessage.MessageNature.Neutral));
            }
            else
            {
                DontShootTheDead.BuildSupportWeaponSequence = true;
                Traverse BuildWeaponDirectorSequence = Traverse.Create(__instance).Method("BuildWeaponDirectorSequence");
                BuildWeaponDirectorSequence.GetValue();
            }
        }
Esempio n. 4
0
        static bool Prefix(MechMeleeSequence __instance)
        {
            // attacker second instability check during melee whiff
            var attacker = __instance.OwningMech;

            attacker.CheckForInstability();
            HandleFall.Say(attacker);  // only one I couldn't get to trigger, but I believe is correctly placed
            attacker.HandleKnockdown(__instance.RootSequenceGUID, attacker.GUID, Vector2.one, null);

            // second target instability check during melee hit if can go to ground in one hit
            if (Core.ModSettings.AllowSteadyToKnockdownForMelee)
            {
                if (!__instance.MeleeTarget.IsDead)
                {
                    var target = __instance.MeleeTarget as AbstractActor;
                    if (target != null)
                    {
                        target.NeedsInstabilityCheck = true;
                        target.CheckForInstability();
                        target.HandleKnockdown(__instance.RootSequenceGUID, attacker.GUID, Vector2.one, null);
                    }
                }
            }

            Logger.Debug($"did we fall? {attacker.IsProne}");
            Logger.Debug($"did they fall? {__instance.MeleeTarget.IsProne}");
            return(true);
        }
 static bool Prefix(MechMeleeSequence __instance, bool __result)
 {
     using (var logwriter = File.AppendText(SprintAndPunch.LogPath))
     {
         logwriter?.WriteLine("Default prefix result of ConsumesMovement is {0}.", __result);
         // __result = true;
         Pilot curPilot = __instance.OwningMech.GetPilot();
         if (curPilot != null && curPilot.PassiveAbilities.Count > 0) //.StatCollection.GetValue<int>("MeleeHitPushBackPhases") > 0)
         {
             logwriter?.WriteLine("Found pilot with abilities.");
             bool foundJug = false;
             for (int i = 0; i < curPilot.PassiveAbilities.Count && !foundJug; i++)
             {
                 if (curPilot.PassiveAbilities[i].Def.Description.Id == "AbilityDefGu8")
                 {
                     logwriter?.WriteLine("Should be returning false for ConsumesMovement.");
                     __result = false; //ignore firing cost with juggernaut active:
                     foundJug = true;
                     return(false);    //overriding if we have this...
                 }
             }
             if (!foundJug) //assume melee cost like normal
             {
                 logwriter?.WriteLine("Should be returning true for ConsumesMovement.");
                 __result = true;
             }
         }
         return(true); //otherwise skip
     }
 }
Esempio n. 6
0
        // Remove the BuildWeaponDirectorSequence, to prevent duplicate ammo consumption
        static bool Prefix(MechMeleeSequence __instance)
        {
            Traverse BuildMeleeDirectorSequenceT = Traverse.Create(__instance).Method("BuildMeleeDirectorSequence");

            BuildMeleeDirectorSequenceT.GetValue();

            if (__instance.OwningMech.GameRep != null)
            {
                __instance.OwningMech.GameRep.ReturnToNeutralFacing(isParellelSequence: true, 0.5f, __instance.RootSequenceGUID, __instance.SequenceGUID, null);
            }
            if (__instance.OwningMech.GameRep != null)
            {
                __instance.OwningMech.GameRep.FadeThrottleAudio(0f, 50f, 1f);
            }
            SharedState.Combat.MessageCenter.AddSubscriber(MessageCenterMessageType.OnAttackComplete, __instance.OnMeleeComplete);
            SharedState.Combat.MessageCenter.AddSubscriber(MessageCenterMessageType.OnAttackSequenceFire, __instance.OnMeleeReady);

            // Reading meleeSequence as a property doesn't seem to work, because it always returns null. I'm unsure if this
            //   is a harmony bug... so read it directly, which seems to work.
            Traverse            meleeSequenceT = Traverse.Create(__instance).Field("meleeSequence");
            AttackStackSequence meleeSequence  = meleeSequenceT.GetValue <AttackStackSequence>();

            SharedState.Combat.MessageCenter.PublishMessage(new AddParallelSequenceToStackMessage(meleeSequence));

            return(false);
        }
Esempio n. 7
0
        static void Postfix(ref MessageCenterMessage message, MechMeleeSequence __instance)
        {
            Logger.Debug($"checking for miss: {(message as AttackCompleteMessage).attackSequence.attackCompletelyMissed}");

            if (Core.ModSettings.AttackMissInstability)
            {
                // Deal with attacker missing
                var attackCompleteMessage = (AttackCompleteMessage)message;
                var attacker = __instance.OwningMech;
                if (attackCompleteMessage.attackSequence.attackCompletelyMissed)
                {
                    Logger.Debug($"melee pre-miss stability: {attacker.CurrentStability}");
                    var rawInstabilityToAdd = attacker.IsLegged
                        ? Core.ModSettings.AttackMissInstabilityLeggedPercent
                        : Core.ModSettings.AttackMissInstabilityPercent;
                    var instabilityToAdd = rawInstabilityToAdd;
                    if (Core.ModSettings.pilotingSkillInstabilityMitigation)
                    {
                        var mitigation        = Calculator.PilotingMitigation(attacker);
                        var mitigationPercent = Mathf.RoundToInt(mitigation * 100);
                        instabilityToAdd = rawInstabilityToAdd - rawInstabilityToAdd * mitigation;
                        Logger.Debug($"melee miss numbers\n" +
                                     $"pilotSkill: {attacker.SkillPiloting}\n" +
                                     $"mitigation: {mitigation}\n" +
                                     $"rawInstabilityToAdd: {rawInstabilityToAdd}\n" +
                                     $"mitigationPercent: {mitigationPercent}\n" +
                                     $"instabilityToAdd: {instabilityToAdd}");
                        attacker.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(attacker, $"Pilot Check: Avoided {mitigationPercent}% Instability!", FloatieMessage.MessageNature.Neutral, true)));
                    }

                    attacker.AddRelativeInstability(instabilityToAdd, StabilityChangeSource.Attack, attacker.GUID);
                    Logger.Debug($"melee post-miss stability: {attacker.CurrentStability}");
                    attacker.NeedsInstabilityCheck = true;
                    if (Core.ModSettings.AllowSteadyToKnockdownForMelee)
                    {
                        attacker.CheckForInstability();
                        attacker.NeedsInstabilityCheck = true;
                    }
                }
            }

            // Deal with target needing additional checks if we want to be able to knock over
            // mechs in a single round from one attack.
            if (Core.ModSettings.AllowSteadyToKnockdownForMelee)
            {
                if (!__instance.MeleeTarget.IsDead)
                {
                    var target = __instance.MeleeTarget as AbstractActor;
                    if (target != null)
                    {
                        target.NeedsInstabilityCheck = true;
                        target.CheckForInstability();
                        var attacker = __instance.OwningMech;
                        HandleFall.Say(attacker);
                        target.HandleKnockdown(__instance.RootSequenceGUID, attacker.GUID, Vector2.one, null);
                    }
                }
            }
        }
Esempio n. 8
0
        static void Postfix(MechMeleeSequence __instance, Mech mech, ICombatant meleeTarget,
                            List <Weapon> requestedWeapons, Vector3 desiredMeleePosition)
        {
            try
            {
                // Find the selectedAttack we should use for this sequence
                MeleeAttack selectedAttack = ModState.GetSelectedAttack(mech);
                if (selectedAttack == null)
                {
                    Mod.MeleeLog.Warn?.Write($"Melee sequence {__instance.SequenceGUID} has no pre-selected attack state, will have to autoselected. Let Frost know as this should not happen!");
                    MeleeState meleeState = ModState.AddorUpdateMeleeState(mech, desiredMeleePosition, meleeTarget as AbstractActor);
                    if (meleeState == null)
                    {
                        Mod.Log.Error?.Write($"Could not build melee state for selected melee attack - this should NEVER happen!");
                        return;
                    }
                    selectedAttack = meleeState.GetHighestDamageAttackForUI();
                }

                if (selectedAttack == null || !selectedAttack.IsValid)
                {
                    Mod.Log.Error?.Write($"Could not select a valid attack for the selected sequence - this should NEVER happen!");
                    return;
                }

                // Check to see if we have an imaginary weapon to use; if not create it
                (Weapon meleeWeapon, Weapon dfaWeapon)weapons = ModState.GetFakedWeapons(mech);

                // Create the weapon + representation
                ModState.AddOrUpdateMeleeSequenceState(__instance.SequenceGUID, selectedAttack, weapons.meleeWeapon);

                StringBuilder sb = new StringBuilder();
                foreach (Weapon weapon in requestedWeapons)
                {
                    sb.Append(weapon.UIName);
                    sb.Append(",");
                }
                Mod.MeleeLog.Info?.Write($"  -- Initial requested weapons: {sb}");

                isValid = true;
            }
            catch (Exception e)
            {
                Mod.Log.Error?.Write(e, $"Failed to initialize Melee sequence {__instance.SequenceGUID}!");
            }
        }
        public static bool Prefix(MechMeleeSequence __instance, ref List <Weapon> ___requestedWeapons)
        {
            Logger.Info("[MechMeleeSequence_BuildWeaponDirectorSequence_PREFIX] DontShootTheDead.BuildSupportWeaponSequence: " + DontShootTheDead.BuildSupportWeaponSequence);

            // Only build a weapon sequence if melee didn't already kill the target
            if (DontShootTheDead.BuildSupportWeaponSequence)
            {
                // Will still only build a weapon sequence if ___requestedWeapons.Count is > 0
                return(true);
            }
            else
            {
                // This always needs to be done for a melee attack
                ___requestedWeapons.RemoveAll((Weapon x) => x.Type == WeaponType.Melee);

                return(false);
            }
        }
Esempio n. 10
0
            static void Postfix(MechMeleeSequence __instance)
            {
                try
                {
                    if (Fields.JuggernautCharges)
                    {
                        // Charge and tackle causes slight instability, check for unsteady
                        __instance.OwningMech.CheckForInstability();
                    }

                    // Just to be sure
                    Fields.JuggernautCharges = false;
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 11
0
        static void Postfix(ref MessageCenterMessage message, MechMeleeSequence __instance)
        {
            if (Core.ModSettings.DfaMissInstability)
            {
                Logger.Debug($"checking for miss: {(message as AttackCompleteMessage).attackSequence.attackCompletelyMissed}");
                var attackCompleteMessage = (AttackCompleteMessage)message;
                var attacker = __instance.OwningMech;
                if (attackCompleteMessage.attackSequence.attackCompletelyMissed)
                {
                    Logger.Debug("We missed!");
                    Logger.Debug($"flagged for knockdown? {attacker.IsFlaggedForKnockdown}");
                    var rawInstabilityToAdd = attacker.IsLegged
                        ? Core.ModSettings.DfaMissInstabilityLeggedPercent
                        : Core.ModSettings.DfaMissInstabilityPercent;
                    var instabilityToAdd = rawInstabilityToAdd;
                    if (Core.ModSettings.PilotingSkillInstabilityMitigation)
                    {
                        var mitigation        = Calculator.PilotingMitigation(attacker);
                        var mitigationPercent = Mathf.RoundToInt(mitigation * 100);
                        instabilityToAdd = rawInstabilityToAdd - rawInstabilityToAdd * mitigation;
                        Logger.Debug($"dfa miss numbers\n" +
                                     $"pilotSkill: {attacker.SkillPiloting}\n" +
                                     $"mitigation: {mitigation}\n" +
                                     $"rawInstabilityToAdd: {rawInstabilityToAdd}\n" +
                                     $"mitigationPercent: {mitigationPercent}\n" +
                                     $"instabilityToAdd: {instabilityToAdd}");
                        attacker.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(attacker, $"Pilot Check: Avoided {mitigationPercent}% Instability!", FloatieMessage.MessageNature.Neutral, true)));
                    }

                    attacker.AddRelativeInstability(instabilityToAdd, StabilityChangeSource.DFA, attacker.GUID);
                    attacker.NeedsInstabilityCheck = true;
                    attacker.CheckForInstability();
                    Logger.Debug($"flagged for knockdown? {attacker.IsFlaggedForKnockdown}");
                    if (Core.ModSettings.AllowSteadyToKnockdownForMelee)
                    {
                        attacker.NeedsInstabilityCheck = true;
                        attacker.CheckForInstability();
                        Logger.Debug($"flagged for knockdown? {attacker.IsFlaggedForKnockdown}");
                    }
                }

                HandleFall.Say(attacker);
            }
        }
Esempio n. 12
0
 static void Prefix(MechMeleeSequence __instance)
 {
     try
     {
         Pilot pilot = __instance.owningActor.GetPilot();
         if (pilot.IsJuggernaut() && Fields.JuggernautCharges)
         {
             Logger.Debug("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges);
             MeleeAttackType selectedMeleeType = (MeleeAttackType)AccessTools.Property(typeof(MechMeleeSequence), "selectedMeleeType").GetValue(__instance, null);
             Logger.Info("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] BEFORE selectedMeleeType: " + selectedMeleeType);
             selectedMeleeType = MeleeAttackType.Charge;
             Logger.Info("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] AFTER selectedMeleeType: " + selectedMeleeType);
         }
     }
     catch (Exception e)
     {
         Logger.Error(e);
     }
 }
Esempio n. 13
0
        static void Postfix(MechMeleeSequence __instance)
        {
            if (!MechMeleeSequence_ctor.isValid)
            {
                Mod.MeleeLog.Info?.Write($"  -- Invalid sequence in OnAdded, skipping!");
                return;
            }

            Mod.MeleeLog.Trace?.Write("MMS:CO - entered.");

            // Base method checks for target knockdown. Do the same for the attacker.
            if (!__instance.OwningMech.IsDead)
            {
                __instance.OwningMech.CheckForInstability();
                __instance.OwningMech.HandleKnockdown(__instance.RootSequenceGUID, __instance.owningActor.GUID, Vector2.one, null);
            }

            ModState.InvalidateState(__instance.OwningMech);
        }
Esempio n. 14
0
        static void Prefix(MechMeleeSequence __instance)
        {
            Mod.MeleeLog.Debug?.Write("Regenerating melee support weapons hit locations...");
            Traverse BuildWeaponDirectorSequenceT = Traverse.Create(__instance).Method("BuildWeaponDirectorSequence");

            if (BuildWeaponDirectorSequenceT == null)
            {
                Mod.Log.Error?.Write($"No method named BuildWeaponDirectorSequence found - no clue what will happen next!");
                System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();
                Mod.Log.Info?.Write($"  Error occured at: {t}");
            }
            else
            {
                BuildWeaponDirectorSequenceT.GetValue();
                Mod.MeleeLog.Debug?.Write(" -- Done!");
            }

            // Reset damage table
            ModState.ForceDamageTable = DamageTable.NONE;
        }
Esempio n. 15
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.");
            }
        }
Esempio n. 16
0
            static void Prefix(MechMeleeSequence __instance)
            {
                try
                {
                    Pilot pilot = __instance.owningActor.GetPilot();
                    if (pilot.IsJuggernaut())
                    {
                        // In some rare occasions DistMovedThisRound is smaller than MaxWalkDistance BUT unit is marked as sprinting via CostLeft from Pathing.
                        // Relying on the mark set at [Pathing_UpdateMeleePath_POSTFIX], DistMovedThisRound is only logged as a reference here.
                        Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] maxWalkDistance: " + __instance.OwningMech.MaxWalkDistance);
                        Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] distMovedThisRound: " + __instance.OwningMech.DistMovedThisRound);
                        Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] SprintedLastRound: " + __instance.owningActor.SprintedLastRound);
                        Logger.Debug("[MechMeleeSequence_ExecuteMove_PREFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges);

                        // Juggernauts only gain GUARDED on regular melee attack...
                        if (!__instance.owningActor.SprintedLastRound)
                        {
                            Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] Juggernaut only moved. Apply braced but don't further reduce instability.");
                            __instance.owningActor.BracedLastRound = true;

                            // Include stability reduction only when Mech remained "stationary"
                            if (__instance.OwningMech.DistMovedThisRound < 10f)
                            {
                                // @ToDo: Check if this will be applied from Core already and thus will result in a doubled reduction...
                                Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] Juggernaut did not move at all. Reduce instability.");
                                __instance.OwningMech.ApplyInstabilityReduction(StabilityChangeSource.RemainingStationary);
                            }
                        }
                        // ...but not when charging
                        else
                        {
                            Logger.Debug("[MechMeleeSequence_OnMoveComplete_PREFIX] Juggernaut sprinted. Should not apply instability reduction.");
                        }
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 17
0
            public static void Postfix(MechMeleeSequence __instance)
            {
                try
                {
                    Logger.Debug($"[MechMeleeSequence_OnAdded_POSTFIX] Focus on melee target...");

                    CombatGameState ___combatGameState = (CombatGameState)AccessTools.Property(typeof(MechMeleeSequence), "Combat").GetValue(__instance, null);

                    if (
                        __instance.owningActor.TeamId == ___combatGameState.LocalPlayerTeamGuid ||
                        __instance.MeleeTarget.team.GUID == ___combatGameState.LocalPlayerTeamGuid ||
                        (___combatGameState.HostilityMatrix.IsLocalPlayerFriendly(__instance.owningActor.TeamId) || ___combatGameState.HostilityMatrix.IsLocalPlayerFriendly(__instance.MeleeTarget.team.GUID)) ||
                        ___combatGameState.LocalPlayerTeam.CanDetectPosition(__instance.MeleeTarget.CurrentPosition, __instance.owningActor)
                        )
                    {
                        CameraControl.Instance.SetMovingToGroundPos(__instance.MeleeTarget.CurrentPosition, 0.95f);
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 18
0
        static void Prefix(MechMeleeSequence __instance)
        {
            if (!MechMeleeSequence_ctor.isValid)
            {
                Mod.MeleeLog.Info?.Write($"  -- Invalid sequence in OnAdded, skipping!");

                Traverse meleeTargetT = Traverse.Create(__instance).Property("MeleeTarget");
                meleeTargetT.SetValue(null);

                // This apparently throws NREs in some cases... so skip
                //Traverse setStateT = Traverse.Create(__instance).Method("setState");
                //setStateT.GetValue(new object[] { FakeMeleeSequenceState.Finished });

                Traverse ordersAreCompleteT = Traverse.Create(__instance).Property("OrdersAreComplete");
                ordersAreCompleteT.SetValue(true);

                return;
            }

            Mod.MeleeLog.Info?.Write($"MeleeSequence added for " +
                                     $"attacker: {__instance.OwningMech.DistinctId()} from pos: {__instance.DesiredMeleePosition}" +
                                     $"against target: {__instance.MeleeTarget.DistinctId()} at pos: {__instance.MeleeTarget.CurrentPosition}");
        }
        static void Prefix(MechMeleeSequence __instance)
        {
            if (__instance == null || __instance.OwningMech == null || __instance.OwningMech.GetPilot() == null)
            {
                return; // Nothing to do
            }
            List <Ability> passives = __instance.OwningMech.GetPilot().PassiveAbilities;

            if (passives.Count > 0)
            {
                foreach (Ability ability in passives)
                {
                    if (ability.Def.Description.Id.Equals(Mod.Config.Abilities.JuggernautId, StringComparison.InvariantCultureIgnoreCase))
                    {
                        Mod.Log.Info?.Write("Pilot has Juggernaut, bracing after melee attack.");
                        __instance.OwningMech.BracedLastRound = true;
                        __instance.OwningMech.ApplyInstabilityReduction(StabilityChangeSource.Bracing);
                    }
                }
            }

            return;
        }
Esempio n. 20
0
            static void Postfix(MechMeleeSequence __instance, ref ActorMovementSequence ___moveSequence)
            {
                try
                {
                    Pilot pilot = __instance.owningActor.GetPilot();
                    if (pilot.IsJuggernaut() && Fields.JuggernautCharges)
                    {
                        Logger.Debug("[MechMeleeSequence_GenerateMeleePath_POSTFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges);

                        // Setting this prevents the footstep effects from Coils to be displayed when a Juggernauts charges
                        new Traverse(___moveSequence).Property("isSprinting").SetValue(true);
                        ___moveSequence.IgnoreEndSmoothing = true;
                        ___moveSequence.meleeType          = MeleeAttackType.Charge;

                        Logger.Info("[MechMeleeSequence_GenerateMeleePath_POSTFIX] moveSequence.isSprinting: " + ___moveSequence.isSprinting);
                        Logger.Info("[MechMeleeSequence_GenerateMeleePath_POSTFIX] moveSequence.IgnoreEndSmoothing: " + ___moveSequence.IgnoreEndSmoothing);
                        Logger.Info("[MechMeleeSequence_GenerateMeleePath_POSTFIX] moveSequence.meleeType: " + ___moveSequence.meleeType);
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 21
0
        static void Prefix(MechMeleeSequence __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: {__instance.selectedMeleeType} and weapon to: {__instance.OwningMech.MeleeWeapon.UIName}");

            (MeleeAttack meleeAttack, Weapon fakeWeapon)seqState = ModState.GetMeleeSequenceState(__instance.SequenceGUID);
            if (seqState.meleeAttack != null)
            {
                // Modify the owning mech melee weapon to do the 'first' hit - but apply stab damage later
                float targetDamage = seqState.meleeAttack.TargetDamageClusters?.Length > 0 ?
                                     seqState.meleeAttack.TargetDamageClusters[0] : 0;
                __instance.OwningMech.MeleeWeapon.StatCollection.Set <float>(ModStats.HBS_Weapon_DamagePerShot, targetDamage);
                __instance.OwningMech.MeleeWeapon.StatCollection.Set <float>(ModStats.HBS_Weapon_Instability, 0);
                Mod.MeleeLog.Info?.Write($"For {CombatantUtils.Label(__instance.OwningMech)} set melee weapon damage: {targetDamage} and instability: {seqState.meleeAttack.TargetInstability}");

                // Make sure we use the targets'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 melee 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);
                }
            }
        }
Esempio n. 22
0
            static void Prefix(MechMeleeSequence __instance)
            {
                try
                {
                    Pilot pilot = __instance.owningActor.GetPilot();
                    if (pilot.IsJuggernaut() && Fields.JuggernautCharges)
                    {
                        Logger.Debug("[MechMeleeSequence_ExecuteMove_PREFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges);

                        // This is to handle instability reduction correctly. If a juggernaut is charging it will be handled as a sprint.
                        // This should also sanitize (that is: disable) the damage multiplier for Coil-S
                        __instance.OwningMech.SprintedLastRound = true;
                        Logger.Debug("[MechMeleeSequence_ExecuteMove_PREFIX] OwningMech.SprintedLastRound: " + __instance.OwningMech.SprintedLastRound);

                        // Push message out
                        AbstractActor actor = __instance.owningActor;
                        actor.Combat.MessageCenter.PublishMessage(new FloatieMessage(actor.GUID, actor.GUID, "CHARGING", FloatieMessage.MessageNature.Buff));
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 23
0
 public static void Postfix(MechMeleeSequence __instance)
 {
     TurnDamageTracker.hintAttackComplete("MechMeleeSequence:CompleteOrders");
 }
 static void Prefix(MechMeleeSequence __instance)
 {
     Mod.MeleeLog.Info?.Write($"DFASequence added for attacker: {__instance.OwningMech.DistinctId()} from position: {__instance.DesiredMeleePosition}  " +
                              $"against target: {__instance.MeleeTarget}");
 }
Esempio n. 25
0
            static void Postfix(MechMeleeSequence __instance, MessageCenterMessage message)
            {
                try
                {
                    AttackCompleteMessage attackCompleteMessage = (AttackCompleteMessage)message;
                    if (attackCompleteMessage.attackSequence.attackCompletelyMissed)
                    {
                        Logger.Debug("[MechMeleeSequence_OnMeleeComplete_POSTFIX] Missed! Aborting...");
                        return;
                    }

                    Pilot pilot = __instance.owningActor.GetPilot();
                    if (pilot.IsJuggernaut())
                    {
                        // Get melee target
                        ICombatant MeleeTarget = (ICombatant)AccessTools.Property(typeof(MechMeleeSequence), "MeleeTarget").GetValue(__instance, null);

                        // Reapplying "MeleeHitPushBackPhases" here as it doesn't seem to work anymore when only defined in AbilityDef
                        (MeleeTarget as AbstractActor).ForceUnitOnePhaseDown(__instance.owningActor.GUID, __instance.SequenceGUID, false);

                        Logger.Debug("[MechMeleeSequence_OnMeleeComplete_POSTFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges);

                        if (Fields.JuggernautCharges)
                        {
                            // Charge and tackle causes slight instability

                            //float stabilityDamageSelf = __instance.OwningMech.GetMinStability(0, -1);
                            //__instance.OwningMech.AddAbsoluteInstability(stabilityDamageSelf, StabilityChangeSource.NotSet, __instance.owningActor.GUID);

                            float resultingStability = __instance.OwningMech.GetMinStability(__instance.OwningMech.CurrentStability, -1);
                            __instance.OwningMech.StatCollection.Set <float>("Stability", resultingStability);
                            __instance.OwningMech.NeedsInstabilityCheck = true;

                            if (MeleeTarget.IsDead || MeleeTarget.IsFlaggedForDeath)
                            {
                                return;
                            }

                            if (MeleeTarget is Mech TargetMech)
                            {
                                // Remove Entrenched from target when charging
                                if (TargetMech.IsEntrenched)
                                {
                                    Logger.Debug("[MechMeleeSequence_OnMeleeComplete_POSTFIX] Removing Entrenched from target");
                                    TargetMech.IsEntrenched = false;
                                    TargetMech.Combat.MessageCenter.PublishMessage(new FloatieMessage(TargetMech.GUID, TargetMech.GUID, "LOST: ENTRENCHED", FloatieMessage.MessageNature.Debuff));
                                }

                                /*
                                 * // IMPORTANT! At this point any stab dmg is already applied to the target, normalized by entrenched or terrain...
                                 * // Additional stability damage depending on distance?
                                 * float additionalStabilityDamage = Utilities.GetAdditionalStabilityDamageFromSprintDistance(__instance.OwningMech, TargetMech, false);
                                 *
                                 * // Using the attacker from the sequence is more reliable than __instance.OwningMech?
                                 * //Mech AttackingMech = attackCompleteMessage.attackSequence.attacker as Mech;
                                 * //float additionalStabilityDamage = Utilities.GetAdditionalStabilityDamageFromSprintDistance(AttackingMech, TargetMech, false);
                                 *
                                 * Logger.Debug("[MechMeleeSequence_OnMeleeComplete_POSTFIX] Apply additional stability damage from distance sprinted: " + additionalStabilityDamage);
                                 *
                                 * TargetMech.AddAbsoluteInstability(additionalStabilityDamage, StabilityChangeSource.NotSet, __instance.owningActor.GUID);
                                 * Logger.Debug("[MechMeleeSequence_OnMeleeComplete_POSTFIX] MeleeTarget.CurrentStability: " + TargetMech.CurrentStability);
                                 */
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
Esempio n. 26
0
 public static void Prefix(MechMeleeSequence __instance)
 {
     // Reset flag for weapon sequence
     DontShootTheDead.BuildSupportWeaponSequence = false;
 }
Esempio n. 27
0
        static void Prefix(MechMeleeSequence __instance, MessageCenterMessage message, AttackStackSequence ___meleeSequence)
        {
            Mod.MeleeLog.Trace?.Write("MMS:OMC entered.");

            AttackCompleteMessage attackCompleteMessage = message as AttackCompleteMessage;

            Mod.MeleeLog.Info?.Write($"== Resolving cluster damage, instability, and unsteady on melee attacker: {CombatantUtils.Label(__instance.OwningMech)} and target: {CombatantUtils.Label(__instance.MeleeTarget)}.");
            (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)
                {
                    // Target 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, seqState.meleeAttack.AttackAnimation);
                        }
                        catch (Exception e)
                        {
                            Mod.Log.Error?.Write(e, "FAILED TO APPLY MELEE DAMAGE TO ATTACKER!");
                        }
                    }
                }

                if (targetWasHit)
                {
                    // Target mech instability and unsteady
                    if (__instance.MeleeTarget 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.MeleeTarget is Vehicle || __instance.MeleeTarget.FakeVehicle() || __instance.MeleeTarget.NavalUnit())
                    {
                        AbstractActor targetActor = __instance.MeleeTarget 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
                    if (seqState.meleeAttack.TargetDamageClusters.Length > 1 && !__instance.MeleeTarget.IsDead)
                    {
                        try
                        {
                            // Make sure we use the targets'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.MeleeTarget, __instance.SequenceGUID, clusterDamage,
                                                               DamageType.Melee, seqState.meleeAttack.AttackAnimation);
                        }
                        catch (Exception e)
                        {
                            Mod.Log.Error?.Write(e, "FAILED TO APPLY MELEE DAMAGE TO TARGET!");
                        }
                    }
                }

                Mod.MeleeLog.Info?.Write($"== Done.");
            }

            // Reset damage table for mechs only; troops need to persist through to the end
            if (!(__instance.OwningMech is TrooperSquad))
            {
                Mod.MeleeLog.Info?.Write($" -- resetting damage table so mech weapons fire will randomize normally");
                ModState.ForceDamageTable = DamageTable.NONE;
            }
        }
Esempio n. 28
0
        public static void Postfix(MechMeleeSequence __instance, MessageCenterMessage message)
        {
            AttackCompleteMessage attackCompleteMessage = message as AttackCompleteMessage;

            if (__instance.selectedMeleeType == MeleeAttackType.Kick || __instance.selectedMeleeType == MeleeAttackType.Stomp)
            {
                if (attackCompleteMessage.attackSequence.attackCompletelyMissed)
                {
                    Mod.Log.Debug($" Kick attack by {CombatantUtils.Label(__instance.OwningMech)} vs. {CombatantUtils.Label(__instance.MeleeTarget)} failed.");
                    // Check for source falling
                    float sourceMulti  = __instance.OwningMech.PilotCheckMod(Mod.Config.Melee.SkillMulti);
                    bool  sourcePassed = CheckHelper.DidCheckPassThreshold(Mod.Config.Melee.MissedKickFallChance, __instance.OwningMech, sourceMulti, ModConfig.FT_Melee_Kick);
                    if (!sourcePassed)
                    {
                        Mod.Log.Info($"Source actor: {CombatantUtils.Label(__instance.OwningMech)} failed pilot check from missed kick, forcing fall.");
                        MechHelper.AddFallingSequence(__instance.OwningMech, __instance, ModConfig.FT_Melee_Kick);
                    }
                }
                else
                {
                    Mod.Log.Debug($" Kick attack by {CombatantUtils.Label(__instance.OwningMech)} vs. {CombatantUtils.Label(__instance.MeleeTarget)} succeeded.");
                    // Check for target falling
                    if (__instance.MeleeTarget is Mech targetMech)
                    {
                        float targetMulti  = targetMech.PilotCheckMod(Mod.Config.Melee.SkillMulti);
                        bool  targetPassed = CheckHelper.DidCheckPassThreshold(Mod.Config.Melee.HitByKickFallChance, targetMech, targetMulti, ModConfig.FT_Melee_Kick);
                        if (!targetPassed)
                        {
                            Mod.Log.Info($"Target actor: {CombatantUtils.Label(targetMech)} failed pilot check from kick, forcing fall.");
                            MechHelper.AddFallingSequence(targetMech, __instance, ModConfig.FT_Melee_Kick);
                        }
                    }
                    else
                    {
                        Mod.Log.Debug($"Target actor: {CombatantUtils.Label(__instance.MeleeTarget)} is not a mech, cannot fall - skipping.");
                    }
                }
            }

            if (__instance.selectedMeleeType == MeleeAttackType.Charge || __instance.selectedMeleeType == MeleeAttackType.Tackle)
            {
                if (!attackCompleteMessage.attackSequence.attackCompletelyMissed)
                {
                    Mod.Log.Debug($" Charge attack by {CombatantUtils.Label(__instance.OwningMech)} vs. {CombatantUtils.Label(__instance.MeleeTarget)} succeeded.");

                    // Check for source falling
                    float sourceSkillMulti = __instance.OwningMech.PilotCheckMod(Mod.Config.Melee.SkillMulti);
                    bool  sourcePassed     = CheckHelper.DidCheckPassThreshold(Mod.Config.Melee.MadeChargeFallChance, __instance.OwningMech, sourceSkillMulti, ModConfig.FT_Melee_Charge);
                    if (!sourcePassed)
                    {
                        Mod.Log.Info($"Source actor: {CombatantUtils.Label(__instance.OwningMech)} failed pilot check from charge, forcing fall.");
                        MechHelper.AddFallingSequence(__instance.OwningMech, __instance, ModConfig.FT_Melee_Charge);
                    }

                    // Check for target falling
                    if (__instance.MeleeTarget is Mech targetMech)
                    {
                        float targetSkillMulti = targetMech.PilotCheckMod(Mod.Config.Melee.SkillMulti);
                        bool  targetPassed     = CheckHelper.DidCheckPassThreshold(Mod.Config.Melee.HitByChargeFallChance, targetMech, targetSkillMulti, ModConfig.FT_Melee_Charge);
                        if (!targetPassed)
                        {
                            Mod.Log.Info($"Target actor: {CombatantUtils.Label(targetMech)} failed pilot check from charge, forcing fall.");
                            MechHelper.AddFallingSequence(targetMech, __instance, ModConfig.FT_Melee_Charge);
                        }
                    }
                    else
                    {
                        Mod.Log.Debug($"Target actor: {CombatantUtils.Label(__instance.MeleeTarget)} is not a mech, cannot fall - skipping.");
                    }
                }
                else
                {
                    Mod.Log.Debug($" Charge attack by {CombatantUtils.Label(__instance.OwningMech)} vs. {CombatantUtils.Label(__instance.MeleeTarget)} failed.");
                }
            }
        }
Esempio n. 29
0
 public static void Postfix(MechMeleeSequence __instance)
 {
     meleeHasSupportWeapons =
         Traverse.Create(__instance).Field("requestedWeapons").GetValue <List <Weapon> >().Count > 0;
 }
Esempio n. 30
0
 public static void Prefix(MechMeleeSequence __instance, ref float timeout)
 {
     // Was a hardcoded 5f
     timeout = 3f;
     Logger.Debug("[MechMeleeSequence_DelayFireWeapons_PREFIX] timeout: " + timeout);
 }