Files
persona-script-editor/FORMAT.md
2026-07-17 01:04:47 +03:00

224 lines
9.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Megami Ibunroku Persona — Event Script Format Documentation
## Overview
The game stores event/dialogue scripts inside `ADV\E0.BIN` on the CD.
This file is a **container** holding 224 sub-files (individual event scripts).
---
## 1. CD Image (BIN/CUE)
- Format: MODE2/2352 (raw CD-ROM XA)
- Sector size: 2352 bytes
- User data offset: 24 bytes from sector start
- User data size: 2048 bytes per sector
The game uses internal file tables (not ISO9660) to locate files:
- **FSECT** (LBA 634): array of uint32_le, each entry = starting LBA of a game file
- **FSIZE** (LBA 623): array of uint32_le, each entry = size in bytes
- E0.BIN is at index **273** in both tables
---
## 2. E0 Container Format
```
┌─────────────────────────────────────────────┐
│ Pointer Table (variable length) │
│ uint16_le[N+1] pointers │
│ Terminated by 0x0000 │
├─────────────────────────────────────────────┤
│ Padding to 0x800 alignment │
├─────────────────────────────────────────────┤
│ Sub-file 0 (aligned to 0x800) │
├─────────────────────────────────────────────┤
│ Sub-file 1 (aligned to 0x800) │
├─────────────────────────────────────────────┤
│ ... │
├─────────────────────────────────────────────┤
│ Sub-file N-1 │
└─────────────────────────────────────────────┘
```
### Pointer Table
| Offset | Type | Description |
|--------|-----------|----------------------------------------------------|
| 0 | uint16_le | Pointer to sub-file 0 (in 0x800-byte units) |
| 2 | uint16_le | Pointer to sub-file 1 |
| ... | ... | ... |
| N*2 | uint16_le | End-of-data pointer (marks end of last sub-file) |
| (N+1)*2| uint16_le | 0x0000 (terminator) |
- Original E0 has **225 entries** (224 sub-files + 1 end marker)
- To get byte offset: `pointer_value * 0x800`
- Sub-file N size: `(ptr[N+1] - ptr[N]) * 0x800`
---
## 3. Event Script Sub-file Format
Each sub-file has:
```
┌─────────────────────────────────────────────┐
│ Sub-file Header (8 bytes typically) │
├─────────────────────────────────────────────┤
│ Script Data Section │
│ ├── Event Command Table (offsets 0x00-0x60+)│
│ ├── Script Bytecode │
│ ├── String Pointer Table │
│ ├── Text Data (strings) │
│ └── Trailing Data │
└─────────────────────────────────────────────┘
```
### Sub-file Header
| Offset | Type | Value | Description |
|--------|-----------|---------|--------------------------|
| 0 | uint16_le | 8 | Header size in bytes |
| 2 | uint16_le | 0x8010 | Marker (always 10 80) |
| 4 | uint16_le | varies | (purpose TBD) |
| 6 | uint16_le | 0x8010 | Marker (always 10 80) |
### Script Data Section
The data section starts immediately after the header (`offset = hdr_size`).
All offsets below are relative to the start of the data section.
#### Key Fields
| Offset | Type | Name | Description |
|--------|-----------|------------|--------------------------------------------------|
| 52 | uint16_le | ett | End of text table / start of text blob area |
| 96 | uint16_le | table_ptr | Offset to string pointer table within data |
If `table_ptr == 0xFFFF`, the sub-file has no dialogue strings.
#### String Pointer Table
Located at `data[table_ptr]`. Entries follow this pattern:
```
FF 55 00 00 [ptr_lo] [ptr_hi] 10 80
```
- `FF 55 00 00` = prefix marker (4 bytes before the pointer)
- `ptr_lo, ptr_hi` = uint16_le offset within data section pointing to string start
- `10 80` = suffix marker
The table continues until a different pattern is encountered.
To find all strings, scan from `table_ptr` looking for `FF 55 00 00 XX XX 10 80` sequences.
---
## 4. Text Encoding
### Single-byte characters (0x01-0x7F)
Originally mapped to Japanese kana. Values 0x01-0x7F are indices into the font file.
| Range | Original Content |
|-----------|--------------------------|
| 0x01-0x2E | Hiragana (あ-ん) |
| 0x2F-0x5E | Katakana (ア-ン) |
| 0x5F-0x7F | Extended katakana + marks |
For Russian translation, these are remapped to Cyrillic:
| Range | Content |
|-----------|--------------------------|
| 0x01-0x42 | А-я (66 letters + Ё/ё) |
| 0x43 | Space |
### Two-byte characters (0x80xx)
High byte 0x80+ triggers a two-byte read. The pair forms a code looked up in the TBL file.
Common punctuation codes:
| Code | Character |
|--------|-----------|
| 80 A5 | . (period) |
| 80 CB | : (colon) |
| 80 CC |   (JP space) |
| 80 D0 | ? (question)|
| 80 D1 | ! (exclaim) |
| 80 D5 | , (comma) |
| 80 E1 | - (dash) |
### Control codes (0xFF xx)
| Code | Parameters | Name | Description |
|-------------|---------------|--------------|------------------------------------|
| FF 00 | none | [ff00] | Unknown/NOP |
| FF 01 | none | (terminator) | End of string |
| FF 02 | none | [end] | End of dialogue sequence |
| FF 03 | none | [nl] | Newline |
| FF 04 | none | [clear] | Clear text box |
| FF 05 XX 00 | 1 byte + 00 | [wait=XX] | Pause for XX frames |
| FF 06 XX | 1 byte | [color=XX] | Set text color |
| FF 07 | none | [firstname] | Insert player's first name |
| FF 08 | none | [nickname] | Insert player's nickname |
| FF 09 | none | [ff09] | Unknown |
| FF 0A | none | [ff0a] | Unknown |
| FF 0B | none | [ff0b] | Unknown |
| FF 0C | none | [ff0c] | Unknown |
| FF 0D | none | [ff0d] | Unknown |
| FF 0E XX | 1 byte | [choice=XX] | Display choice menu (XX = menu ID) |
| FF 0F | none | [lastname] | Insert player's last name |
---
## 5. Font File
- Located at game file index **5** in FSECT/FSIZE
- Size: 65536 bytes
- Glyph size: 32 bytes each (16x16 pixels, 1bpp, 2 bytes per row)
- Glyph index N is at byte offset `N * 32`
- Indices 0x01-0x7F correspond to single-byte text codes
- Indices 0x80+ correspond to two-byte text code second bytes (TBL lookup)
---
## 6. TBL File (Persona_jap.tbl)
Plain text, UTF-8, format: `XXXX=char` per line where XXXX is hex code.
Example:
```
8090=漢
80A5=。
80CB=
80CC= 
80D0=
80D1=
80D5=、
```
The hex code is the 2-byte value as it appears in the script (big-endian in the TBL, but stored little-endian in the binary when the injector tool writes it).
---
## 7. Workflow for Translation
1. **Unpack**: Read ISO → extract E0 → parse pointer table → for each sub-file, parse strings
2. **Edit**: Modify string text (respecting encoding constraints and control codes)
3. **Repack**: Encode strings → rebuild sub-file (update string pointers) → rebuild E0 container → patch ISO
### Constraints when editing:
- New text blob must fit within `sub-file_size - ett` bytes (or sub-file must be resized)
- String pointer table positions are fixed (they're part of the script bytecode)
- Only the text area (after `ett`) is safe to resize
- If sub-file grows, the E0 container must be relocated in the ISO
---
## 8. Statistics (Original Japanese Rev 1)
- E0 container: 1,828,864 bytes (893 sectors)
- Sub-files: 224
- Sub-file sizes: 6,144 - 34,816 bytes
- Total dialogue strings: ~2,500 across all sub-files
- Sub-files with no strings (table_ptr=0xFFFF): ~27