mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-22 15:02:54 -04:00
add basic chest overrides
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user