diff --git a/BaseClasses.py b/BaseClasses.py index c85156d3..23005d5c 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -318,6 +318,9 @@ class World(object): def is_bombshop_start(self, player): return self.is_tile_swapped(0x2c, player) + def is_dark_chapel_start(self, player): + return self.is_tile_swapped(0x13, player) + def is_pyramid_open(self, player): if self.open_pyramid[player] == 'yes': return True diff --git a/DoorShuffle.py b/DoorShuffle.py index fbbabef3..85fac485 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3351,7 +3351,7 @@ def remove_pair_type_if_present(door, world, player): def find_inaccessible_regions(world, player): world.inaccessible_regions[player] = [] start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop'] - start_regions.append('Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint') + start_regions.append('Sanctuary' if not world.is_dark_chapel_start(player) else 'Dark Sanctuary Hint') regs = convert_regions(start_regions, world, player) if all(all(not e.connected_region for e in r.exits) for r in regs): # if attempting to find inaccessible regions before any connections made above, assume eventual access to Pyramid S&Q @@ -3397,7 +3397,7 @@ def find_accessible_entrances(world, player, builder): start_regions = ['Hyrule Castle Courtyard'] else: start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop'] - start_regions.append('Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint') + start_regions.append('Sanctuary' if not world.is_dark_chapel_start(player) else 'Dark Sanctuary Hint') start_regions.append('Pyramid Area' if not world.is_tile_swapped(0x1b, player) else 'Hyrule Castle Ledge') regs = convert_regions(start_regions, world, player) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index c374ec15..f0152b2e 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -67,7 +67,7 @@ def link_entrances(world, player): connect_logical(world, entrancename, exitname, player, exitname.endswith(' Exit')) for entrancename, exitname in default_connector_connections + dropexit_connections: connect_logical(world, entrancename, exitname, player, True) - if invFlag: + if world.is_dark_chapel_start(player): world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance('Dark Sanctuary Hint', player).parent_region) if world.is_bombshop_start(player): world.get_entrance('Big Bomb Shop Exit', player).connect(world.get_entrance('Big Bomb Shop', player).parent_region) @@ -191,8 +191,8 @@ def link_entrances(world, player): connect_caves(world, lw_wdm_entrances, [], caves[0:c], player) connect_caves(world, lw_edm_entrances, [], caves[c:], player) - if invFlag: - # place dark sanc + # place dark sanc + if world.is_dark_chapel_start(player): place_dark_sanc(world, player) # place links house @@ -225,7 +225,7 @@ def link_entrances(world, player): scramble_holes(world, player) # place dark sanc - if invFlag: + if world.is_dark_chapel_start(player): place_dark_sanc(world, player) # place links house @@ -288,7 +288,7 @@ def link_entrances(world, player): caves.append('Ganons Tower Exit') # place dark sanc - if invFlag: + if world.is_dark_chapel_start(player): place_dark_sanc(world, player, list(zip(*drop_connections + dropexit_connections))[0]) # place links house @@ -342,7 +342,7 @@ def link_entrances(world, player): ([] if world.pottery[player] not in ['none', 'keys', 'dungeon'] else default_pot_connections) + ([] if world.take_any[player] == 'fixed' else default_takeany_connections)): connect_logical(world, entrancename, exitname, player, False) - if invFlag: + if world.is_dark_chapel_start(player): world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance('Dark Sanctuary Hint', player).parent_region) suppress_spoiler = False @@ -437,7 +437,7 @@ def link_entrances(world, player): ([] if world.pottery[player] not in ['none', 'keys', 'dungeon'] else default_pot_connections) + ([] if world.take_any[player] == 'fixed' else default_takeany_connections)): connect_logical(world, entrancename, exitname, player, False) - if invFlag: + if world.is_dark_chapel_start(player): world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance('Dark Sanctuary Hint', player).parent_region) suppress_spoiler = False @@ -512,7 +512,7 @@ def link_entrances(world, player): scramble_holes(world, player) # place dark sanc - if invFlag: + if world.is_dark_chapel_start(player): place_dark_sanc(world, player) # place links house @@ -589,7 +589,7 @@ def link_entrances(world, player): connect_entrance(world, hole, hole_targets.pop(), player) # place dark sanc - if invFlag: + if world.is_dark_chapel_start(player): place_dark_sanc(world, player) # place links house diff --git a/OverworldShuffle.py b/OverworldShuffle.py index fa5e536c..b47119c6 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -180,7 +180,7 @@ def link_overworld(world, player): else: connect_simple(world, 'Links House S&Q', 'Big Bomb Shop', player) - if not world.mode[player] == 'inverted': + if not world.is_dark_chapel_start(player): connect_simple(world, 'Sanctuary S&Q', 'Sanctuary', player) else: connect_simple(world, 'Sanctuary S&Q', 'Dark Sanctuary Hint', player) @@ -885,6 +885,7 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None): def determine_forced_flips(world, tile_ow_groups, do_grouped, player): undefined_chance = 50 + allow_flip_sanc = do_grouped flipped_groups = list() nonflipped_groups = list() merged_owids = list() @@ -899,6 +900,8 @@ def determine_forced_flips(world, tile_ow_groups, do_grouped, player): forced_nonflips = list() if 'undefined_chance' in custom_flips: undefined_chance = custom_flips['undefined_chance'] + if not do_grouped and 'always_allow_flipped_sanctuary' in custom_flips: + allow_flip_sanc = custom_flips['always_allow_flipped_sanctuary'] in [1, True, "True", "true"] if 'force_flip' in custom_flips: forced_flips = custom_flips['force_flip'] if 'force_no_flip' in custom_flips: @@ -974,7 +977,7 @@ def determine_forced_flips(world, tile_ow_groups, do_grouped, player): # Check if there are any groups that appear in both sets if any(group in flipped_groups for group in nonflipped_groups): raise GenerationException('Conflict found when flipping tiles') - return flipped_groups, nonflipped_groups, undefined_chance, merged_owids + return flipped_groups, nonflipped_groups, undefined_chance, allow_flip_sanc, merged_owids def shuffle_tiles(world, groups, result_list, do_grouped, forced_flips, player): (flipped_groups, nonflipped_groups, undefined_chance) = forced_flips @@ -1124,9 +1127,9 @@ def define_tile_groups(world, do_grouped, player): return False # sanctuary/chapel should not be flipped if S+Q guaranteed to output on that screen - if 0x13 in group and ((world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'district'] \ - and (world.mode[player] in ['standard', 'inverted'] or world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3)) \ - or (world.shuffle[player] in ['lite', 'lean'] and world.mode[player] == 'inverted')): + if 0x13 in group and not allow_flip_sanc and ((world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'district'] \ + and (world.mode[player] in ['standard', 'inverted'] or world.doorShuffle[player] not in ['partitioned', 'crossed'] \ + or world.intensity[player] < 3)) or (world.shuffle[player] in ['lite', 'lean'] and world.mode[player] == 'inverted')): return False return True @@ -1167,7 +1170,7 @@ def define_tile_groups(world, do_grouped, player): merge_groups([[0x0f, 0x35], [0x12, 0x15, 0x33, 0x3f]]) # customizer adjustments - flipped_groups, nonflipped_groups, undefined_chance, merged_owids = determine_forced_flips(world, groups, do_grouped, player) + flipped_groups, nonflipped_groups, undefined_chance, allow_flip_sanc, merged_owids = determine_forced_flips(world, groups, do_grouped, player) for owids in merged_owids: merge_groups([owids]) @@ -1367,8 +1370,6 @@ def update_world_regions(world, player): def can_reach_smith(world, player): from Items import ItemFactory from BaseClasses import CollectionState - - invFlag = world.mode[player] == 'inverted' def explore_region(region_name, region=None): nonlocal found @@ -1407,7 +1408,7 @@ def can_reach_smith(world, player): start_region = 'Big Bomb Shop' explore_region(start_region) if not found: - if not invFlag: + if not world.is_dark_chapel_start(player): if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla': sanc_mirror = world.get_entrance('Sanctuary Mirror Route', player) explore_region(sanc_mirror.connected_region.name, sanc_mirror.connected_region) @@ -1586,7 +1587,7 @@ def validate_layout(world, player): start_region = 'Big Bomb Shop Area' explore_region(start_region) - if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean'] and world.mode[player] == 'inverted': + if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean'] and world.is_dark_chapel_start(player): start_region = 'Dark Chapel Area' explore_region(start_region) diff --git a/Rom.py b/Rom.py index 9129d519..db416798 100644 --- a/Rom.py +++ b/Rom.py @@ -685,8 +685,6 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_byte(0xDBB73 + exit.addresses, exit.target) if exit.name == 'Tavern North': rom.write_byte(0x157D0, exit.target) - if world.mode[player] == 'inverted': - patch_shuffled_dark_sanc(world, rom, player) # setup dr option flags based on experimental, etc. dr_flags = DROptions.Eternal_Mini_Bosses if world.doorShuffle[player] == 'vanilla' else DROptions.Town_Portal @@ -745,7 +743,7 @@ def patch_rom(world, rom, player, team, is_mystery=False): return region.is_light_world and not region.is_dark_world # dark world spawns - sanc_name = 'Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint' + sanc_name = 'Sanctuary' if not world.is_dark_chapel_start(player) else 'Dark Sanctuary Hint' sanc_region = world.get_region(sanc_name, player) if should_be_bunny(sanc_region, world.mode[player]): rom.write_bytes(0x13fff2, [0x12, 0x00 if sanc_name == 'Sanctuary' else 0x01]) @@ -2050,7 +2048,7 @@ def write_strings(rom, world, player, team): entrances_to_hint.update(ItemEntrances) entrances_to_hint.update(ShopEntrances) entrances_to_hint.update(OtherEntrances) - if world.mode[player] != 'inverted': + if not world.is_dark_chapel_start(player): entrances_to_hint.update({'Dark Sanctuary Hint': 'The dark sanctuary cave'}) if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean', 'district']: if world.shufflelinks[player]: @@ -2368,10 +2366,10 @@ def write_strings(rom, world, player, team): # inverted spawn menu changes lh_text = "House" - if world.is_tile_swapped(0x2c, player): + if world.is_bombshop_start(player): lh_text = "Bomb Shop" sanc_text = "Sanctuary" - if world.mode[player] == 'inverted': + if world.is_dark_chapel_start(player): sanc_text = "Dark Chapel" tt['menu_start_2'] = "{MENU}\n{SPEED0}\n≥@'s " + lh_text + "\n " + sanc_text + "\n{CHOICE3}" tt['menu_start_3'] = "{MENU}\n{SPEED0}\n≥@'s " + lh_text + "\n " + sanc_text + "\n Mountain Cave\n{CHOICE2}" @@ -2468,6 +2466,8 @@ def set_inverted_mode(world, player, rom, inverted_buffer): rom.write_byte(snes_to_pc(0x0ABFBB), 0x90) # move mirror portal indicator to correct map (0xB0 normally) rom.write_byte(snes_to_pc(0x0280A6), 0xD0) # use starting point prompt instead of start at pyramid + if world.is_dark_chapel_start(player): + patch_shuffled_dark_sanc(world, rom, player) write_int16(rom, snes_to_pc(0x02D8D4), 0x112) # change sanctuary spawn point to dark sanc rom.write_bytes(snes_to_pc(0x02D8E8), [0x22, 0x22, 0x22, 0x23, 0x04, 0x04, 0x04, 0x05]) write_int16(rom, snes_to_pc(0x02D91A), 0x0400) @@ -2610,26 +2610,25 @@ def set_inverted_mode(world, player, rom, inverted_buffer): del world.data_tables[player].ow_enemy_table[0xab][5] # remove castle gate warp if world.is_tile_swapped(0x29, player): rom.write_bytes(snes_to_pc(0x06B2AB), [0xF0, 0xE1, 0x05]) # frog pickup on contact - if world.is_tile_swapped(0x2c, player): - if world.is_bombshop_start(player): - rom.write_bytes(snes_to_pc(0x03F484), [0xFD, 0x4B, 0x68]) # place bed in bomb shop - - # spawn in bomb shop - patch_shuffled_bomb_shop(world, rom, player) - rom.write_byte(snes_to_pc(0x02D8D2), 0x1C) - rom.write_bytes(snes_to_pc(0x02D8E0), [0x23, 0x22, 0x23, 0x23, 0x18, 0x18, 0x18, 0x19]) - rom.write_byte(snes_to_pc(0x02D919), 0x18) - rom.write_byte(snes_to_pc(0x02D927), 0x23) - write_int16(rom, snes_to_pc(0x02D934), 0x2398) - rom.write_byte(snes_to_pc(0x02D943), 0x18) - write_int16(rom, snes_to_pc(0x02D950), 0x0087) - write_int16(rom, snes_to_pc(0x02D95E), 0x0081) - rom.write_byte(snes_to_pc(0x02D9A4), 0x53) + if world.is_bombshop_start(player): + rom.write_bytes(snes_to_pc(0x03F484), [0xFD, 0x4B, 0x68]) # place bed in bomb shop + + # spawn in bomb shop + patch_shuffled_bomb_shop(world, rom, player) + rom.write_byte(snes_to_pc(0x02D8D2), 0x1C) + rom.write_bytes(snes_to_pc(0x02D8E0), [0x23, 0x22, 0x23, 0x23, 0x18, 0x18, 0x18, 0x19]) + rom.write_byte(snes_to_pc(0x02D919), 0x18) + rom.write_byte(snes_to_pc(0x02D927), 0x23) + write_int16(rom, snes_to_pc(0x02D934), 0x2398) + rom.write_byte(snes_to_pc(0x02D943), 0x18) + write_int16(rom, snes_to_pc(0x02D950), 0x0087) + write_int16(rom, snes_to_pc(0x02D95E), 0x0081) + rom.write_byte(snes_to_pc(0x02D9A4), 0x53) - # disable custom exit on links house exit - rom.write_byte(snes_to_pc(0x02E225), 0x1C) - rom.write_byte(snes_to_pc(0x02DAEE), 0x1C) - rom.write_byte(snes_to_pc(0x02DB8C), 0x6C) + # disable custom exit on links house exit + rom.write_byte(snes_to_pc(0x02E225), 0x1C) + rom.write_byte(snes_to_pc(0x02DAEE), 0x1C) + rom.write_byte(snes_to_pc(0x02DB8C), 0x6C) if world.is_tile_swapped(0x2f, player): rom.write_bytes(snes_to_pc(0x1BC80D), [0xB2, 0x0B, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC590), 0x00) # remove secret portal diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index cc000c82..16803f88 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -439,11 +439,11 @@ def do_blacksmith(entrances, exits, avail): links_region = links_region.name blacksmith_options = list(get_accessible_entrances(links_region, avail, assumed_inventory, False, True, True)) - if avail.inverted: + if avail.world.is_dark_chapel_start(avail.player): dark_sanc = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name blacksmith_options = list(OrderedDict.fromkeys(blacksmith_options + list(get_accessible_entrances(dark_sanc, avail, assumed_inventory, False, True, True)))) elif avail.is_sanc_forced_in_hc(): - sanc_region = avail.world.get_entrance('Sanctuary Exit',avail. player).connected_region + sanc_region = avail.world.get_entrance('Sanctuary Exit', avail.player).connected_region if sanc_region: blacksmith_options = list(OrderedDict.fromkeys(blacksmith_options + list(get_accessible_entrances(sanc_region.name, avail, assumed_inventory, False, True, True)))) else: @@ -582,7 +582,7 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world): def do_dark_sanc(entrances, exits, avail): - if avail.inverted: + if avail.world.is_dark_chapel_start(avail.player): ext = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player) if 'Dark Sanctuary Hint' in exits: forbidden = list(Isolated_LH_Doors) @@ -630,7 +630,7 @@ def do_links_house(entrances, exits, avail, cross_world): forbidden.append('Mimic Cave') if avail.world.is_bombshop_start(avail.player) and (avail.inverted == avail.world.is_tile_swapped(0x03, avail.player)): forbidden.extend(['Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']) - if avail.inverted and avail.world.shuffle[avail.player] != 'district': + if avail.world.is_dark_chapel_start(avail.player) and avail.world.shuffle[avail.player] != 'district': dark_sanc_region = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name forbidden.extend(get_nearby_entrances(avail, dark_sanc_region)) else: @@ -669,7 +669,7 @@ def do_links_house(entrances, exits, avail, cross_world): avail.links_on_mountain = True # lobby shuffle means you ought to keep links house in the same world - sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] in ['partitioned', 'crossed'] + sanc_spawn_can_be_dark = (not avail.world.is_dark_chapel_start(avail.player) and avail.world.doorShuffle[avail.player] in ['partitioned', 'crossed'] and avail.world.intensity[avail.player] >= 3) if (cross_world and not sanc_spawn_can_be_dark) or avail.world.shuffle[avail.player] == 'district':