fix stuff relating to getting the Iron Boots chest

This commit is contained in:
gymnast86
2026-04-21 18:47:04 -07:00
parent dbdb4daa58
commit 6113df21e0
11 changed files with 278 additions and 7 deletions
+6
View File
@@ -2492,6 +2492,12 @@ inline s8 dComIfGp_getStartStageRoomNo() {
return g_dComIfG_gameInfo.play.getStartStageRoomNo();
}
#if TARGET_PC
inline s8 dComIfGp_getLayerNo() {
return g_dComIfG_gameInfo.play.getLayerNo(0);
}
#endif
inline s8 dComIfGp_getStartStageLayer() {
return g_dComIfG_gameInfo.play.getStartStageLayer();
}
+8
View File
@@ -11469,6 +11469,14 @@ int daAlink_c::orderTalk(int i_checkZTalk) {
static void* daAlink_searchBouDoor(fopAc_ac_c* i_actor, void* i_data) {
UNUSED(i_data);
#if TARGET_PC
// In randomizer, we don't want Bo preventing us from entering his house on Day 2
if (randomizer_IsActive() && daAlink_c::checkStageName("F_SP103"))
{
return NULL;
}
#endif
if (fopAcM_GetName(i_actor) == fpcNm_NPC_BOU_e && ((daNpc_Bou_c*)i_actor)->speakTo()) {
return i_actor;
}
+4
View File
@@ -882,7 +882,11 @@ u8 daNpc_zrC_c::getTypeFromParam() {
int daNpc_zrC_c::isDelete() {
if (mType == 4 || mType == 0 || mType == 1 || (mType == 2 && daNpcF_chkEvtBit(0x108)
#if TARGET_PC
&& (!daNpcF_chkEvtBit(0x10A) || randomizer_IsActive())) || mType == 3)
#else
&& !daNpcF_chkEvtBit(0x10A)) || mType == 3)
#endif
{
return false;
}
+18
View File
@@ -15,6 +15,10 @@
#include "SSystem/SComponent/c_math.h"
#include <cstring>
#if TARGET_PC
#include "dusk/randomizer/game/stages.h"
#endif
dMsgFlow_c::dMsgFlow_c() {
mNonStopJunpFlowFlag = 0;
setInitValue(1);
@@ -1134,6 +1138,20 @@ u16 dMsgFlow_c::query022(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_spea
const u8 prm0 = i_flowNode_p->param;
u16 ret = checkItemGet(prm0 & 0xFF, 1) ? 0 : 1;
#if TARGET_PC
// Check to see if we're currently in one of the Ordon interiors
if (randomizer_IsActive() && daAlink_c::checkStageName(allStages[Ordon_Village_Interiors]))
{
// Check to see if checking for the Iron Boots
if (prm0 == dItemNo_Randomizer_HVY_BOOTS_e)
{
// Return false so that the door in Bo's house can be opened without having the
// Iron Boots
return 0;
}
}
#endif
if (param_2 != 0) {
// "Get Check"
OS_REPORT("\x1B[44;33m所持チェック            \x1B[m|:");
+19 -1
View File
@@ -22,9 +22,11 @@
#include <cstdio>
#include <cstring>
#if TARGET_PC
#include "dusk/logging.h"
#include "dusk/string.hpp"
#if TARGET_PC
#include "dusk/randomizer/game/randomizer_context.hpp"
#include <format>
#include <fmt/ranges.h>
#endif
@@ -1595,6 +1597,22 @@ u8 dStage_roomControl_c::mNoArcBank;
static void dStage_actorCreate(stage_actor_data_class* i_actorData, fopAcM_prm_class* i_actorPrm) {
dStage_objectNameInf* actorInf = dStage_searchName(i_actorData->name);
#if TARGET_PC
// If randomizer is active, override the data for this actor if it's in the actorPatches
if (randomizer_IsActive()) {
auto currentStageKey = getActorPatchesCurrentStageKey();
if (randomizer_GetContext().mActorPatches.contains(currentStageKey)) {
const auto& patches = randomizer_GetContext().mActorPatches.at(currentStageKey);
auto actorKey = getActorCRC32(i_actorData);
if (patches.contains(actorKey)) {
const auto& patchedActorData = patches.at(actorKey);
std::memcpy(i_actorPrm, patchedActorData.data() + 8, RandomizerContext::ACTOR_CRC_SIZE - 8);
}
}
}
#endif
if (actorInf == NULL) {
OS_REPORT("\x1B""[43;30mStage Actor Name Nothing !! <%s>\n\x1B[m", i_actorData->name);
JKRFree(i_actorPrm);
+81 -2
View File
@@ -1,10 +1,10 @@
#include "imgui.h"
#include "d/d_stage.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuRandomizer.hpp"
#include <mutex>
#include "dusk/app_info.hpp"
#include "dusk/logging.h"
#include "dusk/randomizer/game/randomizer_context.hpp"
@@ -13,9 +13,13 @@
#include "SDL3/SDL_filesystem.h"
#include <mutex>
#include <thread>
#include <filesystem>
#include "dusk/randomizer/generator/utility/endian.hpp"
#include "dusk/randomizer/generator/utility/string.hpp"
namespace dusk {
static bool generatingSeed = false;
@@ -126,6 +130,81 @@ namespace dusk {
else if (startTimeSetting == "Night")
randoData.mStartHour = 24;
// Actor Patches
auto actorPatches = LoadYAML(RANDO_DATA_PATH "actor_patches.yaml");
for (const auto& stageNode : actorPatches) {
const auto& stageName = stageNode.first.as<std::string>();
for (const auto& roomNode : stageNode.second) {
const auto& roomStr = roomNode.first.as<std::string>();
u8 roomNo = roomStr.back() - '0';
for (const auto& layerNode : roomNode.second) {
const auto& layerStr = layerNode.first.as<std::string>();
u8 layerNo = layerStr.back() - '0';
// Create key based off of stage index, room, and layer
u32 stageRoomLayerKey{};
stageRoomLayerKey |= getStageID(stageName.c_str()) << 16;
stageRoomLayerKey |= roomNo << 8;
stageRoomLayerKey |= layerNo;
for (const auto& actorNode : layerNode.second) {
using namespace Utility::Endian;
// Get all the data for the actor (with endian shenanigans)
stage_actor_data_class actor{};
const auto& actorName = actorNode["name"].as<std::string>();
strncpy(actor.name, actorName.c_str(), 8);
actor.base.parameters = toPlatform(target, actorNode["parameters"].as<u32>());
actor.base.position.x = toPlatform(target, actorNode["position"]["x"].as<f32>());
actor.base.position.y = toPlatform(target, actorNode["position"]["y"].as<f32>());
actor.base.position.z = toPlatform(target, actorNode["position"]["z"].as<f32>());
// Have to retrieve as u16 and then cast as s16 because otherwise yaml-cpp
// complains about values over 32767 not fitting in s16
actor.base.angle.x = toPlatform(target, static_cast<s16>(actorNode["angle"]["x"].as<u16>()));
actor.base.angle.y = toPlatform(target, static_cast<s16>(actorNode["angle"]["y"].as<u16>()));
actor.base.angle.z = toPlatform(target, static_cast<s16>(actorNode["angle"]["z"].as<u16>()));
// Create unique hash based off of actor data
u32 actorCRC32 = getActorCRC32(&actor);
// Then override the actor with whatever parts are being patched
const auto& patchNode = actorNode["patch"];
if (patchNode["parameters"]) {
actor.base.parameters = toPlatform(target, patchNode["parameters"].as<u32>());
}
if (auto patchPosition = patchNode["position"]) {
if (patchPosition["x"]) {
actor.base.position.x = toPlatform(target, patchPosition["x"].as<f32>());
}
if (patchPosition["y"]) {
actor.base.position.y = toPlatform(target, patchPosition["y"].as<f32>());
}
if (patchPosition["z"]) {
actor.base.position.z = toPlatform(target, patchPosition["z"].as<f32>());
}
}
if (auto patchAngle = patchNode["angle"]) {
// Have to retrieve as u16 and then cast as s16 because otherwise yaml-cpp
// complains about values over 32767 not fitting in s16
if (patchAngle["x"]) {
actor.base.angle.x = toPlatform(target, static_cast<s16>(patchAngle["x"].as<u16>()));
}
if (patchAngle["y"]) {
actor.base.angle.y = toPlatform(target, static_cast<s16>(patchAngle["y"].as<u16>()));
}
if (patchAngle["z"]) {
actor.base.angle.z = toPlatform(target, static_cast<s16>(patchAngle["z"].as<u16>()));
}
}
// Insert the actor patch into the context with our crc32 as the key and the
// raw actor patch data as the value
std::array<u8, RandomizerContext::ACTOR_CRC_SIZE> patchedActorData{};
std::memcpy(patchedActorData.data(), &actor, RandomizerContext::ACTOR_CRC_SIZE);
randoData.mActorPatches[stageRoomLayerKey][actorCRC32] = patchedActorData;
}
}
}
}
randoData.mHash = r.GetConfig().GetHash();
auto writeToFileResult = randoData.WriteToFile();
if (writeToFileResult.has_value()) {
@@ -6,11 +6,15 @@
#include "dusk/logging.h"
#include "dusk/main.h"
#include "dusk/randomizer/game/tools.h"
#include "dusk/randomizer/generator/utility/endian.hpp"
#include "SDL3/SDL_filesystem.h"
#include <zlib-ng.h>
#include <fstream>
#include "d/actor/d_a_alink.h"
RandomizerContext& randomizer_GetContext() {
static RandomizerContext instance;
return instance;
@@ -54,6 +58,12 @@ std::optional<std::string> RandomizerContext::WriteToFile() {
out["mStartHour"] = static_cast<u16>(this->mStartHour);
out["mMapBits"] = static_cast<u16>(this->mMapBits);
for (const auto& [stageRoomLayer, actorPatches] : this->mActorPatches) {
for (const auto& [actorCRC, actorPatch] : actorPatches) {
out["mActorPatches"][stageRoomLayer][actorCRC] = ContainerToHexString(actorPatch);
}
}
seedData << YAML::Dump(out);
seedData.close();
@@ -109,6 +119,17 @@ std::optional<std::string> RandomizerContext::LoadFromHash(const std::string& ha
// Starting map bits
this->mMapBits = in["mMapBits"].as<u8>();
// Actor Patches
for (const auto& stageRoomLayerNode: in["mActorPatches"]) {
u32 stageRoomLayer = stageRoomLayerNode.first.as<u32>();
for (const auto& actorPatchNode : stageRoomLayerNode.second) {
u32 actorCRC = actorPatchNode.first.as<u32>();
auto actorBytes = HexToBytes(actorPatchNode.second.as<std::string>());
auto& patchedActor = this->mActorPatches[stageRoomLayer][actorCRC];
std::copy_n(actorBytes.begin(), actorBytes.size(), patchedActor.begin());
}
}
DuskLog.debug("Loaded Randomizer Seed {}", this->mHash);
return std::nullopt;
@@ -118,3 +139,27 @@ std::string RandomizerContext::GetSeedDataPath() const {
return std::string(SDL_GetPrefPath(dusk::OrgName, dusk::AppName)) + "randomizer/seeds/" + this->mHash + "/seed.dat";
}
std::vector<u8> HexToBytes(std::string hex) {
std::vector<u8> bytes;
// Strip "0x" if present
if (hex.substr(0, 2) == "0x") hex = hex.substr(2);
for (size_t i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
u8 byte = static_cast<u8>(strtol(byteString.c_str(), nullptr, 16));
bytes.push_back(byte);
}
return bytes;
}
u32 getActorPatchesCurrentStageKey() {
u32 actorPatchesStageKey{};
actorPatchesStageKey |= getStageID(dComIfGp_getStartStageName()) << 16;
actorPatchesStageKey |= dComIfGp_getStartStageRoomNo() << 8;
actorPatchesStageKey |= dComIfGp_getLayerNo();
return actorPatchesStageKey;
}
u32 getActorCRC32(stage_actor_data_class* actor) {
return zng_crc32(0, reinterpret_cast<u8*>(actor), RandomizerContext::ACTOR_CRC_SIZE);
}
@@ -2,13 +2,17 @@
#define DUSK_RANDOMIZER_CONTEXT_HPP
#include <dolphin/types.h>
#include <optional>
#include <iomanip>
#include <optional>
#include <string>
#include <sstream>
#include <unordered_map>
class RandomizerContext {
public:
static constexpr size_t ACTOR_CRC_SIZE = 30;
RandomizerContext() = default;
bool mActive{false};
@@ -26,6 +30,8 @@ public:
u8 mStartHour{0};
u8 mMapBits{};
std::unordered_map<u32, std::unordered_map<u32, std::array<u8, 30>>> mActorPatches{};
std::optional<std::string> WriteToFile();
std::optional<std::string> LoadFromHash(const std::string& hash);
std::string GetSeedDataPath() const;
@@ -35,4 +41,47 @@ RandomizerContext& randomizer_GetContext();
bool randomizer_IsActive();
/**
* Helper function to convert raw bytes of a container to a hex string
*/
template <typename T>
std::string ContainerToHexString(const T& container, bool includePrefix = true) {
std::ostringstream oss;
if (includePrefix) {
oss << "0x";
}
// Get the raw byte pointer to the start of the data
const auto* rawBytes = reinterpret_cast<const u8*>(container.data());
// Calculate total byte size (number of elements * size of each element)
size_t totalBytes = container.size() * sizeof(typename T::value_type);
oss << std::hex << std::setfill('0') << std::uppercase;
for (size_t i = 0; i < totalBytes; ++i) {
// static_cast to not u8 is necessary so oss treats it as a number, not a char
oss << std::setw(2) << static_cast<u16>(rawBytes[i]);
}
return oss.str();
}
/**
* Helper function to convert hex string to raw bytes
*/
std::vector<u8> HexToBytes(std::string hex);
/*
* Gets the current stage id, room no, and layer no in the format for a key in mActorPatches
*/
u32 getActorPatchesCurrentStageKey();
class stage_actor_data_class;
/*
* Gets the CRC32 hash of an actors name, parameters, position, and angle
*/
u32 getActorCRC32(stage_actor_data_class*);
#endif //DUSK_RANDOMIZER_CONTEXT_HPP
+4 -2
View File
@@ -99,8 +99,10 @@ int getStageID(const char* stage)
int loopCount = sizeof(allStages) / sizeof(allStages[0]);
for (int i = 0; i < loopCount; i++)
{
if (daAlink_c::checkStageName(allStages[i]))
{
// If stage is NULL, check for current stage
if (stage == NULL) {
if (daAlink_c::checkStageName(allStages[i])) return i;
} else if (strcmp(stage, allStages[i]) == 0) {
return i;
}
}
+5 -1
View File
@@ -7,5 +7,9 @@ void checkTransformFromWolf();
u8 setNextWarashibeItem();
void offWarashibeItem(u8 item);
int initCreatePlayerItem(u32 item, u32 flag, const cXyz* pos, int roomNo, const csXyz* angle, const cXyz* scale);
int getStageID(const char* stage);
/*
* Returns the ID of the passed in stage name. If no stage name is passed in, the id of the current
* stage is returned
*/
int getStageID(const char* stage = NULL);
bool playerIsOnTitleScreen();
@@ -0,0 +1,38 @@
# Patches for actors that already exist on a given map
# NOTE: Data is expressed in little endian format
# Ordon Village
F_SP103:
Room 0:
Layer 0:
# Bo's House left Door
- name: kdoor
parameters: 0x88000627
position:
x: 470.48294
y: 500.19
z: 5323.129
angle:
x: 0x0191
y: 0x3777
z: 0xFFFF
patch:
# Set angle.x to -1 so the door isn't locked
angle:
x: 0xFFFF
# Bo's House right door
- name: kdoor
parameters: 0x94000627
position:
x: 500.71118
y: 500.19
z: 5172.267
angle:
x: 0x0191
y: 0xB778
z: 0xFFFF
patch:
# Set angle.x to -1 so the door isn't locked
angle:
x: 0xFFFF