diasurgical / devilutionX

Diablo build for modern operating systems
Other
7.97k stars 778 forks source link

Hellfire Diablo can perform melee hit check almost immediately after being stunned #2957

Open SoundChaser83 opened 2 years ago

SoundChaser83 commented 2 years ago

Important information Operating system / DevilutionX version / did you download a release or did you compile yourself?

Vanilla Hellfire/any DevilutionX version

Describe Diablo's melee attack seems to perform its hit check almost immediately at the beginning of its animation (when his arms are beginning to raise into the air and not when he sweeps his hands down onto the player's face). Diablo also has a significantly shorter hit recovery animation in Hellfire. This means that you can stun Diablo right after he hits you, and he'll get an immediate double hit on you if he goes for his melee attack. This may not really be a bug, but it's incredibly counter-intuitive behavior that also incentivizes the player to deal less damage rather than more in order to avoid these weird/extreme damage spikes from Diablo as well as getting even more stunlocked yourself.

To Reproduce Steps to reproduce the behavior:

  1. Get a character that deals enough damage to consistently stun Diablo in Hellfire.
  2. Start fighting Diablo.
  3. Watch your health globe and try to observe any extremely fast double hits to your HP (worthy of note: Diablo can cast Apocalypse and then do a melee hit shortly after, and the gap between those two instances of damage is shorter than if Diablo just spammed Apocalypse or just spammed melee attacks. This is NOT what I'm talking about.)

Expected behavior Stunning Diablo should make the gap between the previous hit check and the next hit check at least as long as what would have happened if Diablo wasn't stunned at all.

Clips At 00:48, krobill stuns Diablo twice in succession, resulting in a very rapid triple melee hit from Diablo and killing her. Because she is playing vanilla Hellfire, she is also using the low-life stun immunity exploit which exacerbates this problem even further. Without this exploit, she would have been stunned by Diablo's attacks and this would have prevented her from dealing as many rapid stunning attacks herself.

https://www.twitch.tv/krobill2/clip/SoftBoxyTaroThunBeast?filter=clips&range=all&sort=time

StephenCWills commented 2 years ago

Just poking around at the data a bit, it seems Diablo's hit frame is 4, which is indeed when he's still lifting his arms into the air. His attack animation is 16 frames, and his hands reach the bottom of his downward sweep at frame 12.

julealgon commented 2 years ago

Because she is playing vanilla Hellfire, she is also using the low-life stun immunity exploit which exacerbates this problem even further. Without this exploit, she would have been stunned by Diablo's attacks and this would have prevented her from dealing as many rapid stunning attacks herself.

Would just like to highlight something regarding this right here.

There is another situation where this problem would occur as well, and that's multiplayer: if a player is being targeted by Diablo while all players attack him, the chance that he'll be stunned right after hitting increases, and even without the hit-recovery exploit this behavior would be seen.

EDIT: Even a rogue with perfect blocking would be instantly killed in some situations since the hits would happen while the first block animation was still running and the rogue's block animation is longer than 4 frames.

julealgon commented 2 years ago

Just poking around at the data a bit, it seems Diablo's hit frame is 4, which is indeed when he's still lifting his arms into the air. His attack animation is 16 frames, and his hands reach the bottom of his downward sweep at frame 12.

Nice. My vote as mentioned in IM would be to change the hitframe number to 12 then.

How many frames is his hit-recovery animation in Hellfire?

StephenCWills commented 2 years ago

How many frames is his hit-recovery animation in Hellfire?

Looks like it's 2 in Hellfire and 6 in ~Diablo/DevilutionX~ Diablo.

AJenbo commented 2 years ago

If we are making this change I would turn the definition on it's head: "Diablo hit frame is incorrect it should be 12 but is 4, correcting this also fixes the issue of him not being stunned properly" :)

NiteKat commented 2 years ago

Just curious, what is his hit frame in vanilla Diablo, without Hellfire?

julealgon commented 2 years ago

Just curious, what is his hit frame in vanilla Diablo, without Hellfire?

I don't think that has changed from Diablo to Hellfire, so still 4.

StephenCWills commented 2 years ago

To clarify, it seems there is still logic in DevilutionX that removes 4 frames from Diablo's hit recovery animation based on the Hellfire flag. So the behavior is currently the same between vanilla and DevilutionX.

https://github.com/diasurgical/devilutionX/blob/2c4c277c87801ccbdeabcddafcd484ee7ac810f9/Source/monster.cpp#L799


Diablo

Attack animation: 16 frames Hit frame: 4 Hit recovery animation: 6 frames

Hellfire

Attack animation: 16 frames Hit frame: 4 Hit recovery animation: 2 frames

NiteKat commented 2 years ago

Ah, is the issue moreso then that the hit recovery is only 2 frames in vanilla Hellfire? They wanted to up Diablo's difficulty, so they made his stun shorter, but this amplifies the fact his attack deals damage on the 4th frame and makes it more apparent? I don't think I've ever felt like his melee attack comes too fast in 1.09 Vanilla...

StephenCWills commented 2 years ago

Ah, is the issue moreso then that the hit recovery is only 2 frames in vanilla Hellfire? They wanted to up Diablo's difficulty, so they made his stun shorter, but this amplifies the fact his attack deals damage on the 4th frame and makes it more apparent? I don't think I've ever felt like his melee attack comes too fast in 1.09 Vanilla...

The issue is especially noticeable in Hellfire because of that, but it could easily be argued that it makes no sense for the player to get hit on frame 4. The 12th frame is quite clearly the frame where it looks like the player is getting hit. If Diablo is repeatedly sent back to hit recovery between frames 4 and 8, the player will keep getting hit, but there will be no visible feedback apart from the health/mana orbs.

However, for all we know, Blizzard may have moved the hit frame for balance reasons. From what I can tell, player attack animations can range anywhere from 12 to 24 frames without affixes. We can use some simple math to figure out what Diablo's timings are, and also what they would be if we changed them. From that, you can see that moving these values around could make a huge difference regarding whether the player is able to truly stunlock Diablo.

Time from the start of hit recovery to the hit frame

Diablo: 10 frames Hellfire: 6 frames

If the hit frame is moved to 12

Diablo: 18 frames Hellfire: 14 frames

EDIT: I also forgot that (some?) player attack animations can be cut short after the hit frame if another attack is queued. I'm not sure exactly how that works, but player hit frames seem to occur between frames 8 and 16. You can figure that most players will be using a weapon with an animation that hits around frame 8-10.

julealgon commented 2 years ago

I also forgot that (some?) player attack animations can be cut short after the hit frame if another attack is queued.

All attacks can. Melee, ranged, and spells.

Logic for this is inside CheckNewPath, at the end of the ProcessPlayers call. https://github.com/diasurgical/devilutionX/blob/ada3b3dabae58599449417ae894c7250301c7e2e/Source/player.cpp#L1794-L1861

I'm not sure exactly how that works, but player hit frames seem to occur between frames 8 and 16

Pretty much. Hit frames are usually around the middle of the animation frames, so 9 or 10 for warrior (total animation 16 frames on 1-handed) and earlier for the rogue since her animation is much faster overall.

Animation cancelling allows you to completely ignore all recovery frames (frames that would occur after the hit frame and before you can act again) and start another attack animation immediately after the hit frame. So a warrior which would usually take the full 16 frames to attack, takes only 10 (hit frame +1 IIRC from the logic, since the cancelling effect takes place on the next turn).

It does make sense that the rogue has more issues here since she attacks much faster, but again, this situation could occur under other conditions as well like multiplayer.

AJenbo commented 2 years ago

However, for all we know, Blizzard may have moved the hit frame for balance reasons.

Yeah, thats my biggest hesitation here, it's hard to see this suggestion as anything but an attempt at balancing the gameplay.

SoundChaser83 commented 2 years ago

Yeah, thats my biggest hesitation here, it's hard to see this suggestion as anything but an attempt at balancing the gameplay.

Changing Diablo's hit frame would clearly have balance implications, but DevilutionX is no stranger to this especially with such massive changes like the change to monster AI with respect to fire/lightning walls (to the extent that I substantially alter the way I approach speedruns as a result). Having Diablo's hit frame adjusted to 12 seems to give the player the most accurate feedback on what's happening in the Diablo fight given his animation, and this itself seems like it may be an independently justifiable change given that DevilutionX seems to value bringing accuracy and polish to the original game. Coincidentally, doing so may also solve this other oddity with stuns causing Diablo to deal rapid hits, a feature that I don't think we can reasonably expect the average player to understand, let alone prepare for.

FitzRoyX commented 2 years ago

All attacks can. Melee, ranged, and spells.

fwiw, I despise how this mechanic looks and feels. There's no reason for starting attacks to be slower than queued attacks. I'm guessing they did this purely to enhance visuals at 20hz. Because at 20hz, achieving satisfying attack speeds requires heavily truncating the original frameset. Showing more frames just for the first attack allowed them to show a more complete attack animation a good chunk of the time.

AJenbo commented 2 years ago

? the visuals won't be any better or worse at 20hz, the attack is just faster/shorter. I good reason for why the first attack is longer is that you are getting in to combat where subsequent blows won't need to adjust from a generic stance, that seams reasonable to me.

julealgon commented 2 years ago

All attacks can. Melee, ranged, and spells.

fwiw, I despise how this mechanic looks and feels.

I agree. To me its one out of a handful of things that make the game look less polished than it should. Which is why it was one of the first things I proposed removing. I have now removed it in my fork in preparation for creating my own mod.

I know it was "fixed" with animation interpolation, but I'm not a fan of that approach since it gives the game an unnatural feel to me, with the seemingly arbitrary speed-up in attacks when attacking constantly.

There's no reason for starting attacks to be slower than queued attacks. I'm guessing they did this purely to enhance visuals at 20hz. Because at 20hz, achieving satisfying attack speeds requires heavily truncating the original frameset. It could be something like that yeah. I imagine the frame extraction process from the original 3D models took place somewhat early in the production and this probably wasn't adjusted later for gameplay. They might have had to cut it down artificially to fit their desired speed while butchering fluidity.

This is probably one of the reasons why they bumped it to 25hz for Diablo 2, as it gives you a bit more freedom in how animations are played in these speeds.

Showing more frames just for the first attack allowed them to show a more complete attack animation a good chunk of the time.

That's not how it works though. Its not that "it shows all frames in the first attack", but that "it only shows full frames for isolated attacks". Even if you start an attack sequence, the first attack will also have its recovery frames removed.

So it's actually quite rare to even see the full animation in vanilla if you are playing like most people play: spamming attack all the time. You are never encouraged to attack only once in the game (its actually inefficient to do so). The only time you see the full animation often is when destroying barrels since you never multi-hit those by default, or when you stop continuosly attacking (the last hit on a sequence will play to the end).

The last point above actually impacts axe weapons a lot, since they have a TON of recovery frames after the hit frame, and the fact that they are more likely to kill enemies in fewer hits, so you stay less time in the animation skipping sequence which is supposed to increase attack speed.

Not that axes needed yet another reason to be terrible, but there we are...