>2) I've assumed that Blizzard overloaded multiplication and
>division to do their 8 bit fixed point arithmetic, but was
>wondering exactly how they did it.No idea if they actually made some suchthings or if they just multiply some values and handles them at larger numbers.
>This would show up as an
>8 bit left/right shift before/after each multiplication or
>division in the assembly code (when dealing with 8 bit fixed
>point values).
That doesn't happen, the values are stored left shifted (for example mana and life) and then the normal calcs are performed on those values. You will see the shift prior for any value that will be manipulating the life or mana. The same applies for damage that is at some state shifted left by 8 too for example.
> I was wondering if anyone had noticed it and
>could tell me the exact order Blizzard used for each
>operation (there are several "equivalent" ways of doing it
>that give slightly different rounded results--I've been
>assuming they used the "right" way, but...).
Well, the values are stored and saved shifted and thus treat it like any other value, just with, for example the extra 8 bits of precision.
Almost all values in the game (at least game play wise, no idea about graphics and such) are integer ones. There are some (very few) places that use floating point calcs, usually some intermidiate calcs where the value is then converted back to integer, otherwise, all calcs can for practical purposes be considered as integer ones. How it actually ends up in assembler is up to the compiler, in this case MS Visual Studio 6. So if you are interested in the exact nature of for example a /3, you may if you have acces to it, check how it ends up compiled. Usually such divisions will be compiled into a multiplication by a huge 31 bit value (which ends up in eax/edx) and then some sort (if needed) right shift of the edx register (whic was explained in another reply).
In addition for keeping some stats at higher precision (like life and mana), some other values will also be stored at for example 10 extra bits precision. If you look at the treasure class file, you will see values that modify the chance for an item to be unique and such as fractions of 1024. Basically the game will thus multiply by this value and then divide by 1024 (often only at the end after other modifications are done too), thus resulting in higher precision and avoiding round down issues for low values. This happened for example in earlier versions of the game where the chance being modified could be in the order of 1 in 3 and then the 3 was modified by some value, for example cut in half, resulting in a value of 1 due to truncation in integer calcs which caused "jumps" in the resulting item drops.
The same applies for the frame counter which you seem to be interested in. It also use 8 extra bits of precision. Hence if an animation will take 8 frames to display, it is stored as 8*256. The frame counter which counts current frame will similary be updated by 1*256 each frame. Modifiers to the speed the frames are shown will simply affect this frame counter allready multiplied by 256 (it is stored multiplied by 256 as well). So, if you have a 10% increase in frame speed (like faster attack), the game will take 1*256 and multiply it by 10 and then dividing it by 100 (resulting in 25). This value is then added to the counter (which is 1*256) for a final frame counter value of 281 and so on. The exact way it ends up might vary some, probably due to the compiler working.
>3) How are percentage values actually stored in the code?
As an integer value. Especially since only some stats and values are stored with extra bits of precision this is usefull. The game then typically multiply by this integer value and divide by 100 (through the way I described above.
>I'm not interested in the MPQ files (I know they're stored
>as decimal percentages). Given the use of 8 bit fixed point
>arithmetic, I can see three ways. a) a simple integer with
>the percentage (which is converted to a fraction before
>being used in calculations).
Not really, as I said, the game handle it (regardless of if the value being manipulated is using some sort of extra bits of precision) by muliplying the value by it and then dividing by 100.
> b) a fixed point value with
>the decimal percentage (ie the percentage * 256). c) the
>actual fixed point value corresponding to the percentage.
>There is weak evidence from the werespeeds that it might be
>c).
It really depend on how exactly they wrote the formula in the source and how they emplyed the parentesis and such. As I said above though, the frame counter will bea value allready multiplied by 256.
As for how the frame counter is then used, well in the following way. The game keep the end frame number (if it is 8, it stores it as 8*256), it then calculate the frame counter which is 256 as a base value which is then modified by various effects (typically some sort of summed +% value that is multiplied with it and divided by 100) resulting in a modified frame counter. Each frame, the frame counter is then updated by this value, so if it was 281 from our example above, it would be updated as 281, 562, 843 and so on. WHen it reaches (or goes above) 8*256 (it was 8 frames), it has reached the end. Since the game really never calculate the actual number of frames something will take but uses this formula, one end up with some quite complex formulas (as far as rounding and such is concerned) if one want to write a formula that calculate the actual number of frames it will take.
This method has the nice effect of to be able to know which picture of the animation to show, one simply takes the currnt frame counter and divide by 256 and then has the animation pict to show, this works both for faster and slower animation speeds than default where the game will skip or show the same pic multiple times.
Does this answer your questions?
> Note that (using integer arithmetic) y = x% * 256 / 100
>+ 1 done in 8 bit fixed point gives a good approximation
>(and converts back correctly using y * 100 / 256). The only
>really odd case is that 0 converts to 1, but I suspect that
>this is just forced to 0 upon conversion. I would suspect
>that the conversion is done when reading in the MPQ files
>(easy to do and the cost is irrelevant)--the back conversion
>would then only be for display purposes.