Show Posts

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.


Messages - JWP

Pages: 1 2 3 4 5 6 [7] 8
151
Nice work NFITC1! Saves me having to reinstall FF7 :P.

152
I normally do FF8 stuff but this is how I would go about it:
1.) load a save game
2.) attach a debugger (e.g. Ollydbg) to the FF7 process
3.) search for the save game data in memory - it should mostly match the save game file, it should be in memory in this format
4.) put a memory breakpoint on the EXP of an out of party character
5.) start a battle
6.) if the breakpoint triggers after the battle, trace the code back and look for where the EXP is divided by 2 for out of party characters - it'll probably be something like:

Code: [Select]
SHR REG,1
or
SAR REG,1

where SHR (logical shift right) is used to do an unsigned division and SAR (shift arithmetic right) is used to do a signed division. Shift instructions are commonly used to multiply/divide quickly by powers of 2 when using integers.
REG is an x86 32-bit register e.g. EAX, EBX, ECX...
Those instructions would basically do REG = REG/2

and then you would change it to:
Code: [Select]
XOR REG,REG

XORing (exclusive or) a register with itself is a compact way of setting a register to 0 (it's used instead of MOV REG,0) and it fits into the same 2 bytes as the shift instruction.

Anyway, that's roughly how I'd go about it, I'll take a look tonight if I get some free time.

153
The 20 attack power is for basic attacks mind, other skills that use str e.g. renzokuken use different power values.

154
The actual offset of a byte is the number on the left + the number on the top, the number on the left is the offset of the first byte in the row.
The offset you're looking for isn't on the left in this case due to alignment but that doesn't mean that it doesn't exist.

You're not always going to get data that aligns the way you want it to (first byte of a row being the start of a section) due to all the sections having different sizes that (in your case) aren't multiples of 24.

155
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.

str_bonus is the value that is added to the strength stat when you buy the weapon.
attack_power is an additional byte that's use in damage calculation, so it would also give a damage increase if higher than the previous weapon.
See section 4.1 of this guide in step 3:
Step 3: Base Damage Calculation

  Damage = AttackerStr^2 / 16 + AttackerStr
  Damage = Damage * (265 - TargetVit) / 256
  Damage = Damage * Power / 16

  Note: A normal attack has a Power value of 20

EDIT: I haven't actually tested changing the byte but I made an educated guess as to what it is.

156
Let me know if you do and I'll add a bunch of stuff to it :). I've just finished documenting all of the character section of kernel.bin in this post

157
JWP, do you have wiki account?
I'm afraid not. I'm not really sure how I would go about getting one.
I've updated the list of magic IDs to include all the function pointers (690 of them!), I'll probably add the texture names at some point if I get around to it.

EDIT: They don't all load .TIM files as I had originally thought, for example:
Code: [Select]
0x0006--0x00B58050--0x00B58080--Leviathan Summon (Tsunami)loads "mag005_b.00" and "mag005_b.01"

Code: [Select]
0x008D--0x0061DE50--0x0061DE70--Renzokuken - 5 Hitsloads "mag140-158-159-258-331-332.tim"

Code: [Select]
0x0074--0x006C3560--0x006C3550--Quezacotl Summon (Thunder Storm)loads "mag115.tim"

it seems that to find any associated files, you subtract 1 from the magic ID, convert it to decimal and any files with that number in it tend to get loaded.
It looks like those 2 functions are all that are needed, since I made magic ID 0xE0 turn into the cure/fire animations and assigned that ID to the fire spell.

158
I could but I don't think I'd have enough time to reverse engineer stuff and make an editor :(

159
No problem :). Btw, here's all the stuff you were after in http://forums.qhimm.com/index.php?topic=16679.0:

Quote
2. Damage formulas for Kamikaze and Darkside abilities

Kamikaze:
Code: [Select]
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.

Darkside:
Code: [Select]
CPU Disasm
Address   Hex dump               Command                                      Comments
00491069  |> \8D3476             LEA ESI,[ESI*2+ESI]                          ; ESI = ESI * 3 - darkside multiplier

Quote
3. Angel Wing damage multiplier

Code: [Select]
CPU Disasm
Address   Hex dump               Command                                      Comments
00491085  |.  8D34B6             LEA ESI,[ESI*4+ESI]                          ; ESI = ESI * 5 - angel wing multiplier

Quote
6. Changing character base stats and starting level, also giving Squall, Zell and Quistis some default spells at the beginning of the game

Most of the stuff looks like it's loaded from init.out in main.fi, I'd imagine it's a similar format to sections of: http://wiki.qhimm.com/view/FF8/GameSaveFormat

Looks like init.out starts at the GF data and the character data starts at 0x440 of init.out - the level looks like it's determined by the XP (level = 1+(XP/1000)) and the magic + stats you can change too - note the stats listed in the save file are bonuses and are added to the usual level calculated stat.
The HP stat for each of the characters is set to 9999 and then capped to the max after loading - the max being calculated from the level-calculated HP + the HP bonus (I think it's HP bonus rather than the max HP that the wiki says).
The parameters for the formula that controls the level curve for each character are located in section 7 of kernel.bin, see http://forums.qhimm.com/index.php?topic=16923.msg240609#msg240609
EDIT: does anyone know where the calculation of crisis level for limit breaks is? - it'd be pretty useful for some of my investigation stuff
EDIT1: Callisto helped me find the function, it's at 0x4941F0

160
Magic ID list

ID--File Load Function--Main Function--Description
0x0001--0x008D69E0--0x008D6A00--Cure
0x0002--0x00629880--0x006298A0--Fire
0x0003--0x00575610--0x00700C10--Thunder
0x0004--0x008D5060--0x008D5080--Double
0x0005--0x008D4430--0x008D4450--Phoenix Down
0x0006--0x00B58050--0x00B58080--Leviathan Summon (Tsunami)
0x0007--0x008CE3B0--0x008CE3D0--Mega Phoenix
0x0008--0x008C4960--0x008C4980--Doom
0x0009--0x008C0360--0x008C0380--Doom Activation
0x000A--0x00627E40--0x00627E60--Ray-Bomb
0x000B--0x006EA510--0x006EA500--Storm Breath
0x000C--0x006E8AC0--0x006E8AE0--Blade Shot
0x000D--0x008BE1D0--0x008BE1F0--Dark Mist/Poison Mist
0x000E--0x008B68A0--0x008B68C0--Death/Death Stone
0x000F--0x008B08F0--0x008B0910--Draw
0x0010--0x008AB120--0x008AB140--Recover
0x0011--0x00575600--0x007003C0--Elvoret Entrance
0x0012--0x00B4A500--0x00B4A530--Elvoret Death
0x0013--0x008A3280--0x008A32A0--
0x0014--0x0089FBA0--0x0089FBC0--NORG Pod Opening
0x0015--0x0089DED0--0x0089DEF0--Triple
0x0016--0x0089A690--0x0089A6B0--Bio
0x0017--0x00893000--0x00893020--Psycho Blast
0x0018--0x0088CF50--0x0088CF70--Esuna
0x0019--0x00889D40--0x00889D60--Cura
0x001A--0x008885B0--0x008885D0--Clash
0x001B--0x008830F0--0x00883110--Full-Life
0x001C--0x0087DAF0--0x0087DB10--Curaga
0x001D--0x00879480--0x008794A0--Wind Blast
0x001E--0x008735D0--0x008735F0--Counter Laser-Eye
0x001F--0x0086C9C0--0x0086C9E0--Heartbreak
0x0020--0x0086B980--0x0086B9A0--Protect
0x0021--0x00865FF0--0x00866010--Shell
0x0022--0x008655E0--0x00865600--Pain
0x0023--0x008649A0--0x008649C0--Life
0x0024--0x0085F4C0--0x0085F4E0--Confuse
0x0025--0x008569D0--0x008569F0--Drink Magic
0x0026--0x00575620--0x008D8510--Quake
0x0027--0x008513B0--0x008513D0--Drain
0x0028--0x0084D010--0x0084D030--Scan
0x0029--0x008465A0--0x008465C0--Dribble
0x002A--0x0083ECA0--0x0083ECC0--Shoot
0x002B--0x00839920--0x00839940--Melting Bubble
0x002C--0x006E7AF0--0x006E7AE0--Junk
0x002D--0x00836570--0x00836590--Stare
0x002E--0x00831B30--0x00831B50--Sigh
0x002F--0x0082A7D0--0x0082A7F0--Curse
0x0030--0x00824CD0--0x00824CF0--Magma Breath
0x0031--0x00821520--0x00821540--Resonance
0x0032--0x0081F9F0--0x0081FA10--Potion/Potion+
0x0033--0x0081C7E0--0x0081C800--Hi-Potion/Hi-Potion+
0x0034--0x008173F0--0x00817410--X-Potion
0x0035--0x00811F50--0x00811F70--Mega-Potion
0x0036--0x0080CA90--0x0080CAB0--Everyone's Grudge
0x0037--0x00808800--0x00808820--Aqua Breath
0x0038--0x008031E0--0x00803200--Absorb
0x0039--0x007FD130--0x007FD150--Treatment
0x003A--0x007F7C90--0x007F7CB0--Elixir
0x003B--0x007F27F0--0x007F2810--Megalixir
0x003C--0x007EB070--0x007EB090--
0x003D--0x007E58A0--0x007E58C0--Revive
0x003E--0x007E4AB0--0x007E4B00--Devour
0x003F--0x006E6BF0--0x006E6BE0--
0x0040--0x006E5190--0x006E5180--Griever Tail Falling Off
0x0041--0x006E0360--0x006E0350--Great Attractor
0x0042--0x006225F0--0x00622610--Griever + Ultimecia Death
0x0043--0x007DEA00--0x007DEA20--Remedy/Remedy+
0x0044--0x007DC180--0x007DC1A0--
0x0045--0x005755F0--0x006FE040--Griever Summon
0x0046--0x006DD8E0--0x006DD8D0--Shockwave Pulsar
0x0047--0x007D6130--0x007D6150--Laser Eye (Quistis)
0x0048--0x007D1E60--0x007D1E80--Aqua Breath (Quistis)
0x0049--0x007CBD90--0x007CBDB0--Mighty Guard (Quistis)
0x004A--0x007C4440--0x007C4460--LV?Death (Quistis)
0x004B--0x00B3E8B0--0x00B3E8E0--Hell's Judgement
0x004C--0x0061F980--0x0061F9A0--Ultimecia Final Form Spawn
0x004D--0x00B302C0--0x00B302F0--Ultimecia Final Form Death
0x004E--0x007BE2B0--0x007BE2D0--Mighty Guard
0x004F--0x007B4BB0--0x007B4BD0--Griever Death
0x0050--0x007AB540--0x007AB560--Ultimecia Junctioning to Griever
0x0051--0x007A5190--0x007A51B0--
0x0052--0x0079EE10--0x0079EE30--Ultimecia Blow Away Magic
0x0053--0x007976A0--0x007976C0--Absorbed into time...
0x0054--0x0078D790--0x0078D7B0--Angel Wing
0x0055--0x00784480--0x007844A0--The End
0x0056--0x0077F230--0x0077F250--Angelo Cannon
0x0057--0x00773850--0x00773870--Angelo Strike
0x0058--0x007684D0--0x007684F0--Invincible Moon
0x0059--0x005755E0--0x006F9CF0--Wishing Star
0x005A--0x00762320--0x00762360--Tonberry Summon (Chef's Knife)
0x005B--0x00759350--0x00759370--Angelo Rush
0x005C--0x00755110--0x00755130--Angelo Search
0x005D--0x0074E370--0x0074E390--Angelo Recover
0x005E--0x007475D0--0x007475F0--Angelo Reverse
0x005F--0x00739D80--0x00739DA0--Siren Summon (Silent Voice)
0x0060--0x00731DC0--0x00731DE0--Moogle Dance
0x0061--0x00729A40--0x00729A60--ChocoFire
0x0062--0x00721840--0x00721860--ChocoFlare
0x0063--0x00717D10--0x00717D30--ChocoMeteor
0x0064--0x0070D370--0x0070D390--ChocoBocle
0x0065--0x006DD0D0--0x006DD0C0--
0x0066--0x006DC2B0--0x006DC2D0--Thundara
0x0067--0x006DA2E0--0x006DA300--Blizzara
0x0068--0x006D62F0--0x006D6310--Blizzaga
0x0069--0x006D3DC0--0x006D3DB0--Thundaga
0x006A--0x006D2AC0--0x006D2AE0--Reflect
0x006B--0x006D1320--0x006D1310--Demi
0x006C--0x006CFCE0--0x006CFCD0--Berserk
0x006D--0x006CF4B0--0x006CF4A0--Dispel
0x006E--0x006CE220--0x006CE210--Biggs + Wedge 1st Death
0x006F--0x006CD930--0x006CD920--Aura
0x0070--0x006CBBF0--0x006CBBE0--
0x0071--0x006CAC30--0x006CAC20--Bad Breath
0x0072--0x006C99D0--0x006C99C0--Zombie
0x0073--0x006C9390--0x006C9380--Float
0x0074--0x006C3560--0x006C3550--Quezacotl Summon (Thunder Storm)
0x0075--0x006C16B0--0x006C16A0--Break
0x0076--0x006C0C90--0x006C0C80--Aero
0x0077--0x006BEFE0--0x006BEFD0--Stop
0x0078--0x006BE970--0x006BE960--Petrify Stare
0x0079--0x006BDE90--0x006BDE80--Blind
0x007A--0x006BD8F0--0x006BD8E0--Silence
0x007B--0x006BD1D0--0x006BD1C0--Slow
0x007C--0x006BBDB0--0x006BBDA0--Flare
0x007D--0x006BB6C0--0x006BB6B0--Haste
0x007E--0x006B9A20--0x006B9A10--Electric Discharge
0x007F--0x006B93B0--0x006B93A0--Petrify Stare
0x0080--0x006B7D10--0x006B7D00--Gastric Juice
0x0081--0x006B4C10--0x006B4C00--Breath
0x0082--0x006B4250--0x006B4240--Eerie Sound Wave
0x0083--0x006B2BE0--0x006B2BD0--Bad Breath
0x0084--0x006B1A00--0x006B19F0--Disolving Acid
0x0085--0x006B0FC0--0x006B0FB0--Hypnotize
0x0086--0x006B0080--0x006B0070--Beam Laser
0x0087--0x006AEEB0--0x006AEEA0--Reflect Beam
0x0088--0x006AD1B0--0x006AD1A0--Oil Shot
0x0089--0x006AB860--0x006AB850--Oil Blast
0x008A--0x006A9F20--0x006A9F10--Saliva
0x008B--0x006A8840--0x006A8830--Sonic Wave
0x008C--0x006A6310--0x006A6300--Phoenix Pinion (Rebirth Flame)
0x008D--0x0061DE50--0x0061DE70--Renzokuken - 5 Hits
0x008E--0x0061CDF0--0x0061CE10--Fira
0x008F--0x0061BFC0--0x0061BFE0--Firaga
0x0090--0x0061AB80--0x0061ABA0--Blizzard
0x0091--0x006185B0--0x006185D0--Sleep
0x0092--0x00614D50--0x00614D70--Tornado
0x0093--0x00614270--0x00614290--Regen
0x0094--0x006120B0--0x006120D0--Meltdown
0x0095--0x0060F670--0x0060F690--Ultima
0x0096--0x0060E320--0x0060E340--Gatling Gun
0x0097--0x0060C9A0--0x0060C9C0--Cannon Blow
0x0098--0x0060AF90--0x0060AFB0--Ultrasonic Waves
0x0099--0x00609620--0x00609640--Sticky Web
0x009A--0x00607BF0--0x00607C10--Ultra Waves
0x009B--0x00606CD0--0x00606CF0--Sand Storm
0x009C--0x00605510--0x00605530--Wild Cannon Blow
0x009D--0x00603E70--0x00603E90--Breath
0x009E--0x00602EB0--0x00602ED0--Melt-Eye
0x009F--0x00600BA0--0x00600BC0--Renzokuken (vs X-ATM092)
0x00A0--0x005FF060--0x005FF080--Renzokuken - 4 Hits
0x00A1--0x005FD0E0--0x005FD100--Renzokuken (vs Elnoyle/Elvoret)
0x00A2--0x005F90D0--0x005F90F0--Fated Circle
0x00A3--0x005F5B60--0x005F5B80--Rough Divide
0x00A4--0x005F0240--0x005F0260--Blasting Zone
0x00A5--0x005E9450--0x005E9470--Lion Heart
0x00A6--0x005E4E70--0x005E4E90--Megido Flame
0x00A7--0x005E29F0--0x005E2A10--Zantetsuken
0x00A8--0x005E1730--0x005E1750--Sleeping Gas
0x00A9--0x005DEE40--0x005DEE60--Gastric Juice
0x00AA--0x005DC910--0x005DC930--Acid
0x00AB--0x005DB250--0x005DB270--Poison Gas
0x00AC--0x005D9CB0--0x005D9CD0--Morph
0x00AD--0x005D7490--0x005D74B0--Ice Breath
0x00AE--0x005D4580--0x005D45A0--Degenerator
0x00AF--0x005D1AB0--0x005D1AD0--Holy
0x00B0--0x005D00D0--0x005D00F0--Sand Storm
0x00B1--0x005CF740--0x005CF760--1,000 Needles
0x00B2--0x005CEDB0--0x005CEDD0--10,000 Needles
0x00B3--0x005CDF20--0x005CDF40--
0x00B4--0x005CC820--0x005CC840--Suicide
0x00B5--0x005CB530--0x005CB550--Kamikaze
0x00B6--0x005C9FC0--0x005C9FE0--Card
0x00B7--0x005C9A30--0x005C9A50--Defend
0x00B8--0x005C7FA0--0x005C7FC0--Ultra Waves (Quistis)
0x00B9--0x005C0D30--0x005C0D50--Shiva Summon (Diamond Dust)
0x00BA--0x005BF6D0--0x005BF6F0--Blaster
0x00BB--0x00575570--0x006472E0--Odin Summon (Zantetsuken)
0x00BC--0x005BE320--0x005BE340--Shot - Normal Shot
0x00BD--0x005BC940--0x005BC960--Wall
0x00BE--0x005BB2A0--0x005BB2C0--Chain Gun
0x00BF--0x00575560--0x0063E730--Doomtrain Summon (Runaway Train)
0x00C0--0x005B96D0--0x005B96F0--Shot - Scatter Shot
0x00C1--0x005B7170--0x005B7190--Shot - Dark Shot
0x00C2--0x005B4C40--0x005B4C60--Shot - Flame Shot
0x00C3--0x005B2A20--0x005B2A40--Shot - Canister Shot
0x00C4--0x005B18E0--0x005B1900--Shot - Quick Shot
0x00C5--0x005AED10--0x005AED30--Shot - Armor Shot
0x00C6--0x005AA3C0--0x005AA3E0--Shot - Hyper Shot
0x00C7--0x005A8730--0x005A8750--Cactuar Summon (1,000 Needles)
0x00C8--0x00575530--0x006391D0--No Mercy
0x00C9--0x00B25750--0x00B25780--Ifrit Summon (Hell Fire)
0x00CA--0x00B18970--0x00B189A0--Bahamut Summon (Mega Flare)
0x00CB--0x00B0C170--0x00B0C1A0--Cerberus Summon (Counter Rockets)
0x00CC--0x00AFFC70--0x00AFFCA0--Alexander Summon (Holy Judgment)
0x00CD--0x00AF44F0--0x00AF4520--Brothers Summon (Brotherly Love)
0x00CE--0x00AE2DA0--0x00AE2DD0--Eden Summon (Eternal Breath)
0x00CF--0x006A3AC0--0x006A3AB0--Maelstrom
0x00D0--0x00AD78D0--0x00AD7900--Final "Sorceress" Death
0x00D1--0x00575520--0x00637500--"Sorceress" Spawn
0x00D2--0x005755D0--0x006F6800--Bloodfest
0x00D3--0x00ACA0F0--0x00ACA120--Adel Death
0x00D4--0x006A0D30--0x006A0D20--
0x00D5--0x0069EAD0--0x0069EAC0--Storm Breath
0x00D6--0x0069D5C0--0x0069D5B0--Gravija
0x00D7--0x0069AB70--0x0069AB60--
0x00D8--0x006959F0--0x006959E0--
0x00D9--0x00694E70--0x00694E60--Energy Bomber
0x00DA--0x00575550--0x006326D0--
0x00DB--0x00ABD3F0--0x00ABD420--Terra Break
0x00DC--0x00AB32F0--0x00AB3320--Light Pillar
0x00DD--0x00AA5530--0x00AA5560--Apocalypse
0x00DE--0x00A9B1D0--0x00A9B200--Water
0x00DF--0x00A8F860--0x00A8F890--Meteor
0x00E0--0x00000000--0x00000000--
0x00E1--0x00000000--0x00000000--
0x00E2--0x00694530--0x00694520--White Wind
0x00E3--0x006937A0--0x00693790--Ultimecia First Death
0x00E4--0x00A85590--0x00A855C0--Ice Strike
0x00E5--0x00A7A9F0--0x00A7AA20--Homing Laser (Quistis)
0x00E6--0x00A70B40--0x00A70B70--Fire Breath (Quistis)
0x00E7--0x00A66470--0x00A664A0--Disease Breath
0x00E8--0x00A5C2B0--0x00A5C2E0--Breath of Death
0x00E9--0x00A51F10--0x00A51F40--Earthquake
0x00EA--0x00A488C0--0x00A488F0--Fart
0x00EB--0x00A3E340--0x00A3E370--Breath
0x00EC--0x00A34210--0x00A34240--Gas
0x00ED--0x00A29C00--0x00A29C30--Explosion
0x00EE--0x00A1FD90--0x00A1FDC0--Breath
0x00EF--0x00A15A00--0x00A15A30--Ochu Dance
0x00F0--0x00A0B330--0x00A0B360--Earthquake
0x00F1--0x00A01DE0--0x00A01E10--BGH251F2 Gatling Gun
0x00F2--0x009F7CE0--0x009F7D10--Beam Cannon
0x00F3--0x009EEA60--0x009EEA90--BGH251F2 1st Turret Exploding
0x00F4--0x009E57E0--0x009E5810--BGH251F2 2nd Turret Exploding
0x00F5--0x009DC560--0x009DC590--BGH251F2 3rd Turret Exploding
0x00F6--0x009D32E0--0x009D3310--BGH251F2 4th Turret Exploding
0x00F7--0x009C9860--0x009C9890--BGH251F2 Death
0x00F8--0x009C08A0--0x009C08D0--Soldier Entrance After BGH251F2 Death
0x00F9--0x009B7350--0x009B7380--
0x00FA--0x009ABFC0--0x009ABFF0--Beam Cannon
0x00FB--0x005755C0--0x006F44D0--Demon Slice
0x00FC--0x009A2840--0x009A2870--Corona
0x00FD--0x00997CE0--0x00997D10--Twin Homing Laser
0x00FE--0x0098D180--0x0098D1B0--Homing Laser
0x00FF--0x00982620--0x00982650--Homing Laser
0x0100--0x009793D0--0x00979400--Sand Shake
0x0101--0x0096F260--0x0096F290--Mega Flare
0x0102--0x009649D0--0x00964A00--Mad Cow Special
0x0103--0x005A6C00--0x005A6C20--Renzokuken - 6 Hits
0x0104--0x006906A0--0x00690690--Shockwave Pulsar (Quistis)
0x0105--0x009598A0--0x009598D0--Desperado
0x0106--0x0094F9C0--0x0094F9F0--Blood Pain
0x0107--0x009457E0--0x00945810--Massive Anchor
0x0108--0x00937E80--0x00937EB0--
0x0109--0x0092CBA0--0x0092CBD0--
0x010A--0x0091F5B0--0x0091F5E0--
0x010B--0x00911FC0--0x00911FF0--
0x010C--0x009049D0--0x00904A00--
0x010D--0x008F71F0--0x008F7220--
0x010E--0x008E9C00--0x008E9C30--Ultima Weapon Death
0x010F--0x0068F560--0x0068F550--LV Up
0x0110--0x0068DC80--0x0068DC70--LV Down
0x0111--0x0068D660--0x0068D650--Mad Rush
0x0112--0x006897F0--0x006897E0--Duel
0x0113--0x00687B50--0x00687B40--Electrocute (Quistis)
0x0114--0x00684EF0--0x00684EE0--
0x0115--0x00683F20--0x00683F10--
0x0116--0x00680C60--0x00680C50--Carbuncle Summon (Ruby Light)
0x0117--0x0067EFE0--0x0067EFD0--Mega Spark
0x0118--0x0067E740--0x0067E730--Full Cure
0x0119--0x0067DCF0--0x0067DCE0--Shotgun
0x011A--0x0067D410--0x0067D400--Evil-Eye
0x011B--0x0067C410--0x0067C400--Magic Summon
0x011C--0x0067B7B0--0x0067B7A0--Micro Missiles
0x011D--0x0067A870--0x0067A860--Thunder Summon
0x011E--0x00679E20--0x00679E10--Mini Pulse Cannon
0x011F--0x005755B0--0x006F2E80--Mega Pulse Cannon
0x0120--0x00679200--0x006791F0--Rapture
0x0121--0x006777F0--0x006777E0--"Brrawghh!"
0x0122--0x00675290--0x00675280--
0x0123--0x005755A0--0x006ED250--Pandemona Summon (Tornado Zone)
0x0124--0x00674DA0--0x00674D90--Soft
0x0125--0x00674880--0x00674870--Eye Drops
0x0126--0x00674400--0x006743F0--Antidote
0x0127--0x00673E80--0x00673E70--Echo Screen
0x0128--0x00673980--0x00673970--Holy Water
0x0129--0x00673010--0x00673000--White Wind (Quistis)
0x012A--0x00670980--0x00670970--
0x012B--0x0066FCD0--0x0066FCC0--Micro Missiles (Quistis)
0x012C--0x0066EF10--0x0066EF00--Bad Breath (Quistis)
0x012D--0x0066D8F0--0x0066D8E0--
0x012E--0x0066CA60--0x0066CA50--Snipe Laser
0x012F--0x0066A830--0x0066A820--
0x0130--0x006697A0--0x00669790--Boomerang Sword
0x0131--0x005A57B0--0x005A57D0--Gatling Gun (Quistis)
0x0132--0x005A2C70--0x005A2C90--Degenerator (Quistis)
0x0133--0x005A1150--0x005A1170--Ray-Bomb (Quistis)
0x0134--0x00667680--0x00667670--
0x0135--0x00666DE0--0x00666DD0--Hero-trial/Hero
0x0136--0x006664B0--0x006664A0--Holy War-trial/Holy War
0x0137--0x006652D0--0x006652C0--
0x0138--0x0059CB70--0x0059CB90--
0x0139--0x0059B0B0--0x0059B0D0--
0x013A--0x006628A0--0x00662890--
0x013B--0x00598D90--0x00598DB0--Fake President Death
0x013C--0x006610C0--0x006610B0--
0x013D--0x0065F850--0x0065F840--Acid (Quistis)
0x013E--0x0065E520--0x0065E510--
0x013F--0x0065DB40--0x0065DB30--
0x0140--0x0065BC20--0x0065BC10--Dark Flare
0x0141--0x005979E0--0x00597A00--Ker Plunk
0x0142--0x0065AB80--0x0065AB70--Zan
0x0143--0x00659A90--0x00659A80--Metsu
0x0144--0x00596BA0--0x00596BC0--Tonberry King Death
0x0145--0x006541F0--0x006541E0--Diablos Summon (Dark Messenger)
0x0146--0x00575540--0x0062A7E0--Zantetsuken Reverse
0x0147--0x0058D6E0--0x0058D760--Gilgamesh - Zantetsuken
0x0148--0x0058D700--0x0058D930--Gilgamesh - Masamune
0x0149--0x0058D720--0x0058DB10--Gilgamesh - Excaliber
0x014A--0x0058D740--0x0058DCF0--Gilgamesh - Excalipoor
0x014B--0x008DFF70--0x008DFFA0--
0x014C--0x0058B910--0x0058B930--Renzokuken - 7 Hits
0x014D--0x00589BB0--0x00589BD0--Renzokuken - 8 Hits
0x014E--0x00587770--0x00587790--Renzokuken (vs Bahamut)
0x014F--0x00585690--0x005856B0--Renzokuken (vs NORG)
0x0150--0x00583020--0x00583040--Renzokuken (vs Ultima Weapon)
0x0151--0x00580970--0x00580990--Renzokuken (vs Final "Sorceress")
0x0152--0x00575590--0x006EBD50--Friendship (MoombaMoomba)
0x0153--0x0057E5B0--0x0057E5D0--Renzokuken (vs Adel)
0x0154--0x0057BBE0--0x0057BC00--Renzokuken (vs Ultimecia Final Form)
0x0155--0x00579A60--0x00579A80--Renzokuken (vs Jumbo Cactuar)
0x0156--0x005776B0--0x005776D0--Renzokuken (vs Griever + Ultimecia)
0x0157--0x00575630--0x00575650--Renzokuken (vs Griever)
0x0158--0x00575580--0x0062A650--Final Battle Music
0x0159--0x00705A60--0x00705A80--LV5 Death


LV5 Death is definitely the max magic ID because all the pointers after that are NULL. Most of the missing ones are probably main boss death anims and there's also 2 NULL ones (0xE0 and 0xE1), I've just left them in for the sake of continuity.

EDIT: Managed to find a couple of limit breaks :D - There appear to be at least 2 sets for Renzokuken though =/ - different crisis levels or vs different enemies?
According to the code, the magic IDs go up to 400 - Illegal Magic ID error gets thrown higher than this - see function 0x50AF20
There's a lookup table of DWORDs in memory starting at 0xC81774 (1 is subtracted from the ID first) - looks like a series of function pointers, these probably do most of the work for each magic ID.
0xC81DB8 contains a series of function pointers for the IDs (after subtracting 1) listed above and those functions seem to load textures.

EDIT 1: I put a breakpoint at 0x50AF2E - ESI will contain the magic ID at this point, so I can get the magic ID from any attack that's used, it's like learning Blue Magic :D.
So many Renzokuken IDs >_> - think I managed to get all 16 of them

EDIT 2: Some data located here: http://gamehacking.org/czardragon/FF8/FF8-Code.txt

161
bit more info on kernel.bin:
4 bytes - number of sections
X * 4 bytes - offset to each section
Even though this section contains offsets, most of the offsets are hard-coded into the exe, the only part of this section that seems to be used is the text offsets.

Offsets are for English Steam release, only the text section offsets probably change between languages:
--------DATA SECTION--------
1  - 0x00E4 - Battle commands - 39 items - 8 bytes each
2  - 0x021C - Magic data - 57 items - 60 bytes each
3  - 0x0F78 - Junctionable GFs - 16 items - 132 bytes each
4  - 0x17B8 - Enemy attacks - 384 items - 20 bytes each
5  - 0x35B8 - Weapons - 33 items - 12 bytes each
6  - 0x3744 - Renzokuken finishers - 4 items - 24 bytes each
7  - 0x37A4 - Characters - 11 items - 36 bytes each
8  - 0x3930 - Battle items - 33 items - 24 bytes each
9  - 0x3C48 - Non-battle item name and description offsets - 166 items - 4 bytes each
10 - 0x3EE0 - Non-junctionable GF attacks - 16 items - 20 bytes each
11 - 0x4020 - Command ability data - 12 items - 16 bytes each
12 - 0x40E0 - Junction abilities - 20 items - 8 bytes each
13 - 0x4180 - Command abilities - 19 items - 8 bytes each
14 - 0x4218 - Stat percentage increasing abilities - 19 items - 8 bytes each
15 - 0x42B0 - Character abilities - 20 items - 8 bytes each
16 - 0x4350 - Party abilities - 5 items - 8 bytes each
17 - 0x4378 - GF abilities - 9 items - 8 bytes each
18 - 0x43C0 - Menu abilities - 24 items - 8 bytes each
19 - 0x4480 - Temporary character limit breaks - 5 items - 24 bytes each
20 - 0x44F8 - Blue magic (Quistis limit break) - 16 items - 16 bytes each
21 - 0x45F8 - Quistis limit break parameters - 64 items - 8 bytes each
22 - 0x47F8 - Shot (Irvine limit break) - 8 items - 24 bytes each
23 - 0x48B8 - Duel (Zell limit break) - 10 items - 32 bytes each
24 - 0x49F8 - Zell limit break parameters
25 - 0x4A5C - Rinoa limit breaks - 2 items - 8 bytes each
26 - 0x4A6C - Rinoa limit breaks - 5 items - 20 bytes each
27 - 0x4AD0 - Slot array - 1 byte each (each entry corresponds to a set ID)
28 - 0x4B0C - Selphie limit break sets - 16 items (each slot entry is 1 byte magic ID, 1 byte count) - 16 bytes each
29 - 0x4C0C - Devour - 16 items - 12 bytes each
30 - 0x4CCC - Misc section - status timers (14 bytes), Spd multiplier for ATB (1 byte), Dead Timer (1 byte), status limit effects (32 bytes), Zell limit time + start moves (8 bytes), Irvine shot timers (4 bytes)
31 - 0x4D08 - Misc text pointers - 128 items - 2 bytes each

--------TEXT SECTION--------
32 - 0x4E08 - Battle command text
33 - 0x5188 - Magic text
34 - 0x57B0 - Junctionable GF text
35 - 0x59F0 - Enemy attack text
36 - 0x619C - Weapon text
37 - 0x62F8 - Renzokuken finishers text
38 - 0x6364 - Character names
39 - 0x63A0 - Battle item names
40 - 0x6768 - Non-battle item names
41 - 0x7C28 - Non-junctionable GF attack name
42 - 0x7CDC - Junction abilities text
43 - 0x7E9C - Command abilities text
44 - 0x8000 - Stat percentage increasing abilities text
45 - 0x81A8 - Character ability text
46 - 0x84A8 - Party ability text
47 - 0x8540 - GF ability text
48 - 0x862C - Menu ability text
49 - 0x89C0 - Temporary character limit break text
50 - 0x8A40 - Blue magic text
51 - 0x8C24 - Shot text
52 - 0x8D0C - Duel text
53 - 0x8E04 - Rinoa limit break text
54 - 0x8E38 - Rinoa limit break text
55 - 0x8E74 - Devour text
56 - 0x8F74 - Misc text

Code: [Select]
****************************************
*        Section 2 - Magic Data        *
****************************************

Code: [Select]
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

Code: [Select]
****************************************
*         Section 3 - GF Data          *
****************************************

See alexfilth's post

Code: [Select]
****************************************
*      Section 4 - Enemy Attacks       *
****************************************

Structure:
Code: [Select]
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
}

Code: [Select]
****************************************
*       Section 5 - Weapon Data        *
****************************************

Structure:
Code: [Select]
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];
}

