ff8 monsters : .dat files analysis

  • Thread starter Thread starter myst6re
  • Start date Start date
Status
Not open for further replies.
Unfortunately, there doesn't seem to be a count of how many different texture animations the model has
While there is no count, that kind of list usually marks its end with a zero offset, so you could check for those if you haven't already.

For the coordinate transformation, I don't know. The closest thing I can think of is that in FF9 you have to shift the UV for the weapon textures because in-engine they're not loaded at the beginning of a texture page, but that would only account for translating the coordinates, not scaling them.
 
if you need some informations about the AI section, you can ask me.
the part I meant is section 8 ('Battle scripts')
>:(

What do you wish to know exactly? I cannot answer everything, especially 'cause I am not home this week, but I have been playing a lot with this part and decrypted a lot of enemies strategy code.
 
I apologize.  The question was mostly posed to you, but I thought it best to phrase it in a more general sense.  No offense intended.  Actually, your the only person I know of who is knowledgeable about FF8's battle scripts (others have likely done work on it too, I'm just unaware of it).  I'm new to working on FF8's AI, most of my AI work has been on FF6, which is far more simplistic.  As of now, the only thing I can do reliable is change targeting.  That said, any information on section 8 would be useful, but mostly I'm looking for some basics.
 
I'm finally back home, sorry for keeping you waiting!

Okay, I'll tell you some things about FFVIII ai scripts, I hope myst6re doesn't mind the huge post in this topic. You might have figured out already part (or all?) of what is written below, but I find it more apropriate to start with the basics. I have no idea how monsters ai is coded in other FF game, FFVIII is the only one I've been toying with.

First, structure. Part 8 can be divided as follow :
- offsets
- ai script
- text

I'd be detailling the offsets. Let's take the classical galbadian for example : (note -  '__' stands for '00')

03 __ __ __   
10 __ __ __   : point to ai offsets
d8 __ __ __   : point to text offsets
e4 __ __ __   : point to text lines
 
14 __ __ __   : point to loading code (executed when the enemy appears)
58 __ __ __   : point to code executed at enemy's turn
bc __ __ __   : point to counterattack code
c0 __ __ __   : point to death code
c4 __ __ __   : not sure about that one.

