ChthonVII / d2r_24ptr2_wereform_calculator

Wereform IAS Calculator for Diablo 2 Resurrected 2.4 PTR2
GNU General Public License v3.0
4 stars 0 forks source link

Whirlwind is being adjusted #7

Open Warren1001 opened 2 years ago

Warren1001 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 = [256CharFrames/[(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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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:

Summary:

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

ubeogesh commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

ubeogesh commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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:

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

yup, those are the formulas we are using.

Gel87kjetil commented 2 years ago

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 commented 2 years ago

you get 5 fpa with both attacks

Gel87kjetil commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

Okay thanks :)

huangwj2002 commented 2 years ago

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 commented 2 years ago

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 https://github.com/ChthonVII/d2r_24ptr2_wereform_calculator/issues/7#issuecomment-1174746642)

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: https://github.com/ChthonVII/d2r_24ptr2_wereform_calculator/issues/7#issuecomment-1174402419

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 commented 1 year ago

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(2567/62,0)=28. But in your calculator the result is 29. There are similar bugs with bb(2hw) and asn, too.

Warren1001 commented 1 year ago

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