Code: [Select]
****************************************
*   Section 6 - Renzokuken Finishers   *
****************************************

Structure:
Code: [Select]
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];
}

Code: [Select]
****************************************
*      Section 7 - Character Data      *
****************************************

Structure:
Code: [Select]
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.
Squall and Rinoa have name offsets of 0xFFFF because their name is in the save game data rather than kernel.bin.
crisis_level_hp_mulipilier is multiplied by 10 and used in the formula for crisis level

Formulas for character stats:
Note: this is integer arithmetic, so the results of any division are truncated towards zero.
EXP required to reach level X:
Code: [Select]
((lvl-1)^2*exp_b)/256 + (lvl-1)*exp_a*10

HP formula (function 0x496310):
Code: [Select]
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 formula

Str, Vit, Mag and Spr formula (function 0x496440):
Code: [Select]
stat = ((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

Spd and Luck formula (function 0x496440):
Code: [Select]
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 formula (function 0x4968A0):
Code: [Select]
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)/256

Example:
Code: [Select]
Bytes 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

This gives stats with no modifiers at level 100 as:
Code: [Select]
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)

162
I'll post roughly what I said to Callisto in a PM since I can't actually read what I sent him.
in this part:
Code: [Select]
BYTE mentalRes[40]; //0x1D27BA0offset 0x20 of that array seems to be checked when using meltdown (i.e. vit0).
So the idea behind this post is to implement a way to make some monsters vit0 resistant without getting rid of vit0 entirely.
The following code changes in the exe load the unused 20th status byte in the dat file into that position instead of it being set to 100:

