Esempio n. 1
0
            public static bool Prefix(MultiSequence __instance)
            {
                try
                {
                    //Logger.Debug($"[MultiSequence_SetCamera_PREFIX] Suppressing camera focus...");

                    StackTrace stackTrace = new StackTrace();
                    for (var i = 0; i < stackTrace.FrameCount; i++)
                    {
                        MethodBase methodBase    = stackTrace.GetFrame(i).GetMethod();
                        Type       declaringType = methodBase.DeclaringType;
                        string     caller        = $"{declaringType}.{methodBase.Name}";

                        if (CameraUnchained.Settings.EventWhitelist.Contains(caller))
                        {
                            Logger.Debug($"[MultiSequence_SetCamera_PREFIX] WHITELISTED: {caller}");
                            return(true);
                        }

                        if (Fields.EventList.Contains(caller))
                        {
                            Logger.Info($"[MultiSequence_SetCamera_PREFIX] SUPPRESSING: {caller}");
                            return(false);
                        }
                    }

                    return(false);
                }
                catch (Exception e)
                {
                    Logger.Error(e);

                    return(true);
                }
            }
        // Create a falling sequence, publish a floatie with the error
        public static void AddFallingSequence(Mech mech, MultiSequence parentSequence, string floatieText)
        {
            MechFallSequence mechFallSequence = new MechFallSequence(mech, floatieText, new Vector2(0f, -1f));

            string        fallDebuffText   = new Text(Mod.Config.LocalizedFloaties[floatieText]).ToString();
            MultiSequence showInfoSequence = new ShowActorInfoSequence(mech, fallDebuffText, FloatieMessage.MessageNature.Debuff, false)
            {
                RootSequenceGUID = mechFallSequence.SequenceGUID
            };

            mechFallSequence.AddChildSequence(showInfoSequence, mechFallSequence.MessageIndex);

            mech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(mechFallSequence));
        }
Esempio n. 3
0
        // Create a falling sequence, publish a floatie with the error
        public static void AddFallingSequence(Mech mech, MultiSequence parentSequence, string floatieText)
        {
            Mod.Log.Info?.Write($"Adding falling sequence for mech: {mech.DistinctId()}");

            MechFallSequence mechFallSequence = new MechFallSequence(mech, floatieText, new Vector2(0f, -1f));

            string        fallDebuffText   = new Text(Mod.LocalizedText.Floaties[floatieText]).ToString();
            MultiSequence showInfoSequence = new ShowActorInfoSequence(mech, fallDebuffText, FloatieMessage.MessageNature.Debuff, false)
            {
                RootSequenceGUID = mechFallSequence.SequenceGUID
            };

            mechFallSequence.AddChildSequence(showInfoSequence, mechFallSequence.MessageIndex);
            mech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(mechFallSequence));
            Mod.Log.Info?.Write(" -- published fall sequence.");

            IStackSequence doneWithActorSequence = mech.DoneWithActor();

            mech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(doneWithActorSequence));
            Mod.Log.Info?.Write(" -- published doneWithActor sequence.");
        }
