Individual settings: mode

This commit is contained in:
Bonta-kun 2019-12-16 16:54:46 +01:00
parent 79786c7c9e
commit ab28858a8f
13 changed files with 101 additions and 106 deletions

View File

@ -12,7 +12,7 @@ class World(object):
self.players = players self.players = players
self.shuffle = shuffle self.shuffle = shuffle
self.logic = logic.copy() self.logic = logic.copy()
self.mode = mode self.mode = mode.copy()
self.swords = swords self.swords = swords
self.difficulty = difficulty self.difficulty = difficulty
self.difficulty_adjustments = difficulty_adjustments self.difficulty_adjustments = difficulty_adjustments
@ -39,7 +39,7 @@ class World(object):
self.powder_patch_required = {player: False for player in range(1, players + 1)} self.powder_patch_required = {player: False for player in range(1, players + 1)}
self.ganon_at_pyramid = {player: True for player in range(1, players + 1)} self.ganon_at_pyramid = {player: True for player in range(1, players + 1)}
self.ganonstower_vanilla = {player: True for player in range(1, players + 1)} self.ganonstower_vanilla = {player: True for player in range(1, players + 1)}
self.sewer_light_cone = mode == 'standard' self.sewer_light_cone = {player: mode[player] == 'standard' for player in range(1, players + 1)}
self.light_world_light_cone = False self.light_world_light_cone = False
self.dark_world_light_cone = False self.dark_world_light_cone = False
self.treasure_hunt_count = 0 self.treasure_hunt_count = 0
@ -48,7 +48,7 @@ class World(object):
self.rupoor_cost = 10 self.rupoor_cost = 10
self.aga_randomness = True self.aga_randomness = True
self.lock_aga_door_in_escape = False self.lock_aga_door_in_escape = False
self.fix_trock_doors = self.shuffle != 'vanilla' or self.mode == 'inverted' self.fix_trock_doors = {player: self.shuffle != 'vanilla' or self.mode[player] == 'inverted' for player in range(1, players + 1)}
self.save_and_quit_from_boss = True self.save_and_quit_from_boss = True
self.accessibility = accessibility self.accessibility = accessibility
self.fix_skullwoods_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] self.fix_skullwoods_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
@ -74,7 +74,7 @@ class World(object):
self.difficulty_requirements = None self.difficulty_requirements = None
self.fix_fake_world = True self.fix_fake_world = True
self.boss_shuffle = boss_shuffle self.boss_shuffle = boss_shuffle
self.escape_assist = [] self.escape_assist = {player: [] for player in range(1, players + 1)}
self.hints = hints self.hints = hints
self.crystals_needed_for_ganon = 7 self.crystals_needed_for_ganon = 7
self.crystals_needed_for_gt = 7 self.crystals_needed_for_gt = 7
@ -499,7 +499,7 @@ class CollectionState(object):
if self.has_Pearl(player): if self.has_Pearl(player):
return True return True
return region.is_light_world if self.world.mode != 'inverted' else region.is_dark_world return region.is_light_world if self.world.mode[player] != 'inverted' else region.is_dark_world
def can_reach_light_world(self, player): def can_reach_light_world(self, player):
if True in [i.is_light_world for i in self.reachable_regions[player]]: if True in [i.is_light_world for i in self.reachable_regions[player]]:
@ -689,7 +689,7 @@ class Region(object):
or (item.bigkey and not self.world.bigkeyshuffle) or (item.bigkey and not self.world.bigkeyshuffle)
or (item.map and not self.world.mapshuffle) or (item.map and not self.world.mapshuffle)
or (item.compass and not self.world.compassshuffle)) or (item.compass and not self.world.compassshuffle))
sewer_hack = self.world.mode == 'standard' and item.name == 'Small Key (Escape)' sewer_hack = self.world.mode[item.player] == 'standard' and item.name == 'Small Key (Escape)'
if sewer_hack or inside_dungeon_item: if sewer_hack or inside_dungeon_item:
return self.dungeon and self.dungeon.is_dungeon_item(item) and item.player == self.player return self.dungeon and self.dungeon.is_dungeon_item(item) and item.player == self.player
@ -1025,7 +1025,7 @@ class Spoiler(object):
self.bosses[str(player)]["Ice Palace"] = self.world.get_dungeon("Ice Palace", player).boss.name self.bosses[str(player)]["Ice Palace"] = self.world.get_dungeon("Ice Palace", player).boss.name
self.bosses[str(player)]["Misery Mire"] = self.world.get_dungeon("Misery Mire", player).boss.name self.bosses[str(player)]["Misery Mire"] = self.world.get_dungeon("Misery Mire", player).boss.name
self.bosses[str(player)]["Turtle Rock"] = self.world.get_dungeon("Turtle Rock", player).boss.name self.bosses[str(player)]["Turtle Rock"] = self.world.get_dungeon("Turtle Rock", player).boss.name
if self.world.mode != 'inverted': if self.world.mode[player] != 'inverted':
self.bosses[str(player)]["Ganons Tower Basement"] = self.world.get_dungeon('Ganons Tower', player).bosses['bottom'].name self.bosses[str(player)]["Ganons Tower Basement"] = self.world.get_dungeon('Ganons Tower', player).bosses['bottom'].name
self.bosses[str(player)]["Ganons Tower Middle"] = self.world.get_dungeon('Ganons Tower', player).bosses['middle'].name self.bosses[str(player)]["Ganons Tower Middle"] = self.world.get_dungeon('Ganons Tower', player).bosses['middle'].name
self.bosses[str(player)]["Ganons Tower Top"] = self.world.get_dungeon('Ganons Tower', player).bosses['top'].name self.bosses[str(player)]["Ganons Tower Top"] = self.world.get_dungeon('Ganons Tower', player).bosses['top'].name