!!!--- make a backup if you're going to do this ---!!!
Also make sure you check the from bytes, since I'm not sure if this will work with other versions of FF8 (I'm using the English Steam version).

FF8_EN.exe:
Code: [Select]
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

it's basically a bunch of ASM code that bounces around the place.
The problem is that the jump table doesn't go anywhere near the value needed and there's no space for code to change one status without having a knock-on effect on the others or overriding code, so I had to resort to doing crazy amounts of jumps and using the NOP space between functions.
Anyway, I tested it and it appeared to stop things getting vit0 status - if they had the 20th byte as 0xFF anyway.
It'd probably be a lot easier to do something like this in a mod with an injected DLL - since it wouldn't involve so much code jumping and it wouldn't be permanent.
You could also test it by adding 0x400000 to those addresses and editing the memory of the program.

For those interested, this is the ASM code - note that register EAX is unused until its next modification (otherwise modifying AL like I have without backing it up would have unintended consequences):
Code: [Select]
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.
Basically it ended up using the byte before instead (info + 0x17A instead of info + 0x17B).

163
ok, so according to this: http://forums.qhimm.com/index.php?topic=11137.msg166280#msg166280
flare has a magic ID of 0x0F.
so we have a few things:
0x21C - start of magic data
--blocks of 60 bytes--

