[FF7] AI Template Project - Welder

  • Thread starter Thread starter Bosola
  • Start date Start date
Status
Not open for further replies.
Why do you even think about stack. It's now that hard to create some abstraction to be closer to original code.

Example output from my dumper:

Code: [Select]
Code:
script 1:0x0000 [0x0004 + 0x00] = b(0x00);0x0006 [0x0008 + 0x00] = b(0x00);0x000c [0x0000 + 0x00] = b(0x00);0x0012 JumpIfNotAllFriendsInFrontRow(0x0029);0x001f [0x0008 + 0x00] = b(b[0x0008 + 0x00] & 0x01);0x0029 JumpIfNotAllFriendsInBackRow(0x0040);0x0036 [0x0008 + 0x00] = b(b[0x0008 + 0x00] & 0x02);0x0040 JumpIfNotAllOpponentsInFrontRow(0x0057);0x004d [0x0004 + 0x00] = b(b[0x0004 + 0x00] & 0x01);0x0057 JumpIfNotAllOpponentsInBackRow(0x006e);0x0064 [0x0004 + 0x00] = b(b[0x0004 + 0x00] & 0x02);0x006e JumpIfSelfNotInFrontRow(0x0084);0x007b [0x0000 + 0x00] = b(0x00);0x0081 0x72 JumpTo(0x008a)0x0084 [0x0000 + 0x00] = b(0x01);0x008a JumpIfRandomNot(1/0x03)(0x00c7);0x0092 JumpIf((b[0x0004 + 0x00] & 0x02) != 0x02)(0x00b0);0x009e SetRandomOpponentInBackRowToAttack();0x00ad 0x72 JumpTo(0x00bd)0x00b0 SetRandomOpponentWithLowestCurrentHP();0x00bd [0x000c + 0x00] = h(0x0113);0x00c4 0x72 JumpTo(0x00f9)0x00c7 JumpIf((b[0x0004 + 0x00] & 0x01) != 0x01)(0x00e5);0x00d3 SetRandomOpponentInFrontRowToAttack();0x00e2 0x72 JumpTo(0x00f2)0x00e5 SetRandomOpponentWithLowestCurrentHP();0x00f2 [0x000c + 0x00] = h(0x0112);0x00f9 RunCommand(0x20, h[0x000c + 0x00]);0x00ff 0x73 FinishScript()
...This is a good opportunity to ask more about the AI code and the battle engine. You seem to be suggesting that the AI code is not just some assembly-like scripting language, but was compiled from some other source. What sort of source? If compiled, could some of the 'oddities' of certain scripts (see Ultimate Weapon's HP code) be down to compiler issues? And what *actually* happens to the AI code every frame? Does it just push the battle engine around as a scripting language, or does it get transformed into some intermediate form, like bytecode?
Of course it was normal script that was later compiled to bytecode. Using this instructions you can implement almost all known constructions in languages. For example Lua language compile


Code: [Select]
Code:
y = 5print(y)
into

Code: [Select]
Code:
LOADK           0 1     ; 5SETGLOBAL       0 0     ; yGETGLOBAL       0 2     ; printGETGLOBAL       1 0     ; yCALL            0 2 1RETURN          0 1 0
Let's write decompiler already =)

And what stranges in Ultima Weapon's script you talking about?

Ai code already bytecode that executed when it's called (when timer filled or when some conditions met).
 
Last edited:
Of course it was normal script that was later compiled to bytecode.
So it's bytecode, huh? Do portions of the AI scripting code have 1:1 relations to the binary they eventually yield? Is it bytecode in the sense of 'generalized, partially abstracted ASM'? That surprises me, actually. Especially considering how complex things like calling for targets would be on the machine level.

And what stranges in Ultima Weapon's script you talking about?

Ai code already bytecode that executed when it's called (when timer filled or when some conditions met).
I don't have access to the code right now, but IIRC, Ultima Weapon uses a very verbose method of storing its HP in a GlobalVar.
 
This is very new information to me. And, I think, to other board members - more than once, I've heard people warn each other not to let different creatures use the same LocalVar numbers. I suppose the assumption was that 'Local' referred to a battle-only namespace, as opposed to global vars.
Well, my very first post on the subject of AI scripting all those years ago did show where each set of variables were mapped to: such that 0000-1FFF and 4000+ were mapped to blocks that were unique to each object, but any call to 4000 would retrieve *all* blocks rather than just the object's own block.

Which brings up another thing I've noticed in this thread which is ill-advised: don't use LocalVar 0400 or higher.  Only 128 bytes are given to each enemy, so anything higher than that will start overwriting other data.

So it's bytecode, huh? Do portions of the AI scripting code have 1:1 relations to the binary they eventually yield? Is it bytecode in the sense of 'generalized, partially abstracted ASM'? That surprises me, actually. Especially considering how complex things like calling for targets would be on the machine level.
Just because something is bytecode doesn't mean it's machine code.  It's just a form of code that can be quickly read by an interpreter (in that the operands are all single bytes).  Game designers don't program enemies, rooms or other scripts in bytecode: they use some higher level custom language (usually designed specifically for the game), which they then compile down into an easier format for the game to read.  The resulting code doesn't take up very much memory and is relatively fast to run compared to translating human readable code in real-time (which would be both slower and take up more space).

I don't have access to the code right now, but IIRC, Ultima Weapon uses a very verbose method of storing its HP in a GlobalVar.
It's only verbose because AccessGlobalVar can only read and write Bytes.  So storing what requires at least 3 bytes is going to require a bit of maths.  There's obviously going to be some compiler artifacts around in the code, which is why a lot of the enemy scripts can be rewritten to be more efficient in bytecode, but some of it is just working around the limitations of the system.
 
Last edited:
Ah, so it's a bytecode in the strict sense of 'a code with one-byte opcodes'. I was thinking in terms of the 'bytecode' people refer to when talking about Java etc. It is, technically speaking, the same principle - something between human-readable code and actual machine action that can easily be dealt with by an interpreter.

Which brings up another thing I've noticed in this thread which is ill-advised: don't use LocalVar 0400 or higher.  Only 128 bytes are given to each enemy, so anything higher than that will start overwriting other data.
Asking a bit much, but does anyone actually have a complete memory map? I'm wondering what we get after 0400.

I think at some point I'd like to get into this further, perhaps by using disassemblers. How did you get into reverse engineering yourself?
 
Interesting stuff. What's the actual range of values that can be written from within the AI script? Could AI code, for instance, clear the battle queue (which seems to come shortly after the 2000 addresses)?
 
Interesting stuff. What's the actual range of values that can be written from within the AI script? Could AI code, for instance, clear the battle queue (which seems to come shortly after the 2000 addresses)?
Even if it can - doesn't mean you should.
 
Of course! I'm just curious how values 0-FFFF are assigned in the memory map.
 
To make a little clearer: if you want variable 'IQ' levels, you need to write the custom IQ in AI setups / death counters to address 21A0.

It looks to me as though the following addresses can be used for BattleVars, though I may need to test further:

21a0
21a8
21b0
21b8
21c0-c8

When I'm a little more inclined, I'll probably clean all the material up and link to it from the initial post.
 
Status
Not open for further replies.
Back
Top