mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-20 13:24:40 -04:00
Improve Entrance Coupling Logic, Improve Entrance Shuffle Data, fix seed name
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -665,9 +665,35 @@
|
||||
Exits:
|
||||
Upper Zoras River Izas House: Can_Open_Doors and Upper_Zoras_River_Portal
|
||||
Fishing Hole: Can_Open_Doors
|
||||
Zoras Domain: Nothing
|
||||
Upper Zoras River To Zoras Domain (On Land): Nothing
|
||||
Upper Zoras River To Zoras Domain (Swimming): Nothing
|
||||
Upper Zoras River To Zoras Domain (Underwater): Iron_Boots or Zora_Armor
|
||||
Lanayru Field: Nothing
|
||||
|
||||
- Name: Upper Zoras River To Zoras Domain (On Land)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Upper Zoras River
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain To Upper Zoras River (On Land): Nothing
|
||||
Upper Zoras River: Nothing
|
||||
|
||||
- Name: Upper Zoras River To Zoras Domain (Swimming)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Upper Zoras River
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain To Upper Zoras River (Swimming): Nothing
|
||||
Upper Zoras River: Nothing
|
||||
|
||||
- Name: Upper Zoras River To Zoras Domain (Underwater)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Upper Zoras River
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain To Upper Zoras River (Underwater): Iron_Boots or Zora_Armor
|
||||
Upper Zoras River: Nothing
|
||||
|
||||
- Name: Upper Zoras River Izas House
|
||||
Can Warp: True
|
||||
Locations:
|
||||
@@ -718,7 +744,33 @@
|
||||
Zoras Domain West Ledge: Clawshot or Can_Midna_Jump or Twilight
|
||||
Zoras Domain Top of Waterfall: Clawshot or Can_Midna_Jump or Twilight
|
||||
Snowpeak Climb Lower: Not_Twilight
|
||||
Upper Zoras River: Nothing
|
||||
Zoras Domain To Upper Zoras River (On Land): Nothing
|
||||
Zoras Domain To Upper Zoras River (Swimming): Nothing
|
||||
Zoras Domain To Upper Zoras River (Underwater): Iron_Boots or Zora_Armor
|
||||
|
||||
- Name: Zoras Domain To Upper Zoras River (On Land)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Upper Zoras River To Zoras Domain (On Land): Nothing
|
||||
Zoras Domain: Nothing
|
||||
|
||||
- Name: Zoras Domain To Upper Zoras River (Swimming)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Upper Zoras River To Zoras Domain (Swimming): Nothing
|
||||
Zoras Domain: Nothing
|
||||
|
||||
- Name: Zoras Domain To Upper Zoras River (Underwater)
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Upper Zoras River To Zoras Domain (Underwater): Nothing
|
||||
Zoras Domain: Iron_Boots or Zora_Armor
|
||||
|
||||
- Name: Zoras Domain West Ledge
|
||||
Map Sector: Lanayru Province
|
||||
@@ -747,10 +799,45 @@
|
||||
Zoras Domain Shortcut Lower Boulder Rupee: Can_Smash
|
||||
Zoras Domain Shortcut Upper Boulder Rupee: Can_Smash
|
||||
Exits:
|
||||
Zoras Throne Room: Nothing
|
||||
Zoras Domain Top of Waterfall Center: Nothing
|
||||
Zoras Domain Top of Waterfall West: Nothing
|
||||
Zoras Domain Top of Waterfall East: Nothing
|
||||
Zoras Domain Top of Waterfall Underwater: Iron_Boots or Zora_Armor
|
||||
Zoras Domain West Ledge: Can_Smash
|
||||
Zoras Domain: Nothing
|
||||
|
||||
- Name: Zoras Domain Top of Waterfall Center
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall: Nothing
|
||||
Zoras Throne Room Center: Nothing
|
||||
|
||||
- Name: Zoras Domain Top of Waterfall West
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall: Nothing
|
||||
Zoras Throne Room West: Nothing
|
||||
|
||||
- Name: Zoras Domain Top of Waterfall East
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall: Nothing
|
||||
Zoras Throne Room East: Iron_Boots or Zora_Armor
|
||||
|
||||
- Name: Zoras Domain Top of Waterfall Underwater
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall: Nothing
|
||||
Zoras Throne Room Underwater: Iron_Boots or Zora_Armor
|
||||
|
||||
- Name: Zoras Throne Room
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
@@ -769,4 +856,39 @@
|
||||
Zoras Domain Underwater Goron: Water_Bombs and Iron_Boots and Zora_Armor
|
||||
Zoras Domain Throne Room Twilit Insect: Can_Defeat_Lanayru_Twilit_Insect
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall: Nothing
|
||||
Zoras Throne Room Center: Nothing
|
||||
Zoras Throne Room West: Nothing
|
||||
Zoras Throne Room East: Nothing
|
||||
Zoras Throne Room Underwater: Iron_Boots or Zora_Armor
|
||||
|
||||
- Name: Zoras Throne Room Center
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall Center: Nothing
|
||||
Zoras Throne Room: Nothing
|
||||
|
||||
- Name: Zoras Throne Room West
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall West: Nothing
|
||||
Zoras Throne Room: Nothing
|
||||
|
||||
- Name: Zoras Throne Room East
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall East: Nothing
|
||||
Zoras Throne Room: Nothing
|
||||
|
||||
- Name: Zoras Throne Room Underwater
|
||||
Map Sector: Lanayru Province
|
||||
Region: Zoras Domain
|
||||
Twilight: Lanayru
|
||||
Exits:
|
||||
Zoras Domain Top of Waterfall Underwater: Nothing
|
||||
Zoras Throne Room: Iron_Boots or Zora_Armor
|
||||
|
||||
@@ -357,30 +357,10 @@ namespace randomizer::logic::entrance
|
||||
return {parentAreaName, connectedAreaName};
|
||||
}
|
||||
|
||||
bool Entrance::SetGameInfo(const YAML::Node& node) {
|
||||
bool ret = true;
|
||||
std::string stageIdString = node["Stage"].as<std::string>();
|
||||
if (stageIdString == "null") {
|
||||
stageIdString = "-1";
|
||||
ret = false;
|
||||
}
|
||||
int stageId = std::stoi(stageIdString);
|
||||
if (stageId == -1) {
|
||||
stageId = 0xFF;
|
||||
}
|
||||
SetStageId(static_cast<uint8_t>(stageId));
|
||||
std::string roomNoString = node["Room"].as<std::string>();
|
||||
if (roomNoString == "null") {
|
||||
roomNoString = "-1";
|
||||
ret = false;
|
||||
}
|
||||
SetRoomNo(static_cast<int8_t>(std::stoi(roomNoString)));
|
||||
SetPointNo(static_cast<int16_t>(std::stoi("0x0"+node["Spawn"].as<std::string>(),nullptr,16)));
|
||||
int layer = std::stoi("0x0"+node["State"].as<std::string>(),nullptr,16);
|
||||
if (layer == 0xFF) {
|
||||
layer = -1;
|
||||
}
|
||||
SetLayerNo(static_cast<int8_t>(layer));
|
||||
return ret;
|
||||
void Entrance::SetGameInfo(const YAML::Node& node) {
|
||||
SetStageId(node["Stage"].as<uint8_t>());
|
||||
SetRoomNo(node["Room"].as<int8_t>());
|
||||
SetPointNo(node["Spawn"].as<int16_t>());
|
||||
SetLayerNo(node["State"].as<int8_t>());
|
||||
}
|
||||
} // namespace randomizer::logic::entrance
|
||||
|
||||
@@ -158,9 +158,9 @@ namespace randomizer::logic::entrance
|
||||
int8_t GetRoomNo() const { return _roomNo; }
|
||||
int8_t GetLayerNo() const { return _layerNo; }
|
||||
int16_t GetPointNo() const { return _pointNo; }
|
||||
bool SetGameInfo(const YAML::Node& node);
|
||||
void SetCoupledDoor(int16_t entrance) { _coupledEntrance = entrance; }
|
||||
int16_t getCoupledDoor() { return _coupledEntrance; }
|
||||
void SetGameInfo(const YAML::Node& node);
|
||||
void SetCoupledEntrances(const std::vector<int16_t>& entrances) { _coupledEntrances = entrances; }
|
||||
const std::vector<int16_t>& getCoupledEntrances() const { return _coupledEntrances; }
|
||||
|
||||
private:
|
||||
int _id = -1;
|
||||
@@ -223,7 +223,7 @@ namespace randomizer::logic::entrance
|
||||
Entrance* _assumed = nullptr;
|
||||
|
||||
// If the entrance is a coupled door, this is the other door's point to override
|
||||
int16_t _coupledEntrance = -1;
|
||||
std::vector<int16_t> _coupledEntrances = {};
|
||||
};
|
||||
|
||||
using EntrancePool = std::vector<Entrance*>;
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace randomizer::logic::entrance_shuffle
|
||||
|
||||
void SetAllEntrancesData(world::World* world)
|
||||
{
|
||||
// Keep track of which double door entrances are together
|
||||
std::unordered_map<std::string, std::list<entrance::Entrance*>> coupledDoors = {};
|
||||
// Keep track of which entrances are together
|
||||
std::unordered_map<std::string, std::list<entrance::Entrance*>> coupledEntrances = {};
|
||||
|
||||
auto entranceDataTree = LOAD_EMBED_YAML(RANDO_DATA_PATH "entrance_shuffle_data.yaml");
|
||||
for (const auto& entranceDataNode : entranceDataTree)
|
||||
@@ -60,6 +60,21 @@ namespace randomizer::logic::entrance_shuffle
|
||||
}
|
||||
|
||||
auto& forwardEntry = entranceDataNode["Forward"];
|
||||
|
||||
// If the entrance can't actually be mapped in-game, skip it
|
||||
auto stageString = forwardEntry["Stage"].as<std::string>();
|
||||
auto roomString = forwardEntry["Stage"].as<std::string>();
|
||||
if (stageString == "null" || stageString == "-1" || roomString == "null" || roomString == "-1") {
|
||||
continue;
|
||||
}
|
||||
if (entranceDataNode["Return"]) {
|
||||
stageString = entranceDataNode["Return"]["Stage"].as<std::string>();
|
||||
roomString = entranceDataNode["Return"]["Stage"].as<std::string>();
|
||||
if (stageString == "null" || stageString == "-1" || roomString == "null" || roomString == "-1") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to make sure all required fields are present for the forward entry
|
||||
YAMLVerifyFields(forwardEntry, "Connection" /*, "Info" */);
|
||||
|
||||
@@ -84,45 +99,50 @@ namespace randomizer::logic::entrance_shuffle
|
||||
returnEntry["Alias"] ? returnEntry["Alias"].as<std::string>() : "");
|
||||
forwardEntrance->BindTwoWay(returnEntrance);
|
||||
|
||||
// Add double door entrances to their respective tag group
|
||||
if (entranceDataNode["Door Couple Tag"])
|
||||
// Add coupled entrances to their respective tag group
|
||||
if (entranceDataNode["Entrance Couple Tag"])
|
||||
{
|
||||
auto tag = entranceDataNode["Door Couple Tag"].as<std::string>();
|
||||
if (!coupledDoors.contains(tag))
|
||||
auto tag = entranceDataNode["Entrance Couple Tag"].as<std::string>();
|
||||
if (!coupledEntrances.contains(tag))
|
||||
{
|
||||
coupledDoors[tag] = {};
|
||||
coupledEntrances[tag] = {};
|
||||
}
|
||||
coupledDoors.at(tag).push_back(forwardEntrance);
|
||||
coupledDoors.at(tag).push_back(returnEntrance);
|
||||
coupledEntrances.at(tag).push_back(forwardEntrance);
|
||||
coupledEntrances.at(tag).push_back(returnEntrance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If double doors are coupled, add the coupled door's info to the main door, remove the coupled door entrance, and
|
||||
// If entrances are coupled, add the coupled entrance's spawn point to the main door, remove the coupled door entrance, and
|
||||
// rename the main door to be more general
|
||||
if (world->Setting("Decouple Double Door Entrances") == "Off")
|
||||
{
|
||||
for (auto& [tag, doors] : coupledDoors)
|
||||
for (auto& [tag, entrances] : coupledEntrances)
|
||||
{
|
||||
while (!doors.empty())
|
||||
while (!entrances.empty())
|
||||
{
|
||||
auto mainDoor = doors.back();
|
||||
doors.pop_back();
|
||||
auto mainEntrance = entrances.back();
|
||||
entrances.pop_back();
|
||||
|
||||
auto coupledDoorItr =
|
||||
std::ranges::find_if(doors,
|
||||
[&](const auto& door) { return door->IsPrimary() == mainDoor->IsPrimary(); });
|
||||
auto coupledDoor = *coupledDoorItr;
|
||||
std::vector<int16_t> coupledPoints;
|
||||
for (auto it = entrances.begin(); it != entrances.end();) {
|
||||
auto coupledEntrance = *it;
|
||||
if (coupledEntrance->IsPrimary() == mainEntrance->IsPrimary()) {
|
||||
coupledPoints.push_back(coupledEntrance->GetPointNo());
|
||||
|
||||
mainDoor->SetCoupledDoor(coupledDoor->GetPointNo());
|
||||
// Completely remove the coupled door from the world graph
|
||||
coupledEntrance->GetConnectedArea()->RemoveEntrance(coupledEntrance);
|
||||
coupledEntrance->GetParentArea()->RemoveExit(coupledEntrance);
|
||||
it = entrances.erase(it);
|
||||
}else{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Completely remove the coupled door from the world graph
|
||||
doors.erase(coupledDoorItr);
|
||||
coupledDoor->GetConnectedArea()->RemoveEntrance(coupledDoor);
|
||||
coupledDoor->GetParentArea()->RemoveExit(coupledDoor);
|
||||
mainEntrance->SetCoupledEntrances(std::move(coupledPoints));
|
||||
|
||||
// Change the main door's name to be more general
|
||||
mainDoor->GeneralizeName();
|
||||
mainEntrance->GeneralizeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,17 +867,17 @@ void randomizer_checkAndOverrideEntranceData(const char*& stageName, s8& roomNo,
|
||||
|
||||
// Debugging: Dump mEntranceOverrides
|
||||
// for (const auto& [key,val] : randomizer_GetContext().mEntranceOverrides) {
|
||||
// mods::log::debug("({},{},{},{}) -> ({},{},{},{})",key.stageId,key.roomNo,key.mapLayer,key.pointNo,val.stageId,val.roomNo,val.mapLayer,val.pointNo);
|
||||
// mods::log::info("({},{},{},{}) -> ({},{},{},{})",key.stageId,key.roomNo,key.mapLayer,key.pointNo,val.stageId,val.roomNo,val.mapLayer,val.pointNo);
|
||||
// }
|
||||
|
||||
// mods::log::debug("Original Stage:{}, {}, {}, {}",stageName,roomNo,pointNo,mapLayer);
|
||||
// mods::log::info("Original Stage:{}, {}, {}, {}",stageName,roomNo,pointNo,mapLayer);
|
||||
if (randomizer_GetContext().mEntranceOverrides.contains(override)) {
|
||||
auto& newOverride = randomizer_GetContext().mEntranceOverrides[override];
|
||||
stageName = allStages[newOverride.stageId];
|
||||
pointNo = newOverride.pointNo;
|
||||
roomNo = newOverride.roomNo;
|
||||
mapLayer = newOverride.mapLayer;
|
||||
// mods::log::debug("New Stage:{}, {}, {}, {}",stageName,roomNo,pointNo,mapLayer);
|
||||
// mods::log::info("New Stage:{}, {}, {}, {}",stageName,roomNo,pointNo,mapLayer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1751,7 +1751,6 @@ RandomizerContext WriteSeedData(randomizer::logic::world::World* world) {
|
||||
}
|
||||
|
||||
// Apply entrance randomization
|
||||
auto shuffleData = LOAD_EMBED_YAML(RANDO_DATA_PATH "entrance_shuffle_data.yaml");
|
||||
if (world->AnyEntranceRandomizerEnabled()) {
|
||||
for (const auto& entrance : world->GetShuffledEntrances()) {
|
||||
randomizer::logic::entrance::Entrance* replacesEntrance = entrance->GetReplaces();
|
||||
@@ -1762,9 +1761,9 @@ RandomizerContext WriteSeedData(randomizer::logic::world::World* world) {
|
||||
}
|
||||
randoData.mEntranceOverrides[forward] = replaces;
|
||||
|
||||
// Set an override for the second door, if the entrance is coupled
|
||||
if (entrance->getCoupledDoor() != -1) {
|
||||
RandomizerContext::EntranceOverride coupled = {.stageId = entrance->GetStageId(), .roomNo = entrance->GetRoomNo(), .mapLayer = entrance->GetLayerNo(), .pointNo = entrance->getCoupledDoor()};
|
||||
// Set overrides for all coupled entrances
|
||||
for (const auto& point : entrance->getCoupledEntrances()) {
|
||||
RandomizerContext::EntranceOverride coupled = {.stageId = entrance->GetStageId(), .roomNo = entrance->GetRoomNo(), .mapLayer = entrance->GetLayerNo(), .pointNo = point};
|
||||
randoData.mEntranceOverrides[coupled] = replaces;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ void registerStartingLocation() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we aren't playing only with the setting "Mirror Chamber Access") == "Closed"
|
||||
// Check that we aren't playing only with the setting Mirror Chamber Access set to Closed
|
||||
bool isExclusivelyMirrorChamber = false;
|
||||
const auto& mirrorChamberIt = ctx.mEntranceOverrides.find(RandomizerContext::EntranceOverride{
|
||||
.stageId = StageIDs::Mirror_Chamber,
|
||||
@@ -323,20 +323,10 @@ void registerStartingLocation() {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr std::array<std::string_view,9> kDungeonNames = {
|
||||
"D_MN01","D_MN04","D_MN05","D_MN06","D_MN07","D_MN08","D_MN09","D_MN10","D_MN11"
|
||||
};
|
||||
|
||||
dSv_player_return_place_c& returnPlace = dComIfGs_getSaveData()->mPlayer.getPlayerReturnPlace();
|
||||
bool isDungeon = false;
|
||||
for (const auto& name : kDungeonNames) {
|
||||
if (returnPlace.getName() == name) {
|
||||
isDungeon = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDungeon) {
|
||||
|
||||
// If we are loading into a dungeon, preserve our original return place
|
||||
if (std::string(returnPlace.getName()).find("D_MN") == 0) {
|
||||
// Force-set the entrance without the override
|
||||
g_dComIfG_gameInfo.play.mNextStage.getStartStage()->set(returnPlace.getName(), returnPlace.getRoomNo(), returnPlace.mPlayerStatus, -1);
|
||||
return;
|
||||
@@ -344,7 +334,6 @@ void registerStartingLocation() {
|
||||
|
||||
// Set the spawn to outside of link's house, which will get overrided later if we are replacing it
|
||||
returnPlace.set("F_SP103",1,1);
|
||||
// g_dComIfG_gameInfo.play.mNextStage.getStartStage()->set("F_SP103", 1, 1, -1);
|
||||
dComIfGp_setNextStage("F_SP103", 1, 1, -1);
|
||||
}
|
||||
|
||||
|
||||
@@ -264,9 +264,11 @@ ModResult buildSeedManagementTab(ModContext* ctx, UiWindowHandle, UiElementHandl
|
||||
add_string_input(leftPane,
|
||||
"Seed String",
|
||||
"Current value of the seed used by the randomizer for generation. Leave blank for a random value.",
|
||||
32,
|
||||
31,
|
||||
[](ModContext*, void*, UiControlValue* out_value) {
|
||||
out_value->string_value = GetRandomizerConfig().GetSeed().c_str();
|
||||
static char buffer[32];
|
||||
strncpy(buffer,GetRandomizerConfig().GetSeed().c_str(),31);
|
||||
out_value->string_value = buffer;
|
||||
},
|
||||
[](ModContext*, void*, const UiControlValue* value) {
|
||||
GetRandomizerConfig().SetSeed(value->string_value);
|
||||
|
||||
Reference in New Issue
Block a user