Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Whirlwind is being adjusted #7

Open
Warren1001 opened this issue Jun 27, 2022 · 52 comments
Open

Whirlwind is being adjusted #7

Warren1001 opened this issue Jun 27, 2022 · 52 comments

Comments

@Warren1001
Copy link

While it's not exactly relevant to your calculator (and you may not be working on it anymore), anyone who saw our previous work may return here to learn about how it works, so I'll continue using this place for new changes.

2.4.3 announced Whirlwind attack speed rework (using all gear IAS):

Changed the logic for determining how often Whirlwind attacks occur. Whirlwind now incorporates Increased Attack Speed (IAS) from all equipment. The frames between each Whirlwind attack are equal to the attack frame of a basic attack for that character (modified by increased attack speed). While dual wielding, the attack frame for each weapon will be averaged (rounding up). Overall, Whirlwind attacks should be at least as fast as they were before. Slower weapons will attack notably faster.

@Warren1001
Copy link
Author

Warren1001 commented Jun 27, 2022

If this is to be taken literally, Whirlwind now attacks extremely slowly, 9 FPA is the maximum a Barbarian can attack for "basic attack" for one-handed weapons. What I assume they mean is now gear IAS contributes in the same linear fashion that weapon IAS does now (EIAS = WIAS - WSM -> EIAS = IAS - WSM) and still doesn't incorporate skill IAS.

Edit: it makes no sense to use basic attack frames, its a hard nerf across the board, and they say it should be roughly the same or faster. It's currently more than twice as slow given their info, so their info is simply wrong and I have to test to see what they actually did.

@ChthonVII
Copy link
Owner

I've been very busy lately with real life, but I've not given up hope of eventually finishing this calculator.

Here's a Google Translate of TitanSeal's explanation of legacy WW:

After this second attack, a delay time is set again, but this time the duration of the delay depends on the speed of the weapon. For this, the delay formula is used, which we already got to know during the transformation:

Delay = [256*CharFrames/[(Baserate + WIAS - WSM)*CharSpeed/100]]

CharFrames... The sum of the basic attack frames for our character and weapon type combination.
Base rate... Our basic value, which is 100 again here.
WIAS ... All IAS contained on the weapon
WSM... A weapon dependent stat used to control attack speed
CharSpeed ​​... Value of the A1 animation to be read from the animdata.txt

Two-handed swords (also see next chapter) use the same values ​​for CharFrames and CharSpeed ​​as one-handed swords. Therefore, two-handed swords are just as fast as one-handed swinging weapons.

In order to determine the delay from this delay, there are a number of breakpoints:

Delay => Delay

00-11 => 4
12-14 => 6
15-17 => 8
18-19 => 10
20-22 => 12
23-25 ​​=> 14
26+ => 16

So my guess is that the "equal to the attack frame of a basic attack for that character" business just refers to the fact that A1's framesperdirection and animationspeed are used in the calculation. I really hope they wouldn't be so dumb as to remove the following step involving WW-specific breakpoints... So my hopeful guess would be that they're just changing Delay = [256*CharFrames/[(Baserate + DiminishingReturns(WIAS) - WSM)*CharSpeed/100]] to Delay = [256*CharFrames/[(Baserate + DiminishingReturns(WIAS + nonweapIAS) - WSM)*CharSpeed/100]] then calculating it once for each weapon, then averaging, then proceeding with the WW-specific breakpoints.

Other issues worth investigating:

  1. Are two-handed swords still always treated as one-handed swords for WW's speed calculations?
  2. Has the buggy crazy business while dual wielding -- the stuff with weapon base and some modifiers swapping every swing, but other modifiers only swapping on successful hits -- been resolved?

@Warren1001
Copy link
Author

Warren1001 commented Jun 28, 2022

Fixed an issue where short-distance whirlwinds could end without executing a single attack.

Fixed an issue where Whirlwind would still apply properties and damage from a broken weapon.

Fixed an issue where the first attack of Whirlwind was treated different from the rest. When dual wielding, the first attack will choose two targets, just like all the other attacks.

other bugfixes for whirlwind

  1. With the bugfix to broken offhand, it's possible they may have addressed the issue too. But the statlist swap bug you're describing is for sequence skills (from what I understand) and not unique to Whirlwind, though the broken offhand bug I believe is unique to Whirlwind.

edit: for clarification, the WIAS does not have diminishing returns, it's linear.
edit2: I'm hoping the same as what you're saying, and they're just clarifying a point, not implying that made an adjustment (since that does describe what they are basically already doing now).

@Warren1001
Copy link
Author

Didn't think about this other change they made until just now:

Players can now start a new Whirlwind, Leap, or Leap Attack immediately after a Whirlwind ends.

Do you think this would imply potentially faster than 4 FPA on 4 FPA minimum whirls being cast back to back? I'm assuming that if you hold RMB for minimum whirls you truly hit at 4 FPA. If they make the next Whirlwind seamless into the current one, could they be duplicating NU frame and constant minimum whirls would hit at 3 FPA after the first sequence?

The patch just dropped as I was writing this, so I'll begin testing.

@Warren1001
Copy link
Author

