diff --git a/worlds/noita/Items.py b/worlds/noita/Items.py index 217f546f..c859a803 100644 --- a/worlds/noita/Items.py +++ b/worlds/noita/Items.py @@ -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, } diff --git a/worlds/noita/Rules.py b/worlds/noita/Rules.py index 3eb6be5a..808dd3a2 100644 --- a/worlds/noita/Rules.py +++ b/worlds/noita/Rules.py @@ -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)