so to get the start offset of flare, we would do 0x21C + (60 * 0x0F) - note the 60 is decimal.
this gives the start offset of flare as 0x5A0.
We want to edit the spell power, so we need to add another 8 bytes - because there are 8 bytes before the spell power.
this gives the byte that we need to edit as 0x5A8.
the current value of this byte is 0x30 or 48 in decimal and you can see that this is correct on:http://finalfantasy.wikia.com/wiki/Magic_(Final_Fantasy_VIII)
You would just increase this value to increase the damage.

164
Nice work! :D. Is that slow petrify supposed to be curse? - I didn't think you could defend against slow petrify specifically.

165
Nice work :), although you probably didn't need to document every value, it's pretty much a standard bit field: https://en.wikipedia.org/wiki/Bit_field
In other words, each bit toggles something on/off. Just document what each bit toggles i.e.
LSB Fire, Ice, Thunder, Earth, Poison, Wind, Water, Holy MSB
or if you prefer this way:
Code: [Select]
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:
Code: [Select]
Binary    Hex Element
00000001  01   Fire
00010000  10   Poison
00100000  20   Wind
Result:
00110001  31   Fire | Poison | Wind

To check two bytes, you'd only need to test the following 16 values (note that some bits might be unused):
0x0001
0x0002
0x0004
0x0008
0x0010
0x0020
0x0040
0x0080
0x0100
0x0200
0x0400
0x0800
0x1000
0x2000
0x4000
0x8000

