Shop Item Pool fill feature + multiworld player compatability
This commit is contained in:
		
							parent
							
								
									9e0ed8ab5b
								
							
						
					
					
						commit
						c8034dbb46
					
				| 
						 | 
					@ -131,6 +131,7 @@ class World(object):
 | 
				
			||||||
            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')
 | 
					            set_player_attr('shop_shuffle', 'off')
 | 
				
			||||||
 | 
					            set_player_attr('shop_shuffle_slots', 0)
 | 
				
			||||||
            set_player_attr('shuffle_prizes', "g")
 | 
					            set_player_attr('shuffle_prizes', "g")
 | 
				
			||||||
            set_player_attr('sprite_pool', [])
 | 
					            set_player_attr('sprite_pool', [])
 | 
				
			||||||
            set_player_attr('dark_room_logic', "lamp")
 | 
					            set_player_attr('dark_room_logic', "lamp")
 | 
				
			||||||
| 
						 | 
					@ -340,6 +341,27 @@ class World(object):
 | 
				
			||||||
            if collect:
 | 
					            if collect:
 | 
				
			||||||
                self.state.collect(item, location.event, location)
 | 
					                self.state.collect(item, location.event, location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # TODO: Prevents fast_filling certain items.  Move this to a proper filter.
 | 
				
			||||||
 | 
					            if location.parent_region.shop is not None and location.name != 'Potion Shop': # includes potion shop slots but not potion shop powder
 | 
				
			||||||
 | 
					                slot_num = int(location.name[-1]) - 1
 | 
				
			||||||
 | 
					                my_item = location.parent_region.shop.inventory[slot_num]
 | 
				
			||||||
 | 
					                if (my_item is not None and my_item['item'] == item.name) or 'Rupee' in item.name:
 | 
				
			||||||
 | 
					                    # this will filter items that match the item in the shop or Rupees
 | 
				
			||||||
 | 
					                    # really not a way for the player to know a renewable item from a world item
 | 
				
			||||||
 | 
					                    # bombs can be sitting on top of arrows or a potion refill, but dunno if that's a big deal
 | 
				
			||||||
 | 
					                    logging.debug('skipping item shop {}'.format(item.name))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    if my_item is None:
 | 
				
			||||||
 | 
					                        location.parent_region.shop.add_inventory(slot_num, 'None', 0)
 | 
				
			||||||
 | 
					                        my_item = location.parent_region.shop.inventory[slot_num]
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        my_item['replacement'] = my_item['item']
 | 
				
			||||||
 | 
					                        my_item['replacement_price'] = my_item['price']
 | 
				
			||||||
 | 
					                    my_item['item'] = item.name
 | 
				
			||||||
 | 
					                    my_item['price'] = self.random.randrange(1, 61) * 5  # can probably replace this with a price chart
 | 
				
			||||||
 | 
					                    my_item['max'] = 1
 | 
				
			||||||
 | 
					                    my_item['player'] = item.player if item.player != location.player else 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            logging.debug('Placed %s at %s', item, location)
 | 
					            logging.debug('Placed %s at %s', item, location)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))
 | 
					            raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))
 | 
				
			||||||
| 
						 | 
					@ -1140,7 +1162,8 @@ class Shop():
 | 
				
			||||||
            'max': max,
 | 
					            'max': max,
 | 
				
			||||||
            'replacement': replacement,
 | 
					            'replacement': replacement,
 | 
				
			||||||
            'replacement_price': replacement_price,
 | 
					            'replacement_price': replacement_price,
 | 
				
			||||||
            'create_location': create_location
 | 
					            'create_location': create_location,
 | 
				
			||||||
 | 
					            'player': 0
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def push_inventory(self, slot: int, item: str, price: int, max: int = 1):
 | 
					    def push_inventory(self, slot: int, item: str, price: int, max: int = 1):
 | 
				
			||||||
