# The Hundred Line: Last Defense Academy - Dialogue Browser Toolkit

A searchable bilingual (EN/JP) database and browser for game dialogue, with support for audio playback and character sprites.

## Requirements

- Python 3.8+
- PyQt6: `pip install PyQt6`
- SQLite3 (included with Python)

## Quick Start

1. Place `dialogue_browser_qt.py` and `hundred_line_dialogue_v2.db` in the same folder
2. Run: `python dialogue_browser_qt.py`

---

## Full Setup Guide

### Step 1: Extract Game Files

Use [MVGLTools](https://github.com/TopherLee513/MVGLTools) to extract game data:

**Text files (EN):**
```
MVGLTool.exe extract "path\to\app_text01.mvgl" -o en\app_text01.dx11
MVGLTool.exe extract "path\to\patch_text01.mvgl" -o en\patch_text01.dx11
```

**Text files (JP):**
```
MVGLTool.exe extract "path\to\app_text00.mvgl" -o jp\app_text00.dx11
```

**Lua scripts:**
```
MVGLTool.exe extract "path\to\app_lua.mvgl" -o lua
```

**Images (for sprites):**
```
MVGLTool.exe extract "path\to\app_image.mvgl" -o images
```

### Step 2: Build the Database

Place your extracted folders in this structure:
```
Browser/
├── en/
│   ├── app_text01.dx11/
│   └── patch_text01.dx11/
├── jp/
│   └── app_text00.dx11/
└── rebuild_database_v3.py
```

Run the database builder:
```
python rebuild_database_v3.py
```

This creates `hundred_line_dialogue_v2.db` (~122MB, ~197,000 lines).

### Step 3: Extract Sprite Mappings (Optional)

To display character sprites alongside dialogue:

#### 3a. Decompile Lua Scripts

Download [unluac](https://sourceforge.net/projects/unluac/) and place `unluac.jar` in your lua folder.

Create `decompile_all.bat`:
```batch
@echo off
mkdir decompiled
for %%f in (*.lua) do (
    echo Decompiling %%f...
    java -jar unluac.jar "%%f" > "decompiled\%%f"
)
echo Done!
```

Run it to decompile all ~13,000 Lua scripts.

#### 3b. Parse Sprite Mappings

```
python parse_lua_sprites.py decompiled hundred_line_dialogue_v2.db
```

This adds a `sprite_mapping` table linking each dialogue line to its character sprite.

#### 3c. Convert Sprite Images

The game uses `.img` format. Convert to PNG using IrfanView:

1. File → Batch Conversion/Rename (or press `B`)
2. Add all `t_pic_chr*.img` files from your images folder
3. Set output format to PNG
4. Set output directory (e.g., `sprites_png`)
5. Start batch conversion

Only the `t_pic_chr###_####.img` files are character portraits (~1,837 files).

#### 3d. Configure Browser

In the browser, go to View → Sprite Settings and set the path to your `sprites_png` folder.

### Step 4: Audio Setup (Optional)

**Extract audio:**
```
MVGLTool.exe extract "path\to\app_voice.mvgl" -o voice
```

**Convert HCA to MP3:**

The voice files are in HCA format. Use foobar2000 with the vgmstream plugin to batch convert to MP3.

**Configure browser:**

Go to View → Audio Settings and set paths to your EN and JP audio folders.

---

## Database Schema

### dialogue table
| Column | Description |
|--------|-------------|
| speaker_id | Numeric character ID |
| speaker_name | Character name (corrected) |
| dialogue_raw | Original text with format codes |
| dialogue_clean | Text with format codes stripped |
| dialogue_jp | Japanese text |
| route_code | Internal route identifier |
| route_name | Display name for route |
| branch | Branch code (aa, ab, aaa, etc.) |
| day | In-game day number |
| folder_name | Source .mbe folder |
| line_order | Line number within scene |
| source | 'app' or 'patch' |
| audio_file_en | EN voice file reference |
| audio_file_jp | JP voice file reference |

### sprite_mapping table (if created)
| Column | Description |
|--------|-------------|
| folder_name | Scene folder (.mbe) |
| line_order | Dialogue line number |
| sprite_char_id | Character ID for sprite |
| sprite_code | Expression/variant code |

Sprite filename format: `t_pic_chr{ID:03d}_{CODE}.png`

---

## Features

- **Bilingual search**: Search EN and JP dialogue simultaneously
- **Full-text search**: Fast searching across ~197,000 lines
- **Filters**: Speaker, route, day range, source (app/patch)
- **Context panel**: See surrounding dialogue with synchronized EN/JP rows
- **Color codes**: Game text colors preserved in display
- **Audio playback**: Play EN/JP voice clips (requires audio setup)
- **Sprite display**: See character portraits (requires sprite setup)
- **Spoiler protection**: Hide routes/characters until you've reached them

---

## Special Cases Handled

### Nozomi Narration
Speaker ID 305 is normally "Takumi (Narration)" but becomes "Nozomi (Narration)" in:
- Slasher Route, Day 74+ (branches aa, aaa, aab)
- Second Scenario, Day 100, scene m190+

### Color Codes
The game uses `{fc(HEXCOLOR)text}` for colored text. The browser displays these colors in the context panel:
- `57e4f1` (cyan) - Narration/inner monologue
- `ff635b` (coral) - Emphasized text (book titles, etc.)
- Various others for system messages and special dialogue

---

## Files

| File | Purpose |
|------|---------|
| `dialogue_browser_qt.py` | Main browser application |
| `rebuild_database_v3.py` | Database builder script |
| `parse_lua_sprites.py` | Sprite mapping extractor |
| `hundred_line_dialogue_v2.db` | SQLite database |
| `find_color_codes.py` | Utility to locate color-coded dialogue |
| `find_nozomi_narration.py` | Utility to verify Nozomi narration scenes |

---

## Troubleshooting

**"pip not found"**: Try `py -m pip install PyQt6` instead

**Database not found**: Ensure `.db` file is in the same folder as the browser script

**Audio won't play**: Check paths in View → Audio Settings; ensure files are converted to a playable format

**Sprites not showing**: Verify PNG conversion completed and path is set in View → Sprite Settings

---

## Credits

- Game: *The Hundred Line: Last Defense Academy* by Too Kyo Games / Aniplex
- Extraction: MVGLTools by TopherLee513
- Lua decompilation: unluac
