New Beemizer implementation, no longer replacing health; leaving that to item pool settings.

This commit is contained in:
Fabian Dill 2021-01-30 06:46:17 +01:00
parent 5cc8dd2c71
commit 61bef142a3
4 changed files with 129 additions and 131 deletions

View File

@ -2,12 +2,12 @@ from collections import namedtuple
import logging
from BaseClasses import Region, RegionType, Location
from Shops import ShopType, Shop, TakeAny, total_shop_slots
from Shops import TakeAny, total_shop_slots, set_up_shops, shuffle_shops
from Bosses import place_bosses
from Dungeons import get_dungeon_item_pool
from EntranceShuffle import connect_entrance
from Fill import FillError, fill_restrictive
from Items import ItemFactory
from Items import ItemFactory, trap_replaceable
from Rules import forbid_items_for_player
# This file sets the item pools for various modes. Timed modes and triforce hunt are enforced first, and then extra items are specified per mode to fill in the remaining space.
@ -390,27 +390,22 @@ def generate_itempool(world, player: int):
for i in range(4):
next(adv_heart_pieces).advancement = True
beeweights = {0: {None: 100},
1: {None: 75, 'trap': 25},
2: {None: 40, 'trap': 40, 'bee': 20},
3: {'trap': 50, 'bee': 50},
4: {'trap': 100}}
def beemizer(item):
if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type:
choice = world.random.choices(list(beeweights[world.beemizer[item.player]].keys()),
weights=list(beeweights[world.beemizer[item.player]].values()))[0]
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee",
player)
return item
progressionitems = []
nonprogressionitems = []
for item in items:
if item.advancement or item.priority or item.type:
progressionitems.append(item)
elif world.beemizer[player] and item.name in trap_replaceable:
if world.random.random() < world.beemizer[item.player] * 0.25:
if world.random.random() < (0.5 + world.beemizer[item.player] * 0.1):
nonprogressionitems.append(ItemFactory("Bee Trap", player))
else:
nonprogressionitems.append(ItemFactory("Bee", player))
else:
nonprogressionitems.append(item)
else:
nonprogressionitems.append(beemizer(item))
nonprogressionitems.append(item)
world.random.shuffle(nonprogressionitems)
if additional_triforce_pieces:
@ -446,89 +441,6 @@ def generate_itempool(world, player: int):
set_up_take_anys(world, player) # depends on world.itempool to be set
def shuffle_shops(world, items, player: int):
option = world.shop_shuffle[player]
if 'u' in option:
progressive = world.progressive[player]
progressive = world.random.choice([True, False]) if progressive == 'random' else progressive == 'on'
progressive &= world.goal == 'icerodhunt'
new_items = ["Bomb Upgrade (+5)"] * 6
new_items.append("Bomb Upgrade (+5)" if progressive else "Bomb Upgrade (+10)")
if not world.retro[player]:
new_items += ["Arrow Upgrade (+5)"] * 6
new_items.append("Arrow Upgrade (+5)" if progressive else "Arrow Upgrade (+10)")
world.random.shuffle(new_items) # Decide what gets tossed randomly if it can't insert everything.
capacityshop: Shop = None
for shop in world.shops:
if shop.type == ShopType.UpgradeShop and shop.region.player == player and \
shop.region.name == "Capacity Upgrade":
shop.clear_inventory()
capacityshop = shop
if world.goal[player] != 'icerodhunt':
for i, item in enumerate(items):
if "Heart" not in item.name:
items[i] = ItemFactory(new_items.pop(), player)
if not new_items:
break
else:
logging.warning(f"Not all upgrades put into Player{player}' item pool. Putting remaining items in Capacity Upgrade shop instead.")
bombupgrades = sum(1 for item in new_items if 'Bomb Upgrade' in item)
arrowupgrades = sum(1 for item in new_items if 'Arrow Upgrade' in item)
if bombupgrades:
capacityshop.add_inventory(1, 'Bomb Upgrade (+5)', 100, bombupgrades)
if arrowupgrades:
capacityshop.add_inventory(1, 'Arrow Upgrade (+5)', 100, arrowupgrades)
else:
for item in new_items:
world.push_precollected(ItemFactory(item, player))
if 'p' in option or 'i' in option:
shops = []
upgrade_shops = []
total_inventory = []
for shop in world.shops:
if shop.region.player == player:
if shop.type == ShopType.UpgradeShop:
upgrade_shops.append(shop)
elif shop.type == ShopType.Shop:
if shop.region.name == 'Potion Shop' and not 'w' in option:
# don't modify potion shop
pass
else:
shops.append(shop)
total_inventory.extend(shop.inventory)
if 'p' in option:
def price_adjust(price: int) -> int:
# it is important that a base price of 0 always returns 0 as new price!
adjust = 2 if price < 100 else 5
return int((price / adjust) * (0.5 + world.random.random() * 1.5)) * adjust
def adjust_item(item):
if item:
item["price"] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
for item in total_inventory:
adjust_item(item)
for shop in upgrade_shops:
for item in shop.inventory:
adjust_item(item)
if 'i' 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)',
@ -639,32 +551,6 @@ def fill_prizes(world, attempts=15):
raise FillError('Unable to place dungeon prizes')
def set_up_shops(world, player: int):
# TODO: move hard+ mode changes for shields here, utilizing the new shops
if world.retro[player]:
rss = world.get_region('Red Shield Shop', player).shop
replacement_items = [['Red Potion', 150], ['Green Potion', 75], ['Blue Potion', 200], ['Bombs (10)', 50],
['Blue Shield', 50], ['Small Heart', 10]] # Can't just replace the single arrow with 10 arrows as retro doesn't need them.
if world.keyshuffle[player] == "universal":
replacement_items.append(['Small Key (Universal)', 100])
replacement_item = world.random.choice(replacement_items)
rss.add_inventory(2, 'Single Arrow', 80, 1, replacement_item[0], replacement_item[1])
rss.locked = True
if world.keyshuffle[player] == "universal" or world.retro[player]:
for shop in world.random.sample([s for s in world.shops if
s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player],
5):
shop.locked = True
slots = [0, 0, 1, 1, 2, 2]
world.random.shuffle(slots)
slots = iter(slots)
if world.keyshuffle[player] == "universal":
shop.add_inventory(next(slots), 'Small Key (Universal)', 100)
if world.retro[player]:
shop.push_inventory(next(slots), 'Single Arrow', 80)
def get_pool_core(world, player: int):
progressive = world.progressive[player]
shuffle = world.shuffle[player]

