Last update: 12/17/2021
Many thanks to MysticLord, Robert Seddon (Vanished One), Zanerus, and the sagafrontier @ wiki on assisting with this page.
Required Software
Required tools:
- imf_print.py (by MysticLord)
- Calculates header and free sector bytes of directory with IMF files in it
For manual editing:
For editing sprites and images:
Creating a Patch:
What is an IMF File?
An IMF file is an individual map. Each IMF has a .IMG and a .TEX file. The .IMG file handles dialogue, cutscenes, music playback, sprite placement, and map background display. The .TEX file is the map background. The code for NPC movement, as far as we know, is handled by the IMF. It’s unknown if it’s a simple flag or custom code. The code for enemy movement is handled by another file called MAP.OUT.
IMF*.IMG Structure
There are 10 sub-files in any given IMF*.IMG file. The locations of each sub-file are specified in the header. There are 10 little endian numbers, each 4 bytes long. Here are some examples:
IMF000.IMG 28 00 00 00 //1st sub-file 30 00 00 00 //2nd sub-file 54 00 00 00 //3rd sub-file 58 00 00 00 //4th sub-file 68 00 00 00 //5th sub-file 28 01 00 00 //6th sub-file F4 1F 00 00 //7th sub-file F0 26 00 00 //8th sub-file 10 27 00 00 //9th sub-file EC 46 00 00 //10th sub-file IMF001.IMG 28 00 00 00 //1st sub-file F4 00 00 00 //2 18 01 00 00 //3 E4 01 00 00 //4 0C 02 00 00 //5 A8 05 00 00 //6 F0 08 00 00 //7 58 43 00 00 //8 78 43 00 00 //9 54 63 00 00 //10
Sub-File 1 (Section 0)
Appears to give frame attributes for background animations. This sub-file hasn’t been explored all that much.
Sub-File 2 (Section 1)
Appears to define the attributes of NPCs (collision data, interaction data, etc.).
Sub-File 3 (Section 2)
Currently unknown, though it does appear to affect NPC interactions.
Sub-File 4 (Section 3)
Defines attributes for map transitions (which map to go to, animation to play, if it’s associated with a script, etc.).
Sub-File 5 (Section 4)
Define the field script; dialogue, menus, cutscenes, etc. Basically, all the interactive elements of the map.
Sub-File 6 (Section 5)
AKAO MIDI sequences for music and sound effects. This version of AKAO is closely related to the AKAO format used in Final Fantasy VII, but it’s not an exact carry-over. Uses either an INSTR*.ALL file for instruments or default PS1 sounds, it’s currently unknown if the default PS1 sounds are pre-loaded into all INSTR*.ALL files.
Sub-File 7 (Section 6)
NPC sprite data, palettes, and sheets.
Sub-File 8 (Section 7)
Defines the collision map. Not much is currently known about how this functions, but it was created with default tools included with the PS1 SDK.
Sub-File 9 (Section 8)
Currently unknown.
Sub-File 10 (Section 9)
Defines how the associated IMF*.TEX file is to be displayed on the screen.
IMF*.TEX Structure
Begins with a 4-byte header, followed by the map background and its various pieces, including sprite sheets for animated pieces, on-screen text, etc. Header is formatted as follows:
- XX XX SS SS - XX XX = unknown, tends to be set to 0x08 0x40 - SS SS = size of file after header divided by 10 (0x0A)
Modifying IMF Files
IMF*.IMG Files
- If you decide to expand any of these sub-files, you will have to create an entirely new header. Do note that sometimes, you won’t have to do this as some sectors have free bytes. You can calculate the free bytes of the IMF you’re editing with MysticLord’s imf_print.py script linked at the top of the page.
- If you don’t know how bit toggles work, it’s simple. You have a list of values that determine when something’s enabled or disabled, each one adding up to give you the final value of the byte. For example, if a bit toggle byte is set to 0x03, then toggles 0x01 and 0x02 are currently active.
- Generally, 0x808080 seems to indicate an RGB tint applied to a base palette. This appears to be the case across all sub-files that contain some kind of sprite data.
Sub-File 1 (Section 0)
Currently unknown how exactly to edit.
Sub-File 2 (Section 1)
Currently unknown how exactly to edit.
Sub-File 3 (Section 2)
Currently unknown.
Sub-File 4 (Section 3)
I honestly don’t know if these opcodes apply to this sub-file or the next one. Regardless, the opcodes for these events are:
03 0x yy 05 0x yy - 0x = map jump - yy = point to script routine in current map? (usually 20) 06 0x 00 = forced event occurrence (only when directly after 05 0x 20)
Towards the bottom of the sub-file, there is region movement code formatted exactly the same as what’s used for the RegionMap. It is formatted as such:
MMMM XXXX YYYY ZZ SS - MMMM = IMF hex value (in little endian) - XXXX = x-pos (in little endian) - YYYY = y-pos (in little endian) - ZZ = z-layer (?) - SS = bgm hex value - values are based on the music stored in the IMF - if music can't be found, then nothing's played - 04 = default town theme (usually)
It’s unknown how the game assigns these values to hitboxes, so you’ll have to do some testing. It’s possible that they’re assigned from west-most to east-most. Fortunately, most maps don’t have more than 3 or 4 hitboxes that transition to a new map, so it’s not terrible to figure out which opcode goes to which hitbox.
Sub-File 5 (Section 4)
For reference, there is a header in this sub-file with 16-bit pointers to script routines (the first two bytes are the length of the rest of the header).
Text is formatted in SHIFT_JIS (hence why I said wxMEdit is required instead of HxD), while opcodes are defined in ASCII. To view this SHIFT_JIS text, select View > Encoding > East Asian > [Windows 31J] Windows Japanese (SHIFT_JIS):
Here are the opcodes you’ll need for generating dialogue. The order is just what I thought made sense:
48 = initialize new dialogue window 46 = line feed (immediately display next line) 43 = carriage return (wait for player to press O before advancing to next line) 50 = wait for player to press O (no prompt arrow) 44 XX = wait XX units of time 5F XX = text scrolling - 00 = instant appearance - 01 = scroll into being 60 XX YY = wait YY units of time before continuing - XX is unknown (ID of entity?) 00 = conversation end (return) 53 XX (YYYY) = change color - XX = mode - 00 = default white - 01 = custom color (enables YYYY) - YYYY = color - usually placed preceding text, but can be placed in the middle of text 45 XX = return to start (top left) of current window for subsequent text, overwriting anything already there 47 XX = return to XX char-widths into current line for subsequent text, overwriting anything already there 4B = clear the current dialogue window after a carriage return 4C = initialize large dialogue window (similar to Lute's intro) 54 = close current window (to open a new one) 4A XX YY ZZ = display new dialogue window - XX = window position (relative to speaker) - YY = hex ID of speaker - varies depending on the map. check which sprite they are in the sprite sub-file for this ID - i don't know if the main character's ID is 00 or FF - ZZ = who the character is speaking to (where to face) - FF = speaking to nobody on screen (lets you use a custom facing) 54 (in text) = initialize all windows - if you want to change maps during dialogue, use this 7C/7D/7E WW YY ZZ = window y-pos - WW = unknown - YY = y-pos - ZZ = unknown (z-layer?) 51 XX = dialogue window bg/border style - 01 is used for shop menus - FF might be no visible bg/border 52 XX = affects dialogue window visibility - 01 hides main buying menu when party list is displayed - FF might mean visible at all times 5E yy XX (in text) = call a name of something - yy = type - 00 = item names - 02 = character names - 03 = technique names (up to DeathSynthesis) - 04 = technique names, cont. - 05 = more character names (with tabs for shops and probably other menus) - probably not stripping out padding whitespace - 06 = character names (XX is length variable, max is 09) - 06 00 = "", 06 01 = "Bl", 06 02 = "Blue", = 06 09 = "Blue XA" - 07 = System Data, your name - 08 = System Data, your astrological sign - 09 = System Data, your blood type - XX = ID of name - 02 FF = name of current leader 61 cc = shift control to entity cc (for both scripted behavior and user control) - cc might include bits of scenery as well - FF = entire party 61 FF = move character during conversation 58 XXXX YYYY ZZ = move/walk to a point - coordinates are (XXXX, YYYY) in little endian (origin is bottom-left) - ZZ = mode/speed(?) - 56 = walk - 57 = run(?) - 55 = slide(?) 59 cc ZZ = walk into character cc - used most often for recruiting characters - ZZ = same as opcode 58 FE = vanish instantly - used most often for recruiting characters 5A XXXX YYYY GG = jump to a point - coordinates are (XXXX, YYYY) in little endian (origin is bottom-left) - GG = force? (affects speed and range) - lower = faster and further - may walk to target point to make up for shortfall 54 XXXX YYYY (outside text) = offset sprite relative to entity's actual position - entity's shadow is attached to entity, so it'll stay in the true position 71 cc = attach camera to (scroll to) entity cc 63 cc YYYY = entity cc performs script routing number YYYY 7F XX = bring up name requester - 00 doesn't crash, unknown what other args could be
And here are the different kinds of dialogue windows you can use:
4D XX = normal 4E XX = thinking 4F XX = normal, forced to big and 3 lines - XX = bit toggle, window size - 00 = 3 lines (wide) - 01 = 2 lines (wide) - 02 = 1 line (wide) - 03 = full screen (with window border) - 04 = full screen (without window border) - 05 = 2 lines (narrow) - 06 = 3 lines (narrow) - 07 = 4 lines (narrow) - 08 = 5 lines (narrow) - 0D = 3 lines (medium) - 11 = 6 lines (big)
It’s possible for special events to happen during dialogue or after interacting with something. These codes are usually placed directly after a certain line of dialogue. Here are a bunch of them:
00 = event end (return) 1A bb Fb ZZ = rewrite flag - bb *b = address of start of data(?) - F = what kind of data's being referred to - 3 = flag data - ZZ = value written to address 07 0d 80 yy xx = change the sprite sheet of character yy to xx - xx = FF means your current sprite sheet 07 0d 81 yy xx = (same as above, but for the palette) 20 XX = set character XX to give default name for subsequent name requester 7F 64 0x cc = adjust party - 00 = remove member - 01 = add member - cc = ID of char to add/remove 67 03 cc = change current protagonist to a new character cc 67 05 0x = change T260G's current body - TYPE1 = 00, TYPE2 = 01, ..., TYPE8 = 07 07 01 XXXXXXXX = give XXXXXXXX credits 07 02 XXXXXXXX = deduct XXXXXXXX credits - fails if player has less than amount specified, probably an underflow failsafe 07 04 XXXXXXXX = set current credit amount to XXXXXXXX 07 17 uu vv ww mm ss xx yy zz = begin battle - uu = unknown (usually FF) - transition type? - vv = event ID - 00 = no event, load some random enemies - ww = unknown - mm = music ID - 00 = keep playing the current song - FF is required to change to Battle 1 from the previous song - ss = battle stage - click here for a complete list - xx = unknown (usually 05) - yy = unknown (usually 00) - zz = unknown (usually C0) - can change what battle you're in 28 40 cc 07 0b 40 ss 23 00 30 NN 07 10 40 ss = increase ss stat of character cc by NN - 0E = STR - 0F = QUI - 10 = INT - 11 = WIL - 12 = PSY - 13 = VIT - 14 = CHA 07 20 pp = restore LP 07 1F pp = restore JP? WP? 07 1E pp = restore WP? JP? - pp = which party members to apply it to. most likely a bit toggle - FF = whole party 68 01 ii NN = get NN of item ii
Here are special opcodes specific to shops:
2A XX YYYYYYYY = price of item XX 07 09 00 RR 40 1F 10 = magic shop start - RR = race bit toggle - 01 = human - 02 = mystic - 04 = mec - 08 = monster
It’s also possible to use branching code and jump codes. Unfortunately, it’s not entirely known how to utilize this. Here’s what we have so far:
08 bb cb dd ee xx xx - bb *b = address of start of data(?) - c = what kind of data's being referred to - 3 = flag data - if value of referenced data is between dd and ee, data at xx xx is referenced instead
There are specific functions you can call for each protagonist. This is usually text for an item pickup, but there are more things:
49 0M YY ZZ (GOTO? general functions? MESG?) - 0M = MESGx (0 - 7) - YY = unknown - ZZ = unknown - 02 15 10 = "It's [item]." - 02 14 10 = "0 Credits" - 02 11 10 = battle swirl - 02 21 10 = sends to start of blue's scenario for some reason - 02 00 10 = activate debug menu
Finally, here are the opcodes that we know most likely exist, but don’t know how they work yet. Feel free to mess around with these and report what you find to the forum:
01 (alternate return?) 02 XX (goto routine XX?) 03 XXXX (jump to offset XX in middle of routine? seems to affect clipping) 04 XXXX (plain goto offset 0xXXXX?) 09 XX XX XX XX XX (maybe same as branch code?) 0A XX XX XX XX XX (same as 09? ends with jump?) 0B XX YY ZZ (involved with field entities somehow) 5B (sit down? freezes everything) 5D XX YY (affects bg tiles somehow; YY higher = more distortion?) 5E XX (out of text) = look (in a direction? at an entity?) 62 (stop? send to back?) 66 XX YY = (seems to involve script routines; 0x63 anims don't work without it) 70 XX (YY?) (unknown) 7B XX YY ZZ (start of shop menu or general sfx?)
Sub-File 6 (Section 5)
Currently, you have to edit this manually as there are no known AKAO sequencer tools. It is very similar to the AKAO version used in FF7, but it’s not exactly 1:1 as SaGa Frontier adds a new sound opcode and has a different format for its headers. To learn about how Early AKAO works, click here (external link, QhimmWiki) or here (external link, sagafrontier @ wiki, in Japanese). You can manually edit AKAO sequences through this method. I am not aware of any tools to edit AKAO sequences.
In terms of listening to these sequences, building vgmtrans from Github can pretty perfectly convert AKAO to MIDI, along with the sample collections and instrument banks to DLS and/or SF2. It can even detect multiple AKAO sequences within one file, so you can drop an IMF*.IMG file or the game’s executable (yes, the executable has music in it) into the application and extract their AKAO sequence(s). In order to properly listen to and export these tracks with a soundfont, you must import the correct sample collection into vgmtrans. For battle music, this is INSTR000.ALL located in the B_SOUND folder. For the purposes of just listening to the songs, that’ll suffice. Note that the harp is stored in bank 1 and the drum kit in bank 127, despite the MIDI only loading sounds from bank 0.
Here are the known differences between FF7’s sound opcodes and SaGa Frontier’s:
- 0xF3
- Unknown
- 0xF5 – 0xF8
- Unimplemented
- Code-referenced to 0xA0, shouldn’t be used
- 0xFC
- Set extended tone
- Structure of tone info is described by (addr.) (relative addr.)
- This is the opcode that breaks all FF7 tools
Here’s how SaGa Frontier’s sample files are formatted:
- Notes:
Address |
Type |
Notes |
---|---|---|
0x0000 |
BYTE(4) |
"AKAO" string in ASCII |
0x0004 |
WORD |
Not used? |
0x0006 |
WORD |
Not used? |
0x0008 |
WORD |
Not used? |
0x000A |
BYTE |
Timestamp (Year, BCD format) |
0x000B |
BYTE |
Timestamp (Month, BCD format)
|
0x000C |
BYTE |
Timestamp (Day, BCD format) |
0x000D |
BYTE |
Timestamp (Hour, BCD format) |
0x000E |
BYTE |
Timestamp (Minute, BCD format) |
0x000F |
BYTE |
Timestamp (Second, BCD format) |
0x0010 |
DWORD |
SPU dest. addr. for sample data transfer |
0x0014 |
DWORD |
Size of sample data |
0x0018 |
DWORD |
Start ID |
0x001C |
DWORD |
Not used? |
0x0020 |
DWORD |
Not used? |
0x0024 |
DWORD |
Not used? |
0x0028 |
DWORD |
Not used? |
0x002C |
DWORD |
Not used? |
0x0030 |
DWORD |
Not used? |
0x0034 |
DWORD |
Not used? |
0x0038 |
DWORD |
Not used? |
0x003C |
DWORD |
Not used? |
Number of instruments is calculated as (128 – Start ID).
Articulation and pitch info is next, in a 64-byte repeated structure. The contents of this structure are identical to FF7’s INSTR*.DAT files.
Sample data is placed afterward.
Sub-File 7 (Section 6)
As of now, we only know that palettes for all sprites are defined before the sprite sheet section begins. Each palette is 16 bytes in size. Each sprite is 2-dimensional, formatted as 4bpp linear, reverse-order.
Sub-File 8 (Section 7)
Largely unknown.
- 0xFF = wall - 0x00 = open space(?)
Sub-File 9 (Section 8)
Currently unknown.
Sub-File 10 (Section 9)
There are three known subsections of this sub-file:
- Map attributes and tilemap objects, in lists
- Tile arrangements
- Palette(s)
Begins with a 12-byte section header, followed by a 16-bit pointer table to subsections, ending with a 32-bit pointer table for the remaining subsections and the end of the sub-file. As per usual, all numbers and pointers are in little endian.
The first subsection’s formatted as follows (the number is the number of bytes used for each attribute):
- 1 Red tint - 1 Green tint - 1 Blue tint - 1 Palette ID - 2 X-position, offset from default position - 2 negative Y-position, offset from default position - 2 positive Y-position, offset from default position - 2 Unknown - 1 Unknown - 1 Distortion in X axis (stretching) - 1 Unknown - 1 Flying height: changing this lets the object move vertically above its normal position (not below) - 1 Ripple (01 gives a weird floating animation (SFX, not a sprite animation routine)) - 1 Unknown (Visibility? Anything other than 00 made the test object vanish)
Here is the formatting in the second subsection’s header:
- ????????XXXXYYYYAAAABBBB, followed by tile IDs as UINT16s, in columns, left to right (length (A/0x10) * (B/0x10) * 2) - X = X-position, absolute (origin seems to be top-left for these) - Y = Y-position - A = Width in pixels - B = height in pixels
Here is the formatting of the third subsection’s header:
- 6-bytes long, usually begins 0x00 0x01, followed by one byte defining the number of palettes
Each palette is 512 bytes in length (256 colors).
IMF*.TEX Files
The image is 2-dimensional, formatted as 8bpp linear. The palette for each sprite sheet is stored in the 10th sub-file of its associated .IMG file. Editing these files is as simple as putting it into tilemolester. However, before you can start editing, you first need to manually move the palette(s) that you need to the top of the .TEX file. It’s as simple as copying the palette from the 10th sub-file of the .IMG and pasting that to the top of the .TEX in whichever hex editor you want. As long as the .TEX gets bigger by at least 512 bytes per palette you put in, you’re all set.
Personally, I recommend manually copying/pasting the palette into the .TEX, opening Photopea (free Photoshop alternative, in-browser), and downscaling whichever image you want to display in the .TEX file to around the same size as the source .TEX to make your changes (you’ll have to guess, unfortunately). This way, you can manually transfer your image into the .TEX pixel-by-pixel and modify the .TEX palette to include whatever colors you need. Remember, you only get 256 per palette. It’s kind of like creating pixel art in Minecraft, only more tedious.
How IMF Files are Handled in the Remaster
The remaster does use IMF*.IMG files. For obvious reasons, the remaster does not use .TEX files, so they are not included in resources.assets. Not much is currently known how the remaster handles IMF files. Currently, all we know is that most, but not all, sub-files are used. Some sub-files are used in their entirety, others are only partially used.
- Sub-file 1
- Unknown
- Sub-file 2
- Unknown, not likely to be used
- Sub-file 3
- Unknown
- Sub-file 4
- Unknown
- I have yet to get custom map transitions to work
- Unknown
- Sub-file 5
- Used for at least all dialogue
- Defines a SHIFT_JIS key to point back to BaccaratMessage followed by the usual opcodes
- Within BaccaratMessage, some of the ASCII opcodes have been replaced by line feeds and carriage returns
- Unknown what else is used here
- Used for at least all dialogue
- Sub-file 6
- Not used(?)
- It could be used for small things like song ID’s, but it’s currently unknown
- Not used(?)
- Sub-file 7
- Unknown;
- It’s definitely used in small pieces
- Unknown;
- Sub-file 8
- Most likely used in its entirety
- Unknown how the game handles this as the collision maps in the remaster are blocky and inconsistent
- Most likely used in its entirety
- Sub-file 9
- Unknown
- Sub-file 10
- Unknown; possibly used to define map dimensions and/or sprite layering, but that could be handled by Unity with its Sprite tool
You must be logged in to post a comment.