View File

@ -141,7 +141,7 @@ def place_bosses(world, player):
if world.boss_shuffle == 'none': if world.boss_shuffle == 'none':
return return
# Most to least restrictive order # Most to least restrictive order
if world.mode != 'inverted': if world.mode[player] != 'inverted':
boss_locations = [ boss_locations = [
['Ganons Tower', 'top'], ['Ganons Tower', 'top'],
['Tower of Hera', None], ['Tower of Hera', None],

View File

@ -27,7 +27,7 @@ def create_dungeons(world, player):
MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), ItemFactory(['Small Key (Misery Mire)'] * 3, player), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player)) MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), ItemFactory(['Small Key (Misery Mire)'] * 3, player), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player))
TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player)) TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player))
if world.mode != 'inverted': if world.mode[player] != 'inverted':
AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), []) AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), [])
GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player))
else: else:

View File

@ -286,6 +286,7 @@ def parse_arguments(argv, no_defaults=False):
getattr(ret, name)[player] = value getattr(ret, name)[player] = value
set_player_arg("logic") set_player_arg("logic")
set_player_arg("mode")
return ret return ret

View File

@ -39,7 +39,7 @@ def link_entrances(world, player):
lw_entrances = list(LW_Dungeon_Entrances) lw_entrances = list(LW_Dungeon_Entrances)
dw_entrances = list(DW_Dungeon_Entrances) dw_entrances = list(DW_Dungeon_Entrances)
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
@ -52,7 +52,7 @@ def link_entrances(world, player):
dw_entrances.append('Ganons Tower') dw_entrances.append('Ganons Tower')
dungeon_exits.append('Ganons Tower Exit') dungeon_exits.append('Ganons Tower Exit')
if world.mode == 'standard': if world.mode[player] == 'standard':
# rest of hyrule castle must be in light world, so it has to be the one connected to east exit of desert # rest of hyrule castle must be in light world, so it has to be the one connected to east exit of desert
connect_mandatory_exits(world, lw_entrances, [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], list(LW_Dungeon_Entrances_Must_Exit), player) connect_mandatory_exits(world, lw_entrances, [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], list(LW_Dungeon_Entrances_Must_Exit), player)
else: else:
@ -273,7 +273,7 @@ def link_entrances(world, player):
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
@ -309,7 +309,7 @@ def link_entrances(world, player):
pass pass
else: #if the cave wasn't placed we get here else: #if the cave wasn't placed we get here
connect_caves(world, lw_entrances, [], old_man_house, player) connect_caves(world, lw_entrances, [], old_man_house, player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# rest of hyrule castle must be in light world # rest of hyrule castle must be in light world
connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player) connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player)
@ -376,7 +376,7 @@ def link_entrances(world, player):
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
@ -392,7 +392,7 @@ def link_entrances(world, player):
#place must-exit caves #place must-exit caves
connect_mandatory_exits(world, entrances, caves, must_exits, player) connect_mandatory_exits(world, entrances, caves, must_exits, player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# rest of hyrule castle must be dealt with # rest of hyrule castle must be dealt with
connect_caves(world, entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player) connect_caves(world, entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player)
@ -451,7 +451,7 @@ def link_entrances(world, player):
blacksmith_doors = list(Blacksmith_Single_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
@ -471,7 +471,7 @@ def link_entrances(world, player):
else: else:
connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player)
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# rest of hyrule castle must be in light world # rest of hyrule castle must be in light world
connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player) connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player)
@ -552,7 +552,7 @@ def link_entrances(world, player):
('Lumberjack Tree Exit', 'Lumberjack Tree (top)'), ('Lumberjack Tree Exit', 'Lumberjack Tree (top)'),
(('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Woods Second Section (Drop)')] (('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Woods Second Section (Drop)')]
if world.mode == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player) connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player)
connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player) connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player)
@ -606,7 +606,7 @@ def link_entrances(world, player):
connect_entrance(world, hole, target, player) connect_entrance(world, hole, target, player)
# hyrule castle handling # hyrule castle handling
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player) connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player)
@ -792,7 +792,7 @@ def link_entrances(world, player):
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
if world.mode == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player) connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player)
connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player) connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player)
@ -825,7 +825,7 @@ def link_entrances(world, player):
connect_entrance(world, hole, hole_targets.pop(), player) connect_entrance(world, hole, hole_targets.pop(), player)
# hyrule castle handling # hyrule castle handling
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player) connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player)
@ -927,7 +927,7 @@ def link_entrances(world, player):
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)', hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)',
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)'] 'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
if world.mode == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player) connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player)
connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player) connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs', player)
@ -960,7 +960,7 @@ def link_entrances(world, player):
connect_entrance(world, hole, hole_targets.pop(), player) connect_entrance(world, hole, hole_targets.pop(), player)
# hyrule castle handling # hyrule castle handling
if world.mode == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player) connect_exit(world, 'Hyrule Castle Exit (South)', 'Hyrule Castle Entrance (South)', player)
@ -1831,7 +1831,7 @@ def scramble_holes(world, player):
else: else:
hole_targets.append(('Pyramid Exit', 'Pyramid')) hole_targets.append(('Pyramid Exit', 'Pyramid'))
if world.mode == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
connect_two_way(world, 'Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance Exit', player) connect_two_way(world, 'Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance Exit', player)
connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player) connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player)
@ -1931,11 +1931,11 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player, dp_m
if len(cave) == 2: if len(cave) == 2:
entrance = entrances.pop() entrance = entrances.pop()
# ToDo Better solution, this is a hot fix. Do not connect both sides of trock/desert ledge only to each other # ToDo Better solution, this is a hot fix. Do not connect both sides of trock/desert ledge only to each other
if world.mode != 'inverted' and entrance == 'Dark Death Mountain Ledge (West)': if world.mode[player] != 'inverted' and entrance == 'Dark Death Mountain Ledge (West)':
new_entrance = entrances.pop() new_entrance = entrances.pop()
entrances.append(entrance) entrances.append(entrance)
entrance = new_entrance entrance = new_entrance
if world.mode == 'inverted' and entrance == dp_must_exit: if world.mode[player] == 'inverted' and entrance == dp_must_exit:
new_entrance = entrances.pop() new_entrance = entrances.pop()
entrances.append(entrance) entrances.append(entrance)
entrance = new_entrance entrance = new_entrance
@ -2006,7 +2006,7 @@ def simple_shuffle_dungeons(world, player):
dungeon_entrances = ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section', 'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace'] dungeon_entrances = ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section', 'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace']
dungeon_exits = ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Palace of Darkness Exit', 'Ice Palace Exit', 'Misery Mire Exit', 'Swamp Palace Exit'] dungeon_exits = ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Palace of Darkness Exit', 'Ice Palace Exit', 'Misery Mire Exit', 'Swamp Palace Exit']
if world.mode != 'inverted': if world.mode[player] != 'inverted':
if not world.shuffle_ganon: if not world.shuffle_ganon:
connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player)
else: else:
@ -2021,13 +2021,13 @@ def simple_shuffle_dungeons(world, player):
# mix up 4 door dungeons # mix up 4 door dungeons
multi_dungeons = ['Desert', 'Turtle Rock'] multi_dungeons = ['Desert', 'Turtle Rock']
if world.mode == 'open' or (world.mode == 'inverted' and world.shuffle_ganon): if world.mode[player] == 'open' or (world.mode[player] == 'inverted' and world.shuffle_ganon):
multi_dungeons.append('Hyrule Castle') multi_dungeons.append('Hyrule Castle')
random.shuffle(multi_dungeons) random.shuffle(multi_dungeons)
dp_target = multi_dungeons[0] dp_target = multi_dungeons[0]
tr_target = multi_dungeons[1] tr_target = multi_dungeons[1]
if world.mode not in ['open', 'inverted'] or (world.mode == 'inverted' and world.shuffle_ganon is False): if world.mode[player] not in ['open', 'inverted'] or (world.mode[player] == 'inverted' and world.shuffle_ganon is False):
# place hyrule castle as intended # place hyrule castle as intended
hc_target = 'Hyrule Castle' hc_target = 'Hyrule Castle'
else: else:
@ -2035,7 +2035,7 @@ def simple_shuffle_dungeons(world, player):
# ToDo improve this? # ToDo improve this?
if world.mode != 'inverted': if world.mode[player] != 'inverted':
if hc_target == 'Hyrule Castle': if hc_target == 'Hyrule Castle':
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', player) connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', player)

