Skip to content

Commit 36f95b0

Browse files
authored
Noita: Fix rare item fill failure for single-player games (#2387)
1 parent 9c80a7c commit 36f95b0

File tree

2 files changed

+50
-41
lines changed

2 files changed

+50
-41
lines changed

worlds/noita/Items.py

+44-34
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,18 @@ def create_kantele(victory_condition: VictoryCondition) -> List[str]:
4444
return ["Kantele"] if victory_condition.value >= VictoryCondition.option_pure_ending else []
4545

4646

47-
def create_random_items(multiworld: MultiWorld, player: int, random_count: int) -> List[str]:
48-
filler_pool = filler_weights.copy()
47+
def create_random_items(multiworld: MultiWorld, player: int, weights: Dict[str, int], count: int) -> List[str]:
48+
filler_pool = weights.copy()
4949
if multiworld.bad_effects[player].value == 0:
5050
del filler_pool["Trap"]
5151

52-
return multiworld.random.choices(
53-
population=list(filler_pool.keys()),
54-
weights=list(filler_pool.values()),
55-
k=random_count
56-
)
52+
return multiworld.random.choices(population=list(filler_pool.keys()),
53+
weights=list(filler_pool.values()),
54+
k=count)
5755

5856

5957
def create_all_items(multiworld: MultiWorld, player: int) -> None:
60-
sum_locations = len(multiworld.get_unfilled_locations(player))
58+
locations_to_fill = len(multiworld.get_unfilled_locations(player))
6159

6260
itempool = (
6361
create_fixed_item_pool()
@@ -66,9 +64,18 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None:
6664
+ create_kantele(multiworld.victory_condition[player])
6765
)
6866

69-
random_count = sum_locations - len(itempool)
70-
itempool += create_random_items(multiworld, player, random_count)
71-
67+
# if there's not enough shop-allowed items in the pool, we can encounter gen issues
68+
# 39 is the number of shop-valid items we need to guarantee
69+
if len(itempool) < 39:
70+
itempool += create_random_items(multiworld, player, shop_only_filler_weights, 39 - len(itempool))
71+
# this is so that it passes tests and gens if you have minimal locations and only one player
72+
if multiworld.players == 1:
73+
for location in multiworld.get_unfilled_locations(player):
74+
if "Shop Item" in location.name:
75+
location.item = create_item(player, itempool.pop())
76+
locations_to_fill = len(multiworld.get_unfilled_locations(player))
77+
78+
itempool += create_random_items(multiworld, player, filler_weights, locations_to_fill - len(itempool))
7279
multiworld.itempool += [create_item(player, name) for name in itempool]
7380

7481

@@ -95,7 +102,7 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None:
95102
"Tinker with Wands Everywhere Perk": ItemData(110018, "Perks", ItemClassification.progression, 1),
96103
"All-Seeing Eye Perk": ItemData(110019, "Perks", ItemClassification.progression, 1),
97104
"Spatial Awareness Perk": ItemData(110020, "Perks", ItemClassification.progression),
98-
"Extra Life Perk": ItemData(110021, "Repeatable Perks", ItemClassification.useful, 2),
105+
"Extra Life Perk": ItemData(110021, "Repeatable Perks", ItemClassification.useful, 1),
99106
"Orb": ItemData(110022, "Orbs", ItemClassification.progression_skip_balancing),
100107
"Random Potion": ItemData(110023, "Items", ItemClassification.filler),
101108
"Secret Potion": ItemData(110024, "Items", ItemClassification.filler),
@@ -106,32 +113,35 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None:
106113
"Refreshing Gourd": ItemData(110029, "Items", ItemClassification.filler, 1),
107114
"Sädekivi": ItemData(110030, "Items", ItemClassification.filler),
108115
"Broken Wand": ItemData(110031, "Items", ItemClassification.filler),
116+
}
109117

118+
shop_only_filler_weights: Dict[str, int] = {
119+
"Trap": 15,
120+
"Extra Max HP": 25,
121+
"Spell Refresher": 20,
122+
"Wand (Tier 1)": 10,
123+
"Wand (Tier 2)": 8,
124+
"Wand (Tier 3)": 7,
125+
"Wand (Tier 4)": 6,
126+
"Wand (Tier 5)": 5,
127+
"Wand (Tier 6)": 4,
128+
"Extra Life Perk": 10,
110129
}
111130

112131
filler_weights: Dict[str, int] = {
113-
"Trap": 15,
114-
"Extra Max HP": 25,
115-
"Spell Refresher": 20,
116-
"Potion": 40,
117-
"Gold (200)": 15,
118-
"Gold (1000)": 6,
119-
"Wand (Tier 1)": 10,
120-
"Wand (Tier 2)": 8,
121-
"Wand (Tier 3)": 7,
122-
"Wand (Tier 4)": 6,
123-
"Wand (Tier 5)": 5,
124-
"Wand (Tier 6)": 4,
125-
"Extra Life Perk": 3,
126-
"Random Potion": 10,
127-
"Secret Potion": 10,
128-
"Powder Pouch": 10,
129-
"Chaos Die": 4,
130-
"Greed Die": 4,
131-
"Kammi": 4,
132-
"Refreshing Gourd": 4,
133-
"Sädekivi": 3,
134-
"Broken Wand": 8,
132+
**shop_only_filler_weights,
133+
"Gold (200)": 15,
134+
"Gold (1000)": 6,
135+
"Potion": 40,
136+
"Random Potion": 9,
137+
"Secret Potion": 10,
138+
"Powder Pouch": 10,
139+
"Chaos Die": 4,
140+
"Greed Die": 4,
141+
"Kammi": 4,
142+
"Refreshing Gourd": 4,
143+
"Sädekivi": 3,
144+
"Broken Wand": 10,
135145
}
136146

137147

worlds/noita/Rules.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,10 @@ class EntranceLock(NamedTuple):
4444
"Wand (Tier 6)", # Temple of the Art
4545
]
4646

47-
4847
items_hidden_from_shops: List[str] = ["Gold (200)", "Gold (1000)", "Potion", "Random Potion", "Secret Potion",
4948
"Chaos Die", "Greed Die", "Kammi", "Refreshing Gourd", "Sädekivi", "Broken Wand",
5049
"Powder Pouch"]
5150

52-
5351
perk_list: List[str] = list(filter(Items.item_is_perk, Items.item_table.keys()))
5452

5553

@@ -155,11 +153,12 @@ def victory_unlock_conditions(multiworld: MultiWorld, player: int) -> None:
155153

156154

157155
def create_all_rules(multiworld: MultiWorld, player: int) -> None:
158-
ban_items_from_shops(multiworld, player)
159-
ban_early_high_tier_wands(multiworld, player)
160-
lock_holy_mountains_into_spheres(multiworld, player)
161-
holy_mountain_unlock_conditions(multiworld, player)
162-
biome_unlock_conditions(multiworld, player)
156+
if multiworld.players > 1:
157+
ban_items_from_shops(multiworld, player)
158+
ban_early_high_tier_wands(multiworld, player)
159+
lock_holy_mountains_into_spheres(multiworld, player)
160+
holy_mountain_unlock_conditions(multiworld, player)
161+
biome_unlock_conditions(multiworld, player)
163162
victory_unlock_conditions(multiworld, player)
164163

165164
# Prevent the Map perk (used to find Toveri) from being on Toveri (boss)

0 commit comments

Comments
 (0)