@@ -24,6 +24,7 @@ using namespace Logic;
2424using namespace Settings ;
2525
2626static bool placementFailure = false ;
27+ static bool NoRepeatOnTokens = false ;
2728
2829static void RemoveStartingItemsFromPool () {
2930 for (ItemKey startingItem : StartingInventory) {
@@ -377,23 +378,30 @@ static void FastFill(std::vector<ItemKey> items, std::vector<LocationKey> locati
377378static void AssumedFill (const std::vector<ItemKey>& items, const std::vector<LocationKey>& allowedLocations, bool setLocationsAsHintable = false ) {
378379
379380 if (items.size () > allowedLocations.size ()) {
380- printf (" \x1b [2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS" );
381- PlacementLog_Msg (" Items:\n " );
382- for (const ItemKey item : items) {
383- PlacementLog_Msg (" \t " );
384- PlacementLog_Msg (ItemTable (item).GetName ().GetEnglish ());
385- PlacementLog_Msg (" \n " );
381+ // If Tokensanity is on and RepeatableItemsOnTokens is off
382+ // Don't display this message
383+ if (NoRepeatOnTokens) {
384+ // do nothing here to not display the message
386385 }
387- PlacementLog_Msg (" \n Allowed Locations:\n " );
388- for (const LocationKey loc : allowedLocations) {
389- PlacementLog_Msg (" \t " );
390- PlacementLog_Msg (Location (loc)->GetName ());
391- PlacementLog_Msg (" \n " );
386+ else {
387+ printf (" \x1b [2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS" );
388+ PlacementLog_Msg (" Items:\n " );
389+ for (const ItemKey item : items) {
390+ PlacementLog_Msg (" \t " );
391+ PlacementLog_Msg (ItemTable (item).GetName ().GetEnglish ());
392+ PlacementLog_Msg (" \n " );
393+ }
394+ PlacementLog_Msg (" \n Allowed Locations:\n " );
395+ for (const LocationKey loc : allowedLocations) {
396+ PlacementLog_Msg (" \t " );
397+ PlacementLog_Msg (Location (loc)->GetName ());
398+ PlacementLog_Msg (" \n " );
399+ }
400+ PlacementLog_Write ();
401+ placementFailure = true ;
402+ return ;
392403 }
393- PlacementLog_Write ();
394- placementFailure = true ;
395- return ;
396- }
404+ }
397405
398406 // If No Logic fast fill everything
399407 if (Settings::Logic.Is (LogicSetting::LOGIC_NONE)) {
@@ -427,9 +435,9 @@ static void AssumedFill(const std::vector<ItemKey>& items, const std::vector<Loc
427435 // {
428436 // PlacementLog_Msg(" " + ItemTable(items).GetName().GetEnglish() + "," );
429437 // }
430-
431438 // shuffle the order of items to place
432439 Shuffle (itemsToPlace);
440+
433441 while (!itemsToPlace.empty ()) {
434442 ItemKey item = std::move (itemsToPlace.back ());
435443 ItemTable (item).SetAsPlaythrough ();
@@ -472,6 +480,17 @@ static void AssumedFill(const std::vector<ItemKey>& items, const std::vector<Loc
472480 // retry if there are no more locations to place items
473481 if (accessibleLocations.empty ()) {
474482
483+ // If Tokensanity is on and RepeatableItemsOnTokens is off
484+ // the item pool sent is much larger than the location pool
485+ // in this case we just place 30 of the items and then move on
486+ if (NoRepeatOnTokens) {
487+ // put back the last item we picked up
488+ itemsToPlace.push_back (item);
489+ // then put the unused items back into the main pool and stop
490+ AddElementsToPool (ItemPool, itemsToPlace);
491+ break ;
492+ }
493+
475494 PlacementLog_Msg (" \n CANNOT PLACE " );
476495 PlacementLog_Msg (ItemTable (item).GetName ().GetEnglish ());
477496 PlacementLog_Msg (" . TRYING AGAIN...\n " );
@@ -492,37 +511,73 @@ static void AssumedFill(const std::vector<ItemKey>& items, const std::vector<Loc
492511 break ;
493512 }
494513
495- // place the item within one of the allowed locations accounting for if this item needs to be able to be obtained more than once and if location allows that
496- // the only situation we don't want is a non repeatable location with a reusable item
497514 LocationKey selectedLocation = RandomElement (accessibleLocations);
498- if ( !(Location (selectedLocation)->IsRepeatable ()) && ItemTable (item).IsReusable () ){
499- // unsuccessfulPlacement = true;
500- CitraPrint (" Attemting to place repeatable item in non repeatable spot in AssumedFill" );
501- PlacementLog_Msg (" \n Attempted to place " + ItemTable (item).GetName ().GetEnglish () + " at " + Location (selectedLocation)->GetName ());
515+
516+ // If Tokensanity is on and RepeatableItemsOnTokens is off
517+ // Only place non repeatable items
518+ if (NoRepeatOnTokens) {
519+ // If the item is repeatable put it back and try again
520+ if (ItemTable (item).IsReusable () ) {
521+ CitraPrint (" Attempting to place Repeatable Item in SSH/OSH Location" );
522+ PlacementLog_Msg (" \n Attempted to place Repeatable Item in SSH/OSH Loaction" );
502523 itemsToPlace.push_back (item);
503524 }
504- else {
505- PlaceItemInLocation (selectedLocation, item);
506- // PlacementLog_Msg("Placed " + ItemTable(item).GetName().GetEnglish() + " at " + Location(selectedLocation)->GetName());
507- // CitraPrint("Placed " + ItemTable(item).GetName().GetEnglish() + " at " + Location(selectedLocation)->GetName());
508- attemptedLocations.push_back (selectedLocation);
509-
510- // This tells us the location went through the randomization algorithm
511- // to distinguish it from locations which did not or that the player already
512- // knows
513- if (setLocationsAsHintable) {
514- Location (selectedLocation)->SetAsHintable ();
525+ else {
526+ // Else place it and keep going
527+ PlaceItemInLocation (selectedLocation, item);
528+ attemptedLocations.push_back (selectedLocation);
529+ // This tells us the location went through the randomization algorithm
530+ // to distinguish it from locations which did not or that the player already
531+ // knows
532+ if (setLocationsAsHintable) {
533+ Location (selectedLocation)->SetAsHintable ();
534+ }
535+
536+ // If ALR is off, then we check beatability after placing the item.
537+ // If the game is beatable, then we can stop placing items with logic.
538+ if (!LocationsReachable) {
539+ playthroughBeatable = false ;
540+ Logic::LogicReset ();
541+ GetAccessibleLocations (allLocations, SearchMode::CheckBeatable);
542+ if (playthroughBeatable) {
543+ FastFill (itemsToPlace, GetAllEmptyLocations (), true );
544+ return ;
545+ }
546+ }
515547 }
516-
517- // If ALR is off, then we check beatability after placing the item.
518- // If the game is beatable, then we can stop placing items with logic.
519- if (!LocationsReachable) {
520- playthroughBeatable = false ;
521- Logic::LogicReset ();
522- GetAccessibleLocations (allLocations, SearchMode::CheckBeatable);
523- if (playthroughBeatable) {
524- FastFill (itemsToPlace, GetAllEmptyLocations (), true );
525- return ;
548+ }
549+ else {
550+ // place the item within one of the allowed locations accounting for if this item needs to be able to be obtained more than once and if location allows that
551+ // the only situation we don't want is a non repeatable location with a reusable item
552+ if ( !(Location (selectedLocation)->IsRepeatable ()) && ItemTable (item).IsReusable () ){
553+ // unsuccessfulPlacement = true;
554+ CitraPrint (" Attemting to place repeatable item in non repeatable spot in AssumedFill" );
555+ PlacementLog_Msg (" \n Attempted to place " + ItemTable (item).GetName ().GetEnglish () + " at " + Location (selectedLocation)->GetName ());
556+ itemsToPlace.push_back (item);
557+ }
558+ else {
559+ PlaceItemInLocation (selectedLocation, item);
560+ // PlacementLog_Msg("Placed " + ItemTable(item).GetName().GetEnglish() + " at " + Location(selectedLocation)->GetName());
561+ // CitraPrint("Placed " + ItemTable(item).GetName().GetEnglish() + " at " + Location(selectedLocation)->GetName());
562+ attemptedLocations.push_back (selectedLocation);
563+
564+ // This tells us the location went through the randomization algorithm
565+ // to distinguish it from locations which did not or that the player already
566+ // knows
567+ if (setLocationsAsHintable) {
568+ Location (selectedLocation)->SetAsHintable ();
569+ }
570+
571+ // If ALR is off, then we check beatability after placing the item.
572+ // If the game is beatable, then we can stop placing items with logic.
573+ if (!LocationsReachable) {
574+ playthroughBeatable = false ;
575+ Logic::LogicReset ();
576+ GetAccessibleLocations (allLocations, SearchMode::CheckBeatable);
577+ if (playthroughBeatable) {
578+ FastFill (itemsToPlace, GetAllEmptyLocations (), true );
579+ return ;
580+ }
526581 }
527582 }
528583 }
@@ -547,7 +602,7 @@ std::vector<ItemKey> rewards = FilterAndEraseFromPool(ItemPool, [](const ItemKey
547602 }
548603 }
549604 else if (ShuffleRewards.Is ((u8 )RewardShuffleSetting::REWARDSHUFFLE_ANYWHERE)){
550- AssumedFill (rewards, allLocations);
605+ AssumedFill (rewards, allLocations, true );
551606 }
552607}
553608
@@ -601,12 +656,12 @@ static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) {
601656 }
602657
603658 // randomize boss key and small keys together for even distribution
604- AssumedFill (dungeonItems, dungeonLocations);
659+ AssumedFill (dungeonItems, dungeonLocations, true );
605660
606661 // randomize map and compass separately since they're not progressive
607662 if (MapsAndCompasses.Is ((u8 )MapsAndCompassesSetting::MAPSANDCOMPASSES_OWN_DUNGEON) && dungeon->GetMap () != NONE && dungeon->GetCompass () != NONE) {
608663 auto dungeonMapAndCompass = FilterAndEraseFromPool (ItemPool, [dungeon](const ItemKey i) { return i == dungeon->GetMap () || i == dungeon->GetCompass ();});
609- AssumedFill (dungeonMapAndCompass, dungeonLocations);
664+ AssumedFill (dungeonMapAndCompass, dungeonLocations, true );
610665 }
611666}
612667
@@ -817,20 +872,38 @@ int Fill() {
817872 }
818873 // Then if repeatable items on tokens is off -- fill token spots with nonrepeatable items
819874 if (Tokensanity && !RepeatableItemsOnTokens){
820- // Get all nonrepeatable items
821- std::vector<ItemKey> remainingNonRepeatItemPool = FilterAndEraseFromPool (ItemPool, [](const ItemKey i) {return ItemTable (i).IsReusable () == false ;});
875+ // Set Variable to not mess with fill algorithm
876+ NoRepeatOnTokens = true ;
877+ // Get SSH locations
822878 std::vector<LocationKey> SwampSkullLocations = FilterFromPool (allLocations, [](const LocationKey loc) {return Location (loc)->IsCategory (Category::cSwampSkulltula);});
823- // CitraPrint("Starting Assumed Fill on Swamp Locations");
824- // fill skulltula spots with them
825- FastFill (remainingNonRepeatItemPool, SwampSkullLocations);
879+ // Get NonRepeatItems
880+ std::vector<ItemKey> NonRepeatItems = FilterAndEraseFromPool (ItemPool, [](const ItemKey i) {return !ItemTable (i).IsReusable ();});
881+ // fill SSH spots with nonrepeatableitems
882+ // CitraPrint("Items in NonRepeatItems:\n");
883+ // PlacementLog_Msg("Items in NonRepeatItems:\n");
884+ // for (ItemKey item : NonRepeatItems) {
885+ // CitraPrint(ItemTable(item).GetName().GetEnglish() + "\n");
886+ // PlacementLog_Msg(ItemTable(item).GetName().GetEnglish() + "\n");
887+ // }
888+ AssumedFill (NonRepeatItems, SwampSkullLocations, true );
826889
890+ // Get OSH locations
827891 std::vector<LocationKey> OceanSkullLocations = FilterFromPool (allLocations, [](const LocationKey loc1) {return Location (loc1)->IsCategory (Category::cOceanSkulltula);});
828- // CitraPrint("Starting Assumed Fill on Ocean Locations");
829- FastFill (remainingNonRepeatItemPool, OceanSkullLocations);
892+ // Get NonRepeatItems
893+ std::vector<ItemKey> NonRepeatItems2 = FilterAndEraseFromPool (ItemPool, [](const ItemKey i) {return !ItemTable (i).IsReusable ();});
894+ // CitraPrint("Items in NonRepeatItems2:\n");
895+ // PlacementLog_Msg("Items in NonRepeatItems2:\n");
896+ // for (ItemKey item : NonRepeatItems2) {
897+ // CitraPrint(ItemTable(item).GetName().GetEnglish() + "\n");
898+ // PlacementLog_Msg(ItemTable(item).GetName().GetEnglish() + "\n");
899+ // }
900+ // fill OSH spots with NonRepeatableItems
901+ AssumedFill (NonRepeatItems2, OceanSkullLocations, true );
902+ // Set Variable back to false to go back to normal filling
903+ NoRepeatOnTokens = false ;
830904
831- // CitraPrint("Adding RemainingNonRepeatItems back to main ItemPool");
832- AddElementsToPool (ItemPool, remainingNonRepeatItemPool);
833905 // Then Place Anju & Kafei Items in spots accessable on Day 1, this should prevent situations where you cant get an item in time for its use
906+ // Do this before continuing as the pool of accessable locations is smaller after filling all skulltula locations
834907 std::vector<LocationKey> day1Locations = FilterFromPool (allLocations, [](const LocationKey loc) {return Location (loc)->IsCategory (Category::cDayOne);});
835908 std::vector<ItemKey> anjukafeiitems = FilterAndEraseFromPool (ItemPool, [](const ItemKey i) {return ItemTable (i).GetItemType () == ITEMTYPE_QUEST;});
836909 AssumedFill (anjukafeiitems, day1Locations,true );
0 commit comments