Hero Menu via Skills in the Tween Menu

This commit is contained in:
Eddoursul 2023-12-15 21:39:41 +01:00
parent 467852f52e
commit 9f95c8e68e
10 changed files with 67 additions and 9 deletions

BIN
SKSE/Plugins/EnderalSE.dll (Stored with Git LFS)

Binary file not shown.

BIN
interface/tweenmenu.swf (Stored with Git LFS)

Binary file not shown.

BIN
scripts/_00e_heromenu.pex Normal file

Binary file not shown.

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Util.h"
inline bool bTabBlocked = false; inline bool bTabBlocked = false;
class DialogueMenuPatch final : public RE::DialogueMenu class DialogueMenuPatch final : public RE::DialogueMenu
@ -7,8 +9,6 @@ class DialogueMenuPatch final : public RE::DialogueMenu
public: public:
static void Install() static void Install()
{ {
REL::Relocation<std::uintptr_t> OpenJournalMenuFunc{ 0x0092412C };
REL::Relocation<uintptr_t> vtbl(RE::VTABLE_DialogueMenu[0]); REL::Relocation<uintptr_t> vtbl(RE::VTABLE_DialogueMenu[0]);
_ProcessMessageFn = vtbl.write_vfunc(0x4, &ProcessMessageEx); _ProcessMessageFn = vtbl.write_vfunc(0x4, &ProcessMessageEx);
} }

View File

@ -1,7 +1,4 @@
#include "EventListener.h" #include "EventListener.h"
#include "Util.h"
#include "DialogueMenuPatch.h"
#include <shellapi.h>
auto EventListener::GetSingleton() -> EventListener* auto EventListener::GetSingleton() -> EventListener*
{ {
@ -52,6 +49,8 @@ auto EventListener::ProcessEvent(
if (a_event->menuName == RE::DialogueMenu::MENU_NAME) { if (a_event->menuName == RE::DialogueMenu::MENU_NAME) {
// Make sure Tab is not blocked. If it should be, a Papyrus script will block it a few frames later. // Make sure Tab is not blocked. If it should be, a Papyrus script will block it a few frames later.
DialogueMenuPatch::BlockTab(false); DialogueMenuPatch::BlockTab(false);
} else if (a_event->menuName == "CustomMenu") {
CloseTweenMenu();
} }
} else { } else {
if (a_event->menuName == RE::DialogueMenu::MENU_NAME) { if (a_event->menuName == RE::DialogueMenu::MENU_NAME) {

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include "DialogueMenuPatch.h"
#include "Util.h"
#include <shellapi.h>
class EventListener : class EventListener :
public RE::BSTEventSink<SKSE::ModCallbackEvent>, public RE::BSTEventSink<SKSE::ModCallbackEvent>,
public RE::BSTEventSink<RE::TESContainerChangedEvent>, public RE::BSTEventSink<RE::TESContainerChangedEvent>,

View File

@ -7,6 +7,7 @@
#include "AchievementFix.h" #include "AchievementFix.h"
#include "BinkInterruptPatch.h" #include "BinkInterruptPatch.h"
#include "DialogueMenuPatch.h" #include "DialogueMenuPatch.h"
#include "Patches/TweenMenuPatch.h"
using namespace SKSE; using namespace SKSE;
@ -169,6 +170,7 @@ SKSEPluginLoad(const LoadInterface* skse) {
GetPapyrusInterface()->Register(Papyrus::Bind); GetPapyrusInterface()->Register(Papyrus::Bind);
DialogueMenuPatch::Install(); DialogueMenuPatch::Install();
TweenMenuPatch::Install();
if (g_settings.at("VideoInterruptPatch")) { if (g_settings.at("VideoInterruptPatch")) {
logger::info("Making videos interruptible..."); logger::info("Making videos interruptible...");

View File

@ -0,0 +1,39 @@
#pragma once
inline void OpenMenu(RE::IMenu* tweenMenu, std::int32_t index)
{
using func_t = decltype(&OpenMenu);
REL::Relocation<func_t> func{ REL::RelocationID(51845, 51845) };
return func(tweenMenu, index);
}
class TweenMenuPatch final : public RE::TweenMenu
{
public:
static void Install()
{
REL::Relocation<uintptr_t> vtbl(RE::VTABLE_TweenMenu[0]);
_AcceptFn = vtbl.write_vfunc(0x1, &AcceptEx);
}
private:
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) {
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("_00E_HeroMenu", "Show", RE::MakeFunctionArguments(), stackCallback);
} else if (index <= 4) {
OpenMenu(RE::UI::GetSingleton()->GetMenu(MENU_NAME).get(), index);
}
});
}
using AcceptFn = decltype(&Accept);
inline static REL::Relocation<AcceptFn> _AcceptFn;
};

View File

@ -172,3 +172,12 @@ inline void OpenJournal(bool a_bool)
REL::Relocation<func_t> func{ REL::RelocationID(52428, 53327) }; REL::Relocation<func_t> func{ REL::RelocationID(52428, 53327) };
return func(a_bool); return func(a_bool);
} }
inline void CloseTweenMenu()
{
if (RE::UI::GetSingleton()->IsMenuOpen(RE::TweenMenu::MENU_NAME)) {
using func_t = decltype(&CloseTweenMenu);
REL::Relocation<func_t> func{ REL::RelocationID(51839, 52711) };
return func();
}
}

View File

@ -0,0 +1,5 @@
Scriptname _00E_HeroMenu Hidden
function Show() Global
((Game.GetForm(0x10AA2) as Quest).GetAlias(0) as _00E_Game_SkillmenuSC).OpenSkillmenu()
endfunction