[FF8] Engine reverse engineering

  • Thread starter Thread starter Halfer
  • Start date Start date
Status
Not open for further replies.
The patch I made makes the unused byte in the .dat files (which is marked as percent in ifrit) change vit0, there is no vit0 byte normally.
He's just changing percent byte in Ifrit after applying the patch I made, which edits vit0.
 
Last edited:
No, there is no need for manually changing that byte with a hex editor. After applying JWP's code changes to the .exe, you can use Ifrit and adjust that byte to your liking for Vit 0 resistance. For example, choose 155 for complete immunity, then start up the game and try inflicting Vit 0 on that enemy. It should no longer work.
 
So I had another look at the GFs today... it seems that there are a bunch more functions than I had anticipated =/.

Take for example Shiva...
the main function that I've put in this post is 0x005C0D50.
a bit later in that function, function pointers are pushed as arg2 to the function 0x508360 (it's called twice) - the function pointers that are pushed are 0x5C7F50 and 0x5C0F30 - I'm assuming the function 0x508360 stages those 2 functions to be called every frame.
both of these functions appear to be called every frame (I guess it controls the animation) since there's a switch at 0x5C0FC5 that switches on a number that increases every time the function is called.
This switch appears to control things that happen during the animation - I'm assuming that it's switching on the frame number (e.g. loading extra files - the function 0x508480 loads files from this array)
The arg to both of these functions is a pointer to some sort of struct, of which the DWORD at offset 0x0C is the current frame number.

Since the constants in the function 0x5C0F30 appear to be for Shiva - (for example the file loaded at 0x5C0FFE uses the constant 0x21F for MAG184_D.DAT), I'm assuming that there are functions like this for all the GFs and possibly magic too.
 
Last edited:
@JWP: one more question about your Vit0 patch, I tried it with the german version but it didn't work, and I realised that the offsets in the German FF8.exe are all exactly 48 bytes further down than in the English version that you posted earlier.

While your offsets are:

0x8BEE8:
0x8BF95:
0x8C014:
0x8C131:

Mine are:

0x8BF18:
0x8BFC5:
0x8C044:
0x8C161:

I suppose due to this the patch can't be applied 1:1 because certain jumps in your patch might lead to wrong places. Do you by any chance know what I would need to change in order to make it work for my version?
 
Should work with the new addresses as long as they are offset by the same amount and the code around the area is actually the same because all the jumps are encoded with relative addresses.
Although they appear to be absolute addresses in the assembly code, at the machine code level they are encoded as relative jumps.
EB and E9 opcodes (which are used for the jumps in the patch) both use relative addresses, see here.

If patching the new addresses doesn't work, could you give me a disassembly of the area in question?
 
Last edited:
Ah thanks, I think I see what's wrong now.
The offset of the battle data in memory is different so the offset 0x1D27BC0 in the code no longer works. It looks like the battle data is offset 0x1A80 higher in memory in the German version.
I think the full patch for the German version should be:

Code: [Select]
Code:
from: 0x8BF18: B90A 0A0A 0Ato:   0x8BF18: E9A8 0000 00from: 0x8BFC5: 9090 9090 9090 9090to:   0x8BFC5: 8A87 7B01 0000 EB77from: 0x8C044: 9090 9090 9090 9090 9090 90to:   0x8C044: 8886 4096 D201 E912 0100 00from: 0x8C161: 9090 9090 9090 9090 9090to:   0x8C161: B90A 0A0A 0AE9 B2FD FFFF
let me know if it works :)
 
Last edited:
Thanks a ton, it worked now! I just tried it in the Cerberus battle and casted about 20-30 Meltdowns on him without inflicting the status once!
 
I'm guessing this is known but I can't find a list anywhere.
I found an array of function pointers starting at 0xB8DE94 which appear to be related to all the field opcodes.