View File

@ -234,3 +234,5 @@ progression_items = {name for name, data in item_table.items() if type(data[3])
item_name_groups['Everything'] = {name for name, data in item_table.items() if type(data[3]) == int}
item_name_groups['Progression Items'] = progression_items
item_name_groups['Non Progression Items'] = item_name_groups['Everything'] - progression_items
trap_replaceable = item_name_groups['Rupees'] | {'Arrows (10)', 'Single Bomb', 'Bombs (3)', 'Bombs (10)'}

112
Shops.py
View File

@ -5,7 +5,7 @@ import logging
from BaseClasses import Location
from EntranceShuffle import door_addresses
from Items import item_name_groups, item_table, ItemFactory
from Items import item_name_groups, item_table, ItemFactory, trap_replaceable
from Utils import int16_as_bytes
logger = logging.getLogger("Shops")
@ -328,3 +328,113 @@ shop_generation_types = {
'bottle': [('Small Heart', 10), ('Apple', 50), ('Bee', 10), ('Good Bee', 100), ('Faerie', 100), ('Magic Jar', 100)],
'time': [('Red Clock', 100), ('Blue Clock', 200), ('Green Clock', 300)],
}
def set_up_shops(world, player: int):
# TODO: move hard+ mode changes for shields here, utilizing the new shops
if world.retro[player]:
rss = world.get_region('Red Shield Shop', player).shop
replacement_items = [['Red Potion', 150], ['Green Potion', 75], ['Blue Potion', 200], ['Bombs (10)', 50],
['Blue Shield', 50], ['Small Heart', 10]] # Can't just replace the single arrow with 10 arrows as retro doesn't need them.
if world.keyshuffle[player] == "universal":
replacement_items.append(['Small Key (Universal)', 100])
replacement_item = world.random.choice(replacement_items)
rss.add_inventory(2, 'Single Arrow', 80, 1, replacement_item[0], replacement_item[1])
rss.locked = True
if world.keyshuffle[player] == "universal" or world.retro[player]:
for shop in world.random.sample([s for s in world.shops if
s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player],
5):
shop.locked = True
slots = [0, 1, 2]
world.random.shuffle(slots)
slots = iter(slots)
if world.keyshuffle[player] == "universal":
shop.add_inventory(next(slots), 'Small Key (Universal)', 100)
if world.retro[player]:
shop.push_inventory(next(slots), 'Single Arrow', 80)
def shuffle_shops(world, items, player: int):
option = world.shop_shuffle[player]
if 'u' in option:
progressive = world.progressive[player]
progressive = world.random.choice([True, False]) if progressive == 'random' else progressive == 'on'
progressive &= world.goal == 'icerodhunt'
new_items = ["Bomb Upgrade (+5)"] * 6
new_items.append("Bomb Upgrade (+5)" if progressive else "Bomb Upgrade (+10)")
if not world.retro[player]:
new_items += ["Arrow Upgrade (+5)"] * 6
new_items.append("Arrow Upgrade (+5)" if progressive else "Arrow Upgrade (+10)")
world.random.shuffle(new_items) # Decide what gets tossed randomly if it can't insert everything.
capacityshop: Optional[Shop] = None
for shop in world.shops:
if shop.type == ShopType.UpgradeShop and shop.region.player == player and \
shop.region.name == "Capacity Upgrade":
shop.clear_inventory()
capacityshop = shop
if world.goal[player] != 'icerodhunt':
for i, item in enumerate(items):
if item.name in trap_replaceable:
items[i] = ItemFactory(new_items.pop(), player)
if not new_items:
break
else:
logging.warning(f"Not all upgrades put into Player{player}' item pool. Putting remaining items in Capacity Upgrade shop instead.")
bombupgrades = sum(1 for item in new_items if 'Bomb Upgrade' in item)
arrowupgrades = sum(1 for item in new_items if 'Arrow Upgrade' in item)
if bombupgrades:
capacityshop.add_inventory(1, 'Bomb Upgrade (+5)', 100, bombupgrades)
if arrowupgrades:
capacityshop.add_inventory(1, 'Arrow Upgrade (+5)', 100, arrowupgrades)
else:
for item in new_items:
world.push_precollected(ItemFactory(item, player))
if 'p' in option or 'i' in option:
shops = []
upgrade_shops = []
total_inventory = []
for shop in world.shops:
if shop.region.player == player:
if shop.type == ShopType.UpgradeShop:
upgrade_shops.append(shop)
elif shop.type == ShopType.Shop:
if shop.region.name == 'Potion Shop' and not 'w' in option:
# don't modify potion shop
pass
else:
shops.append(shop)
total_inventory.extend(shop.inventory)
if 'p' in option:
def price_adjust(price: int) -> int:
# it is important that a base price of 0 always returns 0 as new price!
adjust = 2 if price < 100 else 5
return int((price / adjust) * (0.5 + world.random.random() * 1.5)) * adjust
def adjust_item(item):
if item:
item["price"] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
for item in total_inventory:
adjust_item(item)
for shop in upgrade_shops:
for item in shop.inventory:
adjust_item(item)
if 'i' 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

View File

@ -221,12 +221,12 @@ pot_shuffle:
'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile
'off': 50 # Default pot item locations
### End of Enemizer Section ###
beemizer: # Remove items from the global item pool and replace them with single bees and bee traps
beemizer: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps
0: 50 # No bee traps are placed
1: 0 # 25% of the non-essential item pool is replaced with bee traps
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
1: 0 # 25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees
2: 0 # 50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees
3: 0 # 75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees
4: 0 # 100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees
### Shop Settings ###
shop_shuffle_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl)
0: 50