Compare commits
4 Commits
1fedd07be1
...
c7c9017ce8
Author | SHA1 | Date | |
---|---|---|---|
c7c9017ce8 | |||
34046f60db | |||
ea079eafae | |||
deaac1c723 |
@ -21,3 +21,9 @@ Keyword = ETR_ExtraArtifact|Armor|TGMark,SL01AmuletsSkyrim.esp
|
||||
|
||||
; Exclude Hendraheim clutter
|
||||
Keyword = ETR_NotArtifact|Misc Item|cceejsse004-hall.esl,TGMark
|
||||
|
||||
; CACO pond fish - get the CACO+Fishing CC patch from kryptopyr's Patch Hub
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|TGMark,0x33F5D5~Complete Alchemy & Cooking Overhaul.esp,0x32608D~Complete Alchemy & Cooking Overhaul.esp,0x33F5DC~Complete Alchemy & Cooking Overhaul.esp,0x33F5DA~Complete Alchemy & Cooking Overhaul.esp,0x3302A5~Complete Alchemy & Cooking Overhaul.esp,0x3302AA~Complete Alchemy & Cooking Overhaul.esp,0x33A4D2~Complete Alchemy & Cooking Overhaul.esp,0x33F5D7~Complete Alchemy & Cooking Overhaul.esp,0x32608F~Complete Alchemy & Cooking Overhaul.esp,0x3302A6~Complete Alchemy & Cooking Overhaul.esp,0x3353B6~Complete Alchemy & Cooking Overhaul.esp,0x33F5D9~Complete Alchemy & Cooking Overhaul.esp,0x326087~Complete Alchemy & Cooking Overhaul.esp,0x3353B0~Complete Alchemy & Cooking Overhaul.esp,0x32609E~Complete Alchemy & Cooking Overhaul.esp,0x32608E~Complete Alchemy & Cooking Overhaul.esp
|
||||
|
||||
; CACO salmon
|
||||
Keyword = ETR_ExtraArtifact|Potion|TGMark,0xCCA147~Update.esm,0xCCA148~Update.esm
|
||||
|
@ -52,6 +52,9 @@ Keyword = ETR_NotArtifact|Weapon|WeapTypeStaff|-E
|
||||
; Exclude unenchanted clothes
|
||||
Keyword = ETR_NotArtifact|Armor||-E,CLOTHING
|
||||
|
||||
; Pond fish
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|0x106E1C,0x106E1B,0x106E1A,0x106E19,0x106E18
|
||||
|
||||
; Free Creation Club mods
|
||||
Keyword = ETR_ExtraArtifact|Potion|TGMark,0x88B~ccBGSSSE001-Fish.esm,0x890~ccBGSSSE001-Fish.esm,0x891~ccBGSSSE001-Fish.esm,0x896~ccBGSSSE001-Fish.esm,0x897~ccBGSSSE001-Fish.esm,0x898~ccBGSSSE001-Fish.esm,0x89B~ccBGSSSE001-Fish.esm,0x89C~ccBGSSSE001-Fish.esm,0x89E~ccBGSSSE001-Fish.esm,0x8A0~ccBGSSSE001-Fish.esm,0x8A1~ccBGSSSE001-Fish.esm,0x8A2~ccBGSSSE001-Fish.esm,0x8A3~ccBGSSSE001-Fish.esm,0x8A4~ccBGSSSE001-Fish.esm,0xF25~ccBGSSSE001-Fish.esm
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|ccBGSSSE001-Fish.esm,TGMark
|
||||
|
Binary file not shown.
@ -6,7 +6,7 @@ message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.")
|
||||
########################################################################################################################
|
||||
project(
|
||||
ArtifactTracker
|
||||
VERSION 1.0.2
|
||||
VERSION 1.0.3
|
||||
DESCRIPTION "Artifact Tracker"
|
||||
LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
@ -23,6 +23,7 @@ namespace ArtifactTracker
|
||||
RE::BGSKeyword* g_homeKeyword;
|
||||
std::unordered_map<RE::FormID, RE::TESForm*> g_artifactMap;
|
||||
std::unordered_set<RE::FormType> g_artifactFormTypes;
|
||||
std::unordered_set<RE::FormType> g_artifactAllFormTypes;
|
||||
std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
|
||||
RE::TESObjectREFR* g_cellStorage;
|
||||
const SKSE::LoadInterface* g_loadInterface;
|
||||
@ -72,6 +73,14 @@ namespace ArtifactTracker
|
||||
|
||||
// Preloading item lists
|
||||
|
||||
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);
|
||||
|
||||
g_artifactFormTypes.insert(RE::FormType::Weapon);
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectWEAP>()) {
|
||||
if (form->GetPlayable() && !form->IsBound() && !form->weaponData.flags.all(RE::TESObjectWEAP::Data::Flag::kCantDrop)) {
|
||||
@ -269,9 +278,7 @@ namespace ArtifactTracker
|
||||
g_bBookShelf = false;
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
});
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
}).detach();
|
||||
} else {
|
||||
SyncCellStorage();
|
||||
@ -377,8 +384,8 @@ namespace ArtifactTracker
|
||||
log::info("Adding new storage in {}", cell->GetName());
|
||||
#endif
|
||||
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
||||
SKSE::GetTaskInterface()->AddTask([]() {
|
||||
const auto cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
||||
|
||||
if (cellStorage) {
|
||||
cellStorage->Disable();
|
||||
@ -406,83 +413,86 @@ namespace ArtifactTracker
|
||||
log::info("Running SyncCellStorage");
|
||||
#endif
|
||||
|
||||
std::unordered_set<RE::FormID> cellItems;
|
||||
const RE::FormID ignoreFormID = a_ignoreRef ? a_ignoreRef->formID : NULL;
|
||||
|
||||
const auto cell = g_cellStorage->GetParentCell();
|
||||
const auto inv = g_cellStorage->GetInventory();
|
||||
SKSE::GetTaskInterface()->AddTask([ignoreFormID]() {
|
||||
std::unordered_set<RE::FormID> cellItems;
|
||||
|
||||
cell->ForEachReference([&](RE::TESObjectREFR& a_ref) {
|
||||
if (a_ignoreRef && a_ignoreRef->formID == a_ref.formID) {
|
||||
return true;
|
||||
}
|
||||
const auto cell = g_cellStorage->GetParentCell();
|
||||
const auto inv = g_cellStorage->GetInventory();
|
||||
|
||||
const auto baseObj = a_ref.GetBaseObject();
|
||||
|
||||
if (IsValidContainer(&a_ref)) {
|
||||
if (g_cellContainer == baseObj || baseObj->formID == 0xDC9E7 || g_persistentMap.contains(a_ref.formID)) { // skip persistent and PlayerBookShelfContainer
|
||||
cell->ForEachReference([&](RE::TESObjectREFR& a_ref) {
|
||||
if (ignoreFormID && ignoreFormID == a_ref.formID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto contInv = a_ref.GetInventory([&](RE::TESBoundObject& a_object) -> bool {
|
||||
return !cellItems.contains(a_object.formID) && IsArtifact(&a_object);
|
||||
});
|
||||
const auto baseObj = a_ref.GetBaseObject();
|
||||
|
||||
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);
|
||||
if (IsValidContainer(&a_ref)) {
|
||||
if (g_cellContainer == baseObj || baseObj->formID == 0xDC9E7 || g_persistentMap.contains(a_ref.formID)) { // skip persistent and PlayerBookShelfContainer
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto contInv = a_ref.GetInventory([&](RE::TESBoundObject& a_object) -> bool {
|
||||
return !cellItems.contains(a_object.formID) && g_artifactAllFormTypes.contains(a_object.GetFormType());
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
if (IsArtifact(item) && !g_listStored->HasForm(item)) {
|
||||
ListRemoveItem(g_listNew, item);
|
||||
ListRemoveItem(g_listFound, item);
|
||||
g_listStored->AddForm(item);
|
||||
}
|
||||
}
|
||||
if (!g_listStored->HasForm(item)) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!g_artifactAllFormTypes.contains(baseObj->GetFormType()) || a_ref.IsDisabled() || a_ref.IsMarkedForDeletion() || cellItems.contains(baseObj->formID)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cellItems.insert(baseObj->formID);
|
||||
|
||||
if (inv.find(baseObj) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(baseObj, nullptr, 1, nullptr);
|
||||
}
|
||||
|
||||
if (IsArtifact(baseObj) && !g_listStored->HasForm(baseObj)) {
|
||||
ListRemoveItem(g_listNew, baseObj);
|
||||
ListRemoveItem(g_listFound, baseObj);
|
||||
g_listStored->AddForm(baseObj);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
if (IsArtifact(item) && !RefListHasItem(g_persistentStorage, item->formID)) {
|
||||
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_listStored->AddForm(item);
|
||||
g_listNew->AddForm(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a_ref.IsDisabled() || a_ref.IsMarkedForDeletion() || cellItems.contains(baseObj->formID) || !IsArtifact(baseObj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cellItems.insert(baseObj->formID);
|
||||
|
||||
if (inv.find(baseObj) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(baseObj, nullptr, 1, nullptr);
|
||||
}
|
||||
|
||||
if (!g_listStored->HasForm(baseObj)) {
|
||||
ListRemoveItem(g_listNew, baseObj);
|
||||
ListRemoveItem(g_listFound, baseObj);
|
||||
g_listStored->AddForm(baseObj);
|
||||
}
|
||||
|
||||
return true;
|
||||
cellItems.clear();
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
if (!RefListHasItem(g_persistentStorage, item->formID)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellItems.clear();
|
||||
}
|
||||
|
||||
void OnContainerChanged(const RE::TESContainerChangedEvent* a_event, RE::TESForm* form)
|
||||
@ -759,7 +769,7 @@ namespace ArtifactTracker
|
||||
g_iFollowerIndex = iCurrentFollowers;
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(3000)); // wait for followers to load into the new cell
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
SKSE::GetTaskInterface()->AddTask([]() {
|
||||
RescanFoundArtifacts();
|
||||
});
|
||||
}).detach();
|
||||
|
@ -16,6 +16,7 @@ namespace ArtifactTracker
|
||||
extern RE::BGSKeyword* g_homeKeyword;
|
||||
extern std::unordered_map<RE::FormID, RE::TESForm*> g_artifactMap;
|
||||
extern std::unordered_set<RE::FormType> g_artifactFormTypes;
|
||||
extern std::unordered_set<RE::FormType> g_artifactAllFormTypes;
|
||||
extern std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
|
||||
extern RE::TESObjectREFR* g_cellStorage;
|
||||
extern const SKSE::LoadInterface* g_loadInterface;
|
||||
|
@ -84,22 +84,26 @@ auto EventListener::ProcessEvent(
|
||||
SKSE::log::info("MenuOpenCloseEvent");
|
||||
#endif
|
||||
|
||||
if (a_event->opening) {
|
||||
RE::BSInputDeviceManager::GetSingleton()->AddEventSink(EventListener::GetSingleton());
|
||||
} else {
|
||||
RE::BSInputDeviceManager::GetSingleton()->RemoveEventSink(EventListener::GetSingleton());
|
||||
if (ArtifactTracker::g_bTakeAll && ArtifactTracker::g_bNotifyNewArtifact && ArtifactTracker::g_bTakeAllCount > 0) {
|
||||
//RE::DebugNotification(fmt::format("{} new artifact(s) acquired", ArtifactTracker::g_bTakeAllCount).c_str());
|
||||
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
|
||||
RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("ETR_NewArtifactsCombinedNotification", "Show", RE::MakeFunctionArguments<std::uint32_t>(std::move(ArtifactTracker::g_bTakeAllCount)), stackCallback);
|
||||
}
|
||||
ArtifactTracker::g_bTakeAll = false;
|
||||
ArtifactTracker::g_bTakeAllCount = 0;
|
||||
}
|
||||
bool bOpening = a_event->opening;
|
||||
|
||||
if (ArtifactTracker::IsHome()) {
|
||||
ArtifactTracker::SetContainerMode(a_event->opening);
|
||||
}
|
||||
SKSE::GetTaskInterface()->AddTask([bOpening]() {
|
||||
if (bOpening) {
|
||||
RE::BSInputDeviceManager::GetSingleton()->AddEventSink(EventListener::GetSingleton());
|
||||
} else {
|
||||
RE::BSInputDeviceManager::GetSingleton()->RemoveEventSink(EventListener::GetSingleton());
|
||||
if (ArtifactTracker::g_bTakeAll && ArtifactTracker::g_bNotifyNewArtifact && ArtifactTracker::g_bTakeAllCount > 0) {
|
||||
//RE::DebugNotification(fmt::format("{} new artifact(s) acquired", ArtifactTracker::g_bTakeAllCount).c_str());
|
||||
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
|
||||
RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("ETR_NewArtifactsCombinedNotification", "Show", RE::MakeFunctionArguments<std::uint32_t>(std::move(ArtifactTracker::g_bTakeAllCount)), stackCallback);
|
||||
}
|
||||
ArtifactTracker::g_bTakeAll = false;
|
||||
ArtifactTracker::g_bTakeAllCount = 0;
|
||||
}
|
||||
|
||||
if (ArtifactTracker::IsHome()) {
|
||||
ArtifactTracker::SetContainerMode(bOpening);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return RE::BSEventNotifyControl::kContinue;
|
||||
@ -116,9 +120,7 @@ auto EventListener::ProcessEvent(
|
||||
if (ref && ArtifactTracker::IsArtifact(ref->GetBaseObject())) {
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
});
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
||||
"name": "artifact-tracker",
|
||||
"version-string": "1.0.2",
|
||||
"version-string": "1.0.3",
|
||||
"port-version": 0,
|
||||
"description": "Artifact Tracker",
|
||||
"homepage": "https://eddoursul.win/mods/artifact-tracker/",
|
||||
|
Loading…
Reference in New Issue
Block a user