fix(combat): armour durability wear targeted the attacker instead of the defender#574
Merged
Merged
Conversation
…the defender The 'Damage armour' block in ActorAttack (GameServer.bb) was a copy-paste of the weapon-wear block directly above it, which correctly targets A1 (the attacker's weapon wears). The copy kept A1 for armour wear too, so each swing wore down the ATTACKER's equipped armour and echoed the P_ItemHealth durability update to the attacker -- even though the armour that absorbed the blow belongs to A2 (the defender; the damage formulas read GetArmourLevel(A2\Inventory)). Re-target the armour-wear block only: A2's Shield..Feet slots now wear, and the P_ItemHealth echo goes to A2\RNID under the same RNID > 0 NPC guard the block already used. Deliberate test flip: CombatDamageFormulaTest.bb's testArmourWearHitsAttackerNotDefender pinned the shipped bug (FLAG-FOR-HUMAN, PR #572). Renamed to testArmourWearHitsDefender and flipped its assertions to the corrected behavior -- the defender's chest piece loses durability over a 300-swing volley while the attacker's stays at exactly 100. The attacker's weapon-wear pin and every other pin are untouched. Verified: test.bat CombatDamageFormula PASS; full suite 58/58 green; full compile.bat (engine + tools) exit 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug (gameplay, runtime-confirmed, found by PR #572's pins)
In
ActorAttack's melee path, the "Damage armour" block (GameServer.bb:551-566) iteratedA1(the attacker's) inventory over the armour slots and echoedP_ItemHealthtoA1\RNID— but the armour that absorbed the blow is the defender's (all three damage formulas readGetArmourLevel(A2\Inventory)). Net effect: attacking wore down your own armour; the defender's never degraded. Almost certainly a copy-paste of the weapon-wear block above it (:537-549), whereA1is correct. Pinned empirically in #572: defender chest stayed exactly 100 over 300 swings.The fix
A1→A2inside that one block only — the inventory iterated/decremented and the echo recipient. Structure, guards,Rand(1,5)wear rate, slot range, and packet shape unchanged. NPC defenders wear silently under the existingIf RNID > 0convention (same as the weapon block); their armour state stays authoritative server-side.Wire-routing correctness (verifier-checked): the
P_ItemHealthhandler (ClientNet.bb:249-252) carries no actor ID — it updates the recipient's own inventory slot. So sending toA2\RNIDmakes the defending player's client update the same slot the server just decremented in A2's authoritative inventory. Server and client share theSlotI_*constants; the mapping is exact.Coherence bonus:
GetArmourLevelonly counts pieces withItemHealth > 0, so the fix closes the intended loop — the defender's armour degrades and eventually stops protecting the defender (previously, attacking nonsensically degraded the attacker's own defense).Plus the deliberate flip of the #572 pin:
testArmourWearHitsAttackerNotDefender→testArmourWearHitsDefender(defender wears, attacker stays 100; 300 swings × 1-in-5 wear ≈ 60 expected decrements, so the assertions discriminate with enormous margin). The weapon-wear pin is untouched.Deliberately untouched: the formula-3 vulnerability paradox at
:521(separate, maintainer-gated) and the block's position/conditions (wear still rolls on the melee path exactly where it did).Out-of-scope observation for a follow-up: the projectile hit path (
GameServer.bb:268-304) readsGetArmourLevel(A2\Inventory)but has no armour-wear block at all — ranged hits never wear the defender's armour, before or after this fix.Verification (independent verifier ≠ implementer)
GameServer.bb(+ comment) and the one test flip; weapon-wear block and:521byte-identical; no generator-gated files.Ran 58 files: 58 passed, 0 failed.; FULLcompile.bat(engine + all 7 tools) exit 0.🤖 Generated with Claude Code