WIP: fix(gameplay): Half damage uses the full hit before life is clamped #269
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!269
Loading…
Reference in a new issue
No description provided.
Delete branch "simonwjackson/Longshot:fix/damage-taken-review"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
Half can incorrectly save Link from a lethal hit because it halves damage after the game clamps life to zero. This follow-up to #138 scales the full hit instead.
What changed
nx2/oot_patches.py: pass x9 at the damage-site CAS only. Keep both player/life-pointer guards, the healing site's delta, idempotence and supported-build checks.host/oot_damage.c: scale the full hit; preserve Normal's result, healing and Heart protection.tests/test_oot_damage.py: a two-unit life/four-unit hit kills at Half through the emitted guard; exhaustive lethal/nonlethal hits and a changed-old-life CAS retry are covered.docs/development.md: document exact lethal Half and the saved option. The README paragraph wraps below 120 columns.docs/tested-configurations.md: three session rows below the day's existing rows, including the excluded first harness attempt.HumanBean already fixed Debug-tools gating in
b6d695b4, merged with #138. This PR retains his code, help and hidden-means-Normal test unchanged. The stale translation keys from that merge are repaired separately in #273.Flags and settings
damage_taken=0/1/2/3Measurements
main:
514591a30d(2026-11-13)this PR: fix/damage-taken-review @
8c3c77cb08The exact current-main SHA is recorded in the merge commit. The game ran at
2f42b40e01; later changes are tests/docs and main's Discord-link update only. Runtime source is unchanged. The original regression failed on mainf3fe1763dda267a134494f1d21e6ad10b1ec4cd8. The two interleaved pairs below were repeated on the final heads after the last merge.Game-free comparison
Method: two interleaved pairs on the same Linux machine, compiling the real emitted guards and host arithmetic. Main adds only the two-life/four-hit regression assertion, not an implementation change. This is a correctness fix, not an FPS comparison.
514591a38c3c77cbLift and gameplay proof
On aka, the actual supported lift's damage block subtracts x9 before clamping next life. The failed-CAS edge refreshes old life and returns to recompute without changing x9. A local compiled fixture exercises those actual blocks with a forced failed CAS: old life changes from 6 to 2, x9 stays 4, and Half writes zero on retry. The lift, extracted fixture and executable stay on aka; no lifted code is included here. The public game-free test separately checks the emitted guard with authored inputs.
Hardware: AMD RX 7900 XT 20 GB, RADV Mesa 26.2.3; Ryzen 5 7600X, 32 GB RAM; NixOS 26.11, Linux 7.2.7. Private headless Sway 1.12/Xwayland, 1920×1080, game's upscaler, frame generation and HDR Off, mesh fallback, audio disabled. GPU lock held; only isolated builds and copied saves used.
Scene and method: Hyrule Castle Town (
Market_Child), controlled falls onto the same roof. Hardware breakpoints read the full hit, old life, saved choice and Debug-tools state at impact, then detach. The read-only control bridge reads resulting life. No guest-memory or instruction writes. Two protected calibration falls (raw hits 5 and 4) leave life at 16; Heart protection is Off for the table below.How to reproduce: on a disposable save, enable flight to reach the roof and rise until the normal fall hit is four quarter hearts (about six seconds climbing here). Land on that roof at Normal, Double, Half, Half. Use the menu or ordinary hits to reach two quarters before the final Half hit; do not change health with a memory write. For the separate gate check, keep Quadruple saved and compare a three-quarter fall with tools Off and On. Debug-tools state must be checked before impact, not after landing.
2f42b40eUnits are quarter hearts. The last hit enters the death animation. Normal, Double and nonlethal Half retain their expected results.
These pair the debugger's hit record with the subsequent bridge life reading. One initial gate attempt was excluded because tools state was not recorded at impact. Two later no-rise input attempts were also excluded; shorter double-tap spacing and explicit height/state assertions made the completed runs reproducible. No product failure is claimed from those harness attempts.
Testing
Tested: full game-free suite at
98f3fdef: 514 passed, 2 failed, 16 skipped in 494 s, 8 jobs under the shared lock. Both failures reproduce on untouched main:test_linux_tools.pyhardcodes a PATH without Nix tools;test_menu_i18n.pyretains the old Debug-tools translation keys. The latter is fixed by separate #273, whose full suite has 516 passed, 1 inherited PATH failure, 16 skipped. No new failures.Nine affected checks passed after the runtime main merge: damage, Debug menu, option IDs, README, mouse, controls and presets. The final explicit changed-old-life retry test and README checks pass. GCC C11 syntax check with
-Wall -Wextra -Werrorandgit diff --checkpass. No standalone formatter is configured. Native fixtures compile with warnings as errors; the full runner also checks tracked Python syntax.Fresh pinned Linux release build from the NUP succeeded in 29 min 25 s; all tracked source hashes matched the archived commit before and after the build. Shader preparation succeeded. Gameplay above ran the resulting binary, and every screenshot was inspected. No GPU-hang, device-lost or crash marker occurred in the played sessions. All private units stopped and the GPU queue entry was removed. No installed game, live save or
korri*unit was changed.Not tested: Windows build/runtime and non-ASCII Windows paths, other GPU families, physical controllers, Dark Link, Ganon's final hits, drowning and cold water, heat rooms and lava, healing/fairy gameplay and a full playthrough. Requests are not passing results.
Needs other testers:
All five requests are open but await a maintainer's
testing wantedlabel before testers can claim them.Screenshots
PR attachments, verified byte-for-byte through anonymous downloads; no private-fork links:
The gameplay evidence comment also contains the tools-Off and tools-On screenshots.
Risk and rollback
The hook is tied to the supported game's two guarded CAS sites. Other life-write paths can bypass it. Normal or Debug tools Off restores stock damage; reverting this fix restores the old lethal-Half limitation. Dark Link's identity remains unverified.
Reviewer notes
Only the remaining lethal-Half fix and its tests/docs. HumanBean's Debug-tools gate is not reimplemented. No public renderer ABI structure changes. Main was merged normally, not rebased or force-pushed. This stays WIP because the Windows build box is not fulfilled and the description checker requires a literal rebase box rather than the truthful merge wording below.
Issues
See #138 (review 1153).
Checklist
For everyone
type(scope): description).main(514591a) as8c3c77c; no rebase or history rewrite. This replaces the template's inaccurate "Rebased on current main" wording.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested-configurations.mdfor each measured run.mainand passing here.tests/that reads changed source updated in this PR, not weakened.d964886into lethal-Half follow-upMerged current main
d964886as2f42b40ewith a normal push; no rebase. The arithmetic is unchanged from98f3fdef. All nine affected focused checks pass. The full-suite failures both reproduce on untouched main. The fresh Linux build is queued; this stays WIP until gameplay proof and test requests are recorded.Linux gameplay proof at this PR @
2f42b40eis complete. Castle Town roof, RX 7900 XT/RADV 26.2.3, NixOS 26.11. Read-only hardware breakpoints recorded old life, the unclamped hit, Debug-tools state and saved setting; the bridge read life after impact. No guest-memory writes.Units are quarter hearts. The final hit enters the game's death animation. Normal, Double and nonlethal Half retain their expected results. HumanBean's existing Debug-tools gate also works: it was not changed here.
514591ainto lethal-Half follow-upPushed
8c3c77c: measured gameplay and the changed-old-life retry test are recorded; current main514591awas merged normally (Discord links only). The pinned Linux build proves Half kills with 2 units left and a full 4-unit hit; nonlethal Half, Normal and Double retain their expected values. The inherited Debug gate is also proven Off/On. Five test requests are open; they need the testing wanted label. WIP remains honest: Windows is unverified, and the checker requires rebase wording despite the actual merge.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.