Here's a full dump of addresses corresponding to these opcodes:
Code: [Select]
Code:
000 0x0051C160001 0x0051C4B0002 0x0051C4D0003 0x0051C4F0004 0x0051C530005 0x0051C570006 0x0051C5C0007 0x0051C990008 0x0051CAB0009 0x0051CC7000A 0x0051CAF000B 0x0051CCA000C 0x0051CB3000D 0x0051CCD000E 0x0051CB7000F 0x0051CD00010 0x0051CBB0011 0x0051CBF0012 0x0051CC30013 0x0051CD30014 0x0051CD60015 0x0051CED0016 0x0051D060017 0x0051D1F0018 0x0051D360019 0x0051D53001A 0x0051DD8001B 0x0051D70001C 0x0051D71001D 0x0051D72001E 0x0051D78001F 0x0051D7F0020 0x0051D830021 0x0051FF00022 0x00520460023 0x005256A0024 0x00525740025 0x00525900026 0x00525A30027 0x00525B60028 0x00525CA0029 0x00521A2002A 0x00521AC002B 0x0051D8F002C 0x0051D9B002D 0x0052657002E 0x0052662002F 0x005266D0030 0x00526810031 0x00526890032 0x00526910033 0x00526990034 0x005269E0035 0x00526A30036 0x00526AB0037 0x0051DA00038 0x00521B70039 0x0051DC3003A 0x0051DCE003B 0x0051DD0003C 0x0051D87003D 0x005233E003E 0x0052341003F 0x00523640040 0x00523880041 0x00523AD0042 0x00523C20043 0x00525800044 0x005264D0045 0x005264F0046 0x00528E40047 0x00528F20048 0x00529900049 0x00528D4004A 0x0052952004B 0x00529A2004C 0x00529B6004D 0x0051DDA004E 0x0051DE9004F 0x0051F390050 0x0051F4F0051 0x0051E0E0052 0x00526E60053 0x00526E90054 0x00526F30055 0x00526F70056 0x0051F520057 0x0051EBB0058 0x0051EBD0059 0x0051EBF005A 0x0051EC1005B 0x0051ED8005C 0x00521C3005D 0x00521CB005E 0x00521CC005F 0x00528E10060 0x0051EAD0061 0x0051EB40062 0x0051EDD0063 0x0051EE00064 0x00529020065 0x005291E0066 0x0051EE30067 0x0051ED40068 0x0051ED60069 0x0052327006A 0x005232E006B 0x0052330006C 0x0052333006D 0x0051DA5006E 0x0051DAA006F 0x005296C0070 0x0051EEB0071 0x00520C40072 0x00520C90073 0x00520CF0074 0x00520D50075 0x00520D90076 0x00520DF0077 0x00520F50078 0x00524030079 0x005241A007A 0x0052431007B 0x0052449007C 0x0052455007D 0x0052460007E 0x0051D8B007F 0x00520E50080 0x00520E90081 0x00520EF0082 0x00527250083 0x00527320084 0x005273F0085 0x005274C0086 0x0051E160087 0x0051E270088 0x0051E350089 0x0051E5D008A 0x0051E40008B 0x0051E5E008C 0x0051E67008D 0x0051E71008E 0x0051E7D008F 0x00527590090 0x00527690091 0x00527790092 0x005278A0093 0x00524BA0094 0x005299F0095 0x00520570096 0x00520640097 0x005206E0098 0x00520780099 0x005207A009A 0x0052080009B 0x0052085009C 0x005216E009D 0x0052173009E 0x005217F009F 0x00526C300A0 0x00526C800A1 0x0051F6200A2 0x0051F6700A3 0x0051F2C00A4 0x005217100A5 0x005283B00A6 0x005284900A7 0x00528CA00A8 0x00520BA00A9 0x00520C200AA 0x00528D100AB 0x0051EC300AC 0x0051ECF00AD 0x005233700AE 0x005233800AF 0x00526E300B0 0x00526D300B1 0x00523D700B2 0x00523ED00B3 0x00526CD00B4 0x0051F7F00B5 0x0051F7300B6 0x00528CE00B7 0x00526B000B8 0x00526B800B9 0x005217B00BA 0x0051FA500BB 0x0051FB000BC 0x0051FEA00BD 0x0051FDE00BE 0x0051F6800BF 0x0051FBD00C0 0x0051FC700C1 0x0051FCD00C2 0x0051FD400C3 0x0051FFA00C4 0x0051FFD00C5 0x005200100C6 0x005200400C7 0x005200800C8 0x005200C00C9 0x005201100CA 0x005201500CB 0x0051F7000CC 0x005232300CD 0x005201A00CE 0x005208800CF 0x0051F6900D0 0x005208B00D1 0x00520AD00D2 0x005209A00D3 0x00520FA00D4 0x005210100D5 0x005210900D6 0x005211100D7 0x005211700D8 0x005211F00D9 0x005212700DA 0x005212D00DB 0x005213500DC 0x00520F600DD 0x005213D00DE 0x00521D000DF 0x00521CF00E0 0x005204E00E1 0x005205000E2 0x005205200E3 0x005205500E4 0x005219600E5 0x0051DD600E6 0x005250900E7 0x005264A00E8 0x0051D8D00E9 0x005285700EA 0x005286700EB 0x005287700EC 0x005288A00ED 0x005289D00EE 0x00528B200EF 0x00528C700F0 0x00525DE00F1 0x00525E700F2 0x00525F300F3 0x00525FF00F4 0x005260A00F5 0x005261500F6 0x005261800F7 0x005261700F8 0x00521CD00F9 0x00521CE00FA 0x005261900FB 0x0051D9100FC 0x0051D9600FD 0x00527B900FE 0x00527C300FF 0x00527D30100 0x00528300101 0x00527E40102 0x0051DB90103 0x0051DBC0104 0x0051DBF0105 0x0051DC10106 0x00528D80107 0x00528350108 0x00527AF0109 0x0051EFB010A 0x005218E010B 0x0052335010C 0x0052049010D 0x0052182010E 0x00527F1010F 0x00527FA0110 0x00528030111 0x00528130112 0x00528240113 0x00527AD0114 0x0051F0C0115 0x0051F140116 0x00529380117 0x00520B00118 0x005261C0119 0x005261A011A 0x00521D1011B 0x00521D4011C 0x005216B011D 0x0051E64011E 0x00521D6011F 0x00523390120 0x005214C0121 0x00521530122 0x005215F0123 0x00524840124 0x00524810125 0x00522380126 0x00523180127 0x005231C0128 0x0051EA10129 0x00521DA012A 0x005220A012B 0x0052462012C 0x005246F012D 0x0051F1F012E 0x0052219012F 0x005221B0130 0x00522280131 0x0051EA50132 0x0051F600133 0x00523200134 0x00521930135 0x0051F9A0136 0x005224D0137 0x00522770138 0x00522230139 0x0051E0B013A 0x005225A013B 0x00529BF013C 0x00529C4013D 0x00529E7013E 0x0052146013F 0x0051EF70140 0x0051FC20141 0x0051F880142 0x0051DD40143 0x0051DD20144 0x0051F900145 0x005220B0146 0x00522110147 0x00522150148 0x005247E0149 0x0051FDC014A 0x0052639014B 0x005263F014C 0x0051DAF014D 0x0051DB4014E 0x005230E014F 0x00523110150 0x0051FBA0151 0x005223C0152 0x00522420153 0x00522480154 0x00523140155 0x00523030156 0x00522070157 0x0051E910158 0x0051E990159 0x0051E9C015A 0x0052201015B 0x0052624015C 0x0052628015D 0x005262C015E 0x0052250015F 0x00522540160 0x00522570161 0x005222D0162 0x0051E8A0163 0x0051E860164 0x0051F5B0165 0x00529D40166 0x00529EB0167 0x00529EF0168 0x00529F70169 0x0052621016A 0x0052235016B 0x00526FD016C 0x0052707016D 0x0052711016E 0x005271B016F 0x0051FC40170 0x005279B0171 0x00527AB0172 0x00520200173 0x00520230174 0x005258D0175 0x005230A0176 0x005219F0177 0x00522030178 0x00320000179 0x00960064
I've not actually tested them yet though :P
Not sure if they're numbered correctly since there are some jumps in the opcode numbers.
 