Esempio n. 4
0
            private static void Prefix(Mech __instance, string sourceID, int stackItemID)
            {
                if (__instance.IsOverheated)
                {
                    CBTPilotingRules rules          = new CBTPilotingRules(__instance.Combat);
                    float            gutsTestChance = rules.GetGutsModifier(__instance);
                    float            skillRoll      = __instance.Combat.NetworkRandom.Float();
                    float            ammoRoll       = __instance.Combat.NetworkRandom.Float();

                    int   turnsOverheated         = __instance.StatCollection.ContainsStatistic(ModStats.TurnsOverheated) ? __instance.StatCollection.GetValue <int>("TurnsOverheated") : 0;
                    float shutdownPercentage      = HeatHelper.GetShutdownPercentageForTurn(turnsOverheated);
                    float ammoExplosionPercentage = HeatHelper.GetAmmoExplosionPercentageForTurn(turnsOverheated);

                    Mod.Log.Debug($"Mech:{CombatantHelper.LogLabel(__instance)} is overheated for {turnsOverheated} turns. Checking shutdown override.");
                    Mod.Log.Debug($"  Guts -> skill: {__instance.SkillGuts}  divisor: {Mod.Config.GutsDivisor}  bonus: {gutsTestChance}");
                    Mod.Log.Debug($"  Skill roll: {skillRoll} plus guts roll: {skillRoll + gutsTestChance}  target: {shutdownPercentage}");
                    Mod.Log.Debug($"  Ammo roll: {ammoRoll} plus guts roll: {ammoRoll + gutsTestChance}  target: {ammoExplosionPercentage}");

                    if (Mod.Config.UseGuts)
                    {
                        ammoRoll  = ammoRoll + gutsTestChance;
                        skillRoll = skillRoll + gutsTestChance;
                    }

                    MultiSequence sequence = new MultiSequence(__instance.Combat);
                    sequence.SetCamera(CameraControl.Instance.ShowDeathCam(__instance, false, -1f), 0);

                    if (HeatHelper.CanAmmoExplode(__instance))
                    {
                        if (ammoRoll < ammoExplosionPercentage)
                        {
                            __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "Ammo Overheated!", FloatieMessage.MessageNature.CriticalHit));

                            var ammoBox = __instance.ammoBoxes.Where(box => box.CurrentAmmo > 0).OrderByDescending(box => box.CurrentAmmo / box.AmmoCapacity).FirstOrDefault();
                            if (ammoBox != null)
                            {
                                WeaponHitInfo fakeHit = new WeaponHitInfo(stackItemID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, new AttackDirection[] { AttackDirection.None }, null, null, null);
                                ammoBox.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                            }

                            return;
                        }

                        sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Ammo Explosion Avoided!", FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);
                    }

                    if (!__instance.IsPastMaxHeat)
                    {
                        if (skillRoll < shutdownPercentage)
                        {
                            Mod.Log.Debug(string.Format("Skill Check Failed! Initiating Shutdown"));

                            MechEmergencyShutdownSequence mechShutdownSequence = new MechEmergencyShutdownSequence(__instance);
                            sequence.AddChildSequence(mechShutdownSequence, sequence.ChildSequenceCount - 1);

                            __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                        }
                        else
                        {
                            Mod.Log.Debug(string.Format("Skill Check Succeeded!"));

                            sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Shutdown Override Successful!", FloatieMessage.MessageNature.Buff, true), sequence.ChildSequenceCount - 1);

                            turnsOverheated += 1;
                            __instance.StatCollection.Set <int>("TurnsOverheated", turnsOverheated);
                        }
                    }

                    sequence.AddChildSequence(new DelaySequence(__instance.Combat, 2f), sequence.ChildSequenceCount - 1);

                    __instance.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence));
                }
                else
                {
                    int turnsOverheated = __instance.StatCollection.GetValue <int>("TurnsOverheated");
                    if (turnsOverheated > 0)
                    {
                        __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                    }
                }
            }
            public static bool Prefix(MechHeatSequence __instance, HeatSequenceState newState)
            {
                if (newState != HeatSequenceState.Finished)
                {
                    return(true);
                }

                Traverse          stateT       = Traverse.Create(__instance).Field("state");
                HeatSequenceState currentState = (HeatSequenceState)stateT.GetValue <int>();

                if (currentState == newState)
                {
                    return(true);
                }

                Mod.Log.Info($"MHS - executing updated logic for state: {newState} on actor:{__instance.OwningMech.DisplayName}_{__instance.OwningMech.GetPilot().Name}.");
                stateT.SetValue((int)newState);

                Traverse timeInCurrentStateT = Traverse.Create(__instance).Field("timeInCurrentState");

                timeInCurrentStateT.SetValue(0f);

                /* Finished Can be invoked from a rising state (heat being added):
                 *  Attack Sequence, artillery sequence, actor burning effect, (heatSinkStep=false, applyStartupHeatSinks=false)
                 *  On End of turn sequence - (heatSinkStep=true, applyStartupHeatSinks=false)
                 *  On Mech Startup sequence - (heatSinkStep=true, applyStartupHeatSinks=true)
                 */

                if (!__instance.PerformHeatSinkStep)
                {
                    Mod.Log.Debug($"Reconciling heat for actor: {CombatantUtils.Label(__instance.OwningMech)}");
                    Mod.Log.Debug($"  Before - currentHeat: {__instance.OwningMech.CurrentHeat}  tempHeat: {__instance.OwningMech.TempHeat}  " +
                                  $"isPastMaxHeat: {__instance.OwningMech.IsPastMaxHeat}  hasAppliedHeatSinks: {__instance.OwningMech.HasAppliedHeatSinks}");
                    // Checks for heat damage, clamps heat to max and min
                    __instance.OwningMech.ReconcileHeat(__instance.RootSequenceGUID, __instance.InstigatorID);
                    Mod.Log.Debug($"  After - currentHeat: {__instance.OwningMech.CurrentHeat}  tempHeat: {__instance.OwningMech.TempHeat}  " +
                                  $"isPastMaxHeat: {__instance.OwningMech.IsPastMaxHeat}  hasAppliedHeatSinks: {__instance.OwningMech.HasAppliedHeatSinks}");
                }

                //if (__instance.OwningMech.IsPastMaxHeat && !__instance.OwningMech.IsShutDown) {
                //    __instance.OwningMech.GenerateOverheatedSequence(__instance);
                //    return;
                //}

                if (__instance.PerformHeatSinkStep && !__instance.ApplyStartupHeatSinks)
                {
                    // We are at the end of the turn - force an overheat
                    Mod.Log.Info("AT END OF TURN - CHECKING EFFECTS");

                    MultiSequence sequence = new MultiSequence(__instance.OwningMech.Combat);

                    // Possible sequences
                    //  Shutdown
                    //  Fall from shutdown
                    //  Ammo Explosion
                    //  System damage
                    //  Pilot injury
                    //  Pilot death

                    float heatCheck  = __instance.OwningMech.HeatCheckMod(Mod.Config.Piloting.SkillMulti);
                    float pilotCheck = __instance.OwningMech.PilotCheckMod(Mod.Config.Piloting.SkillMulti);
                    Mod.Log.Debug($" Actor: {CombatantUtils.Label(__instance.OwningMech)} has gutsMulti: {heatCheck}  pilotingMulti: {pilotCheck}");

                    // Resolve Pilot Injury
                    bool failedInjuryCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.PilotInjury, __instance.OwningMech.CurrentHeat, __instance.OwningMech, heatCheck, ModConfig.FT_Check_Injury);
                    Mod.Log.Debug($"  failedInjuryCheck: {failedInjuryCheck}");
                    if (failedInjuryCheck)
                    {
                        Mod.Log.Debug("-- Pilot Injury check failed, forcing injury from heat");
                        __instance.OwningMech.pilot.InjurePilot(__instance.SequenceGUID.ToString(), __instance.RootSequenceGUID, 1, DamageType.OverheatSelf, null, __instance.OwningMech);
                        if (!__instance.OwningMech.pilot.IsIncapacitated)
                        {
                            AudioEventManager.SetPilotVOSwitch <AudioSwitch_dialog_dark_light>(AudioSwitch_dialog_dark_light.dark, __instance.OwningMech);
                            AudioEventManager.PlayPilotVO(VOEvents.Pilot_TakeDamage, __instance.OwningMech, null, null, true);
                            if (__instance.OwningMech.team.LocalPlayerControlsTeam)
                            {
                                AudioEventManager.PlayAudioEvent("audioeventdef_musictriggers_combat", "friendly_warrior_injured", null, null);
                            }
                        }
                    }

                    // Resolve System Damage
                    bool failedSystemFailureCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.SystemFailures, __instance.OwningMech.CurrentHeat, __instance.OwningMech, heatCheck, ModConfig.FT_Check_System_Failure);
                    Mod.Log.Debug($"  failedSystemFailureCheck: {failedSystemFailureCheck}");
                    if (failedSystemFailureCheck)
                    {
                        Mod.Log.Debug("-- System Failure check failed, forcing system damage");
                        List <MechComponent> functionalComponents = __instance.OwningMech.allComponents.Where(mc => mc.IsFunctional).ToList();
                        MechComponent        componentToDamage    = functionalComponents.GetRandomElement();
                        Mod.Log.Debug($" Destroying component: {componentToDamage.UIName} from heat damage.");

                        WeaponHitInfo fakeHit = new WeaponHitInfo(__instance.RootSequenceGUID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null,
                                                                  new AttackDirection[] { AttackDirection.None }, null, null, null);
                        componentToDamage.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                    }

                    // Resolve Ammo Explosion - regular ammo
                    bool          failedAmmoCheck = false;
                    AmmunitionBox mostDamaging    = HeatHelper.FindMostDamagingAmmoBox(__instance.OwningMech, false);
                    if (mostDamaging != null)
                    {
                        failedAmmoCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Explosion, __instance.OwningMech.CurrentHeat, __instance.OwningMech, heatCheck, ModConfig.FT_Check_Explosion);
                        Mod.Log.Debug($"  failedAmmoCheck: {failedAmmoCheck}");
                        if (failedAmmoCheck)
                        {
                            Mod.Log.Debug("-- Ammo Explosion check failed, forcing ammo explosion");

                            if (mostDamaging != null)
                            {
                                Mod.Log.Debug($" Exploding ammo: {mostDamaging.UIName}");
                                WeaponHitInfo fakeHit = new WeaponHitInfo(__instance.RootSequenceGUID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null,
                                                                          new AttackDirection[] { AttackDirection.None }, null, null, null);
                                mostDamaging.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                            }
                            else
                            {
                                Mod.Log.Debug(" Unit has no ammo boxes, skipping.");
                            }
                        }
                    }

                    // Resolve Ammo Explosion - inferno ammo
                    bool          failedVolatileAmmoCheck = false;
                    AmmunitionBox mostDamagingVolatile    = HeatHelper.FindMostDamagingAmmoBox(__instance.OwningMech, true);
                    if (mostDamagingVolatile != null)
                    {
                        failedVolatileAmmoCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Explosion, __instance.OwningMech.CurrentHeat, __instance.OwningMech, heatCheck, ModConfig.FT_Check_Explosion);
                        Mod.Log.Debug($"  failedVolatileAmmoCheck: {failedVolatileAmmoCheck}");
                        if (failedVolatileAmmoCheck)
                        {
                            Mod.Log.Debug("-- Volatile Ammo Explosion check failed, forcing volatile ammo explosion");

                            if (mostDamaging != null)
                            {
                                Mod.Log.Debug($" Exploding inferno ammo: {mostDamagingVolatile.UIName}");
                                WeaponHitInfo fakeHit = new WeaponHitInfo(__instance.RootSequenceGUID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null,
                                                                          new AttackDirection[] { AttackDirection.None }, null, null, null);
                                mostDamagingVolatile.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                            }
                            else
                            {
                                Mod.Log.Debug(" Unit has no inferno ammo boxes, skipping.");
                            }
                        }
                    }

                    bool failedShutdownCheck = false;
                    if (!__instance.OwningMech.IsShutDown)
                    {
                        // Resolve Shutdown + Fall
                        failedShutdownCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Shutdown, __instance.OwningMech.CurrentHeat, __instance.OwningMech, heatCheck, ModConfig.FT_Check_Shutdown);
                        Mod.Log.Debug($"  failedShutdownCheck: {failedShutdownCheck}");
                        if (failedShutdownCheck)
                        {
                            Mod.Log.Debug("-- Shutdown check failed, forcing unit to shutdown");

                            string debuffText = new Text(Mod.Config.LocalizedFloaties[ModConfig.FT_Shutdown_Failed_Overide]).ToString();
                            sequence.AddChildSequence(new ShowActorInfoSequence(__instance.OwningMech, debuffText,
                                                                                FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);

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

                            if (__instance.OwningMech.IsOrWillBeProne)
                            {
                                bool failedFallingCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.ShutdownFallThreshold, __instance.OwningMech, pilotCheck, ModConfig.FT_Check_Fall);
                                Mod.Log.Debug($"  failedFallingCheck: {failedFallingCheck}");
                                if (failedFallingCheck)
                                {
                                    Mod.Log.Info("Pilot check from shutdown failed! Forcing a fall!");

                                    string fallDebuffText = new Text(Mod.Config.LocalizedFloaties[ModConfig.FT_Shutdown_Fall]).ToString();
                                    sequence.AddChildSequence(new ShowActorInfoSequence(__instance.OwningMech, fallDebuffText,
                                                                                        FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);

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

                    if (failedInjuryCheck || failedSystemFailureCheck || failedAmmoCheck || failedShutdownCheck)
                    {
                        __instance.OwningMech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence));
                    }

                    return(false);
                }

                if (__instance.OwningMech.GameRep != null)
                {
                    if (__instance.OwningMech.team.LocalPlayerControlsTeam)
                    {
                        if (__instance.OwningMech.CurrentHeat > __instance.OwningMech.OverheatLevel)
                        {
                            string text = string.Format("MechHeatSequence_{0}_{1}", __instance.RootSequenceGUID, __instance.SequenceGUID);
                            AudioEventManager.CreateVOQueue(text, -1f, null, null);
                            AudioEventManager.QueueVOEvent(text, VOEvents.Mech_Overheat_Warning, __instance.OwningMech);
                            AudioEventManager.StartVOQueue(1f);
                        }

                        if ((float)__instance.OwningMech.CurrentHeat > (float)__instance.OwningMech.MaxHeat - (float)(__instance.OwningMech.MaxHeat - __instance.OwningMech.OverheatLevel) * 0.333f)
                        {
                            WwiseManager.PostEvent <AudioEventList_ui>(AudioEventList_ui.ui_overheat_alarm_3, WwiseManager.GlobalAudioObject, null, null);
                        }
                        else if ((float)__instance.OwningMech.CurrentHeat > (float)__instance.OwningMech.MaxHeat - (float)(__instance.OwningMech.MaxHeat - __instance.OwningMech.OverheatLevel) * 0.666f)
                        {
                            WwiseManager.PostEvent <AudioEventList_ui>(AudioEventList_ui.ui_overheat_alarm_2, WwiseManager.GlobalAudioObject, null, null);
                        }
                        else if (__instance.OwningMech.CurrentHeat > __instance.OwningMech.OverheatLevel)
                        {
                            WwiseManager.PostEvent <AudioEventList_ui>(AudioEventList_ui.ui_overheat_alarm_1, WwiseManager.GlobalAudioObject, null, null);
                        }
                    }

                    if (__instance.OwningMech.CurrentHeat > Mod.Config.Heat.ShowLowOverheatAnim)
                    {
                        __instance.OwningMech.GameRep.StopManualPersistentVFX(__instance.OwningMech.Combat.Constants.VFXNames.heat_midHeat_persistent);
                        __instance.OwningMech.GameRep.PlayVFX(8, __instance.OwningMech.Combat.Constants.VFXNames.heat_highHeat_persistent, true, Vector3.zero, false, -1f);
                        return(false);
                    }

                    if ((float)__instance.OwningMech.CurrentHeat > Mod.Config.Heat.ShowExtremeOverheatAnim)
                    {
                        __instance.OwningMech.GameRep.StopManualPersistentVFX(__instance.OwningMech.Combat.Constants.VFXNames.heat_highHeat_persistent);
                        __instance.OwningMech.GameRep.PlayVFX(8, __instance.OwningMech.Combat.Constants.VFXNames.heat_midHeat_persistent, true, Vector3.zero, false, -1f);
                        return(false);
                    }

                    __instance.OwningMech.GameRep.StopManualPersistentVFX(__instance.OwningMech.Combat.Constants.VFXNames.heat_highHeat_persistent);
                    __instance.OwningMech.GameRep.StopManualPersistentVFX(__instance.OwningMech.Combat.Constants.VFXNames.heat_midHeat_persistent);
                }

                return(false);
            }