Warren1001 commented Jun 29, 2022

Okay, we've got weirdness going on, typical of Blizzard.

First, the 8th frame check no longer exists, the varying delay hits starts immediately after the first hit.
Second, SIAS does count. Level 93? Fanaticism lets me attack at 5 FPA using Hydra Edge (DW).
Third, 4 FPA is still the fastest FPA, both holding the button down and doing back-to-back minimum whirls.

Breakpoints are off all over the board (DW = Dual Wield, S = Single Hand):

Weapon Hits FPA Original FPA
Phase Blade (DW) 4, 9, 14, 19, 24, 29 5 6
Phase Blade (DW) (3 WIAS on both) 4, 9, 14, 19, 24, 29 5 6
Phase Blade (DW) (4 WIAS on both) 4, 9, 14, 19, 24, 29 5 4
Phase Blade (DW) (5 WIAS on both) 4, 9, 14, 19, 24, 29 5 4
Hydra Edge (DW) 4, 11, 18, 25, 32, 39 7 8
Hydra Edge (S) 4, 11, 18, 25, 32, 39 7 8
Glorious Axe 4, 14, 24, 34 10 12

Before 2.4.3:

  • Phase Blade would have been at 6 FPA for all breakpoints except 4+ WIAS, it would move to 4 FPA. I tested 5 WIAS because that converts to 4 EIAS if you apply the regular formula, but that didn't move me to 4..
  • Hydra Edge would have been at 8 FPA. I tested single hand to see if the offhand FPD was always set to 12, and this is not the case, since even with single hand I hit 7 FPA.
  • Glorious Axe would have been at 12 FPA. This confirms different FPD usage based on weapon is still at play.

Summary:

  • Odd breakpoints are possible without the frame averaging taking place, as even single hand Hydra Edge hits 7 FPA.
  • A flat -1 wasn't applied, as Glorious Axe is 2 frames less than expected. A neutral frame being shared due to change in my previous message can't be the (only) cause either.

I found these breakpoints by putting fire damage on my main hand and lightning damage on my second hand. alwayshit=1 so I don't miss. I'm whirlwinding through a very densely packed Blood Moor of Idle Zombies, and recording and then playing back frame by frame. I know you don't think it's accurate, but when we tested for Fury, I gave you my breakpoints using this method, and then proceeded to confirm all of them with mana cost testing, so I believe this method is accurate, since we can't use mana cost method for this.

The note I mentioned regarding:

Players can now start a new Whirlwind, Leap, or Leap Attack immediately after a Whirlwind ends.

seems to be irrelevant, I notice no difference casting back-to-back whirlwinds. It feels exactly the same.

Looks like they changed how the second "delay" is calculated.

@ubeogesh
Copy link

ubeogesh commented Jun 29, 2022

For reference I've figured out breakpoints with a Spetum (0 weapon speed)

IAS Frames per attack
81 5
39 6
15 7
2 8
0 9

I have used audio method for this, by turning up the combat sounds and turning down everything else; then looking at the waveform. Hits were always with consistent rates.

@Warren1001
Copy link
Author

Warren1001 commented Jun 30, 2022

well, they lied about how it works. since the formula is now the same as basic attack (presumably), im just basing this off of basic attack frames. for glorious axe, theres a breakpoint at 109 and 163. based on how the logic previously worked, these breakpoints would determine when whirlwind's delay would shift as well (though it differed before because it was WSM and WIAS only). the only difference now is the lack of -1 at the end, but that doesnt matter in this scenario. whirlwind switches from 6 fpa to 5 fpa somewhere inbetween these two breakpoints, though i don't know where exactly. so i don't know what they could be doing. based on a recorded table that i believe to be correct, though im slightly doubting myself now, its not as simple as them dividing the standard attack by two or something either. for example 7 ias is the only basic attack breakpoint thats at whirlwind 9 fpa. there are 3 basic attack breakpoints that have 7 fpa whirlwind, same for 6 fpa. its not linear. i have no clue what they are doing

@ChthonVII
Copy link
Owner

Working theory: They did basically the same thing as wereform attacks. WW has its own framesperdirection value, probably 8. The increment value is adjusted by a multiplier that's X/Y where X is some constant (16? 17?) and Y is the framesperdirection from the weapon type's A1 animation.

@Warren1001
Copy link
Author

u need empirical data or u got that covered yourself? i can look into finding actual ww breakpoints if thats something you need. i tried fiddling with numbers regarding your theory to get something close to what i had recorded and didnt find anything, but my recordings werent actual breakpoints either

@ubeogesh
Copy link

animdata.d2 file has not changed between 2.4.3 and 2.3. SHA256 of both files is 36CB704B85A7A4788533F12AA3E7C61C619DC650C8EFA0CBD1D562446E1DAB68

@ubeogesh
Copy link

ubeogesh commented Jun 30, 2022

I think I figured everything out for 2-handed weapons (i was testing with spears mostly, but 10 with maul; and cross checked 20 with great maul and pike)

Skill IAS works. Item ias uses the same formula for diminishing returns as always

The "actual" breakpoints are these:

Interval Speed
10 0.83
9 0.91
8 1.01
7 1.13
6 1.29
5 1.51

Where speed is the usual thing 1 + (Skill_IAS + Diminished_Item_IAS - Weapon_Speed)/100

Here's a table for all weapon speeds without any skill IAS:

Interval 20 10 0 -10 -20
11 0        
10 4 0      
9 13 2 0  
8 26 13 2 0
7 46 29 15 4 0
6 83 58 39 23 10
5 174 125 89 63 42

@Warren1001
Copy link
Author

Warren1001 commented Jul 1, 2022

i applied ubeo's findings to some common algorithms we've already been using and doing a bit of tweaking. when i only looked at the positive EIAS values, i got a few values that were perfectly correct, but they were very high values, like 30+ for both values (being ww's fpd and 'x'). once i put the negative values in there, couldnt find anything anymore. not entirely sure if its due to a programming mistake now. i tried with the same increment formula we found for werewolf and applied your logic but nothing stood out based on ubeo's findings, so either theres a new/different factor at play or ubeo's findings are wrong (which seems unlikely, his info is roughly the same as mine just more in depth)

@ubeogesh
Copy link

ubeogesh commented Jul 1, 2022

I did some more testing and I think I understand all the breakpoints for using 1 weapon. No clue about how dual-wielding works.

It looks like there are 2 sets of breakpoints. One is for all 2-handers except swords. Another is for all 1-handers plus 2-handed swords. I think I have tested all the weapon types (even wands, they actually make a really strange sound when whirlwinding with them, like mauls)

And here they are

Interval 1H+2H Swords 2H except swords
11 ?? ??
10 ?? 0.83
9 ?? 0.91
8 ?? 1.01
7 0.88 1.13
6 1.01 1.29
5 1.17 1.51
4 1.41 N\A

@Warren1001
Copy link
Author

Warren1001 commented Jul 1, 2022

yeah, STF and 2HT both have FPD=19, whereas 1HS and 1HT have FPD=16, so theres two distinct breakpoint tables for whirlwind. in whirlwind, barbarian uses two handed swords with one handed breakpoints, regardless of the amount of hands used to equip, so 2HS=18 has no relevance to the skill

dual wielding would calculate each hand independently, and then average the frame length together rounding up when needed, and use that frame length between hits for both hands.

could've saved you some trouble lmao, all 1h weapons swing the same speed and all 2h weapons swing the same speed for barbs in whirlwind (cept 2hand swords are treated as 1hand), only difference between them is wsm which is just flat EIAS

@3yearsyoung
Copy link

3yearsyoung commented Jul 3, 2022

Appreciate your great work!

"dual wielding would calculate each hand independently, and then average the frame length together rounding up when needed, and use that frame length between hits for both hands"

Wondering if one hand is 4f and the other is 5f, is the average 4f or 5f?

@Warren1001
Copy link
Author

well, 4 + 5 is 9, divide that by 2 is 4.5, then you round up.. so its 5

@ubeogesh
Copy link

ubeogesh commented Jul 3, 2022

One thing really weirds me out with this situation, are those 1.01 and 1.41 breakpoints.

That's because every other breakpoint matches the animation length formula output, with the animation lengths (what is called "frames per direction") being 9 and 7 frames long. But these 2 breakpoints require just 1 more effective\skill attack speed.

What's curious here, is that for those 1.01 and 1.41 breakpoints, there is a natural number at one step in the calculation, where rounding up is supposed to happen. Could they have just messed up data types somewhere and introduced a floating point error? 😅 Looks very much like this:

image

@ChthonVII
Copy link
Owner

Traditionally D2 used fixed point math exclusively. That's what all those values with 256 bits of precision are. (Back when D2 was originally released, a large proportion of consumer hardware in service couldn't do floating point stuff fast enough for gaming.) That said, we can't entirely rule out that these devs might have used floating point stuff in their new code. It's just unlikely.

We had some "off by one EIAS from what it should be" issues with wereforms, and they turned out to be the result of the increment getting multiplied by a factor (in order to simulate a different framesperdirection) and then rounded.

@ubeogesh
Copy link

ubeogesh commented Jul 3, 2022

Can you explain what "increment" do you mean? I'm referencing formula from here: http://www.mannm.org/d2library/faqtoids/ias_eng.html#form I can't see anything in the formula that I could call "an increment"?

@ChthonVII
Copy link
Owner

See math.js in this repo.


Also, I've had a thought so stupid that it might be right. That "off by .01" breakpoints might simply be a matter of >= versus >. We've been treating WW's delay like an animation counter, but it's not animation counter; it's a delay counter. For animations, the counter being equal to the maxcounter (i.e., maxcounter being evenly divisible by the increment) is sufficient to trigger abortion of the animation. But I don't see any reason that has to necessarily carry over to WW's delay. It may be the case that the counter must exceed the maxcounter for the delay to be considered expired.

@Warren1001
Copy link
Author

Warren1001 commented Jul 3, 2022

