mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Merge branch 'main' into breaking_changes
# Conflicts: # MultiClient.py # Utils.py # worlds/alttp/ItemPool.py # worlds/alttp/Main.py # worlds/alttp/Shops.py
This commit is contained in:
@@ -5,7 +5,7 @@ import logging
|
||||
|
||||
from BaseClasses import Location
|
||||
from worlds.alttp.EntranceShuffle import door_addresses
|
||||
from worlds.alttp.Items import item_name_groups, item_table, ItemFactory, trap_replaceable
|
||||
from worlds.alttp.Items import item_name_groups, item_table, ItemFactory, trap_replaceable, GetBeemizerItem
|
||||
from Utils import int16_as_bytes
|
||||
|
||||
logger = logging.getLogger("Shops")
|
||||
@@ -155,41 +155,59 @@ def ShopSlotFill(world):
|
||||
shop_slots -= removed
|
||||
|
||||
if shop_slots:
|
||||
del shop_slots
|
||||
|
||||
from Fill import swap_location_item
|
||||
# TODO: allow each game to register a blacklist to be used here?
|
||||
blacklist_words = {"Rupee"}
|
||||
blacklist_words = {item_name for item_name in item_table if any(
|
||||
blacklist_word in item_name for blacklist_word in blacklist_words)}
|
||||
blacklist_words.add("Bee")
|
||||
candidates_per_sphere = list(list(sphere) for sphere in world.get_spheres())
|
||||
|
||||
candidate_condition = lambda location: not location.locked and \
|
||||
not location.shop_slot and \
|
||||
not location.item.name in blacklist_words
|
||||
locations_per_sphere = list(list(sphere) for sphere in world.get_spheres())
|
||||
|
||||
|
||||
|
||||
# currently special care needs to be taken so that Shop.region.locations.item is identical to Shop.inventory
|
||||
# Potentially create Locations as needed and make inventory the only source, to prevent divergence
|
||||
cumu_weights = []
|
||||
shops_per_sphere = []
|
||||
candidates_per_sphere = []
|
||||
|
||||
for sphere in candidates_per_sphere:
|
||||
# sort spheres into piles of valid candidates and shops
|
||||
for sphere in locations_per_sphere:
|
||||
current_shops_slots = []
|
||||
current_candidates = []
|
||||
shops_per_sphere.append(current_shops_slots)
|
||||
candidates_per_sphere.append(current_candidates)
|
||||
for location in sphere:
|
||||
if location.shop_slot:
|
||||
if not location.shop_slot_disabled:
|
||||
current_shops_slots.append(location)
|
||||
elif not location.locked and not location.item.name in blacklist_words:
|
||||
current_candidates.append(location)
|
||||
if cumu_weights:
|
||||
x = cumu_weights[-1]
|
||||
else:
|
||||
x = 0
|
||||
cumu_weights.append(len(sphere) + x)
|
||||
world.random.shuffle(sphere)
|
||||
cumu_weights.append(len(current_candidates) + x)
|
||||
|
||||
for i, sphere in enumerate(candidates_per_sphere):
|
||||
current_shop_slots = [location for location in sphere if location.shop_slot and not location.shop_slot_disabled]
|
||||
world.random.shuffle(current_candidates)
|
||||
|
||||
del locations_per_sphere
|
||||
|
||||
total_spheres = len(candidates_per_sphere)
|
||||
|
||||
for i, current_shop_slots in enumerate(shops_per_sphere):
|
||||
if current_shop_slots:
|
||||
|
||||
candidate_sphere_ids = list(range(i, total_spheres))
|
||||
for location in current_shop_slots:
|
||||
shop: Shop = location.parent_region.shop
|
||||
# TODO: might need to implement trying randomly across spheres until canditates are exhausted.
|
||||
# As spheres may be as small as one item.
|
||||
swapping_sphere = world.random.choices(candidates_per_sphere[i:], cum_weights=cumu_weights[i:])[0]
|
||||
swapping_sphere_id = world.random.choices(candidate_sphere_ids,
|
||||
cum_weights=cumu_weights[i:])[0]
|
||||
swapping_sphere: list = candidates_per_sphere[swapping_sphere_id]
|
||||
for c in swapping_sphere: # chosen item locations
|
||||
if candidate_condition(c) and c.item_rule(location.item) and location.item_rule(c.item):
|
||||
if c.item_rule(location.item) and location.item_rule(c.item):
|
||||
swap_location_item(c, location, check_locked=False)
|
||||
logger.debug(f'Swapping {c} into {location}:: {location.item}')
|
||||
break
|
||||
@@ -199,18 +217,22 @@ def ShopSlotFill(world):
|
||||
logger.warning("Ran out of ShopShuffle Item candidate locations.")
|
||||
location.shop_slot_disabled = True
|
||||
continue
|
||||
item_name = location.item.name
|
||||
if any(x in item_name for x in ['Single Bomb', 'Single Arrow', 'Piece of Heart']):
|
||||
price = world.random.randrange(1, 7)
|
||||
elif any(x in item_name for x in ['Arrows', 'Bombs', 'Clock', 'Heart']):
|
||||
price = world.random.randrange(4, 24)
|
||||
elif any(x in item_name for x in ['Compass', 'Map', 'Small Key']):
|
||||
price = world.random.randrange(10, 30)
|
||||
else:
|
||||
price = world.random.randrange(10, 60)
|
||||
|
||||
price *= 5
|
||||
shop.push_inventory(int(location.name[-1]) - 1, item_name, price, 1,
|
||||
# remove candidate
|
||||
swapping_sphere.remove(c)
|
||||
cumu_weights[swapping_sphere_id] -= 1
|
||||
|
||||
item_name = location.item.name
|
||||
if any(x in item_name for x in ['Compass', 'Map', 'Single Bomb', 'Single Arrow', 'Piece of Heart']):
|
||||
price = world.random.randrange(1, 7)
|
||||
elif any(x in item_name for x in ['Arrow', 'Bomb', 'Clock']):
|
||||
price = world.random.randrange(2, 14)
|
||||
elif any(x in item_name for x in ['Small Key', 'Heart']):
|
||||
price = world.random.randrange(4, 28)
|
||||
else:
|
||||
price = world.random.randrange(8, 56)
|
||||
|
||||
shop.push_inventory(int(location.name[-1]) - 1, item_name, price * 5, 1,
|
||||
location.item.player if location.item.player != location.player else 0)
|
||||
|
||||
|
||||
@@ -244,11 +266,16 @@ def create_shops(world, player: int):
|
||||
keeper = world.random.choice([0xA0, 0xC1, 0xFF])
|
||||
player_shop_table[name] = ShopData(typ, shop_id, keeper, custom, locked, new_items, sram_offset)
|
||||
if world.mode[player] == "inverted":
|
||||
# make sure that blue potion is available in inverted, special case locked = None; lock when done.
|
||||
player_shop_table["Dark Lake Hylia Shop"] = \
|
||||
player_shop_table["Dark Lake Hylia Shop"]._replace(locked=True, items=_inverted_hylia_shop_defaults)
|
||||
player_shop_table["Dark Lake Hylia Shop"]._replace(items=_inverted_hylia_shop_defaults, locked=None)
|
||||
chance_100 = int(world.retro[player])*0.25+int(world.keyshuffle[player] == "universal") * 0.5
|
||||
for region_name, (room_id, type, shopkeeper, custom, locked, inventory, sram_offset) in player_shop_table.items():
|
||||
region = world.get_region(region_name, player)
|
||||
shop: Shop = shop_class_mapping[type](region, room_id, shopkeeper, custom, locked, sram_offset)
|
||||
# special case: allow shop slots, but do not allow overwriting of base inventory behind them
|
||||
if locked is None:
|
||||
shop.locked = True
|
||||
region.shop = shop
|
||||
world.shops.append(shop)
|
||||
for index, item in enumerate(inventory):
|
||||
@@ -261,12 +288,15 @@ def create_shops(world, player: int):
|
||||
loc.locked = True
|
||||
if single_purchase_slots.pop():
|
||||
if world.goal[player] != 'icerodhunt':
|
||||
additional_item = 'Rupees (50)' # world.random.choice(['Rupees (50)', 'Rupees (100)', 'Rupees (300)'])
|
||||
if world.random.random() < chance_100:
|
||||
additional_item = 'Rupees (100)'
|
||||
else:
|
||||
additional_item = 'Rupees (50)'
|
||||
else:
|
||||
additional_item = 'Nothing'
|
||||
additional_item = GetBeemizerItem(world, player, 'Nothing')
|
||||
loc.item = ItemFactory(additional_item, player)
|
||||
else:
|
||||
loc.item = ItemFactory('Nothing', player)
|
||||
loc.item = ItemFactory(GetBeemizerItem(world, player, 'Nothing'), player)
|
||||
loc.shop_slot_disabled = True
|
||||
shop.region.locations.append(loc)
|
||||
world.dynamic_locations.append(loc)
|
||||
@@ -278,7 +308,7 @@ class ShopData(NamedTuple):
|
||||
type: ShopType
|
||||
shopkeeper: int
|
||||
custom: bool
|
||||
locked: bool
|
||||
locked: Optional[bool]
|
||||
items: List
|
||||
sram_offset: int
|
||||
|
||||
@@ -405,13 +435,9 @@ def shuffle_shops(world, items, player: int):
|
||||
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)
|
||||
elif shop.type == ShopType.Shop and not shop.locked:
|
||||
shops.append(shop)
|
||||
total_inventory.extend(shop.inventory)
|
||||
|
||||
if 'p' in option:
|
||||
def price_adjust(price: int) -> int:
|
||||
|
||||
Reference in New Issue
Block a user