166
So after a bit more investigation, I've found that the magic data I mentioned in the previous post is loaded from the kernel.bin file and the magic stuff starts at offset 0x21C in kernel.bin and ends at 0xF78 - so you can use HxD to edit it (kernel.bin is in the main.fi archive and you'll need an archive extractor to remove it - see http://wiki.qhimm.com/view/FF8/Tools - in my case, main.fi is located at: "C:\Program Files (x86)\Steam\steamapps\common\FINAL FANTASY VIII\Data\lang-en\main.fi").
!!!--- Don't forget to make a backup of main.fi, main.fs and main.fl files before you edit it ---!!!
the 60 byte structures starting at 0x21C are comprised roughly as follows:

see: http://finalfantasy.wikia.com/wiki/Magic_(Final_Fantasy_VIII) for more information on magic,
see also: http://www.gamefaqs.com/ps/197343-final-fantasy-viii/faqs/58936

2 bytes - offset to spell name
2 bytes - offset to spell description
4 bytes - unknown
1 byte - spell power (basically relates to how much damage it does)
3 bytes - unknown
1 byte - draw resist (how hard it is to draw - higher = harder)
10 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
28 bytes - unknown

so modifying the spell damage is simple enough but this will also modify it for enemies.
If you wanted to modify the actual equation (the one listed on the wiki), then you'd need to know x86 ASM, there's a bunch of sub functions called from 0x4922B0:
arg1 - think this is 0x02 for magic but can be other values depending on attack type (e.g. attacking with gunblade is 0x0A)
arg2 - caster_id
arg3 - target_id
arg4 - spell_power
and one of those probably deals with that but I'd not recommend doing that.

