Fix Golden Wolf item persistence

This commit is contained in:
Luke Street
2026-08-21 20:45:43 -06:00
parent 42805210df
commit 8f5ecdba1c
7 changed files with 82 additions and 14 deletions
+35 -13
View File
@@ -11,6 +11,7 @@
#include <mods/svc/hook.hpp>
#include <mods/svc/log.hpp>
#include <mods/items.h>
#include "c/c_damagereaction.h"
#include "d/actor/d_a_alink.h"
@@ -2812,17 +2813,33 @@ HookAction hookPreObjLifeCreate(ModContext*, void* args, void* retval, void*) {
auto goldenWolfFlags = getCurrentGoldenWolfFlags(roomNo);
// Don't spawn this item if we haven't howled at the howling stone, or if we've already
// obtained the item
if ((goldenWolfFlags.howledAtStoneFlag != 0xFFFF && !dComIfGs_isEventBit(goldenWolfFlags.howledAtStoneFlag)) ||
dComIfGs_isEventBit(goldenWolfFlags.obtainedItemFlag))
if (goldenWolfFlags.obtainedItemFlag == 0xFFFF ||
(goldenWolfFlags.howledAtStoneFlag != 0xFFFF &&
!dComIfGs_isEventBit(goldenWolfFlags.howledAtStoneFlag)) ||
dComIfGs_isEventBit(goldenWolfFlags.obtainedItemFlag) ||
!randomizer_GetContext().mGoldenWolfOverrides.contains(
goldenWolfFlags.obtainedItemFlag))
{
*static_cast<int*>(retval) = cPhs_ERROR_e;
return HOOK_SKIP_ORIGINAL;
}
// Store the map marker flag and obtained item flags to turn off/on later if
// the player collects the item
// The actor moves these placement angles into field_0x938/field_0x93a during create.
i_this->home.angle.z = goldenWolfFlags.mapMarkerFlag;
i_this->home.angle.x = static_cast<s16>(goldenWolfFlags.obtainedItemFlag);
i_this->mItemGiveOriginalNo = itemId;
i_this->mGoldenWolfItem = true;
const std::string checkName =
std::string{ITEM_CHECK_GOLDEN_WOLF_PREFIX} +
std::to_string(goldenWolfFlags.obtainedItemFlag);
if (session::svc_mng.item->resolve_check(session::svc_mng.mod_ctx, checkName.c_str(),
itemId, &itemId) != MOD_OK)
{
*static_cast<int*>(retval) = cPhs_ERROR_e;
return HOOK_SKIP_ORIGINAL;
}
fopAcM_SetParam(i_this, (params & 0xFFFFFF00) | itemId);
}
// Also adjust the height of the object depending on the item
@@ -2913,18 +2930,23 @@ HookAction hookPreObjLifeCreate(ModContext*, void* args, void* retval, void*) {
return HOOK_CONTINUE;
}
void hookPostObjLifeActionGetDemo(ModContext*, void* args, void*, void*) {
HookAction hookPreObjLifeActionGetDemo(ModContext*, void* args, void*, void*) {
auto* i_this = mods::arg<daObjLife_c*>(args, 0);
// In randomizer, turn off the map marker flag for this golden wolf replacement item
// if we're collecting it. We store the map marker flag in unused home.angle.z
// Also set the flag for having collected this golden wolf item, stored in home.angle.x
if (static_cast<u16>(i_this->home.angle.z) != 0xFFFF) {
dComIfGs_offSwitch(static_cast<u16>(i_this->home.angle.z), fopAcM_GetRoomNo(i_this));
if (!i_this->mGoldenWolfItem || !dComIfGp_evmng_endCheck("DEFAULT_GETITEM"))
{
return HOOK_CONTINUE;
}
if (static_cast<u16>(i_this->home.angle.x) != 0xFFFF) {
dComIfGs_onEventBit(static_cast<u16>(i_this->home.angle.x));
const u16 mapMarkerFlag = static_cast<u16>(i_this->field_0x93a);
const u16 obtainedItemFlag = static_cast<u16>(i_this->field_0x938);
if (mapMarkerFlag != 0xFFFF) {
dComIfGs_offSwitch(mapMarkerFlag, fopAcM_GetRoomNo(i_this));
}
if (obtainedItemFlag != 0xFFFF) {
dComIfGs_onEventBit(obtainedItemFlag);
}
return HOOK_CONTINUE;
}
HookAction hookPreObjLifeCalcScale(ModContext*, void* args, void* retval, void*) {
@@ -3231,7 +3253,7 @@ ModResult initialize() {
ADD_HOOK_PRE(daObjLife_c__setEffect, hookPreObjLifeSetEffect);
ADD_HOOK_PRE(daObjLife_c__create, hookPreObjLifeCreate);
ADD_HOOK_POST(daObjLife_c__actionGetDemo, hookPostObjLifeActionGetDemo);
ADD_HOOK_PRE(daObjLife_c__actionGetDemo, hookPreObjLifeActionGetDemo);
ADD_HOOK_PRE(daObjLife_c__calcScale, hookPreObjLifeCalcScale);
ADD_HOOK_POST(getCollectSmell, hookPostGetCollectSmell);
+16
View File
@@ -70,6 +70,19 @@ std::optional<DerivedKey> parse_derived(const char* name, std::string_view prefi
return DerivedKey{stage_id, static_cast<u16>((stage_id << 8) | (n & 0xFF))};
}
std::optional<u16> parse_flag_check(const char* name, std::string_view prefix) {
if (std::strncmp(name, prefix.data(), prefix.size()) != 0) {
return std::nullopt;
}
const char* value = name + prefix.size();
char* end = nullptr;
const unsigned long flag = std::strtoul(value, &end, 10);
if (value == end || *end != '\0' || flag > 0xFFFF) {
return std::nullopt;
}
return static_cast<u16>(flag);
}
template <typename Map>
bool lookup_override(const Map& map, u16 key, uint8_t* out_item, bool progressive) {
const auto it = map.find(key);
@@ -102,6 +115,9 @@ bool resolve_check(ModContext*, const ItemCheckInfo* info, uint8_t* out_item, vo
}
return lookup_override(ctx.mFreestandingItemOverrides, key->key, out_item, true);
}
if (auto flag = parse_flag_check(info->name, ITEM_CHECK_GOLDEN_WOLF_PREFIX)) {
return lookup_override(ctx.mGoldenWolfOverrides, *flag, out_item, true);
}
if (auto key = parse_derived(info->name, ITEM_CHECK_POE_PREFIX)) {
return lookup_override(ctx.mPoeOverrides, key->key, out_item, true);
}