i continued ubeo's work and found something that gives exact EIAS values of ubeo's findings (fixes those one offs)
taking the increment we used for werewolf, where there's x / y where x is some constant and y is the weapon's A1 FPD, but instead reciprocated this and did y / x and set x to 7 (1H) or 9 (2H). all breakpoints match up per ubeo's findings. do note that even though whirlwind is a "sequence" skill, it still -1 at the end. the FPD in the main equation is the weapon's A1 FPD still.

i don't know if this is a "lucky guess" or what, and more data may be able to prove me wrong, but given everything ubeo has found so far its correct

@ChthonVII
Copy link
Owner

ChthonVII commented Jul 4, 2022

Excellent! It sounds probable that the devs picked a similar implementation for "make something with X FPD act like it has Y FPD" as they did in the wereform case. I think you've likely got it!

Now the sticky widget is going to be how dual wield is handled. Literally "compute both delays, then average, rounding up" seems unlikely for a bunch of reasons: (1) Everywhere else in the game where we have a counter going up to a limit, that's all we have. We don't have an independent computation of "how many frames is this going to take to hit the limit." It would be odd to do it here. (2) It wouldn't make a whole lot of sense to do the calculations with 256 bits of extra precision, then just discard the precision in the final rounding step. (3) Assuming they stuck to integer math, rounding up is fugly. Rounding down the increment is easy.

My first guess would be: Average and truncate the FPD; Average and truncate the increment.

My second guess would be: FPD has to be a constant, and the y/x term needs to be adjusted for it. Then we can just average the increments.
Examples assuming FPD is 8 and EAIS is 0:

  • Instead of CEILING((16*256)/FLOOR(256*(16/7))) - 1 use CEILING((8*256)/FLOOR(256*(8/7))) - 1
  • Instead of CEILING((19*256)/FLOOR(256*(19/9))) - 1 use CEILING((8*256)/FLOOR(256*(8/9))) - 1

A couple things I'm uncomfortable with this second guess:

  1. The pick of 8 FPD is arbitrary. There are probably lots of possible values that will give output matching the observations so far. I went with 8 here because (a) the legacy WW was clearly a multiple of 2, and (b) working backwards from the legacy max speed of 4FPA and the 75% EIAS cap gives 8FPD.
  2. The A1's FPD entirely falls out of the picture except insofar as it was used to pick 7 or 9.

Another thought: What about claws?

Also, how do we get from the A1's FPD to 7 or 9 (or whatever claws uses)? Is it just a lookup table? Or is it a computation like ((A1_FPD - 1) >> 1)? (It just occurred to me that ((A1_FPD - 1) >> 1)) is half the actual length of an A1 attack with no EAIS. That's probably not coincidence.)

@ubeogesh
Copy link

ubeogesh commented Jul 4, 2022

taking the increment we used for werewolf, where there's x / y where x is some constant and y is the weapon's A1 FPD, but instead reciprocated this and did y / x and set x to 7 (1H) or 9 (2H). all breakpoints match up per ubeo's findings. do note that even though whirlwind is a "sequence" skill, it still -1 at the end. the FPD in the main equation is the weapon's A1 FPD still.

Perfect!

So the formula is

{ Animation_Length * 256 / [ 256 * IAS * Animation_Length/WW_Factor ] } -1

where this new WW_Factor is 7 or 9; I wonder where the number comes from. It could be [ (Animation_Length-1)/2 ] (an arbitrary formula but it matches both values). I'll see if I can mod the animdata.d2 and test this theory.

Also, how do we get from the A1's FPD to 7 or 9 (or whatever claws uses)? Is it just a lookup table? Or is it a computation like ((A1_FPD - 1) >> 1)? (It just occurred to me that ((A1_FPD - 1) >> 1)) is half the actual length of an A1 attack with no EAIS. That's probably not coincidence.)

If I am reading this programmer-speak (sorry :) ) correctly, then I am probably talking about the same thing as you.

@ChthonVII
Copy link
Owner

So the formula is
{ Animation_Length * 256 / [ 256 * IAS * Animation_Length/WW_Factor ] } -1

Maybe... Animation_Length is on both sides of the / sign, so it drops out of the equation except insofar as the floor function generates rounding errors. There are probably lots of values that could be substituted in that would give output matching the observed values. Blizz might have used a constant here because it would make averaging weapon speeds while dual wielding simpler.

If I am reading this programmer-speak (sorry :) ) correctly, then I am probably talking about the same thing as you.
Yes, you're reading it correctly.

FYI: ">> 1" means "right shift by one." I.e., shuffle the bits one place towards less significance, dropping the least significant bit and putting a 0 in the most significant bit. It's equivalent to dividing by two and truncating any remainder.

@ubeogesh
Copy link

ubeogesh commented Jul 4, 2022

i tried modding animdata.d2 but the formula just breaks after doing so!

Playing with BAA12HT, using a Spetum (0)

Set it to 6 -> 6 FPA

Set it to 10 -> 9 FPA. With 2 more IAS improves to 8, as if i didn't mod anything (actual A1 animation gets faster!)

@Warren1001
Copy link
Author

Warren1001 commented Jul 4, 2022

that would imply that it is some constant, and the A1 isn't be used at all

