diff --git a/BaseClasses.py b/BaseClasses.py index 5617fd85..a4ad724e 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -132,6 +132,7 @@ class World(object): set_player_attr('triforce_pieces_required', 20) set_player_attr('shop_shuffle', 'off') set_player_attr('shop_shuffle_slots', 0) + set_player_attr('potion_shop_shuffle', 'none') set_player_attr('shuffle_prizes', "g") set_player_attr('sprite_pool', []) set_player_attr('dark_room_logic', "lamp") @@ -1341,6 +1342,7 @@ class Spoiler(object): 'triforce_pieces_required': self.world.triforce_pieces_required, 'shop_shuffle': self.world.shop_shuffle, 'shop_shuffle_slots': self.world.shop_shuffle_slots, + 'potion_shop_shuffle': self.world.potion_shop_shuffle, 'shuffle_prizes': self.world.shuffle_prizes, 'sprite_pool': self.world.sprite_pool, 'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss diff --git a/EntranceRandomizer.py b/EntranceRandomizer.py index b94ed0db..48650536 100755 --- a/EntranceRandomizer.py +++ b/EntranceRandomizer.py @@ -335,6 +335,10 @@ def parse_arguments(argv, no_defaults=False): help=''' Maximum amount of shop slots able to be filled by items from the item pool. ''') + parser.add_argument('--potion_shop_shuffle', default=defval('none'), choices=['none', 'a'], help='''\ + Determine if potion shop shuffle items should be affected by the rules of shop shuffle. + Value `none` will only allow prices to be shuffled, `a` will allow any items to be shuffled. + ''') parser.add_argument('--shuffle_prizes', default=defval('g'), choices=['', 'g', 'b', 'gb']) parser.add_argument('--sprite_pool', help='''\ Specifies a colon separated list of sprites used for random/randomonevent. If not specified, the full sprite pool is used.''') @@ -387,7 +391,7 @@ def parse_arguments(argv, no_defaults=False): 'shufflebosses', 'enemy_shuffle', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', "skip_progression_balancing", "triforce_pieces_available", - "triforce_pieces_required", "shop_shuffle", "shop_shuffle_slots", + "triforce_pieces_required", "shop_shuffle", "shop_shuffle_slots", "potion_shop_shuffle", 'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves', 'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool', 'dark_room_logic', 'restrict_dungeon_item_on_boss', 'hud_palettes', 'sword_palettes', 'shield_palettes', 'link_palettes']: diff --git a/ItemPool.py b/ItemPool.py index 132785a1..8267774c 100644 --- a/ItemPool.py +++ b/ItemPool.py @@ -368,13 +368,17 @@ def shuffle_shops(world, items, player: int): shops = [] upgrade_shops = [] total_inventory = [] + potion_option = world.potion_shop_shuffle[player] for shop in world.shops: if shop.region.player == player: if shop.type == ShopType.UpgradeShop: upgrade_shops.append(shop) - elif shop.type == ShopType.Shop and shop.region.name != 'Potion Shop': - shops.append(shop) - total_inventory.extend(shop.inventory) + elif shop.type == ShopType.Shop: + if shop.region.name == 'Potion Shop' and potion_option in [None, '', 'none']: + upgrade_shops.append(shop) # just put it with the upgrade shops/caves so we don't shuffle the items, just prices + else: + shops.append(shop) + total_inventory.extend(shop.inventory) if 'p' in option: def price_adjust(price: int) -> int: @@ -470,7 +474,7 @@ def create_dynamic_shop_locations(world, player): world.clear_location_cache() - world.push_item(loc, ItemFactory(item['item'], player), False) + world.push_item(loc, ItemFactory(item['item'], player), False) loc.event = True loc.locked = True diff --git a/Main.py b/Main.py index e66e2181..31406be9 100644 --- a/Main.py +++ b/Main.py @@ -84,6 +84,7 @@ def main(args, seed=None): world.triforce_pieces_required = args.triforce_pieces_required.copy() world.shop_shuffle = args.shop_shuffle.copy() world.shop_shuffle_slots = args.shop_shuffle_slots.copy() + world.potion_shop_shuffle = args.potion_shop_shuffle.copy() world.progression_balancing = {player: not balance for player, balance in args.skip_progression_balancing.items()} world.shuffle_prizes = args.shuffle_prizes.copy() world.sprite_pool = args.sprite_pool.copy() diff --git a/Mystery.py b/Mystery.py index f28ca26a..c8261f03 100644 --- a/Mystery.py +++ b/Mystery.py @@ -368,6 +368,10 @@ def roll_settings(weights): if not ret.shop_shuffle: ret.shop_shuffle = '' + ret.potion_shop_shuffle = get_choice('potion_shop_shuffle', weights, '') + if not ret.potion_shop_shuffle: + ret.potion_shop_shuffle = '' + ret.mode = get_choice('world_state', weights, None) # legacy support if ret.mode == 'retro': ret.mode = 'open' diff --git a/Rom.py b/Rom.py index 6eaf6854..c36baf4d 100644 --- a/Rom.py +++ b/Rom.py @@ -122,6 +122,9 @@ class LocalRom(object): if not os.path.exists(local_path('data', 'basepatch.bmbp')): Patch.create_patch_file(local_path('basepatch.sfc')) return + + if not os.path.isfile(local_path('data', 'basepatch.bmbp')): + raise RuntimeError('Base patch unverified. Unable to continue.') if os.path.isfile(local_path('data', 'basepatch.bmbp')): _, target, buffer = Patch.create_rom_bytes(local_path('data', 'basepatch.bmbp')) @@ -130,6 +133,7 @@ class LocalRom(object): with open(local_path('basepatch.sfc'), 'wb') as stream: stream.write(buffer) return + raise RuntimeError('Base patch unverified. Unable to continue.') raise RuntimeError('Could not find Base Patch. Unable to continue.') @@ -1509,12 +1513,11 @@ def write_custom_shops(rom, world, player): else: sram_offset += shop.item_count shop_data.extend(bytes) - # [id][item][price-low][price-high][max][repl_id][repl_price-low][repl_price-high] + # [id][item][price-low][price-high][max][repl_id][repl_price-low][repl_price-high][player] for item in shop.inventory: if item is None: break - item_data = [shop_id, ItemFactory(item['item'], player).code] + int16_as_bytes(item['price']) + [ - item['max'], + item_data = [shop_id, ItemFactory(item['item'], player).code] + int16_as_bytes(item['price']) + [ item['max'],\ ItemFactory(item['replacement'], player).code if item['replacement'] else 0xFF] + int16_as_bytes( item['replacement_price']) + [item['player']] items_data.extend(item_data) diff --git a/Rules.py b/Rules.py index 04889a0f..3c12d9b3 100644 --- a/Rules.py +++ b/Rules.py @@ -85,7 +85,7 @@ def set_rules(world, player): add_rule(world.get_entrance('Ganons Tower', player), lambda state: state.world.get_entrance('Ganons Tower Ascent', player).can_reach(state), 'or') set_bunny_rules(world, player, world.mode[player] == 'inverted') - + def mirrorless_path_to_castle_courtyard(world, player): # If Agahnim is defeated then the courtyard needs to be accessible without using the mirror for the mirror offset glitch. diff --git a/WebHostLib/static/static/playerSettings.json b/WebHostLib/static/static/playerSettings.json index 7a3a88d4..48a47264 100644 --- a/WebHostLib/static/static/playerSettings.json +++ b/WebHostLib/static/static/playerSettings.json @@ -1095,7 +1095,7 @@ "i": { "keyString": "shop_shuffle.i", "friendlyName": "Inventory Shuffle", - "description": "Randomizes the inventories of shops.", + "description": "Shuffles the inventories of shops between each other.", "defaultValue": 0 }, "p": { @@ -1162,6 +1162,26 @@ } } }, + "potion_shop_shuffle": { + "keyString": "potion_shop_shuffle", + "friendlyName": "Potion Shop Shuffle Rules", + "description": "Influence on potion shop by shop shuffle options", + "inputType": "range", + "subOptions": { + "none": { + "keyString": "potion_shop_shuffle.none", + "friendlyName": "Vanilla Shops", + "description": "Shop contents are left unchanged, only prices.", + "defaultValue": 50 + }, + "a": { + "keyString": "potion_shop_shuffle.a", + "friendlyName": "Any Items can be shuffled in and out of the shop", + "description": "", + "defaultValue": 0 + } + } + }, "shuffle_prizes": { "keyString": "shuffle_prizes", "friendlyName": "Prize Shuffle", diff --git a/playerSettings.yaml b/playerSettings.yaml index 13f7a472..1ee5abcd 100644 --- a/playerSettings.yaml +++ b/playerSettings.yaml @@ -217,6 +217,9 @@ shop_shuffle_slots: # Maximum amount of allowed shop slots to place item pool it 5: 0 15: 0 999: 0 +potion_shop_shuffle: # influence of potion shop by shop shuffle + none: 50 # only shuffle price + a: 0 # generate/shuffle in any items shop_shuffle: none: 50 i: 0 # Shuffle default inventories of the shops around