static void Prefix(CombatHUDAttackModeSelector __instance, CombatHUDFireButton.FireMode mode,
                           ref string additionalDetails, bool showHeatWarnings)
        {
            Mod.UILog.Trace?.Write($"ShowFireButton called with mode: {mode}");

            // Intentionally regen the meleeStates everytime the button changes, to make sure different positions calculate properly
            if (mode == CombatHUDFireButton.FireMode.Engage || mode == CombatHUDFireButton.FireMode.DFA)
            {
                if (SharedState.CombatHUD?.SelectionHandler?.ActiveState?.PreviewPos != ModState.MeleePreviewPos)
                {
                    ModState.MeleePreviewPos = SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos;

                    // Update melee states
                    ModState.AddorUpdateMeleeState(
                        SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor,
                        SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos,
                        SharedState.CombatHUD.SelectionHandler.ActiveState.TargetedCombatant);
                    Mod.UILog.Debug?.Write($"Updated melee state for position: {ModState.MeleePreviewPos}");

                    // Re-enable any buttons if they were disabled.
                    __instance.FireButton.SetState(ButtonState.Enabled);
                    __instance.DescriptionContainer.SetActive(true);
                }
            }
            else
            {
                ModState.InvalidateState(SharedState.CombatHUD?.SelectionHandler?.ActiveState?.SelectedActor);
            }
        }
        static void Postfix(AbstractActor __instance)
        {
            Mod.ActivationLog.Debug?.Write($"AA:ONR entered - for actor: {__instance.DisplayName} with TD.IsInterleaved: {__instance.Combat.TurnDirector.IsInterleaved}. " +
                                           $"Setting CanShootAfterSprinting: {__instance.Combat.TurnDirector.IsInterleaved}");
            //This is an easy place to put this where it will always be checked. This is the key to full non-interleaved combat.
            __instance.StatCollection.Set(ModStats.CanShootAfterSprinting, __instance.Combat.TurnDirector.IsInterleaved);

            // Invalidate their melee state
            ModState.InvalidateState(__instance);
        }
        public static float NoopDamageModifier(Weapon weapon, Vector3 attackPosition, ICombatant target,
                                               bool IsBreachingShot, int location, float dmg, float ap, float heat, float stab)
        {
            // Invalidate the melee state of the target, to force it to be recalculated
            if (target is AbstractActor targetActor)
            {
                Mod.Log.Debug?.Write($"Invalidating state for actor: {targetActor.DistinctId()}");
                ModState.InvalidateState(targetActor);
            }

            return(1.0f);
        }
        static void Postfix(MechDFASequence __instance)
        {
            Mod.Log.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);
            }

            // Invalidate our melee state as we're done
            ModState.ForceDamageTable = DamageTable.NONE;

            ModState.InvalidateState(__instance.OwningMech);
        }
Exemple #5
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);
        }
