enderalse/source/Enderal DLL/src/PapyrusFunctions.h

201 lines
6.0 KiB
C
Raw Normal View History

#pragma once
#include "Util.h"
#include "PersistentFormManager.h"
2023-12-21 11:41:08 +00:00
#include "Patches/DialogueMenuPatch.h"
namespace Papyrus::PapyrusFunctions
{
inline RE::AlchemyItem* CreatePotion(RE::StaticFunctionTag*, std::vector<RE::EffectSetting*> effects, std::vector<float> magnitudes, std::vector<uint32_t> areas, std::vector<uint32_t> durations, uint32_t arraySize)
{
RE::AlchemyItem* result = NULL;
if (effects.size() >= arraySize && magnitudes.size() >= arraySize && areas.size() >= arraySize && durations.size() >= arraySize) {
RE::tArray<RE::Effect> effectItems;
effectItems.Allocate(effects.size());
uint16_t count = 0;
for (uint16_t i = 0; i < effects.size(); ++i) {
if (effects[i]) {
effectItems[i].baseEffect = effects[i];
effectItems[i].effectItem.duration = durations[i];
effectItems[i].effectItem.magnitude = magnitudes[i];
effectItems[i].effectItem.area = areas[i];
count++;
}
}
effectItems.count = count;
RE::PersistentFormManager::GetSingleton()->CreatePotion(&result, &effectItems);
effectItems.Clear();
} else {
logger::warn("Illegal arrays for creating a potion");
}
return result;
}
inline uint8_t GetNewGameCount(RE::StaticFunctionTag*)
{
return NewGameCount();
}
inline RE::TESObjectREFR* GetCurrentContainer(RE::StaticFunctionTag*)
{
const auto handle = RE::ContainerMenu::GetTargetRefHandle();
const auto refr = RE::TESObjectREFR::LookupByHandle(handle);
return refr ? refr.get() : nullptr;
}
inline std::vector<RE::Actor*> GetPlayerFollowers(RE::StaticFunctionTag*)
{
std::vector<RE::Actor*> result;
if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) {
for (auto& actorHandle : processLists->highActorHandles) {
if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate() && !actor->IsDead() && !actor->IsDisabled()) {
result.push_back(actor.get());
}
}
}
return result;
}
2024-01-24 17:12:06 +00:00
RE::BSFixedString GetAutosaveName(RE::StaticFunctionTag*, std::int32_t a_index)
{
2024-01-24 17:12:06 +00:00
/*
Save Name Structure (from NQS NamedQuicksaves by Ryan McKenzie)
Save3_0C2D58E2_0_507269736F6E6572_Tamriel_000002_20180503063315_4_1.ess
Save3: Type and index of save
0C2D58E2: Unique hash used to identify your save profile. Regenerated on closing racemenu.
0: Flag for modded game.
507269736F6E6572: Character name in hex.
Tamriel: coc code.
000002: Days, hours, minutes played.
20180503063315: Year, month, day, hour, minute, second in GMT + 0.
4: Player level.
1: Unknown flag.
*/
std::stringstream sstream;
2024-01-24 17:12:06 +00:00
sstream << "Autosave0";
sstream << a_index;
sstream << "_";
sstream << GetPlayerHash().c_str();
sstream << "_0_";
sstream << StringToHex(RE::PlayerCharacter::GetSingleton()->GetName()).c_str();
sstream << "_";
2024-01-26 22:10:06 +00:00
// TODO: Add cell names and delete old copies, current implementation breaks rotation
/*
2024-01-24 17:12:06 +00:00
RE::TESObjectCELL* parentCell = RE::PlayerCharacter::GetSingleton()->parentCell;
if (parentCell->IsInteriorCell()) {
sstream << parentCell->GetFormEditorID();
} else {
sstream << RE::PlayerCharacter::GetSingleton()->GetWorldspace()->GetFormEditorID();
}
2024-01-26 22:10:06 +00:00
*/
sstream << "Vyn";
2024-01-24 17:12:06 +00:00
sstream << "_000000_00000000000000_1_1";
return sstream.str();
}
void DisableDialogueQuitting(RE::StaticFunctionTag*)
{
DialogueMenuPatch::BlockTab();
}
void EnableDialogueQuitting(RE::StaticFunctionTag*)
{
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);
}
bool IsInRegion(RE::StaticFunctionTag*, RE::TESForm* playerRegion)
{
2024-01-15 21:16:23 +00:00
if (!playerRegion) {
return false;
}
auto* parentCell = RE::PlayerCharacter::GetSingleton()->parentCell;
if (!parentCell) {
return false;
}
auto regions = parentCell->GetRegionList(false);
2024-01-15 21:16:23 +00:00
if (regions) {
for (auto it = regions->begin(); it != regions->end(); it++) {
if ((*it) && (*it)->formID == playerRegion->formID) {
return true;
}
}
}
return false;
}
uint32_t MoveItemsToCountByKeyword(RE::StaticFunctionTag*, RE::TESObjectREFR* a_sourceRef, RE::TESObjectREFR* a_targetRef, RE::BGSKeyword* a_keyword, uint32_t a_count = 1)
{
const auto inv = a_sourceRef->GetInventory([&](RE::TESBoundObject& a_exform) {
auto miscItem = a_exform.As<RE::TESObjectMISC>();
return miscItem && miscItem->HasKeyword(a_keyword);
});
uint32_t iResult = 0;
for (const auto& item : inv) {
if (item.second.first > 0) {
int32_t iMoveCount = a_count - GetItemCount(a_targetRef, item.first);
if (iMoveCount > 0) {
a_sourceRef->RemoveItem(item.first, iMoveCount, RE::ITEM_REMOVE_REASON::kStoreInContainer, nullptr, a_targetRef);
iResult += iMoveCount;
}
}
}
/*
auto inventory_menu = RE::UI::GetSingleton()->GetMenu<RE::InventoryMenu>();
if (inventory_menu) {
inventory_menu->GetRuntimeData().itemList->Update();
}
*/
return iResult;
}
inline void Bind(VM& a_vm)
{
BIND(CreatePotion);
logger::info("{}", "Registered CreatePotion"sv);
BIND(GetNewGameCount);
logger::info("{}", "Registered GetNewGameCount"sv);
BIND(GetCurrentContainer);
logger::info("{}", "Registered GetCurrentContainer"sv);
BIND(GetPlayerFollowers);
logger::info("{}", "Registered GetPlayerFollowers"sv);
2024-01-24 17:12:06 +00:00
BIND(GetAutosaveName);
logger::info("{}", "Registered GetAutosaveName"sv);
BIND(DisableDialogueQuitting);
logger::info("{}", "Registered DisableDialogueQuitting"sv);
BIND(EnableDialogueQuitting);
logger::info("{}", "Registered EnableDialogueQuitting"sv);
BIND(ComputeNeededExp);
logger::info("{}", "Registered ComputeNeededExp"sv);
BIND(IsInRegion);
logger::info("{}", "Registered IsInRegion"sv);
BIND(MoveItemsToCountByKeyword);
logger::info("{}", "Registered MoveItemsToCountByKeyword"sv);
}
}