parent
a7229e0bea
commit
f312441f13
20 changed files with 834 additions and 751 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,164 +1,91 @@ |
||||
#pragma once |
||||
|
||||
#include "ArtifactTracker.h" |
||||
#include "Util.h" |
||||
|
||||
namespace Papyrus::PapyrusFunctions |
||||
{ |
||||
inline std::int32_t AddAllFormsToList(RE::StaticFunctionTag*, |
||||
RE::BGSListForm* a_targetList, |
||||
short a_formType, |
||||
RE::BGSListForm* a_storedList, |
||||
RE::BGSListForm* a_foundList) |
||||
constexpr bool IsLoaded(RE::StaticFunctionTag*) |
||||
{ |
||||
const auto formType = static_cast<RE::FormType>(a_formType); |
||||
|
||||
switch (formType) { |
||||
|
||||
case RE::FormType::Book: |
||||
for (auto const& item : ArtifactTracker::validBooks) { |
||||
if (!a_storedList->HasForm(item.second) && !a_foundList->HasForm(item.second)) { |
||||
a_targetList->AddForm(item.second); |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case RE::FormType::Misc: |
||||
for (auto const& item : ArtifactTracker::validMisc) { |
||||
if (!a_storedList->HasForm(item.second) && !a_foundList->HasForm(item.second)) { |
||||
a_targetList->AddForm(item.second); |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case RE::FormType::None: |
||||
break; |
||||
|
||||
default: |
||||
const auto dataHandler = RE::TESDataHandler::GetSingleton(); |
||||
|
||||
if (!dataHandler) { |
||||
return a_targetList->forms.size(); |
||||
} |
||||
return ArtifactTracker::g_bLoaded; |
||||
} |
||||
|
||||
for (const auto& form : dataHandler->GetFormArray(formType)) { |
||||
if (!form || !form->GetPlayable()) { |
||||
continue; |
||||
} |
||||
if (a_storedList->HasForm(form) || a_foundList->HasForm(form)) { |
||||
continue; |
||||
} |
||||
a_targetList->AddForm(form); |
||||
} |
||||
} |
||||
inline RE::TESObjectREFR* GetCellStorage(RE::StaticFunctionTag*) |
||||
{ |
||||
return ArtifactTracker::g_cellStorage; |
||||
} |
||||
|
||||
return a_targetList->forms.size(); |
||||
inline void SyncCellStorage(RE::StaticFunctionTag*, RE::FormID skipRefID = NULL) |
||||
{ |
||||
ArtifactTracker::SyncCellStorage(skipRefID); |
||||
} |
||||
|
||||
inline std::int32_t AddArtifactsToList(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, |
||||
RE::TESForm* a_refOrList, |
||||
RE::BGSListForm* a_targetList, |
||||
RE::BGSListForm* a_excludeList = NULL) |
||||
// From po3's Papyrus Extender
|
||||
inline std::vector<RE::Actor*> GetPlayerFollowers(RE::StaticFunctionTag*) |
||||
{ |
||||
if (!a_refOrList) { |
||||
a_vm->TraceStack("a_refOrList in AddArtifactsToList is None", a_stackID); |
||||
return 0; |
||||
} |
||||
if (!a_targetList) { |
||||
a_vm->TraceStack("a_targetList in AddArtifactsToList is None", a_stackID); |
||||
return 0; |
||||
} |
||||
std::vector<RE::Actor*> result; |
||||
|
||||
if (a_refOrList->Is(RE::FormType::FormList)) { |
||||
a_refOrList->As<RE::BGSListForm>()->ForEachForm([&](RE::TESForm& a_exform) { |
||||
const auto refrItem = a_exform.As<RE::TESObjectREFR>(); |
||||
if (refrItem) { |
||||
AddArtifactsToList(a_vm, a_stackID, nullptr, refrItem, a_targetList, a_excludeList); |
||||
if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) { |
||||
for (auto& actorHandle : processLists->highActorHandles) { |
||||
if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate()) { |
||||
result.push_back(actor.get()); |
||||
} |
||||
return true; |
||||
}); |
||||
return a_targetList->forms.size(); |
||||
} |
||||
|
||||
const auto containerRef = a_refOrList->As<RE::TESObjectREFR>(); |
||||
|
||||
if (!containerRef) { |
||||
a_vm->TraceStack("containerRef in AddArtifactsToList is not a reference", a_stackID); |
||||
return 0; |
||||
} |
||||
|
||||
const auto inv = containerRef->GetInventory([&](RE::TESBoundObject& a_exform) { |
||||
return ArtifactTracker::IsArtifact(&a_exform) && (!a_excludeList || !a_excludeList->HasForm(&a_exform)); |
||||
}); |
||||
|
||||
for (const auto& item : inv) { |
||||
if (item.second.first > 0) { |
||||
a_targetList->AddForm(item.first); |
||||
} |
||||
} |
||||
|
||||
return a_targetList->forms.size(); |
||||
return result; |
||||
} |
||||
|
||||
inline RE::TESObjectREFR* GetCellStorage(RE::StaticFunctionTag*, |
||||
RE::TESObjectREFR* a_ref, |
||||
RE::BGSListForm* a_refList, |
||||
RE::TESBoundObject* a_objectToCreate, |
||||
bool a_autoCreate = true) |
||||
inline RE::TESObjectREFR* GetCurrentContainer(RE::StaticFunctionTag*) |
||||
{ |
||||
return ArtifactTracker::GetCellStorage(a_ref, a_refList, a_objectToCreate, a_autoCreate); |
||||
const auto handle = RE::ContainerMenu::GetTargetRefHandle(); |
||||
const auto refr = RE::TESObjectREFR::LookupByHandle(handle); |
||||
return refr ? refr.get() : nullptr; |
||||
} |
||||
|
||||
inline void SyncCellStorage(RE::StaticFunctionTag*, |
||||
RE::TESObjectREFR* a_cellStorage, |
||||
RE::BGSListForm* a_excludeContainers) |
||||
inline void RescanStoredArtifacts(RE::StaticFunctionTag*) |
||||
{ |
||||
ArtifactTracker::SyncCellStorage(a_cellStorage, a_excludeContainers); |
||||
ListRevert(ArtifactTracker::g_listStored); |
||||
ArtifactTracker::AddRefArtifactsToList(ArtifactTracker::g_persistentStorage, ArtifactTracker::g_listStored); |
||||
} |
||||
|
||||
inline std::int32_t AddArtifactsFromFollowersToList(RE::StaticFunctionTag*, |
||||
RE::BGSListForm* a_targetList, |
||||
RE::BGSListForm* a_excludeList = NULL) |
||||
inline void RescanFoundArtifacts(RE::StaticFunctionTag*) |
||||
{ |
||||
if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) { |
||||
for (auto& actorHandle : processLists->highActorHandles) { |
||||
if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate()) { |
||||
|
||||
const auto inv = actor->GetInventory([&](RE::TESBoundObject& a_exform) { |
||||
return ArtifactTracker::IsArtifact(&a_exform) && (!a_excludeList || !a_excludeList->HasForm(&a_exform)); |
||||
}); |
||||
ListRevert(ArtifactTracker::g_listFound); |
||||
ArtifactTracker::AddRefArtifactsToList(RE::PlayerCharacter::GetSingleton(), ArtifactTracker::g_listFound, ArtifactTracker::g_listStored); |
||||
|
||||
for (const auto& item : inv) { |
||||
if (item.second.first > 0) { |
||||
a_targetList->AddForm(item.first); |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
for (const auto& ref : GetPlayerFollowers(nullptr)) { |
||||
ArtifactTracker::AddRefArtifactsToList(ref, ArtifactTracker::g_listFound, ArtifactTracker::g_listStored); |
||||
} |
||||
|
||||
return a_targetList->forms.size(); |
||||
} |
||||
|
||||
inline void OnItemPickup(RE::StaticFunctionTag*, |
||||
RE::TESBoundObject* a_item) |
||||
inline void RescanNewArtifacts(RE::StaticFunctionTag*) |
||||
{ |
||||
ArtifactTracker::OnItemPickup(a_item); |
||||
ListRevert(ArtifactTracker::g_listNew); |
||||
for (auto const& item : ArtifactTracker::g_artifactMap) { |
||||
if (!ArtifactTracker::g_listStored->HasForm(item.second) && !ArtifactTracker::g_listFound->HasForm(item.second)) { |
||||
ArtifactTracker::g_listNew->AddForm(item.second); |
||||
} |
||||
} |
||||
} |
||||
|
||||
inline void Bind(VM& a_vm) |
||||
{ |
||||
BIND(AddAllFormsToList); |
||||
logger::info("Registered AddAllFormsToList"sv); |
||||
BIND(AddArtifactsToList); |
||||
logger::info("Registered AddArtifactsToList"sv); |
||||
BIND(AddArtifactsFromFollowersToList); |
||||
logger::info("Registered AddArtifactsFromFollowersToList"sv); |
||||
BIND(IsLoaded); |
||||
logger::info("Registered IsLoaded"sv); |
||||
BIND(RescanStoredArtifacts); |
||||
logger::info("Registered RescanStoredArtifacts"sv); |
||||
BIND(RescanFoundArtifacts); |
||||
logger::info("Registered RescanFoundArtifacts"sv); |
||||
BIND(RescanNewArtifacts); |
||||
logger::info("Registered RescanNewArtifacts"sv); |
||||
BIND(GetCellStorage); |
||||
logger::info("Registered GetCellStorage"sv); |
||||
BIND(SyncCellStorage); |
||||
logger::info("Registered SyncCellStorage"sv); |
||||
BIND(OnItemPickup); |
||||
logger::info("Registered OnItemPickup"sv); |
||||
BIND(GetPlayerFollowers); |
||||
logger::info("Registered GetPlayerFollowers"sv); |
||||
BIND(GetCurrentContainer); |
||||
logger::info("Registered GetCurrentContainer"sv); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,120 @@ |
||||
Scriptname ArtifactTrackerPlayer extends ReferenceAlias |
||||
|
||||
FormList Property ETR_ItemsNew Auto |
||||
FormList Property ETR_ItemsFound Auto |
||||
FormList Property ETR_ItemsStored Auto |
||||
|
||||
Keyword Property LocTypePlayerHouse Auto |
||||
|
||||
bool bAtHome = false |
||||
int iFollowerIndex |
||||
|
||||
|
||||
event OnInit() |
||||
OnPlayerLoadGame() |
||||
endevent |
||||
|
||||
|
||||
Event OnPlayerLoadGame() |
||||
|
||||
if ! IsLoaded() |
||||
ETR_ItemsNew.Revert() |
||||
ETR_ItemsFound.Revert() |
||||
ETR_ItemsStored.Revert() |
||||
UnregisterForUpdate() |
||||
Debug.Notification("Failed to initialize ArtifactTracker.dll") |
||||
return |
||||
endif |
||||
|
||||
if skse.GetPluginVersion("Ahzaab's moreHUD Plugin") >= 30800 |
||||
ahzmorehud.RegisterIconFormList("dbmNew", ETR_ItemsNew) |
||||
ahzmorehud.RegisterIconFormList("dbmFound", ETR_ItemsFound) |
||||
ahzmorehud.RegisterIconFormList("dbmDisp", ETR_ItemsStored) |
||||
endif |
||||
|
||||
if skse.GetPluginVersion("Ahzaab's moreHUD Inventory Plugin") >= 10017 |
||||
ahzmorehudie.RegisterIconFormList("dbmNew", ETR_ItemsNew) |
||||
ahzmorehudie.RegisterIconFormList("dbmFound", ETR_ItemsFound) |
||||
ahzmorehudie.RegisterIconFormList("dbmDisp", ETR_ItemsStored) |
||||
endif |
||||
|
||||
if SKSE.GetPluginVersion("QuickLootRE") >= 292 |
||||
QuickLootRE.RegisterNewItemsList(ETR_ItemsNew) |
||||
QuickLootRE.RegisterDisplayedItemsList(ETR_ItemsStored) |
||||
QuickLootRE.RegisterFoundItemsList(ETR_ItemsFound) |
||||
endif |
||||
|
||||
; Rebuild all lists to avoid discrepancies, stale data, and broken records |
||||
RescanStoredArtifacts() |
||||
RescanFoundArtifacts() |
||||
RescanNewArtifacts() |
||||
|
||||
Location currentLocation = (GetReference() as ObjectReference).GetCurrentLocation() |
||||
bAtHome = currentLocation && currentLocation.HasKeyword(LocTypePlayerHouse) |
||||
|
||||
if bAtHome |
||||
RegisterForModEvent("AT_HomeInventoryUpdate", "OnHomeInventoryUpdate") |
||||
else |
||||
UnregisterForModEvent("AT_HomeInventoryUpdate") |
||||
endif |
||||
|
||||
EndEvent |
||||
|
||||
|
||||
Event OnLocationChange(Location akOldLoc, Location akNewLoc) |
||||
|
||||
bAtHome = akNewLoc && akNewLoc.HasKeyword(LocTypePlayerHouse) |
||||
|
||||
if bAtHome |
||||
RegisterForModEvent("AT_HomeInventoryUpdate", "OnHomeInventoryUpdate") |
||||
elseif akOldLoc && akOldLoc.HasKeyword(LocTypePlayerHouse) |
||||
UnregisterForModEvent("AT_HomeInventoryUpdate") |
||||
endif |
||||
|
||||
int iCurrentFollowers = 0; |
||||
Actor[] aFollowers = GetPlayerFollowers() |
||||
int i = aFollowers.length |
||||
while i > 0 |
||||
i -= 1 |
||||
iCurrentFollowers += aFollowers[i].GetFormID() |
||||
endwhile |
||||
|
||||
if iCurrentFollowers != iFollowerIndex |
||||
iFollowerIndex = iCurrentFollowers |
||||
RegisterForSingleUpdate(5.0) ; wait until followers load into the location |
||||
endif |
||||
|
||||
endEvent |
||||
|
||||
|
||||
Event OnUpdate() |
||||
|
||||
Debug.Notification("Team changed, updating ETR_ItemsFound") |
||||
RescanFoundArtifacts() |
||||
|
||||
EndEvent |
||||
|
||||
|
||||
event OnHomeInventoryUpdate() |
||||
if bAtHome |
||||
Debug.Notification("Triggered AT_HomeInventoryUpdate") |
||||
SyncCellStorage() |
||||
endif |
||||
endevent |
||||
|
||||
|
||||
; NATIVE FUNCTIONS |
||||
|
||||
bool function IsLoaded() native global |
||||
|
||||
function RescanStoredArtifacts() native global |
||||
|
||||
function RescanFoundArtifacts() native global |
||||
|
||||
function RescanNewArtifacts() native global |
||||
|
||||
ObjectReference function GetCellStorage() native global |
||||
|
||||
function SyncCellStorage(int FormID = 0) native global |
||||
|
||||
Actor[] function GetPlayerFollowers() native global |
@ -1,13 +0,0 @@ |
||||
Scriptname ETR_Functions Hidden |
||||
|
||||
int function AddAllFormsToList(FormList targetList, int formType, FormList storedList, FormList foundList) native global |
||||
|
||||
int function AddArtifactsToList(Form refOrList, FormList targetList, FormList excludeList = None) native global |
||||
|
||||
ObjectReference function GetCellStorage(ObjectReference ref, FormList refList, Form refToCreate, bool autoCreate = true) native global |
||||
|
||||
function SyncCellStorage(ObjectReference cellStorage, FormList excludeContainers) native global |
||||
|
||||
int function AddArtifactsFromFollowersToList(FormList targetList, FormList excludeList = None) native global |
||||
|
||||
function OnItemPickup(Form item) native global |
@ -1,179 +0,0 @@ |
||||
Scriptname ETR_TrackStoredItems extends ReferenceAlias |
||||
|
||||
Actor Property PlayerRef Auto |
||||
|
||||
FormList Property ETR_ItemsNew Auto |
||||
FormList Property ETR_ItemsFound Auto |
||||
FormList Property ETR_ItemsStored Auto |
||||
FormList Property ETR_PersistentStorageList Auto |
||||
|
||||
Container Property ETR_CellStorageContainer Auto |
||||
|
||||
Keyword Property LocTypePlayerHouse Auto |
||||
|
||||
bool bBusy = false |
||||
bool bAtHome = false |
||||
bool bRescanHome = false |
||||
bool bRescanPersistent = false |
||||
ObjectReference lastDestContainer = None |
||||
bool lastDestIsPersistent = false |
||||
ObjectReference lastSourceContainer = None |
||||
bool lastSourceIsPersistent = false |
||||
int iUpdateCount |
||||
|
||||
|
||||
event OnInit() |
||||
OnPlayerLoadGame() |
||||
endevent |
||||
|
||||
|
||||
Event OnPlayerLoadGame() |
||||
AddInventoryEventFilter(ETR_ItemsStored) |
||||
|
||||
if skse.GetPluginVersion("Ahzaab's moreHUD Plugin") >= 30800 |
||||
ahzmorehud.RegisterIconFormList("dbmNew", ETR_ItemsNew) |
||||
ahzmorehud.RegisterIconFormList("dbmFound", ETR_ItemsFound) |
||||
ahzmorehud.RegisterIconFormList("dbmDisp", ETR_ItemsStored) |
||||
endif |
||||
|
||||
if skse.GetPluginVersion("Ahzaab's moreHUD Inventory Plugin") >= 10017 |
||||
ahzmorehudie.RegisterIconFormList("dbmNew", ETR_ItemsNew) |
||||
ahzmorehudie.RegisterIconFormList("dbmFound", ETR_ItemsFound) |
||||
ahzmorehudie.RegisterIconFormList("dbmDisp", ETR_ItemsStored) |
||||
endif |
||||
|
||||
if SKSE.GetPluginVersion("QuickLootRE") >= 292 |
||||
QuickLootRE.RegisterNewItemsList(ETR_ItemsNew) |
||||
QuickLootRE.RegisterDisplayedItemsList(ETR_ItemsStored) |
||||
QuickLootRE.RegisterFoundItemsList(ETR_ItemsFound) |
||||
endif |
||||
|
||||
; Rebuild all lists to avoid discrepancies, stale data, and broken records |
||||
|
||||
ETR_ItemsStored.Revert() |
||||
ETR_Functions.AddArtifactsToList(ETR_PersistentStorageList, ETR_ItemsStored) |
||||
|
||||
ETR_ItemsFound.Revert() |
||||
ETR_Functions.AddArtifactsToList(PlayerRef, ETR_ItemsFound, ETR_ItemsStored) |
||||
ETR_Functions.AddArtifactsFromFollowersToList(ETR_ItemsFound, ETR_ItemsStored) |
||||
|
||||
ETR_ItemsNew.Revert() |
||||
ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 41, ETR_ItemsStored, ETR_ItemsFound) |
||||
ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 32, ETR_ItemsStored, ETR_ItemsFound) |
||||
ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 27, ETR_ItemsStored, ETR_ItemsFound) |
||||
ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 26, ETR_ItemsStored, ETR_ItemsFound) |
||||
|
||||
Location currentLocation = PlayerRef.GetCurrentLocation() |
||||
bAtHome = currentLocation && currentLocation.HasKeyword(LocTypePlayerHouse) |
||||
if bAtHome |
||||
GotoState("AtHome") |
||||
else |
||||
GotoState("") |
||||
endif |
||||
EndEvent |
||||
|
||||
|
||||
Event OnLocationChange(Location akOldLoc, Location akNewLoc) |
||||
bAtHome = akNewLoc && akNewLoc.HasKeyword(LocTypePlayerHouse) |
||||
if bAtHome |
||||
GotoState("AtHome") |
||||
else |
||||
GotoState("") |
||||
endif |
||||
endEvent |
||||
|
||||
|
||||
Event OnMenuClose(String MenuName) |
||||
UnregisterForUpdate() |
||||
OnUpdate() |
||||
EndEvent |
||||
|
||||
|
||||
Event OnUpdate() |
||||
|
||||
if UI.IsMenuOpen("ContainerMenu") |
||||
RegisterForMenu("ContainerMenu") |
||||
return |
||||
endif |
||||
|
||||
while bBusy |
||||
Debug.Notification("Stored OnUpdate is busy") |
||||
Utility.wait(0.5) |
||||
endwhile |
||||
|
||||
bBusy = true |
||||
|
||||
iUpdateCount += 1 |
||||
Debug.Notification("Running Stored OnUpdate " + iUpdateCount) |
||||
|
||||
if bRescanHome |
||||
if lastSourceContainer && lastSourceContainer as Actor && (lastSourceContainer as Actor).IsPlayerTeammate() |
||||
lastSourceContainer = None |
||||
return |
||||
endif |
||||
bRescanHome = false |
||||
|
||||
ObjectReference bookShelf |
||||
if lastDestContainer |
||||
if lastDestContainer as PlayerBookShelfContainerScript |
||||
bookShelf = lastDestContainer |
||||
endif |
||||
elseif lastSourceContainer |
||||
if lastSourceContainer as PlayerBookShelfContainerScript |
||||
bookShelf = lastSourceContainer |
||||
endif |
||||
endif |
||||
|
||||
if bookShelf |
||||
int iLimit = 10 |
||||
while iLimit > 0 && (bookShelf as PlayerBookShelfContainerScript).GetState() == "PlacingBooks" |
||||
Debug.Notification("Waiting for shelf update") |
||||
iLimit -= 1 |
||||
Utility.wait(0.5) |
||||
endwhile |
||||
endif |
||||
|
||||
ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) |
||||
ETR_Functions.SyncCellStorage(cellStorage, ETR_PersistentStorageList) |
||||
endif |
||||
|
||||
if bRescanPersistent |
||||
bRescanPersistent = false |
||||
|
||||
ETR_ItemsStored.Revert() |
||||
Form[] aContainers = ETR_PersistentStorageList.ToArray() |
||||
|
||||
int n = aContainers.length |
||||
while n > 0 |
||||
n -= 1 |
||||
ETR_Functions.AddArtifactsToList(aContainers[n], ETR_ItemsStored) |
||||
endwhile |
||||
|
||||
ETR_ItemsFound.Revert() |
||||
ETR_Functions.AddArtifactsToList(PlayerRef, ETR_ItemsFound, ETR_ItemsStored) |
||||
ETR_Functions.AddArtifactsFromFollowersToList(ETR_ItemsFound, ETR_ItemsStored) |
||||
endif |
||||
|
||||
bBusy = false |
||||
|
||||
EndEvent |
||||
|
||||
|
||||
; We acquired a stored item, and we want to find out if we just have taken the last stored item of its kind |
||||
event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) |
||||
|
||||
if akSourceContainer |
||||
if lastSourceContainer != akSourceContainer |
||||
lastSourceContainer = akSourceContainer |
||||
lastSourceIsPersistent = ETR_PersistentStorageList.HasForm(akSourceContainer) |
||||
endif |
||||
if bAtHome || lastSourceIsPersistent |
||||
bRescanHome = bAtHome |
||||
bRescanPersistent = true |
||||
RegisterForSingleUpdate(0.5) |
||||
endif |
||||
elseif bAtHome |
||||
ETR_Functions.OnItemPickup(akBaseItem) |
||||
endif |
||||
|
||||
endevent |
Loading…
Reference in new issue