From b2f2565271b0be0f064a7b792674e0c2a2c78fda Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 16 Dec 2021 16:02:11 -0700 Subject: [PATCH] Standing Items initial commit --- BaseClasses.py | 34 +- CLI.py | 2 +- DoorShuffle.py | 6 +- EntranceShuffle.py | 18 +- Fill.py | 37 +- InvertedRegions.py | 28 +- ItemList.py | 31 +- Items.py | 4 + Main.py | 2 +- Mystery.py | 2 +- PotShuffle.py | 325 +++++++++++++----- Regions.py | 109 +++--- Rom.py | 140 ++++---- Rules.py | 55 ++- TestSuite.py | 2 +- Utils.py | 49 ++- asm/doorrando.asm | 3 - asm/keydropshuffle.asm | 181 ---------- data/base2current.bps | Bin 136415 -> 136279 bytes mystery_example.yml | 5 +- resources/app/cli/args.json | 7 +- resources/app/cli/lang/en.json | 6 +- resources/app/gui/lang/en.json | 5 +- .../app/gui/randomize/dungeon/keysanity.json | 3 +- .../app/gui/randomize/dungeon/widgets.json | 9 + source/item/FillUtil.py | 24 +- 26 files changed, 618 insertions(+), 469 deletions(-) delete mode 100644 asm/keydropshuffle.asm diff --git a/BaseClasses.py b/BaseClasses.py index b79af29d..df4b8426 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -139,7 +139,7 @@ class World(object): set_player_attr('pseudoboots', False) set_player_attr('shopsanity', False) - set_player_attr('keydropshuffle', False) + set_player_attr('keydropshuffle', 'none') set_player_attr('mixed_travel', 'prevent') set_player_attr('standardize_palettes', 'standardize') set_player_attr('force_fix', {'gt': False, 'sw': False, 'pod': False, 'tr': False}) @@ -2119,6 +2119,7 @@ class Location(object): self.item_rule = lambda item: True self.player = player self.skip = False + self.type = LocationType.Normal if not crystal else LocationType.Prize def can_fill(self, state, item, check_access=True): return self.always_allow(state, item) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state))) @@ -2158,6 +2159,15 @@ class Location(object): return hash((self.name, self.player)) +class LocationType(FastEnum): + Normal = 0 + Prize = 1 + Logical = 2 + Shop = 3 + Pot = 4 + Drop = 5 + + class Item(object): def __init__(self, name='', advancement=False, priority=False, type=None, code=None, price=999, pedestal_hint=None, @@ -2519,6 +2529,7 @@ class Spoiler(object): outfile.write(f"Link's House Shuffled: {yn(self.metadata['shufflelinks'])}\n") outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle'][player]) outfile.write('Intensity: %s\n' % self.metadata['intensity'][player]) + outfile.write(f"Drop Shuffle Mode: {self.metadata['keydropshuffle'][player]}\n") addition = ' (Random)' if self.world.crystals_gt_orig[player] == 'random' else '' outfile.write('Crystals required for GT: %s\n' % (str(self.metadata['gt_crystals'][player]) + addition)) addition = ' (Random)' if self.world.crystals_ganon_orig[player] == 'random' else '' @@ -2537,7 +2548,6 @@ class Spoiler(object): outfile.write(f"Pot shuffle: {yn(self.metadata['potshuffle'][player])}\n") outfile.write(f"Hints: {yn(self.metadata['hints'][player])}\n") outfile.write(f"Experimental: {yn(self.metadata['experimental'][player])}\n") - outfile.write(f"Key Drops shuffled: {yn(self.metadata['keydropshuffle'][player])}\n") outfile.write(f"Shopsanity: {yn(self.metadata['shopsanity'][player])}\n") outfile.write(f"Bombbag: {yn(self.metadata['bombbag'][player])}\n") outfile.write(f"Pseudoboots: {yn(self.metadata['pseudoboots'][player])}\n") @@ -2681,6 +2691,8 @@ class PotFlags(FastEnum): Normal = 0x0 NoSwitch = 0x1 # A switch should never go here SwitchLogicChange = 0x2 # A switch can go here, but requires a logic change + Block = 0x4 # This is actually a block + LowerRegion = 0x8 # This is a pot in the lower region class Pot(object): @@ -2690,6 +2702,23 @@ class Pot(object): self.item = item self.room = room self.flags = flags + self.indicator = None # 0x80 for standing item, 0xC0 multiworld item + self.standing_item_code = None # standing item code if nay + + def copy(self): + return Pot(self.x, self.y, self.item, self.room, self.flags) + + def empty(self): + return self.item == PotItem.Nothing and self.indicator is None + + def pot_data(self): + high_byte = self.y + if self.flags & PotFlags.LowerRegion: + high_byte |= 0x20 + if self.indicator: + high_byte |= self.indicator + item = self.item if not self.indicator else self.standing_item_code + return [self.x, high_byte, item] # byte 0: DDDE EEEE (DR, ER) @@ -2708,6 +2737,7 @@ diff_mode = {"normal": 0, "hard": 1, "expert": 2} func_mode = {"normal": 0, "hard": 1, "expert": 2} # byte 3: SKMM PIII (shop, keydrop, mixed, palettes, intensity) +# todo keydrop is not longer a switch mixed_travel_mode = {"prevent": 0, "allow": 1, "force": 2} # intensity is 3 bits (reserves 4-7 levels) diff --git a/CLI.py b/CLI.py index 636c0450..5c9d90db 100644 --- a/CLI.py +++ b/CLI.py @@ -158,7 +158,7 @@ def parse_settings(): "enemizercli": os.path.join(".", "EnemizerCLI", "EnemizerCLI.Core"), "shopsanity": False, - "keydropshuffle": False, + "keydropshuffle": 'none', "mapshuffle": False, "compassshuffle": False, "keyshuffle": False, diff --git a/DoorShuffle.py b/DoorShuffle.py index bd828756..8417a4f3 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -378,7 +378,7 @@ def choose_portals(world, player): if world.doorShuffle[player] in ['basic', 'crossed']: cross_flag = world.doorShuffle[player] == 'crossed' # key drops allow the big key in the right place in Desert Tiles 2 - bk_shuffle = world.bigkeyshuffle[player] or world.keydropshuffle[player] + bk_shuffle = world.bigkeyshuffle[player] or world.keydropshuffle[player] != 'none' std_flag = world.mode[player] == 'standard' # roast incognito doors world.get_room(0x60, player).delete(5) @@ -994,7 +994,7 @@ def cross_dungeon(world, player): assign_cross_keys(dungeon_builders, world, player) all_dungeon_items_cnt = len(list(y for x in world.dungeons if x.player == player for y in x.all_items)) - if world.keydropshuffle[player]: + if world.keydropshuffle[player] != 'none': target_items = 35 if world.retro[player] else 96 else: target_items = 34 if world.retro[player] else 63 @@ -1055,7 +1055,7 @@ def assign_cross_keys(dungeon_builders, world, player): logging.getLogger('').info(world.fish.translate("cli", "cli", "shuffling.keydoors")) start = time.process_time() if world.retro[player]: - remaining = 61 if world.keydropshuffle[player] else 29 + remaining = 61 if world.keydropshuffle[player] != 'none' else 29 else: remaining = len(list(x for dgn in world.dungeons if dgn.player == player for x in dgn.small_keys)) total_keys = remaining diff --git a/EntranceShuffle.py b/EntranceShuffle.py index d3e2ac44..1eec2b9a 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -3060,12 +3060,14 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Kings Grave Inner Rocks', 'Light World'), ('Kings Grave Mirror Spot', 'Kings Grave Area'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), + ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), ('Hobo Bridge', 'Hobo Bridge'), ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), ('Bat Cave Door', 'Bat Cave (left)'), ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), + ('Blinds Hideout N', 'Blinds Hideout (Top)'), ('Desert Palace Stairs', 'Desert Palace Stairs'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), @@ -3078,6 +3080,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Death Mountain Entrance Drop', 'Light World'), ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), + ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), + ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), ('Death Mountain Return Ledge Drop', 'Light World'), ('Old Man Cave Dropdown', 'Old Man Cave'), ('Old Man House Front to Back', 'Old Man House Back'), @@ -3136,6 +3140,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), + ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), ('Paradox Cave Bomb Jump', 'Paradox Cave'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), @@ -3185,12 +3190,14 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), + ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), ('Hobo Bridge', 'Hobo Bridge'), ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), ('Bat Cave Door', 'Bat Cave (left)'), ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), + ('Blinds Hideout N', 'Blinds Hideout (Top)'), ('Desert Palace Stairs', 'Desert Palace Stairs'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), @@ -3198,6 +3205,8 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Sewer Drop', 'Sewers Rat Path'), ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), ('Death Mountain Entrance Drop', 'Light World'), + ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), + ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Death Mountain Return Ledge Drop', 'Light World'), @@ -3241,6 +3250,7 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Skull Woods Forest', 'Skull Woods Forest'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), + ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), ('Paradox Cave Bomb Jump', 'Paradox Cave'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), @@ -3417,8 +3427,8 @@ default_connections = [('Links House', 'Links House'), ('Old Man House Exit (Bottom)', 'Death Mountain'), ('Old Man House (Top)', 'Old Man House Back'), ('Old Man House Exit (Top)', 'Death Mountain'), - ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'), - ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave'), + ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), + ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave (left)'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Ledge'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), ('Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Peak)'), @@ -3622,7 +3632,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Inverted Dark Sanctuary', 'Inverted Dark Sanctuary'), ('Inverted Dark Sanctuary Exit', 'West Dark World'), ('Old Man Cave (West)', 'Bumper Cave'), - ('Old Man Cave (East)', 'Death Mountain Return Cave'), + ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), ('Old Man Cave Exit (West)', 'West Dark World'), ('Old Man Cave Exit (East)', 'Dark Death Mountain'), ('Dark Death Mountain Fairy', 'Old Man Cave'), @@ -3631,7 +3641,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), ('Bumper Cave Exit (Bottom)', 'Light World'), ('Death Mountain Return Cave (West)', 'Bumper Cave'), - ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'), + ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), ('Hookshot Cave Front Exit', 'Dark Death Mountain'), diff --git a/Fill.py b/Fill.py index fe60d341..5d214af2 100644 --- a/Fill.py +++ b/Fill.py @@ -3,7 +3,7 @@ import collections import itertools import logging -from BaseClasses import CollectionState, FillError +from BaseClasses import CollectionState, FillError, LocationType from Items import ItemFactory from Regions import shop_to_location_table, retro_shops from source.item.FillUtil import filter_locations, classify_major_items, replace_trash_item, vanilla_fallback @@ -350,6 +350,24 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None # get items to distribute classify_major_items(world) + # handle pot shuffle + pots_used = False + pot_item_pool = collections.defaultdict(list) + for item in world.itempool: + if item.name in ['Chicken', 'Big Magic']: # can only fill these in that players world + pot_item_pool[item.player].append(item) + for player, pot_pool in pot_item_pool.items(): + if pot_pool: + for pot_item in pot_pool: + world.itempool.remove(pot_item) + pot_locations = [location for location in fill_locations + if location.type == LocationType.Pot and location.player == player] + fast_fill_helper(world, pot_pool, pot_locations) + pots_used = True + if pots_used: + fill_locations = world.get_unfilled_locations() + random.shuffle(fill_locations) + random.shuffle(world.itempool) progitempool = [item for item in world.itempool if item.advancement] prioitempool = [item for item in world.itempool if not item.advancement and item.priority] @@ -425,6 +443,23 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None if unplaced or unfilled: logging.warning('Unplaced items: %s - Unfilled Locations: %s', unplaced, unfilled) + # convert Arrows 5 and Nothing when necessary + invalid_locations = [loc for loc in world.get_locations() if loc.item.name in {'Arrows (5)', 'Nothing'} and + (loc.type != LocationType.Pot or loc.item.player != loc.player)] + for i_loc in invalid_locations: + i_loc.item = ItemFactory(invalid_location_replacement[i_loc.item.name], i_loc.item.player) + + +invalid_location_replacement = {'Arrows (5)': 'Arrows (10)', 'Nothing': 'Rupees (5)'} + + +def fast_fill_helper(world, item_pool, fill_locations): + if world.algorithm == 'vanilla_fill': + fast_vanilla_fill(world, item_pool, fill_locations) + else: + fast_fill(world, item_pool, fill_locations) + # todo: other fast fill methods? + def fast_fill(world, item_pool, fill_locations): while item_pool and fill_locations: diff --git a/InvertedRegions.py b/InvertedRegions.py index 589f6f87..e66b0962 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -25,11 +25,10 @@ def create_inverted_regions(world, player): create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Secret Passage Inner Bushes']), create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Mirror Spot']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', ["Blind\'s Hideout - Top", - "Blind\'s Hideout - Left", - "Blind\'s Hideout - Right", - "Blind\'s Hideout - Far Left", - "Blind\'s Hideout - Far Right"]), + create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', + ["Blind's Hideout - Left", "Blind's Hideout - Right", "Blind's Hideout - Far Left", + "Blind's Hideout - Far Right"], ['Blinds Hideout N']), + create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), create_lw_region(player, 'Northeast Light World', None, ['Zoras River', 'Waterfall of Wishing Cave', 'Potion Shop Outer Rock', 'Catfish Mirror Spot', 'Northeast Light World Warp']), create_lw_region(player, 'Waterfall of Wishing Cave', None, ['Waterfall of Wishing', 'Northeast Light World Return']), create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Potion Shop Inner Bushes', 'Potion Shop Inner Rock', 'Potion Shop Mirror Spot', 'Potion Shop River Drop']), @@ -68,8 +67,11 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop\'s exit', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle', - 'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']), + create_cave_region(player, 'Kakariko Well (top)', 'a drop\'s exit', + ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', + 'Kakariko Well - Bottom'], + ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), + create_cave_region(player, 'Kakariko Well (back)', 'a drop\'s exit', ['Kakariko Well - Top']), create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), create_lw_region(player, 'Bat Cave Drop Ledge', None, ['Bat Cave Drop']), @@ -114,8 +116,8 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), create_lw_region(player, 'Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Mirror Spot']), - create_cave_region(player, 'Death Mountain Return Cave', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Bumper Cave Ledge Mirror Spot']), + create_cave_region(player, 'Death Mountain Return Cave (left)', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave E']), + create_cave_region(player, 'Death Mountain Return Cave (right)', 'a connector', None, ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']), create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), @@ -127,10 +129,10 @@ def create_inverted_regions(world, player): 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', - 'Paradox Cave Lower - Middle', - 'Paradox Cave Upper - Left', - 'Paradox Cave Upper - Right'], - ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']), + 'Paradox Cave Lower - Middle'], + ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), + create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', + 'Paradox Cave Upper - Right']), create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), create_lw_region(player, 'East Death Mountain (Top)', ['Floating Island'], ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access', diff --git a/ItemList.py b/ItemList.py index 2806af8a..a3096468 100644 --- a/ItemList.py +++ b/ItemList.py @@ -3,10 +3,11 @@ import logging import math import RaceRandom as random -from BaseClasses import Region, RegionType, Shop, ShopType, Location, CollectionState +from BaseClasses import Region, RegionType, Shop, ShopType, Location, CollectionState, PotItem from EntranceShuffle import connect_entrance from Regions import shop_to_location_table, retro_shops, shop_table_by_location from Fill import FillError, fill_restrictive, fast_fill, get_dungeon_item_pool +from PotShuffle import vanilla_pots from Items import ItemFactory from source.item.FillUtil import trash_items @@ -388,11 +389,14 @@ def generate_itempool(world, player): if world.retro[player]: set_up_take_anys(world, player) - if world.keydropshuffle[player]: + if world.keydropshuffle[player] != 'none': world.itempool += [ItemFactory('Small Key (Universal)', player)] * 32 create_dynamic_shop_locations(world, player) + if world.keydropshuffle[player] == 'potsanity': + add_pot_contents(world, player) + take_any_locations = [ 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut', @@ -748,6 +752,28 @@ rupee_chart = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)' 'Rupees (100)': 100, 'Rupees (300)': 300} +pot_items = { + PotItem.Nothing: 'Nothing', + PotItem.Bomb: 'Single Bomb', + PotItem.FiveArrows: 'Arrows (5)', # convert to 10 + PotItem.OneRupee: 'Rupee (1)', + PotItem.FiveRupees: 'Rupees (5)', + PotItem.Heart: 'Small Heart', + PotItem.BigMagic: 'Big Magic', # fast fill + PotItem.SmallMagic: 'Small Magic', + PotItem.Chicken: 'Chicken' # fast fill +} + +valid_pot_items = {y: x for x, y in pot_items.items()} + + +def add_pot_contents(world, player): + for super_tile, pot_list in vanilla_pots.items(): + for pot in pot_list: + if pot.item not in [PotItem.Hole, PotItem.Key, PotItem.Switch]: + world.itempool.append(ItemFactory(pot_items[pot.item], player)) + + def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bombbag, door_shuffle, logic): pool = [] placed_items = {} @@ -894,6 +920,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, bombbag, customitemarray): if isinstance(customitemarray,dict) and 1 in customitemarray: customitemarray = customitemarray[1] diff --git a/Items.py b/Items.py index ba85e51f..ebbd3803 100644 --- a/Items.py +++ b/Items.py @@ -79,6 +79,10 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Arrow Upgrade (+10)': (False, False, None, 0x54, 100, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Arrow Upgrade (+5)': (False, False, None, 0x53, 100, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), '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'), + 'Arrows (5)': (False, False, None, 0x5A, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'), + 'Small Magic': (False, False, None, 0x45, 5, 'A bit of magic', 'and the bit of magic', 'bit-o-magic kid', 'magic bit for sale', 'fungus for magic', 'magic boy conjures again', 'a bit of magic'), + 'Big Magic': (False, False, None, 0x5A, 40, 'A lot of magic', 'and lots of magic', 'lot-o-magic kid', 'magic refill for sale', 'fungus for magic', 'magic boy conjures again', 'a magic refill'), + 'Chicken': (False, False, None, 0x5A, 999, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'), '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'), diff --git a/Main.py b/Main.py index 8406ef4d..04d7cf4f 100644 --- a/Main.py +++ b/Main.py @@ -157,7 +157,7 @@ def main(args, seed=None, fish=None): if any(world.potshuffle.values()): logger.info(world.fish.translate("cli", "cli", "shuffling.pots")) for player in range(1, world.players + 1): - if world.potshuffle[player]: + if world.potshuffle[player] and world.keydropshuffle[player] != 'potsanity': shuffle_pots(world, player) logger.info(world.fish.translate("cli","cli","shuffling.world")) diff --git a/Mystery.py b/Mystery.py index e5074a57..7b509cb9 100644 --- a/Mystery.py +++ b/Mystery.py @@ -173,7 +173,7 @@ def roll_settings(weights): ret.shufflelinks = get_choice('shufflelinks') == 'on' ret.pseudoboots = get_choice('pseudoboots') == 'on' ret.shopsanity = get_choice('shopsanity') == 'on' - ret.keydropshuffle = get_choice('keydropshuffle') == 'on' + ret.keydropshuffle = get_choice('keydropshuffle') ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent' ret.standardize_palettes = get_choice('standardize_palettes') if 'standardize_palettes' in weights else 'standardize' diff --git a/PotShuffle.py b/PotShuffle.py index a0c048bf..eb0a481d 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -1,7 +1,7 @@ from collections import defaultdict from BaseClasses import PotItem, Pot, PotFlags, CrystalBarrier -from Regions import key_drop_data +from Utils import int16_as_bytes, pc_to_snes movable_switch_rooms = defaultdict(lambda: [], {'PoD Stalfos Basement': ['PoD Basement Ledge'], @@ -18,18 +18,24 @@ invalid_key_rooms = { } vanilla_pots = { - 2: [Pot(80, 6, PotItem.Nothing, 'Sewers Yet More Rats'), Pot(80, 8, PotItem.Nothing, 'Sewers Yet More Rats'), Pot(44, 8, PotItem.Nothing, 'Sewers Yet More Rats'), Pot(44, 10, PotItem.Nothing, 'Sewers Yet More Rats')], + 2: [Pot(80, 6, PotItem.Nothing, 'Sewers Yet More Rats', PotFlags.LowerRegion), + Pot(80, 8, PotItem.Nothing, 'Sewers Yet More Rats', PotFlags.LowerRegion), + Pot(44, 8, PotItem.Nothing, 'Sewers Yet More Rats', PotFlags.LowerRegion), + Pot(44, 10, PotItem.Nothing, 'Sewers Yet More Rats', PotFlags.LowerRegion)], 4: [Pot(162, 25, PotItem.Nothing, 'TR Dash Room'), Pot(152, 25, PotItem.Nothing, 'TR Dash Room'), Pot(152, 22, PotItem.Nothing, 'TR Dash Room'), Pot(162, 22, PotItem.Nothing, 'TR Dash Room'), Pot(204, 19, PotItem.Bomb, 'TR Tongue Pull'), Pot(240, 19, PotItem.Bomb, 'TR Tongue Pull')], 9: [Pot(12, 4, PotItem.OneRupee, 'PoD Shooter Room'), Pot(48, 4, PotItem.Heart, 'PoD Shooter Room'), Pot(12, 12, PotItem.Switch, 'PoD Shooter Room')], - 10: [Pot(96, 8, PotItem.Heart, 'PoD Stalfos Basement'), Pot(104, 8, PotItem.Heart, 'PoD Stalfos Basement'), Pot(204, 11, PotItem.Switch, 'PoD Stalfos Basement'), Pot(100, 9, PotItem.Nothing, 'PoD Stalfos Basement'), - Pot(156, 17, PotItem.Bomb, 'PoD Basement Ledge', PotFlags.SwitchLogicChange), Pot(160, 17, PotItem.FiveArrows, 'PoD Basement Ledge', PotFlags.SwitchLogicChange)], - 11: [Pot(202, 3, PotItem.Bomb, 'PoD Dark Pegs Left'), Pot(202, 12, PotItem.Bomb, 'PoD Dark Pegs Left')], - 17: [Pot(152, 19, PotItem.Nothing, 'Sewers Secret Room'), Pot(152, 15, PotItem.Nothing, 'Sewers Secret Room'), Pot(144, 15, PotItem.Heart, 'Sewers Secret Room'), Pot(160, 15, PotItem.Heart, 'Sewers Secret Room'), + 0xa: [Pot(96, 8, PotItem.Heart, 'PoD Stalfos Basement'), Pot(104, 8, PotItem.Heart, 'PoD Stalfos Basement'), + Pot(204, 11, PotItem.Switch, 'PoD Stalfos Basement'), Pot(100, 9, PotItem.Nothing, 'PoD Stalfos Basement'), + Pot(100, 7, PotItem.Nothing, 'PoD Stalfos Basement'), + Pot(156, 17, PotItem.Bomb, 'PoD Basement Ledge', PotFlags.SwitchLogicChange), + Pot(160, 17, PotItem.FiveArrows, 'PoD Basement Ledge', PotFlags.SwitchLogicChange)], + 0xb: [Pot(202, 3, PotItem.Bomb, 'PoD Dark Pegs Left'), Pot(202, 12, PotItem.Bomb, 'PoD Dark Pegs Left')], + 0x11: [Pot(152, 19, PotItem.Nothing, 'Sewers Secret Room'), Pot(152, 15, PotItem.Nothing, 'Sewers Secret Room'), Pot(144, 15, PotItem.Heart, 'Sewers Secret Room'), Pot(160, 15, PotItem.Heart, 'Sewers Secret Room'), Pot(144, 19, PotItem.Heart, 'Sewers Secret Room'), Pot(160, 19, PotItem.Heart, 'Sewers Secret Room')], - 21: [Pot(96, 4, PotItem.Bomb, 'TR Pipe Pit'), Pot(100, 4, PotItem.SmallMagic, 'TR Pipe Pit'), Pot(104, 4, PotItem.Heart, 'TR Pipe Pit'), Pot(108, 4, PotItem.SmallMagic, 'TR Pipe Pit'), Pot(112, 4, PotItem.FiveArrows, 'TR Pipe Pit'), + 0x15: [Pot(96, 4, PotItem.Bomb, 'TR Pipe Pit'), Pot(100, 4, PotItem.SmallMagic, 'TR Pipe Pit'), Pot(104, 4, PotItem.Heart, 'TR Pipe Pit'), Pot(108, 4, PotItem.SmallMagic, 'TR Pipe Pit'), Pot(112, 4, PotItem.FiveArrows, 'TR Pipe Pit'), Pot(12, 6, PotItem.OneRupee, 'TR Pipe Pit'), Pot(16, 6, PotItem.FiveArrows, 'TR Pipe Pit'), Pot(20, 6, PotItem.FiveRupees, 'TR Pipe Pit'), Pot(70, 11, PotItem.BigMagic, 'TR Pipe Ledge')], - 22: [Pot(188, 3, PotItem.Heart, 'Swamp I'), Pot(192, 3, PotItem.Heart, 'Swamp I'), Pot(188, 4, PotItem.SmallMagic, 'Swamp I'), Pot(192, 4, PotItem.SmallMagic, 'Swamp I'), Pot(188, 5, PotItem.FiveArrows, 'Swamp I'), + 0x16: [Pot(188, 3, PotItem.Heart, 'Swamp I'), Pot(192, 3, PotItem.Heart, 'Swamp I'), Pot(188, 4, PotItem.SmallMagic, 'Swamp I'), Pot(192, 4, PotItem.SmallMagic, 'Swamp I'), Pot(188, 5, PotItem.FiveArrows, 'Swamp I'), Pot(192, 5, PotItem.FiveArrows, 'Swamp I'), Pot(188, 6, PotItem.Bomb, 'Swamp I'), Pot(192, 6, PotItem.Bomb, 'Swamp I'), Pot(240, 19, PotItem.Key, 'Swamp Waterway')], 23: [Pot(100, 13, PotItem.Heart, 'Hera 5F'), Pot(100, 14, PotItem.Heart, 'Hera 5F'), Pot(100, 15, PotItem.Heart, 'Hera 5F'), Pot(100, 16, PotItem.Heart, 'Hera 5F'), Pot(100, 17, PotItem.Heart, 'Hera 5F'), Pot(100, 18, PotItem.Heart, 'Hera 5F'), Pot(104, 13, PotItem.Heart, 'Hera 5F'), Pot(104, 14, PotItem.Heart, 'Hera 5F'), Pot(104, 15, PotItem.Heart, 'Hera 5F'), Pot(104, 16, PotItem.Heart, 'Hera 5F'), Pot(104, 17, PotItem.Heart, 'Hera 5F'), Pot(104, 18, PotItem.Heart, 'Hera 5F')], @@ -52,32 +58,39 @@ vanilla_pots = { 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 (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)')], + 0x2F: [Pot(28, 7, PotItem.Heart, 'Kakariko Well (back)'), Pot(32, 7, PotItem.Heart, 'Kakariko Well (back)'), + Pot(28, 9, PotItem.FiveRupees, 'Kakariko Well (back)'), Pot(32, 9, PotItem.FiveRupees, 'Kakariko Well (back)'), + 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')], 50: [Pot(28, 13, PotItem.SmallMagic, 'Sewers Dark Cross')], 52: [Pot(78, 8, PotItem.FiveRupees, 'Swamp Barrier Ledge'), Pot(92, 8, PotItem.FiveRupees, 'Swamp Barrier Ledge')], - 53: [Pot(60, 6, PotItem.Key, 'Swamp Trench 2 Alcove'), Pot(20, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(24, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(28, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), - Pot(32, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(36, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(48, 20, PotItem.Heart, 'Swamp Trench 2 Departure'), Pot(76, 23, PotItem.Nothing, 'Swamp Trench 2 Pots'), - Pot(88, 23, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(100, 27, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(242, 28, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(240, 22, PotItem.Heart, 'Swamp Trench 2 Pots'), - Pot(76, 28, PotItem.Heart, 'Swamp Trench 2 Pots')], - 54: [Pot(108, 4, PotItem.Bomb, 'Swamp Hub Dead Ledge'), Pot(112, 4, PotItem.FiveRupees, 'Swamp Hub Dead Ledge'), Pot(10, 16, PotItem.Heart, 'Swamp Hub'), Pot(154, 15, PotItem.Nothing, 'Swamp Hub'), Pot(114, 16, PotItem.Key, 'Swamp Hub'), - Pot(222, 15, PotItem.Nothing, 'Swamp Hub'), Pot(188, 5, PotItem.Nothing, 'Swamp Hub North Ledge'), Pot(192, 5, PotItem.Nothing, 'Swamp Hub North Ledge')], - 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')], + 0x35: [Pot(60, 6, PotItem.Key, 'Swamp Trench 2 Alcove'), Pot(20, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(24, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(28, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), + Pot(32, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(36, 8, PotItem.FiveRupees, 'Swamp Big Key Ledge'), Pot(48, 20, PotItem.Heart, 'Swamp Trench 2 Departure'), Pot(76, 23, PotItem.Nothing, 'Swamp Trench 2 Pots'), + Pot(88, 23, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(100, 27, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(242, 28, PotItem.Nothing, 'Swamp Trench 2 Pots'), Pot(240, 22, PotItem.Heart, 'Swamp Trench 2 Pots'), + Pot(76, 28, PotItem.Heart, 'Swamp Trench 2 Pots')], + 0x36: [Pot(108, 4, PotItem.Bomb, 'Swamp Hub Dead Ledge'), Pot(112, 4, PotItem.FiveRupees, 'Swamp Hub Dead Ledge'), Pot(10, 16, PotItem.Heart, 'Swamp Hub'), Pot(154, 15, PotItem.Nothing, 'Swamp Hub'), Pot(114, 16, PotItem.Key, 'Swamp Hub'), + Pot(222, 15, PotItem.Nothing, 'Swamp Hub'), Pot(188, 5, PotItem.Nothing, 'Swamp Hub North Ledge'), Pot(192, 5, PotItem.Nothing, 'Swamp Hub North Ledge')], + 0x37: [Pot(60, 6, PotItem.Key, 'Swamp Trench 1 Alcove'), Pot(48, 20, PotItem.Nothing, 'Swamp Trench 1 Key Ledge')], + 0x38: [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 (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')], - 63: [Pot(12, 25, PotItem.OneRupee, 'Ice Hammer Block'), Pot(20, 25, PotItem.OneRupee, 'Ice Hammer Block'), Pot(12, 26, PotItem.Bomb, 'Ice Hammer Block'), Pot(20, 26, PotItem.Bomb, 'Ice Hammer Block'), - Pot(12, 27, PotItem.Switch, 'Ice Hammer Block'), Pot(20, 27, PotItem.Heart, 'Ice Hammer Block'), Pot(28, 23, PotItem.Key, 'Ice Hammer Block')], - 65: [Pot(100, 10, PotItem.Heart, 'Sewers Behind Tapestry'), Pot(52, 15, PotItem.OneRupee, 'Sewers Behind Tapestry'), Pot(52, 16, PotItem.SmallMagic, 'Sewers Behind Tapestry'), Pot(148, 22, PotItem.SmallMagic, 'Sewers Behind Tapestry')], - 67: [Pot(66, 4, PotItem.FiveArrows, 'Desert Wall Slide'), Pot(78, 4, PotItem.SmallMagic, 'Desert Wall Slide'), Pot(66, 9, PotItem.Heart, 'Desert Wall Slide'), Pot(78, 9, PotItem.Heart, 'Desert Wall Slide'), - Pot(112, 28, PotItem.Nothing, 'Desert Tiles 2'), Pot(76, 28, PotItem.Nothing, 'Desert Tiles 2'), Pot(76, 20, PotItem.Nothing, 'Desert Tiles 2'), Pot(112, 20, PotItem.Key, 'Desert Tiles 2')], - 69: [Pot(12, 4, PotItem.FiveArrows, 'Thieves Basement Block'), Pot(48, 12, PotItem.FiveArrows, 'Thieves Basement Block'), Pot(92, 11, PotItem.Nothing, "Thieves Blind's Cell"), Pot(108, 11, PotItem.Heart, "Thieves Blind's Cell"), - Pot(220, 16, PotItem.SmallMagic, "Thieves Blind's Cell"), Pot(236, 16, PotItem.Heart, "Thieves Blind's Cell")], + 0x3F: [Pot(12, 25, PotItem.OneRupee, 'Ice Hammer Block'), Pot(20, 25, PotItem.OneRupee, 'Ice Hammer Block'), Pot(12, 26, PotItem.Bomb, 'Ice Hammer Block'), Pot(20, 26, PotItem.Bomb, 'Ice Hammer Block'), + Pot(12, 27, PotItem.Switch, 'Ice Hammer Block'), Pot(20, 27, PotItem.Heart, 'Ice Hammer Block'), Pot(28, 23, PotItem.Key, 'Ice Hammer Block')], + 0x41: [Pot(100, 10, PotItem.Heart, 'Sewers Behind Tapestry'), Pot(52, 15, PotItem.OneRupee, 'Sewers Behind Tapestry'), Pot(52, 16, PotItem.SmallMagic, 'Sewers Behind Tapestry'), Pot(148, 22, PotItem.SmallMagic, 'Sewers Behind Tapestry')], + 0x43: [Pot(66, 4, PotItem.FiveArrows, 'Desert Wall Slide'), Pot(78, 4, PotItem.SmallMagic, 'Desert Wall Slide'), Pot(66, 9, PotItem.Heart, 'Desert Wall Slide'), Pot(78, 9, PotItem.Heart, 'Desert Wall Slide'), + Pot(112, 28, PotItem.Nothing, 'Desert Tiles 2'), Pot(76, 28, PotItem.Nothing, 'Desert Tiles 2'), Pot(76, 20, PotItem.Nothing, 'Desert Tiles 2'), Pot(112, 20, PotItem.Key, 'Desert Tiles 2')], + 0x44: [Pot(204, 7, PotItem.Nothing, 'Thieves Conveyor Bridge', PotFlags.Block)], + 0x45: [Pot(12, 4, PotItem.FiveArrows, 'Thieves Basement Block'), + Pot(48, 12, PotItem.FiveArrows, 'Thieves Basement Block'), + Pot(92, 11, PotItem.Nothing, "Thieves Blind's Cell"), Pot(108, 11, PotItem.Heart, "Thieves Blind's Cell"), + Pot(220, 16, PotItem.SmallMagic, "Thieves Blind's Cell"), + Pot(236, 16, PotItem.Heart, "Thieves Blind's Cell"), + Pot(0x9C, 7, PotItem.Nothing, 'Thieves Basement Block', PotFlags.Block)], 70: [Pot(96, 5, PotItem.Heart, 'Swamp Donut Top'), Pot(28, 27, PotItem.Heart, 'Swamp Donut Bottom')], 73: [Pot(104, 15, PotItem.SmallMagic, 'Skull Torch Room'), Pot(104, 16, PotItem.SmallMagic, 'Skull Torch Room'), Pot(156, 27, PotItem.Nothing, 'Skull Star Pits'), Pot(172, 24, PotItem.Nothing, 'Skull Star Pits'), Pot(172, 23, PotItem.Nothing, 'Skull Star Pits'), Pot(144, 20, PotItem.Nothing, 'Skull Star Pits'), Pot(144, 19, PotItem.SmallMagic, 'Skull Star Pits'), Pot(172, 20, PotItem.Heart, 'Skull Star Pits'), @@ -87,15 +100,16 @@ vanilla_pots = { 75: [Pot(20, 6, PotItem.FiveArrows, 'PoD Mimics 1'), Pot(40, 6, PotItem.Heart, 'PoD Mimics 1')], 78: [Pot(140, 7, PotItem.Nothing, 'Ice Bomb Jump Catwalk'), Pot(48, 10, PotItem.Nothing, 'Ice Bomb Jump Catwalk'), Pot(140, 11, PotItem.Switch, 'Ice Bomb Jump Catwalk'), Pot(28, 12, PotItem.Heart, 'Ice Bomb Jump Catwalk'), Pot(112, 12, PotItem.SmallMagic, 'Ice Narrow Corridor')], - 80: [Pot(96, 38, PotItem.Heart, 'Hyrule Castle West Hall'), Pot(100, 38, PotItem.Heart, 'Hyrule Castle West Hall')], + 0x50: [Pot(96, 0x6, PotItem.Heart, 'Hyrule Castle West Hall', PotFlags.LowerRegion), + Pot(100, 0x6, PotItem.Heart, 'Hyrule Castle West Hall', PotFlags.LowerRegion)], 82: [Pot(138, 3, PotItem.Heart, 'Hyrule Castle East Hall'), Pot(194, 26, PotItem.Heart, 'Hyrule Castle East Hall')], - 83: [Pot(92, 11, PotItem.Heart, 'Desert Beamos Hall'), Pot(96, 11, PotItem.SmallMagic, 'Desert Beamos Hall'), Pot(100, 11, PotItem.Key, 'Desert Beamos Hall'), Pot(104, 11, PotItem.Heart, 'Desert Beamos Hall')], + 0x53: [Pot(92, 11, PotItem.Heart, 'Desert Beamos Hall'), Pot(96, 11, PotItem.SmallMagic, 'Desert Beamos Hall'), Pot(100, 11, PotItem.Key, 'Desert Beamos Hall'), Pot(104, 11, PotItem.Heart, 'Desert Beamos Hall')], 84: [Pot(186, 25, PotItem.FiveRupees, 'Swamp Attic'), Pot(186, 26, PotItem.Heart, 'Swamp Attic'), Pot(186, 27, PotItem.Heart, 'Swamp Attic'), Pot(186, 28, PotItem.Heart, 'Swamp Attic')], - 85: [Pot(230, 24, PotItem.SmallMagic, 'Secret Passage'), Pot(230, 25, PotItem.SmallMagic, 'Secret Passage')], - 86: [Pot(100, 6, PotItem.Nothing, 'Skull Back Drop'), Pot(96, 10, PotItem.Nothing, 'Skull Back Drop'), Pot(92, 10, PotItem.Nothing, 'Skull Back Drop'), Pot(20, 6, PotItem.SmallMagic, 'Skull X Room'), - Pot(40, 6, PotItem.SmallMagic, 'Skull X Room'), Pot(24, 7, PotItem.SmallMagic, 'Skull X Room'), Pot(36, 7, PotItem.SmallMagic, 'Skull X Room'), Pot(12, 8, PotItem.Heart, 'Skull X Room'), Pot(48, 8, PotItem.Heart, 'Skull X Room'), - Pot(24, 9, PotItem.SmallMagic, 'Skull X Room'), Pot(36, 9, PotItem.SmallMagic, 'Skull X Room'), Pot(20, 10, PotItem.FiveRupees, 'Skull X Room'), Pot(40, 10, PotItem.FiveRupees, 'Skull X Room'), Pot(12, 20, PotItem.Key, 'Skull 2 West Lobby'), - Pot(48, 20, PotItem.Nothing, 'Skull 2 West Lobby')], + 85: [Pot(230, 24, PotItem.SmallMagic, 'Hyrule Castle Secret Entrance'), Pot(230, 25, PotItem.SmallMagic, 'Hyrule Castle Secret Entrance')], + 0x56: [Pot(100, 6, PotItem.Nothing, 'Skull Back Drop'), Pot(96, 10, PotItem.Nothing, 'Skull Back Drop'), Pot(92, 10, PotItem.Nothing, 'Skull Back Drop'), Pot(20, 6, PotItem.SmallMagic, 'Skull X Room'), + Pot(40, 6, PotItem.SmallMagic, 'Skull X Room'), Pot(24, 7, PotItem.SmallMagic, 'Skull X Room'), Pot(36, 7, PotItem.SmallMagic, 'Skull X Room'), Pot(12, 8, PotItem.Heart, 'Skull X Room'), Pot(48, 8, PotItem.Heart, 'Skull X Room'), + Pot(24, 9, PotItem.SmallMagic, 'Skull X Room'), Pot(36, 9, PotItem.SmallMagic, 'Skull X Room'), Pot(20, 10, PotItem.FiveRupees, 'Skull X Room'), Pot(40, 10, PotItem.FiveRupees, 'Skull X Room'), Pot(12, 20, PotItem.Key, 'Skull 2 West Lobby'), + Pot(48, 20, PotItem.Nothing, 'Skull 2 West Lobby')], 87: [Pot(92, 7, PotItem.BigMagic, 'Skull Lone Pot'), Pot(32, 4, PotItem.Nothing, 'Skull Big Key'), Pot(92, 23, PotItem.Bomb, 'Skull Pot Prison'), Pot(100, 23, PotItem.SmallMagic, 'Skull Pot Prison'), Pot(84, 25, PotItem.FiveRupees, 'Skull Pot Prison'), Pot(76, 27, PotItem.Heart, 'Skull Pot Prison'), Pot(12, 20, PotItem.SmallMagic, 'Skull 2 East Lobby'), Pot(48, 20, PotItem.SmallMagic, 'Skull 2 East Lobby'), Pot(30, 22, PotItem.Switch, 'Skull 2 East Lobby')], @@ -103,8 +117,13 @@ vanilla_pots = { Pot(96, 9, PotItem.Nothing, 'Skull Pot Circle'), Pot(92, 8, PotItem.Nothing, 'Skull Pot Circle'), Pot(108, 8, PotItem.Nothing, 'Skull Pot Circle'), Pot(108, 6, PotItem.Nothing, 'Skull Pot Circle'), Pot(104, 5, PotItem.Nothing, 'Skull Pot Circle'), Pot(92, 6, PotItem.Nothing, 'Skull Pot Circle'), Pot(96, 5, PotItem.Bomb, 'Skull Pot Circle'), Pot(100, 5, PotItem.SmallMagic, 'Skull Pot Circle'), Pot(92, 7, PotItem.Heart, 'Skull Pot Circle'), Pot(108, 7, PotItem.Heart, 'Skull Pot Circle'), Pot(100, 9, PotItem.SmallMagic, 'Skull Pot Circle'), Pot(104, 9, PotItem.Bomb, 'Skull Pot Circle')], - 89: [Pot(26, 43, PotItem.Heart, 'Skull 3 Lobby'), Pot(32, 40, PotItem.Nothing, 'Skull 3 Lobby'), Pot(76, 28, PotItem.Nothing, 'Skull East Bridge'), Pot(112, 28, PotItem.Nothing, 'Skull East Bridge')], - 91: [Pot(218, 37, PotItem.Nothing, 'GT Hidden Spikes'), Pot(222, 37, PotItem.Switch, 'GT Hidden Spikes'), Pot(226, 37, PotItem.Nothing, 'GT Hidden Spikes')], + 0x59: [Pot(26, 0xb, PotItem.Heart, 'Skull 3 Lobby', PotFlags.LowerRegion), + Pot(32, 8, PotItem.Nothing, 'Skull 3 Lobby', PotFlags.LowerRegion), + Pot(76, 28, PotItem.Nothing, 'Skull East Bridge'), + Pot(112, 28, PotItem.Nothing, 'Skull East Bridge')], + 0x5B: [Pot(218, 0x5, PotItem.Nothing, 'GT Hidden Spikes', PotFlags.LowerRegion), + Pot(222, 0x5, PotItem.Switch, 'GT Hidden Spikes', PotFlags.LowerRegion), + Pot(226, 0x5, PotItem.Nothing, 'GT Hidden Spikes', PotFlags.LowerRegion)], 92: [Pot(228, 25, PotItem.Nothing, 'GT Refill'), Pot(104, 24, PotItem.Nothing, 'GT Refill'), Pot(228, 22, PotItem.Nothing, 'GT Refill'), Pot(216, 25, PotItem.Nothing, 'GT Refill'), Pot(84, 24, PotItem.Nothing, 'GT Refill'), Pot(216, 22, PotItem.Nothing, 'GT Refill'), Pot(94, 22, PotItem.Bomb, 'GT Refill'), Pot(94, 26, PotItem.BigMagic, 'GT Refill')], 93: [Pot(16, 5, PotItem.Bomb, 'GT Gauntlet 2'), Pot(44, 5, PotItem.FiveRupees, 'GT Gauntlet 2'), Pot(16, 11, PotItem.OneRupee, 'GT Gauntlet 2'), Pot(44, 11, PotItem.FiveArrows, 'GT Gauntlet 2'), Pot(12, 20, PotItem.FiveArrows, 'GT Gauntlet 3'), @@ -113,15 +132,22 @@ vanilla_pots = { 95: [Pot(44, 27, PotItem.Switch, 'Ice Spike Room')], 96: [Pot(76, 4, PotItem.Heart, 'Hyrule Castle West Lobby'), Pot(112, 4, PotItem.Heart, 'Hyrule Castle West Lobby')], 98: [Pot(208, 21, PotItem.Heart, 'Hyrule Castle East Lobby')], - 99: [Pot(48, 4, PotItem.Nothing, 'Desert Tiles 1'), Pot(12, 4, PotItem.Nothing, 'Desert Tiles 1'), Pot(12, 8, PotItem.Nothing, 'Desert Tiles 1'), Pot(48, 12, PotItem.Nothing, 'Desert Tiles 1'), Pot(48, 8, PotItem.Heart, 'Desert Tiles 1'), + 0x63: [Pot(48, 4, PotItem.Nothing, 'Desert Tiles 1'), Pot(12, 4, PotItem.Nothing, 'Desert Tiles 1'), Pot(12, 8, PotItem.Nothing, 'Desert Tiles 1'), Pot(48, 12, PotItem.Nothing, 'Desert Tiles 1'), Pot(48, 8, PotItem.Heart, 'Desert Tiles 1'), Pot(12, 12, PotItem.Key, 'Desert Tiles 1')], 100: [Pot(12, 22, PotItem.Bomb, 'Thieves Attic Hint', PotFlags.SwitchLogicChange), Pot(16, 22, PotItem.Bomb, 'Thieves Attic Hint', PotFlags.SwitchLogicChange), Pot(20, 22, PotItem.Bomb, 'Thieves Attic Hint', PotFlags.SwitchLogicChange), Pot(36, 28, PotItem.Bomb, 'Thieves Attic'), Pot(40, 28, PotItem.SmallMagic, 'Thieves Attic'), Pot(44, 28, PotItem.SmallMagic, 'Thieves Attic'), Pot(48, 28, PotItem.Switch, 'Thieves Attic')], 101: [Pot(100, 28, PotItem.Bomb, 'Thieves Attic Window'), Pot(104, 28, PotItem.Bomb, 'Thieves Attic Window')], - 102: [Pot(48, 37, PotItem.FiveArrows, 'Swamp Refill'), Pot(52, 37, PotItem.Bomb, 'Swamp Refill'), Pot(56, 37, PotItem.FiveRupees, 'Swamp Refill'), Pot(48, 38, PotItem.FiveArrows, 'Swamp Refill'), Pot(52, 38, PotItem.Bomb, 'Swamp Refill'), - Pot(56, 38, PotItem.FiveRupees, 'Swamp Refill'), Pot(84, 5, PotItem.Heart, 'Swamp Behind Waterfall'), Pot(104, 5, PotItem.FiveArrows, 'Swamp Behind Waterfall'), Pot(84, 6, PotItem.Heart, 'Swamp Behind Waterfall'), - Pot(104, 6, PotItem.Bomb, 'Swamp Behind Waterfall')], + 0x66: [Pot(48, 0x5, PotItem.FiveArrows, 'Swamp Refill', PotFlags.LowerRegion), + Pot(52, 0x5, PotItem.Bomb, 'Swamp Refill', PotFlags.LowerRegion), + Pot(56, 0x5, PotItem.FiveRupees, 'Swamp Refill', PotFlags.LowerRegion), + Pot(48, 0x6, PotItem.FiveArrows, 'Swamp Refill', PotFlags.LowerRegion), + Pot(52, 0x6, PotItem.Bomb, 'Swamp Refill', PotFlags.LowerRegion), + Pot(56, 0x6, PotItem.FiveRupees, 'Swamp Refill', PotFlags.LowerRegion), + Pot(84, 5, PotItem.Heart, 'Swamp Behind Waterfall'), + Pot(104, 5, PotItem.FiveArrows, 'Swamp Behind Waterfall'), + Pot(84, 6, PotItem.Heart, 'Swamp Behind Waterfall'), + Pot(104, 6, PotItem.Bomb, 'Swamp Behind Waterfall')], 103: [Pot(22, 26, PotItem.Nothing, 'Skull Left Drop'), Pot(18, 22, PotItem.Nothing, 'Skull Left Drop'), Pot(12, 7, PotItem.FiveArrows, 'Skull Left Drop'), Pot(48, 7, PotItem.SmallMagic, 'Skull Left Drop'), Pot(18, 23, PotItem.SmallMagic, 'Skull Left Drop'), Pot(18, 26, PotItem.Heart, 'Skull Left Drop'), Pot(96, 19, PotItem.Heart, 'Skull Compass Room'), Pot(74, 20, PotItem.SmallMagic, 'Skull Compass Room'), Pot(92, 9, PotItem.Nothing, 'Skull Compass Room'), Pot(84, 28, PotItem.Nothing, 'Skull Compass Room'), Pot(104, 28, PotItem.Heart, 'Skull Compass Room')], @@ -139,22 +165,24 @@ vanilla_pots = { Pot(46, 11, PotItem.FiveArrows, 'Desert Map Room'), Pot(78, 11, PotItem.FiveArrows, 'Desert Map Room'), Pot(110, 11, PotItem.Heart, 'Desert Map Room')], 117: [Pot(148, 22, PotItem.SmallMagic, 'Desert Arrow Pot Corner'), Pot(160, 22, PotItem.FiveArrows, 'Desert Arrow Pot Corner'), Pot(172, 22, PotItem.Heart, 'Desert Arrow Pot Corner')], 118: [Pot(112, 12, PotItem.Heart, 'Swamp Drain Right'), Pot(84, 23, PotItem.Heart, 'Swamp Flooded Spot'), Pot(96, 23, PotItem.Heart, 'Swamp Flooded Spot')], - 123: [Pot(48, 10, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(88, 10, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(76, 7, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(60, 4, PotItem.Heart, 'GT Conveyor Star Pits'), + 0x7B: [Pot(48, 10, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(88, 10, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(76, 7, PotItem.Nothing, 'GT Conveyor Star Pits'), Pot(60, 4, PotItem.Heart, 'GT Conveyor Star Pits'), Pot(64, 4, PotItem.Key, 'GT Conveyor Star Pits')], 124: [Pot(36, 21, PotItem.Nothing, 'GT Falling Bridge'), Pot(24, 11, PotItem.Nothing, 'GT Falling Bridge'), Pot(28, 4, PotItem.Heart, 'GT Falling Bridge'), Pot(32, 4, PotItem.Heart, 'GT Falling Bridge')], 125: [Pot(44, 12, PotItem.Nothing, 'GT Firesnake Room'), Pot(44, 6, PotItem.Nothing, 'GT Firesnake Room'), Pot(112, 6, PotItem.Heart, 'GT Firesnake Room'), Pot(108, 20, PotItem.FiveArrows, 'GT Warp Maze - Pot Rail'), Pot(114, 20, PotItem.Bomb, 'GT Petting Zoo'), Pot(76, 28, PotItem.Bomb, 'GT Petting Zoo')], 126: [Pot(86, 15, PotItem.Heart, 'Ice Tall Hint'), Pot(82, 26, PotItem.SmallMagic, 'Ice Tall Hint'), Pot(100, 26, PotItem.Switch, 'Ice Tall Hint'), Pot(104, 26, PotItem.Nothing, 'Ice Tall Hint')], 128: [Pot(48, 4, PotItem.Heart, 'Hyrule Dungeon Cellblock'), Pot(52, 4, PotItem.Heart, 'Hyrule Dungeon Cellblock'), Pot(56, 4, PotItem.Heart, 'Hyrule Dungeon Cellblock')], - 130: [Pot(50, 5, PotItem.Nothing, 'Hyrule Dungeon South Abyss'), Pot(50, 10, PotItem.Nothing, 'Hyrule Dungeon South Abyss'), Pot(76, 50, PotItem.Heart, 'Hyrule Dungeon South Abyss')], + 0x82: [Pot(50, 0x5, PotItem.Nothing, 'Hyrule Dungeon South Abyss', PotFlags.LowerRegion), + Pot(50, 0xA, PotItem.Nothing, 'Hyrule Dungeon South Abyss', PotFlags.LowerRegion), + Pot(76, 0x12, PotItem.Heart, 'Hyrule Dungeon South Abyss', PotFlags.LowerRegion)], 131: [Pot(76, 4, PotItem.FiveArrows, 'Desert West Wing'), Pot(80, 4, PotItem.OneRupee, 'Desert West Wing'), Pot(76, 28, PotItem.FiveRupees, 'Desert West Wing'), Pot(80, 28, PotItem.FiveArrows, 'Desert West Wing')], 132: [Pot(64, 17, PotItem.Nothing, 'Desert Main Lobby'), Pot(60, 17, PotItem.Nothing, 'Desert Main Lobby'), Pot(80, 14, PotItem.Nothing, 'Desert Main Lobby'), Pot(44, 14, PotItem.Nothing, 'Desert Main Lobby'), Pot(100, 6, PotItem.Nothing, 'Desert Main Lobby'), Pot(24, 6, PotItem.Nothing, 'Desert Main Lobby'), Pot(24, 7, PotItem.FiveArrows, 'Desert Main Lobby'), Pot(100, 7, PotItem.FiveArrows, 'Desert Main Lobby')], 133: [Pot(44, 28, PotItem.Heart, 'Desert East Wing'), Pot(48, 28, PotItem.FiveArrows, 'Desert East Wing')], 135: [Pot(12, 11, PotItem.Nothing, 'Hera Tile Room'), Pot(16, 12, PotItem.Nothing, 'Hera Tile Room'), Pot(40, 12, PotItem.Nothing, 'Hera Tile Room'), Pot(32, 12, PotItem.Nothing, 'Hera Tile Room'), Pot(24, 12, PotItem.Nothing, 'Hera Tile Room'), Pot(16, 11, PotItem.Nothing, 'Hera Tile Room'), Pot(76, 20, PotItem.SmallMagic, 'Hera Torches'), Pot(112, 20, PotItem.BigMagic, 'Hera Torches')], - 139: [Pot(76, 12, PotItem.Nothing, 'GT Conveyor Cross'), Pot(112, 12, PotItem.Key, 'GT Conveyor Cross'), Pot(32, 23, PotItem.Nothing, 'GT Hookshot South Platform'), Pot(28, 23, PotItem.Nothing, 'GT Hookshot South Platform'), - Pot(32, 9, PotItem.SmallMagic, 'GT Hookshot East Platform'), Pot(76, 20, PotItem.Nothing, 'GT Map Room'), Pot(76, 28, PotItem.Heart, 'GT Map Room')], + 0x8B: [Pot(76, 12, PotItem.Nothing, 'GT Conveyor Cross'), Pot(112, 12, PotItem.Key, 'GT Conveyor Cross'), Pot(32, 23, PotItem.Nothing, 'GT Hookshot South Platform'), Pot(28, 23, PotItem.Nothing, 'GT Hookshot South Platform'), + Pot(32, 9, PotItem.SmallMagic, 'GT Hookshot East Platform'), Pot(76, 20, PotItem.Nothing, 'GT Map Room'), Pot(76, 28, PotItem.Heart, 'GT Map Room')], 140: [Pot(76, 12, PotItem.Switch, 'GT Hope Room'), Pot(112, 12, PotItem.SmallMagic, 'GT Hope Room'), Pot(76, 20, PotItem.Bomb, "GT Bob's Room"), Pot(92, 20, PotItem.Bomb, "GT Bob's Room"), Pot(100, 21, PotItem.FiveArrows, "GT Bob's Room"), Pot(104, 26, PotItem.Bomb, "GT Bob's Room"), Pot(88, 27, PotItem.Bomb, "GT Bob's Room")], 141: [Pot(204, 11, PotItem.Nothing, 'GT Speed Torch Upper'), Pot(204, 14, PotItem.BigMagic, 'GT Speed Torch Upper'), Pot(28, 23, PotItem.Heart, 'GT Pots n Blocks'), Pot(36, 23, PotItem.Heart, 'GT Pots n Blocks'), @@ -162,37 +190,59 @@ vanilla_pots = { 142: [Pot(80, 5, PotItem.FiveArrows, 'Ice Lonely Freezor'), Pot(80, 6, PotItem.Nothing, 'Ice Lonely Freezor')], 145: [Pot(84, 4, PotItem.Heart, 'Mire Falling Foes'), Pot(104, 4, PotItem.SmallMagic, 'Mire Falling Foes')], 146: [Pot(86, 23, PotItem.Nothing, 'Mire Tall Dark and Roomy'), Pot(92, 23, PotItem.Nothing, 'Mire Tall Dark and Roomy'), Pot(98, 23, PotItem.Nothing, 'Mire Tall Dark and Roomy'), Pot(104, 23, PotItem.Nothing, 'Mire Tall Dark and Roomy')], - 147: [Pot(28, 7, PotItem.Switch, 'Mire Dark Shooters'), Pot(96, 7, PotItem.Heart, 'Mire Dark Shooters', PotFlags.NoSwitch)], - 150: [Pot(14, 18, PotItem.Nothing, 'GT Torch Cross'), Pot(32, 5, PotItem.Nothing, 'GT Torch Cross'), Pot(32, 17, PotItem.SmallMagic, 'GT Torch Cross'), Pot(32, 24, PotItem.SmallMagic, 'GT Torch Cross'), - Pot(14, 24, PotItem.Nothing, 'GT Torch Cross'), Pot(76, 21, PotItem.Heart, 'GT Staredown'), Pot(112, 21, PotItem.BigMagic, 'GT Staredown')], + 0x93: [Pot(28, 7, PotItem.Switch, 'Mire Dark Shooters'), + Pot(0x9C, 0x17, PotItem.Switch, 'Mire Block X', PotFlags.Block), + Pot(96, 7, PotItem.Heart, 'Mire Dark Shooters', PotFlags.NoSwitch)], + 0x96: [Pot(14, 18, PotItem.Nothing, 'GT Torch Cross'), + Pot(32, 5, PotItem.Nothing, 'GT Torch Cross'), + Pot(0x2e, 0xb, PotItem.Nothing, 'GT Torch Cross'), + Pot(32, 17, PotItem.SmallMagic, 'GT Torch Cross'), + Pot(32, 24, PotItem.SmallMagic, 'GT Torch Cross'), + Pot(14, 24, PotItem.Nothing, 'GT Torch Cross'), + Pot(76, 21, PotItem.Heart, 'GT Staredown'), + Pot(112, 21, PotItem.BigMagic, 'GT Staredown')], 153: [Pot(40, 20, PotItem.SmallMagic, 'Eastern Darkness'), Pot(84, 20, PotItem.Heart, 'Eastern Darkness')], - 155: [Pot(48, 4, PotItem.SmallMagic, 'GT Double Switch Pot Corners'), Pot(48, 12, PotItem.Key, 'GT Double Switch Pot Corners'), Pot(28, 24, PotItem.Nothing, 'GT Warp Maze - Mid Section'), Pot(32, 24, PotItem.Nothing, 'GT Warp Maze - Mid Section')], + 0x9B: [Pot(48, 4, PotItem.SmallMagic, 'GT Double Switch Pot Corners'), Pot(48, 12, PotItem.Key, 'GT Double Switch Pot Corners'), Pot(28, 24, PotItem.Nothing, 'GT Warp Maze - Mid Section'), Pot(32, 24, PotItem.Nothing, 'GT Warp Maze - Mid Section')], 156: [Pot(56, 8, PotItem.SmallMagic, 'GT Invisible Catwalk'), Pot(56, 9, PotItem.FiveArrows, 'GT Invisible Catwalk')], 157: [Pot(76, 4, PotItem.Bomb, 'GT Crystal Conveyor Left'), Pot(84, 4, PotItem.SmallMagic, 'GT Crystal Conveyor Left'), Pot(32, 7, PotItem.Nothing, 'GT Compass Room'), Pot(40, 9, PotItem.Nothing, 'GT Compass Room')], - 159: [Pot(138, 20, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 19, PotItem.Heart, 'Ice Many Pots'), Pot(178, 19, PotItem.Heart, 'Ice Many Pots'), Pot(40, 21, PotItem.Switch, 'Ice Many Pots'), Pot(138, 21, PotItem.Key, 'Ice Many Pots'), - Pot(20, 27, PotItem.Heart, 'Ice Many Pots'), Pot(138, 27, PotItem.Heart, 'Ice Many Pots'), Pot(178, 28, PotItem.Heart, 'Ice Many Pots'), Pot(178, 21, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 20, PotItem.Nothing, 'Ice Many Pots'), - Pot(40, 27, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 27, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 26, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 28, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 26, PotItem.Nothing, 'Ice Many Pots'), - Pot(20, 21, PotItem.Nothing, 'Ice Many Pots')], - 161: [Pot(150, 6, PotItem.Key, 'Mire Fishbone'), Pot(100, 11, PotItem.SmallMagic, 'Mire Fishbone'), Pot(104, 12, PotItem.Heart, 'Mire Fishbone'), Pot(108, 13, PotItem.SmallMagic, 'Mire Fishbone'), Pot(112, 14, PotItem.Heart, 'Mire Fishbone'), - Pot(96, 27, PotItem.Nothing, 'Mire South Fish'), Pot(92, 21, PotItem.Nothing, 'Mire South Fish'), Pot(96, 23, PotItem.Heart, 'Mire South Fish'), Pot(92, 25, PotItem.Nothing, 'Mire South Fish'), - Pot(76, 28, PotItem.Nothing, 'Mire South Fish'), Pot(112, 28, PotItem.Nothing, 'Mire South Fish')], - 162: [Pot(12, 28, PotItem.BigMagic, 'Mire Left Bridge')], + 0x9F: [Pot(138, 20, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 19, PotItem.Heart, 'Ice Many Pots'), Pot(178, 19, PotItem.Heart, 'Ice Many Pots'), Pot(40, 21, PotItem.Switch, 'Ice Many Pots'), Pot(138, 21, PotItem.Key, 'Ice Many Pots'), + Pot(20, 27, PotItem.Heart, 'Ice Many Pots'), Pot(138, 27, PotItem.Heart, 'Ice Many Pots'), Pot(178, 28, PotItem.Heart, 'Ice Many Pots'), Pot(178, 21, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 20, PotItem.Nothing, 'Ice Many Pots'), + Pot(40, 27, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 27, PotItem.Nothing, 'Ice Many Pots'), Pot(178, 26, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 28, PotItem.Nothing, 'Ice Many Pots'), Pot(138, 26, PotItem.Nothing, 'Ice Many Pots'), + Pot(20, 21, PotItem.Nothing, 'Ice Many Pots')], + 0xA1: [Pot(150, 6, PotItem.Key, 'Mire Fishbone'), Pot(100, 11, PotItem.SmallMagic, 'Mire Fishbone'), Pot(104, 12, PotItem.Heart, 'Mire Fishbone'), Pot(108, 13, PotItem.SmallMagic, 'Mire Fishbone'), Pot(112, 14, PotItem.Heart, 'Mire Fishbone'), + Pot(96, 27, PotItem.Nothing, 'Mire South Fish'), Pot(92, 21, PotItem.Nothing, 'Mire South Fish'), Pot(96, 23, PotItem.Heart, 'Mire South Fish'), Pot(92, 25, PotItem.Nothing, 'Mire South Fish'), + Pot(76, 28, PotItem.Nothing, 'Mire South Fish'), Pot(112, 28, PotItem.Nothing, 'Mire South Fish')], + 0xA2: [Pot(12, 28, PotItem.BigMagic, 'Mire Left Bridge')], 168: [Pot(138, 28, PotItem.Nothing, 'Eastern Stalfos Spawn'), Pot(178, 28, PotItem.Nothing, 'Eastern Stalfos Spawn'), Pot(178, 19, PotItem.Nothing, 'Eastern Stalfos Spawn'), Pot(138, 19, PotItem.Heart, 'Eastern Stalfos Spawn'), Pot(30, 24, PotItem.OneRupee, 'Eastern Stalfos Spawn')], - 169: [Pot(144, 43, PotItem.FiveArrows, 'Eastern Courtyard'), Pot(236, 43, PotItem.FiveArrows, 'Eastern Courtyard'), Pot(144, 44, PotItem.FiveArrows, 'Eastern Courtyard'), Pot(236, 44, PotItem.Heart, 'Eastern Courtyard'), - Pot(12, 19, PotItem.Nothing, 'Eastern Courtyard Ledge'), Pot(112, 19, PotItem.Nothing, 'Eastern Courtyard Ledge'), Pot(16, 20, PotItem.Heart, 'Eastern Courtyard Ledge'), Pot(108, 20, PotItem.Heart, 'Eastern Courtyard Ledge')], - 170: [Pot(212, 10, PotItem.Nothing, 'Eastern Pot Switch'), Pot(232, 10, PotItem.Nothing, 'Eastern Pot Switch'), Pot(232, 5, PotItem.Nothing, 'Eastern Pot Switch'), Pot(212, 5, PotItem.Heart, 'Eastern Pot Switch'), - Pot(94, 8, PotItem.Switch, 'Eastern Pot Switch'), Pot(108, 55, PotItem.Heart, 'Eastern Map Balcony'), Pot(108, 56, PotItem.Heart, 'Eastern Map Balcony'), Pot(108, 57, PotItem.Heart, 'Eastern Map Balcony')], - 171: [Pot(20, 24, PotItem.Key, 'Thieves Spike Switch')], + 0xA9: [Pot(144, 0xB, PotItem.FiveArrows, 'Eastern Courtyard', PotFlags.LowerRegion), + Pot(236, 0xB, PotItem.FiveArrows, 'Eastern Courtyard', PotFlags.LowerRegion), + Pot(144, 0xC, PotItem.FiveArrows, 'Eastern Courtyard', PotFlags.LowerRegion), + Pot(236, 0xC, PotItem.Heart, 'Eastern Courtyard', PotFlags.LowerRegion), + Pot(12, 19, PotItem.Nothing, 'Eastern Courtyard Ledge'), + Pot(112, 19, PotItem.Nothing, 'Eastern Courtyard Ledge'), + Pot(16, 20, PotItem.Heart, 'Eastern Courtyard Ledge'), + Pot(108, 20, PotItem.Heart, 'Eastern Courtyard Ledge')], + 0xAA: [Pot(212, 10, PotItem.Nothing, 'Eastern Pot Switch'), Pot(232, 10, PotItem.Nothing, 'Eastern Pot Switch'), + Pot(232, 5, PotItem.Nothing, 'Eastern Pot Switch'), Pot(212, 5, PotItem.Heart, 'Eastern Pot Switch'), + Pot(94, 8, PotItem.Switch, 'Eastern Pot Switch'), + Pot(108, 0x17, PotItem.Heart, 'Eastern Map Balcony', PotFlags.LowerRegion), + Pot(108, 0x18, PotItem.Heart, 'Eastern Map Balcony', PotFlags.LowerRegion), + Pot(108, 0x19, PotItem.Heart, 'Eastern Map Balcony', PotFlags.LowerRegion)], + 0xAB: [Pot(20, 24, PotItem.Key, 'Thieves Spike Switch')], 174: [Pot(76, 12, PotItem.Switch, 'Iced T')], 176: [Pot(20, 27, PotItem.Nothing, 'Tower Circle of Pots'), Pot(24, 24, PotItem.Nothing, 'Tower Circle of Pots'), Pot(44, 25, PotItem.Nothing, 'Tower Circle of Pots'), Pot(20, 21, PotItem.Bomb, 'Tower Circle of Pots'), Pot(28, 21, PotItem.OneRupee, 'Tower Circle of Pots'), Pot(32, 21, PotItem.FiveRupees, 'Tower Circle of Pots'), Pot(40, 21, PotItem.FiveArrows, 'Tower Circle of Pots'), Pot(16, 23, PotItem.FiveRupees, 'Tower Circle of Pots'), Pot(44, 23, PotItem.OneRupee, 'Tower Circle of Pots'), Pot(36, 24, PotItem.Heart, 'Tower Circle of Pots'), Pot(16, 25, PotItem.Heart, 'Tower Circle of Pots'), Pot(28, 27, PotItem.FiveArrows, 'Tower Circle of Pots'), Pot(40, 27, PotItem.Bomb, 'Tower Circle of Pots'), Pot(32, 27, PotItem.Nothing, 'Tower Circle of Pots')], 177: [Pot(76, 4, PotItem.Heart, 'Mire Spike Barrier'), Pot(112, 4, PotItem.OneRupee, 'Mire Spike Barrier')], - 178: [Pot(48, 40, PotItem.OneRupee, 'Mire BK Door Room'), Pot(76, 40, PotItem.OneRupee, 'Mire BK Door Room'), Pot(48, 41, PotItem.Nothing, 'Mire BK Door Room'), Pot(76, 41, PotItem.Heart, 'Mire BK Door Room'), - Pot(48, 42, PotItem.Nothing, 'Mire BK Door Room'), Pot(76, 40, PotItem.Nothing, 'Mire BK Door Room')], - 179: [Pot(12, 20, PotItem.Key, 'Mire Spikes'), Pot(48, 20, PotItem.SmallMagic, 'Mire Spikes'), Pot(48, 28, PotItem.Switch, 'Mire Spikes')], + 0xB2: [Pot(48, 0x8, PotItem.OneRupee, 'Mire BK Door Room', PotFlags.LowerRegion), + Pot(76, 0x8, PotItem.OneRupee, 'Mire BK Door Room', PotFlags.LowerRegion), + Pot(48, 0x9, PotItem.Nothing, 'Mire BK Door Room', PotFlags.LowerRegion), + Pot(76, 0x9, PotItem.Heart, 'Mire BK Door Room', PotFlags.LowerRegion), + Pot(48, 0xA, PotItem.Nothing, 'Mire BK Door Room', PotFlags.LowerRegion), + Pot(76, 0xA, PotItem.Nothing, 'Mire BK Door Room', PotFlags.LowerRegion)], + 0xB3: [Pot(12, 20, PotItem.Key, 'Mire Spikes'), Pot(48, 20, PotItem.SmallMagic, 'Mire Spikes'), Pot(48, 28, PotItem.Switch, 'Mire Spikes')], 180: [Pot(44, 28, PotItem.BigMagic, 'TR Final Abyss'), Pot(48, 28, PotItem.Heart, 'TR Final Abyss')], 181: [Pot(112, 4, PotItem.FiveRupees, 'TR Dark Ride'), Pot(112, 15, PotItem.Heart, 'TR Dark Ride'), Pot(76, 16, PotItem.Switch, 'TR Dark Ride'), Pot(112, 16, PotItem.BigMagic, 'TR Dark Ride'), Pot(112, 17, PotItem.Heart, 'TR Dark Ride'), Pot(112, 28, PotItem.Bomb, 'TR Dark Ride')], @@ -200,9 +250,9 @@ vanilla_pots = { 183: [Pot(30, 5, PotItem.SmallMagic, 'TR Roller Room')], 184: [Pot(96, 13, PotItem.Switch, 'Eastern Big Key'), Pot(88, 16, PotItem.Heart, 'Eastern Big Key'), Pot(104, 16, PotItem.Heart, 'Eastern Big Key')], 185: [Pot(92, 18, PotItem.OneRupee, 'Eastern Cannonball'), Pot(96, 18, PotItem.FiveRupees, 'Eastern Cannonball'), Pot(104, 18, PotItem.FiveRupees, 'Eastern Cannonball'), Pot(108, 18, PotItem.OneRupee, 'Eastern Cannonball')], - 186: [Pot(100, 8, PotItem.Nothing, 'Eastern Dark Pots'), Pot(88, 8, PotItem.Nothing, 'Eastern Dark Pots'), Pot(94, 4, PotItem.OneRupee, 'Eastern Dark Pots'), Pot(76, 6, PotItem.Heart, 'Eastern Dark Pots'), + 0xBA: [Pot(100, 8, PotItem.Nothing, 'Eastern Dark Pots'), Pot(88, 8, PotItem.Nothing, 'Eastern Dark Pots'), Pot(94, 4, PotItem.OneRupee, 'Eastern Dark Pots'), Pot(76, 6, PotItem.Heart, 'Eastern Dark Pots'), Pot(112, 6, PotItem.Key, 'Eastern Dark Pots'), Pot(76, 10, PotItem.Heart, 'Eastern Dark Pots'), Pot(112, 10, PotItem.SmallMagic, 'Eastern Dark Pots'), Pot(94, 12, PotItem.OneRupee, 'Eastern Dark Pots')], - 188: [Pot(86, 4, PotItem.Heart, 'Thieves Hallway'), Pot(102, 4, PotItem.Key, 'Thieves Hallway'), Pot(138, 3, PotItem.Bomb, 'Thieves Conveyor Maze'), Pot(178, 3, PotItem.Switch, 'Thieves Conveyor Maze'), + 0xBC: [Pot(86, 4, PotItem.Heart, 'Thieves Hallway'), Pot(102, 4, PotItem.Key, 'Thieves Hallway'), Pot(138, 3, PotItem.Bomb, 'Thieves Conveyor Maze'), Pot(178, 3, PotItem.Switch, 'Thieves Conveyor Maze'), Pot(138, 12, PotItem.Heart, 'Thieves Conveyor Maze'), Pot(178, 12, PotItem.Bomb, 'Thieves Conveyor Maze'), Pot(12, 20, PotItem.Nothing, 'Thieves Pot Alcove Mid'), Pot(48, 20, PotItem.Bomb, 'Thieves Pot Alcove Mid'), Pot(12, 28, PotItem.Bomb, 'Thieves Pot Alcove Mid'), Pot(48, 28, PotItem.Bomb, 'Thieves Pot Alcove Mid'), Pot(28, 21, PotItem.FiveRupees, 'Thieves Pot Alcove Top'), Pot(32, 21, PotItem.FiveRupees, 'Thieves Pot Alcove Top'), Pot(28, 27, PotItem.FiveRupees, 'Thieves Pot Alcove Bottom'), Pot(32, 27, PotItem.FiveRupees, 'Thieves Pot Alcove Bottom')], @@ -210,7 +260,10 @@ vanilla_pots = { 191: [Pot(40, 20, PotItem.FiveArrows, 'Ice Refill'), Pot(44, 20, PotItem.Heart, 'Ice Refill'), Pot(48, 20, PotItem.Bomb, 'Ice Refill'), Pot(40, 28, PotItem.SmallMagic, 'Ice Refill'), Pot(44, 28, PotItem.SmallMagic, 'Ice Refill'), Pot(48, 28, PotItem.SmallMagic, 'Ice Refill')], 192: [Pot(48, 10, PotItem.Bomb, 'Tower Dark Pits'), Pot(12, 14, PotItem.FiveRupees, 'Tower Dark Pits'), Pot(12, 26, PotItem.Heart, 'Tower Dark Pits'), Pot(28, 27, PotItem.OneRupee, 'Tower Dark Pits')], - 194: [Pot(180, 7, PotItem.Switch, 'Mire Hub Switch'), Pot(100, 46, PotItem.SmallMagic, 'Mire Hub Right'), Pot(68, 48, PotItem.OneRupee, 'Mire Hub'), Pot(64, 52, PotItem.FiveArrows, 'Mire Hub')], + 0xC2: [Pot(180, 7, PotItem.Switch, 'Mire Hub Switch'), + Pot(100, 0xE, PotItem.SmallMagic, 'Mire Hub Right', PotFlags.LowerRegion), + Pot(68, 0x10, PotItem.OneRupee, 'Mire Hub', PotFlags.LowerRegion), + Pot(64, 0x14, PotItem.FiveArrows, 'Mire Hub', PotFlags.LowerRegion)], 196: [Pot(84, 9, PotItem.Bomb, 'TR Crystal Maze Interior'), Pot(24, 14, PotItem.Heart, 'TR Crystal Maze Interior'), Pot(56, 17, PotItem.FiveRupees, 'TR Crystal Maze Interior'), Pot(84, 17, PotItem.Bomb, 'TR Crystal Maze Interior'), Pot(12, 21, PotItem.FiveArrows, 'TR Crystal Maze Interior'), Pot(76, 23, PotItem.OneRupee, 'TR Crystal Maze Interior'), Pot(48, 25, PotItem.SmallMagic, 'TR Crystal Maze Interior'), Pot(12, 26, PotItem.Heart, 'TR Crystal Maze Interior')], 198: [Pot(12, 7, PotItem.BigMagic, 'TR Hub'), Pot(12, 25, PotItem.Heart, 'TR Hub')], @@ -219,7 +272,7 @@ vanilla_pots = { 203: [Pot(80, 4, PotItem.Nothing, 'Thieves Ambush'), Pot(80, 28, PotItem.Nothing, 'Thieves Ambush'), Pot(88, 16, PotItem.Heart, 'Thieves Ambush'), Pot(88, 28, PotItem.FiveRupees, 'Thieves Ambush')], 204: [Pot(36, 4, PotItem.FiveRupees, 'Thieves Rail Ledge'), Pot(36, 28, PotItem.FiveRupees, 'Thieves Rail Ledge'), Pot(112, 4, PotItem.Heart, 'Thieves BK Corner'), Pot(112, 28, PotItem.Bomb, 'Thieves BK Corner')], 206: [Pot(76, 8, PotItem.SmallMagic, 'Ice Antechamber'), Pot(80, 8, PotItem.SmallMagic, 'Ice Antechamber'), Pot(108, 12, PotItem.Bomb, 'Ice Antechamber'), Pot(112, 12, PotItem.FiveArrows, 'Ice Antechamber'), - Pot(204, 11, PotItem.Hole, 'Ice Antechamber')], + Pot(204, 11, PotItem.Hole, 'Ice Antechamber')], # Pot(0x6c, 8, PotItem.Nothing, 'Ice Antechamber', PotFlags.Block) this one has jellies 208: [Pot(158, 5, PotItem.SmallMagic, 'Tower Dark Maze'), Pot(140, 11, PotItem.OneRupee, 'Tower Dark Maze'), Pot(42, 13, PotItem.SmallMagic, 'Tower Dark Maze'), Pot(48, 16, PotItem.Heart, 'Tower Dark Maze'), Pot(176, 20, PotItem.OneRupee, 'Tower Dark Maze'), Pot(146, 23, PotItem.FiveRupees, 'Tower Dark Maze'), Pot(12, 28, PotItem.Heart, 'Tower Dark Maze')], 209: [Pot(48, 4, PotItem.BigMagic, 'Mire Conveyor Barrier'), Pot(168, 7, PotItem.OneRupee, 'Mire Conveyor Barrier'), Pot(76, 4, PotItem.OneRupee, 'Mire Neglected Room'), Pot(112, 4, PotItem.FiveArrows, 'Mire Neglected Room'), @@ -229,55 +282,73 @@ vanilla_pots = { Pot(202, 12, PotItem.FiveArrows, 'Eastern Duo Eyegores'), Pot(242, 12, PotItem.Heart, 'Eastern Duo Eyegores'), Pot(92, 24, PotItem.Heart, 'Eastern Single Eyegore'), Pot(96, 24, PotItem.FiveArrows, 'Eastern Single Eyegore')], 217: [Pot(92, 20, PotItem.FiveArrows, 'Eastern False Switches'), Pot(92, 28, PotItem.Heart, 'Eastern False Switches')], 218: [Pot(24, 23, PotItem.FiveArrows, 'Eastern Attic Start'), Pot(36, 23, PotItem.FiveArrows, 'Eastern Attic Start'), Pot(24, 25, PotItem.Switch, 'Eastern Attic Start'), Pot(36, 25, PotItem.Heart, 'Eastern Attic Start')], - 219: [Pot(12, 4, PotItem.Nothing, 'Thieves Lobby'), Pot(62, 19, PotItem.Nothing, 'Thieves Lobby'), Pot(112, 4, PotItem.FiveRupees, 'Thieves Lobby'), Pot(88, 16, PotItem.Heart, 'Thieves Lobby')], - 220: [Pot(56, 4, PotItem.FiveRupees, 'Thieves Compass Room'), Pot(112, 4, PotItem.Bomb, 'Thieves Compass Room'), Pot(68, 16, PotItem.Heart, 'Thieves Compass Room'), Pot(12, 28, PotItem.FiveArrows, 'Thieves Compass Room')], - 227: [Pot(88, 55, PotItem.Nothing, 'Bat Cave (right)'), Pot(100, 57, PotItem.OneRupee, 'Bat Cave (right)')], - 228: [Pot(32, 9, PotItem.FiveRupees, 'Old Man House'), Pot(112, 10, PotItem.OneRupee, 'Old Man House')], - 229: [Pot(48, 4, PotItem.OneRupee, 'Old Man House Back'), Pot(76, 4, PotItem.OneRupee, 'Old Man House Back'), Pot(112, 16, PotItem.OneRupee, 'Old Man House Back'), Pot(64, 18, PotItem.FiveRupees, 'Old Man House Back')], - 230: [Pot(108, 12, PotItem.FiveArrows, 'Death Mountain Return Cave'), Pot(88, 16, PotItem.Heart, 'Death Mountain Return Cave'), Pot(72, 20, PotItem.Nothing, 'Death Mountain Return Cave'), - Pot(56, 24, PotItem.OneRupee, 'Death Mountain Return Cave')], - 231: [Pot(68, 5, PotItem.OneRupee, 'Death Mountain Return Cave'), Pot(72, 5, PotItem.OneRupee, 'Death Mountain Return Cave')], - 232: [Pot(96, 4, PotItem.Heart, 'Superbunny Cave')], + 0xDB: [Pot(12, 4, PotItem.Nothing, 'Thieves Lobby'), + Pot(62, 19, PotItem.Nothing, 'Thieves Lobby', PotFlags.LowerRegion), + Pot(112, 4, PotItem.FiveRupees, 'Thieves Lobby'), Pot(88, 16, PotItem.Heart, 'Thieves Lobby')], + 0xDC: [Pot(56, 4, PotItem.FiveRupees, 'Thieves Compass Room'), Pot(112, 4, PotItem.Bomb, 'Thieves Compass Room'), Pot(68, 16, PotItem.Heart, 'Thieves Compass Room'), Pot(12, 28, PotItem.FiveArrows, 'Thieves Compass Room')], + 0xE3: [Pot(88, 0x17, PotItem.Nothing, 'Bat Cave (right)', PotFlags.LowerRegion), + Pot(100, 0x19, PotItem.OneRupee, 'Bat Cave (right)', PotFlags.LowerRegion)], + 0xE4: [Pot(32, 9, PotItem.FiveRupees, 'Old Man House'), Pot(112, 10, PotItem.OneRupee, 'Old Man House')], + 0xE5: [Pot(48, 4, PotItem.OneRupee, 'Old Man House Back'), Pot(76, 4, PotItem.OneRupee, 'Old Man House Back'), Pot(112, 16, PotItem.OneRupee, 'Old Man House Back'), Pot(64, 18, PotItem.FiveRupees, 'Old Man House Back')], + 0xE6: [Pot(108, 12, PotItem.FiveArrows, 'Death Mountain Return Cave (left)'), Pot(88, 16, PotItem.Heart, 'Death Mountain Return Cave (left)'), Pot(72, 20, PotItem.Nothing, 'Death Mountain Return Cave (left)'), + Pot(56, 24, PotItem.OneRupee, 'Death Mountain Return Cave (left)')], + 0xE7: [Pot(68, 5, PotItem.OneRupee, 'Death Mountain Return Cave (right)'), Pot(72, 5, PotItem.OneRupee, 'Death Mountain Return Cave (right)')], + 232: [Pot(96, 4, PotItem.Heart, 'Superbunny Cave (Bottom)')], 235: [Pot(206, 8, PotItem.FiveRupees, 'Bumper Cave'), Pot(210, 8, PotItem.FiveRupees, 'Bumper Cave'), Pot(88, 14, PotItem.SmallMagic, 'Bumper Cave'), Pot(92, 14, PotItem.Heart, 'Bumper Cave'), Pot(96, 14, PotItem.SmallMagic, 'Bumper Cave')], 241: [Pot(64, 5, PotItem.Heart, 'Old Man Cave')], - 248: [Pot(242, 13, PotItem.BigMagic, 'Superbunny Cave')], + 0xF3: [Pot(0x28, 0x14, PotItem.Nothing, 'Elder House'), + Pot(0x2C, 0x14, PotItem.Nothing, 'Elder House'), + Pot(0x30, 0x14, PotItem.Nothing, 'Elder House')], + 248: [Pot(242, 13, PotItem.BigMagic, 'Superbunny Cave (Top)')], 253: [Pot(88, 6, PotItem.FiveRupees, 'Fairy Ascension Cave (Top)'), Pot(100, 6, PotItem.FiveRupees, 'Fairy Ascension Cave (Top)'), Pot(84, 23, PotItem.FiveRupees, 'Fairy Ascension Cave (Bottom)'), Pot(84, 24, PotItem.FiveRupees, 'Fairy Ascension Cave (Bottom)')], - 255: [Pot(92, 8, PotItem.Heart, 'Paradox Cave'), Pot(96, 8, PotItem.Heart, 'Paradox Cave'), Pot(112, 28, PotItem.OneRupee, 'Paradox Cave Front')], + 255: [Pot(92, 8, PotItem.Heart, 'Paradox Cave Bomb Area'), Pot(96, 8, PotItem.Heart, 'Paradox Cave Bomb Area'), Pot(112, 28, PotItem.OneRupee, 'Paradox Cave Front')], 257: [Pot(12, 20, PotItem.Heart, 'Snitch Lady (East)'), Pot(224, 19, PotItem.Chicken, 'Snitch Lady (West)'), Pot(228, 19, PotItem.Heart, 'Snitch Lady (West)')], 258: [Pot(146, 19, PotItem.Heart, 'Sick Kids House'), Pot(150, 19, PotItem.Heart, 'Sick Kids House')], 259: [Pot(140, 7, PotItem.Chicken, 'Tavern'), Pot(140, 9, PotItem.Nothing, 'Tavern'), Pot(12, 12, PotItem.Heart, 'Tavern (Front)')], 260: [Pot(202, 21, PotItem.Heart, 'Links House'), Pot(202, 22, PotItem.Heart, 'Links House'), Pot(202, 23, PotItem.Heart, 'Links House')], 261: [Pot(30, 20, PotItem.Heart, 'Sahasrahlas Hut'), Pot(28, 21, PotItem.Heart, 'Sahasrahlas Hut'), Pot(32, 21, PotItem.Heart, 'Sahasrahlas Hut')], + 0x106: [Pot(0x6c, 0x1b, PotItem.Nothing, 'Brewery')], 263: [Pot(214, 23, PotItem.Bomb, 'Light World Bomb Hut'), Pot(222, 23, PotItem.FiveArrows, 'Light World Bomb Hut'), Pot(230, 23, PotItem.Bomb, 'Light World Bomb Hut'), Pot(214, 25, PotItem.OneRupee, 'Light World Bomb Hut'), Pot(222, 25, PotItem.Nothing, 'Light World Bomb Hut'), Pot(230, 25, PotItem.OneRupee, 'Light World Bomb Hut'), Pot(214, 27, PotItem.Bomb, 'Light World Bomb Hut'), Pot(230, 27, PotItem.Bomb, 'Light World Bomb Hut')], 264: [Pot(166, 19, PotItem.Chicken, 'Chicken House')], 268: [Pot(88, 14, PotItem.Heart, 'Hookshot Fairy')], 276: [Pot(92, 4, PotItem.Heart, 'Dark Desert Hint'), Pot(96, 4, PotItem.Heart, 'Dark Desert Hint'), Pot(92, 5, PotItem.Bomb, 'Dark Desert Hint'), Pot(96, 5, PotItem.Bomb, 'Dark Desert Hint'), Pot(92, 10, PotItem.FiveArrows, 'Dark Desert Hint'), Pot(96, 10, PotItem.Heart, 'Dark Desert Hint')], - 279: [Pot(138, 3, PotItem.Heart, 'Spike Cave'), Pot(142, 3, PotItem.Heart, 'Spike Cave'), Pot(166, 3, PotItem.Heart, 'Spike Cave'), Pot(170, 3, PotItem.Heart, 'Spike Cave'), Pot(138, 4, PotItem.Heart, 'Spike Cave'), - Pot(142, 4, PotItem.Heart, 'Spike Cave'), Pot(166, 4, PotItem.Heart, 'Spike Cave'), Pot(170, 4, PotItem.Heart, 'Spike Cave')], + 0x117: [Pot(138, 3, PotItem.Heart, 'Spike Cave'), Pot(142, 3, PotItem.Heart, 'Spike Cave'), + Pot(166, 3, PotItem.Heart, 'Spike Cave'), Pot(170, 3, PotItem.Heart, 'Spike Cave'), + Pot(138, 4, PotItem.Heart, 'Spike Cave'), Pot(142, 4, PotItem.Heart, 'Spike Cave'), + Pot(166, 4, PotItem.Heart, 'Spike Cave'), Pot(170, 4, PotItem.Heart, 'Spike Cave'), + Pot(0x18, 0x8, PotItem.Nothing, 'Spike Cave', PotFlags.Block)], 281: [Pot(44, 28, PotItem.Heart, 'Blinds Hideout'), Pot(48, 28, PotItem.OneRupee, 'Blinds Hideout'), Pot(76, 28, PotItem.Heart, 'Blinds Hideout'), Pot(80, 28, PotItem.Heart, 'Blinds Hideout')], 282: [Pot(214, 10, PotItem.Heart, 'Palace of Darkness Hint'), Pot(218, 10, PotItem.Heart, 'Palace of Darkness Hint'), Pot(226, 10, PotItem.Heart, 'Palace of Darkness Hint'), Pot(230, 10, PotItem.Heart, 'Palace of Darkness Hint')], - 283: [Pot(24, 53, PotItem.Nothing, 'Cave 45'), Pot(24, 54, PotItem.Heart, 'Cave 45'), Pot(32, 54, PotItem.Heart, 'Cave 45'), Pot(40, 54, PotItem.Heart, 'Cave 45'), Pot(24, 55, PotItem.Heart, 'Cave 45'), Pot(28, 56, PotItem.Heart, 'Cave 45'), - Pot(92, 22, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 22, PotItem.Heart, 'Graveyard Cave'), Pot(92, 23, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 23, PotItem.Heart, 'Graveyard Cave'), Pot(92, 24, PotItem.Bomb, 'Graveyard Cave'), - Pot(96, 24, PotItem.Heart, 'Graveyard Cave'), Pot(92, 25, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 25, PotItem.Heart, 'Graveyard Cave')], - 285: [Pot(60, 6, PotItem.FiveRupees, 'Blinds Hideout'), Pot(64, 6, PotItem.FiveRupees, 'Blinds Hideout'), Pot(60, 7, PotItem.FiveRupees, 'Blinds Hideout'), Pot(64, 7, PotItem.FiveRupees, 'Blinds Hideout'), - Pot(60, 8, PotItem.FiveRupees, 'Blinds Hideout'), Pot(64, 8, PotItem.FiveRupees, 'Blinds Hideout')], - 287: [Pot(174, 28, PotItem.Heart, 'Lumberjack House'), Pot(178, 28, PotItem.Heart, 'Lumberjack House')], + 0x11B: [Pot(24, 0x15, PotItem.Nothing, 'Cave 45', PotFlags.LowerRegion), + Pot(24, 0x16, PotItem.Heart, 'Cave 45', PotFlags.LowerRegion), + Pot(32, 0x16, PotItem.Heart, 'Cave 45', PotFlags.LowerRegion), + Pot(40, 0x16, PotItem.Heart, 'Cave 45', PotFlags.LowerRegion), + Pot(24, 0x17, PotItem.Heart, 'Cave 45', PotFlags.LowerRegion), + Pot(28, 0x18, PotItem.Heart, 'Cave 45', PotFlags.LowerRegion), + Pot(92, 22, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 22, PotItem.Heart, 'Graveyard Cave'), + Pot(92, 23, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 23, PotItem.Heart, 'Graveyard Cave'), + Pot(92, 24, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 24, PotItem.Heart, 'Graveyard Cave'), + Pot(92, 25, PotItem.Bomb, 'Graveyard Cave'), Pot(96, 25, PotItem.Heart, 'Graveyard Cave')], + 0x11D: [Pot(60, 6, PotItem.FiveRupees, 'Blinds Hideout (Top)'), Pot(64, 6, PotItem.FiveRupees, 'Blinds Hideout (Top)'), + Pot(60, 7, PotItem.FiveRupees, 'Blinds Hideout (Top)'), Pot(64, 7, PotItem.FiveRupees, 'Blinds Hideout (Top)'), + Pot(60, 8, PotItem.FiveRupees, 'Blinds Hideout (Top)'), Pot(64, 8, PotItem.FiveRupees, 'Blinds Hideout (Top)')], + 0x11F: [Pot(174, 28, PotItem.Heart, 'Lumberjack House'), Pot(178, 28, PotItem.Heart, 'Lumberjack House')], 292: [Pot(20, 20, PotItem.FiveRupees, '50 Rupee Cave'), Pot(40, 20, PotItem.FiveRupees, '50 Rupee Cave'), Pot(20, 21, PotItem.FiveRupees, '50 Rupee Cave'), Pot(40, 21, PotItem.FiveRupees, '50 Rupee Cave'), Pot(20, 22, PotItem.FiveRupees, '50 Rupee Cave'), Pot(40, 22, PotItem.FiveRupees, '50 Rupee Cave'), Pot(24, 24, PotItem.FiveRupees, '50 Rupee Cave'), Pot(28, 24, PotItem.FiveRupees, '50 Rupee Cave'), Pot(32, 24, PotItem.FiveRupees, '50 Rupee Cave'), Pot(36, 24, PotItem.FiveRupees, '50 Rupee Cave')], 293: [Pot(24, 25, PotItem.FiveRupees, '20 Rupee Cave'), Pot(28, 25, PotItem.FiveRupees, '20 Rupee Cave'), Pot(32, 25, PotItem.FiveRupees, '20 Rupee Cave'), Pot(36, 25, PotItem.FiveRupees, '20 Rupee Cave'), - Pot(88, 22, PotItem.Heart, 'Dev Cave Hint'), Pot(100, 22, PotItem.Heart, 'Dev Cave Hint'), Pot(88, 28, PotItem.Heart, 'Dev Cave Hint'), Pot(100, 28, PotItem.Heart, 'Dev Cave Hint')], - 295: [Pot(24, 25, PotItem.Nothing, 'Hammer Pegs Cave'), Pot(28, 25, PotItem.Nothing, 'Hammer Pegs Cave'), Pot(32, 25, PotItem.Nothing, 'Hammer Pegs Cave'), Pot(36, 25, PotItem.Nothing, 'Hammer Pegs Cave')], + Pot(88, 22, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave'), Pot(100, 22, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave'), Pot(88, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave'), Pot(100, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave')], + 295: [Pot(24, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave'), Pot(28, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave'), Pot(32, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave'), Pot(36, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave')], } def shuffle_pots(world, player): import RaceRandom as random - new_pot_contents = {} + new_pot_contents = PotSecretTable() for supertile in vanilla_pots: old_pots = vanilla_pots[supertile] @@ -295,7 +366,7 @@ def shuffle_pots(world, player): elif old_pot.item == PotItem.Switch: available_pots = (pot for pot in new_pots if (pot.room == old_pot.room or pot.room in movable_switch_rooms[old_pot.room]) and not (pot.flags & PotFlags.NoSwitch)) elif old_pot.item == PotItem.Key: - if world.doorShuffle[player] == 'vanilla' and not world.retro[player] and not world.keydropshuffle[player] and world.logic[player] != 'nologic': + if world.doorShuffle[player] == 'vanilla' and not world.retro[player] and world.keydropshuffle[player] == 'none' and world.logic[player] != 'nologic': available_pots = (pot for pot in new_pots if pot.room not in invalid_key_rooms) else: available_pots = new_pots @@ -328,8 +399,80 @@ def shuffle_pots(world, player): # Rule is created based on barrier world.get_door('Thieves Attic ES', player).barrier(CrystalBarrier.Orange) else: - raise Exception("Switch locattion in room %s requires logic change" % new_pot.room) + raise Exception("Switch location in room %s requires logic change" % new_pot.room) - new_pot_contents[supertile] = new_pots + new_pot_contents.room_map[supertile] = new_pots world.pot_contents[player] = new_pot_contents + + +key_drop_data = { + 'Hyrule Castle - Map Guard Key Drop': ['Drop', (0x09E20C, 0x72), 'in Hyrule Castle', 'Small Key (Escape)'], + 'Hyrule Castle - Boomerang Guard Key Drop': ['Drop', (0x09E204, 0x71), 'in Hyrule Castle', 'Small Key (Escape)'], + 'Hyrule Castle - Key Rat Key Drop': ['Drop', (0x09DB80, 0x21), 'in Hyrule Castle', 'Small Key (Escape)'], + 'Hyrule Castle - Big Key Drop': ['Drop', (0x09E327, 0x80), 'in Hyrule Castle', 'Big Key (Escape)'], + 'Eastern Palace - Dark Square Pot Key': ['Pot', 0xBA, 'in Eastern Palace', 'Small Key (Eastern Palace)'], + 'Eastern Palace - Dark Eyegore Key Drop': ['Drop', (0x09E4F8, 0x99), 'in Eastern Palace', 'Small Key (Eastern Palace)'], + 'Desert Palace - Desert Tiles 1 Pot Key': ['Pot', 0x63, 'in Desert Palace', 'Small Key (Desert Palace)'], + 'Desert Palace - Beamos Hall Pot Key': ['Pot', 0x53, 'in Desert Palace', 'Small Key (Desert Palace)'], + 'Desert Palace - Desert Tiles 2 Pot Key': ['Pot', 0x43, 'in Desert Palace', 'Small Key (Desert Palace)'], + 'Castle Tower - Dark Archer Key Drop': ['Drop', (0x09E7C9, 0xC0), 'in Castle Tower', 'Small Key (Agahnims Tower)'], + 'Castle Tower - Circle of Pots Key Drop': ['Drop', (0x09E688, 0xB0), 'in Castle Tower', 'Small Key (Agahnims Tower)'], + 'Swamp Palace - Pot Row Pot Key': ['Pot', 0x38, 'in Swamp Palace', 'Small Key (Swamp Palace)'], + 'Swamp Palace - Trench 1 Pot Key': ['Pot', 0x37, 'in Swamp Palace', 'Small Key (Swamp Palace)'], + 'Swamp Palace - Hookshot Pot Key': ['Pot', 0x36, 'in Swamp Palace', 'Small Key (Swamp Palace)'], + 'Swamp Palace - Trench 2 Pot Key': ['Pot', 0x35, 'in Swamp Palace', 'Small Key (Swamp Palace)'], + 'Swamp Palace - Waterway Pot Key': ['Pot', 0x16, 'in Swamp Palace', 'Small Key (Swamp Palace)'], + 'Skull Woods - West Lobby Pot Key': ['Pot', 0x56, 'in Skull Woods', 'Small Key (Skull Woods)'], + 'Skull Woods - Spike Corner Key Drop': ['Drop', (0x09DD74, 0x39), 'near Mothula', 'Small Key (Skull Woods)'], + "Thieves' Town - Hallway Pot Key": ['Pot', 0xBC, "in Thieves' Town", 'Small Key (Thieves Town)'], + "Thieves' Town - Spike Switch Pot Key": ['Pot', 0xAB, "in Thieves' Town", 'Small Key (Thieves Town)'], + 'Ice Palace - Jelly Key Drop': ['Drop', (0x09DA21, 0xE), 'in Ice Palace', 'Small Key (Ice Palace)'], + 'Ice Palace - Conveyor Key Drop': ['Drop', (0x09DE08, 0x3E), 'in Ice Palace', 'Small Key (Ice Palace)'], + 'Ice Palace - Hammer Block Key Drop': ['Pot', 0x3F, 'in Ice Palace', 'Small Key (Ice Palace)'], + 'Ice Palace - Many Pots Pot Key': ['Pot', 0x9F, 'in Ice Palace', 'Small Key (Ice Palace)'], + 'Misery Mire - Spikes Pot Key': ['Pot', 0xB3, 'in Misery Mire', 'Small Key (Misery Mire)'], + 'Misery Mire - Fishbone Pot Key': ['Pot', 0xA1, 'in forgotten Mire', 'Small Key (Misery Mire)'], + 'Misery Mire - Conveyor Crystal Key Drop': ['Drop', (0x09E7FB, 0xC1), 'in Misery Mire', 'Small Key (Misery Mire)'], + 'Turtle Rock - Pokey 1 Key Drop': ['Drop', (0x09E70D, 0xB6), 'in Turtle Rock', 'Small Key (Turtle Rock)'], + 'Turtle Rock - Pokey 2 Key Drop': ['Drop', (0x09DA5D, 0x13), 'in Turtle Rock', 'Small Key (Turtle Rock)'], + 'Ganons Tower - Conveyor Cross Pot Key': ['Pot', 0x8B, "in Ganon's Tower", 'Small Key (Ganons Tower)'], + 'Ganons Tower - Double Switch Pot Key': ['Pot', 0x9B, "in Ganon's Tower", 'Small Key (Ganons Tower)'], + 'Ganons Tower - Conveyor Star Pits Pot Key': ['Pot', 0x7B, "in Ganon's Tower", 'Small Key (Ganons Tower)'], + 'Ganons Tower - Mini Helmasaur Key Drop': ['Drop', (0x09DDC4, 0x3D), "atop Ganon's Tower", 'Small Key (Ganons Tower)'] +} + + +class PotSecretTable(object): + def __init__(self): + self.room_map = defaultdict(list) + + def write_pot_data_to_rom(self, rom): + pointer_address = 0x140000 # pots currently in bank 28 + pointer_offset = 0x128 * 2 + empty_address = (pointer_address + pointer_offset - 2) + empty_pointer = pc_to_snes(empty_address) & 0xFFFF + data_pointer = pointer_address + pointer_offset + for room in range(0, 0x128): + if room in self.room_map and any(p for p in self.room_map[room] if not p.empty()): + list_idx = 0 + data_address = pc_to_snes(data_pointer) & 0xFFFF + rom.write_bytes(pointer_address + room * 2, int16_as_bytes(data_address)) + for pot in self.room_map[room]: + if not pot.empty(): + rom.write_bytes(data_pointer + list_idx * 3, pot.pot_data()) + list_idx += 1 + rom.write_bytes(data_pointer + list_idx * 3, [0xFF, 0xFF]) + data_pointer += 3 * list_idx + 2 + else: + rom.write_bytes(pointer_address + room * 2, int16_as_bytes(empty_pointer)) + rom.write_bytes(empty_address, [0xFF, 0xFF]) + + def size(self): + size = 0x128 * 2 + for room in range(0, 0x128): + if room in self.room_map: + pot_list = [p for p in self.room_map[room] if not p.empty()] + if pot_list: + size += len(pot_list) * 3 + 2 + return size diff --git a/Regions.py b/Regions.py index f4bfbcb7..ae004bf8 100644 --- a/Regions.py +++ b/Regions.py @@ -1,6 +1,7 @@ import collections from Items import ItemFactory -from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType +from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType, LocationType, PotItem, PotFlags +from PotShuffle import key_drop_data, vanilla_pots, PotSecretTable def create_regions(world, player): @@ -18,11 +19,13 @@ def create_regions(world, player): 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']), create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']), create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', ["Blind\'s Hideout - Top", - "Blind\'s Hideout - Left", - "Blind\'s Hideout - Right", - "Blind\'s Hideout - Far Left", - "Blind\'s Hideout - Far Right"]), + create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ + "Blind's Hideout - Left", + "Blind's Hideout - Right", + "Blind's Hideout - Far Left", + "Blind's Hideout - Far Right"], + ['Blinds Hideout N']), + create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), create_lw_region(player, 'Zoras River', ['King Zora', 'Zora\'s Ledge']), create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), @@ -55,8 +58,11 @@ def create_regions(world, player): create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop\'s exit', ['Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle', - 'Kakariko Well - Right', 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)']), + create_cave_region(player, 'Kakariko Well (top)', 'a drop\'s exit', + ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', + 'Kakariko Well - Bottom'], + ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), + create_cave_region(player, 'Kakariko Well (back)', 'a drop\'s exit', ['Kakariko Well - Top']), create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), create_lw_region(player, 'Bat Cave Drop Ledge', None, ['Bat Cave Drop']), @@ -106,7 +112,8 @@ def create_regions(world, player): create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), create_lw_region(player, 'Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Teleporter']), - create_cave_region(player, 'Death Mountain Return Cave', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)']), + create_cave_region(player, 'Death Mountain Return Cave (left)', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave E']), + create_cave_region(player, 'Death Mountain Return Cave (right)', 'a connector', None, ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']), create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)']), create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), @@ -119,9 +126,10 @@ def create_regions(world, player): 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle', - 'Paradox Cave Upper - Left', - 'Paradox Cave Upper - Right'], - ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']), + ], + ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), + create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', + 'Paradox Cave Upper - Right']), create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'Fairy Ascension Ledge']), @@ -973,7 +981,8 @@ def create_shops(world, player): def adjust_locations(world, player): - if world.keydropshuffle[player]: + if world.keydropshuffle[player] != 'none': + world.pot_contents[player] = PotSecretTable() for location in key_drop_data.keys(): loc = world.get_location(location, player) key_item = loc.item @@ -982,21 +991,46 @@ def adjust_locations(world, player): loc.forced_item = None loc.item = None loc.event = False - loc.address = key_drop_data[location][1] - loc.player_address = key_drop_data[location][0] - - item_dungeon = key_item.name.split('(')[1][:-1] - item_dungeon = 'Hyrule Castle' if item_dungeon == 'Escape' else item_dungeon + datum = key_drop_data[location] + # todo: set type of location + if 'Drop' == datum[0]: + loc.type = LocationType.Drop + snes_address, room = datum[1] + loc.address = snes_address + else: + loc.type = LocationType.Pot + pot = next(p for p in vanilla_pots[datum[1]] if p.item == PotItem.Key).copy() + loc.pot = pot + world.pot_contents[player].room_map[datum[1]].append(pot) + item_dungeon = key_item.dungeon dungeon = world.get_dungeon(item_dungeon, player) if key_item.smallkey and not world.retro[player]: dungeon.small_keys.append(key_item) elif key_item.bigkey: dungeon.big_key = key_item + if world.keydropshuffle[player] == 'potsanity': + for super_tile, pot_list in vanilla_pots.items(): + for pot_index, pot_orig in enumerate(pot_list): + pot = pot_orig.copy() + if pot.item in [PotItem.Hole, PotItem.Switch]: + world.pot_contents[player].room_map[super_tile].append(pot) + elif pot.item != PotItem.Key: + parent = world.get_region(pot.room, player) + descriptor = 'Large Block' if pot.flags & PotFlags.Block else f'Pot #{pot_index+1}' + pot_location = Location(player, f'{pot.room} {descriptor}', player, hint_text='in a pot', + parent=parent) + world.dynamic_locations.append(pot_location) + pot_location.pot = pot + world.pot_contents[player].room_map[super_tile].append(pot) + pot_location.type = LocationType.Pot + parent.locations.append(pot_location) if world.shopsanity[player]: index = 0 for shop, location_list in shop_to_location_table.items(): for location in location_list: - world.get_location(location, player).address = 0x400000 + index + loc = world.get_location(location, player) + loc.address = 0x400000 + index + loc.type = LocationType.Shop # player address? it is in the shop table index += 1 # unreal events: @@ -1005,6 +1039,7 @@ def adjust_locations(world, player): 'Revealing Light', 'Ice Block Drop', 'Zelda Pickup', 'Zelda Drop Off']: location = world.get_location_unsafe(l, player) if location: + location.type = LocationType.Logical location.real = False @@ -1059,42 +1094,6 @@ shop_table_by_location_id = {0x400000+cnt: x for cnt, x in enumerate(flat_normal shop_table_by_location_id = {**shop_table_by_location_id, **{0x400020+cnt: x for cnt, x in enumerate(flat_retro_shops)}} shop_table_by_location = {y: x for x, y in shop_table_by_location_id.items()} -key_drop_data = { - 'Hyrule Castle - Map Guard Key Drop': [0x140036, 0x140037, 'in Hyrule Castle', 'Small Key (Escape)'], - 'Hyrule Castle - Boomerang Guard Key Drop': [0x140033, 0x140034, 'in Hyrule Castle', 'Small Key (Escape)'], - 'Hyrule Castle - Key Rat Key Drop': [0x14000c, 0x14000d, 'in Hyrule Castle', 'Small Key (Escape)'], - 'Hyrule Castle - Big Key Drop': [0x14003c, 0x14003d, 'in Hyrule Castle', 'Big Key (Escape)'], - 'Eastern Palace - Dark Square Pot Key': [0x14005a, 0x14005b, 'in Eastern Palace', 'Small Key (Eastern Palace)'], - 'Eastern Palace - Dark Eyegore Key Drop': [0x140048, 0x140049, 'in Eastern Palace', 'Small Key (Eastern Palace)'], - 'Desert Palace - Desert Tiles 1 Pot Key': [0x140030, 0x140031, 'in Desert Palace', 'Small Key (Desert Palace)'], - 'Desert Palace - Beamos Hall Pot Key': [0x14002a, 0x14002b, 'in Desert Palace', 'Small Key (Desert Palace)'], - 'Desert Palace - Desert Tiles 2 Pot Key': [0x140027, 0x140028, 'in Desert Palace', 'Small Key (Desert Palace)'], - 'Castle Tower - Dark Archer Key Drop': [0x140060, 0x140061, 'in Castle Tower', 'Small Key (Agahnims Tower)'], - 'Castle Tower - Circle of Pots Key Drop': [0x140051, 0x140052, 'in Castle Tower', 'Small Key (Agahnims Tower)'], - 'Swamp Palace - Pot Row Pot Key': [0x140018, 0x140019, 'in Swamp Palace', 'Small Key (Swamp Palace)'], - 'Swamp Palace - Trench 1 Pot Key': [0x140015, 0x140016, 'in Swamp Palace', 'Small Key (Swamp Palace)'], - 'Swamp Palace - Hookshot Pot Key': [0x140012, 0x140013, 'in Swamp Palace', 'Small Key (Swamp Palace)'], - 'Swamp Palace - Trench 2 Pot Key': [0x14000f, 0x140010, 'in Swamp Palace', 'Small Key (Swamp Palace)'], - 'Swamp Palace - Waterway Pot Key': [0x140009, 0x14000a, 'in Swamp Palace', 'Small Key (Swamp Palace)'], - 'Skull Woods - West Lobby Pot Key': [0x14002d, 0x14002e, 'in Skull Woods', 'Small Key (Skull Woods)'], - 'Skull Woods - Spike Corner Key Drop': [0x14001b, 0x14001c, 'near Mothula', 'Small Key (Skull Woods)'], - "Thieves' Town - Hallway Pot Key": [0x14005d, 0x14005e, "in Thieves' Town", 'Small Key (Thieves Town)'], - "Thieves' Town - Spike Switch Pot Key": [0x14004e, 0x14004f, "in Thieves' Town", 'Small Key (Thieves Town)'], - 'Ice Palace - Jelly Key Drop': [0x140003, 0x140004, 'in Ice Palace', 'Small Key (Ice Palace)'], - 'Ice Palace - Conveyor Key Drop': [0x140021, 0x140022, 'in Ice Palace', 'Small Key (Ice Palace)'], - 'Ice Palace - Hammer Block Key Drop': [0x140024, 0x140025, 'in Ice Palace', 'Small Key (Ice Palace)'], - 'Ice Palace - Many Pots Pot Key': [0x140045, 0x140046, 'in Ice Palace', 'Small Key (Ice Palace)'], - 'Misery Mire - Spikes Pot Key': [0x140054, 0x140055 , 'in Misery Mire', 'Small Key (Misery Mire)'], - 'Misery Mire - Fishbone Pot Key': [0x14004b, 0x14004c, 'in forgotten Mire', 'Small Key (Misery Mire)'], - 'Misery Mire - Conveyor Crystal Key Drop': [0x140063, 0x140064 , 'in Misery Mire', 'Small Key (Misery Mire)'], - 'Turtle Rock - Pokey 1 Key Drop': [0x140057, 0x140058, 'in Turtle Rock', 'Small Key (Turtle Rock)'], - 'Turtle Rock - Pokey 2 Key Drop': [0x140006, 0x140007, 'in Turtle Rock', 'Small Key (Turtle Rock)'], - 'Ganons Tower - Conveyor Cross Pot Key': [0x14003f, 0x140040, "in Ganon's Tower", 'Small Key (Ganons Tower)'], - 'Ganons Tower - Double Switch Pot Key': [0x140042, 0x140043, "in Ganon's Tower", 'Small Key (Ganons Tower)'], - 'Ganons Tower - Conveyor Star Pits Pot Key': [0x140039, 0x14003a, "in Ganon's Tower", 'Small Key (Ganons Tower)'], - 'Ganons Tower - Mini Helmasaur Key Drop': [0x14001e, 0x14001f, "atop Ganon's Tower", 'Small Key (Ganons Tower)'] -} - dungeon_events = [ 'Trench 1 Switch', 'Trench 2 Switch', diff --git a/Rom.py b/Rom.py index e4999acd..f5951045 100644 --- a/Rom.py +++ b/Rom.py @@ -1,6 +1,6 @@ import bisect +import collections import io -import itertools import json import hashlib import logging @@ -15,7 +15,7 @@ try: except ImportError: raise Exception('Could not load BPS module') -from BaseClasses import CollectionState, ShopType, Region, Location, Door, DoorType, RegionType, PotItem +from BaseClasses import CollectionState, ShopType, Region, Location, Door, DoorType, RegionType, PotItem, LocationType from DoorShuffle import compass_data, DROptions, boss_indicator, dungeon_portals from Dungeons import dungeon_music_addresses, dungeon_table from Regions import location_table, shop_to_location_table, retro_shops @@ -23,16 +23,19 @@ from RoomData import DoorKind from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable from Text import Uncle_texts, Ganon1_texts, Ganon_Phase_3_No_Silvers_texts, TavernMan_texts, Sahasrahla2_texts from Text import Triforce_texts, Blind_texts, BombShop2_texts, junk_texts -from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts, LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names +from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts +from Text import LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts +from Text import Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_to_pc from Items import ItemFactory +from ItemList import valid_pot_items from EntranceShuffle import door_addresses, exit_ids, ow_prize_table from source.classes.SFX import randomize_sfx JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '2cfa164d4b66a15406f53ca4750ef59a' +RANDOMIZERBASEHASH = '3ee527f67af25e860ffd4364d2369f0e' class JsonRom(object): @@ -547,6 +550,21 @@ class Sprite(object): return array_chunk(palette_as_colors, 15) +def handle_native_dungeon(location, itemid): + # Keys in their native dungeon should use the original item code for keys + if location.parent_region.dungeon: + if location.parent_region.dungeon.is_dungeon_item(location.item): + if location.item.bigkey: + return 0x32 + if location.item.smallkey: + return 0x24 + if location.item.map: + return 0x33 + if location.item.compass: + return 0x25 + return itemid + + def patch_rom(world, rom, player, team, enemized, is_mystery=False): random.seed(world.rom_seeds[player]) @@ -558,28 +576,47 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): distinguished_prog_bow_loc.item.code = 0x65 # patch items + pot_mw_index = 0 for location in world.get_locations(): if location.player != player: continue - itemid = location.item.code if location.item is not None else 0x5A - + if location.type == LocationType.Pot: + if location.item.name in valid_pot_items and location.item.player == player: + location.pot.item = valid_pot_items[location.item.name] + else: + code = handle_native_dungeon(location, itemid) + standing_item_flag = 0x80 + if location.item.player != player: + standing_item_flag |= 0x40 + rom.write_byte(0x142800 + pot_mw_index * 2, code) + rom.write_byte(0x142800 + pot_mw_index * 2 + 1, location.item.player) + code = pot_mw_index + pot_mw_index += 1 + location.pot.indicator = standing_item_flag + location.pot.standing_item_code = code + continue + elif location.type == LocationType.Drop: + if location.item.player != player: + code = 0xF9 + else: + code = 0xF8 + sprite_pointer = snes_to_pc(location.address) + if code != 0xE4: + rom.write_byte(sprite_pointer, handle_native_dungeon(location, itemid)) + if code == 0xF9: + rom.write_byte(sprite_pointer+1, location.item.player) + else: + rom.write_byte(sprite_pointer+1, 0) + rom.write_byte(sprite_pointer+2, code) + continue if location.address is None or (type(location.address) is int and location.address >= 0x400000): continue if not location.crystal: if location.item is not None: # Keys in their native dungeon should use the original item code for keys - if location.parent_region.dungeon: - if location.parent_region.dungeon.is_dungeon_item(location.item): - if location.item.bigkey: - itemid = 0x32 - if location.item.smallkey: - itemid = 0x24 - if location.item.map: - itemid = 0x33 - if location.item.compass: - itemid = 0x25 + itemid = handle_native_dungeon(location, itemid) if world.remote_items[player]: itemid = list(location_table.keys()).index(location.name) + 1 assert itemid < 0x100 @@ -608,7 +645,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle if world.pot_contents[player]: - write_pots_to_rom(rom, world.pot_contents[player]) + if world.pot_contents[player].size() > 0x2800: + raise Exception('Pot table is too big for current area') + world.pot_contents[player].write_pot_data_to_rom(rom) # patch entrance/exits/holes for region in world.regions: @@ -691,14 +730,19 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if world.logic[player] != 'nologic': dr_flags |= DROptions.Fix_EG + my_locations = world.get_filled_locations(player) + valid_locations = [l for l in my_locations if ((l.type == LocationType.Pot and l.pot.indicator) + or (l.type == LocationType.Drop and not l.forced_item) + or (l.type == LocationType.Normal and not l.forced_item) + or (l.type == LocationType.Shop and world.shopsanity[player]))] # fix hc big key problems (map and compass too) - if world.doorShuffle[player] == 'crossed' or world.keydropshuffle[player]: + if world.doorShuffle[player] == 'crossed' or world.keydropshuffle[player] != 'none': rom.write_byte(0x151f1, 2) rom.write_byte(0x15270, 2) sanctuary = world.get_region('Sanctuary', player) rom.write_byte(0x1597b, sanctuary.dungeon.dungeon_id*2) - update_compasses(rom, world, player) + update_compasses(rom, valid_locations, world, player) def should_be_bunny(region, mode): if mode != 'inverted': @@ -816,19 +860,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # bot: $7A is 1, 7B is 2, etc so 7D=4, 82=9 (zero unknown...) return 0x53+int(num), 0x79+int(num) - credits_total = 216 - if world.keydropshuffle[player]: - credits_total += 33 - if world.shopsanity[player]: - credits_total += 32 - if world.retro[player]: - credits_total += 9 if world.shopsanity[player] else 5 + credits_total = len(valid_locations) - if world.keydropshuffle[player]: - rom.write_byte(0x140000, 1) - multiClientFlags = ((0x1 if world.keydropshuffle[player] else 0) | (0x2 if world.shopsanity[player] else 0) - | (0x4 if world.retro[player] else 0)) - rom.write_byte(0x140001, multiClientFlags) + if world.keydropshuffle[player] != 'none': + rom.write_byte(0x142A50, 1) + rom.write_byte(0x142A51, 1) + rom.write_byte(0x142A52, 216-credits_total) # todo: this is now a delta write_int16(rom, 0x187010, credits_total) # dynamic credits if credits_total != 216: @@ -1153,7 +1190,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x180213, [0x00, 0x01]) # Not a Tournament Seed gametype = 0x04 # item - if world.shuffle[player] != 'vanilla' or world.doorShuffle[player] != 'vanilla' or world.keydropshuffle[player]: + if world.shuffle[player] != 'vanilla' or world.doorShuffle[player] != 'vanilla' or world.keydropshuffle[player] != 'none': gametype |= 0x02 # entrance/door if enemized: gametype |= 0x01 # enemizer @@ -1403,7 +1440,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x18003C, 0x00) elif world.dungeon_counters[player] == 'on': compass_mode = 0x02 # always on - elif world.compassshuffle[player] or world.doorShuffle[player] != 'vanilla' or world.dungeon_counters[player] == 'pickup': + elif (world.compassshuffle[player] or world.doorShuffle[player] != 'vanilla' + or world.dungeon_counters[player] == 'pickup' or world.keydropshuffle != 'none'): compass_mode = 0x01 # show on pickup if world.shuffle[player] != 'vanilla' and world.overworld_map[player] != 'default': compass_mode |= 0x80 # turn on locating dungeons @@ -1577,7 +1615,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0xFED31, 0x0E) # preopen bombable exit rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit - if world.doorShuffle[player] != 'vanilla' or world.keydropshuffle[player]: + if world.doorShuffle[player] != 'vanilla' or world.keydropshuffle[player] != 'none': for room in world.rooms: if room.player == player and room.modified: rom.write_bytes(room.address(), room.rom_data()) @@ -2577,12 +2615,16 @@ def patch_shuffled_dark_sanc(world, rom, player): rom.write_bytes(0x180262, [unknown_1, unknown_2, 0x00]) -def update_compasses(rom, world, player): +def update_compasses(rom, valid_locations, world, player): + dungeon_locations = collections.defaultdict(set) + for l in valid_locations: + if l.parent_region.dungeon: + dungeon_locations[l.parent_region.dungeon.name].add(l) layouts = world.dungeon_layouts[player] provided_dungeon = False for name, builder in layouts.items(): dungeon_id = compass_data[name][4] - rom.write_byte(0x187000 + dungeon_id//2, builder.location_cnt) + rom.write_byte(0x187000 + dungeon_id//2, len(dungeon_locations[name])) if builder.bk_provided: if provided_dungeon: logging.getLogger('').warning('Multiple dungeons have forced BKs! Compass code might need updating?') @@ -2851,29 +2893,3 @@ hash_alphabet = [ "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Net", "Book", "Bottle", "Potion", "Cane", "Cape", "Mirror", "Boots", "Gloves", "Flippers", "Pearl", "Shield", "Tunic", "Heart", "Map", "Compass", "Key" ] - -pot_item_room_table_lookup = 0xDB67 - -### -# Pointer to pot location and contents for each non-empty pot in a supertile -# Format: [(x, y, item)] FF FF (Note: x,y are bit packed to include layer) -pot_item_table = 0xDDE7 -pot_item_table_end = 0xE6B0 - -def write_pots_to_rom(rom, pot_contents): - n = pot_item_table - rom.write_bytes(n, [0xFF,0xFF]) - n += 2 - for i in range(0x140): - if i in pot_contents: - pots = [pot for pot in pot_contents[i] if pot.item != PotItem.Nothing] - if len(pots) > 0: - write_int16(rom, pot_item_room_table_lookup + 2*i, n) - rom.write_bytes(n, list(itertools.chain.from_iterable(((pot.x, pot.y, pot.item) for pot in pots)))) - n += 3*len(pots) + 2 - rom.write_bytes(n - 2, [0xFF,0xFF]) - else: - write_int16(rom, pot_item_room_table_lookup + 2*i, n-2) - else: - write_int16(rom, pot_item_room_table_lookup + 2*i, n-2) - assert n <= pot_item_table_end diff --git a/Rules.py b/Rules.py index fd89ea2b..581424b7 100644 --- a/Rules.py +++ b/Rules.py @@ -3,7 +3,8 @@ import logging from collections import deque import OverworldGlitchRules -from BaseClasses import CollectionState, RegionType, DoorType, Entrance, CrystalBarrier, KeyRuleType +from BaseClasses import CollectionState, RegionType, DoorType, Entrance, CrystalBarrier, KeyRuleType, LocationType +from BaseClasses import PotFlags from Dungeons import dungeon_table from RoomData import DoorKind from OverworldGlitchRules import overworld_glitches_rules @@ -33,6 +34,7 @@ def set_rules(world, player): raise NotImplementedError('Not implemented yet') bomb_rules(world, player) + pot_rules(world, player) if world.logic[player] == 'noglitches': no_glitches_rules(world, player) @@ -584,18 +586,19 @@ def global_rules(world, player): def bomb_rules(world, player): + # todo: kak well, pod hint (bonkable pots), hookshot pot, spike cave pots 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 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'] + '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', + 'Paradox Cave Chest Area NE', 'Blinds Hideout N', 'Kakariko Well (top to back)'] 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: add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player)) bonkable_items = ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right'] - bombable_items = ['Blind\'s Hideout - Top', 'Kakariko Well - Top', 'Chicken House', 'Aginah\'s Cave', 'Graveyard Cave', - 'Paradox Cave Upper - Left', 'Paradox Cave Upper - Right', + bombable_items = ['Chicken House', 'Aginah\'s Cave', 'Graveyard Cave', 'Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom'] for location in bonkable_items: add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) @@ -694,6 +697,35 @@ def bomb_rules(world, player): elif door.kind(world) in [DoorKind.Bombable]: add_rule(door.entrance, lambda state: state.can_use_bombs(player)) + +def pot_rules(world, player): + if world.keydropshuffle[player] == 'potsanity': + blocks = [l for l in world.get_locations() if l.type == LocationType.Pot and l.pot.flags & PotFlags.Block] + for block_pot in blocks: + add_rule(block_pot, lambda state: state.can_lift_rocks(player)) + # todo : hera 5f - crystal config + for l in world.get_region('Hookshot Fairy', player).locations: + if l.type == LocationType.Pot: + add_rule(l, lambda state: state.has('Hookshot', player)) + for l in world.get_region('Spike Cave', player).locations: + if l.type == LocationType.Pot: + add_rule(l, lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and + ((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or + (state.has('Cane of Byrna', player) and + (state.can_extend_magic(player, 12, True) or + (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4))))))) + for l in world.get_region('Dark Desert Hint', player).locations: + if l.type == LocationType.Pot: + add_rule(l, lambda state: state.can_use_bombs(player)) + for l in world.get_region('Palace of Darkness Hint', player).locations: + if l.type == LocationType.Pot: + add_rule(l, lambda state: state.can_use_bombs(player) or state.has_Boots(player)) + for l in world.get_region('Dark Lake Hylia Ledge Spike Cave', player).locations: + if l.type == LocationType.Pot: + add_rule(l, lambda state: state.world.can_take_damage or state.has('Hookshot', player)) + + + def default_rules(world, player): # overworld requirements set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) @@ -1070,6 +1102,10 @@ def add_conditional_lamps(world, player): 'Sewers Rope Room': {'sewer': True, 'entrances': ['Sewers Rope Room Up Stairs', 'Sewers Rope Room North Stairs'], 'locations': []}, 'Sewers Water': {'sewer': True, 'entrances': ['Sewers Water S', 'Sewers Water W'], 'locations': []}, 'Sewers Key Rat': {'sewer': True, 'entrances': ['Sewers Key Rat E', 'Sewers Key Rat Key Door N'], 'locations': ['Hyrule Castle - Key Rat Key Drop']}, + 'Old Man Cave': {'sewer': False, 'entrances': ['Old Man Cave Exit (East)']}, + 'Old Man House Back': {'sewer': False, 'entrances': ['Old Man House Back to Front', 'Old Man House Exit (Top)']}, + 'Death Mountain Return Cave (left)': {'sewer': False, 'entrances': ['Death Mountain Return Cave E', 'Death Mountain Return Cave Exit (West)']}, + 'Death Mountain Return Cave (right)': {'sewer': False, 'entrances': ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']}, } dark_debug_set = set() @@ -1086,17 +1122,12 @@ def add_conditional_lamps(world, player): dark_debug_set.add(region) for ent in info['entrances']: add_conditional_lamp(ent, region, 'Entrance') - for loc in info['locations']: + r = world.get_region(region, player) + for loc in r.locations: add_conditional_lamp(loc, region, 'Location') logging.getLogger('').debug('Non Dark Regions: ' + ', '.join(set(dark_rooms.keys()).difference(dark_debug_set))) - add_conditional_lamp('Old Man', 'Old Man Cave', 'Location') - add_conditional_lamp('Old Man Cave Exit (East)', 'Old Man Cave', 'Entrance') - add_conditional_lamp('Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave', 'Entrance') - add_conditional_lamp('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave', 'Entrance') add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance') - add_conditional_lamp('Old Man House Back to Front', 'Old Man House', 'Entrance') - def open_rules(world, player): # softlock protection as you can reach the sewers small key door with a guard drop key diff --git a/TestSuite.py b/TestSuite.py index ede5ae53..062cb2eb 100644 --- a/TestSuite.py +++ b/TestSuite.py @@ -45,7 +45,7 @@ def main(args=None): test("Vanilla ", "--shuffle vanilla") test("Retro ", "--retro --shuffle vanilla") - test("Keysanity ", "--shuffle vanilla --keydropshuffle --keysanity") + test("Keysanity ", "--shuffle vanilla --keydropshuffle drops_only --keysanity") test("Shopsanity", "--shuffle vanilla --shopsanity") test("Simple ", "--shuffle simple") test("Full ", "--shuffle full") diff --git a/Utils.py b/Utils.py index b8cf5497..14be9b71 100644 --- a/Utils.py +++ b/Utils.py @@ -584,10 +584,11 @@ def extract_data_from_jp_rom(rom): with open(rom, 'rb') as stream: rom_data = bytearray(stream.read()) - rooms = [0x1c, 0x1d, 0x4e] + rooms = range(0, 0x128) # rooms = [0x7b, 0x7c, 0x7d, 0x8b, 0x8c, 0x8d, 0x9b, 0x9c, 0x9d] # rooms = [0x1a, 0x2a, 0xd1] for room in rooms: + # print(f'Room {room:02x}') b2idx = room*2 b3idx = room*3 headerptr = 0x271e2 + b2idx @@ -604,6 +605,7 @@ def extract_data_from_jp_rom(rom): stop, idx = False, 0 ffcnt = 0 mode = 0 + secret_cnt = 0 # first two bytes b1 = rom_data[objectloc+idx] b2 = rom_data[objectloc+idx+1] @@ -625,9 +627,20 @@ def extract_data_from_jp_rom(rom): idx += 2 elif not mode and ffcnt < 3: objectdata.append(b3) + if b3 == 0xFA and ((b2 & 0x3) << 2) | (b1 & 0x3) in [0xf, 0xc]: + # potcalc + vram = ((b1 & 0xFC) >> 1) | ((b2 & 0xFC) << 5) + low = vram & 0xFF + high = (vram & 0xFF00) >> 8 + if ffcnt == 1: + high |= 0x20 + print(f'db {", ".join([f"${low:02x}", f"${high:02x}"])}') + secret_cnt += 1 idx += 3 else: idx += 2 + if secret_cnt: + print(f'Room {room:02x} {secret_cnt}') spriteptr = 0x4d62e + b2idx spriteloc = rom_data[spriteptr] + rom_data[spriteptr+1]*0x100 + 0x40000 secretptr = 0xdb67 + b2idx @@ -651,23 +664,23 @@ def extract_data_from_jp_rom(rom): else: secretdata.append(b3) idx += 3 - print(f'Room {room:02x}') - print(f'HeaderPtr {headerptr:06x}') - print(f'HeaderLoc {headerloc:06x}') - print(f'db {",".join([f"${x:02x}" for x in header])}') - print(f'Obj Length: {len(objectdata)}') - print(f'ObjectPtr {objectptr:06x}') - print(f'ObjectLoc {objectloc:06x}') - for i in range(0, len(objectdata)//16 + 1): - slice = objectdata[i*16:i*16+16] - print(f'db {",".join([f"${x:02x}" for x in slice])}') - print(f'SpritePtr {spriteptr:06x}') - print(f'SpriteLoc {spriteloc:06x}') - print_data_block(spritedata) - print(f'SecretPtr {secretptr:06x}') - print(f'SecretLoc {secretloc:06x}') - print_data_block(secretdata) - print() + # print(f'Room {room:02x}') + # print(f'HeaderPtr {headerptr:06x}') + # print(f'HeaderLoc {headerloc:06x}') + # print(f'db {",".join([f"${x:02x}" for x in header])}') + # print(f'Obj Length: {len(objectdata)}') + # print(f'ObjectPtr {objectptr:06x}') + # print(f'ObjectLoc {objectloc:06x}') + # for i in range(0, len(objectdata)//16 + 1): + # slice = objectdata[i*16:i*16+16] + # print(f'db {",".join([f"${x:02x}" for x in slice])}') + # print(f'SpritePtr {spriteptr:06x}') + # print(f'SpriteLoc {spriteloc:06x}') + # print_data_block(spritedata) + # print(f'SecretPtr {secretptr:06x}') + # print(f'SecretLoc {secretloc:06x}') + # print_data_block(secretdata) +# print() if __name__ == '__main__': diff --git a/asm/doorrando.asm b/asm/doorrando.asm index 8cceeba0..cc134be9 100644 --- a/asm/doorrando.asm +++ b/asm/doorrando.asm @@ -42,6 +42,3 @@ warnpc $279C00 incsrc doortables.asm warnpc $288000 - -; deals with own hooks -incsrc keydropshuffle.asm diff --git a/asm/keydropshuffle.asm b/asm/keydropshuffle.asm deleted file mode 100644 index 253753af..00000000 --- a/asm/keydropshuffle.asm +++ /dev/null @@ -1,181 +0,0 @@ -org $06926e ; <- 3126e - sprite_prep.asm : 2664 (LDA $0B9B : STA $0CBA, X) -jsl SpriteKeyPrep : nop #2 - -org $06d049 ; <- 35049 sprite_absorbable : 31-32 (JSL Sprite_DrawRippleIfInWater : JSR Sprite_DrawAbsorbable) -jsl SpriteKeyDrawGFX : bra + : nop : + - -org $06d180 -jsl BigKeyGet : bcs $07 : nop #5 - -org $06d18d ; <- 3518D - sprite_absorbable.asm : 274 (LDA $7EF36F : INC A : STA $7EF36F) -jsl KeyGet - -org $06f9f3 ; bank06.asm : 6732 (JSL Sprite_LoadProperties) -jsl LoadProperties_PreserveItemMaybe - - - - -org $06d23a -Sprite_DrawAbsorbable: -org $1eff81 -Sprite_DrawRippleIfInWater: -org $0db818 -Sprite_LoadProperties: - -org $288000 ;140000 -ShuffleKeyDrops: -db 0 -MultiClientFlags: ; 140001 -> stored in SRAM at 7ef33d -db 0 - -LootTable: ;PC: 140002 -db $0e, $00, $24 ;; ice jelly key -db $13, $00, $24 ;; pokey 2 -db $16, $00, $24 ;; swamp waterway pot -db $21, $00, $24 ;; key rat -db $35, $00, $24 ;; swamp trench 2 pot -db $36, $00, $24 ;; hookshot pot -db $37, $00, $24 ;; trench 1 pot -db $38, $00, $24 ;; pot row pot -db $39, $00, $24 ;; skull gibdo -db $3d, $00, $24 ;; gt minihelma -db $3e, $00, $24 ;; ice conveyor -db $3f, $00, $24 ;; ice hammer block ??? is this a dungeon secret? -db $43, $00, $24 ;; tiles 2 pot -db $53, $00, $24 ;; beamos hall pot -db $56, $00, $24 ;; skull west lobby pot -db $63, $00, $24 ;; desert tiles 1 pot -db $71, $00, $24 ;; boomerang guard -db $72, $00, $24 ;; hc map guard -db $7b, $00, $24 ;; gt star pits pot -db $80, $00, $32 ;; a big key (for the current dungeon) -db $8b, $00, $24 ;; gt conv cross block -db $9b, $00, $24 ;; gt dlb switch pot -db $9f, $00, $24 ;; ice many pots -db $99, $00, $24 ;; eastern eyegore -db $a1, $00, $24 ;; mire fishbone pot -db $ab, $00, $24 ;; tt spike switch pot -db $b0, $00, $24 ;; tower circle of pots usain -db $b3, $00, $24 ;; mire spikes pot -db $b6, $00, $24 ;; pokey 1 -db $ba, $00, $24 ;; eastern dark pot -db $bc, $00, $24 ;; tt hallway pot -db $c0, $00, $24 ;; tower dark archer -db $c1, $00, $24 ;; mire glitchy jelly -db $ff, $00, $ff -;140068 - -KeyTable: -db $a0, $a0, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9, $aa, $ab, $ac, $ad - -SpriteKeyPrep: -{ - lda $0b9b : sta $0cba, x ; what we wrote over - pha - lda.l ShuffleKeyDrops : beq + - phx - ldx #$fd - - inx #3 : lda.l LootTable, x : cmp #$ff : beq ++ : cmp $a0 : bne - - inx : lda.l LootTable, x : sta !MULTIWORLD_SPRITEITEM_PLAYER_ID - inx : lda.l LootTable, x - plx : sta $0e80, x - cmp #$24 : bne +++ - lda $a0 : cmp #$80 : bne + : lda #$24 - +++ jsl PrepDynamicTile : bra + - ++ plx : lda #$24 : sta $0e80, x - + pla - rtl -} - -SpriteKeyDrawGFX: -{ - jsl Sprite_DrawRippleIfInWater - pha - lda.l ShuffleKeyDrops : bne + - - pla - phk : pea.w .jslrtsreturn-1 - pea.w $068014 ; an rtl address - 1 in Bank06 - jml Sprite_DrawAbsorbable - .jslrtsreturn - rtl - + lda $0e80, x - cmp #$24 : bne + - lda $a0 : cmp #$80 : bne - : lda #$24 - + jsl DrawDynamicTile ; see DrawHeartPieceGFX if problems - cmp #$03 : bne + - pha : lda $0e60, x : ora.b #$20 : sta $0E60, x : pla - + - jsl.l Sprite_DrawShadowLong - - pla : rtl -} - -KeyGet: -{ - lda $7ef36f ; what we wrote over - pha - lda.l ShuffleKeyDrops : bne + - - pla : rtl - + ldy $0e80, x - lda $a0 : cmp #$87 : bne + - jsr ShouldKeyBeCountedForDungeon : bcc - - jsl CountChestKeyLong : bra - - + sty $00 - jsr KeyGetPlayer : sta !MULTIWORLD_ITEM_PLAYER_ID - lda !MULTIWORLD_ITEM_PLAYER_ID : bne .receive - phx - lda $040c : lsr : tax - lda $00 : CMP.l KeyTable, x : bne + - - JSL.l FullInventoryExternal : jsl CountChestKeyLong : plx : pla : rtl - + cmp #$af : beq - ; universal key - cmp #$24 : beq - ; small key for this dungeon - plx - .receive - jsl.l $0791b3 ; Player_HaltDashAttackLong - jsl.l Link_ReceiveItem - pla : dec : rtl -} - -; Input Y - the item type -ShouldKeyBeCountedForDungeon: -{ - phx - lda $040c : lsr : tax - tya : cmp KeyTable, x : bne + - - plx : sec : rts - + cmp #$24 : beq - - plx : clc : rts -} - -BigKeyGet: -{ - lda.l ShuffleKeyDrops : bne + - - stz $02e9 : ldy.b #$32 ; what we wrote over - phx : jsl Link_ReceiveItem : plx ; what we wrote over - clc : rtl - + - ldy $0e80, x - cpy #$32 : beq - - + sec : rtl -} - -KeyGetPlayer: -{ - phx - ldx #$fd - - inx #3 : lda.l LootTable, x : cmp #$ff : beq ++ : cmp $a0 : bne - - ++ inx : lda.l LootTable, x - plx - rts -} - -LoadProperties_PreserveItemMaybe: -{ - lda.l ShuffleKeyDrops : bne + - JML Sprite_LoadProperties - + lda $0e80, x : pha - jsl Sprite_LoadProperties - pla : sta $0e80, x - rtl -} diff --git a/data/base2current.bps b/data/base2current.bps index 328d0f8196c9f52c4e8bb095e2ff83a9157dc2ea..0e6d8e39bdf3d6a570fd69fbcf3ff66fa12d8f97 100644 GIT binary patch delta 21437 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 ZxljpGD%cn2x>MWb0e%V9^waF^{|^BN-_`&C delta 21563 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