summaryrefslogtreecommitdiff
path: root/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
diff options
context:
space:
mode:
authorGarrett Cox <garrettjcox@gmail.com>2025-02-01 15:02:07 -0600
committerGarrett Cox <garrettjcox@gmail.com>2025-02-01 15:02:07 -0600
commit106d58585ed039f55b207c8440d2b970925c6ef7 (patch)
tree13a9ed932fe4c8223db7f1070763b10af5d334f3 /mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
parenta6267426aa27a613f6812bbe0bd547406bb76c69 (diff)
Rework item pool creation, split up mundane options and add plentiful items
Diffstat (limited to 'mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp')
-rw-r--r--mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp200
1 files changed, 192 insertions, 8 deletions
diff --git a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
index 591ed34b7..cd1d0d79c 100644
--- a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
+++ b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
@@ -61,13 +61,197 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) {
RANDO_SAVE_OPTIONS[randoOptionId] = CVarGetInteger(randoStaticOption.cvar, 0);
}
- // Begin by placing all vanilla items in their vanilla locations
- for (auto& [randoCheckId, randoStaticCheck] : Rando::StaticData::Checks) {
- if (randoStaticCheck.randoCheckId != RC_UNKNOWN) {
- RANDO_SAVE_CHECKS[randoCheckId].randoItemId = randoStaticCheck.randoItemId;
+ // TODO: This should be driven by the UI
+ std::vector<RandoItemId> startingItems = {
+ RI_PROGRESSIVE_SWORD,
+ RI_SHIELD_HERO,
+ RI_OCARINA,
+ RI_SONG_TIME,
+ };
+
+ std::unordered_map<RandoCheckId, bool> checkPool;
+ std::vector<RandoItemId> itemPool;
+
+ // First loop through all regions and add checks/items to the pool
+ for (auto& [randoRegionId, randoRegion] : Rando::Logic::Regions) {
+ for (auto& [randoCheckId, _] : randoRegion.checks) {
+ auto& randoStaticCheck = Rando::StaticData::Checks[randoCheckId];
+ // Skip checks that are already in the pool
+ if (checkPool.find(randoCheckId) != checkPool.end()) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_SKULL_TOKEN &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_GOLD_SKULLTULAS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_OWL &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_OWL_STATUES] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_POT &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_POT_DROPS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_CRATE &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_CRATE_DROPS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_BARREL &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_BARREL_DROPS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_FREESTANDING &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_FREESTANDING_ITEMS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_REMAINS &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_BOSS_REMAINS] == RO_GENERIC_NO) {
+ continue;
+ }
+
+ if (randoStaticCheck.randoCheckType == RCTYPE_SHOP) {
+ // We always want shuffle RC_CURIOSITY_SHOP_SPECIAL_ITEM &
+ // RC_BOMB_SHOP_ITEM_04_OR_CURIOSITY_SHOP_ITEM
+ if (RANDO_SAVE_OPTIONS[RO_SHUFFLE_SHOPS] == RO_GENERIC_NO &&
+ randoCheckId != RC_CURIOSITY_SHOP_SPECIAL_ITEM &&
+ randoCheckId != RC_BOMB_SHOP_ITEM_04_OR_CURIOSITY_SHOP_ITEM) {
+ continue;
+ } else {
+ // We may come up with a better solution for this in the future, but for now we choose a
+ // random price ahead of time, logic will account for whatever price we choose
+ int price = Ship_Random(0, 200);
+ RANDO_SAVE_CHECKS[randoCheckId].price = price;
+ }
+ }
+
+ checkPool.insert({ randoCheckId, true });
+ itemPool.push_back(randoStaticCheck.randoItemId);
}
}
+ // Add sword and shield to the pool because they don't have a vanilla location, if you are starting with
+ // them they will be removed from the pool in the next step
+ itemPool.push_back(RI_PROGRESSIVE_SWORD);
+ itemPool.push_back(RI_SHIELD_HERO);
+
+ // Add other items that don't have a vanilla location like Sun's Song or Song of Double Time
+
+ // Remove starting items from the pool (but only one per entry in startingItems)
+ for (RandoItemId startingItem : startingItems) {
+ auto it = std::find(itemPool.begin(), itemPool.end(), startingItem);
+ if (it != itemPool.end()) {
+ itemPool.erase(it);
+ }
+ }
+
+ if (RANDO_SAVE_OPTIONS[RO_PLENTIFUL_ITEMS] == RO_GENERIC_YES) {
+ int replaceableItems = 0;
+ std::vector<RandoItemId> plentifulItems;
+ std::vector<RandoItemId> potentialPlentifulItems;
+ for (size_t i = 0; i < itemPool.size(); i++) {
+ switch (Rando::StaticData::Items[itemPool[i]].randoItemType) {
+ case RITYPE_BOSS_KEY:
+ case RITYPE_SMALL_KEY:
+ case RITYPE_MASK:
+ case RITYPE_MAJOR:
+ plentifulItems.push_back(itemPool[i]);
+ break;
+ case RITYPE_LESSER:
+ case RITYPE_SKULLTULA_TOKEN:
+ case RITYPE_STRAY_FAIRY:
+ if (Ship_Random(0, 2) == 1) {
+ potentialPlentifulItems.push_back(itemPool[i]);
+ }
+ break;
+ case RITYPE_HEALTH:
+ case RITYPE_JUNK:
+ default:
+ replaceableItems++;
+ break;
+ }
+ }
+
+ if (replaceableItems > plentifulItems.size()) {
+ for (RandoItemId plentifulItem : plentifulItems) {
+ itemPool.push_back(plentifulItem);
+ }
+ }
+
+ // Only add potentialPlentifulItems if we think we have enough room (this might not be perfect)
+ if ((replaceableItems - plentifulItems.size() - 10) > potentialPlentifulItems.size()) {
+ for (RandoItemId plentifulItem : potentialPlentifulItems) {
+ itemPool.push_back(plentifulItem);
+ }
+ }
+ }
+
+ if (checkPool.empty()) {
+ throw std::runtime_error("No checks in logic");
+ }
+ if (itemPool.empty()) {
+ throw std::runtime_error("No items in logic");
+ }
+
+ int heartPiecesRemoved = 0;
+ // Add/Remove junk items to/from the pool to make the item pool size match the check pool size
+ while (checkPool.size() != itemPool.size()) {
+ if (checkPool.size() > itemPool.size()) {
+ itemPool.push_back(RI_JUNK);
+ } else {
+ // First, remove junk items if we have any
+ bool removedJunk = false;
+ for (int i = 0; i < itemPool.size(); i++) {
+ if (Rando::StaticData::Items[itemPool[i]].randoItemType == RITYPE_JUNK) {
+ itemPool.erase(itemPool.begin() + i);
+ removedJunk = true;
+ break;
+ }
+ }
+ if (removedJunk) {
+ continue;
+ }
+
+ // Next replace 4 heart pieces with a heart container
+ bool removedHeartPieces = false;
+ for (int i = 0; i < itemPool.size(); i++) {
+ if (Rando::StaticData::Items[itemPool[i]].randoItemId == RI_HEART_PIECE) {
+ if (heartPiecesRemoved == 0) {
+ itemPool[i] = RI_HEART_CONTAINER;
+ } else {
+ itemPool.erase(itemPool.begin() + i);
+ }
+
+ removedHeartPieces = true;
+ heartPiecesRemoved++;
+ if (heartPiecesRemoved == 4) {
+ heartPiecesRemoved = 0;
+ }
+ break;
+ }
+ }
+
+ if (removedHeartPieces) {
+ continue;
+ }
+
+ SPDLOG_ERROR("Could not match item pool size to check pool size {}/{}", itemPool.size(),
+ checkPool.size());
+ throw std::runtime_error("Could not match item pool size to check pool size");
+ }
+ }
+
+ // Grant the starting items
+ for (RandoItemId startingItem : startingItems) {
+ GiveItem(ConvertItem(startingItem));
+ }
+
if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_VANILLA) {
GiveItem(RI_SWORD_KOKIRI);
GiveItem(RI_SHIELD_HERO);
@@ -79,13 +263,13 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) {
}
}
} else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_NO_LOGIC) {
- Rando::Logic::ApplyNoLogicToSaveContext();
+ Rando::Logic::ApplyNoLogicToSaveContext(checkPool, itemPool);
} else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_NEARLY_NO_LOGIC) {
- Rando::Logic::ApplyNearlyNoLogicToSaveContext();
+ Rando::Logic::ApplyNearlyNoLogicToSaveContext(checkPool, itemPool);
} else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_GLITCHLESS) {
- Rando::Logic::ApplyGlitchlessLogicToSaveContext();
+ Rando::Logic::ApplyGlitchlessLogicToSaveContext(checkPool, itemPool);
} else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_FRENCH_VANILLA) {
- Rando::Logic::ApplyFrenchVanillaLogicToSaveContext();
+ Rando::Logic::ApplyFrenchVanillaLogicToSaveContext(checkPool, itemPool);
} else {
throw std::runtime_error("Logic option not implemented: " +
std::to_string(RANDO_SAVE_OPTIONS[RO_LOGIC]));