A few inverted fixes

A few inverted fixes
This commit is contained in:
AmazingAmpharos 2019-09-30 18:40:44 -05:00 committed by GitHub
commit bbc71a208f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 40 deletions

View File

@ -492,6 +492,16 @@ class CollectionState(object):
return region.is_light_world if self.world.mode != 'inverted' else region.is_dark_world
def can_reach_light_world(self, player):
if True in [i.is_light_world for i in self.reachable_regions[player]]:
return True
return False
def can_reach_dark_world(self, player):
if True in [i.is_dark_world for i in self.reachable_regions[player]]:
return True
return False
def has_misery_mire_medallion(self, player):
return self.has(self.world.required_medallions[player][0], player)

View File

@ -1184,7 +1184,8 @@ def link_inverted_entrances(world, player):
connect_two_way(world, entrance2, exit2, player)
# place links house
links_house = random.choice(list(bomb_shop_doors + blacksmith_doors))
links_house_doors = [i for i in bomb_shop_doors + blacksmith_doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in bomb_shop_doors:
bomb_shop_doors.remove(links_house)
@ -1256,7 +1257,8 @@ def link_inverted_entrances(world, player):
door_targets = list(Inverted_Single_Cave_Targets)
# place links house
links_house = random.choice(list(lw_entrances + dw_entrances + lw_must_exits))
links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in lw_entrances:
lw_entrances.remove(links_house)
@ -1386,8 +1388,8 @@ def link_inverted_entrances(world, player):
caves.remove('Inverted Agahnims Tower Exit')
# place links house
links_house_doors = [door for door in lw_entrances + dw_entrances + lw_must_exits]
links_house = random.choice(links_house_doors)
links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in lw_entrances:
lw_entrances.remove(links_house)
@ -1525,7 +1527,8 @@ def link_inverted_entrances(world, player):
# place links house
links_house = random.choice(list(entrances + must_exits))
links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in entrances:
entrances.remove(links_house)
@ -1656,7 +1659,8 @@ def link_inverted_entrances(world, player):
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
# place links house and dark sanc
links_house = random.choice(list(entrances + entrances_must_exits))
links_house_doors = [i for i in entrances + entrances_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in entrances:
entrances.remove(links_house)
@ -2824,9 +2828,18 @@ Inverted_Dark_Sanctuary_Doors = ['Inverted Dark Sanctuary',
'Red Shield Shop',
'Bumper Cave (Bottom)',
'Bumper Cave (Top)',
'Skull Woods Final Section',
'Thieves Town']
Isolated_LH_Doors = ['Kings Grave',
'Waterfall of Wishing',
'Desert Palace Entrance (South)',
'Desert Palace Entrance (North)',
'Capacity Upgrade',
'Ice Palace',
'Skull Woods Final Section',
'Dark World Hammer Peg Cave',
'Turtle Rock Isolated Ledge Entrance']
# these are connections that cannot be shuffled and always exist. They link together separate parts of the world we need to divide into regions
mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'),
('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'),
@ -3141,9 +3154,6 @@ inverted_mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia
('Ganon Drop', 'Bottom of Pyramid'),
('Pyramid Drop', 'East Dark World'),
('Post Aga Teleporter', 'Light World'),
('LW Hyrule Castle Ledge SQ', 'Hyrule Castle Ledge'),
('EDM Hyrule Castle Ledge SQ', 'Hyrule Castle Ledge'),
('WDM Hyrule Castle Ledge SQ', 'Hyrule Castle Ledge'),
('Secret Passage Inner Bushes', 'Light World'),
('Secret Passage Outer Bushes', 'Hyrule Castle Secret Entrance Area'),
('Potion Shop Inner Bushes', 'Light World'),

View File

@ -16,7 +16,7 @@ def create_inverted_regions(world, player):
'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)',
'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game',
'East Dark World Mirror Spot', 'West Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Cave 45', 'Checkerboard Cave', 'Mire Mirror Spot', 'Hammer Peg Area Mirror Spot',
'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Inverted Pyramid Entrance','Hyrule Castle Entrance (South)', 'Secret Passage Outer Bushes', 'LW Hyrule Castle Ledge SQ', 'Bush Covered Lawn Outer Bushes',
'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Inverted Pyramid Entrance','Hyrule Castle Entrance (South)', 'Secret Passage Outer Bushes', 'Bush Covered Lawn Outer Bushes',
'Potion Shop Outer Bushes', 'Graveyard Cave Outer Bushes', 'Bomb Hut Outer Bushes']),
create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Bush Covered Lawn Inner Bushes', 'Bush Covered Lawn Mirror Spot']),
create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Bomb Hut Inner Bushes', 'Bomb Hut Mirror Spot']),
@ -124,14 +124,14 @@ def create_inverted_regions(world, player):
create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']),
create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']),
create_lw_region(player, 'Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave',
'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Mirror Spot', 'WDM Hyrule Castle Ledge SQ']),
'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Mirror Spot']),
create_cave_region(player, 'Death Mountain Return Cave', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']),
create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Bumper Cave Ledge Mirror Spot']),
create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']),
create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']),
create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']),
create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'Hookshot Fairy',
'Fairy Ascension Rocks', 'Spiral Cave (Bottom)', 'EDM Hyrule Castle Ledge SQ']),
'Fairy Ascension Rocks', 'Spiral Cave (Bottom)']),
create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'),
create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']),
create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left',
@ -347,7 +347,6 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
def mark_dark_world_regions(world):
# cross world caves may have some sections marked as both in_light_world, and in_dark_work.
# That is ok. the bunny logic will check for this case and incorporate special rules.
queue = collections.deque(region for region in world.regions if region.type == RegionType.DarkWorld)
seen = set(queue)
while queue:

