From 2e24948648d19107cc0350bfb128c6f0cbd542ed Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Tue, 3 Mar 2026 23:13:50 +0100 Subject: [PATCH 1/9] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d55dafa..c777e4e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /coilsnake/assets/ccc/lib/*.ccs .DS_store git_commit.py +/venv/ From cde5c0820ae2e7ef95c614a5e071a8fa20a2f1b3 Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 18:27:48 +0100 Subject: [PATCH 2/9] add _FONT_IMAGE_ARRANGEMENT_224 to coilsnake/model/eb/fonts.py --- coilsnake/model/eb/fonts.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/coilsnake/model/eb/fonts.py b/coilsnake/model/eb/fonts.py index 22072bf..06cf4a3 100644 --- a/coilsnake/model/eb/fonts.py +++ b/coilsnake/model/eb/fonts.py @@ -12,6 +12,7 @@ FONT_IMAGE_ARRANGEMENT_WIDTH = 16 _FONT_IMAGE_ARRANGEMENT_96 = EbTileArrangement(width=FONT_IMAGE_ARRANGEMENT_WIDTH, height=6) _FONT_IMAGE_ARRANGEMENT_128 = EbTileArrangement(width=FONT_IMAGE_ARRANGEMENT_WIDTH, height=8) +_FONT_IMAGE_ARRANGEMENT_224 = EbTileArrangement(width=FONT_IMAGE_ARRANGEMENT_WIDTH, height=14) for y in range(_FONT_IMAGE_ARRANGEMENT_96.height): for x in range(_FONT_IMAGE_ARRANGEMENT_96.width): @@ -19,6 +20,9 @@ for y in range(_FONT_IMAGE_ARRANGEMENT_128.height): for x in range(_FONT_IMAGE_ARRANGEMENT_128.width): _FONT_IMAGE_ARRANGEMENT_128[x, y].tile = y * _FONT_IMAGE_ARRANGEMENT_128.width + x +for y in range(_FONT_IMAGE_ARRANGEMENT_224.height): + for x in range(_FONT_IMAGE_ARRANGEMENT_224.width): + _FONT_IMAGE_ARRANGEMENT_224[x, y].tile = y * _FONT_IMAGE_ARRANGEMENT_224.width + x class EbFont(object): @@ -47,6 +51,8 @@ def to_files(self, image_file, widths_file, image_format="png", widths_format="y image = _FONT_IMAGE_ARRANGEMENT_96.image(self.tileset, FONT_IMAGE_PALETTE) elif self.num_characters == 128: image = _FONT_IMAGE_ARRANGEMENT_128.image(self.tileset, FONT_IMAGE_PALETTE) + elif self.num_characters == 224: + image = _FONT_IMAGE_ARRANGEMENT_224.image(self.tileset, FONT_IMAGE_PALETTE) image.save(image_file, image_format) del image @@ -61,6 +67,8 @@ def from_files(self, image_file, widths_file, image_format="png", widths_format= self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT_96, FONT_IMAGE_PALETTE) elif self.num_characters == 128: self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT_128, FONT_IMAGE_PALETTE) + elif self.num_characters == 224: + self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT_224, FONT_IMAGE_PALETTE) del image if widths_format == "yml": @@ -72,6 +80,8 @@ def image_size(self): arr = _FONT_IMAGE_ARRANGEMENT_96 elif self.num_characters == 128: arr = _FONT_IMAGE_ARRANGEMENT_128 + elif self.num_characters == 224: + arr = _FONT_IMAGE_ARRANGEMENT_224 return arr.width * self.tileset.tile_width, arr.height * self.tileset.tile_height @@ -126,4 +136,4 @@ def from_files(self, image_file, image_format="png"): image = open_indexed_image(image_file) self.palette.from_image(image) self.tileset.from_image(image, _CREDITS_PREVIEW_ARRANGEMENT, self.palette) - del image \ No newline at end of file + del image From b45baa242961be31a10bea0b26c3d4267499259f Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 18:58:56 +0100 Subject: [PATCH 3/9] update from_block() in coilsnake/model/eb/fonts.py to account for _FONT_IMAGE_ARRANGEMENT_224 --- coilsnake/model/eb/fonts.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/coilsnake/model/eb/fonts.py b/coilsnake/model/eb/fonts.py index 06cf4a3..6dcc3de 100644 --- a/coilsnake/model/eb/fonts.py +++ b/coilsnake/model/eb/fonts.py @@ -33,9 +33,24 @@ def __init__(self, num_characters=96, tile_width=16, tile_height=8): def from_block(self, block, tileset_offset, character_widths_offset): self.tileset.from_block(block=block, offset=tileset_offset, bpp=1) - for i in range(96, self.num_characters): - self.tileset.clear_tile(i, color=1) - self.character_widths = block[character_widths_offset:character_widths_offset + self.num_characters].to_list() + if self.num_characters == 224: + # to allow 224 characters in the font, we modify how the game access the font tileset. + # by default, the game access a character by doing : (char_id - 0x50) & 0x7f + # we'll change that to : char_id - 0x20 + # this mean we have 0x30 new characters to add BEFORE the current tileset + for i in range(223, -1, -1): + if i < 0x30 or i >= 0x90: + self.tileset.clear_tile(i, color=1) + else: + self.tileset.tiles[i] = self.tileset.tiles[i - 0x30] + self.character_widths = block[ + character_widths_offset - 0x30 : + character_widths_offset - 0x30 + self.num_characters + ].to_list() + else: + for i in range(96, self.num_characters): + self.tileset.clear_tile(i, color=1) + self.character_widths = block[character_widths_offset:character_widths_offset + self.num_characters].to_list() def to_block(self, block): tileset_offset = block.allocate(size=self.tileset.block_size(bpp=1)) From 00aa36921ea85f70dc25f93633506765ce844317 Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 19:10:39 +0100 Subject: [PATCH 4/9] add patch() to coilsnake/util/eb/helper.py --- coilsnake/util/eb/helper.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coilsnake/util/eb/helper.py b/coilsnake/util/eb/helper.py index 42e1f6e..85cb1d7 100644 --- a/coilsnake/util/eb/helper.py +++ b/coilsnake/util/eb/helper.py @@ -1,6 +1,12 @@ +from coilsnake.util.eb.pointer import from_snes_address + def is_in_bank(bank, address): return (address >> 16) == bank def not_in_bank(bank, address): - return not is_in_bank(bank, address) \ No newline at end of file + return not is_in_bank(bank, address) + + +def patch(rom, size, offset, instructions): + rom[from_snes_address(offset) : from_snes_address(offset + size)] = instructions From 6771f8ad0a726a68c0fbfefac9c698f4c1b6f900 Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 19:22:42 +0100 Subject: [PATCH 5/9] patch the rom if needed for it to account 224 character per fonts --- coilsnake/model/eb/fonts.py | 2 +- coilsnake/modules/eb/FontModule.py | 130 +++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/coilsnake/model/eb/fonts.py b/coilsnake/model/eb/fonts.py index 6dcc3de..49c8f7a 100644 --- a/coilsnake/model/eb/fonts.py +++ b/coilsnake/model/eb/fonts.py @@ -36,7 +36,7 @@ def from_block(self, block, tileset_offset, character_widths_offset): if self.num_characters == 224: # to allow 224 characters in the font, we modify how the game access the font tileset. # by default, the game access a character by doing : (char_id - 0x50) & 0x7f - # we'll change that to : char_id - 0x20 + # we change that in coilsnake/modules/eb/FontModule.py to : char_id - 0x20 # this mean we have 0x30 new characters to add BEFORE the current tileset for i in range(223, -1, -1): if i < 0x30 or i >= 0x90: diff --git a/coilsnake/modules/eb/FontModule.py b/coilsnake/modules/eb/FontModule.py index 80c845a..f807319 100644 --- a/coilsnake/modules/eb/FontModule.py +++ b/coilsnake/modules/eb/FontModule.py @@ -2,12 +2,14 @@ from PIL import Image +from coilsnake.model.eb import fonts from coilsnake.model.eb.fonts import EbFont, EbCreditsFont, FONT_IMAGE_PALETTE from coilsnake.modules.eb.EbModule import EbModule from coilsnake.model.eb.table import eb_table_from_offset from coilsnake.util.common.image import open_indexed_image from coilsnake.util.common.yml import yml_load, yml_dump from coilsnake.util.eb.pointer import from_snes_address, to_snes_address +from coilsnake.util.eb.helper import patch log = logging.getLogger(__name__) @@ -31,11 +33,11 @@ def __init__(self): super(FontModule, self).__init__() self.font_pointer_table = eb_table_from_offset(offset=FONT_POINTER_TABLE_OFFSET) self.fonts = [ - EbFont(num_characters=128, tile_width=16, tile_height=16), - EbFont(num_characters=128, tile_width=16, tile_height=16), - EbFont(num_characters=128, tile_width=8, tile_height=16), - EbFont(num_characters=128, tile_width=8, tile_height=8), - EbFont(num_characters=128, tile_width=16, tile_height=16) + EbFont(num_characters=224, tile_width=16, tile_height=16), + EbFont(num_characters=224, tile_width=16, tile_height=16), + EbFont(num_characters=224, tile_width=8, tile_height=16), + EbFont(num_characters=224, tile_width=8, tile_height=8), + EbFont(num_characters=224, tile_width=16, tile_height=16) ] self.credits_font = EbCreditsFont() @@ -62,6 +64,124 @@ def write_to_rom(self, rom): self.font_pointer_table.to_block(block=rom, offset=from_snes_address(FONT_POINTER_TABLE_OFFSET)) + if all(font.num_characters == 224 for font in self.fonts): + log.debug("Patching the ROM so it can support 224 character per font") + + # AND #$007F -> NOP NOP NOP + # this is used at $C19249: + # something about printing numbers + patch(rom, 3, 0xC19282, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $EF01D2: + # Inserts a newline if printing chr would overflow the window + patch(rom, 3, 0xEF01F5, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xEF01F8, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C43E31: + # Gets the render width, of pixels, of a given string using the focused window's font + patch(rom, 3, 0xC43E6C, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC43E6F, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C440B5: + # Prefills the input field for text entry screens + patch(rom, 3, 0xC440E0, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC440E3, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C4424A: + # Writes a character to the various text entry buffers + patch(rom, 3, 0xC44272, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC44275, [0xEA, 0xEA, 0xEA]) + + # SBC #CHAR::SPACE -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C444FB: + # Renders text in small font directly to VRAM + patch(rom, 3, 0xC4454A, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC4454D, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C445E1: + # Looks ahead at text script and handles automatic newlines if the word is too long + patch(rom, 3, 0xC44752, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC44755, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C44E61: + # Prints a VWF character with the specified font to the focused window at the current cursor coordinates + patch(rom, 3, 0xC44EEC, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC44EEF, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C44FF3: + # Gets the width, in pixels, of a character string with padding included + patch(rom, 3, 0xC4501D, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC45020, [0xEA, 0xEA, 0xEA]) + + # SBC #80 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C47C3F: + # Prepares text layer graphics for BG3 + patch(rom, 3, 0xC47D3B, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC47D3E, [0xEA, 0xEA, 0xEA]) + + # SBC #80 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C4827B: + # Renders a full text character into the VWF buffer + patch(rom, 3, 0xC48289, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC4828C, [0xEA, 0xEA, 0xEA]) + + # SBC #$50 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C4999B: + # Render a full large font character to the VWF buffer, adjusting flyoverByteOffset and flyoverPixelOffset as appropriate + patch(rom, 3, 0xC48289, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC4828C, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, 0xC499A6, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC499A9, [0xEA, 0xEA, 0xEA]) + + # SBC #80 -> SBC #$20 + # AND #$007F -> NOP NOP NOP + # this is used at $C4E583: + # Renders text to tiles for the cast scene + patch(rom, 3, 0xC4E5E6, [0xE9, 0x20, 0x00]) + patch(rom, 3, 0xC4E5E9, [0xEA, 0xEA, 0xEA]) + + # LDA #32 -> LDA #$50 + # this is an hardcoded bullet point char ID + # this is used at $C440B5: + # Prefills the input field for text entry screens + patch(rom, 2, 0xC44151, [0xA9, 0x50]) + + # LDA #3 -> LDA #$33 + # this is an hardcoded middle dot char ID + # this is used at $C440B5: + # Prefills the input field for text entry screens + patch(rom, 2, 0xC4418D, [0xA9, 0x33]) + + # LDA #3 -> LDA #$33 + # this is an hardcoded middle dot char ID + # this is used at $C441B7: + # Clears the input field for text entry screens + patch(rom, 3, 0xC441D5, [0xA9, 0x33, 0x00]) + + # LDA #32 -> LDA #$50 + # this is an hardcoded bullet point char ID + # this is used at $C441B7: + # Clears the input field for text entry screens + patch(rom, 2, 0xC441F9, [0xA9, 0x50]) + self.write_credits_font_to_rom(rom) def read_from_project(self, resource_open): From ec0515ee3cdf30416391f722b05c15d7ede436ed Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 19:29:30 +0100 Subject: [PATCH 6/9] add comments to write_to_rom() in coilsnake/module/eb/FontModule.py --- coilsnake/modules/eb/FontModule.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coilsnake/modules/eb/FontModule.py b/coilsnake/modules/eb/FontModule.py index f807319..5c2ff82 100644 --- a/coilsnake/modules/eb/FontModule.py +++ b/coilsnake/modules/eb/FontModule.py @@ -64,6 +64,12 @@ def write_to_rom(self, rom): self.font_pointer_table.to_block(block=rom, offset=from_snes_address(FONT_POINTER_TABLE_OFFSET)) + # we're patching the ROM if the user uses 224 character per font + # as of right now, to acces a certain character, the game does this : (char_id - 0x50) & 0x7f + # we're changing it to that : char_id - 0x20 + # so all SBC #$50 becomes SBC #$20 + # and all AND #$007F becomes NOPs (we're skipping them) + # we're also changing the internal ID of some hardcoded character IDs if all(font.num_characters == 224 for font in self.fonts): log.debug("Patching the ROM so it can support 224 character per font") From 0a598325dac9b38b02989ae04420c68cbe4c3fda Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 23:37:43 +0100 Subject: [PATCH 7/9] put the patches addresses in a const for readability and added printPrice to the patch --- coilsnake/modules/eb/FontModule.py | 144 +++++++++++++---------------- 1 file changed, 65 insertions(+), 79 deletions(-) diff --git a/coilsnake/modules/eb/FontModule.py b/coilsnake/modules/eb/FontModule.py index 5c2ff82..649f169 100644 --- a/coilsnake/modules/eb/FontModule.py +++ b/coilsnake/modules/eb/FontModule.py @@ -2,7 +2,6 @@ from PIL import Image -from coilsnake.model.eb import fonts from coilsnake.model.eb.fonts import EbFont, EbCreditsFont, FONT_IMAGE_PALETTE from coilsnake.modules.eb.EbModule import EbModule from coilsnake.model.eb.table import eb_table_from_offset @@ -20,6 +19,28 @@ CREDITS_GRAPHICS_ASM_POINTER = 0x4f1a7 CREDITS_PALETTES_ADDRESS = 0x21e914 +# Constants for the ROM patching +SBC = 0xE9 +NOP = 0xEA +LDA = 0xA9 +LDX = 0xA2 +FUNCTION_OFFSETS = { +"printStat" : 0xC19282, #Original_Address: 0xC19249 +"printNewlineIfNeeded" : (0xEF01F5, 0xEF01F8), #Original_Address: 0xEF01D2 +"getStringRenderWidth" : (0xC43E6C, 0xC43E6F), #Original_Address: 0xC43E31 +"prefillKeyboardInput" : (0xC440E0, 0xC440E3, 0xC44151, 0xC4418D),#Original_Address: 0xC440B5 +"emptyKeyboardInput" : (0xC441D5, 0xC441F9), #Original_Address: 0xC441B7 +"writeCharacterToKeyboardInputBuffer" : (0xC44272, 0xC44275), #Original_Address: 0xC4424A +"renderSmallTextToVRAM" : (0xC4454A, 0xC4454D), #Original_Address: 0xC444FB +"printAutoNewline" : (0xC44752, 0xC44755), #Original_Address: 0xC445E1 +"renderVWFCharToWindow" : (0xC44EEC, 0xC44EEF), #Original_Address: 0xC44E61 +"getTextWidth" : (0xC4501D, 0xC45020), #Original_Address: 0xC44FF3 +"printPrice" : 0xC450E1, #Original_Address: 0xC4507A +"prepareWindowGraphics" : (0xC47D3B, 0xC47D3E), #Original_Address: 0xC47C3F +"renderWholeCharacter" : (0xC48289, 0xC4828C), #Original_Address: 0xC4827B +"renderLargeCharacterInternal" : (0xC499A6, 0xC499A9), #Original_Address: 0xC4999B +"renderCastNameText" : (0xC4E5E6, 0xC4E5E9), #Original_Address: 0xC4E583 +} class FontModule(EbModule): NAME = "Fonts" @@ -74,119 +95,84 @@ def write_to_rom(self, rom): log.debug("Patching the ROM so it can support 224 character per font") # AND #$007F -> NOP NOP NOP - # this is used at $C19249: - # something about printing numbers - patch(rom, 3, 0xC19282, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["printStat"], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $EF01D2: - # Inserts a newline if printing chr would overflow the window - patch(rom, 3, 0xEF01F5, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xEF01F8, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["printNewlineIfNeeded"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["printNewlineIfNeeded"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C43E31: - # Gets the render width, of pixels, of a given string using the focused window's font - patch(rom, 3, 0xC43E6C, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC43E6F, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["getStringRenderWidth"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["getStringRenderWidth"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C440B5: - # Prefills the input field for text entry screens - patch(rom, 3, 0xC440E0, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC440E3, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["prefillKeyboardInput"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["prefillKeyboardInput"][1], [NOP, NOP, NOP]) + # LDA #32 -> LDA #$50 + # this is an hardcoded bullet point char ID + patch(rom, 2, FUNCTION_OFFSETS["prefillKeyboardInput"][2], [LDA, 0x50]) + # LDA #3 -> LDA #$33 + # this is an hardcoded middle dot char ID + patch(rom, 2, FUNCTION_OFFSETS["prefillKeyboardInput"][3], [LDA, 0x33]) + + # LDA #3 -> LDA #$33 + # this is an hardcoded middle dot char ID + patch(rom, 3, FUNCTION_OFFSETS["emptyKeyboardInput"][0], [LDA, 0x33, 0x00]) + # LDA #32 -> LDA #$50 + # this is an hardcoded bullet point char ID + patch(rom, 2, FUNCTION_OFFSETS["emptyKeyboardInput"][1], [LDA, 0x50]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C4424A: - # Writes a character to the various text entry buffers - patch(rom, 3, 0xC44272, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC44275, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["writeCharacterToKeyboardInputBuffer"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["writeCharacterToKeyboardInputBuffer"][1], [NOP, NOP, NOP]) # SBC #CHAR::SPACE -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C444FB: - # Renders text in small font directly to VRAM - patch(rom, 3, 0xC4454A, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC4454D, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["renderSmallTextToVRAM"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["renderSmallTextToVRAM"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C445E1: - # Looks ahead at text script and handles automatic newlines if the word is too long - patch(rom, 3, 0xC44752, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC44755, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["printAutoNewline"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["printAutoNewline"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C44E61: - # Prints a VWF character with the specified font to the focused window at the current cursor coordinates - patch(rom, 3, 0xC44EEC, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC44EEF, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["renderVWFCharToWindow"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["renderVWFCharToWindow"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C44FF3: - # Gets the width, in pixels, of a character string with padding included - patch(rom, 3, 0xC4501D, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC45020, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["getTextWidth"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["getTextWidth"][1], [NOP, NOP, NOP]) + + # LDX #4 -> LDX #$34 + # this is an hardcoded dollar sign char ID + patch(rom, 3, FUNCTION_OFFSETS["printPrice"], [LDX, 0x34, 0x00]) # SBC #80 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C47C3F: - # Prepares text layer graphics for BG3 - patch(rom, 3, 0xC47D3B, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC47D3E, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["prepareWindowGraphics"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["prepareWindowGraphics"][1], [NOP, NOP, NOP]) - # SBC #80 -> SBC #$20 + # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C4827B: - # Renders a full text character into the VWF buffer - patch(rom, 3, 0xC48289, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC4828C, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["renderWholeCharacter"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["renderWholeCharacter"][1], [NOP, NOP, NOP]) # SBC #$50 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C4999B: - # Render a full large font character to the VWF buffer, adjusting flyoverByteOffset and flyoverPixelOffset as appropriate - patch(rom, 3, 0xC48289, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC4828C, [0xEA, 0xEA, 0xEA]) - patch(rom, 3, 0xC499A6, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC499A9, [0xEA, 0xEA, 0xEA]) + patch(rom, 3, FUNCTION_OFFSETS["renderLargeCharacterInternal"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["renderLargeCharacterInternal"][1], [NOP, NOP, NOP]) # SBC #80 -> SBC #$20 # AND #$007F -> NOP NOP NOP - # this is used at $C4E583: - # Renders text to tiles for the cast scene - patch(rom, 3, 0xC4E5E6, [0xE9, 0x20, 0x00]) - patch(rom, 3, 0xC4E5E9, [0xEA, 0xEA, 0xEA]) - - # LDA #32 -> LDA #$50 - # this is an hardcoded bullet point char ID - # this is used at $C440B5: - # Prefills the input field for text entry screens - patch(rom, 2, 0xC44151, [0xA9, 0x50]) - - # LDA #3 -> LDA #$33 - # this is an hardcoded middle dot char ID - # this is used at $C440B5: - # Prefills the input field for text entry screens - patch(rom, 2, 0xC4418D, [0xA9, 0x33]) - - # LDA #3 -> LDA #$33 - # this is an hardcoded middle dot char ID - # this is used at $C441B7: - # Clears the input field for text entry screens - patch(rom, 3, 0xC441D5, [0xA9, 0x33, 0x00]) - - # LDA #32 -> LDA #$50 - # this is an hardcoded bullet point char ID - # this is used at $C441B7: - # Clears the input field for text entry screens - patch(rom, 2, 0xC441F9, [0xA9, 0x50]) + patch(rom, 3, FUNCTION_OFFSETS["renderCastNameText"][0], [SBC, 0x20, 0x00]) + patch(rom, 3, FUNCTION_OFFSETS["renderCastNameText"][1], [NOP, NOP, NOP]) self.write_credits_font_to_rom(rom) From b6ef5eba890b51dd7591f4100c0d9295d517d246 Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 23:50:36 +0100 Subject: [PATCH 8/9] whiten control code tiles --- coilsnake/model/eb/fonts.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coilsnake/model/eb/fonts.py b/coilsnake/model/eb/fonts.py index 49c8f7a..cdd5c3b 100644 --- a/coilsnake/model/eb/fonts.py +++ b/coilsnake/model/eb/fonts.py @@ -40,7 +40,11 @@ def from_block(self, block, tileset_offset, character_widths_offset): # this mean we have 0x30 new characters to add BEFORE the current tileset for i in range(223, -1, -1): if i < 0x30 or i >= 0x90: - self.tileset.clear_tile(i, color=1) + # whiten tiles that represents used control codes to indicate that they shouldn't be used + if i == 0 or i == 2 or i == 15: + self.tileset.clear_tile(i, color=0) + else: + self.tileset.clear_tile(i, color=1) else: self.tileset.tiles[i] = self.tileset.tiles[i - 0x30] self.character_widths = block[ From 6afc42b4032b34674caa83f51f29968eb11e181f Mon Sep 17 00:00:00 2001 From: KiliLoje Date: Sat, 7 Mar 2026 23:52:54 +0100 Subject: [PATCH 9/9] changes default font size to 128 --- coilsnake/modules/eb/FontModule.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coilsnake/modules/eb/FontModule.py b/coilsnake/modules/eb/FontModule.py index 649f169..5ad3d09 100644 --- a/coilsnake/modules/eb/FontModule.py +++ b/coilsnake/modules/eb/FontModule.py @@ -54,11 +54,11 @@ def __init__(self): super(FontModule, self).__init__() self.font_pointer_table = eb_table_from_offset(offset=FONT_POINTER_TABLE_OFFSET) self.fonts = [ - EbFont(num_characters=224, tile_width=16, tile_height=16), - EbFont(num_characters=224, tile_width=16, tile_height=16), - EbFont(num_characters=224, tile_width=8, tile_height=16), - EbFont(num_characters=224, tile_width=8, tile_height=8), - EbFont(num_characters=224, tile_width=16, tile_height=16) + EbFont(num_characters=128, tile_width=16, tile_height=16), + EbFont(num_characters=128, tile_width=16, tile_height=16), + EbFont(num_characters=128, tile_width=8, tile_height=16), + EbFont(num_characters=128, tile_width=8, tile_height=8), + EbFont(num_characters=128, tile_width=16, tile_height=16) ] self.credits_font = EbCreditsFont()