-
Notifications
You must be signed in to change notification settings - Fork 6
TALK.DAT
TALK.DAT is a container that holds Talk scripts, which are to the most part a linear scripting language designed for in-game conversations and menu options.
It is located at SUBDATA.DAT->START.DAT, START.DAT (needs to be decompressed first).
Original work has been done by Krisan Thyme by his Toolpack.
Type | Size | Description |
---|---|---|
uInt | 4 byte | Number of scripts |
uInt | 4 byte | Number of scripts again |
For each script (32 byte):
Type | Size | Description |
---|---|---|
uInt | 4 byte | Start address (The header size is not counted, therefore is first value is 0) |
uInt | 4 byte | The script id |
uShort | 2 byte | DungeonId |
uShort | 2 byte | Unknown Search Flag (mostly 0-2, 102-111) |
uShort | 2 byte | Game state filter positive size (from 0-4) |
uShort | 2 byte | Game state filter negative size (from 0-4) |
uShort | 2 byte | Game state filter positive 0 |
uShort | 2 byte | Game state filter positive 1 |
uShort | 2 byte | Game state filter positive 2 |
uShort | 2 byte | Game state filter positive 3 |
uShort | 2 byte | Game state filter negative 0 |
uShort | 2 byte | Game state filter negative 1 |
uShort | 2 byte | Game state filter negative 2 |
uShort | 2 byte | Game state filter negative 3 |
To find the size of each talk script, subtract the start address of the next script from the start address of the current script.
The game chooses a script based on a combination of ID, Dungeon ID, and some Unknown Flag. Afterwards the game checks the current state of the game (probably from the save file), but only if any are given, i.e the size is bigger 0. If these checks pass, then the script is chosen. Otherwise it searches until it finds one.
The positive filter tests if a bit is set, while the negative tests if a bit is not set. The first 3 bits of "game state filter" are used to create a bit mask for checking against a global game state, determined by the rest of the bits:
struct DisaGameStateFilter {
unsigned short bitIndex: 3; //the bit that should be tested (same as x & 7)
unsigned short index: 13; //the index of a gamestate (same as x >> 3)
inline unsigned short getIndex() const noexcept { return index; }
inline byte getMask() const noexcept { return 1 << bitIndex; }
};
const byte mask = gameStateFilter.getMask(); // Create a bit mask (0-7)
const byte state = (globalStateStartPtr)[gameStateFilter.getIndex()]; // Get the state to check
return (state & mask) != 0; // Positive: When true then script is valid
return (state & mask) == 0; // Negative: When true then script is valid
Name | Index | Bit | Description |
---|---|---|---|
Skip Story | 275 | 0 | When set then the story at the beginning of a stage should be skipped |
Two script languages are used: TALK and SCRIPT. Each has its own unique commands, though some commands are shared between them. They serve different purposes in the game:
- TALK: Manages dialogue and serves as an entry point to game levels.
- SCRIPT: Handles a broader range of in-game functions and effects.
What TALK can do
- Play dialog in the game
- Show character images and animations
- Opening menus like the area select, shop, assembly, etc
- Execute scripts from SCRIPT.DAT
What TALK can not do
- Controll the camera
- Spawn units on map and play there animations (for cutscenes)
- Control sounds and background musik
All other effects are achived with the scripts within SCRIPT.DAT.
Each command consists of a op code (byte) and a body with arguments.
Name | Op Code | Arguments | Arguments Size | Description |
---|---|---|---|---|
Dialog | 01 | Display string in Shift JIS. | x + 1 byte | Display dialog |
Confirm | 02 | None | 0 byte | Wait for user to press confirm to continue dialog |
ConfirmClose | 03 | None | 0 byte | Like Confirm, however it will close the dialog box |
CharLeft | 04 | Slot, seed and animation, modefier | 2 + 2 + 1 byte | Display image in slot at left. |
Portrait | 05 | Character portrait Id | 2 byte | Character portrait to display |
Voice | 06 | Id of dialog | 2 byte | Play character dialog |
SpeechBubble | 07 | Bubble type, arrow position | 1 + 1 byte | The style of speech bubble. |
NameLabel | 08 | uShort name id, Char label position | 2 + 1 byte | Display name lable |
Set | 09 | Set a game state flag | 2 byte | Set a bit in game state |
Clear | 0A | Clear a game state flag | 2 byte | Clear a bit in game state |
Script | 0B | Id of script from SCRIPT.DAT | 3 byte | Exectue script form SCRIPT.DAT |
Call | 0C | Id of talk script | 3 byte | Exectue another talk script |
MenuStart | 14 | Number of entries, followed by string of first entry and it's bransh code | 1 + x * y byte | Defines the start of a menu. |
MenuEntry | 14 | String of entry and it's bransh code | x * y byte | Defines consequent menu enries after MenuEntry. |
ShowBox | C9 | char (Boolean) | 1 byte | Will open background box. |
CharRight | 18 | Slot, seed and animation, modefier | 2 + 2 + 1 byte | Display image in slot at right. |
CharMid | 0E | Slot, seed and animation, modefier | 2 + 2 + 1 byte | Display image in slot at center. |
LoadImg | 64 | slot * 10000 + BUImageId | 3 byte | Load a BU** Image into a slot. |
ConfirmAuto | 65 | delay, delayAlt, boolean to close the dialog box | 2 + 2 + 1 byte | Will automatically ConfirmClose or Confirm after given delay. |
NOP | FA | char | 1 byte | Does nothing skipping a byte, used to skip 1 byte menu commands. |
MenuEnd | FD | None | 0 byte | Marks the end of conversation selection. |
Return | FF | None | 0 byte | Will terminate script. |
Restart | FE | None | 0 byte | Restarts the script from the beginning. Usually used in connection with menus. |
- Op Code: 01
- Construction: 01 XX XX 00
- Arguments: Zero terminating string in Shift JIS.
Will open the dialog box and display the given string inside. The string can't be larger then 128 bytes (or the memory will bleed over), must be encoded in Shift_JIS and be terminated by a 0 byte. You can have up to 3 dialog commands, each indicating the row inside the text box. The text also will be animated, appearing letter by letter.
- Op Code: 02
- Construction: 02
- Arguments: None
Will pause and prompt the user to press continue between dialog lines. Usually used when the same character continues talking.
- Op Code: 03
- Construction: 03
- Arguments: None
Will pause and prompt the user to press continue between dialog lines. But unlike Confirm this will close the dialog box on confirmation. This is usually used when a different character starts talking. Or when the SpeechBubble command is used to change the stlye of it to play a nice transition animation.
- Op Code: 65
- Construction: 65 11 11 22 22 33
- Arguments: delay, delay alternative (language), continue or confirm
Will pause, however it will not wait for user input, instead it will automatically trigger ConfirmClose (false) or Confirm (true) after a given delay depending on last boolean argument. Also user can't skip forward. There are two delay timers, the first is base. The second is used if not zero and a certain game state flag is set (probably language, so delay is in sync with the audio track). For example it is used in the cutscene where Laharl interrupts Vyers..
- Op Code: 64
- Construction: 64 00 00 00
- Argument: slot * 10000 + BUImageId (3 byte)
Before an character image can be used it must be loaded into a slot so it can be refereced later. LoadImg
takes one argument, which is a combination of the BU** image id, plus the slot times 10000: slot * 10000 + BUImageId
.
For example, 50103, will load BU0103.TX2 (angry Laharl) from DATA.DAT into slot 5. The total number of slots is 7. The image is loaded asynchronous. If you attempt to use an image from a slot that has not been fully loaded, the game will crash!
Thus call script(0);
to force the game to wait for the image to be loaded.
- Op Code: 04/0E/18
- Construction: 04/0E/18 00 11 11 22
- Arguments: Slot Id (2 byte), Animation speed and type (speed * 100 + type)(2 byte), Modefier (1 byte)
Display image in slot at position defined and default orientation by op code. Image must have been fully loaded with LoadImg otherwise the game will crash.
The way the character image enters the frame is determined by the second argument, which is a combination of speed and type: speed * 100 + type
.
The type indicates the entry animation, while the speed determines the speed of this animation.
Lower speed values mean slower animations, with 0 resulting in an instant appearance.
For example, a value of 1002
means the image will slide from the right (2) to it's target position at a slow speed of 10.
Known animation types:
- 0 - INSTANT
- 1 - SLIDE_FROM_LEFT
- 2 - SLIDE_FROM_RIGHT
- 3 - SLIDE_FROM_LEFT_TO_CENTER
- 4 - SLIDE_FROM_RIGHT_TO_CENTER
- 5 - FADE_IN
- 7 - SLIDE_FROM_BOTTOM
- 9 - SLIDE_FROM_TOP
- 11 - SLIDE_TO_LEFT
- 13 - SLIDE_TO_ALMOST_LEFT
The Modefier is a bit mask, with only two bits. The fist will mirror the image vertically. The second will offset the image down.
- Op Code: 07
- Construction: 07 00 11
- Arguments: Bubble type (1 byte), Arrow position (1 byte)
Defines the style and position of the arrow of the character that is speeking.
Bubble types:
- 1: Normal
- 2: Shouting
- 3: Inner thought
The arrow position is defined from left to right with the corresponding values 1 to 4. Some bubble types don't support arrows.
- Op Code: 08
- Construction: 08 00 00 11
- Arguments: Name Id (2 byte), Label position (1 byte)
Display a name tag at given position. The position is defined from left to right with the corresponding values 1 to 4. If Id is -1 or position is out of bounds then name tag will not be displayed.
- Op Code: 0B
- Construction: 0B 00 00 00
- Arguments: Script Id (3 byte)
Execute a script from SCRIPT.DAT. The script will run asynchronous. To wait for the script to finish call script
with id 0: script(0);
.
A script from SCRIPT.DAT is used to control the camera, spawn cutscene characters, play sound effects and more.
- Op Code: 0C
- Construction: 0C 00 00 00
- Arguments: Talk script Id (3 byte)
Execute a script from TALK.DAT. This will completely stop the current script execution and start a new script. The game has not call stack, so after the called script finished, the game will not continue with the previous script! Also many settings done by other commands will be reset.
A menu is created using branching instructions, with MenuStart to begin the menu, including the first entry, and MenuEntry for each additional entry and branching path. MenuEnd indicates the end of the menu and where the code execution will continue after the menu is closed. Basically it functions like a switch case.
Example:
MenuStart(3, “First entry”);
//code for entry 1
MenuEntry(“Second entry”);
//code for entry 2
MenuEntry(“Third entry”);
//code for entry 3
MenuEnd();
//code after menu is closed
- Op Code: 14
- Construction: 14 NN 01 STRING 00 BRANSH_CODE…
- Argument: Number of entries (1 byte).
MenuStart initializes the menu. The first argument specifies the total number of menu entries (including the initial entry and any MenuEntry entries). After this, there is a '01' byte, a null-terminated string for the first entry, and the branching code that will execute when this entry is selected. The string should not exceed 128 bytes and must be encoded in Shift-JIS.
It's now allowed to have sub menus directly, for that you must call another talk script inside the brash code.
(Note, the '01' is not the same as the Dialog command. In fact it's not even required in all cases, the game mainly use it to search for 0x1401.)
- Op Code: 14
- Construction: 14 01 STRING 00 BRANSH_CODE…
- Argument: None.
MenuEntry adds additional entries to the menu after MenuStart is defined. The total number of MenuEntry instances should match the number specified in MenuStart minus one. Apart from not requiring an argument, it is constructed equally to MenuStart.
- Op Code: FD
- Construction: FD
- Argument: None.
Marks the end of the menu and the point where the code will continue after the menu is closed. Note this is solely a marker, if it where to be reached then it will be treated the same as return. Use NOP to skip it if needed.