View File

@ -239,8 +239,8 @@ def distribute_items_restrictive(world, gftower_trash_count=0, fill_locations=No
fill_locations.reverse() fill_locations.reverse()
# Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots # Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots
if world.keyshuffle and world.mode == 'standard': if world.keyshuffle:
progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)' else 0) progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)' and world.mode[item.player] == 'standard' else 0)
fill_restrictive(world, world.state, fill_locations, progitempool) fill_restrictive(world, world.state, fill_locations, progitempool)

View File

@ -344,10 +344,10 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address)) ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address))
return ret return ret
def mark_dark_world_regions(world): def mark_dark_world_regions(world, player):
# cross world caves may have some sections marked as both in_light_world, and in_dark_work. # 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. # 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) queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.DarkWorld)
seen = set(queue) seen = set(queue)
while queue: while queue:
current = queue.popleft() current = queue.popleft()
@ -360,7 +360,7 @@ def mark_dark_world_regions(world):
seen.add(exit.connected_region) seen.add(exit.connected_region)
queue.append(exit.connected_region) queue.append(exit.connected_region)
queue = collections.deque(region for region in world.regions if region.type == RegionType.LightWorld) queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld)
seen = set(queue) seen = set(queue)
while queue: while queue:
current = queue.popleft() current = queue.popleft()

View File

