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); }
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); }
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!"); } }