From 051a47e0cde59e75f26bd1dfcb9c739377095605 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Fri, 23 Jul 2021 20:35:48 +0200 Subject: [PATCH 01/31] Bomblogic added --- BaseClasses.py | 6 ++- CLI.py | 2 + ItemList.py | 47 +++++++++++-------- Items.py | 2 +- Main.py | 2 + Mystery.py | 2 + Rom.py | 9 ++-- Rules.py | 2 +- resources/app/cli/args.json | 4 ++ resources/app/cli/lang/en.json | 1 + resources/app/gui/lang/en.json | 1 + resources/app/gui/randomize/item/widgets.json | 1 + source/classes/constants.py | 1 + 13 files changed, 54 insertions(+), 26 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 0e3e8af4..42acdefe 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -114,6 +114,7 @@ class World(object): set_player_attr('compassshuffle', False) set_player_attr('keyshuffle', False) set_player_attr('bigkeyshuffle', False) + set_player_attr('bomblogic', False) set_player_attr('difficulty_requirements', None) set_player_attr('boss_shuffle', 'none') set_player_attr('enemy_shuffle', 'none') @@ -686,8 +687,7 @@ class CollectionState(object): # In the future, this can be used to check if the player starts without bombs def can_use_bombs(self, player): - StartingBombs = True - return StartingBombs or self.has('Bomb Upgrade (+10)', player) + return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) def can_hit_crystal(self, player): return (self.can_use_bombs(player) @@ -2013,6 +2013,7 @@ class Spoiler(object): 'logic': self.world.logic, 'mode': self.world.mode, 'retro': self.world.retro, + 'bomblogic': self.world.bomblogic, 'weapons': self.world.swords, 'goal': self.world.goal, 'shuffle': self.world.shuffle, @@ -2111,6 +2112,7 @@ class Spoiler(object): outfile.write('Experimental: %s\n' % ('Yes' if self.metadata['experimental'][player] else 'No')) outfile.write('Key Drops shuffled: %s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No')) outfile.write(f"Shopsanity: {'Yes' if self.metadata['shopsanity'][player] else 'No'}\n") + outfile.write('Bomblogic: %s\n' % ('Yes' if self.metadata['bomblogic'][player] else 'No')) if self.doors: outfile.write('\n\nDoors:\n\n') outfile.write('\n'.join( diff --git a/CLI.py b/CLI.py index d87e1e2c..10fb211c 100644 --- a/CLI.py +++ b/CLI.py @@ -96,6 +96,7 @@ def parse_cli(argv, no_defaults=False): for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', + 'bomblogic', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', @@ -126,6 +127,7 @@ def parse_settings(): settings = { "lang": "en", "retro": False, + "bomblogic": False, "mode": "open", "logic": "noglitches", "goal": "ganon", diff --git a/ItemList.py b/ItemList.py index a16219f4..a1d31968 100644 --- a/ItemList.py +++ b/ItemList.py @@ -37,7 +37,7 @@ Difficulty = namedtuple('Difficulty', ['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield', 'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother', - 'retro', + 'retro', 'bomblogic', 'extras', 'progressive_sword_limit', 'progressive_shield_limit', 'progressive_armor_limit', 'progressive_bottle_limit', 'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit']) @@ -61,6 +61,7 @@ difficulties = { timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 4, progressive_shield_limit = 3, @@ -86,6 +87,7 @@ difficulties = { timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 3, progressive_shield_limit = 2, @@ -111,6 +113,7 @@ difficulties = { timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 2, progressive_shield_limit = 1, @@ -251,10 +254,10 @@ def generate_itempool(world, player): # set up item pool 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[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], 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[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bomblogic[player], world.customitemarray) world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999) else: - (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player], world.logic[player]) + (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bomblogic[player], world.doorShuffle[player], world.logic[player]) if player in world.pool_adjustment.keys(): amt = world.pool_adjustment[player] @@ -284,7 +287,7 @@ def generate_itempool(world, player): if item in ['Hammer', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']: if item not in possible_weapons: possible_weapons.append(item) - if item in ['Bombs (10)']: + if not world.bomblogic[player] and item in ['Bombs (10)']: if item not in possible_weapons and world.doorShuffle[player] != 'crossed': possible_weapons.append(item) starting_weapon = random.choice(possible_weapons) @@ -709,7 +712,7 @@ rupee_chart = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)' 'Rupees (100)': 100, 'Rupees (300)': 300} -def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, door_shuffle, logic): +def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic): pool = [] placed_items = {} precollected_items = [] @@ -756,6 +759,11 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, diff = difficulties[difficulty] pool.extend(diff.baseitems) + if bomblogic: + pool = [item.replace('Bomb Upgrade (+5)','Rupees (5)') for item in pool] + pool = [item.replace('Bomb Upgrade (+10)','Rupees (5)') for item in pool] + pool.extend(diff.bomblogic) + # expert+ difficulties produce the same contents for # all bottles, since only one bottle is available if diff.same_bottle: @@ -850,7 +858,7 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, pool.extend(['Small Key (Universal)']) return (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) -def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray): +def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic, customitemarray): if isinstance(customitemarray,dict) and 1 in customitemarray: customitemarray = customitemarray[1] pool = [] @@ -966,20 +974,21 @@ def test(): for shuffle in ['full', 'insanity_legacy']: for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']: for retro in [True, False]: - for door_shuffle in ['basic', 'crossed', 'vanilla']: - out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, door_shuffle, logic) - count = len(out[0]) + len(out[1]) + for bomblogic in [True, False]: + for door_shuffle in ['basic', 'crossed', 'vanilla']: + out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic) + count = len(out[0]) + len(out[1]) - correct_count = total_items_to_place - if goal == 'pedestal' and swords != 'vanilla': - # pedestal goals generate one extra item - correct_count += 1 - if retro: - correct_count += 28 - try: - assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro)) - except AssertionError as e: - print(e) + correct_count = total_items_to_place + if goal == 'pedestal' and swords != 'vanilla': + # pedestal goals generate one extra item + correct_count += 1 + if retro: + correct_count += 28 + try: + assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic)) + except AssertionError as e: + print(e) if __name__ == '__main__': test() diff --git a/Items.py b/Items.py index 808a0740..279cc33d 100644 --- a/Items.py +++ b/Items.py @@ -81,7 +81,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), - 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Bomb Upgrade (+10)': (True, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Blue Mail': (False, True, None, 0x22, 50, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), 'Red Mail': (False, True, None, 0x23, 100, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), diff --git a/Main.py b/Main.py index 8909301a..06ccf51c 100644 --- a/Main.py +++ b/Main.py @@ -69,6 +69,7 @@ def main(args, seed=None, fish=None): world.compassshuffle = args.compassshuffle.copy() world.keyshuffle = args.keyshuffle.copy() world.bigkeyshuffle = args.bigkeyshuffle.copy() + world.bomblogic = args.bomblogic.copy() world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)} world.crystals_ganon_orig = args.crystals_ganon.copy() @@ -372,6 +373,7 @@ def copy_world(world): ret.compassshuffle = world.compassshuffle.copy() ret.keyshuffle = world.keyshuffle.copy() ret.bigkeyshuffle = world.bigkeyshuffle.copy() + ret.bomblogic = world.bomblogic.copy() ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon.copy() ret.crystals_needed_for_gt = world.crystals_needed_for_gt.copy() ret.crystals_ganon_orig = world.crystals_ganon_orig.copy() diff --git a/Mystery.py b/Mystery.py index d3e3bddf..3786ae15 100644 --- a/Mystery.py +++ b/Mystery.py @@ -176,6 +176,8 @@ def roll_settings(weights): ret.retro = True ret.retro = get_choice('retro') == 'on' # this overrides world_state if used + ret.bomblogic = get_choice('bomblogic') == 'on' + ret.hints = get_choice('hints') == 'on' ret.swords = {'randomized': 'random', diff --git a/Rom.py b/Rom.py index 40249d56..bbf76726 100644 --- a/Rom.py +++ b/Rom.py @@ -1032,7 +1032,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x184000, [ # original_item, limit, replacement_item, filler 0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees - 0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade + 0x51, 0x00 if world.bomblogic[player] else 0x06, 0x31 if world.bomblogic[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bomblogic -> turns into Bombs (10) 0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade 0x58, 0x01, 0x36 if world.retro[player] else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode) 0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20 @@ -1169,7 +1169,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): equip[0x36C] = 0x18 equip[0x36D] = 0x18 equip[0x379] = 0x68 - starting_max_bombs = 10 + if world.bomblogic[player]: + starting_max_bombs = 0 + else: + starting_max_bombs = 10 starting_max_arrows = 30 startingstate = CollectionState(world) @@ -1461,7 +1464,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x180188, [0, 0, 10]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0, 0, 10]) # Mantle respawn refills (magic, bombs, arrows) bow_max, bow_small = 70, 10 - elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']: + elif uncle_location.item is not None and uncle_location.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)']: rom.write_byte(0x18004E, 2) # Escape Fill (bombs) rom.write_bytes(0x180185, [0, 50, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0, 3, 0]) # Zelda respawn refills (magic, bombs, arrows) diff --git a/Rules.py b/Rules.py index 3762b9bb..75deec4a 100644 --- a/Rules.py +++ b/Rules.py @@ -1160,7 +1160,7 @@ def standard_rules(world, player): def bomb_escape_rule(): loc = world.get_location("Link's Uncle", player) - return loc.item and loc.item.name == 'Bombs (10)' + return loc.item and loc.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)'] def standard_escape_rule(state): return state.can_kill_most_things(player) or bomb_escape_rule() diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 47bb3987..817e2607 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -220,6 +220,10 @@ "type": "bool", "help": "suppress" }, + "bomblogic": { + "action": "store_true", + "type": "bool" + }, "retro": { "action": "store_true", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index ef1a8f3d..dffd41ff 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -263,6 +263,7 @@ "and a few other little things make this more like Zelda-1. (default: %(default)s)" ], "pseudoboots": [ " Players starts with pseudo boots that allow dashing but no item checks (default: %(default)s"], + "bomblogic": ["Start with 0 bomb capacity. Two capacity upgrades (+10) are added to the pool (default: %(default)s)" ], "startinventory": [ "Specifies a list of items that will be in your starting inventory (separated by commas). (default: %(default)s)" ], "usestartinventory": [ "Toggle usage of Starting Inventory." ], "custom": [ "Not supported." ], diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 0d9e3836..2d8bf3f8 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -190,6 +190,7 @@ "randomizer.item.hints": "Include Helpful Hints", "randomizer.item.retro": "Retro mode (universal keys)", "randomizer.item.pseudoboots": "Start with Pseudo Boots", + "randomizer.item.bomblogic": "Bomblogic", "randomizer.item.worldstate": "World State", "randomizer.item.worldstate.standard": "Standard", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index a6f10a14..15d049c8 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -1,6 +1,7 @@ { "checkboxes": { "retro": { "type": "checkbox" }, + "bomblogic": { "type": "checkbox" }, "shopsanity": { "type": "checkbox" }, "hints": { "type": "checkbox" diff --git a/source/classes/constants.py b/source/classes/constants.py index 04cbde2e..7c76913f 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -57,6 +57,7 @@ SETTINGSTOPROCESS = { "item": { "hints": "hints", "retro": "retro", + "bomblogic": "bomblogic", "shopsanity": "shopsanity", "pseudoboots": "pseudoboots", "worldstate": "mode", From cce5adc4538aff00c247c7150f378c77ab685c2c Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Sat, 24 Jul 2021 14:21:22 +0200 Subject: [PATCH 02/31] Good bee cave & spiral cave logic for bombs Good bee cave requires bombs to access. Spiral cave is never assumed to be transversable as a super bunny, so it makes sense to force bombs OR can_kill_most_things if the cave is in the LW. --- BaseClasses.py | 1 + Rules.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 42acdefe..b7a80af7 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -719,6 +719,7 @@ class CollectionState(object): def can_get_good_bee(self, player): cave = self.world.get_region('Good Bee Cave', player) return ( + self.can_use_bombs(player) and self.has_bottle(player) and self.has('Bug Catching Net', player) and (self.has_Boots(player) or (self.has_sword(player) and self.has('Quake', player))) and diff --git a/Rules.py b/Rules.py index 75deec4a..9560970d 100644 --- a/Rules.py +++ b/Rules.py @@ -576,9 +576,10 @@ def bomb_rules(world, player): for location in bombable_items: add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player)) - cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy'] + cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy', 'Spiral Cave'] for location in cave_kill_locations: add_rule(world.get_location(location, player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player)) + add_rule(world.get_entrance('Spiral Cave (top to bottom)', player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player)) paradox_switch_chests = ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle'] for location in paradox_switch_chests: From 779c7d78c0f01a8924a18a9baa3d7bc64f7827bd Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Sat, 24 Jul 2021 17:22:48 +0200 Subject: [PATCH 03/31] New hookshot cave region definitions --- EntranceShuffle.py | 30 +++++++++++++++++++----------- InvertedRegions.py | 7 +++++-- PotShuffle.py | 6 +++--- Regions.py | 7 +++++-- Rules.py | 5 +++-- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 1b8ce162..1c1a6ab8 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2373,7 +2373,7 @@ Cave_Exits_Base = [['Elder House Exit (East)', 'Elder House Exit (West)'], ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)'], ['Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)'], ['Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']] + ['Hookshot Cave Back Exit', 'Hookshot Cave Front Exit']] Cave_Exits_Base += [('Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'), ('Spiral Cave Exit (Top)', 'Spiral Cave Exit')] @@ -3115,6 +3115,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), + ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), + ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), + ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), ('Floating Island Drop', 'Dark Death Mountain (Top)'), @@ -3233,6 +3237,10 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), + ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), + ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), + ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Desert Ledge Drop', 'Light World'), ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), @@ -3428,16 +3436,16 @@ default_connections = [('Links House', 'Links House'), ('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), ('Spike Cave', 'Spike Cave'), - ('Hookshot Cave', 'Hookshot Cave'), + ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Exit (South)', 'Dark Death Mountain (Top)'), - ('Hookshot Cave Exit (North)', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), + ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), + ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Mimic Cave', 'Mimic Cave'), ('Pyramid Hole', 'Pyramid'), @@ -3562,13 +3570,13 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), ('Spike Cave', 'Spike Cave'), - ('Hookshot Cave', 'Hookshot Cave'), + ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Exit (North)', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave'), + ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), + ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Mimic Cave', 'Mimic Cave'), ('Inverted Pyramid Hole', 'Pyramid'), ('Inverted Links House', 'Inverted Links House'), @@ -3589,7 +3597,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), - ('Hookshot Cave Exit (South)', 'Dark Death Mountain'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain'), ('Superbunny Cave Exit (Top)', 'Dark Death Mountain'), ('Pyramid Exit', 'Light World'), ('Inverted Pyramid Entrance', 'Bottom of Pyramid')] @@ -3937,8 +3945,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bumper Cave Exit (Bottom)': (0x16, 0x17), 'Superbunny Cave Exit (Top)': (0x14, 0x15), 'Superbunny Cave Exit (Bottom)': (0x13, 0x14), - 'Hookshot Cave Exit (South)': (0x3A, 0x3B), - 'Hookshot Cave Exit (North)': (0x3B, 0x3C), + 'Hookshot Cave Front Exit': (0x3A, 0x3B), + 'Hookshot Cave Back Exit': (0x3B, 0x3C), 'Ganons Tower Exit': (0x37, 0x38), 'Inverted Ganons Tower Exit': (0x37, 0x38), 'Pyramid Exit': (0x36, 0x37), diff --git a/InvertedRegions.py b/InvertedRegions.py index d935ed28..589f6f87 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -199,8 +199,11 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], + ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit']), + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), + create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), + create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance']), create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), diff --git a/PotShuffle.py b/PotShuffle.py index d62f52eb..a0c048bf 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -51,7 +51,7 @@ vanilla_pots = { 43: [Pot(16, 5, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 5, PotItem.Switch, 'PoD Sexy Statue'), Pot(16, 6, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 6, PotItem.Bomb, 'PoD Sexy Statue'), Pot(16, 7, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 7, PotItem.Bomb, 'PoD Sexy Statue'), Pot(146, 21, PotItem.Bomb, 'PoD Map Balcony'), Pot(170, 21, PotItem.FiveArrows, 'PoD Map Balcony'), Pot(146, 22, PotItem.Bomb, 'PoD Map Balcony'), Pot(170, 22, PotItem.FiveArrows, 'PoD Map Balcony')], - 44: [Pot(108, 24, PotItem.Heart, 'Hookshot Cave'), Pot(112, 24, PotItem.Heart, 'Hookshot Cave')], + 44: [Pot(108, 24, PotItem.Heart, 'Hookshot Cave (Middle)'), Pot(112, 24, PotItem.Heart, 'Hookshot Cave (Middle)')], 47: [Pot(28, 7, PotItem.Heart, 'Kakariko Well (top)'), Pot(32, 7, PotItem.Heart, 'Kakariko Well (top)'), Pot(28, 9, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(32, 9, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(172, 19, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(180, 19, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(104, 27, PotItem.Heart, 'Kakariko Well (bottom)'), Pot(104, 28, PotItem.Heart, 'Kakariko Well (bottom)')], 49: [Pot(92, 28, PotItem.Bomb, 'Hera Beetles'), Pot(96, 28, PotItem.Nothing, 'Hera Beetles')], @@ -66,8 +66,8 @@ vanilla_pots = { 55: [Pot(60, 6, PotItem.Key, 'Swamp Trench 1 Alcove'), Pot(48, 20, PotItem.Nothing, 'Swamp Trench 1 Key Ledge')], 56: [Pot(164, 12, PotItem.Bomb, 'Swamp Pot Row'), Pot(164, 13, PotItem.FiveRupees, 'Swamp Pot Row'), Pot(164, 18, PotItem.Bomb, 'Swamp Pot Row'), Pot(164, 19, PotItem.Key, 'Swamp Pot Row')], 57: [Pot(12, 20, PotItem.Heart, 'Skull Spike Corner'), Pot(48, 28, PotItem.FiveArrows, 'Skull Spike Corner'), Pot(100, 22, PotItem.SmallMagic, 'Skull Final Drop'), Pot(100, 26, PotItem.FiveArrows, 'Skull Final Drop')], - 60: [Pot(24, 8, PotItem.SmallMagic, 'Hookshot Cave'), Pot(64, 12, PotItem.FiveRupees, 'Hookshot Cave'), Pot(20, 14, PotItem.OneRupee, 'Hookshot Cave'), Pot(20, 19, PotItem.Nothing, 'Hookshot Cave'), - Pot(68, 18, PotItem.FiveRupees, 'Hookshot Cave'), Pot(96, 19, PotItem.Heart, 'Hookshot Cave'), Pot(64, 20, PotItem.FiveRupees, 'Hookshot Cave'), Pot(64, 26, PotItem.FiveRupees, 'Hookshot Cave')], + 60: [Pot(24, 8, PotItem.SmallMagic, 'Hookshot Cave (Front)'), Pot(64, 12, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(20, 14, PotItem.OneRupee, 'Hookshot Cave (Front)'), Pot(20, 19, PotItem.Nothing, 'Hookshot Cave (Front)'), + Pot(68, 18, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(96, 19, PotItem.Heart, 'Hookshot Cave (Front)'), Pot(64, 20, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(64, 26, PotItem.FiveRupees, 'Hookshot Cave (Front)')], 61: [Pot(76, 12, PotItem.Bomb, 'GT Mini Helmasaur Room'), Pot(112, 12, PotItem.Bomb, 'GT Mini Helmasaur Room'), Pot(24, 22, PotItem.Heart, 'GT Crystal Inner Circle'), Pot(40, 22, PotItem.FiveArrows, 'GT Crystal Inner Circle'), Pot(32, 24, PotItem.Heart, 'GT Crystal Inner Circle'), Pot(20, 26, PotItem.FiveRupees, 'GT Crystal Inner Circle'), Pot(36, 26, PotItem.BigMagic, 'GT Crystal Inner Circle')], 62: [Pot(96, 6, PotItem.Bomb, 'Ice Stalfos Hint'), Pot(100, 6, PotItem.SmallMagic, 'Ice Stalfos Hint'), Pot(88, 10, PotItem.Heart, 'Ice Stalfos Hint'), Pot(92, 10, PotItem.SmallMagic, 'Ice Stalfos Hint')], diff --git a/Regions.py b/Regions.py index b2af454a..35a7eda3 100644 --- a/Regions.py +++ b/Regions.py @@ -190,8 +190,11 @@ def create_regions(world, player): create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], + ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit']), + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), + create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), + create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot']), create_lw_region(player, 'Death Mountain Floating Island (Light World)', ['Floating Island']), create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop']), diff --git a/Rules.py b/Rules.py index 9560970d..cd65e748 100644 --- a/Rules.py +++ b/Rules.py @@ -561,7 +561,8 @@ def global_rules(world, player): def bomb_rules(world, player): bonkable_doors = ['Two Brothers House Exit (West)', 'Two Brothers House Exit (East)'] # Technically this is incorrectly defined, but functionally the same as what is intended. bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Light World Death Mountain Shop', 'Mini Moldorm Cave', - 'Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)', 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery'] + 'Hookshot Cave Back to Middle', 'Hookshot Cave Front to Middle', 'Hookshot Cave Middle to Front','Hookshot Cave Middle to Back', + 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery'] for entrance in bonkable_doors: add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) for entrance in bombable_doors: @@ -1672,7 +1673,7 @@ def set_bunny_rules(world, player, inverted): # regions for the exits of multi-entrace caves/drops that bunny cannot pass # 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 (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', From c981b362d29ee8f0e01fd8bd918e31d046af3921 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:15:11 +1000 Subject: [PATCH 04/31] Add warning for old python versions. --- Gui.py | 9 +++++++++ Main.py | 12 ++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Gui.py b/Gui.py index 4cc5b106..6433c79f 100755 --- a/Gui.py +++ b/Gui.py @@ -24,6 +24,13 @@ from source.classes.BabelFish import BabelFish from source.classes.Empty import Empty +def check_python_version(): + import sys + version = sys.version_info + if version.major < 3 or version.minor < 7: + messagebox.showinfo("Door Shuffle " + ESVersion, 'Door Rando may have issues with python versions earlier than 3.7. Detected version: %s' % sys.version) + + def guiMain(args=None): # Save settings to file def save_settings(args): @@ -188,6 +195,8 @@ def guiMain(args=None): # load adjust settings into options loadadjustargs(self, self.settings) + check_python_version() + # run main window mainWindow.mainloop() diff --git a/Main.py b/Main.py index eb8380f3..5a2e4370 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,15 @@ class EnemizerError(RuntimeError): pass +def check_python_version(): + import sys + version = sys.version_info + if version.major < 3 or version.minor < 7: + logging.warning('Door Rando may have issues with python versions earlier than 3.7. Detected version: %s', sys.version) + + def main(args, seed=None, fish=None): + check_python_version() if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) output_path.cached_path = args.outputpath @@ -257,11 +265,11 @@ def main(args, seed=None, fish=None): rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom) if use_enemizer and (args.enemizercli or not args.jsonout): - base_patch = LocalRom(args.rom) # update base2current.json (side effect) + local_rom = LocalRom(args.rom) # update base2current.json (side effect) if args.rom and not(os.path.isfile(args.rom)): raise RuntimeError("Could not find valid base rom for enemizing at expected path %s." % args.rom) if os.path.exists(args.enemizercli): - patch_enemizer(world, player, rom, args.rom, args.enemizercli, sprite_random_on_hit) + patch_enemizer(world, player, rom, local_rom, args.enemizercli, sprite_random_on_hit) enemized = True if not args.jsonout: rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000) From 4d8bfe0e22791b17aeb7e428e76eac8a35fdc535 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:15:51 +1000 Subject: [PATCH 05/31] Check for headered roms before passing to enemizer. --- Rom.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Rom.py b/Rom.py index 5c61e5c2..bde37484 100644 --- a/Rom.py +++ b/Rom.py @@ -86,10 +86,12 @@ class LocalRom(object): self.name = name self.hash = hash self.orig_buffer = None + self.file = file + self.has_smc_header = False if not os.path.isfile(file): raise RuntimeError("Could not find valid local base rom for patching at expected path %s." % file) with open(file, 'rb') as stream: - self.buffer = read_rom(stream) + self.buffer, self.has_smc_header = read_rom(stream) if patch: self.patch_base_rom() self.orig_buffer = self.buffer.copy() @@ -187,12 +189,21 @@ def write_int32s(rom, startaddress, values): def read_rom(stream): "Reads rom into bytearray and strips off any smc header" buffer = bytearray(stream.read()) + has_smc_header = False if len(buffer)%0x400 == 0x200: buffer = buffer[0x200:] - return buffer + has_smc_header = True + return buffer, has_smc_header -def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_on_hit): - baserom_path = os.path.abspath(baserom_path) +def patch_enemizer(world, player, rom, local_rom, enemizercli, random_sprite_on_hit): + baserom_path = os.path.abspath(local_rom.file) + unheadered_path = None + if local_rom.has_smc_header: + headered_path = baserom_path + unheadered_path = baserom_path = os.path.abspath(output_path('unheadered_rom.sfc')) + with open(headered_path, 'rb') as headered: + with open(baserom_path, 'wb') as unheadered: + unheadered.write(headered.read()[0x200:]) basepatch_path = os.path.abspath(local_path(os.path.join("data","base2current.json"))) enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json") randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json')) @@ -336,6 +347,12 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_ rom.write_bytes(0x307000 + (i * 0x8000), sprite.palette) rom.write_bytes(0x307078 + (i * 0x8000), sprite.glove_palette) + if local_rom.has_smc_header: + try: + os.remove(unheadered_path) + except OSError: + pass + try: os.remove(randopatch_path) except OSError: From dc950112d9a89e35260920cddc0324112b1a124f Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:17:10 +1000 Subject: [PATCH 06/31] Fix Aga rule for standard - should be Zelda + normal requirements. --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 3762b9bb..c9dc03f9 100644 --- a/Rules.py +++ b/Rules.py @@ -1149,7 +1149,7 @@ def standard_rules(world, player): set_rule(entrance, lambda state: state.has('Zelda Delivered', player)) set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) # zelda should be saved before agahnim is in play - set_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) + add_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) # too restrictive for crossed? def uncle_item_rule(item): From 4d90ca9181267828dbe003686525e798bd126372 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 19:48:07 +1000 Subject: [PATCH 07/31] Add python version warning to the translation file. --- Gui.py | 6 +++--- Main.py | 4 +++- resources/app/cli/lang/en.json | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Gui.py b/Gui.py index 6433c79f..55defa7a 100755 --- a/Gui.py +++ b/Gui.py @@ -24,11 +24,11 @@ from source.classes.BabelFish import BabelFish from source.classes.Empty import Empty -def check_python_version(): +def check_python_version(fish): import sys version = sys.version_info if version.major < 3 or version.minor < 7: - messagebox.showinfo("Door Shuffle " + ESVersion, 'Door Rando may have issues with python versions earlier than 3.7. Detected version: %s' % sys.version) + messagebox.showinfo("Door Shuffle " + ESVersion, fish.translate("cli","cli","old.python.version") % sys.version) def guiMain(args=None): @@ -195,7 +195,7 @@ def guiMain(args=None): # load adjust settings into options loadadjustargs(self, self.settings) - check_python_version() + check_python_version(self.fish) # run main window mainWindow.mainloop() diff --git a/Main.py b/Main.py index 5a2e4370..665196fc 100644 --- a/Main.py +++ b/Main.py @@ -29,6 +29,8 @@ from Utils import output_path, parse_player_names __version__ = '0.4.0.11u' +from source.classes.BabelFish import BabelFish + class EnemizerError(RuntimeError): pass @@ -38,7 +40,7 @@ def check_python_version(): import sys version = sys.version_info if version.major < 3 or version.minor < 7: - logging.warning('Door Rando may have issues with python versions earlier than 3.7. Detected version: %s', sys.version) + logging.warning(BabelFish().translate("cli","cli","old.python.version"), sys.version) def main(args, seed=None, fish=None): diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 0ff910a9..d2be5eb0 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -52,7 +52,8 @@ "enemizer.nothing.applied": "No Enemizer options will be applied until this is resolved.", "building.collection.spheres": "Building up collection spheres", "building.calculating.spheres": "Calculated sphere %i, containing %i of %i progress items.", - "building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items." + "building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items.", + "old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s" }, "help": { "lang": [ "App Language, if available, defaults to English" ], From e5e90fc805eba03f61d0694081e7432f51b32829 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:09:24 +0200 Subject: [PATCH 08/31] Remove default bomb upgrades from shop --- ItemList.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index a1d31968..5ad981bf 100644 --- a/ItemList.py +++ b/ItemList.py @@ -523,6 +523,17 @@ def set_up_shops(world, player): rss.locked = True cap_shop = world.get_region('Capacity Upgrade', player).shop cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro + if world.bomblogic[player]: + if world.shopsanity[player]: + removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] + for i in removals: + print(i) + for remove in removals: + world.itempool.remove(remove) + world.itempool.append(ItemFactory('Rupees (50)', player)) # replace the bomb upgrade + else: + cap_shop = world.get_region('Capacity Upgrade', player).shop + cap_shop.inventory[0] = cap_shop.inventory[1] # remove bomb capacity upgrades in bomblogic def customize_shops(world, player): @@ -567,7 +578,7 @@ def customize_shops(world, player): if not found_bomb_upgrade and len(possible_replacements) > 0: choices = [] for shop, idx, loc, item in possible_replacements: - if item.name in ['Bombs (3)', 'Bombs (10)']: + if item.name in ['Bombs (3)', 'Bombs (10)'] and not world.bomblogic[player]: choices.append((shop, idx, loc, item)) if len(choices) > 0: shop, idx, loc, item = random.choice(choices) From 9247c547d3ff00e237639fbca6810aa50890f954 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:12:47 +0200 Subject: [PATCH 09/31] Update ItemList.py --- ItemList.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ItemList.py b/ItemList.py index 5ad981bf..f3853e4f 100644 --- a/ItemList.py +++ b/ItemList.py @@ -526,8 +526,6 @@ def set_up_shops(world, player): if world.bomblogic[player]: if world.shopsanity[player]: removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] - for i in removals: - print(i) for remove in removals: world.itempool.remove(remove) world.itempool.append(ItemFactory('Rupees (50)', player)) # replace the bomb upgrade From 322273673b8a56610f685c9d229137526c474b11 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 26 Jul 2021 12:19:45 -0600 Subject: [PATCH 10/31] stage unstable for next release cycle --- Main.py | 2 +- RELEASENOTES.md | 130 ++---------------------------------------------- 2 files changed, 5 insertions(+), 127 deletions(-) diff --git a/Main.py b/Main.py index 8909301a..aea113c0 100644 --- a/Main.py +++ b/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 Utils import output_path, parse_player_names -__version__ = '0.4.0.12u' +__version__ = '0.5.0.0-u' class EnemizerError(RuntimeError): diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0ccceb80..2eb25d4a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,116 +1,11 @@ # New Features -## Maiden Hint for Theives Town Attic - -In crossed dungeon mode, if you bring the maiden to the boss room when the attic is not bombed (and thus no light in the room), she mentions the dungeon where you can find the cracked floor. - -## 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 - -## Pseudo Boots - -Thanks to Bonta. You can now start with pseudo boots that let you move fast, but have no other logical uses (bonking open things, hovering, etc) - -## Pendant/Crystal Indicator - -For accessibility, you now get a C or P indicator to the left of the magic bar on the HUD when instead a Crystal or Pendant. Requires ownership of the map of that dungeon for display. Thanks to kan. +None yet # Bug Fixes and Notes. -* 0.4.0.12 - * ER Inverted fix for HC Ledge, and Aga Tower choosing Links House incorrectly - * Credits again - hopefully for good - * Incorporated music fixes for now (may revisit later) - * Secure random re-incorporated -* 0.4.0.11 - * Some minor base rom fixes - * Improved distribution of bombable/dashable doors -* 0.4.0.10 - * Renamed to pseudoboots - * Some release note updates -* 0.4.0.9 - * Fixes for stats and P/C indicator (thanks Kara) - * Swamp lobby fixes (thanks Catobat) - * Fix for --hints flag on CLI -* 0.4.0.8 - * Ganon jokes added for when silvers aren't available - * Some text updated (Blind jokes, uncle text) - * Fixed some enemizer Mystery settings - * Added a setting that's random enemy shuffle without Unkillable Thieves possible - * Fixed shop spoiler when money balancing/multiworld balancing - * Fixed a problem with insanity - * Fixed an issue with the credit stats specific to DR (e.g. collection rate total) - * More helpful error message when bps is missing? - * Minor generation issues involving enemizer and the link sprite - * Baserom updates (from Bonta, kan, qwertymodo, ardnaxelark) - * Boss icon on dungeon map (if you have a compass) - * Progressive bow sprite replacement - * Quickswap - consecutive special swaps - * Bonk Counter - * One mind - * MSU fix - * Chest turn tracking (not yet in credits) - * Damaged and magic stats in credits (gt bk removed) - * Fix for infinite bombs - * Pseudo boots option - * Always allowed medallions for swordless (no option yet) -* 0.4.0.7 - * Reduce flashing option added - * Sprite author credit added - * Ranged Crystal switch rules tweaked - * Baserom update: includes Credits Speedup, reduced flashing option, msu resume (but turned off by default) - * Create link sprite's zspr from local ROM and no longer attempts to download it from website - * Some minor bug fixes -* 0.4.0.6 - * Hints now default to off - * The maiden gives you a hint to the attic if you bring her to the unlit boss room - * Beemizer support and fix for shopsanity - * Capacity upgrades removed in hard/expert item difficulties - * Swamp Hub added to lobby shuffle with ugly cave entrance. - * TR Lava Escape added to lobby shuffle. - * Hyrule Main Lobby and Sanctuary can now have a more visible outside exit, and rugs modified to be fully clipped. -* 0.4.0.5 - * Insanity - less restrictions on exiting (all modes) - * Fix for simple bosses shuffle - * Fix for boss shuffle from Mystery.py - * Minor msu fade out bug (thanks codemann8) - * Other bug fixes (thanks Catobat) -* 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 - * Fixed a bug where Defeat Ganon is not possible - * Fixed the item counter total - * Fixed the bunny state when starting out in Sanc in a dark world dungeon -* 0.4.0.1 - * Moved stonewall pre-opening to not happen in experimental - * Updated baserom - * Boss RNG perseved between files - * Vanilla prize pack fix - * Starting equipment fix - * Post-Aga world state option - * Code optimzation - * Bottle quickswap via double shoulder - * Credits update - * Accessibility option - * Sewer map/compass fix - * Fixed a standard bug where the exits to the ledge would be unavailable if the pyramid was pre-opened - * DR ASM optimization - * Removed Archery Game from Take-Any caves in inverted - * Fixed a problem with new YAML parser -* 0.4.0.0 - * Mystery yaml parser updated to a package maintained version (Thanks StructuralMike) - * Bomb-logic and extend crystal switch logic (Thanks StructuralMike) - * Fixed logic for moved locations in playthrough (Thanks compiling) - * OWG Glitch logic added +* 0.5.0.0 + * None yet # Known Issues @@ -118,21 +13,4 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o * Hints for items in shops can be misleading (ER) * Forfeit in Multiworld not granting all shop items * Potential keylocks in multi-entrance dungeons -* Incorrect vanilla key logic for Mire - -## Other Notes - -### Triforce Hunt Options - -Thanks to deathFouton! - ---triforce_pool and --triforce_goal added to the CLI. - -Also, to the Mystery.py he added the following options: -* triforce_goal_min -* triforce_goal_max -* triforce_pool_min -* triforce_pool_max -* triforce_min_difference - -See the example yaml file for demonstrated usage. \ No newline at end of file +* Incorrect vanilla key logic for Mire \ No newline at end of file From 14079b373f1a86b87339c1eb7284aec5479c34ab Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 27 Jul 2021 02:40:51 -0500 Subject: [PATCH 11/31] Fix for boss music not playing in non-DR modes --- Rom.py | 2 +- data/base2current.bps | Bin 141213 -> 141217 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index bf4275ea..55d8a929 100644 --- a/Rom.py +++ b/Rom.py @@ -31,7 +31,7 @@ from OverworldShuffle import default_flute_connections, flute_data JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'abcc9ca7e5ec6eac56a70e8b248a5883' +RANDOMIZERBASEHASH = '9f660065954a8ebdca25773531c93543' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index f66931c092e72fc563326a568893875d44bf4599..40ef303eb26adce053ddd198860789822073b4f4 100644 GIT binary patch delta 5445 zcmW+)30xD$_s`^ja3`R0s2Enc1Qk%LA}FGG&}cotgQkj#iUyB*)Ejouh=FWE7{ZDH zv%mlb#8p!PMWsM(33$Y671VlFtwsAYUe)5i^*@;X?7Z*H&YPKc&AdtJRdLx>aXt}M zqDQ<8(KD*$8HHjo8^c)olMhKuCrWgvM|_r=p)XzRekd39^ejG3$s!II6k$*RLWm$M@*!zrAB_-A zpyO=O%<$(CC(RLj7ZDHe>JHCe1!sdW;0AYs@L;nQiAe)7p#TpPGKbUy@c`iHQ=nIT zDn~tCG;!_@3dvO$!Al@WEH$9HaKk`P5ckG@sk4Yx1$@-t6klEoK-M1(ZsQ7 zDs>q|!zexBY+!rl>S!Vu#t7m;f0!j8z!X?6i1zTZq8BP6{nI2;n5`yG!{>rnpoXEs zC@%o+{$I7s|^ z2U1|sC2+f#7_I43Voy)nF?CNJdx$2^7qZXv#J`28C!&xVVB~3exNB_zN-v~|?sjyH zCdBZPI8u5?kH)iVA}_xwBr-d{m>2@xo#b9$ccKzzP4WRbW*T|0<`Aur!}U(#{eH?r zGqW3PXL8Vtd;43ST(iWgb`!kxRH+68%|$`CIoJ6bu8UfCT`TReQFrh(H9G1v2lhle-lN8ohT+=7a+nLE^{3)ih#%!&+(uc^~=4Nm7J>@ z9&>ny%aOR<+3Iiu+Jr?}b+D!NVwPOtzkwgu|=P9em5tVjR+D?7KS- z(!|(uWW!!>F}PO)um{FUMgk9*A@Kp%p-S>Ku)~Lvw(y&b!@7L}Rbt{{`cXvrr=-#Q ziixJHNd9x13{NkyA(kc_ZAgK&VS+YkoOsMFB*u>63w=C;Jsfn1`EutOW|QmLMit=& z=Xf&UBYf(q5aZBFJz7RITN1s-gn*YYYvPPC9l2Dg5@h2;^I)Zr=<*lBIsfUm~yyqRf?mvWT;$ z0&on<$!#FY(n@;BWY1XCDj|d>B%5BZ5WL{EN-$`ZmAfkmP=<*0mRD?>aL!&z$??hH zno9No&nB^Y@@&HLex#$7&$IE%B}$^A6A{rlpjA@EHve`IJ(3V5IlOumYEYr+2hgtv zP+AUJm4jC2Ajg9!1O8X(hyBR6YNmrUN=$x~Sk_cc0`4oE@71r5Mn5f=lHTMhXsM0> zgW==qP+YnnP4Wz%r7ch_R>3u!X{tl#MlybI>(N*c3r`(Q93bvQl>_a;rgT^O_uSGA zRD??2s|bdk<`vEp6N}fAH*FFkA7+{ddY5Q=l_xZ(G~a7(YaVI-(AYJvH6JwR;0bfU zs4wKj#WrFFjZ!(|6hikZmHeTvmVZ`WMcakMlB;5FDH&nK(kt4oFv5bGDR}z$nhw|F z+RE2znaz!ilHG+0TW?+ zT@rAIgOAG+n0CZi%yu!C{3g@JPgkZNk&iRN?Lw__wMcu$^>edBNUxd4Q-<_1OP2Of zO5-kEI>Brh`He>F7fYI^!R+ISgHtMyVlIn_sBA=Z!eFAc2@yQ9nULuau@?S$e9~~= z46TY=R=ZF{skk}DRU!(m`v5m=rqz7A0~4E|gYgMEHLwRWp>Q7OU*Pr+v6g}hGa zF}2GoKWUJ67(zesY!2m5N-&I$X86;(R3{C(1JqxpZ0a3;|20*pM5RU@<)&*?mG{@> zLXrF3hc@MZ2jO<;B?4*GVDc@$g zK@G01roJ&9qMVF{h7JR#5o}_7#q=4QOF3<1AAIf@$!QpwBdvBRSD6No)L>Xgk-8Jq zUc3&>b-Ke)ZZNWsC0x8%ec1;; z?NnZA)T_9!P3P%4JX|%RPMgl**7JR>N>dqq5wpN=_d|#M)Me9165gVI{mk~8acrHL zncx@A*ICfEIRGF<+>*ObAy zS;{SBhU65FC}H<_a*G%birQ+5AoZ~&>>w}3DVrK=jL3tPW&A!LNho1u)ddjYI_Rs< zhNr)m_4nvco80@;`r%%FbU2d>XV24^2Em^1FM@IK#Oc3rhErWXUoyix8&3DmRxOkm z!!Y!OP7Qy9p#_aTUb|Y+uHKM7&z@u6FqqbQG4U|0aUysO*EBu_QaI;K0(b@s&x8Rv z{NYS2*bM(WnI%j$8NG@?LSKqG8g|1;FlL=$b2Y^Lz+4)H69=tP67~?>yNblS81VwEF zVA*-Uz^~$UD%&_FCW%~opw^5o5+?>X*Y(l-{>>bwvJ-C2C*gzh?}0Pyx-d4YyQa1^ zqG(81XK}qz7&UV*Ub>`_MO{tuK8EYwNZUkVpCAp;@^b7Q(PrH}_(1jD3y7@#VH;_rS z3~5Uff>DLJE0!G2`&P1>aZtu)+ijA|YQ@NDua?6X(3_f@Rms|-1dYE-( zs`%+S&gX5W>=Nv_GADTB9J-WnYetV`+(sCvq6pKlWLotgpPS{QHBR!;Qmai46kHD{ zUmY_yvl-b3r zfV5((le|j5P*+}JqCMJ*17$_g78!SD6KuQsFW3fKY+0Tg2rc|lQ$_`tSJBx4<}BlA zIR9GE;z`qW#kJ|>JYKG{DDuh~zZMkLg66fL`K>6u6*VkMyr;$~4zojbS}FUsEv-Gx zO5otJxxn?5fhXD2A^E3}}7h<=dVY1n<4#@}Hqy3j|huG=57PAwqzCPG9{72-o zc7N(~9bd|;v@&#^9NxTc0P!&6#;{QyyI&PdROHPg1y#J}aR^ljN*yE^PWTMPeQ@Gu z=-vloVe^eafUw-X!STUfsJSH@6ER*(jbH*K`IS@OX4;&%5pOf2nVFLOhs{IU06Bw* zRr9!PDk79`m({rg>u#H`aSD8JE5JA7}|w#`y$9cFV#Ioj97=m{@$4HA7j zOUuaN{jNw~mkccx&1CD-mBjK!<0Pe4KV;@@F4*V>f8D$jZz=K=osmE%>w4 zjhomf!bD~y{Hc4m8~zj)lV3FI%eroP5d63M3r}%BePz(wOrMS8aLVNY4?qu?a61RM z!ppZKfdYQIUATV621oK&#bvuF@5@@VW9eKE+5IcTA8-9-L#~=)M*nrhSw!nUsl?_h z7m@-W!EGtoRnmwy>O)16Z|TL3I3Ax{gRche+$5Yuig3;}`U`!*EMH?;5etYtWO=^3 zY3T@^Azw(mg{&pG;BK1t&8tWEN66Z78L7OT>$6tIt6_PvF1Y*dSm*YuKC2$79w}uv z;n}-0!AL0hEi16}I;sl?RL!C$%2wy%7=sU$8`Qj5T?9sX5 z?`|QxLx<#jF4=A->41RN2*zchBl%B_v-4VB5$!oOg_ZFh$(r$>B+}o@BV!^jHN1QI zgSwg6-RaoRk!+BAI+Dy#?}`SI@6i@>nt6w9Z)Ly9SurUaR&;*X`&w>c{r{-+?K=+mrM%ibNX^@1`S+=>vyt1gWj=)*I>^fwYkH|BNd3Gf?6mR@5nD;B@k~p7U9j`9t0b4LP z=}m1KbN?IY{C*I=@&v!9y)$-^E$HXW^AUELnbB4KoLQUt-zR32rSttiVB~jJbej=0 zpL9vAX+D92&V-BJjpV?gYIO?BiXhcsVbJ%3Yi_2*Z&N03`lpqM7#5Nj!nMv zE_LqQUC#*l2WL>b;+@Fmz@3_bi3dW)ikFBzYP5z#;iJmRBjR5D)C!mm}T0BM_~ zp?V?^_<&%hb^!2?G^i|Jr!OJ5B&LW_+Wg)jR5`(5r}671@m`` N<*i?cVh$4E{{it~ylVge delta 5544 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 From 066d239b70de5137ca5a556352571db592e027d3 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 08:58:31 -0600 Subject: [PATCH 12/31] Boss music fix --- RELEASENOTES.md | 5 ++++- Rom.py | 2 +- data/base2current.bps | Bin 136267 -> 136271 bytes 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2eb25d4a..95d116ef 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,7 +5,10 @@ None yet # Bug Fixes and Notes. * 0.5.0.0 - * None yet + * Handles headered roms for enemizer (Thanks compiling) + * Warning added for earlier version of pythong (Thanks compiling) + * Minor logic issue for defeating Aga in standard (Thanks compiling) + * Fix for boss music in non-DR modes (Thanks codemann8) # Known Issues diff --git a/Rom.py b/Rom.py index fcc9d426..dd4e287e 100644 --- a/Rom.py +++ b/Rom.py @@ -30,7 +30,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '9c2878d1035bb3889784906a55a92a26' +RANDOMIZERBASEHASH = '988f1546b14d8f2e6ee30b9de44882da' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index a904b07d50f9fadac099414d033b0c27b309563b..5f41171067dccc266f98a3c0b2daee5a07a03f06 100644 GIT binary patch delta 5253 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 delta 5364 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 q>=Zx2ly7Ye>5S6|F From c182e73b778ae198a690cf3cd087e779e0e6b78f Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 11:33:10 -0600 Subject: [PATCH 13/31] Mystery can apply reduce_flashing --- Mystery.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Mystery.py b/Mystery.py index d3e3bddf..1ab4a90b 100644 --- a/Mystery.py +++ b/Mystery.py @@ -226,6 +226,7 @@ def roll_settings(weights): ret.sprite = get_choice('sprite', romweights) ret.disablemusic = get_choice('disablemusic', romweights) == 'on' ret.quickswap = get_choice('quickswap', romweights) == 'on' + ret.reduce_flashing = get_choice('reduce_flashing', romweights) == 'on' ret.fastmenu = get_choice('menuspeed', romweights) ret.heartcolor = get_choice('heartcolor', romweights) ret.heartbeep = get_choice('heartbeep', romweights) From ce24017297bc48daa12546aa56d238aae97ac474 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 13:13:18 -0600 Subject: [PATCH 14/31] typo --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 95d116ef..2ac7dbdc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,7 +6,7 @@ None yet * 0.5.0.0 * Handles headered roms for enemizer (Thanks compiling) - * Warning added for earlier version of pythong (Thanks compiling) + * Warning added for earlier version of python (Thanks compiling) * Minor logic issue for defeating Aga in standard (Thanks compiling) * Fix for boss music in non-DR modes (Thanks codemann8) From d70f2ee355b47c047688be9b4977d2330c34d400 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 28 Jul 2021 15:21:51 -0600 Subject: [PATCH 15/31] Small changes for bomblogic --- ItemList.py | 7 +++++-- Items.py | 2 +- Main.py | 2 +- RELEASENOTES.md | 9 +++++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ItemList.py b/ItemList.py index f3853e4f..57566418 100644 --- a/ItemList.py +++ b/ItemList.py @@ -524,6 +524,9 @@ def set_up_shops(world, player): cap_shop = world.get_region('Capacity Upgrade', player).shop cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro if world.bomblogic[player]: + for item in world.itempool: + if item.name == 'Bomb Upgrade (+10)' and item.player == player: + item.advancement = True if world.shopsanity[player]: removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] for remove in removals: @@ -573,10 +576,10 @@ def customize_shops(world, player): shop.shopkeeper_config = shopkeeper # handle capacity upgrades - randomly choose a bomb bunch or arrow bunch to become capacity upgrades if world.difficulty[player] == 'normal': - if not found_bomb_upgrade and len(possible_replacements) > 0: + if not found_bomb_upgrade and len(possible_replacements) > 0 and not world.bomblogic[player]: choices = [] for shop, idx, loc, item in possible_replacements: - if item.name in ['Bombs (3)', 'Bombs (10)'] and not world.bomblogic[player]: + if item.name in ['Bombs (3)', 'Bombs (10)']: choices.append((shop, idx, loc, item)) if len(choices) > 0: shop, idx, loc, item = random.choice(choices) diff --git a/Items.py b/Items.py index 279cc33d..808a0740 100644 --- a/Items.py +++ b/Items.py @@ -81,7 +81,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), - 'Bomb Upgrade (+10)': (True, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Blue Mail': (False, True, None, 0x22, 50, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), 'Red Mail': (False, True, None, 0x23, 100, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), diff --git a/Main.py b/Main.py index 0a8519b6..75831f5c 100644 --- a/Main.py +++ b/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 Utils import output_path, parse_player_names -__version__ = '0.5.0.0-u' +__version__ = '0.5.0.1-u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2ac7dbdc..c0fae696 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,9 +1,14 @@ # New Features -None yet +Bomb Logic added as an option. This removes your ability to use bombs until you find a "bomb bag", a +10 Bomb Capacity item. It is accounted for in the logic, so you aren't expected to get items behind bomb walls until you have found the bomb capacity item. The upgrades are removed from the upgrade fairy as well. + +``` +--bomblogic +``` # Bug Fixes and Notes. - +* 0.5.0.1 + * --bomblogic option added * 0.5.0.0 * Handles headered roms for enemizer (Thanks compiling) * Warning added for earlier version of python (Thanks compiling) From 263a7d1db9c4e71496115a4035d670ffc44c00d1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 17:31:06 -0500 Subject: [PATCH 16/31] Minor formatting and trimming --- EntranceShuffle.py | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 7ac7485d..d26bc157 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -7,7 +7,7 @@ from collections import defaultdict def link_entrances(world, player): invFlag = world.mode[player] == 'inverted' - Dungeon_Exits = Dungeon_Exits_Base.copy() if not invFlag else Inverted_Dungeon_Exits_Base.copy() + Dungeon_Exits = Dungeon_Exits_Base.copy() Cave_Exits = Cave_Exits_Base.copy() Old_Man_House = Old_Man_House_Base.copy() Cave_Three_Exits = Cave_Three_Exits_Base.copy() @@ -2058,14 +2058,13 @@ Cave_Exits_Base = [['Elder House Exit (East)', 'Elder House Exit (West)'], ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)'], ['Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)'], ['Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)'], - ['Hookshot Cave Back Exit', 'Hookshot Cave Front Exit']] - -Cave_Exits_Base += [('Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'), - ('Spiral Cave Exit (Top)', 'Spiral Cave Exit')] + ['Hookshot Cave Back Exit', 'Hookshot Cave Front Exit'], + ['Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'], + ['Spiral Cave Exit (Top)', 'Spiral Cave Exit']] -Cave_Three_Exits_Base = [('Spectacle Rock Cave Exit (Peak)', 'Spectacle Rock Cave Exit (Top)', - 'Spectacle Rock Cave Exit'), +Cave_Three_Exits_Base = [['Spectacle Rock Cave Exit (Peak)', 'Spectacle Rock Cave Exit (Top)', + 'Spectacle Rock Cave Exit'], ['Paradox Cave Exit (Top)', 'Paradox Cave Exit (Middle)','Paradox Cave Exit (Bottom)']] @@ -2387,20 +2386,6 @@ Inverted_DW_Dungeon_Entrances = ['Thieves Town', Inverted_LW_Dungeon_Entrances_Must_Exit = ['Desert Palace Entrance (East)'] -Inverted_Dungeon_Exits_Base = [['Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)'], - 'Desert Palace Exit (North)', - 'Eastern Palace Exit', - 'Tower of Hera Exit', - 'Thieves Town Exit', - 'Skull Woods Final Section Exit', - 'Ice Palace Exit', - 'Misery Mire Exit', - 'Palace of Darkness Exit', - 'Swamp Palace Exit', - 'Agahnims Tower Exit', - ['Turtle Rock Ledge Exit (East)', - 'Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Isolated Ledge Exit']] - Inverted_LW_Entrances_Must_Exit = ['Death Mountain Return Cave (West)', 'Two Brothers House (West)'] From e1b8428d58a1d24d16ad92febd1b957d5da9325e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 17:36:14 -0500 Subject: [PATCH 17/31] Merged in DR v0.5.0.1 --- EntranceShuffle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index d26bc157..495a99be 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2856,8 +2856,8 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), - ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), - ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), + ('Superbunny Cave Exit (Top)', 'East Dark Death Mountain (Top)'), + ('Superbunny Cave Exit (Bottom)', 'East Dark Death Mountain (Bottom)'), ('Hookshot Cave Front Exit', 'East Dark Death Mountain (Top)'), ('Hookshot Cave Back Exit', 'Dark Death Mountain Floating Island'), ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), From 19dca02c6e59b5ab5eb4118d5d138cf695b6dfc9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 20:11:38 -0500 Subject: [PATCH 18/31] Added bomb logic to OW and removed starting rupees/bombs in Mixed OW Shuffle --- BaseClasses.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++- ItemList.py | 6 ----- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 72267aca..e2b7b1f8 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -672,6 +672,66 @@ class CollectionState(object): if shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self): return True return False + + def can_farm_bombs(self, player): + if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player): + return True + + bush_bombs = ['Flute Boy Approach Area', + 'Kakariko Area', + 'Village of Outcasts Area', + 'Forgotten Forest Area', + 'Bat Cave Ledge', + 'East Dark Death Mountain (Bottom)'] + rock_bombs = ['Links House Area', + 'Dark Chapel Area', + 'Wooden Bridge Area', + 'Ice Cave Area', + 'Eastern Nook Area', + 'West Death Mountain (Bottom)', + 'Kakariko Fortune Area', + 'Skull Woods Forest', + 'Catfish Area', + 'Dark Fortune Area', + 'Qirn Jump Area', + 'Shield Shop Area', + 'Palace of Darkness Nook Area', + 'Swamp Nook Area', + 'Dark South Pass Area'] + bonk_bombs = ['Kakariko Fortune Area', 'Dark Graveyard Area'] #TODO: Flute Boy Approach Area and Bonk Rock Ledge are available post-Aga + + # TODO: Possibly use tree pulls also in the future, bush crabs also if enemizer is disabled + tree_pulls = ['Lost Woods East Area', + 'Snitch Lady (East)', + 'Turtle Rock Area', + 'Pyramid Area', + 'Hype Cave Area', + 'Dark South Pass Area', + 'Bumper Cave Area'] + pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area'] + post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area'] + + def can_reach_non_bunny(regionname): + region = self.world.get_region(regionname, player) + return region.can_reach(self) and (region.type == RegionType.LightWorld or self.has('Pearl', player)) + + for region in bush_bombs: + if can_reach_non_bunny(region): + return True + + if self.can_lift_rocks(player): + for region in rock_bombs: + if can_reach_non_bunny(region): + return True + + if self.has_Boots(player): + for region in bonk_bombs: + if can_reach_non_bunny(region): + return True + + if self.can_reach('Archery Game', None, player) and self.can_buy_unlimited('Bombs (10)', player): + return True + return False def item_count(self, item, player): return self.prog_items[item, player] @@ -731,7 +791,7 @@ class CollectionState(object): # In the future, this can be used to check if the player starts without bombs def can_use_bombs(self, player): - return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) + return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) and self.can_farm_bombs(player) def can_hit_crystal(self, player): return (self.can_use_bombs(player) diff --git a/ItemList.py b/ItemList.py index 95ebcaea..e1d40b09 100644 --- a/ItemList.py +++ b/ItemList.py @@ -750,12 +750,6 @@ def get_pool_core(progressive, owShuffle, owSwap, shuffle, difficulty, treasure_ pool.remove('Pegasus Boots') pool.extend(['Rupees (20)']) - if owSwap in ['mixed', 'crossed'] and owShuffle == 'vanilla': - precollected_items.append('Bombs (3)') - precollected_items.append('Rupees (5)') - precollected_items.append('Rupees (5)') - precollected_items.append('Rupees (5)') - if want_progressives(): pool.extend(progressivegloves) else: From 10be4c8bb19d392b92cf8393b2bbf2173a0985c5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 20:51:01 -0500 Subject: [PATCH 19/31] Added bomb logic to OW and removed starting rupees/bombs in Mixed OW Shuffle --- BaseClasses.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index e2b7b1f8..2cb93b45 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -672,6 +672,29 @@ class CollectionState(object): if shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self): return True return False + + def can_farm_rupees(self, player): + # TODO: Possibly use tree pulls also in the future, bush crabs also if enemizer is disabled + tree_pulls = ['Lost Woods East Area', + 'Snitch Lady (East)', + 'Turtle Rock Area', + 'Pyramid Area', + 'Hype Cave Area', + 'Dark South Pass Area', + 'Bumper Cave Area'] + pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area'] + post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area'] + + rupee_farms = ['Archery Game', '50 Rupee Cave', '20 Rupee Cave'] + + def can_reach_non_bunny(regionname): + region = self.world.get_region(regionname, player) + return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player)) + + for region in rupee_farms: + if can_reach_non_bunny(region): + return True + return False def can_farm_bombs(self, player): if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player): @@ -713,7 +736,7 @@ class CollectionState(object): def can_reach_non_bunny(regionname): region = self.world.get_region(regionname, player) - return region.can_reach(self) and (region.type == RegionType.LightWorld or self.has('Pearl', player)) + return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player)) for region in bush_bombs: if can_reach_non_bunny(region): @@ -729,7 +752,7 @@ class CollectionState(object): if can_reach_non_bunny(region): return True - if self.can_reach('Archery Game', None, player) and self.can_buy_unlimited('Bombs (10)', player): + if self.can_farm_rupees(player) and self.can_buy_unlimited('Bombs (10)', player): return True return False From f9da22f92070ca2c4c63a6d82bd4d88b3d45a636 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 20:51:54 -0500 Subject: [PATCH 20/31] Version bump 0.1.7.0 --- CHANGELOG.md | 4 ++++ OverworldShuffle.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 343a7c36..19498a68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 0.1.7.0 +- Expanded new DR bomb logic to all modes (bomb usage in logic only if there is an unlimited supply of bombs available) +- ~~Merged DR v0.5.0.1 - Bomblogic mode / Enemizer fixes~~ + ### 0.1.6.9 - ~~Merged DR v0.4.0.12 - Secure random update / Credits fix~~ diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 2f75659e..d1ddfb65 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -2,7 +2,7 @@ import RaceRandom as random, logging, copy from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel -__version__ = '0.1.6.9-u' +__version__ = '0.1.7.0-u' def link_overworld(world, player): # setup mandatory connections From e9957d87dd77554aabfb87a63331db40b226fe92 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 28 Jul 2021 21:06:19 -0500 Subject: [PATCH 21/31] Added bomb caves to bomb logic --- BaseClasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 2cb93b45..49bac1de 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -722,6 +722,7 @@ class CollectionState(object): 'Swamp Nook Area', 'Dark South Pass Area'] bonk_bombs = ['Kakariko Fortune Area', 'Dark Graveyard Area'] #TODO: Flute Boy Approach Area and Bonk Rock Ledge are available post-Aga + bomb_caves = ['Graveyard Cave', 'Light World Bomb Hut'] # TODO: Possibly use tree pulls also in the future, bush crabs also if enemizer is disabled tree_pulls = ['Lost Woods East Area', @@ -738,7 +739,7 @@ class CollectionState(object): region = self.world.get_region(regionname, player) return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player)) - for region in bush_bombs: + for region in bush_bombs + bomb_caves: if can_reach_non_bunny(region): return True From c14ad502cd022de0c51e5faba245e17b68823e62 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 03:40:45 -0500 Subject: [PATCH 22/31] Adding tree pulls, bush crabs, and stun prizes to logic consideration --- BaseClasses.py | 80 ++++++++++++++++++++++++++++++++++++++++++++------ Fill.py | 30 +++++++++++++++++++ Main.py | 5 +++- Rom.py | 37 +++++++++++------------ Tables.py | 15 ++++++++++ 5 files changed, 139 insertions(+), 28 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 49bac1de..09ff5b3b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -70,6 +70,7 @@ class World(object): self.customitemarray = customitemarray self.can_take_damage = True self.hints = hints.copy() + self.prizes = {} self.dynamic_regions = [] self.dynamic_locations = [] self.spoiler = Spoiler(self) @@ -148,6 +149,7 @@ class World(object): set_player_attr('standardize_palettes', 'standardize') set_player_attr('force_fix', {'gt': False, 'sw': False, 'pod': False, 'tr': False}) set_player_attr('owswaps', [[],[],[]]) + set_player_attr('prizes', {'pull': [0, 0, 0], 'crab': [0, 0], 'stun': 0, 'fish': 0}) def get_name_string_for_object(self, obj): return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})' @@ -674,7 +676,6 @@ class CollectionState(object): return False def can_farm_rupees(self, player): - # TODO: Possibly use tree pulls also in the future, bush crabs also if enemizer is disabled tree_pulls = ['Lost Woods East Area', 'Snitch Lady (East)', 'Turtle Rock Area', @@ -684,16 +685,29 @@ class CollectionState(object): 'Bumper Cave Area'] pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area'] post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area'] - + rupee_farms = ['Archery Game', '50 Rupee Cave', '20 Rupee Cave'] - + def can_reach_non_bunny(regionname): region = self.world.get_region(regionname, player) return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player)) - + for region in rupee_farms: if can_reach_non_bunny(region): return True + + if any(i in [0xda, 0xdb] for i in self.world.prizes[player]['pull']): + for region in tree_pulls: + if can_reach_non_bunny(region): + return True + if not self.has('Beat Agahnim 1', player): + for region in pre_aga_tree_pulls: + if can_reach_non_bunny(region): + return True + else: + for region in post_aga_tree_pulls: + if can_reach_non_bunny(region): + return True return False def can_farm_bombs(self, player): @@ -724,7 +738,6 @@ class CollectionState(object): bonk_bombs = ['Kakariko Fortune Area', 'Dark Graveyard Area'] #TODO: Flute Boy Approach Area and Bonk Rock Ledge are available post-Aga bomb_caves = ['Graveyard Cave', 'Light World Bomb Hut'] - # TODO: Possibly use tree pulls also in the future, bush crabs also if enemizer is disabled tree_pulls = ['Lost Woods East Area', 'Snitch Lady (East)', 'Turtle Rock Area', @@ -734,15 +747,20 @@ class CollectionState(object): 'Bumper Cave Area'] pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area'] post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area'] - + + bush_crabs = ['Lost Woods East Area', 'Mountain Entry Area'] + pre_aga_bush_crabs = ['Lumberjack Area', 'South Pass Area'] + rock_crabs = ['Desert Pass Area'] + def can_reach_non_bunny(regionname): region = self.world.get_region(regionname, player) return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player)) - + + # bomb pickups for region in bush_bombs + bomb_caves: if can_reach_non_bunny(region): return True - + if self.can_lift_rocks(player): for region in rock_bombs: if can_reach_non_bunny(region): @@ -753,7 +771,41 @@ class CollectionState(object): if can_reach_non_bunny(region): return True - if self.can_farm_rupees(player) and self.can_buy_unlimited('Bombs (10)', player): + # tree pulls + if any(i in [0xdc, 0xdd, 0xde] for i in self.world.prizes[player]['pull']): + for region in tree_pulls: + if can_reach_non_bunny(region): + return True + if not self.has('Beat Agahnim 1', player): + for region in pre_aga_tree_pulls: + if can_reach_non_bunny(region): + return True + else: + for region in post_aga_tree_pulls: + if can_reach_non_bunny(region): + return True + + # bush crabs (final item isn't considered) + if self.world.enemy_shuffle[player] != 'none': + if self.world.prizes[player]['crab'][0] in [0xdc, 0xdd, 0xde]: + for region in bush_crabs: + if can_reach_non_bunny(region): + return True + if not self.has('Beat Agahnim 1', player): + for region in pre_aga_bush_crabs: + if can_reach_non_bunny(region): + return True + if self.can_lift_rocks(player) and self.world.prizes[player]['crab'][0] in [0xdc, 0xdd, 0xde]: + for region in rock_crabs: + if can_reach_non_bunny(region): + return True + + # stun prize + if self.can_stun_enemies(player) and self.world.prizes[player]['stun'] in [0xdc, 0xdd, 0xde]: + return True + + # bomb purchases + if self.can_farm_rupees(player) and (self.can_buy_unlimited('Bombs (10)', player) or self.can_reach('Big Bomb Shop', None, player)): return True return False @@ -813,6 +865,16 @@ class CollectionState(object): or self.has('Fire Rod', player) ) + def can_stun_enemies(self, player): + if self.world.difficulty_adjustments[player] == 'expert': + return False + elif self.world.difficulty_adjustments[player] == 'hard': + return self.has('Hookshot', player) + else: + return self.has('Hookshot', player) \ + or self.has('Blue Boomerang', player) \ + or self.has('Red Boomerang', player) + # In the future, this can be used to check if the player starts without bombs def can_use_bombs(self, player): return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) and self.can_farm_bombs(player) diff --git a/Fill.py b/Fill.py index de59a2b5..3e046600 100644 --- a/Fill.py +++ b/Fill.py @@ -712,3 +712,33 @@ def balance_money_progression(world): unchecked_locations.remove(location) if location.item.name.startswith('Rupee'): wallet[location.item.player] += rupee_chart[location.item.name] + +def set_prize_drops(world, player): + prizes = [0xD8, 0xD8, 0xD8, 0xD8, 0xD9, 0xD8, 0xD8, 0xD9, 0xDA, 0xD9, 0xDA, 0xDB, 0xDA, 0xD9, 0xDA, 0xDA, 0xE0, 0xDF, 0xDF, 0xDA, 0xE0, 0xDF, 0xD8, 0xDF, + 0xDC, 0xDC, 0xDC, 0xDD, 0xDC, 0xDC, 0xDE, 0xDC, 0xE1, 0xD8, 0xE1, 0xE2, 0xE1, 0xD8, 0xE1, 0xE2, 0xDF, 0xD9, 0xD8, 0xE1, 0xDF, 0xDC, 0xD9, 0xD8, + 0xD8, 0xE3, 0xE0, 0xDB, 0xDE, 0xD8, 0xDB, 0xE2, 0xD9, 0xDA, 0xDB, 0xD9, 0xDB, 0xD9, 0xDB] + + # randomize last 7 slots + new_prizes = random.sample(prizes, 7) + + if world.difficulty_adjustments[player] in ['hard', 'expert']: + prize_replacements = {0xE0: 0xDF, # Fairy -> heart + 0xE3: 0xD8} # Big magic -> small magic + new_prizes = [prize_replacements.get(prize, prize) for prize in new_prizes] + + if world.retro[player]: + prize_replacements = {0xE1: 0xDA, #5 Arrows -> Blue Rupee + 0xE2: 0xDB} #10 Arrows -> Red Rupee + new_prizes = [prize_replacements.get(prize, prize) for prize in new_prizes] + + # write tree pull prizes + world.prizes[player]['pull'] = [ new_prizes.pop(), new_prizes.pop(), new_prizes.pop() ] + + # rupee crab prizes + world.prizes[player]['crab'] = [ new_prizes.pop(), new_prizes.pop() ] + + # stunned enemy prize + world.prizes[player]['stun'] = new_prizes.pop() + + # saved fish prize + world.prizes[player]['fish'] = new_prizes.pop() \ No newline at end of file diff --git a/Main.py b/Main.py index 05090de7..715b0ace 100644 --- a/Main.py +++ b/Main.py @@ -25,7 +25,7 @@ from RoomData import create_rooms from Rules import set_rules from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items -from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations +from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations, set_prize_drops from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names @@ -195,6 +195,8 @@ def main(args, seed=None, fish=None): else: lock_shop_locations(world, player) + for player in range(1, world.players + 1): + set_prize_drops(world, player) logger.info(world.fish.translate("cli","cli","placing.dungeon.prizes")) @@ -414,6 +416,7 @@ def copy_world(world): ret.standardize_palettes = world.standardize_palettes.copy() ret.owswaps = world.owswaps.copy() ret.owflutespots = world.owflutespots.copy() + ret.prizes = world.prizes.copy() for player in range(1, world.players + 1): create_regions(ret, player) diff --git a/Rom.py b/Rom.py index da431388..aea11ce7 100644 --- a/Rom.py +++ b/Rom.py @@ -1066,9 +1066,13 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x178000 + i, random.randint(0, 255)) # shuffle prize packs - prizes = [0xD8, 0xD8, 0xD8, 0xD8, 0xD9, 0xD8, 0xD8, 0xD9, 0xDA, 0xD9, 0xDA, 0xDB, 0xDA, 0xD9, 0xDA, 0xDA, 0xE0, 0xDF, 0xDF, 0xDA, 0xE0, 0xDF, 0xD8, 0xDF, - 0xDC, 0xDC, 0xDC, 0xDD, 0xDC, 0xDC, 0xDE, 0xDC, 0xE1, 0xD8, 0xE1, 0xE2, 0xE1, 0xD8, 0xE1, 0xE2, 0xDF, 0xD9, 0xD8, 0xE1, 0xDF, 0xDC, 0xD9, 0xD8, - 0xD8, 0xE3, 0xE0, 0xDB, 0xDE, 0xD8, 0xDB, 0xE2, 0xD9, 0xDA, 0xDB, 0xD9, 0xDB, 0xD9, 0xDB] + pack_prizes = [0xD8, 0xD8, 0xD8, 0xD8, 0xD9, 0xD8, 0xD8, 0xD9, + 0xDA, 0xD9, 0xDA, 0xDB, 0xDA, 0xD9, 0xDA, 0xDA, + 0xE0, 0xDF, 0xDF, 0xDA, 0xE0, 0xDF, 0xD8, 0xDF, + 0xDC, 0xDC, 0xDC, 0xDD, 0xDC, 0xDC, 0xDE, 0xDC, + 0xE1, 0xD8, 0xE1, 0xE2, 0xE1, 0xD8, 0xE1, 0xE2, + 0xDF, 0xD9, 0xD8, 0xE1, 0xDF, 0xDC, 0xD9, 0xD8, + 0xD8, 0xE3, 0xE0, 0xDB, 0xDE, 0xD8, 0xDB, 0xE2] dig_prizes = [0xB2, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, @@ -1080,44 +1084,41 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): def chunk(l,n): return [l[i:i+n] for i in range(0, len(l), n)] - # randomize last 7 slots - prizes [-7:] = random.sample(prizes, 7) - #shuffle order of 7 main packs - packs = chunk(prizes[:56], 8) + packs = chunk(pack_prizes, 8) random.shuffle(packs) - prizes[:56] = [drop for pack in packs for drop in pack] + pack_prizes = [drop for pack in packs for drop in pack] if world.difficulty_adjustments[player] in ['hard', 'expert']: prize_replacements = {0xE0: 0xDF, # Fairy -> heart 0xE3: 0xD8} # Big magic -> small magic - prizes = [prize_replacements.get(prize, prize) for prize in prizes] + pack_prizes = [prize_replacements.get(prize, prize) for prize in pack_prizes] dig_prizes = [prize_replacements.get(prize, prize) for prize in dig_prizes] if world.retro[player]: prize_replacements = {0xE1: 0xDA, #5 Arrows -> Blue Rupee 0xE2: 0xDB} #10 Arrows -> Red Rupee - prizes = [prize_replacements.get(prize, prize) for prize in prizes] + pack_prizes = [prize_replacements.get(prize, prize) for prize in pack_prizes] dig_prizes = [prize_replacements.get(prize, prize) for prize in dig_prizes] rom.write_bytes(0x180100, dig_prizes) # write tree pull prizes - rom.write_byte(0xEFBD4, prizes.pop()) - rom.write_byte(0xEFBD5, prizes.pop()) - rom.write_byte(0xEFBD6, prizes.pop()) + rom.write_byte(0xEFBD4, world.prizes[player]['pull'][0]) + rom.write_byte(0xEFBD5, world.prizes[player]['pull'][1]) + rom.write_byte(0xEFBD6, world.prizes[player]['pull'][2]) # rupee crab prizes - rom.write_byte(0x329C8, prizes.pop()) # first prize - rom.write_byte(0x329C4, prizes.pop()) # final prize + rom.write_byte(0x329C8, world.prizes[player]['crab'][0]) # first prize + rom.write_byte(0x329C4, world.prizes[player]['crab'][1]) # final prize # stunned enemy prize - rom.write_byte(0x37993, prizes.pop()) + rom.write_byte(0x37993, world.prizes[player]['stun']) # saved fish prize - rom.write_byte(0xE82CC, prizes.pop()) + rom.write_byte(0xE82CC, world.prizes[player]['fish']) # fill enemy prize packs - rom.write_bytes(0x37A78, prizes) + rom.write_bytes(0x37A78, pack_prizes) # set bonk prizes bonk_prizes = [0x79, 0xE3, 0x79, 0xAC, 0xAC, 0xE0, 0xDC, 0xAC, 0xE3, 0xE3, 0xDA, 0xE3, 0xDA, 0xD8, 0xAC, 0xAC, 0xE3, 0xD8, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xDC, 0xDB, 0xE3, 0xDA, 0x79, 0x79, 0xE3, 0xE3, diff --git a/Tables.py b/Tables.py index 5365e69c..64464b9f 100644 --- a/Tables.py +++ b/Tables.py @@ -124,3 +124,18 @@ divisor_lookup = { # 0xf0: 0xb53, 0xf1: 0xb53, 0xf2: 0xba0, 0xf3: 0xba0, 0xf4: 0xba5, 0xf5: 0xba5, 0xf6: 0xbac, 0xf7: 0xbac, # 0xf8: 0xbac, 0xf9: 0xbba, 0xfa: 0xbc1, 0xfb: 0xbcc, 0xfc: 0xbd7, 0xfd: 0xbd7, 0xfe: 0xbba, 0xff: 0xbe3 # } + +prize_lookup = { + 0xd8: 'Small Magic Refill', + 0xd9: 'Rupee (1)', + 0xda: 'Rupees (5)', + 0xdb: 'Rupees (20)', + 0xdc: 'Bomb (1)', + 0xdd: 'Bombs (4)', + 0xde: 'Bombs (8)', + 0xdf: 'Heart', + 0xe0: 'Fairy', + 0xe1: 'Arrows (5)', + 0xe2: 'Arrows (10)', + 0xe3: 'Full Magic Refill' +} From 166b24c4b212361cd1d3dbe2b85b4d7fa6f613a2 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 03:46:57 -0500 Subject: [PATCH 23/31] Fixed mystery terminology for OW modes --- Mystery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mystery.py b/Mystery.py index fa17ece5..7b46e72b 100644 --- a/Mystery.py +++ b/Mystery.py @@ -135,8 +135,8 @@ def roll_settings(weights): ret.ow_shuffle = overworld_shuffle if overworld_shuffle != 'none' else 'vanilla' overworld_swap = get_choice('overworld_swap') ret.ow_swap = overworld_swap if overworld_swap != 'none' else 'vanilla' - ret.ow_keepsimilar = get_choice('ow_keepsimilar') - overworld_flute = get_choice('overworld_flute') + ret.ow_keepsimilar = get_choice('overworld_keepsimilar') + overworld_flute = get_choice('flute_shuffle') ret.ow_swap = overworld_flute if overworld_flute != 'none' else 'vanilla' entrance_shuffle = get_choice('entrance_shuffle') ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' From 25667b6c014ccba0635f66307d7bed868a76a9c3 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 03:51:51 -0500 Subject: [PATCH 24/31] Fixed mystery terminology for OW modes --- mystery_example.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mystery_example.yml b/mystery_example.yml index bf0987c6..b6b6f051 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -1,16 +1,16 @@ description: Example door rando weights - ow_shuffle: + overworld_shuffle: vanilla: 0 parallel: 2 full: 2 - ow_keepsimilar: + overworld_keepsimilar: on: 1 off: 1 - ow_swap: + overworld_swap: vanilla: 0 mixed: 2 crossed: 2 - ow_fluteshuffle: + flute_shuffle: vanilla: 0 balanced: 1 random: 1 From 64fd35f7fcfa5d4c2940c09b7f9b0810f94d5843 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 03:52:19 -0500 Subject: [PATCH 25/31] Version bump 0.1.7.1 --- CHANGELOG.md | 4 ++++ OverworldShuffle.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19498a68..d3c0de79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 0.1.7.1 +- Improved bomb logic to consider tree pulls, bush crabs, and stun prize +- Fixed Mystery to use new updated OW mode terminology + ### 0.1.7.0 - Expanded new DR bomb logic to all modes (bomb usage in logic only if there is an unlimited supply of bombs available) - ~~Merged DR v0.5.0.1 - Bomblogic mode / Enemizer fixes~~ diff --git a/OverworldShuffle.py b/OverworldShuffle.py index d1ddfb65..65c3effb 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -2,7 +2,7 @@ import RaceRandom as random, logging, copy from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel -__version__ = '0.1.7.0-u' +__version__ = '0.1.7.1-u' def link_overworld(world, player): # setup mandatory connections From 730b97b37f070f79829e13f47cb1b845c4138e60 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 06:51:18 -0500 Subject: [PATCH 26/31] Fixed Flute Shuffle overwriting OW Swap in Mystery --- Mystery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mystery.py b/Mystery.py index 7b46e72b..8302398e 100644 --- a/Mystery.py +++ b/Mystery.py @@ -137,7 +137,7 @@ def roll_settings(weights): ret.ow_swap = overworld_swap if overworld_swap != 'none' else 'vanilla' ret.ow_keepsimilar = get_choice('overworld_keepsimilar') overworld_flute = get_choice('flute_shuffle') - ret.ow_swap = overworld_flute if overworld_flute != 'none' else 'vanilla' + ret.ow_fluteshuffle = overworld_flute if overworld_flute != 'none' else 'vanilla' entrance_shuffle = get_choice('entrance_shuffle') ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' door_shuffle = get_choice('door_shuffle') From b6f913596b97cf5529e006886190f47b6ef1576a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Jul 2021 07:10:46 -0500 Subject: [PATCH 27/31] Fixed Mystery to not spoil OW Shuffle in filename --- Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 715b0ace..007595de 100644 --- a/Main.py +++ b/Main.py @@ -261,7 +261,7 @@ def main(args, seed=None, fish=None): customize_shops(world, player) balance_money_progression(world) - if world.owShuffle[1] != 'vanilla' or world.owSwap[1] != 'vanilla': + if world.owShuffle[1] != 'vanilla' or world.owSwap[1] != 'vanilla' or world.seed.startsWith('M'): outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' else: outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' From 6332b48c3a95822bd433f524112fc8f0c7951d9f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 1 Aug 2021 23:49:26 -0500 Subject: [PATCH 28/31] Removed convenient portal on DM for OW Layout Shuffle --- Rom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index aea11ce7..fba877cd 100644 --- a/Rom.py +++ b/Rom.py @@ -639,12 +639,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x18004C, 0x01) # patch for allowing Frogsmith to enter multi-entrance caves # patches map data specific for OW Shuffle - inverted_buffer[0x03] = inverted_buffer[0x03] | 0x2 # convenient portal on WDM + #inverted_buffer[0x03] = inverted_buffer[0x03] | 0x2 # convenient portal on WDM inverted_buffer[0x1A] = inverted_buffer[0x1A] | 0x2 # rocks added to prevent OWG hardlock inverted_buffer[0x1B] = inverted_buffer[0x1B] | 0x2 # rocks added to prevent OWG hardlock inverted_buffer[0x22] = inverted_buffer[0x22] | 0x2 # rocks added to prevent OWG hardlock inverted_buffer[0x3F] = inverted_buffer[0x3F] | 0x2 # added C to terrain - inverted_buffer[0x43] = inverted_buffer[0x43] | 0x2 # convenient portal on WDDM + #inverted_buffer[0x43] = inverted_buffer[0x43] | 0x2 # convenient portal on WDDM inverted_buffer[0x5A] = inverted_buffer[0x5A] | 0x2 # rocks added to prevent OWG hardlock inverted_buffer[0x5B] = inverted_buffer[0x5B] | 0x2 # rocks added to prevent OWG hardlock inverted_buffer[0x62] = inverted_buffer[0x62] | 0x2 # rocks added to prevent OWG hardlock From bb5830686e23e5555e34d4cb9a7c6ef4a7d5c604 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 2 Aug 2021 04:20:49 -0500 Subject: [PATCH 29/31] Fixed music algorithm in OW Shuffle --- Rom.py | 2 +- data/base2current.bps | Bin 141216 -> 141129 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index fba877cd..cab4cc48 100644 --- a/Rom.py +++ b/Rom.py @@ -31,7 +31,7 @@ from OverworldShuffle import default_flute_connections, flute_data JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '5ed6e672720482d3448a25b07f5fa92b' +RANDOMIZERBASEHASH = 'b71ccf874145fd21bf215b4b553e26ad' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index abfc0e3ed532415a6fbcab61313e63491533453e..290c305750aca233d584940f68f1a989a6cbb82e 100644 GIT binary patch delta 7866 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 A>i_@% From 3f9edbc599733c80b82c9a4e61485cc53b5d5b7b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 2 Aug 2021 04:23:16 -0500 Subject: [PATCH 30/31] Version bump 0.1.7.2 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3c0de79..94736e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### 0.1.7.2 +- Fixed music algorithm to play correct track in OW Shuffle +- Removed convenient portal on WDM in OW Layout Shuffle +- Fixed Mystery to not spoil OW Shuffle in filename + ### 0.1.7.1 - Improved bomb logic to consider tree pulls, bush crabs, and stun prize - Fixed Mystery to use new updated OW mode terminology diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 65c3effb..612a5f7e 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -2,7 +2,7 @@ import RaceRandom as random, logging, copy from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel -__version__ = '0.1.7.1-u' +__version__ = '0.1.7.2-u' def link_overworld(world, player): # setup mandatory connections From 935b257ad92ce8f2c102f098c210422ad9666207 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 2 Aug 2021 20:33:19 -0500 Subject: [PATCH 31/31] Minor formatting --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f466faf..2d8221f3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ See https://alttpr.com/ for more details on the normal randomizer. ### Trackers & Guides -This is a very new mode of LTTPR so the tools and info is very limited. - There is an [OW Rando Cheat Sheet](https://zelda.codemann8.com/images/shared/ow-rando-reference-sheet.png) that shows all the transitions that exist and are candidates for shuffle. +This is a very new mode of LTTPR so the tools and info is very limited. +- There is an [OW Rando Cheat Sheet](https://zelda.codemann8.com/images/shared/ow-rando-reference-sheet.png) that shows all the transitions that exist and are candidates for shuffle. - There is OW tracking capability within the following trackers: - CodeTracker, an [EmoTracker](https://emotracker.net) package for LTTPR - [Community Tracker](https://alttptracker.dunka.net/)