diff --git a/extern/aurora b/extern/aurora index 8005d336ab..1d10fa1bc5 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 8005d336ab02f0c617fc27fabbea4af42ab04caa +Subproject commit 1d10fa1bc502910a6336fdac32f31cd0ac39710d diff --git a/mods/randomizer/CMakeLists.txt b/mods/randomizer/CMakeLists.txt index 2b55767154..3496312a59 100644 --- a/mods/randomizer/CMakeLists.txt +++ b/mods/randomizer/CMakeLists.txt @@ -101,7 +101,6 @@ file(GLOB_RECURSE RANDOMIZER_DATA RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" # to both the mod and the standalone generator add_library(randomizer_embeds OBJECT) -b_embed(randomizer_embeds "res/shadow_crystal.bti") foreach (RANDOMIZER_FILE IN LISTS RANDOMIZER_DATA) if (RANDOMIZER_FILE MATCHES "^generator/data/tests") continue() diff --git a/mods/randomizer/src/hooks.cpp b/mods/randomizer/src/hooks.cpp index 864a86cd8f..ca82a24dfc 100644 --- a/mods/randomizer/src/hooks.cpp +++ b/mods/randomizer/src/hooks.cpp @@ -2,15 +2,58 @@ #include "session.hpp" #include "randomizer_context.hpp" #include "ui/rando_config.hpp" +#include "flags.h" +#include "stages.h" +#include "tools.h" +#include "item_ids.h" #include #include +#include "d/actor/d_a_alink.h" #include "d/d_file_select.h" +#include "d/d_meter2_info.h" +#include "d/d_save.h" +#include "d/d_shop_system.h" DEFINE_HOOK(&dFile_select_c::selectDataNameMove, dFile_select_c__selectDataNameMove); DEFINE_HOOK(&dFile_select_c::dataSelect, dFile_select_c__dataSelect); +DEFINE_HOOK(&dSv_event_c::isEventBit, dSv_event_c__isEventBit); +DEFINE_HOOK(&dSv_event_c::onEventBit, dSv_event_c__onEventBit); + +DEFINE_HOOK(&dSv_memBit_c::isSwitch, dSv_memBit_c__isSwitch); +DEFINE_HOOK(&dSv_memBit_c::onSwitch, dSv_memBit_c__onSwitch); +DEFINE_HOOK(&dSv_memBit_c::onDungeonItem, dSv_memBit_c__onDungeonItem); +DEFINE_HOOK(&dSv_memBit_c::offDungeonItem, dSv_memBit_c__offDungeonItem); +DEFINE_HOOK(&dSv_memBit_c::isDungeonItem, dSv_memBit_c__isDungeonItem); + +DEFINE_HOOK(&dSv_player_status_b_c::isDarkClearLV, dSv_player_status_b_c__isDarkClearLV); + +DEFINE_HOOK(&dSv_player_item_c::checkEmptyBottle, dSv_player_item_c__checkEmptyBottle); +DEFINE_HOOK(&dSv_player_item_c::setLineUpItem, dSv_player_item_c__setLineUpItem); + +DEFINE_HOOK(&dSv_info_c::onSwitch, dSv_info_c__onSwitch); + +DEFINE_HOOK(&dMsgFlow_c::query001, dMsgFlow_c__query001); +DEFINE_HOOK(&dMsgFlow_c::query022, dMsgFlow_c__query022); +DEFINE_HOOK(&dMsgFlow_c::query025, dMsgFlow_c__query025); +DEFINE_HOOK(&dMsgFlow_c::query049, dMsgFlow_c__query049); +DEFINE_HOOK(&dMsgFlow_c::event035, dMsgFlow_c__event035); + +/*DEFINE_HOOK_SYMBOL("__Z21dComIfGp_setNextStagePKcsaafjiasii", + void(char const*, s16, s8, s8, f32, u32, int, s8, s16, int, int), setNextStage);*/ + +DEFINE_HOOK_SYMBOL("daObj_Gb_Create", int(fopAc_ac_c*), ObjGb_Create); + +DEFINE_HOOK(&dMeter2Info_readItemTexture, readItemTexture); + +DEFINE_HOOK(&dShopSystem_c::seq_decide_yes, dShopSystem_c__seq_decide_yes); + +DEFINE_HOOK(&CheckFieldItemCreateHeap, dItemData_CheckFieldItemCreateHeap); + +DEFINE_HOOK(&dEvt_control_c::talkEnd, dEvt_control_c__talkEnd); + namespace randomizer::ui { dialogSelectModeState g_dialogSelectModeState = SelectReady; } @@ -18,7 +61,6 @@ dialogSelectModeState g_dialogSelectModeState = SelectReady; namespace randomizer::hooks { namespace { UiDialogHandle playModeDialog{0}; - HookAction hookPreDataSelect(ModContext*, void* args, void* retval, void* userdata) { ui::g_dialogSelectModeState = ui::SelectReady; ui::g_file_select_window_ctx.is_proceed = false; @@ -94,6 +136,493 @@ HookAction hookPreSelectDataNameMove(ModContext*, void* args, void* retval, void return HOOK_SKIP_ORIGINAL; } + + +HookAction hookPreIsEventBit(ModContext*, void* args, void* retval, void*) { + const u16 i_no = mods::arg(args, 1); + auto& out = *static_cast(retval); + + switch (i_no) { + case BO_TALKED_TO_YOU_AFTER_OPENING_IRON_BOOTS_CHEST: { + if (daAlink_c::checkStageName(allStages[Ordon_Village_Interiors])) { + out = dComIfGs_isEventBit(HEARD_BO_TEXT_AFTER_SUMO_FIGHT) ? TRUE : FALSE; + return HOOK_SKIP_ORIGINAL; + } + break; + } + case GAVE_ILIA_HER_CHARM: // Gave Ilia the charm + case CITY_OOCCOO_CS_WATCHED: // CiTS Intro CS watched + { + if (daAlink_c::checkStageName(allStages[Hidden_Village])) { + if (!dComIfGs_isEventBit(GOT_ILIAS_CHARM)) { + // If we haven't gotten the item from Impaz then we need to return false or it + // will break her dialogue. + out = FALSE; + return HOOK_SKIP_ORIGINAL; + } + } + break; + } + case GORON_MINES_CLEARED: { + if (daAlink_c::checkStageName(allStages[Goron_Mines]) || + daAlink_c::checkStageName(allStages[Death_Mountain_Interiors])) { + out = FALSE; // The gorons will not act properly if the flag is set. + return HOOK_SKIP_ORIGINAL; + } + break; + } + case ZORA_ESCORT_CLEARED: { + if (daAlink_c::checkStageName(allStages[Castle_Town])) { + // If the flag isn't set the player will be thrown into escort when they open the door + out = TRUE; + return HOOK_SKIP_ORIGINAL; + } + if (playerIsInRoomStage(0, allStages[Kakariko_Village_Interiors])) { + out = TRUE; // Return true to prevent Renado/Ilia crash after ToT + return HOOK_SKIP_ORIGINAL; + } + break; + } + case CITY_IN_THE_SKY_CLEARED: // Would like to find where this is checked and patch it there. + { + if (!dComIfGs_isEventBit(FIXED_THE_MIRROR_OF_TWILIGHT)) { + if (randomizer_GetContext().mSettings[RandomizerContext::PALACE_OF_TWILIGHT_REQUIREMENTS] != + RandomizerContext::VANILLA) { + out = FALSE; + return HOOK_SKIP_ORIGINAL; + } + } + break; + } + case HOWLED_AT_SNOWPEAK_STONE: { + if (daAlink_c::checkStageName(allStages[Snowpeak])) { + // return false so the player can howl at the stone multiple times to remove map glitch + out = FALSE; + return HOOK_SKIP_ORIGINAL; + } + break; + } + case WATCHED_CUTSCENE_AFTER_GOATS_2: { + if (playerIsInRoomStage(1, allStages[Ordon_Village_Interiors])) { + // false -> Sera gives the milk item once they help the cat; + // true -> the shop is always usable even if the cat is not returned. + out = dComIfGs_isEventBit(SERAS_CAT_RETURNED_TO_SHOP) ? FALSE : TRUE; + return HOOK_SKIP_ORIGINAL; + } + break; + } + case FIXED_THE_MIRROR_OF_TWILIGHT: { + if (daAlink_c::checkStageName(allStages[Palace_of_Twilight])) { + out = TRUE; // If the flag is not set, the player cannot leave PoT from the inside. + return HOOK_SKIP_ORIGINAL; + } + break; + } + default: + break; + } + + return HOOK_CONTINUE; +} + +HookAction hookPreOnEventBit(ModContext*, void* args, void*, void*) { + const u16 i_no = mods:: arg(args, 1); + + switch (i_no) { + // Wolf <-> Human crash patches/bug fixes: some cutscenes/events either crash or act + // weird if Link is in the wrong form and the game no longer auto-transforms once the + // Shadow Crystal has been obtained. + case ENTERED_ORDON_SPRING_DAY_3: + if (dComIfGs_isEventBit(TRANSFORMING_UNLOCKED)) { + dComIfGs_setTransformStatus(0); + } + break; + + case WATCHED_CUTSCENE_AFTER_BEING_CAPTURED_IN_FARON_TWILIGHT: + if (dComIfGs_isEventBit(TRANSFORMING_UNLOCKED)) { + dComIfGs_setTransformStatus(1); + } + break; + + case MIDNAS_DESPERATE_HOUR_COMPLETED: + dComIfGs_onDarkClearLV(3); + break; + + case CLEARED_FARON_TWILIGHT: + // If we've already cleared Eldin Twilight, Lanayru Twilight, and MDH + if (dComIfGs_isEventBit(MIDNAS_DESPERATE_HOUR_COMPLETED)) { + if (dComIfGs_isDarkClearLV(2) && dComIfGs_isDarkClearLV(3)) { + // Set the flag for the last transformed twilight; also puts Midna on the + // player's back + dComIfGs_onTransformLV(3); + dComIfGs_onDarkClearLV(3); + } + } + break; + + case CLEARED_ELDIN_TWILIGHT: + dComIfGs_onEventBit(MAP_WARPING_UNLOCKED); // in glitched logic, you can skip the gorge bridge + if (dComIfGs_isEventBit(MIDNAS_DESPERATE_HOUR_COMPLETED)) { + if (dComIfGs_isDarkClearLV(1) && dComIfGs_isDarkClearLV(3)) { + dComIfGs_onTransformLV(3); + dComIfGs_onDarkClearLV(3); + } + } + // Set flag for the bridge between Castle Town and Eldin field if skip bridge + // donation is on and both Eldin and Lanayru twilight are cleared + if (dComIfGs_isEventBit(CLEARED_LANAYRU_TWILIGHT) && + randomizer_GetContext().mSettings[RandomizerContext::SKIP_BRIDGE_DONATION] == + RandomizerContext::ON) + { + dComIfGs_onEventBit(BRIDGE_REPAIR_FUNDRAISING_COMPLETED); + dComIfGs_onStageSwitch(6, 0x1B); // Bridge exists + } + break; + + case CLEARED_LANAYRU_TWILIGHT: + if (dComIfGs_isEventBit(MIDNAS_DESPERATE_HOUR_COMPLETED)) { + if (dComIfGs_isDarkClearLV(1) && dComIfGs_isDarkClearLV(2)) { + dComIfGs_onTransformLV(3); + dComIfGs_onDarkClearLV(3); + } + } + if (dComIfGs_isEventBit(CLEARED_ELDIN_TWILIGHT) && + randomizer_GetContext().mSettings[RandomizerContext::SKIP_BRIDGE_DONATION] == + RandomizerContext::ON) + { + dComIfGs_onEventBit(BRIDGE_REPAIR_FUNDRAISING_COMPLETED); + dComIfGs_onStageSwitch(6, 0x1B); // Bridge exists + } + break; + + case REMOVE_SWORD_SHIELD_FROM_WOLF_BACK: + if (!dComIfGs_isEventBit(CLEARED_FARON_TWILIGHT)) { + dComIfGs_onTransformLV(0); // Set the last transformed twilight to include Faron + } + break; + + case GAVE_TELMA_RENADOS_LETTER: + offWarashibeItem(dItemNo_Randomizer_LETTER_e); + break; + + default: + break; + } + return HOOK_CONTINUE; +} + +HookAction hookPreMembitIsSwitch(ModContext*, void* args, void* retval, void*) { + if (getStageID() == Hidden_Village_Interiors) { + if (mods::arg(args, 1) == 0x61) { // Is Impaz in her house + *static_cast(retval) = TRUE; + return HOOK_SKIP_ORIGINAL; + } + } + return HOOK_CONTINUE; +} + +// kinda hacky check to see if this membit object is the temp memory area in save info +inline bool isTempMemBit(dSv_memBit_c* i_this) { + return i_this == &dComIfGs_getSaveInfo()->getMemory().getBit(); +} + +HookAction hookPreMembitOnSwitch(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + const int i_no = mods::arg(args, 1); + + if (isTempMemBit(i_this)) { + if (getStageID() == Arbiters_Grounds) { + // Poe flame CS trigger + if (i_no == 0x26) { + i_this->offSwitch(0x45); // Open the Poe gate + return HOOK_SKIP_ORIGINAL; + } + } else if (getStageID() == Lake_Hylia) { + // Lanayru Twilight End CS trigger + if (i_no == 0xD) { + if (dComIfGs_isEventBit(TRANSFORMING_UNLOCKED)) { + // Set player to Human as the game will not do so if Shadow Crystal has + // been obtained. + dComIfGs_setTransformStatus(0); + } + } + } else if (getStageID() == Kakariko_Village) { + // Hawkeye is for sale + if (i_no == 0x3E) { + i_this->offSwitch(0xB); // Remove the coming soon sign so the hawkeye can be bought + } + } else if (getStageID() == Hyrule_Field) { + // Destroyed North Eldin rocks barrier + if (i_no == 0x11) { + // Unlock Eldin Province on the map. Done manually rather than via + // `onRegionBit`, which would see the rocks unbroken and skip the region. + dComIfGs_getSaveData()->getPlayer().getPlayerFieldLastStayInfo().mRegion |= 0x08; + } + } + } + return HOOK_CONTINUE; +} + +HookAction hookPreOnDungeonItem(ModContext*, void* args, void*, void*) { + int i_no = mods::arg(args, 1); + + // Don't use the stage life collection flag for rando + if (i_no == dSv_memBit_c::STAGE_LIFE) { + return HOOK_SKIP_ORIGINAL; + } + // Don't turn Ooccoo into the note when defeating a boss + else if (dComIfGs_isStageBossEnemy() && i_no == dSv_memBit_c::OOCCOO_NOTE) { + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +HookAction hookPreOffDungeonItem(ModContext*, void* args, void*, void*) { + if (mods::arg(args, 1) == dSv_memBit_c::STAGE_LIFE) { + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +HookAction hookPreIsDungeonItem(ModContext*, void* args, void* retval, void*) { + const int i_no = mods::arg(args, 1); + auto& out = *static_cast(retval); + + switch (i_no) { + case dSv_memBit_c::STAGE_LIFE: + out = FALSE; + return HOOK_SKIP_ORIGINAL; + case dSv_memBit_c::STAGE_BOSS_ENEMY: { + // If we are in a dungeon or fighting a midboss, we don't want the boss being + // defeated to affect the gameplay. + std::string stageName = dComIfGp_getStartStageName(); + if (stageName.starts_with("D_MN")) { + out = FALSE; + return HOOK_SKIP_ORIGINAL; + } + break; + } + case dSv_memBit_c::STAGE_BOSS_ENEMY_2: { + // If we are in the early rooms of FT, we don't want Ook being defeated to affect + // gameplay + if (daAlink_c::checkStageName("D_MN05") && dComIfGp_roomControl_getStayNo() < 4) { + out = FALSE; + return HOOK_SKIP_ORIGINAL; + } + break; + } + default: + break; + } + return HOOK_CONTINUE; +} + +HookAction hookPreIsDarkClearLV(ModContext*, void* args, void* retval, void*) { + if (mods::arg(args, 1) == 0 && + playerIsInRoomStage(1, allStages[Ordon_Village_Interiors])) + { + // Return false so Sera will give us the bottle if we have rescued the cat. + *static_cast(retval) = FALSE; + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +HookAction hookPreCheckEmptyBottle(ModContext*, void*, void* retval, void*) { + if (getStageID() == Cave_of_Ordeals) { + // Return 1 to allow the player to collect the floor 50 reward, as this makes the + // game think the player has an empty bottle. + *static_cast(retval) = 1; + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +void hookPostSetLineUpItem(ModContext*, void* args, void*, void*) { + // Allow rando to use all item slots. Checks the loaded hash rather than + // randomizer_IsActive() because this runs on file select. + if (randomizer_GetContext().mHash.empty()) { + return; + } + + auto* i_this = mods::arg(args, 0); + if (i_this->mItems[7] == dItemNo_NONE_e) { + return; + } + + // append slot 7 after the vanilla lineup, unless already present + int slot_idx = 0; + for (; slot_idx < 24; slot_idx++) { + const u8 lineup = i_this->mItemSlots[slot_idx]; + if (lineup == 7) { + return; + } + if (lineup == 0xFF) { + break; + } + } + + if (slot_idx < 24) { + i_this->mItemSlots[slot_idx] = 7; + } +} + +HookAction hookPreSaveInfoOnSwitch(ModContext*, void* args, void*, void*) { + // Set custom flag for the Temple of Time pedestal strike + if (getStageID() == Sacred_Grove && mods::arg(args, 1) == 0xEE) { + mods::arg(args, 0)->onSwitch(0x63, mods::arg(args, 2)); + } + return HOOK_CONTINUE; +} + +HookAction hookPreQuery001(ModContext*, void* args, void* retval, void*) { + auto* node = mods::arg(args, 1); + if (node->param == 0xFA) { // MDH Completed + // Return 0 to be able to turn souls into Jovani pre MDH + if (playerIsInRoomStage(5, allStages[Castle_Town_Shops])) { + *static_cast(retval) = 0; + return HOOK_SKIP_ORIGINAL; + } + } + return HOOK_CONTINUE; +} + +HookAction hookPreQuery022(ModContext*, void* args, void* retval, void*) { + if (daAlink_c::checkStageName(allStages[Ordon_Village_Interiors])) { + auto* node = mods::arg(args, 1); + if ((node->param & 0xFF) == dItemNo_Randomizer_HVY_BOOTS_e) { + // Return false so that the door in Bo's house can be opened without the Iron Boots + *static_cast(retval) = 0; + return HOOK_SKIP_ORIGINAL; + } + } + return HOOK_CONTINUE; +} + +HookAction hookPreQuery025(ModContext*, void* args, void* retval, void*) { + // 0x4461 is the key for the red potion shop item + if (playerIsInRoomStage(3, allStages[Kakariko_Village_Interiors]) && + randomizer_GetContext().mShopOverrides.contains(0x4461)) { + // Return 0 so the player can buy the red potion item from the shop. + *static_cast(retval) = 0; + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +void hookPostQuery049(ModContext*, void*, void* retval, void*) { + // Split up getting both rewards from Jovani in randomizer + auto& out = *static_cast(retval); + if (out == 4 && !dComIfGs_isEventBit(GOT_BOTTLE_FROM_JOVANI)) { + out = 3; + } +} + +HookAction hookPreEvent035(ModContext*, void* args, void* retval, void*) { + auto* node = mods::arg(args, 1); + const u8* p = node->params; + const int prm0 = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + + if (prm0 == dItemNo_TOMATO_PUREE_e || prm0 == dItemNo_TASTE_e) { + dComIfGs_offItemFirstBit(prm0); + } else if (prm0 == dItemNo_RAFRELS_MEMO_e || prm0 == dItemNo_ASHS_SCRIBBLING_e) { + // rando: keep SLOT_19 (the items are randomized) + } else if (prm0 == dItemNo_LETTER_e || prm0 == dItemNo_BILL_e || + prm0 == dItemNo_WOOD_STATUE_e || prm0 == dItemNo_IRIAS_PENDANT_e) { + offWarashibeItem(prm0); + } + *static_cast(retval) = 1; + return HOOK_SKIP_ORIGINAL; +} + +// TODO: item service +/* HookAction hookPreExecItemGet(ModContext*, void* args, void*, void*) { + if (randomizer_IsActive()) { + const u8 item = mods::arg(args, 0); + item_funcs::exec_item_get(item); + dusk::mods::item_granted(item, mods::arg(args, 1), mods::arg(args, 2)); + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} */ + +/* HookAction hookPreCheckItemGet(ModContext*, void* args, void* retval, void*) { + if (randomizer_IsActive()) { + *static_cast(retval) = item_funcs::check_item_get(mods::arg(args, 0), mods::arg(args, 1)); + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} */ + +HookAction hookPreSetNextStage(ModContext*, void* args, void*, void*) { + randomizer_checkAndOverrideEntranceData( + mods::arg_ref(args, 0), + mods::arg_ref(args, 2), + mods::arg_ref(args, 1), + mods::arg_ref(args, 3) + ); + return HOOK_CONTINUE; +} + +HookAction hookPreObjGbCreate(ModContext*, void* args, void* retval, void*) { + if (getStageID() == StageIDs::Mirror_Chamber && !randomizer_mirrorChamberWallShouldExist()) { + *static_cast(retval) = cPhs_ERROR_e; + return HOOK_SKIP_ORIGINAL; + } + return HOOK_CONTINUE; +} + +void hookPostReadItemTexture(ModContext*, void* args, void*, void*) { + const u8 item_no = mods::arg(args, 1); + void* tex_buf1 = mods::arg(args, 2); + if (tex_buf1 == nullptr || item_no != dItemNo_Randomizer_MAGIC_LV1_e) { + return; + } + + ResourceBuffer bti = RESOURCE_BUFFER_INIT; + if (session::svc_mng.resource->load(session::svc_mng.mod_ctx, "shadow_crystal.bti", &bti) == MOD_OK) { + std::memcpy(tex_buf1, bti.data, bti.size < 0xC00 ? bti.size : 0xC00); + session::svc_mng.resource->free(session::svc_mng.mod_ctx, &bti); + } +} + +HookAction hookPreShopSeqDecideYes(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + int item_no = 0; + + if (i_this->mFlow.getEventId(&item_no) == 1 && playerIsInRoomStage(3, "R_SP109")) { + const u16 key = static_cast((getStageID() << 8) | (item_no & 0xFF)); + if (randomizer_GetContext().mShopOverrides.contains(key)) { + i_this->setSoldOutFlag(); + } + } + return HOOK_CONTINUE; +} + +HookAction hookPreCheckFieldItemCreateHeap(ModContext*, void* args, void* retval, void*) { + auto* i_this = mods::arg(args, 0); + + switch (static_cast(i_this)->getItemNo()) { + case dItemNo_Randomizer_EMPTY_BOTTLE_e: + case dItemNo_Randomizer_HALF_MILK_BOTTLE_e: + case dItemNo_Randomizer_OIL_BOTTLE3_e: + case dItemNo_Randomizer_DROP_BOTTLE_e: + case dItemNo_Randomizer_LINKS_SAVINGS_e: + case dItemNo_Randomizer_POU_SPIRIT_e: + *static_cast(retval) = CheckItemCreateHeap(i_this); + return HOOK_SKIP_ORIGINAL; + default: + return HOOK_CONTINUE; + } +} + +void hookPostTalkEnd(ModContext*, void*, void*, void*) { + if (g_randomizerState.getHasPendingToDChange()) { + g_randomizerState.setHasPendingToDChange(false); + g_randomizerState.handleTimeOfDayChange(); + } +} + } ModResult initialize() { @@ -103,9 +632,49 @@ ModResult initialize() { return MOD_ERROR; \ } +#define ADD_HOOK_POST(originalFn, hookFn) \ + if (mods::hook::add_post(hookFn) != MOD_OK) { \ + mods::log::error("Failed to add post-hook for " #originalFn); \ + return MOD_ERROR; \ + } + ADD_HOOK_PRE(dFile_select_c__selectDataNameMove, hookPreSelectDataNameMove); ADD_HOOK_PRE(dFile_select_c__dataSelect, hookPreDataSelect); + ADD_HOOK_PRE(dSv_event_c__isEventBit, hookPreIsEventBit); + ADD_HOOK_PRE(dSv_event_c__onEventBit, hookPreOnEventBit); + + ADD_HOOK_PRE(dSv_memBit_c__isSwitch, hookPreMembitIsSwitch); + ADD_HOOK_PRE(dSv_memBit_c__onSwitch, hookPreMembitOnSwitch); + ADD_HOOK_PRE(dSv_memBit_c__onDungeonItem, hookPreOnDungeonItem); + ADD_HOOK_PRE(dSv_memBit_c__offDungeonItem, hookPreOffDungeonItem); + ADD_HOOK_PRE(dSv_memBit_c__isDungeonItem, hookPreIsDungeonItem); + + ADD_HOOK_PRE(dSv_player_status_b_c__isDarkClearLV, hookPreIsDarkClearLV); + + ADD_HOOK_PRE(dSv_player_item_c__checkEmptyBottle, hookPreCheckEmptyBottle); + ADD_HOOK_POST(dSv_player_item_c__setLineUpItem, hookPostSetLineUpItem); + + ADD_HOOK_PRE(dSv_info_c__onSwitch, hookPreSaveInfoOnSwitch); + + ADD_HOOK_PRE(dMsgFlow_c__query001, hookPreQuery001); + ADD_HOOK_PRE(dMsgFlow_c__query022, hookPreQuery022); + ADD_HOOK_PRE(dMsgFlow_c__query025, hookPreQuery025); + ADD_HOOK_POST(dMsgFlow_c__query049, hookPostQuery049); + ADD_HOOK_PRE(dMsgFlow_c__event035, hookPreEvent035); + + //ADD_HOOK_PRE(setNextStage, hookPreSetNextStage); + + ADD_HOOK_PRE(ObjGb_Create, hookPreObjGbCreate); + + ADD_HOOK_POST(readItemTexture, hookPostReadItemTexture); + + ADD_HOOK_PRE(dShopSystem_c__seq_decide_yes, hookPreShopSeqDecideYes); + + ADD_HOOK_PRE(dItemData_CheckFieldItemCreateHeap, hookPreCheckFieldItemCreateHeap); + + ADD_HOOK_POST(dEvt_control_c__talkEnd, hookPostTalkEnd); + return MOD_OK; } } \ No newline at end of file