diff --git a/include/ArmorAddonOverrideService.h b/include/ArmorAddonOverrideService.h index 435c927..f81242f 100644 --- a/include/ArmorAddonOverrideService.h +++ b/include/ArmorAddonOverrideService.h @@ -62,8 +62,12 @@ class ArmorAddonOverrideService { public: typedef Outfit Outfit; static constexpr std::uint32_t signature = 'AAOS'; - // Uses protobufs starting with V4 - enum { kSaveVersionV1 = 1, kSaveVersionV2 = 2, kSaveVersionV3 = 3, kSaveVersionV4 = 4 }; + enum { + kSaveVersionV1 = 1, + kSaveVersionV2 = 2, + kSaveVersionV3 = 3, + kSaveVersionV4 = 4 // First version with protobuf + }; // static constexpr std::uint32_t ce_outfitNameMaxLength = 256; // SKSE caps serialized std::strings and const char*s to 256 bytes. // @@ -124,7 +128,8 @@ class ArmorAddonOverrideService { void setOutfit(const char* name, RE::Actor* target); void addActor(RE::Actor* target); void removeActor(RE::Actor* target); - // + std::unordered_set listActors(); + // void setLocationBasedAutoSwitchEnabled(bool) noexcept; void setOutfitUsingLocation(LocationType location, RE::Actor* target); void setLocationOutfit(LocationType location, const char* name, RE::Actor* target); diff --git a/include/version.h b/include/version.h index 31536a2..15e7fc9 100644 --- a/include/version.h +++ b/include/version.h @@ -5,8 +5,8 @@ #define SKYRIMOUTFITSYSTEMSE_MAKE_STR(x) SKYRIMOUTFITSYSTEMSE_MAKE_STR_HELPER(x) #define SKYRIMOUTFITSYSTEMSE_VERSION_MAJOR 0 -#define SKYRIMOUTFITSYSTEMSE_VERSION_MINOR 3 -#define SKYRIMOUTFITSYSTEMSE_VERSION_PATCH 1 +#define SKYRIMOUTFITSYSTEMSE_VERSION_MINOR 4 +#define SKYRIMOUTFITSYSTEMSE_VERSION_PATCH 0 #define SKYRIMOUTFITSYSTEMSE_VERSION_BETA 0 #define SKYRIMOUTFITSYSTEMSE_VERSION_VERSTRING SKYRIMOUTFITSYSTEMSE_MAKE_STR(SKYRIMOUTFITSYSTEMSE_VERSION_MAJOR) "." SKYRIMOUTFITSYSTEMSE_MAKE_STR(SKYRIMOUTFITSYSTEMSE_VERSION_MINOR) "." SKYRIMOUTFITSYSTEMSE_MAKE_STR(SKYRIMOUTFITSYSTEMSE_VERSION_PATCH) "." SKYRIMOUTFITSYSTEMSE_MAKE_STR(SKYRIMOUTFITSYSTEMSE_VERSION_BETA) diff --git a/mod_files/interface/translations/skyrimoutfitsystem_english.txt b/mod_files/interface/translations/skyrimoutfitsystem_english.txt index 398dfa1..3fcf5e1 100644 Binary files a/mod_files/interface/translations/skyrimoutfitsystem_english.txt and b/mod_files/interface/translations/skyrimoutfitsystem_english.txt differ diff --git a/src/ArmorAddonOverrideService.cpp b/src/ArmorAddonOverrideService.cpp index 1260996..974c6db 100644 --- a/src/ArmorAddonOverrideService.cpp +++ b/src/ArmorAddonOverrideService.cpp @@ -344,6 +344,14 @@ void ArmorAddonOverrideService::removeActor(RE::Actor* target) { actorOutfitAssignments.erase(target); } +std::unordered_set ArmorAddonOverrideService::listActors() { + std::unordered_set actors; + for (auto& assignment : actorOutfitAssignments) { + actors.insert(assignment.first); + } + return actors; +} + void ArmorAddonOverrideService::setLocationBasedAutoSwitchEnabled(bool newValue) noexcept { locationBasedAutoSwitchEnabled = newValue; } diff --git a/src/OutfitSystem.cpp b/src/OutfitSystem.cpp index 301303b..3327886 100644 --- a/src/OutfitSystem.cpp +++ b/src/OutfitSystem.cpp @@ -121,8 +121,7 @@ namespace OutfitSystem { void RefreshArmorFor(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, - RE::Actor* target_skse) { - auto target = (RE::Actor*)(target_skse); + RE::Actor* target) { ERROR_AND_RETURN_IF(target == nullptr, "Cannot refresh armor on a None RE::Actor.", registry, stackId); auto pm = target->currentProcess; if (pm) { @@ -138,6 +137,29 @@ namespace OutfitSystem { pm->UpdateEquipment(target); } } + void RefreshArmorForAllConfiguredActors(RE::BSScript::IVirtualMachine* registry, + std::uint32_t stackId, + RE::StaticFunctionTag*) { + auto& service = ArmorAddonOverrideService::GetInstance(); + auto actors = service.listActors(); + for (auto& actor : actors) { + if (!actor) continue; + auto pm = actor->currentProcess; + if (pm) { + // + // "SetEquipFlag" tells the process manager that the RE::Actor's + // equipment has changed, and that their ArmorAddons should + // be updated. If you need to find it in Skyrim Special, you + // should see a call near the start of EquipManager's func- + // tion to equip an item. + // + // NOTE: AIProcess is also called as RE::ActorProcessManager + pm->SetEquipFlag(RE::AIProcess::Flag::kUnk01); + pm->UpdateEquipment(actor); + } + } + } + std::vector ActorsNearPC(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*) { @@ -546,9 +568,11 @@ namespace OutfitSystem { } RE::BSFixedString GetSelectedOutfit(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, - RE::StaticFunctionTag*) { + RE::StaticFunctionTag*, + RE::Actor* actor) { + if (!actor) return RE::BSFixedString(""); auto& service = ArmorAddonOverrideService::GetInstance(); - return service.currentOutfit(RE::PlayerCharacter::GetSingleton()).name.c_str(); + return service.currentOutfit(actor).name.c_str(); } bool IsEnabled(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*) { auto& service = ArmorAddonOverrideService::GetInstance(); @@ -699,9 +723,11 @@ namespace OutfitSystem { void SetSelectedOutfit(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, + RE::Actor* actor, RE::BSFixedString name) { + if (!actor) return; auto& service = ArmorAddonOverrideService::GetInstance(); - service.setOutfit(name.data(), RE::PlayerCharacter::GetSingleton()); + service.setOutfit(name.data(), actor); } void AddActor(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, @@ -717,6 +743,24 @@ namespace OutfitSystem { auto& service = ArmorAddonOverrideService::GetInstance(); service.removeActor((RE::Actor*)target); } + std::vector ListActors(RE::BSScript::IVirtualMachine* registry, + std::uint32_t stackId, + RE::StaticFunctionTag*) { + auto& service = ArmorAddonOverrideService::GetInstance(); + auto actors = service.listActors(); + std::vector actorVec; + for (auto& actor : actors) { + actorVec.push_back(actor); + } + std::sort( + actorVec.begin(), + actorVec.end(), + [](const RE::Actor* x, const RE::Actor* y) { + return x < y; + } + ); + return actorVec; + } void SetLocationBasedAutoSwitchEnabled(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, @@ -795,14 +839,14 @@ namespace OutfitSystem { .value_or(LocationType::World)); } void SetOutfitUsingLocation(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, - + RE::Actor* actor, RE::BGSLocation* location_skse, RE::TESWeather* weather_skse) { // NOTE: Location can be NULL. auto& service = ArmorAddonOverrideService::GetInstance(); - + if (!actor) return; if (service.locationBasedAutoSwitchEnabled) { - auto location = identifyLocation((RE::BGSLocation*)location_skse, (RE::TESWeather*)weather_skse); + auto location = identifyLocation(location_skse, weather_skse); // Debug notifications for location classification. /* const char* locationName = locationTypeStrings[static_cast(location)]; @@ -811,35 +855,38 @@ namespace OutfitSystem { RE::DebugNotification(message, nullptr, false); */ if (location.has_value()) { - service.setOutfitUsingLocation(location.value(), RE::PlayerCharacter::GetSingleton()); + service.setOutfitUsingLocation(location.value(), actor); } } } void SetLocationOutfit(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, - + RE::Actor* actor, std::uint32_t location, RE::BSFixedString name) { + if (!actor) return; if (strcmp(name.data(), "") == 0) { // Location outfit assignment is never allowed to be empty string. Use unset instead. return; } return ArmorAddonOverrideService::GetInstance() - .setLocationOutfit(LocationType(location), name.data(), RE::PlayerCharacter::GetSingleton()); + .setLocationOutfit(LocationType(location), name.data(), actor); } void UnsetLocationOutfit(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, - + RE::Actor* actor, std::uint32_t location) { + if (!actor) return; return ArmorAddonOverrideService::GetInstance() - .unsetLocationOutfit(LocationType(location), RE::PlayerCharacter::GetSingleton()); + .unsetLocationOutfit(LocationType(location), actor); } RE::BSFixedString GetLocationOutfit(RE::BSScript::IVirtualMachine* registry, std::uint32_t stackId, RE::StaticFunctionTag*, - + RE::Actor* actor, std::uint32_t location) { + if (!actor) return RE::BSFixedString(""); auto outfit = ArmorAddonOverrideService::GetInstance() - .getLocationOutfit(LocationType(location), RE::PlayerCharacter::GetSingleton()); + .getLocationOutfit(LocationType(location), actor); if (outfit.has_value()) { return RE::BSFixedString(outfit.value().c_str()); } else { @@ -923,6 +970,11 @@ bool OutfitSystem::RegisterPapyrus(RE::BSScript::IVirtualMachine* registry) { "SkyrimOutfitSystemNativeFuncs", RefreshArmorFor ); + registry->RegisterFunction( + "RefreshArmorForAllConfiguredActors", + "SkyrimOutfitSystemNativeFuncs", + RefreshArmorForAllConfiguredActors + ); registry->RegisterFunction( "ActorNearPC", "SkyrimOutfitSystemNativeFuncs", @@ -1122,6 +1174,11 @@ bool OutfitSystem::RegisterPapyrus(RE::BSScript::IVirtualMachine* registry) { "SkyrimOutfitSystemNativeFuncs", RemoveActor ); + registry->RegisterFunction( + "ListActors", + "SkyrimOutfitSystemNativeFuncs", + ListActors + ); registry->RegisterFunction( "SetLocationBasedAutoSwitchEnabled", "SkyrimOutfitSystemNativeFuncs", diff --git a/src/hooking/PlayerSkinning_AE.cpp b/src/hooking/PlayerSkinning_AE.cpp index ac1aa56..3a5ce33 100644 --- a/src/hooking/PlayerSkinning_AE.cpp +++ b/src/hooking/PlayerSkinning_AE.cpp @@ -9,9 +9,12 @@ namespace OutfitSystem { SKSE::Trampoline* g_branchTrampoline = nullptr; bool ShouldOverrideSkinning(RE::TESObjectREFR* target) { - if (!ArmorAddonOverrideService::GetInstance().shouldOverride((RE::Actor*)target)) - return false; - return target == RE::PlayerCharacter::GetSingleton(); + if (!target) return false; + if (!ArmorAddonOverrideService::GetInstance().enabled) return false; + auto actor = skyrim_cast(target); + if (!actor) return false; + if (!ArmorAddonOverrideService::GetInstance().shouldOverride(actor)) return false; + return true; } class EquippedArmorVisitor : public RE::InventoryChanges::IItemChangeVisitor { diff --git a/src/hooking/PlayerSkinning_PRE_AE.cpp b/src/hooking/PlayerSkinning_PRE_AE.cpp index 4058050..a7977bb 100644 --- a/src/hooking/PlayerSkinning_PRE_AE.cpp +++ b/src/hooking/PlayerSkinning_PRE_AE.cpp @@ -9,9 +9,12 @@ namespace OutfitSystem { SKSE::Trampoline* g_branchTrampoline = nullptr; bool ShouldOverrideSkinning(RE::TESObjectREFR* target) { - if (!ArmorAddonOverrideService::GetInstance().shouldOverride((RE::Actor*)target)) - return false; - return target == RE::PlayerCharacter::GetSingleton(); + if (!target) return false; + if (!ArmorAddonOverrideService::GetInstance().enabled) return false; + auto actor = skyrim_cast(target); + if (!actor) return false; + if (!ArmorAddonOverrideService::GetInstance().shouldOverride(actor)) return false; + return true; } class EquippedArmorVisitor : public RE::InventoryChanges::IItemChangeVisitor { diff --git a/src/papyrus/skyoutsysautoswitchtrigger.psc b/src/papyrus/skyoutsysautoswitchtrigger.psc index d038f8c..d673088 100644 --- a/src/papyrus/skyoutsysautoswitchtrigger.psc +++ b/src/papyrus/skyoutsysautoswitchtrigger.psc @@ -5,7 +5,7 @@ Event OnLocationChange(Location akOldLoc, Location akNewLoc) ; Debug.Trace("SOS: Running OnLocationChange") GoToState("Waiting") Utility.Wait(10.0) - SkyrimOutfitSystemNativeFuncs.SetOutfitUsingLocation(Game.GetPlayer().GetCurrentLocation(), Weather.GetCurrentWeather()) + SkyrimOutfitSystemNativeFuncs.SetOutfitUsingLocation(Game.GetPlayer(), Game.GetPlayer().GetCurrentLocation(), Weather.GetCurrentWeather()) SkyrimOutfitSystemNativeFuncs.RefreshArmorFor(Game.GetPlayer()) GoToState("Listening") endEvent diff --git a/src/papyrus/skyoutsysmcm.psc b/src/papyrus/skyoutsysmcm.psc index 693be76..80db4c2 100644 --- a/src/papyrus/skyoutsysmcm.psc +++ b/src/papyrus/skyoutsysmcm.psc @@ -5,6 +5,9 @@ Int _iOutfitNameMaxBytes = 256 ; should never change at run-time; can chang String[] _sOutfitNames String _sSelectedOutfit = "" +Actor _aCurrentActor +Actor[] _kActorSelection_SelectCandidates + String _sEditingOutfit = "" String _sOutfitShowingContextMenu = "" Int _iOutfitEditorBodySlotPage = 0 @@ -45,7 +48,7 @@ Event OnConfigOpen() RefreshCache() EndEvent Event OnConfigClose() - SkyrimOutfitSystemNativeFuncs.RefreshArmorFor(Game.GetPlayer()) + SkyrimOutfitSystemNativeFuncs.RefreshArmorForAllConfiguredActors() ResetOutfitBrowser() ResetOutfitEditor() EndEvent @@ -72,7 +75,7 @@ EndFunction Function RefreshCache() _sOutfitNames = SkyrimOutfitSystemNativeFuncs.ListOutfits() - _sSelectedOutfit = SkyrimOutfitSystemNativeFuncs.GetSelectedOutfit() + _sSelectedOutfit = SkyrimOutfitSystemNativeFuncs.GetSelectedOutfit(_aCurrentActor) ; _sOutfitNames = SkyrimOutfitSystemNativeFuncs.NaturalSort_ASCII(_sOutfitNames) EndFunction @@ -80,6 +83,8 @@ EndFunction Function ResetOutfitBrowser() _iOutfitBrowserPage = 0 _iOutfitEditorBodySlotPage = 0 + _kActorSelection_SelectCandidates = new Actor[1] + _aCurrentActor = Game.GetPlayer() _sEditingOutfit = "" _sOutfitShowingContextMenu = "" _sOutfitNames = new String[1] @@ -189,12 +194,12 @@ EndFunction EndIf Int iAutoswitchIndex = StringUtil.Substring(sState, 19) as Int If aiIndex == -1 ; user wants no outfit - SkyrimOutfitSystemNativeFuncs.UnsetLocationOutfit(iAutoswitchIndex) + SkyrimOutfitSystemNativeFuncs.UnsetLocationOutfit(_aCurrentActor, iAutoswitchIndex) SetMenuOptionValueST("$SkyOutSys_AutoswitchEdit_None") Else ; set the requested outfit String sOutfitName = _sOutfitNames[aiIndex] - SkyrimOutfitSystemNativeFuncs.SetLocationOutfit(iAutoswitchIndex, sOutfitName) - SetMenuOptionValueST(SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(iAutoswitchIndex)) + SkyrimOutfitSystemNativeFuncs.SetLocationOutfit(_aCurrentActor, iAutoswitchIndex, sOutfitName) + SetMenuOptionValueST(SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(_aCurrentActor, iAutoswitchIndex)) EndIf Return EndIf @@ -220,7 +225,7 @@ EndFunction Int iAutoswitchIndex = StringUtil.Substring(sState, 19) as Int Bool bDelete = ShowMessage("$SkyOutSys_Confirm_UnsetAutoswitch_Text", True, "$SkyOutSys_Confirm_UnsetAutoswitch_Yes", "$SkyOutSys_Confirm_UnsetAutoswitch_No") If bDelete - SkyrimOutfitSystemNativeFuncs.UnsetLocationOutfit(iAutoswitchIndex) + SkyrimOutfitSystemNativeFuncs.UnsetLocationOutfit(_aCurrentActor, iAutoswitchIndex) SetMenuOptionValueST("") EndIf Return @@ -234,6 +239,7 @@ EndFunction SetCursorFillMode(TOP_TO_BOTTOM) SetCursorPosition(0) AddToggleOptionST("OPT_Enabled", "$Enabled", SkyrimOutfitSystemNativeFuncs.IsEnabled()) + AddMenuOptionST("OPT_SelectActorSelection", "$SkyOutSys_Text_SelectActorSelection", _aCurrentActor.GetBaseObject().GetName()) AddEmptyOption() ; ; Quickslots: @@ -243,6 +249,13 @@ EndFunction AddToggleOptionST("OPT_QuickslotsEnabled", "$SkyOutSys_Text_EnableQuickslots", kQM.GetEnabled()) AddEmptyOption() ; + ; Active actor selection + ; + AddHeaderOption("$SkyOutSys_Text_ActiveActorHeader") + AddMenuOptionST("OPT_AddActorSelection", "$SkyOutSys_Text_AddActorSelection", "") + AddMenuOptionST("OPT_RemoveActorSelection", "$SkyOutSys_Text_RemoveActorSelection", "") + AddEmptyOption() + ; ; Setting import/export ; AddHeaderOption("$SkyOutSys_Text_SettingExportImport") @@ -251,20 +264,22 @@ EndFunction ;/EndBlock/; ;/Block/; ; Right column SetCursorPosition(1) - AddHeaderOption("$SkyOutSys_MCMHeader_Autoswitch") - Int[] iIndices = SkyrimOutfitSystemNativeFuncs.GetAutoSwitchLocationArray() - Int iCount = iIndices.Length - AddToggleOptionST("OPT_AutoswitchEnabled", "$SkyOutSys_Text_EnableAutoswitch", SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled()) - If SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled() - Int iIterator = 0 - While iIterator < iCount - String sLocationOutfit = SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(iIndices[iIterator]) - If sLocationOutfit == "" - sLocationOutfit = "$SkyOutSys_AutoswitchEdit_None" - EndIf - AddMenuOptionST("OPT_AutoswitchEntry" + iIndices[iIterator], "$SkyOutSys_Text_Autoswitch" + iIndices[iIterator], sLocationOutfit) - iIterator = iIterator + 1 - EndWhile + If _aCurrentActor == Game.GetPlayer() + AddHeaderOption("$SkyOutSys_MCMHeader_Autoswitch") + Int[] iIndices = SkyrimOutfitSystemNativeFuncs.GetAutoSwitchLocationArray() + Int iCount = iIndices.Length + AddToggleOptionST("OPT_AutoswitchEnabled", "$SkyOutSys_Text_EnableAutoswitch", SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled()) + If SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled() + Int iIterator = 0 + While iIterator < iCount + String sLocationOutfit = SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(_aCurrentActor, iIndices[iIterator]) + If sLocationOutfit == "" + sLocationOutfit = "$SkyOutSys_AutoswitchEdit_None" + EndIf + AddMenuOptionST("OPT_AutoswitchEntry" + iIndices[iIterator], "$SkyOutSys_Text_Autoswitch" + iIndices[iIterator], sLocationOutfit) + iIterator = iIterator + 1 + EndWhile + EndIf EndIf ;/EndBlock/; @@ -277,6 +292,81 @@ EndFunction SetToggleOptionValueST(bToggle) EndEvent EndState + State OPT_AddActorSelection + Event OnMenuOpenST() + _kActorSelection_SelectCandidates = SkyrimOutfitSystemNativeFuncs.ActorNearPC() + String[] kActorNames = Utility.CreateStringArray(_kActorSelection_SelectCandidates.Length) + Int iIterator = 0 + While iIterator < _kActorSelection_SelectCandidates.Length + kActorNames[iIterator] = _kActorSelection_SelectCandidates[iIterator].GetActorBase().GetName() + iIterator = iIterator + 1 + EndWhile + String[] sMenu = PrependStringToArray(kActorNames, "$SkyOutSys_OEdit_AddCancel") + SetMenuDialogOptions(sMenu) + SetMenuDialogStartIndex(0) + SetMenuDialogDefaultIndex(0) + EndEvent + Event OnMenuAcceptST(Int aiIndex) + If aiIndex == 0 || aiIndex > _kActorSelection_SelectCandidates.Length + return + Endif + SkyrimOutfitSystemNativeFuncs.AddActor(_kActorSelection_SelectCandidates[aiIndex - 1]) + EndEvent + Event OnDefaultST() + EndEvent + EndState + State OPT_RemoveActorSelection + Event OnMenuOpenST() + _kActorSelection_SelectCandidates = SkyrimOutfitSystemNativeFuncs.ListActors() + String[] kActorNames = Utility.CreateStringArray(_kActorSelection_SelectCandidates.Length) + Int iIterator = 0 + While iIterator < _kActorSelection_SelectCandidates.Length + kActorNames[iIterator] = _kActorSelection_SelectCandidates[iIterator].GetActorBase().GetName() + iIterator = iIterator + 1 + EndWhile + String[] sMenu = PrependStringToArray(kActorNames, "$SkyOutSys_OEdit_AddCancel") + SetMenuDialogOptions(sMenu) + SetMenuDialogStartIndex(0) + SetMenuDialogDefaultIndex(0) + EndEvent + Event OnMenuAcceptST(Int aiIndex) + If aiIndex == 0 || aiIndex > _kActorSelection_SelectCandidates.Length + return + Endif + If _kActorSelection_SelectCandidates[aiIndex - 1] == Game.GetPlayer() + return + Endif + SkyrimOutfitSystemNativeFuncs.RemoveActor(_kActorSelection_SelectCandidates[aiIndex - 1]) + SkyrimOutfitSystemNativeFuncs.RefreshArmorFor(_kActorSelection_SelectCandidates[aiIndex - 1]) + EndEvent + Event OnDefaultST() + EndEvent + EndState + State OPT_SelectActorSelection + Event OnMenuOpenST() + _kActorSelection_SelectCandidates = SkyrimOutfitSystemNativeFuncs.ListActors() + String[] kActorNames = Utility.CreateStringArray(_kActorSelection_SelectCandidates.Length) + Int iIterator = 0 + While iIterator < _kActorSelection_SelectCandidates.Length + kActorNames[iIterator] = _kActorSelection_SelectCandidates[iIterator].GetActorBase().GetName() + iIterator = iIterator + 1 + EndWhile + String[] sMenu = PrependStringToArray(kActorNames, "$SkyOutSys_OEdit_AddCancel") + SetMenuDialogOptions(sMenu) + SetMenuDialogStartIndex(0) + SetMenuDialogDefaultIndex(0) + EndEvent + Event OnMenuAcceptST(Int aiIndex) + If aiIndex == 0 || aiIndex > _kActorSelection_SelectCandidates.Length + return + Endif + _aCurrentActor = _kActorSelection_SelectCandidates[aiIndex - 1] + RefreshCache() + ForcePageReset() + EndEvent + Event OnDefaultST() + EndEvent + EndState State OPT_QuickslotsEnabled Event OnSelectST() SkyOutSysQuickslotManager kQM = GetQuickslotManager() @@ -479,9 +569,9 @@ EndFunction State OutfitContext_Toggle Event OnSelectST() If _sSelectedOutfit == _sOutfitShowingContextMenu - SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit("") + SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit(_aCurrentActor, "") Else - SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit(_sOutfitShowingContextMenu) + SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit(_aCurrentActor, _sOutfitShowingContextMenu) EndIf RefreshCache() ForcePageReset() diff --git a/src/papyrus/skyoutsysquicksloteffect.psc b/src/papyrus/skyoutsysquicksloteffect.psc index 259c287..cca5ca9 100644 --- a/src/papyrus/skyoutsysquicksloteffect.psc +++ b/src/papyrus/skyoutsysquicksloteffect.psc @@ -21,14 +21,14 @@ Event OnEffectStart(Actor akCaster, Actor akTarget) result = "" Endif If result != "[DISMISS]" - SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit(result) + SkyrimOutfitSystemNativeFuncs.SetSelectedOutfit(Game.GetPlayer(), result) ; Update the autoswitch slot if ; 1) autoswitching is enabled, ; 2) the current location has an outfit assigned already, and ; 3) if we have an outfit selected in this menu Int playerLocationType = SkyrimOutfitSystemNativeFuncs.IdentifyLocationType(Game.GetPlayer().GetCurrentLocation(), Weather.GetCurrentWeather()) - If SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled() && SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(playerLocationType) != "" && result != "" - SkyrimOutfitSystemNativeFuncs.SetLocationOutfit(playerLocationType, result) + If SkyrimOutfitSystemNativeFuncs.GetLocationBasedAutoSwitchEnabled() && SkyrimOutfitSystemNativeFuncs.GetLocationOutfit(Game.GetPlayer(), playerLocationType) != "" && result != "" + SkyrimOutfitSystemNativeFuncs.SetLocationOutfit(Game.GetPlayer(), playerLocationType, result) Debug.Notification("This outfit will be remembered for this location type.") EndIf SkyrimOutfitSystemNativeFuncs.RefreshArmorFor(Game.GetPlayer()) diff --git a/src/papyrus/skyrimoutfitsystemnativefuncs.psc b/src/papyrus/skyrimoutfitsystemnativefuncs.psc index 8b23f9f..dbe69bd 100644 --- a/src/papyrus/skyrimoutfitsystemnativefuncs.psc +++ b/src/papyrus/skyrimoutfitsystemnativefuncs.psc @@ -27,11 +27,11 @@ Int Function GetOutfitNameMaxLength() Global Native Armor[] Function GetCarriedArmor (Actor akSubject) Global Native Armor[] Function GetWornItems (Actor akSubject) Global Native Function RefreshArmorFor (Actor akSubject) Global Native ; force akSubject to update their ArmorAddons - + Function RefreshArmorForAllConfiguredActors () Global Native ; force all known actors to update their ArmorAddons ; ; Searching for actors. Used in menus. ; -Actor[] Function GetActorNearPC () Global Native +Actor[] Function ActorNearPC () Global Native ; ; Search through all armor forms defined in the game (excluding templated ones). @@ -75,7 +75,7 @@ Bool Function GetOutfitPassthroughStatus(String asOutfitName) Global Native Function SetOutfitPassthroughStatus(String asOutfitName, Bool abPassthrough) Global Native Bool Function GetOutfitEquipRequiredStatus(String asOutfitName) Global Native Function SetOutfitEquipRequiredStatus(String asOutfitName, Bool asEquipRequired) Global Native -String Function GetSelectedOutfit () Global Native +String Function GetSelectedOutfit (Actor actor) Global Native Bool Function IsEnabled () Global Native String[] Function ListOutfits (Bool favoritesOnly = False) Global Native Function RemoveArmorFromOutfit (String asOutfitName, Armor akArmor) Global Native @@ -84,17 +84,18 @@ Bool Function RenameOutfit (String asOutfitName, String asRenameTo) Glo Bool Function OutfitExists (String asOutfitName) Global Native Function OverwriteOutfit (String asOutfitName, Armor[] akArmors) Global Native Function SetEnabled (Bool abEnabled) Global Native - Function SetSelectedOutfit (String asOutfitName) Global Native + Function SetSelectedOutfit (Actor actor, String asOutfitName) Global Native Function AddActor (Actor akSubject) Global Native Function RemoveActor (Actor akSubject) Global Native +Actor[] Function ListActors() Global Native Function SetLocationBasedAutoSwitchEnabled (Bool abEnabled) Global Native Bool Function GetLocationBasedAutoSwitchEnabled () Global Native Int[] Function GetAutoSwitchLocationArray () Global Native Int Function IdentifyLocationType (Location alLocation, Weather awWeather) Global Native - Function SetOutfitUsingLocation (Location alLocation, Weather awWeather) Global Native - Function SetLocationOutfit (Int aiLocationType, String asOutfitName) Global Native - Function UnsetLocationOutfit (Int aiLocationType) Global Native -String Function GetLocationOutfit (Int aiLocationType) Global Native + Function SetOutfitUsingLocation (Actor actor, Location alLocation, Weather awWeather) Global Native + Function SetLocationOutfit (Actor actor, Int aiLocationType, String asOutfitName) Global Native + Function UnsetLocationOutfit (Actor actor, Int aiLocationType) Global Native +String Function GetLocationOutfit (Actor actor, Int aiLocationType) Global Native Bool Function ExportSettings () Global Native Bool Function ImportSettings () Global Native