mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-20 13:24:40 -04:00
hook up item check overriding
This commit is contained in:
@@ -86,6 +86,7 @@ set(RANDOMIZER_SOURCES
|
||||
src/paths.cpp
|
||||
src/session.cpp
|
||||
src/hooks.cpp
|
||||
src/item.cpp
|
||||
src/ui/config_store.cpp
|
||||
src/ui/rando_seed_generation.cpp
|
||||
src/ui/rando_config.cpp
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "flags.h"
|
||||
#include "stages.h"
|
||||
#include "tools.h"
|
||||
#include "item.hpp"
|
||||
#include "item_ids.h"
|
||||
|
||||
#include <mods/svc/hook.hpp>
|
||||
@@ -50,7 +51,13 @@ DEFINE_HOOK(&CheckFieldItemCreateHeap, dItemData_CheckFieldItemCreateHeap);
|
||||
DEFINE_HOOK(&dEvt_control_c::talkEnd, dEvt_control_c__talkEnd);
|
||||
|
||||
DEFINE_HOOK(&dComIfG_play_c::getLayerNo_common_common, dComIfG_play_c__getLayerNo_common_common);
|
||||
DEFINE_HOOK(&dComIfGs_onStageSwitch, onStageSwitch);
|
||||
|
||||
extern void getItemFunc(u8);
|
||||
DEFINE_HOOK(&getItemFunc, dItem_getItemFunc);
|
||||
|
||||
extern int checkItemGet(u8 i_itemNo, int i_default);
|
||||
DEFINE_HOOK(&checkItemGet, dItem_checkItemGet);
|
||||
|
||||
namespace randomizer::ui {
|
||||
dialogSelectModeState g_dialogSelectModeState = SelectReady;
|
||||
@@ -482,24 +489,16 @@ HookAction hookPreSaveInfoOnSwitch(ModContext*, void* args, void*, void*) {
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
// TODO: item service
|
||||
/* HookAction hookPreExecItemGet(ModContext*, void* args, void*, void*) {
|
||||
if (randomizer_IsActive()) {
|
||||
const u8 item = mods::arg<u8>(args, 0);
|
||||
item_funcs::exec_item_get(item);
|
||||
dusk::mods::item_granted(item, mods::arg<u32>(args, 1), mods::arg<fopAc_ac_c*>(args, 2));
|
||||
return HOOK_SKIP_ORIGINAL;
|
||||
}
|
||||
return HOOK_CONTINUE;
|
||||
} */
|
||||
HookAction hookPreGetItemFunc(ModContext*, void* args, void*, void*) {
|
||||
const u8 item = mods::arg<u8>(args, 0);
|
||||
item::exec_item_get(item);
|
||||
return HOOK_SKIP_ORIGINAL;
|
||||
}
|
||||
|
||||
/* HookAction hookPreCheckItemGet(ModContext*, void* args, void* retval, void*) {
|
||||
if (randomizer_IsActive()) {
|
||||
*static_cast<int*>(retval) = item_funcs::check_item_get(mods::arg<u8>(args, 0), mods::arg<int>(args, 1));
|
||||
return HOOK_SKIP_ORIGINAL;
|
||||
}
|
||||
return HOOK_CONTINUE;
|
||||
} */
|
||||
HookAction hookPreCheckItemGet(ModContext*, void* args, void* retval, void*) {
|
||||
*static_cast<int*>(retval) = item::check_item_get(mods::arg<u8>(args, 0), mods::arg<int>(args, 1));
|
||||
return HOOK_SKIP_ORIGINAL;
|
||||
}
|
||||
|
||||
HookAction hookPreSetNextStage(ModContext*, void* args, void*, void*) {
|
||||
randomizer_checkAndOverrideEntranceData(
|
||||
@@ -1161,6 +1160,19 @@ HookAction hookPreGetLayerNo(ModContext*, void* args, void* retval, void*) {
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
HookAction hookPreOnStageSwitch(ModContext*, void* args, void* retval, void*) {
|
||||
const int i_stageNo = mods::arg<int>(args, 0);
|
||||
const int i_no = mods::arg<int>(args, 1);
|
||||
|
||||
// Avoid trying to get the save table if stag info is NULL
|
||||
if (dComIfGp_getStageStagInfo() == NULL) {
|
||||
dComIfGs_onSaveSwitch(i_stageNo, i_no);
|
||||
return HOOK_SKIP_ORIGINAL;
|
||||
}
|
||||
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ModResult initialize() {
|
||||
@@ -1211,6 +1223,11 @@ ModResult initialize() {
|
||||
|
||||
ADD_HOOK_PRE(dComIfG_play_c__getLayerNo_common_common, hookPreGetLayerNo);
|
||||
|
||||
ADD_HOOK_PRE(dItem_getItemFunc, hookPreGetItemFunc);
|
||||
ADD_HOOK_PRE(dItem_checkItemGet, hookPreCheckItemGet);
|
||||
|
||||
ADD_HOOK_PRE(onStageSwitch, hookPreOnStageSwitch);
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
namespace randomizer::item {
|
||||
void exec_item_get(u8 item_no);
|
||||
int check_item_get(u8 item_no, int param);
|
||||
|
||||
void apply_item_data_tables();
|
||||
void restore_item_data_tables();
|
||||
} // namespace randomizer::item
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "mods/service.hpp"
|
||||
#include "mods/svc/log.h"
|
||||
|
||||
#include "hooks.hpp"
|
||||
#include "item.hpp"
|
||||
#include "session.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
#include "hooks.hpp"
|
||||
|
||||
DEFINE_MOD();
|
||||
IMPORT_SERVICE(HostService, svc_host);
|
||||
@@ -14,6 +15,7 @@ IMPORT_SERVICE(ResourceService, svc_res);
|
||||
IMPORT_SERVICE(ConfigService, svc_config);
|
||||
IMPORT_SERVICE(SaveService, svc_save);
|
||||
IMPORT_SERVICE(StageService, svc_stage);
|
||||
IMPORT_SERVICE(ItemService, svc_item);
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -28,6 +30,7 @@ MOD_EXPORT ModResult mod_initialize(ModError* error) {
|
||||
svc_config,
|
||||
svc_save,
|
||||
svc_stage,
|
||||
svc_item,
|
||||
});
|
||||
if (result != MOD_OK) {
|
||||
return mods::set_error(error, result, "failed to initialize session");
|
||||
@@ -54,6 +57,7 @@ MOD_EXPORT ModResult mod_update(ModError*) {
|
||||
|
||||
MOD_EXPORT ModResult mod_shutdown(ModError*) {
|
||||
svc_log->info(mod_ctx, "randomizer unloaded");
|
||||
randomizer::item::restore_item_data_tables();
|
||||
return MOD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "item_ids.h"
|
||||
#include "tools.h"
|
||||
#include "stages.h"
|
||||
#include "item.hpp"
|
||||
#include "verify_item_functions.h"
|
||||
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_item.h"
|
||||
@@ -21,7 +23,118 @@ ModResult initialize(const ServiceManager& services) {
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ItemCheckHandle s_check_resolver{};
|
||||
ItemGiveHandle s_check_observer{};
|
||||
|
||||
struct DerivedKey {
|
||||
int stage_id;
|
||||
u16 key;
|
||||
};
|
||||
|
||||
std::optional<DerivedKey> parse_derived(const char* name, std::string_view prefix) {
|
||||
if (std::strncmp(name, prefix.data(), prefix.size()) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const char* stage_begin = name + prefix.size();
|
||||
const char* stage_end = std::strchr(stage_begin, ':');
|
||||
if (stage_end == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const std::string stage{stage_begin, stage_end};
|
||||
const int stage_id = getStageID(stage.c_str());
|
||||
if (stage_id < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const int n = std::atoi(stage_end + 1);
|
||||
return DerivedKey{stage_id, static_cast<u16>((stage_id << 8) | (n & 0xFF))};
|
||||
}
|
||||
|
||||
template <typename Map>
|
||||
bool lookup_override(const Map& map, u16 key, uint8_t* out_item, bool progressive) {
|
||||
const auto it = map.find(key);
|
||||
if (it == map.end()) {
|
||||
return false;
|
||||
}
|
||||
*out_item = progressive ? static_cast<uint8_t>(verifyProgressiveItem(it->second)) : it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool resolve_check(ModContext*, const ItemCheckInfo* info, uint8_t* out_item, void*) {
|
||||
auto& ctx = randomizer_GetContext();
|
||||
|
||||
if (auto it = ctx.mItemLocations.find(info->name); it != ctx.mItemLocations.end()) {
|
||||
*out_item = static_cast<uint8_t>(it->second.itemId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto key = parse_derived(info->name, "chest:")) {
|
||||
return lookup_override(ctx.mTreasureChestOverrides, key->key, out_item, false);
|
||||
}
|
||||
if (auto key = parse_derived(info->name, "freestanding:")) {
|
||||
if (key->stage_id == Ook) {
|
||||
if (auto it = ctx.mItemLocations.find("Forest Temple Gale Boomerang");
|
||||
it != ctx.mItemLocations.end()) {
|
||||
*out_item = static_cast<uint8_t>(verifyProgressiveItem(it->second.itemId));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return lookup_override(ctx.mFreestandingItemOverrides, key->key, out_item, true);
|
||||
}
|
||||
if (auto key = parse_derived(info->name, "poe:")) {
|
||||
return lookup_override(ctx.mPoeOverrides, key->key, out_item, false);
|
||||
}
|
||||
if (auto key = parse_derived(info->name, "shop:")) {
|
||||
return lookup_override(ctx.mShopOverrides, key->key, out_item, true);
|
||||
}
|
||||
if (auto key = parse_derived(info->name, "sky:")) {
|
||||
return lookup_override(ctx.mSkyCharacterOverrides, key->key, out_item, true);
|
||||
}
|
||||
|
||||
if (std::strncmp(info->name, "bug:", 4) == 0) {
|
||||
const u8 insect = static_cast<u8>(std::atoi(info->name + 4));
|
||||
if (auto it = ctx.mBugRewardOverrides.find(insect); it != ctx.mBugRewardOverrides.end()) {
|
||||
*out_item = static_cast<uint8_t>(verifyProgressiveItem(it->second));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void observe_give(ModContext*, const ItemGiveInfo* info, void*) {
|
||||
if (info->check_name == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& ctx = randomizer_GetContext();
|
||||
if (ctx.mItemLocations.contains(info->check_name)) {
|
||||
randomizer_setTempFlagForLocation(info->check_name);
|
||||
}
|
||||
|
||||
if (std::strcmp(info->check_name, "Arbiters Grounds Dungeon Reward") == 0) {
|
||||
dComIfGs_onItem(0x9E, -1);
|
||||
} else if (auto key = parse_derived(info->check_name, "freestanding:");
|
||||
key && key->stage_id == Ook)
|
||||
{
|
||||
dComIfGs_onItem(0x9D, -1);
|
||||
randomizer_setTempFlagForLocation("Forest Temple Gale Boomerang");
|
||||
}
|
||||
}
|
||||
|
||||
void activateSeed() {
|
||||
auto& ctx = randomizer_GetContext();
|
||||
|
||||
item::apply_item_data_tables();
|
||||
|
||||
svc_mng.item->set_check_resolver(mod_ctx, nullptr, resolve_check, nullptr, &s_check_resolver);
|
||||
svc_mng.item->observe_gives(mod_ctx, observe_give, nullptr, &s_check_observer);
|
||||
}
|
||||
|
||||
void setupRandomizerFile() {
|
||||
activateSeed();
|
||||
|
||||
// Setup file based on randomizer data
|
||||
auto& randoData = randomizer_GetContext();
|
||||
randoData.mCreatingSave = true;
|
||||
@@ -46,22 +159,22 @@ void setupRandomizerFile() {
|
||||
{
|
||||
dComIfGs_onDarkClearLV(0);
|
||||
dComIfGs_setLightDropNum(0, 0x10);
|
||||
execItemGet(dItemNo_Randomizer_DROP_CONTAINER_e);
|
||||
execItemGet(dItemNo_Randomizer_WEAR_KOKIRI_e);
|
||||
item::exec_item_get(dItemNo_Randomizer_DROP_CONTAINER_e);
|
||||
item::exec_item_get(dItemNo_Randomizer_WEAR_KOKIRI_e);
|
||||
}
|
||||
|
||||
if (dComIfGs_isEventBit(CLEARED_ELDIN_TWILIGHT))
|
||||
{
|
||||
dComIfGs_onDarkClearLV(1);
|
||||
dComIfGs_setLightDropNum(1, 0x10);
|
||||
execItemGet(dItemNo_Randomizer_DROP_CONTAINER02_e);
|
||||
item::exec_item_get(dItemNo_Randomizer_DROP_CONTAINER02_e);
|
||||
}
|
||||
|
||||
if (dComIfGs_isEventBit(CLEARED_LANAYRU_TWILIGHT))
|
||||
{
|
||||
dComIfGs_onDarkClearLV(2);
|
||||
dComIfGs_setLightDropNum(2, 0x10);
|
||||
execItemGet(dItemNo_Randomizer_DROP_CONTAINER03_e);
|
||||
item::exec_item_get(dItemNo_Randomizer_DROP_CONTAINER03_e);
|
||||
}
|
||||
|
||||
if (randoData.mSettings[RandomizerContext::SKIP_MINOR_CUTSCENES] == RandomizerContext::ON)
|
||||
@@ -90,7 +203,7 @@ void setupRandomizerFile() {
|
||||
|
||||
// Set starting inventory
|
||||
for (const auto& itemId: randoData.mStartingInventory) {
|
||||
execItemGet(itemId);
|
||||
item::exec_item_get(itemId);
|
||||
}
|
||||
|
||||
g_randomizerState = RandomizerState();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "mods/svc/resource.h"
|
||||
#include "mods/svc/save.h"
|
||||
#include "mods/svc/stage.h"
|
||||
#include "mods/svc/item.h"
|
||||
|
||||
namespace randomizer::session {
|
||||
struct ServiceManager {
|
||||
@@ -20,6 +21,7 @@ struct ServiceManager {
|
||||
const ConfigService* config;
|
||||
const SaveService* save;
|
||||
const StageService* stage;
|
||||
const ItemService* item;
|
||||
};
|
||||
|
||||
extern ServiceManager svc_mng;
|
||||
|
||||
+4
-1
@@ -269,7 +269,10 @@ static void (*item_func_ptr[256])() = {
|
||||
item_func_noentry,
|
||||
};
|
||||
|
||||
inline void getItemFunc(u8 i_itemNo) {
|
||||
#if !TARGET_PC
|
||||
inline
|
||||
#endif
|
||||
void getItemFunc(u8 i_itemNo) {
|
||||
dComIfGs_onItemFirstBit(i_itemNo);
|
||||
item_func_ptr[i_itemNo]();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user