Skip to content

Commit 09d30ae

Browse files
committed
use both jp and en text files for messages
1 parent 47d83ca commit 09d30ae

File tree

8 files changed

+22237
-22064
lines changed

8 files changed

+22237
-22064
lines changed

ASM/build/asm_symbols.txt

Lines changed: 420 additions & 419 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ASM/src/build.asm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ RANDO_CONTEXT:
111111
.include "drop_overrides/obj_comb.asm"
112112
.include "drop_overrides/actor.asm"
113113
.include "rand_seed.asm"
114+
.include "messages.asm"
114115

115116
.align 0x10
116117
.importobj "../build/bundle.o"

ASM/src/hacks.asm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,6 +3023,25 @@ skip_GS_BGS_text:
30233023
.orga 0xB575C8
30243024
sw t6, 0x00(a1)
30253025

3026+
; Dynamically load the en/jp message files for text lookup. Both files are utilized to make room
3027+
; for additional text. The jp file is filled first. The segment value for the requested text ID
3028+
; is used to manipulate the language bit to tell Message_OpenText (func_800DC838) which file
3029+
; to load and search. Hook at VRAM 0x800DCB60 in message.s
3030+
.orga 0xB52AC0
3031+
jal set_message_file_to_search
3032+
nop
3033+
3034+
; Since message lookup already occurs in the above hook, remove the lookup from both the JP and EN
3035+
; branches.
3036+
.orga 0xB52AD0 ; JP branch
3037+
nop
3038+
nop
3039+
nop
3040+
nop
3041+
.orga 0xB52B64 ; EN branch
3042+
nop
3043+
nop
3044+
30263045
;==================================================================================================
30273046
; Null Boomerang Pointer in Links Instance
30283047
;==================================================================================================

ASM/src/messages.asm

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
; Manipulates the save context language bit based
2+
; on the segment value for the requested text ID.
3+
; Message lookup is moved here from the vanilla
4+
; branches.
5+
; t6 used for branching to JP/EN file loading
6+
; in parent function func_800DC838 at VRAM 0x800DCB68
7+
; 0 == JP
8+
; 1 == EN
9+
set_message_file_to_search:
10+
; displaced code
11+
lhu a1, 0x0046($sp)
12+
lw a0, 0x0040($sp)
13+
14+
; Saved by vanilla code prior to jump to
15+
; message lookup function. Called here so
16+
; we can safely store $ra.
17+
sw t0, 0x002C($sp)
18+
19+
; Message lookup saves to the stack without
20+
; changing the stack pointer. Save to an
21+
; unused variable to avoid changing the stack.
22+
or t4, $zero, $ra
23+
24+
; call JP message lookup function exclusively
25+
; since the JP/EN tables are merged.
26+
jal 0x800D69EC
27+
nop
28+
29+
; a1 contains the segment/offset word, formatted as
30+
; ssoooooo
31+
; where "s" is the segment and "o" is the offset.
32+
; Vanilla crashes on a failed text lookup already,
33+
; so we don't need to worry about bad values.
34+
srl t0, a1, 0x18
35+
andi t0, t0, 0x08
36+
sltiu t6, t0, 0x0001
37+
38+
or $ra, $zero, t4
39+
jr $ra
40+
nop

Messages.py

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from TextBox import line_wrap
66
from Utils import find_last
77

8-
TEXT_START = 0x92D000
8+
ENG_TEXT_START = 0x92D000
9+
JPN_TEXT_START = 0x8EB000
910
ENG_TEXT_SIZE_LIMIT = 0x39000
10-
JPN_TEXT_SIZE_LIMIT = 0x3A150
11+
JPN_TEXT_SIZE_LIMIT = 0x3B000
1112

1213
JPN_TABLE_START = 0xB808AC
1314
ENG_TABLE_START = 0xB849EC
@@ -19,6 +20,9 @@
1920
EXTENDED_TABLE_START = JPN_TABLE_START # start writing entries to the jp table instead of english for more space
2021
EXTENDED_TABLE_SIZE = JPN_TABLE_SIZE + ENG_TABLE_SIZE # 0x8360 bytes, 4204 entries
2122

