Customizer option to always allow flipping Sanctuary
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
49
Rom.py
49
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
|
||||
|
||||
@@ -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':
|
||||
|
||||
Reference in New Issue
Block a user