From ef56d468c567dbd255dc6d7486a253882d2f0658 Mon Sep 17 00:00:00 2001 From: Eddoursul Date: Tue, 19 Dec 2023 16:58:36 +0100 Subject: [PATCH] Hero menu: moved handling to DLL, opens on Quick Stats hotkey, added widescreen support --- Enderal - Forgotten Stories.esm | Bin 10858413 -> 10857949 bytes SKSE/Plugins/EnderalSE.dll | 4 +- scripts/_00E_AffinityControl.pex | Bin 21926 -> 22268 bytes scripts/_00E_Func_ComputeNeededExp.pex | Bin 0 -> 1032 bytes scripts/_00e_epupdatefunctions.pex | Bin 14101 -> 12683 bytes scripts/_00e_heromenualias.pex | Bin 9293 -> 9252 bytes scripts/enderalfunctions.pex | Bin 1357 -> 1516 bytes source/Enderal DLL/CMakeLists.txt | 2 + source/Enderal DLL/src/EventListener.cpp | 14 +- source/Enderal DLL/src/Main.cpp | 2 + source/Enderal DLL/src/PapyrusFunctions.h | 9 +- .../Enderal DLL/src/Patches/HeroMenuPatch.cpp | 153 ++++++++++++++++++ .../Enderal DLL/src/Patches/HeroMenuPatch.h | 22 +++ .../src/Patches/TweenMenuPatch.cpp | 8 + .../Enderal DLL/src/Patches/TweenMenuPatch.h | 31 +--- source/Enderal DLL/src/Util.h | 26 +++ source/scripts/_00E_AffinityControl.psc | 6 + source/scripts/_00E_Func_ComputeNeededExp.psc | 54 +++++++ source/scripts/_00e_epupdatefunctions.psc | 58 +------ source/scripts/_00e_heromenualias.psc | 5 +- source/scripts/enderalfunctions.psc | 2 + 21 files changed, 302 insertions(+), 94 deletions(-) create mode 100644 scripts/_00E_Func_ComputeNeededExp.pex create mode 100644 source/Enderal DLL/src/Patches/HeroMenuPatch.cpp create mode 100644 source/Enderal DLL/src/Patches/HeroMenuPatch.h create mode 100644 source/Enderal DLL/src/Patches/TweenMenuPatch.cpp create mode 100644 source/scripts/_00E_Func_ComputeNeededExp.psc diff --git a/Enderal - Forgotten Stories.esm b/Enderal - Forgotten Stories.esm index 5fd023b5cf2ab384f244b509c9b2de9e365df3ea..69fa031e77f8282bbde23ae58c93702727467692 100644 GIT binary patch delta 541 zcmWN~XIBjX9KhjIxgum{&wi0T!p+X6LiQeIkI25Vqn}GwifhY!>D(8N(--JlI8HBo z5&sv@>*r^8Ch_-ACed1)^Q#HTkzC1>9+Hrrk}tiaw-iVp=_~!DQ2NUN87PBfundtR z87jkMxQvjIGD=3v7#S<$WV}p}Vu`3kCdwo!mB}(irph##E;D4N%#ztMN6KWb%#-<& zlyX@h3uTckmL;-OmPv&ymld*7R>^8vBWq=ytd~lul4{u?8)cK!$Y$9hTVyJ|B=_XLG>h^;((+IqNsBy|C-PLD$#ZFy7r$xi$mSN3?#i}> v_VBW^EBoqSb2^pGgxBFscpKh@_u)hM7(RuL@Hu=5U&FWXy)%{kk!<`A;-tH^ delta 801 zcmXxeNpqA{6o>J*0}%uo5X2y$K%NLHr~xChLZAagXaUJ=l<_Ge?Kl&-hNW5JX4*xa|lUD zg$$5^QYkOUAQ>z#$`BbU!z3xgWrU2Bmt>TTmX~FWydqUHR$i5HGF~RgYx25Glu0sK zswE7nkvC+DOqDm~EqPm}$#i)~-j(;HR%Xadd0*<}1DPeWWsc01c`{!X$cOTgER;o3 zFN^`~_wUgI_YzUx z>D-*CC|{-r4XMV|$Y^<{J)h3xic9jjLVG?NZAjOr7A7jA^0U6D{mF8$TuelxqNdu~ zhNkDa`fO|S&S+>fC~DZWCSA-H5+U&P>9p=B8uq-jE}6}@W%?VBhbQAz_j@Lc84|6` zwCCE2x$T8#t-r<%h@VgzA5WcAm5l#;G@>f5DDD{>|GB?ZGyB=tWz9P>P33(X)2mbc zKQec8l#J?IT3U0hg^s>`%8e-67j};G4@+C(gPo;;UAO8=K^&Y9ehq#Leh)4L7lTW| V<={$iHMkaB4{qGORd;h%$Nwb81@r&_ diff --git a/SKSE/Plugins/EnderalSE.dll b/SKSE/Plugins/EnderalSE.dll index db60213e..f3275206 100644 --- a/SKSE/Plugins/EnderalSE.dll +++ b/SKSE/Plugins/EnderalSE.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2672a34820e8f3cac71ba28296fbafb5a92142f00e847e398e4319627cc81a8b -size 737280 +oid sha256:c7bf01547071c10496b6bf64ed446f7e8ab6572b62b10aae26b34d93292b7417 +size 750080 diff --git a/scripts/_00E_AffinityControl.pex b/scripts/_00E_AffinityControl.pex index 0b662a030078b91bb9dc3513c23c77a5cf99b7d0..24b984e13815dfa5e6b8e35594fb83ced6282397 100644 GIT binary patch literal 22268 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

R%{z;Km$ZZ5|{AMKV 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 diff --git a/scripts/_00E_Func_ComputeNeededExp.pex b/scripts/_00E_Func_ComputeNeededExp.pex new file mode 100644 index 0000000000000000000000000000000000000000..5cc1c366607f62f22849b0d30dfb787aa6bb3201 GIT binary patch literal 1032 zcmb7CO>Yx15Pi;PoAe_s(9%*`-vA+^0KJeKRB43-6`}}^(bhX@jJEd5>rLp9f5D&N zjyUm4IPxPnG2TtoQi%h*8hiXae)Bxz-yeSbtX3evAASD*4ZFi$Z!kQ}jT#=<^ECH# zOcYZ*_>^|jOrbT1W1G7yPb5}o?suo!NJwn|`!pw5I3j=IBTra7vfh?%^=)pjWX%gY z)24)4)(lKs`i-%UV=`zfYhvxSHBo~4VPYeXFEfRi^kb6V`Y4gClbj}_NZud3c_2-p zUY=eQF=-NAkmFG4C{p7BOK3ugJjk6R<6jkvhw^b(z8mXIYNL`orZNLva?fZ-mdQAG z>S&^Ep2>o&i>0e{sJ=8F^^?S=gxc#o@o0`%=X0g7I&+3a;wQapz|-r%eh8 zLx)UEE=oq+tWcN?o$D<_?bsT^v(V2F!eS#Yv#IuKTwIE;Xiq}7cXgce}iFewZVX@y2r0*k#T1Lqz2r45U4JKSdF0CRxVTS3LLPpL}aLM45sbfxu zdw;8PJ~oJN=` zX!3IvjEC6+ab1!4QvMDKz$oqJZ>{o-4tjD+~HMm1wOmO`;6AFpe$?ycgxe| TSYd|UOF(dr9W*#(BSR+qQhwJ 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 F{{cDu_Y(jB literal 9293 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 Vp60I+xGS(~T4T2!^Q7(}`XAnEYvBL@ delta 596 zcmZ8dxlY4C5PfSq2N;rYB!Dpz_Z0}2Xb=sDkZ3?6LLd-Aj=g{(*vM>wM3I&@a!W_U zXYd2mbbJ8?H3eeUCgPaY?##S7_RYNM&&|1yy{A`I0RsuYeP68S7TA1!{jvVJKd#%p z=eWZ4J*$f3nd>;*gSP7XRiu`d1i!qRg}Uj9u%axiCCegky;G#E7s746?~3aRKoC-MXpNNYU|T@2j} z9jdHT(9_CLAh(?%PZpsofI$wLVZ?1zQoZCzX(3k8-?Cgv8hw9(CK%z3)>rF~!YTUn zPksUe4IqI*3}F}}7{wUI=}u6#6#f4%N%S|Wq68Yt#AIwT6eFfn1gSJ!mSLKqJQXpd j=}MG9a3+Fdl-6iqCN7sRqk&7bX%n+QAZX(z=6(TRQ)))v diff --git a/source/Enderal DLL/CMakeLists.txt b/source/Enderal DLL/CMakeLists.txt index 493c5a47..d5ae852c 100644 --- a/source/Enderal DLL/CMakeLists.txt +++ b/source/Enderal DLL/CMakeLists.txt @@ -26,6 +26,8 @@ set(sources src/Main.cpp src/EventListener.cpp src/Papyrus.cpp + src/Patches/TweenMenuPatch.cpp + src/Patches/HeroMenuPatch.cpp ${CMAKE_CURRENT_BINARY_DIR}/version.rc) diff --git a/source/Enderal DLL/src/EventListener.cpp b/source/Enderal DLL/src/EventListener.cpp index 45df00b6..bc93217c 100644 --- a/source/Enderal DLL/src/EventListener.cpp +++ b/source/Enderal DLL/src/EventListener.cpp @@ -1,4 +1,5 @@ #include "EventListener.h" +#include "Patches/HeroMenuPatch.h" auto EventListener::GetSingleton() -> EventListener* { @@ -22,9 +23,6 @@ auto EventListener::ProcessEvent( if (a_event->eventName == "Enderal_OpenHelpURL") { ShowWindow(GetForegroundWindow(), SW_MINIMIZE); ShellExecuteA(NULL, "open", "https://go.eddoursul.win/enderal-se-support", NULL, NULL, SW_SHOWNORMAL); - - //} else if (a_event->eventName == "Enderal_OpenQuestJournal") { - // RE::UIMessageQueue::GetSingleton()->AddMessage(RE::InterfaceStrings::GetSingleton()->journalMenu, RE::UI_MESSAGE_TYPE::kShow, 0i64); } return RE::BSEventNotifyControl::kContinue; @@ -49,8 +47,14 @@ auto EventListener::ProcessEvent( 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. DialogueMenuPatch::BlockTab(false); - } else if (a_event->menuName == "CustomMenu" && RE::UI::GetSingleton()->IsMenuOpen(RE::TweenMenu::MENU_NAME)) { - CloseTweenMenu(); + } else if (a_event->menuName == "CustomMenu") { + auto uiMovie = RE::UI::GetSingleton()->GetMovieView("CustomMenu"); + if (uiMovie && std::strstr(uiMovie->GetMovieDef()->GetFileURL(), "00e_heromenu.swf") != NULL) { + if (RE::UI::GetSingleton()->IsMenuOpen(RE::TweenMenu::MENU_NAME)) { + CloseTweenMenu(); + } + HeroMenuPatch::FillMenuValues(); + } } } else { if (a_event->menuName == RE::DialogueMenu::MENU_NAME) { diff --git a/source/Enderal DLL/src/Main.cpp b/source/Enderal DLL/src/Main.cpp index 3d22c370..cce768c4 100644 --- a/source/Enderal DLL/src/Main.cpp +++ b/source/Enderal DLL/src/Main.cpp @@ -8,6 +8,7 @@ #include "BinkInterruptPatch.h" #include "DialogueMenuPatch.h" #include "Patches/TweenMenuPatch.h" +#include "Patches/HeroMenuPatch.h" using namespace SKSE; @@ -170,6 +171,7 @@ SKSEPluginLoad(const LoadInterface* skse) { GetPapyrusInterface()->Register(Papyrus::Bind); DialogueMenuPatch::Install(); + HeroMenuPatch::Install(); TweenMenuPatch::Install(); if (g_settings.at("VideoInterruptPatch")) { diff --git a/source/Enderal DLL/src/PapyrusFunctions.h b/source/Enderal DLL/src/PapyrusFunctions.h index 18720627..f36360d5 100644 --- a/source/Enderal DLL/src/PapyrusFunctions.h +++ b/source/Enderal DLL/src/PapyrusFunctions.h @@ -98,6 +98,11 @@ namespace Papyrus::PapyrusFunctions DialogueMenuPatch::BlockTab(false); } + float ComputeNeededExp(RE::StaticFunctionTag*, std::uint32_t CurrentLevel, float Slope, float Mult, float fExpAcc = 1.0f, float fExpAcc_Level20 = 1.2f, float fExpAcc_Level30 = 1.5f, float fExpAcc_Level40 = 2.0f) + { + return ComputeNeededExpPoints(CurrentLevel, Slope, Mult, fExpAcc, fExpAcc_Level20, fExpAcc_Level30, fExpAcc_Level40); + } + inline void Bind(VM& a_vm) { BIND(CreatePotion); @@ -114,7 +119,7 @@ namespace Papyrus::PapyrusFunctions logger::info("{}", "Registered StringToHex"sv); BIND(DisableDialogueQuitting); logger::info("{}", "Registered DisableDialogueQuitting"sv); - BIND(EnableDialogueQuitting); - logger::info("{}", "Registered EnableDialogueQuitting"sv); + BIND(ComputeNeededExp); + logger::info("{}", "Registered ComputeNeededExp"sv); } } diff --git a/source/Enderal DLL/src/Patches/HeroMenuPatch.cpp b/source/Enderal DLL/src/Patches/HeroMenuPatch.cpp new file mode 100644 index 00000000..2120a9fa --- /dev/null +++ b/source/Enderal DLL/src/Patches/HeroMenuPatch.cpp @@ -0,0 +1,153 @@ +#include "HeroMenuPatch.h" + +RE::BSEventNotifyControl HeroMenuPatch::ProcessEvent_Hook(RE::InputEvent** a_event, RE::BSTEventSource* a_source) +{ + if (RE::UI::GetSingleton()->GameIsPaused() && a_event && *a_event) { + auto buttonEvent = (*a_event)->AsButtonEvent(); + if (buttonEvent && buttonEvent->IsDown() && RE::UI::GetSingleton()->IsMenuOpen("CustomMenu")) { + auto& eventName = (*a_event)->QUserEvent(); + auto userEvents = RE::UserEvents::GetSingleton(); + if (eventName == userEvents->cancel || eventName == userEvents->quickStats) { + auto uiMovie = RE::UI::GetSingleton()->GetMovieView("CustomMenu"); + if (uiMovie && std::strstr(uiMovie->GetMovieDef()->GetFileURL(), "00e_heromenu.swf") != NULL) { + RE::UIMessageQueue::GetSingleton()->AddMessage("CustomMenu", RE::UI_MESSAGE_TYPE::kHide, nullptr); + } + } + } + } + + return _ProcessEvent(this, a_event, a_source); +} + +void HeroMenuPatch::Install() +{ + // Patch MenuControls + REL::Relocation vTable(RE::VTABLE_MenuControls[0]); + _ProcessEvent = vTable.write_vfunc(0x1, &HeroMenuPatch::ProcessEvent_Hook); + + // Patch the Quick Stats hotkey + REL::Relocation target{ REL::RelocationID(51400, 52249), REL::Relocate(0x41E, 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(0x436, 0x439) }; + std::uint8_t code[] = { 0x40, 0xB5, 0x01 }; + REL::safe_write(target2.address(), code, sizeof(code)); +} + +uint64_t HeroMenuPatch::OpenStats(uint32_t arg_1, uint32_t arg_2, uint32_t arg_3, uint32_t arg_4, uint32_t arg_5) +{ + OpenHeroMenu(); + return 0; +} + +void HeroMenuPatch::OpenHeroMenu() +{ + RE::BSTSmartPointer stackCallback; + RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("UI", "OpenCustomMenu", RE::MakeFunctionArguments("00e_heromenu", 0), stackCallback); +} + +void HeroMenuPatch::FillMenuValues() +{ + class ScriptClassNameCallback : public RE::BSScript::IStackCallbackFunctor + { + public: + void operator()(RE::BSScript::Variable a_result) + { + auto uiMovie = RE::UI::GetSingleton()->GetMovieView("CustomMenu"); + uiMovie->SetVariable("_root.heromenu_mc.stats.playerclass.stat_value.text", a_result.GetString()); + } + bool CanSave() { return false; } + void SetObject(const RE::BSTSmartPointer&) {} + }; + + auto uiMovie = RE::UI::GetSingleton()->GetMovieView("CustomMenu"); + uiMovie->SetViewScaleMode(RE::BSScaleformManager::ScaleModeType::kShowAll); + + const auto dataHandler = RE::TESDataHandler::GetSingleton(); + RE::TESGlobal* playerLevel = dataHandler->LookupForm(0x12595, "Skyrim.esm"); + RE::TESGlobal* playerExp = dataHandler->LookupForm(0x12596, "Skyrim.esm"); + RE::TESGlobal* EXPMultSlope = dataHandler->LookupForm(0xD0EDB, "Skyrim.esm"); + RE::TESGlobal* EXPMult = dataHandler->LookupForm(0x8D2B, "Skyrim.esm"); + RE::TESGlobal* Lernpunkte = dataHandler->LookupForm(0x31ACB, "Skyrim.esm"); + RE::TESGlobal* Handwerkspunkte = dataHandler->LookupForm(0x85A79, "Skyrim.esm"); + RE::TESGlobal* TalentPoints = dataHandler->LookupForm(0x5BCFA, "Skyrim.esm"); + + auto player = RE::PlayerCharacter::GetSingleton(); + auto playerAV = player->AsActorValueOwner(); + + float fEXPNeededForCurrentLevel = ComputeNeededExpPoints(playerLevel->value - 1, EXPMultSlope->value, EXPMult->value); + float fEXPNeededForNextLevel = ComputeNeededExpPoints(playerLevel->value, EXPMultSlope->value, EXPMult->value); + + RE::GFxValue args[2]; + args[0].SetString(player->GetDisplayFullName()); + args[1].SetString(""); + uiMovie->Invoke("_root.heromenu_mc.SetStringValues", nullptr, args, 2); + + RE::BSTSmartPointer stackCallback{ new ScriptClassNameCallback }; + RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("_00E_AffinityControl", "GetPlayerClassNameGlobal", RE::MakeFunctionArguments(), stackCallback); + + RE::GFxValue args2[33]; + args2[0].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kHealth)); + args2[1].SetNumber(playerAV->GetActorValue(RE::ActorValue::kHealth)); + args2[2].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kMagicka)); + args2[3].SetNumber(playerAV->GetActorValue(RE::ActorValue::kMagicka)); + args2[4].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kStamina)); + args2[5].SetNumber(playerAV->GetActorValue(RE::ActorValue::kStamina)); + args2[6].SetNumber(-playerAV->GetActorValue(RE::ActorValue::kLastFlattered)); + args2[7].SetNumber(fEXPNeededForNextLevel); + args2[8].SetNumber(playerExp->value); + args2[9].SetNumber(playerLevel->value); + args2[10].SetNumber(Lernpunkte->value); + args2[11].SetNumber(Handwerkspunkte->value); + args2[12].SetNumber(TalentPoints->value); + args2[13].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kIllusion)); + args2[14].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kDestruction)); + args2[15].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kAlteration)); + args2[16].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kOneHanded)); + args2[17].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kBlock)); + args2[18].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kArchery)); + args2[19].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kConjuration)); + args2[20].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kRestoration)); + args2[21].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kTwoHanded)); + args2[22].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kLightArmor)); + args2[23].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kHeavyArmor)); + args2[24].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kSneak)); + args2[25].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kAlchemy)); + args2[26].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kPickpocket)); + args2[27].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kLockpicking)); + args2[28].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kEnchanting)); + args2[29].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kSmithing)); + args2[30].SetNumber(playerAV->GetBaseActorValue(RE::ActorValue::kSpeech)); + + args2[31].SetNumber(playerExp->value - fEXPNeededForCurrentLevel); + args2[32].SetNumber(fEXPNeededForNextLevel - fEXPNeededForCurrentLevel); + uiMovie->Invoke("_root.heromenu_mc.SetIntValues", nullptr, args2, 33); + + RE::GFxValue args3[21]; + args3[0].SetNumber(0); + args3[1].SetNumber(0); + args3[2].SetNumber(0); + args3[3].SetNumber(playerAV->GetActorValue(RE::ActorValue::kIllusion) - playerAV->GetBaseActorValue(RE::ActorValue::kIllusion)); + args3[4].SetNumber(playerAV->GetActorValue(RE::ActorValue::kDestruction) - playerAV->GetBaseActorValue(RE::ActorValue::kDestruction)); + args3[5].SetNumber(playerAV->GetActorValue(RE::ActorValue::kAlteration) - playerAV->GetBaseActorValue(RE::ActorValue::kAlteration)); + args3[6].SetNumber(playerAV->GetActorValue(RE::ActorValue::kOneHanded) - playerAV->GetBaseActorValue(RE::ActorValue::kOneHanded)); + args3[7].SetNumber(playerAV->GetActorValue(RE::ActorValue::kBlock) - playerAV->GetBaseActorValue(RE::ActorValue::kBlock)); + args3[8].SetNumber(playerAV->GetActorValue(RE::ActorValue::kArchery) - playerAV->GetBaseActorValue(RE::ActorValue::kArchery)); + args3[9].SetNumber(playerAV->GetActorValue(RE::ActorValue::kConjuration) - playerAV->GetBaseActorValue(RE::ActorValue::kConjuration)); + args3[10].SetNumber(playerAV->GetActorValue(RE::ActorValue::kRestoration) - playerAV->GetBaseActorValue(RE::ActorValue::kRestoration)); + args3[11].SetNumber(playerAV->GetActorValue(RE::ActorValue::kTwoHanded) - playerAV->GetBaseActorValue(RE::ActorValue::kTwoHanded)); + args3[12].SetNumber(playerAV->GetActorValue(RE::ActorValue::kLightArmor) - playerAV->GetBaseActorValue(RE::ActorValue::kLightArmor)); + args3[13].SetNumber(playerAV->GetActorValue(RE::ActorValue::kHeavyArmor) - playerAV->GetBaseActorValue(RE::ActorValue::kHeavyArmor)); + args3[14].SetNumber(playerAV->GetActorValue(RE::ActorValue::kSneak) - playerAV->GetBaseActorValue(RE::ActorValue::kSneak)); + args3[15].SetNumber(playerAV->GetActorValue(RE::ActorValue::kAlchemy) - playerAV->GetBaseActorValue(RE::ActorValue::kAlchemy)); + args3[16].SetNumber(playerAV->GetActorValue(RE::ActorValue::kPickpocket) - playerAV->GetBaseActorValue(RE::ActorValue::kPickpocket)); + args3[17].SetNumber(playerAV->GetActorValue(RE::ActorValue::kLockpicking) - playerAV->GetBaseActorValue(RE::ActorValue::kLockpicking)); + args3[18].SetNumber(playerAV->GetActorValue(RE::ActorValue::kEnchanting) - playerAV->GetBaseActorValue(RE::ActorValue::kEnchanting)); + args3[19].SetNumber(playerAV->GetActorValue(RE::ActorValue::kSmithing) - playerAV->GetBaseActorValue(RE::ActorValue::kSmithing)); + args3[20].SetNumber(playerAV->GetActorValue(RE::ActorValue::kSpeech) - playerAV->GetBaseActorValue(RE::ActorValue::kSpeech)); + uiMovie->Invoke("_root.heromenu_mc.SetModifier", nullptr, args3, 21); +} diff --git a/source/Enderal DLL/src/Patches/HeroMenuPatch.h b/source/Enderal DLL/src/Patches/HeroMenuPatch.h new file mode 100644 index 00000000..28a20779 --- /dev/null +++ b/source/Enderal DLL/src/Patches/HeroMenuPatch.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Util.h" + +class HeroMenuPatch : public RE::MenuControls +{ +public: + static void Install(); + + static uint64_t OpenStats(uint32_t arg_1, uint32_t arg_2, uint32_t arg_3, uint32_t arg_4, uint32_t arg_5); + + static void FillMenuValues(); + + static void OpenHeroMenu(); + + inline static REL::Relocation _OpenStats; + + RE::BSEventNotifyControl ProcessEvent_Hook(RE::InputEvent** a_event, RE::BSTEventSource* a_source); + + using ProcessEvent_t = decltype(static_cast*)>(&RE::MenuControls::ProcessEvent)); + static inline REL::Relocation _ProcessEvent; +}; diff --git a/source/Enderal DLL/src/Patches/TweenMenuPatch.cpp b/source/Enderal DLL/src/Patches/TweenMenuPatch.cpp new file mode 100644 index 00000000..6a8cd67b --- /dev/null +++ b/source/Enderal DLL/src/Patches/TweenMenuPatch.cpp @@ -0,0 +1,8 @@ +#include "TweenMenuPatch.h" + +void TweenMenuPatch::Install() +{ + // Patch the Tween Menu + REL::Relocation vtbl(RE::VTABLE_TweenMenu[0]); + _AcceptFn = vtbl.write_vfunc(0x1, &AcceptEx); +} diff --git a/source/Enderal DLL/src/Patches/TweenMenuPatch.h b/source/Enderal DLL/src/Patches/TweenMenuPatch.h index 6277a1e6..347a34c2 100644 --- a/source/Enderal DLL/src/Patches/TweenMenuPatch.h +++ b/source/Enderal DLL/src/Patches/TweenMenuPatch.h @@ -1,34 +1,13 @@ #pragma once +#include "HeroMenuPatch.h" + 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(0x41E, 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(0x436, 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; - } + static void Install(); private: - static void OpenMenu(RE::IMenu* tweenMenu, std::int32_t index) { using func_t = decltype(&OpenMenu); @@ -44,8 +23,7 @@ private: 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); + HeroMenuPatch::OpenHeroMenu(); } else if (index <= 4) { OpenMenu(RE::UI::GetSingleton()->GetMenu(MENU_NAME).get(), index); } @@ -53,5 +31,4 @@ private: } inline static REL::Relocation _AcceptFn; - inline static REL::Relocation _OpenStats; }; diff --git a/source/Enderal DLL/src/Util.h b/source/Enderal DLL/src/Util.h index e54a0452..83c3e9c1 100644 --- a/source/Enderal DLL/src/Util.h +++ b/source/Enderal DLL/src/Util.h @@ -178,3 +178,29 @@ inline void CloseTweenMenu() return func(); } } + +inline float ComputeNeededExpPoints(std::uint32_t CurrentLevel, float Slope, float Mult, float fExpAcc = 1.0f, float fExpAcc_Level20 = 1.2f, float fExpAcc_Level30 = 1.5f, float fExpAcc_Level40 = 2.0f) +{ + Mult *= fExpAcc; + + if (CurrentLevel <= 20) { + return pow(CurrentLevel, Slope) * Mult; + } + + float result = pow(20, Slope) * Mult; + + if (CurrentLevel <= 30) { + return result + (pow(CurrentLevel, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20; + } + + if (CurrentLevel <= 40) { + result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20; + result += (pow(CurrentLevel, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30; + return result; + } + + result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20; + result += (pow(40, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30; + result += (pow(CurrentLevel, Slope) - pow(40, Slope)) * Mult * fExpAcc_Level40; + return result; +} \ No newline at end of file diff --git a/source/scripts/_00E_AffinityControl.psc b/source/scripts/_00E_AffinityControl.psc index 78f208f0..01e87099 100644 --- a/source/scripts/_00E_AffinityControl.psc +++ b/source/scripts/_00E_AffinityControl.psc @@ -466,6 +466,12 @@ String Function GetPlayerClassName() EndIf EndFunction +String Function GetPlayerClassNameGlobal() Global +{Called by EnderalSE.dll} + Quest AffinityQuest = Game.GetFormFromFile(0x1597B, "Enderal - Forgotten Stories.esm") as Quest; + return (AffinityQuest.GetAlias(0) as _00E_AffinityControl).GetPlayerClassName() +endfunction + ;===================================================================================== ; PROPERTIES diff --git a/source/scripts/_00E_Func_ComputeNeededExp.psc b/source/scripts/_00E_Func_ComputeNeededExp.psc new file mode 100644 index 00000000..21e4bcf6 --- /dev/null +++ b/source/scripts/_00E_Func_ComputeNeededExp.psc @@ -0,0 +1,54 @@ +Scriptname _00E_Func_ComputeNeededExp Hidden + +;import Math + +float Function Run(int CurrentLevel, float Slope, float Mult, float fExpAcc = 1.0, float fExpAcc_Level20 = 1.2, float fExpAcc_Level30 = 1.5, float fExpAcc_Level40 = 2.0) Global +{Computes the total Experience (EP) needed by the player to reach the level CurrentLevel + 1. This includes the experience needed for the previous level.} + + return EnderalFunctions.ComputeNeededExp(CurrentLevel, Slope, Mult, fExpAcc, fExpAcc_Level20, fExpAcc_Level30, fExpAcc_Level40); + + ; This can be used as a quick way to scale the leveling process + ; for all levels: + ;/ + float fExpAcc = 1.0 + float fExpAcc_Level20 = 1.2 + float fExpAcc_Level30 = 1.5 + float fExpAcc_Level40 = 2.0 + + Mult *= fExpAcc + + If CurrentLevel <= 20 + ; no changes to the old formula until level 20. + return pow(CurrentLevel, Slope) * Mult + Else + ; no changes to the old formula for the first 20 levels. + float result = pow(20, Slope) * Mult + ; Progressive taxation: + if CurrentLevel <= 30 + result += (pow(CurrentLevel, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 + return result + elseif CurrentLevel <= 40 + result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 + result += (pow(CurrentLevel, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30 + return result + else + result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 + result += (pow(40, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30 + result += (pow(CurrentLevel, Slope) - pow(40, Slope)) * Mult * fExpAcc_Level40 + return result + endif + EndIf + /; +EndFunction + +; A debugging function: +;function DumpLevelCurve() +;{Dump a table of required EP for each level from 0 to 100 to the Papyrus log} +; string aua = "" +; int iIndex = 0 +; while iIndex < 100 +; aua += "To get to level " + (iIndex + 1) + ", you need " + ComputeNeededExp(iIndex, EXPMultSlope.GetValue(), EXPMult.GetValue()) + "EP. \n " +; iIndex += 1 +; endwhile +; Debug.Trace(aua) +;Endfunction diff --git a/source/scripts/_00e_epupdatefunctions.psc b/source/scripts/_00e_epupdatefunctions.psc index f6530ad4..2358b6e9 100644 --- a/source/scripts/_00e_epupdatefunctions.psc +++ b/source/scripts/_00e_epupdatefunctions.psc @@ -284,7 +284,7 @@ bool function receiveEP(int amount) iLevelUpsNeeded = iLevelUpCount _UnlockLevelUpSystem() - PlayerNeededExp.SetValue(ComputeNeededExp((PlayerLevel.GetValueInt()+iLevelUpCount), EXPMultSlope.GetValue(), EXPMult.GetValue())) + PlayerNeededExp.SetValue(_00E_Func_ComputeNeededExp.Run((PlayerLevel.GetValueInt()+iLevelUpCount), EXPMultSlope.GetValue(), EXPMult.GetValue())) int iNeededExpNextLevel = (PlayerNeededExp.GetValueInt()-PlayerExp.GetValueInt()) _00E_sEPNeeded.Show(amount, iNeededExpNextLevel) @@ -303,7 +303,7 @@ int function getLevelUpCount() While LevelCheckRequired LevelCheckRequired = false - NeededExp = ComputeNeededExp(iCurrentLevel, EXPMultSlope.GetValue(), EXPMult.GetValue()) + NeededExp = _00E_Func_ComputeNeededExp.Run(iCurrentLevel, EXPMultSlope.GetValue(), EXPMult.GetValue()) if iCurrentExp >= NeededExp LevelCheckRequired = true @@ -317,60 +317,6 @@ int function getLevelUpCount() EndFunction -float Function ComputeNeededExp(int CurrentLevel, float Slope, float Mult) -{Computes the total Experience (EP) needed by the player to reach the level CurrentLevel + 1. This includes the experience needed for the previous level.} - - ; commented out as it is useless upon the Steam releases - ; GlobalVariable _00E_FS_IsForgottenStoriesActivated = Game.GetForm(0x0004320E) as GlobalVariable - ; If _00E_FS_IsForgottenStoriesActivated.GetValueInt() == 0 - ; Pre-DLC formula: - ; return pow(CurrentLevel, Slope) * Mult - ; EndIf - - ; This can be used as a quick way to scale the leveling process - ; for all levels: - float fExpAcc = 1.0 - float fExpAcc_Level20 = 1.2 - float fExpAcc_Level30 = 1.5 - float fExpAcc_Level40 = 2.0 - - Mult *= fExpAcc - - If CurrentLevel <= 20 - ; no changes to the old formula until level 20. - return pow(CurrentLevel, Slope) * Mult - Else - ; no changes to the old formula for the first 20 levels. - float result = pow(20, Slope) * Mult - ; Progressive taxation: - if CurrentLevel <= 30 - result += (pow(CurrentLevel, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 - return result - elseif CurrentLevel <= 40 - result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 - result += (pow(CurrentLevel, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30 - return result - else - result += (pow(30, Slope) - pow(20, Slope)) * Mult * fExpAcc_Level20 - result += (pow(40, Slope) - pow(30, Slope)) * Mult * fExpAcc_Level30 - result += (pow(CurrentLevel, Slope) - pow(40, Slope)) * Mult * fExpAcc_Level40 - return result - endif - EndIf - -EndFunction - -; A debugging function: -;function DumpLevelCurve() -;{Dump a table of required EP for each level from 0 to 100 to the Papyrus log} -; string aua = "" -; int iIndex = 0 -; while iIndex < 100 -; aua += "To get to level " + (iIndex + 1) + ", you need " + ComputeNeededExp(iIndex, EXPMultSlope.GetValue(), EXPMult.GetValue()) + "EP. \n " -; iIndex += 1 -; endwhile -; Debug.Trace(aua) -;Endfunction ;===================================================================================== ; PROPERTIES diff --git a/source/scripts/_00e_heromenualias.psc b/source/scripts/_00e_heromenualias.psc index 0c5dc1a9..0380a334 100644 --- a/source/scripts/_00e_heromenualias.psc +++ b/source/scripts/_00e_heromenualias.psc @@ -1,4 +1,5 @@ Scriptname _00E_HeroMenuAlias extends ReferenceAlias Hidden +{This script is unused, hero menu handling has been moved to DLL in 2.1+.} int function _GetScriptVersion() Global return 1 @@ -99,8 +100,8 @@ Float[] Function GetFloats() int iPlayerLevel = PlayerLevel.GetValueInt() float fEXPMultSlope = EXPMultSlope.GetValue() float fEXPMult = EXPMult.GetValue() - float fEXPNeededForCurrentLevel = (PlayerREF as _00E_EPUpdateFunctions).ComputeNeededExp(iPlayerLevel - 1, fEXPMultSlope, fEXPMult) - float fEXPNeededForNextLevel = (PlayerREF as _00E_EPUpdateFunctions).ComputeNeededExp(iPlayerLevel, fEXPMultSlope, fEXPMult) + float fEXPNeededForCurrentLevel = _00E_Func_ComputeNeededExp.Run(iPlayerLevel - 1, fEXPMultSlope, fEXPMult) + float fEXPNeededForNextLevel = _00E_Func_ComputeNeededExp.Run(iPlayerLevel, fEXPMultSlope, fEXPMult) int iPlayerExp = PlayerExp.GetValueInt() SkillmenuFloats[0] = (AiHealth.GetBaseValue(PlayerREF)) as Int diff --git a/source/scripts/enderalfunctions.psc b/source/scripts/enderalfunctions.psc index 80d94a0f..541fb41d 100644 --- a/source/scripts/enderalfunctions.psc +++ b/source/scripts/enderalfunctions.psc @@ -19,6 +19,8 @@ String Function GetPlayerHash() Global Native ; RETURN - Returns the hexadecimal equivalent of the passed string. String Function StringToHex(String a_string) Global Native +float function ComputeNeededExp(int CurrentLevel, float Slope, float Mult, float fExpAcc = 1.0, float fExpAcc_Level20 = 1.2, float fExpAcc_Level30 = 1.5, float fExpAcc_Level40 = 2.0) global native + ; Disables the TAB Key during dialogue. Resets automatically upon dialogue exit via Goodbye. Function DisableDialogueQuitting() Global Native Function EnableDialogueQuitting() Global Native