Miscellaneous Forums > Scripting and Reverse Engineering

[FF8] Monster stats and level formulas

<< < (2/3) > >>

JWP:
looking at the code:

--- Code: ---0048BD33  |.  8A57 1B       MOV DL,BYTE PTR DS:[EDI+1B] //dl = d
0048BD36  |.  8886 CB7BD201 MOV BYTE PTR DS:[ESI+1D27BCB],AL //line not used in calculation
0048BD3C  |.  33C0          XOR EAX,EAX //eax = 0
0048BD3E  |.  33C9          XOR ECX,ECX //ecx = 0
0048BD40  |.  8D1492        LEA EDX,[EDX*4+EDX] //edx = d*5
0048BD43  |.  8A47 18       MOV AL,BYTE PTR DS:[EDI+18] al = a
0048BD46  |.  8A8E CC7BD201 MOV CL,BYTE PTR DS:[ESI+1D27BCC] //cl = lvl
0048BD4C  |.  8D2C92        LEA EBP,[EDX*4+EDX] //ebp = d*25
0048BD4F  |.  33D2          XOR EDX,EDX //edx = 0
0048BD51  |.  8A57 19       MOV DL,BYTE PTR DS:[EDI+19] //dl = b
0048BD54  |.  8D14AA        LEA EDX,[EBP*4+EDX] //edx = 100*d + b
0048BD57  |.  8D2C92        LEA EBP,[EDX*4+EDX] //ebp = 500*d + 5*b
0048BD5A  |.  33D2          XOR EDX,EDX //edx = 0
0048BD5C  |.  8A57 1A       MOV DL,BYTE PTR DS:[EDI+1A] //dl = c
0048BD5F  |.  8D1492        LEA EDX,[EDX*4+EDX] //edx = c*5
0048BD62  |.  8D1492        LEA EDX,[EDX*4+EDX] //edx = c*25
0048BD65  |.  8D1490        LEA EDX,[EDX*4+EAX] //edx = c*100 + a
0048BD68  |.  0FAFC1        IMUL EAX,ECX //eax = a*lvl
0048BD6B  |.  0FAFC1        IMUL EAX,ECX //eax = a*lvl*lvl
0048BD6E  |.  0FAFD1        IMUL EDX,ECX //edx = (c*100 + a)*lvl
0048BD71  |.  8BC8          MOV ECX,EAX //ecx = a*lvl*lvl
0048BD73  |.  B8 67666666   MOV EAX,66666667 //eax = 0x66666667
0048BD78  |.  8D2C6A        LEA EBP,[EBP*2+EDX] //ebp = 1000*d + 10*b + (c*100 + a)*lvl
0048BD7B  |.  F7E9          IMUL ECX //edx:eax = (a*lvl*lvl)*0x66666667
0048BD7D  |.  C1FA 03       SAR EDX,3 //edx = floor((a*lvl*lvl)*0x66666667/2^35)
0048BD80  |.  8BC2          MOV EAX,EDX //eax = floor((a*lvl*lvl)*0x66666667/2^35)
0048BD82  |.  03D5          ADD EDX,EBP //edx = floor((a*lvl*lvl)*0x66666667/2^35) + 1000*d + 10*b + (c*100 + a)*lvl
0048BD84  |.  C1E8 1F       SHR EAX,1F //add 1 if the result was negative (this isn't going to happen, it's probably due to them putting the result in a signed int)

--- End code ---

Think this gives:
HP = floor(a*lvl*lvl/20) + 1000*d + 10*b + (c*100 + a)*lvl
or if you're using integers:
(a*lvl*lvl)/20 + 1000*d + 10*b + (c*100 + a)*lvl

This looks like it matches with what you have and also the formula I gave several years ago in this post: http://forums.qhimm.com/index.php?topic=6961.msg86799#msg86799

--- Quote ---BYTE HP[4]; //HP = (HP[0]*x*x)/20 + (HP[0] + 100*HP[2])*x + 10*HP[1] + 1000*HP[3], where x = monster lvl
--- End quote ---

You mentioned MAG twice in your post, did you mean VIT/SPR/SPD/EVA?

myst6re:

--- Quote from: JWP on 2016-04-17 23:52:49 ---You mentioned MAG twice in your post, did you mean VIT/SPR/SPD/EVA?

--- End quote ---

Yes, sorry for the confusion, and I fixed this on the wiki page yesterday.

So for the PC version, we're sure that is the right formula :) . It would be good to know if the PS version shares the same formulas.

JWP:
Ah nice  :), I should probably see about getting a wiki account rather than just dumping info all over the forum  :-P.
I'm curious as to what project you're using the formulas for :-P.
I'd guess that the original PS game was written in C/C++ and they copied functions like that for the PC version but I could be wrong.

I'm tempted to take a look at the PS version to see if some of the data structures in memory are similar and it might be easier to find information with snapshotting.
In addition to this, seeing the same routines in 2 different ASM implementations might help with reverse engineering.
PSX looks like it has a pretty good R3000 debugger to do that sort of thing.

While looking through the forums for FF8 posts (to see if there was anything I didn't know), I came across this old post: http://forums.qhimm.com/index.php?topic=3723.msg51764#msg51764
It seems that people have looked through the section of code before - although I think their interpretation is slightly off since there aren't enough brackets - divisions end up taking priority, which causes different results when using integer division:

--- Code: ---4*4/3 = 4 * floor(4/3) = 4
(4*4)/3 = floor(16/3) = 5

--- End code ---
Note the division order doesn't actually make a difference due to the nested division property mentioned below:

--- Code: ---floor(floor(x/y)/z) = floor(x/(y*z)) = floor(x/(z*y)) = floor(floor(x/z)/y)

--- End code ---
So many things just seem to get lost in time on this forum :(.

btw, I noticed that the STR/MAG formula can be simplified slightly due to this property:
https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#Nested_divisions
it might be possible to simplify it further but I'm not too familiar with that sort of mathematics.

--- Code: ---floor((floor(level * a/10) + floor(level / b) - floor(level * level / d / 2) + c)/4)

--- End code ---

myst6re:

--- Quote from: JWP on 2016-04-19 10:23:49 ---I'm curious as to what project you're using the formulas for :-P.

--- End quote ---

A french website that will become the FF8 reference guide.

I removed nested floors, it works well :)
For now, Iron Giant is the only monster I know with errors, according to the Ultimania, maybe the error isn't on our side...

--- Code: ---Values : 30, 0, 6, 0
Level   Ultimania   Known formula
LV1     663 HP      631 HP
LV10    6900 HP     6450 HP
LV20    14400 HP    13200 HP
LV30    22500 HP    20250 HP
LV40    31200 HP    27600 HP
LV50    40500 HP    35250 HP
LV60    50400 HP    43200 HP
LV70    60900 HP    51450 HP
LV80    72000 HP    60000 HP
LV90    83700 HP    68850 HP
LV100   96000 HP    78000 HP
--- End code ---

There is nothing special about Iron Giant HPs on IA scripts.

JWP:
I forced a battle against a lvl 20 Iron Giant by using encounter code 248 (8420 when entering it) in the debug room and memory editing the level just after it loaded using a memory breakpoint.
It had 13200 HP so either it's an issue with the guide or the guide is based on a different version of the game.