mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-09-01 16:29:55 -04:00
fix stuff relating to getting the Iron Boots chest
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user