Noita: Fix rare item fill failure for single-player games (#2387)

This commit is contained in:
Scipio Wright 2023-10-29 15:02:53 -04:00 committed by GitHub
parent 9c80a7c4ec
commit 36f95b0683
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 40 deletions

View File

@ -44,20 +44,18 @@ def create_kantele(victory_condition: VictoryCondition) -> List[str]:
return ["Kantele"] if victory_condition.value >= VictoryCondition.option_pure_ending else [] return ["Kantele"] if victory_condition.value >= VictoryCondition.option_pure_ending else []
def create_random_items(multiworld: MultiWorld, player: int, random_count: int) -> List[str]: def create_random_items(multiworld: MultiWorld, player: int, weights: Dict[str, int], count: int) -> List[str]:
filler_pool = filler_weights.copy() filler_pool = weights.copy()
if multiworld.bad_effects[player].value == 0: if multiworld.bad_effects[player].value == 0:
del filler_pool["Trap"] del filler_pool["Trap"]
return multiworld.random.choices( return multiworld.random.choices(population=list(filler_pool.keys()),
population=list(filler_pool.keys()), weights=list(filler_pool.values()),
weights=list(filler_pool.values()), k=count)
k=random_count
)
def create_all_items(multiworld: MultiWorld, player: int) -> None: def create_all_items(multiworld: MultiWorld, player: int) -> None:
sum_locations = len(multiworld.get_unfilled_locations(player)) locations_to_fill = len(multiworld.get_unfilled_locations(player))
itempool = ( itempool = (
create_fixed_item_pool() create_fixed_item_pool()
@ -66,9 +64,18 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None:
+ create_kantele(multiworld.victory_condition[player]) + create_kantele(multiworld.victory_condition[player])
) )
random_count = sum_locations - len(itempool) # if there's not enough shop-allowed items in the pool, we can encounter gen issues
itempool += create_random_items(multiworld, player, random_count) # 39 is the number of shop-valid items we need to guarantee
if len(itempool) < 39:
itempool += create_random_items(multiworld, player, shop_only_filler_weights, 39 - len(itempool))
# this is so that it passes tests and gens if you have minimal locations and only one player
if multiworld.players == 1:
for location in multiworld.get_unfilled_locations(player):
if "Shop Item" in location.name:
location.item = create_item(player, itempool.pop())
locations_to_fill = len(multiworld.get_unfilled_locations(player))
itempool += create_random_items(multiworld, player, filler_weights, locations_to_fill - len(itempool))
multiworld.itempool += [create_item(player, name) for name in itempool] multiworld.itempool += [create_item(player, name) for name in itempool]
@ -95,7 +102,7 @@ item_table: Dict[str, ItemData] = {
"Tinker with Wands Everywhere Perk": ItemData(110018, "Perks", ItemClassification.progression, 1), "Tinker with Wands Everywhere Perk": ItemData(110018, "Perks", ItemClassification.progression, 1),
"All-Seeing Eye Perk": ItemData(110019, "Perks", ItemClassification.progression, 1), "All-Seeing Eye Perk": ItemData(110019, "Perks", ItemClassification.progression, 1),
"Spatial Awareness Perk": ItemData(110020, "Perks", ItemClassification.progression), "Spatial Awareness Perk": ItemData(110020, "Perks", ItemClassification.progression),
"Extra Life Perk": ItemData(110021, "Repeatable Perks", ItemClassification.useful, 2), "Extra Life Perk": ItemData(110021, "Repeatable Perks", ItemClassification.useful, 1),
"Orb": ItemData(110022, "Orbs", ItemClassification.progression_skip_balancing), "Orb": ItemData(110022, "Orbs", ItemClassification.progression_skip_balancing),
"Random Potion": ItemData(110023, "Items", ItemClassification.filler), "Random Potion": ItemData(110023, "Items", ItemClassification.filler),
"Secret Potion": ItemData(110024, "Items", ItemClassification.filler), "Secret Potion": ItemData(110024, "Items", ItemClassification.filler),
@ -106,32 +113,35 @@ item_table: Dict[str, ItemData] = {
"Refreshing Gourd": ItemData(110029, "Items", ItemClassification.filler, 1), "Refreshing Gourd": ItemData(110029, "Items", ItemClassification.filler, 1),
"Sädekivi": ItemData(110030, "Items", ItemClassification.filler), "Sädekivi": ItemData(110030, "Items", ItemClassification.filler),
"Broken Wand": ItemData(110031, "Items", ItemClassification.filler), "Broken Wand": ItemData(110031, "Items", ItemClassification.filler),
}
shop_only_filler_weights: Dict[str, int] = {
"Trap": 15,
"Extra Max HP": 25,
"Spell Refresher": 20,
"Wand (Tier 1)": 10,
"Wand (Tier 2)": 8,
"Wand (Tier 3)": 7,
"Wand (Tier 4)": 6,
"Wand (Tier 5)": 5,
"Wand (Tier 6)": 4,
"Extra Life Perk": 10,
} }
filler_weights: Dict[str, int] = { filler_weights: Dict[str, int] = {
"Trap": 15, **shop_only_filler_weights,
"Extra Max HP": 25, "Gold (200)": 15,
"Spell Refresher": 20, "Gold (1000)": 6,
"Potion": 40, "Potion": 40,
"Gold (200)": 15, "Random Potion": 9,
"Gold (1000)": 6, "Secret Potion": 10,
"Wand (Tier 1)": 10, "Powder Pouch": 10,
"Wand (Tier 2)": 8, "Chaos Die": 4,
"Wand (Tier 3)": 7, "Greed Die": 4,
"Wand (Tier 4)": 6, "Kammi": 4,
"Wand (Tier 5)": 5, "Refreshing Gourd": 4,
"Wand (Tier 6)": 4, "Sädekivi": 3,
"Extra Life Perk": 3, "Broken Wand": 10,
"Random Potion": 10,
"Secret Potion": 10,
"Powder Pouch": 10,
"Chaos Die": 4,
"Greed Die": 4,
"Kammi": 4,
"Refreshing Gourd": 4,
"Sädekivi": 3,
"Broken Wand": 8,
} }

View File

@ -44,12 +44,10 @@ wand_tiers: List[str] = [
"Wand (Tier 6)", # Temple of the Art "Wand (Tier 6)", # Temple of the Art
] ]
items_hidden_from_shops: List[str] = ["Gold (200)", "Gold (1000)", "Potion", "Random Potion", "Secret Potion", items_hidden_from_shops: List[str] = ["Gold (200)", "Gold (1000)", "Potion", "Random Potion", "Secret Potion",
"Chaos Die", "Greed Die", "Kammi", "Refreshing Gourd", "Sädekivi", "Broken Wand", "Chaos Die", "Greed Die", "Kammi", "Refreshing Gourd", "Sädekivi", "Broken Wand",
"Powder Pouch"] "Powder Pouch"]
perk_list: List[str] = list(filter(Items.item_is_perk, Items.item_table.keys())) perk_list: List[str] = list(filter(Items.item_is_perk, Items.item_table.keys()))
@ -155,11 +153,12 @@ def victory_unlock_conditions(multiworld: MultiWorld, player: int) -> None:
def create_all_rules(multiworld: MultiWorld, player: int) -> None: def create_all_rules(multiworld: MultiWorld, player: int) -> None:
ban_items_from_shops(multiworld, player) if multiworld.players > 1:
ban_early_high_tier_wands(multiworld, player) ban_items_from_shops(multiworld, player)
lock_holy_mountains_into_spheres(multiworld, player) ban_early_high_tier_wands(multiworld, player)
holy_mountain_unlock_conditions(multiworld, player) lock_holy_mountains_into_spheres(multiworld, player)
biome_unlock_conditions(multiworld, player) holy_mountain_unlock_conditions(multiworld, player)
biome_unlock_conditions(multiworld, player)
victory_unlock_conditions(multiworld, player) victory_unlock_conditions(multiworld, player)
# Prevent the Map perk (used to find Toveri) from being on Toveri (boss) # Prevent the Map perk (used to find Toveri) from being on Toveri (boss)