@ -126,7 +126,7 @@ difficulties = {
def generate_itempool(world, player): def generate_itempool(world, player):
if (world.difficulty not in ['normal', 'hard', 'expert'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'] 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', '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[player] 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') raise NotImplementedError('Not supported yet')
if world.timer in ['ohko', 'timed-ohko']: if world.timer in ['ohko', 'timed-ohko']:
@ -138,7 +138,7 @@ def generate_itempool(world, player):
world.push_item(world.get_location('Ganon', player), ItemFactory('Triforce', player), False) world.push_item(world.get_location('Ganon', player), ItemFactory('Triforce', player), False)
if world.goal in ['triforcehunt']: if world.goal in ['triforcehunt']:
if world.mode == 'inverted': if world.mode[player] == 'inverted':
region = world.get_region('Light World',player) region = world.get_region('Light World',player)
else: else:
region = world.get_region('Hyrule Castle Courtyard', player) region = world.get_region('Hyrule Castle Courtyard', player)
@ -177,15 +177,15 @@ def generate_itempool(world, player):
# set up item pool # set up item pool
if world.custom: if world.custom:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode, world.swords, world.retro, world.customitemarray) (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode[player], world.swords, world.retro, world.customitemarray)
world.rupoor_cost = min(world.customitemarray[69], 9999) world.rupoor_cost = min(world.customitemarray[69], 9999)
else: else:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode, world.swords, world.retro) (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle, world.difficulty, world.timer, world.goal, world.mode[player], world.swords, world.retro)
for item in precollected_items: for item in precollected_items:
world.push_precollected(ItemFactory(item, player)) world.push_precollected(ItemFactory(item, player))
if world.mode == 'standard' and not world.state.has_blunt_weapon(player) and "Link's Uncle" not in placed_items: if world.mode[player] == 'standard' and not world.state.has_blunt_weapon(player) and "Link's Uncle" not in placed_items:
found_sword = False found_sword = False
found_bow = False found_bow = False
possible_weapons = [] possible_weapons = []
@ -261,7 +261,7 @@ take_any_locations = [
'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint'] 'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint']
def set_up_take_anys(world, player): def set_up_take_anys(world, player):
if world.mode == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations: if world.mode[player] == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations:
take_any_locations.remove('Dark Sanctuary Hint') take_any_locations.remove('Dark Sanctuary Hint')
regions = random.sample(take_any_locations, 5) regions = random.sample(take_any_locations, 5)

44
Main.py
View File