Esempio n. 6
0
        private static void Prefix(Mech __instance, string sourceID, int stackItemID)
        {
            ILog heatLogger = HBS.Logging.Logger.GetLogger("CombatLog.Heat", LogLevel.Warning);

            if (heatLogger.IsLogEnabled)
            {
                heatLogger.Log(string.Format("[CBTHeat] Is Overheated: {0}", __instance.IsOverheated));
            }

            if (__instance.IsOverheated)
            {
                CBTPilotingRules rules          = new CBTPilotingRules(__instance.Combat);
                float            gutsTestChance = rules.GetGutsModifier(__instance);
                float            skillRoll      = __instance.Combat.NetworkRandom.Float();
                float            ammoRoll       = __instance.Combat.NetworkRandom.Float();

                int   turnsOverheated         = __instance.StatCollection.GetValue <int>("TurnsOverheated");
                float shutdownPercentage      = CBTHeat.GetShutdownPercentageForTurn(turnsOverheated);
                float ammoExplosionPercentage = CBTHeat.GetAmmoExplosionPercentageForTurn(turnsOverheated);

                if (heatLogger.IsLogEnabled)
                {
                    heatLogger.Log(string.Format("[CBTHeat] Turns Overheated: {0}", turnsOverheated));
                    heatLogger.Log(string.Format("[CBTHeat] Intiating Shutdown Override Check"));
                    heatLogger.Log(string.Format("[CBTHeat] Guts Skill: {0}", (float)__instance.SkillGuts));
                    heatLogger.Log(string.Format("[CBTHeat] Guts Divisor: {0}", CBTHeat.Settings.GutsDivisor));
                    heatLogger.Log(string.Format("[CBTHeat] Guts Bonus: {0}", gutsTestChance));
                    heatLogger.Log(string.Format("[CBTHeat] Skill Roll: {0}", skillRoll));
                    heatLogger.Log(string.Format("[CBTHeat] Skill + Guts Roll: {0}", skillRoll + gutsTestChance));
                    heatLogger.Log(string.Format("[CBTHeat] Ammo Roll: {0}", ammoRoll));
                    heatLogger.Log(string.Format("[CBTHeat] Ammo + Guts Roll: {0}", ammoRoll + gutsTestChance));
                    heatLogger.Log(string.Format("[CBTHeat] Skill Target: {0}", shutdownPercentage));
                    heatLogger.Log(string.Format("[CBTHeat] Ammo Roll Target: {0}", ammoExplosionPercentage));
                }

                if (CBTHeat.Settings.UseGuts)
                {
                    ammoRoll  = ammoRoll + gutsTestChance;
                    skillRoll = skillRoll + gutsTestChance;
                }

                MultiSequence sequence = new MultiSequence(__instance.Combat);
                sequence.SetCamera(CameraControl.Instance.ShowDeathCam(__instance, false, -1f), 0);

                if (CBTHeat.CanAmmoExplode(__instance))
                {
                    if (ammoRoll < ammoExplosionPercentage)
                    {
                        __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "Ammo Overheated!", FloatieMessage.MessageNature.CriticalHit));

                        var ammoBox = __instance.ammoBoxes.Where(box => box.CurrentAmmo > 0).OrderByDescending(box => box.CurrentAmmo / box.AmmoCapacity).FirstOrDefault();
                        if (ammoBox != null)
                        {
                            var fakeHit = new WeaponHitInfo(stackItemID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, AttackDirection.None, Vector2.zero, null);
                            ammoBox.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                        }

                        return;
                    }

                    sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Ammo Explosion Avoided!", FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);
                }

                if (!__instance.IsPastMaxHeat)
                {
                    if (skillRoll < shutdownPercentage)
                    {
                        if (heatLogger.IsLogEnabled)
                        {
                            heatLogger.Log(string.Format("[CBTHeat] Skill Check Failed! Initiating Shutdown"));
                        }

                        MechEmergencyShutdownSequence mechShutdownSequence = new MechEmergencyShutdownSequence(__instance);
                        sequence.AddChildSequence(mechShutdownSequence, sequence.ChildSequenceCount - 1);

                        __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                    }
                    else
                    {
                        if (heatLogger.IsLogEnabled)
                        {
                            heatLogger.Log(string.Format("[CBTHeat] Skill Check Succeeded!"));
                        }

                        sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Shutdown Override Successful!", FloatieMessage.MessageNature.Buff, true), sequence.ChildSequenceCount - 1);

                        turnsOverheated += 1;
                        __instance.StatCollection.Set <int>("TurnsOverheated", turnsOverheated);
                    }
                }

                sequence.AddChildSequence(new DelaySequence(__instance.Combat, 2f), sequence.ChildSequenceCount - 1);

                __instance.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence));
            }
            else
            {
                int turnsOverheated = __instance.StatCollection.GetValue <int>("TurnsOverheated");

                if (turnsOverheated > 0)
                {
                    __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                }
            }
        }
 public static bool Prefix(MultiSequence __instance, MethodBase __originalMethod, CameraSequence sequence, int messageIndex)
 {
     return(!SequenceHelper.SkipSequenceByTrace(new StackTrace()));
 }
        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));
            }
        }