add basic chest overrides

This commit is contained in:
gymnast86
2026-04-13 23:51:10 -07:00
parent f478751080
commit bf70de83f1
8 changed files with 95 additions and 30 deletions
+8
View File
@@ -1269,6 +1269,14 @@ int dComIfGd_setShadow(u32 param_0, s8 param_1, J3DModel* param_2, cXyz* param_3
dKy_tevstr_c* param_9, s16 param_10, f32 param_11, TGXTexObj* param_12);
#if TARGET_PC
inline dSv_randomizer_c& dComIfG_getRandomizer() {
return g_dComIfG_gameInfo.info.mRandomizer;
}
inline BOOL dComIfG_isRandomizer() {
return g_dComIfG_gameInfo.info.mRandomizer.mActive;
}
void dComIfGs_setupRandomizerSave();
#endif
+18
View File
@@ -10,6 +10,10 @@
#include "JSystem/JHostIO/JORReflexible.h"
#include "dusk/endian.h"
#if TARGET_PC
#include <unordered_map>
#endif
static const int DEFAULT_SELECT_ITEM_INDEX = 0;
static const int MAX_SELECT_ITEM = 4;
static const int SELECT_ITEM_NUM = 2;
@@ -929,6 +933,17 @@ public:
/* 0x8 */ s8 m_no;
};
#if TARGET_PC
class dSv_randomizer_c {
public:
BOOL mActive{false};
std::unordered_map<std::string, std::unordered_map<u8, u8>> mTreasureChestOverrides{};
std::unordered_map<std::string, std::unordered_map<u8, u8>> mPoeOverrides{};
void clear();
};
#endif
class dSv_info_c {
public:
void init();
@@ -1011,6 +1026,9 @@ public:
#if DEBUG
/* 0xF80 */ flagFile_c mFlagFile;
#endif
#if TARGET_PC
/* 0xF38 */ dSv_randomizer_c mRandomizer;
#endif
}; // Size: 0xF38
class dSv_event_flag_c {
+7
View File
@@ -1785,6 +1785,13 @@ void daTbox_c::mode_exec() {
cPhs_Step daTbox_c::create1st() {
if (!mParamsInit) {
field_0x980 = home.angle.x;
#if TARGET_PC
// The upper 8 bits of home.angle.z hold the itemId
if (dComIfG_isRandomizer()) {
home.angle.z &= 0x00FF;
home.angle.z |= dComIfG_getRandomizer().mTreasureChestOverrides[dComIfGp_getStartStageName()][getTboxNo()] << 8;
}
#endif
field_0x982 = home.angle.z;
home.angle.z = 0;
home.angle.x = 0;
+13
View File
@@ -2329,6 +2329,19 @@ void dComIfGs_setupRandomizerSave() {
}
}
// Setup randomizer data
auto& randoData = g_dComIfG_gameInfo.info.mRandomizer;
randoData.mActive = TRUE;
for (const auto& location : world->GetAllLocations()) {
const auto& metaData = location->GetMetadata();
if (location->HasCategories("Chest")) {
const auto& stage = metaData[0]["Stage"].as<std::string>();
const auto& tboxId = metaData[0]["Tbox ID"].as<u8>();
const auto& itemId = location->GetCurrentItem()->GetID();
randoData.mTreasureChestOverrides[stage][tboxId] = itemId;
}
}
DuskLog.debug("Created Rando Save");
}
#endif
+6
View File
@@ -1528,6 +1528,12 @@ dSv_memory2_c* dSv_save_c::getSave2(int i_stage2No) {
return &mSave2[i_stage2No];
}
void dSv_randomizer_c::clear() {
mTreasureChestOverrides.clear();
mPoeOverrides.clear();
mActive = FALSE;
}
void dSv_info_c::getSave(int i_stageNo) {
JUT_ASSERT(4133, 0 <= i_stageNo && i_stageNo < dSv_save_c::STAGE_MAX);
mMemory = mSavedata.getSave(i_stageNo);
+9 -2
View File
@@ -11,14 +11,16 @@ namespace randomizer::logic::location
world::World* world,
item::Item* originalItem,
const bool& goalLocation,
const std::string& hintPriority):
const std::string& hintPriority,
const YAML::Node& metadata):
_id(id),
_name(name),
_categories(categories),
_world(world),
_originalItem(originalItem),
_goalLocation(goalLocation),
_hintPriority(hintPriority)
_hintPriority(hintPriority),
_metadata(metadata)
{
this->_computedRequirement._type = requirement::Type::IMPOSSIBLE;
}
@@ -106,6 +108,11 @@ namespace randomizer::logic::location
return this->_hinted;
}
const YAML::Node& Location::GetMetadata() const
{
return this->_metadata;
}
void Location::AddLocationAccess(area::LocationAccess* locAcc)
{
this->_locationAccessList.push_back(locAcc);
+5 -1
View File
@@ -2,6 +2,7 @@
#include "item.hpp"
#include "requirement.hpp"
#include "../utility/yaml.hpp"
#include <stdexcept>
#include <unordered_set>
@@ -28,7 +29,8 @@ namespace randomizer::logic::location
world::World* world,
item::Item* originalItem,
const bool& goalLocation,
const std::string& hintPriority);
const std::string& hintPriority,
const YAML::Node& metadata);
int GetID() const;
std::string GetName() const;
@@ -46,6 +48,7 @@ namespace randomizer::logic::location
bool IsProgression() const;
void SetHinted(const bool& hinted);
bool IsHinted() const;
const YAML::Node& GetMetadata() const;
void AddLocationAccess(area::LocationAccess* locAcc);
std::list<area::LocationAccess*> GetAccessList() const;
void AddForbiddenItem(item::Item* forbiddenItem);
@@ -94,6 +97,7 @@ namespace randomizer::logic::location
std::string _hintPriority = "Never";
std::unordered_set<item::Item*> _forbiddenItems = {};
requirement::Requirement _computedRequirement;
YAML::Node _metadata{};
/**
* @brief _registeredLocationCategories is the set of all categories that are processed after reading locations.yaml.
* This structure is held in the World class and every location in that world has a pointer to it.
+29 -27
View File
@@ -76,7 +76,7 @@ namespace randomizer::logic::world
void World::Build()
{
randomizer::utility::platform::Log(std::string("Building World ") + std::to_string(this->GetID()));
utility::platform::Log(std::string("Building World ") + std::to_string(this->GetID()));
this->BuildItemTable();
this->BuildLocationTable();
this->LoadLogicMacros();
@@ -90,7 +90,7 @@ namespace randomizer::logic::world
LOG_TO_DEBUG("Building Item Table for World " + std::to_string(this->GetID()));
// Check if we can open the file before parsing
auto filepath = RANDO_DATA_PATH "items.yaml";
randomizer::utility::file::Verify(filepath);
utility::file::Verify(filepath);
auto itemDataTree = LoadYAML(filepath);
// Process all nodes of the yaml file. Each node contains one item
@@ -157,8 +157,8 @@ namespace randomizer::logic::world
{
LOG_TO_DEBUG("Building Location Table for World " + std::to_string(this->GetID()));
// check if we can open the file before parsing because exceptions won't work on console
auto filepath = RANDO_DATA_PATH "locations.yaml";
randomizer::utility::file::Verify(filepath);
const auto filepath = RANDO_DATA_PATH "locations.yaml";
utility::file::Verify(filepath);
auto locationDataTree = LoadYAML(filepath);
// Process all nodes of the yaml file. Each node contains one location
@@ -197,14 +197,16 @@ namespace randomizer::logic::world
auto originalItem = this->GetItem(originalItemName);
auto goalLocation = locationNode["Goal Location"].as<bool>(false);
auto hintPriority = locationNode["Hint Priority"].as<std::string>("Never");
auto metadata = locationNode["Metadata"];
auto location = std::make_unique<location::Location>(locationIdCounter++,
name,
categories,
this,
originalItem,
goalLocation,
hintPriority);
name,
categories,
this,
originalItem,
goalLocation,
hintPriority,
metadata);
LOG_TO_DEBUG("Processing new location " + name + "\tid: " + std::to_string(locationIdCounter - 1) +
"\toriginal item: " + originalItemName);
@@ -220,7 +222,7 @@ namespace randomizer::logic::world
LOG_TO_DEBUG("Loading Macros for World " + std::to_string(this->GetID()));
// check if we can open the file before parsing
auto filepath = RANDO_DATA_PATH "macros.yaml";
randomizer::utility::file::Verify(filepath);
utility::file::Verify(filepath);
auto macrosDataTree = LoadYAML(filepath);
@@ -275,7 +277,7 @@ namespace randomizer::logic::world
for (const auto& file : files)
{
auto filepath = folder + file;
randomizer::utility::file::Verify(filepath);
utility::file::Verify(filepath);
auto worldDataTree = LoadYAML(filepath);
for (const auto& areaNode : worldDataTree)
@@ -535,7 +537,7 @@ namespace randomizer::logic::world
// Vanilla Small Keys
if ((this->Setting("Small Keys") == "Vanilla" &&
(originalItem->IsDungeonSmallKey() ||
randomizer::utility::str::Contains(originalItemName, "Ordon Pumpkin", "Ordon Cheese"))) ||
utility::str::Contains(originalItemName, "Ordon Pumpkin", "Ordon Cheese"))) ||
// Vanilla Big Keys (only include Hyrule Castle Big Key if it has no requirements)
(this->Setting("Big Keys") == "Vanilla" && originalItem->IsBigKey() &&
(originalItemName != "Hyrule Castle Big Key" || this->Setting("Hyrule Castle Big Key Requirements") == "None")) ||
@@ -566,7 +568,7 @@ namespace randomizer::logic::world
// North Faron Woods Gate Key
(this->Setting("Skip Prologue") == "Off" && locationName == "Faron Mist Cave Open Chest") ||
// Some locations which will always be vanilla for the time being
(randomizer::utility::str::Contains(locationName,
(utility::str::Contains(locationName,
"Renados Letter",
"Telma Invoice",
"Wooden Statue",
@@ -592,7 +594,7 @@ namespace randomizer::logic::world
location->SetCurrentItem(originalItem);
location->SetKnownVanillaItem(true);
randomizer::utility::container::Erase(this->_itemPool, originalItem);
utility::container::Erase(this->_itemPool, originalItem);
}
}
}
@@ -608,7 +610,7 @@ namespace randomizer::logic::world
"\" already exists there.");
}
location->SetCurrentItem(item);
randomizer::utility::container::Erase(this->_itemPool, item);
utility::container::Erase(this->_itemPool, item);
}
}
@@ -643,7 +645,7 @@ namespace randomizer::logic::world
location->HasCategories("Sky Book")) ||
// We're starting with a shop item, but shop items aren't randomized
(this->Setting("Shop Items") == "Off" && location->HasCategories("Shop") &&
randomizer::utility::container::ElementInContainer(this->_startingItemPool, originalItem)))
utility::container::ElementInContainer(this->_startingItemPool, originalItem)))
{
location->RemoveCurrentItem();
location->SetKnownVanillaItem(false);
@@ -721,7 +723,7 @@ namespace randomizer::logic::world
// assigned a goal location. Dungeons without a goal location cannot be chosen as required dungeons.
if (!possibleGoalLocations.empty())
{
dungeon->SetGoalLocation(randomizer::utility::random::RandomElement(possibleGoalLocations));
dungeon->SetGoalLocation(utility::random::RandomElement(possibleGoalLocations));
}
else
{
@@ -737,16 +739,16 @@ namespace randomizer::logic::world
{
// Gather all boss locations (heart container and dungeon reward checks)
auto bossLocations = this->GetAllLocations();
randomizer::utility::container::FilterAndEraseFromVector(
utility::container::FilterAndEraseFromVector(
bossLocations,
[](const auto& location)
{ return !randomizer::utility::str::Contains(location->GetName(), "Heart Container", "Dungeon Reward"); });
{ return !utility::str::Contains(location->GetName(), "Heart Container", "Dungeon Reward"); });
// Gather all small key items
item_pool::ItemPool smallKeys = {};
for (const auto& [itemName, item] : this->_itemTable)
{
if (item->IsDungeonSmallKey() || randomizer::utility::general::IsAnyOf(itemName,
if (item->IsDungeonSmallKey() || utility::general::IsAnyOf(itemName,
"Ordon Pumpkin",
"Ordon Cheese",
"North Faron Woods Gate Key",
@@ -858,11 +860,11 @@ namespace randomizer::logic::world
item::Item* randomJunkItem;
if (!mainJunkPool.empty())
{
randomJunkItem = randomizer::utility::random::PopRandomElement(mainJunkPool);
randomJunkItem = utility::random::PopRandomElement(mainJunkPool);
}
else
{
randomJunkItem = randomizer::utility::random::RandomElement(mainJunkPoolCopy);
randomJunkItem = utility::random::RandomElement(mainJunkPoolCopy);
}
this->_itemPool.emplace_back(randomJunkItem);
LOG_TO_DEBUG("Added junk item \"" + randomJunkItem->GetName() + "\" to item pool for world " +
@@ -921,10 +923,10 @@ namespace randomizer::logic::world
}
// Place the new bottle items
randomizer::utility::random::ShufflePool(bottleLocations);
utility::random::ShufflePool(bottleLocations);
for (auto& bottleLocation : bottleLocations)
{
bottleLocation->SetCurrentItem(randomizer::utility::random::PopRandomElement(bottlePool));
bottleLocation->SetCurrentItem(utility::random::PopRandomElement(bottlePool));
}
}
}
@@ -1109,7 +1111,7 @@ namespace randomizer::logic::world
auto entrances = this->GetShuffleableEntrances(type, onlyPrimary);
// Remove any entrances which aren't shuffled
randomizer::utility::container::FilterAndEraseFromVector(entrances, [](const auto& e) { return !e->IsShuffled(); });
utility::container::FilterAndEraseFromVector(entrances, [](const auto& e) { return !e->IsShuffled(); });
return entrances;
}
@@ -1163,7 +1165,7 @@ namespace randomizer::logic::world
return this->_eventNames.at(eventIndex);
}
randomizer::seedgen::settings::Setting& World::Setting(const std::string& settingName)
seedgen::settings::Setting& World::Setting(const std::string& settingName)
{
auto& settings = this->_settings;
// Check to make sure the setting exists