#include "EventListener.h" #include "ArtifactTracker.h" #include "Util.h" auto EventListener::GetSingleton() -> EventListener* { static EventListener singleton{}; return std::addressof(singleton); } void EventListener::Install() { RE::PlayerCharacter::GetSingleton()->AddEventSink(EventListener::GetSingleton()); RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink(EventListener::GetSingleton()); RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink(EventListener::GetSingleton()); RE::UI::GetSingleton()->AddEventSink(EventListener::GetSingleton()); } auto EventListener::ProcessEvent( const SKSE::ModCallbackEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { if (a_event->eventName == "KID_KeywordDistributionDone") { ArtifactTracker::Init(true); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::TESContainerChangedEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { const auto form = ArtifactTracker::GetArtifactByID(a_event->baseObj); if (form) { ArtifactTracker::OnContainerChanged(a_event, form); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::BGSActorCellEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { // Fires on every cell change, loaded or not. // If it's new and not loaded, we can't add a new cell storage. // In this case, it registers TESCellFullyLoadedEvent, which ensures a new ref can be added. if (a_event->flags == RE::BGSActorCellEvent::CellFlag::kEnter) { #ifdef _DEBUG SKSE::log::info("BGSActorCellEvent"); #endif ArtifactTracker::OnCellEnter(a_event->cellID); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::TESCellFullyLoadedEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { #ifdef _DEBUG SKSE::log::info("TESCellFullyLoadedEvent"); #endif ArtifactTracker::OnCellEnter(a_event->cell->GetLocation(), a_event->cell); return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::MenuOpenCloseEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { if (a_event->menuName == "ContainerMenu") { #ifdef _DEBUG SKSE::log::info("MenuOpenCloseEvent"); #endif bool bOpening = 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 stackCallback; RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("ETR_NewArtifactsCombinedNotification", "Show", RE::MakeFunctionArguments(std::move(ArtifactTracker::g_bTakeAllCount)), stackCallback); } ArtifactTracker::g_bTakeAll = false; ArtifactTracker::g_bTakeAllCount = 0; } if (ArtifactTracker::IsHome()) { ArtifactTracker::SetContainerMode(bOpening); } }); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::TESActivateEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { // This listener is expected to be unregistered outside of home. if (ArtifactTracker::IsHome() && a_event->actionRef->IsPlayerRef() && a_event->objectActivated) { const auto ref = a_event->objectActivated.get(); if (ref && ArtifactTracker::g_artifactAllFormTypes.contains(ref->GetBaseObject()->GetFormType())) { std::thread([]() { std::this_thread::sleep_for(std::chrono::milliseconds(200)); ArtifactTracker::SyncCellStorage(); }).detach(); } } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::TESActorLocationChangeEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { if (a_event->actor->IsPlayerRef() || (a_event->actor->As() && a_event->actor->As()->IsPlayerTeammate())) { ArtifactTracker::OnLocationChange(); } return RE::BSEventNotifyControl::kContinue; } RE::BSEventNotifyControl EventListener::ProcessEvent( RE::InputEvent* const* a_event, RE::BSTEventSource* a_eventSource) { auto inputEvent = a_event ? *a_event : nullptr; auto buttonEvent = inputEvent ? inputEvent->AsButtonEvent() : nullptr; if (!buttonEvent || !buttonEvent->IsPressed()) { return RE::BSEventNotifyControl::kContinue; } if (RE::UI::GetSingleton()->GameIsPaused() && RE::UI::GetSingleton()->IsItemMenuOpen() && RE::UI::GetSingleton()->IsMenuOpen("ContainerMenu")) { const auto takeAllKey = RE::ControlMap::GetSingleton()->GetMappedKey(RE::UserEvents::GetSingleton()->readyWeapon, buttonEvent->GetDevice(), RE::UserEvents::INPUT_CONTEXT_ID::kGameplay); if (takeAllKey == buttonEvent->GetIDCode()) { ArtifactTracker::g_bTakeAll = true; ArtifactTracker::g_bTakeAllCount = 0; } } return RE::BSEventNotifyControl::kContinue; }