23+
EXTENDED_TEXT_START = JPN_TABLE_START # start writing text to the jp table instead of english for more space
24+
EXTENDED_TEXT_SIZE_LIMIT = JPN_TEXT_SIZE_LIMIT + ENG_TEXT_SIZE_LIMIT # 0x74000 bytes
25+
2226
# name of type, followed by number of additional bytes to read, follwed by a function that prints the code
2327
CONTROL_CODES = {
2428
0x00: ('pad', 0, lambda _: '<pad>' ),
@@ -455,14 +459,14 @@ def size(self):
455459
return size
456460

457461
# writes the code to the given offset, and returns the offset of the next byte
458-
def write(self, rom, offset):
459-
rom.write_byte(TEXT_START + offset, self.code)
462+
def write(self, rom, text_start, offset):
463+
rom.write_byte(text_start + offset, self.code)
460464

461465
extra_bytes = 0
462466
if self.code in CONTROL_CODES:
463467
extra_bytes = CONTROL_CODES[self.code][1]
464468
bytes_to_write = int_to_bytes(self.data, extra_bytes)
465-
rom.write_bytes(TEXT_START + offset + 1, bytes_to_write)
469+
rom.write_bytes(text_start + offset + 1, bytes_to_write)
466470

467471
return offset + 1 + extra_bytes
468472

@@ -609,20 +613,20 @@ def transform(self, replace_ending=False, ending=None, always_allow_skip=True, s
609613

610614
# writes a Message back into the rom, using the given index and offset to update the table
611615
# returns the offset of the next message
612-
def write(self, rom, index, offset):
616+
def write(self, rom, index, text_start, offset, bank):
613617
# construct the table entry
614618
id_bytes = int_to_bytes(self.id, 2)
615619
offset_bytes = int_to_bytes(offset, 3)
616-
entry = id_bytes + bytes([self.opts, 0x00, 0x07]) + offset_bytes
620+
entry = id_bytes + bytes([self.opts, 0x00, bank]) + offset_bytes
617621
# write it back
618622
entry_offset = EXTENDED_TABLE_START + 8 * index
619623
rom.write_bytes(entry_offset, entry)
620624

621625
for code in self.text_codes:
622-
offset = code.write(rom, offset)
626+
offset = code.write(rom, text_start, offset)
623627

624628
while offset % 4 > 0:
625-
offset = Text_Code(0x00, 0).write(rom, offset) # pad to 4 byte align
629+
offset = Text_Code(0x00, 0).write(rom, text_start, offset) # pad to 4 byte align
626630

627631
return offset
628632

@@ -651,8 +655,14 @@ def __init__(self, raw_text, index, id, opts, offset, length):
651655

652656
# read a single message from rom
653657
@classmethod
654-
def from_rom(cls, rom, index):
655-
entry_offset = ENG_TABLE_START + 8 * index
658+
def from_rom(cls, rom, index, eng=True):
659+
if eng:
660+
table_start = ENG_TABLE_START
661+
text_start = ENG_TEXT_START
662+
else:
663+
table_start = JPN_TABLE_START
664+
text_start = JPN_TEXT_START
665+
entry_offset = table_start + 8 * index
656666
entry = rom.read_bytes(entry_offset, 8)
657667
next = rom.read_bytes(entry_offset + 8, 8)
658668

@@ -661,7 +671,7 @@ def from_rom(cls, rom, index):
661671
offset = bytes_to_int(entry[5:8])
662672
length = bytes_to_int(next[5:8]) - offset
663673

664-
raw_text = rom.read_bytes(TEXT_START + offset, length)
674+
raw_text = rom.read_bytes(text_start + offset, length)
665675

666676
return cls(raw_text, index, id, opts, offset, length)
667677

@@ -922,19 +932,50 @@ def read_messages(rom):
922932
index += 1
923933
table_offset += 8
924934

935+
# Also grab 0xFFFC entry from JP table.
936+
messages.append(read_fffc_message(rom))
925937
return messages
926938

939+
# The JP text table is the only source for ID 0xFFFC, which is used by the
940+
# title and file select screens. Preserve this table entry and text data when
941+
# overwriting the JP data. The regular read_messages function only reads English
942+
# data.
943+
def read_fffc_message(rom):
944+
table_offset = JPN_TABLE_START
945+
index = 0
946+
while True:
947+
entry = rom.read_bytes(table_offset, 8)
948+
id = bytes_to_int(entry[0:2])
949+
950+
if id == 0xFFFC:
951+
message = Message.from_rom(rom, index)
952+
break
953+
954+
index += 1
955+
table_offset += 8
956+
957+
return message
958+
927959
# write the messages back
928960
def repack_messages(rom, messages, permutation=None, always_allow_skip=True, speed_up_text=True):
929961

930-
rom.update_dmadata_record(TEXT_START, TEXT_START, TEXT_START + ENG_TEXT_SIZE_LIMIT)
962+
rom.update_dmadata_record(ENG_TEXT_START, ENG_TEXT_START, ENG_TEXT_START + ENG_TEXT_SIZE_LIMIT)
963+
rom.update_dmadata_record(JPN_TEXT_START, JPN_TEXT_START, JPN_TEXT_START + JPN_TEXT_SIZE_LIMIT)
931964

932965
if permutation is None:
933966
permutation = range(len(messages))
934967

935968
# repack messages
936969
offset = 0
937-
text_size_limit = ENG_TEXT_SIZE_LIMIT
970+
text_start = JPN_TEXT_START
971+
text_size_limit = EXTENDED_TEXT_SIZE_LIMIT
972+
text_bank = 0x08 # start with the Japanese text bank
973+
jp_bytes = 0
974+
# An extra dummy message is inserted after exhausting the JP text file.
975+
# Written message IDs are independent of the python list index, but the
976+
# index has to be maintained for old/new lookups. This wouldn't be an
977+
# issue if text shuffle didn't exist.
978+
jp_index_offset = 0
938979

939980
for old_index, new_index in enumerate(permutation):
940981
old_message = messages[old_index]
@@ -943,21 +984,57 @@ def repack_messages(rom, messages, permutation=None, always_allow_skip=True, spe
943984
new_message.id = old_message.id
944985

945986
# modify message, making it represent how we want it to be written
946-
new_message.transform(True, old_message.ending, always_allow_skip, speed_up_text)
987+
if new_message.id != 0xFFFC:
988+
new_message.transform(True, old_message.ending, always_allow_skip, speed_up_text)
989+
990+
# check if there is space to write the message
991+
message_size = new_message.size()
992+
if message_size + offset > JPN_TEXT_SIZE_LIMIT:
993+
# Add a dummy entry to the table for the last entry in the
994+
# JP file. This is used by the game to calculate message
995+
# length. Since the next entry in the English table has an
996+
# offset of zero, which would lead to a negative length.
997+
# 0xFFFD is used as the text ID for this in vanilla.
998+
# Text IDs need to be in order across the table for the
999+
# split to work.
1000+
entry = bytes([0xFF, 0xFD, 0x00, 0x00, text_bank]) + int_to_bytes(offset, 3)
1001+
entry_offset = EXTENDED_TABLE_START + 8 * old_index
1002+
rom.write_bytes(entry_offset, entry)
1003+
# if there is no room then switch to the English text bank
1004+
text_bank = 0x07
1005+
text_start = ENG_TEXT_START
1006+
jp_bytes = offset
1007+
jp_index_offset = 1
1008+
offset = 0
1009+
1010+
# Special handling for text ID 0xFFFC, which has hard-coded offsets to
1011+
# the JP file in function Font_LoadOrderedFont in z_kanfont.c
1012+
if new_message.id == 0xFFFC:
1013+
# hard-coded offset including segment
1014+
rom.write_int16(0xAD1CE2, (text_bank << 8) + ((offset & 0xFFFF0000) >> 16) + (1 if offset & 0xFFFF > 0x8000 else 0))
1015+
rom.write_int16(0xAD1CE6, offset & 0XFFFF)
1016+
# hard-coded message length, represented by offset of end of message
1017+
rom.write_int16(0xAD1D16, (text_bank << 8) + (((offset + new_message.size()) & 0xFFFF0000) >> 16) + (1 if (offset + new_message.size()) & 0xFFFF > 0x8000 else 0))
1018+
rom.write_int16(0xAD1D1E, (offset + new_message.size()) & 0XFFFF)
1019+
# hard-coded segment, default JP file (0x08)
1020+
rom.write_int16(0xAD1D12, (text_bank << 8))
1021+
# hard-coded text file start address in rom, default JP
1022+
rom.write_int16(0xAD1D22, ((text_start & 0xFFFF0000) >> 16) + (1 if text_start & 0xFFFF > 0x8000 else 0))
1023+
rom.write_int16(0xAD1D2E, text_start & 0XFFFF)
9471024

9481025
# actually write the message
949-
offset = new_message.write(rom, old_index, offset)
1026+
offset = new_message.write(rom, old_index + jp_index_offset, text_start, offset, text_bank)
9501027

9511028
new_message.id = remember_id
9521029

9531030
# raise an exception if too much is written
9541031
# we raise it at the end so that we know how much overflow there is
955-
if offset > text_size_limit:
956-
raise(TypeError("Message Text table is too large: 0x" + "{:x}".format(offset) + " written / 0x" + "{:x}".format(ENG_TEXT_SIZE_LIMIT) + " allowed."))
1032+
if jp_bytes + offset > text_size_limit:
1033+
raise(TypeError("Message Text table is too large: 0x" + "{:x}".format(jp_bytes + offset) + " written / 0x" + "{:x}".format(EXTENDED_TEXT_SIZE_LIMIT) + " allowed."))
9571034

958-
# end the table
959-
table_index = len(messages)
960-
entry = bytes([0xFF, 0xFD, 0x00, 0x00, 0x07]) + int_to_bytes(offset, 3)
1035+
# end the table, accounting for additional entry for file split
1036+
table_index = len(messages) + (1 if text_bank == 0x07 else 0)
1037+
entry = bytes([0xFF, 0xFD, 0x00, 0x00, text_bank]) + int_to_bytes(offset, 3)
9611038
entry_offset = EXTENDED_TABLE_START + 8 * table_index
9621039
rom.write_bytes(entry_offset, entry)
9631040
table_index += 1
@@ -982,6 +1059,7 @@ def is_exempt(m):
9821059
)
9831060
shuffle_exempt = [
9841061
0x208D, # "One more lap!" for Cow in House race.
1062+
0xFFFC, # Character data from JP table used on title and file select screens
9851063
]
9861064
is_hint = (except_hints and m.id in hint_ids)
9871065
is_error_message = (m.id == ERROR_MESSAGE)

Notes/message_table_notes.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Message_FindMessage (debug) -> func_800D6A90 (1.0 EN) / func_800D69EC (1.0 JP)
2+
save context + 0x2200 = play->msgCtx.font
3+
line 12279 in data.s in disassembly
4+
80112E34 = pointer to JP table (8010A94C) line 10152
5+
80112E38 = pointer to EN table (8010EA8C) line 11196
6+
credit table? 80112CAC line 12254
7+
findmessage called near lbl_800DCB60 (JP) / lbl_800DCC04 (EN)
8+
9+
text ID FFFC hard-coded offsets for JP file in func_8005BD78 / Font_LoadOrderedFont in kanfont.s / z_kanfont.c
10+
DMA request needs to be modified to point to EN file if FFFC relocated there
11+
a3 = 0803A150 change to actual FFFC offset, modify segment to 07 if in EN file
12+
t6 = 08000000 change to 07000000 if FFFC in EN file
13+
t7 = 0803A340 change to actual FFFD offset, modify segment to 07 if in EN file (used for FFFC length)
14+
t8 = 008EB000 change to 0092D000 for start of file pointer
15+
16+

0 commit comments

Comments
 (0)