edit: well, guess it doesn't matter either which way, since it's just set that way for rounding purposes, but otherwise A1 makes no impact whether its there or not. but that does confirm the whirlwind constants arent based on the A1 FPD

oh wait, are you saying setting A12HT to 6 results in 6 FPA WW with 0 EIAS?
and setting A12HT to 10 results in the same whirlwind breakpoint table as A12HT=19 (what it is by default)?

@Warren1001
Copy link
Author

Warren1001 commented Jul 4, 2022

its the action frame of A1!
barbarian 1HS, 1HT have an AF of 7, barbarian 2HT and STF have an AF of 9
edit: barbarian 2HS AF is 8, but we can assume its using the same logic as original whirlwind and all 2HS for barbarian are treated as 1HS
this could further be confirmed by testing unarmed whirlwind, which is FPD=12, AF=6 or assassin whirlwind, FPD=12, i don't have a recorded AF for assassin.

edit2: this would likely explain what you saw. chthonvii may correct me here, but from what i understand, since the AF of 2HT by default is 9, setting it to anything higher will keep the AF the same. but once you set it lower than 9, the AF changes too? this could be tested with unarmed whirlwind, you set the FPD of 2HT to 6, which i would assume set the AF to 6 too. the AF of unarmed whirlwind is already 6, so you should see FPA=6 there too.

@ubeogesh
Copy link

ubeogesh commented Jul 4, 2022

its the action frame of A1!

Eureka!

Do you have any idea where the action frames are set?

P.S. i think i figured it out, testing. It's the whatever next byte is set in the animdata after the FramesPerDirection

image

P.P.S. Yes! if I change the action frame of BAA12HT to 7, then spetum starts performing basically at the same breakpoints as the 1 handed weapons (2-20-63 item IAS).

Now what's left to confirm is that the FramesPerDirection actually matters in the function - because changing between 19 and 16 barely does anything. Which makes sense since this factor is both in the numenator and the denominator, so I'll have to find a place where rounding does the differentiation

@ubeogesh
Copy link

ubeogesh commented Jul 4, 2022

It kinda feels impossible to find the right values to test this assumption. I've found some combinations where my spreadsheet makes the difference, for example FPD10 & AF8 & 60 speed (supposed to be 4 FPA) versus FPD11 & AF8 & 60 speed (supposed to be 5 FPA) - but in both cases it is 5 FPA. It's as if D2's "rounding up" function is actually "add 1 then and round down", because FPD10 & AF8 & 60 speed variant has whole frame number at the end. I tried to find some combination of FPD\AF\Speed where one FPD would be slightly below a certain FPA (before rounding) and another above or equal

But if we try to simplify the equation by removing the FPD, we get back to those issues with with missing 1 breakpoint.

So unless you guys got better ideas, the final formula is

{ Animation_Length * 256 / { 256 * Speed_Multiplier * Animation_Length / Action_Length + 1 } }- 1

P.S. ok that thought rings a bell

We've been treating WW's delay like an animation counter, but it's not animation counter; it's a delay counter. For animations, the counter being equal to the maxcounter (i.e., maxcounter being evenly divisible by the increment) is sufficient to trigger abortion of the animation. But I don't see any reason that has to necessarily carry over to WW's delay. It may be the case that the counter must exceed the maxcounter for the delay to be considered expired.

Therefore this formula is correct and should be final?

@ubeogesh
Copy link

ubeogesh commented Jul 4, 2022

Ok, I've found a combination to test it.

Animation_Lengths = 26 and 27, Action_Length = 18, Speed_Multiplier = 1.06.

With the above formula, Animation_Length = 26 should produce 17 FPA (rounded from 16.023), Animation_Length = 27 should produce 16 FPA (rounded from 15.9828).

But actual result for both is 17.

This means that Animation_Length (aka FramesPerDirection) has no place in the formula.

