diff --git a/.gitignore b/.gitignore
index 98d05f0..c175678 100644
--- a/.gitignore
+++ b/.gitignore
@@ -333,4 +333,8 @@ ASALocalRun/
# Local History for Visual Studio
.localhistory/
-x64
\ No newline at end of file
+x64
+dependencies/skse64/src/common/x64_v142
+executables
+vcpkg_installed
+x64_v142
diff --git a/SkyrimOutfitSystemSE.sln b/SkyrimOutfitSystemSE.sln
index f4023ea..423ef80 100644
--- a/SkyrimOutfitSystemSE.sln
+++ b/SkyrimOutfitSystemSE.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.1259
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30517.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SkyrimOutfitSystemSE", "SkyrimOutfitSystemSE.vcxproj", "{10D1A242-54ED-467F-846C-E84EBD82FB7D}"
EndProject
@@ -27,18 +27,18 @@ Global
{C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Debug|x64.Build.0 = Debug|x64
{C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Release|x64.ActiveCfg = Release|x64
{C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Release|x64.Build.0 = Release|x64
- {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.ActiveCfg = Debug|x64
- {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.Build.0 = Debug|x64
- {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.ActiveCfg = Release|x64
- {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.Build.0 = Release|x64
- {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.ActiveCfg = Debug|x64
- {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.Build.0 = Debug|x64
- {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.ActiveCfg = Release|x64
- {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.Build.0 = Release|x64
- {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.ActiveCfg = Debug|x64
- {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.Build.0 = Debug|x64
- {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.ActiveCfg = Release|x64
- {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.Build.0 = Release|x64
+ {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.ActiveCfg = Debug_Lib_VC142|x64
+ {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.Build.0 = Debug_Lib_VC142|x64
+ {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.ActiveCfg = Release_Lib_VC142|x64
+ {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.Build.0 = Release_Lib_VC142|x64
+ {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.ActiveCfg = Debug_VC142|x64
+ {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.Build.0 = Debug_VC142|x64
+ {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.ActiveCfg = Release_VC142|x64
+ {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.Build.0 = Release_VC142|x64
+ {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.ActiveCfg = Debug_VC142|x64
+ {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.Build.0 = Debug_VC142|x64
+ {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.ActiveCfg = Release_VC142|x64
+ {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.Build.0 = Release_VC142|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SkyrimOutfitSystemSE.vcxproj b/SkyrimOutfitSystemSE.vcxproj
index 5ab3908..35c5a47 100644
--- a/SkyrimOutfitSystemSE.vcxproj
+++ b/SkyrimOutfitSystemSE.vcxproj
@@ -53,6 +53,14 @@
false
dependencies\CommonLibSSE\include;include;dependencies\skse64\src;dependencies\skse64\src\skse64;$(IncludePath)
+
+ true
+ true
+
+
+ true
+ true
+
Disabled
@@ -175,11 +183,13 @@
{c1af9204-ee2d-421b-b11e-1d70d8acc11f}
+
+ {7028b79c-06e3-4d9a-b38c-1dc3680b1bdb}
+
{5fd1c08d-db80-480c-a1c6-f0920005cd13}
-
-
+
\ No newline at end of file
diff --git a/include/ArmorAddonOverrideService.h b/include/ArmorAddonOverrideService.h
index d1a2681..c7f12b1 100644
--- a/include/ArmorAddonOverrideService.h
+++ b/include/ArmorAddonOverrideService.h
@@ -26,7 +26,7 @@ struct Outfit {
void load(SKSESerializationInterface* intfc, UInt32 version); // can throw ArmorAddonOverrideService::load_error
void save(SKSESerializationInterface*) const; // can throw ArmorAddonOverrideService::save_error
};
-const char* g_noOutfitName = "";
+const constexpr char* g_noOutfitName = "";
static Outfit g_noOutfit(g_noOutfitName); // can't be const; prevents us from assigning it to Outfit&s
class ArmorAddonOverrideService {
diff --git a/src/ArmorAddonOverrideService.cpp b/src/ArmorAddonOverrideService.cpp
index ab23a9c..5a8d317 100644
--- a/src/ArmorAddonOverrideService.cpp
+++ b/src/ArmorAddonOverrideService.cpp
@@ -47,7 +47,7 @@ void Outfit::load(SKSESerializationInterface* intfc, UInt32 version) {
_assertRead(ReadData(intfc, &formID), "Failed to read an outfit's armor.");
UInt32 fixedID;
if (intfc->ResolveFormId(formID, &fixedID)) {
- auto armor = reinterpret_cast(DYNAMIC_CAST(LookupFormByID(fixedID), TESForm, TESObjectARMO));
+ auto armor = reinterpret_cast(Runtime_DynamicCast((void*) LookupFormByID(fixedID), RTTI_TESForm, RTTI_TESObjectARMO));
if (armor)
this->armors.insert(armor);
}
diff --git a/src/OutfitSystem.cpp b/src/OutfitSystem.cpp
index d63226c..7cbd333 100644
--- a/src/OutfitSystem.cpp
+++ b/src/OutfitSystem.cpp
@@ -5,12 +5,17 @@
#include "skse64/PapyrusVM.h"
#include "skse64/GameRTTI.h"
+#include "skse64/GameFormComponents.h"
+#include "skse64/GameObjects.h"
+#include "skse64/GameReferences.h"
#include "RE/FormComponents/TESForm/TESObject/TESBoundObject/TESObjectARMO.h"
#include "RE/FileIO/TESDataHandler.h"
#include "RE/FormComponents/TESForm/TESObjectREFR/Actor/Actor.h"
+#include "RE/AI/AIProcess.h"
#include "RE/Inventory/InventoryChanges.h"
#include "RE/Inventory/InventoryEntryData.h"
+
#include "ArmorAddonOverrideService.h"
#include "cobb/strings.h"
@@ -24,11 +29,13 @@
SInt32 GetOutfitNameMaxLength(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
return ArmorAddonOverrideService::ce_outfitNameMaxLength;
}
- VMResultArray GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) {
+ VMResultArray GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) {
VMResultArray result;
+ auto target = (RE::Actor*) (target_skse);
if (target == nullptr) {
registry->LogError("Cannot retrieve data for a None actor.", stackId);
- return result;
+ VMResultArray empty;
+ return empty;
}
//
class _Visitor : public RE::InventoryChanges::IItemChangeVisitor {
@@ -37,11 +44,12 @@
// shield, then we need to grab the equipped shield's worn-flags.
//
public:
- virtual ReturnType Visit(RE::InventoryEntryData* data) override {
- const auto form = data->type;
+ virtual bool Visit(RE::InventoryEntryData* data) override {
+ // Return true to continue, or else false to break.
+ const auto form = data->object;
if (form && form->formType == RE::FormType::Armor)
this->list.push_back(reinterpret_cast(form));
- return ReturnType::kContinue;
+ return true;
};
VMResultArray& list;
@@ -53,13 +61,20 @@
_Visitor visitor(result);
inventory->ExecuteVisitor(&visitor);
}
- return result;
+ VMResultArray converted_result;
+ converted_result.reserve(result.size());
+ for (const auto ptr : result) {
+ converted_result.push_back((TESObjectARMO*)ptr);
+ }
+ return converted_result;
}
- VMResultArray GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) {
+ VMResultArray GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) {
VMResultArray result;
+ auto target = (RE::Actor*) (target_skse);
if (target == nullptr) {
registry->LogError("Cannot retrieve data for a None actor.", stackId);
- return result;
+ VMResultArray empty;
+ return empty;
}
//
class _Visitor : public RE::InventoryChanges::IItemChangeVisitor {
@@ -68,11 +83,11 @@
// shield, then we need to grab the equipped shield's worn-flags.
//
public:
- virtual ReturnType Visit(RE::InventoryEntryData* data) override {
- auto form = data->type;
+ virtual bool Visit(RE::InventoryEntryData* data) override {
+ auto form = data->object;
if (form && form->formType == RE::FormType::Armor)
this->list.push_back(reinterpret_cast(form));
- return ReturnType::kContinue;
+ return true;
};
VMResultArray& list;
@@ -84,11 +99,17 @@
_Visitor visitor(result);
inventory->ExecuteVisitorOnWorn(&visitor);
}
- return result;
+ VMResultArray converted_result;
+ converted_result.reserve(result.size());
+ for (const auto ptr : result) {
+ converted_result.push_back((TESObjectARMO*)ptr);
+ }
+ return converted_result;
}
- void RefreshArmorFor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) {
+ void RefreshArmorFor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) {
+ auto target = (RE::Actor*) (target_skse);
ERROR_AND_RETURN_IF(target == nullptr, "Cannot refresh armor on a None actor.", registry, stackId);
- auto pm = target->processManager;
+ auto pm = target->currentProcess;
if (pm) {
//
// "SetEquipFlag" tells the process manager that the actor's
@@ -97,7 +118,8 @@
// should see a call near the start of EquipManager's func-
// tion to equip an item.
//
- pm->SetEquipFlag(RE::ActorProcessManager::Flag::kUnk01);
+ // NOTE: AIProcess is also called as ActorProcessManager
+ pm->SetEquipFlag(RE::AIProcess::Flag::kUnk01);
pm->UpdateEquipment(target);
}
}
@@ -110,7 +132,7 @@
void setup(std::string nameFilter, bool mustBePlayable) {
auto data = RE::TESDataHandler::GetSingleton();
auto& list = data->GetFormArray(RE::FormType::Armor);
- const auto size = list.GetSize();
+ const auto size = list.size();
this->names.reserve(size);
this->armors.reserve(size);
for (UInt32 i = 0; i < size; i++) {
@@ -119,11 +141,12 @@
auto armor = static_cast(form);
if (armor->templateArmor) // filter out predefined enchanted variants, to declutter the list
continue;
- if (mustBePlayable && !!(armor->flags & 4))
+ if (mustBePlayable && !!(armor->formFlags & RE::TESObjectARMO::RecordFlags::kNonPlayable))
continue;
std::string armorName;
{ // get name
- TESFullName* tfn = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName);
+ // TESFullName* tfn = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName);
+ TESFullName* tfn = (TESFullName*)Runtime_DynamicCast((void*)armor, RTTI_TESObjectARMO, RTTI_TESFullName);
if (tfn)
armorName = tfn->name.data;
}
@@ -153,12 +176,17 @@
void Prep(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString filter, bool mustBePlayable) {
data.setup(filter.data, mustBePlayable);
}
- VMResultArray GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
+ VMResultArray GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
VMResultArray result;
auto& list = data.armors;
for (auto it = list.begin(); it != list.end(); it++)
result.push_back(*it);
- return result;
+ VMResultArray converted_result;
+ converted_result.reserve(result.size());
+ for (const auto ptr : result) {
+ converted_result.push_back((TESObjectARMO*)ptr);
+ }
+ return converted_result;
}
VMResultArray GetNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
VMResultArray result;
@@ -204,7 +232,8 @@
data.bodySlots.push_back(i);
data.armors.push_back(armor);
{ // name
- TESFullName* pFullName = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName);
+ // TESFullName* pFullName = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName);
+ TESFullName* pFullName = (TESFullName*) Runtime_DynamicCast((void*) armor, RTTI_TESObjectARMO, RTTI_TESFullName);
if (pFullName)
data.armorNames.push_back(pFullName->name.data);
else
@@ -218,12 +247,17 @@
registry->LogWarning("The specified outfit does not exist.", stackId);
}
}
- VMResultArray GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
+ VMResultArray GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
VMResultArray result;
auto& list = data.armors;
for (auto it = list.begin(); it != list.end(); it++)
result.push_back(*it);
- return result;
+ VMResultArray converted_result;
+ converted_result.reserve(result.size());
+ for (const auto ptr : result) {
+ converted_result.push_back((TESObjectARMO*)ptr);
+ }
+ return converted_result;
}
VMResultArray GetArmorNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
VMResultArray result;
@@ -343,7 +377,8 @@
}
}
//
- void AddArmorToOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, RE::TESObjectARMO* armor) {
+ void AddArmorToOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, TESObjectARMO* armor_skse) {
+ auto armor = (RE::TESObjectARMO*) (armor_skse);
ERROR_AND_RETURN_IF(armor == nullptr, "Cannot add a None armor to an outfit.", registry, stackId);
auto& service = ArmorAddonOverrideService::GetInstance();
try {
@@ -354,7 +389,8 @@
registry->LogWarning("The specified outfit does not exist.", stackId);
}
}
- bool ArmorConflictsWithOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::TESObjectARMO* armor, BSFixedString name) {
+ bool ArmorConflictsWithOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, TESObjectARMO* armor_skse, BSFixedString name) {
+ auto armor = (RE::TESObjectARMO*) (armor_skse);
if (armor == nullptr) {
registry->LogWarning("A None armor can't conflict with anything in an outfit.", stackId);
return false;
@@ -383,7 +419,7 @@
auto& service = ArmorAddonOverrideService::GetInstance();
service.deleteOutfit(name.data);
}
- VMResultArray GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) {
+ VMResultArray GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) {
VMResultArray result;
auto& service = ArmorAddonOverrideService::GetInstance();
try {
@@ -395,7 +431,12 @@
catch (std::out_of_range) {
registry->LogWarning("The specified outfit does not exist.", stackId);
}
- return result;
+ VMResultArray converted_result;
+ converted_result.reserve(result.size());
+ for (const auto ptr : result) {
+ converted_result.push_back((TESObjectARMO*)ptr);
+ }
+ return converted_result;
}
BSFixedString GetSelectedOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
auto& service = ArmorAddonOverrideService::GetInstance();
@@ -415,7 +456,8 @@
result.push_back(it->c_str());
return result;
}
- void RemoveArmorFromOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, RE::TESObjectARMO* armor) {
+ void RemoveArmorFromOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, TESObjectARMO* armor_skse) {
+ auto armor = (RE::TESObjectARMO*) (armor_skse);
ERROR_AND_RETURN_IF(armor == nullptr, "Cannot remove a None armor from an outfit.", registry, stackId);
auto& service = ArmorAddonOverrideService::GetInstance();
try {
@@ -426,7 +468,8 @@
registry->LogWarning("The specified outfit does not exist.", stackId);
}
}
- void RemoveConflictingArmorsFrom(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::TESObjectARMO* armor, BSFixedString name) {
+ void RemoveConflictingArmorsFrom(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, TESObjectARMO* armor_skse, BSFixedString name) {
+ auto armor = (RE::TESObjectARMO*) (armor_skse);
ERROR_AND_RETURN_IF(armor == nullptr, "A None armor can't conflict with anything in an outfit.", registry, stackId);
auto& service = ArmorAddonOverrideService::GetInstance();
try {
@@ -438,7 +481,7 @@
RE::TESObjectARMO* existing = *it;
if (existing) {
const auto mask = existing->GetSlotMask();
- if ((mask & candidateMask) != RE::BGSBipedObjectForm::FirstPersonFlag::kNone)
+ if ((static_cast(mask) & static_cast(candidateMask)) != static_cast(RE::BGSBipedObjectForm::FirstPersonFlag::kNone))
conflicts.push_back(existing);
}
}
@@ -473,15 +516,24 @@
auto& service = ArmorAddonOverrideService::GetInstance();
return service.hasOutfit(name.data);
}
- void OverwriteOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, VMArray armors) {
+ void OverwriteOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, VMArray armors_skse) {
auto& service = ArmorAddonOverrideService::GetInstance();
+ // Convert input array.
+ VMResultArray armors;
+ armors.reserve(armors_skse.Length());
+ for (std::size_t i = 0; i < armors_skse.Length(); i++) {
+ TESObjectARMO* ptr;
+ armors_skse.Get(&ptr, i);
+ armors.push_back((RE::TESObjectARMO*)ptr);
+ }
+ // End convert
try {
auto& outfit = service.getOrCreateOutfit(name.data);
outfit.armors.clear();
- auto count = armors.Length();
+ auto count = armors.size();
for (UInt32 i = 0; i < count; i++) {
RE::TESObjectARMO* ptr = nullptr;
- armors.Get(&ptr, i);
+ ptr = armors.at(i);
if (ptr)
outfit.armors.insert(ptr);
}
@@ -510,19 +562,19 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
registry
));
registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "GetOutfitNameMaxLength", VMClassRegistry::kFunctionFlag_NoWait);
- registry->RegisterFunction(new NativeFunction1, RE::Actor*>(
+ registry->RegisterFunction(new NativeFunction1, Actor*>(
"GetCarriedArmor",
"SkyrimOutfitSystemNativeFuncs",
GetCarriedArmor,
registry
));
- registry->RegisterFunction(new NativeFunction1, RE::Actor*>(
+ registry->RegisterFunction(new NativeFunction1, Actor*>(
"GetWornItems",
"SkyrimOutfitSystemNativeFuncs",
GetWornItems,
registry
));
- registry->RegisterFunction(new NativeFunction1(
+ registry->RegisterFunction(new NativeFunction1(
"RefreshArmorFor",
"SkyrimOutfitSystemNativeFuncs",
RefreshArmorFor,
@@ -536,7 +588,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
ArmorFormSearchUtils::Prep,
registry
));
- registry->RegisterFunction(new NativeFunction0>(
+ registry->RegisterFunction(new NativeFunction0>(
"GetArmorSearchResultForms",
"SkyrimOutfitSystemNativeFuncs",
ArmorFormSearchUtils::GetForms,
@@ -562,7 +614,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
BodySlotListing::Prep,
registry
));
- registry->RegisterFunction(new NativeFunction0>(
+ registry->RegisterFunction(new NativeFunction0>(
"GetOutfitBodySlotListingArmorForms",
"SkyrimOutfitSystemNativeFuncs",
BodySlotListing::GetArmorForms,
@@ -595,10 +647,10 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
registry
));
registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "NaturalSort_ASCII", VMClassRegistry::kFunctionFlag_NoWait);
- registry->RegisterFunction(new NativeFunction3, VMArray, VMArray, bool>(
+ registry->RegisterFunction(new NativeFunction3, VMArray, VMArray, bool>(
"NaturalSortPairArmor_ASCII",
"SkyrimOutfitSystemNativeFuncs",
- StringSorts::NaturalSortPair_ASCII,
+ StringSorts::NaturalSortPair_ASCII,
registry
));
registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "NaturalSortPairArmor_ASCII", VMClassRegistry::kFunctionFlag_NoWait);
@@ -620,13 +672,13 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "ToHex", VMClassRegistry::kFunctionFlag_NoWait);
}
//
- registry->RegisterFunction(new NativeFunction2(
+ registry->RegisterFunction(new NativeFunction2(
"AddArmorToOutfit",
"SkyrimOutfitSystemNativeFuncs",
AddArmorToOutfit,
registry
));
- registry->RegisterFunction(new NativeFunction2(
+ registry->RegisterFunction(new NativeFunction2(
"ArmorConflictsWithOutfit",
"SkyrimOutfitSystemNativeFuncs",
ArmorConflictsWithOutfit,
@@ -644,7 +696,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
DeleteOutfit,
registry
));
- registry->RegisterFunction(new NativeFunction1, BSFixedString>(
+ registry->RegisterFunction(new NativeFunction1, BSFixedString>(
"GetOutfitContents",
"SkyrimOutfitSystemNativeFuncs",
GetOutfitContents,
@@ -668,13 +720,13 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
ListOutfits,
registry
));
- registry->RegisterFunction(new NativeFunction2(
+ registry->RegisterFunction(new NativeFunction2(
"RemoveArmorFromOutfit",
"SkyrimOutfitSystemNativeFuncs",
RemoveArmorFromOutfit,
registry
));
- registry->RegisterFunction(new NativeFunction2(
+ registry->RegisterFunction(new NativeFunction2(
"RemoveConflictingArmorsFrom",
"SkyrimOutfitSystemNativeFuncs",
RemoveConflictingArmorsFrom,
@@ -692,7 +744,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
OutfitExists,
registry
));
- registry->RegisterFunction(new NativeFunction2>(
+ registry->RegisterFunction(new NativeFunction2>(
"OverwriteOutfit",
"SkyrimOutfitSystemNativeFuncs",
OverwriteOutfit,
diff --git a/src/PlayerSkinning.cpp b/src/PlayerSkinning.cpp
index 1b7a6b3..277774c 100644
--- a/src/PlayerSkinning.cpp
+++ b/src/PlayerSkinning.cpp
@@ -6,8 +6,10 @@
#include "RE/FormComponents/TESForm/TESObjectREFR/Actor/Character/PlayerCharacter.h"
#include "RE/FormComponents/TESForm/TESObject/TESBoundObject/TESObjectARMO.h"
#include "RE/FormComponents/TESForm/TESObjectREFR/TESObjectREFR.h"
+#include "RE/FormComponents/TESForm/TESForm.h"
#include "ArmorAddonOverrideService.h"
+#include "skse64_common/Relocation.h"
#include "skse64_common/BranchTrampoline.h"
#include "skse64/GameRTTI.h"
#include "RE/Inventory/ActorEquipManager.h"
@@ -35,7 +37,7 @@ namespace OutfitSystem
bool _stdcall ShouldOverride(RE::TESObjectARMO* armor, RE::TESObjectREFR* target) {
if (!ShouldOverrideSkinning(target))
return false;
- if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
+ if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
auto& svc = ArmorAddonOverrideService::GetInstance();
auto& outfit = svc.currentOutfit();
if (!outfit.hasShield()) {
@@ -108,16 +110,16 @@ namespace OutfitSystem
// shield, then we need to grab the equipped shield's worn-flags.
//
public:
- virtual ReturnType Visit(RE::InventoryEntryData* data) override {
- auto form = data->type;
+ virtual bool Visit(RE::InventoryEntryData* data) override {
+ auto form = data->object;
if (form && form->formType == RE::FormType::Armor) {
auto armor = reinterpret_cast(form);
- if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
+ if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
this->mask |= static_cast(armor->GetSlotMask());
this->hasShield = true;
}
}
- return ReturnType::kContinue;
+ return true; // Return true to "continue visiting".
};
UInt32 mask = 0;
@@ -140,7 +142,7 @@ namespace OutfitSystem
for (auto armor : armors)
{
if (armor) {
- if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
+ if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
if (!shield)
continue;
}
@@ -219,16 +221,16 @@ namespace OutfitSystem
// shield, then we need to grab the equipped shield's worn-flags.
//
public:
- virtual ReturnType Visit(RE::InventoryEntryData* data) override {
- auto form = data->type;
+ virtual bool Visit(RE::InventoryEntryData* data) override {
+ auto form = data->object;
if (form && form->formType == RE::FormType::Armor) {
auto armor = reinterpret_cast(form);
- if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
+ if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
this->result = true;
- return ReturnType::kBreak; // halt visitor early
+ return false; // False halt visitor early
}
}
- return ReturnType::kContinue;
+ return true; // True to continue visiting
};
bool result = false;
};
@@ -236,7 +238,7 @@ namespace OutfitSystem
void Custom(RE::Actor* target, RE::ActorWeightModel * actorWeightModel) {
if (!actorWeightModel)
return;
- auto base = reinterpret_cast(DYNAMIC_CAST(target->baseForm, TESForm, TESNPC));
+ auto base = reinterpret_cast(Runtime_DynamicCast(static_cast(target->data.objectReference), RTTI_TESForm, RTTI_TESNPC));
if (!base)
return;
auto race = base->race;
@@ -246,7 +248,7 @@ namespace OutfitSystem
for (auto it = armors.cbegin(); it != armors.cend(); ++it) {
RE::TESObjectARMO* armor = *it;
if (armor) {
- if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
+ if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
//
// We should only apply a shield's armor-addons if the player has
// a shield equipped.
@@ -358,12 +360,12 @@ namespace OutfitSystem
// visitor to check for conflicts?
//
public:
- virtual ReturnType Visit(RE::InventoryEntryData* data) override {
- auto form = data->type;
+ virtual bool Visit(RE::InventoryEntryData* data) override {
+ auto form = data->object;
if (form && form->formType == RE::FormType::Armor) {
auto armor = reinterpret_cast(form);
if (armor->TestBodyPartByIndex(this->conflictIndex)) {
- auto em = RE::EquipManager::GetSingleton();
+ auto em = RE::ActorEquipManager::GetSingleton();
//
// TODO: The third argument to this call is meant to be a BaseExtraList*,
// and Bethesda supplies one when calling from Unk_120. Can we get away
@@ -376,10 +378,10 @@ namespace OutfitSystem
// I was unable to stack the helmets with each other or with other helmets,
// suggesting that the BaseExtraList may not be strictly necessary.
//
- em->UnEquipItem(this->target, form, nullptr, 1, nullptr, false, false, true, false, nullptr);
+ em->UnequipObject(this->target, form, nullptr, 1, nullptr, false, false, true, false, nullptr);
}
}
- return ReturnType::kContinue;
+ return true; // True to continue visiting
};
RE::Actor* target;
@@ -448,7 +450,7 @@ namespace OutfitSystem
pop(rcx);
L(j_Exit);
- xor(al, al);
+ xor_(al, al);
L(j_Out);
jmp(ptr[rip]);
diff --git a/src/main.cpp b/src/main.cpp
index 728b5a5..19b72ee 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,7 +9,6 @@
#include "OutfitSystem.h"
#include "PlayerSkinning.h"
-
static PluginHandle g_pluginHandle = kPluginHandle_Invalid;
static SKSEPapyrusInterface* g_Papyrus = nullptr;
static SKSEMessagingInterface* g_Messaging = nullptr;
@@ -42,7 +41,7 @@ bool SKSEPlugin_Query(const SKSEInterface* a_skse, PluginInfo* a_info)
return false;
}
- if (a_skse->runtimeVersion != RUNTIME_VERSION_1_5_73)
+ if (a_skse->runtimeVersion != RUNTIME_VERSION_1_5_97)
{
_FATALERROR("[FATAL ERROR] Unsupported runtime version %08X!\n", a_skse->runtimeVersion);
return false;
@@ -112,7 +111,8 @@ bool SKSEPlugin_Load(const SKSEInterface* a_skse)
}
{ // Papyrus registrations
g_Papyrus = (SKSEPapyrusInterface*)a_skse->QueryInterface(kInterface_Papyrus);
- _RegisterAndEchoPapyrus(OutfitSystem::RegisterPapyrus, "SkyrimOutfitSystemNativeFuncs");
+ char name[] = "SkyrimOutfitSystemNativeFuncs";
+ _RegisterAndEchoPapyrus(OutfitSystem::RegisterPapyrus, name);
}
return true;
}
diff --git a/vcpkg.json b/vcpkg.json
new file mode 100644
index 0000000..ce781ff
--- /dev/null
+++ b/vcpkg.json
@@ -0,0 +1,11 @@
+{
+ "name": "skyrimoutfitsystem",
+ "version-string": "1.0.0",
+ "description": "Skyrim Outfit System for Skyrim Special Edition",
+ "supports": "windows & x64",
+ "dependencies": [
+ "span-lite",
+ "spdlog"
+ ]
+ }
+
\ No newline at end of file