Exemple #6
0
 public static void Prefix(Turret __instance)
 {
     // Invalidate any held state on damage
     ModState.InvalidateState(__instance);
 }
        static void Prefix(Mech __instance)
        {
            Mod.HeatLog.Info?.Write($"AT END OF TURN: ACTOR: {__instance.DistinctId()} has currentHeat: {__instance.CurrentHeat}" +
                                    $" tempHeat: {__instance.TempHeat}  maxHeat: {__instance.MaxHeat}  heatsinkCapacity: {__instance.AdjustedHeatsinkCapacity}");

            // Invalidate any melee state the actor may have set
            ModState.InvalidateState(__instance);

            // Make the checks for ammo explosions, etc
            float heatCheck  = __instance.HeatCheckMod(Mod.Config.SkillChecks.ModPerPointOfGuts);
            float pilotCheck = __instance.PilotCheckMod(Mod.Config.SkillChecks.ModPerPointOfPiloting);

            Mod.HeatLog.Debug?.Write($" Actor: {__instance.DistinctId()} has heatCheckMod: {heatCheck}  pilotingCheckMod: {pilotCheck}");

            MultiSequence sequence                 = new MultiSequence(__instance.Combat);
            bool          failedInjuryCheck        = CheckHelper.ResolvePilotInjuryCheck(__instance, __instance.CurrentHeat, sequence.RootSequenceGUID, sequence.SequenceGUID, heatCheck);
            bool          failedSystemFailureCheck = CheckHelper.ResolveSystemFailureCheck(__instance, __instance.CurrentHeat, sequence.SequenceGUID, heatCheck);
            bool          failedAmmoCheck          = CheckHelper.ResolveRegularAmmoCheck(__instance, __instance.CurrentHeat, sequence.SequenceGUID, heatCheck);
            bool          failedVolatileAmmoCheck  = CheckHelper.ResolveVolatileAmmoCheck(__instance, __instance.CurrentHeat, sequence.SequenceGUID, heatCheck);

            Mod.HeatLog.Info?.Write($"  failedInjuryCheck: {failedInjuryCheck}  failedSystemFailureCheck: {failedSystemFailureCheck}  " +
                                    $"failedAmmoCheck: {failedAmmoCheck}  failedVolatileAmmoCheck: {failedVolatileAmmoCheck}");

            bool failedShutdownCheck = false;

            if (!__instance.IsShutDown)
            {
                // Resolve Shutdown + Fall
                failedShutdownCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Shutdown, __instance.CurrentHeat, __instance, heatCheck, ModText.FT_Check_Shutdown);
                Mod.HeatLog.Info?.Write($"  failedShutdownCheck: {failedShutdownCheck}");
                if (failedShutdownCheck)
                {
                    Mod.HeatLog.Info?.Write($"-- Shutdown check failed for unit {CombatantUtils.Label(__instance)}, forcing unit to shutdown");

                    string debuffText = new Text(Mod.LocalizedText.Floaties[ModText.FT_Shutdown_Failed_Overide]).ToString();
                    sequence.AddChildSequence(new ShowActorInfoSequence(__instance, debuffText,
                                                                        FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);

                    MechEmergencyShutdownSequence mechShutdownSequence = new MechEmergencyShutdownSequence(__instance);
                    //{
                    //    RootSequenceGUID = __instance.SequenceGUID
                    //};
                    sequence.AddChildSequence(mechShutdownSequence, sequence.ChildSequenceCount - 1);

                    if (__instance.IsOrWillBeProne)
                    {
                        bool failedFallingCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.ShutdownFallThreshold, __instance, pilotCheck, ModText.FT_Check_Fall);
                        Mod.HeatLog.Debug?.Write($"  failedFallingCheck: {failedFallingCheck}");
                        if (failedFallingCheck)
                        {
                            Mod.HeatLog.Info?.Write("   Pilot check from shutdown failed! Forcing a fall!");
                            string fallDebuffText = new Text(Mod.LocalizedText.Floaties[ModText.FT_Shutdown_Fall]).ToString();
                            sequence.AddChildSequence(new ShowActorInfoSequence(__instance, fallDebuffText,
                                                                                FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);

                            MechFallSequence mfs = new MechFallSequence(__instance, "Overheat", new Vector2(0f, -1f));
                            //{
                            //    RootSequenceGUID = __instance.SequenceGUID
                            //};
                            sequence.AddChildSequence(mfs, sequence.ChildSequenceCount - 1);
                        }
                        else
                        {
                            Mod.HeatLog.Info?.Write($"Pilot check to avoid falling passed. Applying unstead to unit.");
                            __instance.ApplyUnsteady();
                        }
                    }
                    else
                    {
                        Mod.HeatLog.Debug?.Write("Unit is already prone, skipping.");
                    }
                }
            }
            else
            {
                Mod.HeatLog.Debug?.Write("Unit is already shutdown, skipping.");
            }

            if (failedInjuryCheck || failedSystemFailureCheck || failedAmmoCheck || failedVolatileAmmoCheck || failedShutdownCheck)
            {
                __instance.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence));
            }
        }
        static void Postfix(CombatHUDAttackModeSelector __instance, CombatHUDFireButton.FireMode mode,
                            ref string additionalDetails, bool showHeatWarnings)
        {
            try
            {
                // Disable the melee container if there's no active state
                if (SharedState.CombatHUD?.SelectionHandler?.ActiveState == null ||
                    SharedState.CombatHUD?.SelectionHandler?.ActiveState?.SelectedActor == null ||
                    SharedState.CombatHUD?.SelectionHandler?.ActiveState?.PreviewPos == null)
                {
                    Mod.UILog.Trace?.Write($"Disabling all CHUD_Fire_Buttons");
                    ModState.MeleeAttackContainer.SetActive(false);
                    return;
                }

                Mod.UILog.Trace?.Write($"ShowFireButton called with mode: {mode}");

                if (mode == CombatHUDFireButton.FireMode.Engage)
                {
                    Mod.UILog.Trace?.Write($"Enabling all CHUD_Fire_Buttons");
                    ModState.MeleeAttackContainer.SetActive(true);

                    MeleeState meleeState = ModState.GetMeleeState(
                        SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor,
                        SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos);

                    // Toggle each button by available state
                    ToggleStateButtons(meleeState);

                    // Autoselect best option
                    MeleeAttack autoselectedAttack = meleeState.GetHighestDamageAttackForUI();
                    if (autoselectedAttack != null)
                    {
                        Mod.UILog.Info?.Write($"Autoselecting state of type: '{autoselectedAttack.Label}' as most damaging.");
                    }
                    else
                    {
                        Mod.UILog.Info?.Write("No highest damaging state - no melee options!");
                    }

                    // Final check - if everything is disabled, disable the button
                    bool hasValidAttack = meleeState.Charge.IsValid || meleeState.Kick.IsValid ||
                                          meleeState.PhysicalWeapon.IsValid || meleeState.Punch.IsValid;
                    if (!hasValidAttack)
                    {
                        Mod.UILog.Info?.Write("NO VALID MELEE ATTACKS, DISABLING!");
                        __instance.FireButton.SetState(ButtonState.Disabled);
                        __instance.FireButton.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                        __instance.DescriptionContainer.SetActive(false);
                        SharedState.CombatHUD.SelectionHandler.ActiveState.BackOut();
                        __instance.ForceRefreshImmediate();
                    }
                    else
                    {
                        Mod.UILog.Info?.Write($" CHECKING FOR VALID ATTACKS: hasValidAttack=>{hasValidAttack}" +
                                              $"  charge=>{meleeState.Charge.IsValid}" +
                                              $"  kick=>{meleeState.Kick.IsValid}" +
                                              $"  punch=>{meleeState.Punch.IsValid}" +
                                              $"  weapon=>{meleeState.PhysicalWeapon.IsValid}" +
                                              $"");
                    }
                }
                else
                {
                    Mod.UILog.Trace?.Write($"Disabling all CHUD_Fire_Buttons");
                    ModState.MeleeAttackContainer.SetActive(false);
                    if (ModState.ChargeFB != null)
                    {
                        ModState.ChargeFB.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                    }
                    if (ModState.KickFB != null)
                    {
                        ModState.KickFB.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                    }
                    if (ModState.PhysicalWeaponFB != null)
                    {
                        ModState.PhysicalWeaponFB.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                    }
                    if (ModState.PunchFB != null)
                    {
                        ModState.PunchFB.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                    }

                    ModState.InvalidateState(SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor);
                }

                // Handle the DFA button here
                if (mode == CombatHUDFireButton.FireMode.DFA)
                {
                    MeleeState meleeState = ModState.GetMeleeState(
                        SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor,
                        SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos);

                    // Check for valid attack
                    if (!meleeState.DFA.IsValid)
                    {
                        Mod.UILog.Info?.Write($"DFA attack failed validation, disabling button.");
                        __instance.FireButton.SetState(ButtonState.Disabled);
                        __instance.FireButton.CurrentFireMode = CombatHUDFireButton.FireMode.None;
                        __instance.DescriptionContainer.SetActive(false);
                        SharedState.CombatHUD.SelectionHandler.ActiveState.BackOut();
                        __instance.ForceRefreshImmediate();
                    }

                    HashSet <string> descriptonNotes = meleeState.DFA.DescriptionNotes;
                    additionalDetails = String.Join(", ", descriptonNotes);
                    Mod.UILog.Info?.Write($"Aggregate description is: {additionalDetails}");

                    // Select state here as a click will validate
                    ModState.AddOrUpdateSelectedAttack(
                        SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor,
                        meleeState.DFA
                        );
                }
            }
            catch (Exception e)
            {
                Mod.Log.Warn?.Write(e, "Failed to update the CombatButton states - warn Frost!");
            }
        }