Final formula should just be then (and no need to add and subtract the 1 like in my previous comment, also there's clearly a typo somewhere in it)

[ Action_Length * 256 / [ 256 * Speed_Multiplier ] ]

It passes all tests for the known breakpoints too. So simple and pretty.

@Warren1001
Copy link
Author

i plan to generate more breakpoints (extreme negatives, assassin, dual wield) sometime today or maybe tomorrow, and we can apply that formula and see if it works unanimously. looked up the AF for assassin A1 (can find the info on AB), its 6 as well.

@ChthonVII
Copy link
Owner

ChthonVII commented Jul 5, 2022

its the action frame of A1!

Eureka indeed!

this could further be confirmed by testing unarmed whirlwind, which is FPD=12, AF=6 or assassin whirlwind, FPD=12, i don't have a recorded AF for assassin.

Assassin's A1 attack for 1 or 2 claws is actionframe = 6, framesperdirection = 11, animationspeed = 208 (not 256!)

Do you have any idea where the action frames are set?

For most stuff they are in animdata.d2. The numbered columns correspond to frame numbers. A non-zero value means an action frame of some type. I believe 1 is "melee hit" and 2 is "release missile." (Frame data for sequence animations is hard-coded in the executable.)

P.S. i think i figured it out, testing. It's the whatever next byte is set in the animdata after the FramesPerDirection

You don't need to be hex editing animdata.d2. There's a tool for converting animdata.d2 to/from csv txt. There's also a newfangled python script.

chthonvii may correct me here, but from what i understand, since the AF of 2HT by default is 9, setting it to anything higher will keep the AF the same. but once you set it lower than 9, the AF changes too? this could be tested with unarmed whirlwind, you set the FPD of 2HT to 6, which i would assume set the AF to 6 too. the AF of unarmed whirlwind is already 6, so you should see FPA=6 there too.

I'm afraid I have no idea what the game does when actionframe >= FPD.

[ Action_Length * 256 / [ 256 * Speed_Multiplier ] ]

This returns us to a question from earlier: Is the underlying code calculating a delay in advance or running a counter up until it hits a limit? Everything in the game that's tied to an animation uses the counter method. But WW is a special case, and the animation appears to be independent of the hit timing, so maybe it's calculating the delay in advance. Your proposed formula has an outermost floor function, and I cannot think of a non-ridiculous way to write "run a counter up to a limit" code for which you can summarize the number of steps using a floor function. So it can only be correct if the delay is being calculated in advance.

The "run a counter up to a limit" alternative, with added complexity to generate the observed off-by-one's, would have to be something like CEILING( (256 * K) / FLOOR( increment * (K / A1actionframe) ) ) - 1 where K is some constant that's not a multiple of 7 or 9.

It's as if D2's "rounding up" function is actually "add 1 then and round down"

Didn't I say rounding up in integer/fixed-point math is fugly?
You can round up fixed-point to integer by adding the maximum possible mantissa value, then shifting right to drop the mantissa. (E.g., if you have 8 bits of mantissa (precision of 1/256), then you add 255 and then right shift by 8.) That's almost "add one, then round down."
If you're averaging exactly two integers, then you can do FLOOR((A+B+1)/2)
It's also possible that Blizz just screwed up because fixed-point math is awful, and almost no one uses it daily, and most programmers under age 40 or 50 or so have never used it at all, and "add one, then round down" is the kind of of thing that almost sounds right if you don't quite understand it.

@ubeogesh
Copy link

ubeogesh commented Jul 5, 2022

I'm afraid I have no idea what the game does when actionframe >= FPD.

Well now we know, since I've tested it. Basic attacks... well they just don't connect, lol. Looks quite funny.

Your proposed formula has an outermost floor function, and I cannot think of a non-ridiculous way to write "run a counter up to a limit" code for which you can summarize the number of steps using a floor function.

It's kind of a ceiling, actually, because I omitted the - 1 at the end

(1) { Action_Length * 256 / [ 256 * Speed_Multiplier ]  } - 1

equals

(2) [ Action_Length * 256 / [ 256 * Speed_Multiplier ] + 1 ] - 1

or simply

(3) [ Action_Length * 256 / [ 256 * Speed_Multiplier ] ] 

in all cases except when the fraction is an integer number.

And I have tested that for sure when this fraction equals an integer number, it goes up (which is what the transformation suggests).

What does this represents? It just represents that there's a strict comparison (greater than VS greater than or equal)

Using formula (1), if we calculate FPA for 2HT (Action_Length = 9) with 0 base speed and no IAS items, we get 8! But it is actually 9. And formulas (2) or (3) give out 9.

@Warren1001
Copy link
Author

Warren1001 commented Jul 5, 2022

ubeo and i have been working on assassin, the formula works for assassin just the same (with AF=6)

i've been testing whirlwind dual wielded (on assassin). so far, the results i've found indicate what blizzard said about rounding is true, as thats what im basing my math on. in all tests, both claws always both hit on the same frame. there was never an exception to this. assassin whirlwind also has the free frame at 4, then moves onto the variable FPA.

first, the assassin whirlwind EIAS breakpoint table, with a 0 WSM claw

EIAS FPA
0 7
6 6
24 5
49 4

with gloveside suwayyah and bootside runic talons:
0 EIAS: 6 FPA
18 EIAS: 6 FPA
19 EIAS: 5 FPA
48 EIAS: 5 FPA
49 EIAS: 4 FPA

at 0 EIAS, suwayyah at 7 and runic at 5 (6 FPA)
at 18 EIAS, suwayyah at 6 and runic at 5 (6 FPA)
at 19 EIAS, suwayyah at 6 and runic at 4 (5 FPA)
at 48 EIAS, suwayyah at 5 and runic at 4 (5 FPA)
at 49 EIAS, suwayyah at 4 and runic at 4 (4 FPA)

the math that blizzard describes demonstrates this: calculate each FPA independently, average them, raise to ceiling, use that FPA for both weapons, which returns the same results observed ingame

edit: im not really sure of a good case to try to disprove what blizzard says they're doing

@Warren1001
Copy link
Author

Warren1001 commented Jul 5, 2022

on another note:

Well now we know, since I've tested it. Basic attacks... well they just don't connect, lol. Looks quite funny.

dual wielded attacks in wereforms don't connect either. the first hit swings successfully, the second swing (and every subsequent swing) never succeeds. FPD=12 in offhand (much lower than FPD human forms). is the A1 (or whatever) for wereform normal attacks AF >= 12? could this explain why dual wielded attacks wont swing? it would likely have to be trying to swing with the second hand.. feral rage (main hand only) works just fine.

edit: or maybe in the complete other direction, maybe the math is causing AF to be 0?

@ChthonVII
Copy link
Owner

So... it sounds like you two have solved it:

  1. First hit is on 4th frame, following hits use an attack-speed-dependent delay.
  2. Delay is precomputed, not counter-based.
  3. Delay = Truncate((A1ActionFrame * 256) / Truncate((A1AnimationSpeed * (BaseRate + EIASCap(skillIAS + DiminshingReturns(gearIAS) - WSM))) / 100))
  4. If dual wielding, compute delay independently for each hand, and then Delay = Truncate((DelayRight + DelayLeft + 1) / 2)
  5. Two-handed swords are treated as one-handed for calculating delay, regardless of how they're actually being held.
  6. If dual wielding, every hit strikes with both weapons. (And, unless Blizz changed this from before, each weapon strikes a different target if possible.)

That sound correct?


My understanding of the situation with dual wielding in wereform is that barbs/sins have some special logic for the "normal attack using offhand weapon and S3/S4 animation" skill, which the wereform morphs simply lack, and the "A1/A2 animation with no hit" thing that we get is sort of an unplanned default behavior. In legacy D2, the offhand swing did nothing, but every other swing was fine. D2R seems to require something extra to swap back to the main hand attack, but it's never occurring. Anyway, something is missing, but I don't think it's the action frame. The buggy offhand swing appears to use A1/A2, and those have action frames. Even if it used S3 or S4 like the barb/sin manform does, those have action frames too. My guess is that the buggy offhand swing has no weapon assigned to it (not even bare hands).

@Warren1001
Copy link
Author

yes that would be correct.
something else i would like to confirm: if delay is pre-computed, does this imply a slowing factor applied mid-ww will NOT change the hit frequency during the whirlwind?
need to figure out a way to test that

@huangwj2002
Copy link

I think delay is NOT pre-computed, it's still counter-based. But the condition to end the counter is changed, from "≥” to “>”. For example, barbarian with 1hs, EIAS=0, increment=256, terminateing_value=7*256=1792. In tick 7, counter=1792, but the condition to end this counter is “>1792”, not "≥1792” as usual, so counter continues to tick 8, and the FPA is 7. Blizzard do this change to aviod FPA=3(when EIAS=75) or FPA=4(until EIAS=75).

@ChthonVII
Copy link
Owner

if delay is pre-computed, does this imply a slowing factor applied mid-ww will NOT change the hit frequency during the whirlwind?
need to figure out a way to test that

Presumably the delay would get recalculated when a speed modifying effect was applied or removed.

Anywho, if you want to test it, stick one of the sorc's retaliating cold armor skills on a zombie or something.

@Gel87kjetil
Copy link

Gel87kjetil commented Jul 7, 2022

Hello,
You have some progammer words in here which goes over my head.
Based on the EIAS tables posted somewhere i just tried the regular formula and it matched perfect as long as i used RoundUP instead of Ceiling. (I use excel, so i dont know or understand all those "trunctate" etc )

So this formula i tried and it seemed to hit every EIAS breakpoint:
1 handed wepons and 2 handed swords:
Roundup(7x256/floor(256x(100+EIAS)/100))-1
2 handed weps:
Roundup(9x256/floor(256x(100+EIAS)/100))-1

Where indeed 7 happens to be the actionframe of 1 handed wepons and 2 handed swords and 9 happens to be other 2 handers action frames.
This formula does match sin EIAS breaks as well.
Roundup(6x256/floor(208x(100+EIAS)/100))-1

@Warren1001
Copy link
Author

yup, those are the formulas we are using.

@Gel87kjetil
Copy link

Thanks,
Delay = Truncate((DelayRight + DelayLeft + 1) / 2)
So if 1 wepon hit the 4 fpa attack, and the other wepon hits the 5 fpa attack, then 4+5 = 9 / 2 = 4,5 fpa?
like 6,25 attacks per second with 1, and 5 attacks per second with the other. Or does it blend and round it and gives u a set 5 fpa output where both wepons hit simultanious?

@Warren1001
Copy link
Author

you get 5 fpa with both attacks

@Gel87kjetil
Copy link

Okay, then i understand the formula, but i dont understand why xD
So if you hit 4fpa breakpoint with both wepons, then u actually ends up at 5 as well, cause according to that formula:
Roundup or ceiling(4+4+1)/2 = 4,5 -> 5
I dont understand what that +1 has to do there?

I would just do:
Ceiling((4+4)/2)/2 = 2 fpa output attacks
25/2 = 12,5 attacks per second.

Or if 4 and 5 fpa:
Ceiling((4+5)/2)/2 = 2,5 fpa output attacks
25/2,5 = 10 attacks per second

@Warren1001
Copy link
Author

ah didn't read all of what chthonvii wrote, i am definitely not adding +1 to get my answers, probably just a misunderstanding. theres no +1

@Gel87kjetil
Copy link

Okay thanks :)

