151
Gameplay / Re: [FFVII STEAM] Possible to disable exp. for out of party characters?
« on: 2016-05-18 15:37:17 »
Nice work NFITC1! Saves me having to reinstall FF7 .
This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.
SHR REG,1
or
SAR REG,1
XOR REG,REG
A question about the weapon data: the strength bonus is the increase towards a character's strength stat once the weapon is bought, right? That's what pretty much all websites list as the weapon's attack power. However, here seems to be an additional attack power byte which is the same for every single weapon (just looked in the kernel, and all weapons have a value of 20 for their attack power). What is this byte used for? Is it an additional but invisible strength increase? Or does it serve a different purpose in damage calculation? I'm just confused because all guides around the web always refer to the strength bonus when talking about a weapon's attack power.
JWP, do you have wiki account?I'm afraid not. I'm not really sure how I would go about getting one.
0x0006--0x00B58050--0x00B58080--Leviathan Summon (Tsunami)
loads "mag005_b.00" and "mag005_b.01"0x008D--0x0061DE50--0x0061DE70--Renzokuken - 5 Hits
loads "mag140-158-159-258-331-332.tim"0x0074--0x006C3560--0x006C3550--Quezacotl Summon (Thunder Storm)
loads "mag115.tim"2. Damage formulas for Kamikaze and Darkside abilities
CPU Disasm
Address Hex dump Command Comments
00492D6C |. 8B81 2C7BD201 MOV EAX,DWORD PTR DS:[ECX+1D27B2C] ; EAX = caster max HP
00492D72 |. 8D0480 LEA EAX,[EAX*4+EAX] ; EAX = EAX*5
Some sites say that the damage multiplier is 6 for kamikaze, so either it's been changed or the code for critting is elsewhere.CPU Disasm
Address Hex dump Command Comments
00491069 |> \8D3476 LEA ESI,[ESI*2+ESI] ; ESI = ESI * 3 - darkside multiplier
3. Angel Wing damage multiplier
CPU Disasm
Address Hex dump Command Comments
00491085 |. 8D34B6 LEA ESI,[ESI*4+ESI] ; ESI = ESI * 5 - angel wing multiplier
6. Changing character base stats and starting level, also giving Squall, Zell and Quistis some default spells at the beginning of the game
****************************************
* Section 2 - Magic Data *
****************************************
2 bytes - offset to spell name
2 bytes - offset to spell description
2 byte - magic id - decides what animation to play
2 bytes - unknown
1 byte - spell power (basically relates to how much damage it does)
1 byte - unknown
1 byte - default target
1 byte - unknown
1 byte - draw resist (how hard it is to draw - higher = harder)
1 byte - hit count (works with meteor animation, not sure about others)
1 byte - element
0x01 - Fire
0x02 - Ice
0x04 - Thunder
0x08 - Earth
0x10 - Poison
0x20 - Wind
0x40 - Water
0x80 - Holy
1 byte - unknown
1 byte - status
0x01 - sleep
0x02 - haste
0x04 - slow
0x08 - stop
0x10 - regen
0x20 - protect
0x40 - shell
0x80 - reflect
1 byte - status
0x01 - aura
0x02 - curse
0x04 - doom
0x08 - invincible
0x10 - petrifying
0x20 - float
0x40 - confuse
0x80 - drain
1 byte - status
0x01 - eject
0x02 - double
0x04 - triple
0x08 - defend
0x10 - ???
0x20 - ???
0x40 - ???
0x80 - ???
1 byte - status
0x01 - vit0
0x02 - ???
Last Edit: Today at 16:40:45
0x04 - ???
0x08 - ???
0x10 - ???
0x20 - ???
0x40 - ???
0x80 - ???
1 byte - status
0x01 - death
0x02 - poison
0x04 - petrify
0x08 - blind
0x10 - silence
0x20 - berserk
0x40 - zombie
0x80 - ???
2 bytes - unknown
1 byte - HP junction value
1 byte - str junction value
1 byte - vit junction value
1 byte - mag junction value
1 byte - spr junction value
1 byte - spd junction value
1 byte - eva junction value
1 byte - hit junction value
1 byte - luck junction value
1 byte - elemental attack enabler*
1 byte - elemental attack value
1 byte - elemental defense enabler*
1 byte - elemental defense value
1 byte - status attack value
1 byte - status defense value
2 bytes - status attack enabler**
2 bytes - status defense enabler**
18 bytes - unknown
****************************************
* Section 3 - GF Data *
****************************************
****************************************
* Section 4 - Enemy Attacks *
****************************************
struct EnemyAttack {
WORD name_offset;
WORD magic_id;
BYTE unk[2];
BYTE attack_type;
BYTE attack_power;
BYTE attack_flags;
BYTE unk;
BYTE element;
BYTE unk;
BYTE status_attack;
BYTE unk;
WORD status_0; //statuses 0-7 (only 8 bits are used)
DWORD status_1; //statuses 8-31
}
****************************************
* Section 5 - Weapon Data *
****************************************
struct Weapon {
WORD name_offset;
BYTE renzokuken_finishers; //0x01 = Rough Divide, 0x02 = Fated Circle, 0x04 = Blasting Zone, 0x08 = Lion Heart
BYTE unk;
BYTE character_id;
BYTE attack_type;
BYTE attack_power;
BYTE hit_bonus;
BYTE str_bonus;
BYTE weapon_tier;
BYTE unk[2];
}
****************************************
* Section 6 - Renzokuken Finishers *
****************************************
struct Renzokuken_Finisher {
WORD name_offset;
WORD description_offset;
WORD magic_id;
BYTE attack_type;
BYTE unk;
BYTE attack_power;
BYTE unk;
BYTE target_info;
BYTE unk;
BYTE hit_count;
BYTE unk[11];
}
****************************************
* Section 7 - Character Data *
****************************************
struct Character {
WORD name_offset;
BYTE crisis_level_hp_multiplier;
BYTE gender; //0x00 for male, 0x01 for female
BYTE limit_break_id;
BYTE limit_break_param; //used for the power of each renzokuken hit before finisher - see address 0x490FCE
BYTE exp_modifier[2]
BYTE HP[4]
BYTE str[4];
BYTE vit[4];
BYTE mag[4];
BYTE spr[4];
BYTE spd[4];
BYTE luck[4];
}
Character order is: Squall, Zell, Irvine, Quistis, Rinoa, Selphie, Seifer, Edea, Laguna, Kiros, Ward.((lvl-1)^2*exp_b)/256 + (lvl-1)*exp_a*10
HP = ((stat_magic_J_value*magic_count + stat_bonus + lvl*a - (10*lvl^2)/b +c)*percent_modifier)/100
stat_magic_J_value = The junction value of the junctioned magic - this is located with the magic in section 2 of kernel.bin
magic_count = The amount of the junctioned magic that the character holds
stat_bonus = permanent bonus gained from XBonus skills and Devour
percent_modifier = is 100 + any %bonuses added, so if you had stat +20% and stat +60% equipped, it would be 180
a, b, c and d are the bytes in the example below
Note: d appears to be unused in the HP formulastat = ((X + (stat_magic_J_value*magic_count)/100 + stat_bonus + ((lvl*a)/10 + lvl/b - (lvl*lvl)/d/2 + c)/4)*percent_modifier)/100
X is currently unknown - probably weapon modifier
stat = ((X + (stat_magic_J_value*magic_count)/100 + stat_bonus + lvl/b - lvl/d + lvl*a +c)*percent_modifier)/100
X is currently unknown - probably 0
eva = (((stat_magic_J_value*magic_count)/100 + spd/4)*percent_modifier)/100
note that this is for calculating the eva stat in memory, when it is presented, it appears to be a percentage of 256, i.e. (eva*100)/256Bytes for Squall:
a b c d
HP: 2C FF B3 00
Str: 1E 05 02 26
Vit: 1A 05 05 29
Mag: 1C 04 06 27
Spr: 18 05 05 29
Spd: 00 05 14 1E
Luck: 00 07 0F 0E
Eva: calculated from speed
Hit: based entirely on weapon and Hit-J
HP: 4187
Str: 47 (+11 from starting weapon)
Vit: 41
Mag: 45
Spr: 36
Spd: 37
Luck: 22
Eva: 3%
Hit: 0% (+255% from starting weapon)
BYTE mentalRes[40]; //0x1D27BA0
offset 0x20 of that array seems to be checked when using meltdown (i.e. vit0).from: 0x8BEE8: B90A 0A0A 0A
to: 0x8BEE8: E9A8 0000 00
from: 0x8BF95: 9090 9090 9090 9090
to: 0x8BF95: 8A87 7B01 0000 EB77
from: 0x8C014: 9090 9090 9090 9090 9090 90
to: 0x8C014: 8886 C07B D201 E912 0100 00
from: 0x8C131: 9090 9090 9090 9090 9090
to: 0x8C131: B90A 0A0A 0AE9 B2FD FFFF
0x48BEE8: JMP 0048BF95 ; jump to unused code section
...
0x48BF95: MOV AL, BYTE PTR DS:[EDI+17B] ; load 20th byte into AL (EDI points to the start of section 7 of a DAT file)
0x48BF9B: JMP SHORT 0048C014 ; jump to unused code section
...
0x48C014: MOV BYTE PTR DS:[ESI+1D27BC0],AL ; move 20th byte into the monster data in memory at the vit0 resistance point (ESI is 208 * monster_id)
0x48C01A: JMP 0048C131 ; jump to unused code section
...
0x48C131: MOV ECX,0A0A0A0A ; do overwritten instruction
0x48C136: JMP 0048BEED ; jump back to where we started
EDIT: was accidentally using the wrong byte, should be fixed now... it looks like that byte isn't usually loaded into memory at all - I screwed my numbering up when converting from hex to dec and fixed it in my previous post.0x01 - Fire - 00000001
0x02 - Ice - 00000010
0x04 - Thunder - 00000100
0x08 - Earth - 00001000
0x10 - Poison - 00010000
0x20 - Wind - 00100000
0x40 - Water - 01000000
0x80 - Holy - 10000000
To get combinations, you'd just binary or the components together. e.g. to get fire + poison + wind:Binary Hex Element
00000001 01 Fire
00010000 10 Poison
00100000 20 Wind
Result:
00110001 31 Fire | Poison | Wind
CPU Disasm
Address Hex dump Command Comments
00491C62 |> \E8 B9D3FFFF CALL 0048F020 ; [FF8_EN.0048F020, case 0 of switch FF8_EN.491C17 - this call is to get_random_number
00491C67 |. 25 FF000000 AND EAX,000000FF
00491C6C |. B9 21000000 MOV ECX,21
00491C71 |. 99 CDQ
00491C72 |. F7F9 IDIV ECX
00491C74 |. 8BCA MOV ECX,EDX
00491C76 |. 8D145B LEA EDX,[EBX*2+EBX]
00491C79 |. 81C1 F0000000 ADD ECX,0F0
00491C7F |. 8D0493 LEA EAX,[EDX*4+EBX]
00491C82 |. 33D2 XOR EDX,EDX
00491C84 |. C1E0 04 SHL EAX,4
00491C87 |. 8A90 CF7BD201 MOV DL,BYTE PTR DS:[EAX+1D27BCF] ;get mag of caster
00491C8D |. 8BC2 MOV EAX,EDX ;EAX = mag of caster
00491C8F |. BA 09010000 MOV EDX,109 ;EDX = 265
00491C94 |. 03C5 ADD EAX,EBP ;EAX = mag + spell_power
00491C96 |. 2BD7 SUB EDX,EDI ;EDX = 265 - target_spr
00491C98 |. 0FAFC2 IMUL EAX,EDX ;EAX = (mag + spell_power) * (265 - target_spr)
00491C9B |. 99 CDQ ;/*
00491C9C |. 83E2 03 AND EDX,00000003 ;correction for signed division with SAR
00491C9F |. 03C2 ADD EAX,EDX ;*/
00491CA1 |. C1F8 02 SAR EAX,2 ;EAX = ((mag + spell_power) * (265 - target_spr))/4
00491CA4 |. 0FAFC5 IMUL EAX,EBP ;EAX = (((mag + spell_power) * (265 - target_spr))/4) * spell_power
00491CA7 |. 99 CDQ ;/*
00491CA8 |. 81E2 FF000000 AND EDX,000000FF ;correction for signed division with SAR
00491CAE |. 03C2 ADD EAX,EDX ;*/
00491CB0 |. C1F8 08 SAR EAX,8 ;EAX = ((((mag + spell_power) * (265 - target_spr))/4) * spell_power)/256
00491CB3 |. 0FAFC1 IMUL EAX,ECX
00491CB6 |. 99 CDQ
00491CB7 |. 81E2 FF000000 AND EDX,000000FF
00491CBD |. 03C2 ADD EAX,EDX
00491CBF |. 8BF0 MOV ESI,EAX
00491CC1 |. C1FE 08 SAR ESI,8
00491CC4 |. 83FB 03 CMP EBX,3
00491CC7 |. 7C 02 JL SHORT 00491CCB
00491CC9 |. D1FE SAR ESI,1
00491CCB |> 8B4C24 10 MOV ECX,DWORD PTR SS:[LOCAL.2]
00491CCF |> A0 0E8ED201 MOV AL,BYTE PTR DS:[1D28E0E]
00491CD4 |. 24 03 AND AL,03
00491CD6 |. 3C 01 CMP AL,1
00491CD8 |. 75 16 JNE SHORT 00491CF0
00491CDA |. 85F6 TEST ESI,ESI
00491CDC |. 74 12 JE SHORT 00491CF0
00491CDE |. F681 187BD201 TEST BYTE PTR DS:[ECX+1D27B18],40
00491CE5 |. 74 09 JE SHORT 00491CF0
00491CE7 |. 800D DD7AD201 OR BYTE PTR DS:[1D27ADD],20
00491CEE |. D1FE SAR ESI,1
00491CF0 |> F781 187BD201 TEST DWORD PTR DS:[ECX+1D27B18],00080000
00491CFA |. 74 02 JE SHORT 00491CFE
00491CFC |. D1FE SAR ESI,1
00491CFE |> A1 44A2D201 MOV EAX,DWORD PTR DS:[1D2A244]
00491D03 |. 84C0 TEST AL,AL
00491D05 |. 0F84 11020000 JE 00491F1C
00491D0B |. 8D4C24 14 LEA ECX,[LOCAL.1]
00491D0F |. 25 FF000000 AND EAX,000000FF
00491D14 |. 51 PUSH ECX ; /Arg2 => OFFSET LOCAL.1
00491D15 |. 50 PUSH EAX ; |Arg1 => 0
00491D16 |. E8 35D2FFFF CALL 0048EF50 ; \FF8_EN.0048EF50
00491D1B |. 8B5424 18 MOV EDX,DWORD PTR SS:[LOCAL.2]
00491D1F |. 8B4424 1C MOV EAX,DWORD PTR SS:[LOCAL.1]
00491D23 |. 83C4 08 ADD ESP,8
00491D26 |. 25 FF000000 AND EAX,000000FF
00491D2B |. F682 907BD201 TEST BYTE PTR DS:[EDX+1D27B90],40
00491D32 |. 0F84 AC010000 JE 00491EE4
00491D38 |. 83F8 07 CMP EAX,7
00491D3B |. 0F85 A3010000 JNE 00491EE4
00491D41 |. B8 BC020000 MOV EAX,2BC
00491D46 |. E9 B0010000 JMP 00491EFB
struct Character
{
BYTE **infoSection; //0x1D27B10 - points to section 7 of a loaded dat file - NULL for SeeDs
BYTE **aiSection; //0x1D27B14 - NULL for SeeDs
DWORD status1D27B18; //0x1D27B18 0x27
BYTE status; //0x1D27B1C - MSB - reflect / shell / protect / regen / stop / slow / haste / sleep - LSB
BYTE unk1[3]; //0x1D27B1D
DWORD ATBmax; //0x1D27B20
DWORD ATBcur; //0x1D27B24
DWORD currentHP; //0x1D27B28
DWORD maxHP; //0x1D27B2C
BYTE unk2_0[4]; //0x1D27B30
DWORD localVars[8]; //0x1D27B34 - DC to E3 - base address used is 0x1D277C4
WORD elemRes[8]; //0x1D27B54 - 500 = very weak, 800 = normal, 1000 = fully absorb - 0. Fire, 1. Ice, 2. Thunder, 3. Earth, 4. Poison, 5. Wind, 6. Water, 7. Holy
WORD timers[16]; //0x1D27B64 - status timers
DWORD unkdword1D27B84; //0x1D27B84
DWORD unkdword1D27B88; //0x1D27B88
DWORD unkdword1D27B8C; //0x1D27B8C - edited by function 0x48C5C0
WORD status1; //0x1D27B90 MSB - ? / zombie / berserk / silence / blind / petrify / ? / death - LSB
WORD unkword1D27B92; //0x1D27B92
WORD unkword1D27B94; //0x1D27B94 ????? 0x2E, 0x29, 0x06,
WORD unkword1D27B96; //0x1D27B96 ?????
BYTE lastAttacker; //0x1D27B98 - used in opcode 0x0E case 0xCB
BYTE unk5_0[7]; //0x1D27B99
BYTE mentalRes[40]; //0x1D27BA0 - Mental resistances - 0. Death, 1. Poison, 2. Petrify, 3. Darkness, 4. Silence, 5. Berserk, 6. Zombie, 8. Sleep, 9. Haste, 10. Slow, 11. Stop, 12. Regen, 15. Reflect, 18. Doom, 20. Petrifying, 21. Float, 22. Confuse, 23. Drain, 24. Expulsion, rest are always 100 for monsters
BYTE unkbyte1D27BC8; //0x1D27BC8 used in case 0x2A - edited by function 0x48C5C0
BYTE unkbyte1D27BC9; //0x1D27BC9 - edited by function 0x48C5C0
BYTE unkbyte1D27BCA; //0x1D27BCA
BYTE unkbyte1D27BCB; //0x1D27BCB - edited by function 0x48C5C0
BYTE lvl; //0x1D27BCC
BYTE str; //0x1D27BCD
BYTE vit; //0x1D27BCE
BYTE mag; //0x1D27BCF
BYTE spr; //0x1D27BD0
BYTE spd; //0x1D27BD1
BYTE luck; //0x1D27BD2
BYTE eva; //0x1D27BD3
BYTE hit; //0x1D27BD4
BYTE unk7[5]; //0x1D27BD5
BYTE crisisLevel; //0x1D27BDA
BYTE unkbyte1D27BDB; //0x1D27BDB
WORD unkword1D27BDC; //0x1D27BDC
BYTE unk8[2]; //0x1D27BDE
};
DWORD * const vars = (DWORD*)0x1D28D98; //- 60 to 67 - base address used is 0x1D28C18 - array of size 8
int(*count_valid_targets)() = (int(*)())0x4860A0; //0xFF if no valid targets - counts SeeDs that are not petrified or dead
int(*getStat)(int level, BYTE *datfile, int stat) = (int(*)(int, BYTE*, int))0x48C3F0; //gets str, vit, mag, spr, spd, eva from dat file
BYTE(*get_random_number)() = (BYTE(*)())0x48F020;
EDIT: see section 2 of http://www.gamefaqs.com/ps/197343-final-fantasy-viii/faqs/58936 for how the RNG works if (init_done && (character_info[id].status1 & 0x20) != 0) { //if berserk
if (count_valid_targets() == 0xFF) {
target = 0; //set no target
next_ai_byte_1 = 0; //make sure to skip AI code on next loop
//00487E6B | .BE 1DA2D201 MOV ESI, OFFSET 01D2A21D
goto lbl489804; //jump to attack code in switch?
}
BYTE randomTarget;
do {
randomTarget = get_random_number() % 3;
} while (character_info[randomTarget].status1 & 0x01 != 0); //check target isn't dead
next_ai_byte_1 = 0; //make sure to skip AI code on next loop
target = 1 << randomTarget;
//00487E6B | .BE 1DA2D201 MOV ESI, OFFSET 01D2A21D
goto lbl489804; //jump to attack code in switch?
}
4*4/3 = 4 * floor(4/3) = 4
(4*4)/3 = floor(16/3) = 5
Note the division order doesn't actually make a difference due to the nested division property mentioned below:floor(floor(x/y)/z) = floor(x/(y*z)) = floor(x/(z*y)) = floor(floor(x/z)/y)
So many things just seem to get lost in time on this forum .floor((floor(level * a/10) + floor(level / b) - floor(level * level / d / 2) + c)/4)
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)
0048BD87 |. 03C2 ADD EAX,EDX
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
0048C447 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ARG.1] ; default case of switch FF8_EN.48C43D
0048C44B |. 33C9 XOR ECX,ECX
0048C44D |. 8A4E 03 MOV CL,BYTE PTR DS:[ESI+3]
0048C450 |. 8BC7 MOV EAX,EDI
0048C452 |. 99 CDQ
0048C453 |. F7F9 IDIV ECX
0048C455 |. 33DB XOR EBX,EBX
0048C457 |. 8A5E 01 MOV BL,BYTE PTR DS:[ESI+1]
0048C45A |. 8BC8 MOV ECX,EAX
0048C45C |. 8BC7 MOV EAX,EDI
0048C45E |. 99 CDQ
0048C45F |. F7FB IDIV EBX
0048C461 |. 33D2 XOR EDX,EDX
0048C463 |. 8A16 MOV DL,BYTE PTR DS:[ESI]
0048C465 |. 0FAFD7 IMUL EDX,EDI
0048C468 |. 2BC1 SUB EAX,ECX
0048C46A |. 33C9 XOR ECX,ECX
0048C46C |. 8A4E 02 MOV CL,BYTE PTR DS:[ESI+2]
0048C46F |. 03C2 ADD EAX,EDX
0048C471 |. 03C1 ADD EAX,ECX
0048C480 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ARG.1] ; cases 0, 2 of switch FF8_EN.48C43D
0048C484 |. 33C9 XOR ECX,ECX //ecx = 0
0048C486 |. 8BC7 MOV EAX,EDI //eax = lvl
0048C488 |. 8A4E 03 MOV CL,BYTE PTR DS:[ESI+3] //cl = d
0048C48B |. 0FAFC7 IMUL EAX,EDI EAX //edx:eax = lvl^2
0048C48E |. 99 CDQ //sign extend eax into edx
0048C48F |. F7F9 IDIV ECX //eax = floor(lvl^2/d)
0048C491 |. 33DB XOR EBX,EBX //ebx = 0
0048C493 |. 8A5E 01 MOV BL,BYTE PTR DS:[ESI+1] bl = b
0048C496 |. 99 CDQ //sign extend eax into edx
0048C497 |. 2BC2 SUB EAX,EDX //not sure about this one edx will either be 0xFFFFFFFF or 0x00000000 eax ends up as eax or eax + 1
0048C499 |. 8BC8 MOV ECX,EAX //ecx = floor(lvl^2/d)
0048C49B |. 8BC7 MOV EAX,EDI //eax = lvl
0048C49D |. 99 CDQ //sign extend eax into edx
0048C49E |. F7FB IDIV EBX //eax = floor(lvl/b)
0048C4A0 |. D1F9 SAR ECX,1 //ecx = floor(floor(lvl^2/d)/2)
0048C4A2 |. 8BD8 MOV EBX,EAX //ebx = floor(lvl/b)
0048C4A4 |. B8 67666666 MOV EAX,0x66666667 //eax = 0x66666667
0048C4A9 |. 2BD9 SUB EBX,ECX //ebx = floor(lvl/b) - floor(floor(lvl^2/d)/2)
0048C4AB |. 33C9 XOR ECX,ECX //ecx = 0
0048C4AD |. 8A0E MOV CL,BYTE PTR DS:[ESI] cl = a
0048C4AF |. 0FAFCF IMUL ECX,EDI //edx:ecx = lvl*a
0048C4B2 |. F7E9 IMUL ECX //edx:eax = lvl*a*0x66666667
0048C4B4 |. C1FA 02 SAR EDX,2 //edx = floor(lvl*a*0x66666667/2^34)
0048C4B7 |. 8BC2 MOV EAX,EDX //eax = floor(lvl*a*0x66666667/2^34)
0048C4B9 |. 03D3 ADD EDX,EBX //edx = floor(lvl*a*0x66666667/2^34) + floor(lvl/b) - floor(floor(lvl^2/d)/2)
0048C4BB |. C1E8 1F SHR EAX,1F //eax = sign bit of eax
0048C4BE |. 03C2 ADD EAX,EDX //not sure what effect this has
0048C4C0 |. 33D2 XOR EDX,EDX //edx = 0
0048C4C2 |. 8A56 02 MOV DL,BYTE PTR DS:[ESI+2] dl = c
0048C4C5 |. 03C2 ADD EAX,EDX //eax = floor(lvl*a*0x66666667/2^34) + floor(lvl/b) - floor(floor(lvl^2/d)/2) + c
0048C4C7 |. 99 CDQ //sign extend eax into edx
0048C4C8 |. 83E2 03 AND EDX,0x00000003 //edx = either 0x00000000%4 or 0xFFFFFFFF%4, so 0 or 3 depending on sign of eax
0048C4CB |. 03C2 ADD EAX,EDX //eax = floor(lvl*a*0x66666667/2^34) + floor(lvl/b) - floor(floor(lvl^2/d)/2) + c
0048C4CD |. C1F8 02 SAR EAX,2//eax = floor((floor(lvl*a*0x66666667/2^34) + floor(lvl/b) - floor(floor(lvl^2/d)/2) + c)/4)
//0x1D27B10
#pragma pack(push, 1)
struct Character
{
BYTE **monster_info; //0x1D27B10 - could just be used for the name but points to section 7 of a loaded dat file
BYTE unk[8]; //0x1D27B14
BYTE status; //0x1D27B1C - MSB - reflect / shell / protect / regen / stop / slow / haste / ? - LSB
BYTE unk1[3]; //0x1D27B1D
DWORD unkdword1D27B20; //0x1D27B20 - used in opcode 0x24
DWORD unkdword1D27B24; //0x1D27B24 - used in opcode 0x24
DWORD currentHP; //0x1D27B28
DWORD maxHP; //0x1D27B2C
BYTE unk2_0[4]; //0x1D27B30
DWORD localVars[8]; //0x1D27B34 - DC to E3 - base address used is 0x1D277C4
WORD unkwordarr1D27B54[6]; //0x1D27B54 at least 6 items, changed by opcode 2D
BYTE unk3_0[4]; //0x1D27B60
WORD unkword1D27B64[16]; //0x1D27B64
DWORD unkdword1D27B84[3]; //0x1D27B84
BYTE status1; //0x1D27B90 MSB - ? / zombie / berserk / ? / ? / ? / ? / ? - LSB
BYTE unk4[7]; //0x1D27B91
BYTE lastAttacker; //0x1D27B98 - used in opcode 0x0E case 0xCB - 0, 1 or 2 for SeeD 3+ for monsters
BYTE unk5_0[7]; //0x1D27B99 - this whole section of unknowns looks to be status resistances
BYTE unk5_1[8]; //0x1D27BA0
BYTE unk5_2[8]; //0x1D27BA8
BYTE unk5_3[8]; //0x1D27BB0
BYTE unk5_4[8]; //0x1D27BB8
BYTE unk5_5[8]; //0x1D27BC0
BYTE unkbyte1D27BC8; //0x1D27BC8 used in case 0x2A
BYTE unk6[3]; //0x1D27BC9
BYTE lvl; //0x1D27BCB
BYTE str; //0x1D27BCC
BYTE vit; //0x1D27BCD
BYTE mag; //0x1D27BCE
BYTE spr; //0x1D27BCF
BYTE spd; //0x1D27BD0
BYTE luck; //0x1D27BD1
BYTE eva; //0x1D27BD2
BYTE unk7[12];
};
#pragma pack(pop)