220 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from .rom import ROM
 | |
| from .pointerTable import PointerTable
 | |
| from .assembler import ASM
 | |
| 
 | |
| 
 | |
| class Texts(PointerTable):
 | |
|     END_OF_DATA = (0xfe, 0xff)
 | |
| 
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x2B0,
 | |
|             "pointers_addr": 1,
 | |
|             "pointers_bank": 0x1C,
 | |
|             "banks_addr": 0x741,
 | |
|             "banks_bank": 0x1C,
 | |
|         })
 | |
| 
 | |
| 
 | |
| class Entities(PointerTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x320,
 | |
|             "pointers_addr": 0,
 | |
|             "pointers_bank": 0x16,
 | |
|             "data_bank": 0x16,
 | |
|         })
 | |
| 
 | |
| class RoomsTable(PointerTable):
 | |
|     HEADER = 2
 | |
| 
 | |
|     def _readData(self, rom, bank_nr, pointer):
 | |
|         bank = rom.banks[bank_nr]
 | |
|         start = pointer
 | |
|         pointer += self.HEADER
 | |
|         while bank[pointer] != 0xFE:
 | |
|             obj_type = (bank[pointer] & 0xF0)
 | |
|             if obj_type == 0xE0:
 | |
|                 pointer += 5
 | |
|             elif obj_type == 0xC0 or obj_type == 0x80:
 | |
|                 pointer += 3
 | |
|             else:
 | |
|                 pointer += 2
 | |
|         pointer += 1
 | |
|         self._addStorage(bank_nr, start, pointer)
 | |
|         return bank[start:pointer]
 | |
| 
 | |
| 
 | |
| class RoomsOverworldTop(RoomsTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x080,
 | |
|             "pointers_addr": 0x000,
 | |
|             "pointers_bank": 0x09,
 | |
|             "data_bank": 0x09,
 | |
|             "alt_pointers": {
 | |
|                 "Alt06": (0x00, 0x31FD),
 | |
|                 "Alt0E": (0x00, 0x31CD),
 | |
|                 "Alt1B": (0x00, 0x320D),
 | |
|                 "Alt2B": (0x00, 0x321D),
 | |
|                 "Alt79": (0x00, 0x31ED),
 | |
|             }
 | |
|         })
 | |
| 
 | |
| 
 | |
| class RoomsOverworldBottom(RoomsTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x080,
 | |
|             "pointers_addr": 0x100,
 | |
|             "pointers_bank": 0x09,
 | |
|             "data_bank": 0x1A,
 | |
|             "alt_pointers": {
 | |
|                 "Alt8C": (0x00, 0x31DD),
 | |
|             }
 | |
|         })
 | |
| 
 | |
| 
 | |
| class RoomsIndoorA(RoomsTable):
 | |
|     # TODO: The color dungeon tables are in the same bank, but the pointer table is after the room data.
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x100,
 | |
|             "pointers_addr": 0x000,
 | |
|             "pointers_bank": 0x0A,
 | |
|             "data_bank": 0x0A,
 | |
|             "alt_pointers": {
 | |
|                 "Alt1F5": (0x00, 0x31A1),
 | |
|             }
 | |
|         })
 | |
| 
 | |
| 
 | |
| class RoomsIndoorB(RoomsTable):
 | |
|     # Most likely, this table can be expanded all the way to the end of the bank,
 | |
|     # giving a few 100 extra bytes to work with.
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x0FF,
 | |
|             "pointers_addr": 0x000,
 | |
|             "pointers_bank": 0x0B,
 | |
|             "data_bank": 0x0B,
 | |
|         })
 | |
| 
 | |
| 
 | |
| class RoomsColorDungeon(RoomsTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x016,
 | |
|             "pointers_addr": 0x3B77,
 | |
|             "pointers_bank": 0x0A,
 | |
|             "data_bank": 0x0A,
 | |
|             "expand_to_end_of_bank": True
 | |
|         })
 | |
| 
 | |
| 
 | |
| class BackgroundTable(PointerTable):
 | |
|     def _readData(self, rom, bank_nr, pointer):
 | |
|         bank = rom.banks[bank_nr]
 | |
|         start = pointer
 | |
|         while bank[pointer] != 0x00:
 | |
|             addr = bank[pointer] << 8 | bank[pointer + 1]
 | |
|             amount = (bank[pointer + 2] & 0x3F) + 1
 | |
