176
Scripting and Reverse Engineering / Re: [FF8] Engine reverse engineering
« on: 2016-04-11 16:40:40 »
There's an interesting sub at 0x00487DF0 (Steam version) which controls the AI code for monster turns (i.e. it parses section 8 of the .dat files).
Most of the function is essentially a giant switch statement on the current AI byte and then it goes to the next one until it finds 0x00.
The thing I like about this function is that if you replace it, you could make your own AI scripting system (e.g. using Lua), which would make for more interesting battle AI without faffing about with byte code.
the logic is something like: (note that this isn't 100% correct)
I'm currently working on reversing this function and the 60 cases of the switch statement (there's also nested switches for cases 0x02 and 0x04 =/) with some help from discoveries by random_npc (http://forums.qhimm.com/index.php?topic=11137.0) and the debug room.
EDIT: Slowly getting there, the structures are starting to make sense and it's helping with the AI opcodes... e.g. opcode 0x3C looks it adds the next word to it's own HP and 0x16 sets the current HP to the max HP.
Most of the function is essentially a giant switch statement on the current AI byte and then it goes to the next one until it finds 0x00.
The thing I like about this function is that if you replace it, you could make your own AI scripting system (e.g. using Lua), which would make for more interesting battle AI without faffing about with byte code.
the logic is something like: (note that this isn't 100% correct)
Code: [Select]
//0x1D27B10 - note: actual start address is earlier and some of the later items in the struct probably need to be moved to the start
#pragma pack(push, 1)
struct Character
{
uint8_t **monster_info; //pointer to section 7 of a loaded dat file in memory
uint8_t unk[124];
uint8_t unkbyte1D27B90; //unknown flag byte
uint8_t unk1[79];
};
#pragma pack(pop)
//0x1D28E89 - note: actual start address is earlier and some of the later items in the struct probably need to be moved to the start
#pragma pack(push, 1)
struct unk1D28E89
{
uint8_t unk_byte;
uint8_t unk[70];
};
#pragma pack(pop)
Character *ptr1D27B10 = (Character*)0x1D27B10; //208 byte structure - appears to be array of 6 items
bool *init_done = (bool*)0x1D28E09; //1 byte - seems to be 0 at first turn in battle for init then 1 otherwise
unk1D28E89 *ptr1D28E89 = (unk1D28E89*)0x1D28E89; //71 byte structure - appears to be array of 6 items
uint32_t my_sub_487DF0(uint32_t monster_id, uint8_t *AICode, uint8_t *arg3, uint8_t *arg4) //monster id seems to be 3,4 or 5... I'm assuming 0, 1 and 2 are reserved for your party
{
uint32_t local0;
uint32_t local1;
uint32_t local2;
uint32_t local3;
uint8_t next_ai_byte_1; //local.4_0
uint8_t next_ai_byte_2; //local.4_1
uint8_t next_ai_byte_3; //local.4_2
uint32_t local5;
uint8_t current_ai_byte; //local.6_0
uint8_t local7_0;
uint8_t *monster_info; //local.8_0
uint32_t local9;
uint32_t local10;
uint32_t local11;
uint32_t local12;
uint32_t local13;
uint8_t local14_0;
uint32_t local15;
uint32_t local16;
uint32_t local17;
uint32_t local18;
uint32_t local19;
uint32_t local20;
uint8_t local21_0;
uint32_t local22;
uint8_t local23_0;
uint32_t local24;
local22 = (uint32_t)ptr1D28E89[monster_id].unk;
local21_0 = 0;
local7_0 = 0;
local23_0 = 0;
monster_info = *ptr1D27B10[monster_id].monster_info;
local14_0 = 0;
local24 = 0; //esi
//monster_id = 0 - esi
if (init_done && ptr1D27B10[monster_id].unkbyte1D27B90 & 0x20 != 0) {
//TO DO
//jumps somewhere - I've not really seen this section of code called
}
//loop
do {
current_ai_byte = *AICode++;
switch (current_ai_byte) {
//TO DO
}
} while (current_ai_byte != 0);
}
I'm currently working on reversing this function and the 60 cases of the switch statement (there's also nested switches for cases 0x02 and 0x04 =/) with some help from discoveries by random_npc (http://forums.qhimm.com/index.php?topic=11137.0) and the debug room.
EDIT: Slowly getting there, the structures are starting to make sense and it's helping with the AI opcodes... e.g. opcode 0x3C looks it adds the next word to it's own HP and 0x16 sets the current HP to the max HP.