@huangwj2002
Copy link

Hello, You have some progammer words in here which goes over my head. Based on the EIAS tables posted somewhere i just tried the regular formula and it matched perfect as long as i used RoundUP instead of Ceiling. (I use excel, so i dont know or understand all those "trunctate" etc )

So this formula i tried and it seemed to hit every EIAS breakpoint: 1 handed wepons and 2 handed swords: Roundup(7x256/floor(256x(100+EIAS)/100))-1 2 handed weps: Roundup(9x256/floor(256x(100+EIAS)/100))-1

Where indeed 7 happens to be the actionframe of 1 handed wepons and 2 handed swords and 9 happens to be other 2 handers action frames. This formula does match sin EIAS breaks as well. Roundup(6x256/floor(208x(100+EIAS)/100))-1

when EIAS is 0, Roundup(7x256/floor(256x(100+EIAS)/100))-1=6, but actual FPA is 7

@ubeogesh
Copy link

ubeogesh commented Jul 7, 2022

when EIAS is 0, Roundup(7x256/floor(256x(100+EIAS)/100))-1=6, but actual FPA is 7

yes, and same with 2-handers (9 action length, 0 EIAS or 50 EIAS). To alleviate this error we had 2 theories

a) replace action length (7 or 9) in the numenator with full animation length (16 or 19); and multiply the denominator by following fraction: Animation_length/Action_length (16/7 or 19/9)