|             repeat = (bank[pointer + 2] & 0x40) == 0x40
 | |
|             vertical = (bank[pointer + 2] & 0x80) == 0x80
 | |
|             pointer += 3
 | |
|             if not repeat:
 | |
|                 pointer += amount
 | |
|             if repeat:
 | |
|                 pointer += 1
 | |
|         pointer += 1
 | |
|         self._addStorage(bank_nr, start, pointer)
 | |
|         return bank[start:pointer]
 | |
| 
 | |
| 
 | |
| class BackgroundTilesTable(BackgroundTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x26,
 | |
|             "pointers_addr": 0x052B,
 | |
|             "pointers_bank": 0x20,
 | |
|             "data_bank": 0x08,
 | |
|             "expand_to_end_of_bank": True
 | |
|         })
 | |
| 
 | |
| 
 | |
| class BackgroundAttributeTable(BackgroundTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x26,
 | |
|             "pointers_addr": 0x1C4B,
 | |
|             "pointers_bank": 0x24,
 | |
|             "data_bank": 0x24,
 | |
|             "expand_to_end_of_bank": True
 | |
|         })
 | |
| 
 | |
| 
 | |
| class OverworldRoomSpriteData(PointerTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x100,
 | |
|             "pointers_addr": 0x30D3,
 | |
|             "pointers_bank": 0x20,
 | |
|             "data_bank": 0x20,
 | |
|             "data_addr": 0x33F3,
 | |
|             "data_size": 4,
 | |
|             "claim_storage_gaps": True,
 | |
|         })
 | |
| 
 | |
| 
 | |
| class IndoorRoomSpriteData(PointerTable):
 | |
|     def __init__(self, rom):
 | |
|         super().__init__(rom, {
 | |
|             "count": 0x220,
 | |
|             "pointers_addr": 0x31D3,
 | |
|             "pointers_bank": 0x20,
 | |
|             "data_bank": 0x20,
 | |
|             "data_addr": 0x363B,
 | |
|             "data_size": 4,
 | |
|             "claim_storage_gaps": True,
 | |
|         })
 | |
| 
 | |
| 
 | |
| class ROMWithTables(ROM):
 | |
|     def __init__(self, filename, patches=None):
 | |
|         super().__init__(filename, patches)
 | |
| 
 | |
|         # Ability to patch any text in the game with different text
 | |
|         self.texts = Texts(self)
 | |
|         # Ability to modify rooms
 | |
|         self.entities = Entities(self)
 | |
|         self.rooms_overworld_top = RoomsOverworldTop(self)
 | |
|         self.rooms_overworld_bottom = RoomsOverworldBottom(self)
 | |
|         self.rooms_indoor_a = RoomsIndoorA(self)
 | |
|         self.rooms_indoor_b = RoomsIndoorB(self)
 | |
|         self.rooms_color_dungeon = RoomsColorDungeon(self)
 | |
|         self.room_sprite_data_overworld = OverworldRoomSpriteData(self)
 | |
|         self.room_sprite_data_indoor = IndoorRoomSpriteData(self)
 | |
| 
 | |
|         # Backgrounds for things like the title screen.
 | |
|         self.background_tiles = BackgroundTilesTable(self)
 | |
|         self.background_attributes = BackgroundAttributeTable(self)
 | |
| 
 | |
|         self.itemNames = {}
 | |
| 
 | |
|     def save(self, filename, *, name=None):
 | |
|         self.texts.store(self)
 | |
|         self.entities.store(self)
 | |
|         self.rooms_overworld_top.store(self)
 | |
|         self.rooms_overworld_bottom.store(self)
 | |
|         self.rooms_indoor_a.store(self)
 | |
|         self.rooms_indoor_b.store(self)
 | |
|         self.rooms_color_dungeon.store(self)
 | |
|         leftover_storage = self.room_sprite_data_overworld.store(self)
 | |
|         self.room_sprite_data_indoor.addStorage(leftover_storage)
 | |
|         self.patch(0x00, 0x0DFA, ASM("ld hl, $763B"), ASM("ld hl, $%04x" % (leftover_storage[0]["start"] | 0x4000)))
 | |
|         self.room_sprite_data_indoor.adjustDataStart(leftover_storage[0]["start"])
 | |
|         self.room_sprite_data_indoor.store(self)
 | |
|         self.background_tiles.store(self)
 | |
|         self.background_attributes.store(self)
 | |
|         super().save(filename, name=name)
 | 
