summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/dump_names.py8
-rw-r--r--tools/dump_text.py262
-rw-r--r--tools/read_charmap.py49
-rw-r--r--tools/tests/README.txt1
-rw-r--r--tools/tests/charmap.asm293
-rw-r--r--tools/tests/dump_test.cc.txt26
-rw-r--r--tools/tests/dump_test.cc_endless.txt33
-rw-r--r--tools/tests/dump_test.cc_tc.txt27
-rw-r--r--tools/tests/dump_test.cc_tc_endless.txt35
-rw-r--r--tools/tests/dump_test.endless.txt9
-rw-r--r--tools/tests/dump_test.tc.txt4
-rw-r--r--tools/tests/dump_test.tc_endless.txt11
-rw-r--r--tools/tests/dump_test.txt3
-rw-r--r--tools/tests/dump_text_test.binbin0 -> 69 bytes
14 files changed, 711 insertions, 50 deletions
diff --git a/tools/dump_names.py b/tools/dump_names.py
index a80677e..81f357a 100644
--- a/tools/dump_names.py
+++ b/tools/dump_names.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
import sys, os, io
-from read_charmap import get_project_dir, read_charmap
+from read_charmap import read_charmap
def calc_bank(p):
return p // 0x4000
@@ -15,6 +15,12 @@ def get_sym_loc(p):
b, a = calc_bank(p), calc_address(p)
return '%02x:%04x' % (b, a)
+def get_project_dir():
+ script_path = os.path.realpath(__file__)
+ script_dir = os.path.dirname(script_path)
+ project_dir = os.path.join(script_dir, '..')
+ return os.path.normpath(project_dir)
+
def get_baserom_path():
project_dir = get_project_dir()
return os.path.join(project_dir, 'baserom.gb')
diff --git a/tools/dump_text.py b/tools/dump_text.py
index 3242c31..057de04 100644
--- a/tools/dump_text.py
+++ b/tools/dump_text.py
@@ -1,38 +1,252 @@
#!/usr/bin/python3
-from sys import argv, stdout
+import argparse
+import sys
from read_charmap import read_charmap
+charmap = {}
bank_size = 0x4000
-charmap = read_charmap()
+textcodes = {
+ '<NEXT>' : {'label': 'next', 'fin': False},
+ '<LINE>' : {'label': 'line', 'fin': False},
+ '<PARA>' : {'label': 'para', 'fin': False},
+ '<CONT>' : {'label': 'cont', 'fin': False},
+ '<DONE>' : {'label': 'done', 'fin': True},
+ '<PROMPT>': {'label': 'prompt', 'fin': True},
+}
-if len(argv) != 4:
- print(f"Usage: {argv[0]} path/to/ROM.gb start_offset end_offset\noffsets are in the form bank:address (both hex), and end_offset is *not* included.")
- exit(1)
+# codes that end text control code 0x00
+# True if this code exits control code parsing as well
+end_codes = {
+ '@' : False,
+ '<DONE>' : True,
+ '<PROMPT>': True,
+}
+def conv_address(x):
+ if ':' in x:
+ bank, addr = [ int(s, 16) for s in x.split(':') ]
+ if (addr < bank_size and bank != 0):
+ raise argparse.ArgumentTypeError('Illegal ROM bank 0x00 address {0:02X}:{1:04X}. '
+ 'Bank 0x{0:02X} must be 0x00.'.format(bank, addr))
+ elif (addr >= bank_size and bank == 0):
+ raise argparse.ArgumentTypeError('Illegal ROM bank 0x00 address {0:02X}:{1:04X}. '
+ 'Address 0x{1:04X} > 0x{2:04X}.'.format(bank, addr, bank_size - 1))
+ elif (addr >= 2*bank_size):
+ raise argparse.ArgumentTypeError('Illegal ROM bank address {0:02X}:{1:04X}. '
+ 'Address 0x{1:04X} > 0x{2:04X}.'.format(bank, addr, 2*bank_size - 1))
+ return bank * 0x4000 + (addr & 0x3fff)
+ return int(x, 0)
-try:
- start_bank,start_addr = [ int(s, 16) for s in argv[2].split(':') ]
- end_bank, end_addr = [ int(s, 16) for s in argv[3].split(':') ]
- if start_bank != 0:
- start_addr += (start_bank - 1) * bank_size
- if end_bank != 0:
- end_addr += (end_bank - 1) * bank_size
-except Error:
- print("Please specify valid offsets (bank:address, both hex)")
- exit(1)
+def addr2gb(addr):
+ bank = addr // bank_size
+ offset = addr % bank_size
+ if (bank > 0):
+ offset += bank_size
+ return bank, offset
+def transform_char(char, do_transform, is_begin):
+ result = ''
+ if (do_transform and char in textcodes):
+ replace = textcodes[char]
+ if (not is_begin):
+ result += '"\n'
+ result += replace['label']
+ if (not replace['fin']):
+ result += ' "'
+ return replace['fin'], result
+ else:
+ if (is_begin):
+ result += '"'
+ return False, (result + char)
-with open(argv[1], "rb") as f:
- f.seek(start_addr)
+def dump_asm(data):
+
+ result = 'start_asm ; text dumper cannot dump asm\n'
+ result += ' ; Try dumping asm from the following offset and\n'
+ result += ' ; then continue dumping text in control mode.\n'
+ return True, result
+
+def dump_control(data, label, signature):
- string = ""
- while start_addr < end_addr:
- b = f.read(1)
- v = int.from_bytes(b, "little")
- string += char_table[ v ]
- start_addr += 1
+ lengths = {'b': 1, 'n': 1, 'w': 2}
+
+ required_bytes = sum([lengths.get(c, 0) for c in signature])
+
+ if (data['len'] - data['offset'] < required_bytes):
+ #silently drop split control code
+ return True, ''
+
+ result = ''
+
+ for c in signature:
+ if result != '':
+ result += ', '
+ if c == 'b':
+ byte = data['bytes'][data['offset']]
+ data['offset'] += 1
+ result += '${0:02x}'.format(byte)
+ elif c == 'n':
+ byte = data['bytes'][data['offset']]
+ data['offset'] += 1
+ result += '${0:01x}, ${1:01x}'.format(byte >> 4, byte & 0x0f)
+ elif c == 'w':
+ word = data['bytes'][data['offset']]
+ data['offset'] += 1
+ word |= data['bytes'][data['offset']] << 8
+ data['offset'] += 1
+ result += '${0:02x}'.format(word)
+ else:
+ raise ValueError('Unknown signature char in {0:s}\'s signature "{1:s}".'.format(label, signature))
+
+ if (result != ''):
+ result = ' ' + result
+ return False, label + result
- stdout.buffer.write( f"db \"{string}\"\n".encode('utf-8') )
+def dump_text(data):
+
+ string = ''
+ exit_control = False
+ done = False
+ while (not done):
+
+ byte = data['bytes'][data['offset']]
+ data['offset'] += 1
+
+ char = charmap[byte]
+ fin, tchar = transform_char(char, data['textmode'], string == '')
+ string += tchar
+ if (char in end_codes):
+ done = True
+ exit_control = end_codes[char]
+ # end string if textmode didn't do it
+ if not data['textmode'] or not fin:
+ string += '"'
+ if (data['offset'] >= data['len']):
+ done = True
+ string += '"'
+
+ return exit_control, string
+
+def dump_text_control(data):
+
+ res, text = dump_text(data)
+ return res, 'text ' + text
+
+control_codes = {
+ 0x00: dump_text_control,
+ 0x01: lambda data: dump_control(data, 'text_from_ram' , 'w' ),
+ 0x02: lambda data: dump_control(data, 'text_bcd' , 'wb' ),
+ 0x03: lambda data: dump_control(data, 'text_move' , 'w' ),
+ 0x04: lambda data: dump_control(data, 'text_box' , 'wbb' ),
+ 0x05: lambda data: dump_control(data, 'text_low' , '' ),
+ 0x06: lambda data: dump_control(data, 'text_waitbutton' , '' ),
+ 0x07: lambda data: dump_control(data, 'text_scroll' , '' ),
+ 0x08: dump_asm,
+ 0x09: lambda data: dump_control(data, 'deciram' , 'wn' ),
+ 0x0A: lambda data: dump_control(data, 'text_exit' , '' ),
+ 0x0B: lambda data: dump_control(data, 'sound_dex_fanfare_50_79' , '' ),
+ 0x0C: lambda data: dump_control(data, 'text_dots' , 'b' ),
+ 0x0D: lambda data: dump_control(data, 'link_wait_button' , '' ),
+ 0x0E: lambda data: dump_control(data, 'sound_dex_fanfare_20_49' , '' ),
+ 0x0F: lambda data: dump_control(data, 'sound_item' , '' ),
+ 0x10: lambda data: dump_control(data, 'sound_caught_mon' , '' ),
+ 0x11: lambda data: dump_control(data, 'sound_dex_fanfare_80_109', '' ),
+ 0x12: lambda data: dump_control(data, 'sound_fanfare' , '' ),
+ 0x13: lambda data: dump_control(data, 'sound_slot_machine_start', '' ),
+ 0x14: lambda data: dump_control(data, 'cry_nidorina' , '' ),
+ 0x15: lambda data: dump_control(data, 'cry_pigeot' , '' ),
+ 0x16: lambda data: dump_control(data, 'cry_jugon' , '' ),
+ 0x50: lambda data: (True, 'text_end\n'),
+}
+
+def print_location(data):
+ return '.loc_{0:04X}:\n'.format(data['offset'])
+
+if __name__ == '__main__':
+ # argument parser
+ ap = argparse.ArgumentParser()
+ ap.add_argument('--cc', dest='ccmode', action='store_true',
+ help='dump in control code mode, implies text code macro mode'
+ )
+ ap.add_argument('--endless', dest='endless', action='store_true',
+ help='continue dumping even if string end text code was reached'
+ )
+ ap.add_argument('--tc', dest='textmode', action='store_true',
+ help='dump text codes (line breaks, prompt etc) as macros instead of inline text'
+ )
+ ap.add_argument('-o', dest='outfile', default=sys.stdout, help='output file name')
+ ap.add_argument('-m', dest='charmap', default='../charmap.asm', help='charmap file name')
+ ap.add_argument('rom', help='path to ROM')
+ ap.add_argument('start', help='start offset', type=conv_address)
+ ap.add_argument('end', help='end offset', type=conv_address, nargs='?')
+
+ args = ap.parse_args()
+ romname = args.rom
+ start_addr = args.start
+ end_addr = start_addr + bank_size if args.end is None else args.end
+ ccmode = args.ccmode
+ endless = args.endless
+ outfile = args.outfile
+ charmap = read_charmap(args.charmap)
+
+ if (end_addr < start_addr):
+ print('End address 0x{0:06X} ({1:02X}:{2:04X}) is before '
+ 'start address 0x{3:06X} ({4:02X}:{5:04X}).'.format(
+ end_addr,
+ *addr2gb(end_addr),
+ start_addr,
+ *addr2gb(start_addr)
+ ),
+ file=sys.stderr
+ )
+ sys.exit(-1)
+
+ bank_addr = start_addr & (~(bank_size - 1))
+ offset = start_addr - bank_addr
+ end_offset = end_addr - bank_addr
+
+ with open(romname, 'rb') as f:
+ f.seek(bank_addr)
+ bank_data = f.read(bank_size)
+
+ data = {'offset': offset, 'bytes': bank_data, 'len': min(end_offset, len(bank_data)), 'textmode': args.textmode}
+
+ with open(outfile, 'wb') if outfile != sys.stdout else outfile.buffer as f:
+ string = print_location(data)
+ while(data['offset'] < data['len']):
+ if (not ccmode):
+ # dumb mode
+ _, text = dump_text(data)
+ # start with db unless starting with a control code
+ # in textmode
+ if text[0] == '"' and data['textmode']:
+ string += '\tdb '
+ elif text[0] == '"':
+ string += '\tdb '
+ string += text.replace('\n', '\n\t')
+ string += '\n{0:s}'.format(print_location(data))
+ if (not endless):
+ break
+ else:
+ # control code mode
+ control_byte = data['bytes'][data['offset']]
+ data['offset'] += 1
+
+ if (control_byte in control_codes):
+ res, text = control_codes[control_byte](data)
+ string += '\t' + text.replace('\n', '\n\t')
+ string += '\n'
+ if (res):
+ string += print_location(data)
+ # exit out of control code parsing
+ if (res and not endless):
+ break
+ else:
+ print('Encountered unknown control code 0x{0:02X}. Abort...'.format(control_byte), file=sys.stderr)
+ break
+
+ f.write(string.encode('utf-8'))
+ f.close()
diff --git a/tools/read_charmap.py b/tools/read_charmap.py
index 9f396b4..af290c3 100644
--- a/tools/read_charmap.py
+++ b/tools/read_charmap.py
@@ -1,4 +1,20 @@
import os, io
+from re import compile
+from sys import stderr
+
+charmap_regex = compile('[ \t]*charmap[ \t]+"(.*?)",[ \t]*(\$[0-9A-Fa-f]{2}|%[01]{8}|[0-9]{3})')
+# A charmap line is
+# [ \t]* - zero or more space chars
+# charmap - literal charmap
+# [ \t]+ - one or more space chars
+# "(.*?)" - a lazily-matched text identifier in quotes
+# , - literal comma
+# [ \t]* - zero or more space chars
+# ( - either of
+# \$[0-9A-Fa-f]{2} - two hexadecimal digits preceeded by literal $
+# %[01]{8} - eight dual digits preceeded by literal %
+# [0-9]{3} - three decimal digits
+# )
def parse_int(s):
# assumes integers are literal; no +-*/, etc
@@ -9,35 +25,18 @@ def parse_int(s):
return int(s[1:], 2)
return int(s)
-def parse_string(s):
- # assumes strings are literal; no STRCAT() etc
- return s.strip('" ')
-
-def strip_comment(s):
- # assumes ";" is not in the charmap
- return s.split(';')[0].rstrip()
-
-def get_project_dir():
- script_path = os.path.realpath(__file__)
- script_dir = os.path.dirname(script_path)
- project_dir = os.path.join(script_dir, '..')
- return os.path.normpath(project_dir)
-
-def get_charmap_path():
- project_dir = get_project_dir()
- return os.path.join(project_dir, 'charmap.asm')
-
-def read_charmap():
- charmap_path = get_charmap_path()
+def read_charmap(charmap_path):
charmap = {}
with io.open(charmap_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
- line = strip_comment(line).lstrip()
- if not line.startswith('charmap '):
+ m = charmap_regex.match(line)
+ if m is None:
+ continue
+ char = m.group(1)
+ value = parse_int(m.group(2))
+ if value in charmap:
+ print('Value {0:s} already in charmap, dropping it in favor of first charmap entry'.format(m.group(2)))
continue
- char, value = line[len('charmap '):].rsplit(',', 1)
- char = parse_string(char)
- value = parse_int(value)
charmap[value] = char
return charmap
diff --git a/tools/tests/README.txt b/tools/tests/README.txt
new file mode 100644
index 0000000..750482e
--- /dev/null
+++ b/tools/tests/README.txt
@@ -0,0 +1 @@
+python dump_text.py -o dump_test.txt -m charmap.asm dump_text_test.bin 00:0000
diff --git a/tools/tests/charmap.asm b/tools/tests/charmap.asm
new file mode 100644
index 0000000..228bb6b
--- /dev/null
+++ b/tools/tests/charmap.asm
@@ -0,0 +1,293 @@
+ charmap "<NULL>", $00
+
+ charmap "イ゛", $01
+ charmap "ヴ", $02
+ charmap "エ゛", $03
+ charmap "オ゛", $04
+
+ charmap "ガ", $05
+ charmap "ギ", $06
+ charmap "グ", $07
+ charmap "ゲ", $08
+ charmap "ゴ", $09
+ charmap "ザ", $0a
+ charmap "ジ", $0b
+ charmap "ズ", $0c
+ charmap "ゼ", $0d
+ charmap "ゾ", $0e
+ charmap "ダ", $0f
+ charmap "ヂ", $10
+ charmap "ヅ", $11
+ charmap "デ", $12
+ charmap "ド", $13
+
+ charmap "<PLAY_G>", $14 ; "<PLAYER>くん" or "<PLAYER>ちゃん"
+
+ charmap "<15>", $15 ; nothing
+ charmap "<16>", $16 ; nothing
+
+ charmap "ネ゛", $17
+ charmap "ノ゛", $18
+
+ charmap "バ", $19
+ charmap "ビ", $1a
+ charmap "ブ", $1b
+ charmap "ボ", $1c
+
+ charmap "<NI>", $1d ; "に "
+ charmap "<TTE>", $1e ; "って"
+ charmap "<WO>", $1f ; "を "
+
+ charmap "ィ゛", $20
+ charmap "あ゛", $21
+
+ charmap "<TA!>", $22 ; "た!"
+ charmap "<KOUGEKI>", $23 ; "こうげき"
+ charmap "<WA>", $24 ; "は "
+ charmap "<NO>", $25 ; "の "
+
+ charmap "が", $26
+ charmap "ぎ", $27
+ charmap "ぐ", $28
+ charmap "げ", $29
+ charmap "ご", $2a
+ charmap "ざ", $2b
+ charmap "じ", $2c
+ charmap "ず", $2d
+ charmap "ぜ", $2e
+ charmap "ぞ", $2f
+ charmap "だ", $30
+ charmap "ぢ", $31
+ charmap "づ", $32
+ charmap "で", $33
+ charmap "ど", $34
+
+ charmap "<ROUTE>", $35 ; "ばん どうろ"
+ charmap "<WATASHI>", $36 ; "わたし"
+ charmap "<KOKO_WA>", $37 ; "ここは"
+ charmap "<RED>", $38 ; wRedsName
+ charmap "<GREEN>", $39 ; wGreensName
+
+ charmap "ば", $3a
+ charmap "び", $3b
+ charmap "ぶ", $3c
+ charmap "べ", $3d
+ charmap "ぼ", $3e
+
+ charmap "<ENEMY>", $3f
+
+ charmap "パ", $40
+ charmap "ピ", $41
+ charmap "プ", $42
+ charmap "ポ", $43
+ charmap "ぱ", $44
+ charmap "ぴ", $45
+ charmap "ぷ", $46
+ charmap "ぺ", $47
+ charmap "ぽ", $48
+
+ charmap "<MOM>", $49 ; wMomsName
+ charmap "<GA>", $4a ; "が "
+ charmap "<_CONT>", $4b ; implements "<CONT>"
+ charmap "<SCROLL>", $4c
+
+ charmap "も゜", $4d
+
+ charmap "<NEXT>", $4e
+ charmap "<LINE>", $4f
+ charmap "@", $50 ; string terminator
+ charmap "<PARA>", $51
+ charmap "<PLAYER>", $52 ; wPlayerName
+ charmap "<RIVAL>", $53 ; wRivalName
+ charmap "#", $54 ; "POKé"
+ charmap "<CONT>", $55
+ charmap "<……>", $56 ; "……"
+ charmap "<DONE>", $57
+ charmap "<PROMPT>", $58
+ charmap "<TARGET>", $59
+ charmap "<USER>", $5a
+ charmap "<PC>", $5b ; "PC"
+ charmap "<TM>", $5c ; "TM"
+ charmap "<TRAINER>", $5d ; "TRAINER"
+ charmap "<ROCKET>", $5e ; "ROCKET"
+ charmap "<DEXEND>", $5f
+
+ charmap "■", $60
+ charmap "▲", $61
+ charmap "☎", $62
+
+ charmap "D", $63
+ charmap "E", $64
+ charmap "F", $65
+ charmap "G", $66
+ charmap "H", $67
+ charmap "I", $68
+ charmap "V", $69
+ charmap "S", $6a
+ charmap "L", $6b
+ charmap "M", $6c
+
+ charmap ":", $6d
+
+ charmap "ぃ", $6e
+ charmap "ぅ", $6f
+
+ charmap "「", $70
+ charmap "」", $71
+ charmap "『", $72
+ charmap "』", $73
+ charmap "・", $74
+ charmap "…", $75
+
+ charmap "ぁ", $76
+ charmap "ぇ", $77
+ charmap "ぉ", $78
+
+ charmap "┌", $79
+ charmap "─", $7a
+ charmap "┐", $7b
+ charmap "│", $7c
+ charmap "└", $7d
+ charmap "┘", $7e
+
+ charmap " ", $7f
+
+ charmap "ア", $80
+ charmap "イ", $81
+ charmap "ウ", $82
+ charmap "エ", $83
+ charmap "オ", $84
+ charmap "カ", $85
+ charmap "キ", $86
+ charmap "ク", $87
+ charmap "ケ", $88
+ charmap "コ", $89
+ charmap "サ", $8a
+ charmap "シ", $8b
+ charmap "ス", $8c
+ charmap "セ", $8d
+ charmap "ソ", $8e
+ charmap "タ", $8f
+ charmap "チ", $90
+ charmap "ツ", $91
+ charmap "テ", $92
+ charmap "ト", $93
+ charmap "ナ", $94
+ charmap "ニ", $95
+ charmap "ヌ", $96
+ charmap "ネ", $97
+ charmap "ノ", $98
+ charmap "ハ", $99
+ charmap "ヒ", $9a
+ charmap "フ", $9b
+ charmap "ホ", $9c
+ charmap "マ", $9d
+ charmap "ミ", $9e
+ charmap "ム", $9f
+ charmap "メ", $a0
+ charmap "モ", $a1
+ charmap "ヤ", $a2
+ charmap "ユ", $a3
+ charmap "ヨ", $a4
+ charmap "ラ", $a5
+ charmap "ル", $a6
+ charmap "レ", $a7
+ charmap "ロ", $a8
+ charmap "ワ", $a9
+ charmap "ヲ", $aa
+ charmap "ン", $ab
+
+ charmap "ッ", $ac
+ charmap "ャ", $ad
+ charmap "ュ", $ae
+ charmap "ョ", $af
+ charmap "ィ", $b0
+
+ charmap "あ", $b1
+ charmap "い", $b2
+ charmap "う", $b3
+ charmap "え", $b4
+ charmap "お", $b5
+ charmap "か", $b6
+ charmap "き", $b7
+ charmap "く", $b8
+ charmap "け", $b9
+ charmap "こ", $ba
+ charmap "さ", $bb
+ charmap "し", $bc
+ charmap "す", $bd
+ charmap "せ", $be
+ charmap "そ", $bf
+ charmap "た", $c0
+ charmap "ち", $c1
+ charmap "つ", $c2
+ charmap "て", $c3
+ charmap "と", $c4
+ charmap "な", $c5
+ charmap "に", $c6
+ charmap "ぬ", $c7
+ charmap "ね", $c8
+ charmap "の", $c9
+ charmap "は", $ca
+ charmap "ひ", $cb
+ charmap "ふ", $cc
+ charmap "へ", $cd
+ charmap "ほ", $ce
+ charmap "ま", $cf
+ charmap "み", $d0
+ charmap "む", $d1
+ charmap "め", $d2
+ charmap "も", $d3
+ charmap "や", $d4
+ charmap "ゆ", $d5
+ charmap "よ", $d6
+ charmap "ら", $d7
+ charmap "り", $d8
+ charmap "る", $d9
+ charmap "れ", $da
+ charmap "ろ", $db
+ charmap "わ", $dc
+ charmap "を", $dd
+ charmap "ん", $de
+
+ charmap "っ", $df
+ charmap "ゃ", $e0
+ charmap "ゅ", $e1
+ charmap "ょ", $e2
+
+ charmap "ー", $e3
+
+ charmap "゚", $e4
+ charmap "゙", $e5
+
+ charmap "?", $e6
+ charmap "!", $e7
+ charmap "。", $e8
+
+ charmap "ァ", $e9
+ charmap "ゥ", $ea
+ charmap "ェ", $eb
+
+ charmap "▷", $ec
+ charmap "▶", $ed
+ charmap "▲", $ed
+ charmap "▼", $ee
+ charmap "♂", $ef
+ charmap "円", $f0
+ charmap "×", $f1
+ charmap ".", $f2
+ charmap "/", $f3
+
+ charmap "ォ", $f4
+
+ charmap "♀", $f5
+ charmap "0", $f6
+ charmap "1", $f7
+ charmap "2", $f8
+ charmap "3", $f9
+ charmap "4", $fa
+ charmap "5", $fb
+ charmap "6", $fc
+ charmap "7", $fd
+ charmap "8", $fe
+ charmap "9", $ff
diff --git a/tools/tests/dump_test.cc.txt b/tools/tests/dump_test.cc.txt
new file mode 100644
index 0000000..4dfd14a
--- /dev/null
+++ b/tools/tests/dump_test.cc.txt
@@ -0,0 +1,26 @@
+.loc_0000:
+ text "ほんとにりセットしますか?<LINE>@"
+ text_from_ram $ce33
+ text_bcd $ce34, $78
+ text_move $ce35
+ text_box $cc36, $08, $12
+ text_low
+ text_waitbutton
+ text_scroll
+ deciram $cc37, $6, $5
+ text_exit
+ sound_dex_fanfare_50_79
+ text_dots $14
+ link_wait_button
+ sound_dex_fanfare_20_49
+ sound_item
+ sound_caught_mon
+ sound_dex_fanfare_80_109
+ sound_fanfare
+ sound_slot_machine_start
+ cry_nidorina
+ cry_pigeot
+ cry_jugon
+ text_end
+
+.loc_0035:
diff --git a/tools/tests/dump_test.cc_endless.txt b/tools/tests/dump_test.cc_endless.txt
new file mode 100644
index 0000000..5c59830
--- /dev/null
+++ b/tools/tests/dump_test.cc_endless.txt
@@ -0,0 +1,33 @@
+.loc_0000:
+ text "ほんとにりセットしますか?<LINE>@"
+ text_from_ram $ce33
+ text_bcd $ce34, $78
+ text_move $ce35
+ text_box $cc36, $08, $12
+ text_low
+ text_waitbutton
+ text_scroll
+ deciram $cc37, $6, $5
+ text_exit
+ sound_dex_fanfare_50_79
+ text_dots $14
+ link_wait_button
+ sound_dex_fanfare_20_49
+ sound_item
+ sound_caught_mon
+ sound_dex_fanfare_80_109
+ sound_fanfare
+ sound_slot_machine_start
+ cry_nidorina
+ cry_pigeot
+ cry_jugon
+ text_end
+
+.loc_0035:
+ text "ほんとにりセットしますか?<DONE>"
+.loc_0044:
+ start_asm ; text dumper cannot dump asm
+ ; Try dumping asm from the following offset and
+ ; then continue dumping text in control mode.
+
+.loc_0045:
diff --git a/tools/tests/dump_test.cc_tc.txt b/tools/tests/dump_test.cc_tc.txt
new file mode 100644
index 0000000..e49a010
--- /dev/null
+++ b/tools/tests/dump_test.cc_tc.txt
@@ -0,0 +1,27 @@
+.loc_0000:
+ text "ほんとにりセットしますか?"
+ line "@"
+ text_from_ram $ce33
+ text_bcd $ce34, $78
+ text_move $ce35
+ text_box $cc36, $08, $12
+ text_low
+ text_waitbutton
+ text_scroll
+ deciram $cc37, $6, $5
+ text_exit
+ sound_dex_fanfare_50_79
+ text_dots $14
+ link_wait_button
+ sound_dex_fanfare_20_49
+ sound_item
+ sound_caught_mon
+ sound_dex_fanfare_80_109
+ sound_fanfare
+ sound_slot_machine_start
+ cry_nidorina
+ cry_pigeot
+ cry_jugon
+ text_end
+
+.loc_0035:
diff --git a/tools/tests/dump_test.cc_tc_endless.txt b/tools/tests/dump_test.cc_tc_endless.txt
new file mode 100644
index 0000000..dbf8e8b
--- /dev/null
+++ b/tools/tests/dump_test.cc_tc_endless.txt
@@ -0,0 +1,35 @@
+.loc_0000:
+ text "ほんとにりセットしますか?"
+ line "@"
+ text_from_ram $ce33
+ text_bcd $ce34, $78
+ text_move $ce35
+ text_box $cc36, $08, $12
+ text_low
+ text_waitbutton
+ text_scroll
+ deciram $cc37, $6, $5
+ text_exit
+ sound_dex_fanfare_50_79
+ text_dots $14
+ link_wait_button
+ sound_dex_fanfare_20_49
+ sound_item
+ sound_caught_mon
+ sound_dex_fanfare_80_109
+ sound_fanfare
+ sound_slot_machine_start
+ cry_nidorina
+ cry_pigeot
+ cry_jugon
+ text_end
+
+.loc_0035:
+ text "ほんとにりセットしますか?"
+ done
+.loc_0044:
+ start_asm ; text dumper cannot dump asm
+ ; Try dumping asm from the following offset and
+ ; then continue dumping text in control mode.
+
+.loc_0045:
diff --git a/tools/tests/dump_test.endless.txt b/tools/tests/dump_test.endless.txt
new file mode 100644
index 0000000..fbbdeef
--- /dev/null
+++ b/tools/tests/dump_test.endless.txt
@@ -0,0 +1,9 @@
+.loc_0000:
+ db "<NULL>ほんとにりセットしますか?<LINE>@"
+.loc_0010:
+ db "イ゛でほヴどほぉエ゛<ROUTE>ほオ゛<WATASHI>ふゲデガギグゴ<KOKO_WA>ふFザジズ<PLAY_G>ゼゾダヂヅデド<PLAY_G><15><16>@"
+.loc_0035:
+ db "<NULL>ほんとにりセットしますか?<DONE>"
+.loc_0044:
+ db "ゲ"
+.loc_0045:
diff --git a/tools/tests/dump_test.tc.txt b/tools/tests/dump_test.tc.txt
new file mode 100644
index 0000000..82c276d
--- /dev/null
+++ b/tools/tests/dump_test.tc.txt
@@ -0,0 +1,4 @@
+.loc_0000:
+ db "<NULL>ほんとにりセットしますか?"
+ line "@"
+.loc_0010:
diff --git a/tools/tests/dump_test.tc_endless.txt b/tools/tests/dump_test.tc_endless.txt
new file mode 100644
index 0000000..37bdda0
--- /dev/null
+++ b/tools/tests/dump_test.tc_endless.txt
@@ -0,0 +1,11 @@
+.loc_0000:
+ db "<NULL>ほんとにりセットしますか?"
+ line "@"
+.loc_0010:
+ db "イ゛でほヴどほぉエ゛<ROUTE>ほオ゛<WATASHI>ふゲデガギグゴ<KOKO_WA>ふFザジズ<PLAY_G>ゼゾダヂヅデド<PLAY_G><15><16>@"
+.loc_0035:
+ db "<NULL>ほんとにりセットしますか?"
+ done
+.loc_0044:
+ db "ゲ"
+.loc_0045:
diff --git a/tools/tests/dump_test.txt b/tools/tests/dump_test.txt
new file mode 100644
index 0000000..a181744
--- /dev/null
+++ b/tools/tests/dump_test.txt
@@ -0,0 +1,3 @@
+.loc_0000:
+ db "<NULL>ほんとにりセットしますか?<LINE>@"
+.loc_0010:
diff --git a/tools/tests/dump_text_test.bin b/tools/tests/dump_text_test.bin
new file mode 100644
index 0000000..778a446
--- /dev/null
+++ b/tools/tests/dump_text_test.bin
Binary files differ