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 []
def create_random_items(multiworld: MultiWorld, player: int, random_count: int) -> List[str]:
filler_pool = filler_weights.copy()
def create_random_items(multiworld: MultiWorld, player: int, weights: Dict[str, int], count: int) -> List[str]:
filler_pool = weights.copy()
if multiworld.bad_effects[player].value == 0:
del filler_pool["Trap"]
return multiworld.random.choices(
population=list(filler_pool.keys()),
weights=list(filler_pool.values()),
k=random_count
)
return multiworld.random.choices(population=list(filler_pool.keys()),
weights=list(filler_pool.values()),
k=count)
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 = (
create_fixed_item_pool()
@ -66,9 +64,18 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None:
+ create_kantele(multiworld.victory_condition[player])
)
random_count = sum_locations - len(itempool)
itempool += create_random_items(multiworld, player, random_count)
# if there's not enough shop-allowed items in the pool, we can encounter gen issues
# 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]
@ -95,7 +102,7 @@ item_table: Dict[str, ItemData] = {
"Tinker with Wands Everywhere Perk": ItemData(110018, "Perks", ItemClassification.progression, 1),
"All-Seeing Eye Perk": ItemData(110019, "Perks", ItemClassification.progression, 1),
"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),
"Random Potion": ItemData(110023, "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),
"Sädekivi": ItemData(110030, "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] = {
"Trap": 15,
"Extra Max HP": 25,
"Spell Refresher": 20,
"Potion": 40,
"Gold (200)": 15,
"Gold (1000)": 6,
"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": 3,
"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,
**shop_only_filler_weights,
"Gold (200)": 15,
"Gold (1000)": 6,
"Potion": 40,
"Random Potion": 9,
"Secret Potion": 10,
"Powder Pouch": 10,
"Chaos Die": 4,
"Greed Die": 4,
"Kammi": 4,
"Refreshing Gourd": 4,
"Sädekivi": 3,
"Broken Wand": 10,
}

View File

@ -44,12 +44,10 @@ wand_tiers: List[str] = [
"Wand (Tier 6)", # Temple of the Art
]
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",
"Powder Pouch"]
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:
ban_items_from_shops(multiworld, player)
ban_early_high_tier_wands(multiworld, player)
lock_holy_mountains_into_spheres(multiworld, player)
holy_mountain_unlock_conditions(multiworld, player)
biome_unlock_conditions(multiworld, player)
if multiworld.players > 1:
ban_items_from_shops(multiworld, player)
ban_early_high_tier_wands(multiworld, player)
lock_holy_mountains_into_spheres(multiworld, player)
holy_mountain_unlock_conditions(multiworld, player)
biome_unlock_conditions(multiworld, player)
victory_unlock_conditions(multiworld, player)
# Prevent the Map perk (used to find Toveri) from being on Toveri (boss)