201 lines
6.0 KiB
C++
201 lines
6.0 KiB
C++
#pragma once
|
|
|
|
#include "Util.h"
|
|
#include "PersistentFormManager.h"
|
|
#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;
|
|
}
|
|
|
|
RE::BSFixedString GetAutosaveName(RE::StaticFunctionTag*, std::int32_t a_index)
|
|
{
|
|
/*
|
|
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;
|
|
sstream << "Autosave0";
|
|
sstream << a_index;
|
|
sstream << "_";
|
|
sstream << GetPlayerHash().c_str();
|
|
sstream << "_0_";
|
|
sstream << StringToHex(RE::PlayerCharacter::GetSingleton()->GetName()).c_str();
|
|
sstream << "_";
|
|
|
|
// TODO: Add cell names and delete old copies, current implementation breaks rotation
|
|
/*
|
|
RE::TESObjectCELL* parentCell = RE::PlayerCharacter::GetSingleton()->parentCell;
|
|
if (parentCell->IsInteriorCell()) {
|
|
sstream << parentCell->GetFormEditorID();
|
|
} else {
|
|
sstream << RE::PlayerCharacter::GetSingleton()->GetWorldspace()->GetFormEditorID();
|
|
}
|
|
*/
|
|
sstream << "Vyn";
|
|
|
|
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)
|
|
{
|
|
if (!playerRegion) {
|
|
return false;
|
|
}
|
|
|
|
auto* parentCell = RE::PlayerCharacter::GetSingleton()->parentCell;
|
|
|
|
if (!parentCell) {
|
|
return false;
|
|
}
|
|
|
|
auto regions = parentCell->GetRegionList(false);
|
|
|
|
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);
|
|
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);
|
|
}
|
|
}
|