Qhimm.com Forums

Miscellaneous Forums => Scripting and Reverse Engineering => Topic started by: Tirlititi on 2015-12-13 23:28:45

Title: FF9 script syntax
Post by: Tirlititi on 2015-12-13 23:28:45
Hello everyone !

I'm going smoothly with the update of my tool, but I would like your opinions about how I should establish scripting conventions.
You don't need to know of Final Fantasy IX or anything to give your opinion, so I ask it here.

I'm about to choose what should be the final syntax for FF9 coding scripts. Up to now, I used a syntax which was thought to look like assembly, but I don't think that's relevant anymore. I naturally came, without thinking too much about it, to this :

1) code control keywords are lower case
Examples : if, then, while

2) function names are capitalized. Most of the time, the first part of the name is a verb, but that's not the case for very fundamental functions of one of the game's system.
Examples : AddItem, MoveCamera, RunScript
Other examples : Battle, Field, Menu

3) unknown variable names look like "VAR_AX_Y" where X and Y are numbers, and A is a letter (A, B, C or D).
Examples : VAR_A1_10, VAR_B7_95, VAR_C3_1816

4) known global variable names are capitalized and can be prefixed either with their category, or with something they are related to.
Examples : SV_PlayerTeam, SV_Target, MV_WorldPositionX
Other examples : Chocobo_BeakLevel, Global_ScenarioCounter, World_CurrentTransport

5) there are also getters, for which the syntax is like the one of a variable (ie. with no parenthesis) but with no prefix and a "Get" instead.
Examples : GetTime, GetDialogProgression, GetRandom

6) known local variable names are lower case.
Examples : i, attackamount, attacklist1

7) some operations are a bit obscure and not in the standard operation list of many programming languages. The boolean XOR operation is noted ^ and there are list operators which are normal operators with a $ appended.
Examples : =$, >$, >=$

8 ) unknown functions and operations obviously have gibberish names, but if you have an idea to make them more convenient, you're also welcome.
Examples : 0x0E, 0xA4, 0x39
Other examples : Op43, Op2B, OpF

Here is a sample of 3 functions (2 from an IA and 1 from a world map character creation) written with these conventions, as they would be displayed in the tool.
Code: [Select]
Function Adamantoise_Init
    set attackamount = 6
    set attacklist1 = 262144L
    set attacklist2 = 130
    set attackmplist1 = 3145728L
    set attackmplist2 = 1300
    set i = 0
    while ( i < attackamount ) {
        set tmp1 |= ( i << ( i * 3 ) )
        set i++
    }
    set i = attackamount
    while ( i > 1 ) {
        set tmp2 = ( GetRandom % i )
        set tmp3 = ( 7 << ( tmp2 * 3 ) )
        set tmp3 &= tmp1
        set attackshuffledlist |= ( tmp3 << ( ( ( i - tmp2 ) - 1 ) * 3 ) )
        set tmp2 = ( ( 1 << ( tmp2 * 3 ) ) - 1 )
        set tmp3 = ( tmp2 & tmp1 )
        set tmp2 ^= 16777215L
        set tmp1 = ( ( tmp1 >> 3 ) & tmp2 )
        set tmp1 |= tmp3
        set i--
    }
    set attackshuffledlist |= ( tmp1 & 7 )
    return

Function Adamantoise_ATB
    set attacklistselection = ( attackshuffledlist & 7 )
    set tmp2 = GetRandom
    set tmp3 = 128
    set i = ( attackamount - 1 )
    while ( i >= 0 ) {
        if ( tmp2 > tmp3 ) {
            break
        }
        set tmp3 >>= 1
        set i--
    }
    if ( i == 65535 ) {
        set i = ( attackamount - 1 )
    }
    if ( i == ( attackamount - 1 ) ) {
        set attackshuffledlist = ( ( attackshuffledlist >> 3 ) & 2097151L )
        set attackshuffledlist |= ( attacklistselection << ( i * 3 ) )
    } else {
        if ( i ) {
            set tmp1 = ( attacklistselection << ( i * 3 ) )
            set tmp2 = ( ( 1 << ( ( i + 1 ) * 3 ) ) - 1 )
            set tmp3 = ( ( tmp2 & attackshuffledlist ) >> 3 )
            set tmp3 |= tmp1
            set tmp2 ^= 16777215L
            set attackshuffledlist &= tmp2
            set attackshuffledlist |= tmp3
        }
    }
    set i = attackamount
    while ( i >= 0 ) {
        switch 8 ( attacklistselection ) from 0 {
        case +0:
            set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
            break
        case +1:
            set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
            break
        case +2:
            set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
            break
        case +3:
            set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
            break
        case +4:
            set #( SV_Target = SV_PlayerTeam )
            break
        case +5:
            set #( SV_Target = SV_PlayerTeam )
            break
        case +6:
            set #( SV_Target = SV_FunctionEnemy )
            break
        case +7:
            set #( SV_Target = SV_FunctionEnemy )
        }
        if ( attacklistselection >= 4 ) {
            set tmp2 = ( ( attackmplist2 >> ( ( attacklistselection - 4 ) * 6 ) ) & 63 )
        } else {
            set tmp2 = ( ( attackmplist1 >> ( attacklistselection * 6 ) ) & 63 )
        }
        set tmp1 = ( #SV_Target )
        set tmp3 = Op2B(SV_FunctionEnemy[MP])
        if ( tmp1 && ( tmp2 <= tmp3 ) ) {
            break
        }
        if ( i <= 0 ) {
            break
        }
        set attacklistselection = ( attackshuffledlist & 7 )
        set attackshuffledlist = ( ( attackshuffledlist >> 3 ) & 2097151L )
        set attackshuffledlist |= ( attacklistselection << ( ( attackamount - 1 ) * 3 ) )
        set i--
    }
    if ( attacklistselection >= 4 ) {
        set selectedattack = ( ( attacklist2 >> ( ( attacklistselection - 4 ) * 6 ) ) & 63 )
    } else {
        set selectedattack = ( ( attacklist1 >> ( attacklistselection * 6 ) ) & 63 )
    }
    if ( ( #( SV_FunctionEnemy[HP] ==$ 1 ) ) && ( #( SV_FunctionEnemy[MP] >$ 10 ) ) ) {
        set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
        set selectedattack = 3
    }
    Attack( selectedattack )
    return

Function World_Zidane_Init
    0x3B( 1 )
    SetModel( 310, 100 )
    0x93( 5 )
    SetObjectLogicalSize( 0, 50, 100 )
    SetObjectSize( 7, 67, 67, 67 )
    SetStandAnimation( 4724 )
    SetWalkAnimation( 4727 )
    SetRunAnimation( 4727 )
    MoveInstant( 241934L, -1254, 4294713142L )
    TurnInstant( 77 )
    return

What do you think?
Title: Re: FF9 script syntax
Post by: halkun on 2015-12-14 05:17:56
May be relevant, may be not....

The PSX version of Metal Gear Solid use Lua as it's scripting language....

Maybe.... Just maybe... PSX script designers swapped notes?
Title: Re: FF9 script syntax
Post by: Tirlititi on 2015-12-14 16:00:35
I had no idea lua was so old...

But that's not a lua-like language. At least not on purpose. I mainly took example from the C syntax to design it.
Title: Re: FF9 script syntax
Post by: nfitc1 on 2015-12-14 18:08:16
Find some site with coding standards. Each language has its own established readability practices. Find one that has close to the same capabilities as the one you're disassembling and use those standards. Since this is a script you might want to emulate something along the lines of JavaScript or Perl.
Title: Re: FF9 script syntax
Post by: paul on 2015-12-14 23:45:38
I was going to suggest using LUA style syntax if its fits. Also @halkun are you sure MGS1 used lua? I thought all of the game scripts in MSG1 was hard coded..
Title: Re: FF9 script syntax
Post by: halkun on 2015-12-15 00:02:52
I was going to suggest using LUA style syntax if its fits. Also @halkun are you sure MGS1 used lua? I thought all of the game scripts in MSG1 was hard coded..


Yup, There was an interview with a developer who ported the program to PC. The two big things was the amazing amount of Lua scripts in the game and also Konami was very militant over not changing the graphics, even when it benefited the PC port. including adding eyes to any of the characters.