diff --git a/DoorShuffle.py b/DoorShuffle.py index 9f6a297e..4de8b9a9 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2020,36 +2020,18 @@ default_one_way_connections = [ ] # For crossed -default_dungeon_sets = [ - ['Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Sewers Rat Path', 'Sanctuary', - 'Hyrule Dungeon Cellblock'], - ['Eastern Lobby', 'Eastern Boss'], - ['Desert Back Lobby', 'Desert Boss', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'], - ['Hera Lobby', 'Hera Boss'], - ['Tower Lobby', 'Tower Agahnim 1'], - ['PoD Lobby', 'PoD Boss'], - ['Swamp Lobby', 'Swamp Boss'], - ['Skull 1 Lobby', 'Skull Pinball', 'Skull Left Drop', 'Skull Pot Circle', 'Skull 2 East Lobby', - 'Skull 2 West Lobby', 'Skull Back Drop', 'Skull 3 Lobby', 'Skull Boss'], - ['Thieves Lobby', 'Thieves Attic Window', 'Thieves Blind\'s Cell', 'Thieves Boss'], - ['Ice Lobby', 'Ice Boss'], - ['Mire Lobby', 'Mire Boss'], - ['TR Main Lobby', 'TR Boss', 'TR Eye Bridge', 'TR Big Chest Entrance', 'TR Lazy Eyes'], - ['GT Lobby', 'GT Agahnim 2'] -] - -dungeon_x_idx_to_name = { - 0: 'Hyrule Castle', - 1: 'Eastern Palace', - 2: 'Desert Palace', - 3: 'Tower of Hera', - 4: 'Agahnims Tower', - 5: 'Palace of Darkness', - 6: 'Swamp Palace', - 7: 'Skull Woods', - 8: 'Thieves Town', - 9: 'Ice Palace', - 10: 'Misery Mire', - 11: 'Turtle Rock', - 12: 'Ganons Tower' +compass_data = { # offset from 0x122e17, sram storage, write offset from 1037b9, 0 = jmp or # of nops + 'Hyrule Castle': (0x1, 0xc0, 0x16, 0), + 'Eastern Palace': (0x1C, 0xc1, 0x28, 0), + 'Desert Palace': (0x35, 0xc2, 0x4a, 0), + 'Tower of Hera': (0xEB, 0xc3, 0x5c, 0), + 'Agahnims Tower': (0x51, 0xc4, 0x7e, 0), + 'Palace of Darkness': (0x83, 0xc5, 0xa4, 0), + 'Swamp Palace': (0x6A, 0xc6, 0xca, 0), + 'Skull Woods': (0xB5, 0xc7, 0xf0, 0), + 'Thieves Town': (0x106, 0xc8, 0x102, 0), + 'Ice Palace': (0xD0, 0xc9, 0x114, 0), + 'Misery Mire': (0x9C, 0xca, 0x138, 0), + 'Turtle Rock': (0x11F, 0xcb, 0x15e, 0), + 'Ganons Tower': (0x13A, 0xcc, 0x170, 2) } diff --git a/Rom.py b/Rom.py index 7a78c9cb..47d148b6 100644 --- a/Rom.py +++ b/Rom.py @@ -8,6 +8,7 @@ import struct import subprocess from BaseClasses import ShopType, Region, Location, Item, DoorType +from DoorShuffle import compass_data from Dungeons import dungeon_music_addresses from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts @@ -538,6 +539,10 @@ def patch_rom(world, player, rom): rom.write_byte(0x151f1, 2) rom.write_byte(0x15270, 2) rom.write_byte(0x1597b, 2) + if compass_code_good(rom): + update_compasses(rom, world, player) + else: + logging.getLogger('').warning('Randomizer rom update! Compasses in crossed are borken') for door in world.doors: if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs]: rom.write_bytes(door.getAddress(), door.dest.getTarget(door.toggle)) @@ -1636,6 +1641,50 @@ def patch_shuffled_dark_sanc(world, rom, player): rom.write_int16s(0x180253, [vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x]) rom.write_bytes(0x180262, [unknown_1, unknown_2, 0x00]) +# 24AE17 and 20B7B9 +compass_r_addr = 0x122e17 # a9 90 24 8f 9a c7 7e +compass_w_addr = 0x1037b9 # e2 20 ad 0c 04 c9 00 d0 + + +def compass_code_good(rom): + if isinstance(rom, LocalRom): + # a990248f9ac77e + if rom.buffer[compass_r_addr] != 0xa9 or rom.buffer[compass_r_addr+1] != 0x90 or rom.buffer[compass_r_addr+2] != 0x24: + return False + if rom.buffer[compass_r_addr+3] != 0x8f or rom.buffer[compass_r_addr+4] != 0x9a or rom.buffer[compass_r_addr+5] != 0xc7: + return False + if rom.buffer[compass_w_addr] != 0xe2 or rom.buffer[compass_w_addr+1] != 0x20 or rom.buffer[compass_w_addr+2] != 0xad: + return False + if rom.buffer[compass_w_addr+3] != 0x0c or rom.buffer[compass_w_addr+4] != 0x04 or rom.buffer[compass_w_addr+5] != 0xc9: + return False + return True + + +def update_compasses(rom, world, player): + layouts = world.dungeon_layouts[player] + for name, builder in layouts.items(): + digit_offset, sram_byte, write_offset, jmp_nop_flag = compass_data[name] + digit1 = builder.location_cnt // 10 + digit2 = builder.location_cnt % 10 + rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1) + rom.write_byte(compass_r_addr+digit_offset+7, 0x90+digit2) + + # read compass count code + start_address = compass_r_addr+digit_offset+15 + # lda $7ef4(sb); jmp $adbe (or 0x122dbe is the next instruction 2dbe=bead) + rom.write_bytes(start_address, [0xaf, sram_byte, 0xf4, 0x7e, 0x4c, 0xbe, 0xad]) + + # write compass count code + write_address = compass_w_addr+write_offset + # lda $7ef4(sb); inc; sta $7ef4(sb) + rom.write_bytes(write_address, [0xaf, sram_byte, 0xf4, 0x7e, 0x1a, 0x8f, sram_byte, 0xf4, 0x7e]) + if jmp_nop_flag == 0: + rom.write_bytes(write_address+9, [0x4c, 0x3f, 0xb9]) # jmp $b93f (or 0x10393f is the next instruction 393f=3fb9) + else: + for i in range(0, jmp_nop_flag): + rom.write_byte(write_address+9+i, 0xea) # nop + + InconvenientEntrances = {'Turtle Rock': 'Turtle Rock Main', 'Misery Mire': 'Misery Mire', 'Ice Palace': 'Ice Palace',