#include "EventListener.h" #include "Util.h" auto EventListener::GetSingleton() -> EventListener* { static EventListener singleton{}; return std::addressof(singleton); } void EventListener::Install() { SKSE::GetModCallbackEventSource()->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 == "Enderal_StartPortableLab") { SKSE::GetTaskInterface()->AddTask([]() { FetchSupplies(RE::TESForm::LookupByID(0xBAD0C)->As()); // CraftingAlchemyWorkbench }); } else if (a_event->eventName == "Enderal_StartSpectralizing") { SKSE::GetTaskInterface()->AddTask([]() { FetchSpectralizingSupplies(); }); } else if (a_event->eventName == "Enderal_FinishSpectralizing") { SKSE::GetTaskInterface()->AddTask([]() { ReturnSupplies(); }); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::MenuOpenCloseEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { if (a_event->menuName != RE::CraftingMenu::MENU_NAME) { return RE::BSEventNotifyControl::kContinue; } if (a_event->opening) { RE::CraftingMenu* menu = static_cast(RE::UI::GetSingleton()->GetMenu(RE::CraftingMenu::MENU_NAME).get()); if (!menu || !menu->GetCraftingSubMenu()) { return RE::BSEventNotifyControl::kContinue; } const auto furn = menu->GetCraftingSubMenu()->furniture; if (!furn || furn->workBenchData.benchType != RE::TESFurniture::WorkBenchData::BenchType::kCreateObject || furn->As()->HasKeywordString("CraftingSmelterDismantling")) { return RE::BSEventNotifyControl::kContinue; } SKSE::GetTaskInterface()->AddTask([furn]() { if (!FetchSupplies(furn)) { return; } std::thread([]() { std::this_thread::sleep_for(std::chrono::milliseconds(50)); SKSE::GetTaskInterface()->AddTask([]() { // Trigger item list update, this trick works only with the kCreateObject workbenches if (auto scriptFactory = RE::IFormFactory::GetConcreteFormFactoryByType()) { if (auto script = scriptFactory->Create()) { script->SetCommand("player.additem 1FE82 1 1"); script->CompileAndRun(nullptr); } } RE::PlayerCharacter::GetSingleton()->RemoveItem(RE::TESForm::LookupByID(0x1FE82)->As(), 99, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr, 0, 0); }); }).detach(); }); } else { SKSE::GetTaskInterface()->AddTask([]() { ReturnSupplies(); }); } return RE::BSEventNotifyControl::kContinue; } auto EventListener::ProcessEvent( const RE::TESActivateEvent* a_event, RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl { if (!a_event->actionRef || !a_event->actionRef->IsPlayerRef() || !a_event->objectActivated) { return RE::BSEventNotifyControl::kContinue; } const auto refr = a_event->objectActivated.get(); if (!refr || !refr->GetBaseObject()->Is(RE::FormType::Furniture)) { return RE::BSEventNotifyControl::kContinue; } auto* furn = refr->GetBaseObject()->As(); if (furn->workBenchData.benchType == RE::TESFurniture::WorkBenchData::BenchType::kNone || furn->workBenchData.benchType == RE::TESFurniture::WorkBenchData::BenchType::kCreateObject) { return RE::BSEventNotifyControl::kContinue; } if (RE::PlayerCharacter::GetSingleton()->GetRace()->As()->HasKeywordString("ActorTypeCreature")) { // No crafting in the werewolf form return RE::BSEventNotifyControl::kContinue; } std::thread([furn]() { std::this_thread::sleep_for(std::chrono::milliseconds(300)); const auto playerRef = RE::PlayerCharacter::GetSingleton(); const auto sitState = playerRef->AsActorState()->GetSitSleepState(); if (sitState != RE::SIT_SLEEP_STATE::kWantToSit && sitState != RE::SIT_SLEEP_STATE::kWaitingForSitAnim) { return; } SKSE::GetTaskInterface()->AddTask([furn]() { if (!FetchSupplies(furn)) { return; } std::thread([]() { const auto playerRef = RE::PlayerCharacter::GetSingleton(); const auto sitState = playerRef->AsActorState()->GetSitSleepState(); while (sitState == RE::SIT_SLEEP_STATE::kWantToSit || sitState == RE::SIT_SLEEP_STATE::kWaitingForSitAnim) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); if (!RE::UI::GetSingleton()->IsMenuOpen(RE::CraftingMenu::MENU_NAME)) { SKSE::GetTaskInterface()->AddTask([]() { ReturnSupplies(); }); } }).detach(); }); }).detach(); return RE::BSEventNotifyControl::kContinue; }