| 
						 | 
					@ -1153,7 +1176,8 @@ class Shop():
 | 
				
			||||||
            'max': max,
 | 
					            'max': max,
 | 
				
			||||||
            'replacement': self.inventory[slot]["item"],
 | 
					            'replacement': self.inventory[slot]["item"],
 | 
				
			||||||
            'replacement_price': self.inventory[slot]["price"],
 | 
					            'replacement_price': self.inventory[slot]["price"],
 | 
				
			||||||
            'create_location': self.inventory[slot]["create_location"]
 | 
					            'create_location': self.inventory[slot]["create_location"],
 | 
				
			||||||
 | 
					            'player': self.inventory[slot]["player"]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1239,6 +1263,10 @@ class Spoiler(object):
 | 
				
			||||||
                if item is None:
 | 
					                if item is None:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                shopdata['item_{}'.format(index)] = "{} — {}".format(item['item'], item['price']) if item['price'] else item['item']
 | 
					                shopdata['item_{}'.format(index)] = "{} — {}".format(item['item'], item['price']) if item['price'] else item['item']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if item['player'] > 0:
 | 
				
			||||||
 | 
					                    shopdata['item_{}'.format(index)] = shopdata['item_{}'.format(index)].replace('—', '(Player {}) — '.format(item['player']))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if item['max'] == 0:
 | 
					                if item['max'] == 0:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                shopdata['item_{}'.format(index)] += " x {}".format(item['max'])
 | 
					                shopdata['item_{}'.format(index)] += " x {}".format(item['max'])
 | 
				
			||||||
