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('local_items', set())
set_player_attr('triforce_pieces_available', 30) set_player_attr('triforce_pieces_available', 30)
set_player_attr('triforce_pieces_required', 20) set_player_attr('triforce_pieces_required', 20)
set_player_attr('shop_shuffle', 'off')
def secure(self): def secure(self):
self.random = secrets.SystemRandom() self.random = secrets.SystemRandom()
@ -1052,6 +1053,7 @@ class ShopType(Enum):
UpgradeShop = 2 UpgradeShop = 2
class Shop(object): class Shop(object):
slots = 3
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked): def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
self.region = region self.region = region
self.room_id = room_id 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('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
parser.add_argument('--shufflepots', default=defval(False), action='store_true') 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('--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('--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('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
parser.add_argument('--names', default=defval('')) 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', 'shufflebosses', 'enemy_shuffle', 'enemy_health', 'enemy_damage', 'shufflepots',
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'heartbeep', "skip_progression_balancing", "triforce_pieces_available", 'heartbeep', "skip_progression_balancing", "triforce_pieces_available",
"triforce_pieces_required", "triforce_pieces_required", "shop_shuffle",
'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves', 'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves',
'tile_shuffle', 'bush_shuffle']: 'tile_shuffle', 'bush_shuffle']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) 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) shuffleFrame = Frame(drowDownFrame)
shuffleVar = StringVar() shuffleVar = StringVar()
shuffleVar.set('vanilla') 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) shuffleOptionMenu.pack(side=RIGHT)
shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm') shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm')
shuffleLabel.pack(side=LEFT) 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) modeFrame.pack(expand=True, anchor=E)
logicFrame.pack(expand=True, anchor=E) logicFrame.pack(expand=True, anchor=E)
goalFrame.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) accessibilityFrame.pack(expand=True, anchor=E)
algorithmFrame.pack(expand=True, anchor=E) algorithmFrame.pack(expand=True, anchor=E)
shuffleFrame.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) enemizerFrame = LabelFrame(randomizerWindow, text="Enemizer", padx=5, pady=2)
@ -479,6 +491,7 @@ def guiMain(args=None):
guiargs.accessibility = accessibilityVar.get() guiargs.accessibility = accessibilityVar.get()
guiargs.algorithm = algorithmVar.get() guiargs.algorithm = algorithmVar.get()
guiargs.shuffle = shuffleVar.get() guiargs.shuffle = shuffleVar.get()
guiargs.shop_shuffle = shop_shuffleVar.get()
guiargs.heartbeep = heartbeepVar.get() guiargs.heartbeep = heartbeepVar.get()
guiargs.heartcolor = heartcolorVar.get() guiargs.heartcolor = heartcolorVar.get()
guiargs.fastmenu = fastMenuVar.get() guiargs.fastmenu = fastMenuVar.get()

View File

@ -323,9 +323,45 @@ def generate_itempool(world, player: int):
if world.retro[player]: if world.retro[player]:
set_up_take_anys(world, player) set_up_take_anys(world, player)
if world.shop_shuffle[player] != 'off':
shuffle_shops(world, player)
create_dynamic_shop_locations(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 = [ take_any_locations = [
'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut', '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)', '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.glitch_boots = args.glitch_boots.copy()
world.triforce_pieces_available = args.triforce_pieces_available.copy() world.triforce_pieces_available = args.triforce_pieces_available.copy()
world.triforce_pieces_required = args.triforce_pieces_required.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.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)} 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 = get_choice('triforce_pieces_required', weights, 20)
ret.triforce_pieces_required = min(max(1, int(ret.triforce_pieces_required)), 90) 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 ret.mode = get_choice('world_state', weights, None) # legacy support
if ret.mode == 'retro': if ret.mode == 'retro':
ret.mode = 'open' 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 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 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 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: timer:
none: 1 none: 1
timed: 0 timed: 0