From 8f00f7969b81cca68d1f01cfa4b92047536853b7 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 17 May 2021 13:41:32 -0600 Subject: [PATCH 1/3] Actually restrict Sanctuary from being a DW lobby in non-crossed ER modes --- BaseClasses.py | 1 + DoorShuffle.py | 3 +++ Doors.py | 2 ++ Main.py | 2 +- RELEASENOTES.md | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 36437715..411e9438 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1280,6 +1280,7 @@ class Door(object): self.dungeonLink = None self.bk_shuffle_req = False 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.sectorLink = False diff --git a/DoorShuffle.py b/DoorShuffle.py index 1b505377..5c1285a9 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -563,6 +563,9 @@ def assign_portal(candidates, possible_portals, world, player): candidate = random.choice(candidates) portal_choice = random.choice(possible_portals) 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.entranceFlag: for other_portal in world.dungeon_portals[player]: diff --git a/Doors.py b/Doors.py index 5f20d285..eb824fb1 100644 --- a/Doors.py +++ b/Doors.py @@ -1465,6 +1465,8 @@ def create_doors(world, player): # static portal flags 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('TR Big Chest Entrance SE', player).passage = False world.get_door('Sewers Secret Room Key Door S', player).dungeonLink = 'Hyrule Castle' diff --git a/Main.py b/Main.py index c1f01cc2..4064b27d 100644 --- a/Main.py +++ b/Main.py @@ -27,7 +27,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.4.0.2-u' +__version__ = '0.4.0.3-u' class EnemizerError(RuntimeError): diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4873d28c..d3057c15 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,6 +6,8 @@ Thanks to qadan, cheuer, & compiling # Bug Fixes and Notes. +* 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 * Fixed a bug where Defeat Ganon is not possible * Fixed the item counter total From e77ae23359d88522fd6625b37afb55fd65b9bd06 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+structuralmike@users.noreply.github.com> Date: Fri, 21 May 2021 08:21:00 -0600 Subject: [PATCH 2/3] fixing my illogical logic --- DoorShuffle.py | 1 - Rules.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 5c1285a9..b1bf22fd 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2176,7 +2176,6 @@ logical_connections = [ ('Ice Cross Bottom Push Block Left', 'Ice Floor Switch'), ('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 Crystal Exit', 'Ice Conveyor'), ('Ice Big Key Push Block', 'Ice Dead End'), diff --git a/Rules.py b/Rules.py index 3a02844d..94de5322 100644 --- a/Rules.py +++ b/Rules.py @@ -640,7 +640,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('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', 'TR Dash Room NW', 'TR Crystaroller SW', 'TR Dash Room ES', 'GT Four Torches NW','GT Fairy Abyss SW' From fff7cd691ee0b662f55d1bcf7cd4e0a8035987fa Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 24 May 2021 15:14:23 -0600 Subject: [PATCH 3/3] Added the --shufflelinks option Moved bunny spawn to experimental Baserom bugfixes --- CLI.py | 3 +- DoorShuffle.py | 1 + EntranceShuffle.py | 139 ++++++++++++++---- Main.py | 3 +- Mystery.py | 1 + RELEASENOTES.md | 8 + Rom.py | 21 ++- Rules.py | 2 +- asm/doortables.asm | 10 +- asm/dr_lobby.asm | 15 +- asm/drhooks.asm | 2 +- asm/hudadditions.asm | 2 +- data/base2current.bps | Bin 132984 -> 133024 bytes resources/app/cli/args.json | 4 + resources/app/cli/lang/en.json | 3 + resources/app/gui/lang/en.json | 1 + .../app/gui/randomize/entrando/widgets.json | 3 +- source/classes/constants.py | 1 + 18 files changed, 174 insertions(+), 45 deletions(-) diff --git a/CLI.py b/CLI.py index 29dce609..9c15e4cb 100644 --- a/CLI.py +++ b/CLI.py @@ -98,7 +98,7 @@ def parse_cli(argv, no_defaults=False): 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', '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', 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', @@ -143,6 +143,7 @@ def parse_settings(): "openpyramid": False, "shuffleganon": True, "shuffle": "vanilla", + "shufflelinks": False, "shufflepots": False, "shuffleenemies": "none", diff --git a/DoorShuffle.py b/DoorShuffle.py index b1bf22fd..75bad2b8 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2021,6 +2021,7 @@ class DROptions(Flag): 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 Hide_Total = 0x100 + DarkWorld_Spawns = 0x200 # DATA GOES DOWN HERE diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 34d482b3..8956770e 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -5,7 +5,6 @@ from collections import defaultdict 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 Dungeon_Exits = Dungeon_Exits_Base.copy() @@ -80,7 +79,7 @@ def link_entrances(world, player): single_doors = list(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) # we shuffle all 2 entrance caves as pairs as a start @@ -103,6 +102,18 @@ def link_entrances(world, player): connect_two_way(world, entrance1, exit1, 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 # 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)', @@ -155,6 +166,16 @@ def link_entrances(world, player): blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) 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 connect_doors(world, ['Tavern North'], ['Tavern'], player) @@ -299,7 +320,18 @@ def link_entrances(world, player): else: dw_entrances.append('Ganons Tower') 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 also places the Old Man House at this time to make sure he can be connected to the desert one way @@ -406,6 +438,22 @@ def link_entrances(world, player): entrances.append('Ganons Tower') 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 connect_mandatory_exits(world, entrances, caves, must_exits, player) @@ -852,6 +900,23 @@ def link_entrances(world, player): entrances.append('Hyrule Castle Entrance (South)') 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 def extract_reachable_exit(cavelist): random.shuffle(cavelist) @@ -1196,8 +1261,11 @@ def link_inverted_entrances(world, player): connect_two_way(world, entrance2, exit2, player) # 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] - links_house = random.choice(list(links_house_doors)) + if not world.shufflelinks[player]: + links_house = 'Inverted Links House' + 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: bomb_shop_doors.remove(links_house) @@ -1273,15 +1341,14 @@ def link_inverted_entrances(world, player): door_targets = list(Inverted_Single_Cave_Targets) # 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] - links_house = random.choice(list(links_house_doors)) + if not world.shufflelinks[player]: + links_house = 'Inverted Links House' + else: + links_house_doors = [i for i in dw_entrances 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 lw_entrances: - lw_entrances.remove(links_house) - elif links_house in dw_entrances: + if links_house in dw_entrances: dw_entrances.remove(links_house) - elif links_house in lw_must_exits: - lw_must_exits.remove(links_house) # place dark sanc sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances] @@ -1403,15 +1470,14 @@ def link_inverted_entrances(world, player): caves.remove('Inverted Agahnims Tower Exit') # 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] - links_house = random.choice(list(links_house_doors)) + if not world.shufflelinks[player]: + links_house = 'Inverted Links House' + else: + links_house_doors = [i for i in dw_entrances 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 lw_entrances: - lw_entrances.remove(links_house) if links_house in dw_entrances: dw_entrances.remove(links_house) - if links_house in lw_must_exits: - lw_must_exits.remove(links_house) # place dark sanc sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances] @@ -1525,7 +1591,7 @@ def link_inverted_entrances(world, player): hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] # 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: hc_ledge_entrances.remove(aga_door) @@ -1539,10 +1605,12 @@ def link_inverted_entrances(world, player): connect_two_way(world, aga_door, 'Inverted Agahnims Tower Exit', player) caves.remove('Inverted Agahnims Tower Exit') - # place links house - links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] - links_house = random.choice(list(links_house_doors)) + if not world.shufflelinks[player]: + links_house = 'Inverted Links House' + 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: entrances.remove(links_house) @@ -1674,8 +1742,11 @@ def link_inverted_entrances(world, player): caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) # place links house and dark sanc - links_house_doors = [i for i in entrances + entrances_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] - links_house = random.choice(list(links_house_doors)) + if not world.shufflelinks[player]: + links_house = 'Inverted Links House' + 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: entrances.remove(links_house) @@ -2436,7 +2507,19 @@ LW_Single_Cave_Doors = ['Blinds Hideout', 'Kings Grave', 'Bonk Fairy (Light)', '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)', 'Dark Sanctuary Hint', @@ -2724,7 +2807,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_LW_Single_Cave_Doors = LW_Single_Cave_Doors + ['Inverted Big Bomb Shop'] +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 Dark Sanctuary', @@ -3215,7 +3298,9 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Bomb Hut Outer Bushes', 'Bomb Hut Area'), ('Bomb Hut Mirror Spot', 'West Dark World')] # non-shuffled entrance links -default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), +default_connections = [('Links House', 'Links House'), + ('Links House Exit', 'Light World'), + ('Waterfall of Wishing', 'Waterfall of Wishing'), ("Blinds Hideout", "Blinds Hideout"), ('Dam', 'Dam'), ('Lumberjack House', 'Lumberjack House'), diff --git a/Main.py b/Main.py index 4064b27d..a64e317f 100644 --- a/Main.py +++ b/Main.py @@ -27,7 +27,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.4.0.3-u' +__version__ = '0.4.0.4-u' class EnemizerError(RuntimeError): @@ -89,6 +89,7 @@ def main(args, seed=None, fish=None): world.standardize_palettes = args.standardize_palettes.copy() world.treasure_hunt_count = args.triforce_goal.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)} diff --git a/Mystery.py b/Mystery.py index 7ab7b735..e9d438de 100644 --- a/Mystery.py +++ b/Mystery.py @@ -142,6 +142,7 @@ def roll_settings(weights): if ret.dungeon_counters == 'default': 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.keydropshuffle = get_choice('keydropshuffle') == 'on' ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d3057c15..6bbab2ce 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,11 +1,19 @@ # 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 Thanks to qadan, cheuer, & compiling # 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 diff --git a/Rom.py b/Rom.py index 6da01207..3dab4c8e 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '5c5111bcb73b033ddf72be5b8ea08a8e' +RANDOMIZERBASEHASH = '32b289d8294deba1603c75bb1321d3da' class JsonRom(object): @@ -655,6 +655,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): dr_flags |= DROptions.Rails if world.standardize_palettes[player] == 'original': dr_flags |= DROptions.OriginalPalettes + if world.experimental[player]: + dr_flags |= DROptions.DarkWorld_Spawns # fix hc big key problems (map and compass too) @@ -665,6 +667,23 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x1597b, sanctuary.dungeon.dungeon_id*2) 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 if world.doorShuffle[player] == 'crossed': rom.write_byte(0x138002, 2) diff --git a/Rules.py b/Rules.py index 94de5322..f1ade62a 100644 --- a/Rules.py +++ b/Rules.py @@ -1669,7 +1669,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. bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', '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', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith', diff --git a/asm/doortables.asm b/asm/doortables.asm index 2c0140ea..dbbdb3c4 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -669,6 +669,10 @@ db $07,$07,$02,$02,$02,$02,$07,$07,$07,$20,$20,$07,$20,$20,$20,$07 ;27f300 ; -org $27ff00 -SancDarkWorldFlag: -db 0 +;org $27ff00 + +org $27fff0 +LinksHouseDarkWorld: +dw $ffff +SanctuaryDarkWorld: +dw $ffff \ No newline at end of file diff --git a/asm/dr_lobby.asm b/asm/dr_lobby.asm index 2c1b9c87..1cac9d10 100644 --- a/asm/dr_lobby.asm +++ b/asm/dr_lobby.asm @@ -1,10 +1,9 @@ -CheckDarkWorldSanc: +CheckDarkWorldSpawn: STA $A0 : STA $048E ; what we wrote over - LDA.l InvertedMode : AND #$00FF : BNE + - LDA.l SancDarkWorldFlag : AND #$00FF : BEQ + - SEP #$30 - LDA $A0 : CMP #$12 : BNE ++ - LDA.l $7EF357 : BNE ++ ; moon pearl? - LDA #$17 : STA $5D : INC $02E0 : LDA.b #$40 : STA !DARK_WORLD - ++ REP #$30 + LDA.l DRFlags : AND #$0200 : BEQ + ; skip if the flag isn't set + LDA.l $7EF357 : AND #$00FF : BNE + ; moon pearl? + LDA.l LinksHouseDarkWorld : CMP $A0 : BEQ ++ + LDA.l SanctuaryDarkWorld : CMP $A0 : BNE + + ++ SEP #$30 : LDA #$17 : STA $5D + INC $02E0 : LDA.b #$40 : STA !DARK_WORLD : REP #$30 + RTL diff --git a/asm/drhooks.asm b/asm/drhooks.asm index c4939e9d..6739de34 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -165,7 +165,7 @@ org $08c450 ; <- ancilla_receive_item.asm : 146-148 (STY $5D : STZ $02D8) JSL RetrieveBunnyState : NOP 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) JSL RainPrevention : NOP #2 diff --git a/asm/hudadditions.asm b/asm/hudadditions.asm index f5e4a119..7f9eb342 100644 --- a/asm/hudadditions.asm +++ b/asm/hudadditions.asm @@ -8,7 +8,7 @@ DrHudOverride: HudAdditions: { lda.l DRFlags : and #$0008 : beq ++ - LDA.w #$28A4 : STA !GOAL_DRAW_ADDRESS +; LDA.w #$28A4 : STA !GOAL_DRAW_ADDRESS lda $7EF423 jsr HudHexToDec4DigitCopy LDX.b $05 : TXA : ORA.w #$2400 : STA !GOAL_DRAW_ADDRESS+2 ; draw 100's digit diff --git a/data/base2current.bps b/data/base2current.bps index 8a0d34e2b68d60947b14ed1e98fab8af3dacd692..abda4b8c6894e42f2fc35fa6a2747920bfa7c6b9 100644 GIT binary patch delta 5631 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 IRju#;0h6oRjQ{`u delta 5726 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 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 1e04769d..45f0e808 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -297,6 +297,10 @@ "dest": "shuffleganon", "help": "suppress" }, + "shufflelinks": { + "action": "store_true", + "type": "bool" + }, "calc_playthrough": { "action": "store_false", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 0720adea..183b3c2e 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -278,6 +278,9 @@ "Include the Ganon's Tower and Pyramid Hole in the", "entrance shuffle pool. (default: %(default)s)" ], + "shufflelink": [ + "Include Link's House in the entrance shuffle pool. (default: %(default)s)" + ], "heartbeep": [ "Select the rate at which the heart beep sound is played at", "low health. (default: %(default)s)" diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index a5f3fec6..f7cdc0a3 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -111,6 +111,7 @@ "randomizer.entrance.openpyramid": "Pre-open Pyramid Hole", "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.vanilla": "Vanilla", diff --git a/resources/app/gui/randomize/entrando/widgets.json b/resources/app/gui/randomize/entrando/widgets.json index e46ee36e..5e2b75b2 100644 --- a/resources/app/gui/randomize/entrando/widgets.json +++ b/resources/app/gui/randomize/entrando/widgets.json @@ -18,6 +18,7 @@ "dungeonsfull", "dungeonssimple" ] - } + }, + "shufflelinks": { "type": "checkbox" } } } diff --git a/source/classes/constants.py b/source/classes/constants.py index 1ff3a2f3..64f44398 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -73,6 +73,7 @@ SETTINGSTOPROCESS = { "entrance": { "openpyramid": "openpyramid", "shuffleganon": "shuffleganon", + "shufflelinks": "shufflelinks", "entranceshuffle": "shuffle" }, "enemizer": {