Shop Shuffle

- more can be done here, but this works fine as a sometimes fun proof of concept
This commit is contained in:
Fabian Dill 2020-08-23 15:03:06 +02:00
parent 40e4e3c0c6
commit 26ab3dd69a
7 changed files with 65 additions and 3 deletions

View File

@ -124,6 +124,7 @@ class World(object):
set_player_attr('local_items', set())
set_player_attr('triforce_pieces_available', 30)
set_player_attr('triforce_pieces_required', 20)
set_player_attr('shop_shuffle', 'off')
def secure(self):
self.random = secrets.SystemRandom()
@ -1052,6 +1053,7 @@ class ShopType(Enum):
UpgradeShop = 2
class Shop(object):
slots = 3
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
self.region = region
self.room_id = room_id

View File

@ -312,6 +312,7 @@ def parse_arguments(argv, no_defaults=False):
parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
parser.add_argument('--shufflepots', default=defval(False), action='store_true')
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4))
parser.add_argument('--shop_shuffle', default='off', choices=['off', 'inventory', 'price', 'inventory_price'])
parser.add_argument('--remote_items', default=defval(False), action='store_true')
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
parser.add_argument('--names', default=defval(''))
@ -355,7 +356,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",
"triforce_pieces_required", "shop_shuffle",
'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves',
'tile_shuffle', 'bush_shuffle']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)

15
Gui.py
View File

@ -344,11 +344,22 @@ def guiMain(args=None):
shuffleFrame = Frame(drowDownFrame)
shuffleVar = StringVar()
shuffleVar.set('vanilla')
shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple')
shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'crossed',
'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy',
'dungeonsfull', 'dungeonssimple')
shuffleOptionMenu.pack(side=RIGHT)
shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm')
shuffleLabel.pack(side=LEFT)
shop_shuffleFrame = Frame(drowDownFrame)
shop_shuffleVar = StringVar()
shop_shuffleVar.set('off')
shop_shuffleOptionMenu = OptionMenu(shop_shuffleFrame, shop_shuffleVar, 'off', 'inventory', 'price',
'price and inventory')
shop_shuffleOptionMenu.pack(side=RIGHT)
shop_shuffleLabel = Label(shop_shuffleFrame, text='Shop Shuffle')
shop_shuffleLabel.pack(side=LEFT)
modeFrame.pack(expand=True, anchor=E)
logicFrame.pack(expand=True, anchor=E)
goalFrame.pack(expand=True, anchor=E)
@ -363,6 +374,7 @@ def guiMain(args=None):
accessibilityFrame.pack(expand=True, anchor=E)
algorithmFrame.pack(expand=True, anchor=E)
shuffleFrame.pack(expand=True, anchor=E)
shop_shuffleFrame.pack(expand=True, anchor=E)
enemizerFrame = LabelFrame(randomizerWindow, text="Enemizer", padx=5, pady=2)
@ -479,6 +491,7 @@ def guiMain(args=None):
guiargs.accessibility = accessibilityVar.get()
guiargs.algorithm = algorithmVar.get()
guiargs.shuffle = shuffleVar.get()
guiargs.shop_shuffle = shop_shuffleVar.get()
guiargs.heartbeep = heartbeepVar.get()
guiargs.heartcolor = heartcolorVar.get()
guiargs.fastmenu = fastMenuVar.get()

View File

@ -323,9 +323,45 @@ def generate_itempool(world, player: int):
if world.retro[player]:
set_up_take_anys(world, player)
if world.shop_shuffle[player] != 'off':
shuffle_shops(world, player)
create_dynamic_shop_locations(world, player)
def shuffle_shops(world, player: int):
option = world.shop_shuffle[player]
shops = []
total_inventory = []
for shop in world.shops:
if shop.type == ShopType.Shop and shop.region.player == player:
shops.append(shop)
total_inventory.extend(shop.inventory)
if 'price' in option:
def price_adjust(price: int) -> int:
# it is important that a base price of 0 always returns 0 as new price!
return int(price * (0.5 + world.random.random() * 2))
for item in total_inventory:
if item:
item["price"] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
for shop in world.shops:
if shop.type == ShopType.UpgradeShop and shop.region.player == player:
for item in shop.inventory:
if item:
item['price'] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
if 'inventory' in option:
world.random.shuffle(total_inventory)
i = 0
for shop in shops:
slots = shop.slots
shop.inventory = total_inventory[i:i + slots]
i += slots
take_any_locations = [
'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut',
'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Lumberjack House', 'Bonk Fairy (Light)',

View File

@ -79,6 +79,7 @@ def main(args, seed=None):
world.glitch_boots = args.glitch_boots.copy()
world.triforce_pieces_available = args.triforce_pieces_available.copy()
world.triforce_pieces_required = args.triforce_pieces_required.copy()
world.shop_shuffle = args.shop_shuffle.copy()
world.progression_balancing = {player: not balance for player, balance in args.skip_progression_balancing.items()}
world.rom_seeds = {player: random.Random(world.random.randint(0, 999999999)) for player in range(1, world.players + 1)}

View File

@ -310,6 +310,10 @@ def roll_settings(weights):
ret.triforce_pieces_required = get_choice('triforce_pieces_required', weights, 20)
ret.triforce_pieces_required = min(max(1, int(ret.triforce_pieces_required)), 90)
ret.shop_shuffle = get_choice('shop_shuffle', weights, False)
if not ret.shop_shuffle:
ret.shop_shuffle = 'off'
ret.mode = get_choice('world_state', weights, None) # legacy support
if ret.mode == 'retro':
ret.mode = 'open'

View File

@ -189,6 +189,11 @@ beemizer: # Remove items from the global item pool and replace them with single
2: 0 # 60% of the non-essential item pool is replaced with bee traps, of which 20% could be single bees
3: 0 # 100% of the non-essential item pool is replaced with bee traps, of which 50% could be single bees
4: 0 # 100% of the non-essential item pool is replaced with bee traps
shop_shuffle:
off: 1
inventory: 0 # shuffle the inventories of the shops around
price: 0 # randomize the prices of the items in shop inventories
inventory_price: 0 # shuffle inventories and randomize prices
timer:
none: 1
timed: 0