b) for whirlwind, game uses a counter rather than speed calculation, and when the check happens the comparison works as "strictly greater than" rather than "greater than or equal". This means instead of rounding up in the formula, we should add 1 and round down (explanation in #7 (comment))

both amendments produce correct results for all the known breakpoints, so i did some modding to test these theories and (a) turned out to be incorrect. See this comment: #7 (comment)

thus correct formula is this, it has passed all the tests i've thrown at it

[ Action_Length * 256 / [ Animation_Speed * Speed_Multiplier ] ] 

where in your case Action_Length = 7, Animation_Speed = 256, Speed_Multiplier = (100+EIAS)/100. [ x ] means round down

@huangwj2002
Copy link

i plan to generate more breakpoints (extreme negatives, assassin, dual wield) sometime today or maybe tomorrow, and we can apply that formula and see if it works unanimously. looked up the AF for assassin A1 (can find the info on AB), its 6 as well.

I see your calculator in site"https://warren1001.github.io/IAS_Calculator/", but i think there are some bugs with it. For example, when barb with 1hs weapon and EIAS=-76, increment=256+rounddown(256*(-76)/100,0)=256+rounddown(-194.56)=62, and then FPA=rounddown(256*7/62,0)=28. But in your calculator the result is 29. There are similar bugs with bb(2hw) and asn, too.

@Warren1001
Copy link
Author

i hadn't bothered to use ubeo's latest formula, mine is different. ill change it to his since you found numbers that are off

@Warren1001
Copy link
Author

Warren1001 commented Jul 11, 2022

The statlist swap bug still exists and impacts ALL dual wielded sequence skills (Whirlwind, Frenzy, Double Swing, Double Throw, Dragon Claw, Fists of Fire, Blades of Ice, and Claws of Thunder). This means with attack speeds averaged (either by averaging EIAS or by averaging attack frames in Whirlwind's case) the weapon with the highest chance to hit should ALWAYS be glove-side (primary) for these skills.

Correction: statlist swap bug actually does not exist (fixed I suppose), instead I made a bug report on what's happening: https://us.forums.blizzard.com/en/d2r/t/dual-wielded-sequence-skills-only-use-primary-hands-chance-to-hit/137434

@Warren1001
Copy link
Author

i plan to generate more breakpoints (extreme negatives, assassin, dual wield) sometime today or maybe tomorrow, and we can apply that formula and see if it works unanimously. looked up the AF for assassin A1 (can find the info on AB), its 6 as well.

I see your calculator in site"https://warren1001.github.io/IAS_Calculator/", but i think there are some bugs with it. For example, when barb with 1hs weapon and EIAS=-76, increment=256+rounddown(256*(-76)/100,0)=256+rounddown(-194.56)=62, and then FPA=rounddown(256*7/62,0)=28. But in your calculator the result is 29. There are similar bugs with bb(2hw) and asn, too.

bit of a necro but following up on this, i realize i misunderstood him originally. he's using the alternative formula for wereforms where the denominator is calculated by trun(Animation_Speed + trun(Animation_Speed * EIAS / 100), but we decided on the human denominator calculated by trun(Animation_Speed * (100 + EIAS) / 100). i'm going with the assumption that ubeo's formula is correct, as i don't feel like testing huang's noted breakpoint.

and something else to note for future readers, ubeo is using floor to truncate, but (iirc) chthonvii and i had concluded that d2r truncates to 0 instead of negative infinity like it was in LOD. in human formulas, it doesn't matter, as the formula for humans don't get into negative values and thus flooring or truncating to 0 have the same value. anywhere else this would be incorrect (wereform formula for example) where negative intermediate values are possible.

i plan to open a new issue in the next coming days testing the changes they made to assassin with claws in the 2.5 ptr.

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

No branches or pull requests

6 participants