dotnet 8 conversion + attempt at "hitless practice" feature - #3
Open
nacitar wants to merge 2 commits into
Open
Conversation
Introduce a dedicated player-hit behavior service that powers two independent options in the Enemy tab: negate non-fatal player damage and heal enemies when the player is hit. Wire the new service through main composition and enemy view model bindings, and add the required ASM/hook plumbing (scripts, offsets, code-cave layout, and resources) to detect player-hit events with attacker context. Track observed enemy health across play (including when heal-on-hit is off) and bound tracker lifetime/size to keep restore behavior accurate while avoiding unbounded growth.
Author
|
One other deficit here that I neglected to consider is that ideally you'd still be able to die to Seath in the first encounter. |
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.
This PR is primarily a write-up of my findings while trying to add a feature I very much want for my own practice. I am hoping that someone with a stronger understanding of the game internals and the hook/ASM side of this codebase might be able to take the idea further or implement it more cleanly.
I made an earnest attempt to solve it myself and will keep iterating on it regardless, but I want to be upfront that this branch is just the best that I could manage.
This branch also includes a .NET 8 conversion so I can build and test on ArchLinux. That part is directly useful to me because the older framework setup is much harder to deal with when not on Windows.
Goal
The feature I want is a more natural way to practice hitless runs.
If I do not get hit, the run should behave exactly like a normal run.
If I do get hit, I want special behavior that extends fights until I've managed to clear the full enemy healthbar hitless.
Desired behavior
When the player is hit by an enemy:
Important detail: restore to spawned/observed health, not always full max health. For example, the second Bell Gargoyle should only heal back to its half-health spawn state.
When the player is not hit by an enemy:
In other words, the only behavior I want to change is what happens when the player is hit by an enemy. The run should be indistinguishable from a vanilla run if the player is never hit.
Why I want this
The idea is that the game still feels like normal gameplay, but if I get hit I effectively have to replay the full boss health bar in order to move on.
To me, that feels much more fun than making both the player and the boss unkillable and then grinding for a long time. It preserves the natural rhythm of the run while automatically pushing practice toward the parts that actually need work. At least for me, that makes it feel less like "practice" and more like just playing the game for fun on a given day, gradually getting better while the game implicitly extends my practice in areas where I still make mistakes.
Existing features I investigated
The two existing features that seemed most relevant are
No DeathandNo Damage.For the desired functionality, every column below would ideally be
TRUE:Ignoring enemy healing for a moment,
No Damageinitially looked like the most promising approach. The problem is that it also negates fall/environmental damage, which means no RTSR setup and generally makes it unusable for the behavior I want.No Deathgives a closer approximation if I accept some compromises. Assuming I ignore death planes and accept that falls/environmental damage can hurt me but not kill me, it becomes usable if I can separately restore player health on hit and heal enemies on hit.What I used to build this branch
One of your other repositories,
AutoHitCounter, shows that the problem of external hit detection has already been solved. That gave me a proof of concept I could borrow from, because without that prior work and without deeper expertise here, I do not think I would have been able to get this part working myself. By pulling ideas from that project into this one, I was able to get to the point where SilkySouls can react to the player being hit.What I added here
I added
Heal enemies when player hit.This tracks enemies' health when they appear, stores those observed values, and restores them to those amounts whenever the player is hit. That means it preserves cases like the second Bell Gargoyle correctly; restoring that enemy to absolute full health would be wrong.
I also added
On non-fatal player hit: no player damage.This does not truly prevent the damage event. Instead, it immediately restores the player's health afterward. I could only make this work for non-fatal hits. If the hit would have been fatal, the death processing was winning the race before the health restoration took effect, and I could not figure out how to resolve that cleanly.
Best approximation I could get working
Right now, my best approximation of the intended feature is:
No Death.On non-fatal player hit: no player damageso normal enemy hits restore the player's health.Heal enemies when player hit.With that combination, the feature is effectively implemented except for two remaining limitations:
So this gets very close to what I want, but it is still not fully correct. That said, it is fully playable as a prototype for the feature I am after, and it is already good enough for me to use for practice even though it is not yet ideal.
Why I am opening this anyway
I suspect there is a better implementation path that could solve the remaining problems more cleanly.
I am a seasoned developer, but I am not familiar with the internals of this game and I am not very capable at the assembly level. C++ is about as low-level as I comfortably go.
To get this far, I used AI with both this project's code and the
AutoHitCountercode as context, and had it help me piece the approach together.I am quite confident in the .NET 8 conversion. I am much less confident in the hook/ASM-heavy parts of this branch; some of this may be horrible AI-slop code, but I did test it quite thoroughly.
I do not expect this PR to be merged as-is. I do think this feature would be useful for people interested in practicing speedruns, though, because it lets you practice without taking the fun out of simply playing the game. It makes the process feel less rigid and less militaristic. I am hopeful that the maintainers of this project will agree that the idea is worthwhile and perhaps help turn it into something cleaner and more broadly usable.