@@ -35,8 +35,8 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
35
35
"""
36
36
:param multiworld: Multiworld to be filled.
37
37
:param base_state: State assumed before fill.
38
- :param locations: Locations to be filled with item_pool
39
- :param item_pool: Items to fill into the locations
38
+ :param locations: Locations to be filled with item_pool, gets mutated by removing locations that get filled.
39
+ :param item_pool: Items to fill into the locations, gets mutated by removing items that get placed.
40
40
:param single_player_placement: if true, can speed up placement if everything belongs to a single player
41
41
:param lock: locations are set to locked as they are filled
42
42
:param swap: if true, swaps of already place items are done in the event of a dead end
@@ -220,7 +220,8 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
220
220
def remaining_fill (multiworld : MultiWorld ,
221
221
locations : typing .List [Location ],
222
222
itempool : typing .List [Item ],
223
- name : str = "Remaining" ) -> None :
223
+ name : str = "Remaining" ,
224
+ move_unplaceable_to_start_inventory : bool = False ) -> None :
224
225
unplaced_items : typing .List [Item ] = []
225
226
placements : typing .List [Location ] = []
226
227
swapped_items : typing .Counter [typing .Tuple [int , str ]] = Counter ()
@@ -284,13 +285,21 @@ def remaining_fill(multiworld: MultiWorld,
284
285
285
286
if unplaced_items and locations :
286
287
# There are leftover unplaceable items and locations that won't accept them
287
- raise FillError (f"No more spots to place { len (unplaced_items )} items. Remaining locations are invalid.\n "
288
- f"Unplaced items:\n "
289
- f"{ ', ' .join (str (item ) for item in unplaced_items )} \n "
290
- f"Unfilled locations:\n "
291
- f"{ ', ' .join (str (location ) for location in locations )} \n "
292
- f"Already placed { len (placements )} :\n "
293
- f"{ ', ' .join (str (place ) for place in placements )} " )
288
+ if move_unplaceable_to_start_inventory :
289
+ last_batch = []
290
+ for item in unplaced_items :
291
+ logging .debug (f"Moved { item } to start_inventory to prevent fill failure." )
292
+ multiworld .push_precollected (item )
293
+ last_batch .append (multiworld .worlds [item .player ].create_filler ())
294
+ remaining_fill (multiworld , locations , unplaced_items , name + " Start Inventory Retry" )
295
+ else :
296
+ raise FillError (f"No more spots to place { len (unplaced_items )} items. Remaining locations are invalid.\n "
297
+ f"Unplaced items:\n "
298
+ f"{ ', ' .join (str (item ) for item in unplaced_items )} \n "
299
+ f"Unfilled locations:\n "
300
+ f"{ ', ' .join (str (location ) for location in locations )} \n "
301
+ f"Already placed { len (placements )} :\n "
302
+ f"{ ', ' .join (str (place ) for place in placements )} " )
294
303
295
304
itempool .extend (unplaced_items )
296
305
@@ -420,7 +429,8 @@ def distribute_early_items(multiworld: MultiWorld,
420
429
return fill_locations , itempool
421
430
422
431
423
- def distribute_items_restrictive (multiworld : MultiWorld ) -> None :
432
+ def distribute_items_restrictive (multiworld : MultiWorld ,
433
+ panic_method : typing .Literal ["swap" , "raise" , "start_inventory" ] = "swap" ) -> None :
424
434
fill_locations = sorted (multiworld .get_unfilled_locations ())
425
435
multiworld .random .shuffle (fill_locations )
426
436
# get items to distribute
@@ -470,8 +480,29 @@ def mark_for_locking(location: Location):
470
480
471
481
if progitempool :
472
482
# "advancement/progression fill"
473
- fill_restrictive (multiworld , multiworld .state , defaultlocations , progitempool , single_player_placement = multiworld .players == 1 ,
474
- name = "Progression" )
483
+ if panic_method == "swap" :
484
+ fill_restrictive (multiworld , multiworld .state , defaultlocations , progitempool ,
485
+ swap = True ,
486
+ on_place = mark_for_locking , name = "Progression" , single_player_placement = multiworld .players == 1 )
487
+ elif panic_method == "raise" :
488
+ fill_restrictive (multiworld , multiworld .state , defaultlocations , progitempool ,
489
+ swap = False ,
490
+ on_place = mark_for_locking , name = "Progression" , single_player_placement = multiworld .players == 1 )
491
+ elif panic_method == "start_inventory" :
492
+ fill_restrictive (multiworld , multiworld .state , defaultlocations , progitempool ,
493
+ swap = False , allow_partial = True ,
494
+ on_place = mark_for_locking , name = "Progression" , single_player_placement = multiworld .players == 1 )
495
+ if progitempool :
496
+ for item in progitempool :
497
+ logging .debug (f"Moved { item } to start_inventory to prevent fill failure." )
498
+ multiworld .push_precollected (item )
499
+ filleritempool .append (multiworld .worlds [item .player ].create_filler ())
500
+ logging .warning (f"{ len (progitempool )} items moved to start inventory,"
501
+ f" due to failure in Progression fill step." )
502
+ progitempool [:] = []
503
+
504
+ else :
505
+ raise ValueError (f"Generator Panic Method { panic_method } not recognized." )
475
506
if progitempool :
476
507
raise FillError (
477
508
f"Not enough locations for progression items. "
@@ -486,7 +517,9 @@ def mark_for_locking(location: Location):
486
517
487
518
inaccessible_location_rules (multiworld , multiworld .state , defaultlocations )
488
519
489
- remaining_fill (multiworld , excludedlocations , filleritempool , "Remaining Excluded" )
520
+ remaining_fill (multiworld , excludedlocations , filleritempool , "Remaining Excluded" ,
521
+ move_unplaceable_to_start_inventory = panic_method == "start_inventory" )
522
+
490
523
if excludedlocations :
491
524
raise FillError (
492
525
f"Not enough filler items for excluded locations. "
@@ -495,7 +528,8 @@ def mark_for_locking(location: Location):
495
528
496
529
restitempool = filleritempool + usefulitempool
497
530
498
- remaining_fill (multiworld , defaultlocations , restitempool )
531
+ remaining_fill (multiworld , defaultlocations , restitempool ,
532
+ move_unplaceable_to_start_inventory = panic_method == "start_inventory" )
499
533
500
534
unplaced = restitempool
501
535
unfilled = defaultlocations
0 commit comments