├── .clang-format ├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── Scripts └── Source │ └── LibFire.psc ├── src ├── PCH.cpp ├── PCH.h ├── Papyrus │ ├── ActorValueHelper.cpp │ ├── ActorValueHelper.h │ ├── PapyrusActor.cpp │ ├── PapyrusActor.h │ ├── PapyrusArray.cpp │ ├── PapyrusArray.h │ ├── PapyrusFaction.cpp │ ├── PapyrusFaction.h │ ├── PapyrusFormList.cpp │ ├── PapyrusFormList.h │ ├── PapyrusObjectREFR.cpp │ ├── PapyrusObjectREFR.h │ ├── PapyrusPlayerCharacter.cpp │ ├── PapyrusPlayerCharacter.h │ ├── PapyrusRace.cpp │ ├── PapyrusRace.h │ ├── PapyrusSpell.cpp │ ├── PapyrusSpell.h │ ├── PapyrusString.cpp │ ├── PapyrusString.h │ ├── PapyrusTime.cpp │ ├── PapyrusTime.h │ ├── Registration.cpp │ └── Registration.h └── main.cpp ├── update-baselines.py ├── vcpkg-configuration.json ├── vcpkg.json └── version.rc.in /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: DontAlign 4 | AlignConsecutiveAssignments: None 5 | AlignConsecutiveDeclarations: None 6 | AlignConsecutiveMacros: None 7 | AlignEscapedNewlines: Left 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllArgumentsOnNextLine: false 11 | AllowAllConstructorInitializersOnNextLine: false 12 | AllowAllParametersOfDeclarationOnNextLine: false 13 | AllowShortBlocksOnASingleLine: Empty 14 | AllowShortCaseLabelsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine: All 16 | AllowShortIfStatementsOnASingleLine: Never 17 | AllowShortLambdasOnASingleLine: All 18 | AllowShortLoopsOnASingleLine: true 19 | AlwaysBreakAfterReturnType: None 20 | AlwaysBreakBeforeMultilineStrings: true 21 | AlwaysBreakTemplateDeclarations: 'Yes' 22 | BinPackArguments: true 23 | BinPackParameters: true 24 | BraceWrapping: 25 | AfterCaseLabel: true 26 | AfterClass: true 27 | AfterControlStatement: 'false' 28 | AfterEnum: true 29 | AfterExternBlock: true 30 | AfterFunction: true 31 | AfterNamespace: true 32 | AfterStruct: true 33 | AfterUnion: true 34 | BeforeCatch: false 35 | BeforeElse: false 36 | IndentBraces: false 37 | SplitEmptyFunction: false 38 | SplitEmptyNamespace: false 39 | SplitEmptyRecord: false 40 | BreakBeforeBinaryOperators: None 41 | BreakBeforeBraces: Custom 42 | BreakBeforeTernaryOperators: false 43 | BreakConstructorInitializers: AfterColon 44 | BreakInheritanceList: AfterColon 45 | BreakStringLiterals: true 46 | ColumnLimit: 0 47 | CompactNamespaces: false 48 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 49 | ConstructorInitializerIndentWidth: 4 50 | ContinuationIndentWidth: 4 51 | Cpp11BracedListStyle: false 52 | DeriveLineEnding: true 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | FixNamespaceComments: false 56 | IncludeBlocks: Preserve 57 | IndentCaseBlocks: true 58 | IndentCaseLabels: true 59 | IndentGotoLabels: false 60 | IndentPPDirectives: None 61 | IndentWidth: 4 62 | IndentWrappedFunctionNames: true 63 | KeepEmptyLinesAtTheStartOfBlocks: false 64 | Language: Cpp 65 | MaxEmptyLinesToKeep: 2 66 | NamespaceIndentation: All 67 | PointerAlignment: Left 68 | ReflowComments : false 69 | SortIncludes: CaseSensitive 70 | SortUsingDeclarations: true 71 | SpaceAfterCStyleCast: false 72 | SpaceAfterLogicalNot: false 73 | SpaceAfterTemplateKeyword: true 74 | SpaceBeforeAssignmentOperators: true 75 | SpaceBeforeCpp11BracedList: false 76 | SpaceBeforeCtorInitializerColon: true 77 | SpaceBeforeInheritanceColon: true 78 | SpaceBeforeParens: ControlStatements 79 | SpaceBeforeRangeBasedForLoopColon: true 80 | SpaceBeforeSquareBrackets: false 81 | SpaceInEmptyBlock: false 82 | SpaceInEmptyParentheses: false 83 | SpacesBeforeTrailingComments: 2 84 | SpacesInAngles: false 85 | SpacesInCStyleCastParentheses: false 86 | SpacesInConditionalStatement: false 87 | SpacesInContainerLiterals: true 88 | SpacesInParentheses: false 89 | SpacesInSquareBrackets: false 90 | Standard: c++17 91 | TabWidth: 4 92 | UseCRLF: true 93 | UseTab: Always 94 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /build* 3 | /build-debug* 4 | /build-release* 5 | workspace.xml 6 | 7 | ## Ignore Visual Studio temporary files, build results, and 8 | ## files generated by popular Visual Studio add-ons. 9 | ## 10 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 11 | 12 | # User-specific files 13 | *.rsuser 14 | *.suo 15 | *.user 16 | *.userosscache 17 | *.sln.docstates 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUNIT 47 | *.VisualState.xml 48 | TestResult.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # Benchmark Results 56 | BenchmarkDotNet.Artifacts/ 57 | 58 | # .NET Core 59 | project.lock.json 60 | project.fragment.lock.json 61 | artifacts/ 62 | 63 | # StyleCop 64 | StyleCopReport.xml 65 | 66 | # Files built by Visual Studio 67 | *_i.c 68 | *_p.c 69 | *_h.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.iobj 74 | *.pch 75 | *.pdb 76 | *.ipdb 77 | *.pgc 78 | *.pgd 79 | *.rsp 80 | *.sbr 81 | *.tlb 82 | *.tli 83 | *.tlh 84 | *.tmp 85 | *.tmp_proj 86 | *_wpftmp.csproj 87 | *.log 88 | *.vspscc 89 | *.vssscc 90 | .builds 91 | *.pidb 92 | *.svclog 93 | *.scc 94 | 95 | # Chutzpah Test files 96 | _Chutzpah* 97 | 98 | # Visual C++ cache files 99 | ipch/ 100 | *.aps 101 | *.ncb 102 | *.opendb 103 | *.opensdf 104 | *.sdf 105 | *.cachefile 106 | *.VC.db 107 | *.VC.VC.opendb 108 | 109 | # Visual Studio profiler 110 | *.psess 111 | *.vsp 112 | *.vspx 113 | *.sap 114 | 115 | # Visual Studio Trace Files 116 | *.e2e 117 | 118 | # TFS 2012 Local Workspace 119 | $tf/ 120 | 121 | # Guidance Automation Toolkit 122 | *.gpState 123 | 124 | # ReSharper is a .NET coding add-in 125 | _ReSharper*/ 126 | *.[Rr]e[Ss]harper 127 | *.DotSettings.user 128 | 129 | # JustCode is a .NET coding add-in 130 | .JustCode 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | 214 | # Visual Studio cache files 215 | # files ending in .cache can be ignored 216 | *.[Cc]ache 217 | # but keep track of directories ending in .cache 218 | !*.[Cc]ache/ 219 | 220 | # Others 221 | ClientBin/ 222 | ~$* 223 | *~ 224 | *.dbmdl 225 | *.dbproj.schemaview 226 | *.jfm 227 | *.pfx 228 | *.publishsettings 229 | orleans.codegen.cs 230 | 231 | # Including strong name files can present a security risk 232 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 233 | #*.snk 234 | 235 | # Since there are multiple workflows, uncomment next line to ignore bower_components 236 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 237 | #bower_components/ 238 | 239 | # RIA/Silverlight projects 240 | Generated_Code/ 241 | 242 | # Backup & report files from converting an old project file 243 | # to a newer Visual Studio version. Backup files are not needed, 244 | # because we have git ;-) 245 | _UpgradeReport_Files/ 246 | Backup*/ 247 | UpgradeLog*.XML 248 | UpgradeLog*.htm 249 | ServiceFabricBackup/ 250 | *.rptproj.bak 251 | 252 | # SQL Server files 253 | *.mdf 254 | *.ldf 255 | *.ndf 256 | 257 | # Business Intelligence projects 258 | *.rdl.data 259 | *.bim.layout 260 | *.bim_*.settings 261 | *.rptproj.rsuser 262 | 263 | # Microsoft Fakes 264 | FakesAssemblies/ 265 | 266 | # GhostDoc plugin setting file 267 | *.GhostDoc.xml 268 | 269 | # Node.js Tools for Visual Studio 270 | .ntvs_analysis.dat 271 | node_modules/ 272 | 273 | # Visual Studio 6 build log 274 | *.plg 275 | 276 | # Visual Studio 6 workspace options file 277 | *.opt 278 | 279 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 280 | *.vbw 281 | 282 | # Visual Studio LightSwitch build output 283 | **/*.HTMLClient/GeneratedArtifacts 284 | **/*.DesktopClient/GeneratedArtifacts 285 | **/*.DesktopClient/ModelManifest.xml 286 | **/*.Server/GeneratedArtifacts 287 | **/*.Server/ModelManifest.xml 288 | _Pvt_Extensions 289 | 290 | # Paket dependency manager 291 | .paket/paket.exe 292 | paket-files/ 293 | 294 | # FAKE - F# Make 295 | .fake/ 296 | 297 | # JetBrains Rider 298 | .idea/ 299 | *.sln.iml 300 | 301 | # CodeRush personal settings 302 | .cr/personal 303 | 304 | # Python Tools for Visual Studio (PTVS) 305 | __pycache__/ 306 | *.pyc 307 | 308 | # Cake - Uncomment if you are using it 309 | # tools/** 310 | # !tools/packages.config 311 | 312 | # Tabs Studio 313 | *.tss 314 | 315 | # Telerik's JustMock configuration file 316 | *.jmconfig 317 | 318 | # BizTalk build output 319 | *.btp.cs 320 | *.btm.cs 321 | *.odx.cs 322 | *.xsd.cs 323 | 324 | # OpenCover UI analysis results 325 | OpenCover/ 326 | 327 | # Azure Stream Analytics local run output 328 | ASALocalRun/ 329 | 330 | # MSBuild Binary and Structured Log 331 | *.binlog 332 | 333 | # NVidia Nsight GPU debugger configuration file 334 | *.nvuser 335 | 336 | # MFractors (Xamarin productivity tool) working folder 337 | .mfractor/ 338 | 339 | # Local History for Visual Studio 340 | .localhistory/ 341 | 342 | .idea/ 343 | *.DotSettings 344 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | 3 | # ---- Project ---- 4 | 5 | project( 6 | LibFire 7 | VERSION 1.0.8.2 8 | HOMEPAGE_URL https://github.com/fireundubh/LibFire 9 | LANGUAGES CXX 10 | ) 11 | set(CMAKE_CXX_STANDARD 23) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | configure_file( 15 | ${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in 16 | ${CMAKE_CURRENT_BINARY_DIR}/version.rc 17 | @ONLY 18 | ) 19 | 20 | set(headers 21 | src/PCH.h 22 | src/Papyrus/Registration.h 23 | src/Papyrus/ActorValueHelper.h 24 | src/Papyrus/PapyrusActor.h 25 | src/Papyrus/PapyrusArray.h 26 | src/Papyrus/PapyrusFaction.h 27 | src/Papyrus/PapyrusFormList.h 28 | src/Papyrus/PapyrusObjectREFR.h 29 | src/Papyrus/PapyrusPlayerCharacter.h 30 | src/Papyrus/PapyrusRace.h 31 | src/Papyrus/PapyrusSpell.h 32 | src/Papyrus/PapyrusString.h 33 | src/Papyrus/PapyrusTime.h 34 | ) 35 | 36 | set(sources 37 | src/main.cpp 38 | src/PCH.cpp 39 | src/Papyrus/Registration.cpp 40 | src/Papyrus/ActorValueHelper.cpp 41 | src/Papyrus/PapyrusActor.cpp 42 | src/Papyrus/PapyrusArray.cpp 43 | src/Papyrus/PapyrusFaction.cpp 44 | src/Papyrus/PapyrusFormList.cpp 45 | src/Papyrus/PapyrusObjectREFR.cpp 46 | src/Papyrus/PapyrusPlayerCharacter.cpp 47 | src/Papyrus/PapyrusRace.cpp 48 | src/Papyrus/PapyrusSpell.cpp 49 | src/Papyrus/PapyrusString.cpp 50 | src/Papyrus/PapyrusTime.cpp 51 | ) 52 | 53 | source_group( 54 | TREE 55 | ${CMAKE_CURRENT_SOURCE_DIR} 56 | FILES 57 | ${headers} 58 | ${sources} 59 | ) 60 | 61 | # ---- Add CMake features ---- 62 | 63 | include(CheckIPOSupported) 64 | include(GNUInstallDirs) 65 | include(GoogleTest) 66 | 67 | # ---- Dependencies ---- 68 | 69 | find_package(CommonLibSSE CONFIG REQUIRED) 70 | find_package(binary_io REQUIRED) 71 | find_package(spdlog REQUIRED) 72 | find_package(fmt REQUIRED) 73 | 74 | # ---- Configuration for all targets ---- 75 | 76 | if (MSVC) 77 | add_compile_definitions( 78 | UNICODE 79 | _UNICODE 80 | NOMINMAX 81 | _AMD64_ 82 | WIN32_LEAN_AND_MEAN 83 | _CRT_USE_BUILTIN_OFFSETOF # Fixes MSVC being non-compliant with offsetof behavior by default. 84 | ) 85 | 86 | if ($ENV{CLION_IDE}) 87 | add_compile_definitions( 88 | __cpp_lib_char8_t # Workaround for CLion bug. 89 | __cpp_consteval # Workaround for CLion bug. 90 | ) 91 | endif () 92 | 93 | add_compile_options( 94 | /bigobj # support large object file format 95 | /utf-8 # assume UTF-8 sources even without a BOM 96 | 97 | # warnings -> errors 98 | /we4715 # 'function' : not all control paths return a value 99 | 100 | # disable warnings 101 | /wd4005 # macro redefinition 102 | /wd4061 # enumerator 'identifier' in switch of enum 'enumeration' is not explicitly handled by a case label 103 | /wd4117 # definition of reserved macro, needed for workarounds for CLion 104 | /wd4200 # nonstandard extension used : zero-sized array in struct/union 105 | /wd4201 # nonstandard extension used : nameless struct/union 106 | /wd4265 # 'type': class has virtual functions, but its non-trivial destructor is not virtual; instances of this class may not be destructed correctly 107 | /wd4266 # 'function' : no override available for virtual member function from base 'type'; function is hidden 108 | /wd4371 # 'classname': layout of class may have changed from a previous version of the compiler due to better packing of member 'member' 109 | /wd4459 # declaration of 'identifier' hides global declaration 110 | /wd4514 # 'function' : unreferenced inline function has been removed 111 | /wd4582 # 'type': constructor is not implicitly called 112 | /wd4583 # 'type': destructor is not implicitly called 113 | /wd4623 # 'derived class' : default constructor was implicitly defined as deleted because a base class default constructor is inaccessible or deleted 114 | /wd4625 # 'derived class' : copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted 115 | /wd4626 # 'derived class' : assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted 116 | /wd4710 # 'function' : function not inlined 117 | /wd4711 # function 'function' selected for inline expansion 118 | /wd4820 # 'bytes' bytes padding added after construct 'member_name' 119 | /wd5026 # 'type': move constructor was implicitly defined as deleted 120 | /wd5027 # 'type': move assignment operator was implicitly defined as deleted 121 | /wd5045 # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 122 | /wd5053 # support for 'explicit()' in C++17 and earlier is a vendor extension 123 | /wd5204 # 'type-name': class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly 124 | /wd5220 # 'member': a non-static data member with a volatile qualified type no longer implies that compiler generated copy / move constructors and copy / move assignment operators are not trivial 125 | ) 126 | endif () 127 | 128 | check_ipo_supported(RESULT USE_IPO OUTPUT IPO_OUTPUT) 129 | if(USE_IPO) 130 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION "$<$:ON>") 131 | endif() 132 | 133 | # ---- Configure target DLL ---- 134 | 135 | add_commonlibsse_plugin( 136 | ${PROJECT_NAME} 137 | AUTHOR 138 | fireundubh 139 | SOURCES 140 | ${headers} 141 | ${sources} 142 | ${CMAKE_CURRENT_BINARY_DIR}/version.rc 143 | .clang-format 144 | ) 145 | 146 | target_compile_features( 147 | ${PROJECT_NAME} 148 | PUBLIC 149 | cxx_std_23 150 | ) 151 | 152 | target_compile_definitions( 153 | ${PROJECT_NAME} 154 | PUBLIC 155 | WINVER=0x0601 # windows 7, minimum supported version by skyrim special edition 156 | _WIN32_WINNT=0x0601 157 | "$<$:SKSE_SUPPORT_XBYAK=1>" 158 | "$<$:ENABLE_SKYRIM_SE=1>" 159 | "$<$:ENABLE_SKYRIM_AE=1>" 160 | "$<$:ENABLE_SKYRIM_VR=1>" 161 | ) 162 | 163 | target_include_directories( 164 | ${PROJECT_NAME} 165 | PRIVATE 166 | $ 167 | $ 168 | ) 169 | 170 | target_link_options( 171 | ${PROJECT_NAME} 172 | PUBLIC 173 | ${LINK_OPTIONS_${CONFIG}} 174 | ) 175 | 176 | target_precompile_headers( 177 | ${PROJECT_NAME} 178 | PRIVATE 179 | src/PCH.h 180 | ) 181 | 182 | set(OUTPUT_ROOT "$ENV{SkyrimAE_Mods}/${PROJECT_NAME}" CACHE STRING "") 183 | 184 | add_custom_command( 185 | TARGET ${PROJECT_NAME} 186 | POST_BUILD 187 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${OUTPUT_ROOT}/SKSE/Plugins/" 188 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_SOURCE_DIR}/Scripts/Source/${PROJECT_NAME}.psc" "${OUTPUT_ROOT}/Scripts/Source/${PROJECT_NAME}.psc" 189 | ) 190 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurePresets": [ 3 | { 4 | "name": "common", 5 | "hidden": true, 6 | "errors": { 7 | "deprecated": true 8 | }, 9 | "warnings": { 10 | "deprecated": true, 11 | "dev": true 12 | } 13 | }, 14 | 15 | { 16 | "name": "debug", 17 | "hidden": true, 18 | "inherits": [ 19 | "common" 20 | ], 21 | "cacheVariables": { 22 | "CMAKE_BUILD_TYPE": { 23 | "type": "STRING", 24 | "value": "Debug" 25 | } 26 | } 27 | }, 28 | { 29 | "name": "release", 30 | "hidden": true, 31 | "inherits": [ 32 | "common" 33 | ], 34 | "cacheVariables": { 35 | "CMAKE_BUILD_TYPE": { 36 | "type": "STRING", 37 | "value": "RelWithDebInfo" 38 | } 39 | } 40 | }, 41 | 42 | { 43 | "name": "vcpkg", 44 | "hidden": true, 45 | "cacheVariables": { 46 | "CMAKE_TOOLCHAIN_FILE": { 47 | "type": "STRING", 48 | "value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" 49 | } 50 | } 51 | }, 52 | 53 | { 54 | "name": "windows", 55 | "hidden": true, 56 | "cacheVariables": { 57 | "CMAKE_MSVC_RUNTIME_LIBRARY": { 58 | "type": "STRING", 59 | "value": "MultiThreaded$<$:Debug>DLL" 60 | }, 61 | "VCPKG_TARGET_TRIPLET": { 62 | "type": "STRING", 63 | "value": "x64-windows-static-md" 64 | } 65 | } 66 | }, 67 | 68 | { 69 | "name": "msvc", 70 | "hidden": true, 71 | "cacheVariables": { 72 | "CMAKE_CXX_FLAGS": "/EHsc /MP /W4 /WX $penv{CXXFLAGS}" 73 | }, 74 | "generator": "Ninja", 75 | "vendor": { 76 | "microsoft.com/VisualStudioSettings/CMake/1.0": { 77 | "intelliSenseMode": "windows-msvc-x64", 78 | "enableMicrosoftCodeAnalysis": true, 79 | "enableClangTidyCodeAnalysis": true 80 | } 81 | } 82 | }, 83 | { 84 | "name": "clangcl", 85 | "hidden": true, 86 | "cacheVariables": { 87 | "CMAKE_CXX_FLAGS": "/EHsc /W4 /WX $penv{CXXFLAGS}", 88 | "CMAKE_CXX_COMPILER": "clang-cl" 89 | }, 90 | "generator": "Ninja", 91 | "vendor": { 92 | "microsoft.com/VisualStudioSettings/CMake/1.0": { 93 | "intelliSenseMode": "windows-clang-x64", 94 | "enableMicrosoftCodeAnalysis": true, 95 | "enableClangTidyCodeAnalysis": true 96 | } 97 | } 98 | }, 99 | 100 | { 101 | "cacheVariables": { 102 | "ENABLE_SKYRIM_AE": { 103 | "type": "STRING", 104 | "value": "OFF" 105 | }, 106 | "ENABLE_SKYRIM_SE": { 107 | "type": "STRING", 108 | "value": "OFF" 109 | } 110 | }, 111 | "hidden": true, 112 | "name": "vr-only" 113 | }, 114 | { 115 | "cacheVariables": { 116 | "ENABLE_SKYRIM_VR": { 117 | "type": "STRING", 118 | "value": "OFF" 119 | } 120 | }, 121 | "hidden": true, 122 | "name": "flatrim-only" 123 | }, 124 | { 125 | "cacheVariables": { 126 | "ENABLE_SKYRIM_AE": { 127 | "type": "STRING", 128 | "value": "OFF" 129 | }, 130 | "ENABLE_SKYRIM_VR": { 131 | "type": "STRING", 132 | "value": "OFF" 133 | } 134 | }, 135 | "hidden": true, 136 | "name": "se-only" 137 | }, 138 | { 139 | "cacheVariables": { 140 | "ENABLE_SKYRIM_SE": { 141 | "type": "STRING", 142 | "value": "OFF" 143 | }, 144 | "ENABLE_SKYRIM_VR": { 145 | "type": "STRING", 146 | "value": "OFF" 147 | } 148 | }, 149 | "hidden": true, 150 | "name": "ae-only" 151 | }, 152 | { 153 | "cacheVariables": { 154 | "ENABLE_SKYRIM_AE": { 155 | "type": "STRING", 156 | "value": "OFF" 157 | } 158 | }, 159 | "hidden": true, 160 | "name": "pre-ae-only" 161 | }, 162 | { 163 | "cacheVariables": { 164 | "ENABLE_SKYRIM_SE": { 165 | "type": "STRING", 166 | "value": "OFF" 167 | } 168 | }, 169 | "hidden": true, 170 | "name": "current" 171 | }, 172 | 173 | { 174 | "inherits": [ 175 | "debug", 176 | "vcpkg", 177 | "windows", 178 | "msvc" 179 | ], 180 | "name": "Debug-All-MSVC", 181 | "displayName": "Debug (All, MSVC)", 182 | "binaryDir": "${sourceDir}/build/debug-all-msvc" 183 | }, 184 | { 185 | "inherits": [ 186 | "debug", 187 | "vcpkg", 188 | "windows", 189 | "clangcl" 190 | ], 191 | "name": "Debug-All-ClangCL", 192 | "displayName": "Debug (All, ClangCL)", 193 | "binaryDir": "${sourceDir}/build/debug-all-clangcl" 194 | }, 195 | { 196 | "inherits": [ 197 | "Debug-All-MSVC", 198 | "flatrim-only" 199 | ], 200 | "name": "Debug-Flatrim-MSVC", 201 | "displayName": "Debug (Flatrim, MSVC)", 202 | "binaryDir": "${sourceDir}/build/debug-flatrim-msvc" 203 | }, 204 | { 205 | "inherits": [ 206 | "Debug-All-ClangCL", 207 | "flatrim-only" 208 | ], 209 | "name": "Debug-Flatrim-ClangCL", 210 | "displayName": "Debug (Flatrim, ClangCL)", 211 | "binaryDir": "${sourceDir}/build/debug-flatrim-clangcl" 212 | }, 213 | { 214 | "inherits": [ 215 | "Debug-All-MSVC", 216 | "vr-only" 217 | ], 218 | "name": "Debug-VR-MSVC", 219 | "displayName": "Debug (VR, MSVC)", 220 | "binaryDir": "${sourceDir}/build/debug-vr-msvc" 221 | }, 222 | { 223 | "inherits": [ 224 | "Debug-All-ClangCL", 225 | "vr-only" 226 | ], 227 | "name": "Debug-VR-ClangCL", 228 | "displayName": "Debug (VR, ClangCL)", 229 | "binaryDir": "${sourceDir}/build/debug-vr-clangcl" 230 | }, 231 | { 232 | "inherits": [ 233 | "Debug-All-MSVC", 234 | "ae-only" 235 | ], 236 | "name": "Debug-AE-MSVC", 237 | "displayName": "Debug (AE, MSVC)", 238 | "binaryDir": "${sourceDir}/build/debug-ae-msvc" 239 | }, 240 | { 241 | "inherits": [ 242 | "Debug-All-ClangCL", 243 | "ae-only" 244 | ], 245 | "name": "Debug-AE-ClangCL", 246 | "displayName": "Debug (AE, ClangCL)", 247 | "binaryDir": "${sourceDir}/build/debug-ae-clangcl" 248 | }, 249 | { 250 | "inherits": [ 251 | "Debug-All-MSVC", 252 | "se-only" 253 | ], 254 | "name": "Debug-SE-MSVC", 255 | "displayName": "Debug (SE, MSVC)", 256 | "binaryDir": "${sourceDir}/build/debug-se-msvc" 257 | }, 258 | { 259 | "inherits": [ 260 | "Debug-All-ClangCL", 261 | "se-only" 262 | ], 263 | "name": "Debug-SE-ClangCL", 264 | "displayName": "Debug (SE, ClangCL)", 265 | "binaryDir": "${sourceDir}/build/debug-se-clangcl" 266 | }, 267 | { 268 | "inherits": [ 269 | "Debug-All-MSVC", 270 | "pre-ae-only" 271 | ], 272 | "name": "Debug-PreAE-MSVC", 273 | "displayName": "Debug (PreAE, MSVC)", 274 | "binaryDir": "${sourceDir}/build/debug-pre-ae-msvc" 275 | }, 276 | { 277 | "inherits": [ 278 | "Debug-All-ClangCL", 279 | "pre-ae-only" 280 | ], 281 | "name": "Debug-PreAE-ClangCL", 282 | "displayName": "Debug (PreAE, ClangCL)", 283 | "binaryDir": "${sourceDir}/build/debug-pre-ae-clangcl" 284 | }, 285 | { 286 | "inherits": [ 287 | "Debug-All-MSVC", 288 | "current" 289 | ], 290 | "name": "Debug-Current-MSVC", 291 | "displayName": "Debug (Current, MSVC)", 292 | "binaryDir": "${sourceDir}/build/debug-current-msvc" 293 | }, 294 | { 295 | "inherits": [ 296 | "Debug-All-ClangCL", 297 | "current" 298 | ], 299 | "name": "Debug-Current-ClangCL", 300 | "displayName": "Debug (Current, ClangCL)", 301 | "binaryDir": "${sourceDir}/build/debug-current-clangcl" 302 | }, 303 | 304 | { 305 | "inherits": [ 306 | "release", 307 | "vcpkg", 308 | "windows", 309 | "msvc" 310 | ], 311 | "name": "Release-All-MSVC", 312 | "displayName": "Release (All, MSVC)", 313 | "binaryDir": "${sourceDir}/build/relwithdebinfo-all-msvc" 314 | }, 315 | { 316 | "inherits": [ 317 | "release", 318 | "vcpkg", 319 | "windows", 320 | "clangcl" 321 | ], 322 | "name": "Release-All-ClangCL", 323 | "displayName": "Release (All, ClangCL)", 324 | "binaryDir": "${sourceDir}/build/relwithdebinfo-all-clangcl" 325 | }, 326 | { 327 | "inherits": [ 328 | "Release-All-MSVC", 329 | "flatrim-only" 330 | ], 331 | "name": "Release-Flatrim-MSVC", 332 | "displayName": "Release (Flatrim, MSVC)", 333 | "binaryDir": "${sourceDir}/build/relwithdebinfo-flatrim-msvc" 334 | }, 335 | { 336 | "inherits": [ 337 | "Release-All-ClangCL", 338 | "flatrim-only" 339 | ], 340 | "name": "Release-Flatrim-ClangCL", 341 | "displayName": "Release (Flatrim, ClangCL)", 342 | "binaryDir": "${sourceDir}/build/relwithdebinfo-flatrim-clangcl" 343 | }, 344 | { 345 | "inherits": [ 346 | "Release-All-MSVC", 347 | "vr-only" 348 | ], 349 | "name": "Release-VR-MSVC", 350 | "displayName": "Release (VR, MSVC)", 351 | "binaryDir": "${sourceDir}/build/relwithdebinfo-vr-msvc" 352 | }, 353 | { 354 | "inherits": [ 355 | "Release-All-ClangCL", 356 | "vr-only" 357 | ], 358 | "name": "Release-VR-ClangCL", 359 | "displayName": "Release (VR, ClangCL)", 360 | "binaryDir": "${sourceDir}/build/relwithdebinfo-vr-clangcl" 361 | }, 362 | { 363 | "inherits": [ 364 | "Release-All-MSVC", 365 | "ae-only" 366 | ], 367 | "name": "Release-AE-MSVC", 368 | "displayName": "Release (AE, MSVC)", 369 | "binaryDir": "${sourceDir}/build/relwithdebinfo-ae-msvc" 370 | }, 371 | { 372 | "inherits": [ 373 | "Release-All-ClangCL", 374 | "ae-only" 375 | ], 376 | "name": "Release-AE-ClangCL", 377 | "displayName": "Release (AE, ClangCL)", 378 | "binaryDir": "${sourceDir}/build/relwithdebinfo-ae-clangcl" 379 | }, 380 | { 381 | "inherits": [ 382 | "Release-All-MSVC", 383 | "se-only" 384 | ], 385 | "name": "Release-SE-MSVC", 386 | "displayName": "Release (SE, MSVC)", 387 | "binaryDir": "${sourceDir}/build/relwithdebinfo-se-msvc" 388 | }, 389 | { 390 | "inherits": [ 391 | "Release-All-ClangCL", 392 | "se-only" 393 | ], 394 | "name": "Release-SE-ClangCL", 395 | "displayName": "Release (SE, ClangCL)", 396 | "binaryDir": "${sourceDir}/build/relwithdebinfo-se-clangcl" 397 | }, 398 | { 399 | "inherits": [ 400 | "Release-All-MSVC", 401 | "pre-ae-only" 402 | ], 403 | "name": "Release-PreAE-MSVC", 404 | "displayName": "Release (PreAE, MSVC)", 405 | "binaryDir": "${sourceDir}/build/relwithdebinfo-pre-ae-msvc" 406 | }, 407 | { 408 | "inherits": [ 409 | "Release-All-ClangCL", 410 | "pre-ae-only" 411 | ], 412 | "name": "Release-PreAE-ClangCL", 413 | "displayName": "Release (PreAE, ClangCL)", 414 | "binaryDir": "${sourceDir}/build/relwithdebinfo-pre-ae-clangcl" 415 | }, 416 | { 417 | "inherits": [ 418 | "Release-All-MSVC", 419 | "current" 420 | ], 421 | "name": "Release-Current-MSVC", 422 | "displayName": "Release (Current, MSVC)", 423 | "binaryDir": "${sourceDir}/build/relwithdebinfo-current-msvc" 424 | }, 425 | { 426 | "inherits": [ 427 | "Release-All-ClangCL", 428 | "current" 429 | ], 430 | "name": "Release-Current-ClangCL", 431 | "displayName": "Release (Current, ClangCL)", 432 | "binaryDir": "${sourceDir}/build/relwithdebinfo-current-clangcl" 433 | } 434 | ], 435 | "buildPresets": [ 436 | { 437 | "name": "Debug-All-MSVC", 438 | "displayName": "Debug (All, MSVC)", 439 | "configurePreset": "Debug-All-MSVC" 440 | }, 441 | { 442 | "name": "Debug-All-ClangCL", 443 | "displayName": "Debug (All, ClangCL)", 444 | "configurePreset": "Debug-All-ClangCL" 445 | }, 446 | { 447 | "name": "Debug-Flatrim-MSVC", 448 | "displayName": "Debug (Flatrim)", 449 | "configurePreset": "Debug-Flatrim-MSVC" 450 | }, 451 | { 452 | "name": "Debug-Flatrim-ClangCL", 453 | "displayName": "Debug (Flatrim, ClangCL)", 454 | "configurePreset": "Debug-Flatrim-ClangCL" 455 | }, 456 | { 457 | "name": "Debug-VR-MSVC", 458 | "displayName": "Debug (VR, MSVC)", 459 | "configurePreset": "Debug-VR-MSVC" 460 | }, 461 | { 462 | "name": "Debug-VR-ClangCL", 463 | "displayName": "Debug (VR, ClangCL)", 464 | "configurePreset": "Debug-VR-ClangCL" 465 | }, 466 | { 467 | "name": "Debug-AE-MSVC", 468 | "displayName": "Debug (AE, MSVC)", 469 | "configurePreset": "Debug-AE-MSVC" 470 | }, 471 | { 472 | "name": "Debug-AE-ClangCL", 473 | "displayName": "Debug (AE, ClangCL)", 474 | "configurePreset": "Debug-AE-ClangCL" 475 | }, 476 | { 477 | "name": "Debug-SE-MSVC", 478 | "displayName": "Debug (SE, MSVC)", 479 | "configurePreset": "Debug-SE-MSVC" 480 | }, 481 | { 482 | "name": "Debug-SE-ClangCL", 483 | "displayName": "Debug (SE, ClangCL)", 484 | "configurePreset": "Debug-SE-ClangCL" 485 | }, 486 | { 487 | "name": "Debug-PreAE-MSVC", 488 | "displayName": "Debug (PreAE, MSVC)", 489 | "configurePreset": "Debug-PreAE-MSVC" 490 | }, 491 | { 492 | "name": "Debug-PreAE-ClangCL", 493 | "displayName": "Debug (PreAE, ClangCL)", 494 | "configurePreset": "Debug-PreAE-ClangCL" 495 | }, 496 | { 497 | "name": "Debug-Current-MSVC", 498 | "displayName": "Debug (Current, MSVC)", 499 | "configurePreset": "Debug-Current-MSVC" 500 | }, 501 | { 502 | "name": "Debug-Current-ClangCL", 503 | "displayName": "Debug (Current, ClangCL)", 504 | "configurePreset": "Debug-Current-ClangCL" 505 | }, 506 | 507 | { 508 | "name": "Release-All-MSVC", 509 | "displayName": "Release (All, MSVC)", 510 | "configurePreset": "Release-All-MSVC" 511 | }, 512 | { 513 | "name": "Release-All-ClangCL", 514 | "displayName": "Release (All, ClangCL)", 515 | "configurePreset": "Release-All-ClangCL" 516 | }, 517 | { 518 | "name": "Release-Flatrim-MSVC", 519 | "displayName": "Release (Flatrim)", 520 | "configurePreset": "Release-Flatrim-MSVC" 521 | }, 522 | { 523 | "name": "Release-Flatrim-ClangCL", 524 | "displayName": "Release (Flatrim, ClangCL)", 525 | "configurePreset": "Release-Flatrim-ClangCL" 526 | }, 527 | { 528 | "name": "Release-VR-MSVC", 529 | "displayName": "Release (VR, MSVC)", 530 | "configurePreset": "Release-VR-MSVC" 531 | }, 532 | { 533 | "name": "Release-VR-ClangCL", 534 | "displayName": "Release (VR, ClangCL)", 535 | "configurePreset": "Release-VR-ClangCL" 536 | }, 537 | { 538 | "name": "Release-AE-MSVC", 539 | "displayName": "Release (AE, MSVC)", 540 | "configurePreset": "Release-AE-MSVC" 541 | }, 542 | { 543 | "name": "Release-AE-ClangCL", 544 | "displayName": "Release (AE, ClangCL)", 545 | "configurePreset": "Release-AE-ClangCL" 546 | }, 547 | { 548 | "name": "Release-SE-MSVC", 549 | "displayName": "Release (SE, MSVC)", 550 | "configurePreset": "Release-SE-MSVC" 551 | }, 552 | { 553 | "name": "Release-SE-ClangCL", 554 | "displayName": "Release (SE, ClangCL)", 555 | "configurePreset": "Release-SE-ClangCL" 556 | }, 557 | { 558 | "name": "Release-PreAE-MSVC", 559 | "displayName": "Release (PreAE, MSVC)", 560 | "configurePreset": "Release-PreAE-MSVC" 561 | }, 562 | { 563 | "name": "Release-PreAE-ClangCL", 564 | "displayName": "Release (PreAE, ClangCL)", 565 | "configurePreset": "Release-PreAE-ClangCL" 566 | }, 567 | { 568 | "name": "Release-Current-MSVC", 569 | "displayName": "Release (Current, MSVC)", 570 | "configurePreset": "Release-Current-MSVC" 571 | }, 572 | { 573 | "name": "Release-Current-ClangCL", 574 | "displayName": "Release (Current, ClangCL)", 575 | "configurePreset": "Release-Current-ClangCL" 576 | } 577 | ], 578 | "version": 2 579 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 fireundubh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibFire (CommonLibSSE Plugin) 2 | 3 | Papyrus extensions by fireundubh 4 | 5 | ## Actor Functions 6 | 7 | ```papyrus 8 | ; Returns the index of the first keyword in `argKeywords` assigned to `akActor` - if not found, -1 is returned 9 | Int Function ActorFindAnyKeyword(Actor akActor, Keyword[] argKeywords) Global Native 10 | 11 | ; Returns the index of the first perk in `argPerks` assigned to `akActor` - if not found, -1 is returned 12 | Int Function ActorFindAnyPerk(Actor akActor, Perk[] argPerks) Global Native 13 | 14 | ; Returns whether `akActor` has any keyword in `akKeywords` 15 | Bool Function ActorHasAnyKeyword(Actor akActor, FormList akKeywords) Global Native 16 | 17 | ; Returns whether `akActor` has `akPerk` and its rank is `aiRank` - if match not found, `False` is returned 18 | Bool Function ActorHasPerkRank(Actor akActor, Perk akPerk, Int aiRank) Global Native 19 | 20 | ; Returns whether `akActor` is commanded by `akOtherActor` 21 | Bool Function ActorIsCommandedBy(Actor akActor, Actor akOtherActor) Global Native 22 | 23 | ; Returns whether `akActor` is commanded by the player 24 | Bool Function ActorIsCommandedByPlayer(Actor akActor) Global Native 25 | 26 | ; Returns whether `akActor` is a teammate or player-controlled commanded/summoned actor 27 | Bool Function ActorIsFollower(Actor akActor) Global Native 28 | 29 | ; Returns whether `akActor` is a member of any faction in `akFactions` with a rank greater than -1 30 | Bool Function ActorIsInAnyFaction(Actor akActor, FormList akFactions) Global Native 31 | 32 | ; Returns whether `akActor` is a member of `akFaction` with a rank greater than -1 33 | Bool Function ActorIsInFaction(Actor akActor, Faction akFaction) Global Native 34 | 35 | ; Returns whether `akActor` is a summoned actor 36 | Bool Function ActorIsSummoned(Actor akActor) Global Native 37 | 38 | ; Returns the current rank of `akPerk` assigned to `akActor` - if perk not assigned, -1 is returned 39 | Int Function GetActorPerkRank(Actor akActor, Perk akPerk) Global Native 40 | 41 | ; Returns an array of perks assigned to `akActor` 42 | Perk[] Function GetActorPerks(Actor akActor) Global Native 43 | 44 | ; Returns an array of commanded actors for `akActor` or `None` 45 | Actor[] Function GetCommandedActors(Actor akActor) Global Native 46 | 47 | ; Returns the commanding actor for `akActor` when actor is commanded 48 | Actor Function GetCommandingActor(Actor akActor) Global Native 49 | 50 | ; Returns the ammo currently equipped by `akActor` 51 | Ammo Function GetEquippedAmmo(Actor akActor) Global Native 52 | ``` 53 | 54 | ## Faction Functions 55 | 56 | ```papyrus 57 | ; Sets `akFaction` as ally or friend to each faction in `akFactions` 58 | Function SetAllies(Faction akFaction, FormList akFactions, Bool abSelfIsFriendToOther = False, Bool abOtherIsFriendToSelf = False) Global Native 59 | 60 | ; Sets `akFaction` as enemy or neutral to each faction in `akFactions` 61 | Function SetEnemies(Faction akFaction, FormList akFactions, Bool abSelfIsNeutralToOther = False, Bool abOtherIsNeutralToSelf = False) Global Native 62 | ``` 63 | 64 | ## FormList Functions 65 | 66 | ```papyrus 67 | ; Returns whether `akHaystack` contains each form in `argNeedles` 68 | Bool[] Function SearchListForForms(FormList akHaystack, Form[] argNeedles) Global Native 69 | 70 | ; Returns whether each formlist in `akHaystack` contains `akNeedle` 71 | Bool[] Function SearchListsForForm(FormList akHaystack, Form akNeedle) Global Native 72 | ``` 73 | 74 | ## ObjectReference Functions 75 | 76 | ```papyrus 77 | ; Returns actors in loaded cells within `afRadius` of `akOrigin` 78 | Actor[] Function FindNearbyActors(ObjectReference akOrigin, Float afRadius) Global Native 79 | 80 | ; Returns books in loaded cells within `afRadius` of `akOrigin` 81 | ObjectReference[] Function FindNearbyBooks(ObjectReference akOrigin, Float afRadius) Global Native 82 | 83 | ; Returns commanded actors in loaded cells within `afRadius` of `akOrigin` who are controlled by `akOrigin` 84 | Actor[] Function FindNearbyCommandedActors(ObjectReference akOrigin, Float afRadius) Global Native 85 | 86 | ; Returns teammates and player-controlled commanded/summoned actors in loaded cells within `afRadius` of player 87 | Actor[] Function FindNearbyFollowers(Float afRadius) Global Native 88 | 89 | ; Returns summoned actors in loaded cells within `afRadius` of `akOrigin` 90 | Actor[] Function FindNearbySummons(ObjectReference akOrigin, Float afRadius) Global Native 91 | 92 | ; Returns teammates in loaded cells within `afRadius` of player 93 | Actor[] Function FindNearbyTeammates(Float afRadius) Global Native 94 | 95 | ; Returns the permanent value of `asActorValue` for `akActor` 96 | Float Function GetPermanentActorValue(ObjectReference akActor, String asActorValue) Global Native 97 | ``` 98 | 99 | ## Race Functions 100 | 101 | ```papyrus 102 | ; Returns the skill boost value of `asActorValue` for `akRace` 103 | Int Function GetRaceSkillBonus(Race akRace, String asActorValue) Global Native 104 | 105 | ; Returns names of boosted actor values for `akRace` 106 | String[] Function GetRaceSkills(Race akRace) Global Native 107 | 108 | ; Returns the base male height for `akRace` 109 | Float Function GetRaceMaleHeight(Race akRace) Global Native 110 | 111 | ; Returns the base female height for `akRace` 112 | Float Function GetRaceFemaleHeight(Race akRace) Global Native 113 | 114 | ; Returns the base male weight for `akRace` 115 | Float Function GetRaceMaleWeight(Race akRace) Global Native 116 | 117 | ; Returns the base female weight for `akRace` 118 | Float Function GetRaceFemaleWeight(Race akRace) Global Native 119 | 120 | ; Returns the starting health for `akRace` 121 | Float Function GetRaceStartingHealth(Race akRace) Global Native 122 | 123 | ; Returns the starting magicka for `akRace` 124 | Float Function GetRaceStartingMagicka(Race akRace) Global Native 125 | 126 | ; Returns the starting stamina for `akRace` 127 | Float Function GetRaceStartingStamina(Race akRace) Global Native 128 | 129 | ; Returns the base carry weight for `akRace` 130 | Float Function GetRaceCarryWeight(Race akRace) Global Native 131 | 132 | ; Returns the base mass for `akRace` 133 | Float Function GetRaceMass(Race akRace) Global Native 134 | 135 | ; Returns the base health regen for `akRace` 136 | Float Function GetRaceHealthRegen(Race akRace) Global Native 137 | 138 | ; Returns the base magicka regen for `akRace` 139 | Float Function GetRaceMagickaRegen(Race akRace) Global Native 140 | 141 | ; Returns the base stamina regen for `akRace` 142 | Float Function GetRaceStaminaRegen(Race akRace) Global Native 143 | 144 | ; Returns the base unarmed damage for `akRace` 145 | Float Function GetRaceUnarmedDamage(Race akRace) Global Native 146 | 147 | ; Returns the base unarmed reach for `akRace` 148 | Float Function GetRaceUnarmedReach(Race akRace) Global Native 149 | ``` 150 | 151 | ## String Functions 152 | 153 | ```papyrus 154 | ; Returns whether `asText` contains `asSubText` (all Papyrus string comparisons are case-insensitive) 155 | Bool Function ContainsText(String asText, String asSubText) Global Native 156 | 157 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 158 | ; Note: Arrays exceeding the maximum number of values will be truncated. 159 | ; Syntax: https://fmt.dev/latest/syntax.html 160 | String Function FormatFloat(String asFormat, Float[] argValues) Global Native 161 | 162 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 163 | ; Note: Arrays exceeding the maximum number of values will be truncated. 164 | ; Syntax: https://fmt.dev/latest/syntax.html 165 | String Function FormatInt(String asFormat, Int[] argValues) Global Native 166 | 167 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 168 | ; Note: Arrays exceeding the maximum number of values will be truncated. 169 | ; Syntax: https://fmt.dev/latest/syntax.html 170 | String Function FormatString(String asFormat, String[] argValues) Global Native 171 | 172 | ; Returns the hexadecimal string representation of `aiSource` 173 | String Function IntToHex(Int aiSource) Global Native 174 | 175 | ; Returns `asSource` as array of String split by `asDelimiter` 176 | String[] Function SplitString(String asSource, String asDelimiter) Global Native 177 | 178 | ; Returns `asSource` as array of Float split by `asDelimiter` 179 | Float[] Function StrToFloatArray(String asSource, String asDelimiter) Global Native 180 | 181 | ; Returns `asSource` as array of Int split by `asDelimiter` 182 | Int[] Function StrToIntArray(String asSource, String asDelimiter) Global Native 183 | 184 | ; Returns `asSource` wrapped to column `aiMaxLength` with lines delimited by newline character 185 | String Function WrapString(String asSource, Int aiMaxLength) Global Native 186 | ``` 187 | 188 | ## Spell Functions 189 | 190 | ```papyrus 191 | ; Returns highest minimum skill level for `akSpell` (does not account for conditions, like level-based perks) 192 | Int Function GetHighestMinSkillLevelForSpell(Spell akSpell) Global Native 193 | ``` 194 | 195 | ## Time Functions 196 | 197 | ```papyrus 198 | ; Returns hours passed since current day began 199 | Float Function GetCurrentHourOfDay() Global Native 200 | ``` 201 | -------------------------------------------------------------------------------- /Scripts/Source/LibFire.psc: -------------------------------------------------------------------------------- 1 | ScriptName LibFire Hidden 2 | 3 | { Actor } 4 | 5 | ; Returns the index of the first keyword in `argKeywords` assigned to `akActor` - if not found, -1 is returned 6 | Int Function ActorFindAnyKeyword(Actor akActor, Keyword[] argKeywords) Global Native 7 | 8 | ; Returns the index of the first perk in `argPerks` assigned to `akActor` - if not found, -1 is returned 9 | Int Function ActorFindAnyPerk(Actor akActor, Perk[] argPerks) Global Native 10 | 11 | ; Returns an array of factions that track crime and of which `akActor` is a current member 12 | Faction[] Function ActorFindCrimeFactions(Actor akActor) Global Native 13 | 14 | ; Returns whether `akActor` has any keyword in `akKeywords` 15 | Bool Function ActorHasAnyKeyword(Actor akActor, FormList akKeywords) Global Native 16 | 17 | ; Returns whether `akActor` has `akPerk` and its rank is `aiRank` - if match not found, `False` is returned 18 | Bool Function ActorHasPerkRank(Actor akActor, Perk akPerk, Int aiRank) Global Native 19 | 20 | ; Returns whether `akActor` is commanded by `akOtherActor` 21 | Bool Function ActorIsCommandedBy(Actor akActor, Actor akOtherActor) Global Native 22 | 23 | ; Returns whether `akActor` is commanded by the player 24 | Bool Function ActorIsCommandedByPlayer(Actor akActor) Global Native 25 | 26 | ; Returns whether `akActor` is a teammate or player-controlled commanded/summoned actor 27 | Bool Function ActorIsFollower(Actor akActor) Global Native 28 | 29 | ; Returns whether `akActor` is a member of any faction in `akFactions` with a rank greater than -1 30 | Bool Function ActorIsInAnyFaction(Actor akActor, FormList akFactions) Global Native 31 | 32 | ; Returns whether `akActor` is a member of `akFaction` with a rank greater than -1 33 | Bool Function ActorIsInFaction(Actor akActor, Faction akFaction) Global Native 34 | 35 | ; Returns whether `akActor` is a summoned actor 36 | Bool Function ActorIsSummoned(Actor akActor) Global Native 37 | 38 | ; Returns the current rank of `akPerk` assigned to `akActor` - if perk not assigned, -1 is returned 39 | Int Function GetActorPerkRank(Actor akActor, Perk akPerk) Global Native 40 | 41 | ; Returns an array of perks assigned to `akActor` 42 | Perk[] Function GetActorPerks(Actor akActor) Global Native 43 | 44 | ; Returns an array of commanded actors for `akActor` or `None` 45 | Actor[] Function GetCommandedActors(Actor akActor) Global Native 46 | 47 | ; Returns the commanding actor for `akActor` when actor is commanded 48 | Actor Function GetCommandingActor(Actor akActor) Global Native 49 | 50 | ; Returns the ammo currently used by `akActor` 51 | Ammo Function GetEquippedAmmo(Actor akActor) Global Native 52 | 53 | { Array } 54 | 55 | ; Searches `argActors` for closest actor to `akOrigin` and returns index of member - if not found, -1 is returned 56 | Int Function ArrayFindClosestActor(Actor[] argActors, ObjectReference akOrigin) Global Native 57 | 58 | ; Searches `argHaystack` for `afValue` and returns index of member - if not found, -1 is returned 59 | Int Function ArrayFindGlobalValue(GlobalVariable[] argGlobals, Float afValue) Global Native 60 | 61 | { Faction } 62 | 63 | ; Returns flag values for `akFaction` 64 | Bool Function GetFactionIgnoresMurder(Faction akFaction) Global Native 65 | Bool Function GetFactionIgnoresAssault(Faction akFaction) Global Native 66 | Bool Function GetFactionIgnoresTrespass(Faction akFaction) Global Native 67 | Bool Function GetFactionIgnoresPickpocket(Faction akFaction) Global Native 68 | Bool Function GetFactionIgnoresStealing(Faction akFaction) Global Native 69 | Bool Function GetFactionIgnoresWerewolf(Faction akFaction) Global Native 70 | Bool Function GetFactionReportsCrimesAgainstMembers(Faction akFaction) Global Native 71 | Bool Function GetFactionTracksCrime(Faction akFaction) Global Native 72 | Bool Function GetFactionUsesCrimeGoldDefaults(Faction akFaction) Global Native 73 | 74 | ; Returns crime value (murder, assault, etc.) for `akFaction` at `aiMember` offset 75 | ; Valid offsets: 76 | ; - 0x0 Arrest (cast to Boolean) 77 | ; - 0x01 Attack On Sight (cast to Boolean) 78 | ; - 0x02 Murder (cast to Int) 79 | ; - 0x04 Assault (cast to Int) 80 | ; - 0x06 Trespass (cast to Int) 81 | ; - 0x08 Pickpocket (cast to Int) 82 | ; - 0x0C Steal Multiplier (Float) 83 | ; - 0x10 Escape (cast to Int) 84 | ; - 0x12 Werewolf (cast to Int) 85 | Float Function GetFactionCrimeValue(Faction akFaction, Int aiMember) Global Native 86 | 87 | ; Sets `akFaction` as ally or friend to each faction in `akFactions` 88 | Function SetAllies(Faction akFaction, FormList akFactions, Bool abSelfIsFriendToOther = False, Bool abOtherIsFriendToSelf = False) Global Native 89 | 90 | ; Sets `akFaction` as enemy or neutral to each faction in `akFactions` 91 | Function SetEnemies(Faction akFaction, FormList akFactions, Bool abSelfIsNeutralToOther = False, Bool abOtherIsNeutralToSelf = False) Global Native 92 | 93 | ; Copies violent and nonviolent crime gold from `akFaction` to `akOtherFaction`. If `abModify` is True, 94 | ; adds crime gold values to existing values instead. 95 | Function CopyFactionCrimeGold(Faction akFaction, Faction akOtherFaction, Bool abModify) Global Native 96 | 97 | ; Zeroes out violent and nonviolent crime gold on `akFaction` 98 | Function ResetFactionCrimeGold(Faction akFaction) Global Native 99 | 100 | ; Clears cached faction fight reactions (sometimes required to update faction actors) 101 | ; Note: SetAllies and SetEnemies already clears the faction reactions cache. 102 | Bool Function ClearFactionReactionsCache() Global Native 103 | 104 | { FormList } 105 | 106 | ; Returns whether `akHaystack` contains each form in `argNeedles` 107 | Bool[] Function SearchListForForms(FormList akHaystack, Form[] argNeedles) Global Native 108 | 109 | ; Returns whether each formlist in `akHaystack` contains `akNeedle` 110 | Bool[] Function SearchListsForForm(FormList akHaystack, Form akNeedle) Global Native 111 | 112 | { ObjectReference } 113 | 114 | ; Returns closest actor within `afRadius` of and line of sight to `akOrigin` 115 | Actor Function FindClosestActorByLOS(ObjectReference akOrigin, Float afRadius) Global Native 116 | 117 | ; Returns closest actor who is a member of `akFaction` within `afRadius` of `akOrigin` 118 | Actor Function FindClosestActorInFaction(ObjectReference akOrigin, Faction akFaction, Float afRadius) Global Native 119 | 120 | ; Returns closest actor who is a member of `akFaction` within `afRadius` of and line of sight to `akOrigin` 121 | Actor Function FindClosestActorInFactionByLOS(ObjectReference akOrigin, Faction akFaction, Float afRadius) Global Native 122 | 123 | ; Returns actors in loaded cells within `afRadius` of `akOrigin` 124 | Actor[] Function FindNearbyActors(ObjectReference akOrigin, Float afRadius) Global Native 125 | 126 | ; Returns actors who are members of `akFaction` in loaded cells within `afRadius` of `akOrigin` 127 | Actor[] Function FindNearbyActorsInFaction(ObjectReference akOrigin, Faction akFaction, Float afRadius) Global Native 128 | 129 | ; Returns actors who are members of `akFaction` in loaded cells within `afRadius` of and line of sight to `akOrigin` 130 | Actor[] Function FindNearbyActorsInFactionByLOS(ObjectReference akOrigin, Faction akFaction, Float afRadius) Global Native 131 | 132 | ; Returns books in loaded cells within `afRadius` of `akOrigin` 133 | ObjectReference[] Function FindNearbyBooks(ObjectReference akOrigin, Float afRadius) Global Native 134 | 135 | ; Returns commanded actors in loaded cells within `afRadius` of `akOrigin` who are controlled by `akOrigin` 136 | Actor[] Function FindNearbyCommandedActors(ObjectReference akOrigin, Float afRadius) Global Native 137 | 138 | ; Returns teammates and player-controlled commanded/summoned actors in loaded cells within `afRadius` of player 139 | Actor[] Function FindNearbyFollowers(Float afRadius) Global Native 140 | 141 | ; Returns summoned actors in loaded cells within `afRadius` of `akOrigin` 142 | Actor[] Function FindNearbySummons(ObjectReference akOrigin, Float afRadius) Global Native 143 | 144 | ; Returns teammates in loaded cells within `afRadius` of player 145 | Actor[] Function FindNearbyTeammates(Float afRadius) Global Native 146 | 147 | ; Returns the permanent value of `asActorValue` for `akActor` 148 | Float Function GetPermanentActorValue(ObjectReference akActor, String asActorValue) Global Native 149 | 150 | { Player Character } 151 | 152 | ; Returns an array of factions with which the player is infamous 153 | Faction[] Function FindPlayerInfamousWithFactions() Global Native 154 | 155 | ; Returns an array of factions to which the player owes crime gold 156 | Faction[] Function FindPlayerWantedByFactions() Global Native 157 | 158 | ; Returns whether the player is infamous with any faction 159 | Bool Function IsPlayerInfamous() Global Native 160 | 161 | ; Returns whether the player is wanted by any faction 162 | Bool Function IsPlayerWanted() Global Native 163 | 164 | { Race } 165 | 166 | ; Returns the skill boost value of `asActorValue` for `akRace` 167 | Int Function GetRaceSkillBonus(Race akRace, String asActorValue) Global Native 168 | 169 | ; Returns names of boosted actor values for `akRace` 170 | String[] Function GetRaceSkills(Race akRace) Global Native 171 | 172 | ; Returns the base male height for `akRace` 173 | Float Function GetRaceMaleHeight(Race akRace) Global Native 174 | 175 | ; Returns the base female height for `akRace` 176 | Float Function GetRaceFemaleHeight(Race akRace) Global Native 177 | 178 | ; Returns the base male weight for `akRace` 179 | Float Function GetRaceMaleWeight(Race akRace) Global Native 180 | 181 | ; Returns the base female weight for `akRace` 182 | Float Function GetRaceFemaleWeight(Race akRace) Global Native 183 | 184 | ; Returns the starting health for `akRace` 185 | Float Function GetRaceStartingHealth(Race akRace) Global Native 186 | 187 | ; Returns the starting magicka for `akRace` 188 | Float Function GetRaceStartingMagicka(Race akRace) Global Native 189 | 190 | ; Returns the starting stamina for `akRace` 191 | Float Function GetRaceStartingStamina(Race akRace) Global Native 192 | 193 | ; Returns the base carry weight for `akRace` 194 | Float Function GetRaceCarryWeight(Race akRace) Global Native 195 | 196 | ; Returns the base mass for `akRace` 197 | Float Function GetRaceMass(Race akRace) Global Native 198 | 199 | ; Returns the base health regen for `akRace` 200 | Float Function GetRaceHealthRegen(Race akRace) Global Native 201 | 202 | ; Returns the base magicka regen for `akRace` 203 | Float Function GetRaceMagickaRegen(Race akRace) Global Native 204 | 205 | ; Returns the base stamina regen for `akRace` 206 | Float Function GetRaceStaminaRegen(Race akRace) Global Native 207 | 208 | ; Returns the base unarmed damage for `akRace` 209 | Float Function GetRaceUnarmedDamage(Race akRace) Global Native 210 | 211 | ; Returns the base unarmed reach for `akRace` 212 | Float Function GetRaceUnarmedReach(Race akRace) Global Native 213 | 214 | { String } 215 | 216 | ; Returns whether `asText` contains `asSubText` (all Papyrus string comparisons are case-insensitive) 217 | Bool Function ContainsText(String asText, String asSubText) Global Native 218 | 219 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 220 | ; Note: Arrays exceeding the maximum number of values will be truncated. 221 | ; Syntax: https://fmt.dev/latest/syntax.html 222 | String Function FormatFloat(String asFormat, Float[] argValues) Global Native 223 | 224 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 225 | ; Note: Arrays exceeding the maximum number of values will be truncated. 226 | ; Syntax: https://fmt.dev/latest/syntax.html 227 | String Function FormatInt(String asFormat, Int[] argValues) Global Native 228 | 229 | ; Replaces `{}` tokens in `asFormat` with `argValues` (supports up to 9 values) 230 | ; Note: Arrays exceeding the maximum number of values will be truncated. 231 | ; Syntax: https://fmt.dev/latest/syntax.html 232 | String Function FormatString(String asFormat, String[] argValues) Global Native 233 | 234 | ; Returns the hexadecimal string representation of `aiSource` 235 | String Function IntToHex(Int aiSource) Global Native 236 | 237 | ; Returns `asSource` as array of String split by `asDelimiter` 238 | String[] Function SplitString(String asSource, String asDelimiter) Global Native 239 | 240 | ; Returns `asSource` as array of Float split by `asDelimiter` 241 | Float[] Function StrToFloatArray(String asSource, String asDelimiter) Global Native 242 | 243 | ; Returns `asSource` as array of Int split by `asDelimiter` 244 | Int[] Function StrToIntArray(String asSource, String asDelimiter) Global Native 245 | 246 | ; Returns `asSource` wrapped to column `aiMaxLength` with lines delimited by newline character 247 | String Function WrapString(String asSource, Int aiMaxLength) Global Native 248 | 249 | { Spell } 250 | 251 | ; Returns highest minimum skill level for `akSpell` (does not account for conditions) 252 | Int Function GetHighestMinSkillLevelForSpell(Spell akSpell) Global Native 253 | 254 | { Time } 255 | 256 | ; Returns hours passed since current day began 257 | Float Function GetCurrentHourOfDay() Global Native 258 | -------------------------------------------------------------------------------- /src/PCH.cpp: -------------------------------------------------------------------------------- 1 | #include "PCH.h" 2 | -------------------------------------------------------------------------------- /src/PCH.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/Skyrim.h" 4 | #include "SKSE/SKSE.h" 5 | 6 | #ifdef NDEBUG 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | using namespace std::literals; 13 | 14 | namespace stl = SKSE::stl; 15 | 16 | namespace logger = SKSE::log; 17 | 18 | namespace util 19 | { 20 | using SKSE::stl::report_and_fail; 21 | } 22 | 23 | #define DLLEXPORT __declspec(dllexport) -------------------------------------------------------------------------------- /src/Papyrus/ActorValueHelper.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4244) 4 | 5 | namespace ActorValueHelper 6 | { 7 | auto ActorValueToString(const RE::ActorValue a_actorValue) -> RE::BSFixedString 8 | { 9 | switch (a_actorValue) { 10 | case RE::ActorValue::kNone: 11 | return "None"sv; 12 | case RE::ActorValue::kAggression: 13 | return "Aggression"sv; 14 | case RE::ActorValue::kConfidence: 15 | return "Confidence"sv; 16 | case RE::ActorValue::kEnergy: 17 | return "Energy"sv; 18 | case RE::ActorValue::kMorality: 19 | return "Morality"sv; 20 | case RE::ActorValue::kMood: 21 | return "Mood"sv; 22 | case RE::ActorValue::kAssistance: 23 | return "Assistance"sv; 24 | case RE::ActorValue::kOneHanded: 25 | return "OneHanded"sv; 26 | case RE::ActorValue::kTwoHanded: 27 | return "TwoHanded"sv; 28 | case RE::ActorValue::kArchery: 29 | return "Marksman"sv; 30 | case RE::ActorValue::kBlock: 31 | return "Block"sv; 32 | case RE::ActorValue::kSmithing: 33 | return "Smithing"sv; 34 | case RE::ActorValue::kHeavyArmor: 35 | return "HeavyArmor"sv; 36 | case RE::ActorValue::kLightArmor: 37 | return "LightArmor"sv; 38 | case RE::ActorValue::kPickpocket: 39 | return "Pickpocket"sv; 40 | case RE::ActorValue::kLockpicking: 41 | return "Lockpicking"sv; 42 | case RE::ActorValue::kSneak: 43 | return "Sneak"sv; 44 | case RE::ActorValue::kAlchemy: 45 | return "Alchemy"sv; 46 | case RE::ActorValue::kSpeech: 47 | return "Speechcraft"sv; 48 | case RE::ActorValue::kAlteration: 49 | return "Alteration"sv; 50 | case RE::ActorValue::kConjuration: 51 | return "Conjuration"sv; 52 | case RE::ActorValue::kDestruction: 53 | return "Destruction"sv; 54 | case RE::ActorValue::kIllusion: 55 | return "Illusion"sv; 56 | case RE::ActorValue::kRestoration: 57 | return "Restoration"sv; 58 | case RE::ActorValue::kEnchanting: 59 | return "Enchanting"sv; 60 | case RE::ActorValue::kHealth: 61 | return "Health"sv; 62 | case RE::ActorValue::kMagicka: 63 | return "Magicka"sv; 64 | case RE::ActorValue::kStamina: 65 | return "Stamina"sv; 66 | case RE::ActorValue::kHealRate: 67 | return "HealRate"sv; 68 | case RE::ActorValue::kMagickaRate: 69 | return "MagickaRate"sv; 70 | case RE::ActorValue::kStaminaRate: 71 | return "StaminaRate"sv; 72 | case RE::ActorValue::kSpeedMult: 73 | return "SpeedMult"sv; 74 | case RE::ActorValue::kInventoryWeight: 75 | return "InventoryWeight"sv; 76 | case RE::ActorValue::kCarryWeight: 77 | return "CarryWeight"sv; 78 | case RE::ActorValue::kCriticalChance: 79 | return "CriticalChance"sv; 80 | case RE::ActorValue::kMeleeDamage: 81 | return "MeleeDamage"sv; 82 | case RE::ActorValue::kUnarmedDamage: 83 | return "UnarmedDamage"sv; 84 | case RE::ActorValue::kMass: 85 | return "Mass"sv; 86 | case RE::ActorValue::kVoicePoints: 87 | return "VoicePoints"sv; 88 | case RE::ActorValue::kVoiceRate: 89 | return "VoiceRate"sv; 90 | case RE::ActorValue::kDamageResist: 91 | return "DamageResist"sv; 92 | case RE::ActorValue::kPoisonResist: 93 | return "PoisonResist"sv; 94 | case RE::ActorValue::kResistFire: 95 | return "ResistFire"sv; 96 | case RE::ActorValue::kResistShock: 97 | return "ResistShock"sv; 98 | case RE::ActorValue::kResistFrost: 99 | return "ResistFrost"sv; 100 | case RE::ActorValue::kResistMagic: 101 | return "ResistMagic"sv; 102 | case RE::ActorValue::kResistDisease: 103 | return "ResistDisease"sv; 104 | case RE::ActorValue::kPerceptionCondition: 105 | return "PerceptionCondition"sv; 106 | case RE::ActorValue::kEnduranceCondition: 107 | return "EnduranceCondition"sv; 108 | case RE::ActorValue::kLeftAttackCondition: 109 | return "LeftAttackCondition"sv; 110 | case RE::ActorValue::kRightAttackCondition: 111 | return "RightAttackCondition"sv; 112 | case RE::ActorValue::kLeftMobilityCondition: 113 | return "LeftMobilityCondition"sv; 114 | case RE::ActorValue::kRightMobilityCondition: 115 | return "RightMobilityCondition"sv; 116 | case RE::ActorValue::kBrainCondition: 117 | return "BrainCondition"sv; 118 | case RE::ActorValue::kParalysis: 119 | return "Paralysis"sv; 120 | case RE::ActorValue::kInvisibility: 121 | return "Invisibility"sv; 122 | case RE::ActorValue::kNightEye: 123 | return "NightEye"sv; 124 | case RE::ActorValue::kDetectLifeRange: 125 | return "DetectLifeRange"sv; 126 | case RE::ActorValue::kWaterBreathing: 127 | return "WaterBreathing"sv; 128 | case RE::ActorValue::kWaterWalking: 129 | return "WaterWalking"sv; 130 | case RE::ActorValue::kIgnoreCrippledLimbs: 131 | return "IgnoreCrippledLimbs"sv; 132 | case RE::ActorValue::kFame: 133 | return "Fame"sv; 134 | case RE::ActorValue::kInfamy: 135 | return "Infamy"sv; 136 | case RE::ActorValue::kJumpingBonus: 137 | return "JumpingBonus"sv; 138 | case RE::ActorValue::kWardPower: 139 | return "WardPower"sv; 140 | case RE::ActorValue::kRightItemCharge: 141 | return "RightItemCharge"sv; 142 | case RE::ActorValue::kArmorPerks: 143 | return "ArmorPerks"sv; 144 | case RE::ActorValue::kShieldPerks: 145 | return "ShieldPerks"sv; 146 | case RE::ActorValue::kWardDeflection: 147 | return "WardDeflection"sv; 148 | case RE::ActorValue::kVariable01: 149 | return "Variable01"sv; 150 | case RE::ActorValue::kVariable02: 151 | return "Variable02"sv; 152 | case RE::ActorValue::kVariable03: 153 | return "Variable03"sv; 154 | case RE::ActorValue::kVariable04: 155 | return "Variable04"sv; 156 | case RE::ActorValue::kVariable05: 157 | return "Variable05"sv; 158 | case RE::ActorValue::kVariable06: 159 | return "Variable06"sv; 160 | case RE::ActorValue::kVariable07: 161 | return "Variable07"sv; 162 | case RE::ActorValue::kVariable08: 163 | return "Variable08"sv; 164 | case RE::ActorValue::kVariable09: 165 | return "Variable09"sv; 166 | case RE::ActorValue::kVariable10: 167 | return "Variable10"sv; 168 | case RE::ActorValue::kBowSpeedBonus: 169 | return "BowSpeedBonus"sv; 170 | case RE::ActorValue::kFavorActive: 171 | return "FavorActive"sv; 172 | case RE::ActorValue::kFavorsPerDay: 173 | return "FavorsPerDay"sv; 174 | case RE::ActorValue::kFavorsPerDayTimer: 175 | return "FavorsPerDayTimer"sv; 176 | case RE::ActorValue::kLeftItemCharge: 177 | return "LeftItemCharge"sv; 178 | case RE::ActorValue::kAbsorbChance: 179 | return "AbsorbChance"sv; 180 | case RE::ActorValue::kBlindness: 181 | return "Blindness"sv; 182 | case RE::ActorValue::kWeaponSpeedMult: 183 | return "WeaponSpeedMult"sv; 184 | case RE::ActorValue::kShoutRecoveryMult: 185 | return "ShoutRecoveryMult"sv; 186 | case RE::ActorValue::kBowStaggerBonus: 187 | return "BowStaggerBonus"sv; 188 | case RE::ActorValue::kTelekinesis: 189 | return "Telekinesis"sv; 190 | case RE::ActorValue::kFavorPointsBonus: 191 | return "FavorPointsBonus"sv; 192 | case RE::ActorValue::kLastBribedIntimidated: 193 | return "LastBribedIntimidated"sv; 194 | case RE::ActorValue::kLastFlattered: 195 | return "LastFlattered"sv; 196 | case RE::ActorValue::kMovementNoiseMult: 197 | return "MovementNoiseMult"sv; 198 | case RE::ActorValue::kBypassVendorStolenCheck: 199 | return "BypassVendorStolenCheck"sv; 200 | case RE::ActorValue::kBypassVendorKeywordCheck: 201 | return "BypassVendorKeywordCheck"sv; 202 | case RE::ActorValue::kWaitingForPlayer: 203 | return "WaitingForPlayer"sv; 204 | case RE::ActorValue::kOneHandedModifier: 205 | return "OneHandedModifier"sv; 206 | case RE::ActorValue::kTwoHandedModifier: 207 | return "TwoHandedModifier"sv; 208 | case RE::ActorValue::kMarksmanModifier: 209 | return "MarksmanModifier"sv; 210 | case RE::ActorValue::kBlockModifier: 211 | return "BlockModifier"sv; 212 | case RE::ActorValue::kSmithingModifier: 213 | return "SmithingModifier"sv; 214 | case RE::ActorValue::kHeavyArmorModifier: 215 | return "HeavyArmorModifier"sv; 216 | case RE::ActorValue::kLightArmorModifier: 217 | return "LightArmorModifier"sv; 218 | case RE::ActorValue::kPickpocketModifier: 219 | return "PickpocketModifier"sv; 220 | case RE::ActorValue::kLockpickingModifier: 221 | return "LockpickingModifier"sv; 222 | case RE::ActorValue::kSneakingModifier: 223 | return "SneakingModifier"sv; 224 | case RE::ActorValue::kAlchemyModifier: 225 | return "AlchemyModifier"sv; 226 | case RE::ActorValue::kSpeechcraftModifier: 227 | return "SpeechcraftModifier"sv; 228 | case RE::ActorValue::kAlterationModifier: 229 | return "AlterationModifier"sv; 230 | case RE::ActorValue::kConjurationModifier: 231 | return "ConjurationModifier"sv; 232 | case RE::ActorValue::kDestructionModifier: 233 | return "DestructionModifier"sv; 234 | case RE::ActorValue::kIllusionModifier: 235 | return "IllusionModifier"sv; 236 | case RE::ActorValue::kRestorationModifier: 237 | return "RestorationModifier"sv; 238 | case RE::ActorValue::kEnchantingModifier: 239 | return "EnchantingModifier"sv; 240 | case RE::ActorValue::kOneHandedSkillAdvance: 241 | return "OneHandedSkillAdvance"sv; 242 | case RE::ActorValue::kTwoHandedSkillAdvance: 243 | return "TwoHandedSkillAdvance"sv; 244 | case RE::ActorValue::kMarksmanSkillAdvance: 245 | return "MarksmanSkillAdvance"sv; 246 | case RE::ActorValue::kBlockSkillAdvance: 247 | return "BlockSkillAdvance"sv; 248 | case RE::ActorValue::kSmithingSkillAdvance: 249 | return "SmithingSkillAdvance"sv; 250 | case RE::ActorValue::kHeavyArmorSkillAdvance: 251 | return "HeavyArmorSkillAdvance"sv; 252 | case RE::ActorValue::kLightArmorSkillAdvance: 253 | return "LightArmorSkillAdvance"sv; 254 | case RE::ActorValue::kPickpocketSkillAdvance: 255 | return "PickpocketSkillAdvance"sv; 256 | case RE::ActorValue::kLockpickingSkillAdvance: 257 | return "LockpickingSkillAdvance"sv; 258 | case RE::ActorValue::kSneakingSkillAdvance: 259 | return "SneakingSkillAdvance"sv; 260 | case RE::ActorValue::kAlchemySkillAdvance: 261 | return "AlchemySkillAdvance"sv; 262 | case RE::ActorValue::kSpeechcraftSkillAdvance: 263 | return "SpeechcraftSkillAdvance"sv; 264 | case RE::ActorValue::kAlterationSkillAdvance: 265 | return "AlterationSkillAdvance"sv; 266 | case RE::ActorValue::kConjurationSkillAdvance: 267 | return "ConjurationSkillAdvance"sv; 268 | case RE::ActorValue::kDestructionSkillAdvance: 269 | return "DestructionSkillAdvance"sv; 270 | case RE::ActorValue::kIllusionSkillAdvance: 271 | return "IllusionSkillAdvance"sv; 272 | case RE::ActorValue::kRestorationSkillAdvance: 273 | return "RestorationSkillAdvance"sv; 274 | case RE::ActorValue::kEnchantingSkillAdvance: 275 | return "EnchantingSkillAdvance"sv; 276 | case RE::ActorValue::kLeftWeaponSpeedMultiply: 277 | return "LeftWeaponSpeedMultiply"sv; 278 | case RE::ActorValue::kDragonSouls: 279 | return "DragonSouls"sv; 280 | case RE::ActorValue::kCombatHealthRegenMultiply: 281 | return "CombatHealthRegenMultiply"sv; 282 | case RE::ActorValue::kOneHandedPowerModifier: 283 | return "OneHandedPowerModifier"sv; 284 | case RE::ActorValue::kTwoHandedPowerModifier: 285 | return "TwoHandedPowerModifier"sv; 286 | case RE::ActorValue::kMarksmanPowerModifier: 287 | return "MarksmanPowerModifier"sv; 288 | case RE::ActorValue::kBlockPowerModifier: 289 | return "BlockPowerModifier"sv; 290 | case RE::ActorValue::kSmithingPowerModifier: 291 | return "SmithingPowerModifier"sv; 292 | case RE::ActorValue::kHeavyArmorPowerModifier: 293 | return "HeavyArmorPowerModifier"sv; 294 | case RE::ActorValue::kLightArmorPowerModifier: 295 | return "LightArmorPowerModifier"sv; 296 | case RE::ActorValue::kPickpocketPowerModifier: 297 | return "PickpocketPowerModifier"sv; 298 | case RE::ActorValue::kLockpickingPowerModifier: 299 | return "LockpickingPowerModifier"sv; 300 | case RE::ActorValue::kSneakingPowerModifier: 301 | return "SneakingPowerModifier"sv; 302 | case RE::ActorValue::kAlchemyPowerModifier: 303 | return "AlchemyPowerModifier"sv; 304 | case RE::ActorValue::kSpeechcraftPowerModifier: 305 | return "SpeechcraftPowerModifier"sv; 306 | case RE::ActorValue::kAlterationPowerModifier: 307 | return "AlterationPowerModifier"sv; 308 | case RE::ActorValue::kConjurationPowerModifier: 309 | return "ConjurationPowerModifier"sv; 310 | case RE::ActorValue::kDestructionPowerModifier: 311 | return "DestructionPowerModifier"sv; 312 | case RE::ActorValue::kIllusionPowerModifier: 313 | return "IllusionPowerModifier"sv; 314 | case RE::ActorValue::kRestorationPowerModifier: 315 | return "RestorationPowerModifier"sv; 316 | case RE::ActorValue::kEnchantingPowerModifier: 317 | return "EnchantingPowerModifier"sv; 318 | case RE::ActorValue::kDragonRend: 319 | return "DragonRend"sv; 320 | case RE::ActorValue::kAttackDamageMult: 321 | return "AttackDamageMult"sv; 322 | case RE::ActorValue::kHealRateMult: 323 | return "HealRateMult"sv; 324 | case RE::ActorValue::kMagickaRateMult: 325 | return "MagickaRateMult"sv; 326 | case RE::ActorValue::kStaminaRateMult: 327 | return "StaminaRateMult"sv; 328 | case RE::ActorValue::kWerewolfPerks: 329 | return "WerewolfPerks"sv; 330 | case RE::ActorValue::kVampirePerks: 331 | return "VampirePerks"sv; 332 | case RE::ActorValue::kGrabActorOffset: 333 | return "GrabActorOffset"sv; 334 | case RE::ActorValue::kGrabbed: 335 | return "Grabbed"sv; 336 | case RE::ActorValue::kDEPRECATED05: 337 | return "DEPRECATED05"sv; 338 | case RE::ActorValue::kReflectDamage: 339 | return "ReflectDamage"sv; 340 | default: 341 | return "None"sv; 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/Papyrus/ActorValueHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4244) 4 | 5 | namespace ActorValueHelper 6 | { 7 | auto ActorValueToString(RE::ActorValue a_actorValue) -> RE::BSFixedString; 8 | } 9 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusActor.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusActor.h" 4 | 5 | namespace PapyrusActor 6 | { 7 | auto ActorFindAnyKeyword(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, std::vector a_keywords) -> std::int32_t 8 | { 9 | if (!a_actor) { 10 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 11 | return -1; 12 | } 13 | 14 | if (a_keywords.empty()) { 15 | a_vm->TraceStack("argKeywords cannot be empty", a_stackID, Severity::kInfo); 16 | return -1; 17 | } 18 | 19 | for (auto& keyword : a_keywords) { 20 | if (keyword && a_actor->HasKeyword(keyword)) { 21 | if (auto it = std::find(a_keywords.begin(), a_keywords.end(), keyword); it != a_keywords.end()) { 22 | return static_cast(it - a_keywords.begin()); 23 | } 24 | } 25 | } 26 | 27 | return -1; 28 | } 29 | 30 | auto ActorFindAnyPerk(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, std::vector a_perks) -> std::int32_t 31 | { 32 | if (!a_actor) { 33 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 34 | return -1; 35 | } 36 | 37 | if (a_perks.empty()) { 38 | a_vm->TraceStack("argPerks cannot be empty", a_stackID, Severity::kInfo); 39 | return -1; 40 | } 41 | 42 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_actor) { 43 | if (const auto perkArray = player->GetPlayerRuntimeData().addedPerks; !perkArray.empty()) { 44 | for (auto perkData : perkArray) { 45 | if (const auto perk = perkData->perk; perk) { 46 | if (auto it = std::find(a_perks.begin(), a_perks.end(), perk); it != a_perks.end()) { 47 | return static_cast(it - a_perks.begin()); 48 | } 49 | } 50 | } 51 | } 52 | } else { 53 | if (const auto actorBase = a_actor->GetActorBase(); actorBase) { 54 | if (const auto perkArray = actorBase->As(); perkArray) { 55 | for (std::uint32_t i = 0; i < perkArray->perkCount; ++i) { 56 | const auto perkData = perkArray->perks[i]; 57 | 58 | if (const auto perk = perkData.perk; perk) { 59 | if (auto it = std::find(a_perks.begin(), a_perks.end(), perk); it != a_perks.end()) { 60 | return static_cast(it - a_perks.begin()); 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | return -1; 69 | } 70 | 71 | auto ActorHasAnyKeyword(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSListForm* a_keywords) -> bool 72 | { 73 | if (!a_actor) { 74 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 75 | return false; 76 | } 77 | 78 | if (!a_keywords) { 79 | a_vm->TraceStack("akKeywords cannot be None", a_stackID, Severity::kInfo); 80 | return false; 81 | } 82 | 83 | for (auto& form : a_keywords->forms) { 84 | if (form == nullptr) 85 | continue; 86 | 87 | if (auto* const keyword = form->As(); keyword) { 88 | if (a_actor->HasKeyword(keyword)) { 89 | return true; 90 | } 91 | } 92 | } 93 | 94 | return false; 95 | } 96 | 97 | auto ActorFindCrimeFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector 98 | { 99 | std::vector results; 100 | 101 | if (!a_actor) { 102 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 103 | return results; 104 | } 105 | 106 | a_actor->VisitFactions([&](RE::TESFaction* faction, int8_t rank) -> bool { 107 | if (rank > -1 && faction->TracksCrimes()) { 108 | results.emplace_back(faction); 109 | } 110 | return true; 111 | }); 112 | 113 | return results; 114 | } 115 | 116 | auto ActorHasPerkRank(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSPerk* a_perk, std::int32_t a_rank) -> bool 117 | { 118 | if (!a_actor) { 119 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 120 | return false; 121 | } 122 | 123 | if (!a_perk) { 124 | a_vm->TraceStack("akPerk cannot be None", a_stackID, Severity::kInfo); 125 | return false; 126 | } 127 | 128 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_actor) { 129 | if (const auto perkArray = player->GetPlayerRuntimeData().addedPerks; !perkArray.empty()) { 130 | for (auto perkData : perkArray) { 131 | if (const auto perk = perkData->perk; perk && a_perk == perk && a_rank == static_cast(perkData->currentRank)) { 132 | return true; 133 | } 134 | } 135 | } 136 | } else { 137 | if (const auto actorBase = a_actor->GetActorBase(); actorBase) { 138 | if (const auto perkArray = actorBase->As(); perkArray) { 139 | for (std::uint32_t i = 0; i < perkArray->perkCount; ++i) { 140 | const auto perkData = perkArray->perks[i]; 141 | 142 | if (const auto perk = perkData.perk; perk && a_perk == perk && a_rank == static_cast(perkData.currentRank)) { 143 | return true; 144 | } 145 | } 146 | } 147 | } 148 | } 149 | 150 | return false; 151 | } 152 | 153 | auto ActorIsCommandedBy(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::Actor* a_otherActor) -> bool 154 | { 155 | if (!a_actor) { 156 | a_vm->TraceStack("akCommandedActor cannot be None", a_stackID, Severity::kInfo); 157 | return false; 158 | } 159 | 160 | if (!a_otherActor) { 161 | a_vm->TraceStack("akCommandingActor cannot be None", a_stackID, Severity::kInfo); 162 | return false; 163 | } 164 | 165 | if (!a_actor->IsCommandedActor()) { 166 | return false; 167 | } 168 | 169 | if (const auto commandingActorPtr = a_actor->GetCommandingActor(); commandingActorPtr) { 170 | const auto commandingActor = commandingActorPtr.get(); 171 | 172 | return commandingActor != nullptr && commandingActor == a_otherActor; 173 | } 174 | 175 | return false; 176 | } 177 | 178 | auto ActorIsCommandedByPlayer(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool 179 | { 180 | if (!a_actor) { 181 | a_vm->TraceStack("akCommandedActor cannot be None", a_stackID, Severity::kInfo); 182 | return false; 183 | } 184 | 185 | if (!a_actor->IsCommandedActor()) { 186 | return false; 187 | } 188 | 189 | if (auto player = RE::PlayerCharacter::GetSingleton(); player) { 190 | if (const auto commandingActorPtr = a_actor->GetCommandingActor(); commandingActorPtr) { 191 | const auto commandingActor = commandingActorPtr.get(); 192 | 193 | return commandingActor != nullptr && commandingActor == player; 194 | } 195 | } 196 | 197 | return false; 198 | } 199 | 200 | auto ActorIsFollower(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool 201 | { 202 | if (!a_actor) { 203 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 204 | return false; 205 | } 206 | 207 | if (a_actor->IsPlayerTeammate()) { 208 | return true; 209 | } 210 | 211 | if (a_actor->IsCommandedActor() || a_actor->IsSummoned()) { 212 | if (auto player = RE::PlayerCharacter::GetSingleton(); player) { 213 | if (const auto commandingActorPtr = a_actor->GetCommandingActor(); commandingActorPtr) { 214 | const auto commandingActor = commandingActorPtr.get(); 215 | 216 | return commandingActor != nullptr && commandingActor == player; 217 | } 218 | } 219 | } 220 | 221 | return false; 222 | } 223 | 224 | auto ActorIsInAnyFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSListForm* a_factions) -> bool 225 | { 226 | if (!a_actor) { 227 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 228 | return false; 229 | } 230 | 231 | if (!a_factions) { 232 | a_vm->TraceStack("akFactions cannot be None", a_stackID, Severity::kInfo); 233 | return false; 234 | } 235 | 236 | if (auto* actorBase = a_actor->GetActorBase(); actorBase) { 237 | if (auto* factionChanges = a_actor->extraList.GetByType(); factionChanges) { 238 | for (auto& change : factionChanges->factionChanges) { 239 | if (a_factions->HasForm(change.faction) && change.rank > -1) { 240 | return true; 241 | } 242 | } 243 | } 244 | 245 | for (auto& factionInfo : actorBase->factions) { 246 | if (a_factions->HasForm(factionInfo.faction) && factionInfo.rank > -1) { 247 | return true; 248 | } 249 | } 250 | } 251 | 252 | return false; 253 | } 254 | 255 | auto ActorIsInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::TESFaction* a_faction) -> bool 256 | { 257 | if (!a_actor) { 258 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 259 | return false; 260 | } 261 | 262 | if (!a_faction) { 263 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kInfo); 264 | return false; 265 | } 266 | 267 | if (auto* actorBase = a_actor->GetActorBase(); actorBase) { 268 | if (auto* factionChanges = a_actor->extraList.GetByType(); factionChanges) { 269 | for (auto& change : factionChanges->factionChanges) { 270 | if (change.faction == a_faction && change.rank > -1) { 271 | return true; 272 | } 273 | } 274 | } 275 | 276 | for (auto& factionInfo : actorBase->factions) { 277 | if (factionInfo.faction == a_faction && factionInfo.rank > -1) { 278 | return true; 279 | } 280 | } 281 | } 282 | 283 | return false; 284 | } 285 | 286 | auto ActorIsSummoned(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool 287 | { 288 | if (!a_actor) { 289 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 290 | return false; 291 | } 292 | 293 | return a_actor->IsSummoned(); 294 | } 295 | 296 | auto GetActorPerkRank(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSPerk* a_perk) -> std::int32_t 297 | { 298 | if (!a_actor) { 299 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 300 | return -1; 301 | } 302 | 303 | if (!a_perk) { 304 | a_vm->TraceStack("akPerk cannot be None", a_stackID, Severity::kInfo); 305 | return -1; 306 | } 307 | 308 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_actor) { 309 | if (const auto perkArray = player->GetPlayerRuntimeData().addedPerks; !perkArray.empty()) { 310 | for (auto perkData : perkArray) { 311 | if (const auto perk = perkData->perk; perk && a_perk == perk) { 312 | return static_cast(perkData->currentRank); 313 | } 314 | } 315 | } 316 | } else { 317 | if (const auto actorBase = a_actor->GetActorBase(); actorBase) { 318 | if (const auto perkArray = actorBase->As(); perkArray) { 319 | for (std::uint32_t i = 0; i < perkArray->perkCount; ++i) { 320 | const auto perkData = perkArray->perks[i]; 321 | 322 | if (const auto perk = perkData.perk; perk && a_perk == perk) { 323 | return static_cast(perkData.currentRank); 324 | } 325 | } 326 | } 327 | } 328 | } 329 | 330 | return -1; 331 | } 332 | 333 | auto GetActorPerks(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector 334 | { 335 | std::vector result; 336 | 337 | if (!a_actor) { 338 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 339 | return result; 340 | } 341 | 342 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_actor) { 343 | if (const auto perkArray = player->GetPlayerRuntimeData().addedPerks; !perkArray.empty()) { 344 | for (auto perkData : perkArray) { 345 | if (const auto perk = perkData->perk; perk) { 346 | result.emplace_back(perk); 347 | } 348 | } 349 | } 350 | } else { 351 | if (const auto actorBase = a_actor->GetActorBase(); actorBase) { 352 | if (const auto perkArray = actorBase->As(); perkArray) { 353 | for (std::uint32_t i = 0; i < perkArray->perkCount; ++i) { 354 | const auto perkData = perkArray->perks[i]; 355 | 356 | if (const auto perk = perkData.perk; perk) { 357 | result.emplace_back(perk); 358 | } 359 | } 360 | } 361 | } 362 | } 363 | 364 | return result; 365 | } 366 | 367 | auto GetCommandedActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector 368 | { 369 | std::vector result; 370 | 371 | if (!a_actor) { 372 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 373 | return result; 374 | } 375 | 376 | if (const auto currentProcess = a_actor->GetActorRuntimeData().currentProcess; currentProcess) { 377 | if (const auto middleProcess = currentProcess->middleHigh; middleProcess) { 378 | if (const auto commandedActors = middleProcess->commandedActors; !commandedActors.empty()) { 379 | for (const auto& commandedActorData : commandedActors) { 380 | if (const auto commandedActorHandle = commandedActorData.commandedActor; commandedActorHandle) { 381 | const auto commandedActorPtr = commandedActorHandle.get(); 382 | const auto commandedActor = commandedActorPtr.get(); 383 | 384 | result.push_back(commandedActor); 385 | } 386 | } 387 | } 388 | } 389 | } 390 | 391 | return result; 392 | } 393 | 394 | auto GetCommandingActor(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> RE::Actor* 395 | { 396 | if (!a_actor) { 397 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 398 | return nullptr; 399 | } 400 | 401 | if (!a_actor->IsCommandedActor()) { 402 | return nullptr; 403 | } 404 | 405 | if (const auto commandingActorPtr = a_actor->GetCommandingActor(); commandingActorPtr) { 406 | const auto commandingActor = commandingActorPtr.get(); 407 | 408 | return commandingActor; 409 | } 410 | 411 | return nullptr; 412 | } 413 | 414 | auto GetEquippedAmmo(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> RE::TESAmmo* 415 | { 416 | if (!a_actor) { 417 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 418 | return nullptr; 419 | } 420 | 421 | return a_actor->GetCurrentAmmo(); 422 | } 423 | 424 | auto RegisterFuncs(VM* a_vm) -> bool 425 | { 426 | if (!a_vm) { 427 | logger::info("PapyrusActor - couldn't get VMState"sv); 428 | return false; 429 | } 430 | 431 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 432 | auto project_name = plugin->GetName(); 433 | 434 | a_vm->RegisterFunction("ActorFindAnyKeyword"sv, project_name, ActorFindAnyKeyword); 435 | a_vm->RegisterFunction("ActorFindAnyPerk"sv, project_name, ActorFindAnyPerk); 436 | a_vm->RegisterFunction("ActorFindCrimeFactions"sv, project_name, ActorFindCrimeFactions); 437 | a_vm->RegisterFunction("ActorHasAnyKeyword"sv, project_name, ActorHasAnyKeyword); 438 | a_vm->RegisterFunction("ActorHasPerkRank"sv, project_name, ActorHasPerkRank); 439 | a_vm->RegisterFunction("ActorIsCommandedBy"sv, project_name, ActorIsCommandedBy); 440 | a_vm->RegisterFunction("ActorIsCommandedByPlayer"sv, project_name, ActorIsCommandedByPlayer); 441 | a_vm->RegisterFunction("ActorIsFollower"sv, project_name, ActorIsFollower); 442 | a_vm->RegisterFunction("ActorIsInAnyFaction"sv, project_name, ActorIsInAnyFaction); 443 | a_vm->RegisterFunction("ActorIsInFaction"sv, project_name, ActorIsInFaction); 444 | a_vm->RegisterFunction("ActorIsSummoned"sv, project_name, ActorIsSummoned); 445 | a_vm->RegisterFunction("GetActorPerkRank"sv, project_name, GetActorPerkRank); 446 | a_vm->RegisterFunction("GetActorPerks"sv, project_name, GetActorPerks); 447 | a_vm->RegisterFunction("GetCommandedActors"sv, project_name, GetCommandedActors); 448 | a_vm->RegisterFunction("GetCommandingActor"sv, project_name, GetCommandingActor); 449 | a_vm->RegisterFunction("GetEquippedAmmo"sv, project_name, GetEquippedAmmo); 450 | 451 | return true; 452 | } 453 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusActor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusActor 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto ActorFindAnyKeyword(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, std::vector a_keywords) -> std::int32_t; 12 | auto ActorFindAnyPerk(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, std::vector a_perks) -> std::int32_t; 13 | auto ActorFindCrimeFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector; 14 | auto ActorHasAnyKeyword(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSListForm* a_keywords) -> bool; 15 | auto ActorHasPerkRank(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSPerk* a_perk, std::int32_t a_rank) -> bool; 16 | auto ActorIsCommandedBy(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::Actor* a_otherActor) -> bool; 17 | auto ActorIsCommandedByPlayer(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool; 18 | auto ActorIsFollower(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool; 19 | auto ActorIsInAnyFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSListForm* a_factions) -> bool; 20 | auto ActorIsInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::TESFaction* a_faction) -> bool; 21 | auto ActorIsSummoned(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> bool; 22 | auto GetActorPerkRank(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor, RE::BGSPerk* a_perk) -> std::int32_t; 23 | auto GetActorPerks(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector; 24 | auto GetCommandedActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> std::vector; 25 | auto GetCommandingActor(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> RE::Actor*; 26 | auto GetEquippedAmmo(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::Actor* a_actor) -> RE::TESAmmo*; 27 | 28 | auto RegisterFuncs(VM* a_vm) -> bool; 29 | } 30 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusArray.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusArray.h" 4 | 5 | static volatile float FloatMinNormal = 1.175494E-38f; 6 | static volatile float FloatMinDenormal = 1.401298E-45f; 7 | static bool IsFlushToZeroEnabled = static_cast(FloatMinDenormal) == 0.0; 8 | 9 | static float Epsilon = IsFlushToZeroEnabled ? FloatMinNormal : FloatMinDenormal; 10 | 11 | static auto approximately(const float a, const float b) -> bool 12 | { 13 | return fabs(b - a) < std::max(0.000001f * std::max(fabs(a), fabs(b)), Epsilon * 8); 14 | } 15 | 16 | namespace PapyrusArray 17 | { 18 | auto ArrayFindClosestActor(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, std::vector a_actors, RE::TESObjectREFR* a_origin) -> std::int32_t 19 | { 20 | if (a_actors.empty()) { 21 | a_vm->TraceStack("argHaystack cannot be empty", a_stackID, Severity::kInfo); 22 | return -1; 23 | } 24 | 25 | std::multimap results; 26 | 27 | for (auto* actor : a_actors) { 28 | auto distance = a_origin->As()->GetSquaredDistance(actor->GetPosition()); 29 | results.insert(std::pair(distance, actor)); 30 | } 31 | 32 | auto needle = results.cbegin()->second; 33 | auto it = std::find(a_actors.cbegin(), a_actors.cend(), needle); 34 | 35 | return it != a_actors.cend() ? (std::int32_t)(it - a_actors.cbegin()) : -1; 36 | } 37 | 38 | auto ArrayFindGlobalValue(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, std::vector a_haystack, float a_needle) -> std::int32_t 39 | { 40 | if (a_haystack.empty()) { 41 | a_vm->TraceStack("argHaystack cannot be empty", a_stackID, Severity::kInfo); 42 | return -1; 43 | } 44 | 45 | for (std::int32_t i = 0; i < a_haystack.size(); ++i) { 46 | const auto* glob = a_haystack[i]; 47 | if (glob->value == a_needle || approximately(glob->value, a_needle)) { 48 | return i; 49 | } 50 | } 51 | 52 | return -1; 53 | } 54 | 55 | auto RegisterFuncs(VM* a_vm) -> bool 56 | { 57 | if (!a_vm) { 58 | logger::info("PapyrusArray - cannot get VMState"sv); 59 | return false; 60 | } 61 | 62 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 63 | auto project_name = plugin->GetName(); 64 | 65 | a_vm->RegisterFunction("ArrayFindClosestActor"sv, project_name, ArrayFindClosestActor); 66 | a_vm->RegisterFunction("ArrayFindGlobalValue"sv, project_name, ArrayFindGlobalValue); 67 | 68 | return true; 69 | } 70 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusArray 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto ArrayFindClosestActor(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, std::vector a_actors, RE::TESObjectREFR* a_origin) -> std::int32_t; 12 | auto ArrayFindGlobalValue(VM* glob, StackID a_stackID, RE::StaticFunctionTag*, std::vector a_haystack, float a_needle) -> std::int32_t; 13 | 14 | auto RegisterFuncs(VM* a_vm) -> bool; 15 | } 16 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusFaction.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusFaction.h" 4 | 5 | namespace PapyrusFaction 6 | { 7 | auto GetFactionIgnoresMurder(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 8 | { 9 | if (!a_faction) { 10 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 11 | return false; 12 | } 13 | return a_faction->IgnoresMurder(); 14 | } 15 | 16 | auto GetFactionIgnoresAssault(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 17 | { 18 | if (!a_faction) { 19 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 20 | return false; 21 | } 22 | return a_faction->IgnoresAssault(); 23 | } 24 | 25 | auto GetFactionIgnoresTrespass(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 26 | { 27 | if (!a_faction) { 28 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 29 | return false; 30 | } 31 | return a_faction->IgnoresTrespass(); 32 | } 33 | 34 | auto GetFactionIgnoresPickpocket(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 35 | { 36 | if (!a_faction) { 37 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 38 | return false; 39 | } 40 | return a_faction->IgnoresPickpocket(); 41 | } 42 | 43 | auto GetFactionIgnoresStealing(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 44 | { 45 | if (!a_faction) { 46 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 47 | return false; 48 | } 49 | return a_faction->IgnoresStealing(); 50 | } 51 | 52 | auto GetFactionIgnoresWerewolf(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 53 | { 54 | if (!a_faction) { 55 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 56 | return false; 57 | } 58 | return a_faction->IgnoresWerewolf(); 59 | } 60 | 61 | auto GetFactionReportsCrimesAgainstMembers(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 62 | { 63 | if (!a_faction) { 64 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 65 | return false; 66 | } 67 | 68 | return a_faction->ReportsCrimesAgainstMembers(); 69 | } 70 | 71 | auto GetFactionTracksCrime(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 72 | { 73 | if (!a_faction) { 74 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 75 | return false; 76 | } 77 | 78 | return a_faction->TracksCrimes(); 79 | } 80 | 81 | auto GetFactionUsesCrimeGoldDefaults(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool 82 | { 83 | if (!a_faction) { 84 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 85 | return false; 86 | } 87 | 88 | return a_faction->UsesCrimeGoldDefaults(); 89 | } 90 | 91 | auto GetFactionCrimeValue(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, std::int32_t a_member) -> float 92 | { 93 | if (!a_faction) { 94 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 95 | return -1.0f; 96 | } 97 | 98 | switch (a_member) { 99 | case 0x0: 100 | return a_faction->crimeData.crimevalues.arrest ? 1.0f : 0.0f; 101 | case 0x01: 102 | return a_faction->crimeData.crimevalues.attackOnSight ? 1.0f : 0.0f; 103 | case 0x02: 104 | return a_faction->crimeData.crimevalues.murderCrimeGold; 105 | case 0x04: 106 | return a_faction->crimeData.crimevalues.assaultCrimeGold; 107 | case 0x06: 108 | return a_faction->crimeData.crimevalues.trespassCrimeGold; 109 | case 0x08: 110 | return a_faction->crimeData.crimevalues.pickpocketCrimeGold; 111 | case 0x0C: 112 | return a_faction->crimeData.crimevalues.stealCrimeGoldMult; 113 | case 0x10: 114 | return a_faction->crimeData.crimevalues.escapeCrimeGold; 115 | case 0x12: 116 | return a_faction->crimeData.crimevalues.werewolfCrimeGold; 117 | default: 118 | break; 119 | } 120 | 121 | a_vm->TraceStack("aiMember is out of range", a_stackID, Severity::kWarning); 122 | return -1.0f; 123 | } 124 | 125 | auto SetAllies(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::BGSListForm* a_factions, const bool a_selfIsFriendToOther, const bool a_otherIsFriendToSelf) -> void 126 | { 127 | if (!a_faction) { 128 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 129 | return; 130 | } 131 | 132 | if (!a_factions) { 133 | a_vm->TraceStack("akFactions cannot be None", a_stackID, Severity::kWarning); 134 | return; 135 | } 136 | 137 | bool forceRefresh = false; 138 | 139 | for (auto& form : a_factions->forms) { 140 | if (form == nullptr) { 141 | continue; 142 | } 143 | 144 | if (auto* const otherFaction = form->As(); otherFaction) { 145 | a_faction->SetFactionFightReaction(otherFaction, a_selfIsFriendToOther ? RE::FIGHT_REACTION::kFriend : RE::FIGHT_REACTION::kAlly); 146 | otherFaction->SetFactionFightReaction(a_faction, a_otherIsFriendToSelf ? RE::FIGHT_REACTION::kFriend : RE::FIGHT_REACTION::kAlly); 147 | 148 | if (!forceRefresh) { 149 | forceRefresh = true; 150 | } 151 | } 152 | } 153 | 154 | if (forceRefresh) { 155 | if (auto* const processLists = RE::ProcessLists::GetSingleton(); processLists) { 156 | processLists->ClearCachedFactionFightReactions(); 157 | } 158 | } 159 | } 160 | 161 | auto SetEnemies(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::BGSListForm* a_factions, const bool a_selfIsNeutralToOther, const bool a_otherIsNeutralToSelf) -> void 162 | { 163 | if (!a_faction) { 164 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 165 | return; 166 | } 167 | 168 | if (!a_factions) { 169 | a_vm->TraceStack("akFactions cannot be None", a_stackID, Severity::kWarning); 170 | return; 171 | } 172 | 173 | bool forceRefresh = false; 174 | 175 | for (auto& form : a_factions->forms) { 176 | if (form == nullptr) { 177 | continue; 178 | } 179 | 180 | if (auto* const otherFaction = form->As(); otherFaction) { 181 | a_faction->SetFactionFightReaction(otherFaction, a_selfIsNeutralToOther ? RE::FIGHT_REACTION::kNeutral : RE::FIGHT_REACTION::kEnemy); 182 | otherFaction->SetFactionFightReaction(a_faction, a_otherIsNeutralToSelf ? RE::FIGHT_REACTION::kNeutral : RE::FIGHT_REACTION::kEnemy); 183 | 184 | if (!forceRefresh) { 185 | forceRefresh = true; 186 | } 187 | } 188 | } 189 | 190 | if (forceRefresh) { 191 | if (auto* const processLists = RE::ProcessLists::GetSingleton(); processLists) { 192 | processLists->ClearCachedFactionFightReactions(); 193 | } 194 | } 195 | } 196 | 197 | auto CopyFactionCrimeGold(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::TESFaction* a_otherFaction, const bool a_modify) -> void 198 | { 199 | if (!a_faction) { 200 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 201 | return; 202 | } 203 | 204 | if (!a_otherFaction) { 205 | a_vm->TraceStack("akOtherFaction cannot be None", a_stackID, Severity::kWarning); 206 | return; 207 | } 208 | 209 | if (a_modify) { 210 | a_otherFaction->ModCrimeGold(a_faction->GetCrimeGoldViolent(), true); 211 | a_otherFaction->ModCrimeGold(a_faction->GetCrimeGoldNonViolent(), false); 212 | } else { 213 | a_otherFaction->SetCrimeGoldViolent(a_faction->GetCrimeGoldViolent()); 214 | a_otherFaction->SetCrimeGold(a_faction->GetCrimeGoldNonViolent()); 215 | } 216 | 217 | if (auto* const processLists = RE::ProcessLists::GetSingleton(); processLists) { 218 | processLists->ClearCachedFactionFightReactions(); 219 | } 220 | } 221 | 222 | auto ResetFactionCrimeGold(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> void 223 | { 224 | if (!a_faction) { 225 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kWarning); 226 | return; 227 | } 228 | 229 | a_faction->SetCrimeGoldViolent(0); 230 | a_faction->SetCrimeGold(0); 231 | 232 | if (auto* const processLists = RE::ProcessLists::GetSingleton(); processLists) { 233 | processLists->ClearCachedFactionFightReactions(); 234 | } 235 | } 236 | 237 | auto ClearFactionReactionsCache(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool 238 | { 239 | if (auto* const processLists = RE::ProcessLists::GetSingleton(); processLists) { 240 | processLists->ClearCachedFactionFightReactions(); 241 | return true; 242 | } 243 | 244 | return false; 245 | } 246 | 247 | auto RegisterFuncs(VM* a_vm) -> bool 248 | { 249 | if (!a_vm) { 250 | logger::info("PapyrusFaction - cannot get VMState"sv); 251 | return false; 252 | } 253 | 254 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 255 | auto project_name = plugin->GetName(); 256 | 257 | a_vm->RegisterFunction("GetFactionIgnoresMurder"sv, project_name, GetFactionIgnoresMurder); 258 | a_vm->RegisterFunction("GetFactionIgnoresAssault"sv, project_name, GetFactionIgnoresAssault); 259 | a_vm->RegisterFunction("GetFactionIgnoresTrespass"sv, project_name, GetFactionIgnoresTrespass); 260 | a_vm->RegisterFunction("GetFactionIgnoresPickpocket"sv, project_name, GetFactionIgnoresPickpocket); 261 | a_vm->RegisterFunction("GetFactionIgnoresStealing"sv, project_name, GetFactionIgnoresStealing); 262 | a_vm->RegisterFunction("GetFactionIgnoresWerewolf"sv, project_name, GetFactionIgnoresWerewolf); 263 | a_vm->RegisterFunction("GetFactionReportsCrimesAgainstMembers"sv, project_name, GetFactionReportsCrimesAgainstMembers); 264 | a_vm->RegisterFunction("GetFactionTracksCrime"sv, project_name, GetFactionTracksCrime); 265 | a_vm->RegisterFunction("GetFactionUsesCrimeGoldDefaults"sv, project_name, GetFactionUsesCrimeGoldDefaults); 266 | a_vm->RegisterFunction("GetFactionCrimeValue"sv, project_name, GetFactionCrimeValue); 267 | 268 | a_vm->RegisterFunction("SetAllies"sv, project_name, SetAllies); 269 | a_vm->RegisterFunction("SetEnemies"sv, project_name, SetEnemies); 270 | 271 | a_vm->RegisterFunction("CopyFactionCrimeGold"sv, project_name, CopyFactionCrimeGold); 272 | a_vm->RegisterFunction("ResetFactionCrimeGold"sv, project_name, ResetFactionCrimeGold); 273 | 274 | a_vm->RegisterFunction("ClearFactionReactionsCache"sv, project_name, ClearFactionReactionsCache); 275 | 276 | return true; 277 | } 278 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusFaction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusFaction 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto GetFactionIgnoresMurder(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 12 | auto GetFactionIgnoresAssault(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 13 | auto GetFactionIgnoresTrespass(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 14 | auto GetFactionIgnoresPickpocket(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 15 | auto GetFactionIgnoresStealing(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 16 | auto GetFactionIgnoresWerewolf(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 17 | auto GetFactionReportsCrimesAgainstMembers(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 18 | auto GetFactionTracksCrime(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 19 | auto GetFactionUsesCrimeGoldDefaults(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> bool; 20 | auto GetFactionCrimeValue(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, std::int32_t a_member) -> float; 21 | 22 | auto SetAllies(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::BGSListForm* a_factions, bool a_selfIsFriendToOther, bool a_otherIsFriendToSelf) -> void; 23 | auto SetEnemies(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::BGSListForm* a_factions, bool a_selfIsNeutralToOther, bool a_otherIsNeutralToSelf) -> void; 24 | 25 | auto CopyFactionCrimeGold(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction, RE::TESFaction* a_otherFaction, bool a_modify) -> void; 26 | auto ResetFactionCrimeGold(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESFaction* a_faction) -> void; 27 | 28 | auto ClearFactionReactionsCache(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool; 29 | 30 | auto RegisterFuncs(VM* a_vm) -> bool; 31 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusFormList.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusFormList.h" 4 | 5 | namespace PapyrusFormList 6 | { 7 | auto SearchListForForms(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BGSListForm* a_list, std::vector a_forms) -> std::vector 8 | { 9 | std::vector vec; 10 | 11 | if (!a_list) { 12 | a_vm->TraceStack("akHaystack cannot be None", a_stackID, Severity::kInfo); 13 | return vec; 14 | } 15 | 16 | if (a_list->forms.empty()) { 17 | a_vm->TraceStack("akHaystack cannot be empty", a_stackID, Severity::kInfo); 18 | return vec; 19 | } 20 | 21 | if (a_forms.empty()) { 22 | a_vm->TraceStack("argNeedles cannot be None", a_stackID, Severity::kInfo); 23 | return vec; 24 | } 25 | 26 | for (auto* form : a_forms) { 27 | vec.push_back(form != nullptr && a_list->HasForm(form)); 28 | } 29 | 30 | return vec; 31 | } 32 | 33 | auto SearchListsForForm(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BGSListForm* a_lists, RE::TESForm* a_form) -> std::vector 34 | { 35 | std::vector vec; 36 | 37 | if (a_form == nullptr) { 38 | a_vm->TraceStack("akNeedle cannot be None", a_stackID, Severity::kInfo); 39 | return vec; 40 | } 41 | 42 | if (a_lists == nullptr) { 43 | a_vm->TraceStack("akHaystack cannot be None", a_stackID, Severity::kInfo); 44 | return vec; 45 | } 46 | 47 | if (a_lists->forms.empty()) { 48 | a_vm->TraceStack("akHaystack cannot be empty", a_stackID, Severity::kInfo); 49 | return vec; 50 | } 51 | 52 | for (auto& column : a_lists->forms) { 53 | if (auto* row = column->As(); row) { 54 | vec.push_back(!row->forms.empty() && row->HasForm(a_form)); 55 | } 56 | } 57 | 58 | return vec; 59 | } 60 | 61 | auto RegisterFuncs(VM* a_vm) -> bool 62 | { 63 | if (!a_vm) { 64 | logger::info("PapyrusFormList - cannot get VMState"sv); 65 | return false; 66 | } 67 | 68 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 69 | auto project_name = plugin->GetName(); 70 | 71 | a_vm->RegisterFunction("SearchListForForms"sv, project_name, SearchListForForms); 72 | a_vm->RegisterFunction("SearchListsForForm"sv, project_name, SearchListsForForm); 73 | 74 | return true; 75 | } 76 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusFormList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusFormList 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto SearchListForForms(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BGSListForm* a_list, std::vector a_forms) -> std::vector; 12 | auto SearchListsForForm(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BGSListForm* a_lists, RE::TESForm* a_form) -> std::vector; 13 | 14 | auto RegisterFuncs(VM* a_vm) -> bool; 15 | } 16 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusObjectREFR.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusObjectREFR.h" 4 | 5 | namespace PapyrusObjectREFR 6 | { 7 | auto FindClosestActorByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> RE::Actor* 8 | { 9 | if (!a_origin) { 10 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 11 | return nullptr; 12 | } 13 | 14 | std::vector vec; 15 | 16 | if (const auto TES = RE::TES::GetSingleton(); TES) { 17 | const auto formType = RE::FormType::NPC; 18 | 19 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_origin) { 20 | bool codePath = false; 21 | 22 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 23 | auto base = a_ref.GetBaseObject(); 24 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 25 | if (auto actor = a_ref.As(); actor && actor->HasLineOfSight(a_origin, codePath)) { 26 | vec.push_back(actor); 27 | } 28 | } 29 | return RE::BSContainer::ForEachResult::kStop; 30 | }); 31 | } 32 | else { 33 | bool codePath = true; 34 | 35 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 36 | auto base = a_ref.GetBaseObject(); 37 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 38 | if (auto actor = a_ref.As(); actor && actor->HasLineOfSight(a_origin, codePath)) { 39 | vec.push_back(actor); 40 | } 41 | } 42 | return RE::BSContainer::ForEachResult::kStop; 43 | }); 44 | } 45 | } 46 | 47 | if (vec.empty()) 48 | return nullptr; 49 | 50 | if (vec.size() == 1) 51 | return vec.front(); 52 | 53 | std::multimap results; 54 | 55 | for (auto* actor : vec) { 56 | auto distance = a_origin->As()->GetSquaredDistance(actor->GetPosition()); 57 | results.insert(std::pair(distance, actor)); 58 | } 59 | 60 | return results.cbegin()->second; 61 | } 62 | 63 | auto FindClosestActorInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> RE::Actor* 64 | { 65 | if (!a_origin) { 66 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 67 | return nullptr; 68 | } 69 | 70 | if (!a_faction) { 71 | a_vm->TraceStack("akFaction cannot be None", a_stackID, Severity::kInfo); 72 | return nullptr; 73 | } 74 | 75 | std::vector vec; 76 | 77 | if (const auto TES = RE::TES::GetSingleton(); TES) { 78 | const auto formType = RE::FormType::NPC; 79 | 80 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 81 | auto base = a_ref.GetBaseObject(); 82 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 83 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction)) { 84 | vec.push_back(actor); 85 | } 86 | } 87 | return RE::BSContainer::ForEachResult::kStop; 88 | }); 89 | } 90 | 91 | if (vec.empty()) 92 | return nullptr; 93 | 94 | if (vec.size() == 1) 95 | return vec.front(); 96 | 97 | std::multimap results; 98 | 99 | for (auto* actor : vec) { 100 | auto distance = a_origin->As()->GetSquaredDistance(actor->GetPosition()); 101 | results.insert(std::pair(distance, actor)); 102 | } 103 | 104 | return results.cbegin()->second; 105 | } 106 | 107 | auto FindClosestActorInFactionByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> RE::Actor* 108 | { 109 | if (!a_origin) { 110 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 111 | return nullptr; 112 | } 113 | 114 | std::vector vec; 115 | 116 | if (const auto TES = RE::TES::GetSingleton(); TES) { 117 | const auto formType = RE::FormType::NPC; 118 | 119 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_origin) { 120 | bool codePath = false; 121 | 122 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 123 | auto base = a_ref.GetBaseObject(); 124 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 125 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction) && actor->HasLineOfSight(a_origin, codePath)) { 126 | vec.push_back(actor); 127 | } 128 | } 129 | return RE::BSContainer::ForEachResult::kStop; 130 | }); 131 | } else { 132 | bool codePath = true; 133 | 134 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 135 | auto base = a_ref.GetBaseObject(); 136 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 137 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction) && actor->HasLineOfSight(a_origin, codePath)) { 138 | vec.push_back(actor); 139 | } 140 | } 141 | return RE::BSContainer::ForEachResult::kStop; 142 | }); 143 | } 144 | } 145 | 146 | if (vec.empty()) 147 | return nullptr; 148 | 149 | if (vec.size() == 1) 150 | return vec.front(); 151 | 152 | std::multimap results; 153 | 154 | for (auto* actor : vec) { 155 | auto distance = a_origin->As()->GetSquaredDistance(actor->GetPosition()); 156 | results.insert(std::pair(distance, actor)); 157 | } 158 | 159 | return results.cbegin()->second; 160 | } 161 | 162 | auto FindNearbyActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector 163 | { 164 | std::vector vec; 165 | 166 | if (!a_origin) { 167 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 168 | return vec; 169 | } 170 | 171 | if (const auto TES = RE::TES::GetSingleton(); TES) { 172 | const auto formType = RE::FormType::NPC; 173 | 174 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 175 | auto base = a_ref.GetBaseObject(); 176 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 177 | if (auto actor = a_ref.As(); actor) { 178 | vec.push_back(actor); 179 | } 180 | } 181 | return RE::BSContainer::ForEachResult::kStop; 182 | }); 183 | } 184 | 185 | return vec; 186 | } 187 | 188 | auto FindNearbyActorsInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> std::vector 189 | { 190 | std::vector vec; 191 | 192 | if (!a_origin) { 193 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 194 | return vec; 195 | } 196 | 197 | if (const auto TES = RE::TES::GetSingleton(); TES) { 198 | const auto formType = RE::FormType::NPC; 199 | 200 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 201 | auto base = a_ref.GetBaseObject(); 202 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 203 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction)) { 204 | vec.push_back(actor); 205 | } 206 | } 207 | return RE::BSContainer::ForEachResult::kStop; 208 | }); 209 | } 210 | 211 | return vec; 212 | } 213 | 214 | auto FindNearbyActorsInFactionByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> std::vector 215 | { 216 | std::vector vec; 217 | 218 | if (!a_origin) { 219 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 220 | return vec; 221 | } 222 | 223 | if (const auto TES = RE::TES::GetSingleton(); TES) { 224 | const auto formType = RE::FormType::NPC; 225 | 226 | if (auto player = RE::PlayerCharacter::GetSingleton(); player == a_origin) { 227 | bool codePath = false; 228 | 229 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 230 | auto base = a_ref.GetBaseObject(); 231 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 232 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction) && actor->HasLineOfSight(a_origin, codePath)) { 233 | vec.push_back(actor); 234 | } 235 | } 236 | return RE::BSContainer::ForEachResult::kStop; 237 | }); 238 | } else { 239 | bool codePath = true; 240 | 241 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 242 | auto base = a_ref.GetBaseObject(); 243 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 244 | if (auto actor = a_ref.As(); actor && actor->IsInFaction(a_faction) && actor->HasLineOfSight(a_origin, codePath)) { 245 | vec.push_back(actor); 246 | } 247 | } 248 | return RE::BSContainer::ForEachResult::kStop; 249 | }); 250 | } 251 | } 252 | 253 | return vec; 254 | } 255 | 256 | auto FindNearbyBooks(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector 257 | { 258 | std::vector vec; 259 | 260 | if (!a_origin) { 261 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 262 | return vec; 263 | } 264 | 265 | if (const auto TES = RE::TES::GetSingleton(); TES) { 266 | const auto formType = RE::FormType::Book; 267 | 268 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 269 | auto base = a_ref.GetBaseObject(); 270 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 271 | vec.push_back(&a_ref); 272 | } 273 | return RE::BSContainer::ForEachResult::kStop; 274 | }); 275 | } 276 | 277 | return vec; 278 | } 279 | 280 | auto FindNearbyCommandedActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector 281 | { 282 | std::vector vec; 283 | 284 | if (!a_origin) { 285 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 286 | return vec; 287 | } 288 | 289 | if (const auto TES = RE::TES::GetSingleton(); TES) { 290 | const auto formType = RE::FormType::NPC; 291 | 292 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 293 | auto base = a_ref.GetBaseObject(); 294 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 295 | if (auto actor = a_ref.As(); actor) { 296 | if (actor->IsCommandedActor()) { 297 | if (const auto commandingActorPtr = actor->GetCommandingActor(); commandingActorPtr) { 298 | const auto commandingActor = commandingActorPtr.get(); 299 | 300 | if (commandingActor != nullptr && commandingActor == a_origin) { 301 | vec.push_back(actor); 302 | } 303 | } 304 | } 305 | } 306 | } 307 | return RE::BSContainer::ForEachResult::kStop; 308 | }); 309 | } 310 | 311 | return vec; 312 | } 313 | 314 | auto FindNearbyFollowers(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, float a_radius) -> std::vector 315 | { 316 | std::vector vec; 317 | 318 | if (const auto TES = RE::TES::GetSingleton(); TES) { 319 | if (const auto player = RE::PlayerCharacter::GetSingleton(); player) { 320 | const auto formType = RE::FormType::NPC; 321 | 322 | TES->ForEachReferenceInRange(player, a_radius, [&](RE::TESObjectREFR& a_ref) { 323 | auto base = a_ref.GetBaseObject(); 324 | if (a_ref.As() != player && (a_ref.Is(formType) || base && base->Is(formType))) { 325 | if (auto actor = a_ref.As(); actor) { 326 | if (actor->IsPlayerTeammate()) { 327 | vec.push_back(actor); 328 | } else if (actor->IsCommandedActor() || actor->IsSummoned()) { 329 | if (const auto commandingActorPtr = actor->GetCommandingActor(); commandingActorPtr) { 330 | const auto commandingActor = commandingActorPtr.get(); 331 | 332 | if (commandingActor != nullptr && commandingActor == player) { 333 | vec.push_back(actor); 334 | } 335 | } 336 | } 337 | } 338 | } 339 | return RE::BSContainer::ForEachResult::kStop; 340 | }); 341 | } 342 | } 343 | 344 | return vec; 345 | } 346 | 347 | auto FindNearbySummons(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector 348 | { 349 | std::vector vec; 350 | 351 | if (!a_origin) { 352 | a_vm->TraceStack("akOrigin cannot be None", a_stackID, Severity::kInfo); 353 | return vec; 354 | } 355 | 356 | if (const auto TES = RE::TES::GetSingleton(); TES) { 357 | const auto formType = RE::FormType::NPC; 358 | 359 | TES->ForEachReferenceInRange(a_origin, a_radius, [&](RE::TESObjectREFR& a_ref) { 360 | auto base = a_ref.GetBaseObject(); 361 | if (a_ref.As() != a_origin && (a_ref.Is(formType) || base && base->Is(formType))) { 362 | if (auto actor = a_ref.As(); actor) { 363 | if (actor->IsSummoned()) { 364 | vec.push_back(actor); 365 | } 366 | } 367 | } 368 | return RE::BSContainer::ForEachResult::kStop; 369 | }); 370 | } 371 | 372 | return vec; 373 | } 374 | 375 | auto FindNearbyTeammates(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, float a_radius) -> std::vector 376 | { 377 | std::vector vec; 378 | 379 | if (const auto TES = RE::TES::GetSingleton(); TES) { 380 | if (const auto player = RE::PlayerCharacter::GetSingleton(); player) { 381 | if (player->GetPlayerRuntimeData().teammateCount > 0) { 382 | const auto formType = RE::FormType::NPC; 383 | 384 | TES->ForEachReferenceInRange(player, a_radius, [&](RE::TESObjectREFR& a_ref) { 385 | auto base = a_ref.GetBaseObject(); 386 | if (a_ref.As() != player && (a_ref.Is(formType) || base && base->Is(formType))) { 387 | if (auto actor = a_ref.As(); actor) { 388 | if (actor->IsPlayerTeammate()) { 389 | vec.push_back(actor); 390 | } 391 | } 392 | } 393 | return RE::BSContainer::ForEachResult::kStop; 394 | }); 395 | } 396 | } 397 | } 398 | 399 | return vec; 400 | } 401 | 402 | auto GetPermanentActorValue(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_ref, RE::BSFixedString a_actorValue) -> float 403 | { 404 | if (!a_ref) { 405 | a_vm->TraceStack("akActor cannot be None", a_stackID, Severity::kInfo); 406 | return -1.0; 407 | } 408 | 409 | if (const auto actor = a_ref->As(); actor) { 410 | const auto actorValueId = RE::ActorValueList::GetSingleton()->LookupActorValueByName(a_actorValue); 411 | const auto actorValue = static_cast(actorValueId); 412 | return actor->GetActorBase()->GetPermanentActorValue(actorValue); 413 | } 414 | 415 | return -1.0; 416 | } 417 | 418 | auto RegisterFuncs(VM* a_vm) -> bool 419 | { 420 | if (!a_vm) { 421 | logger::info("PapyrusObjectREFR - couldn't get VMState"sv); 422 | return false; 423 | } 424 | 425 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 426 | auto project_name = plugin->GetName(); 427 | 428 | a_vm->RegisterFunction("FindClosestActorByLOS"sv, project_name, FindClosestActorByLOS); 429 | a_vm->RegisterFunction("FindClosestActorInFaction"sv, project_name, FindClosestActorInFaction); 430 | a_vm->RegisterFunction("FindClosestActorInFactionByLOS"sv, project_name, FindClosestActorInFactionByLOS); 431 | a_vm->RegisterFunction("FindNearbyActors"sv, project_name, FindNearbyActors); 432 | a_vm->RegisterFunction("FindNearbyActorsInFaction"sv, project_name, FindNearbyActorsInFaction); 433 | a_vm->RegisterFunction("FindNearbyActorsInFactionByLOS"sv, project_name, FindNearbyActorsInFactionByLOS); 434 | a_vm->RegisterFunction("FindNearbyBooks"sv, project_name, FindNearbyBooks); 435 | a_vm->RegisterFunction("FindNearbyCommandedActors"sv, project_name, FindNearbyCommandedActors); 436 | a_vm->RegisterFunction("FindNearbyFollowers"sv, project_name, FindNearbyFollowers); 437 | a_vm->RegisterFunction("FindNearbySummons"sv, project_name, FindNearbySummons); 438 | a_vm->RegisterFunction("FindNearbyTeammates"sv, project_name, FindNearbyTeammates); 439 | a_vm->RegisterFunction("GetPermanentActorValue"sv, project_name, GetPermanentActorValue); 440 | 441 | return true; 442 | } 443 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusObjectREFR.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusObjectREFR 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto FindClosestActorByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> RE::Actor*; 12 | auto FindClosestActorInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> RE::Actor*; 13 | auto FindClosestActorInFactionByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> RE::Actor*; 14 | auto FindNearbyActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector; 15 | auto FindNearbyActorsInFaction(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> std::vector; 16 | auto FindNearbyActorsInFactionByLOS(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, RE::TESFaction* a_faction, float a_radius) -> std::vector; 17 | auto FindNearbyBooks(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector; 18 | auto FindNearbyCommandedActors(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector; 19 | auto FindNearbyFollowers(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, float a_radius) -> std::vector; 20 | auto FindNearbySummons(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_origin, float a_radius) -> std::vector; 21 | auto FindNearbyTeammates(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, float a_radius) -> std::vector; 22 | auto GetPermanentActorValue(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESObjectREFR* a_ref, RE::BSFixedString a_actorValue) -> float; 23 | 24 | auto RegisterFuncs(VM* a_vm) -> bool; 25 | } 26 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusPlayerCharacter.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusPlayerCharacter.h" 4 | 5 | namespace PapyrusPlayerCharacter 6 | { 7 | auto FindPlayerInfamousWithFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> std::vector 8 | { 9 | std::vector results; 10 | 11 | if (auto player = RE::PlayerCharacter::GetSingleton()) { 12 | for (const auto& [first, second] : player->GetCrimeValue().crimeGoldMap) { 13 | auto total = second.nonViolentInfamy + second.violentInfamy; 14 | if (total > 0.0f) { 15 | results.push_back(const_cast(first)); 16 | } 17 | } 18 | } 19 | 20 | return results; 21 | } 22 | 23 | auto FindPlayerWantedByFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> std::vector 24 | { 25 | std::vector results; 26 | 27 | if (auto player = RE::PlayerCharacter::GetSingleton()) { 28 | for (const auto& [first, second] : player->GetCrimeValue().crimeGoldMap) { 29 | auto total = second.nonViolentCur + second.violentCur; 30 | if (total > 0.0f) { 31 | results.push_back(const_cast(first)); 32 | } 33 | } 34 | } 35 | 36 | return results; 37 | } 38 | 39 | auto IsPlayerInfamous(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool 40 | { 41 | auto total = 0.0f; 42 | 43 | if (auto player = RE::PlayerCharacter::GetSingleton()) { 44 | for (const auto& [first, second] : player->GetCrimeValue().crimeGoldMap) { 45 | total += (second.nonViolentInfamy + second.violentInfamy); 46 | } 47 | } 48 | 49 | return total > 0.0f; 50 | } 51 | 52 | auto IsPlayerWanted(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool 53 | { 54 | auto total = 0.0f; 55 | 56 | if (auto player = RE::PlayerCharacter::GetSingleton()) { 57 | for (const auto& [first, second] : player->GetCrimeValue().crimeGoldMap) { 58 | total += (second.nonViolentCur + second.violentCur); 59 | } 60 | } 61 | 62 | return total > 0.0f; 63 | } 64 | 65 | auto RegisterFuncs(VM* a_vm) -> bool 66 | { 67 | if (!a_vm) { 68 | logger::info("PapyrusPlayerCharacter - cannot get VMState"sv); 69 | return false; 70 | } 71 | 72 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 73 | auto project_name = plugin->GetName(); 74 | 75 | a_vm->RegisterFunction("FindPlayerInfamousWithFactions"sv, project_name, FindPlayerInfamousWithFactions); 76 | a_vm->RegisterFunction("FindPlayerWantedByFactions"sv, project_name, FindPlayerWantedByFactions); 77 | a_vm->RegisterFunction("IsPlayerInfamous"sv, project_name, IsPlayerInfamous); 78 | a_vm->RegisterFunction("IsPlayerWanted"sv, project_name, IsPlayerWanted); 79 | 80 | return true; 81 | } 82 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusPlayerCharacter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusPlayerCharacter 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto FindPlayerInfamousWithFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> std::vector; 12 | auto FindPlayerWantedByFactions(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> std::vector; 13 | auto IsPlayerInfamous(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool; 14 | auto IsPlayerWanted(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> bool; 15 | 16 | auto RegisterFuncs(VM* a_vm) -> bool; 17 | } 18 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusRace.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ActorValueHelper.h" 4 | 5 | #include "PapyrusRace.h" 6 | 7 | namespace PapyrusRace 8 | { 9 | auto GetRaceSkillBonus(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race, RE::BSFixedString a_actorValue) -> std::int32_t 10 | { 11 | if (!a_race) { 12 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 13 | return -1; 14 | } 15 | 16 | const auto actorValueId = RE::ActorValueList::GetSingleton()->LookupActorValueByName(a_actorValue); 17 | const auto actorValue = static_cast(actorValueId); 18 | 19 | for (const auto& [skill, bonus] : a_race->data.skillBoosts) { 20 | const auto skillValue = static_cast(skill.get()); 21 | if (skillValue == actorValue) { 22 | return static_cast(bonus); 23 | } 24 | } 25 | 26 | return -1; 27 | } 28 | 29 | auto GetRaceSkills(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> std::vector 30 | { 31 | std::vector vec; 32 | 33 | if (!a_race) { 34 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 35 | return vec; 36 | } 37 | 38 | for (const auto& [skill, bonus] : a_race->data.skillBoosts) { 39 | const auto skillValue = static_cast(skill.get()); 40 | const auto skillName = ActorValueHelper::ActorValueToString(skillValue); 41 | vec.push_back(skillName); 42 | } 43 | 44 | return vec; 45 | } 46 | 47 | auto GetRaceMaleHeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 48 | { 49 | if (!a_race) { 50 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 51 | return -1; 52 | } 53 | 54 | return a_race->data.height[RE::SEXES::kMale]; 55 | } 56 | 57 | auto GetRaceFemaleHeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 58 | { 59 | if (!a_race) { 60 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 61 | return -1; 62 | } 63 | 64 | return a_race->data.height[RE::SEXES::kFemale]; 65 | } 66 | 67 | auto GetRaceMaleWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 68 | { 69 | if (!a_race) { 70 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 71 | return -1; 72 | } 73 | 74 | return a_race->data.weight[RE::SEXES::kMale]; 75 | } 76 | 77 | auto GetRaceFemaleWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 78 | { 79 | if (!a_race) { 80 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 81 | return -1; 82 | } 83 | 84 | return a_race->data.weight[RE::SEXES::kFemale]; 85 | } 86 | 87 | auto GetRaceStartingHealth(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 88 | { 89 | if (!a_race) { 90 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 91 | return -1; 92 | } 93 | 94 | return a_race->data.startingHealth; 95 | } 96 | 97 | auto GetRaceStartingMagicka(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 98 | { 99 | if (!a_race) { 100 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 101 | return -1; 102 | } 103 | 104 | return a_race->data.startingMagicka; 105 | } 106 | 107 | auto GetRaceStartingStamina(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 108 | { 109 | if (!a_race) { 110 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 111 | return -1; 112 | } 113 | 114 | return a_race->data.startingStamina; 115 | } 116 | 117 | auto GetRaceCarryWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 118 | { 119 | if (!a_race) { 120 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 121 | return -1; 122 | } 123 | 124 | return a_race->data.baseCarryWeight; 125 | } 126 | 127 | auto GetRaceMass(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 128 | { 129 | if (!a_race) { 130 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 131 | return -1; 132 | } 133 | 134 | return a_race->data.baseMass; 135 | } 136 | 137 | auto GetRaceHealthRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 138 | { 139 | if (!a_race) { 140 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 141 | return -1; 142 | } 143 | 144 | return a_race->data.healthRegen; 145 | } 146 | 147 | auto GetRaceMagickaRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 148 | { 149 | if (!a_race) { 150 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 151 | return -1; 152 | } 153 | 154 | return a_race->data.magickaRegen; 155 | } 156 | 157 | auto GetRaceStaminaRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 158 | { 159 | if (!a_race) { 160 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 161 | return -1; 162 | } 163 | 164 | return a_race->data.staminaRegen; 165 | } 166 | 167 | auto GetRaceUnarmedDamage(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 168 | { 169 | if (!a_race) { 170 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 171 | return -1; 172 | } 173 | 174 | return a_race->data.unarmedDamage; 175 | } 176 | 177 | auto GetRaceUnarmedReach(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float 178 | { 179 | if (!a_race) { 180 | a_vm->TraceStack("akRace cannot be None", a_stackID, Severity::kInfo); 181 | return -1; 182 | } 183 | 184 | return a_race->data.unarmedReach; 185 | } 186 | 187 | auto RegisterFuncs(VM* a_vm) -> bool 188 | { 189 | if (!a_vm) { 190 | logger::info("PapyrusRace - cannot get VMState"sv); 191 | return false; 192 | } 193 | 194 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 195 | auto project_name = plugin->GetName(); 196 | 197 | a_vm->RegisterFunction("GetRaceSkillBonus"sv, project_name, GetRaceSkillBonus); 198 | a_vm->RegisterFunction("GetRaceSkills"sv, project_name, GetRaceSkills); 199 | 200 | a_vm->RegisterFunction("GetRaceMaleHeight"sv, project_name, GetRaceMaleHeight); 201 | a_vm->RegisterFunction("GetRaceMaleWeight"sv, project_name, GetRaceMaleWeight); 202 | a_vm->RegisterFunction("GetRaceFemaleHeight"sv, project_name, GetRaceFemaleHeight); 203 | a_vm->RegisterFunction("GetRaceFemaleWeight"sv, project_name, GetRaceFemaleWeight); 204 | 205 | a_vm->RegisterFunction("GetRaceStartingHealth"sv, project_name, GetRaceStartingHealth); 206 | a_vm->RegisterFunction("GetRaceStartingMagicka"sv, project_name, GetRaceStartingMagicka); 207 | a_vm->RegisterFunction("GetRaceStartingStamina"sv, project_name, GetRaceStartingStamina); 208 | 209 | a_vm->RegisterFunction("GetRaceCarryWeight"sv, project_name, GetRaceCarryWeight); 210 | a_vm->RegisterFunction("GetRaceMass"sv, project_name, GetRaceMass); 211 | 212 | a_vm->RegisterFunction("GetRaceHealthRegen"sv, project_name, GetRaceHealthRegen); 213 | a_vm->RegisterFunction("GetRaceMagickaRegen"sv, project_name, GetRaceMagickaRegen); 214 | a_vm->RegisterFunction("GetRaceStaminaRegen"sv, project_name, GetRaceStaminaRegen); 215 | 216 | a_vm->RegisterFunction("GetRaceUnarmedDamage"sv, project_name, GetRaceUnarmedDamage); 217 | a_vm->RegisterFunction("GetRaceUnarmedReach"sv, project_name, GetRaceUnarmedReach); 218 | 219 | return true; 220 | } 221 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusRace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusRace 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto GetRaceSkillBonus(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race, RE::BSFixedString a_actorValue) -> std::int32_t; 12 | auto GetRaceSkills(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> std::vector; 13 | 14 | auto GetRaceMaleHeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 15 | auto GetRaceFemaleHeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 16 | 17 | auto GetRaceMaleWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 18 | auto GetRaceFemaleWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 19 | 20 | auto GetRaceStartingHealth(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 21 | auto GetRaceStartingMagicka(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 22 | auto GetRaceStartingStamina(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 23 | 24 | auto GetRaceCarryWeight(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 25 | auto GetRaceMass(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 26 | 27 | auto GetRaceHealthRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 28 | auto GetRaceMagickaRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 29 | auto GetRaceStaminaRegen(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 30 | 31 | auto GetRaceUnarmedDamage(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 32 | auto GetRaceUnarmedReach(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::TESRace* a_race) -> float; 33 | 34 | auto RegisterFuncs(VM* a_vm) -> bool; 35 | } 36 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusSpell.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusSpell.h" 4 | 5 | namespace PapyrusSpell 6 | { 7 | auto GetHighestMinSkillLevelForSpell(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::SpellItem* a_spell) -> std::uint32_t 8 | { 9 | if (!a_spell) { 10 | a_vm->TraceStack("akSpell cannot be None", a_stackID, Severity::kInfo); 11 | return 0; 12 | } 13 | 14 | const auto effects = a_spell->effects; 15 | 16 | if (effects.empty()) { 17 | return 0; 18 | } 19 | 20 | auto level = 0; 21 | 22 | for (const auto effect : effects) { 23 | if (const auto baseEffect = effect->baseEffect; baseEffect) { 24 | const auto effectData = baseEffect->data; 25 | level = std::max(level, effectData.minimumSkill); 26 | } 27 | } 28 | 29 | return level; 30 | } 31 | 32 | auto RegisterFuncs(VM* a_vm) -> bool 33 | { 34 | if (!a_vm) { 35 | logger::info("PapyrusSpell - cannot get VMState"sv); 36 | return false; 37 | } 38 | 39 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 40 | auto project_name = plugin->GetName(); 41 | 42 | a_vm->RegisterFunction("GetHighestMinSkillLevelForSpell"sv, project_name, GetHighestMinSkillLevelForSpell); 43 | 44 | return true; 45 | } 46 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusSpell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusSpell 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto GetHighestMinSkillLevelForSpell(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::SpellItem* a_spell) -> std::uint32_t; 12 | 13 | auto RegisterFuncs(VM* a_vm) -> bool; 14 | } 15 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusString.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusString.h" 4 | 5 | template 6 | static auto intToHex(T i) -> std::string 7 | { 8 | std::stringstream stream; 9 | stream << std::setfill('0') << std::setw(sizeof(T) * 2) 10 | << std::hex << i; 11 | return stream.str(); 12 | } 13 | 14 | static auto ltrim(std::string& s) -> void 15 | { 16 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](const int ch) { 17 | return !std::isspace(ch); 18 | })); 19 | } 20 | 21 | static auto rtrim(std::string& s) -> void 22 | { 23 | s.erase(std::find_if(s.rbegin(), s.rend(), [](const int ch) { 24 | return !std::isspace(ch); 25 | }).base(), 26 | s.end()); 27 | } 28 | 29 | static auto split(const RE::BSFixedString& src, const char delimiter) -> std::vector 30 | { 31 | std::vector vec; 32 | 33 | const auto* cstr = src.c_str(); 34 | 35 | std::stringstream ss(cstr); 36 | 37 | while (ss.good()) { 38 | std::string substr; 39 | 40 | std::getline(ss, substr, delimiter); 41 | 42 | ltrim(substr); 43 | rtrim(substr); 44 | 45 | vec.emplace_back(substr.c_str()); 46 | } 47 | 48 | return vec; 49 | } 50 | 51 | static auto splitAsFloat(const RE::BSFixedString& src, const char delimiter) -> std::vector 52 | { 53 | std::vector vec; 54 | 55 | const auto* cstr = src.c_str(); 56 | 57 | std::stringstream ss(cstr); 58 | 59 | while (ss.good()) { 60 | std::string substr; 61 | 62 | std::getline(ss, substr, delimiter); 63 | 64 | try { 65 | auto n = std::stof(substr); 66 | vec.push_back(n); 67 | } catch (std::invalid_argument& e) { 68 | logger::critical(e.what()); 69 | vec.push_back(-1.f); 70 | } catch (std::out_of_range& e) { 71 | logger::critical(e.what()); 72 | vec.push_back(-1.f); 73 | } 74 | } 75 | 76 | return vec; 77 | } 78 | 79 | static auto splitAsInt(const RE::BSFixedString& src, const char delimiter) -> std::vector 80 | { 81 | std::vector vec; 82 | 83 | const auto* cstr = src.c_str(); 84 | 85 | std::stringstream ss(cstr); 86 | 87 | while (ss.good()) { 88 | std::string substr; 89 | 90 | std::getline(ss, substr, delimiter); 91 | 92 | try { 93 | const auto n = std::stol(substr); 94 | vec.push_back(n); 95 | } catch (std::invalid_argument& e) { 96 | logger::critical(e.what()); 97 | vec.push_back(-1); 98 | } catch (std::out_of_range& e) { 99 | logger::critical(e.what()); 100 | vec.push_back(-1); 101 | } 102 | } 103 | 104 | return vec; 105 | } 106 | 107 | namespace PapyrusString 108 | { 109 | auto ContainsText(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_text, RE::BSFixedString a_subtext) -> bool 110 | { 111 | auto text = std::string(a_text); 112 | auto subtext = std::string(a_subtext); 113 | 114 | std::transform(text.begin(), text.end(), text.begin(), 115 | [](unsigned char c) { return std::tolower(c); }); 116 | 117 | std::transform(subtext.begin(), subtext.end(), subtext.begin(), 118 | [](unsigned char c) { return std::tolower(c); }); 119 | 120 | auto it = std::search(text.begin(), text.end(), std::boyer_moore_searcher(subtext.begin(), subtext.end())); 121 | return it != text.end(); 122 | } 123 | 124 | auto FormatFloat(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString 125 | { 126 | if (a_format.empty()) { 127 | a_vm->TraceStack("asFormat cannot be empty", a_stackID, Severity::kInfo); 128 | return ""; 129 | } 130 | 131 | if (a_argv.empty()) { 132 | a_vm->TraceStack("argValues cannot be empty", a_stackID, Severity::kInfo); 133 | return ""; 134 | } 135 | 136 | auto format = std::string(a_format); 137 | auto argv = std::vector(a_argv); 138 | 139 | if (argv.size() != 9) { 140 | while (argv.size() > 9) { 141 | argv.pop_back(); 142 | } 143 | 144 | while (argv.size() < 9) { 145 | argv.emplace_back(0.0); 146 | } 147 | } 148 | 149 | return fmt::format(format, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); 150 | } 151 | 152 | auto FormatInt(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString 153 | { 154 | if (a_format.empty()) { 155 | a_vm->TraceStack("asFormat cannot be empty", a_stackID, Severity::kInfo); 156 | return ""; 157 | } 158 | 159 | if (a_argv.empty()) { 160 | a_vm->TraceStack("argValues cannot be empty", a_stackID, Severity::kInfo); 161 | return ""; 162 | } 163 | 164 | auto format = std::string(a_format); 165 | auto argv = std::vector(a_argv); 166 | 167 | if (argv.size() != 9) { 168 | while (argv.size() > 9) { 169 | argv.pop_back(); 170 | } 171 | 172 | while (argv.size() < 9) { 173 | argv.emplace_back(0); 174 | } 175 | } 176 | 177 | return fmt::format(format, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); 178 | } 179 | 180 | auto FormatString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString 181 | { 182 | if (a_format.empty()) { 183 | a_vm->TraceStack("asFormat cannot be empty", a_stackID, Severity::kInfo); 184 | return ""; 185 | } 186 | 187 | if (a_argv.empty()) { 188 | a_vm->TraceStack("argValues cannot be empty", a_stackID, Severity::kInfo); 189 | return ""; 190 | } 191 | 192 | auto format = std::string(a_format); 193 | auto argv = std::vector(a_argv); 194 | 195 | if (argv.size() != 9) { 196 | while (argv.size() > 9) { 197 | argv.pop_back(); 198 | } 199 | 200 | while (argv.size() < 9) { 201 | argv.emplace_back(""); 202 | } 203 | } 204 | 205 | return fmt::format(format, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); 206 | } 207 | 208 | auto IntToHex(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, std::int32_t a_source) -> RE::BSFixedString 209 | { 210 | return intToHex(a_source); 211 | } 212 | 213 | auto StrToFloatArray(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector 214 | { 215 | std::vector vec; 216 | 217 | if (a_string.empty()) { 218 | a_vm->TraceStack("asString cannot be empty", a_stackID, Severity::kInfo); 219 | return vec; 220 | } 221 | 222 | if (a_delimiter.empty()) { 223 | a_vm->TraceStack("asDelimiter cannot be empty", a_stackID, Severity::kInfo); 224 | return vec; 225 | } 226 | 227 | const auto delimiter = a_delimiter[0]; 228 | vec = splitAsFloat(a_string, delimiter); 229 | 230 | return vec; 231 | } 232 | 233 | auto StrToIntArray(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector 234 | { 235 | std::vector vec; 236 | 237 | if (a_string.empty()) { 238 | a_vm->TraceStack("asString cannot be empty", a_stackID, Severity::kInfo); 239 | return vec; 240 | } 241 | 242 | if (a_delimiter.empty()) { 243 | a_vm->TraceStack("asDelimiter cannot be empty", a_stackID, Severity::kInfo); 244 | return vec; 245 | } 246 | 247 | const auto delimiter = a_delimiter[0]; 248 | vec = splitAsInt(a_string, delimiter); 249 | 250 | return vec; 251 | } 252 | 253 | auto SplitString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector 254 | { 255 | std::vector vec; 256 | 257 | if (a_string.empty()) { 258 | a_vm->TraceStack("asString cannot be empty", a_stackID, Severity::kInfo); 259 | return vec; 260 | } 261 | 262 | if (a_delimiter.empty()) { 263 | a_vm->TraceStack("asDelimiter cannot be empty", a_stackID, Severity::kInfo); 264 | return vec; 265 | } 266 | 267 | const auto delimiter = a_delimiter[0]; 268 | vec = split(a_string, delimiter); 269 | 270 | return vec; 271 | } 272 | 273 | auto WrapString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, std::int32_t a_max_length) -> RE::BSFixedString 274 | { 275 | auto S = std::string(a_string); 276 | 277 | const auto lineWrap = std::regex{ "(.{1," + std::to_string(a_max_length) + "})(?: +|$)" }; 278 | 279 | S = std::regex_replace(S, lineWrap, "$1\n"); 280 | S.resize(S.size() - 1); 281 | 282 | return S; 283 | } 284 | 285 | auto RegisterFuncs(VM* a_vm) -> bool 286 | { 287 | if (!a_vm) { 288 | logger::info("PapyrusString - cannot get VMState"sv); 289 | return false; 290 | } 291 | 292 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 293 | auto project_name = plugin->GetName(); 294 | 295 | a_vm->RegisterFunction("ContainsText"sv, project_name, ContainsText); 296 | a_vm->RegisterFunction("FormatFloat"sv, project_name, FormatFloat); 297 | a_vm->RegisterFunction("FormatInt"sv, project_name, FormatInt); 298 | a_vm->RegisterFunction("FormatString"sv, project_name, FormatString); 299 | a_vm->RegisterFunction("IntToHex"sv, project_name, IntToHex); 300 | a_vm->RegisterFunction("SplitString"sv, project_name, SplitString); 301 | a_vm->RegisterFunction("StrToFloatArray"sv, project_name, StrToFloatArray); 302 | a_vm->RegisterFunction("StrToIntArray"sv, project_name, StrToIntArray); 303 | a_vm->RegisterFunction("WrapString"sv, project_name, WrapString); 304 | 305 | return true; 306 | } 307 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusString.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | #pragma warning(disable : 4244) 5 | 6 | namespace PapyrusString 7 | { 8 | using VM = RE::BSScript::IVirtualMachine; 9 | using StackID = RE::VMStackID; 10 | using Severity = RE::BSScript::ErrorLogger::Severity; 11 | 12 | auto ContainsText(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_text, RE::BSFixedString a_subtext) -> bool; 13 | auto FormatFloat(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString; 14 | auto FormatInt(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString; 15 | auto FormatString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_format, std::vector a_argv) -> RE::BSFixedString; 16 | auto IntToHex(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, std::int32_t a_source) -> RE::BSFixedString; 17 | auto SplitString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector; 18 | auto StrToFloatArray(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector; 19 | auto StrToIntArray(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, RE::BSFixedString a_delimiter) -> std::vector; 20 | auto WrapString(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, RE::BSFixedString a_string, std::int32_t a_max_length) -> RE::BSFixedString; 21 | 22 | auto RegisterFuncs(VM* a_vm) -> bool; 23 | } 24 | -------------------------------------------------------------------------------- /src/Papyrus/PapyrusTime.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PapyrusTime.h" 4 | 5 | namespace PapyrusTime 6 | { 7 | auto GetCurrentHourOfDay(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> float 8 | { 9 | auto* const calendar = RE::Calendar::GetSingleton(); 10 | 11 | if (calendar == nullptr) { 12 | a_vm->TraceStack("Cannot initialize calendar singleton", a_stackID, Severity::kWarning); 13 | return false; 14 | } 15 | 16 | auto currentGameTime = calendar->GetCurrentGameTime(); 17 | currentGameTime -= floorf(currentGameTime); 18 | currentGameTime *= 24.f; 19 | 20 | return currentGameTime; 21 | } 22 | 23 | auto RegisterFuncs(VM* a_vm) -> bool 24 | { 25 | if (!a_vm) { 26 | logger::info("PapyrusTime - cannot get VMState"sv); 27 | return false; 28 | } 29 | 30 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 31 | auto project_name = plugin->GetName(); 32 | 33 | a_vm->RegisterFunction("GetCurrentHourOfDay"sv, project_name, GetCurrentHourOfDay); 34 | 35 | return true; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Papyrus/PapyrusTime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma warning(disable : 4100) 4 | 5 | namespace PapyrusTime 6 | { 7 | using VM = RE::BSScript::IVirtualMachine; 8 | using StackID = RE::VMStackID; 9 | using Severity = RE::BSScript::ErrorLogger::Severity; 10 | 11 | auto GetCurrentHourOfDay(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*) -> float; 12 | 13 | auto RegisterFuncs(VM* a_vm) -> bool; 14 | } 15 | -------------------------------------------------------------------------------- /src/Papyrus/Registration.cpp: -------------------------------------------------------------------------------- 1 | #include "Papyrus/Registration.h" 2 | 3 | #include "Papyrus/PapyrusActor.h" 4 | #include "Papyrus/PapyrusArray.h" 5 | #include "Papyrus/PapyrusFaction.h" 6 | #include "Papyrus/PapyrusFormList.h" 7 | #include "Papyrus/PapyrusObjectREFR.h" 8 | #include "Papyrus/PapyrusPlayerCharacter.h" 9 | #include "Papyrus/PapyrusRace.h" 10 | #include "Papyrus/PapyrusSpell.h" 11 | #include "Papyrus/PapyrusString.h" 12 | #include "Papyrus/PapyrusTime.h" 13 | 14 | 15 | namespace Papyrus 16 | { 17 | auto Register() -> void 18 | { 19 | const auto papyrus = SKSE::GetPapyrusInterface(); 20 | 21 | papyrus->Register(PapyrusActor::RegisterFuncs); 22 | logger::info("Registered actor functions"sv); 23 | 24 | papyrus->Register(PapyrusArray::RegisterFuncs); 25 | logger::info("Registered array functions"sv); 26 | 27 | papyrus->Register(PapyrusFaction::RegisterFuncs); 28 | logger::info("Registered faction functions"sv); 29 | 30 | papyrus->Register(PapyrusFormList::RegisterFuncs); 31 | logger::info("Registered formlist functions"sv); 32 | 33 | papyrus->Register(PapyrusObjectREFR::RegisterFuncs); 34 | logger::info("Registered object reference functions"sv); 35 | 36 | papyrus->Register(PapyrusPlayerCharacter::RegisterFuncs); 37 | logger::info("Registered player character functions"sv); 38 | 39 | papyrus->Register(PapyrusRace::RegisterFuncs); 40 | logger::info("Registered race functions"sv); 41 | 42 | papyrus->Register(PapyrusSpell::RegisterFuncs); 43 | logger::info("Registered spell functions"sv); 44 | 45 | papyrus->Register(PapyrusString::RegisterFuncs); 46 | logger::info("Registered string functions"sv); 47 | 48 | papyrus->Register(PapyrusTime::RegisterFuncs); 49 | logger::info("Registered time functions"sv); 50 | } 51 | } -------------------------------------------------------------------------------- /src/Papyrus/Registration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Papyrus 4 | { 5 | void Register(); 6 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Papyrus/Registration.h" 2 | 3 | namespace 4 | { 5 | void InitializeLog(const std::string_view a_project) 6 | { 7 | #ifndef NDEBUG 8 | auto sink = std::make_shared(); 9 | #else 10 | auto path = logger::log_directory(); 11 | if (!path) { 12 | util::report_and_fail("Failed to find standard logging directory"sv); 13 | } 14 | 15 | *path /= fmt::format("{}.log"sv, a_project); 16 | auto sink = std::make_shared(path->string(), true); 17 | #endif 18 | 19 | #ifndef NDEBUG 20 | const auto level = spdlog::level::trace; 21 | #else 22 | const auto level = spdlog::level::info; 23 | #endif 24 | 25 | auto log = std::make_shared("global log"s, std::move(sink)); 26 | log->set_level(level); 27 | log->flush_on(level); 28 | 29 | spdlog::set_default_logger(std::move(log)); 30 | spdlog::set_pattern("%g(%#): [%^%l%$] %v"s); 31 | } 32 | } 33 | 34 | SKSEPluginLoad(const SKSE::LoadInterface* a_skse) 35 | { 36 | auto* plugin = SKSE::PluginDeclaration::GetSingleton(); 37 | auto project_name = plugin->GetName(); 38 | auto project_version = plugin->GetVersion(); 39 | 40 | InitializeLog(project_name); 41 | 42 | logger::info("{} v{} is loading..."sv, project_name, project_version); 43 | 44 | Init(a_skse); 45 | 46 | Papyrus::Register(); 47 | 48 | logger::info("{} has finished loading."sv, project_name); 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /update-baselines.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import subprocess 4 | 5 | ENCODING = 'utf-8' 6 | VCPKG_FILE = 'vcpkg.json' 7 | VCPKG_CFG_FILE = 'vcpkg-configuration.json' 8 | VCPKG_URL = r'https://github.com/microsoft/vcpkg.git/' 9 | VCPKG_COLORGLASS_URL = r'https://gitlab.com/colorglass/vcpkg-colorglass.git/' 10 | VCPKG_INSTALLATION_ROOT = os.path.expanduser(os.path.expandvars('%VCPKG_INSTALLATION_ROOT%')) 11 | 12 | 13 | def get_latest_baseline_commit(url: str, refs: str) -> str: 14 | process = subprocess.Popen(f'git ls-remote {url} {refs}', 15 | stdout=subprocess.PIPE, 16 | stderr=subprocess.DEVNULL, 17 | encoding=ENCODING, 18 | text=True, 19 | shell=False) 20 | 21 | while process.poll() is None: 22 | if line := process.stdout.readline().strip(): 23 | commit, _ = line.split() 24 | return commit 25 | 26 | return '' 27 | 28 | 29 | def update_local_vcpkg() -> bool: 30 | os.chdir(VCPKG_INSTALLATION_ROOT) 31 | process = subprocess.Popen(f'git pull --rebase origin', 32 | stdout=subprocess.PIPE, 33 | stderr=subprocess.DEVNULL, 34 | encoding=ENCODING, 35 | text=True, 36 | shell=False) 37 | 38 | while process.poll() is None: 39 | if line := process.stdout.readline().strip(): 40 | if line == 'Already up to date.': 41 | return False 42 | 43 | return True 44 | 45 | 46 | def run() -> None: 47 | if commit := get_latest_baseline_commit(VCPKG_URL, 'master'): 48 | with open(VCPKG_FILE, encoding=ENCODING) as f: 49 | data = json.load(f) 50 | 51 | if data['builtin-baseline'] != commit: 52 | data['builtin-baseline'] = commit 53 | 54 | with open(VCPKG_FILE, encoding=ENCODING, mode='w') as f: 55 | json.dump(data, f, indent=2) 56 | 57 | if commit := get_latest_baseline_commit(VCPKG_COLORGLASS_URL, 'main'): 58 | with open(VCPKG_CFG_FILE, encoding=ENCODING) as f: 59 | data = json.load(f) 60 | 61 | if data['registries'][0]['baseline'] != commit: 62 | data['registries'][0]['baseline'] = commit 63 | 64 | with open(VCPKG_CFG_FILE, encoding=ENCODING, mode='w') as f: 65 | json.dump(data, f, indent=2) 66 | 67 | if update_local_vcpkg(): 68 | print('Updated local repo: "%s"' % VCPKG_INSTALLATION_ROOT) 69 | 70 | 71 | if __name__ == '__main__': 72 | run() 73 | -------------------------------------------------------------------------------- /vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "registries": [ 3 | { 4 | "kind": "git", 5 | "repository": "https://gitlab.com/colorglass/vcpkg-colorglass", 6 | "baseline": "6309841a1ce770409708a67a9ba5c26c537d2937", 7 | "packages": [ 8 | "commonlibsse-ng-flatrim" 9 | ] 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libfire", 3 | "version-string": "1.0.0", 4 | "description": "Papyrus extensions for LibFire", 5 | "homepage": "https://github.com/fireundubh/LibFire", 6 | "license": "MIT", 7 | "dependencies": [ 8 | "boost-stl-interfaces", 9 | "rsm-binary-io", 10 | "commonlibsse-ng-flatrim" 11 | ], 12 | "builtin-baseline": "49ac2134b31b95b0ddf29d56873dcd24392691df", 13 | "overrides": [ 14 | { 15 | "name": "fmt", 16 | "version": "8.0.1" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /version.rc.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, @PROJECT_VERSION_TWEAK@ 5 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, @PROJECT_VERSION_TWEAK@ 6 | FILEFLAGSMASK 0x17L 7 | #ifdef _DEBUG 8 | FILEFLAGS 0x1L 9 | #else 10 | FILEFLAGS 0x0L 11 | #endif 12 | FILEOS 0x4L 13 | FILETYPE 0x1L 14 | FILESUBTYPE 0x0L 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904b0" 19 | BEGIN 20 | VALUE "FileDescription", "@PROJECT_HOMEPAGE_URL@" 21 | VALUE "FileVersion", "@PROJECT_VERSION@" 22 | VALUE "InternalName", "@PROJECT_NAME@" 23 | VALUE "LegalCopyright", "MIT License" 24 | VALUE "ProductName", "@PROJECT_NAME@" 25 | VALUE "ProductVersion", "@PROJECT_VERSION@" 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END --------------------------------------------------------------------------------