| 
						 | 
					@ -1312,6 +1340,7 @@ class Spoiler(object):
 | 
				
			||||||
                         'triforce_pieces_available': self.world.triforce_pieces_available,
 | 
					                         'triforce_pieces_available': self.world.triforce_pieces_available,
 | 
				
			||||||
                         'triforce_pieces_required': self.world.triforce_pieces_required,
 | 
					                         'triforce_pieces_required': self.world.triforce_pieces_required,
 | 
				
			||||||
                         'shop_shuffle': self.world.shop_shuffle,
 | 
					                         'shop_shuffle': self.world.shop_shuffle,
 | 
				
			||||||
 | 
					                         'shop_shuffle_slots': self.world.shop_shuffle_slots,
 | 
				
			||||||
                         'shuffle_prizes': self.world.shuffle_prizes,
 | 
					                         'shuffle_prizes': self.world.shuffle_prizes,
 | 
				
			||||||
                         'sprite_pool': self.world.sprite_pool,
 | 
					                         'sprite_pool': self.world.sprite_pool,
 | 
				
			||||||
                         'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss
 | 
					                         'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -330,6 +330,11 @@ def parse_arguments(argv, no_defaults=False):
 | 
				
			||||||
    p: randomize the prices of the items in shop inventories
 | 
					    p: randomize the prices of the items in shop inventories
 | 
				
			||||||
    u: shuffle capacity upgrades into the item pool
 | 
					    u: shuffle capacity upgrades into the item pool
 | 
				
			||||||
    ''')
 | 
					    ''')
 | 
				
			||||||
 | 
					    parser.add_argument('--shop_shuffle_slots', default=defval(0),
 | 
				
			||||||
 | 
					                        type=lambda value: min(max(int(value), 1), 96),
 | 
				
			||||||
 | 
					                        help='''
 | 
				
			||||||
 | 
					        Maximum amount of shop slots able to be filled by items from the item pool.
 | 
				
			||||||
 | 
					    ''')
 | 
				
			||||||
    parser.add_argument('--shuffle_prizes', default=defval('g'), choices=['', 'g', 'b', 'gb'])
 | 
					    parser.add_argument('--shuffle_prizes', default=defval('g'), choices=['', 'g', 'b', 'gb'])
 | 
				
			||||||
    parser.add_argument('--sprite_pool', help='''\
 | 
					    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.''')
 | 
					    Specifies a colon separated list of sprites used for random/randomonevent. If not specified, the full sprite pool is used.''')
 | 
				
			||||||
| 
						 | 
					@ -382,7 +387,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", "shop_shuffle",
 | 
					                         "triforce_pieces_required", "shop_shuffle", "shop_shuffle_slots",
 | 
				
			||||||
                         'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves',
 | 
					                         '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',
 | 
					                         'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool', 'dark_room_logic', 'restrict_dungeon_item_on_boss',
 | 
				
			||||||
                         'hud_palettes', 'sword_palettes', 'shield_palettes', 'link_palettes']:
 | 
					                         'hud_palettes', 'sword_palettes', 'shield_palettes', 'link_palettes']:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										1
									
								
								Main.py
								
								
								
								
							| 
						 | 
					@ -83,6 +83,7 @@ def main(args, seed=None):
 | 
				
			||||||
    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.shop_shuffle = args.shop_shuffle.copy()
 | 
				
			||||||
 | 
					    world.shop_shuffle_slots = args.shop_shuffle_slots.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.shuffle_prizes = args.shuffle_prizes.copy()
 | 
					    world.shuffle_prizes = args.shuffle_prizes.copy()
 | 
				
			||||||
    world.sprite_pool = args.sprite_pool.copy()
 | 
					    world.sprite_pool = args.sprite_pool.copy()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,6 +362,8 @@ def roll_settings(weights):
 | 
				
			||||||
    # change minimum to required pieces to avoid problems
 | 
					    # change minimum to required pieces to avoid problems
 | 
				
			||||||
    ret.triforce_pieces_available = min(max(ret.triforce_pieces_required, int(ret.triforce_pieces_available)), 90)
 | 
					    ret.triforce_pieces_available = min(max(ret.triforce_pieces_required, int(ret.triforce_pieces_available)), 90)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret.shop_shuffle_slots = int(get_choice('shop_shuffle_slots', weights, '0'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret.shop_shuffle = get_choice('shop_shuffle', weights, '')
 | 
					    ret.shop_shuffle = get_choice('shop_shuffle', weights, '')
 | 
				
			||||||
    if not ret.shop_shuffle:
 | 
					    if not ret.shop_shuffle:
 | 
				
			||||||
        ret.shop_shuffle = ''
 | 
					        ret.shop_shuffle = ''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								Regions.py
								
								
								
								
							
							
						
						
									
										25
									
								
								Regions.py
								
								
								
								
							| 
						 | 
					@ -368,7 +368,17 @@ def create_shops(world, player: int):
 | 
				
			||||||
    cls_mapping = {ShopType.UpgradeShop: UpgradeShop,
 | 
					    cls_mapping = {ShopType.UpgradeShop: UpgradeShop,
 | 
				
			||||||
                   ShopType.Shop: Shop,
 | 
					                   ShopType.Shop: Shop,
 | 
				
			||||||
                   ShopType.TakeAny: TakeAny}
 | 
					                   ShopType.TakeAny: TakeAny}
 | 
				
			||||||
    for region_name, (room_id, type, shopkeeper, custom, locked, inventory) in shop_table.items():
 | 
					    option = world.shop_shuffle[player]
 | 
				
			||||||
 | 
					    my_shop_table = dict(shop_table)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    num_slots = int(world.shop_shuffle_slots[player])
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    my_shop_slots = ([True] * num_slots + [False] * (len(shop_table) * 3))[:len(shop_table)*3 - 2] 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    world.random.shuffle(my_shop_slots)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from Items import ItemFactory
 | 
				
			||||||
 | 
					    for region_name, (room_id, type, shopkeeper, custom, locked, inventory) in my_shop_table.items():
 | 
				
			||||||
        if world.mode[player] == 'inverted' and region_name == 'Dark Lake Hylia Shop':
 | 
					        if world.mode[player] == 'inverted' and region_name == 'Dark Lake Hylia Shop':
 | 
				
			||||||
            locked = True
 | 
					            locked = True
 | 
				
			||||||
            inventory = [('Blue Potion', 160), ('Blue Shield', 50), ('Bombs (10)', 50)]
 | 
					            inventory = [('Blue Potion', 160), ('Blue Shield', 50), ('Bombs (10)', 50)]
 | 
				
			||||||
| 
						 | 
					@ -378,6 +388,19 @@ def create_shops(world, player: int):
 | 
				
			||||||
        world.shops.append(shop)
 | 
					        world.shops.append(shop)
 | 
				
			||||||
        for index, item in enumerate(inventory):
 | 
					        for index, item in enumerate(inventory):
 | 
				
			||||||
            shop.add_inventory(index, *item)
 | 
					            shop.add_inventory(index, *item)
 | 
				
			||||||
 | 
					            if region_name == 'Potion Shop':
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            elif region_name == 'Capacity Upgrade':
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if my_shop_slots.pop():
 | 
				
			||||||
 | 
					                    additional_item = world.random.choice(['Rupees (20)', 'Rupees (50)', 'Rupees (100)'])
 | 
				
			||||||
 | 
					                    world.itempool.append(ItemFactory(additional_item, player))
 | 
				
			||||||
 | 
					                    loc = Location(player, "{} Slot Item {}".format(shop.region.name, index+1), parent=shop.region)
 | 
				
			||||||
 | 
					                    shop.region.locations.append(loc)
 | 
				
			||||||
 | 
					                    world.dynamic_locations.append(loc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    world.clear_location_cache()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# (type, room_id, shopkeeper, custom, locked, [items])
 | 
					# (type, room_id, shopkeeper, custom, locked, [items])
 | 
				
			||||||
# item = (item, price, max=0, replacement=None, replacement_price=0)
 | 
					# item = (item, price, max=0, replacement=None, replacement_price=0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,9 +211,15 @@ 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
 | 
				
			||||||
 | 
					### Item Shuffle (shop)
 | 
				
			||||||
 | 
					shop_shuffle_slots: 
 | 
				
			||||||
 | 
					  0: 50
 | 
				
			||||||
 | 
					  5: 0
 | 
				
			||||||
 | 
					  15: 0
 | 
				
			||||||
 | 
					  999: 0
 | 
				
			||||||
shop_shuffle:
 | 
					shop_shuffle:
 | 
				
			||||||
  none: 50
 | 
					  none: 50
 | 
				
			||||||
  i: 0 # Shuffle the inventories of the shops around
 | 
					  i: 0 # Shuffle default inventories of the shops around
 | 
				
			||||||
  p: 0 # Randomize the prices of the items in shop inventories
 | 
					  p: 0 # Randomize the prices of the items in shop inventories
 | 
				
			||||||
  u: 0 # Shuffle capacity upgrades into the item pool (and allow them to traverse the multiworld)
 | 
					  u: 0 # Shuffle capacity upgrades into the item pool (and allow them to traverse the multiworld)
 | 
				
			||||||
  ip: 0 # Shuffle inventories and randomize prices
 | 
					  ip: 0 # Shuffle inventories and randomize prices
 | 
				
			||||||
| 
						 | 
					@ -253,11 +259,6 @@ green_clock_time: # For all timer modes, the amount of time in minutes to gain o
 | 
				
			||||||
#  - "Small Keys"
 | 
					#  - "Small Keys"
 | 
				
			||||||
#  - "Big Keys"
 | 
					#  - "Big Keys"
 | 
				
			||||||
# Can be uncommented to use it
 | 
					# Can be uncommented to use it
 | 
				
			||||||
# non_local_items: # Force certain items to appear outside your world only, always across the multiworld. Recognizes some group names, like "Swords"
 | 
					 | 
				
			||||||
#  - "Moon Pearl"
 | 
					 | 
				
			||||||
#  - "Small Keys"
 | 
					 | 
				
			||||||
#  - "Big Keys"
 | 
					 | 
				
			||||||
# Can be uncommented to use it
 | 
					 | 
				
			||||||
# startinventory: # Begin the file with the listed items/upgrades
 | 
					# startinventory: # Begin the file with the listed items/upgrades
 | 
				
			||||||
  # Pegasus Boots: on
 | 
					  # Pegasus Boots: on
 | 
				
			||||||
  # Bomb Upgrade (+10): 4
 | 
					  # Bomb Upgrade (+10): 4
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue