Skip to content

Commit 4e3d396

Browse files
The Messenger: Fix precollected notes not being removed from the itempool (#3066)
* The Messenger: fix precollected notes not being properly removed from pool * The Messenger: bump required client version
1 parent 72c5351 commit 4e3d396

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

worlds/messenger/__init__.py

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from datetime import date
23
from typing import Any, ClassVar, Dict, List, Optional, TextIO
34

45
from BaseClasses import CollectionState, Entrance, Item, ItemClassification, MultiWorld, Tutorial
@@ -9,7 +10,8 @@
910
from worlds.LauncherComponents import Component, Type, components
1011
from .client_setup import launch_game
1112
from .connections import CONNECTIONS, RANDOMIZED_CONNECTIONS, TRANSITIONS
12-
from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS
13+
from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, TRAPS, \
14+
USEFUL_ITEMS
1315
from .options import AvailablePortals, Goal, Logic, MessengerOptions, NotesNeeded, ShuffleTransitions
1416
from .portals import PORTALS, add_closed_portal_reqs, disconnect_portals, shuffle_portals, validate_portals
1517
from .regions import LEVELS, MEGA_SHARDS, LOCATIONS, REGION_CONNECTIONS
@@ -110,7 +112,7 @@ class MessengerWorld(World):
110112
},
111113
}
112114

113-
required_client_version = (0, 4, 3)
115+
required_client_version = (0, 4, 4)
114116

115117
web = MessengerWeb()
116118

@@ -127,6 +129,7 @@ class MessengerWorld(World):
127129
portal_mapping: List[int]
128130
transitions: List[Entrance]
129131
reachable_locs: int = 0
132+
filler: Dict[str, int]
130133

131134
def generate_early(self) -> None:
132135
if self.options.goal == Goal.option_power_seal_hunt:
@@ -146,15 +149,20 @@ def generate_early(self) -> None:
146149
self.starting_portals = [f"{portal} Portal"
147150
for portal in starting_portals[:3] +
148151
self.random.sample(starting_portals[3:], k=self.options.available_portals - 3)]
152+
149153
# super complicated method for adding searing crags to starting portals if it wasn't chosen
150-
# need to add a check for transition shuffle when that gets added back in
154+
# TODO add a check for transition shuffle when that gets added back in
151155
if not self.options.shuffle_portals and "Searing Crags Portal" not in self.starting_portals:
152156
self.starting_portals.append("Searing Crags Portal")
153157
if len(self.starting_portals) > 4:
154158
portals_to_strip = [portal for portal in ["Riviere Turquoise Portal", "Sunken Shrine Portal"]
155159
if portal in self.starting_portals]
156160
self.starting_portals.remove(self.random.choice(portals_to_strip))
157161

162+
self.filler = FILLER.copy()
163+
if (not hasattr(self.options, "traps") and date.today() < date(2024, 4, 2)) or self.options.traps:
164+
self.filler.update(TRAPS)
165+
158166
self.plando_portals = []
159167
self.portal_mapping = []
160168
self.spoiler_portal_mapping = {}
@@ -182,12 +190,13 @@ def create_regions(self) -> None:
182190
def create_items(self) -> None:
183191
# create items that are always in the item pool
184192
main_movement_items = ["Rope Dart", "Wingsuit"]
193+
precollected_names = [item.name for item in self.multiworld.precollected_items[self.player]]
185194
itempool: List[MessengerItem] = [
186195
self.create_item(item)
187196
for item in self.item_name_to_id
188-
if "Time Shard" not in item and item not in {
197+
if item not in {
189198
"Power Seal", *NOTES, *FIGURINES, *main_movement_items,
190-
*{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]},
199+
*precollected_names, *FILLER, *TRAPS,
191200
}
192201
]
193202

@@ -199,7 +208,7 @@ def create_items(self) -> None:
199208
if self.options.goal == Goal.option_open_music_box:
200209
# make a list of all notes except those in the player's defined starting inventory, and adjust the
201210
# amount we need to put in the itempool and precollect based on that
202-
notes = [note for note in NOTES if note not in self.multiworld.precollected_items[self.player]]
211+
notes = [note for note in NOTES if note not in precollected_names]
203212
self.random.shuffle(notes)
204213
precollected_notes_amount = NotesNeeded.range_end - \
205214
self.options.notes_needed - \
@@ -228,8 +237,8 @@ def create_items(self) -> None:
228237
remaining_fill = len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool)
229238
if remaining_fill < 10:
230239
self._filler_items = self.random.choices(
231-
list(FILLER)[2:],
232-
weights=list(FILLER.values())[2:],
240+
list(self.filler)[2:],
241+
weights=list(self.filler.values())[2:],
233242
k=remaining_fill
234243
)
235244
filler = [self.create_filler() for _ in range(remaining_fill)]
@@ -300,8 +309,8 @@ def fill_slot_data(self) -> Dict[str, Any]:
300309
def get_filler_item_name(self) -> str:
301310
if not getattr(self, "_filler_items", None):
302311
self._filler_items = [name for name in self.random.choices(
303-
list(FILLER),
304-
weights=list(FILLER.values()),
312+
list(self.filler),
313+
weights=list(self.filler.values()),
305314
k=20
306315
)]
307316
return self._filler_items.pop(0)
@@ -335,6 +344,9 @@ def get_item_classification(self, name: str) -> ItemClassification:
335344

336345
if name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}:
337346
return ItemClassification.useful
347+
348+
if name in TRAPS:
349+
return ItemClassification.trap
338350

339351
return ItemClassification.filler
340352

worlds/messenger/constants.py

+7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
"Time Shard (500)": 5,
4949
}
5050

51+
TRAPS = {
52+
"Teleport Trap": 5,
53+
"Prophecy Trap": 10,
54+
}
55+
5156
# item_name_to_id needs to be deterministic and match upstream
5257
ALL_ITEMS = [
5358
*NOTES,
@@ -71,6 +76,8 @@
7176
*SHOP_ITEMS,
7277
*FIGURINES,
7378
"Money Wrench",
79+
"Teleport Trap",
80+
"Prophecy Trap",
7481
]
7582

7683
# locations

worlds/messenger/options.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from dataclasses import dataclass
2+
from datetime import date
23
from typing import Dict
34

45
from schema import And, Optional, Or, Schema
@@ -123,6 +124,11 @@ class RequiredSeals(Range):
123124
default = range_end
124125

125126

127+
class Traps(Toggle):
128+
"""Whether traps should be included in the itempool."""
129+
display_name = "Include Traps"
130+
131+
126132
class ShopPrices(Range):
127133
"""Percentage modifier for shuffled item prices in shops"""
128134
display_name = "Shop Prices Modifier"
@@ -199,3 +205,6 @@ class MessengerOptions(DeathLinkMixin, PerGameCommonOptions):
199205
percent_seals_required: RequiredSeals
200206
shop_price: ShopPrices
201207
shop_price_plan: PlannedShopPrices
208+
209+
if date.today() > date(2024, 4, 1):
210+
traps: Traps

0 commit comments

Comments
 (0)