Merged in DR v0.4.0.4
This commit is contained in:
@@ -1318,6 +1318,7 @@ class Door(object):
|
|||||||
self.dungeonLink = None
|
self.dungeonLink = None
|
||||||
self.bk_shuffle_req = False
|
self.bk_shuffle_req = False
|
||||||
self.standard_restricted = False # flag if portal is not allowed in HC in standard
|
self.standard_restricted = False # flag if portal is not allowed in HC in standard
|
||||||
|
self.lw_restricted = False # flag if portal is not allowed in DW
|
||||||
# self.incognitoPos = -1
|
# self.incognitoPos = -1
|
||||||
# self.sectorLink = False
|
# self.sectorLink = False
|
||||||
|
|
||||||
|
|||||||
3
CLI.py
3
CLI.py
@@ -98,7 +98,7 @@ def parse_cli(argv, no_defaults=False):
|
|||||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||||
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
|
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
|
||||||
'triforce_min_difference', 'triforce_goal', 'triforce_pool',
|
'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks',
|
||||||
'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
||||||
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
|
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
|
||||||
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep',
|
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep',
|
||||||
@@ -145,6 +145,7 @@ def parse_settings():
|
|||||||
"ow_shuffle": "vanilla",
|
"ow_shuffle": "vanilla",
|
||||||
"ow_keepsimilar": False,
|
"ow_keepsimilar": False,
|
||||||
"shuffle": "vanilla",
|
"shuffle": "vanilla",
|
||||||
|
"shufflelinks": False,
|
||||||
|
|
||||||
"shufflepots": False,
|
"shufflepots": False,
|
||||||
"shuffleenemies": "none",
|
"shuffleenemies": "none",
|
||||||
|
|||||||
@@ -563,6 +563,9 @@ def assign_portal(candidates, possible_portals, world, player):
|
|||||||
candidate = random.choice(candidates)
|
candidate = random.choice(candidates)
|
||||||
portal_choice = random.choice(possible_portals)
|
portal_choice = random.choice(possible_portals)
|
||||||
portal = world.get_portal(portal_choice, player)
|
portal = world.get_portal(portal_choice, player)
|
||||||
|
while candidate.lw_restricted and not portal.light_world:
|
||||||
|
candidates.remove(candidate)
|
||||||
|
candidate = random.choice(candidates)
|
||||||
if candidate != portal.door:
|
if candidate != portal.door:
|
||||||
if candidate.entranceFlag:
|
if candidate.entranceFlag:
|
||||||
for other_portal in world.dungeon_portals[player]:
|
for other_portal in world.dungeon_portals[player]:
|
||||||
@@ -2025,6 +2028,7 @@ class DROptions(Flag):
|
|||||||
Open_PoD_Wall = 0x40 # If on, pre opens the PoD wall, no bow required
|
Open_PoD_Wall = 0x40 # If on, pre opens the PoD wall, no bow required
|
||||||
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required
|
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required
|
||||||
Hide_Total = 0x100
|
Hide_Total = 0x100
|
||||||
|
DarkWorld_Spawns = 0x200
|
||||||
|
|
||||||
|
|
||||||
# DATA GOES DOWN HERE
|
# DATA GOES DOWN HERE
|
||||||
@@ -2180,7 +2184,6 @@ logical_connections = [
|
|||||||
|
|
||||||
('Ice Cross Bottom Push Block Left', 'Ice Floor Switch'),
|
('Ice Cross Bottom Push Block Left', 'Ice Floor Switch'),
|
||||||
('Ice Cross Right Push Block Top', 'Ice Bomb Drop'),
|
('Ice Cross Right Push Block Top', 'Ice Bomb Drop'),
|
||||||
('Ice Cross Top Push Block Bottom', 'Ice Compass Room'),
|
|
||||||
('Ice Conveyor to Crystal', 'Ice Conveyor - Crystal'),
|
('Ice Conveyor to Crystal', 'Ice Conveyor - Crystal'),
|
||||||
('Ice Conveyor Crystal Exit', 'Ice Conveyor'),
|
('Ice Conveyor Crystal Exit', 'Ice Conveyor'),
|
||||||
('Ice Big Key Push Block', 'Ice Dead End'),
|
('Ice Big Key Push Block', 'Ice Dead End'),
|
||||||
|
|||||||
2
Doors.py
2
Doors.py
@@ -1465,6 +1465,8 @@ def create_doors(world, player):
|
|||||||
|
|
||||||
# static portal flags
|
# static portal flags
|
||||||
world.get_door('Sanctuary S', player).dead_end(allowPassage=True)
|
world.get_door('Sanctuary S', player).dead_end(allowPassage=True)
|
||||||
|
if world.mode[player] == 'open' and world.shuffle[player] not in ['crossed', 'insanity']:
|
||||||
|
world.get_door('Sanctuary S', player).lw_restricted = True
|
||||||
world.get_door('Eastern Hint Tile Blocked Path SE', player).passage = False
|
world.get_door('Eastern Hint Tile Blocked Path SE', player).passage = False
|
||||||
world.get_door('TR Big Chest Entrance SE', player).passage = False
|
world.get_door('TR Big Chest Entrance SE', player).passage = False
|
||||||
world.get_door('Sewers Secret Room Key Door S', player).dungeonLink = 'Hyrule Castle'
|
world.get_door('Sewers Secret Room Key Door S', player).dungeonLink = 'Hyrule Castle'
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from collections import defaultdict
|
|||||||
|
|
||||||
|
|
||||||
def link_entrances(world, player):
|
def link_entrances(world, player):
|
||||||
connect_two_way(world, 'Links House', 'Links House Exit', player) # unshuffled. For now
|
|
||||||
connect_exit(world, 'Chris Houlihan Room Exit', 'Links House', player) # should always match link's house, except for plandos
|
connect_exit(world, 'Chris Houlihan Room Exit', 'Links House', player) # should always match link's house, except for plandos
|
||||||
|
|
||||||
Dungeon_Exits = Dungeon_Exits_Base.copy()
|
Dungeon_Exits = Dungeon_Exits_Base.copy()
|
||||||
@@ -82,7 +81,7 @@ def link_entrances(world, player):
|
|||||||
|
|
||||||
single_doors = list(Single_Cave_Doors)
|
single_doors = list(Single_Cave_Doors)
|
||||||
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors)
|
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors)
|
||||||
blacksmith_doors = list(Blacksmith_Single_Cave_Doors)
|
blacksmith_doors = list(Blacksmith_Single_Cave_Doors) + ['Links House']
|
||||||
door_targets = list(Single_Cave_Targets)
|
door_targets = list(Single_Cave_Targets)
|
||||||
|
|
||||||
# we shuffle all 2 entrance caves as pairs as a start
|
# we shuffle all 2 entrance caves as pairs as a start
|
||||||
@@ -105,6 +104,18 @@ def link_entrances(world, player):
|
|||||||
connect_two_way(world, entrance1, exit1, player)
|
connect_two_way(world, entrance1, exit1, player)
|
||||||
connect_two_way(world, entrance2, exit2, player)
|
connect_two_way(world, entrance2, exit2, player)
|
||||||
|
|
||||||
|
# place links house
|
||||||
|
if world.mode[player] == 'standard' or not world.shufflelinks[player]:
|
||||||
|
links_house = 'Links House'
|
||||||
|
else:
|
||||||
|
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in Isolated_LH_Doors_Open]
|
||||||
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Links House Exit', player)
|
||||||
|
if links_house in bomb_shop_doors:
|
||||||
|
bomb_shop_doors.remove(links_house)
|
||||||
|
if links_house in blacksmith_doors:
|
||||||
|
blacksmith_doors.remove(links_house)
|
||||||
|
|
||||||
# at this point only Light World death mountain entrances remain
|
# at this point only Light World death mountain entrances remain
|
||||||
# place old man, has limited options
|
# place old man, has limited options
|
||||||
remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)',
|
remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)',
|
||||||
@@ -157,6 +168,16 @@ def link_entrances(world, player):
|
|||||||
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
|
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
|
||||||
door_targets = list(Single_Cave_Targets)
|
door_targets = list(Single_Cave_Targets)
|
||||||
|
|
||||||
|
# place links house
|
||||||
|
if world.mode[player] == 'standard' or not world.shufflelinks[player]:
|
||||||
|
links_house = 'Links House'
|
||||||
|
else:
|
||||||
|
links_house_doors = [i for i in lw_entrances if i not in Isolated_LH_Doors_Open]
|
||||||
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Links House Exit', player)
|
||||||
|
if links_house in lw_entrances:
|
||||||
|
lw_entrances.remove(links_house)
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
@@ -301,7 +322,18 @@ def link_entrances(world, player):
|
|||||||
else:
|
else:
|
||||||
dw_entrances.append('Ganons Tower')
|
dw_entrances.append('Ganons Tower')
|
||||||
caves.append('Ganons Tower Exit')
|
caves.append('Ganons Tower Exit')
|
||||||
|
|
||||||
|
# place links house
|
||||||
|
if world.mode[player] == 'standard' or not world.shufflelinks[player]:
|
||||||
|
links_house = 'Links House'
|
||||||
|
else:
|
||||||
|
links_house_doors = [i for i in lw_entrances + lw_must_exits if i not in Isolated_LH_Doors_Open]
|
||||||
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Links House Exit', player)
|
||||||
|
if links_house in lw_entrances:
|
||||||
|
lw_entrances.remove(links_house)
|
||||||
|
if links_house in lw_must_exits:
|
||||||
|
lw_must_exits.remove(links_house)
|
||||||
|
|
||||||
# we randomize which world requirements we fulfill first so we get better dungeon distribution
|
# we randomize which world requirements we fulfill first so we get better dungeon distribution
|
||||||
#we also places the Old Man House at this time to make sure he can be connected to the desert one way
|
#we also places the Old Man House at this time to make sure he can be connected to the desert one way
|
||||||
@@ -408,6 +440,22 @@ def link_entrances(world, player):
|
|||||||
entrances.append('Ganons Tower')
|
entrances.append('Ganons Tower')
|
||||||
caves.append('Ganons Tower Exit')
|
caves.append('Ganons Tower Exit')
|
||||||
|
|
||||||
|
# place links house
|
||||||
|
if world.mode[player] == 'standard' or not world.shufflelinks[player]:
|
||||||
|
links_house = 'Links House'
|
||||||
|
else:
|
||||||
|
links_house_doors = [i for i in entrances + must_exits if i not in Isolated_LH_Doors_Open]
|
||||||
|
if world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3:
|
||||||
|
exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors\
|
||||||
|
+ DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower']
|
||||||
|
links_house_doors = [i for i in links_house_doors if i not in exclusions]
|
||||||
|
links_house = random.choice(list(links_house_doors))
|
||||||
|
connect_two_way(world, links_house, 'Links House Exit', player)
|
||||||
|
if links_house in entrances:
|
||||||
|
entrances.remove(links_house)
|
||||||
|
elif links_house in must_exits:
|
||||||
|
must_exits.remove(links_house)
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
@@ -854,6 +902,23 @@ def link_entrances(world, player):
|
|||||||
entrances.append('Hyrule Castle Entrance (South)')
|
entrances.append('Hyrule Castle Entrance (South)')
|
||||||
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
|
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
|
||||||
|
|
||||||
|
# place links house
|
||||||
|
if world.mode[player] == 'standard' or not world.shufflelinks[player]:
|
||||||
|
links_house = 'Links house'
|
||||||
|
else:
|
||||||
|
links_house_doors = [i for i in entrances + entrances_must_exits if i not in Isolated_LH_Doors_Open]
|
||||||
|
if world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3:
|
||||||
|
exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors \
|
||||||
|
+ DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower']
|
||||||
|
links_house_doors = [i for i in links_house_doors if i not in exclusions]
|
||||||
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Links House Exit', player)
|
||||||
|
if links_house in entrances:
|
||||||
|
entrances.remove(links_house)
|
||||||
|
elif links_house in entrances_must_exits:
|
||||||
|
entrances_must_exits.remove(links_house)
|
||||||
|
doors.remove(links_house)
|
||||||
|
|
||||||
# now let's deal with mandatory reachable stuff
|
# now let's deal with mandatory reachable stuff
|
||||||
def extract_reachable_exit(cavelist):
|
def extract_reachable_exit(cavelist):
|
||||||
random.shuffle(cavelist)
|
random.shuffle(cavelist)
|
||||||
@@ -1200,9 +1265,12 @@ def link_inverted_entrances(world, player):
|
|||||||
connect_two_way(world, entrance2, exit2, player)
|
connect_two_way(world, entrance2, exit2, player)
|
||||||
|
|
||||||
# place links house
|
# place links house
|
||||||
links_house_doors = [i for i in bomb_shop_doors + blacksmith_doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
if not world.shufflelinks[player]:
|
||||||
links_house = random.choice(list(links_house_doors))
|
links_house = 'Inverted Links House'
|
||||||
connect_two_way(world, links_house, 'Links House Exit', player)
|
else:
|
||||||
|
links_house_doors = [i for i in DW_Single_Cave_Doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
||||||
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
|
||||||
if links_house in bomb_shop_doors:
|
if links_house in bomb_shop_doors:
|
||||||
bomb_shop_doors.remove(links_house)
|
bomb_shop_doors.remove(links_house)
|
||||||
if links_house in blacksmith_doors:
|
if links_house in blacksmith_doors:
|
||||||
@@ -1277,15 +1345,14 @@ def link_inverted_entrances(world, player):
|
|||||||
door_targets = list(Inverted_Single_Cave_Targets)
|
door_targets = list(Inverted_Single_Cave_Targets)
|
||||||
|
|
||||||
# place links house
|
# place links house
|
||||||
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]
|
if not world.shufflelinks[player]:
|
||||||
links_house = random.choice(list(links_house_doors))
|
links_house = 'Inverted Links House'
|
||||||
connect_two_way(world, links_house, 'Links House Exit', player)
|
else:
|
||||||
if links_house in lw_entrances:
|
links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
||||||
lw_entrances.remove(links_house)
|
links_house = random.choice(links_house_doors)
|
||||||
elif links_house in dw_entrances:
|
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
|
||||||
|
if links_house in dw_entrances:
|
||||||
dw_entrances.remove(links_house)
|
dw_entrances.remove(links_house)
|
||||||
elif links_house in lw_must_exits:
|
|
||||||
lw_must_exits.remove(links_house)
|
|
||||||
|
|
||||||
# place dark sanc
|
# place dark sanc
|
||||||
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
|
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
|
||||||
@@ -1407,15 +1474,14 @@ def link_inverted_entrances(world, player):
|
|||||||
caves.remove('Agahnims Tower Exit')
|
caves.remove('Agahnims Tower Exit')
|
||||||
|
|
||||||
# place links house
|
# place links house
|
||||||
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]
|
if not world.shufflelinks[player]:
|
||||||
links_house = random.choice(list(links_house_doors))
|
links_house = 'Inverted Links House'
|
||||||
connect_two_way(world, links_house, 'Links House Exit', player)
|
else:
|
||||||
if links_house in lw_entrances:
|
links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
||||||
lw_entrances.remove(links_house)
|
links_house = random.choice(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
|
||||||
if links_house in dw_entrances:
|
if links_house in dw_entrances:
|
||||||
dw_entrances.remove(links_house)
|
dw_entrances.remove(links_house)
|
||||||
if links_house in lw_must_exits:
|
|
||||||
lw_must_exits.remove(links_house)
|
|
||||||
|
|
||||||
# place dark sanc
|
# place dark sanc
|
||||||
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
|
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
|
||||||
@@ -1529,7 +1595,7 @@ def link_inverted_entrances(world, player):
|
|||||||
hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower']
|
hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower']
|
||||||
|
|
||||||
# shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit
|
# shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit
|
||||||
aga_door = random.choice(list(entrances))
|
aga_door = random.choice(entrances)
|
||||||
|
|
||||||
if aga_door in hc_ledge_entrances:
|
if aga_door in hc_ledge_entrances:
|
||||||
hc_ledge_entrances.remove(aga_door)
|
hc_ledge_entrances.remove(aga_door)
|
||||||
@@ -1543,11 +1609,13 @@ def link_inverted_entrances(world, player):
|
|||||||
connect_two_way(world, aga_door, 'Agahnims Tower Exit', player)
|
connect_two_way(world, aga_door, 'Agahnims Tower Exit', player)
|
||||||
caves.remove('Agahnims Tower Exit')
|
caves.remove('Agahnims Tower Exit')
|
||||||
|
|
||||||
|
|
||||||
# place links house
|
# place links house
|
||||||
links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
if not world.shufflelinks[player]:
|
||||||
links_house = random.choice(list(links_house_doors))
|
links_house = 'Inverted Links House'
|
||||||
connect_two_way(world, links_house, 'Links House Exit', player)
|
else:
|
||||||
|
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(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
|
||||||
if links_house in entrances:
|
if links_house in entrances:
|
||||||
entrances.remove(links_house)
|
entrances.remove(links_house)
|
||||||
elif links_house in must_exits:
|
elif links_house in must_exits:
|
||||||
@@ -1678,9 +1746,12 @@ def link_inverted_entrances(world, player):
|
|||||||
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
|
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
|
||||||
|
|
||||||
# place links house and dark sanc
|
# place links house and dark sanc
|
||||||
links_house_doors = [i for i in entrances + entrances_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
|
if not world.shufflelinks[player]:
|
||||||
links_house = random.choice(list(links_house_doors))
|
links_house = 'Inverted Links House'
|
||||||
connect_two_way(world, links_house, 'Links House Exit', player)
|
else:
|
||||||
|
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(links_house_doors)
|
||||||
|
connect_two_way(world, links_house, 'Inverted Links House Exit', player)
|
||||||
if links_house in entrances:
|
if links_house in entrances:
|
||||||
entrances.remove(links_house)
|
entrances.remove(links_house)
|
||||||
elif links_house in entrances_must_exits:
|
elif links_house in entrances_must_exits:
|
||||||
@@ -2440,7 +2511,19 @@ LW_Single_Cave_Doors = ['Blinds Hideout',
|
|||||||
'Kings Grave',
|
'Kings Grave',
|
||||||
'Bonk Fairy (Light)',
|
'Bonk Fairy (Light)',
|
||||||
'Hookshot Fairy',
|
'Hookshot Fairy',
|
||||||
'Mimic Cave']
|
'Mimic Cave',
|
||||||
|
'Links House']
|
||||||
|
|
||||||
|
Isolated_LH_Doors_Open = ['Mimic Cave',
|
||||||
|
'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']
|
||||||
|
|
||||||
DW_Single_Cave_Doors = ['Bonk Fairy (Dark)',
|
DW_Single_Cave_Doors = ['Bonk Fairy (Dark)',
|
||||||
'Dark Sanctuary Hint',
|
'Dark Sanctuary Hint',
|
||||||
@@ -2728,7 +2811,7 @@ Inverted_Bomb_Shop_Multi_Cave_Doors = ['Hyrule Castle Entrance (South)',
|
|||||||
|
|
||||||
Inverted_Blacksmith_Multi_Cave_Doors = Blacksmith_Multi_Cave_Doors # same as non-inverted
|
Inverted_Blacksmith_Multi_Cave_Doors = Blacksmith_Multi_Cave_Doors # same as non-inverted
|
||||||
|
|
||||||
Inverted_LW_Single_Cave_Doors = LW_Single_Cave_Doors + ['Links House']
|
Inverted_LW_Single_Cave_Doors = [x for x in LW_Single_Cave_Doors if x != 'Links House'] + ['Inverted Big Bomb Shop']
|
||||||
|
|
||||||
Inverted_DW_Single_Cave_Doors = ['Bonk Fairy (Dark)',
|
Inverted_DW_Single_Cave_Doors = ['Bonk Fairy (Dark)',
|
||||||
'Dark Sanctuary Hint',
|
'Dark Sanctuary Hint',
|
||||||
@@ -2974,7 +3057,9 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'),
|
|||||||
('Other World S&Q', 'Hyrule Castle Ledge')]
|
('Other World S&Q', 'Hyrule Castle Ledge')]
|
||||||
|
|
||||||
# non-shuffled entrance links
|
# non-shuffled entrance links
|
||||||
default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'),
|
default_connections = [('Links House', 'Links House'),
|
||||||
|
('Links House Exit', 'Links House Area'),
|
||||||
|
('Waterfall of Wishing', 'Waterfall of Wishing'),
|
||||||
("Blinds Hideout", "Blinds Hideout"),
|
("Blinds Hideout", "Blinds Hideout"),
|
||||||
('Dam', 'Dam'),
|
('Dam', 'Dam'),
|
||||||
('Lumberjack House', 'Lumberjack House'),
|
('Lumberjack House', 'Lumberjack House'),
|
||||||
@@ -3140,6 +3225,10 @@ inverted_default_connections = [('Old Man Cave (West)', 'Bumper Cave'),
|
|||||||
('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'),
|
('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'),
|
||||||
('Death Mountain Return Cave Exit (West)', 'West Death Mountain (Bottom)'),
|
('Death Mountain Return Cave Exit (West)', 'West Death Mountain (Bottom)'),
|
||||||
('Death Mountain Return Cave Exit (East)', 'West Death Mountain (Bottom)'),
|
('Death Mountain Return Cave Exit (East)', 'West Death Mountain (Bottom)'),
|
||||||
|
|
||||||
|
('Links House', 'Big Bomb Shop'),
|
||||||
|
('Links House Exit', 'Big Bomb Shop Area'),
|
||||||
|
('Big Bomb Shop', 'Links House'),
|
||||||
('Pyramid Exit', 'Hyrule Castle Courtyard')]
|
('Pyramid Exit', 'Hyrule Castle Courtyard')]
|
||||||
|
|
||||||
# non shuffled dungeons
|
# non shuffled dungeons
|
||||||
|
|||||||
3
Main.py
3
Main.py
@@ -28,7 +28,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc
|
|||||||
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops
|
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops
|
||||||
from Utils import output_path, parse_player_names
|
from Utils import output_path, parse_player_names
|
||||||
|
|
||||||
__version__ = '0.4.0.2-u'
|
__version__ = '0.4.0.4-u'
|
||||||
|
|
||||||
|
|
||||||
class EnemizerError(RuntimeError):
|
class EnemizerError(RuntimeError):
|
||||||
@@ -91,6 +91,7 @@ def main(args, seed=None, fish=None):
|
|||||||
world.standardize_palettes = args.standardize_palettes.copy()
|
world.standardize_palettes = args.standardize_palettes.copy()
|
||||||
world.treasure_hunt_count = args.triforce_goal.copy()
|
world.treasure_hunt_count = args.triforce_goal.copy()
|
||||||
world.treasure_hunt_total = args.triforce_pool.copy()
|
world.treasure_hunt_total = args.triforce_pool.copy()
|
||||||
|
world.shufflelinks = args.shufflelinks.copy()
|
||||||
|
|
||||||
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
|
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ def roll_settings(weights):
|
|||||||
if ret.dungeon_counters == 'default':
|
if ret.dungeon_counters == 'default':
|
||||||
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
|
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
|
||||||
|
|
||||||
|
ret.shufflelinks = get_choice('shufflelinks') == 'on'
|
||||||
ret.shopsanity = get_choice('shopsanity') == 'on'
|
ret.shopsanity = get_choice('shopsanity') == 'on'
|
||||||
ret.keydropshuffle = get_choice('keydropshuffle') == 'on'
|
ret.keydropshuffle = get_choice('keydropshuffle') == 'on'
|
||||||
ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent'
|
ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent'
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
# New Features
|
# New Features
|
||||||
|
|
||||||
|
## Shuffle Links House
|
||||||
|
|
||||||
|
Links house can now be shuffled in different ER settings. It will be limited to the Light World (or Dark World in inverted) if Crossed or Insanity shuffle is not one. It it also limited if door shuffle settings allow the Sanctuary to be in the dark world. (This is prevent having no Light World spawn points in Open modes) This setting is ignored by standard mode. THe CLI parameter is --shufflelinks
|
||||||
|
|
||||||
## OWG Glitch Logic
|
## OWG Glitch Logic
|
||||||
|
|
||||||
Thanks to qadan, cheuer, & compiling
|
Thanks to qadan, cheuer, & compiling
|
||||||
|
|
||||||
# Bug Fixes and Notes.
|
# Bug Fixes and Notes.
|
||||||
|
|
||||||
|
* 0.4.0.4
|
||||||
|
* Added --shufflelinks option
|
||||||
|
* Moved spawning as a bunny indoors to experimental
|
||||||
|
* Baserom bug fixes
|
||||||
|
* 0.4.0.3
|
||||||
|
* Fixed a bug where Sanctuary could be chosen as a lobby for a DW dungeon in non-crossed ER modes
|
||||||
* 0.4.0.2
|
* 0.4.0.2
|
||||||
* Fixed a bug where Defeat Ganon is not possible
|
* Fixed a bug where Defeat Ganon is not possible
|
||||||
* Fixed the item counter total
|
* Fixed the item counter total
|
||||||
|
|||||||
21
Rom.py
21
Rom.py
@@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = 'a6186512f1c02acfcb8554e0538a84f9'
|
RANDOMIZERBASEHASH = '06e14a9760b94dc64806b401cacd4680'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -677,6 +677,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
|||||||
dr_flags |= DROptions.Rails
|
dr_flags |= DROptions.Rails
|
||||||
if world.standardize_palettes[player] == 'original':
|
if world.standardize_palettes[player] == 'original':
|
||||||
dr_flags |= DROptions.OriginalPalettes
|
dr_flags |= DROptions.OriginalPalettes
|
||||||
|
if world.experimental[player]:
|
||||||
|
dr_flags |= DROptions.DarkWorld_Spawns
|
||||||
|
|
||||||
|
|
||||||
# fix hc big key problems (map and compass too)
|
# fix hc big key problems (map and compass too)
|
||||||
@@ -687,6 +689,23 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
|||||||
rom.write_byte(0x1597b, sanctuary.dungeon.dungeon_id*2)
|
rom.write_byte(0x1597b, sanctuary.dungeon.dungeon_id*2)
|
||||||
update_compasses(rom, world, player)
|
update_compasses(rom, world, player)
|
||||||
|
|
||||||
|
def should_be_bunny(region, mode):
|
||||||
|
if mode != 'inverted':
|
||||||
|
return region.is_dark_world and not region.is_light_world
|
||||||
|
else:
|
||||||
|
return region.is_light_world and not region.is_dark_world
|
||||||
|
|
||||||
|
# dark world spawns
|
||||||
|
sanc_region = world.get_region('Sanctuary', player)
|
||||||
|
if should_be_bunny(sanc_region, world.mode[player]):
|
||||||
|
rom.write_bytes(0x13fff2, [0x12, 0x00])
|
||||||
|
|
||||||
|
lh_name = 'Links House' if world.mode[player] != 'inverted' else 'Inverted Links House'
|
||||||
|
links_house = world.get_region(lh_name, player)
|
||||||
|
if should_be_bunny(links_house, world.mode[player]):
|
||||||
|
rom.write_bytes(0x13fff0, [0x04, 0x01])
|
||||||
|
|
||||||
|
|
||||||
# patch doors
|
# patch doors
|
||||||
if world.doorShuffle[player] == 'crossed':
|
if world.doorShuffle[player] == 'crossed':
|
||||||
rom.write_byte(0x138002, 2)
|
rom.write_byte(0x138002, 2)
|
||||||
|
|||||||
5
Rules.py
5
Rules.py
@@ -679,7 +679,8 @@ def bomb_rules(world, player):
|
|||||||
add_rule(world.get_entrance('TR Lazy Eyes SE', player), lambda state: state.can_use_bombs(player)) # ToDo: Add always true for inverted, cross-entrance, and door-variants and so on.
|
add_rule(world.get_entrance('TR Lazy Eyes SE', player), lambda state: state.can_use_bombs(player)) # ToDo: Add always true for inverted, cross-entrance, and door-variants and so on.
|
||||||
add_rule(world.get_entrance('Turtle Rock Ledge Exit (West)', player), lambda state: state.can_use_bombs(player)) # Is this the same as above?
|
add_rule(world.get_entrance('Turtle Rock Ledge Exit (West)', player), lambda state: state.can_use_bombs(player)) # Is this the same as above?
|
||||||
|
|
||||||
dungeon_bonkable = ['PoD Warp Hint SE', 'PoD Jelly Hall NW', 'PoD Jelly Hall NE', 'PoD Mimics 1 SW',
|
dungeon_bonkable = ['Sewers Rat Path WS', 'Sewers Rat Path WN',
|
||||||
|
'PoD Warp Hint SE', 'PoD Jelly Hall NW', 'PoD Jelly Hall NE', 'PoD Mimics 1 SW',
|
||||||
'Thieves Ambush E', 'Thieves Rail Ledge W',
|
'Thieves Ambush E', 'Thieves Rail Ledge W',
|
||||||
'TR Dash Room NW', 'TR Crystaroller SW', 'TR Dash Room ES',
|
'TR Dash Room NW', 'TR Crystaroller SW', 'TR Dash Room ES',
|
||||||
'GT Four Torches NW','GT Fairy Abyss SW'
|
'GT Four Torches NW','GT Fairy Abyss SW'
|
||||||
@@ -2082,7 +2083,7 @@ def set_bunny_rules(world, player, inverted):
|
|||||||
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
|
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
|
||||||
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave',
|
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave',
|
||||||
'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)']
|
'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)']
|
||||||
bunny_accessible_locations = ['Link\'s House', 'Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree',
|
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree',
|
||||||
'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid',
|
'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid',
|
||||||
'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins',
|
'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins',
|
||||||
'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith',
|
'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith',
|
||||||
|
|||||||
@@ -669,6 +669,10 @@ db $07,$07,$02,$02,$02,$02,$07,$07,$07,$20,$20,$07,$20,$20,$20,$07
|
|||||||
;27f300
|
;27f300
|
||||||
|
|
||||||
;
|
;
|
||||||
org $27ff00
|
;org $27ff00
|
||||||
SancDarkWorldFlag:
|
|
||||||
db 0
|
org $27fff0
|
||||||
|
LinksHouseDarkWorld:
|
||||||
|
dw $ffff
|
||||||
|
SanctuaryDarkWorld:
|
||||||
|
dw $ffff
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
CheckDarkWorldSanc:
|
CheckDarkWorldSpawn:
|
||||||
STA $A0 : STA $048E ; what we wrote over
|
STA $A0 : STA $048E ; what we wrote over
|
||||||
LDA.l InvertedMode : AND #$00FF : BNE +
|
LDA.l DRFlags : AND #$0200 : BEQ + ; skip if the flag isn't set
|
||||||
LDA.l SancDarkWorldFlag : AND #$00FF : BEQ +
|
LDA.l $7EF357 : AND #$00FF : BNE + ; moon pearl?
|
||||||
SEP #$30
|
LDA.l LinksHouseDarkWorld : CMP $A0 : BEQ ++
|
||||||
LDA $A0 : CMP #$12 : BNE ++
|
LDA.l SanctuaryDarkWorld : CMP $A0 : BNE +
|
||||||
LDA.l $7EF357 : BNE ++ ; moon pearl?
|
++ SEP #$30 : LDA #$17 : STA $5D
|
||||||
LDA #$17 : STA $5D : INC $02E0 : LDA.b #$40 : STA !DARK_WORLD
|
INC $02E0 : LDA.b #$40 : STA !DARK_WORLD : REP #$30
|
||||||
++ REP #$30
|
|
||||||
+ RTL
|
+ RTL
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ org $08c450 ; <- ancilla_receive_item.asm : 146-148 (STY $5D : STZ $02D8)
|
|||||||
JSL RetrieveBunnyState : NOP
|
JSL RetrieveBunnyState : NOP
|
||||||
|
|
||||||
org $02d9ce ; <- Bank02.asm : Dungeon_LoadEntrance 10829 (STA $A0 : STA $048E)
|
org $02d9ce ; <- Bank02.asm : Dungeon_LoadEntrance 10829 (STA $A0 : STA $048E)
|
||||||
JSL CheckDarkWorldSanc : NOP
|
JSL CheckDarkWorldSpawn : NOP
|
||||||
|
|
||||||
org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF)
|
org $01891e ; <- Bank 01.asm : 991 Dungeon_LoadType2Object (LDA $00 : XBA : AND.w #$00FF)
|
||||||
JSL RainPrevention : NOP #2
|
JSL RainPrevention : NOP #2
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ DrHudOverride:
|
|||||||
HudAdditions:
|
HudAdditions:
|
||||||
{
|
{
|
||||||
lda.l DRFlags : and #$0008 : beq ++
|
lda.l DRFlags : and #$0008 : beq ++
|
||||||
LDA.w #$28A4 : STA !GOAL_DRAW_ADDRESS
|
; LDA.w #$28A4 : STA !GOAL_DRAW_ADDRESS
|
||||||
lda $7EF423
|
lda $7EF423
|
||||||
jsr HudHexToDec4DigitCopy
|
jsr HudHexToDec4DigitCopy
|
||||||
LDX.b $05 : TXA : ORA.w #$2400 : STA !GOAL_DRAW_ADDRESS+2 ; draw 100's digit
|
LDX.b $05 : TXA : ORA.w #$2400 : STA !GOAL_DRAW_ADDRESS+2 ; draw 100's digit
|
||||||
|
|||||||
Binary file not shown.
@@ -327,6 +327,10 @@
|
|||||||
"dest": "shuffleganon",
|
"dest": "shuffleganon",
|
||||||
"help": "suppress"
|
"help": "suppress"
|
||||||
},
|
},
|
||||||
|
"shufflelinks": {
|
||||||
|
"action": "store_true",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
"calc_playthrough": {
|
"calc_playthrough": {
|
||||||
"action": "store_false",
|
"action": "store_false",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
|
|||||||
@@ -291,6 +291,9 @@
|
|||||||
"Include the Ganon's Tower and Pyramid Hole in the",
|
"Include the Ganon's Tower and Pyramid Hole in the",
|
||||||
"entrance shuffle pool. (default: %(default)s)"
|
"entrance shuffle pool. (default: %(default)s)"
|
||||||
],
|
],
|
||||||
|
"shufflelink": [
|
||||||
|
"Include Link's House in the entrance shuffle pool. (default: %(default)s)"
|
||||||
|
],
|
||||||
"heartbeep": [
|
"heartbeep": [
|
||||||
"Select the rate at which the heart beep sound is played at",
|
"Select the rate at which the heart beep sound is played at",
|
||||||
"low health. (default: %(default)s)"
|
"low health. (default: %(default)s)"
|
||||||
|
|||||||
@@ -118,6 +118,7 @@
|
|||||||
|
|
||||||
"randomizer.entrance.openpyramid": "Pre-open Pyramid Hole",
|
"randomizer.entrance.openpyramid": "Pre-open Pyramid Hole",
|
||||||
"randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool",
|
"randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool",
|
||||||
|
"randomizer.entrance.shufflelinks": "Include Link's House in the shuffle pool",
|
||||||
|
|
||||||
"randomizer.entrance.entranceshuffle": "Entrance Shuffle",
|
"randomizer.entrance.entranceshuffle": "Entrance Shuffle",
|
||||||
"randomizer.entrance.entranceshuffle.vanilla": "Vanilla",
|
"randomizer.entrance.entranceshuffle.vanilla": "Vanilla",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"dungeonsfull",
|
"dungeonsfull",
|
||||||
"dungeonssimple"
|
"dungeonssimple"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"shufflelinks": { "type": "checkbox" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ SETTINGSTOPROCESS = {
|
|||||||
"entrance": {
|
"entrance": {
|
||||||
"openpyramid": "openpyramid",
|
"openpyramid": "openpyramid",
|
||||||
"shuffleganon": "shuffleganon",
|
"shuffleganon": "shuffleganon",
|
||||||
|
"shufflelinks": "shufflelinks",
|
||||||
"entranceshuffle": "shuffle"
|
"entranceshuffle": "shuffle"
|
||||||
},
|
},
|
||||||
"enemizer": {
|
"enemizer": {
|
||||||
|
|||||||
Reference in New Issue
Block a user