EDIT:
function 0x491DA0 is probably the main damage calculation function:
arg1 - caster_id
arg2 - target_id
arg3 - spell_power (I made haste deal damage by changing this on the fly with a debugger :D)
arg4 - 0 = magic damage?, 2 = GF?

The main magic damage calculation is in this section of code (note that it's elsewhere for different damage types) - I'd recommend modifying the spell power listed above instead, since it's a lot easier:
note you can see the formula listed at section 4.2 of http://www.gamefaqs.com/ps/197343-final-fantasy-viii/faqs/58936 listed in the code
Code: [Select]
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

there's a bunch of other modification but that's the main part of it. See section 6 of the link above for the rest.
If you know ASM, you could jmp based on the caster ID (it's always <3 for allies) and write custom code for the damage stuff - either in-place, injected dll etc. but it's not exactly trivial unless you're familiar with that sort of thing.

167
It's probably in the exe, you'll probably need a disassembler and debugger to modify them.

There's a function at 0x48D200 (in memory) that takes 7 args which might lead to where the values are stored:
arg1: caster id (0-2 for Seeds, 3+ for monsters - each person in a battle has an id)
arg2: either something like 2 (for magic) or a large value that might be some sort of offset/pointer
arg3: integer representing magic type e.g. 0x0C for Bio, 0x23 for haste
arg4: some pointer?
arg5: some dinput call or null (I've not actually investigated it, it might just be an assumption by my debugger)
arg6: target bitmask
arg7: some d3d call or null (I've not actually investigated it, it might just be an assumption by my debugger)

EDIT: Couple of other things:
function at 0x47E970 gets the name of magic from an ID
all the magic is listed in structs of 60 bytes from 0x1CF4064, no idea what these values are or if they're static/loaded from a file. I only know that the first word is an offset for locating the name and the second word is an offset for the description - the rest are a mystery and may relate to damage, status etc. or they could be completely useless for what you want.
The bytes that are usually 0x64 are probably for status/elemental stuff - could also be for junctions.
for example: bio has an id of 0x0C, so all the bio stuff is the 60 bytes at address 0x1CF4334
There's probably magic info stored elsewhere too, I'll see if I can dig out any more information at a later date.
Hope that helps! :)

list of magic can be found in this post:
http://forums.qhimm.com/index.php?topic=11137.msg166280#msg166280

168
Gameplay / Re: [FF8PC-Steam] Magic Strengthen
« on: 2016-04-28 13:52:26 »
I'm currently also looking in the the AI code - I'm slowly working on reversing the function located at 0x00487DF0 in the Steam version - it's essentially what handles every opcode.
See this thread:
http://forums.qhimm.com/index.php?topic=16838.msg240173#msg240173

JeMaCheHi, is there a list of known opcodes somewhere? - it'd help with the reversing process :).

169
Is this for the PC or Playstation version of FF8?

170
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.

171
Nice work! That seems like a crazy amount of functions o_0

Here's my latest information on the battle stuff:
Code: [Select]
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
};

vars 60-67:
Code: [Select]
DWORD * const vars = (DWORD*)0x1D28D98; //- 60 to 67 - base address used is 0x1D28C18 - array of size 8

and a few functions (note that parameter signs/sizes might not be accurate):

Code: [Select]
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

the start of the AI function mentioned before goes something like this:
Code: [Select]
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?
}

so there are a couple of interesting things...
There appear to be 40 bytes used for status resistance stuff but only 19 are actually loaded from dat files, the rest are just set to 100 during loading... so the rest are a mystery - could be The End, Vit0, unused...
The first status byte seems to contain timed statuses, so I wonder where the timers for these are.
Also I believe opcode 0x0F is used to set global vars (60-67) and 0x0E to set local ones (DC-E3) you can write outside those variable ranges but:
a) you'll probably be writing into areas of memory that you probably shouldn't (overriding stats etc.)
b) the test opcode (0x02) will not test values outside of those ranges
opcode 0x12 is for adding to local vars.
opcode 0x13 is for adding to global vars.
opcode 0x15 also do addition of some sort but I haven't discovered what to yet.
opcode 0x24 fills the ATB gauge.
opcode 0x2D is for changing elemental resistances (e.g. 2D 00 F4 01 sets fire resistance to 500).
opcode 0x36 disables Odin and enables Gilgamesh

