#pragma once class TweenMenuPatch final : public RE::TweenMenu { public: static void Install() { REL::Relocation vtbl(RE::VTABLE_TweenMenu[0]); _AcceptFn = vtbl.write_vfunc(0x1, &AcceptEx); REL::Relocation target{ REL::RelocationID(51400, 52249), REL::Relocate(0x409, 0x421) }; REL::safe_fill(target.address(), REL::NOP, 45); auto& trampoline = SKSE::GetTrampoline(); SKSE::AllocTrampoline(14); _OpenStats = trampoline.write_call<5>(target.address(), OpenStats); REL::Relocation target2{ REL::RelocationID(51400, 52249), REL::Relocate(0x409, 0x439) }; std::uint8_t code[] = { 0x40, 0xB5, 0x01 }; REL::safe_write(target2.address(), code, sizeof(code)); } static uint64_t OpenStats(uint32_t arg_1, uint32_t arg_2, uint32_t arg_3, uint32_t arg_4, uint32_t arg_5) { SKSE::ModCallbackEvent modEvent{ "Enderal_OpenHeroMenu", "", 0.0f, nullptr }; SKSE::GetModCallbackEventSource()->SendEvent(&modEvent); return 0; } private: static void OpenMenu(RE::IMenu* tweenMenu, std::int32_t index) { using func_t = decltype(&OpenMenu); REL::Relocation func{ REL::RelocationID(51845, 52718) }; return func(tweenMenu, index); } void AcceptEx(CallbackProcessor* a_cbReg) { _AcceptFn(this, a_cbReg); fxDelegate->callbacks.Remove("OpenHighlightedMenu"); a_cbReg->Process("OpenHighlightedMenu", [](const RE::FxDelegateArgs& args) { auto index = args[0].GetSInt(); if (index <= 1) { SKSE::ModCallbackEvent modEvent{ "Enderal_OpenHeroMenu", "", 0.0f, nullptr }; SKSE::GetModCallbackEventSource()->SendEvent(&modEvent); } else if (index <= 4) { OpenMenu(RE::UI::GetSingleton()->GetMenu(MENU_NAME).get(), index); } }); } inline static REL::Relocation _AcceptFn; inline static REL::Relocation _OpenStats; };