values are given starting from the beginning of part 8 for the first four, and from one line after for the other (I suppose that's what the second offset is for.)


Now, syntaxis.
Let's take an extract from Edea1 :
02 04 c8 03 15 __ 07__ 04 c8 0c 06 23 06 __ 04 c9 0b 01 02 03 23 06 __

here we have three parts. The first one is actually a test : 02 04 c8 03 15
All tests begin with 02 ; I'll detail them later. If the result from this test is true, it will follow with the amount of bytes that is given afterwards : 07 00, that's 7 bytes. So now we have : [test] __ 07 00 [code if true] 04 c9 0b 01 02 03 23 06 __

That 'code if true' ends with 23 06 00. You can translate that by : skip 6 bytes. So in this case, we have a simple "if(condition is true) {04 c8 0c 06} else {04 c9 0b 01 02 03}"!

Last thing to tell : when the code will enconter a 00 it will stop. Best example is that piece of code, which you'll encounter with a lot of enemies, that tell them to skip their turn :
02 02 03 __ __ __ 04 __ [__ 23 __ __]
(02 02 03 is a probabilty of 1/3)


Now. Let's detail a little more what we can encounter - keep in mind that I'm far for having decrytped everything.


Tests

for most of them (I'm not sure about how the probability thing exactly works)
first byte  : 02
third byte : target.
fourth byte  :
   00 :  =
   01 : <
   02 : >
   03 : !=
   04 : <or= 
   05 : >or=
fith byte : number

second byte - tells what to check
00 : monster own HP   (ex : 02 00 c8 01 03 __ would be if his HP are below 30%)
01 : other monster HP (ex: 02 01 57 01 05 __ would be if a galbadian is below 50%)
03 : battle scene         (ex : 02 03 c8 03 04 : if we are not in fight 04)
04 : self, status (ex below : 02 04 c8 03 15, if she haven't got status 15 (safe))
05 : ennemies, status  (ex : 02 05 c8 00 17, if one of us acursed seeds have got status 17 (reflect))
06 : number of alive members in our party (ex : 02 06 c8 00 01, only one remains)
09 : is a certain character is present & alive (ex : 02 09 c8 00 03 : if Quistis is here)
0e : monster difficulty level (ex : 02 0e c8 05 01 : if difficulty level higher or equal to ‘1’ (medium)
   00 = retarded n00b, 01 = medium, 02 = hard.
11 : check if we have stolen a GF (ex : 02 11 c8 03 cc : monster lost his GF.)

talking of status, here is my current list :
        01 :   poison
        03 :   blind
        04 :   mute
        05 :   berserk
        06 :   zombi
        10 :   sleep
        11 :   haste
        15 :   safe
        16 :   shell
        17 :   reflect 
        18 :   aura
        1d :   float
        1e :   confuse
        21 :   double
        22 :   triple


Variables - just a few examples

ex : dc, dd, de, df, 60, 61 ...
0e dc 00 : set dc = 0
13 60 01 : add 1 to 60.
02 dc c8 00 00 : if(dc=0)

 
Text :
texts can be launched by some attacks, but it can be called directly from the ai code as well.
01 02 : say text line n°3.
1a 01 : say text line n°2, but after attack.
There are others, I won't detail all of them.


... I will continue later
 
Last edited:
Excellent work, random_npc.

As for the AI scripts you're unsure about, c4 could be a battle end, pre-turn or 'special script'. FF7's AI engine let scripts call one of eight 'custom event' AI functions; it's entirely possible something similar is done here. Practically speaking, there's quite a few interesting hacks and effects you can implement with a pre-turn script, so again, that's another contender.

Keep posting!
 
Thanks Bosola !

About the one that I am unsure, I mostly haven't try putting stuff in here, and all monster files I've been working on had it empty.

Well, what should be added...


Stats
you can increase/decrease your monster stats.
Best example for that is Jelleye, that monster who change its characteristics. If you analyse its ai script, you'll see a lot of those :
25 [some value]   28 00 [some value]   28 02 [some value]   28 01 [some value]   28 03 [some value]

don't bother with 25 [some value], this will just add the specified line of text to the scan. 25 01 add the second line of text to the scan, and so on.

Normal Defense Morph    : 28 00 0a   28 02 0a   28 01 0a   28 03 0a
Complete Defense Morph : 28 00 0a   28 02 0a   28 01 28   28 03 28
Magic Defense Morph      : 28 00 05   28 02 14   28 01 03   28 03 64
Physical Defense Morph   : 28 00 14   28 02 05   28 01 64   28 03 03 

stats : 00=strength, 02=magic, 01=physical defense, 03=magic defense. There is also 04=speed, 05=evasion.
value : 0a = 10 in decimal, that means the monster normal stat. 28 would be 40, so four time the normal stat, and 64 10 times the normal stat. 03 or 05 will decrease its stat.


Items
You can award items to the player at the end of the combat in the ai script as well. For example, in Elvoret original code, 38 b2 will give you the march weapon magazine. 


Auto-status
You can give some auto-status to your enemies. For example, the two Iguion have a permanent reflect on them as long as you haven't stolen Carbunkl from them. It's a bit buggy, and it cannot be remove with dispel spell. The command to remove this auto-reflect is 27 17 00. 27 17 01 would set it up. 


Removing/Adding monsters.
We have an example in Wedge or Biggs code :
1d 00    1d 01    1f 02 = remove monster n°1, remove monster n°2, launch monster n°3 (Elvoret).
There can be up to 8 monsters in one battle, but there can be only 4 present at the same time.
(In the time compression sorcerers fight, there are actually 6 monsters, that are resurrected with different characteristics to fight you again)

An enemy can be launched or not, visible or not, targetable or not - I won't detail it today.
 

Target & Attack
04 ... is the simple way to target something.
   00->07 : Squall -> Edea (it should work up to Laguna, Kiros and Ward as well but I haven't check those)
       00 : Squall 
       01 : Zell
       02 : Irvine
       03 : Quistis
       04 : Linoa
       05 : Selphie
       06 : Seifer
       07 : Edea
        c8 :  self
        c9 :  random enemy
        cc :  all enemies
        cd :  all allies
        cf :  random ally
there are other values I'm not totally sure about.
Usually the target code is followed with a move command, in the Edea1 example I had given previously you had 04 c8 0c 06, 0c 06 being move n°7 (the move are listed in the section before, myst6re wrote about those). In this case move n°7 was the safe spell, so the code was simply : if(self hasn't got safe status) cast safe on self.
The target can be set way before the actual move command, and in some cases it seems the programmer forgot he had already set a target, because he wrotes the target code again - you might have notice it : some monsters first turn to one of your character, but then attack another one... that's why.

There are more complex target code. For example, still in Edea1's code :
02 05 c8 00 17 __ 17__ [26 __ c8 00 17    02 02 04 03 __ __ 05__ [0c 07 23 02 __] 0c 00 23 c8__]
move 07 is dispel magic and move 00 is her (weak) physical attack, so you can translate it in pseudo-C++  by :

if(an enemy has got reflect status) { target the enemy with reflect status;
   if(some probability) cast dispel; else astral punch; }

The whole target code is 26 00 c8 00 17. 

You can also target a specific monster : 26 00 57 00 09 targets a wounded galbadian. (the most wounded?)
Raijin or the red galbadian use this code to cure them. Totally useless in the original game, considering galbadian soldiers had so few HP you'd kill them in one hit. 02 01 57 01 05 __ 0c__[26 __ 57__ 09...
   

I've explained an attack code just before, but there are some other things you could add : let's take the final part of the first example I had taken from Edea1 : 04 c9 0b 01 02 03 23 06 __
so that's "target a random enemy; 0b=chose one of those three moves: move 2,3 or 4; skip 6 bytes".   
       
You can use some moves not listed in the moves section. However, it will only be some graphical or sound stuff, no damage will be calculated and no status applied. For example, in my edited Elvoret I've used 04 cd 1e 5f to sort-of summon Siren, or in Biggs or Wedge code, 04 cd 1e 6e  is the Wind attack that make them fly away.


Well, I don't know what else I could tell for now. Any questions?... Or would someone want to add anything?
 
Last edited:
Thanks!  Amazing!  Wonderful work!  That covered pretty much everything I was looking for and then some.  I need to take a few days and test all this information to make sure that I understand it correctly, but I'll probably have a few questions.  For now, though, I have two questions.  One, do you have any idea what the status byte for "death" is (probably not all that necessary with FF8's targeting system, but it was essential for FF6)?  Two, have you found the target byte for "last enemy that attacked" (mainly for use with controlled counterattacks)?

Thanks again for all the information!

Edit:  The target byte for "last enemy that attacked" is CB (I'm fairly certain, but I haven't tested it extensively).
 
Last edited:
Wow, you did a pretty good job and all, but... myst6re is a French GUY :evil:

More seriously, I believe that now that FF7 is mostly decoded, we will go into FF8 ^^
 
Oops, indeed I forgot to elaborate on counterattacks. You might want to analyse Ifrit's ai, it checks a lot of interesting things here : if attack was a GF, if attack was shiva, if attack was a spell, if it dealt no damage at all, if Squall was the attacker... The death status, I'm not sure about it - reading my notes I suspect 00, or maybe 02. The target byte for "last enemy who attacked", that should be cb indeed, somehow I forgot to mention this one.  :D 
Anyway, glad I could be of help. I hope you'll release some ai re-written monsters available to test! For my part, I have several changes I'd like to make to my Elvoret, and I still haven't managed to remove that anoying bug from my galbadians.
 
Wow. Thanks for analysis, now I can change something more in the next hardcore mod :)
 
People probably already know this, but I haven’t seen a list anywhere, so I thought I’d throw it out there.  In section 7 for altering monster abilities you need to know three things:  the byte for the type of ability, the byte for the type of animation, and the byte or bytes for the specific ability.

Ability Type: Magic, Byte 02
Animation Type: Byte 0B
Spell Bytes:
00 – Empty
01 – Fire
02 – Fira
03 – Firaga
04 – Blizzard
05 – Blizzara
06 – Blizzaga
07 – Thunder
08 – Thundara
09 – Thundaga
0A – Water
0B – Aero
0C – Bio
0D – Demi
0E – Holy
0F – Flare
10 – Meteor
11 – Quake
12 – Tornado
13 – Ultima
14 – Apocalypse
15 – Cure
16 – Cura
17 – Curaga
18 – Life
19 – Full-Life
1A – Regan
1B – Esuna
1C –Dispel
1D – Protect
1E – Shell
1F – Reflect
20 – Aura
21 – Double
22 – Triple
23 – Haste
24 – Slow
25 – Stop
26 – Blind
27 – Confuse
28 – Sleep
29 – Silence
2A – Break
2B – Death
2C – Drain
2D – Pain
2E – Berserk
2F – Float
30 – Zombie
31 – Meltdown
32 – Scan
33 – Full-Cure
34 – Wall
35 – Rapture
36 – Percent
37 – Catastrophe
38 – The End

Ability Type: Item, Byte 04
Animation Type: Byte 0B
Item Bytes:
00 – Empty
01 – Potion
02 – Potion+
03 – Hi-Potion
04 – Hi-Potion+
05 – X-Potion
06 – Mega-Potion
07 – Phoenix Down
08 – Mega-Phoenix
09 – Elixir
0A – Megalixir
0B – Antidote
0C – Soft
0D – Eyedrops
0E – Echo Screen
0F – Holy Water
10 – Remedy
11 – Remedy+
12 – Hero-Trial
13 – Hero
14 – Holy War-Trial
15 – Holy War
16 – Shell Stone
17 – Protect Stone
18 – Aura Stone
19 – Death Stone
1A – Holy Stone
1B – Flare Stone
1C – Meteor Stone
1D – Ultima Stone
1E – Gysahl Greens
1F – Phoenix Pinion
20 – Friendship

I’m still working on a list of monster abilities as well as what animations work with them (as sometimes there are multiple).

Sorry for the long post, but hopefully someone finds it useful.
 
Is there any more information anywhere on the DAT animation data?

What I've figured out so far is as follows:
The first byte is the number of frames as shown on the wiki.
The main function that reads the dat animation data looks to be at 0x00508F90.
There's a fixed array at 0xB8B9F0 of 4 bytes to help with uncompressing bits.
byte[] uncompress_helper = { 0x03, 0x06, 0x09, 0x10 }
There are 2 types of reads that are done on the animation data, bit reads and compressed bit reads.

there's a structure in memory used to parse the data that looks like:
struct animatonReadHelper {
    BYTE* current_animation_byte;
    int current_bit_position;
}

for bit reads, the following takes place:
int temp = *(current_position + 2) << 12 | *(current_position + 1) << 8 | *current_position //essentially reads 3 bytes in little-endian format
short value = (temp >> current_bit_position) & ~(0xFFFFFFFF << bitsToRead)
value = (value << (16 - bitsToRead)) >> bitsToRead //This looks odd but it's done as an arithmetic right shift to sign extend the bits

current_animation_byte += (bitsToRead + current_bit_position) / 8 // increases pointer by number of bytes read
current_bit_position = (bitsToRead + current_bit_position) % 8 // sets the position in the next byte to read from

For reading compressed bits, the following happens:
2 bits are read and this is used as an index with the fixed array above i.e.
0 -> 0x03
1 -> 0x06
2 -> 0x09
3 -> 0x10

Then this amount of bits are read and sign extended as above.
The function for compressed bit reads is at 0x00509320
The function for standard bit reads is at 0x005092A0
All offsets are for the English Steam version
 
What I said seems to match up to the position data stuff, I haven't looked deep enough into it yet to comment about the other stuff.
 
Status
Not open for further replies.
Back
Top