mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-24 23:01:23 -04:00
backend tracker updates
This commit is contained in:
@@ -305,6 +305,10 @@ int item_getcheck_func_ARROW_20();
|
||||
int item_getcheck_func_ARROW_30();
|
||||
int item_getcheck_func_ARROW_1();
|
||||
int item_getcheck_func_PACHINKO_SHOT();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_ORDON_PORTAL();
|
||||
int item_getcheck_func_SOUTH_FARON_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_WATER_BOMB_5();
|
||||
int item_getcheck_func_WATER_BOMB_10();
|
||||
int item_getcheck_func_WATER_BOMB_20();
|
||||
@@ -338,6 +342,12 @@ int item_getcheck_func_DUNGEON_EXIT_2();
|
||||
int item_getcheck_func_WALLET_LV1();
|
||||
int item_getcheck_func_WALLET_LV2();
|
||||
int item_getcheck_func_WALLET_LV3();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_UPPER_ZORAS_RIVER_PORTAL();
|
||||
int item_getcheck_func_CASTLE_TOWN_PORTAL();
|
||||
int item_getcheck_func_GERUDO_DESERT_PORTAL();
|
||||
int item_getcheck_func_NORTH_FARON_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_ZORAS_JEWEL();
|
||||
int item_getcheck_func_HAWK_EYE();
|
||||
int item_getcheck_func_WOOD_STICK();
|
||||
@@ -354,13 +364,23 @@ int item_getcheck_func_LIGHT_SWORD();
|
||||
int item_getcheck_func_FISHING_ROD_1();
|
||||
int item_getcheck_func_PACHINKO();
|
||||
int item_getcheck_func_COPY_ROD_2();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_KAKARIKO_GORGE_PORTAL();
|
||||
int item_getcheck_func_KAKARIKO_VILLAGE_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_BOMB_BAG_LV2();
|
||||
int item_getcheck_func_BOMB_BAG_LV1();
|
||||
int item_getcheck_func_BOMB_IN_BAG();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_DEATH_MOUNTAIN_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_LIGHT_ARROW();
|
||||
int item_getcheck_func_ARROW_LV1();
|
||||
int item_getcheck_func_ARROW_LV2();
|
||||
int item_getcheck_func_ARROW_LV3();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_ZORAS_DOMAIN_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_LURE_ROD();
|
||||
int item_getcheck_func_BOMB_ARROW();
|
||||
int item_getcheck_func_HAWK_ARROW();
|
||||
@@ -406,6 +426,10 @@ int item_getcheck_func_BILL();
|
||||
int item_getcheck_func_WOOD_STATUE();
|
||||
int item_getcheck_func_IRIAS_PENDANT();
|
||||
int item_getcheck_func_HORSE_FLUTE();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_CAMP_SMALL_KEY();
|
||||
int item_getcheck_func_LAKE_HYLIA_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_RAFRELS_MEMO();
|
||||
int item_getcheck_func_ASHS_SCRIBBLING();
|
||||
int item_getcheck_func_CHUCHU_YELLOW2();
|
||||
@@ -420,12 +444,19 @@ int item_getcheck_func_FILLED_CONTAINER();
|
||||
int item_getcheck_func_MIRROR_PIECE_2();
|
||||
int item_getcheck_func_MIRROR_PIECE_3();
|
||||
int item_getcheck_func_MIRROR_PIECE_4();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_MIRROR_CHAMBER_PORTAL();
|
||||
int item_getcheck_func_SNOWPEAK_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_SMELL_YELIA_POUCH();
|
||||
int item_getcheck_func_SMELL_PUMPKIN();
|
||||
int item_getcheck_func_SMELL_POH();
|
||||
int item_getcheck_func_SMELL_FISH();
|
||||
int item_getcheck_func_SMELL_CHILDREN();
|
||||
int item_getcheck_func_SMELL_MEDICINE();
|
||||
#if TARGET_PC
|
||||
int item_getcheck_func_SACRED_GROVE_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_M_BEETLE();
|
||||
int item_getcheck_func_F_BEETLE();
|
||||
int item_getcheck_func_M_BUTTERFLY();
|
||||
@@ -465,6 +496,7 @@ int item_getcheck_func_HELM_SPLITTER();
|
||||
int item_getcheck_func_MORTAL_DRAW();
|
||||
int item_getcheck_func_JUMP_STRIKE();
|
||||
int item_getcheck_func_GREAT_SPIN();
|
||||
int item_getcheck_func_ELDIN_BRIDGE_PORTAL();
|
||||
#endif
|
||||
int item_getcheck_func_ANCIENT_DOCUMENT();
|
||||
int item_getcheck_func_AIR_LETTER();
|
||||
|
||||
+595
-549
File diff suppressed because it is too large
Load Diff
@@ -3021,7 +3021,11 @@ int dStage_changeScene4Event(int i_exitId, s8 room_no, int i_wipe, bool param_3,
|
||||
// If randomizer is active and we're loading the first spawn, set our starting time of day
|
||||
if (randomizer_IsActive() && strcmp(scls_info->mStage, "F_SP103") == 0 &&
|
||||
scls_info->mRoom == 1 && scls_info->mStart == 1)
|
||||
{
|
||||
timeH = randomizer_GetContext().mStartHour;
|
||||
g_randomizerState.mUpdateTracker = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
dKy_set_nexttime(15.0f * timeH);
|
||||
}
|
||||
|
||||
@@ -3,19 +3,17 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuRandomizer.hpp"
|
||||
|
||||
#include "dusk/app_info.hpp"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/data.hpp"
|
||||
#include "dusk/randomizer/generator/logic/search.hpp"
|
||||
#include "dusk/randomizer/game/randomizer_context.hpp"
|
||||
#include "dusk/randomizer/game/tools.h"
|
||||
|
||||
#include "SDL3/SDL_filesystem.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <filesystem>
|
||||
|
||||
#include "dusk/data.hpp"
|
||||
#include "dusk/randomizer/generator/logic/search.hpp"
|
||||
#include "dusk/randomizer/generator/utility/string.hpp"
|
||||
|
||||
namespace dusk {
|
||||
|
||||
@@ -221,9 +219,10 @@ namespace dusk {
|
||||
|
||||
if (ImGui::Begin("Rando Tracker", nullptr, windowFlags)) {
|
||||
auto trackerRando = getTrackerRando();
|
||||
ImGui::Text("Here's where the tracker will be");
|
||||
|
||||
if (ImGui::Button("Update Tracker")) {
|
||||
// Uncomment button for manual updating
|
||||
if (/*ImGui::Button("Update Tracker") || */g_randomizerState.mUpdateTracker) {
|
||||
g_randomizerState.mUpdateTracker = false;
|
||||
auto trackerRando = getTrackerRando();
|
||||
|
||||
// Generate tracker world if it doesn't exist
|
||||
@@ -233,37 +232,49 @@ namespace dusk {
|
||||
if (trackerHash.empty() || (trackerHash != contextHash && !contextHash.empty())) {
|
||||
*trackerRando = randomizer::Randomizer(data::configured_data_path());
|
||||
trackerRando->GenerateTrackerWorld();
|
||||
auto trackerWorld = trackerRando->GetWorlds()[0].get();
|
||||
auto currentItems = trackerWorld->GetStartingItemPool();
|
||||
|
||||
m_currentSearch = randomizer::logic::search::Search::Accessible(&trackerRando->GetWorlds(), currentItems);
|
||||
m_currentSearch.SearchWorlds();
|
||||
} else {
|
||||
// Don't try to update inventory when on the title screen
|
||||
if (!playerIsOnTitleScreen()) {
|
||||
// TODO: Translate game save inventory into ItemPool that can be used for searching
|
||||
randomizer::logic::item_pool::ItemPool currentItems = {};
|
||||
m_currentSearch = randomizer::logic::search::Search::Accessible(&trackerRando->GetWorlds(), currentItems);
|
||||
if (randomizer_IsActive()) {
|
||||
auto currentItems = getSaveItemPool(trackerRando->GetWorlds()[0].get());
|
||||
m_currentSearch = randomizer::logic::search::Search::AccessibleNoStartingInventory(&trackerRando->GetWorlds(), currentItems);
|
||||
}
|
||||
|
||||
m_currentSearch.SearchWorlds();
|
||||
}
|
||||
}
|
||||
|
||||
if (trackerRando->GetConfig().GetHash(false).empty()) {
|
||||
ImGui::Text("There is currently no tracker world");
|
||||
ImGui::Text("Load a seed and start a file to activate the tracker");
|
||||
} else {
|
||||
ImGui::Text("Tracker world loaded from seed %s", trackerRando->GetConfig().GetHash().c_str());
|
||||
|
||||
ImGui::Checkbox("Show Only Accessible Locations", &m_onlyAccessible);
|
||||
ImGui::Checkbox("Show Location Requirements", &m_showRequirements);
|
||||
ImGui::InputText("Location Filter", m_locationFilter, 100);
|
||||
|
||||
// Show total number of available locations
|
||||
auto locations = trackerRando->GetWorlds()[0]->GetAllLocations();
|
||||
auto numProgressionLocations = std::ranges::count_if(locations, [](auto* location) {return location->IsProgression();});
|
||||
auto numAvailableLocations = m_currentSearch._visitedLocations.size();
|
||||
ImGui::Text("Locations Available: %zu / %zu", numAvailableLocations, locations.size());
|
||||
ImGui::Text("Locations Available: %zu / %zu", numAvailableLocations, numProgressionLocations);
|
||||
|
||||
if (ImGui::BeginChild("ScrollRegion", ImVec2(500, 500), true))
|
||||
{
|
||||
std::string filter = m_locationFilter;
|
||||
// Show all locations. Green for accessible. Red for Unaccessible
|
||||
for (auto location : locations) {
|
||||
// Don't show locations which aren't progression
|
||||
// Don't show any locations which aren't accessible if only accessible is checked
|
||||
// Don't show any locations which don't meet the filter
|
||||
if (!location->IsProgression() ||
|
||||
(m_onlyAccessible && !m_currentSearch._visitedLocations.contains(location)) ||
|
||||
!randomizer::utility::str::Contains(location->GetName(), filter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't show warp portals for now either
|
||||
if (location->HasCategories("Warp Portal")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Color red
|
||||
auto color = ImVec4(1.f, 0.f, 0.f, 1.f);
|
||||
|
||||
@@ -275,7 +286,9 @@ namespace dusk {
|
||||
ImGui::TextColored(color, "%s", location->GetName().c_str());
|
||||
|
||||
// Show requirements for the location below it (formatting isn't pretty right now)
|
||||
ImGui::Text(" %s", location->GetComputedRequirement().to_string().c_str());
|
||||
if (m_showRequirements) {
|
||||
ImGui::Text(" %s", location->GetComputedRequirement().to_string().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
@@ -27,6 +27,10 @@ private:
|
||||
bool m_showRandoGeneration{false};
|
||||
bool m_showRandoTracker{false};
|
||||
|
||||
bool m_onlyAccessible{false};
|
||||
bool m_showRequirements{false};
|
||||
char m_locationFilter[100];
|
||||
|
||||
randomizer::logic::search::Search m_currentSearch = randomizer::logic::search::Search();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ static bool checkFoolishItemEffectReady()
|
||||
}
|
||||
|
||||
static void handleFoolishItem() {
|
||||
u32 count = g_randomizerState.foolishItemCount;
|
||||
u32 count = g_randomizerState.mFoolishItemCount;
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -401,7 +401,7 @@ static void handleFoolishItem() {
|
||||
}
|
||||
|
||||
// Reset count
|
||||
g_randomizerState.foolishItemCount = 0;
|
||||
g_randomizerState.mFoolishItemCount = 0;
|
||||
|
||||
/* Store the currently loaded sound wave to local variables as we will need to load them back later.
|
||||
* We use this method because if we just loaded the sound waves every time the item was gotten, we'd
|
||||
|
||||
@@ -172,7 +172,8 @@ public:
|
||||
// things like the sound of the rupee counter going up.
|
||||
u8 mFlowMessageItemId{0};
|
||||
|
||||
int foolishItemCount{0};
|
||||
int mFoolishItemCount{0};
|
||||
bool mUpdateTracker{false};
|
||||
};
|
||||
|
||||
extern RandomizerState g_randomizerState;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "tools.h"
|
||||
#include "stages.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_item.h"
|
||||
#include "d/d_item_data.h"
|
||||
#include "dusk/logging.h"
|
||||
#include "f_op/f_op_actor_mng.h"
|
||||
#include "stages.h"
|
||||
#include "verify_item_functions.h"
|
||||
|
||||
bool playerIsInRoomStage(s32 room, const char* stage)
|
||||
{
|
||||
@@ -149,4 +151,317 @@ int numMirrorShards() {
|
||||
numMirrorShards += dComIfGs_isCollectMirror(i);
|
||||
}
|
||||
return numMirrorShards;
|
||||
}
|
||||
|
||||
int getTempleKeysFound(int stage) {
|
||||
static std::unordered_map<int, std::vector<int>> keyDoorFlags = {
|
||||
{0xA, {0x0}},
|
||||
{0x10, {0x7, 0xB, 0x2B, 0x3E}},
|
||||
{0x11, {0x33, 0x3D, 0x3F}},
|
||||
{0x12, {0x23, 0x24, 0x34}},
|
||||
{0x13, {0x27, 0x46, 0x4D, 0x5A, 0x5B}},
|
||||
{0x14, {0x2B, 0x2C, 0x2F, 0x30}},
|
||||
{0x15, {0x1B, 0x1C, 0x1D}},
|
||||
{0x16, {0x6}},
|
||||
{0x17, {0x6, 0x7, 0x8, 0xB, 0x23, 0x24, 0x25}},
|
||||
{0x18, {0x4C, 0x6F, 0x7C}}
|
||||
};
|
||||
|
||||
int count = dComIfGs_getKeyNum(stage);
|
||||
|
||||
// Add number of unlocked key doors for this dungeon to current key count
|
||||
for (auto flag : keyDoorFlags[stage]) {
|
||||
if (dComIfGs_isSwitch(stage, flag)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool isTempleBigKeyFound(int stage) {
|
||||
// The boss key never gets taken away unlike small keys
|
||||
return dComIfGs_isDungeonItemBossKey(stage);
|
||||
}
|
||||
|
||||
randomizer::logic::item_pool::ItemPool getSaveItemPool(randomizer::logic::world::World* world) {
|
||||
randomizer::logic::item_pool::ItemPool pool{};
|
||||
|
||||
// Item wheel items
|
||||
for (int i = 0; i < MAX_ITEM_SLOTS; ++i) {
|
||||
switch (dComIfGs_getItem(i, false)) {
|
||||
case dItemNo_Randomizer_HAWK_EYE_e:
|
||||
pool.push_back(world->GetItem("Hawkeye", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_BOOMERANG_e:
|
||||
pool.push_back(world->GetItem("Gale Boomerang", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_SPINNER_e:
|
||||
pool.push_back(world->GetItem("Spinner", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_IRONBALL_e:
|
||||
pool.push_back(world->GetItem("Ball and Chain", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_BOW_e:
|
||||
pool.push_back(world->GetItem("Progressive Bow", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_W_HOOKSHOT_e:
|
||||
pool.push_back(world->GetItem("Progressive Clawshot", true));
|
||||
[[fallthrough]];
|
||||
case dItemNo_Randomizer_HOOKSHOT_e:
|
||||
pool.push_back(world->GetItem("Progressive Clawshot", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_HVY_BOOTS_e:
|
||||
pool.push_back(world->GetItem("Iron Boots", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_COPY_ROD_e:
|
||||
pool.push_back(world->GetItem("Progressive Dominion Rod", true));
|
||||
// Powered up dominion rod
|
||||
if (dComIfGs_isEventBit(0x2580)) {
|
||||
pool.push_back(world->GetItem("Progressive Dominion Rod", true));
|
||||
}
|
||||
break;
|
||||
case dItemNo_Randomizer_KANTERA_e:
|
||||
pool.push_back(world->GetItem("Lantern", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_JEWEL_ROD_e:
|
||||
case dItemNo_Randomizer_JEWEL_BEE_ROD_e:
|
||||
case dItemNo_Randomizer_JEWEL_WORM_ROD_e:
|
||||
pool.push_back(world->GetItem("Progressive Fishing Rod", true));
|
||||
[[fallthrough]];
|
||||
case dItemNo_Randomizer_FISHING_ROD_1_e:
|
||||
case dItemNo_Randomizer_BEE_ROD_e:
|
||||
case dItemNo_Randomizer_WORM_ROD_e:
|
||||
pool.push_back(world->GetItem("Progressive Fishing Rod", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_PACHINKO_e:
|
||||
pool.push_back(world->GetItem("Slingshot", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_BOMB_BAG_LV1_e:
|
||||
pool.push_back(world->GetItem("Bomb Bag", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_RAFRELS_MEMO_e:
|
||||
pool.push_back(world->GetItem("Aurus Memo", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_ASHS_SCRIBBLING_e:
|
||||
pool.push_back(world->GetItem("Asheis Sketch", true));
|
||||
break;
|
||||
case dItemNo_Randomizer_EMPTY_BOTTLE_e:
|
||||
case dItemNo_Randomizer_RED_BOTTLE_e:
|
||||
case dItemNo_Randomizer_GREEN_BOTTLE_e:
|
||||
case dItemNo_Randomizer_BLUE_BOTTLE_e:
|
||||
case dItemNo_Randomizer_MILK_BOTTLE_e:
|
||||
case dItemNo_Randomizer_HALF_MILK_BOTTLE_e:
|
||||
case dItemNo_Randomizer_OIL_BOTTLE_e:
|
||||
case dItemNo_Randomizer_WATER_BOTTLE_e:
|
||||
case dItemNo_Randomizer_OIL_BOTTLE_2_e:
|
||||
case dItemNo_Randomizer_RED_BOTTLE_2_e:
|
||||
case dItemNo_Randomizer_UGLY_SOUP_e:
|
||||
case dItemNo_Randomizer_HOT_SPRING_e:
|
||||
case dItemNo_Randomizer_FAIRY_e:
|
||||
case dItemNo_Randomizer_HOT_SPRING_2_e:
|
||||
case dItemNo_Randomizer_OIL2_e:
|
||||
case dItemNo_Randomizer_OIL_e:
|
||||
case dItemNo_Randomizer_FAIRY_DROP_e:
|
||||
case dItemNo_Randomizer_DROP_BOTTLE_e:
|
||||
case dItemNo_Randomizer_BEE_CHILD_e:
|
||||
case dItemNo_Randomizer_CHUCHU_RARE_e:
|
||||
case dItemNo_Randomizer_CHUCHU_RED_e:
|
||||
case dItemNo_Randomizer_CHUCHU_BLUE_e:
|
||||
case dItemNo_Randomizer_CHUCHU_GREEN_e:
|
||||
case dItemNo_Randomizer_CHUCHU_YELLOW_e:
|
||||
case dItemNo_Randomizer_CHUCHU_PURPLE_e:
|
||||
case dItemNo_Randomizer_LV1_SOUP_e:
|
||||
case dItemNo_Randomizer_LV2_SOUP_e:
|
||||
case dItemNo_Randomizer_LV3_SOUP_e:
|
||||
case dItemNo_Randomizer_OIL_BOTTLE3_e:
|
||||
case dItemNo_Randomizer_CHUCHU_BLACK_e:
|
||||
pool.push_back(world->GetItem("Empty Bottle", true));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow Crystal
|
||||
if (dComIfGs_isEventBit(0xD04)) {
|
||||
pool.push_back(world->GetItem("Shadow Crystal", true));
|
||||
}
|
||||
|
||||
// Fused Shadows
|
||||
for (int i = 0; i < numFusedShadows(); ++i) {
|
||||
pool.push_back(world->GetItem("Progressive Fused Shadow", true));
|
||||
}
|
||||
|
||||
// Mirror Shards
|
||||
for (int i = 0; i < numMirrorShards(); ++i) {
|
||||
pool.push_back(world->GetItem("Progressive Mirror Shard", true));
|
||||
}
|
||||
|
||||
// Poe Souls
|
||||
for (int i = 0; i < dComIfGs_getPohSpiritNum(); ++i) {
|
||||
pool.push_back(world->GetItem("Poe Soul", true));
|
||||
}
|
||||
|
||||
// Hearts
|
||||
for (int i = 0; i < dComIfGs_getMaxLife(); ++i) {
|
||||
pool.push_back(world->GetItem("Piece of Heart", true));
|
||||
}
|
||||
|
||||
// Sky Book characters
|
||||
for (int i = 0; i < dComIfGs_getAncientDocumentNum(); ++i) {
|
||||
pool.push_back(world->GetItem("Progressive Sky Book", true));
|
||||
}
|
||||
|
||||
// Small Keys
|
||||
static std::unordered_map<int, std::string> keyRegionItemNameMap = {
|
||||
{0xA, "Gerudo Desert Bulblin Camp Key"},
|
||||
{0x10, "Forest Temple Small Key"},
|
||||
{0x11, "Goron Mines Small Key"},
|
||||
{0x12, "Lakebed Temple Small Key"},
|
||||
{0x13, "Arbiters Grounds Small Key"},
|
||||
{0x14, "Snowpeak Ruins Small Key"},
|
||||
{0x15, "Temple of Time Small Key"},
|
||||
{0x16, "City in the Sky Small Key"},
|
||||
{0x17, "Palace of Twilight Small Key"},
|
||||
{0x18, "Hyrule Castle Small Key"},
|
||||
};
|
||||
for (auto& [stage, keyName] : keyRegionItemNameMap) {
|
||||
for (int i = 0; i < getTempleKeysFound(stage); ++i) {
|
||||
pool.push_back(world->GetItem(keyName, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Gate Keys
|
||||
if (haveItem(dItemNo_Randomizer_BOSSRIDER_KEY_e)) {
|
||||
pool.push_back(world->GetItem(dItemNo_Randomizer_BOSSRIDER_KEY_e, true));
|
||||
}
|
||||
|
||||
// Big Keys
|
||||
static std::unordered_map<int, std::string> bigKeyRegionItemNameMap = {
|
||||
{0x10, "Forest Temple Big Key"},
|
||||
{0x12, "Lakebed Temple Big Key"},
|
||||
{0x13, "Arbiters Grounds Big Key"},
|
||||
{0x14, "Snowpeak Ruins Bedroom Key"},
|
||||
{0x15, "Temple of Time Big Key"},
|
||||
{0x16, "City in the Sky Big Key"},
|
||||
{0x17, "Palace of Twilight Big Key"},
|
||||
{0x18, "Hyrule Castle Big Key"},
|
||||
};
|
||||
for (auto& [stage, keyName] : bigKeyRegionItemNameMap) {
|
||||
if (isTempleBigKeyFound(stage)) {
|
||||
pool.push_back(world->GetItem(keyName, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Goron Mines Key Shards
|
||||
for (int i = dItemNo_Randomizer_L2_KEY_PIECES1_e; i < dItemNo_Randomizer_L2_KEY_PIECES3_e; ++i) {
|
||||
if (haveItem(i)) {
|
||||
pool.push_back(world->GetItem("Goron Mines Key Shard", true));
|
||||
}
|
||||
}
|
||||
|
||||
// Ordon Pumpkin
|
||||
if (haveItem(dItemNo_Randomizer_TOMATO_PUREE_e)) {
|
||||
pool.push_back(world->GetItem(dItemNo_Randomizer_TOMATO_PUREE_e, true));
|
||||
}
|
||||
|
||||
// Ordon Cheese
|
||||
if (haveItem(dItemNo_Randomizer_TASTE_e)) {
|
||||
pool.push_back(world->GetItem(dItemNo_Randomizer_TASTE_e, true));
|
||||
}
|
||||
|
||||
// Golden Bugs
|
||||
for (int i = dItemNo_Randomizer_M_BEETLE_e; i < dItemNo_Randomizer_F_MAYFLY_e; ++i) {
|
||||
if (haveItem(i)) {
|
||||
pool.push_back(world->GetItem(i, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Ilia quest items
|
||||
for (int i = dItemNo_Randomizer_LETTER_e; i < dItemNo_Randomizer_HORSE_FLUTE_e; ++i) {
|
||||
if (haveItem(i)) {
|
||||
pool.push_back(world->GetItem(i, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Warp Portals
|
||||
// Item ids are scattered so we have to explicitly list them all
|
||||
static const int portals[] = {
|
||||
dItemNo_Randomizer_ORDON_PORTAL_e,
|
||||
dItemNo_Randomizer_SOUTH_FARON_PORTAL_e,
|
||||
dItemNo_Randomizer_NORTH_FARON_PORTAL_e,
|
||||
dItemNo_Randomizer_SACRED_GROVE_PORTAL_e,
|
||||
dItemNo_Randomizer_KAKARIKO_GORGE_PORTAL_e,
|
||||
dItemNo_Randomizer_KAKARIKO_VILLAGE_PORTAL_e,
|
||||
dItemNo_Randomizer_DEATH_MOUNTAIN_PORTAL_e,
|
||||
dItemNo_Randomizer_ELDIN_BRIDGE_PORTAL_e,
|
||||
dItemNo_Randomizer_CASTLE_TOWN_PORTAL_e,
|
||||
dItemNo_Randomizer_UPPER_ZORAS_RIVER_PORTAL_e,
|
||||
dItemNo_Randomizer_ZORAS_DOMAIN_PORTAL_e,
|
||||
dItemNo_Randomizer_SNOWPEAK_PORTAL_e,
|
||||
dItemNo_Randomizer_GERUDO_DESERT_PORTAL_e,
|
||||
dItemNo_Randomizer_MIRROR_CHAMBER_PORTAL_e,
|
||||
};
|
||||
for (auto portal : portals) {
|
||||
if (haveItem(portal)) {
|
||||
pool.push_back(world->GetItem(portal, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Swords
|
||||
static const int swords[] = {
|
||||
dItemNo_Randomizer_WOOD_STICK_e,
|
||||
dItemNo_Randomizer_SWORD_e,
|
||||
dItemNo_Randomizer_MASTER_SWORD_e,
|
||||
dItemNo_Randomizer_LIGHT_SWORD_e,
|
||||
};
|
||||
for (auto sword : swords) {
|
||||
if (haveItem(sword)) {
|
||||
pool.push_back(world->GetItem("Progressive Sword", true));
|
||||
}
|
||||
}
|
||||
|
||||
// Other Equipment
|
||||
static const int equipment[] = {
|
||||
dItemNo_Randomizer_WOOD_SHIELD_e,
|
||||
dItemNo_Randomizer_HYLIA_SHIELD_e,
|
||||
dItemNo_Randomizer_WEAR_ZORA_e,
|
||||
dItemNo_Randomizer_ARMOR_e,
|
||||
};
|
||||
for (auto item : equipment) {
|
||||
if (haveItem(item)) {
|
||||
pool.push_back(world->GetItem(item, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden Skills
|
||||
static const int hiddenSkills[] = {
|
||||
dItemNo_Randomizer_ENDING_BLOW_e,
|
||||
dItemNo_Randomizer_SHIELD_ATTACK_e,
|
||||
dItemNo_Randomizer_BACK_SLICE_e,
|
||||
dItemNo_Randomizer_HELM_SPLITTER_e,
|
||||
dItemNo_Randomizer_MORTAL_DRAW_e,
|
||||
dItemNo_Randomizer_JUMP_STRIKE_e,
|
||||
dItemNo_Randomizer_GREAT_SPIN_e,
|
||||
};
|
||||
for (auto skill : hiddenSkills) {
|
||||
if (haveItem(skill)) {
|
||||
pool.push_back(world->GetItem("Progressive Hidden Skill", true));
|
||||
}
|
||||
}
|
||||
|
||||
// Wallets
|
||||
switch (dComIfGs_getWalletSize()) {
|
||||
case GIANT_WALLET:
|
||||
pool.push_back(world->GetItem("Progressive Wallet", true));
|
||||
[[fallthrough]];
|
||||
case BIG_WALLET:
|
||||
pool.push_back(world->GetItem("Progressive Wallet", true));
|
||||
[[fallthrough]];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
@@ -16,4 +16,10 @@ bool playerIsOnTitleScreen();
|
||||
u16 getItemMessageID(u8 itemId);
|
||||
int numCompletedDungeons();
|
||||
int numFusedShadows();
|
||||
int numMirrorShards();
|
||||
int numMirrorShards();
|
||||
|
||||
/*
|
||||
* Reads the current player inventory and returns an ItemPool that can be used for logic searches
|
||||
*
|
||||
*/
|
||||
randomizer::logic::item_pool::ItemPool getSaveItemPool(randomizer::logic::world::World* world);
|
||||
@@ -281,7 +281,7 @@
|
||||
- Name: Castle Town Doctors Office Entrance
|
||||
Can Transform: If Transform Anywhere
|
||||
Exits:
|
||||
Castle Town Doctors Office Lower: Invoice
|
||||
Castle Town Doctors Office Lower: Invoice and Can_Talk_to_Humans
|
||||
Castle Town Doctors Office West Door Interior: Nothing
|
||||
Castle Town Doctors Office East Door Interior: Nothing
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
Medicine Scent: Can_Sniff
|
||||
Exits:
|
||||
Castle Town Doctors Office Upper: Wolf_Link
|
||||
Castle Town Doctors Office Entrance: Invoice
|
||||
Castle Town Doctors Office Entrance: Invoice and Can_Talk_to_Humans
|
||||
|
||||
- Name: Castle Town Doctors Office Upper
|
||||
Exits:
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace randomizer::logic::item_pool
|
||||
{"Aurus Memo", 1},
|
||||
{"Asheis Sketch", 1},
|
||||
{"Renados Letter", 1},
|
||||
{"Invoice", 1},
|
||||
{"Wooden Statue", 1},
|
||||
{"Ilias Charm", 1},
|
||||
{"Zora Armor", 1},
|
||||
{"Hylian Shield", 1},
|
||||
{"Ordon Shield", 1},
|
||||
@@ -127,6 +130,11 @@ namespace randomizer::logic::item_pool
|
||||
{"Gerudo Desert Portal", 1},
|
||||
{"Mirror Chamber Portal", 1},
|
||||
|
||||
// Tears
|
||||
{"Faron Twilight Tear", 16},
|
||||
{"Eldin Twilight Tear", 16},
|
||||
{"Lanayru Twilight Tear", 16},
|
||||
|
||||
// Junk we should always have
|
||||
{"Purple Rupee Links House", 1},
|
||||
{"Green Rupee", 2},
|
||||
|
||||
@@ -17,19 +17,22 @@ namespace randomizer::logic::search
|
||||
Search::Search(const SearchMode& searchMode,
|
||||
world::WorldPool* worlds,
|
||||
const item_pool::ItemPool& items /* = {} */,
|
||||
const int& worldToSearch /* = -1 */):
|
||||
_searchMode(searchMode), _worlds(worlds)
|
||||
const int& worldToSearch /* = -1 */,
|
||||
bool startingInventory /*= true */):
|
||||
_searchMode(searchMode), _worlds(worlds), _startingInventory(startingInventory)
|
||||
{
|
||||
// Set the items we should already own
|
||||
this->_ownedItems.insert(items.begin(), items.end());
|
||||
|
||||
// Add starting inventory items for each world
|
||||
for (const auto& world : *(this->_worlds))
|
||||
{
|
||||
if (worldToSearch == -1 || world->GetID() == worldToSearch)
|
||||
if (this->_startingInventory) {
|
||||
for (const auto& world : *(this->_worlds))
|
||||
{
|
||||
const auto& startingInventory = world->GetStartingItemPool();
|
||||
this->_ownedItems.insert(startingInventory.begin(), startingInventory.end());
|
||||
if (worldToSearch == -1 || world->GetID() == worldToSearch)
|
||||
{
|
||||
const auto& startingInventory = world->GetStartingItemPool();
|
||||
this->_ownedItems.insert(startingInventory.begin(), startingInventory.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace randomizer::logic::search
|
||||
Search(const SearchMode& searchMode,
|
||||
world::WorldPool* worlds,
|
||||
const item_pool::ItemPool& items = {},
|
||||
const int& worldToSearch = -1);
|
||||
const int& worldToSearch = -1,
|
||||
bool startingInventory = true);
|
||||
|
||||
static auto Accessible(world::WorldPool* worlds,
|
||||
const item_pool::ItemPool& items = {},
|
||||
@@ -73,6 +74,13 @@ namespace randomizer::logic::search
|
||||
return Search(SearchMode::ACCESSIBLE_LOCATIONS, worlds, items, worldToSearch);
|
||||
}
|
||||
|
||||
static auto AccessibleNoStartingInventory(world::WorldPool* worlds,
|
||||
const item_pool::ItemPool& items = {},
|
||||
const int& worldToSearch = -1)
|
||||
{
|
||||
return Search(SearchMode::ACCESSIBLE_LOCATIONS, worlds, items, worldToSearch, false);
|
||||
}
|
||||
|
||||
static auto AllLocationsReachable(world::WorldPool* worlds,
|
||||
const item_pool::ItemPool& items = {},
|
||||
const int& worldToSearch = -1)
|
||||
@@ -136,6 +144,7 @@ namespace randomizer::logic::search
|
||||
bool _newThingsFound = true;
|
||||
bool _isBeatable = false;
|
||||
bool _collectItems = true;
|
||||
bool _startingInventory = true;
|
||||
std::unordered_set<int> _ownedEvents;
|
||||
std::unordered_multiset<item::Item*> _ownedItems;
|
||||
|
||||
|
||||
@@ -116,15 +116,8 @@ namespace randomizer::logic::world
|
||||
auto dungeonMap = itemNode["Dungeon Map"].as<std::string>("");
|
||||
|
||||
// Make the item and insert it into the item table
|
||||
auto item = std::make_unique<item::Item>(id,
|
||||
name,
|
||||
this,
|
||||
importance,
|
||||
gameWinningItem,
|
||||
dungeonSmallKey != "",
|
||||
dungeonBigKey != "",
|
||||
dungeonCompass != "",
|
||||
dungeonMap != "");
|
||||
auto item = std::make_unique<item::Item>(id, name, this, importance, gameWinningItem,
|
||||
dungeonSmallKey != "", dungeonBigKey != "", dungeonCompass != "", dungeonMap != "");
|
||||
|
||||
this->_itemTable.try_emplace(name, std::move(item));
|
||||
|
||||
@@ -146,6 +139,9 @@ namespace randomizer::logic::world
|
||||
{
|
||||
this->GetDungeon(dungeonMap)->SetDungeonMap(curItem);
|
||||
}
|
||||
|
||||
// Put item into itemIdTable as well
|
||||
this->_itemIdTable.try_emplace(id, curItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,6 +988,18 @@ namespace randomizer::logic::world
|
||||
return this->_itemTable.at(name).get();
|
||||
}
|
||||
|
||||
item::Item* World::GetItem(uint8_t id, const bool& ignoreError /*= false*/) {
|
||||
if (!this->_itemIdTable.contains(id))
|
||||
{
|
||||
if (!ignoreError)
|
||||
{
|
||||
throw std::runtime_error("Unknown item id \"" + std::to_string(id) + "\"");
|
||||
}
|
||||
return item::Nothing.get();
|
||||
}
|
||||
return this->_itemIdTable.at(id);
|
||||
}
|
||||
|
||||
item::Item* World::GetGameWinningItem() const
|
||||
{
|
||||
return this->_itemTable.at("Game Beatable").get();
|
||||
|
||||
@@ -113,6 +113,7 @@ namespace randomizer::logic::world
|
||||
dungeon::Dungeon* GetDungeon(const std::string& name);
|
||||
const std::map<std::string, std::unique_ptr<dungeon::Dungeon>>& GetDungeonTable() const;
|
||||
item::Item* GetItem(const std::string& name, const bool& ignoreError = false);
|
||||
item::Item* GetItem(uint8_t id, const bool& ignoreError = false);
|
||||
item::Item* GetShadowCrystal();
|
||||
item::Item* GetGameWinningItem() const;
|
||||
item_pool::ItemPool& GetItemPool();
|
||||
@@ -144,6 +145,7 @@ namespace randomizer::logic::world
|
||||
|
||||
seedgen::settings::Settings _settings;
|
||||
std::map<std::string, std::unique_ptr<item::Item>> _itemTable = {};
|
||||
std::map<int, item::Item*> _itemIdTable = {};
|
||||
std::map<std::string, std::unique_ptr<location::Location>> _locationTable = {};
|
||||
std::unordered_set<std::string> _intentionallyRemovedLocations = {};
|
||||
std::unordered_set<std::string> _registeredLocationCategories = {};
|
||||
|
||||
Reference in New Issue
Block a user