From ee97a2f8e1375fe700c7a1ddfe4c2728c43d171c Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Thu, 1 Aug 2024 04:33:28 +0530 Subject: [PATCH] Add `WornRestrictionsForWeapons` --- .github/workflows/main.yml | 2 +- CMakeLists.txt | 2 +- cmake/sourcelist.cmake | 1 + src/Fixes.cpp | 7 ++ src/Fixes.h | 5 + src/Fixes/WornRestrictionsForWeapons.cpp | 127 +++++++++++++++++++++++ src/Settings.cpp | 1 + src/Settings.h | 1 + vcpkg.json | 2 +- 9 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 src/Fixes/WornRestrictionsForWeapons.cpp diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f7f3b15..5948752 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,4 +26,4 @@ jobs: FOMOD_AE_MIN_GAME_VERSION: '1.6' FOMOD_REQUIRED_INSTALLATION_DIR: "Skyrim/Data" PUBLISH_ARCHIVE_TYPE: '7z' - VCPKG_COMMIT_ID: 'ee1093857f3d16b007065542bbb2229369c70c2e' + VCPKG_COMMIT_ID: '5c7d3a872dd861817fc812647176d5076085a7eb' diff --git a/CMakeLists.txt b/CMakeLists.txt index fdc8b1e..c0e11d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) set(NAME "po3_Tweaks" CACHE STRING "") -set(VERSION 1.10.2 CACHE STRING "") +set(VERSION 1.11.0 CACHE STRING "") set(AE_VERSION 1) set(VR_VERSION 1) diff --git a/cmake/sourcelist.cmake b/cmake/sourcelist.cmake index 33511b5..e678041 100644 --- a/cmake/sourcelist.cmake +++ b/cmake/sourcelist.cmake @@ -28,6 +28,7 @@ set(sources ${sources} src/Fixes/UnderwaterCamera.cpp src/Fixes/UseFurnitureInCombat.cpp src/Fixes/ValidateScreenshotFolder.cpp + src/Fixes/WornRestrictionsForWeapons.cpp src/PCH.cpp src/Papyrus.cpp src/Settings.cpp diff --git a/src/Fixes.cpp b/src/Fixes.cpp index 41b58f2..3f0e641 100644 --- a/src/Fixes.cpp +++ b/src/Fixes.cpp @@ -68,6 +68,13 @@ void Fixes::PostLoad::Install() // broken on some setups //FirstPersonAlpha::Install(); } + if (fixes.wornRestrictionsForWeapons) { + if (GetModuleHandle(L"AmmoEnchanting")) { + logger::info("\t\tDetected AmmoEnchanting, skipping ExpandedWornRestrictions patch."sv); + } else { + WornRestrictionsForWeapons::Install(); + } + } //UnderWaterCamera::Install(); tbd } diff --git a/src/Fixes.h b/src/Fixes.h index 52f3d14..1ffd6c7 100644 --- a/src/Fixes.h +++ b/src/Fixes.h @@ -136,4 +136,9 @@ namespace Fixes { void Install(); } + + namespace WornRestrictionsForWeapons + { + void Install(); + } } diff --git a/src/Fixes/WornRestrictionsForWeapons.cpp b/src/Fixes/WornRestrictionsForWeapons.cpp new file mode 100644 index 0000000..8c20d6c --- /dev/null +++ b/src/Fixes/WornRestrictionsForWeapons.cpp @@ -0,0 +1,127 @@ +#include "Fixes.h" + +//make weapon enchantments support worn restriction list +//adapted from: https://github.com/Exit-9B/AmmoEnchanting/blob/main/src/Ext/EnchantConstructMenu.cpp + +namespace Fixes::WornRestrictionsForWeapons +{ + struct detail + { + static bool GetCompatibleRestrictions( + RE::CraftingSubMenus::EnchantConstructMenu::ItemChangeEntry* a_item, + RE::CraftingSubMenus::EnchantConstructMenu::EnchantmentEntry* a_effect) + { + if (!a_item || !a_item->data || !a_item->data->object || !a_effect || !a_effect->data) { + return true; + } + + auto wornRestrictionList = a_effect->data->data.wornRestrictions; + auto keywordForm = a_item->data->object->As(); + + if (!wornRestrictionList || !keywordForm) { + return true; + } + + bool valid = false; + + keywordForm->ForEachKeyword([&](auto* keyword) { + if (wornRestrictionList->HasForm(keyword)) { + valid = true; + return RE::BSContainer::ForEachResult::kStop; + } + return RE::BSContainer::ForEachResult::kContinue; + }); + + return valid; + } + }; + + struct CanSelectEnchantmentEntry + { + static bool func(RE::CraftingSubMenus::EnchantConstructMenu* a_this, std::uint32_t a_index, bool a_showNotification) + { + if (a_index >= a_this->listEntries.size()) { + return false; + } + + using FilterFlag = RE::CraftingSubMenus::EnchantConstructMenu::FilterFlag; + + bool compatibleRestrictions = true; + auto& entry = a_this->listEntries[a_index]; + + switch (entry->filterFlag.get()) { + case FilterFlag::EnchantArmor: + case FilterFlag::EnchantWeapon: + { + for (auto& effect : a_this->selected.effects) { + const auto item = static_cast(entry.get()); + compatibleRestrictions &= detail::GetCompatibleRestrictions(item, effect.get()); + } + } + break; + case FilterFlag::EffectWeapon: + case FilterFlag::EffectArmor: + { + const auto item = a_this->selected.item.get(); + const auto effect = static_cast(entry.get()); + compatibleRestrictions = detail::GetCompatibleRestrictions(item, effect); + } + break; + } + + if (!compatibleRestrictions) { + if (a_showNotification) { + static const auto setting = RE::GameSettingCollection::GetSingleton()->GetSetting("sEnchantArmorIncompatible"); + if (setting) { + RE::DebugNotification(setting->GetString()); + } + } + return false; + } + + switch (entry->filterFlag.get()) { + case FilterFlag::EnchantWeapon: + { + if (!a_this->selected.effects.empty()) { + return a_this->selected.effects[0]->filterFlag == FilterFlag::EffectWeapon; + } + } + break; + case FilterFlag::EnchantArmor: + { + if (!a_this->selected.effects.empty()) { + return a_this->selected.effects[0]->filterFlag == FilterFlag::EffectArmor; + } + } + break; + case FilterFlag::EffectWeapon: + { + if (a_this->selected.item) { + return a_this->selected.item->filterFlag == FilterFlag::EnchantWeapon; + } + } + break; + case FilterFlag::EffectArmor: + { + if (a_this->selected.item) { + return a_this->selected.item->filterFlag == FilterFlag::EnchantArmor; + } + } + break; + default: + break; + } + + return true; + } + static inline constexpr std::size_t size{ OFFSET(0x27D, 0x1E9) }; + }; + + void Install() + { + REL::Relocation func{ REL_ID(50569, 51461) }; + stl::asm_replace(func.address()); + + logger::info("\t\tInstalled worn restrictions for weapons patch"sv); + } +} diff --git a/src/Settings.cpp b/src/Settings.cpp index 3d35dff..f149d4b 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -70,6 +70,7 @@ void Settings::Fixes::Load(CSimpleIniA& a_ini) get_value(a_ini, validateScreenshotFolder, section, "Validate Screenshot Location", ";Validates game screenshot location.\n;Defaults to Skyrim root directory if sScreenshotBaseName ini setting is empty or folder path does not exist"); get_value(a_ini, loadEditorIDs, section, "Load EditorIDs", ";Loads editorIDs for skipped forms at runtime"); get_value(a_ini, firstPersonAlpha, section, "First Person SetAlpha Fix", ";Fixes SetAlpha function making hands invisible for first person"); + get_value(a_ini, wornRestrictionsForWeapons, section, "Worn Restrictions For Weapons", ";Enable enchantment 'Worn Restrictions' feature on weapons"); #ifdef SKYRIMVR get_value(a_ini, fixVRCrosshairRefEvent, section, "VR CrosshairRefEvent Fix", "; Trigger CrossHairRefEvent with hand selection (normally requires game controller to enable crosshair events)"); #endif diff --git a/src/Settings.h b/src/Settings.h index 9903a3c..ffbd28e 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -28,6 +28,7 @@ class Settings : public ISingleton bool validateScreenshotFolder{ true }; bool loadEditorIDs{ true }; bool firstPersonAlpha{ true }; + bool wornRestrictionsForWeapons{ true }; #ifdef SKYRIMVR bool fixVRCrosshairRefEvent{ true }; #endif diff --git a/vcpkg.json b/vcpkg.json index eb26bbc..d43fff2 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "po3tweaks", - "version-string": "1.10.2", + "version-string": "1.11.0", "description": "Collection of bug fixes and tweaks for Skyrim SE/AE/VR", "homepage": "https://github.com/powerof3/po3-Tweaks/", "license": "MIT",