private static void Prefix(ActorMovementSequence __instance) { Mod.ActivationLog.Info?.Write($"AMS:OC:PRE entered for actor: {CombatantUtils.Label(__instance?.OwningActor)}"); // Interleaved - check for visibility to any enemies if (!__instance.owningActor.Combat.TurnDirector.IsInterleaved) { __instance.owningActor.AutoBrace = true; } // Movement - check for damage after a sprint, and if so force a piloting check if (__instance.OwningMech != null && __instance.isSprinting && __instance.OwningMech.ActuatorDamageMalus() != 0) { Mod.Log.Info?.Write($"Actor: {CombatantUtils.Label(__instance.OwningMech)} has actuator damage, forcing piloting check."); float sourceSkillMulti = __instance.OwningMech.PilotCheckMod(Mod.Config.SkillChecks.ModPerPointOfPiloting); float damagePenalty = __instance.OwningMech.ActuatorDamageMalus() * Mod.Config.SkillChecks.ModPerPointOfPiloting; float checkMod = sourceSkillMulti + damagePenalty; Mod.Log.Debug?.Write($" moveSkillMulti:{sourceSkillMulti} - damagePenalty: {damagePenalty} = checkMod: {checkMod}"); bool sourcePassed = CheckHelper.DidCheckPassThreshold(Mod.Config.Move.FallAfterRunChance, __instance.OwningMech, checkMod, ModText.FT_Fall_After_Run); if (!sourcePassed) { Mod.Log.Info?.Write($"Source actor: {CombatantUtils.Label(__instance.OwningMech)} failed pilot check after sprinting with actuator damage, forcing fall."); MechHelper.AddFallingSequence(__instance.OwningMech, __instance, ModText.FT_Fall_After_Run); } } }
// Token: 0x0600866D RID: 34413 RVA: 0x0022E4D0 File Offset: 0x0022C6D0 public override bool Invoke(CombatGameState combatGameState) { InvocationMessage.logger.Log("Invoking a MOVE!"); AbstractActor abstractActor = combatGameState.FindActorByGUID(this.ActorGUID); if (abstractActor == null) { InvocationMessage.logger.LogError(string.Format("MechMovement.Invoke Actor with GUID {0} not found!", this.ActorGUID)); return(false); } ICombatant combatant = null; if (!string.IsNullOrEmpty(this.MeleeTargetGUID)) { combatant = combatGameState.FindCombatantByGUID(this.MeleeTargetGUID, false); if (combatant == null) { InvocationMessage.logger.LogError(string.Format("MechMovement.Invoke ICombatant with GUID {0} not found!", this.MeleeTargetGUID)); return(false); } } if (!combatGameState.TurnDirector.IsInterleaved && this.MoveType != MoveType.Sprinting) { abstractActor.AutoBrace = true; } ActorMovementSequence stackSequence = new ActorMovementSequence(abstractActor, this.Waypoints, this.FinalOrientation, this.MoveType, combatant, this.AbilityConsumesFiring); base.PublishStackSequence(combatGameState.MessageCenter, stackSequence, this); return(true); }
public static void Postfix(ActorMovementSequence __instance) { var traverse = Traverse.Create(__instance); var combat = traverse.Property("Combat").GetValue <CombatGameState>(); AuraCache.RefreshECMStates(combat.AllActors, EffectTriggerType.Passive); }
// Token: 0x060000F6 RID: 246 RVA: 0x00014860 File Offset: 0x00012A60 private static void Postfix(ActorMovementSequence __instance, ref bool __result) { if (!__instance.OwningActor.Combat.TurnDirector.IsInterleaved) { __result = false; } }
// Token: 0x060000F4 RID: 244 RVA: 0x00014618 File Offset: 0x00012818 private static void Prefix(ActorMovementSequence __instance) { if (!__instance.owningActor.Combat.TurnDirector.IsInterleaved) { __instance.owningActor.AutoBrace = true; } }
private static void Prefix(ActorMovementSequence __instance) { Mod.Log.Trace("AMS:OC entered"); // Interleaved - check for visibility to any enemies if (!__instance.owningActor.Combat.TurnDirector.IsInterleaved) { if (__instance.owningActor.Combat.LocalPlayerTeam.GetDetectedEnemyUnits().Count > 0) { Mod.Log.Info("AMS:OC TD is not interleaved but enemies are detected - disabling autobrace. "); __instance.owningActor.AutoBrace = false; } else { Mod.Log.Info("AMS:OC TD is not interleaved and no enemies - autobracing "); __instance.owningActor.AutoBrace = true; } } // Movement - check for damage after a sprint, and if so force a piloting check if (__instance.OwningMech != null && __instance.isSprinting && __instance.OwningMech.ActuatorDamageMalus() != 0) { Mod.Log.Debug($"Actor: {CombatantUtils.Label(__instance.OwningMech)} has actuator damage, forcing piloting check."); float sourceSkillMulti = __instance.OwningMech.PilotCheckMod(Mod.Config.Move.SkillMulti); bool sourcePassed = CheckHelper.DidCheckPassThreshold(Mod.Config.Move.FallAfterRunChance, __instance.OwningMech, sourceSkillMulti, ModConfig.FT_Fall_After_Run); if (!sourcePassed) { Mod.Log.Info($"Source actor: {CombatantUtils.Label(__instance.OwningMech)} failed pilot check after sprinting with actuator damage, forcing fall."); MechHelper.AddFallingSequence(__instance.OwningMech, __instance, ModConfig.FT_Fall_After_Run); } } }
private static void Postfix(ActorMovementSequence __instance, ref bool __result) { Mod.Log.Trace?.Write("AMS:CF:GET entered"); if (!__instance.OwningActor.Combat.TurnDirector.IsInterleaved) { // We want to auto-brace, and auto-brace requires that consumesFiring = false. So when no enemies are around, don't consume firing so // that we can auto-brace __result = false; } }
public static void Postfix(ActorMovementSequence __instance) { /*if (__instance.owningActor == null) { return; } * switch (Core.Settings.auraUpdateFix) { * case AuraUpdateFix.Never: * case AuraUpdateFix.Position: * case AuraUpdateFix.Time: * __instance.owningActor.RemoveAuraUpdateData(); * AuraCache.UpdateAurasToActor(__instance.owningActor.Combat.AllActors, __instance.owningActor, __instance.owningActor.CurrentPosition, EffectTriggerType.Passive, false); * break; * }*/ }
// Token: 0x0600866A RID: 34410 RVA: 0x0022E3D8 File Offset: 0x0022C5D8 public AbstractActorMovementInvocation(AbstractActor actor, bool abilityConsumesFiring) : base(UnityEngine.Random.Range(0, 99999)) { Pathing pathing = actor.Pathing; this.ActorGUID = actor.GUID; this.AbilityConsumesFiring = abilityConsumesFiring; List <WayPoint> collection = ActorMovementSequence.ExtractWaypointsFromPath(actor, pathing.CurrentPath, pathing.ResultDestination, pathing.CurrentMeleeTarget, this.MoveType); this.Waypoints = new List <WayPoint>(collection); this.MoveType = pathing.MoveType; this.FinalOrientation = pathing.ResultAngleAsVector; if (pathing.CurrentMeleeTarget == null) { this.MeleeTargetGUID = string.Empty; return; } this.MeleeTargetGUID = pathing.CurrentMeleeTarget.GUID; }
/* CAC introduces burning effects, which applies heat for each hex you move through, and if you end your turn in a burning hex. * Calculate this heat so we can show it to the player * TODO: Handle unaffected by fire */ public static int CACTerrainHeat(this Mech mech) { float terrainHeat = 0f; // If the unit has been marked as not being affected by fire, skip it entirely if (mech.UnaffectedFire()) { return(0); } if (mech.Pathing.CurrentPath != null && mech.Pathing.CurrentPath.Count > 0) { List <WayPoint> waypointsFromPath = ActorMovementSequence.ExtractWaypointsFromPath( mech, mech.Pathing.CurrentPath, mech.Pathing.ResultDestination, (ICombatant)mech.Pathing.CurrentMeleeTarget, mech.Pathing.MoveType ); List <MapTerrainCellWaypoint> terrainWaypoints = DynamicMapHelper.getVisitedWaypoints(mech.Combat, waypointsFromPath); Mod.HeatLog.Trace?.Write($" Count of waypointsFromPath: {waypointsFromPath.Count} terrainWaypoints: {terrainWaypoints.Count}"); float sumOfCellHeat = 0f; int totalCells = 0; foreach (MapTerrainCellWaypoint cell in terrainWaypoints) { if (cell != null && cell.cell.BurningStrength > 0) { Mod.HeatLog.Trace?.Write($" --Adding {cell.cell.BurningStrength} heat from cell at worldPos: {cell.cell.WorldPos()}"); sumOfCellHeat += cell.cell.BurningStrength; totalCells += 1; } } terrainHeat = totalCells != 0 ? (float)Math.Ceiling(sumOfCellHeat / totalCells) : 0; Mod.HeatLog.Trace?.Write($"TerrainHeat: {terrainHeat} = sumOfHeat: {sumOfCellHeat} / totalCells: {totalCells}"); } else { MapTerrainDataCellEx cell = mech.Combat.MapMetaData.GetCellAt(mech.CurrentPosition) as MapTerrainDataCellEx; if (cell != null && cell.BurningStrength > 0) { Mod.HeatLog.Trace?.Write($"Adding {cell.BurningStrength} heat from current position: {mech.CurrentPosition}"); terrainHeat = cell.BurningStrength; } } return((int)Math.Ceiling(terrainHeat)); }
public static void Postfix(ActorMovementSequence __instance) { try { //if (__instance.owningActor.team.IsLocalPlayer) if (__instance.owningActor.team.LocalPlayerControlsTeam) { return; } Logger.Debug($"[ActorMovementSequence_OnAdded_POSTFIX] Focus on enemy moving..."); CombatGameState ___combatGameState = (CombatGameState)AccessTools.Property(typeof(ActorMovementSequence), "Combat").GetValue(__instance, null); if (___combatGameState.LocalPlayerTeam.CanDetectPosition(__instance.OwningActor.CurrentPosition, __instance.OwningActor)) { //CameraSequence cameraSequence = CameraControl.Instance.ShowMovementCam(__instance.OwningActor.CurrentPosition, __instance.FinalPos, __instance); //MultiSequence multiSequence = __instance; //multiSequence.SetCamera(cameraSequence, __instance.MessageIndex); //Quaternion rotation = CameraControl.Instance.CameraRot; //Traverse FrameTwoPoints = Traverse.Create(CameraControl.Instance).Method("FrameTwoPoints", rotation * Vector3.forward, __instance.OwningActor.CurrentPosition, __instance.FinalPos, 0.9f, ___combatGameState.Constants.CameraConstants.MaxHeightAboveTerrain * 0.9f); //Vector3 poi = (Vector3)FrameTwoPoints.GetValue(); //Vector3 poi = Vector3.Lerp(__instance.OwningActor.CurrentPosition, __instance.FinalPos, 0.5f); //CameraControl.Instance.SetMovingToGroundPos(poi, 0.95f); // KISS CameraControl.Instance.SetMovingToGroundPos(__instance.OwningActor.CurrentPosition, 0.95f); } else if (___combatGameState.LocalPlayerTeam.CanDetectPosition(__instance.FinalPos, __instance.OwningActor)) { CameraControl.Instance.SetMovingToGroundPos(__instance.FinalPos, 0.95f); } else { // Nothing? } } catch (Exception e) { Logger.Error(e); } }
static void Postfix(SelectionStateMove __instance, ref float __result) { Mod.Log.Trace?.Write("SSM:PSFS - entered."); MeleeAttack selectedAttack = ModState.GetSelectedAttack(__instance.SelectedActor); if (__instance.SelectedActor is Mech selectedMech && selectedAttack != null && __instance.PotentialMeleeTarget != null) { float newStability = selectedMech.CurrentStability + selectedAttack.AttackerInstability; List <WayPoint> waypoints = ActorMovementSequence.ExtractWaypointsFromPath(selectedMech, selectedMech.Pathing.CurrentPath, selectedMech.Pathing.ResultDestination, selectedMech.Pathing.CurrentMeleeTarget, selectedMech.Pathing.MoveType); StabilityChangeSource changeSource = StabilityChangeSource.Moving; if (WayPoint.GetDistFromWaypointList(selectedMech.CurrentPosition, waypoints) < 1f) { changeSource = StabilityChangeSource.RemainingStationary; } float minStability = selectedMech.GetMinStability(changeSource, newStability); Mod.Log.Debug?.Write($"Stability change for {CombatantUtils.Label(selectedMech)} => " + $"current: {selectedMech.CurrentStability} projectedNew: {selectedAttack.AttackerInstability} " + $"totalChange: {newStability} afterDump: {minStability}"); __result = minStability; } }
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); } }
public static void Postfix(ActorMovementSequence __instance) { TurnDamageTracker.hintAttackComplete("ActorMovementSequence:CompleteOrders"); }
static void Postfix(ActorMovementSequence __instance) { Mod.ActivationLog.Info?.Write($"AMS:OC:POST - actor: {CombatantUtils.Label(__instance.OwningActor)} " + $"autoBrace: {__instance.OwningActor.AutoBrace} hasFired: {__instance.OwningActor.HasFiredThisRound} consumesFiring: {__instance.ConsumesFiring}"); }
// Replicates logic from Mech::AdjustedHeatSinkCapacity to allow displaying multiplier public static float DesignMaskHeatMulti(this Mech mech, bool isProjectedHeat) { float capacityMulti = 1f; try { // Check for currently occupied, or future if (isProjectedHeat) { Mod.HeatLog.Trace?.Write("Calculating projected position heat."); if (mech.Pathing != null && mech.Pathing.CurrentPath != null && mech.Pathing.CurrentPath.Count > 0) { // Determine the destination designMask Mod.HeatLog.Trace?.Write($"CurrentPath has: {mech.Pathing.CurrentPath.Count} nodes, using destination path: {mech.Pathing.ResultDestination}"); DesignMaskDef destinationDesignMaskDef = mech?.Combat?.MapMetaData?.GetPriorityDesignMaskAtPos(mech.Pathing.ResultDestination); if (destinationDesignMaskDef != null && !Mathf.Approximately(destinationDesignMaskDef.heatSinkMultiplier, 1f)) { Mod.HeatLog.Trace?.Write($"Destination design mask: {destinationDesignMaskDef?.Description?.Name} has heatSinkMulti: x{destinationDesignMaskDef?.heatSinkMultiplier} "); capacityMulti *= destinationDesignMaskDef.heatSinkMultiplier; } // Check for any cells along the way that will apply the burning sticky effect. // See CustomAmmoCategories\designmask\DesignMaskBurningForest List <WayPoint> waypointsFromPath = ActorMovementSequence.ExtractWaypointsFromPath( mech, mech.Pathing.CurrentPath, mech.Pathing.ResultDestination, (ICombatant)mech.Pathing.CurrentMeleeTarget, mech.Pathing.MoveType ); List <MapTerrainCellWaypoint> terrainWaypoints = DynamicMapHelper.getVisitedWaypoints(mech.Combat, waypointsFromPath); Mod.HeatLog.Trace?.Write($" Count of waypointsFromPath: {waypointsFromPath?.Count} terrainWaypoints: {terrainWaypoints?.Count}"); // This assumes 1) only KMission is using stickyEffects that modify HeatSinkCapacity and 2) it has a stackLimit of 1. Anything else will break this. float stickyModifier = 1f; foreach (MapTerrainCellWaypoint cell in terrainWaypoints) { if (cell != null && cell?.cell?.BurningStrength > 0 && cell?.cell?.mapMetaData?.designMaskDefs != null) { Mod.HeatLog.Trace?.Write($" checking burningCell for designMask."); foreach (DesignMaskDef cellDesignMaskDef in cell?.cell?.mapMetaData?.designMaskDefs?.Values) { Mod.HeatLog.Trace?.Write($" checking designMask for stickyEffects."); if (cellDesignMaskDef.stickyEffect != null && cellDesignMaskDef.stickyEffect?.statisticData != null && cellDesignMaskDef.stickyEffect.statisticData.statName == ModStats.HBS_HeatSinkCapacity) { Mod.HeatLog.Trace?.Write($" found stickyEffects."); stickyModifier = Single.Parse(cellDesignMaskDef.stickyEffect.statisticData.modValue); } } } } if (!Mathf.Approximately(stickyModifier, 1f)) { capacityMulti *= stickyModifier; Mod.HeatLog.Trace?.Write($" capacityMulti: {capacityMulti} after stickyModifier: {stickyModifier}"); } } else { Mod.HeatLog.Trace?.Write($"Current path is null or has 0 count, skipping."); } } else { Mod.HeatLog.Trace?.Write("Calculating current position heat."); if (mech.occupiedDesignMask != null && !Mathf.Approximately(mech.occupiedDesignMask.heatSinkMultiplier, 1f)) { Mod.HeatLog.Trace?.Write($"Multi for currentPos is: {mech?.occupiedDesignMask?.heatSinkMultiplier}"); capacityMulti *= mech.occupiedDesignMask.heatSinkMultiplier; } } if (mech?.Combat?.MapMetaData?.biomeDesignMask != null && !Mathf.Approximately(mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier, 1f)) { Mod.HeatLog.Trace?.Write($"Biome: {mech.Combat.MapMetaData.biomeDesignMask.Id} has heatSinkMulti: x{mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier} "); capacityMulti *= mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier; } } catch (Exception e) { Mod.HeatLog.Error?.Write(e, $"Failed to calculate designMaskHeatMulti due to error: {e}"); } Mod.HeatLog.Trace?.Write($"Calculated capacityMulti: {capacityMulti} x globalHeatSinkMulti: {mech.Combat.Constants.Heat.GlobalHeatSinkMultiplier} "); capacityMulti *= mech.Combat.Constants.Heat.GlobalHeatSinkMultiplier; return(capacityMulti); }
public static void Postfix(ActorMovementSequence __instance) { AuraCache.RefreshECMStates(__instance.Combat.AllActors, EffectTriggerType.Passive); }