@ -56,30 +56,26 @@ def main(args, seed=None):
logger.info('ALttP Entrance Randomizer Version %s - Seed: %s\n\n', __version__, world.seed) logger.info('ALttP Entrance Randomizer Version %s - Seed: %s\n\n', __version__, world.seed)
world.difficulty_requirements = difficulties[world.difficulty] world.difficulty_requirements = difficulties[world.difficulty]
if world.mode == 'standard' and (args.shuffleenemies != 'none' or args.enemy_health not in ['default', 'easy']):
world.escape_assist.append(['bombs']) # enemized escape assumes infinite bombs available and will likely be unbeatable without it
if world.mode != 'inverted': for player in range(1, world.players + 1):
for player in range(1, world.players + 1): if world.mode[player] == 'standard' and (args.shuffleenemies != 'none' or args.enemy_health not in ['default', 'easy']):
world.escape_assist[player].append(['bombs']) # enemized escape assumes infinite bombs available and will likely be unbeatable without it
if world.mode[player] != 'inverted':
create_regions(world, player) create_regions(world, player)
create_dungeons(world, player) else:
else:
for player in range(1, world.players + 1):
create_inverted_regions(world, player) create_inverted_regions(world, player)
create_dungeons(world, player) create_dungeons(world, player)
logger.info('Shuffling the World about.') logger.info('Shuffling the World about.')
if world.mode != 'inverted': for player in range(1, world.players + 1):
for player in range(1, world.players + 1): if world.mode[player] != 'inverted':
link_entrances(world, player) link_entrances(world, player)
mark_light_world_regions(world, player)
mark_light_world_regions(world) else:
else:
for player in range(1, world.players + 1):
link_inverted_entrances(world, player) link_inverted_entrances(world, player)
mark_dark_world_regions(world, player)
mark_dark_world_regions(world)
logger.info('Generating Item Pool.') logger.info('Generating Item Pool.')
@ -189,7 +185,7 @@ def main(args, seed=None):
outfilesuffix = ('%s%s_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (f'_P{player}' if world.players > 1 else '', outfilesuffix = ('%s%s_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (f'_P{player}' if world.players > 1 else '',
f'_{player_names[player]}' if player in player_names else '', f'_{player_names[player]}' if player in player_names else '',
world.logic[player], world.difficulty, world.difficulty_adjustments, world.logic[player], world.difficulty, world.difficulty_adjustments,
world.mode, world.goal, world.mode[player], world.goal,
"" if world.timer in ['none', 'display'] else "-" + world.timer, "" if world.timer in ['none', 'display'] else "-" + world.timer,
world.shuffle, world.algorithm, mcsb_name, world.shuffle, world.algorithm, mcsb_name,
"-retro" if world.retro else "", "-retro" if world.retro else "",
@ -232,7 +228,7 @@ def copy_world(world):
ret.ganonstower_vanilla = world.ganonstower_vanilla.copy() ret.ganonstower_vanilla = world.ganonstower_vanilla.copy()
ret.treasure_hunt_count = world.treasure_hunt_count ret.treasure_hunt_count = world.treasure_hunt_count
ret.treasure_hunt_icon = world.treasure_hunt_icon ret.treasure_hunt_icon = world.treasure_hunt_icon
ret.sewer_light_cone = world.sewer_light_cone ret.sewer_light_cone = world.sewer_light_cone.copy()
ret.light_world_light_cone = world.light_world_light_cone ret.light_world_light_cone = world.light_world_light_cone
ret.dark_world_light_cone = world.dark_world_light_cone ret.dark_world_light_cone = world.dark_world_light_cone
ret.seed = world.seed ret.seed = world.seed
@ -251,14 +247,12 @@ def copy_world(world):
ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon
ret.crystals_needed_for_gt = world.crystals_needed_for_gt ret.crystals_needed_for_gt = world.crystals_needed_for_gt
if world.mode != 'inverted': for player in range(1, world.players + 1):
for player in range(1, world.players + 1): if world.mode[player] != 'inverted':
create_regions(ret, player) create_regions(ret, player)
create_dungeons(ret, player) else:
else:
for player in range(1, world.players + 1):
create_inverted_regions(ret, player) create_inverted_regions(ret, player)
create_dungeons(ret, player) create_dungeons(ret, player)
copy_dynamic_regions_and_locations(world, ret) copy_dynamic_regions_and_locations(world, ret)
@ -436,7 +430,7 @@ def create_playthrough(world):
old_world.spoiler.paths.update({ str(location) : get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player}) old_world.spoiler.paths.update({ str(location) : get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player})
for _, path in dict(old_world.spoiler.paths).items(): for _, path in dict(old_world.spoiler.paths).items():
if any(exit == 'Pyramid Fairy' for (_, exit) in path): if any(exit == 'Pyramid Fairy' for (_, exit) in path):
if world.mode != 'inverted': if world.mode[player] != 'inverted':
old_world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = get_path(state, world.get_region('Big Bomb Shop', player)) old_world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = get_path(state, world.get_region('Big Bomb Shop', player))
else: else:
old_world.spoiler.paths[str(world.get_region('Inverted Big Bomb Shop', player))] = get_path(state, world.get_region('Inverted Big Bomb Shop', player)) old_world.spoiler.paths[str(world.get_region('Inverted Big Bomb Shop', player))] = get_path(state, world.get_region('Inverted Big Bomb Shop', player))

View File

@ -116,7 +116,7 @@ def fill_world(world, plando, text_patches):
tr_medallion = medallionstr.strip() tr_medallion = medallionstr.strip()
elif line.startswith('!mode'): elif line.startswith('!mode'):
_, modestr = line.split(':', 1) _, modestr = line.split(':', 1)
world.mode = modestr.strip() world.mode = {1: modestr.strip()}
elif line.startswith('!logic'): elif line.startswith('!logic'):
_, logicstr = line.split(':', 1) _, logicstr = line.split(':', 1)
world.logic = {1: logicstr.strip()} world.logic = {1: logicstr.strip()}
@ -125,7 +125,7 @@ def fill_world(world, plando, text_patches):
world.goal = goalstr.strip() world.goal = goalstr.strip()
elif line.startswith('!light_cone_sewers'): elif line.startswith('!light_cone_sewers'):
_, sewerstr = line.split(':', 1) _, sewerstr = line.split(':', 1)
world.sewer_light_cone = sewerstr.strip().lower() == 'true' world.sewer_light_cone = {1: sewerstr.strip().lower() == 'true'}
elif line.startswith('!light_cone_lw'): elif line.startswith('!light_cone_lw'):
_, lwconestr = line.split(':', 1) _, lwconestr = line.split(':', 1)
world.light_world_light_cone = lwconestr.strip().lower() == 'true' world.light_world_light_cone = lwconestr.strip().lower() == 'true'
@ -134,7 +134,7 @@ def fill_world(world, plando, text_patches):
world.dark_world_light_cone = dwconestr.strip().lower() == 'true' world.dark_world_light_cone = dwconestr.strip().lower() == 'true'
elif line.startswith('!fix_trock_doors'): elif line.startswith('!fix_trock_doors'):
_, trdstr = line.split(':', 1) _, trdstr = line.split(':', 1)
world.fix_trock_doors = trdstr.strip().lower() == 'true' world.fix_trock_doors = {1: trdstr.strip().lower() == 'true'}
elif line.startswith('!fix_trock_exit'): elif line.startswith('!fix_trock_exit'):
_, trfstr = line.split(':', 1) _, trfstr = line.split(':', 1)
world.fix_trock_exit = trfstr.strip().lower() == 'true' world.fix_trock_exit = trfstr.strip().lower() == 'true'

View File

@ -335,10 +335,10 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address)) ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address))
return ret return ret
def mark_light_world_regions(world): def mark_light_world_regions(world, player):
# cross world caves may have some sections marked as both in_light_world, and in_dark_work. # 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. # 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.LightWorld) queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld)
seen = set(queue) seen = set(queue)
while queue: while queue:
current = queue.popleft() current = queue.popleft()
@ -351,7 +351,7 @@ def mark_light_world_regions(world):
seen.add(exit.connected_region) seen.add(exit.connected_region)
queue.append(exit.connected_region) queue.append(exit.connected_region)
queue = collections.deque(region for region in world.regions if region.type == RegionType.DarkWorld) queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.DarkWorld)
seen = set(queue) seen = set(queue)
while queue: while queue:
current = queue.popleft() current = queue.popleft()

44
Rom.py
View File

