2022-06-30 10:31:01 +00:00
# include "ArtifactTracker.h"
# include "BookCheck.h"
# include "EventListener.h"
# include "Util.h"
2022-07-11 11:41:07 +00:00
using namespace SKSE ;
using namespace SKSE : : log ;
2022-06-30 10:31:01 +00:00
namespace ArtifactTracker
{
2022-07-11 22:37:19 +00:00
bool g_bLoaded = false ;
2022-07-18 09:38:38 +00:00
bool g_bSaveLoaded = true ;
2022-07-11 22:37:19 +00:00
bool g_bHomeContainer = false ;
bool g_bBookShelf = false ;
bool g_bTakeAll = false ;
bool g_bNotifyNewArtifact = false ;
2022-09-16 00:39:07 +00:00
bool g_bWarnMissingMoreHUD = true ;
2022-07-11 22:37:19 +00:00
std : : uint32_t g_bTakeAllCount = 0 ;
std : : int32_t g_iFollowerIndex = 0 ;
2022-06-30 10:31:01 +00:00
RE : : TESBoundObject * g_cellContainer ;
RE : : BGSListForm * g_listNew ;
RE : : BGSListForm * g_listStored ;
RE : : BGSListForm * g_listFound ;
RE : : BGSListForm * g_persistentStorage ;
RE : : BGSKeyword * g_homeKeyword ;
std : : unordered_map < RE : : FormID , RE : : TESForm * > g_artifactMap ;
2022-07-03 01:35:16 +00:00
std : : unordered_set < RE : : FormType > g_artifactFormTypes ;
2022-07-16 18:14:12 +00:00
std : : unordered_set < RE : : FormType > g_artifactAllFormTypes ;
2022-06-30 10:31:01 +00:00
std : : unordered_map < RE : : FormID , RE : : TESObjectREFR * > g_persistentMap ;
RE : : TESObjectREFR * g_cellStorage ;
2022-07-11 11:41:07 +00:00
const SKSE : : LoadInterface * g_loadInterface ;
2022-06-30 10:31:01 +00:00
2022-07-07 01:04:51 +00:00
bool Init ( bool bKID )
2022-06-30 10:31:01 +00:00
{
2022-07-05 15:52:30 +00:00
if ( g_bLoaded ) {
return true ;
}
2022-06-30 10:31:01 +00:00
const auto dataHandler = RE : : TESDataHandler : : GetSingleton ( ) ;
if ( ! dataHandler ) {
2022-07-11 11:41:07 +00:00
// Called before kDataLoaded?
2022-07-11 14:36:22 +00:00
log : : error ( " DataHandler is not initialized. " ) ;
2022-07-05 15:52:30 +00:00
return false ;
2022-06-30 10:31:01 +00:00
}
2022-07-11 11:41:07 +00:00
SKSE : : GetModCallbackEventSource ( ) - > RemoveEventSink ( EventListener : : GetSingleton ( ) ) ;
g_cellContainer = dataHandler - > LookupForm ( 0x804 , " Artifact Tracker.esp " ) - > As < RE : : TESBoundObject > ( ) ; // ETR_CellStorageContainer
2022-06-30 10:31:01 +00:00
2022-07-11 11:41:07 +00:00
g_listNew = dataHandler - > LookupForm < RE : : BGSListForm > ( 0x800 , " Artifact Tracker.esp " ) ; // ETR_ItemsNew
g_listStored = dataHandler - > LookupForm < RE : : BGSListForm > ( 0x801 , " Artifact Tracker.esp " ) ; // ETR_ItemsStored
g_listFound = dataHandler - > LookupForm < RE : : BGSListForm > ( 0x802 , " Artifact Tracker.esp " ) ; // ETR_ItemsFound
g_persistentStorage = dataHandler - > LookupForm < RE : : BGSListForm > ( 0x803 , " Artifact Tracker.esp " ) ; // ETR_PersistentStorageList
2022-06-30 10:31:01 +00:00
2022-07-01 14:40:15 +00:00
g_homeKeyword = dataHandler - > LookupForm < RE : : BGSKeyword > ( 0xFC1A3 , " Skyrim.esm " ) ; // LocTypePlayerHouse
2022-06-30 10:31:01 +00:00
2022-07-11 11:41:07 +00:00
const auto extraArtifactKeyword = dataHandler - > LookupForm < RE : : BGSKeyword > ( 0xAFC110 , " Update.esm " ) ; // ETR_ExtraArtifact
const auto notArtifactKeyword = dataHandler - > LookupForm < RE : : BGSKeyword > ( 0xAFC111 , " Update.esm " ) ; // ETR_NotArtifact
const auto npcRaceKeyword = dataHandler - > LookupForm < RE : : BGSKeyword > ( 0x13794 , " Skyrim.esm " ) ; // ActorTypeNPC
2022-06-30 10:31:01 +00:00
2023-09-09 21:02:35 +00:00
if ( ! g_cellContainer | | ! g_listNew | | ! g_listStored | | ! g_listFound | | ! g_persistentStorage | | ! g_homeKeyword | | ! extraArtifactKeyword | | ! notArtifactKeyword | | ! npcRaceKeyword ) {
2022-07-11 11:41:07 +00:00
log : : warn ( " Unable to load data from Artifact Tracker.esp " ) ;
2022-07-05 15:52:30 +00:00
RE : : DebugMessageBox ( " Unable to load data from Artifact Tracker.esp, the mod is disabled. " ) ;
return false ;
2022-06-30 10:31:01 +00:00
}
2022-07-11 11:41:07 +00:00
std : : map < std : : string , bool > settings {
2022-07-05 21:30:41 +00:00
{ " DumpItemList " , false } ,
2022-07-14 18:36:46 +00:00
{ " NewArtifactNotifications " , false } ,
2022-09-16 00:39:07 +00:00
{ " WarnMissingMoreHUD " , true } ,
{ " WarnMissingKID " , true } ,
2022-07-05 19:17:52 +00:00
} ;
LoadINI ( & settings , " Data/SKSE/Plugins/ArtifactTracker.ini " ) ;
2022-07-11 22:37:19 +00:00
g_bNotifyNewArtifact = settings . at ( " NewArtifactNotifications " ) ;
2022-09-16 00:39:07 +00:00
g_bWarnMissingMoreHUD = settings . at ( " WarnMissingMoreHUD " ) ;
2022-07-11 22:37:19 +00:00
2022-07-07 01:04:51 +00:00
// Preloading item lists
2022-07-16 18:14:12 +00:00
g_artifactAllFormTypes . insert ( RE : : FormType : : Weapon ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : Armor ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : Book ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : Misc ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : AlchemyItem ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : Ingredient ) ;
g_artifactAllFormTypes . insert ( RE : : FormType : : SoulGem ) ;
2022-07-03 01:35:16 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : Weapon ) ;
2022-07-05 15:52:30 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : TESObjectWEAP > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > GetPlayable ( ) & & ! form - > IsBound ( ) & & ! form - > weaponData . flags . all ( RE : : TESObjectWEAP : : Data : : Flag : : kCantDrop ) ) {
2022-07-05 21:30:41 +00:00
if ( ( ! form - > HasKeyword ( notArtifactKeyword ) | | form - > HasKeyword ( extraArtifactKeyword ) ) & & strlen ( form - > GetName ( ) ) > 0 ) {
g_artifactMap [ form - > formID ] = form ;
2022-07-05 19:17:52 +00:00
}
2022-07-03 01:35:16 +00:00
}
}
g_artifactMap . erase ( 0x1F4 ) ; // Unarmed
2022-07-11 11:41:07 +00:00
2022-07-03 01:35:16 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : Armor ) ;
2022-07-05 15:52:30 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : TESObjectARMO > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > GetPlayable ( ) & & form - > race & & ( form - > race - > formID = = 0x19 | | form - > race - > HasKeyword ( npcRaceKeyword ) ) ) {
2022-07-05 21:30:41 +00:00
if ( ( ! form - > HasKeyword ( notArtifactKeyword ) | | form - > HasKeyword ( extraArtifactKeyword ) ) & & strlen ( form - > GetName ( ) ) > 0 ) {
g_artifactMap [ form - > formID ] = form ;
2022-07-05 19:17:52 +00:00
}
2022-07-03 01:35:16 +00:00
}
}
2022-07-11 11:41:07 +00:00
g_artifactMap . erase ( 0xD64 ) ; // SkinNaked
g_artifactMap . erase ( 0x69CE3 ) ; // SkinNakedBeast
g_artifactMap . erase ( 0xCDD86 ) ; // SkinNakedWerewolfBeast
2022-07-03 01:35:16 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : Book ) ;
2022-06-30 10:31:01 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : TESObjectBOOK > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( ( form - > HasKeyword ( extraArtifactKeyword ) | | ( ! form - > TeachesSpell ( ) & & BookCheck : : IsBook ( form ) ) ) & & ! form - > HasKeyword ( notArtifactKeyword ) ) {
2022-06-30 10:31:01 +00:00
g_artifactMap [ form - > formID ] = form ;
}
}
2022-07-03 11:58:41 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : Misc ) ;
for ( const auto & form : dataHandler - > GetFormArray < RE : : TESObjectMISC > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > GetPlayable ( ) & & ( form - > GetNumKeywords ( ) = = 0 | | ( ! bKID & & form - > HasKeyword ( extraArtifactKeyword ) ) | | ( bKID & & ( ! form - > HasKeyword ( notArtifactKeyword ) | | form - > HasKeyword ( extraArtifactKeyword ) ) ) ) & & strlen ( form - > GetName ( ) ) > 0 ) {
2022-07-03 11:58:41 +00:00
g_artifactMap [ form - > formID ] = form ;
}
}
g_artifactMap . erase ( 0xA ) ; // Lockpick
g_artifactMap . erase ( 0xF ) ; // Gold
2022-07-03 01:35:16 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : AlchemyItem > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > HasKeyword ( extraArtifactKeyword ) & & ! form - > HasKeyword ( notArtifactKeyword ) ) {
2022-06-30 10:31:01 +00:00
g_artifactMap [ form - > formID ] = form ;
2022-07-03 01:35:16 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : AlchemyItem ) ;
2022-06-30 10:31:01 +00:00
}
}
2022-07-05 15:52:30 +00:00
2022-07-03 01:35:16 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : IngredientItem > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > HasKeyword ( extraArtifactKeyword ) & & ! form - > HasKeyword ( notArtifactKeyword ) ) {
2022-06-30 10:31:01 +00:00
g_artifactMap [ form - > formID ] = form ;
2022-07-03 01:35:16 +00:00
g_artifactFormTypes . insert ( RE : : FormType : : Ingredient ) ;
2022-06-30 10:31:01 +00:00
}
}
2022-07-05 15:52:30 +00:00
2022-07-03 01:35:16 +00:00
for ( const auto & form : dataHandler - > GetFormArray < RE : : TESSoulGem > ( ) ) {
2022-07-07 23:10:14 +00:00
if ( form - > HasKeyword ( extraArtifactKeyword ) & & ! form - > HasKeyword ( notArtifactKeyword ) ) {
2022-07-03 01:35:16 +00:00
g_artifactMap [ form - > formID ] = form ;
g_artifactFormTypes . insert ( RE : : FormType : : SoulGem ) ;
}
}
2022-07-05 15:52:30 +00:00
EventListener : : Install ( ) ;
2022-07-11 11:41:07 +00:00
OnGameLoad ( ) ; // covers new game and coc'ing from the main menu
2022-12-01 00:39:28 +00:00
2022-07-05 15:52:30 +00:00
g_bLoaded = true ;
2022-07-05 19:17:52 +00:00
2022-09-16 00:39:07 +00:00
if ( bKID ) {
log : : info ( " Keyword Item Distributor is detected. " ) ;
} else {
log : : info ( " Keyword Item Distributor has NOT been detected, using the baseline configuration. " ) ;
}
2022-07-16 22:09:08 +00:00
RE : : ConsoleLog : : GetSingleton ( ) - > Print ( std : : format ( " Artifact Tracker registered {} items. " , g_artifactMap . size ( ) ) . c_str ( ) ) ;
2022-07-11 11:41:07 +00:00
log : : info ( " Total artifacts: {} " , g_artifactMap . size ( ) ) ;
2022-07-05 19:17:52 +00:00
2022-07-05 21:30:41 +00:00
if ( settings . at ( " DumpItemList " ) ) {
2022-07-05 19:17:52 +00:00
for ( const auto & item : g_artifactMap ) {
2022-07-11 11:41:07 +00:00
log : : info ( " [{:08X}] {} " , item . second - > formID , item . second - > GetName ( ) ) ;
2022-07-05 19:17:52 +00:00
}
}
2022-09-16 00:39:07 +00:00
if ( dataHandler - > LookupLoadedModByName ( " DBM_RelicNotifications.esp " ) ) {
RE : : DebugMessageBox ( " Artifact Tracker is incompatible with The Curator's Companion. " ) ;
}
if ( ! bKID & & settings . at ( " WarnMissingKID " ) ) {
RE : : DebugMessageBox ( " Artifact Tracker requires Keyword Item Distributor. If its absence is intentional, set WarnMissingKID=false in ArtifactTracker.ini. " ) ;
}
2022-07-05 15:52:30 +00:00
return true ;
2022-06-30 10:31:01 +00:00
}
2022-07-05 15:52:30 +00:00
bool IsArtifact ( const RE : : TESForm * a_form )
2022-06-30 10:31:01 +00:00
{
2022-07-03 01:35:16 +00:00
return a_form & & g_artifactFormTypes . contains ( a_form - > GetFormType ( ) ) & & g_artifactMap . contains ( a_form - > formID ) ;
2022-06-30 10:31:01 +00:00
}
2022-07-05 15:52:30 +00:00
RE : : TESForm * GetArtifactByID ( const RE : : FormID a_formID )
2022-06-30 10:31:01 +00:00
{
if ( ! a_formID ) {
return nullptr ;
}
const auto it = g_artifactMap . find ( a_formID ) ;
return it ! = g_artifactMap . end ( ) ? it - > second : nullptr ;
}
void OnGameLoad ( )
{
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " OnGameLoad " ) ;
2022-06-30 10:31:01 +00:00
# endif
g_persistentMap . clear ( ) ;
g_persistentStorage - > ForEachForm ( [ & ] ( RE : : TESForm & a_exform ) {
if ( & a_exform ) {
g_persistentMap [ a_exform . formID ] = a_exform . As < RE : : TESObjectREFR > ( ) ;
}
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
} ) ;
2022-07-11 14:36:22 +00:00
std : : uint32_t savedCount = g_listStored - > forms . size ( ) + g_listFound - > forms . size ( ) + g_listNew - > forms . size ( ) ;
if ( savedCount ! = g_artifactMap . size ( ) ) {
2022-07-11 11:41:07 +00:00
ListRevert ( g_listNew ) ;
}
RescanStoredArtifacts ( ) ;
RescanFoundArtifacts ( ) ;
RescanNewArtifacts ( ) ;
const auto vm = RE : : BSScript : : Internal : : VirtualMachine : : GetSingleton ( ) ;
RE : : BSTSmartPointer < RE : : BSScript : : IStackCallbackFunctor > stackCallback ;
2022-09-16 00:39:07 +00:00
bool bMoreHUDInstalled = false ;
2022-07-11 11:41:07 +00:00
if ( const auto pluginInfo = g_loadInterface - > GetPluginInfo ( " Ahzaab's moreHUD Plugin " ) ; pluginInfo ) {
if ( ! g_bLoaded ) log : : info ( " Detected {} v{} " , pluginInfo - > name , pluginInfo - > version ) ;
if ( pluginInfo - > version = = 0 ) {
log : : error ( " MoreHUD has not been detected. " ) ;
} else if ( pluginInfo - > version < 30800 ) {
log : : error ( " MoreHUD is outdated. " ) ;
} else if ( vm - > TypeIsValid ( " AhzMoreHud " ) ) {
if ( ! g_bLoaded ) log : : info ( " Registering icons in MoreHUD... " ) ;
vm - > DispatchStaticCall ( " AhzMoreHud " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmNew " , std : : move ( g_listNew ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " AhzMoreHud " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmFound " , std : : move ( g_listFound ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " AhzMoreHud " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmDisp " , std : : move ( g_listStored ) ) , stackCallback ) ;
2022-09-16 00:39:07 +00:00
bMoreHUDInstalled = true ;
2022-07-11 11:41:07 +00:00
} else {
log : : error ( " MoreHUD has not been installed correctly. " ) ;
}
} else if ( ! g_bLoaded ) {
log : : error ( " MoreHUD has not been detected. " ) ;
}
2022-09-16 00:39:07 +00:00
bool bMoreHUDInvInstalled = false ;
2022-07-11 11:41:07 +00:00
if ( const auto pluginInfo = g_loadInterface - > GetPluginInfo ( " Ahzaab's moreHUD Inventory Plugin " ) ; pluginInfo ) {
if ( ! g_bLoaded ) log : : info ( " Detected {} v{} " , pluginInfo - > name , pluginInfo - > version ) ;
if ( pluginInfo - > version = = 0 ) {
log : : error ( " MoreHUD Inventory Edition has not been detected. " ) ;
} else if ( pluginInfo - > version < 10017 ) {
log : : error ( " MoreHUD Inventory Edition is outdated. " ) ;
} else if ( vm - > TypeIsValid ( " AhzMoreHudIE " ) ) {
if ( ! g_bLoaded ) log : : info ( " Registering icons in MoreHUD Inventory Edition... " ) ;
vm - > DispatchStaticCall ( " AhzMoreHudIE " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmNew " , std : : move ( g_listNew ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " AhzMoreHudIE " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmFound " , std : : move ( g_listFound ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " AhzMoreHudIE " , " RegisterIconFormList " , RE : : MakeFunctionArguments < RE : : BSString , RE : : BGSListForm * > ( " dbmDisp " , std : : move ( g_listStored ) ) , stackCallback ) ;
2022-09-16 00:39:07 +00:00
bool bMoreHUDInvInstalled = true ;
2022-07-11 11:41:07 +00:00
} else {
log : : error ( " MoreHUD Inventory Edition has not been installed correctly. " ) ;
}
} else if ( ! g_bLoaded ) {
log : : error ( " MoreHUD Inventory Edition has not been detected. " ) ;
}
2022-09-16 00:39:07 +00:00
if ( g_bWarnMissingMoreHUD & & ! bMoreHUDInstalled & & ! bMoreHUDInvInstalled ) {
RE : : DebugMessageBox ( " Artifact Tracker requires up-to-date MoreHUD and/or MoreHUD Inventory Edition. If their absence is intentional, set WarnMissingMoreHUD=false in ArtifactTracker.ini. " ) ;
}
2022-07-14 18:36:46 +00:00
// TODO: Uncomment when/if QuickLoot EE brings back registering formlists
/*
2022-07-11 11:41:07 +00:00
if ( const auto pluginInfo = g_loadInterface - > GetPluginInfo ( " QuickLootEE " ) ; pluginInfo ) {
if ( ! g_bLoaded ) log : : info ( " Detected {} v{} " , pluginInfo - > name , pluginInfo - > version ) ;
if ( pluginInfo - > version = = 0 ) {
log : : error ( " QuickLoot EE has not been detected. " ) ;
} else if ( vm - > TypeIsValid ( " QuickLootEE " ) ) {
if ( ! g_bLoaded ) log : : info ( " Registering icons with QuickLootEE... " ) ;
vm - > DispatchStaticCall ( " QuickLootEE " , " RegisterNewItemsList " , RE : : MakeFunctionArguments < RE : : BGSListForm * > ( std : : move ( g_listNew ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " QuickLootEE " , " RegisterFoundItemsList " , RE : : MakeFunctionArguments < RE : : BGSListForm * > ( std : : move ( g_listFound ) ) , stackCallback ) ;
vm - > DispatchStaticCall ( " QuickLootEE " , " RegisterDisplayedItemsList " , RE : : MakeFunctionArguments < RE : : BGSListForm * > ( std : : move ( g_listStored ) ) , stackCallback ) ;
} else {
log : : error ( " QuickLoot EE has not been installed correctly. " ) ;
}
} else if ( ! g_bLoaded ) {
log : : error ( " QuickLoot EE has not been detected. " ) ;
}
2022-07-14 18:36:46 +00:00
*/
2022-06-30 10:31:01 +00:00
}
2022-07-05 15:52:30 +00:00
void SetContainerMode ( const bool bOpening )
2022-06-30 10:31:01 +00:00
{
if ( bOpening ) {
const auto refr = RE : : TESObjectREFR : : LookupByHandle ( RE : : ContainerMenu : : GetTargetRefHandle ( ) ) ;
g_bHomeContainer = IsHome ( )
& & refr
2022-07-04 12:13:47 +00:00
& & IsInSameCell ( refr . get ( ) )
2022-07-01 14:40:15 +00:00
& & ! g_persistentMap . contains ( refr . get ( ) - > formID ) ;
2022-06-30 10:31:01 +00:00
2022-07-09 12:15:35 +00:00
g_bBookShelf = g_bHomeContainer & & refr - > GetBaseObject ( ) - > formID = = 0xDC9E7 ;
2022-06-30 10:31:01 +00:00
# ifdef _DEBUG
if ( g_bHomeContainer ) {
RE : : DebugNotification ( " Delayed processing enabled " ) ;
}
# endif
} else if ( g_bHomeContainer ) {
g_bHomeContainer = false ;
2022-07-09 12:15:35 +00:00
if ( g_bBookShelf ) {
g_bBookShelf = false ;
std : : thread ( [ ] ( ) {
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1200 ) ) ;
2022-07-16 16:19:30 +00:00
ArtifactTracker : : SyncCellStorage ( ) ;
2022-07-09 12:15:35 +00:00
} ) . detach ( ) ;
} else {
SyncCellStorage ( ) ;
}
2022-06-30 10:31:01 +00:00
}
}
bool IsHome ( )
{
return ( bool ) g_cellStorage ;
}
bool ToggleHomeMode ( RE : : TESObjectREFR * cellStorage )
{
if ( cellStorage ) {
g_bHomeContainer = false ;
g_cellStorage = cellStorage ;
2022-07-08 22:47:03 +00:00
RE : : ScriptEventSourceHolder : : GetSingleton ( ) - > AddEventSink < RE : : TESActivateEvent > ( EventListener : : GetSingleton ( ) ) ;
2022-06-30 10:31:01 +00:00
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " Home mode ON " ) ;
2022-06-30 10:31:01 +00:00
# endif
return true ;
} else if ( g_cellStorage ) {
g_bHomeContainer = false ;
g_cellStorage = nullptr ;
2022-07-08 22:47:03 +00:00
RE : : ScriptEventSourceHolder : : GetSingleton ( ) - > RemoveEventSink < RE : : TESActivateEvent > ( EventListener : : GetSingleton ( ) ) ;
2022-06-30 10:31:01 +00:00
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " Home mode OFF " ) ;
2022-06-30 10:31:01 +00:00
# endif
}
return false ;
}
bool IsValidContainer ( RE : : TESObjectREFR * a_ref )
{
2022-07-18 09:38:38 +00:00
if ( ! a_ref | | a_ref - > IsMarkedForDeletion ( ) ) {
2022-06-30 10:31:01 +00:00
return false ;
}
const auto baseObj = a_ref - > GetBaseObject ( ) ;
2022-07-11 11:41:07 +00:00
return baseObj - > formType = = RE : : FormType : : Container | | ( baseObj - > formType = = RE : : FormType : : NPC & & ! a_ref - > IsDisabled ( ) & & baseObj - > As < RE : : TESNPC > ( ) - > GetRace ( ) - > formID = = 0x10760A ) ;
2022-06-30 10:31:01 +00:00
}
2022-07-05 15:52:30 +00:00
void OnCellEnter ( const RE : : FormID a_formID )
2022-06-30 10:31:01 +00:00
{
2022-07-18 09:38:38 +00:00
if ( ! g_bSaveLoaded ) {
// Cell load events fire before formlists are loaded from savegame
return ;
}
2022-06-30 10:31:01 +00:00
RE : : TESObjectCELL * cell = RE : : TESForm : : LookupByID < RE : : TESObjectCELL > ( a_formID ) ;
2022-07-01 20:58:02 +00:00
RE : : BGSLocation * location = cell ? cell - > GetLocation ( ) : nullptr ;
2022-06-30 10:31:01 +00:00
2023-09-09 21:02:35 +00:00
if ( ! cell | | ! location | | ! cell - > IsInteriorCell ( ) | | ! location - > HasKeyword ( g_homeKeyword ) ) {
2022-06-30 10:31:01 +00:00
if ( IsHome ( ) ) {
RE : : ScriptEventSourceHolder : : GetSingleton ( ) - > RemoveEventSink < RE : : TESCellFullyLoadedEvent > ( EventListener : : GetSingleton ( ) ) ;
ToggleHomeMode ( nullptr ) ;
}
return ;
}
RE : : TESObjectREFR * cellStorage = nullptr ;
2022-07-18 09:38:38 +00:00
bool bHasDupes = false ;
2022-06-30 10:31:01 +00:00
g_persistentStorage - > ForEachForm ( [ & ] ( RE : : TESForm & a_form ) {
const auto refr = a_form . As < RE : : TESObjectREFR > ( ) ;
2022-07-18 09:38:38 +00:00
if ( refr & & refr - > GetParentCell ( ) - > formID = = a_formID & & refr - > GetBaseObject ( ) = = g_cellContainer ) {
if ( cellStorage ) {
log : : warn ( " Multiple cell storages detected in {} " , cell - > GetName ( ) ) ;
bHasDupes = true ;
} else {
cellStorage = refr ;
}
2022-06-30 10:31:01 +00:00
}
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-06-30 10:31:01 +00:00
} ) ;
2022-07-18 09:38:38 +00:00
# ifdef _DEBUG
if ( cellStorage ) {
log : : info ( " Found cell storage in {} (first pass) " , cell - > GetName ( ) ) ;
}
# endif
2022-06-30 10:31:01 +00:00
ToggleHomeMode ( cellStorage ) ;
2022-07-18 09:38:38 +00:00
if ( ! cellStorage | | bHasDupes ) {
2022-06-30 10:31:01 +00:00
RE : : ScriptEventSourceHolder : : GetSingleton ( ) - > AddEventSink < RE : : TESCellFullyLoadedEvent > ( EventListener : : GetSingleton ( ) ) ;
}
}
2022-07-05 15:52:30 +00:00
void OnCellEnter ( const RE : : BGSLocation * location , const RE : : TESObjectCELL * cell )
2022-06-30 10:31:01 +00:00
{
2022-07-18 09:38:38 +00:00
RE : : ScriptEventSourceHolder : : GetSingleton ( ) - > RemoveEventSink < RE : : TESCellFullyLoadedEvent > ( EventListener : : GetSingleton ( ) ) ;
if ( ! g_bSaveLoaded ) {
// Cell load events fire before formlists are loaded from savegame, duh!
return ;
}
2023-09-09 21:02:35 +00:00
if ( ! location | | ! cell - > IsInteriorCell ( ) | | cell ! = RE : : PlayerCharacter : : GetSingleton ( ) - > GetParentCell ( ) | | ! location - > HasKeyword ( g_homeKeyword ) ) {
2022-06-30 10:31:01 +00:00
ToggleHomeMode ( nullptr ) ;
return ;
}
RE : : TESObjectREFR * cellStorage = nullptr ;
2022-07-18 09:38:38 +00:00
std : : vector < RE : : TESObjectREFR * > dupes ;
cell - > ForEachReference ( [ & cellStorage , & dupes ] ( RE : : TESObjectREFR & a_ref ) {
if ( a_ref . GetBaseObject ( ) = = g_cellContainer & & ! a_ref . IsMarkedForDeletion ( ) ) {
if ( cellStorage ) {
dupes . push_back ( & a_ref ) ;
} else {
cellStorage = & a_ref ;
}
2022-06-30 10:31:01 +00:00
}
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-07-18 09:38:38 +00:00
} ) ;
for ( int i = 0 ; i < dupes . size ( ) ; i + + ) {
log : : warn ( " Removing duplicate storage {:08X} " , dupes [ i ] - > formID ) ;
g_persistentMap . erase ( dupes [ i ] - > formID ) ;
ListRemoveItem ( g_persistentStorage , dupes [ i ] ) ;
dupes [ i ] - > Disable ( ) ;
dupes [ i ] - > SetDelete ( true ) ;
2022-06-30 10:31:01 +00:00
}
2022-07-18 09:38:38 +00:00
dupes . clear ( ) ;
2022-06-30 10:31:01 +00:00
if ( cellStorage ) {
2022-07-18 09:38:38 +00:00
# ifdef _DEBUG
log : : info ( " Found cell storage in {} (second pass) " , cell - > GetName ( ) ) ;
# endif
2022-07-11 14:36:22 +00:00
if ( ! g_persistentMap . contains ( cellStorage - > formID ) ) {
2022-06-30 10:31:01 +00:00
g_persistentStorage - > AddForm ( cellStorage ) ;
g_persistentMap [ cellStorage - > formID ] = cellStorage ;
}
ToggleHomeMode ( cellStorage ) ;
2022-07-11 11:41:07 +00:00
SyncCellStorage ( ) ;
2022-06-30 10:31:01 +00:00
return ;
}
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " Adding new storage in {} " , cell - > GetName ( ) ) ;
2022-06-30 10:31:01 +00:00
# endif
2022-07-16 16:19:30 +00:00
SKSE : : GetTaskInterface ( ) - > AddTask ( [ ] ( ) {
const auto cellStorage = RE : : PlayerCharacter : : GetSingleton ( ) - > PlaceObjectAtMe ( g_cellContainer , true ) . get ( ) ;
2022-06-30 10:31:01 +00:00
2022-07-12 18:27:35 +00:00
if ( cellStorage ) {
2022-07-18 09:38:38 +00:00
# ifdef _DEBUG
log : : info ( " Created storage {:08X} " , cellStorage - > formID ) ;
# endif
2022-07-12 18:27:35 +00:00
cellStorage - > Disable ( ) ;
g_persistentStorage - > AddForm ( cellStorage ) ;
g_persistentMap [ cellStorage - > formID ] = cellStorage ;
ToggleHomeMode ( cellStorage ) ;
2022-07-11 19:18:07 +00:00
SyncCellStorage ( ) ;
2022-07-12 18:27:35 +00:00
} else {
log : : error ( " Failed to create cell storage in OnCellEnter " ) ;
ToggleHomeMode ( nullptr ) ;
}
} ) ;
2022-06-30 10:31:01 +00:00
}
2022-07-05 15:52:30 +00:00
void SyncCellStorage ( const RE : : TESObjectREFR * a_ignoreRef )
2022-06-30 10:31:01 +00:00
{
if ( ! IsHome ( ) ) {
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " SyncCellStorage called while not at home " ) ;
2022-06-30 10:31:01 +00:00
# endif
return ;
}
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " Running SyncCellStorage " ) ;
2022-06-30 10:31:01 +00:00
# endif
2022-07-16 16:19:30 +00:00
const RE : : FormID ignoreFormID = a_ignoreRef ? a_ignoreRef - > formID : NULL ;
2022-06-30 10:31:01 +00:00
2022-07-16 16:19:30 +00:00
SKSE : : GetTaskInterface ( ) - > AddTask ( [ ignoreFormID ] ( ) {
std : : unordered_set < RE : : FormID > cellItems ;
2022-06-30 10:31:01 +00:00
2022-07-16 16:19:30 +00:00
const auto cell = g_cellStorage - > GetParentCell ( ) ;
const auto inv = g_cellStorage - > GetInventory ( ) ;
2022-07-04 00:30:51 +00:00
2022-07-16 16:19:30 +00:00
cell - > ForEachReference ( [ & ] ( RE : : TESObjectREFR & a_ref ) {
if ( ignoreFormID & & ignoreFormID = = a_ref . formID ) {
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-06-30 10:31:01 +00:00
}
2022-07-16 16:19:30 +00:00
const auto baseObj = a_ref . GetBaseObject ( ) ;
2022-06-30 10:31:01 +00:00
2022-07-16 16:19:30 +00:00
if ( IsValidContainer ( & a_ref ) ) {
if ( g_cellContainer = = baseObj | | baseObj - > formID = = 0xDC9E7 | | g_persistentMap . contains ( a_ref . formID ) ) { // skip persistent and PlayerBookShelfContainer
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-06-30 10:31:01 +00:00
}
2022-07-16 16:19:30 +00:00
const auto contInv = a_ref . GetInventory ( [ & ] ( RE : : TESBoundObject & a_object ) - > bool {
2022-07-16 18:14:12 +00:00
return ! cellItems . contains ( a_object . formID ) & & g_artifactAllFormTypes . contains ( a_object . GetFormType ( ) ) ;
2022-07-16 16:19:30 +00:00
} ) ;
2022-06-30 10:31:01 +00:00
2022-07-16 16:19:30 +00:00
for ( const auto & [ item , data ] : contInv ) {
if ( data . first > 0 ) {
cellItems . insert ( item - > formID ) ;
if ( inv . find ( item ) = = inv . end ( ) ) {
g_cellStorage - > AddObjectToContainer ( item , nullptr , 1 , nullptr ) ;
}
2022-07-16 18:14:12 +00:00
if ( IsArtifact ( item ) & & ! g_listStored - > HasForm ( item ) ) {
2022-07-16 16:19:30 +00:00
ListRemoveItem ( g_listNew , item ) ;
ListRemoveItem ( g_listFound , item ) ;
g_listStored - > AddForm ( item ) ;
}
}
}
2022-06-30 10:31:01 +00:00
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-07-16 16:19:30 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-16 18:14:12 +00:00
if ( ! g_artifactAllFormTypes . contains ( baseObj - > GetFormType ( ) ) | | a_ref . IsDisabled ( ) | | a_ref . IsMarkedForDeletion ( ) | | cellItems . contains ( baseObj - > formID ) ) {
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-07-16 16:19:30 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-16 16:19:30 +00:00
cellItems . insert ( baseObj - > formID ) ;
2022-07-11 19:18:07 +00:00
2022-07-16 16:19:30 +00:00
if ( inv . find ( baseObj ) = = inv . end ( ) ) {
g_cellStorage - > AddObjectToContainer ( baseObj , nullptr , 1 , nullptr ) ;
}
2022-06-30 10:31:01 +00:00
2022-07-16 18:14:12 +00:00
if ( IsArtifact ( baseObj ) & & ! g_listStored - > HasForm ( baseObj ) ) {
2022-07-16 16:19:30 +00:00
ListRemoveItem ( g_listNew , baseObj ) ;
ListRemoveItem ( g_listFound , baseObj ) ;
g_listStored - > AddForm ( baseObj ) ;
}
2022-07-06 01:14:05 +00:00
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-07-16 16:19:30 +00:00
} ) ;
2022-07-06 01:14:05 +00:00
2022-07-16 16:19:30 +00:00
for ( const auto & [ item , data ] : inv ) {
const auto & [ count , entry ] = data ;
if ( count > 0 & & ! cellItems . contains ( item - > formID ) ) {
g_cellStorage - > RemoveItem ( item , count , RE : : ITEM_REMOVE_REASON : : kRemove , nullptr , nullptr ) ;
2023-09-09 21:02:35 +00:00
if ( IsArtifact ( item ) & & ! RefListHasItem ( g_persistentStorage , item - > formID ) ) {
2022-07-16 16:19:30 +00:00
ListRemoveItem ( g_listStored , item ) ;
if ( GetItemCount ( RE : : PlayerCharacter : : GetSingleton ( ) , item ) | | FollowersHaveItem ( item ) ) {
ListRemoveItem ( g_listNew , item ) ;
g_listFound - > AddForm ( item ) ;
} else {
ListRemoveItem ( g_listFound , item ) ;
g_listNew - > AddForm ( item ) ;
}
2022-07-06 01:14:05 +00:00
}
2022-06-30 10:31:01 +00:00
}
}
2022-07-16 16:19:30 +00:00
cellItems . clear ( ) ;
} ) ;
2022-06-30 10:31:01 +00:00
}
void OnContainerChanged ( const RE : : TESContainerChangedEvent * a_event , RE : : TESForm * form )
{
2022-07-04 00:30:51 +00:00
if ( a_event - > newContainer ) { // added to a container or actor
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( a_event - > newContainer = = 0x14 ) { // acquired by player
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( a_event - > oldContainer ) {
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( const auto it = g_persistentMap . find ( a_event - > oldContainer ) ; it ! = g_persistentMap . end ( ) ) { // moved from a persistent container
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
const auto ref = it - > second ;
2022-06-30 10:31:01 +00:00
2022-07-06 00:46:35 +00:00
if ( ref & & ! GetItemCount ( ref , form ) ) { // no items left in the container
2022-07-04 00:30:51 +00:00
for ( const auto & persref : g_persistentMap ) {
if ( persref . second ! = ref ) {
2022-07-04 12:13:47 +00:00
if ( GetItemCount ( persref . second , form ) ) {
2022-07-04 00:30:51 +00:00
// if other containers have it, do nothing
return ;
}
}
}
ListRemoveItem ( g_listStored , form ) ;
g_listFound - > AddForm ( form ) ;
}
2022-07-04 12:13:47 +00:00
return ;
2022-06-30 10:31:01 +00:00
2022-07-04 12:13:47 +00:00
} else if ( g_cellStorage ) { // taken from a container at home
if ( ! g_bHomeContainer ) {
const auto container = RE : : TESForm : : LookupByID < RE : : TESObjectREFR > ( a_event - > oldContainer ) ;
if ( container & & ! GetItemCount ( container , form ) ) {
2022-07-05 15:52:30 +00:00
SyncCellStorage ( container ) ;
2022-07-04 12:13:47 +00:00
}
2022-07-04 00:30:51 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-04 12:13:47 +00:00
return ;
2022-07-04 00:30:51 +00:00
}
2022-06-30 10:31:01 +00:00
}
2022-07-04 00:30:51 +00:00
if ( ! g_listStored - > HasForm ( form ) & & ! g_listFound - > HasForm ( form ) ) { // it's a new item, move it to found
ListRemoveItem ( g_listNew , form ) ;
g_listFound - > AddForm ( form ) ;
2022-07-11 22:37:19 +00:00
if ( g_bNotifyNewArtifact ) {
if ( g_bTakeAll ) {
g_bTakeAllCount + + ;
} else {
2022-07-14 12:30:14 +00:00
//RE::DebugNotification(fmt::format("New artifact acquired: {}", form->GetName()).c_str());
RE : : BSTSmartPointer < RE : : BSScript : : IStackCallbackFunctor > stackCallback ;
RE : : BSScript : : Internal : : VirtualMachine : : GetSingleton ( ) - > DispatchStaticCall ( " ETR_NewArtifactNotification " , " Show " , RE : : MakeFunctionArguments < RE : : TESForm * > ( std : : move ( form ) ) , stackCallback ) ;
2022-07-11 22:37:19 +00:00
}
}
2022-07-04 00:30:51 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else if ( g_cellStorage & & g_cellStorage - > formID = = a_event - > newContainer ) {
return ; // ignore cell storage
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else if ( g_persistentMap . contains ( a_event - > newContainer ) ) { // stored in a registered persistent container
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( ! g_listStored - > HasForm ( form ) ) {
ListRemoveItem ( g_listFound , form ) ;
g_listStored - > AddForm ( form ) ;
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else {
const auto ref = RE : : TESForm : : LookupByID ( a_event - > newContainer ) ;
if ( ref - > Is ( RE : : FormType : : ActorCharacter ) ) {
if ( ref - > As < RE : : Actor > ( ) - > IsPlayerTeammate ( ) ) { // acquired by companion
if ( ! g_listFound - > HasForm ( form ) & & ! g_listStored - > HasForm ( form ) ) {
ListRemoveItem ( g_listNew , form ) ;
g_listFound - > AddForm ( form ) ;
}
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else {
const auto container = ref - > As < RE : : TESObjectREFR > ( ) ;
if ( container ) {
2022-07-04 12:13:47 +00:00
if ( g_cellStorage & & IsInSameCell ( container ) ) { // stored at home
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( ! g_bHomeContainer & & ! g_listStored - > HasForm ( form ) ) {
ListRemoveItem ( g_listFound , form ) ;
ListRemoveItem ( g_listNew , form ) ;
g_listStored - > AddForm ( form ) ;
}
2022-07-18 13:13:23 +00:00
} else if ( a_event - > oldContainer = = 0x14 & & ! g_listStored - > HasForm ( form ) ) {
SKSE : : GetTaskInterface ( ) - > AddTask ( [ form ] ( ) {
if ( ! GetItemCount ( RE : : PlayerCharacter : : GetSingleton ( ) , form ) & & ! FollowersHaveItem ( form ) ) {
// disposed by player
ListRemoveItem ( g_listFound , form ) ;
g_listNew - > AddForm ( form ) ;
}
} ) ;
2022-07-04 00:30:51 +00:00
}
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
}
2022-07-04 00:30:51 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else if ( a_event - > oldContainer ) { // removed from container
if ( g_cellStorage & & a_event - > reference ) { // dropped or placed on rack at home by any actor
2022-07-04 12:13:47 +00:00
if ( a_event - > oldContainer ! = 0x14 ) {
const auto ref = RE : : TESForm : : LookupByID < RE : : TESObjectREFR > ( a_event - > oldContainer ) ;
if ( ! ref | | ! IsInSameCell ( ref ) ) {
return ;
}
}
if ( ! GetItemCount ( g_cellStorage , form ) ) {
2022-07-04 00:30:51 +00:00
# ifdef _DEBUG
2022-07-11 11:41:07 +00:00
log : : info ( " Added dropped {} to cell storage " , form - > GetName ( ) ) ;
2022-07-04 00:30:51 +00:00
RE : : DebugNotification ( " Adding to cell storage " ) ;
# endif
g_cellStorage - > AddObjectToContainer ( form - > As < RE : : TESBoundObject > ( ) , nullptr , 1 , nullptr ) ;
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
if ( ! g_listStored - > HasForm ( form ) ) {
2022-07-03 14:37:56 +00:00
ListRemoveItem ( g_listFound , form ) ;
ListRemoveItem ( g_listNew , form ) ;
2022-07-04 00:30:51 +00:00
g_listStored - > AddForm ( form ) ;
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-11 14:36:22 +00:00
} else if ( a_event - > oldContainer = = 0x14 ) { // dropped, consumed, dismantled, removed by script
2022-06-30 10:31:01 +00:00
2022-07-03 14:37:56 +00:00
if ( ! g_listStored - > HasForm ( form ) ) {
2022-07-18 13:13:23 +00:00
// Seems like OnContainerChanged runs concurrently with updating ContainerChanges.
// In small modlists ContainerChanges may not be propagated yet in this event, so we need to schedule GetItemCount.
SKSE : : GetTaskInterface ( ) - > AddTask ( [ form ] ( ) {
if ( ! GetItemCount ( RE : : PlayerCharacter : : GetSingleton ( ) , form ) & & ! FollowersHaveItem ( form ) ) {
ListRemoveItem ( g_listFound , form ) ;
g_listNew - > AddForm ( form ) ;
2022-07-04 00:30:51 +00:00
2022-07-18 13:13:23 +00:00
} else if ( ! g_listFound - > HasForm ( form ) ) {
ListRemoveItem ( g_listNew , form ) ;
g_listFound - > AddForm ( form ) ;
}
} ) ;
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else if ( g_cellStorage & & g_cellStorage - > formID = = a_event - > oldContainer ) {
return ; // ignore cell storage
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
} else if ( const auto it = g_persistentMap . find ( a_event - > oldContainer ) ; it ! = g_persistentMap . end ( ) ) { // deleted from a persistent container
2022-06-30 10:31:01 +00:00
2022-07-04 00:30:51 +00:00
const auto ref = it - > second ;
2022-06-30 10:31:01 +00:00
2022-07-04 12:13:47 +00:00
if ( ref & & ! GetItemCount ( ref , form ) ) { // no items left in the container
2022-07-04 00:30:51 +00:00
for ( const auto & persref : g_persistentMap ) {
if ( persref . second ! = ref ) {
2022-07-04 12:13:47 +00:00
if ( GetItemCount ( persref . second , form ) ) {
2022-07-04 00:30:51 +00:00
// if other containers have it, do nothing
return ;
}
}
}
ListRemoveItem ( g_listStored , form ) ;
if ( GetItemCount ( RE : : PlayerCharacter : : GetSingleton ( ) , form ) | | FollowersHaveItem ( form ) ) {
g_listFound - > AddForm ( form ) ;
} else {
g_listNew - > AddForm ( form ) ;
}
}
} else {
const auto ref = RE : : TESForm : : LookupByID ( a_event - > oldContainer ) ;
if ( ref - > Is ( RE : : FormType : : ActorCharacter ) ) {
2022-07-06 00:46:35 +00:00
const auto actor = ref - > As < RE : : Actor > ( ) ;
if ( actor & & actor - > IsPlayerTeammate ( ) & & ! GetItemCount ( actor , form ) ) { // removed from companion (probably, disarmed)
if ( g_listFound - > HasForm ( form ) ) {
2022-07-04 00:30:51 +00:00
2022-07-04 12:13:47 +00:00
if ( ! GetItemCount ( RE : : PlayerCharacter : : GetSingleton ( ) , form ) ) {
2022-07-04 00:30:51 +00:00
// player does not have it, check companions
if ( const auto processLists = RE : : ProcessLists : : GetSingleton ( ) ; processLists ) {
for ( auto & actorHandle : processLists - > highActorHandles ) {
if ( auto actor = actorHandle . get ( ) ; actor & & actor - > IsPlayerTeammate ( ) & & actor - > formID ! = ref - > formID ) {
2022-07-04 12:13:47 +00:00
if ( GetItemCount ( actor . get ( ) , form ) ) {
2022-07-04 00:30:51 +00:00
// other companion has it, do nothing
return ;
}
}
}
}
ListRemoveItem ( g_listFound , form ) ;
g_listNew - > AddForm ( form ) ;
}
}
2022-07-03 14:37:56 +00:00
}
2022-07-04 00:30:51 +00:00
} else {
const auto container = ref - > As < RE : : TESObjectREFR > ( ) ;
if ( container ) {
2022-07-11 14:36:22 +00:00
if ( g_cellStorage & & IsInSameCell ( container ) ) { // removed from container at home
2022-07-04 00:30:51 +00:00
2022-07-04 12:13:47 +00:00
if ( ! GetItemCount ( container , form ) ) {
2022-07-05 15:52:30 +00:00
SyncCellStorage ( container ) ;
2022-07-04 00:30:51 +00:00
}
}
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
}
2022-07-03 14:37:56 +00:00
}
2022-06-30 10:31:01 +00:00
}
}
void AddRefArtifactsToList ( RE : : TESForm * a_refOrList , RE : : BGSListForm * a_targetList , RE : : BGSListForm * a_excludeList )
{
if ( ! a_refOrList | | ! a_targetList ) {
2022-07-11 11:41:07 +00:00
log : : warn ( " Invalid arguments in AddRefArtifactsToList " ) ;
2022-06-30 10:31:01 +00:00
return ;
}
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 ) {
AddRefArtifactsToList ( refrItem , a_targetList , a_excludeList ) ;
}
2022-12-01 00:39:28 +00:00
return RE : : BSContainer : : ForEachResult : : kContinue ;
2022-06-30 10:31:01 +00:00
} ) ;
return ;
}
const auto containerRef = a_refOrList - > As < RE : : TESObjectREFR > ( ) ;
if ( ! containerRef ) {
2022-07-11 11:41:07 +00:00
log : : warn ( " containerRef in AddRefArtifactsToList is not a reference " ) ;
2022-06-30 10:31:01 +00:00
return ;
}
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 ) ;
2022-07-02 21:22:58 +00:00
ListRemoveItem ( g_listNew , item . first ) ;
2022-06-30 10:31:01 +00:00
}
}
}
2022-07-09 12:30:51 +00:00
void RescanFoundArtifacts ( )
{
ListRevert ( g_listFound ) ;
AddRefArtifactsToList ( RE : : PlayerCharacter : : GetSingleton ( ) , g_listFound , g_listStored ) ;
for ( const auto & ref : GetPlayerFollowers ( ) ) {
AddRefArtifactsToList ( ref , g_listFound , g_listStored ) ;
}
}
2022-07-11 11:41:07 +00:00
void RescanStoredArtifacts ( )
{
ListRevert ( g_listStored ) ;
AddRefArtifactsToList ( g_persistentStorage , g_listStored ) ;
}
void RescanNewArtifacts ( )
{
for ( auto const & item : g_artifactMap ) {
if ( ! g_listNew - > HasForm ( item . second ) & & ! g_listStored - > HasForm ( item . second ) & & ! g_listFound - > HasForm ( item . second ) ) {
g_listNew - > AddForm ( item . second ) ;
}
}
}
2022-07-09 12:30:51 +00:00
void OnLocationChange ( )
{
2022-07-11 14:36:22 +00:00
std : : int32_t iCurrentFollowers = 0 ;
2022-07-09 12:30:51 +00:00
for ( const auto & actor : GetPlayerFollowers ( ) ) {
iCurrentFollowers + = actor - > formID ;
}
if ( iCurrentFollowers ! = g_iFollowerIndex ) {
g_iFollowerIndex = iCurrentFollowers ;
std : : thread ( [ ] ( ) {
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 3000 ) ) ; // wait for followers to load into the new cell
2022-07-16 16:19:30 +00:00
SKSE : : GetTaskInterface ( ) - > AddTask ( [ ] ( ) {
2022-07-15 18:36:26 +00:00
RescanFoundArtifacts ( ) ;
} ) ;
2022-07-09 12:30:51 +00:00
} ) . detach ( ) ;
}
}
2022-06-30 10:31:01 +00:00
}