Changes
From Final Fantasy Inside
Again, if anyone knows better than I, feel free to fix some of this. I just wanted SOMETHING here.
(Information on opcodes provided by Terence Fergusson. Almost all information comes from [http://forums.qhimm.com/index.php?topic=3290.msg45951#msg45951 this post] on the forums.)
There are four actions to be explained when dealing with any opcode in AI script: Arguments, Values to take from the stack, what to do with Arguments and Values, and what to put back on the stack. So to fully understand what is happening a brief explanation of the stack is necessary.
The stack is more-or-less a list of values with different lengths. Only the top of the stack can be accessed at any given time, but when that value is accessed it leaves the stack and the previously added value now becomes the top of the stack. Adding to the stack is called "Pushing" a value and taking a value off is called "Popping". When pushing a value to the stack, the value of the number is pushed followed by the value type. The value type can be one of three different things:
<br/>
<br/>
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" align="center" | Code
! style="background:rgb(204,204,204)" align="center" | Type
|-
| align="center" | 0Xh
| Value
|-
| align="center" | 1Xh
| Address
|-
| align="center" | 2Xh
| Multiple (between 1-10) Values
|-
|}
<br/>
They are stored as DWords, but the X will determine how many bytes to use: 0 = bit, 1 = Byte, 2 = Word, 3 = DWord
Now that we've seen the stack, here are the opcodes:
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" align="center" | Code
! style="background:rgb(204,204,204)" align="center" | Arguments
! style="background:rgb(204,204,204)" align="center" | Value(s) to pop
! style="background:rgb(204,204,204)" align="center" | Value to push
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Values
|-
| 0Xh
| 2 byte Address
|
| Type 0X stored at translated Address
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Addresses
|-
| 1Xh
| 2 byte Address
|
| Argument Type 1X
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Mathematical and Bit-wise Operators
|-
| 30h
|
| Two of any type
| Sum of pops
|-
| 31h
|
| Two of any type
| Difference of pops
|-
| 32h
|
| Two of any type
| Product of pops
|-
| 33h
|
| Two of any type
| Quotient of pops
|-
| 34h
|
| Two of any type
| Remainder from quotient of pops
|-
| 35h
|
| Two of any type
| Bit-wise AND of pops
|-
| 36h
|
| Two of any type
| Bit-wise OR of pops
|-
| 37h
|
| One of any type
| Bit-wise NOT of pop
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Logical Operators
|-
| 40h
|
| Two of any type
| True if pops are EQUAL
|-
| 41h
|
| Two of any type
| True if pops are NOT EQUAL
|-
| 42h
|
| Two of any type
| True if first pop is GREATER THAN OR EQUAL TO second pop
|-
| 43h
|
| Two of any type
| True if first pop is LESS THAN OR EQUAL TO second pop
|-
| 44h
|
| Two of any type
| True if first pop is GREATER THAN second pop
|-
| 45h
|
| Two of any type
| True if first pop is LESS THAN second pop
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Logical Comparisons
|-
| 50h
|
| Two of any type
| True if both pops are NON-ZERO (Logical AND)
|-
| 51h
|
| Two of any type
| True if either pop is NON-ZERO (Logical OR)
|-
| 52h
|
| One of any type
| True if pop is ZERO (Logical NOT)
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Constants
|-
| 60h
| One Byte
|
| Argument of type 01
|-
| 61h
| Two Bytes
|
| Argument of type 02
|-
| 62h
| Four Bytes
|
| Argument of type 03
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Script Jumps
|-
| 70h
| Two Bytes
| One of any type
| Jumps to script address in argument if pop is 0
|-
| 71h
| Two Bytes
| One of any type
| Jumps to script address in argument if pop and top of stack are not equal
|-
| 72h
| Two Bytes
|
| Jumps to script address in argument
|-
| 73h
| colspan="3" align="center"| This ends the script
|-
| 74h
|
| One of any type
|
|-
| 75h
|
| One of any type
|
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Bit Operations
|-
| 80h
|
| One of type 0X or 2X, One of any type
| First pop ANDed with second pop.
|-
| 81h
|
|
| Random Word (0-65535)
|-
| 82h
|
| One of any type
| Random bit of pop stored as type 02
|-
| 83h
|
| One of any type
| Type 01 with count of number of bits set in pop
|-
| 84h
|
| One of type 2X
| Type 02 indicating which values in popped set were greatest
|-
| 85h
|
| One of type 2X
| Type 02 indicating which values in popped set were least
|-
| 86h
|
| One of type 1X
| Type 02 indicating MP Cost of attack index referenced in pop
|-
| 87h
|
| One of any type
| Type 02 with only bit in pop turned on (1 << [pop])
|-
! style="background:rgb(224,224,224)" align="center" colspan = "3" | Commands
! style="background:rgb(224,224,224)" align="center" | Effect
|-
| 90h
|
| One of type 1X, One of type 0X or 2X
| If first pop < 4000h; Stores second pop at first pop
|-
| 90h
|
| One of type 1X, One of type 0X or 2X, One of type 1X
| If first pop >= 4000h; Stores second pop at first pop constrained by mask at third pop
|-
| 91h
|
| One of any type
|
|-
| 92h
|
| Two of any type
| First pop is attack ID to perform. Second pop's usage is unknown (0x20 or 0x24)
|-
| 93h
| NULL terminated string
| colspan="2" align = "center"| Displays string
|-
| 94h
|
| Two of any type
|
|-
| 95h
|
| One of type 1X, one of type 00
| If second pop is 0, reads value from global address and stores in local address of 2010
|-
| 95h
|
| One of type 1X, one of type 00
| If second pop is 1, takes value at local address 2010 and writes value at global address
|-
| 96h
|
| Two of any type
|
|-
| A0h
| One byte, NULL terminated ASCII
| First argument of any type
| Displays string to debug console, replacing "%d"s with pops
|-
| A1h
| ?
| ?
| ?
|-
|}
<br/>
GENERAL NOTES:
*Commands 90h and 95h are overloaded.
*If a type 2X is popped and any type is accepted, only the first value will be considered.
*If specific type is expected and that type is not available, the game with either crash or ignore that entire line.
*TRUE and FALSE are stored as type 00 as '1' and '0' respectively.
3X CODES NOTES:
*The pushed value is type 2x if either of the pops are a 1X or 2X. In that case, the Masks of both pops are ANDed together. In *all* cases, the highest pop's size is used to determine the new pop's size.
4X CODES NOTES:
*The Pushed value will be type 00 if either component is a 1X or 2X type. It will only push TRUE or FALSE
*If both were 0X types, the result will be a type 02 which contains the Mask of all the objects in the pops that passed the comparison
86 CODE NOTES:
*This get the MP Cost of the ability referenced in the pop. The value of pop is referenced to the following areas:
If Value >= 0xFFFF, return 0
If Value <= 0x00FF, Addr = 00DAAC78 + Value*0x1C
If Value >= 0x0100, match Value with wr[0099AAF4+(ID=[0..31])*2]
First ID it matches, Addr = 0099A774 + ID*0x1C
If no Addr is found, return 0
Otherwise, return wr[Addr + 4]
The pushed value is, thus, the MP cost of the defined ability as a type 02. Note that 0x00 to 0xFF are standard magic and always loaded, while 0x100+ are the unique abilities loaded through scene.bin.
There are four actions to be explained when dealing with any opcode in AI script: Arguments, Values to take from the stack, what to do with Arguments and Values, and what to put back on the stack. So to fully understand what is happening a brief explanation of the stack is necessary.
The stack is more-or-less a list of values with different lengths. Only the top of the stack can be accessed at any given time, but when that value is accessed it leaves the stack and the previously added value now becomes the top of the stack. Adding to the stack is called "Pushing" a value and taking a value off is called "Popping". When pushing a value to the stack, the value of the number is pushed followed by the value type. The value type can be one of three different things:
<br/>
<br/>
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" align="center" | Code
! style="background:rgb(204,204,204)" align="center" | Type
|-
| align="center" | 0Xh
| Value
|-
| align="center" | 1Xh
| Address
|-
| align="center" | 2Xh
| Multiple (between 1-10) Values
|-
|}
<br/>
They are stored as DWords, but the X will determine how many bytes to use: 0 = bit, 1 = Byte, 2 = Word, 3 = DWord
Now that we've seen the stack, here are the opcodes:
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" align="center" | Code
! style="background:rgb(204,204,204)" align="center" | Arguments
! style="background:rgb(204,204,204)" align="center" | Value(s) to pop
! style="background:rgb(204,204,204)" align="center" | Value to push
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Values
|-
| 0Xh
| 2 byte Address
|
| Type 0X stored at translated Address
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Addresses
|-
| 1Xh
| 2 byte Address
|
| Argument Type 1X
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Mathematical and Bit-wise Operators
|-
| 30h
|
| Two of any type
| Sum of pops
|-
| 31h
|
| Two of any type
| Difference of pops
|-
| 32h
|
| Two of any type
| Product of pops
|-
| 33h
|
| Two of any type
| Quotient of pops
|-
| 34h
|
| Two of any type
| Remainder from quotient of pops
|-
| 35h
|
| Two of any type
| Bit-wise AND of pops
|-
| 36h
|
| Two of any type
| Bit-wise OR of pops
|-
| 37h
|
| One of any type
| Bit-wise NOT of pop
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Logical Operators
|-
| 40h
|
| Two of any type
| True if pops are EQUAL
|-
| 41h
|
| Two of any type
| True if pops are NOT EQUAL
|-
| 42h
|
| Two of any type
| True if first pop is GREATER THAN OR EQUAL TO second pop
|-
| 43h
|
| Two of any type
| True if first pop is LESS THAN OR EQUAL TO second pop
|-
| 44h
|
| Two of any type
| True if first pop is GREATER THAN second pop
|-
| 45h
|
| Two of any type
| True if first pop is LESS THAN second pop
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Logical Comparisons
|-
| 50h
|
| Two of any type
| True if both pops are NON-ZERO (Logical AND)
|-
| 51h
|
| Two of any type
| True if either pop is NON-ZERO (Logical OR)
|-
| 52h
|
| One of any type
| True if pop is ZERO (Logical NOT)
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Push Constants
|-
| 60h
| One Byte
|
| Argument of type 01
|-
| 61h
| Two Bytes
|
| Argument of type 02
|-
| 62h
| Four Bytes
|
| Argument of type 03
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Script Jumps
|-
| 70h
| Two Bytes
| One of any type
| Jumps to script address in argument if pop is 0
|-
| 71h
| Two Bytes
| One of any type
| Jumps to script address in argument if pop and top of stack are not equal
|-
| 72h
| Two Bytes
|
| Jumps to script address in argument
|-
| 73h
| colspan="3" align="center"| This ends the script
|-
| 74h
|
| One of any type
|
|-
| 75h
|
| One of any type
|
|-
! style="background:rgb(224,224,224)" align="center" colspan = "4" | Bit Operations
|-
| 80h
|
| One of type 0X or 2X, One of any type
| First pop ANDed with second pop.
|-
| 81h
|
|
| Random Word (0-65535)
|-
| 82h
|
| One of any type
| Random bit of pop stored as type 02
|-
| 83h
|
| One of any type
| Type 01 with count of number of bits set in pop
|-
| 84h
|
| One of type 2X
| Type 02 indicating which values in popped set were greatest
|-
| 85h
|
| One of type 2X
| Type 02 indicating which values in popped set were least
|-
| 86h
|
| One of type 1X
| Type 02 indicating MP Cost of attack index referenced in pop
|-
| 87h
|
| One of any type
| Type 02 with only bit in pop turned on (1 << [pop])
|-
! style="background:rgb(224,224,224)" align="center" colspan = "3" | Commands
! style="background:rgb(224,224,224)" align="center" | Effect
|-
| 90h
|
| One of type 1X, One of type 0X or 2X
| If first pop < 4000h; Stores second pop at first pop
|-
| 90h
|
| One of type 1X, One of type 0X or 2X, One of type 1X
| If first pop >= 4000h; Stores second pop at first pop constrained by mask at third pop
|-
| 91h
|
| One of any type
|
|-
| 92h
|
| Two of any type
| First pop is attack ID to perform. Second pop's usage is unknown (0x20 or 0x24)
|-
| 93h
| NULL terminated string
| colspan="2" align = "center"| Displays string
|-
| 94h
|
| Two of any type
|
|-
| 95h
|
| One of type 1X, one of type 00
| If second pop is 0, reads value from global address and stores in local address of 2010
|-
| 95h
|
| One of type 1X, one of type 00
| If second pop is 1, takes value at local address 2010 and writes value at global address
|-
| 96h
|
| Two of any type
|
|-
| A0h
| One byte, NULL terminated ASCII
| First argument of any type
| Displays string to debug console, replacing "%d"s with pops
|-
| A1h
| ?
| ?
| ?
|-
|}
<br/>
GENERAL NOTES:
*Commands 90h and 95h are overloaded.
*If a type 2X is popped and any type is accepted, only the first value will be considered.
*If specific type is expected and that type is not available, the game with either crash or ignore that entire line.
*TRUE and FALSE are stored as type 00 as '1' and '0' respectively.
3X CODES NOTES:
*The pushed value is type 2x if either of the pops are a 1X or 2X. In that case, the Masks of both pops are ANDed together. In *all* cases, the highest pop's size is used to determine the new pop's size.
4X CODES NOTES:
*The Pushed value will be type 00 if either component is a 1X or 2X type. It will only push TRUE or FALSE
*If both were 0X types, the result will be a type 02 which contains the Mask of all the objects in the pops that passed the comparison
86 CODE NOTES:
*This get the MP Cost of the ability referenced in the pop. The value of pop is referenced to the following areas:
If Value >= 0xFFFF, return 0
If Value <= 0x00FF, Addr = 00DAAC78 + Value*0x1C
If Value >= 0x0100, match Value with wr[0099AAF4+(ID=[0..31])*2]
First ID it matches, Addr = 0099A774 + ID*0x1C
If no Addr is found, return 0
Otherwise, return wr[Addr + 4]
The pushed value is, thus, the MP cost of the defined ability as a type 02. Note that 0x00 to 0xFF are standard magic and always loaded, while 0x100+ are the unique abilities loaded through scene.bin.