@ -248,7 +248,7 @@ def get_enemizer_patch(world, player, rom, baserom_path, enemizercli, shuffleene
} }
} }
if world.mode != 'inverted': if world.mode[player] != 'inverted':
options['ManualBosses']['GanonsTower1'] = world.get_dungeon('Ganons Tower', player).bosses['bottom'].enemizer_name options['ManualBosses']['GanonsTower1'] = world.get_dungeon('Ganons Tower', player).bosses['bottom'].enemizer_name
options['ManualBosses']['GanonsTower2'] = world.get_dungeon('Ganons Tower', player).bosses['middle'].enemizer_name options['ManualBosses']['GanonsTower2'] = world.get_dungeon('Ganons Tower', player).bosses['middle'].enemizer_name
options['ManualBosses']['GanonsTower3'] = world.get_dungeon('Ganons Tower', player).bosses['top'].enemizer_name options['ManualBosses']['GanonsTower3'] = world.get_dungeon('Ganons Tower', player).bosses['top'].enemizer_name
@ -550,7 +550,7 @@ def patch_rom(world, player, rom, enemized):
else: else:
# patch door table # patch door table
rom.write_byte(0xDBB73 + exit.addresses, exit.target) rom.write_byte(0xDBB73 + exit.addresses, exit.target)
if world.mode == 'inverted': if world.mode[player] == 'inverted':
patch_shuffled_dark_sanc(world, rom, player) patch_shuffled_dark_sanc(world, rom, player)
write_custom_shops(rom, world, player) write_custom_shops(rom, world, player)
@ -578,11 +578,11 @@ def patch_rom(world, player, rom, enemized):
rom.write_byte(0x51DE, 0x00) rom.write_byte(0x51DE, 0x00)
# set open mode: # set open mode:
if world.mode in ['open', 'inverted']: if world.mode[player] in ['open', 'inverted']:
rom.write_byte(0x180032, 0x01) # open mode rom.write_byte(0x180032, 0x01) # open mode
if world.mode == 'inverted': if world.mode[player] == 'inverted':
set_inverted_mode(world, rom) set_inverted_mode(world, rom)
elif world.mode == 'standard': elif world.mode[player] == 'standard':
rom.write_byte(0x180032, 0x00) # standard mode rom.write_byte(0x180032, 0x00) # standard mode
uncle_location = world.get_location('Link\'s Uncle', player) uncle_location = world.get_location('Link\'s Uncle', player)
@ -600,7 +600,7 @@ def patch_rom(world, player, rom, enemized):
rom.write_bytes(0x6D323, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E]) rom.write_bytes(0x6D323, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
# set light cones # set light cones
rom.write_byte(0x180038, 0x01 if world.sewer_light_cone else 0x00) rom.write_byte(0x180038, 0x01 if world.sewer_light_cone[player] else 0x00)
rom.write_byte(0x180039, 0x01 if world.light_world_light_cone else 0x00) rom.write_byte(0x180039, 0x01 if world.light_world_light_cone else 0x00)
rom.write_byte(0x18003A, 0x01 if world.dark_world_light_cone else 0x00) rom.write_byte(0x18003A, 0x01 if world.dark_world_light_cone else 0x00)
@ -892,7 +892,7 @@ def patch_rom(world, player, rom, enemized):
# assorted fixes # assorted fixes
rom.write_byte(0x1800A2, 0x01) # remain in real dark world when dying in dark world dungeon before killing aga1 rom.write_byte(0x1800A2, 0x01) # remain in real dark world when dying in dark world dungeon before killing aga1
rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence. rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence.
if world.mode == 'inverted': if world.mode[player] == 'inverted':
rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted
rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid[player] else 0x00) # Enable respawning on pyramid after ganon death rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid[player] else 0x00) # Enable respawning on pyramid after ganon death
rom.write_byte(0x180173, 0x01) # Bob is enabled rom.write_byte(0x180173, 0x01) # Bob is enabled
@ -930,18 +930,18 @@ def patch_rom(world, player, rom, enemized):
else: else:
raise RuntimeError("Unsupported pre-collected item: {}".format(item)) raise RuntimeError("Unsupported pre-collected item: {}".format(item))
rom.write_byte(0x18004A, 0x00 if world.mode != 'inverted' else 0x01) # Inverted mode rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode
rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier
rom.write_byte(0x2AF79, 0xD0 if world.mode != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both) rom.write_byte(0x2AF79, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both)
rom.write_byte(0x3A943, 0xD0 if world.mode != 'inverted' else 0xF0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both) rom.write_byte(0x3A943, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both)
rom.write_byte(0x3A96D, 0xF0 if world.mode != 'inverted' else 0xD0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader)) rom.write_byte(0x3A96D, 0xF0 if world.mode[player] != 'inverted' else 0xD0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader))
rom.write_byte(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader)) rom.write_byte(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader))
rom.write_bytes(0x180080, [50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10) rom.write_bytes(0x180080, [50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10)
rom.write_byte(0x18004D, ((0x01 if 'arrows' in world.escape_assist else 0x00) | rom.write_byte(0x18004D, ((0x01 if 'arrows' in world.escape_assist[player] else 0x00) |
(0x02 if 'bombs' in world.escape_assist else 0x00) | (0x02 if 'bombs' in world.escape_assist[player] else 0x00) |
(0x04 if 'magic' in world.escape_assist else 0x00))) # Escape assist (0x04 if 'magic' in world.escape_assist[player] else 0x00))) # Escape assist
if world.goal in ['pedestal', 'triforcehunt']: if world.goal in ['pedestal', 'triforcehunt']:
rom.write_byte(0x18003E, 0x01) # make ganon invincible rom.write_byte(0x18003E, 0x01) # make ganon invincible
@ -954,7 +954,7 @@ def patch_rom(world, player, rom, enemized):
rom.write_byte(0x18005E, world.crystals_needed_for_gt) rom.write_byte(0x18005E, world.crystals_needed_for_gt)
rom.write_byte(0x18005F, world.crystals_needed_for_ganon) rom.write_byte(0x18005F, world.crystals_needed_for_ganon)
rom.write_byte(0x18008A, 0x01 if world.mode == "standard" else 0x00) # block HC upstairs doors in rain state in standard mode rom.write_byte(0x18008A, 0x01 if world.mode[player] == "standard" else 0x00) # block HC upstairs doors in rain state in standard mode
rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle else 0x00) rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle else 0x00)
| (0x02 if world.compassshuffle else 0x00) | (0x02 if world.compassshuffle else 0x00)
@ -1031,7 +1031,7 @@ def patch_rom(world, player, rom, enemized):
rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows)
rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows)
rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows)
if world.mode == 'standard': if world.mode[player] == 'standard':
if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']: if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']:
rom.write_byte(0x18004E, 1) # Escape Fill (arrows) rom.write_byte(0x18004E, 1) # Escape Fill (arrows)
write_int16(rom, 0x180183, 300) # Escape fill rupee bow write_int16(rom, 0x180183, 300) # Escape fill rupee bow
@ -1068,7 +1068,7 @@ def patch_rom(world, player, rom, enemized):
rom.write_byte(0x4E3BB, 0xEB) rom.write_byte(0x4E3BB, 0xEB)
# fix trock doors for reverse entrances # fix trock doors for reverse entrances
if world.fix_trock_doors: if world.fix_trock_doors[player]:
rom.write_byte(0xFED31, 0x0E) # preopen bombable exit rom.write_byte(0xFED31, 0x0E) # preopen bombable exit
rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit
# included unconditionally in base2current # included unconditionally in base2current
@ -1375,7 +1375,7 @@ def write_strings(rom, world, player):
entrances_to_hint = {} entrances_to_hint = {}
entrances_to_hint.update(InconvenientDungeonEntrances) entrances_to_hint.update(InconvenientDungeonEntrances)
if world.shuffle_ganon: if world.shuffle_ganon:
if world.mode == 'inverted': if world.mode[player] == 'inverted':
entrances_to_hint.update({'Inverted Ganons Tower': 'The sealed castle door'}) entrances_to_hint.update({'Inverted Ganons Tower': 'The sealed castle door'})
else: else:
entrances_to_hint.update({'Ganons Tower': 'Ganon\'s Tower'}) entrances_to_hint.update({'Ganons Tower': 'Ganon\'s Tower'})
@ -1408,14 +1408,14 @@ def write_strings(rom, world, player):
if world.shuffle not in ['simple', 'restricted', 'restricted_legacy']: if world.shuffle not in ['simple', 'restricted', 'restricted_legacy']:
entrances_to_hint.update(ConnectorEntrances) entrances_to_hint.update(ConnectorEntrances)
entrances_to_hint.update(DungeonEntrances) entrances_to_hint.update(DungeonEntrances)
if world.mode == 'inverted': if world.mode[player] == 'inverted':
entrances_to_hint.update({'Inverted Agahnims Tower': 'The dark mountain tower'}) entrances_to_hint.update({'Inverted Agahnims Tower': 'The dark mountain tower'})
else: else:
entrances_to_hint.update({'Agahnims Tower': 'The sealed castle door'}) entrances_to_hint.update({'Agahnims Tower': 'The sealed castle door'})
elif world.shuffle == 'restricted': elif world.shuffle == 'restricted':
entrances_to_hint.update(ConnectorEntrances) entrances_to_hint.update(ConnectorEntrances)
entrances_to_hint.update(OtherEntrances) entrances_to_hint.update(OtherEntrances)
if world.mode == 'inverted': if world.mode[player] == 'inverted':
entrances_to_hint.update({'Inverted Dark Sanctuary': 'The dark sanctuary cave'}) entrances_to_hint.update({'Inverted Dark Sanctuary': 'The dark sanctuary cave'})
entrances_to_hint.update({'Inverted Big Bomb Shop': 'The old hero\'s dark home'}) entrances_to_hint.update({'Inverted Big Bomb Shop': 'The old hero\'s dark home'})
entrances_to_hint.update({'Inverted Links House': 'The old hero\'s light home'}) entrances_to_hint.update({'Inverted Links House': 'The old hero\'s light home'})
@ -1425,7 +1425,7 @@ def write_strings(rom, world, player):
if world.shuffle in ['insanity', 'madness_legacy', 'insanity_legacy']: if world.shuffle in ['insanity', 'madness_legacy', 'insanity_legacy']:
entrances_to_hint.update(InsanityEntrances) entrances_to_hint.update(InsanityEntrances)
if world.shuffle_ganon: if world.shuffle_ganon:
if world.mode == 'inverted': if world.mode[player] == 'inverted':
entrances_to_hint.update({'Inverted Pyramid Entrance': 'The extra castle passage'}) entrances_to_hint.update({'Inverted Pyramid Entrance': 'The extra castle passage'})
else: else:
entrances_to_hint.update({'Pyramid Ledge': 'The pyramid ledge'}) entrances_to_hint.update({'Pyramid Ledge': 'The pyramid ledge'})
@ -1592,7 +1592,7 @@ def write_strings(rom, world, player):
tt['tablet_bombos_book'] = bombos_text tt['tablet_bombos_book'] = bombos_text
# inverted spawn menu changes # inverted spawn menu changes
if world.mode == 'inverted': if world.mode[player] == 'inverted':
tt['menu_start_2'] = "{MENU}\n{SPEED0}\n≥@'s house\n Dark Chapel\n{CHOICE3}" tt['menu_start_2'] = "{MENU}\n{SPEED0}\n≥@'s house\n Dark Chapel\n{CHOICE3}"
tt['menu_start_3'] = "{MENU}\n{SPEED0}\n≥@'s house\n Dark Chapel\n Mountain Cave\n{CHOICE2}" tt['menu_start_3'] = "{MENU}\n{SPEED0}\n≥@'s house\n Dark Chapel\n Mountain Cave\n{CHOICE2}"
tt['intro_main'] = CompressedTextMapper.convert( tt['intro_main'] = CompressedTextMapper.convert(

View File

@ -7,7 +7,7 @@ def set_rules(world, player):
if world.logic[player] == 'nologic': if world.logic[player] == 'nologic':
logging.getLogger('').info('WARNING! Seeds generated under this logic often require major glitches and may be impossible!') logging.getLogger('').info('WARNING! Seeds generated under this logic often require major glitches and may be impossible!')
if world.mode != 'inverted': if world.mode[player] != 'inverted':
world.get_region('Links House', player).can_reach_private = lambda state: True world.get_region('Links House', player).can_reach_private = lambda state: True
world.get_region('Sanctuary', player).can_reach_private = lambda state: True world.get_region('Sanctuary', player).can_reach_private = lambda state: True
old_rule = world.get_region('Old Man House', player).can_reach old_rule = world.get_region('Old Man House', player).can_reach
@ -22,14 +22,14 @@ def set_rules(world, player):
return return
global_rules(world, player) global_rules(world, player)
if world.mode != 'inverted': if world.mode[player] != 'inverted':
default_rules(world, player) default_rules(world, player)
if world.mode == 'open': if world.mode[player] == 'open':
open_rules(world, player) open_rules(world, player)
elif world.mode == 'standard': elif world.mode[player] == 'standard':
standard_rules(world, player) standard_rules(world, player)
elif world.mode == 'inverted': elif world.mode[player] == 'inverted':
open_rules(world, player) open_rules(world, player)
inverted_rules(world, player) inverted_rules(world, player)
else: else:
@ -49,7 +49,7 @@ def set_rules(world, player):
# require aga2 to beat ganon # require aga2 to beat ganon
add_rule(world.get_location('Ganon', player), lambda state: state.has('Beat Agahnim 2', player)) add_rule(world.get_location('Ganon', player), lambda state: state.has('Beat Agahnim 2', player))
if world.mode != 'inverted': if world.mode[player] != 'inverted':
set_big_bomb_rules(world, player) set_big_bomb_rules(world, player)
else: else:
set_inverted_big_bomb_rules(world, player) set_inverted_big_bomb_rules(world, player)
@ -58,7 +58,7 @@ def set_rules(world, player):
if not world.swamp_patch_required[player]: if not world.swamp_patch_required[player]:
add_rule(world.get_entrance('Swamp Palace Moat', player), lambda state: state.has_Mirror(player)) add_rule(world.get_entrance('Swamp Palace Moat', player), lambda state: state.has_Mirror(player))
if world.mode != 'inverted': if world.mode[player] != 'inverted':
set_bunny_rules(world, player) set_bunny_rules(world, player)
else: else:
set_inverted_bunny_rules(world, player) set_inverted_bunny_rules(world, player)
@ -345,7 +345,7 @@ def global_rules(world, player):
def default_rules(world, player): def default_rules(world, player):
if world.mode == 'standard': if world.mode[player] == 'standard':
world.get_region('Hyrule Castle Secret Entrance', player).can_reach_private = lambda state: True world.get_region('Hyrule Castle Secret Entrance', player).can_reach_private = lambda state: True
old_rule = world.get_region('Links House', player).can_reach_private 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) world.get_region('Links House', player).can_reach_private = lambda state: state.can_reach('Sanctuary', 'Region', player) or old_rule(state)
@ -621,7 +621,7 @@ def inverted_rules(world, player):
set_rule(world.get_entrance('Inverted Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt, player)) set_rule(world.get_entrance('Inverted Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt, player))
def no_glitches_rules(world, player): def no_glitches_rules(world, player):
if world.mode != 'inverted': if world.mode[player] != 'inverted':
set_rule(world.get_entrance('Zoras River', player), lambda state: state.has('Flippers', player) or state.can_lift_rocks(player)) set_rule(world.get_entrance('Zoras River', player), lambda state: state.has('Flippers', player) or state.can_lift_rocks(player))
set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has('Flippers', player)) # can be fake flippered to set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has('Flippers', player)) # can be fake flippered to
set_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has('Flippers', player))
@ -672,7 +672,7 @@ def no_glitches_rules(world, player):
add_conditional_lamp('Palace of Darkness Maze Door', 'Palace of Darkness (Entrance)', 'Entrance') add_conditional_lamp('Palace of Darkness Maze Door', 'Palace of Darkness (Entrance)', 'Entrance')
add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)', 'Location') add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)', 'Location')
add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)', 'Location') add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)', 'Location')
if world.mode != 'inverted': if world.mode[player] != 'inverted':
add_conditional_lamp('Agahnim 1', 'Agahnims Tower', 'Entrance') add_conditional_lamp('Agahnim 1', 'Agahnims Tower', 'Entrance')
add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower', 'Location') add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower', 'Location')
else: else:
@ -688,7 +688,7 @@ def no_glitches_rules(world, player):
add_conditional_lamp('Eastern Palace - Boss', 'Eastern Palace', 'Location') add_conditional_lamp('Eastern Palace - Boss', 'Eastern Palace', 'Location')
add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location') add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location')
if not world.sewer_light_cone: if not world.sewer_light_cone[player]:
add_lamp_requirement(world.get_location('Sewers - Dark Cross', player), player) add_lamp_requirement(world.get_location('Sewers - Dark Cross', player), player)
add_lamp_requirement(world.get_entrance('Sewers Back Door', player), player) add_lamp_requirement(world.get_entrance('Sewers Back Door', player), player)
add_lamp_requirement(world.get_entrance('Throne Room', player), player) add_lamp_requirement(world.get_entrance('Throne Room', player), player)
@ -709,7 +709,7 @@ def swordless_rules(world, player):
set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon, player)) set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon, player))
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop
if world.mode != 'inverted': if world.mode[player] != 'inverted':
set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!)
set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_Pearl(player) and state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_Pearl(player) and state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!)