1
1
import logging
2
+ from datetime import date
2
3
from typing import Any , ClassVar , Dict , List , Optional , TextIO
3
4
4
5
from BaseClasses import CollectionState , Entrance , Item , ItemClassification , MultiWorld , Tutorial
9
10
from worlds .LauncherComponents import Component , Type , components
10
11
from .client_setup import launch_game
11
12
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
13
15
from .options import AvailablePortals , Goal , Logic , MessengerOptions , NotesNeeded , ShuffleTransitions
14
16
from .portals import PORTALS , add_closed_portal_reqs , disconnect_portals , shuffle_portals , validate_portals
15
17
from .regions import LEVELS , MEGA_SHARDS , LOCATIONS , REGION_CONNECTIONS
@@ -110,7 +112,7 @@ class MessengerWorld(World):
110
112
},
111
113
}
112
114
113
- required_client_version = (0 , 4 , 3 )
115
+ required_client_version = (0 , 4 , 4 )
114
116
115
117
web = MessengerWeb ()
116
118
@@ -127,6 +129,7 @@ class MessengerWorld(World):
127
129
portal_mapping : List [int ]
128
130
transitions : List [Entrance ]
129
131
reachable_locs : int = 0
132
+ filler : Dict [str , int ]
130
133
131
134
def generate_early (self ) -> None :
132
135
if self .options .goal == Goal .option_power_seal_hunt :
@@ -146,15 +149,20 @@ def generate_early(self) -> None:
146
149
self .starting_portals = [f"{ portal } Portal"
147
150
for portal in starting_portals [:3 ] +
148
151
self .random .sample (starting_portals [3 :], k = self .options .available_portals - 3 )]
152
+
149
153
# 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
151
155
if not self .options .shuffle_portals and "Searing Crags Portal" not in self .starting_portals :
152
156
self .starting_portals .append ("Searing Crags Portal" )
153
157
if len (self .starting_portals ) > 4 :
154
158
portals_to_strip = [portal for portal in ["Riviere Turquoise Portal" , "Sunken Shrine Portal" ]
155
159
if portal in self .starting_portals ]
156
160
self .starting_portals .remove (self .random .choice (portals_to_strip ))
157
161
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
+
158
166
self .plando_portals = []
159
167
self .portal_mapping = []
160
168
self .spoiler_portal_mapping = {}
@@ -182,12 +190,13 @@ def create_regions(self) -> None:
182
190
def create_items (self ) -> None :
183
191
# create items that are always in the item pool
184
192
main_movement_items = ["Rope Dart" , "Wingsuit" ]
193
+ precollected_names = [item .name for item in self .multiworld .precollected_items [self .player ]]
185
194
itempool : List [MessengerItem ] = [
186
195
self .create_item (item )
187
196
for item in self .item_name_to_id
188
- if "Time Shard" not in item and item not in {
197
+ if item not in {
189
198
"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 ,
191
200
}
192
201
]
193
202
@@ -199,7 +208,7 @@ def create_items(self) -> None:
199
208
if self .options .goal == Goal .option_open_music_box :
200
209
# make a list of all notes except those in the player's defined starting inventory, and adjust the
201
210
# 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 ]
203
212
self .random .shuffle (notes )
204
213
precollected_notes_amount = NotesNeeded .range_end - \
205
214
self .options .notes_needed - \
@@ -228,8 +237,8 @@ def create_items(self) -> None:
228
237
remaining_fill = len (self .multiworld .get_unfilled_locations (self .player )) - len (itempool )
229
238
if remaining_fill < 10 :
230
239
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 :],
233
242
k = remaining_fill
234
243
)
235
244
filler = [self .create_filler () for _ in range (remaining_fill )]
@@ -300,8 +309,8 @@ def fill_slot_data(self) -> Dict[str, Any]:
300
309
def get_filler_item_name (self ) -> str :
301
310
if not getattr (self , "_filler_items" , None ):
302
311
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 ()),
305
314
k = 20
306
315
)]
307
316
return self ._filler_items .pop (0 )
@@ -335,6 +344,9 @@ def get_item_classification(self, name: str) -> ItemClassification:
335
344
336
345
if name in {* USEFUL_ITEMS , * USEFUL_SHOP_ITEMS }:
337
346
return ItemClassification .useful
347
+
348
+ if name in TRAPS :
349
+ return ItemClassification .trap
338
350
339
351
return ItemClassification .filler
340
352
0 commit comments