Skip to content

Make Disarm work on other players in PvP - #33

Open
absol89 wants to merge 1 commit into
devfrom
fix/pvp-disarm
Open

absol89 wants to merge 1 commit into
devfrom
fix/pvp-disarm

Conversation

@absol89

@absol89 absol89 commented Nov 5, 2026

Copy link
Copy Markdown
Owner

Requested by Eric · project thread

Part of tiltedphoques#938 ("Disarm doesn't work on players").

Why it failed

The engine refuses to disarm essential actors, and every player is made essential by SetPlayerRespawnMode.

What

  • The essential check is lifted only when the target is the local player, the caster is a remote player and PvP is on. NPC disarms and PvP off take the original path.
  • Perk disarms (Disarming Bash, Riposte, Trick Shot) are now forwarded from the attacker's client to the victim's; before, HookAddTarget dropped them on the attacker's side. The victim's client still runs the effect's own condition check (e.g. victim must be attacking) instead of auto-succeeding.
  • A PvP disarm always uses Drop=false on other clients, so the weapon only drops on the victim's client. Other players' copies of the victim just lose it from inventory, even with bEnableItemDrops on. Trade-off: other players don't see or can't take the dropped weapon.

Verified vs assumed

Verified in Ghidra, SkyrimSE 1.6.1170:

  • 37523 (0x140678bd0), which finds the weapon to disarm, rejects actors with flags2 bit 18 (IS_ESSENTIAL, flags2 at 0x204).
  • It is called from all three hooked paths: 34289 (0x1405b6fd0, the archetype 9 add check), 34286 (0x1405b6ed0, DisarmEffect::Start) and 37524 (0x140678c70, the drop, reached from DisarmEffect::Update 34287 via task 0x5b).
  • The check's argument order is target then caster (built in 0x1405c4580, passed through 34525).
  • PlayerCharacter vtable +0x658 is 0x140734250 (ID 40454), so HookDropObject fires for the local player.
  • Non-voice disarms require the victim to be attacking (0x1406b8ec0).
  • From Skyrim.esm (read only): the shouts are Voice/Aimed/Cone. PerkBashDisarm 0x9CD4D, PerkRiposte 0x9CD4C and PerkTrickShot 0x105F1D are Touch, and only those are forwarded.

1.7.104: only checked that the IDs resolve.

Assumed:

  • The perk spell reaches HookAddTarget on the attacker's client when they hit a remote copy.
  • Removing the weapon from a remote copy also unequips it visually.

Dupe/loss: other clients can't drop a copy (they stay essential and get Drop=false). The dropped ref is temporary, so pickup sends +1 against the -1. It can be lost like any dropped item if the victim disconnects and the cell resets.

Testing

Not built locally (CI builds it) and not tested in game. Two clients, PvP on:

  1. Disarm shout on a player with a drawn weapon: "You have been disarmed!", the weapon drops once, on the victim's side only.
  2. The victim picks it up and re-equips it; inventory counts match on both clients, and enchantment and charge survive.
  3. The attacker's view of the victim loses the weapon, then gets it back.
  4. Disarming Bash on a victim mid-attack.
  5. Repeat 1 with Gameplay:bEnableItemDrops on: no second weapon.

Must not change: PvP off (no effect), an NPC disarming a player (no effect, as on dev), a player disarming an NPC (as on dev).

Merge note: also edits MagicTarget.cpp like #30 and #31, in different lines.


Generated by Claude Code

The engine won't disarm essential actors and every player is essential, so
the shout and the perks silently did nothing. Lift that check only for the
local player being disarmed by another player. Perk disarms are sent to the
victim's client since they only run on the attacker's, and the weapon is
only dropped on the victim's client so it can't be duplicated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fvQxQEu7yvi9eRZyKsEur
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant