Info about the field scripting language goes here.

  • Thread starter Thread starter halkun
  • Start date Start date
Status
Not open for further replies.
It works.  Thanks.  I'll get to work on Chocobo Breeding then.

Edit: Well, locked down some more variables.  I'll just go over the types again fully...

(1/2) = 00DB1EC4
(3/4) = 00DB1FC4
(B/C) = 00DB20C4
(D/E) = 00DB21C4
(7/F) = 00DB22C4
(5/6) = 00CB2B80 (temporary variables)
(0) = Constants

This just leaves 8, 9 and A...
 
Didn't you just say above that bank 4/5 was the savemap? That looks to be spread between two different banks. Did I miss something?

Also does anyone have a quick copy of the FF7 save map, including how any checksums are calculated?

I'm torn where to put the memory map in gears. The save map belongs in the "Menu" section, the memory management belongs in "Kernel" and so far I've only seen "Field" make extensive use of the memory.

Should I split up the explanations?

Also I seem to have found out why I was gettng so confused about memory. Here I was thinking about the PSX memory map and not the PC one. Now that I can see the memory banks are contiguous, this is quite helpful.

The PSX has a high-speed scratchpad memory area internal to the CPU. It's 1k and between the ranges of 0x1f80_0000-0x1f80_03ff. You think there is a throwback in the PC code to represent this?

::EDIT::

Never mind, I see that the memory *ISN'T* contiguous. You have grouped the sections into blocks of memory.

::EDIT 2::
No wait, I'm confused. I'm letting my own assuptions get the best of me.

A PSX FF7 save has to fit into a single memory block of 8K. Now a PSX memory card has a finer "resolution" than that. The 8K block is actually split up into 64 "frames" made up of 128 bytes each. The first two frames are reserved for the filename and save icon. You can allocte the next two frames for additional icon animations, but isn't required. (Max allocations are 4 frames, one for the filename, and then three frames of animation)

Common sense is telling me that the savemap should be a direct mirror of what's saved on the card. This way a simple counter can attach the save data to the card stream. Writing to memory cards is a really qirkey process as it's really just another controller port. The more elegent solution, the faster the saves.
 
From what I know, the FF7 "save block" is a contiguous block of memory simply dumped to the memory card (with checksums and stuff added/updated of course). Common sense prevails again. :wink:  Now, the global script variables have five banks of 256 bytes each, all of which reside inside the memory area that constitutes the save block. Thus no specific bank refers to the savedata, rather they're all already in the save data. So another way to describe the banks would be temporary variables and permanent variables.

I hope that provided some information you were looking for.
 
I'm mapping the save block with that little doc you had in the Jenova source there Qhimm. This will be in Gears and should work as a psudo-map for the field file's memory mapping.
 
I found these in "ebexit6.fs" (Disc 1, field.fi):

Code: [Select]
Code:
SNIPED

I don't know if it's just leftovers from development if it actually has something to do with the scripting engine, though. (And yes, dic::defalut is how it was spelled)
It's likely dic::defalut is a mispelling by the programer.
If I were to hazard a guess these are function references, did you check if there were anything interesting around the text like addresses?

Cyb
 
First bit of info from FF7.exe mainly confirms Terence's findings about memory variable banks. The complete mapping is:

Code: [Select]
Code:
Code  Bank  Size-------------------------------------------------------------------0     -     -        (16-bit constant fetched from argument list)1     1     8 bits2     1     16 bits3     2     8 bits4     2     16 bits5     temp  8 bits   (temporary variables)6     temp  16 bits  (...)7     5     16 bits8     -     -        (unused, always returns zero when read)9     -     -        (...)A     -     -        (...)B     3     8 bitsC     3     16 bitsD     4     8 bitsE     4     16 bitsF     5     8 bits
Any of these banks can be accessed by script commands, as long as the code nibble used to select the variable type is in one of the first three arguments. (e.g. the MINUS2 command uses two variable references, and uses the first argument to contain the two type codes)

Naturally, since variable references are 8-bit (the offset from the start of the bank, that is) while constants are 16-bit, script commands must take special care to support constant arguments (usually as the last argument where the final byte is either part of the constant or unused). It is thus not guaranteed that all commands support constant arguments.
 
First bit of info from FF7.exe mainly confirms Terence's findings about memory variable banks. The complete mapping is:

 [MAP SNIPPED]

I'm going to bed and I'm going to attempt to look at that with fresh eyes when I wake up. I'm not getting this whole code <-> bank thing at all.

I'm going to talk out loud, then go to bed. Let's take the following command.

set byte(50)[07]=14

In this case the [07] means code 7, which selects bank 5 at a "depth" of 16 bits.

It then writes 0x14 at +0x50 within bank 5.

So what's the difference than doing this?

set byte(50)[0F]=14

....

Wait, I have the sentax wrong. I guess I simply don't know how to read the opcodes... I've been playing with the ones that don't deal with memory at all, like BATTLE, PRTYP, GOLD+ and others like that. I think you tried to explain it above, but you started tossing around terms like "nybbles" (I honestly thought this term was made up hacker speak for the 4 bit upper/lower half of a byte. Even on an 8 bit 6502 you can't split a register in half, everything aligns on a 8 bit byte or 16 bit word.) The script dumps also align on 8 bit bytes and 16 bit words.

I guess the script dumper is displaying memory locations in a pretty unintuitive way. I'm used to seeing explicit memory address ($0000-$FFFF), "zero-page" offsets ($00-$FF), or immidatle accessors (LDA #10)

Could you use give me some examples on how I'm supposed to properly parse these things? Thanks....
 
I'm going to talk out loud, then go to bed. Let's take the following command.

set byte(50)[07]=14

In this case the [07] means code 7, which selects bank 5 at a "depth" of 16 bits.
Don't look at the disassembled script for this.  Look at the *Op Codes* and associated data.  So what you really wanted to say was:

80 50 07 14, which becomes, properly:
set byte (5)[07] = (0)14

This means: Put the Constant 0x14 into the Byte at Offset 0x07 using ID 5 (which refers to the Temporary Bank and only dealing with bytes).

So what's the difference than doing this?

set byte(50)[0F]=14
I believe you want for your example:
set byte (6)[07] = (0)14

This means: Put the Constant 0x14 into the Byte at Offset 0x07 using ID 5 (which refers to the Temporary Bank and only dealing with words).  Which... isn't exactly the most sensible of code... you don't *really* want to mix opcodes dealing with bytes and telling the script engines variable handling subroutine that you want to store it in a word.  Who knows what might be put into that spare byte?

Wait, I have the sentax wrong. I guess I simply don't know how to read the opcodes... I've been playing with the ones that don't deal with memory at all, like BATTLE, PRTYP, GOLD+ and others like that. I think you tried to explain it above, but you started tossing around terms like "nybbles" (I honestly thought this term was made up hacker speak for the 4 bit upper/lower half of a byte. Even on an 8 bit 6502 you can't split a register in half, everything aligns on a 8 bit byte or 16 bit word.) The script dumps also align on 8 bit bytes and 16 bit words.
You're thinking about this too much.  If I want to check a single bit, do I use a command to *only* get that bit?  (Assume we're working in Assembler; the script engine has comparisons to check single bits)  No: I grab the whole byte and store it in one of the 4-byte registers, then I'll AND it with the bit I want to check, and then test it against 0.  It's the same with nibbles (which, yes, is another term for a half-byte, and is reasonably old in terms of when it was defined); I used it at the time because I thought it strange that, say: Random (05, 6D) and And (50, 6D, 01) would be associated with the same address.  It was only later that I was able to parse them as:
99 05 6D: Random (5)[6D]
8F 50 6D 01: And (5)[6D], (0)01

I guess the script dumper is displaying memory locations in a pretty unintuitive way. I'm used to seeing explicit memory address ($0000-$FFFF), "zero-page" offsets ($00-$FF), or immidatle accessors (LDA #10)

Could you use give me some examples on how I'm supposed to properly parse these things? Thanks....
They're not that unintuitive.  See, the script doesn't *know* all the addresses.  It doesn't have nearly as much control you give it credit for.  It has, as we've stated, access to 5 main banks of permenant variables, and 1 bank of temporary variables.  (Please note: VARIABLES.  We are currently ignoring stuff like XYZI which are specific commands that FF7 will go and do its own business with.)  The permenant variables contain stuff that will be saved out in FF7's save file.  Stuff like the number of Chocobos you have, or the last time you fought at Fort Condor, or how many battles you've been in since the start of the game.  Temporary variables change and are reset from scene to scene and are used and thrown away as and when they're needed.

All you really have to know about the addresses is the following:

 B/W
(1/2)[xx]: Bank 1
(3/4)[xx]: Bank 2
(B/C)[xx]: Bank 3
(D/E)[xx]: Bank 4
(F/7)[xx]: Bank 5
(5/6)[xx]: Temporary Bank

The 5 Banks are sequential sets of 256 addresses, and in v1.0, they start at 00DB1EC4 in memory, which starts with the Plot Progression Variable I've made note of several times.

The Temporary Bank is a set of 256 addresses that start at 00CB2B80 in v1.0, and are reserved for the script engine's use alone.

To put it simply: the scripts are interpreted by FF7, and FF7 itself will eventually convert (2)[00] to Word(0x00DB1EC4) when it's asked by the script engine to grab that particular address.  Script writers are not expected to know exactly where in memory all this is going to eventually be placed... all they need to know is their offset from the start of the Global or Temporary areas.
 
I've updated Gears with the FF7 save map, it's on page 12 under "menu" You can use it to help map out variables. It me know if I missed anything and if I need any corrections.

You know, I wonder of those banks arn't object conatiners.

For example the original code was something like Chocobo::slot_1::Intelligence==100

or If Character::Cloud::Vitality==21 then jump :label3

The bank is "Character" and the offset is handeled by the script compiler, (or even a hand ful of #define)

It would be easier when the save map is mapped to the banks...
 
I've updated Gears with the FF7 save map, it's on page 12 under "menu" You can use it to help map out variables. It me know if I missed anything and if I need any corrections.

You know, I wonder of those banks arn't object conatiners.

For example the original code was something like Chocobo::slot_1::Intelligence==100

or If Character::Cloud::Vitality==21 then jump :label3

The bank is "Character" and the offset is handeled by the script compiler, (or even a hand ful of #define)

It would be easier when the save map is mapped to the banks...
Judging from the way things are being handled in terms of 'functions' within the script I would say you might be closer to the truth.  Perhaps the 'global' values are really values within the game object and each character object has a set of associated variables, such as the 'love points' for example. I wonder if these are less global and more object oriented.  Or I could be completely wrong (wouldn't be the first time).

Cyb
 
Script values are definitely not object-oriented, at least not on any visible level. As for the rest of the save block (and probably most of the game), a certain level of object-oriented thinking exists, but mostly its just POD (plain-old-data) structs.
 
Right it's a double-post, but they're completely unrelated and separated by a lot of time so it's warranted.

A question for people who have actually been looking at the FF7 scripts... are there any scripts that use the DM_TRA or CM_TRA commands? (delete materia and check materia, respectively)

The reason being that in the PC version, these commands are not implemented. But since no one has complained about any materia bugs, I'm speculating that the commands aren't actually used anywhere in the game... I'd like to confirm it though.
 
CM_TRA might be used for that one timer for that underwater battle.
 
I don't think the game ever removes materia. I've been diggin with MNU files as of late but I think all yuffie does is move the materia to an unaccessable part of memory.

When I finaly figure out the menu thing, I'll have to play with that.

Heck. I haven even started on the REQ opcodes, I'm kinda hoping because they are first, someone will beet me to it.... :P
 
Right it's a double-post, but they're completely unrelated and separated by a lot of time so it's warranted.

A question for people who have actually been looking at the FF7 scripts... are there any scripts that use the DM_TRA or CM_TRA commands? (delete materia and check materia, respectively)

The reason being that in the PC version, these commands are not implemented. But since no one has complained about any materia bugs, I'm speculating that the commands aren't actually used anywhere in the game... I'd like to confirm it though.

DM_TRA and CM_TRA are those for removing/deleting materia?
Do we know exactly what these do?
They may have been for things that were never implemented in the game.  I know FF7 is incomplete and unused opcodes might be a good indicator of this.

Cyb
 
DM_TRA and CM_TRA are those for removing/deleting materia?
Do we know exactly what these do?
I'm fairly sure they are the delete-materia-from-inventory and check-if-materia-exists-in-inventory commands. Even if the actual command is unimplemented, the forms are very similar to the ST-ITM, DL-ITM and CK-ITM commands (which add, remove and check for items in the inventory, respectively). Also, the SM-TRA commans is fully implemented, which adds materia to the inventory. DM-TRA and CM-TRA use the same type of arguments as SM-TRA, with small differences equal to those between ST-ITM and DL-ITM/CK-ITM.

All I can't figure out is what TRA stands for... :P
 
Yes I am, dear. ^_~
I'm dumping all info on the commands I find into C++ header files for now, the plan is to incorporate them into a complete script viewer capable of presenting (and later editing) the script in an easily comprehensible manner. For example, replacing variable references like "14 56 1F 00" with "(1)[56], <2>[1F]" and replacing some command names to more descriptive versions, with (simplified) syntax and description denoted. The actual "hardcode" syntax can then still be easily retrieved from reading the C++ header files, even if you don't read C++ too well.
 
SM-TRA most likely stands for:

Set MaTeRiA.
Ooh, that's clever that.  :D  I would've thought Store or Stock though, from the ST-ITM variant, but SeT is equally likely I guess. ^_^
 
Status
Not open for further replies.
Back
Top