Stage 1: walk while healing legs, for SPT 4.0.13
Ground-up reimplementation of yox92/SmartAction targeting SPT 4.0.13 / EFT 0.16.9.0.40087. Only the walk-while-healing feature is implemented; see NOTES.md for status and the deferred sprint work. Design departures from upstream: - CanWalk is a guarded postfix, not a transpiler. Upstream rewrote the method body, which affects every MovementContext in the raid including bots, and is hard-incompatible with the three other mods already patching MovementContext in a typical load order (SAIN, ORBIT, maschine-DualSideDoorBreach). A postfix that only flips false -> true for IsYourPlayer is inert for other entities by construction. - The postfix re-tests ObstacleCollisionFacade_1.CanMove() before lifting. Upstream's transpiler dropped that check along with the HealingLegs check, silently disabling obstacle blocking. - Targets resolve by name via AccessTools.PropertyGetter + nameof rather than by GClass number, so they survive EFT version bumps. Verified in-game against 78 loaded plugins: both patches attach, the guard rejected 985 non-local MovementContext calls with zero leaks, and _player was never null across ~4000 guard calls. CanSprintPatch is parked in deferred/ rather than deleted: MovementContext.CanSprint does not gate sprinting (EnableSprint calls Physical.Sprint unconditionally), and forcing it true makes EnableSprint run ForceStopInteractions()/RemoveLeftHandItem() mid-heal. Details and the 3.11 -> 4.0.13 rename table are in NOTES.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
using System.Reflection;
|
||||
using EFT;
|
||||
using HarmonyLib;
|
||||
using SPT.Reflection.Patching;
|
||||
|
||||
namespace SmartAction.Patch;
|
||||
|
||||
/// <summary>
|
||||
/// Lets you sprint while using meds / healing legs.
|
||||
///
|
||||
/// Vanilla MovementContext.CanSprint (EFT 0.16.9.0.40087):
|
||||
/// if (PhysicalConditionIs(SprintDisabled)) return false;
|
||||
/// if (PhysicalConditionIs(UsingMeds)) return false; // lifted here
|
||||
/// if (PhysicalConditionIs(HealingLegs)) return false; // lifted here
|
||||
/// if (PhysicalConditionIs(OnPainkillers)) return true;
|
||||
/// if (PhysicalConditionIs(RightLegDamaged)) return false;
|
||||
/// if (PhysicalConditionIs(LeftLegDamaged)) return false;
|
||||
/// return true;
|
||||
///
|
||||
/// Upstream SmartAction used a prefix that returned false outright, suppressing the original
|
||||
/// getter for every MovementContext in the raid. That is hard-incompatible with any other mod
|
||||
/// touching sprint or stamina. This lifts exactly the two med-related blocks and replays the
|
||||
/// rest of vanilla's chain, so leg damage and SprintDisabled keep their normal meaning.
|
||||
/// </summary>
|
||||
public class CanSprintPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.PropertyGetter(typeof(MovementContext), nameof(MovementContext.CanSprint));
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void Postfix(MovementContext __instance, ref bool __result)
|
||||
{
|
||||
if (__result) return;
|
||||
|
||||
if (!MovementPatchUtil.IsLocalPlayer(__instance)) return;
|
||||
|
||||
// Not ours to override — this is a deliberate game/quest/effect lockout.
|
||||
if (__instance.PhysicalConditionIs(EPhysicalCondition.SprintDisabled))
|
||||
{
|
||||
if (Diagnostics.Enabled) Diagnostics.SprintHeldBySprintDisabled++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only intervene when meds or leg-healing is what blocked us.
|
||||
var blockedByMeds = __instance.PhysicalConditionIs(EPhysicalCondition.UsingMeds)
|
||||
|| __instance.PhysicalConditionIs(EPhysicalCondition.HealingLegs);
|
||||
if (!blockedByMeds) return;
|
||||
|
||||
// Replay the remainder of vanilla's chain so a broken leg still stops you.
|
||||
if (__instance.PhysicalConditionIs(EPhysicalCondition.OnPainkillers))
|
||||
{
|
||||
__result = true;
|
||||
if (Diagnostics.Enabled)
|
||||
{
|
||||
Diagnostics.SprintLifted++;
|
||||
Diagnostics.OnceSprintLifted();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (__instance.PhysicalConditionIs(EPhysicalCondition.RightLegDamaged)
|
||||
|| __instance.PhysicalConditionIs(EPhysicalCondition.LeftLegDamaged))
|
||||
{
|
||||
if (Diagnostics.Enabled)
|
||||
{
|
||||
Diagnostics.SprintHeldByLeg++;
|
||||
Diagnostics.OnceSprintHeldByLeg();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
__result = true;
|
||||
|
||||
if (Diagnostics.Enabled)
|
||||
{
|
||||
Diagnostics.SprintLifted++;
|
||||
Diagnostics.OnceSprintLifted();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user