Expanding on what random_npc said about 02 02 being probability:
The next byte is used as a modulus and the comparison is done as normal e.g.
02 02 03 01 02 00 XX XX
is basically:
if (rand() % 3 < 2) { //should be 2/3 probability
    do stuff;
}

EDIT: realized that I screwed the padding up at some point and all the addresses were out of alignment, should be fixed now.
EDIT1: this: http://wiki.qhimm.com/view/FF8/GameSaveFormat is located at 0x1CFDC58 in memory, I noticed some checks for stuff in there in the battle code.

172
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: [Select]
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:
Code: [Select]
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 :(.

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: [Select]
floor((floor(level * a/10) + floor(level / b) - floor(level * level / d / 2) + c)/4)

173
looking at the code:
Code: [Select]
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

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

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

174
I noticed when poking around the memory at the actual values that some of the values in Ifrit were 1 off but it's probably a rounding issue, I could take a look in the code and see where it pushes the value from.

EDIT:
Function that gets the values in FF8_EN.exe (Steam version) is at 0x48C3F0 and takes 3 parameters:
param 1: level
param 2: pointer to section 7 of a dat file
param 3: integer (0 = str, 1 = mag (think this actually vit), 2 = vit (think this is actually mag), 3 = spr, 4 = spd, 5 = eva)

Is the information on http://wiki.qhimm.com/view/FF8/FileFormat_DAT#Section_7:_Informations_.26_stats in the correct order?
Since I'd expect the formulas for str and mag to be the same rather than str and vit - I'm guessing mag and vit should be swapped since the order they usually appear in is str, vit, mag, spr, spd, luck, eva (although monsters have no luck).

For the following sections:
ESI = pointer to the 4 bytes needed, so ESI = 1st byte, ESI+1 = 2nd byte, ESI+2 = 3rd byte, ESI+3 = 4th byte
arg.1 = level
result ends up in EAX
ok, here is the ASM for the mag, spr, spd and eva cases (it gets capped to 255 after this but I've omitted that part) - I think this is actually for vit, spr, spd and eva, see note above:
Code: [Select]
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

if you're not using integer arithmetic, this is the same as: floor(lvl/b) - floor(lvl/d) + a*lvl + c - which is the same as JBedford128's formula above


ASM for str and vit (it gets capped to 255 after this but I've omitted that part): - I think this is actually for str and mag, see note above
Code: [Select]
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)

So something like:
floor((floor((lvl*a*0x66666667)/2^34) + floor(lvl/b) - floor(floor(lvl^2/d)/2) + c)/4)
as a rough guess.
There are a couple of things I'm not sure about above though and probably some mistakes in the annotations above. Someone that's better at signed arithmetic would probably help :P.
The formula actually looks fairly close to what JBedford128 had (note that 0x66666667/2^34 is ~1/10 - it's so close that you could probably just use divide by 10 and it probably was in the original code - I suspect it's a compiler optimization for division by 10) - the only main difference is the flooring.
I'd say that:
floor((floor(lvl*a/10) + floor(lvl/b) - floor(floor(lvl^2/d)/2) + c)/4) probably works.
or if you're using integer arithmetic:
((lvl*a)/10 + lvl/b - (lvl^2/d)/2 + c)/4
I do wonder if this differs from the PSX code though.

175
Hehe, looks nice! Now you can deal all of the damage in the world :D

Update to the Monster structure:
Note, the offsets listed are for the first struct in the array, they are usually referenced with address + (208*monster_id) - the unknown padding is mostly in sizes of 8 so it's easy to replace it when I find out what some values are.
Code: [Select]
//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)

I'd imagine that the struct above is referenced all over the battle code, so I'm trying to decipher as much of it as I can so that understanding what other battle functions do will be a lot easier.
I've found that generally the ID of the monsters is 3, 4 and 5 (no idea what happens with 8 monster battles yet), so the first monster you fight will have its parameters at 0x1D27D80 rather than 0x1D27B10. It looks like it stores most of the parameters for the monsters that you're fighting, all I need now is to finish decoding it :D.
There's a bunch of interesting things I didn't know about the AI code, you have to be careful with some opcodes because you can override bits of memory that you shouldn't - which could lead to some random crashes.
opcode 0x0E is used to set a variable as mentioned by random_npc, there's a special case where the immediate is 0xCB which causes the variable to be assigned the value of last attacker instead of the immediate - it appears that 0xCB is treated as a special case in quite a few opcodes.
After further investigation, it seems there are 2 sets of variables DC-E3 (which are stored in the struct above) and 60-67 (which are stored separately - I assume these are global for the battle).
It looks like bad things would happen if you used opcode 0x0E to write outside the range DC-E3 but there's no constraint checking!

The 71 byte structure I mentioned before contains a series of multipliers for stats (str, mag etc.) which default to 10 (1x multiplier) among some other things that I haven't identified.

Notes on opcode 0x04 - Targeting:
the final form of this in the function is a bit mask to represent which enemies are targeted, looking at the code I can see the following:
0xC8: 0000 0000 0000 1000 //self (it just shifts 1 left by the monster id - this represents and id of 3)
0xC9: //random enemy - probably one of the first 3 bits is set
0xCA: //??
0xCB: //last attacker - does 1 << the value in it's struct (see struct above)
0xCC: 1000 0000 0000 0111 //all enemies
0xCD: 1000 0000 1111 1000 //all allies
0xCE: 1000 0000 1111 1111 //everyone?
0xCF: //random ally
0xD0: 1010 0000 0000 0111 //something to do with enemies
0xD1: //?? does 1 << the value in 0x1D28DFB
0xDC-0xE3: //does 1 << the value in the corresponding variable

Pages: 1 2 3 4 5 6 [7] 8