View File

@ -126,7 +126,7 @@ difficulties = {
def generate_itempool(world, player):
if (world.difficulty not in ['normal', 'hard', 'expert'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals']
or world.mode not in ['open', 'standard', 'swordless', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']):
or world.mode not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']):
raise NotImplementedError('Not supported yet')
if world.timer in ['ohko', 'timed-ohko']:

29
Rom.py
View File

@ -785,11 +785,11 @@ def patch_rom(world, player, rom):
rom.write_byte(0x180029, 0x01) # Smithy quick item give
# set swordless mode settings
rom.write_byte(0x18003F, 0x01 if world.mode == 'swordless' else 0x00) # hammer can harm ganon
rom.write_byte(0x180040, 0x01 if world.mode == 'swordless' else 0x00) # open curtains
rom.write_byte(0x180041, 0x01 if world.mode == 'swordless' else 0x00) # swordless medallions
rom.write_byte(0x180043, 0xFF if world.mode == 'swordless' else 0x00) # starting sword for link
rom.write_byte(0x180044, 0x01 if world.mode == 'swordless' else 0x00) # hammer activates tablets
rom.write_byte(0x18003F, 0x01 if world.swords == 'swordless' else 0x00) # hammer can harm ganon
rom.write_byte(0x180040, 0x01 if world.swords == 'swordless' else 0x00) # open curtains
rom.write_byte(0x180041, 0x01 if world.swords == 'swordless' else 0x00) # swordless medallions
rom.write_byte(0x180043, 0xFF if world.swords == 'swordless' else 0x00) # starting sword for link
rom.write_byte(0x180044, 0x01 if world.swords == 'swordless' else 0x00) # hammer activates tablets
# set up clocks for timed modes
if world.shuffle == 'vanilla':
@ -1442,13 +1442,14 @@ def set_inverted_mode(world, rom):
# the following bytes should only be written in vanilla
# or they'll overwrite the randomizer's shuffles
if world.shuffle == 'vanilla':
rom.write_byte(0x15B8C, 0x6C)
rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house
rom.write_byte(0xDBB73 + 0x52, 0x01)
rom.write_byte(0xDBB73 + 0x23, 0x37) # switch AT and GT
rom.write_byte(0xDBB73 + 0x36, 0x24)
rom.write_int16(0x15AEE + 2*0x38, 0x00E0)
rom.write_int16(0x15AEE + 2*0x25, 0x000C)
if world.shuffle in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
rom.write_byte(0x15B8C, 0x6C)
rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house
rom.write_byte(0xDBB73 + 0x52, 0x01)
rom.write_byte(0xDBB73 + 0x15, 0x06) # bumper and old man cave
rom.write_int16(0x15AEE + 2*0x17, 0x00F0)
rom.write_byte(0xDBB73 + 0x05, 0x16)
@ -1503,7 +1504,7 @@ def set_inverted_mode(world, rom):
rom.write_int16(snes_to_pc(0x02D9A6), 0x005A)
rom.write_byte(snes_to_pc(0x02D9B3), 0x12)
# keep the old man spawn point at old man house unless shuffle is vanilla
if world.shuffle == 'vanilla':
if world.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple']:
rom.write_bytes(snes_to_pc(0x308350), [0x00, 0x00, 0x01])
rom.write_int16(snes_to_pc(0x02D8DE), 0x00F1)
rom.write_bytes(snes_to_pc(0x02D910), [0x1F, 0x1E, 0x1F, 0x1F, 0x03, 0x02, 0x03, 0x03])
@ -1564,9 +1565,9 @@ def set_inverted_mode(world, rom):
0x190F, 0x9D04, 0x9D04])
rom.write_int16s(snes_to_pc(0x1bb810), [0x00BE, 0x00C0, 0x013E])
rom.write_int16s(snes_to_pc(0x1bb836), [0x001B, 0x001B, 0x001B])
rom.write_int16(snes_to_pc(0x308300), 0x0140)
rom.write_int16(snes_to_pc(0x308300), 0x0140) # new pyramid hole entrance
rom.write_int16(snes_to_pc(0x308320), 0x001B)
if world.shuffle == 'vanilla':
if world.shuffle in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
rom.write_byte(snes_to_pc(0x308340), 0x7B)
rom.write_int16(snes_to_pc(0x1af504), 0x148B)
rom.write_int16(snes_to_pc(0x1af50c), 0x149B)
@ -1603,10 +1604,10 @@ def set_inverted_mode(world, rom):
rom.write_bytes(snes_to_pc(0x1BC85A), [0x50, 0x0F, 0x82])
rom.write_int16(0xDB96F + 2 * 0x35, 0x001B) # move pyramid exit door
rom.write_int16(0xDBA71 + 2 * 0x35, 0x06A4)
if world.shuffle == 'vanilla':
if world.shuffle in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
rom.write_byte(0xDBB73 + 0x35, 0x36)
rom.write_byte(snes_to_pc(0x09D436), 0xF3) # remove castle gate warp
if world.shuffle == 'vanilla':
if world.shuffle in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
rom.write_int16(0x15AEE + 2 * 0x37, 0x0010) # pyramid exit to new hc area
rom.write_byte(0x15B8C + 0x37, 0x1B)
rom.write_int16(0x15BDB + 2 * 0x37, 0x0418)
@ -1630,8 +1631,6 @@ def set_inverted_mode(world, rom):
def patch_shuffled_dark_sanc(world, rom, player):
dark_sanc_entrance = str(world.get_region('Inverted Dark Sanctuary', player).entrances[0].name)
room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = door_addresses[dark_sanc_entrance][1]
if dark_sanc_entrance == 'Skull Woods Final Section':
link_y = 0x00F8
door_index = door_addresses[str(dark_sanc_entrance)][0]
rom.write_byte(0x180241, 0x01)

View File

@ -115,7 +115,7 @@ def global_rules(world, player):
if world.mode == 'standard':
world.get_region('Hyrule Castle Secret Entrance', player).can_reach_private = lambda state: True
old_rule = world.get_region('Links House', player).can_reach
old_rule = world.get_region('Links House', player).can_reach_private
world.get_region('Links House', player).can_reach_private = lambda state: state.can_reach('Sanctuary', 'Region', player) or old_rule(state)
else:
# these are default save&quit points and always accessible
@ -123,7 +123,7 @@ def global_rules(world, player):
world.get_region('Sanctuary', player).can_reach_private = lambda state: True
# we can s&q to the old man house after we rescue him. This may be somewhere completely different if caves are shuffled!
old_rule = world.get_region('Old Man House', player).can_reach
old_rule = world.get_region('Old Man House', player).can_reach_private
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
# overworld requirements
@ -469,13 +469,17 @@ def inverted_rules(world, player):
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
# s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
world.get_region('Inverted Links House', player).entrances[0].can_reach = lambda state: True
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach_private = lambda state: True
# we can s&q to the old man house after we rescue him. This may be somewhere completely different if caves are shuffled!
if world.shuffle != 'vanilla':
old_rule = world.get_region('Old Man House', player).can_reach
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
old_rule = world.get_region('Old Man House', player).can_reach_private
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
old_rule = world.get_region('Hyrule Castle Ledge', player).can_reach_private
world.get_region('Hyrule Castle Ledge', player).can_reach_private = lambda state: (state.has_Mirror(player) and state.has('Beat Agahnim 1', player) and state.can_reach_light_world(player)) or old_rule(state)
# overworld requirements
set_rule(world.get_location('Maze Race', player), lambda state: state.has_Pearl(player))
set_rule(world.get_entrance('Mini Moldorm Cave', player), lambda state: state.has_Pearl(player))
@ -540,9 +544,6 @@ def inverted_rules(world, player):
set_rule(world.get_entrance('Agahnim 1', player), lambda state: state.has_sword(player) and state.has_key('Small Key (Agahnims Tower)', player, 2))
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1', player))
set_rule(world.get_location('Castle Tower - Dark Maze', player), lambda state: state.has_key('Small Key (Agahnims Tower)', player))
set_rule(world.get_entrance('LW Hyrule Castle Ledge SQ', player), lambda state: state.has('Beat Agahnim 1', player))
set_rule(world.get_entrance('EDM Hyrule Castle Ledge SQ', player), lambda state: state.has('Beat Agahnim 1', player))
set_rule(world.get_entrance('WDM Hyrule Castle Ledge SQ', player), lambda state: state.has('Beat Agahnim 1', player))
set_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), lambda state: state.has_Pearl(player))
set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up
set_rule(world.get_entrance('Broken Bridge (West)', player), lambda state: state.has('Hookshot', player) and state.has_Pearl(player))
@ -1395,7 +1396,7 @@ def set_inverted_big_bomb_rules(world, player):
'Hookshot Cave',
'Turtle Rock Isolated Ledge Entrance',
'Hookshot Cave Back Entrance',
'Inverted Ganons Tower']
'Inverted Agahnims Tower']
Isolated_LW_entrances = ['Capacity Upgrade',
'Tower of Hera',
'Death Mountain Return Cave (West)',