diff --git a/BaseClasses.py b/BaseClasses.py index c0248d11..cda3ff61 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -36,7 +36,7 @@ class World(object): self.algorithm = algorithm self.dungeons = [] self.regions = [] - self.shops = [] + self.shops = {} self.itempool = [] self.seed = None self.precollected_items = [] @@ -130,6 +130,7 @@ class World(object): set_player_attr('potshuffle', False) set_player_attr('pot_contents', None) + set_player_attr('shopsanity', False) set_player_attr('keydropshuffle', False) set_player_attr('mixed_travel', 'prevent') set_player_attr('standardize_palettes', 'standardize') @@ -610,7 +611,7 @@ class CollectionState(object): return self.prog_items[item, player] >= count def can_buy_unlimited(self, item, player): - for shop in self.world.shops: + for shop in self.world.shops[player]: if shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self): return True return False @@ -674,7 +675,7 @@ class CollectionState(object): def can_shoot_arrows(self, player): if self.world.retro[player]: #todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe - return self.has('Bow', player) and self.can_buy_unlimited('Single Arrow', player) + return self.has('Bow', player) and (self.can_buy_unlimited('Single Arrow', player) or self.has('Single Arrow', player)) return self.has('Bow', player) def can_get_good_bee(self, player): @@ -1640,6 +1641,7 @@ class Location(object): self.access_rule = lambda state: True self.item_rule = lambda item: True self.player = player + self.skip = False 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))) @@ -1677,7 +1679,9 @@ class Location(object): class Item(object): - def __init__(self, name='', advancement=False, priority=False, type=None, code=None, pedestal_hint=None, pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None, hint_text=None, player=None): + def __init__(self, name='', advancement=False, priority=False, type=None, code=None, price=999, pedestal_hint=None, + pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None, + hint_text=None, player=None): self.name = name self.advancement = advancement self.priority = priority @@ -1690,6 +1694,7 @@ class Item(object): self.fluteboy_credit_text = fluteboy_credit self.hint_text = hint_text self.code = code + self.price = price self.location = None self.world = None self.player = player @@ -1853,12 +1858,12 @@ class Spoiler(object): self.locations['Dark World'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in dw_locations]) listed_locations.update(dw_locations) - cave_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.type == RegionType.Cave] + cave_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.type == RegionType.Cave and not loc.skip] self.locations['Caves'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in cave_locations]) listed_locations.update(cave_locations) for dungeon in self.world.dungeons: - dungeon_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.dungeon == dungeon] + dungeon_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.dungeon == dungeon and not loc.forced_item] self.locations[str(dungeon)] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in dungeon_locations]) listed_locations.update(dungeon_locations) @@ -1868,17 +1873,19 @@ class Spoiler(object): listed_locations.update(other_locations) self.shops = [] - for shop in self.world.shops: - if not shop.custom: - continue - shopdata = {'location': str(shop.region), - 'type': 'Take Any' if shop.type == ShopType.TakeAny else 'Shop' - } - for index, item in enumerate(shop.inventory): - if item is None: + for player in range(1, self.world.players + 1): + for shop in self.world.shops[player]: + if not shop.custom: continue - shopdata['item_{}'.format(index)] = "{} - {}".format(item['item'], item['price']) if item['price'] else item['item'] - self.shops.append(shopdata) + shopdata = {'location': str(shop.region), + 'type': 'Take Any' if shop.type == ShopType.TakeAny else 'Shop' + } + for index, item in enumerate(shop.inventory): + if item is None: + continue + # todo: indicate player? might be fine + shopdata[f'item_{index}'] = f"{item['item']} — {item['price']}" if item['price'] else item['item'] + self.shops.append(shopdata) for player in range(1, self.world.players + 1): self.bosses[str(player)] = OrderedDict() diff --git a/CLI.py b/CLI.py index 35204b65..bcfc2181 100644 --- a/CLI.py +++ b/CLI.py @@ -93,7 +93,7 @@ def parse_cli(argv, no_defaults=False): 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', - 'remote_items', 'keydropshuffle', 'mixed_travel', 'standardize_palettes']: + 'remote_items', 'shopsanity', 'keydropshuffle', 'mixed_travel', 'standardize_palettes']: value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) if player == 1: setattr(ret, name, {1: value}) @@ -133,6 +133,7 @@ def parse_settings(): "enemy_health": "default", "enemizercli": os.path.join(".", "EnemizerCLI", "EnemizerCLI.Core"), + "shopsanity": False, "keydropshuffle": False, "mapshuffle": False, "compassshuffle": False, diff --git a/Fill.py b/Fill.py index bc841a5b..a4fe672f 100644 --- a/Fill.py +++ b/Fill.py @@ -2,6 +2,7 @@ import random import logging from BaseClasses import CollectionState +from Regions import shop_to_location_table class FillError(RuntimeError): @@ -374,6 +375,22 @@ def flood_items(world): itempool.remove(item_to_place) break + +def sell_keys(world, player): + choices = [] + shop_map = {} + for shop in world.shops[player]: + if shop.region.name in shop_to_location_table: + choices.append(shop.region.name) + shop_map[shop.region.name] = shop + key_seller = random.choice(choices) + location = random.choice(shop_to_location_table[key_seller]) + universal_key = next(item for item in world.itempool if item.name == 'Small Key (Universal)' and item.player == player) + world.push_item(world.get_location(location, player), universal_key, collect=False) + shop_map[key_seller].add_inventory(0, 'Small Key (Universal)', 100) # will be fixed later in customize shops + world.itempool.remove(universal_key) + + def balance_multiworld_progression(world): state = CollectionState(world) checked_locations = [] diff --git a/InvertedRegions.py b/InvertedRegions.py index 71c26fc9..9e439093 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -2,7 +2,7 @@ import collections from BaseClasses import RegionType from Regions import create_lw_region, create_dw_region, create_cave_region, create_dungeon_region, create_menu_region - +# todo: shopsanity locations def create_inverted_regions(world, player): world.regions += [ diff --git a/ItemList.py b/ItemList.py index ae05e9ee..aa93602b 100644 --- a/ItemList.py +++ b/ItemList.py @@ -6,7 +6,8 @@ from BaseClasses import Region, RegionType, Shop, ShopType, Location from Bosses import place_bosses from Dungeons import get_dungeon_item_pool from EntranceShuffle import connect_entrance -from Fill import FillError, fill_restrictive, fast_fill +from Regions import shop_to_location_table, retro_shops +from Fill import FillError, fill_restrictive from Items import ItemFactory import source.classes.constants as CONST @@ -304,6 +305,13 @@ def generate_itempool(world, player): world.get_location(location, player).event = True world.get_location(location, player).locked = True + if world.shopsanity[player]: + for shop in world.shops[player]: + if shop.region.name in shop_to_location_table: + for index, slot in enumerate(shop.inventory): + if slot: + pool.append(slot['item']) + items = ItemFactory(pool, player) world.lamps_needed_for_dark_rooms = lamps_needed_for_dark_rooms @@ -371,6 +379,7 @@ take_any_locations = [ 'Palace of Darkness Hint', 'East Dark World Hint', 'Archery Game', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint'] + def set_up_take_anys(world, player): if world.mode[player] == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations: take_any_locations.remove('Dark Sanctuary Hint') @@ -385,38 +394,43 @@ def set_up_take_anys(world, player): entrance = world.get_region(reg, player).entrances[0] connect_entrance(world, entrance, old_man_take_any, player) entrance.target = 0x58 - old_man_take_any.shop = Shop(old_man_take_any, 0x0112, ShopType.TakeAny, 0xE2, True, True) - world.shops.append(old_man_take_any.shop) + old_man_take_any.shop = Shop(old_man_take_any, 0x0112, ShopType.TakeAny, 0xE2, True, not world.shopsanity[player]) + world.shops[player].append(old_man_take_any.shop) - swords = [item for item in world.itempool if item.type == 'Sword' and item.player == player] - if swords: - sword = random.choice(swords) - world.itempool.remove(sword) + sword = next((item for item in world.itempool if item.type == 'Sword' and item.player == player), None) + if sword: world.itempool.append(ItemFactory('Rupees (20)', player)) + if not world.shopsanity[player]: + world.itempool.remove(sword) old_man_take_any.shop.add_inventory(0, sword.name, 0, 0, create_location=True) else: - old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0) + if world.shopsanity[player]: + world.itempool.append(ItemFactory('Rupees (300)', player)) + old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0, create_location=world.shopsanity[player]) + take_any_type = ShopType.Shop if world.shopsanity[player] else ShopType.TakeAny for num in range(4): take_any = Region("Take-Any #{}".format(num+1), RegionType.Cave, 'a cave of choice', player) world.regions.append(take_any) world.dynamic_regions.append(take_any) - target, room_id = random.choice([(0x58, 0x0112), (0x60, 0x010F), (0x46, 0x011F)]) reg = regions.pop() entrance = world.get_region(reg, player).entrances[0] connect_entrance(world, entrance, take_any, player) entrance.target = target - take_any.shop = Shop(take_any, room_id, ShopType.TakeAny, 0xE3, True, True) - world.shops.append(take_any.shop) - take_any.shop.add_inventory(0, 'Blue Potion', 0, 0) - take_any.shop.add_inventory(1, 'Boss Heart Container', 0, 0) + take_any.shop = Shop(take_any, room_id, take_any_type, 0xE3, True, not world.shopsanity[player]) + world.shops[player].append(take_any.shop) + take_any.shop.add_inventory(0, 'Blue Potion', 0, 0, create_location=world.shopsanity[player]) + take_any.shop.add_inventory(1, 'Boss Heart Container', 0, 0, create_location=world.shopsanity[player]) + if world.shopsanity[player]: + world.itempool.append(ItemFactory('Blue Potion', player)) + world.itempool.append(ItemFactory('Boss Heart Container', player)) world.initialize_regions() def create_dynamic_shop_locations(world, player): - for shop in world.shops: + for shop in world.shops[player]: if shop.region.player == player: for i, item in enumerate(shop.inventory): if item is None: @@ -428,9 +442,10 @@ def create_dynamic_shop_locations(world, player): world.clear_location_cache() - world.push_item(loc, ItemFactory(item['item'], player), False) - loc.event = True - loc.locked = True + if not world.shopsanity[player]: + world.push_item(loc, ItemFactory(item['item'], player), False) + loc.event = True + loc.locked = True def fill_prizes(world, attempts=15): @@ -462,20 +477,125 @@ def fill_prizes(world, attempts=15): def set_up_shops(world, player): - # TODO: move hard+ mode changes for sheilds here, utilizing the new shops - if world.retro[player]: - rss = world.get_region('Red Shield Shop', player).shop - if not rss.locked: - rss.custom = True - rss.add_inventory(2, 'Single Arrow', 80) - for shop in random.sample([s for s in world.shops if not s.locked and s.region.player == player], 5): - shop.custom = True - shop.locked = True - shop.add_inventory(0, 'Single Arrow', 80) - shop.add_inventory(1, 'Small Key (Universal)', 100) - shop.add_inventory(2, 'Bombs (10)', 50) - rss.locked = True + if world.shopsanity[player]: + removals = [next(item for item in world.itempool if item.name == 'Arrows (10)' and item.player == player)] + red_pots = [item for item in world.itempool if item.name == 'Red Potion' and item.player == player][:5] + shields_n_hearts = [item for item in world.itempool if item.name in ['Blue Shield', 'Small Heart'] and item.player == player] + removals.extend(red_pots) + removals.extend(random.sample(shields_n_hearts, 5)) + for remove in removals: + world.itempool.remove(remove) + for i in range(6): + arrow_item = ItemFactory('Single Arrow', player) + arrow_item.advancement = True + world.itempool.append(arrow_item) + for i in range(5): + world.itempool.append(ItemFactory('Small Key (Universal)', player)) + # TODO: move hard+ mode changes for shields here, utilizing the new shops + else: + rss = world.get_region('Red Shield Shop', player).shop + if not rss.locked: + rss.custom = True + rss.add_inventory(2, 'Single Arrow', 80) + for shop in random.sample([s for s in world.shops if not s.locked and s.region.player == player], 5): + shop.custom = True + shop.locked = True + shop.add_inventory(0, 'Single Arrow', 80) + shop.add_inventory(1, 'Small Key (Universal)', 100) + shop.add_inventory(2, 'Bombs (10)', 50) + rss.locked = True + + +def customize_shops(world, player): + found_bomb_upgrade, found_arrow_upgrade = False, False + possible_replacements = [] + shops_to_customize = shop_to_location_table.copy() + if world.retro[player]: + shops_to_customize.update(retro_shops) + for shop_name, loc_list in shops_to_customize.items(): + shop = world.get_region(shop_name, player).shop + shop.custom = True + shop.clear_inventory() + for idx, loc in enumerate(loc_list): + location = world.get_location(loc, player) + item = location.item + max_repeat = 1 + if shop_name not in retro_shops: + if item.name in repeatable_shop_items: + max_repeat = 0 + if item.name in ['Bomb Upgrade (+5)', 'Arrow Upgrade (+5)']: + if item.name == 'Bomb Upgrade (+5)': + found_bomb_upgrade = True + if item.name == 'Arrow Upgrade (+5)': + found_arrow_upgrade = True + max_repeat = 7 + if shop_name in retro_shops: + price = 0 + else: + price = 120 if shop_name == 'Potion Shop' and item.name == 'Red Potion' else item.price + if world.retro[player] and item.name == 'Single Arrow': + price = 80 + # randomize price + shop.add_inventory(idx, item.name, randomize_price(price), max_repeat) + if item.name in cap_replacements and shop_name not in retro_shops: + possible_replacements.append((shop, idx, location, item)) + # todo: randomize shopkeeper + # handle capacity upgrades - randomly choose a bomb bunch or arrow bunch to become capacity upgrades + if not found_bomb_upgrade and len(possible_replacements) > 0: + choices = [] + for shop, idx, loc, item in possible_replacements: + if item.name in ['Bombs (3)', 'Bombs (10)']: + choices.append((shop, idx, loc, item)) + if len(choices) > 0: + shop, idx, loc, item = random.choice(choices) + upgrade = ItemFactory('Bomb Upgrade (+5)', player) + shop.add_inventory(idx, upgrade.name, randomize_price(upgrade.price), 6, + item.name, randomize_price(item.price)) + loc.item = upgrade + upgrade.location = loc + if not found_arrow_upgrade and len(possible_replacements) > 0: + choices = [] + for shop, idx, loc, item in possible_replacements: + if item.name == 'Arrows (10)' or (item.name == 'Single Arrow' and not world.retro[player]): + choices.append((shop, idx, loc, item)) + if len(choices) > 0: + shop, idx, loc, item = random.choice(choices) + upgrade = ItemFactory('Arrow Upgrade (+5)', player) + shop.add_inventory(idx, upgrade.name, randomize_price(upgrade.price), 6, + item.name, randomize_price(item.price)) + loc.item = upgrade + upgrade.location = loc + change_shop_items_to_rupees(world, player, shops_to_customize) + + +def randomize_price(price): + half_price = price // 2 + max_price = price - half_price + if max_price % 5 == 0: + max_price //= 5 + return random.randint(0, max_price) * 5 + half_price + else: + return price + + +def change_shop_items_to_rupees(world, player, shops): + locations = world.get_filled_locations(player) + for location in locations: + if location.item.name in shop_transfer.keys() and location.parent_region not in shops: + new_item = ItemFactory(shop_transfer[location.item.name], location.item.player) + location.item = new_item + + +repeatable_shop_items = ['Single Arrow', 'Arrows (10)', 'Bombs (3)', 'Bombs (10)', 'Red Potion', 'Small Heart', + 'Blue Shield', 'Red Shield', 'Bee', 'Small Key (Universal)'] + + +cap_replacements = ['Single Arrow', 'Arrows (10)', 'Bombs (3)', 'Bombs (10)'] + + +shop_transfer = {'Red Potion': 'Rupees (100)', 'Bee': 'Rupees (5)', 'Blue Potion': 'Rupees (100)', + 'Blue Shield': 'Rupees (50)', 'Red Shield': 'Rupees (300)'} def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, door_shuffle): diff --git a/Items.py b/Items.py index b20ebe35..e5d91d4a 100644 --- a/Items.py +++ b/Items.py @@ -11,8 +11,8 @@ def ItemFactory(items, player): singleton = True for item in items: if item in item_table: - advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text = item_table[item] - ret.append(Item(item, advancement, priority, type, code, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text, player)) + advancement, priority, type, code, price, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text = item_table[item] + ret.append(Item(item, advancement, priority, type, code, price, pedestal_hint, pedestal_credit, sickkid_credit, zora_credit, witch_credit, fluteboy_credit, hint_text, player)) else: logging.getLogger('').warning('Unknown Item: %s', item) return None @@ -23,167 +23,167 @@ def ItemFactory(items, player): # Format: Name: (Advancement, Priority, Type, ItemCode, Pedestal Hint Text, Pedestal Credit Text, Sick Kid Credit Text, Zora Credit Text, Witch Credit Text, Flute Boy Credit Text, Hint Text) -item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'the Bow'), - 'Progressive Bow': (True, False, None, 0x64, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'a Bow'), - 'Progressive Bow (Alt)': (True, False, None, 0x65, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'a Bow'), - 'Book of Mudora': (True, False, None, 0x1D, 'This is a\nparadox?!', 'and the story book', 'the scholarly kid', 'moon runes for sale', 'drugs for literacy', 'book-worm boy can read again', 'the Book'), - 'Hammer': (True, False, None, 0x09, 'stop\nhammer time!', 'and m c hammer', 'hammer-smashing kid', 'm c hammer for sale', 'stop... hammer time', 'stop, hammer time', 'the hammer'), - 'Hookshot': (True, False, None, 0x0A, 'BOING!!!\nBOING!!!\nBOING!!!', 'and the tickle beam', 'tickle-monster kid', 'tickle beam for sale', 'witch and tickle boy', 'beam boy tickles again', 'the Hookshot'), - 'Magic Mirror': (True, False, None, 0x1A, 'Isn\'t your\nreflection so\npretty?', 'the face reflector', 'the narcissistic kid', 'your face for sale', 'trades looking-glass', 'narcissistic boy is happy again', 'the Mirror'), - 'Ocarina': (True, False, None, 0x14, 'Save the duck\nand fly to\nfreedom!', 'and the duck call', 'the duck-call kid', 'duck call for sale', 'duck-calls for trade', 'ocarina boy plays again', 'the Flute'), - 'Pegasus Boots': (True, False, None, 0x4B, 'Gotta go fast!', 'and the sprint shoes', 'the running-man kid', 'sprint shoe for sale', 'shrooms for speed', 'gotta-go-fast boy runs again', 'the Boots'), - 'Power Glove': (True, False, None, 0x1B, 'Now you can\nlift weak\nstuff!', 'and the grey mittens', 'body-building kid', 'lift glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'the glove'), - 'Cape': (True, False, None, 0x19, 'Wear this to\nbecome\ninvisible!', 'the camouflage cape', 'red riding-hood kid', 'red hood for sale', 'hood from a hood', 'dapper boy hides again', 'the cape'), - 'Mushroom': (True, False, None, 0x29, 'I\'m a fun guy!\n\nI\'m a funghi!', 'and the legal drugs', 'the drug-dealing kid', 'legal drugs for sale', 'shroom swap', 'shroom boy sells drugs again', 'the mushroom'), - 'Shovel': (True, False, None, 0x13, 'Can\n You\n Dig it?', 'and the spade', 'archaeologist kid', 'dirt spade for sale', 'can you dig it', 'shovel boy digs again', 'the shovel'), - 'Lamp': (True, False, None, 0x12, 'Baby, baby,\nbaby.\nLight my way!', 'and the flashlight', 'light-shining kid', 'flashlight for sale', 'fungus for illumination', 'illuminated boy can see again', 'the lamp'), - 'Magic Powder': (True, False, None, 0x0D, 'you can turn\nanti-faeries\ninto faeries', 'and the magic sack', 'the sack-holding kid', 'magic sack for sale', 'the witch and assistant', 'magic boy plays marbles again', 'the powder'), - 'Moon Pearl': (True, False, None, 0x1F, ' Bunny Link\n be\n gone!', 'and the jaw breaker', 'fortune-telling kid', 'lunar orb for sale', 'shrooms for moon rock', 'moon boy plays ball again', 'the moon pearl'), - 'Cane of Somaria': (True, False, None, 0x15, 'I make blocks\nto hold down\nswitches!', 'and the red blocks', 'the block-making kid', 'block stick for sale', 'block stick for trade', 'cane boy makes blocks again', 'the red cane'), - 'Fire Rod': (True, False, None, 0x07, 'I\'m the hot\nrod. I make\nthings burn!', 'and the flamethrower', 'fire-starting kid', 'rage rod for sale', 'fungus for rage-rod', 'firestarter boy burns again', 'the fire rod'), - 'Flippers': (True, False, None, 0x1E, 'fancy a swim?', 'and the toewebs', 'the swimming kid', 'finger webs for sale', 'shrooms let you swim', 'swimming boy swims again', 'the flippers'), - 'Ice Rod': (True, False, None, 0x08, 'I\'m the cold\nrod. I make\nthings freeze!', 'and the freeze ray', 'the ice-bending kid', 'freeze ray for sale', 'fungus for ice-rod', 'ice-cube boy freezes again', 'the ice rod'), - 'Titans Mitts': (True, False, None, 0x1C, 'Now you can\nlift heavy\nstuff!', 'and the golden glove', 'body-building kid', 'carry glove for sale', 'fungus for bling-gloves', 'body-building boy has gold again', 'the mitts'), - 'Bombos': (True, False, None, 0x0F, 'Burn, baby,\nburn! Fear my\nring of fire!', 'and the swirly coin', 'coin-collecting kid', 'swirly coin for sale', 'shrooms for swirly-coin', 'medallion boy melts room again', 'Bombos'), - 'Ether': (True, False, None, 0x10, 'This magic\ncoin freezes\neverything!', 'and the bolt coin', 'coin-collecting kid', 'bolt coin for sale', 'shrooms for bolt-coin', 'medallion boy sees floor again', 'Ether'), - 'Quake': (True, False, None, 0x11, 'Maxing out the\nRichter scale\nis what I do!', 'and the wavy coin', 'coin-collecting kid', 'wavy coin for sale', 'shrooms for wavy-coin', 'medallion boy shakes dirt again', 'Quake'), - 'Bottle': (True, False, None, 0x16, 'Now you can\nstore potions\nand stuff!', 'and the terrarium', 'the terrarium kid', 'terrarium for sale', 'special promotion', 'bottle boy has terrarium again', 'a Bottle'), - 'Bottle (Red Potion)': (True, False, None, 0x2B, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a Bottle'), - 'Bottle (Green Potion)': (True, False, None, 0x2C, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a Bottle'), - 'Bottle (Blue Potion)': (True, False, None, 0x2D, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a Bottle'), - 'Bottle (Fairy)': (True, False, None, 0x3D, 'Save me and I will revive you', 'and the captive', 'the tingle kid', 'hostage for sale', 'fairy dust and shrooms', 'bottle boy has friend again', 'a Bottle'), - 'Bottle (Bee)': (True, False, None, 0x3C, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a Bottle'), - 'Bottle (Good Bee)': (True, False, None, 0x48, 'I will sting your foes a whole lot!', 'and the sparkle sting', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has beetor again', 'a Bottle'), - 'Master Sword': (True, False, 'Sword', 0x50, 'I beat barries and pigs alike', 'and the master sword', 'sword-wielding kid', 'glow sword for sale', 'fungus for blue slasher', 'sword boy fights again', 'the Master Sword'), - 'Tempered Sword': (True, False, 'Sword', 0x02, 'I stole the\nblacksmith\'s\njob!', 'the tempered sword', 'sword-wielding kid', 'flame sword for sale', 'fungus for red slasher', 'sword boy fights again', 'the Tempered Sword'), - 'Fighter Sword': (True, False, 'Sword', 0x49, 'A pathetic\nsword rests\nhere!', 'the tiny sword', 'sword-wielding kid', 'tiny sword for sale', 'fungus for tiny slasher', 'sword boy fights again', 'the small sword'), - 'Golden Sword': (True, False, 'Sword', 0x03, 'The butter\nsword rests\nhere!', 'and the butter sword', 'sword-wielding kid', 'butter for sale', 'cap churned to butter', 'sword boy fights again', 'the Golden Sword'), - 'Progressive Sword': (True, False, 'Sword', 0x5E, 'a better copy\nof your sword\nfor your time', 'the unknown sword', 'sword-wielding kid', 'sword for sale', 'fungus for some slasher', 'sword boy fights again', 'a sword'), - 'Progressive Glove': (True, False, None, 0x61, 'a way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a glove'), - 'Silver Arrows': (True, False, None, 0x58, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again', 'the silver arrows'), - 'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x01], None, None, None, None, None, None, None), - 'Blue Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], None, None, None, None, None, None, None), - 'Red Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], None, None, None, None, None, None, None), - 'Triforce': (True, False, None, 0x6A, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'), - 'Power Star': (True, False, None, 0x6B, 'a small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'), - 'Triforce Piece': (True, False, None, 0x6C, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce Piece'), - 'Crystal 1': (True, False, 'Crystal', [0x02, 0x34, 0x64, 0x40, 0x7F, 0x06], None, None, None, None, None, None, None), - 'Crystal 2': (True, False, 'Crystal', [0x10, 0x34, 0x64, 0x40, 0x79, 0x06], None, None, None, None, None, None, None), - 'Crystal 3': (True, False, 'Crystal', [0x40, 0x34, 0x64, 0x40, 0x6C, 0x06], None, None, None, None, None, None, None), - 'Crystal 4': (True, False, 'Crystal', [0x20, 0x34, 0x64, 0x40, 0x6D, 0x06], None, None, None, None, None, None, None), - 'Crystal 5': (True, False, 'Crystal', [0x04, 0x32, 0x64, 0x40, 0x6E, 0x06], None, None, None, None, None, None, None), - 'Crystal 6': (True, False, 'Crystal', [0x01, 0x32, 0x64, 0x40, 0x6F, 0x06], None, None, None, None, None, None, None), - 'Crystal 7': (True, False, 'Crystal', [0x08, 0x34, 0x64, 0x40, 0x7C, 0x06], None, None, None, None, None, None, None), - 'Single Arrow': (False, False, None, 0x43, 'a lonely arrow\nsits here.', 'and the arrow', 'stick-collecting kid', 'sewing needle for sale', 'fungus for arrow', 'archer boy sews again', 'an arrow'), - 'Arrows (10)': (False, False, None, 0x44, 'This will give\nyou ten shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'ten arrows'), - 'Arrow Upgrade (+10)': (False, False, None, 0x54, '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, '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, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), - 'Bombs (3)': (False, False, None, 0x28, '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, '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, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), - 'Bomb Upgrade (+5)': (False, False, None, 0x51, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), - 'Blue Mail': (False, True, None, 0x22, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), - 'Red Mail': (False, True, None, 0x23, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), - 'Progressive Armor': (False, True, None, 0x60, 'time for a\nchange of\nclothes?', 'and the unknown hat', 'the protected kid', 'new hat for sale', 'the clothing store', 'tailor boy has threads again', 'some armor'), - 'Blue Boomerang': (True, False, None, 0x0C, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again', 'the blue boomerang'), - 'Red Boomerang': (True, False, None, 0x2A, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again', 'the red boomerang'), - 'Blue Shield': (False, True, None, 0x04, 'Now you can\ndefend against\npebbles!', 'and the stone blocker', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'the blue shield'), - 'Red Shield': (False, True, None, 0x05, 'Now you can\ndefend against\nfireballs!', 'and the shot blocker', 'shield-wielding kid', 'fire shield for sale', 'fungus for fire shield', 'shield boy defends again', 'the red shield'), - 'Mirror Shield': (True, False, None, 0x06, 'Now you can\ndefend against\nlasers!', 'and the laser blocker', 'shield-wielding kid', 'face shield for sale', 'fungus for face shield', 'shield boy defends again', 'the mirror shield'), - 'Progressive Shield': (True, False, None, 0x5F, 'have a better\nblocker in\nfront of you', 'and the new shield', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'a shield'), - 'Bug Catching Net': (True, False, None, 0x21, 'Let\'s catch\nsome bees and\nfaeries!', 'and the bee catcher', 'the bug-catching kid', 'stick web for sale', 'fungus for butterflies', 'wrong boy catches bees again', 'the bug net'), - 'Cane of Byrna': (True, False, None, 0x18, 'Use this to\nbecome\ninvincible!', 'and the bad cane', 'the spark-making kid', 'spark stick for sale', 'spark-stick for trade', 'cane boy encircles again', 'the blue cane'), - 'Boss Heart Container': (False, False, None, 0x3E, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'), - 'Sanctuary Heart Container': (False, False, None, 0x3F, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'), - 'Piece of Heart': (False, False, None, 0x17, 'Just a little\npiece of love!', 'and the broken heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart piece'), - 'Rupee (1)': (False, False, None, 0x34, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a green rupee'), - 'Rupees (5)': (False, False, None, 0x35, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a blue rupee'), - 'Rupees (20)': (False, False, None, 0x36, 'Just couch\ncash. Move\nright along.', 'and the couch cash', 'the piggy-bank kid', 'life lesson for sale', 'the witch buying drugs', 'destitute boy has lunch again', 'a red rupee'), - 'Rupees (50)': (False, False, None, 0x41, 'A rupee pile!\nOkay?', 'and the rupee pile', 'the well-off kid', 'life lesson for sale', 'buying okay drugs', 'destitute boy has dinner again', 'fifty rupees'), - 'Rupees (100)': (False, False, None, 0x40, 'A rupee stash!\nHell yeah!', 'and the rupee stash', 'the kind-of-rich kid', 'life lesson for sale', 'buying good drugs', 'affluent boy goes drinking again', 'one hundred rupees'), - 'Rupees (300)': (False, False, None, 0x46, 'A rupee hoard!\nHell yeah!', 'and the rupee hoard', 'the really-rich kid', 'life lesson for sale', 'buying the best drugs', 'fat-cat boy is rich again', 'three hundred rupees'), - 'Rupoor': (False, False, None, 0x59, 'a debt collector', 'and the toll-booth', 'the toll-booth kid', 'double loss for sale', 'witch stole your rupees', 'affluent boy steals rupees', 'a rupoor'), - 'Red Clock': (False, True, None, 0x5B, 'a waste of time', 'the ruby clock', 'the ruby-time kid', 'red time for sale', 'for ruby time', 'moment boy travels time again', 'a red clock'), - 'Blue Clock': (False, True, None, 0x5C, 'a bit of time', 'the sapphire clock', 'sapphire-time kid', 'blue time for sale', 'for sapphire time', 'moment boy time travels again', 'a blue clock'), - 'Green Clock': (False, True, None, 0x5D, 'a lot of time', 'the emerald clock', 'the emerald-time kid', 'green time for sale', 'for emerald time', 'moment boy adjusts time again', 'a red clock'), - 'Single RNG': (False, True, None, 0x62, 'something you don\'t yet have', None, None, None, None, 'unknown boy somethings again', 'a new mystery'), - 'Multi RNG': (False, True, None, 0x63, 'something you may already have', None, None, None, None, 'unknown boy somethings again', 'a total mystery'), - 'Magic Upgrade (1/2)': (True, False, None, 0x4E, 'Your magic\npower has been\ndoubled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'half magic'), # can be required to beat mothula in an open seed in very very rare circumstance - 'Magic Upgrade (1/4)': (True, False, None, 0x4F, 'Your magic\npower has been\nquadrupled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'quarter magic'), # can be required to beat mothula in an open seed in very very rare circumstance - 'Small Key (Eastern Palace)': (False, False, 'SmallKey', 0xA2, 'A small key to Armos Knights', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Eastern Palace'), - 'Big Key (Eastern Palace)': (False, False, 'BigKey', 0x9D, 'A big key to Armos Knights', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Eastern Palace'), - 'Compass (Eastern Palace)': (False, True, 'Compass', 0x8D, 'Now you can find the Armos Knights!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Eastern Palace'), - 'Map (Eastern Palace)': (False, True, 'Map', 0x7D, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Eastern Palace'), - 'Small Key (Desert Palace)': (False, False, 'SmallKey', 0xA3, 'A small key to the desert', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Desert Palace'), - 'Big Key (Desert Palace)': (False, False, 'BigKey', 0x9C, 'A big key to the desert', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Desert Palace'), - 'Compass (Desert Palace)': (False, True, 'Compass', 0x8C, 'Now you can find Lanmolas!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Desert Palace'), - 'Map (Desert Palace)': (False, True, 'Map', 0x7C, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Desert Palace'), - 'Small Key (Tower of Hera)': (False, False, 'SmallKey', 0xAA, 'A small key to Hera', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Tower of Hera'), - 'Big Key (Tower of Hera)': (False, False, 'BigKey', 0x95, 'A big key to Hera', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Tower of Hera'), - 'Compass (Tower of Hera)': (False, True, 'Compass', 0x85, 'Now you can find Moldorm!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Tower of Hera'), - 'Map (Tower of Hera)': (False, True, 'Map', 0x75, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Tower of Hera'), - 'Small Key (Escape)': (False, False, 'SmallKey', 0xA0, 'A small key to the castle', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Hyrule Castle'), - 'Big Key (Escape)': (False, False, 'BigKey', 0x9F, 'A big key to the castle', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Hyrule Castle'), - 'Compass (Escape)': (False, True, 'Compass', 0x8F, 'Now you can find no boss!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Hyrule Castle'), - 'Map (Escape)': (False, True, 'Map', 0x7F, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Hyrule Castle'), - 'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'), - 'Big Key (Agahnims Tower)': (False, False, 'BigKey', 0x9B, 'A big key to Agahnim', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Castle Tower'), - 'Compass (Agahnims Tower)': (False, True, 'Compass', 0x8B, 'Now you can find Aga1!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Castle Tower'), - 'Map (Agahnims Tower)': (False, True, 'Map', 0x7B, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Castle Tower'), - 'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'), - 'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'), - 'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'), - 'Map (Palace of Darkness)': (False, True, 'Map', 0x79, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Palace of Darkness'), - 'Small Key (Thieves Town)': (False, False, 'SmallKey', 0xAB, 'A small key to thievery', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Thieves\' Town'), - 'Big Key (Thieves Town)': (False, False, 'BigKey', 0x94, 'A big key to thievery', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Thieves\' Town'), - 'Compass (Thieves Town)': (False, True, 'Compass', 0x84, 'Now you can find Blind!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Thieves\' Town'), - 'Map (Thieves Town)': (False, True, 'Map', 0x74, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Thieves\' Town'), - 'Small Key (Skull Woods)': (False, False, 'SmallKey', 0xA8, 'A small key to the woods', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Skull Woods'), - 'Big Key (Skull Woods)': (False, False, 'BigKey', 0x97, 'A big key to the woods', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Skull Woods'), - 'Compass (Skull Woods)': (False, True, 'Compass', 0x87, 'Now you can find Mothula!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Skull Woods'), - 'Map (Skull Woods)': (False, True, 'Map', 0x77, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Skull Woods'), - 'Small Key (Swamp Palace)': (False, False, 'SmallKey', 0xA5, 'A small key to the swamp', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Swamp Palace'), - 'Big Key (Swamp Palace)': (False, False, 'BigKey', 0x9A, 'A big key to the swamp', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Swamp Palace'), - 'Compass (Swamp Palace)': (False, True, 'Compass', 0x8A, 'Now you can find Arrghus!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Swamp Palace'), - 'Map (Swamp Palace)': (False, True, 'Map', 0x7A, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Swamp Palace'), - 'Small Key (Ice Palace)': (False, False, 'SmallKey', 0xA9, 'A small key to the iceberg', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ice Palace'), - 'Big Key (Ice Palace)': (False, False, 'BigKey', 0x96, 'A big key to the iceberg', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ice Palace'), - 'Compass (Ice Palace)': (False, True, 'Compass', 0x86, 'Now you can find Kholdstare!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Ice Palace'), - 'Map (Ice Palace)': (False, True, 'Map', 0x76, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ice Palace'), - 'Small Key (Misery Mire)': (False, False, 'SmallKey', 0xA7, 'A small key to the mire', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Misery Mire'), - 'Big Key (Misery Mire)': (False, False, 'BigKey', 0x98, 'A big key to the mire', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Misery Mire'), - 'Compass (Misery Mire)': (False, True, 'Compass', 0x88, 'Now you can find Vitreous!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Misery Mire'), - 'Map (Misery Mire)': (False, True, 'Map', 0x78, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Misery Mire'), - 'Small Key (Turtle Rock)': (False, False, 'SmallKey', 0xAC, 'A small key to the pipe maze', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Turtle Rock'), - 'Big Key (Turtle Rock)': (False, False, 'BigKey', 0x93, 'A big key to the pipe maze', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Turtle Rock'), - 'Compass (Turtle Rock)': (False, True, 'Compass', 0x83, 'Now you can find Trinexx!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Turtle Rock'), - 'Map (Turtle Rock)': (False, True, 'Map', 0x73, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Turtle Rock'), - 'Small Key (Ganons Tower)': (False, False, 'SmallKey', 0xAD, 'A small key to the evil tower', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ganon\'s Tower'), - 'Big Key (Ganons Tower)': (False, False, 'BigKey', 0x92, 'A big key to the evil tower', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ganon\'s Tower'), - 'Compass (Ganons Tower)': (False, True, 'Compass', 0x82, 'Now you can find Agahnim!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a comapss to Ganon\'s Tower'), - 'Map (Ganons Tower)': (False, True, 'Map', 0x72, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ganon\'s Tower'), - 'Small Key (Universal)': (False, True, None, 0xAF, 'A small key for any door', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key'), - 'Nothing': (False, False, None, 0x5A, 'Some Hot Air', 'and the Nothing', 'the zen kid', 'outright theft', 'shroom theft', 'empty boy is bored again', 'nothing'), - 'Bee Trap': (False, False, None, 0xB0, 'We will sting your face a whole lot!', 'and the sting buddies', 'the beekeeper kid', 'insects for sale', 'shroom pollenation', 'bottle boy has mad bees again', 'friendship'), - 'Red Potion': (False, False, None, 0x2E, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a red potion'), - 'Green Potion': (False, False, None, 0x2F, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'), - 'Blue Potion': (False, False, None, 0x30, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'), - 'Bee': (False, False, None, 0x0E, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a bee'), - 'Small Heart': (False, False, None, 0x42, 'Just a little\npiece of love!', 'and the heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart'), - 'Beat Agahnim 1': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Beat Agahnim 2': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Get Frog': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Return Smith': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Pick Up Purple Chest': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Open Floodgate': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Trench 1 Filled': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Trench 2 Filled': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Drained Swamp': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Shining Light': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Maiden Rescued': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Maiden Unmasked': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Convenient Block': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Zelda Herself': (True, False, 'Event', None, None, None, None, None, None, None, None), - 'Zelda Delivered': (True, False, 'Event', None, None, None, None, None, None, None, None), +item_table = {'Bow': (True, False, None, 0x0B, 300, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'the Bow'), + 'Progressive Bow': (True, False, None, 0x64, 200, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'a Bow'), + 'Progressive Bow (Alt)': (True, False, None, 0x65, 200, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'a Bow'), + 'Book of Mudora': (True, False, None, 0x1D, 200, 'This is a\nparadox?!', 'and the story book', 'the scholarly kid', 'moon runes for sale', 'drugs for literacy', 'book-worm boy can read again', 'the Book'), + 'Hammer': (True, False, None, 0x09, 300, 'stop\nhammer time!', 'and m c hammer', 'hammer-smashing kid', 'm c hammer for sale', 'stop... hammer time', 'stop, hammer time', 'the hammer'), + 'Hookshot': (True, False, None, 0x0A, 300, 'BOING!!!\nBOING!!!\nBOING!!!', 'and the tickle beam', 'tickle-monster kid', 'tickle beam for sale', 'witch and tickle boy', 'beam boy tickles again', 'the Hookshot'), + 'Magic Mirror': (True, False, None, 0x1A, 300, 'Isn\'t your\nreflection so\npretty?', 'the face reflector', 'the narcissistic kid', 'your face for sale', 'trades looking-glass', 'narcissistic boy is happy again', 'the Mirror'), + 'Ocarina': (True, False, None, 0x14, 300, 'Save the duck\nand fly to\nfreedom!', 'and the duck call', 'the duck-call kid', 'duck call for sale', 'duck-calls for trade', 'ocarina boy plays again', 'the Flute'), + 'Pegasus Boots': (True, False, None, 0x4B, 300, 'Gotta go fast!', 'and the sprint shoes', 'the running-man kid', 'sprint shoe for sale', 'shrooms for speed', 'gotta-go-fast boy runs again', 'the Boots'), + 'Power Glove': (True, False, None, 0x1B, 150, 'Now you can\nlift weak\nstuff!', 'and the grey mittens', 'body-building kid', 'lift glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'the glove'), + 'Cape': (True, False, None, 0x19, 100, 'Wear this to\nbecome\ninvisible!', 'the camouflage cape', 'red riding-hood kid', 'red hood for sale', 'hood from a hood', 'dapper boy hides again', 'the cape'), + 'Mushroom': (True, False, None, 0x29, 100, 'I\'m a fun guy!\n\nI\'m a funghi!', 'and the legal drugs', 'the drug-dealing kid', 'legal drugs for sale', 'shroom swap', 'shroom boy sells drugs again', 'the mushroom'), + 'Shovel': (True, False, None, 0x13, 100, 'Can\n You\n Dig it?', 'and the spade', 'archaeologist kid', 'dirt spade for sale', 'can you dig it', 'shovel boy digs again', 'the shovel'), + 'Lamp': (True, False, None, 0x12, 200, 'Baby, baby,\nbaby.\nLight my way!', 'and the flashlight', 'light-shining kid', 'flashlight for sale', 'fungus for illumination', 'illuminated boy can see again', 'the lamp'), + 'Magic Powder': (True, False, None, 0x0D, 100, 'you can turn\nanti-faeries\ninto faeries', 'and the magic sack', 'the sack-holding kid', 'magic sack for sale', 'the witch and assistant', 'magic boy plays marbles again', 'the powder'), + 'Moon Pearl': (True, False, None, 0x1F, 300, ' Bunny Link\n be\n gone!', 'and the jaw breaker', 'fortune-telling kid', 'lunar orb for sale', 'shrooms for moon rock', 'moon boy plays ball again', 'the moon pearl'), + 'Cane of Somaria': (True, False, None, 0x15, 300, 'I make blocks\nto hold down\nswitches!', 'and the red blocks', 'the block-making kid', 'block stick for sale', 'block stick for trade', 'cane boy makes blocks again', 'the red cane'), + 'Fire Rod': (True, False, None, 0x07, 300, 'I\'m the hot\nrod. I make\nthings burn!', 'and the flamethrower', 'fire-starting kid', 'rage rod for sale', 'fungus for rage-rod', 'firestarter boy burns again', 'the fire rod'), + 'Flippers': (True, False, None, 0x1E, 300, 'fancy a swim?', 'and the toewebs', 'the swimming kid', 'finger webs for sale', 'shrooms let you swim', 'swimming boy swims again', 'the flippers'), + 'Ice Rod': (True, False, None, 0x08, 300, 'I\'m the cold\nrod. I make\nthings freeze!', 'and the freeze ray', 'the ice-bending kid', 'freeze ray for sale', 'fungus for ice-rod', 'ice-cube boy freezes again', 'the ice rod'), + 'Titans Mitts': (True, False, None, 0x1C, 300, 'Now you can\nlift heavy\nstuff!', 'and the golden glove', 'body-building kid', 'carry glove for sale', 'fungus for bling-gloves', 'body-building boy has gold again', 'the mitts'), + 'Bombos': (True, False, None, 0x0F, 200, 'Burn, baby,\nburn! Fear my\nring of fire!', 'and the swirly coin', 'coin-collecting kid', 'swirly coin for sale', 'shrooms for swirly-coin', 'medallion boy melts room again', 'Bombos'), + 'Ether': (True, False, None, 0x10, 200, 'This magic\ncoin freezes\neverything!', 'and the bolt coin', 'coin-collecting kid', 'bolt coin for sale', 'shrooms for bolt-coin', 'medallion boy sees floor again', 'Ether'), + 'Quake': (True, False, None, 0x11, 200, 'Maxing out the\nRichter scale\nis what I do!', 'and the wavy coin', 'coin-collecting kid', 'wavy coin for sale', 'shrooms for wavy-coin', 'medallion boy shakes dirt again', 'Quake'), + 'Bottle': (True, False, None, 0x16, 100, 'Now you can\nstore potions\nand stuff!', 'and the terrarium', 'the terrarium kid', 'terrarium for sale', 'special promotion', 'bottle boy has terrarium again', 'a Bottle'), + 'Bottle (Red Potion)': (True, False, None, 0x2B, 130, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a Bottle'), + 'Bottle (Green Potion)': (True, False, None, 0x2C, 110, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a Bottle'), + 'Bottle (Blue Potion)': (True, False, None, 0x2D, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a Bottle'), + 'Bottle (Fairy)': (True, False, None, 0x3D, 150, 'Save me and I will revive you', 'and the captive', 'the tingle kid', 'hostage for sale', 'fairy dust and shrooms', 'bottle boy has friend again', 'a Bottle'), + 'Bottle (Bee)': (True, False, None, 0x3C, 100, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a Bottle'), + 'Bottle (Good Bee)': (True, False, None, 0x48, 110, 'I will sting your foes a whole lot!', 'and the sparkle sting', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has beetor again', 'a Bottle'), + 'Master Sword': (True, False, 'Sword', 0x50, 150, 'I beat barries and pigs alike', 'and the master sword', 'sword-wielding kid', 'glow sword for sale', 'fungus for blue slasher', 'sword boy fights again', 'the Master Sword'), + 'Tempered Sword': (True, False, 'Sword', 0x02, 250, 'I stole the\nblacksmith\'s\njob!', 'the tempered sword', 'sword-wielding kid', 'flame sword for sale', 'fungus for red slasher', 'sword boy fights again', 'the Tempered Sword'), + 'Fighter Sword': (True, False, 'Sword', 0x49, 50, 'A pathetic\nsword rests\nhere!', 'the tiny sword', 'sword-wielding kid', 'tiny sword for sale', 'fungus for tiny slasher', 'sword boy fights again', 'the small sword'), + 'Golden Sword': (True, False, 'Sword', 0x03, 300, 'The butter\nsword rests\nhere!', 'and the butter sword', 'sword-wielding kid', 'butter for sale', 'cap churned to butter', 'sword boy fights again', 'the Golden Sword'), + 'Progressive Sword': (True, False, 'Sword', 0x5E, 200, 'a better copy\nof your sword\nfor your time', 'the unknown sword', 'sword-wielding kid', 'sword for sale', 'fungus for some slasher', 'sword boy fights again', 'a sword'), + 'Progressive Glove': (True, False, None, 0x61, 200, 'a way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a glove'), + 'Silver Arrows': (True, False, None, 0x58, 100, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again', 'the silver arrows'), + 'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x01], 999, None, None, None, None, None, None, None), + 'Blue Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], 999, None, None, None, None, None, None, None), + 'Red Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], 999, None, None, None, None, None, None, None), + 'Triforce': (True, False, None, 0x6A, 777, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'), + 'Power Star': (True, False, None, 0x6B, 50, 'a small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'), + 'Triforce Piece': (True, False, None, 0x6C, 50, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce Piece'), + 'Crystal 1': (True, False, 'Crystal', [0x02, 0x34, 0x64, 0x40, 0x7F, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 2': (True, False, 'Crystal', [0x10, 0x34, 0x64, 0x40, 0x79, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 3': (True, False, 'Crystal', [0x40, 0x34, 0x64, 0x40, 0x6C, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 4': (True, False, 'Crystal', [0x20, 0x34, 0x64, 0x40, 0x6D, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 5': (True, False, 'Crystal', [0x04, 0x32, 0x64, 0x40, 0x6E, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 6': (True, False, 'Crystal', [0x01, 0x32, 0x64, 0x40, 0x6F, 0x06], 999, None, None, None, None, None, None, None), + 'Crystal 7': (True, False, 'Crystal', [0x08, 0x34, 0x64, 0x40, 0x7C, 0x06], 999, None, None, None, None, None, None, None), + 'Single Arrow': (False, False, None, 0x43, 3, 'a lonely arrow\nsits here.', 'and the arrow', 'stick-collecting kid', 'sewing needle for sale', 'fungus for arrow', 'archer boy sews again', 'an arrow'), + 'Arrows (10)': (False, False, None, 0x44, 30, 'This will give\nyou ten shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'ten arrows'), + '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'), + 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), + 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), + 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Blue Mail': (False, True, None, 0x22, 100, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), + 'Red Mail': (False, True, None, 0x23, 200, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), + 'Progressive Armor': (False, True, None, 0x60, 100, 'time for a\nchange of\nclothes?', 'and the unknown hat', 'the protected kid', 'new hat for sale', 'the clothing store', 'tailor boy has threads again', 'some armor'), + 'Blue Boomerang': (True, False, None, 0x0C, 100, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again', 'the blue boomerang'), + 'Red Boomerang': (True, False, None, 0x2A, 100, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again', 'the red boomerang'), + 'Blue Shield': (False, True, None, 0x04, 50, 'Now you can\ndefend against\npebbles!', 'and the stone blocker', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'the blue shield'), + 'Red Shield': (False, True, None, 0x05, 500, 'Now you can\ndefend against\nfireballs!', 'and the shot blocker', 'shield-wielding kid', 'fire shield for sale', 'fungus for fire shield', 'shield boy defends again', 'the red shield'), + 'Mirror Shield': (True, False, None, 0x06, 300, 'Now you can\ndefend against\nlasers!', 'and the laser blocker', 'shield-wielding kid', 'face shield for sale', 'fungus for face shield', 'shield boy defends again', 'the mirror shield'), + 'Progressive Shield': (True, False, None, 0x5F, 100, 'have a better\nblocker in\nfront of you', 'and the new shield', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again', 'a shield'), + 'Bug Catching Net': (True, False, None, 0x21, 100, 'Let\'s catch\nsome bees and\nfaeries!', 'and the bee catcher', 'the bug-catching kid', 'stick web for sale', 'fungus for butterflies', 'wrong boy catches bees again', 'the bug net'), + 'Cane of Byrna': (True, False, None, 0x18, 100, 'Use this to\nbecome\ninvincible!', 'and the bad cane', 'the spark-making kid', 'spark stick for sale', 'spark-stick for trade', 'cane boy encircles again', 'the blue cane'), + 'Boss Heart Container': (False, False, None, 0x3E, 80, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'), + 'Sanctuary Heart Container': (False, False, None, 0x3F, 100, 'Maximum health\nincreased!\nYeah!', 'and the full heart', 'the life-giving kid', 'love for sale', 'fungus for life', 'life boy feels love again', 'a heart'), + 'Piece of Heart': (False, False, None, 0x17, 20, 'Just a little\npiece of love!', 'and the broken heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart piece'), + 'Rupee (1)': (False, False, None, 0x34, 0, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a green rupee'), + 'Rupees (5)': (False, False, None, 0x35, 2, 'Just pocket\nchange. Move\nright along.', 'the pocket change', 'poverty-struck kid', 'life lesson for sale', 'buying cheap drugs', 'destitute boy has snack again', 'a blue rupee'), + 'Rupees (20)': (False, False, None, 0x36, 10, 'Just couch\ncash. Move\nright along.', 'and the couch cash', 'the piggy-bank kid', 'life lesson for sale', 'the witch buying drugs', 'destitute boy has lunch again', 'a red rupee'), + 'Rupees (50)': (False, False, None, 0x41, 25, 'A rupee pile!\nOkay?', 'and the rupee pile', 'the well-off kid', 'life lesson for sale', 'buying okay drugs', 'destitute boy has dinner again', 'fifty rupees'), + 'Rupees (100)': (False, False, None, 0x40, 50, 'A rupee stash!\nHell yeah!', 'and the rupee stash', 'the kind-of-rich kid', 'life lesson for sale', 'buying good drugs', 'affluent boy goes drinking again', 'one hundred rupees'), + 'Rupees (300)': (False, False, None, 0x46, 150, 'A rupee hoard!\nHell yeah!', 'and the rupee hoard', 'the really-rich kid', 'life lesson for sale', 'buying the best drugs', 'fat-cat boy is rich again', 'three hundred rupees'), + 'Rupoor': (False, False, None, 0x59, 0, 'a debt collector', 'and the toll-booth', 'the toll-booth kid', 'double loss for sale', 'witch stole your rupees', 'affluent boy steals rupees', 'a rupoor'), + 'Red Clock': (False, True, None, 0x5B, 0, 'a waste of time', 'the ruby clock', 'the ruby-time kid', 'red time for sale', 'for ruby time', 'moment boy travels time again', 'a red clock'), + 'Blue Clock': (False, True, None, 0x5C, 50, 'a bit of time', 'the sapphire clock', 'sapphire-time kid', 'blue time for sale', 'for sapphire time', 'moment boy time travels again', 'a blue clock'), + 'Green Clock': (False, True, None, 0x5D, 200, 'a lot of time', 'the emerald clock', 'the emerald-time kid', 'green time for sale', 'for emerald time', 'moment boy adjusts time again', 'a red clock'), + 'Single RNG': (False, True, None, 0x62, 300, 'something you don\'t yet have', None, None, None, None, 'unknown boy somethings again', 'a new mystery'), + 'Multi RNG': (False, True, None, 0x63, 100, 'something you may already have', None, None, None, None, 'unknown boy somethings again', 'a total mystery'), + 'Magic Upgrade (1/2)': (True, False, None, 0x4E, 100, 'Your magic\npower has been\ndoubled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'half magic'), # can be required to beat mothula in an open seed in very very rare circumstance + 'Magic Upgrade (1/4)': (True, False, None, 0x4F, 200, 'Your magic\npower has been\nquadrupled!', 'and the spell power', 'the magic-saving kid', 'wizardry for sale', 'mekalekahi mekahiney ho', 'magic boy saves magic again', 'quarter magic'), # can be required to beat mothula in an open seed in very very rare circumstance + 'Small Key (Eastern Palace)': (False, False, 'SmallKey', 0xA2, 50, 'A small key to Armos Knights', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Eastern Palace'), + 'Big Key (Eastern Palace)': (False, False, 'BigKey', 0x9D, 100, 'A big key to Armos Knights', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Eastern Palace'), + 'Compass (Eastern Palace)': (False, True, 'Compass', 0x8D, 10, 'Now you can find the Armos Knights!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Eastern Palace'), + 'Map (Eastern Palace)': (False, True, 'Map', 0x7D, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Eastern Palace'), + 'Small Key (Desert Palace)': (False, False, 'SmallKey', 0xA3, 50, 'A small key to the desert', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Desert Palace'), + 'Big Key (Desert Palace)': (False, False, 'BigKey', 0x9C, 100, 'A big key to the desert', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Desert Palace'), + 'Compass (Desert Palace)': (False, True, 'Compass', 0x8C, 10, 'Now you can find Lanmolas!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Desert Palace'), + 'Map (Desert Palace)': (False, True, 'Map', 0x7C, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Desert Palace'), + 'Small Key (Tower of Hera)': (False, False, 'SmallKey', 0xAA, 50, 'A small key to Hera', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Tower of Hera'), + 'Big Key (Tower of Hera)': (False, False, 'BigKey', 0x95, 100, 'A big key to Hera', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Tower of Hera'), + 'Compass (Tower of Hera)': (False, True, 'Compass', 0x85, 10, 'Now you can find Moldorm!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Tower of Hera'), + 'Map (Tower of Hera)': (False, True, 'Map', 0x75, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Tower of Hera'), + 'Small Key (Escape)': (False, False, 'SmallKey', 0xA0, 50, 'A small key to the castle', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Hyrule Castle'), + 'Big Key (Escape)': (False, False, 'BigKey', 0x9F, 100, 'A big key to the castle', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Hyrule Castle'), + 'Compass (Escape)': (False, True, 'Compass', 0x8F, 10, 'Now you can find no boss!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Hyrule Castle'), + 'Map (Escape)': (False, True, 'Map', 0x7F, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Hyrule Castle'), + 'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 50, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'), + 'Big Key (Agahnims Tower)': (False, False, 'BigKey', 0x9B, 100, 'A big key to Agahnim', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Castle Tower'), + 'Compass (Agahnims Tower)': (False, True, 'Compass', 0x8B, 10, 'Now you can find Aga1!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Castle Tower'), + 'Map (Agahnims Tower)': (False, True, 'Map', 0x7B, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Castle Tower'), + 'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 50, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'), + 'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 100, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'), + 'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 10, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'), + 'Map (Palace of Darkness)': (False, True, 'Map', 0x79, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Palace of Darkness'), + 'Small Key (Thieves Town)': (False, False, 'SmallKey', 0xAB, 50, 'A small key to thievery', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Thieves\' Town'), + 'Big Key (Thieves Town)': (False, False, 'BigKey', 0x94, 100, 'A big key to thievery', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Thieves\' Town'), + 'Compass (Thieves Town)': (False, True, 'Compass', 0x84, 10, 'Now you can find Blind!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Thieves\' Town'), + 'Map (Thieves Town)': (False, True, 'Map', 0x74, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Thieves\' Town'), + 'Small Key (Skull Woods)': (False, False, 'SmallKey', 0xA8, 50, 'A small key to the woods', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Skull Woods'), + 'Big Key (Skull Woods)': (False, False, 'BigKey', 0x97, 100, 'A big key to the woods', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Skull Woods'), + 'Compass (Skull Woods)': (False, True, 'Compass', 0x87, 10, 'Now you can find Mothula!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Skull Woods'), + 'Map (Skull Woods)': (False, True, 'Map', 0x77, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Skull Woods'), + 'Small Key (Swamp Palace)': (False, False, 'SmallKey', 0xA5, 50, 'A small key to the swamp', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Swamp Palace'), + 'Big Key (Swamp Palace)': (False, False, 'BigKey', 0x9A, 100, 'A big key to the swamp', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Swamp Palace'), + 'Compass (Swamp Palace)': (False, True, 'Compass', 0x8A, 10, 'Now you can find Arrghus!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Swamp Palace'), + 'Map (Swamp Palace)': (False, True, 'Map', 0x7A, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Swamp Palace'), + 'Small Key (Ice Palace)': (False, False, 'SmallKey', 0xA9, 50, 'A small key to the iceberg', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ice Palace'), + 'Big Key (Ice Palace)': (False, False, 'BigKey', 0x96, 100, 'A big key to the iceberg', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ice Palace'), + 'Compass (Ice Palace)': (False, True, 'Compass', 0x86, 10, 'Now you can find Kholdstare!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Ice Palace'), + 'Map (Ice Palace)': (False, True, 'Map', 0x76, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ice Palace'), + 'Small Key (Misery Mire)': (False, False, 'SmallKey', 0xA7, 50, 'A small key to the mire', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Misery Mire'), + 'Big Key (Misery Mire)': (False, False, 'BigKey', 0x98, 100, 'A big key to the mire', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Misery Mire'), + 'Compass (Misery Mire)': (False, True, 'Compass', 0x88, 10, 'Now you can find Vitreous!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Misery Mire'), + 'Map (Misery Mire)': (False, True, 'Map', 0x78, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Misery Mire'), + 'Small Key (Turtle Rock)': (False, False, 'SmallKey', 0xAC, 50, 'A small key to the pipe maze', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Turtle Rock'), + 'Big Key (Turtle Rock)': (False, False, 'BigKey', 0x93, 100, 'A big key to the pipe maze', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Turtle Rock'), + 'Compass (Turtle Rock)': (False, True, 'Compass', 0x83, 10, 'Now you can find Trinexx!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Turtle Rock'), + 'Map (Turtle Rock)': (False, True, 'Map', 0x73, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Turtle Rock'), + 'Small Key (Ganons Tower)': (False, False, 'SmallKey', 0xAD, 50, 'A small key to the evil tower', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Ganon\'s Tower'), + 'Big Key (Ganons Tower)': (False, False, 'BigKey', 0x92, 100, 'A big key to the evil tower', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Ganon\'s Tower'), + 'Compass (Ganons Tower)': (False, True, 'Compass', 0x82, 10, 'Now you can find Agahnim!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a comapss to Ganon\'s Tower'), + 'Map (Ganons Tower)': (False, True, 'Map', 0x72, 50, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Ganon\'s Tower'), + 'Small Key (Universal)': (False, True, None, 0xAF, 100, 'A small key for any door', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key'), + 'Nothing': (False, False, None, 0x5A, 1, 'Some Hot Air', 'and the Nothing', 'the zen kid', 'outright theft', 'shroom theft', 'empty boy is bored again', 'nothing'), + 'Bee Trap': (False, False, None, 0xB0, 0, 'We will sting your face a whole lot!', 'and the sting buddies', 'the beekeeper kid', 'insects for sale', 'shroom pollenation', 'bottle boy has mad bees again', 'friendship'), + 'Red Potion': (False, False, None, 0x2E, 150, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a red potion'), + 'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'), + 'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'), + 'Bee': (False, False, None, 0x0E, 10, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a bee'), + 'Small Heart': (False, False, None, 0x42, 10, 'Just a little\npiece of love!', 'and the heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart'), + 'Beat Agahnim 1': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Beat Agahnim 2': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Get Frog': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Return Smith': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Pick Up Purple Chest': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Open Floodgate': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Trench 1 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Trench 2 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Drained Swamp': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Shining Light': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Maiden Rescued': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Maiden Unmasked': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Convenient Block': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Zelda Herself': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Zelda Delivered': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), } diff --git a/Main.py b/Main.py index aaed4a61..721541bc 100644 --- a/Main.py +++ b/Main.py @@ -21,11 +21,12 @@ from DoorShuffle import link_doors, connect_portal_copy from RoomData import create_rooms from Rules import set_rules from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive -from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items, balance_multiworld_progression -from ItemList import generate_itempool, difficulties, fill_prizes, fill_specific_items +from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items, sell_keys, balance_multiworld_progression +from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.2.0.18u' +__version__ = '0.2.1.0-u' + class EnemizerError(RuntimeError): pass @@ -70,6 +71,7 @@ def main(args, seed=None, fish=None): world.dungeon_counters = args.dungeon_counters.copy() world.potshuffle = args.shufflepots.copy() world.fish = fish + world.shopsanity = args.shopsanity.copy() world.keydropshuffle = args.keydropshuffle.copy() world.mixed_travel = args.mixed_travel.copy() world.standardize_palettes = args.standardize_palettes.copy() @@ -147,6 +149,10 @@ def main(args, seed=None, fish=None): for player in range(1, world.players + 1): set_rules(world, player) + for player in range(1, world.players + 1): + if world.retro[player] and world.shopsanity[player]: + sell_keys(world, player) + logger.info(world.fish.translate("cli","cli","placing.dungeon.prizes")) fill_prizes(world) @@ -205,6 +211,10 @@ def main(args, seed=None, fish=None): if not world.can_beat_game(): raise RuntimeError(world.fish.translate("cli","cli","cannot.beat.game")) + for player in range(1, world.players+1): + if world.shopsanity[player]: + customize_shops(world, player) + outfilebase = 'DR_%s' % (args.outputname if args.outputname else world.seed) rom_names = [] @@ -398,6 +408,7 @@ def copy_world(world): ret.beemizer = world.beemizer.copy() ret.intensity = world.intensity.copy() ret.experimental = world.experimental.copy() + ret.shopsanity = world.shopsanity.copy() ret.keydropshuffle = world.keydropshuffle.copy() ret.mixed_travel = world.mixed_travel.copy() ret.standardize_palettes = world.standardize_palettes.copy() @@ -426,9 +437,10 @@ def copy_world(world): for level, boss in dungeon.bosses.items(): ret.get_dungeon(dungeon.name, dungeon.player).bosses[level] = boss - for shop in world.shops: - copied_shop = ret.get_region(shop.region.name, shop.region.player).shop - copied_shop.inventory = copy.copy(shop.inventory) + for player in range(1, world.players + 1): + for shop in world.shops[player]: + copied_shop = ret.get_region(shop.region.name, shop.region.player).shop + copied_shop.inventory = copy.copy(shop.inventory) # connect copied world for region in world.regions: @@ -490,6 +502,7 @@ def copy_world(world): return ret + def copy_dynamic_regions_and_locations(world, ret): for region in world.dynamic_regions: new_reg = Region(region.name, region.type, region.hint_text, region.player) @@ -501,7 +514,7 @@ def copy_dynamic_regions_and_locations(world, ret): if region.shop: new_reg.shop = Shop(new_reg, region.shop.room_id, region.shop.type, region.shop.shopkeeper_config, region.shop.custom, region.shop.locked) - ret.shops.append(new_reg.shop) + ret.shops[region.player].append(new_reg.shop) for location in world.dynamic_locations: new_reg = ret.get_region(location.parent_region.name, location.parent_region.player) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 46f32ff9..b48a6dc5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -28,7 +28,13 @@ * Known issues: * Palettes aren't perfect * Some ugly colors - * Invisible floors can be see in many palettes + * Invisible floors can be see in many palettes + +## Shopsanity + +--shopsanity added. This adds 29 shop locations (9 more in retro) to the general and location pool. + +** **Todo** **: add more info here. ## Key Drop Shuffle diff --git a/Regions.py b/Regions.py index fb991200..ee251a18 100644 --- a/Regions.py +++ b/Regions.py @@ -1,4 +1,5 @@ import collections +from Items import ItemFactory from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType @@ -38,7 +39,7 @@ def create_regions(world, player): create_cave_region(player, 'Bush Covered House', 'the grass man'), create_cave_region(player, 'Tavern (Front)', 'the tavern'), create_cave_region(player, 'Light World Bomb Hut', 'a restock room'), - create_cave_region(player, 'Kakariko Shop', 'a common shop'), + create_cave_region(player, 'Kakariko Shop', 'a common shop', ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right']), create_cave_region(player, 'Fortune Teller (Light)', 'a fortune teller'), create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), create_cave_region(player, 'Lumberjack House', 'a boring house'), @@ -78,14 +79,14 @@ def create_regions(world, player): create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), create_cave_region(player, 'Good Bee Cave', 'a cold bee'), create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), - create_cave_region(player, 'Cave Shop (Lake Hylia)', 'a common shop'), - create_cave_region(player, 'Cave Shop (Dark Death Mountain)', 'a common shop'), + create_cave_region(player, 'Cave Shop (Lake Hylia)', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), + create_cave_region(player, 'Cave Shop (Dark Death Mountain)', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), create_cave_region(player, 'Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']), create_cave_region(player, 'Library', 'the library', ['Library']), create_cave_region(player, 'Kakariko Gamble Game', 'a game of chance'), create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), - create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies'), + create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)']), create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), @@ -122,7 +123,7 @@ def create_regions(world, player): 'Paradox Cave Upper - Right'], ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump']), 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'), + 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']), create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop']), create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), @@ -157,16 +158,16 @@ def create_regions(world, player): create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks']), create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), - create_cave_region(player, 'Village of Outcasts Shop', 'a common shop'), - create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop'), - create_cave_region(player, 'Dark World Lumberjack Shop', 'a common shop'), - create_cave_region(player, 'Dark World Potion Shop', 'a common shop'), + create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), + create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), + create_cave_region(player, 'Dark World Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), + create_cave_region(player, 'Dark World Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), create_cave_region(player, 'Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), create_cave_region(player, 'Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), create_cave_region(player, 'Brewery', 'a house with a chest', ['Brewery']), create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), - create_cave_region(player, 'Red Shield Shop', 'the rare shop'), + create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller'), create_cave_region(player, 'Bumper Cave', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Exit (Top)']), create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot']), @@ -857,6 +858,7 @@ def mark_light_world_regions(world, player): def create_shops(world, player): + world.shops[player] = [] for region_name, (room_id, type, shopkeeper, custom, locked, inventory) in shop_table.items(): if world.mode[player] == 'inverted' and region_name == 'Dark Lake Hylia Shop': locked = True @@ -864,9 +866,16 @@ def create_shops(world, player): region = world.get_region(region_name, player) shop = Shop(region, room_id, type, shopkeeper, custom, locked) region.shop = shop - world.shops.append(shop) + world.shops[player].append(shop) for index, item in enumerate(inventory): shop.add_inventory(index, *item) + if not world.shopsanity[player]: + if region_name in shop_to_location_table.keys(): + for index, location in enumerate(shop_to_location_table[region_name]): + loc = world.get_location(location, player) + loc.skip = True + loc.forced_item = loc.item = ItemFactory(shop.inventory[index]['item'], player) + loc.item.location = loc def adjust_locations(world, player): @@ -909,6 +918,29 @@ shop_table = { 'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)]) } + +shop_to_location_table = { + 'Cave Shop (Dark Death Mountain)': ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right'], + 'Red Shield Shop': ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right'], + 'Dark Lake Hylia Shop': ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right'], + 'Dark World Lumberjack Shop': ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right'], + 'Village of Outcasts Shop': ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right'], + 'Dark World Potion Shop': ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right'], + 'Light World Death Mountain Shop': ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right'], + 'Kakariko Shop': ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right'], + 'Cave Shop (Lake Hylia)': ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right'], + 'Capacity Upgrade': ['Capacity Upgrade - Left', 'Capacity Upgrade - Right'], +} + +retro_shops = { + 'Old Man Sword Cave': ['Old Man Sword Cave Item 1'], + 'Take-Any #1': ['Take-Any #1 Item 1', 'Take-Any #1 Item 2'], + 'Take-Any #2': ['Take-Any #2 Item 1', 'Take-Any #2 Item 2'], + 'Take-Any #3': ['Take-Any #3 Item 1', 'Take-Any #3 Item 2'], + 'Take-Any #4': ['Take-Any #4 Item 1', 'Take-Any #4 Item 2'], +} + + 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)'], @@ -1202,7 +1234,37 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), 'Skull Woods - Prize': ([0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], None, True, 'Skull Woods'), 'Ice Palace - Prize': ([0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], None, True, 'Ice Palace'), 'Misery Mire - Prize': ([0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], None, True, 'Misery Mire'), - 'Turtle Rock - Prize': ([0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')} + 'Turtle Rock - Prize': ([0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock'), + 'Kakariko Shop - Left': (None, None, False, 'for sale in Kakariko'), + 'Kakariko Shop - Middle': (None, None, False, 'for sale in Kakariko'), + 'Kakariko Shop - Right': (None, None, False, 'for sale in Kakariko'), + 'Lake Hylia Shop - Left': (None, None, False, 'for sale near the lake'), + 'Lake Hylia Shop - Middle': (None, None, False, 'for sale near the lake'), + 'Lake Hylia Shop - Right': (None, None, False, 'for sale near the lake'), + 'Paradox Shop - Left': (None, None, False, 'for sale near seven chests'), + 'Paradox Shop - Middle': (None, None, False, 'for sale near seven chests'), + 'Paradox Shop - Right': (None, None, False, 'for sale near seven chests'), + 'Capacity Upgrade - Left': (None, None, False, 'for sale near the queen'), + 'Capacity Upgrade - Right': (None, None, False, 'for sale near the queen'), + 'Village of Outcasts Shop - Left': (None, None, False, 'for sale near outcasts'), + 'Village of Outcasts Shop - Middle': (None, None, False, 'for sale near outcasts'), + 'Village of Outcasts Shop - Right': (None, None, False, 'for sale near outcasts'), + 'Dark Lumberjack Shop - Left': (None, None, False, 'for sale in the far north'), + 'Dark Lumberjack Shop - Middle': (None, None, False, 'for sale in the far north'), + 'Dark Lumberjack Shop - Right': (None, None, False, 'for sale in the far north'), + 'Dark Lake Hylia Shop - Left': (None, None, False, 'for sale near the dark lake'), + 'Dark Lake Hylia Shop - Middle': (None, None, False, 'for sale near the dark lake'), + 'Dark Lake Hylia Shop - Right': (None, None, False, 'for sale near the dark lake'), + 'Dark Potion Shop - Left': (None, None, False, 'for sale near a catfish'), + 'Dark Potion Shop - Middle': (None, None, False, 'for sale near a catfish'), + 'Dark Potion Shop - Right': (None, None, False, 'for sale near a catfish'), + 'Dark Death Mountain Shop - Left': (None, None, False, 'for sale on the dark mountain'), + 'Dark Death Mountain Shop - Middle': (None, None, False, 'for sale on the dark mountain'), + 'Dark Death Mountain Shop - Right': (None, None, False, 'for sale on the dark mountain'), + 'Red Shield Shop - Left': (None, None, False, 'for sale as a curiosity'), + 'Red Shield Shop - Middle': (None, None, False, 'for sale as a curiosity'), + 'Red Shield Shop - Right': (None, None, False, 'for sale as a curiosity') + } lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}} diff --git a/Rom.py b/Rom.py index 620470e9..4d24a0c7 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '185a0f74ab0e2ce8899c8d7d309ca68c' +RANDOMIZERBASEHASH = '7264ffb7c430dde5d6bfe6030b79a575' class JsonRom(object): @@ -1493,7 +1493,7 @@ def patch_race_rom(rom): RaceRom.encrypt(rom) def write_custom_shops(rom, world, player): - shops = [shop for shop in world.shops if shop.custom and shop.region.player == player] + shops = [shop for shop in world.shops[player] if shop.custom and shop.region.player == player] shop_data = bytearray() items_data = bytearray() diff --git a/data/base2current.bps b/data/base2current.bps index 61323175..c0d427e8 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 70bc1148..44bf9fc7 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -59,6 +59,10 @@ "expert" ] }, + "shopsanity" : { + "action": "store_true", + "type": "bool" + }, "keydropshuffle" : { "action": "store_true", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index a0fa6296..389fd0de 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -245,6 +245,7 @@ "compassshuffle": [ "Compasses are no longer restricted to their dungeons, but can be anywhere. (default: %(default)s)" ], "keyshuffle": [ "Small Keys are no longer restricted to their dungeons, but can be anywhere. (default: %(default)s)" ], "bigkeyshuffle": [ "Big Keys are no longer restricted to their dungeons, but can be anywhere. (default: %(default)s)" ], + "shopsanity": ["Shop contents are shuffle in the main item pool and other items can take their place. (default: %(default)s)"], "keydropshuffle": [ "Key Drops (Pots and Enemies) are shuffled and other items can take their place (default: %(default)s)" ], "mixed_travel": [ "How to handle potential traversal between dungeon in Crossed door shuffle", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index b3140d40..d6ba7e87 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -237,6 +237,8 @@ "randomizer.item.itempool.hard": "Hard", "randomizer.item.itempool.expert": "Expert", + "randomizer.item.shopsanity": "Shopsanity", + "randomizer.item.itemfunction": "Item Functionality", "randomizer.item.itemfunction.normal": "Normal", "randomizer.item.itemfunction.hard": "Hard", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index d485cdb8..fa8681d3 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -1,6 +1,7 @@ { "checkboxes": { - "retro": { "type": "checkbox" } + "retro": { "type": "checkbox" }, + "shopsanity": { "type": "checkbox" } }, "leftItemFrame": { "worldstate": { diff --git a/source/classes/constants.py b/source/classes/constants.py index 18bca6ac..231386dc 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -56,6 +56,7 @@ SETTINGSTOPROCESS = { "randomizer": { "item": { "retro": "retro", + "shopsanity": "shopsanity", "worldstate": "mode", "logiclevel": "logic", "goal": "goal",