Last edited:
I'm guessing this is known but I can't find a list anywhere.
I found an array of function pointers starting at 0xB8DE94 which appear to be related to all the field opcodes.
Oh, this is gold! Thank you so much JWP! This will speed up reversing process extremely, because we could be able to locate functions and variables via scripting!

They are not numbered correctly. I could test it only on three examples, but:
53 entry is mine SFX_sub_51FDB0 (related to sound effect) and on list 0x35 is 035 RANIMELOOP
299 entry is mine WorldMap_To_Balamb_Music (Related to AKAO frame and is called when from WM to town) and on list 0x12B is 12B MOVECANCEL
329 entry is mine Draw_Interaction_GetMagic (In fact it's DRAWPOINT opcode) and on list 0x149 is 149 MUSICVOLSYNC, but should be     137 DRAWPOINT

@UPDATE: No, it's kind of okay I think.
The first 16 offset pointers are for 01 CAL operations:
http://wiki.qhimm.com/view/FF8/Field/Script/Opcodes/001_CAL

Now it works:
33 entry (0x21) is opcode:     021 EFFECTPLAY2 (OKAY!)
180 entry (0xB4) is opcode: 0B4 MUSICCHANGE (Yes, therefore my WorldMap_To_Balamb_Music is correct then. It's only for music)
and last one to check for sure: 311 (0x137)     137 DRAWPOINT. Correct!
They are correctly numbered then.
 
Last edited:
Odd, I tested the following:
Code: [Select]
Code:
137 0x00522770 DRAWPOINT
and
Code: [Select]
Code:
155 0x00523030 SETDRAWPOINT
and they both seemed correct to me, what version of the game are you using? - it might be offset slightly in your version.
Easiest way to find the function pointer address list is to put a breakpoint on the DRAWPOINT opcode function, then exec until return and look at the line that called it, should be something like CALL DWORD PTR DS:[EAX*4+some_address]
some_address is where the function pointer list starts.

The only time the opcodes get weird is near all the unknown stuff but I think that might be the wiki since they're all called with opcode*4+function_pointer_base.
For instance, UNKNOWN16 in Deling (0x175) is labelled UNKNOWN10 on the wiki.
 
Last edited:
The 2000 version, but it's all right now. I counted the offsets including 16 CAL offsets, that's why there were some errors.
Cool, I'm going to update my database with correct names. The game uses those scripts even from own code function, so again JWP, great work!
 
Ah yeah, there are a bunch of function pointers for other stuff before the offset I listed, I was wondering what those were for.
 
I've been looking through and documenting some of the field stuff.
It seems like all of the field functions are called with 2 arguments:
arg1 = pointer to current entity data
arg2 = function argument

Background entities are 436 bytes each.
Door entities are 396 bytes each.
line entities are 416 bytes each.
Other entities are 612 bytes each.

the entity data looks something like the following (note there are gaps between the entries since I'm still filling the data in and there are probably some differences between entities):
There is probably a base class with all the stack and instruction stuff that the entities have in common and then it's extended differently depending on the entity type.
Code: [Select]
Code:
struct entity { DWORD stack[]; DWORD templist[8]; //+0x140 WORD instruction_pointer; //+0x176 BYTE stack_count; //+0x184 DWORD x_pos; //+0x190 DWORD y_pos; //+0x194 DWORD z_pos; //+0x198 WORD push_radius; //+0x1F6 WORD talk_radius; //+0x1F8 WORD triangle_id; //+0x1FA WORD move_speed; //+0x1FE WORD move_speed; //+0x200 WORD anime_speed; //+0x208 WORD model; //+0x218 BYTE angle; //+0x241 BYTE push_disabled; //+0x249 BYTE talk_disabled; //+0x24B BYTE through_enabled; //+0x24C BYTE base_anim_id; //+24F BYTE base_anim_first; //+250 BYTE base_anim_last; //+251 BYTE ladder_anim_id; //+252 BYTE ladder_anim_first; //+253 BYTE ladder_anim_last; //+254}
for init, the scripts are executed in this order (called in func 0x52C650):
1. background
2. door
3. line
4. other

during each frame, they are executed in this order (called in func 0x529FF0):
1. other
2. line
3. door
4. background

notable memory variables (offsets are for English Steam version):
Code: [Select]
Code:
BYTE 0x1D9CDF1 current_entityDWORD 0x1D9CF88 entity_ptr_otherDWORD 0x1D9CF8C entity_ptr_backgroundDWORD 0x1D9CF90 entity_ptr_doorBYTE 0x1D9D019 entity_count_otherBYTE 0x1D9D0E0 entity_count_lineBYTE 0x1D9D0E1 entity_count_doorBYTE 0x1D9D0E8 entity_count_backgroundDWORD 0x1D9D0F0 entity_ptr_line
 
Last edited:
I've been working quite a lot on Doomtrain but I also decided to take another look at the battle AI and coded a quick extension to Ifrit to help me view the AI data.
ifritai.png

Here's a list of opcodes - the names are just ones that I'm using for the pseudo-code:
Code: [Select]
Code:
0x01 - say(arg1)0x02 - if0x03 - setmagic(arg1) - sets a magic spell to use - not used but this can be used with 0x06 to cast the magic0x04 - target(arg1)0x05 - unknown05(arg1) - Used by Elvoret0x06 - domove() - not used in the game0x07 - setenemyattack(arg1) - similar to 0x03 but uses 0x08 as the type flag0x08 - die() - used a lot in death code to actually kill the entity (e.g. creeps, NORG Pod, Biggs, Wedge) - monsters that use this cannot be killed normally0x09 - unknown09(arg1) - I think this sets a flag byte to the byte specified - used by Seifer, Raijin, Edea, Left/Right Orb, Fake President, Adel0x0B - choose(arg1, arg2, arg3) - pick randomly between 3 moves0x0C - domoveid(arg1) - does the specified move from the move list0x0D - unused and appears to do nothing 0x0E - set self variable (vars are DC - E3)0x0F - set global battle variable (vars are 60 - 67)0x11 - set save variable (vars are 50-57 - these are stored in the save game file - tonberry count etc.)0x12 - add to self variable0x13 - add to battle variable0x15 - add to save variable0x16 - fillhp()0x17 - cannotescape(arg1)0x18 - unknown18(arg1) - appears to be another text print function - used by Tiamat, Wedge0x19 - all this does is skip a byte, it's used in the init code for Biggs and Wedge but does nothing useful0x1A - movesay(arg1)0x1B - unknown1B(arg1, arg2) - used by Biggs0x1C - unknown1C(arg1) - used by Fake President, BGH251F2, Mobile Type 8, Slapper, Biggs0x1D - remove(arg1)0x1E - magicid(arg1) - play specified magic id - used by Biggs, Wedge, Elvoret, G-soldier (for BGH251F2 battle)0x1F - launch(arg1)0x20 - similar to 0x1C but unused0x22 - unknown and unused0x23 - jump X bytes0x24 - fillatb()0x25 - scanadd(arg1)0x26 - targetadv(arg1, arg2, arg3, arg4)0x27 - autostatus(arg1, arg2)0x28 - changestat(arg1, arg2)0x29 - stealmagic() - steal random magic0x2A - castmagic() - cast stolen magic0x2B - targetposition(arg1)0x2C - uknown2C() - kills the entity and does something? - used by Seifer, Elvoret?0x2D - changeresistance(arg1, arg2)0x2E - killmagic() - blow away random magic0x2F - targetable() - not used0x30 - untargetable() - makes current entity untargetable0x31 - givegf(arg1)0x32 - unknown32() - used by Sphinxaur, Griever, Trauma0x33 - unknown33() - used by Sphinxara, Edea, Trauma, "Sorceress", Ultimecia0x34 - unknown34(arg1) - used by Trauma0x35 - unknown35(arg1) - used by Griever, Trauma0x36 - gilgamesh() - disables Odin and enabled Gilgamesh0x37 - givecard(arg1)0x38 - giveitem(arg1)0x39 - gameover()0x3A - targetableid(arg1) - makes entity in slot X targetable0x3B - unknown3B(arg1, arg2) - used by Ultimecia when spawning helixes and final form0x3C - addhp(arg1)0x3D - proofofomega()
note: opcodes 0x0A, 0x10, 0x14 and 0x21 don't exist.
Quite a few of the unknown codes might be related to spawning enemies, changing music or changing scene.

I might go into detail about some of the opcodes at another point.
 
Last edited:
DAMN!
This is amazing!

If you could, show the witch script please, either the first or second type witch. I'm looking for a starting point of level switch in witches battle (probably some magic or maybe other opcode). Still can't replace the stages even by using the original stage warp function, I'm missing something...
 
Sure :)

Sorc1 init:
Code: [Select]
Code:
if (var60 != 0){    var60 += 1    if (var62 == 0){        var62 = 1    }    else {        var62 = 2    }    target(200)    domove(1)    if (var60 == 2){        self.varDC = 2    }    if (var60 == 3){        self.varDC = 3    }    if (var60 == 4){        self.varDC = 4    }    if (var60 == 5){        self.varDC = 5    }    if (var60 == 6){        self.varDC = 6    }    if (var61 == 3){        var61 = 0        self.varDD = 3    }    else {        var61 = 0        self.varDD = 6    }}else {    var60 += 1    var62 = 1    var63 = 0    self.varDC = 1    self.varDD = 3    target(200)    domove(0)}
Sorc1 turn:
Code: [Select]
Code:
if (var60 >= 10){}else {    if (rand() % 2 == 0){        if (var62 == 1){            if (self.varDD == 3){                if (var60 >= 6){                    var61 = 4                    unknown33()                    launch(1)                    return                }                else {                    var61 = 6                    unknown33()                    launch(3)                    return                }            }            else {                if (self.varDD == 6){                    if (var60 >= 6){                        var61 = 5                        unknown33()                        launch(2)                        return                    }                    else {                        var61 = 3                        unknown33()                        launch(0)                        return                    }                }            }        }    }}if (rand() % 3 == 0){    return}if (rand() % 3 == 0){    target(201)    domove(3)    return}if (self.varDC == 1){    if (unknown(0x14) == 23){        if (enemy.status == 23){            targetadv(0, 201, 0, 23)            domove(2)            return        }        else {            target(202)            domove(5)            return        }    }    else {        targetadv(0, 200, 3, 23)        domove(2)        return    }}if (self.varDC == 2){    if (enemies.alive == 1){        if (unknown(0x14) == 23){            target(201)            domove(3)            return        }    }    else {        target(201)        domove(4)        return    }}if (self.varDC == 3){    if (enemies.alive == 1){        if (unknown(0x14) == 23){            target(201)            domove(3)            return        }    }    else {        target(201)        domove(8)        return    }}if (self.varDC == 4){    if (unknown(0x14) == 23){        if (enemy.status == 23){            targetadv(0, 201, 0, 23)            domove(9)            return        }        else {            target(202)            domove(5)            return        }    }    else {        target(201)        domove(9)        return    }}if (self.varDC == 5){    if (enemy.status == 4){        targetadv(0, 201, 0, 4)        domove(11)        return    }    else {        if (unknown(0x14) == 23){            if (enemies.alive == 1){                target(201)                domove(3)                return            }            else {                target(201)                domove(7)                return            }        }        else {            target(201)            domove(10)            return        }    }}if (self.varDC == 6){    if (unknown(0x14) == 23){        if (enemies.alive == 1){            target(201)            domove(3)            return        }        else {            target(201)            domove(7)            return        }    }    else {        target(201)        domove(15)        return    }}
Sorc1 death:
Code: [Select]
Code:
if (var63 >= 9){    die()    unknown33()    launch(4)}else {    if (var62 == 1){        var62 = 0        var63 += 1        die()        if (self.varDD == 3){            if (var60 >= 6){                var61 = 4                unknown33()                launch(1)            }            else {                var61 = 6                unknown33()                launch(3)            }        }        else {            if (self.varDD == 6){                if (var60 >= 6){                    var61 = 5                    unknown33()                    launch(2)                }                else {                    var61 = 3                    unknown33()                    launch(0)                }            }        }    }    else {        var62 = 1        var63 += 1        die()    }}
-----------------------------------------------------------------------------------

Sorc2 init:
Code: [Select]
Code:
var60 += 1if (var62 == 0){    var62 = 1}else {    var62 = 2}target(200)domove(1)if (var60 == 7){    self.varDC = 7}if (var60 == 8){    self.varDC = 8}if (var60 == 9){    self.varDC = 9}if (var60 == 10){    self.varDC = 10}if (var61 == 4){    var61 = 0    self.varDD = 4}else {    var61 = 0    self.varDD = 5}
Sorc2 turn:
Code: [Select]
Code:
if (var60 >= 10){}else {    if (rand() % 2 == 0){        if (var62 == 1){            if (self.varDD == 4){                var61 = 5                unknown33()                launch(2)                return            }            else {                if (self.varDD == 5){                    var61 = 4                    unknown33()                    launch(1)                    return                }            }        }    }}if (rand() % 3 == 0){    return}if (enemies.alive == 1){    if (rand() % 3 == 0){        target(201)        choose(4, 3, 15)        return    }    else {        return    }}if (rand() % 3 == 0){    target(201)    domove(4)    return}if (self.varDC == 7){    if (self.status != 23){        if (self.status != 33){            if (rand() % 2 == 0){                target(200)                domove(11)                return            }        }    }    if (self.status == 33){        target(201)        domove(3)        if (enemies.alive != 0){            target(201)            domove(3)        }    }    else {        target(201)        domove(3)    }    return}if (self.varDC == 8){    if (rand() % 2 == 0){        target(204)        domove(13)        return    }    else {        target(201)        domove(12)        return    }}if (self.varDC == 9){    target(208)    domove(8)    return}if (self.varDC == 10){    if (self.status != 23){        if (self.status != 33){            if (rand() % 2 == 0){                target(200)                domove(11)                return            }        }    }    if (self.status == 33){        target(201)        domove(7)        if (enemies.alive != 0){            target(201)            domove(7)        }    }    else {        target(201)        domove(7)    }    return}
Sorc2 death:
Code: [Select]
Code:
if (var63 >= 9){    die()    unknown33()    launch(4)}else {    if (var62 == 1){        var62 = 0        var63 += 1        die()        if (self.varDD == 4){            var61 = 5            unknown33()            launch(2)            return        }        else {            if (self.varDD == 5){                var61 = 4                unknown33()                launch(1)                return            }        }    }    else {        var62 = 1        var63 += 1        die()    }}
-----------------------------------------------------------------------------------

Sorc3 init:
Code: [Select]
Code:
self.varDC = 0self.varDD = 0target(200)domove(1)target(200)domove(3)
Sorc3 turn:
Code: [Select]
Code:
if (self.varDC != 0){    return}self.varDD += 1if (self.varDD == 3){    unknown18(0)    self.varDE = 1    target(200)    domove(4)}else {    if (self.varDD == 4){        unknown18(1)    }    else {        if (self.varDD == 5){            unknown18(2)            self.varDE = 1            target(200)            domove(5)        }        else {            if (self.varDD == 6){                unknown18(3)            }            else {                if (self.varDD == 7){                    unknown18(4)                    self.varDE = 1                    target(200)                    domove(6)                }                else {                    if (self.varDD >= 8){                        self.varDD = 0                        target(204)                        domove(2)                        self.varDE = 1                        target(200)                        domove(3)                    }                }            }        }    }}
Sorc 3 counter:
Code: [Select]
Code:
if (self.varDE == 1){    self.varDE = 0}else {    if (self.varDD <= 2){        target(203)        domove(0)    }}
Sorc3 death:
Code: [Select]
Code:
if (self.varDC == 0){    self.varDC = 1    target(200)    domove(7)    remove(200)}
Sorc3 unknown:
Code: [Select]
Code:
if (self.varDC == 0){    if (self.status == 0){        unknown09(3)    }}
I make no claims as to the accuracy of the above code :P - I know some of the if statements aren't very clear on their meaning and I haven't bothered fixing it yet.
 
Last edited:
I've been toying around with the AI code some more and I've added a working compiler for my pseudocode :D.
I can now make bytecode but I still haven't injected it into the dat files yet as I'd need to patch some offsets in.
In addition to this I've added if/else parsing to turn code like this:

Code: [Select]
Code:
self.varDC = 0self.varDD = 0self.varDE = 0if (character.alive == 3) {    movesay(1)    if (character.alive == 0) {        movesay(6)    }    else {        if (character.alive == 1) {            movesay(8)        }        else {            if (character.alive == 5) {                movesay(9)            }            else {                if (character.alive == 2) {                    movesay(10)                }                else {                    if (character.alive == 4) {                        movesay(11)                    }                }            }        }    }}else {    if (character.alive == 1) {        movesay(2)        if (character.alive == 0) {            movesay(6)        }        else {            if (character.alive == 3) {                movesay(7)            }            else {                if (character.alive == 5) {                    movesay(9)                }                else {                    if (character.alive == 2) {                        movesay(10)                    }                    else {                        if (character.alive == 4) {                            movesay(11)                        }                    }                }            }        }    }    else {        if (character.alive == 5) {            movesay(3)            if (character.alive == 0) {                movesay(6)            }            else {                if (character.alive == 3) {                    movesay(7)                }                else {                    if (character.alive == 1) {                        movesay(8)                    }                    else {                        if (character.alive == 2) {                            movesay(10)                        }                        else {                            if (character.alive == 4) {                                movesay(11)                            }                        }                    }                }            }        }        else {            if (character.alive == 2) {                movesay(4)                if (character.alive == 0) {                    movesay(6)                }                else {                    if (character.alive == 3) {                        movesay(7)                    }                    else {                        if (character.alive == 1) {                            movesay(8)                        }                        else {                            if (character.alive == 5) {                                movesay(9)                            }                            else {                                if (character.alive == 4) {                                    movesay(11)                                }                            }                        }                    }                }            }            else {                if (character.alive == 0) {                    movesay(0)                    if (character.alive == 3) {                        movesay(7)                    }                    else {                        if (character.alive == 1) {                            movesay(8)                        }                        else {                            if (character.alive == 5) {                                movesay(9)                            }                            else {                                if (character.alive == 2) {                                    movesay(10)                                }                                else {                                    if (character.alive == 4) {                                        movesay(11)                                    }                                }                            }                        }                    }                }                else {                    movesay(5)                    if (character.alive == 0) {                        movesay(6)                    }                    else {                        if (character.alive == 3) {                            movesay(7)                        }                        else {                            if (character.alive == 1) {                                movesay(8)                            }                            else {                                if (character.alive == 5) {                                    movesay(9)                                }                                else {                                    if (character.alive == 2) {                                        movesay(10)                                    }                                }                            }                        }                    }                }            }        }    }}movesay(12)movesay(13)unknown1C(4)
into this:
Code: [Select]
Code:
self.varDC = 0self.varDD = 0self.varDE = 0if (character.alive == 3) {    movesay(1)    if (character.alive == 0) {        movesay(6)    }    else if (character.alive == 1) {        movesay(8)    }    else if (character.alive == 5) {        movesay(9)    }    else if (character.alive == 2) {        movesay(10)    }    else if (character.alive == 4) {        movesay(11)    }}else if (character.alive == 1) {    movesay(2)    if (character.alive == 0) {        movesay(6)    }    else if (character.alive == 3) {        movesay(7)    }    else if (character.alive == 5) {        movesay(9)    }    else if (character.alive == 2) {        movesay(10)    }    else if (character.alive == 4) {        movesay(11)    }}else if (character.alive == 5) {    movesay(3)    if (character.alive == 0) {        movesay(6)    }    else if (character.alive == 3) {        movesay(7)    }    else if (character.alive == 1) {        movesay(8)    }    else if (character.alive == 2) {        movesay(10)    }    else if (character.alive == 4) {        movesay(11)    }}else if (character.alive == 2) {    movesay(4)    if (character.alive == 0) {        movesay(6)    }    else if (character.alive == 3) {        movesay(7)    }    else if (character.alive == 1) {        movesay(8)    }    else if (character.alive == 5) {        movesay(9)    }    else if (character.alive == 4) {        movesay(11)    }}else if (character.alive == 0) {    movesay(0)    if (character.alive == 3) {        movesay(7)    }    else if (character.alive == 1) {        movesay(8)    }    else if (character.alive == 5) {        movesay(9)    }    else if (character.alive == 2) {        movesay(10)    }    else if (character.alive == 4) {        movesay(11)    }}else {    movesay(5)    if (character.alive == 0) {        movesay(6)    }    else if (character.alive == 3) {        movesay(7)    }    else if (character.alive == 1) {        movesay(8)    }    else if (character.alive == 5) {        movesay(9)    }    else if (character.alive == 2) {        movesay(10)    }}movesay(12)movesay(13)unknown1C(4)
In addition to this, the editor now has better highlighting and line numbering due to the use of ScintillaNET.

I'm not really sure what to do with the tool though since it's tied into Ifrit at the moment.
I guess there's a few things I could do:
a) pull out the code and put it in a standalone application
b) speak to the person who wrote Ifrit and try to get it put into the main release
c) fork Ifrit (although I don't really want to do this one)

What do you guys think?
 
This sounds very promising.

Will your tool also allow editing the probability of attacks being used? For example, making the two GIM52As in Desert Prison use Ray Bomb more often while Elite Soldier is alive? That would be neat. As well as preventing enemies from mindlessly casting positive status effects over and over, such as Fujin does in LP.

As for what to do with the tool, I would suggest option b)
 
Status
Not open for further replies.
Back
Top