├── .editorconfig ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── mfgfix.sln ├── mfgfix.vcxproj ├── mfgfix.vcxproj.filters └── src ├── main.cpp ├── mfgfix ├── BSFaceGenAnimationData.cpp ├── BSFaceGenAnimationData.h ├── BSFaceGenKeyframe.h ├── BSFaceGenKeyframeMultiple.cpp ├── BSFaceGenKeyframeMultiple.h ├── ConsoleCommands.cpp ├── ConsoleCommands.h ├── MfgConsoleFunc.cpp ├── MfgConsoleFunc.h ├── Offsets.h ├── Settings.cpp ├── Settings.h ├── SettingsPapyrus.cpp ├── SettingsPapyrus.h ├── SimpleIni.h ├── mfgfixinit.cpp └── mfgfixinit.h ├── pch.cpp ├── pch.h ├── version.h └── version.rc /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{h,cpp}] 2 | indent_style = tab 3 | indent_size = 4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 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 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 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 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/CommonLibSSE"] 2 | path = ext/CommonLibSSE 3 | url = https://github.com/Ryan-rsm-McKenzie/CommonLibSSE 4 | [submodule "ext/Detours"] 5 | path = ext/Detours 6 | url = https://github.com/microsoft/Detours 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 andrelo1 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mfgfix 2 | 3 | ## Dependencies 4 | - [CommonLibSSE](https://github.com/Ryan-rsm-McKenzie/CommonLibSSE) 5 | - [Detours](https://github.com/microsoft/Detours) 6 | ## Building 7 | Prerequisites: 8 | - Visual Studio 2022 9 | - [vcpkg](https://github.com/microsoft/vcpkg) (for CommonLibSSE) 10 | 11 | Open x64 Native Tools Command Prompt for VS 2022. 12 | 13 | Clone repository: 14 | ``` 15 | git clone --recurse-submodules https://github.com/andrelo1/mfgfix 16 | ``` 17 | Build CommonLibSSE: 18 | 19 | ``` 20 | cd mfgfix/ext/CommonLibSSE 21 | cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static-md 22 | cmake --build build --config Release 23 | ``` 24 | Build Detours: 25 | ``` 26 | cd ../Detours/ 27 | nmake 28 | ``` 29 | Build mfgfix: 30 | 31 | Open and build `mfgfix.sln` in Visual Studio. 32 | -------------------------------------------------------------------------------- /mfgfix.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31911.196 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mfgfix", "mfgfix.vcxproj", "{6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Debug|x64.ActiveCfg = Debug|x64 17 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Debug|x64.Build.0 = Debug|x64 18 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Debug|x86.ActiveCfg = Debug|Win32 19 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Debug|x86.Build.0 = Debug|Win32 20 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Release|x64.ActiveCfg = Release|x64 21 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Release|x64.Build.0 = Release|x64 22 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Release|x86.ActiveCfg = Release|Win32 23 | {6C7E7079-990B-4EA3-89C4-A5BC4CA746A6}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {449BDA17-9D53-4A79-8F14-B22E41228791} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /mfgfix.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | Use 24 | pch.h 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Create 35 | Create 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 16.0 57 | Win32Proj 58 | {6c7e7079-990b-4ea3-89c4-a5bc4ca746a6} 59 | mfgfix 60 | 61 | 62 | 63 | 64 | 65 | DynamicLibrary 66 | true 67 | v143 68 | Unicode 69 | 70 | 71 | DynamicLibrary 72 | false 73 | v143 74 | true 75 | Unicode 76 | 77 | 78 | DynamicLibrary 79 | true 80 | v143 81 | MultiByte 82 | 83 | 84 | DynamicLibrary 85 | false 86 | v143 87 | true 88 | MultiByte 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | true 112 | 113 | 114 | false 115 | 116 | 117 | true 118 | 119 | 120 | false 121 | 122 | 123 | 124 | Level3 125 | true 126 | WIN32;_DEBUG;MFGFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 127 | true 128 | Use 129 | pch.h 130 | 131 | 132 | Windows 133 | true 134 | false 135 | 136 | 137 | 138 | 139 | Level3 140 | true 141 | true 142 | true 143 | WIN32;NDEBUG;MFGFIX_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 144 | true 145 | Use 146 | pch.h 147 | 148 | 149 | Windows 150 | true 151 | true 152 | true 153 | false 154 | 155 | 156 | 157 | 158 | Level3 159 | true 160 | _DEBUG;SPDLOG_COMPILED_LIB;SPDLOG_FMT_EXTERNAL;FMT_LOCALE;BOOST_STL_INTERFACES_DISABLE_CONCEPTS;%(PreprocessorDefinitions) 161 | true 162 | Use 163 | pch.h 164 | pch.h 165 | .\ext;.\ext\CommonLibSSE\include;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\include;%(AdditionalIncludeDirectories) 166 | stdcpplatest 167 | MultiThreadedDebugDLL 168 | 4200;4251;4275 169 | 170 | 171 | Windows 172 | true 173 | false 174 | .\ext\CommonLibSSE\build\Debug\CommonLibSSE.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\debug\lib\spdlogd.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\debug\lib\fmtd.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\debug\lib\binary_iod.lib;.\ext\Detours\lib.X64\detours.lib;Version.lib;%(AdditionalDependencies) 175 | 176 | 177 | 178 | 179 | Level3 180 | true 181 | true 182 | true 183 | NDEBUG;BOOST_STL_INTERFACES_DISABLE_CONCEPTS;SPDLOG_COMPILED_LIB;SPDLOG_FMT_EXTERNAL;FMT_LOCALE;%(PreprocessorDefinitions) 184 | true 185 | Use 186 | pch.h 187 | pch.h 188 | .\ext;.\ext\CommonLibSSE\include;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\include;%(AdditionalIncludeDirectories) 189 | stdcpplatest 190 | MultiThreadedDLL 191 | 192 | 193 | 4200;4251;4275 194 | 195 | 196 | Windows 197 | true 198 | true 199 | true 200 | false 201 | .\ext\CommonLibSSE\build\Release\CommonLibSSE.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\lib\spdlog.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\lib\fmt.lib;.\ext\CommonLibSSE\build\vcpkg_installed\x64-windows-static-md\lib\binary_io.lib;.\ext\Detours\lib.X64\detours.lib;Version.lib;%(AdditionalDependencies) 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /mfgfix.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {6ff6e8d5-3c13-49a6-bcff-bc96a449bed9} 18 | 19 | 20 | {3b7e0726-063b-4fd7-8e7b-52acd317fe92} 21 | 22 | 23 | 24 | 25 | src 26 | 27 | 28 | src 29 | 30 | 31 | src\mfgfix 32 | 33 | 34 | src\mfgfix 35 | 36 | 37 | src\mfgfix 38 | 39 | 40 | src\mfgfix 41 | 42 | 43 | src\mfgfix 44 | 45 | 46 | src\mfgfix 47 | 48 | 49 | src\mfgfix 50 | 51 | 52 | 53 | 54 | src 55 | 56 | 57 | src 58 | 59 | 60 | src\mfgfix 61 | 62 | 63 | src\mfgfix 64 | 65 | 66 | src\mfgfix 67 | 68 | 69 | src\mfgfix 70 | 71 | 72 | src\mfgfix 73 | 74 | 75 | src\mfgfix 76 | 77 | 78 | src\mfgfix 79 | 80 | 81 | src\mfgfix 82 | 83 | 84 | src\mfgfix 85 | 86 | 87 | src\mfgfix 88 | 89 | 90 | 91 | 92 | src 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mfgfix/mfgfixinit.h" 2 | 3 | namespace 4 | { 5 | constexpr SKSE::PluginVersionData GetPluginVersionData() 6 | { 7 | SKSE::PluginVersionData version; 8 | 9 | version.PluginVersion({ Version::MAJOR, Version::MINOR, Version::PATCH, 0 }); 10 | version.PluginName(Version::PROJECT); 11 | version.UsesAddressLibrary(true); 12 | 13 | return version; 14 | } 15 | } 16 | 17 | extern "C" __declspec(dllexport) SKSE::PluginVersionData SKSEPlugin_Version{ GetPluginVersionData() }; 18 | 19 | extern "C" __declspec(dllexport) bool SKSEAPI SKSEPlugin_Load(const SKSE::LoadInterface * a_skse) 20 | { 21 | auto path = SKSE::log::log_directory(); 22 | 23 | if (path) { 24 | *path /= Version::PROJECT; 25 | *path += ".log"; 26 | spdlog::set_default_logger(spdlog::basic_logger_mt("default", path->string(), true)); 27 | } 28 | 29 | spdlog::set_level(spdlog::level::trace); 30 | spdlog::flush_on(spdlog::level::trace); 31 | spdlog::info("loaded"); 32 | 33 | SKSE::Init(a_skse); 34 | MfgFix::Init(); 35 | 36 | return true; 37 | } -------------------------------------------------------------------------------- /src/mfgfix/BSFaceGenAnimationData.cpp: -------------------------------------------------------------------------------- 1 | #include "BSFaceGenAnimationData.h" 2 | #include "Offsets.h" 3 | #include "Settings.h" 4 | 5 | namespace MfgFix 6 | { 7 | namespace 8 | { 9 | constexpr float pi_180 = 0.0174532925f; 10 | 11 | float rand(float a_min, float a_max) 12 | { 13 | return a_min + (a_max - a_min) * (static_cast(std::rand()) / RAND_MAX); 14 | } 15 | 16 | float rand(float a_min, float a_max, float a_exp) 17 | { 18 | return a_min + (a_max - a_min) * pow(static_cast(std::rand()) / RAND_MAX, a_exp); 19 | } 20 | 21 | float deg2rad(float a_degrees) 22 | { 23 | return a_degrees * pi_180; 24 | } 25 | } 26 | 27 | void BSFaceGenAnimationData::SetExpressionOverride(std::uint32_t a_idx, float a_value) 28 | { 29 | using func_t = decltype(&BSFaceGenAnimationData::SetExpressionOverride); 30 | REL::Relocation func(Offsets::BSFaceGenAnimationData::SetExpressionOverride); 31 | func(this, a_idx, a_value); 32 | } 33 | 34 | void BSFaceGenAnimationData::ClearExpressionOverride() 35 | { 36 | expressionOverride = false; 37 | } 38 | 39 | void BSFaceGenAnimationData::Reset(float a_timer, bool a_resetExpression, bool a_resetModifierAndPhoneme, bool a_resetCustom, bool a_closeEyes) 40 | { 41 | using func_t = decltype(&BSFaceGenAnimationData::Reset); 42 | REL::Relocation func(Offsets::BSFaceGenAnimationData::Reset); 43 | func(this, a_timer, a_resetExpression, a_resetModifierAndPhoneme, a_resetCustom, a_closeEyes); 44 | } 45 | 46 | std::uint32_t BSFaceGenAnimationData::GetActiveExpression() const 47 | { 48 | std::uint32_t expression = Expression::MoodNeutral; 49 | 50 | for (std::uint32_t i = 0; i < expression3.count; ++i) { 51 | if (expression3.values[i] > expression3.values[expression]) { 52 | expression = i; 53 | } 54 | } 55 | 56 | return expression; 57 | } 58 | 59 | void BSFaceGenAnimationData::DialogueModifiersUpdate(float a_timeDelta) 60 | { 61 | if (!dialogueData || (((dialogueData->refCount & 0x70000000) + 0xD0000000) & 0xEFFFFFFF) != 0) { 62 | return; 63 | } 64 | 65 | REL::Relocation sub_1FCD10{ REL::ID(16267) }; 66 | 67 | modifier1.timer += a_timeDelta; 68 | sub_1FCD10(dialogueData->unk28, modifier1.timer, modifier1.values); 69 | } 70 | 71 | void BSFaceGenAnimationData::DialoguePhonemesUpdate(float a_timeDelta) 72 | { 73 | if (!dialogueData || (((dialogueData->refCount & 0x70000000) + 0xD0000000) & 0xEFFFFFFF) != 0) { 74 | return; 75 | } 76 | 77 | REL::Relocation sub_1FC9B0{ REL::ID(16266) }; 78 | 79 | phoneme1.timer += a_timeDelta; 80 | sub_1FC9B0(dialogueData->unk28, phoneme1.timer, phoneme1.values); 81 | } 82 | 83 | void BSFaceGenAnimationData::CheckAndReleaseDialogueData() 84 | { 85 | if (!dialogueData || (((dialogueData->refCount & 0x70000000) + 0xD0000000) & 0xEFFFFFFF) != 0) { 86 | return; 87 | } 88 | 89 | auto timer = (dialogueData->unk28->unk0 + (dialogueData->unk28->unk4 < 0 ? -dialogueData->unk28->unk4 : 0)) * 0.033f + 0.2f; 90 | 91 | if (phoneme1.timer <= timer) { 92 | return; 93 | } 94 | 95 | REL::Relocation ReleaseDialogueData{ REL::ID(16318) }; 96 | 97 | ReleaseDialogueData(dialogueData); 98 | 99 | dialogueData = nullptr; 100 | } 101 | 102 | void BSFaceGenAnimationData::EyesBlinkingUpdate(float a_timeDelta) 103 | { 104 | auto& settings = Settings::Get(); 105 | 106 | eyesBlinkingTimer = std::max(eyesBlinkingTimer - a_timeDelta, 0.0f); 107 | auto blinkValue = 0.0f; 108 | 109 | switch (eyesBlinkingStage) { 110 | case EyesBlinkingStage::BlinkDelay: { 111 | blinkValue = 0.0f; 112 | 113 | if (eyesBlinkingTimer == 0.0f) { 114 | eyesBlinkingStage = EyesBlinkingStage::BlinkDown; 115 | eyesBlinkingTimer = settings.eyesBlinking.fBlinkDownTime; 116 | } 117 | 118 | break; 119 | } 120 | case EyesBlinkingStage::BlinkDown: { 121 | blinkValue = settings.eyesBlinking.fBlinkDownTime != 0.0f ? 1.0f - eyesBlinkingTimer / settings.eyesBlinking.fBlinkDownTime : 1.0f; 122 | 123 | if (eyesBlinkingTimer == 0.0f) { 124 | eyesBlinkingStage = EyesBlinkingStage::BlinkUp; 125 | eyesBlinkingTimer = settings.eyesBlinking.fBlinkUpTime; 126 | } 127 | 128 | break; 129 | } 130 | case EyesBlinkingStage::BlinkUp: { 131 | blinkValue = settings.eyesBlinking.fBlinkUpTime != 0.0f ? eyesBlinkingTimer / settings.eyesBlinking.fBlinkUpTime : 0.0f; 132 | 133 | if (eyesBlinkingTimer == 0.0f) { 134 | eyesBlinkingStage = EyesBlinkingStage::BlinkDelay; 135 | eyesBlinkingTimer = rand(settings.eyesBlinking.fBlinkDelayMin, settings.eyesBlinking.fBlinkDelayMax, 2.0f); 136 | } 137 | 138 | break; 139 | } 140 | case EyesBlinkingStage::BlinkDownAndWait1: { 141 | if (unk21A) { 142 | blinkValue = settings.eyesBlinking.fBlinkDownTime != 0.0f ? 1.0f - eyesBlinkingTimer / settings.eyesBlinking.fBlinkDownTime : 1.0f; 143 | } else { 144 | blinkValue = 1.0f; 145 | eyesBlinkingStage = EyesBlinkingStage::BlinkUp; 146 | eyesBlinkingTimer = settings.eyesBlinking.fBlinkUpTime; 147 | } 148 | 149 | break; 150 | } 151 | case EyesBlinkingStage::BlinkDownAndWait2: { 152 | eyesBlinkingStage = EyesBlinkingStage::BlinkDownAndWait1; 153 | 154 | break; 155 | } 156 | default: { 157 | blinkValue = 0.0f; 158 | eyesBlinkingStage = EyesBlinkingStage::BlinkDelay; 159 | eyesBlinkingTimer = rand(settings.eyesBlinking.fBlinkDelayMin, settings.eyesBlinking.fBlinkDelayMax, 2.0f); 160 | 161 | break; 162 | } 163 | } 164 | 165 | blinkValue = std::clamp(blinkValue, 0.0f, 1.0f); 166 | 167 | modifier3.values[Modifier::BlinkLeft] = blinkValue; 168 | modifier3.values[Modifier::BlinkRight] = blinkValue; 169 | } 170 | 171 | void BSFaceGenAnimationData::EyesMovementUpdate(float a_timeDelta) 172 | { 173 | auto& settings = Settings::Get(); 174 | 175 | eyesOffsetTimer = std::max(eyesOffsetTimer - a_timeDelta, 0.0f); 176 | 177 | if (eyesOffsetTimer > 0.0f) { 178 | return; 179 | } 180 | 181 | switch (GetActiveExpression()) { 182 | case Expression::DialogueAnger: 183 | case Expression::MoodAnger: { 184 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionAngry, settings.eyesMovement.fEyeOffsetDelayMaxEmotionAngry, 2.0f); 185 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionAngry, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionAngry); 186 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionAngry, settings.eyesMovement.fEyePitchMaxOffsetEmotionAngry); 187 | 188 | break; 189 | } 190 | case Expression::DialogueHappy: 191 | case Expression::MoodHappy: { 192 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionHappy, settings.eyesMovement.fEyeOffsetDelayMaxEmotionHappy, 0.5f); 193 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionHappy, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionHappy); 194 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionHappy, settings.eyesMovement.fEyePitchMaxOffsetEmotionHappy); 195 | 196 | break; 197 | } 198 | case Expression::DialogueSurprise: 199 | case Expression::MoodSurprise: { 200 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionSurprise, settings.eyesMovement.fEyeOffsetDelayMaxEmotionSurprise, 0.5f); 201 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionSurprise, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise); 202 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionSurprise, settings.eyesMovement.fEyePitchMaxOffsetEmotionSurprise); 203 | 204 | break; 205 | } 206 | case Expression::DialogueSad: 207 | case Expression::MoodSad: { 208 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionSad, settings.eyesMovement.fEyeOffsetDelayMaxEmotionSad); 209 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionSad, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionSad); 210 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionSad, settings.eyesMovement.fEyePitchMaxOffsetEmotionSad); 211 | 212 | break; 213 | } 214 | case Expression::DialogueFear: 215 | case Expression::MoodFear: { 216 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionFear, settings.eyesMovement.fEyeOffsetDelayMaxEmotionFear); 217 | eyesHeadingOffset = rand(0.0f, 1.0f) <= 0.5f ? 0.0f : rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionFear, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionFear); 218 | eyesPitchOffset = rand(0.0f, 1.0f) <= 0.5f ? 0.0f : rand(settings.eyesMovement.fEyePitchMinOffsetEmotionFear, settings.eyesMovement.fEyePitchMaxOffsetEmotionFear); 219 | 220 | break; 221 | } 222 | case Expression::DialoguePuzzled: 223 | case Expression::MoodPuzzled: { 224 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionPuzzled, settings.eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled); 225 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled); 226 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionPuzzled, settings.eyesMovement.fEyePitchMaxOffsetEmotionPuzzled); 227 | 228 | break; 229 | } 230 | case Expression::DialogueDisgusted: 231 | case Expression::MoodDisgusted: { 232 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionDisgusted, settings.eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted); 233 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted); 234 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionDisgusted, settings.eyesMovement.fEyePitchMaxOffsetEmotionDisgusted); 235 | 236 | break; 237 | } 238 | case Expression::CombatAnger: { 239 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger, settings.eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger); 240 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger); 241 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionCombatAnger, settings.eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger); 242 | 243 | break; 244 | } 245 | case Expression::CombatShout: { 246 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionCombatShout, settings.eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout); 247 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout); 248 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionCombatShout, settings.eyesMovement.fEyePitchMaxOffsetEmotionCombatShout); 249 | 250 | break; 251 | } 252 | default: { 253 | eyesOffsetTimer = rand(settings.eyesMovement.fEyeOffsetDelayMinEmotionNeutral, settings.eyesMovement.fEyeOffsetDelayMaxEmotionNeutral, 2.0f); 254 | eyesHeadingOffset = rand(settings.eyesMovement.fEyeHeadingMinOffsetEmotionNeutral, settings.eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral); 255 | eyesPitchOffset = rand(settings.eyesMovement.fEyePitchMinOffsetEmotionNeutral, settings.eyesMovement.fEyePitchMaxOffsetEmotionNeutral); 256 | 257 | break; 258 | } 259 | } 260 | } 261 | 262 | void BSFaceGenAnimationData::EyesDirectionUpdate(float a_timeDelta) 263 | { 264 | auto& settings = Settings::Get(); 265 | 266 | auto eyesHeadingMax = deg2rad(settings.eyesMovement.fTrackEyeXY); 267 | auto eyesPitchMax = deg2rad(settings.eyesMovement.fTrackEyeZ); 268 | auto eyesHeadingDeltaMax = settings.eyesMovement.fTrackSpeed * a_timeDelta; 269 | auto eyesPitchDeltaMax = settings.eyesMovement.fTrackSpeed * a_timeDelta; 270 | 271 | eyesHeading = std::clamp(eyesHeadingBase + eyesHeadingOffset, eyesHeading - eyesHeadingDeltaMax, eyesHeading + eyesHeadingDeltaMax); 272 | eyesPitch = std::clamp(eyesPitchBase + eyesPitchOffset, eyesPitch - eyesPitchDeltaMax, eyesPitch + eyesPitchDeltaMax); 273 | eyesHeading = std::clamp(eyesHeading, -eyesHeadingMax, eyesHeadingMax); 274 | eyesPitch = std::clamp(eyesPitch, -eyesPitchMax, eyesPitchMax); 275 | 276 | modifier3.values[Modifier::LookLeft] = eyesHeading < 0.0f ? (eyesHeadingMax != 0.0f ? -eyesHeading / eyesHeadingMax : 0.0f) : 0.0f; 277 | modifier3.values[Modifier::LookRight] = eyesHeading > 0.0f ? (eyesHeadingMax != 0.0f ? eyesHeading / eyesHeadingMax : 0.0f) : 0.0f; 278 | modifier3.values[Modifier::LookDown] = eyesPitch < 0.0f ? (eyesPitchMax != 0.0f ? -eyesPitch / eyesPitchMax : 0.0f) : 0.0f; 279 | modifier3.values[Modifier::LookUp] = eyesPitch > 0.0f ? (eyesPitchMax != 0.0f ? eyesPitch / eyesPitchMax : 0.0f) : 0.0f; 280 | } 281 | 282 | bool BSFaceGenAnimationData::KeyframesUpdateHook(float a_timeDelta, bool a_updateBlinking) 283 | { 284 | RE::BSSpinLockGuard locker(lock); 285 | 286 | // expressions 287 | { 288 | auto merge = [](Keyframe& a_src, Keyframe& a_dst) { 289 | if (!a_src.IsZero()) { 290 | a_dst.Copy(&a_src); 291 | } 292 | }; 293 | 294 | expression3.Reset(); 295 | 296 | expression1.TransitionUpdate(a_timeDelta, transitionTarget); 297 | 298 | merge(expression1, expression3); 299 | merge(expression2, expression3); 300 | } 301 | 302 | // modifiers 303 | { 304 | auto merge = [](Keyframe& a_src, Keyframe& a_dst) { 305 | auto count = std::min(a_src.count, a_dst.count); 306 | for (std::uint32_t i = 0; i < count; ++i) { 307 | if (a_src.values[i] != 0.0f) { 308 | a_dst.values[i] = a_src.values[i]; 309 | } 310 | } 311 | if (a_src.values[Modifier::LookDown] != 0.0f || a_src.values[Modifier::LookLeft] != 0.0f || a_src.values[Modifier::LookRight] != 0.0f || a_src.values[Modifier::LookUp] != 0.0f) { 312 | a_dst.values[Modifier::LookDown] = a_src.values[Modifier::LookDown]; 313 | a_dst.values[Modifier::LookLeft] = a_src.values[Modifier::LookLeft]; 314 | a_dst.values[Modifier::LookRight] = a_src.values[Modifier::LookRight]; 315 | a_dst.values[Modifier::LookUp] = a_src.values[Modifier::LookUp]; 316 | } 317 | }; 318 | 319 | modifier3.Reset(); 320 | 321 | DialogueModifiersUpdate(a_timeDelta); 322 | EyesBlinkingUpdate(a_timeDelta); 323 | 324 | merge(modifier1, modifier3); 325 | 326 | if (!unk21A) { 327 | EyesMovementUpdate(a_timeDelta); 328 | EyesDirectionUpdate(a_timeDelta); 329 | } 330 | 331 | merge(modifier2, modifier3); 332 | } 333 | 334 | // phonemes 335 | { 336 | auto merge = [](Keyframe& a_src, Keyframe& a_dst) { 337 | auto count = std::min(a_src.count, a_dst.count); 338 | for (std::uint32_t i = 0; i < count; ++i) { 339 | if (a_src.values[i] != 0.0f) { 340 | a_dst.values[i] = a_src.values[i]; 341 | } 342 | } 343 | }; 344 | 345 | phoneme3.Reset(); 346 | 347 | DialoguePhonemesUpdate(a_timeDelta); 348 | 349 | merge(phoneme1, phoneme3); 350 | merge(phoneme2, phoneme3); 351 | } 352 | 353 | // custom 354 | { 355 | auto merge = [](BSFaceGenKeyframeMultiple& a_src, BSFaceGenKeyframeMultiple& a_dst) { 356 | auto count = std::min(a_src.count, a_dst.count); 357 | for (std::uint32_t i = 0; i < count; ++i) { 358 | if (a_src.values[i] != 0.0f) { 359 | a_dst.values[i] = a_src.values[i]; 360 | } 361 | } 362 | }; 363 | 364 | custom3.Reset(); 365 | 366 | merge(custom1, custom3); 367 | merge(custom2, custom3); 368 | } 369 | 370 | CheckAndReleaseDialogueData(); 371 | 372 | unk217 = true; 373 | 374 | return unk217; 375 | } 376 | 377 | void BSFaceGenAnimationData::Init() 378 | { 379 | auto KeyframesUpdateAddr = Offsets::BSFaceGenAnimationData::KeyframesUpdate.address(); 380 | auto KeyframesUpdateHookAddr = &KeyframesUpdateHook; 381 | 382 | DetourTransactionBegin(); 383 | DetourUpdateThread(GetCurrentThread()); 384 | DetourAttach(reinterpret_cast(&KeyframesUpdateAddr), reinterpret_cast(KeyframesUpdateHookAddr)); 385 | 386 | if (DetourTransactionCommit() != NO_ERROR) { 387 | spdlog::error("failed to attach detour"); 388 | } 389 | 390 | // remove eyes update from UpdateDownwardPass, it was moved to KeyframesUpdate 391 | REL::safe_write(Offsets::BSFaceGenNiNode::sub_3F1800.address() + 0x0139, static_cast(0x47EB)); 392 | } 393 | } -------------------------------------------------------------------------------- /src/mfgfix/BSFaceGenAnimationData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BSFaceGenKeyframeMultiple.h" 4 | 5 | namespace MfgFix 6 | { 7 | class BSFaceGenAnimationData: public RE::NiExtraData 8 | { 9 | public: 10 | using Keyframe = BSFaceGenKeyframeMultiple; 11 | using Expression = Keyframe::Expression; 12 | using Phoneme = Keyframe::Phoneme; 13 | using Modifier = Keyframe::Modifier; 14 | 15 | enum class EyesBlinkingStage : std::uint32_t 16 | { 17 | BlinkDelay = 0, 18 | BlinkDown, 19 | BlinkUp, 20 | WaitForLookDown, 21 | BlinkDownAndWait1, 22 | BlinkDownAndWait2 23 | }; 24 | 25 | struct DialogueData 26 | { 27 | struct Unk28 28 | { 29 | std::int32_t unk0; // 00 30 | std::int32_t unk4; // 04 31 | std::uint8_t unk8[0x8]; // 08 32 | void* unk10; // 10 33 | void* unk18; // 18 34 | std::uint8_t unk20; // 20 35 | }; 36 | 37 | std::uint8_t unk0[0xC]; // 00 38 | std::uint32_t refCount; // 0C 39 | std::uint8_t unk10[0x18]; // 10 40 | Unk28* unk28; // 28 41 | }; 42 | 43 | Keyframe* transitionTarget; // 18 used to animate transition between expressions 44 | Keyframe expression1; // 20 used by console command and SetExpressionOverride 45 | Keyframe expression2; // 40 unused? 46 | Keyframe modifier2; // 60 used by console command 47 | Keyframe phoneme2; // 80 used by console command 48 | Keyframe custom2; // A0 used by console command 49 | Keyframe expression3; // C0 final values 50 | Keyframe modifier1; // E0 dialogue values 51 | Keyframe modifier3; // 100 final values 52 | Keyframe phoneme1; // 120 dialogue values 53 | Keyframe phoneme3; // 140 final values 54 | Keyframe custom1; // 160 unused? 55 | Keyframe custom3; // 180 final values 56 | float unk1A0; // 1A0 57 | float unk1A4; // 1A4 58 | float unk1A8; // 1A8 59 | std::uint32_t unk1AC; // 1AC 60 | std::uint32_t unk1B0; // 1B0 61 | std::uint32_t nk1B4; // 1B4 62 | std::uint32_t unk1B8; // 1B8 63 | float eyesHeading; // 1BC eyesHeadingBase + eyesHeadingOffset 64 | float eyesPitch; // 1C0 eyesPitchBase + eyesPitchOffset 65 | std::uint32_t pad1C4; // 1C4 66 | std::uint64_t unk1C8; // 1C8 67 | std::uint8_t unk1D0; // 1D0 68 | std::uint8_t unk1D1; // 1D1 69 | std::uint8_t nk1D2; // 1D2 70 | std::uint8_t unk1D3; // 1D3 71 | float eyesHeadingBase; // 1D4 72 | float eyesPitchBase; // 1D8 73 | std::uint32_t unk1DC; // 1DC 74 | std::uint32_t unk1E0; // 1E0 75 | std::uint32_t unk1E4; // 1E4 76 | std::uint32_t unk1E8; // 1E8 77 | std::uint32_t unk1EC; // 1EC 78 | std::uint32_t unk1F0; // 1F0 79 | std::uint32_t unk1F4; // 1F4 80 | std::uint32_t unk1F8; // 1F8 81 | std::uint32_t unk1FC; // 1FC 82 | EyesBlinkingStage eyesBlinkingStage; // 200 83 | float eyesBlinkingTimer; // 204 84 | float eyesOffsetTimer; // 208 85 | float eyesHeadingOffset; // 20C 86 | float eyesPitchOffset; // 210 87 | std::uint8_t unk214; // 214 88 | std::uint8_t unk215; // 215 89 | std::uint8_t unk216; // 216 90 | bool unk217; // 217 91 | std::uint8_t unk218; // 218 92 | std::uint8_t unk219; // 219 93 | std::uint8_t unk21A; // 21A 94 | std::uint8_t unk21B; // 21B 95 | std::uint8_t unk21C; // 21C 96 | std::uint8_t unk21D; // 21D 97 | bool expressionOverride; // 21E 98 | std::uint8_t unk21F; // 21F 99 | mutable RE::BSSpinLock lock; // 220 100 | DialogueData* dialogueData; // 228 101 | 102 | 103 | void SetExpressionOverride(std::uint32_t a_idx, float a_value); 104 | void ClearExpressionOverride(); 105 | void Reset(float a_timer, bool a_resetExpression, bool a_resetModifierAndPhoneme, bool a_resetCustom, bool a_closeEyes); 106 | std::uint32_t GetActiveExpression() const; 107 | void DialogueModifiersUpdate(float a_timeDelta); 108 | void DialoguePhonemesUpdate(float a_timeDelta); 109 | void CheckAndReleaseDialogueData(); 110 | void EyesBlinkingUpdate(float a_timeDelta); 111 | void EyesMovementUpdate(float a_timeDelta); 112 | void EyesDirectionUpdate(float a_timeDelta); 113 | bool KeyframesUpdateHook(float a_timeDelta, bool a_updateBlinking); 114 | 115 | static void Init(); 116 | }; 117 | 118 | static_assert(sizeof(BSFaceGenAnimationData) == 0x230); 119 | } -------------------------------------------------------------------------------- /src/mfgfix/BSFaceGenKeyframe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MfgFix 4 | { 5 | class BSFaceGenKeyframe 6 | { 7 | public: 8 | virtual ~BSFaceGenKeyframe(); // 00 9 | virtual bool Unk_01(RE::BSTArray& a_arr) = 0; // 01 10 | // Linear interpolation between keyframes. 11 | virtual bool Interpolate(BSFaceGenKeyframe* a_keyframe1, BSFaceGenKeyframe* a_keyframe2, float a_k) = 0; // 02 12 | // Linear interpolation between keyframes. 13 | virtual bool Interpolate(BSFaceGenKeyframe* a_keyframe, float a_k, bool a_ignoreSmall, bool a_copyBig) = 0; // 03 14 | virtual void Reset(bool a_initToZero) = 0; // 04 15 | virtual BSFaceGenKeyframe* Clone() = 0; // 05 16 | virtual void Copy(BSFaceGenKeyframe* a_keyframe) = 0; // 06 17 | virtual bool NotEqual(BSFaceGenKeyframe* a_keyframe) = 0; // 07 18 | virtual float GetMaxValue() = 0; // 08 19 | virtual bool IsZero() = 0; // 09 20 | virtual bool TransitionUpdate(float a_timeDelta, BSFaceGenKeyframe* a_keyframe) = 0; // 0A 21 | virtual bool NotZero() = 0; // 0B 22 | virtual bool IsKeyframeMultiple(); // 0C { return false; }; 23 | virtual bool IsKeyframeExclusive(); // 0D { return false; }; 24 | 25 | std::int32_t type; // 08 26 | float timer; // 0C 27 | }; 28 | 29 | static_assert(sizeof(BSFaceGenKeyframe) == 0x10); 30 | } -------------------------------------------------------------------------------- /src/mfgfix/BSFaceGenKeyframeMultiple.cpp: -------------------------------------------------------------------------------- 1 | #include "BSFaceGenKeyframeMultiple.h" 2 | #include "Offsets.h" 3 | 4 | namespace MfgFix 5 | { 6 | namespace { 7 | const char* GetExpressionName(std::uint32_t a_expression) 8 | { 9 | using func_t = decltype(&GetExpressionName); 10 | REL::Relocation func(Offsets::GetExpressionName); 11 | return func(a_expression); 12 | } 13 | 14 | const char* GetModifierName(std::uint32_t a_modifier) 15 | { 16 | using func_t = decltype(&GetModifierName); 17 | REL::Relocation func(Offsets::GetModifierName); 18 | return func(a_modifier); 19 | } 20 | 21 | const char* GetPhonemeName(std::uint32_t a_phoneme) 22 | { 23 | using func_t = decltype(&GetPhonemeName); 24 | REL::Relocation func(Offsets::GetPhonemeName); 25 | return func(a_phoneme); 26 | } 27 | 28 | const char* GetCustomName(std::uint32_t a_custom) 29 | { 30 | using func_t = decltype(&GetCustomName); 31 | REL::Relocation func(Offsets::GetCustomName); 32 | return func(a_custom); 33 | } 34 | } 35 | 36 | void BSFaceGenKeyframeMultiple::SetValue(std::uint32_t a_idx, float a_value) 37 | { 38 | if (a_idx < count) { 39 | values[a_idx] = a_value; 40 | isUpdated = false; 41 | } 42 | } 43 | 44 | void BSFaceGenKeyframeMultiple::Reset() 45 | { 46 | std::fill_n(values, count, 0.0f); 47 | isUpdated = false; 48 | } 49 | 50 | std::string BSFaceGenKeyframeMultiple::GetValueName(Type a_type, std::uint32_t a_idx) 51 | { 52 | const char* name{ nullptr }; 53 | 54 | switch (a_type) { 55 | case Type::Expression: { 56 | name = GetExpressionName(a_idx); 57 | break; 58 | } 59 | case Type::Modifier: { 60 | name = GetModifierName(a_idx); 61 | break; 62 | } 63 | case Type::Phoneme: { 64 | name = GetPhonemeName(a_idx); 65 | break; 66 | } 67 | case Type::Custom: { 68 | name = GetCustomName(a_idx); 69 | break; 70 | } 71 | } 72 | 73 | return name ? name : ""; 74 | } 75 | } -------------------------------------------------------------------------------- /src/mfgfix/BSFaceGenKeyframeMultiple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BSFaceGenKeyframe.h" 4 | 5 | namespace MfgFix 6 | { 7 | class BSFaceGenKeyframeMultiple: public BSFaceGenKeyframe 8 | { 9 | public: 10 | enum class Type : std::int32_t 11 | { 12 | Undefined = -1, 13 | Phoneme, 14 | Expression, 15 | Modifier, 16 | Custom 17 | }; 18 | 19 | enum Expression : std::uint32_t 20 | { 21 | DialogueAnger = 0, 22 | DialogueFear, 23 | DialogueHappy, 24 | DialogueSad, 25 | DialogueSurprise, 26 | DialoguePuzzled, 27 | DialogueDisgusted, 28 | MoodNeutral, 29 | MoodAnger, 30 | MoodFear, 31 | MoodHappy, 32 | MoodSad, 33 | MoodSurprise, 34 | MoodPuzzled, 35 | MoodDisgusted, 36 | CombatAnger, 37 | CombatShout 38 | }; 39 | 40 | enum Modifier : std::uint32_t 41 | { 42 | BlinkLeft = 0, 43 | BlinkRight, 44 | BrowDownLeft, 45 | BrowDownRight, 46 | BrowInLeft, 47 | BrowInRight, 48 | BrowUpLeft, 49 | BrowUpRight, 50 | LookDown, 51 | LookLeft, 52 | LookRight, 53 | LookUp, 54 | SquintLeft, 55 | SquintRight, 56 | HeadPitch, 57 | HeadRoll, 58 | HeadYaw 59 | }; 60 | 61 | enum Phoneme : std::uint32_t 62 | { 63 | Aah = 0, 64 | BigAah, 65 | BMP, 66 | ChJSh, 67 | DST, 68 | Eee, 69 | Eh, 70 | FV, 71 | I, 72 | K, 73 | N, 74 | Oh, 75 | OohQ, 76 | R, 77 | Th, 78 | W 79 | }; 80 | 81 | enum Custom : std::uint32_t 82 | { 83 | SkinnyMorph = 0 84 | }; 85 | 86 | ~BSFaceGenKeyframeMultiple() override; // 00 87 | bool Unk_01(RE::BSTArray& a_arr) override; // 01 88 | bool Interpolate(BSFaceGenKeyframe* a_keyframe1, BSFaceGenKeyframe* a_keyframe2, float a_k) override; // 02 89 | bool Interpolate(BSFaceGenKeyframe* a_keyframe, float a_k, bool a_ignoreSmall, bool a_copyBig) override; // 03 90 | void Reset(bool a_initToZero) override; // 04 91 | BSFaceGenKeyframe* Clone() override; // 05 92 | void Copy(BSFaceGenKeyframe* a_keyframe) override; // 06 93 | bool NotEqual(BSFaceGenKeyframe* a_keyframe) override; // 07 94 | float GetMaxValue() override; // 08 95 | bool IsZero() override; // 09 96 | bool TransitionUpdate(float a_timeDelta, BSFaceGenKeyframe* a_keyframe) override; // 0A 97 | bool NotZero() override; // 0B 98 | bool IsKeyframeMultiple() override; // 0C { return true; }; 99 | bool IsKeyframeExclusive() override; // 0D { return false; }; 100 | 101 | // Is value in range [0, 1]. 102 | virtual bool IsValueValid(std::uint32_t a_idx); // 0E 103 | virtual void Allocate(std::uint32_t a_count, bool a_initToZero); // 0F 104 | 105 | static std::string GetValueName(Type a_type, std::uint32_t a_idx); 106 | 107 | void SetValue(std::uint32_t a_idx, float a_value); 108 | void Reset(); 109 | 110 | float* values; // 10 111 | std::uint32_t count; // 18 112 | bool isUpdated; // 1C 113 | std::uint8_t pad1D[3]; // 1D 114 | }; 115 | 116 | static_assert(sizeof(BSFaceGenKeyframeMultiple) == 0x20); 117 | } -------------------------------------------------------------------------------- /src/mfgfix/ConsoleCommands.cpp: -------------------------------------------------------------------------------- 1 | #include "ConsoleCommands.h" 2 | #include "BSFaceGenAnimationData.h" 3 | #include "Offsets.h" 4 | 5 | namespace MfgFix::ConsoleCommands 6 | { 7 | using Keyframe = BSFaceGenAnimationData::Keyframe; 8 | 9 | uintptr_t ModifyFaceGenCommandAddr{ 0 }; 10 | 11 | void SetValue(RE::TESObjectREFR* a_ref, Keyframe::Type a_keyframeType, std::uint32_t a_idx, float a_value) 12 | { 13 | if (!a_ref) { 14 | return; 15 | } 16 | 17 | auto animData = reinterpret_cast(a_ref->GetFaceGenAnimationData()); 18 | 19 | if (!animData) { 20 | return; 21 | } 22 | 23 | RE::BSSpinLockGuard locker(animData->lock); 24 | 25 | switch (a_keyframeType) { 26 | case Keyframe::Type::Phoneme: { 27 | animData->phoneme2.SetValue(a_idx, a_value); 28 | break; 29 | } 30 | case Keyframe::Type::Expression: { 31 | animData->expressionOverride = false; 32 | animData->SetExpressionOverride(a_idx, a_value); 33 | animData->expressionOverride = true; 34 | break; 35 | } 36 | case Keyframe::Type::Modifier: { 37 | animData->modifier2.SetValue(a_idx, a_value); 38 | break; 39 | } 40 | case Keyframe::Type::Custom: { 41 | animData->custom2.SetValue(a_idx, a_value); 42 | break; 43 | } 44 | } 45 | } 46 | 47 | void PrintInfo(RE::TESObjectREFR* a_ref, Keyframe::Type a_keyframeType) 48 | { 49 | if (!a_ref) { 50 | return; 51 | } 52 | 53 | auto animData = reinterpret_cast(a_ref->GetFaceGenAnimationData()); 54 | 55 | if (!animData) { 56 | return; 57 | } 58 | 59 | auto console = RE::ConsoleLog::GetSingleton(); 60 | 61 | if (!console) { 62 | return; 63 | } 64 | 65 | RE::BSSpinLockGuard locker(animData->lock); 66 | 67 | Keyframe* keyframe{ nullptr }; 68 | 69 | switch (a_keyframeType) { 70 | case Keyframe::Type::Phoneme: { 71 | keyframe = &animData->phoneme2; 72 | break; 73 | } 74 | case Keyframe::Type::Expression: { 75 | keyframe = &animData->expression1; 76 | break; 77 | } 78 | case Keyframe::Type::Modifier: { 79 | keyframe = &animData->modifier2; 80 | break; 81 | } 82 | case Keyframe::Type::Custom: { 83 | keyframe = &animData->custom2; 84 | break; 85 | } 86 | } 87 | 88 | if (!keyframe) { 89 | return; 90 | } 91 | 92 | for (std::uint32_t i = 0; i < keyframe->count; ++i) { 93 | console->Print(fmt::format("{:2d} {:3.0f} {:s}", i, keyframe->values[i] * 100.0f, Keyframe::GetValueName(a_keyframeType, i)).c_str()); 94 | } 95 | } 96 | 97 | void Reset(RE::TESObjectREFR* a_ref) 98 | { 99 | if (!a_ref) { 100 | return; 101 | } 102 | 103 | auto animData = reinterpret_cast(a_ref->GetFaceGenAnimationData()); 104 | 105 | if (!animData) { 106 | return; 107 | } 108 | 109 | RE::BSSpinLockGuard locker(animData->lock); 110 | 111 | animData->ClearExpressionOverride(); 112 | animData->Reset(0.0f, true, true, true, false); 113 | } 114 | 115 | bool ModifyFaceGenCommand(const RE::SCRIPT_PARAMETER* a_paramInfo, RE::SCRIPT_FUNCTION::ScriptData* a_scriptData, RE::TESObjectREFR* a_thisObj, RE::TESObjectREFR* a_containingObj, RE::Script* a_scriptObj, RE::ScriptLocals* a_locals, double& a_result, std::uint32_t& a_opcodeOffsetPtr) 116 | { 117 | using func_t = decltype(&ModifyFaceGenCommand); 118 | REL::Relocation func(ModifyFaceGenCommandAddr); 119 | return func(a_paramInfo, a_scriptData, a_thisObj, a_containingObj, a_scriptObj, a_locals, a_result, a_opcodeOffsetPtr); 120 | } 121 | 122 | bool ModifyFaceGenCommandHook(const RE::SCRIPT_PARAMETER* a_paramInfo, RE::SCRIPT_FUNCTION::ScriptData* a_scriptData, RE::TESObjectREFR* a_thisObj, RE::TESObjectREFR* a_containingObj, RE::Script* a_scriptObj, RE::ScriptLocals* a_locals, double& a_result, std::uint32_t& a_opcodeOffsetPtr) 123 | { 124 | auto thisObj = a_thisObj ? a_thisObj : RE::PlayerCharacter::GetSingleton(); 125 | 126 | if (a_scriptData && a_paramInfo) { 127 | auto param1 = a_scriptData->numParams > 0 && a_paramInfo[0].paramType == RE::SCRIPT_PARAM_TYPE::kChar ? a_scriptData->GetChunk()->AsString() : nullptr; 128 | auto param2 = a_scriptData->numParams > 1 && a_paramInfo[1].paramType == RE::SCRIPT_PARAM_TYPE::kInt && param1 ? param1->GetNext()->AsInteger() : nullptr; 129 | auto param3 = a_scriptData->numParams > 2 && a_paramInfo[2].paramType == RE::SCRIPT_PARAM_TYPE::kInt && param2 ? param2->GetNext()->AsInteger() : nullptr; 130 | 131 | if (param1) { 132 | if (_strnicmp(param1->str, "expression", param1->length) == 0) { 133 | if (param2 && param3) { 134 | SetValue(thisObj, Keyframe::Type::Expression, param2->value, param3->value / 100.0f); 135 | } else if (!param2 && !param3) { 136 | PrintInfo(thisObj, Keyframe::Type::Expression); 137 | } 138 | return true; 139 | } else if (_strnicmp(param1->str, "modifier", param1->length) == 0) { 140 | if (param2 && param3) { 141 | SetValue(thisObj, Keyframe::Type::Modifier, param2->value, param3->value / 100.0f); 142 | } else if (!param2 && !param3) { 143 | PrintInfo(thisObj, Keyframe::Type::Modifier); 144 | } 145 | return true; 146 | } else if (_strnicmp(param1->str, "phoneme", param1->length) == 0) { 147 | if (param2 && param3) { 148 | SetValue(thisObj, Keyframe::Type::Phoneme, param2->value, param3->value / 100.0f); 149 | } else if (!param2 && !param3) { 150 | PrintInfo(thisObj, Keyframe::Type::Phoneme); 151 | } 152 | return true; 153 | } else if (_strnicmp(param1->str, "custom", param1->length) == 0) { 154 | if (param2 && param3) { 155 | SetValue(thisObj, Keyframe::Type::Custom, param2->value, param3->value / 100.0f); 156 | } else if (!param2 && !param3) { 157 | PrintInfo(thisObj, Keyframe::Type::Custom); 158 | } 159 | return true; 160 | } else if (_strnicmp(param1->str, "reset", param1->length) == 0) { 161 | Reset(thisObj); 162 | return true; 163 | } 164 | } 165 | } 166 | 167 | return ModifyFaceGenCommand(a_paramInfo, a_scriptData, a_thisObj, a_containingObj, a_scriptObj, a_locals, a_result, a_opcodeOffsetPtr); 168 | } 169 | 170 | void Init() 171 | { 172 | ModifyFaceGenCommandAddr = Offsets::ModifyFaceGenCommand.address(); 173 | 174 | DetourTransactionBegin(); 175 | DetourUpdateThread(GetCurrentThread()); 176 | DetourAttach(reinterpret_cast(&ModifyFaceGenCommandAddr), reinterpret_cast(ModifyFaceGenCommandHook)); 177 | 178 | if (DetourTransactionCommit() != NO_ERROR) { 179 | spdlog::error("failed to attach detour"); 180 | } 181 | } 182 | 183 | } -------------------------------------------------------------------------------- /src/mfgfix/ConsoleCommands.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace MfgFix::ConsoleCommands 5 | { 6 | void Init(); 7 | } -------------------------------------------------------------------------------- /src/mfgfix/MfgConsoleFunc.cpp: -------------------------------------------------------------------------------- 1 | #include "MfgConsoleFunc.h" 2 | #include "BSFaceGenAnimationData.h" 3 | 4 | namespace MfgFix::MfgConsoleFunc 5 | { 6 | namespace 7 | { 8 | enum Mode : std::int32_t 9 | { 10 | Reset = -1, 11 | Phoneme, 12 | Modifier, 13 | ExpressionValue, 14 | ExpressionId 15 | }; 16 | } 17 | 18 | std::uint32_t GetActiveExpression(const BSFaceGenAnimationData& a_animData) 19 | { 20 | std::uint32_t expression = BSFaceGenAnimationData::Expression::MoodNeutral; 21 | 22 | for (std::uint32_t i = 0; i < a_animData.expression1.count; ++i) { 23 | if (a_animData.expression1.values[i] > a_animData.expression1.values[expression]) { 24 | expression = i; 25 | } 26 | } 27 | 28 | return expression; 29 | } 30 | 31 | bool SetPhonemeModifier(RE::StaticFunctionTag*, RE::Actor* a_actor, std::int32_t a_mode, std::uint32_t a_id, std::int32_t a_value) 32 | { 33 | if (!a_actor) { 34 | return false; 35 | } 36 | 37 | auto animData = reinterpret_cast(a_actor->GetFaceGenAnimationData()); 38 | 39 | if (!animData) { 40 | return false; 41 | } 42 | 43 | RE::BSSpinLockGuard locker(animData->lock); 44 | 45 | switch (a_mode) { 46 | case Mode::Reset: { 47 | animData->ClearExpressionOverride(); 48 | animData->Reset(0.0f, true, true, true, false); 49 | return true; 50 | } 51 | case Mode::Phoneme: { 52 | animData->phoneme2.SetValue(a_id, std::clamp(a_value, 0, 100) / 100.0f); 53 | return true; 54 | } 55 | case Mode::Modifier: { 56 | animData->modifier2.SetValue(a_id, std::clamp(a_value, 0, 100) / 100.0f); 57 | return true; 58 | } 59 | } 60 | 61 | return false; 62 | } 63 | 64 | std::int32_t GetPhonemeModifier(RE::StaticFunctionTag*, RE::Actor* a_actor, std::int32_t a_mode, std::uint32_t a_id) 65 | { 66 | if (!a_actor) { 67 | return -1; 68 | } 69 | 70 | auto animData = reinterpret_cast(a_actor->GetFaceGenAnimationData()); 71 | 72 | if (!animData) { 73 | return -1; 74 | } 75 | 76 | RE::BSSpinLockGuard locker(animData->lock); 77 | 78 | switch(a_mode) { 79 | case Mode::Phoneme: { 80 | return a_id < animData->phoneme2.count ? std::lround(animData->phoneme2.values[a_id] * 100.0f) : 0; 81 | } 82 | case Mode::Modifier: { 83 | return a_id < animData->modifier2.count ? std::lround(animData->modifier2.values[a_id] * 100.0f) : 0; 84 | } 85 | case Mode::ExpressionValue: { 86 | return a_id < animData->expression1.count ? std::lround(animData->expression1.values[a_id] * 100.0f) : 0; 87 | } 88 | case Mode::ExpressionId: { 89 | return GetActiveExpression(*animData); 90 | } 91 | } 92 | 93 | return -1; 94 | } 95 | 96 | void Register() 97 | { 98 | SKSE::GetPapyrusInterface()->Register([](RE::BSScript::IVirtualMachine* a_vm) { 99 | a_vm->RegisterFunction("SetPhonemeModifier", "MfgConsoleFunc", SetPhonemeModifier); 100 | a_vm->RegisterFunction("GetPhonemeModifier", "MfgConsoleFunc", GetPhonemeModifier); 101 | 102 | return true; 103 | }); 104 | } 105 | } -------------------------------------------------------------------------------- /src/mfgfix/MfgConsoleFunc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MfgFix::MfgConsoleFunc 4 | { 5 | void Register(); 6 | } -------------------------------------------------------------------------------- /src/mfgfix/Offsets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace MfgFix::Offsets 5 | { 6 | 7 | namespace 8 | { 9 | static constexpr REL::ID ModifyFaceGenCommand(static_cast(23017)); 10 | static constexpr REL::ID GetExpressionName(static_cast(27007)); 11 | static constexpr REL::ID GetModifierName(static_cast(27008)); 12 | static constexpr REL::ID GetPhonemeName(static_cast(27009)); 13 | static constexpr REL::ID GetCustomName(static_cast(27010)); 14 | } 15 | 16 | namespace BSFaceGenAnimationData 17 | { 18 | static constexpr REL::ID KeyframesUpdate(static_cast(26598)); 19 | static constexpr REL::ID SetExpressionOverride(static_cast(26594)); 20 | static constexpr REL::ID sub_3DB770(static_cast(26593)); 21 | static constexpr REL::ID Reset(static_cast(26586)); 22 | } 23 | 24 | namespace BSFaceGenNiNode 25 | { 26 | static constexpr REL::ID sub_3F1800(static_cast(26998)); 27 | static constexpr REL::ID sub_3F0C90(static_cast(26988)); 28 | } 29 | 30 | namespace Papyrus 31 | { 32 | namespace Actor 33 | { 34 | static constexpr REL::ID SetExpressionOverride(static_cast(54748)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/mfgfix/Settings.cpp: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | #include "SimpleIni.h" 3 | 4 | namespace MfgFix 5 | { 6 | namespace 7 | { 8 | std::filesystem::path GetIniPath() 9 | { 10 | wchar_t buf[4096] = L""; 11 | 12 | std::uint32_t size = GetModuleFileNameW(NULL, buf, static_cast(std::size(buf))); 13 | 14 | if (size == 0 || size == std::size(buf)) { 15 | return ""; 16 | } 17 | 18 | std::filesystem::path path{ buf }; 19 | 20 | return path.replace_filename(L"Data\\SKSE\\Plugins\\mfgfix.ini"); 21 | } 22 | } 23 | 24 | Settings& Settings::Get() 25 | { 26 | static Settings settings; 27 | 28 | return settings; 29 | } 30 | 31 | void Settings::Read() 32 | { 33 | CSimpleIniA ini; 34 | auto path = GetIniPath(); 35 | 36 | if (ini.LoadFile(path.c_str()) != SI_Error::SI_OK) { 37 | return; 38 | } 39 | 40 | eyesBlinking.fBlinkDownTime = static_cast(ini.GetDoubleValue("EyesBlinking", "fBlinkDownTime", eyesBlinking.fBlinkDownTime)); 41 | eyesBlinking.fBlinkUpTime = static_cast(ini.GetDoubleValue("EyesBlinking", "fBlinkUpTime", eyesBlinking.fBlinkUpTime)); 42 | eyesBlinking.fBlinkDelayMin = static_cast(ini.GetDoubleValue("EyesBlinking", "fBlinkDelayMin", eyesBlinking.fBlinkDelayMin)); 43 | eyesBlinking.fBlinkDelayMax = static_cast(ini.GetDoubleValue("EyesBlinking", "fBlinkDelayMax", eyesBlinking.fBlinkDelayMax)); 44 | eyesMovement.fTrackSpeed = static_cast(ini.GetDoubleValue("EyesMovement", "fTrackSpeed", eyesMovement.fTrackSpeed)); 45 | eyesMovement.fTrackEyeXY = static_cast(ini.GetDoubleValue("EyesMovement", "fTrackEyeXY", eyesMovement.fTrackEyeXY)); 46 | eyesMovement.fTrackEyeZ = static_cast(ini.GetDoubleValue("EyesMovement", "fTrackEyeZ", eyesMovement.fTrackEyeZ)); 47 | eyesMovement.fEyeHeadingMinOffsetEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionAngry", eyesMovement.fEyeHeadingMinOffsetEmotionAngry)); 48 | eyesMovement.fEyeHeadingMaxOffsetEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionAngry", eyesMovement.fEyeHeadingMaxOffsetEmotionAngry)); 49 | eyesMovement.fEyePitchMinOffsetEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionAngry", eyesMovement.fEyePitchMinOffsetEmotionAngry)); 50 | eyesMovement.fEyePitchMaxOffsetEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionAngry", eyesMovement.fEyePitchMaxOffsetEmotionAngry)); 51 | eyesMovement.fEyeOffsetDelayMinEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionAngry", eyesMovement.fEyeOffsetDelayMinEmotionAngry)); 52 | eyesMovement.fEyeOffsetDelayMaxEmotionAngry = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionAngry", eyesMovement.fEyeOffsetDelayMaxEmotionAngry)); 53 | eyesMovement.fEyeHeadingMinOffsetEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionHappy", eyesMovement.fEyeHeadingMinOffsetEmotionHappy)); 54 | eyesMovement.fEyeHeadingMaxOffsetEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionHappy", eyesMovement.fEyeHeadingMaxOffsetEmotionHappy)); 55 | eyesMovement.fEyePitchMinOffsetEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionHappy", eyesMovement.fEyePitchMinOffsetEmotionHappy)); 56 | eyesMovement.fEyePitchMaxOffsetEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionHappy", eyesMovement.fEyePitchMaxOffsetEmotionHappy)); 57 | eyesMovement.fEyeOffsetDelayMinEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionHappy", eyesMovement.fEyeOffsetDelayMinEmotionHappy)); 58 | eyesMovement.fEyeOffsetDelayMaxEmotionHappy = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionHappy", eyesMovement.fEyeOffsetDelayMaxEmotionHappy)); 59 | eyesMovement.fEyeHeadingMinOffsetEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionSurprise", eyesMovement.fEyeHeadingMinOffsetEmotionSurprise)); 60 | eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionSurprise", eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise)); 61 | eyesMovement.fEyePitchMinOffsetEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionSurprise", eyesMovement.fEyePitchMinOffsetEmotionSurprise)); 62 | eyesMovement.fEyePitchMaxOffsetEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionSurprise", eyesMovement.fEyePitchMaxOffsetEmotionSurprise)); 63 | eyesMovement.fEyeOffsetDelayMinEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionSurprise", eyesMovement.fEyeOffsetDelayMinEmotionSurprise)); 64 | eyesMovement.fEyeOffsetDelayMaxEmotionSurprise = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionSurprise", eyesMovement.fEyeOffsetDelayMaxEmotionSurprise)); 65 | eyesMovement.fEyeHeadingMinOffsetEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionSad", eyesMovement.fEyeHeadingMinOffsetEmotionSad)); 66 | eyesMovement.fEyeHeadingMaxOffsetEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionSad", eyesMovement.fEyeHeadingMaxOffsetEmotionSad)); 67 | eyesMovement.fEyePitchMinOffsetEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionSad", eyesMovement.fEyePitchMinOffsetEmotionSad)); 68 | eyesMovement.fEyePitchMaxOffsetEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionSad", eyesMovement.fEyePitchMaxOffsetEmotionSad)); 69 | eyesMovement.fEyeOffsetDelayMinEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionSad", eyesMovement.fEyeOffsetDelayMinEmotionSad)); 70 | eyesMovement.fEyeOffsetDelayMaxEmotionSad = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionSad", eyesMovement.fEyeOffsetDelayMaxEmotionSad)); 71 | eyesMovement.fEyeHeadingMinOffsetEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionFear", eyesMovement.fEyeHeadingMinOffsetEmotionFear)); 72 | eyesMovement.fEyeHeadingMaxOffsetEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionFear", eyesMovement.fEyeHeadingMaxOffsetEmotionFear)); 73 | eyesMovement.fEyePitchMinOffsetEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionFear", eyesMovement.fEyePitchMinOffsetEmotionFear)); 74 | eyesMovement.fEyePitchMaxOffsetEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionFear", eyesMovement.fEyePitchMaxOffsetEmotionFear)); 75 | eyesMovement.fEyeOffsetDelayMinEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionFear", eyesMovement.fEyeOffsetDelayMinEmotionFear)); 76 | eyesMovement.fEyeOffsetDelayMaxEmotionFear = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionFear", eyesMovement.fEyeOffsetDelayMaxEmotionFear)); 77 | eyesMovement.fEyeHeadingMinOffsetEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionNeutral", eyesMovement.fEyeHeadingMinOffsetEmotionNeutral)); 78 | eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionNeutral", eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral)); 79 | eyesMovement.fEyePitchMinOffsetEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionNeutral", eyesMovement.fEyePitchMinOffsetEmotionNeutral)); 80 | eyesMovement.fEyePitchMaxOffsetEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionNeutral", eyesMovement.fEyePitchMaxOffsetEmotionNeutral)); 81 | eyesMovement.fEyeOffsetDelayMinEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionNeutral", eyesMovement.fEyeOffsetDelayMinEmotionNeutral)); 82 | eyesMovement.fEyeOffsetDelayMaxEmotionNeutral = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionNeutral", eyesMovement.fEyeOffsetDelayMaxEmotionNeutral)); 83 | eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionPuzzled", eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled)); 84 | eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionPuzzled", eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled)); 85 | eyesMovement.fEyePitchMinOffsetEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionPuzzled", eyesMovement.fEyePitchMinOffsetEmotionPuzzled)); 86 | eyesMovement.fEyePitchMaxOffsetEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionPuzzled", eyesMovement.fEyePitchMaxOffsetEmotionPuzzled)); 87 | eyesMovement.fEyeOffsetDelayMinEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionPuzzled", eyesMovement.fEyeOffsetDelayMinEmotionPuzzled)); 88 | eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionPuzzled", eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled)); 89 | eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionDisgusted", eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted)); 90 | eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionDisgusted", eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted)); 91 | eyesMovement.fEyePitchMinOffsetEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionDisgusted", eyesMovement.fEyePitchMinOffsetEmotionDisgusted)); 92 | eyesMovement.fEyePitchMaxOffsetEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionDisgusted", eyesMovement.fEyePitchMaxOffsetEmotionDisgusted)); 93 | eyesMovement.fEyeOffsetDelayMinEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionDisgusted", eyesMovement.fEyeOffsetDelayMinEmotionDisgusted)); 94 | eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionDisgusted", eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted)); 95 | eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionCombatAnger", eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger)); 96 | eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionCombatAnger", eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger)); 97 | eyesMovement.fEyePitchMinOffsetEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionCombatAnger", eyesMovement.fEyePitchMinOffsetEmotionCombatAnger)); 98 | eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionCombatAnger", eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger)); 99 | eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionCombatAnger", eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger)); 100 | eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionCombatAnger", eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger)); 101 | eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionCombatShout", eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout)); 102 | eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionCombatShout", eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout)); 103 | eyesMovement.fEyePitchMinOffsetEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionCombatShout", eyesMovement.fEyePitchMinOffsetEmotionCombatShout)); 104 | eyesMovement.fEyePitchMaxOffsetEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionCombatShout", eyesMovement.fEyePitchMaxOffsetEmotionCombatShout)); 105 | eyesMovement.fEyeOffsetDelayMinEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionCombatShout", eyesMovement.fEyeOffsetDelayMinEmotionCombatShout)); 106 | eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout = static_cast(ini.GetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionCombatShout", eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout)); 107 | } 108 | 109 | void Settings::Write() 110 | { 111 | CSimpleIniA ini; 112 | auto path = GetIniPath(); 113 | 114 | ini.LoadFile(path.c_str()); 115 | 116 | ini.SetDoubleValue("EyesBlinking", "fBlinkDownTime", eyesBlinking.fBlinkDownTime); 117 | ini.SetDoubleValue("EyesBlinking", "fBlinkUpTime", eyesBlinking.fBlinkUpTime); 118 | ini.SetDoubleValue("EyesBlinking", "fBlinkDelayMin", eyesBlinking.fBlinkDelayMin); 119 | ini.SetDoubleValue("EyesBlinking", "fBlinkDelayMax", eyesBlinking.fBlinkDelayMax); 120 | ini.SetDoubleValue("EyesMovement", "fTrackSpeed", eyesMovement.fTrackSpeed); 121 | ini.SetDoubleValue("EyesMovement", "fTrackEyeXY", eyesMovement.fTrackEyeXY); 122 | ini.SetDoubleValue("EyesMovement", "fTrackEyeZ", eyesMovement.fTrackEyeZ); 123 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionAngry", eyesMovement.fEyeHeadingMinOffsetEmotionAngry); 124 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionAngry", eyesMovement.fEyeHeadingMaxOffsetEmotionAngry); 125 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionAngry", eyesMovement.fEyePitchMinOffsetEmotionAngry); 126 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionAngry", eyesMovement.fEyePitchMaxOffsetEmotionAngry); 127 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionAngry", eyesMovement.fEyeOffsetDelayMinEmotionAngry); 128 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionAngry", eyesMovement.fEyeOffsetDelayMaxEmotionAngry); 129 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionHappy", eyesMovement.fEyeHeadingMinOffsetEmotionHappy); 130 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionHappy", eyesMovement.fEyeHeadingMaxOffsetEmotionHappy); 131 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionHappy", eyesMovement.fEyePitchMinOffsetEmotionHappy); 132 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionHappy", eyesMovement.fEyePitchMaxOffsetEmotionHappy); 133 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionHappy", eyesMovement.fEyeOffsetDelayMinEmotionHappy); 134 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionHappy", eyesMovement.fEyeOffsetDelayMaxEmotionHappy); 135 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionSurprise", eyesMovement.fEyeHeadingMinOffsetEmotionSurprise); 136 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionSurprise", eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise); 137 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionSurprise", eyesMovement.fEyePitchMinOffsetEmotionSurprise); 138 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionSurprise", eyesMovement.fEyePitchMaxOffsetEmotionSurprise); 139 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionSurprise", eyesMovement.fEyeOffsetDelayMinEmotionSurprise); 140 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionSurprise", eyesMovement.fEyeOffsetDelayMaxEmotionSurprise); 141 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionSad", eyesMovement.fEyeHeadingMinOffsetEmotionSad); 142 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionSad", eyesMovement.fEyeHeadingMaxOffsetEmotionSad); 143 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionSad", eyesMovement.fEyePitchMinOffsetEmotionSad); 144 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionSad", eyesMovement.fEyePitchMaxOffsetEmotionSad); 145 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionSad", eyesMovement.fEyeOffsetDelayMinEmotionSad); 146 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionSad", eyesMovement.fEyeOffsetDelayMaxEmotionSad); 147 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionFear", eyesMovement.fEyeHeadingMinOffsetEmotionFear); 148 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionFear", eyesMovement.fEyeHeadingMaxOffsetEmotionFear); 149 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionFear", eyesMovement.fEyePitchMinOffsetEmotionFear); 150 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionFear", eyesMovement.fEyePitchMaxOffsetEmotionFear); 151 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionFear", eyesMovement.fEyeOffsetDelayMinEmotionFear); 152 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionFear", eyesMovement.fEyeOffsetDelayMaxEmotionFear); 153 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionNeutral", eyesMovement.fEyeHeadingMinOffsetEmotionNeutral); 154 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionNeutral", eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral); 155 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionNeutral", eyesMovement.fEyePitchMinOffsetEmotionNeutral); 156 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionNeutral", eyesMovement.fEyePitchMaxOffsetEmotionNeutral); 157 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionNeutral", eyesMovement.fEyeOffsetDelayMinEmotionNeutral); 158 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionNeutral", eyesMovement.fEyeOffsetDelayMaxEmotionNeutral); 159 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionPuzzled", eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled); 160 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionPuzzled", eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled); 161 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionPuzzled", eyesMovement.fEyePitchMinOffsetEmotionPuzzled); 162 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionPuzzled", eyesMovement.fEyePitchMaxOffsetEmotionPuzzled); 163 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionPuzzled", eyesMovement.fEyeOffsetDelayMinEmotionPuzzled); 164 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionPuzzled", eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled); 165 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionDisgusted", eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted); 166 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionDisgusted", eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted); 167 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionDisgusted", eyesMovement.fEyePitchMinOffsetEmotionDisgusted); 168 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionDisgusted", eyesMovement.fEyePitchMaxOffsetEmotionDisgusted); 169 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionDisgusted", eyesMovement.fEyeOffsetDelayMinEmotionDisgusted); 170 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionDisgusted", eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted); 171 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionCombatAnger", eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger); 172 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionCombatAnger", eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger); 173 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionCombatAnger", eyesMovement.fEyePitchMinOffsetEmotionCombatAnger); 174 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionCombatAnger", eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger); 175 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionCombatAnger", eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger); 176 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionCombatAnger", eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger); 177 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMinOffsetEmotionCombatShout", eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout); 178 | ini.SetDoubleValue("EyesMovement", "fEyeHeadingMaxOffsetEmotionCombatShout", eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout); 179 | ini.SetDoubleValue("EyesMovement", "fEyePitchMinOffsetEmotionCombatShout", eyesMovement.fEyePitchMinOffsetEmotionCombatShout); 180 | ini.SetDoubleValue("EyesMovement", "fEyePitchMaxOffsetEmotionCombatShout", eyesMovement.fEyePitchMaxOffsetEmotionCombatShout); 181 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMinEmotionCombatShout", eyesMovement.fEyeOffsetDelayMinEmotionCombatShout); 182 | ini.SetDoubleValue("EyesMovement", "fEyeOffsetDelayMaxEmotionCombatShout", eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout); 183 | 184 | ini.SaveFile(path.c_str()); 185 | } 186 | } -------------------------------------------------------------------------------- /src/mfgfix/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MfgFix 4 | { 5 | struct Settings 6 | { 7 | struct EyesBlinking 8 | { 9 | float fBlinkDownTime{ 0.04f }; 10 | float fBlinkUpTime{ 0.14f }; 11 | float fBlinkDelayMin{ 0.5f }; 12 | float fBlinkDelayMax{ 8.0f }; 13 | }; 14 | 15 | struct EyesMovement 16 | { 17 | float fTrackSpeed{ 5.0f }; 18 | float fTrackEyeXY{ 28.0f }; 19 | float fTrackEyeZ{ 20.0f }; 20 | float fEyeHeadingMinOffsetEmotionAngry{ -0.05f }; 21 | float fEyeHeadingMaxOffsetEmotionAngry{ 0.05f }; 22 | float fEyePitchMinOffsetEmotionAngry{ -0.05f }; 23 | float fEyePitchMaxOffsetEmotionAngry{ 0.1f }; 24 | float fEyeOffsetDelayMinEmotionAngry{ 0.5f }; 25 | float fEyeOffsetDelayMaxEmotionAngry{ 3.0f }; 26 | float fEyeHeadingMinOffsetEmotionHappy{ -0.1f }; 27 | float fEyeHeadingMaxOffsetEmotionHappy{ 0.1f }; 28 | float fEyePitchMinOffsetEmotionHappy{ -0.05f }; 29 | float fEyePitchMaxOffsetEmotionHappy{ 0.1f }; 30 | float fEyeOffsetDelayMinEmotionHappy{ 0.5f }; 31 | float fEyeOffsetDelayMaxEmotionHappy{ 4.0f }; 32 | float fEyeHeadingMinOffsetEmotionSurprise{ -0.1f }; 33 | float fEyeHeadingMaxOffsetEmotionSurprise{ 0.1f }; 34 | float fEyePitchMinOffsetEmotionSurprise{ -0.05f }; 35 | float fEyePitchMaxOffsetEmotionSurprise{ 0.1f }; 36 | float fEyeOffsetDelayMinEmotionSurprise{ 0.5f }; 37 | float fEyeOffsetDelayMaxEmotionSurprise{ 4.0f }; 38 | float fEyeHeadingMinOffsetEmotionSad{ -0.1f }; 39 | float fEyeHeadingMaxOffsetEmotionSad{ 0.1f }; 40 | float fEyePitchMinOffsetEmotionSad{ -0.05f }; 41 | float fEyePitchMaxOffsetEmotionSad{ -0.015f }; 42 | float fEyeOffsetDelayMinEmotionSad{ 2.0f }; 43 | float fEyeOffsetDelayMaxEmotionSad{ 3.0f }; 44 | float fEyeHeadingMinOffsetEmotionFear{ -0.1f }; 45 | float fEyeHeadingMaxOffsetEmotionFear{ 0.1f }; 46 | float fEyePitchMinOffsetEmotionFear{ 0.01f }; 47 | float fEyePitchMaxOffsetEmotionFear{ 0.01f }; 48 | float fEyeOffsetDelayMinEmotionFear{ 0.5f }; 49 | float fEyeOffsetDelayMaxEmotionFear{ 1.5f }; 50 | float fEyeHeadingMinOffsetEmotionNeutral{ -0.1f }; 51 | float fEyeHeadingMaxOffsetEmotionNeutral{ 0.1f }; 52 | float fEyePitchMinOffsetEmotionNeutral{ -0.025f }; 53 | float fEyePitchMaxOffsetEmotionNeutral{ 0.1f }; 54 | float fEyeOffsetDelayMinEmotionNeutral{ 0.5f }; 55 | float fEyeOffsetDelayMaxEmotionNeutral{ 4.0f }; 56 | float fEyeHeadingMinOffsetEmotionPuzzled{ 0.0f }; 57 | float fEyeHeadingMaxOffsetEmotionPuzzled{ 0.0f }; 58 | float fEyePitchMinOffsetEmotionPuzzled{ 0.0f }; 59 | float fEyePitchMaxOffsetEmotionPuzzled{ 0.0f }; 60 | float fEyeOffsetDelayMinEmotionPuzzled{ 3.0f }; 61 | float fEyeOffsetDelayMaxEmotionPuzzled{ 3.0f }; 62 | float fEyeHeadingMinOffsetEmotionDisgusted{ 0.0f }; 63 | float fEyeHeadingMaxOffsetEmotionDisgusted{ 0.0f }; 64 | float fEyePitchMinOffsetEmotionDisgusted{ 0.0f }; 65 | float fEyePitchMaxOffsetEmotionDisgusted{ 0.0f }; 66 | float fEyeOffsetDelayMinEmotionDisgusted{ 3.0f }; 67 | float fEyeOffsetDelayMaxEmotionDisgusted{ 3.0f }; 68 | float fEyeHeadingMinOffsetEmotionCombatAnger{ 0.0f }; 69 | float fEyeHeadingMaxOffsetEmotionCombatAnger{ 0.0f }; 70 | float fEyePitchMinOffsetEmotionCombatAnger{ 0.0f }; 71 | float fEyePitchMaxOffsetEmotionCombatAnger{ 0.0f }; 72 | float fEyeOffsetDelayMinEmotionCombatAnger{ 3.0f }; 73 | float fEyeOffsetDelayMaxEmotionCombatAnger{ 3.0f }; 74 | float fEyeHeadingMinOffsetEmotionCombatShout{ 0.0f }; 75 | float fEyeHeadingMaxOffsetEmotionCombatShout{ 0.0f }; 76 | float fEyePitchMinOffsetEmotionCombatShout{ 0.0f }; 77 | float fEyePitchMaxOffsetEmotionCombatShout{ 0.0f }; 78 | float fEyeOffsetDelayMinEmotionCombatShout{ 3.0f }; 79 | float fEyeOffsetDelayMaxEmotionCombatShout{ 3.0f }; 80 | }; 81 | 82 | static Settings& Get(); 83 | 84 | void Read(); 85 | void Write(); 86 | 87 | EyesBlinking eyesBlinking; 88 | EyesMovement eyesMovement; 89 | }; 90 | } -------------------------------------------------------------------------------- /src/mfgfix/SettingsPapyrus.cpp: -------------------------------------------------------------------------------- 1 | #include "SettingsPapyrus.h" 2 | #include "Settings.h" 3 | 4 | namespace MfgFix::SettingsPapyrus 5 | { 6 | void Save(RE::StaticFunctionTag*) 7 | { 8 | Settings::Get().Write(); 9 | } 10 | 11 | float GetFBlinkDownTime(RE::StaticFunctionTag*) 12 | { 13 | return Settings::Get().eyesBlinking.fBlinkDownTime; 14 | } 15 | 16 | void SetFBlinkDownTime(RE::StaticFunctionTag*, float a_value) 17 | { 18 | Settings::Get().eyesBlinking.fBlinkDownTime = a_value; 19 | } 20 | 21 | float GetFBlinkUpTime(RE::StaticFunctionTag*) 22 | { 23 | return Settings::Get().eyesBlinking.fBlinkUpTime; 24 | } 25 | 26 | void SetFBlinkUpTime(RE::StaticFunctionTag*, float a_value) 27 | { 28 | Settings::Get().eyesBlinking.fBlinkUpTime = a_value; 29 | } 30 | 31 | float GetFBlinkDelayMin(RE::StaticFunctionTag*) 32 | { 33 | return Settings::Get().eyesBlinking.fBlinkDelayMin; 34 | } 35 | 36 | void SetFBlinkDelayMin(RE::StaticFunctionTag*, float a_value) 37 | { 38 | Settings::Get().eyesBlinking.fBlinkDelayMin = a_value; 39 | } 40 | 41 | float GetFBlinkDelayMax(RE::StaticFunctionTag*) 42 | { 43 | return Settings::Get().eyesBlinking.fBlinkDelayMax; 44 | } 45 | 46 | void SetFBlinkDelayMax(RE::StaticFunctionTag*, float a_value) 47 | { 48 | Settings::Get().eyesBlinking.fBlinkDelayMax = a_value; 49 | } 50 | 51 | float GetFTrackSpeed(RE::StaticFunctionTag*) 52 | { 53 | return Settings::Get().eyesMovement.fTrackSpeed; 54 | } 55 | 56 | void SetFTrackSpeed(RE::StaticFunctionTag*, float a_value) 57 | { 58 | Settings::Get().eyesMovement.fTrackSpeed = a_value; 59 | } 60 | 61 | float GetFTrackEyeXY(RE::StaticFunctionTag*) 62 | { 63 | return Settings::Get().eyesMovement.fTrackEyeXY; 64 | } 65 | 66 | void SetFTrackEyeXY(RE::StaticFunctionTag*, float a_value) 67 | { 68 | Settings::Get().eyesMovement.fTrackEyeXY = a_value; 69 | } 70 | 71 | float GetFTrackEyeZ(RE::StaticFunctionTag*) 72 | { 73 | return Settings::Get().eyesMovement.fTrackEyeZ; 74 | } 75 | 76 | void SetFTrackEyeZ(RE::StaticFunctionTag*, float a_value) 77 | { 78 | Settings::Get().eyesMovement.fTrackEyeZ = a_value; 79 | } 80 | 81 | float GetFEyeHeadingMinOffsetEmotionAngry(RE::StaticFunctionTag*) 82 | { 83 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionAngry; 84 | } 85 | 86 | void SetFEyeHeadingMinOffsetEmotionAngry(RE::StaticFunctionTag*, float a_value) 87 | { 88 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionAngry = a_value; 89 | } 90 | 91 | float GetFEyeHeadingMaxOffsetEmotionAngry(RE::StaticFunctionTag*) 92 | { 93 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionAngry; 94 | } 95 | 96 | void SetFEyeHeadingMaxOffsetEmotionAngry(RE::StaticFunctionTag*, float a_value) 97 | { 98 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionAngry = a_value; 99 | } 100 | 101 | float GetFEyePitchMinOffsetEmotionAngry(RE::StaticFunctionTag*) 102 | { 103 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionAngry; 104 | } 105 | 106 | void SetFEyePitchMinOffsetEmotionAngry(RE::StaticFunctionTag*, float a_value) 107 | { 108 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionAngry = a_value; 109 | } 110 | 111 | float GetFEyePitchMaxOffsetEmotionAngry(RE::StaticFunctionTag*) 112 | { 113 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionAngry; 114 | } 115 | 116 | void SetFEyePitchMaxOffsetEmotionAngry(RE::StaticFunctionTag*, float a_value) 117 | { 118 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionAngry = a_value; 119 | } 120 | 121 | float GetFEyeOffsetDelayMinEmotionAngry(RE::StaticFunctionTag*) 122 | { 123 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionAngry; 124 | } 125 | 126 | void SetFEyeOffsetDelayMinEmotionAngry(RE::StaticFunctionTag*, float a_value) 127 | { 128 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionAngry = a_value; 129 | } 130 | 131 | float GetFEyeOffsetDelayMaxEmotionAngry(RE::StaticFunctionTag*) 132 | { 133 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionAngry; 134 | } 135 | 136 | void SetFEyeOffsetDelayMaxEmotionAngry(RE::StaticFunctionTag*, float a_value) 137 | { 138 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionAngry = a_value; 139 | } 140 | 141 | float GetFEyeHeadingMinOffsetEmotionHappy(RE::StaticFunctionTag*) 142 | { 143 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionHappy; 144 | } 145 | 146 | void SetFEyeHeadingMinOffsetEmotionHappy(RE::StaticFunctionTag*, float a_value) 147 | { 148 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionHappy = a_value; 149 | } 150 | 151 | float GetFEyeHeadingMaxOffsetEmotionHappy(RE::StaticFunctionTag*) 152 | { 153 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionHappy; 154 | } 155 | 156 | void SetFEyeHeadingMaxOffsetEmotionHappy(RE::StaticFunctionTag*, float a_value) 157 | { 158 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionHappy = a_value; 159 | } 160 | 161 | float GetFEyePitchMinOffsetEmotionHappy(RE::StaticFunctionTag*) 162 | { 163 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionHappy; 164 | } 165 | 166 | void SetFEyePitchMinOffsetEmotionHappy(RE::StaticFunctionTag*, float a_value) 167 | { 168 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionHappy = a_value; 169 | } 170 | 171 | float GetFEyePitchMaxOffsetEmotionHappy(RE::StaticFunctionTag*) 172 | { 173 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionHappy; 174 | } 175 | 176 | void SetFEyePitchMaxOffsetEmotionHappy(RE::StaticFunctionTag*, float a_value) 177 | { 178 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionHappy = a_value; 179 | } 180 | 181 | float GetFEyeOffsetDelayMinEmotionHappy(RE::StaticFunctionTag*) 182 | { 183 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionHappy; 184 | } 185 | 186 | void SetFEyeOffsetDelayMinEmotionHappy(RE::StaticFunctionTag*, float a_value) 187 | { 188 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionHappy = a_value; 189 | } 190 | 191 | float GetFEyeOffsetDelayMaxEmotionHappy(RE::StaticFunctionTag*) 192 | { 193 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionHappy; 194 | } 195 | 196 | void SetFEyeOffsetDelayMaxEmotionHappy(RE::StaticFunctionTag*, float a_value) 197 | { 198 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionHappy = a_value; 199 | } 200 | 201 | float GetFEyeHeadingMinOffsetEmotionSurprise(RE::StaticFunctionTag*) 202 | { 203 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionSurprise; 204 | } 205 | 206 | void SetFEyeHeadingMinOffsetEmotionSurprise(RE::StaticFunctionTag*, float a_value) 207 | { 208 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionSurprise = a_value; 209 | } 210 | 211 | float GetFEyeHeadingMaxOffsetEmotionSurprise(RE::StaticFunctionTag*) 212 | { 213 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise; 214 | } 215 | 216 | void SetFEyeHeadingMaxOffsetEmotionSurprise(RE::StaticFunctionTag*, float a_value) 217 | { 218 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionSurprise = a_value; 219 | } 220 | 221 | float GetFEyePitchMinOffsetEmotionSurprise(RE::StaticFunctionTag*) 222 | { 223 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionSurprise; 224 | } 225 | 226 | void SetFEyePitchMinOffsetEmotionSurprise(RE::StaticFunctionTag*, float a_value) 227 | { 228 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionSurprise = a_value; 229 | } 230 | 231 | float GetFEyePitchMaxOffsetEmotionSurprise(RE::StaticFunctionTag*) 232 | { 233 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionSurprise; 234 | } 235 | 236 | void SetFEyePitchMaxOffsetEmotionSurprise(RE::StaticFunctionTag*, float a_value) 237 | { 238 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionSurprise = a_value; 239 | } 240 | 241 | float GetFEyeOffsetDelayMinEmotionSurprise(RE::StaticFunctionTag*) 242 | { 243 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionSurprise; 244 | } 245 | 246 | void SetFEyeOffsetDelayMinEmotionSurprise(RE::StaticFunctionTag*, float a_value) 247 | { 248 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionSurprise = a_value; 249 | } 250 | 251 | float GetFEyeOffsetDelayMaxEmotionSurprise(RE::StaticFunctionTag*) 252 | { 253 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionSurprise; 254 | } 255 | 256 | void SetFEyeOffsetDelayMaxEmotionSurprise(RE::StaticFunctionTag*, float a_value) 257 | { 258 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionSurprise = a_value; 259 | } 260 | 261 | float GetFEyeHeadingMinOffsetEmotionSad(RE::StaticFunctionTag*) 262 | { 263 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionSad; 264 | } 265 | 266 | void SetFEyeHeadingMinOffsetEmotionSad(RE::StaticFunctionTag*, float a_value) 267 | { 268 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionSad = a_value; 269 | } 270 | 271 | float GetFEyeHeadingMaxOffsetEmotionSad(RE::StaticFunctionTag*) 272 | { 273 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionSad; 274 | } 275 | 276 | void SetFEyeHeadingMaxOffsetEmotionSad(RE::StaticFunctionTag*, float a_value) 277 | { 278 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionSad = a_value; 279 | } 280 | 281 | float GetFEyePitchMinOffsetEmotionSad(RE::StaticFunctionTag*) 282 | { 283 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionSad; 284 | } 285 | 286 | void SetFEyePitchMinOffsetEmotionSad(RE::StaticFunctionTag*, float a_value) 287 | { 288 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionSad = a_value; 289 | } 290 | 291 | float GetFEyePitchMaxOffsetEmotionSad(RE::StaticFunctionTag*) 292 | { 293 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionSad; 294 | } 295 | 296 | void SetFEyePitchMaxOffsetEmotionSad(RE::StaticFunctionTag*, float a_value) 297 | { 298 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionSad = a_value; 299 | } 300 | 301 | float GetFEyeOffsetDelayMinEmotionSad(RE::StaticFunctionTag*) 302 | { 303 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionSad; 304 | } 305 | 306 | void SetFEyeOffsetDelayMinEmotionSad(RE::StaticFunctionTag*, float a_value) 307 | { 308 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionSad = a_value; 309 | } 310 | 311 | float GetFEyeOffsetDelayMaxEmotionSad(RE::StaticFunctionTag*) 312 | { 313 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionSad; 314 | } 315 | 316 | void SetFEyeOffsetDelayMaxEmotionSad(RE::StaticFunctionTag*, float a_value) 317 | { 318 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionSad = a_value; 319 | } 320 | 321 | float GetFEyeHeadingMinOffsetEmotionFear(RE::StaticFunctionTag*) 322 | { 323 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionFear; 324 | } 325 | 326 | void SetFEyeHeadingMinOffsetEmotionFear(RE::StaticFunctionTag*, float a_value) 327 | { 328 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionFear = a_value; 329 | } 330 | 331 | float GetFEyeHeadingMaxOffsetEmotionFear(RE::StaticFunctionTag*) 332 | { 333 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionFear; 334 | } 335 | 336 | void SetFEyeHeadingMaxOffsetEmotionFear(RE::StaticFunctionTag*, float a_value) 337 | { 338 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionFear = a_value; 339 | } 340 | 341 | float GetFEyePitchMinOffsetEmotionFear(RE::StaticFunctionTag*) 342 | { 343 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionFear; 344 | } 345 | 346 | void SetFEyePitchMinOffsetEmotionFear(RE::StaticFunctionTag*, float a_value) 347 | { 348 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionFear = a_value; 349 | } 350 | 351 | float GetFEyePitchMaxOffsetEmotionFear(RE::StaticFunctionTag*) 352 | { 353 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionFear; 354 | } 355 | 356 | void SetFEyePitchMaxOffsetEmotionFear(RE::StaticFunctionTag*, float a_value) 357 | { 358 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionFear = a_value; 359 | } 360 | 361 | float GetFEyeOffsetDelayMinEmotionFear(RE::StaticFunctionTag*) 362 | { 363 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionFear; 364 | } 365 | 366 | void SetFEyeOffsetDelayMinEmotionFear(RE::StaticFunctionTag*, float a_value) 367 | { 368 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionFear = a_value; 369 | } 370 | 371 | float GetFEyeOffsetDelayMaxEmotionFear(RE::StaticFunctionTag*) 372 | { 373 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionFear; 374 | } 375 | 376 | void SetFEyeOffsetDelayMaxEmotionFear(RE::StaticFunctionTag*, float a_value) 377 | { 378 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionFear = a_value; 379 | } 380 | 381 | float GetFEyeHeadingMinOffsetEmotionNeutral(RE::StaticFunctionTag*) 382 | { 383 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionNeutral; 384 | } 385 | 386 | void SetFEyeHeadingMinOffsetEmotionNeutral(RE::StaticFunctionTag*, float a_value) 387 | { 388 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionNeutral = a_value; 389 | } 390 | 391 | float GetFEyeHeadingMaxOffsetEmotionNeutral(RE::StaticFunctionTag*) 392 | { 393 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral; 394 | } 395 | 396 | void SetFEyeHeadingMaxOffsetEmotionNeutral(RE::StaticFunctionTag*, float a_value) 397 | { 398 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionNeutral = a_value; 399 | } 400 | 401 | float GetFEyePitchMinOffsetEmotionNeutral(RE::StaticFunctionTag*) 402 | { 403 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionNeutral; 404 | } 405 | 406 | void SetFEyePitchMinOffsetEmotionNeutral(RE::StaticFunctionTag*, float a_value) 407 | { 408 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionNeutral = a_value; 409 | } 410 | 411 | float GetFEyePitchMaxOffsetEmotionNeutral(RE::StaticFunctionTag*) 412 | { 413 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionNeutral; 414 | } 415 | 416 | void SetFEyePitchMaxOffsetEmotionNeutral(RE::StaticFunctionTag*, float a_value) 417 | { 418 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionNeutral = a_value; 419 | } 420 | 421 | float GetFEyeOffsetDelayMinEmotionNeutral(RE::StaticFunctionTag*) 422 | { 423 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionNeutral; 424 | } 425 | 426 | void SetFEyeOffsetDelayMinEmotionNeutral(RE::StaticFunctionTag*, float a_value) 427 | { 428 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionNeutral = a_value; 429 | } 430 | 431 | float GetFEyeOffsetDelayMaxEmotionNeutral(RE::StaticFunctionTag*) 432 | { 433 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionNeutral; 434 | } 435 | 436 | void SetFEyeOffsetDelayMaxEmotionNeutral(RE::StaticFunctionTag*, float a_value) 437 | { 438 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionNeutral = a_value; 439 | } 440 | 441 | float GetFEyeHeadingMinOffsetEmotionPuzzled(RE::StaticFunctionTag*) 442 | { 443 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled; 444 | } 445 | 446 | void SetFEyeHeadingMinOffsetEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 447 | { 448 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionPuzzled = a_value; 449 | } 450 | 451 | float GetFEyeHeadingMaxOffsetEmotionPuzzled(RE::StaticFunctionTag*) 452 | { 453 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled; 454 | } 455 | 456 | void SetFEyeHeadingMaxOffsetEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 457 | { 458 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionPuzzled = a_value; 459 | } 460 | 461 | float GetFEyePitchMinOffsetEmotionPuzzled(RE::StaticFunctionTag*) 462 | { 463 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionPuzzled; 464 | } 465 | 466 | void SetFEyePitchMinOffsetEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 467 | { 468 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionPuzzled = a_value; 469 | } 470 | 471 | float GetFEyePitchMaxOffsetEmotionPuzzled(RE::StaticFunctionTag*) 472 | { 473 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionPuzzled; 474 | } 475 | 476 | void SetFEyePitchMaxOffsetEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 477 | { 478 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionPuzzled = a_value; 479 | } 480 | 481 | float GetFEyeOffsetDelayMinEmotionPuzzled(RE::StaticFunctionTag*) 482 | { 483 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionPuzzled; 484 | } 485 | 486 | void SetFEyeOffsetDelayMinEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 487 | { 488 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionPuzzled = a_value; 489 | } 490 | 491 | float GetFEyeOffsetDelayMaxEmotionPuzzled(RE::StaticFunctionTag*) 492 | { 493 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled; 494 | } 495 | 496 | void SetFEyeOffsetDelayMaxEmotionPuzzled(RE::StaticFunctionTag*, float a_value) 497 | { 498 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionPuzzled = a_value; 499 | } 500 | 501 | float GetFEyeHeadingMinOffsetEmotionDisgusted(RE::StaticFunctionTag*) 502 | { 503 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted; 504 | } 505 | 506 | void SetFEyeHeadingMinOffsetEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 507 | { 508 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionDisgusted = a_value; 509 | } 510 | 511 | float GetFEyeHeadingMaxOffsetEmotionDisgusted(RE::StaticFunctionTag*) 512 | { 513 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted; 514 | } 515 | 516 | void SetFEyeHeadingMaxOffsetEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 517 | { 518 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionDisgusted = a_value; 519 | } 520 | 521 | float GetFEyePitchMinOffsetEmotionDisgusted(RE::StaticFunctionTag*) 522 | { 523 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionDisgusted; 524 | } 525 | 526 | void SetFEyePitchMinOffsetEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 527 | { 528 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionDisgusted = a_value; 529 | } 530 | 531 | float GetFEyePitchMaxOffsetEmotionDisgusted(RE::StaticFunctionTag*) 532 | { 533 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionDisgusted; 534 | } 535 | 536 | void SetFEyePitchMaxOffsetEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 537 | { 538 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionDisgusted = a_value; 539 | } 540 | 541 | float GetFEyeOffsetDelayMinEmotionDisgusted(RE::StaticFunctionTag*) 542 | { 543 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionDisgusted; 544 | } 545 | 546 | void SetFEyeOffsetDelayMinEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 547 | { 548 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionDisgusted = a_value; 549 | } 550 | 551 | float GetFEyeOffsetDelayMaxEmotionDisgusted(RE::StaticFunctionTag*) 552 | { 553 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted; 554 | } 555 | 556 | void SetFEyeOffsetDelayMaxEmotionDisgusted(RE::StaticFunctionTag*, float a_value) 557 | { 558 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionDisgusted = a_value; 559 | } 560 | 561 | float GetFEyeHeadingMinOffsetEmotionCombatAnger(RE::StaticFunctionTag*) 562 | { 563 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger; 564 | } 565 | 566 | void SetFEyeHeadingMinOffsetEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 567 | { 568 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionCombatAnger = a_value; 569 | } 570 | 571 | float GetFEyeHeadingMaxOffsetEmotionCombatAnger(RE::StaticFunctionTag*) 572 | { 573 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger; 574 | } 575 | 576 | void SetFEyeHeadingMaxOffsetEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 577 | { 578 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionCombatAnger = a_value; 579 | } 580 | 581 | float GetFEyePitchMinOffsetEmotionCombatAnger(RE::StaticFunctionTag*) 582 | { 583 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionCombatAnger; 584 | } 585 | 586 | void SetFEyePitchMinOffsetEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 587 | { 588 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionCombatAnger = a_value; 589 | } 590 | 591 | float GetFEyePitchMaxOffsetEmotionCombatAnger(RE::StaticFunctionTag*) 592 | { 593 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger; 594 | } 595 | 596 | void SetFEyePitchMaxOffsetEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 597 | { 598 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionCombatAnger = a_value; 599 | } 600 | 601 | float GetFEyeOffsetDelayMinEmotionCombatAnger(RE::StaticFunctionTag*) 602 | { 603 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger; 604 | } 605 | 606 | void SetFEyeOffsetDelayMinEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 607 | { 608 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionCombatAnger = a_value; 609 | } 610 | 611 | float GetFEyeOffsetDelayMaxEmotionCombatAnger(RE::StaticFunctionTag*) 612 | { 613 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger; 614 | } 615 | 616 | void SetFEyeOffsetDelayMaxEmotionCombatAnger(RE::StaticFunctionTag*, float a_value) 617 | { 618 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionCombatAnger = a_value; 619 | } 620 | 621 | float GetFEyeHeadingMinOffsetEmotionCombatShout(RE::StaticFunctionTag*) 622 | { 623 | return Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout; 624 | } 625 | 626 | void SetFEyeHeadingMinOffsetEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 627 | { 628 | Settings::Get().eyesMovement.fEyeHeadingMinOffsetEmotionCombatShout = a_value; 629 | } 630 | 631 | float GetFEyeHeadingMaxOffsetEmotionCombatShout(RE::StaticFunctionTag*) 632 | { 633 | return Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout; 634 | } 635 | 636 | void SetFEyeHeadingMaxOffsetEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 637 | { 638 | Settings::Get().eyesMovement.fEyeHeadingMaxOffsetEmotionCombatShout = a_value; 639 | } 640 | 641 | float GetFEyePitchMinOffsetEmotionCombatShout(RE::StaticFunctionTag*) 642 | { 643 | return Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionCombatShout; 644 | } 645 | 646 | void SetFEyePitchMinOffsetEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 647 | { 648 | Settings::Get().eyesMovement.fEyePitchMinOffsetEmotionCombatShout = a_value; 649 | } 650 | 651 | float GetFEyePitchMaxOffsetEmotionCombatShout(RE::StaticFunctionTag*) 652 | { 653 | return Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionCombatShout; 654 | } 655 | 656 | void SetFEyePitchMaxOffsetEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 657 | { 658 | Settings::Get().eyesMovement.fEyePitchMaxOffsetEmotionCombatShout = a_value; 659 | } 660 | 661 | float GetFEyeOffsetDelayMinEmotionCombatShout(RE::StaticFunctionTag*) 662 | { 663 | return Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionCombatShout; 664 | } 665 | 666 | void SetFEyeOffsetDelayMinEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 667 | { 668 | Settings::Get().eyesMovement.fEyeOffsetDelayMinEmotionCombatShout = a_value; 669 | } 670 | 671 | float GetFEyeOffsetDelayMaxEmotionCombatShout(RE::StaticFunctionTag*) 672 | { 673 | return Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout; 674 | } 675 | 676 | void SetFEyeOffsetDelayMaxEmotionCombatShout(RE::StaticFunctionTag*, float a_value) 677 | { 678 | Settings::Get().eyesMovement.fEyeOffsetDelayMaxEmotionCombatShout = a_value; 679 | } 680 | 681 | void Register() 682 | { 683 | SKSE::GetPapyrusInterface()->Register([](RE::BSScript::IVirtualMachine* a_vm) { 684 | a_vm->RegisterFunction("Save", "MFGFIX_Settings", Save); 685 | a_vm->RegisterFunction("GetFBlinkDownTime", "MFGFIX_Settings", GetFBlinkDownTime); 686 | a_vm->RegisterFunction("SetFBlinkDownTime", "MFGFIX_Settings", SetFBlinkDownTime); 687 | a_vm->RegisterFunction("GetFBlinkUpTime", "MFGFIX_Settings", GetFBlinkUpTime); 688 | a_vm->RegisterFunction("SetFBlinkUpTime", "MFGFIX_Settings", SetFBlinkUpTime); 689 | a_vm->RegisterFunction("GetFBlinkDelayMin", "MFGFIX_Settings", GetFBlinkDelayMin); 690 | a_vm->RegisterFunction("SetFBlinkDelayMin", "MFGFIX_Settings", SetFBlinkDelayMin); 691 | a_vm->RegisterFunction("GetFBlinkDelayMax", "MFGFIX_Settings", GetFBlinkDelayMax); 692 | a_vm->RegisterFunction("SetFBlinkDelayMax", "MFGFIX_Settings", SetFBlinkDelayMax); 693 | a_vm->RegisterFunction("GetFTrackSpeed", "MFGFIX_Settings", GetFTrackSpeed); 694 | a_vm->RegisterFunction("SetFTrackSpeed", "MFGFIX_Settings", SetFTrackSpeed); 695 | a_vm->RegisterFunction("GetFTrackEyeXY", "MFGFIX_Settings", GetFTrackEyeXY); 696 | a_vm->RegisterFunction("SetFTrackEyeXY", "MFGFIX_Settings", SetFTrackEyeXY); 697 | a_vm->RegisterFunction("GetFTrackEyeZ", "MFGFIX_Settings", GetFTrackEyeZ); 698 | a_vm->RegisterFunction("SetFTrackEyeZ", "MFGFIX_Settings", SetFTrackEyeZ); 699 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionAngry", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionAngry); 700 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionAngry", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionAngry); 701 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionAngry", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionAngry); 702 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionAngry", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionAngry); 703 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionAngry", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionAngry); 704 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionAngry", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionAngry); 705 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionAngry", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionAngry); 706 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionAngry", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionAngry); 707 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionAngry", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionAngry); 708 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionAngry", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionAngry); 709 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionAngry", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionAngry); 710 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionAngry", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionAngry); 711 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionHappy", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionHappy); 712 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionHappy", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionHappy); 713 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionHappy", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionHappy); 714 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionHappy", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionHappy); 715 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionHappy", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionHappy); 716 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionHappy", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionHappy); 717 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionHappy", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionHappy); 718 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionHappy", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionHappy); 719 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionHappy", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionHappy); 720 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionHappy", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionHappy); 721 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionHappy", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionHappy); 722 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionHappy", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionHappy); 723 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionSurprise", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionSurprise); 724 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionSurprise", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionSurprise); 725 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionSurprise", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionSurprise); 726 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionSurprise", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionSurprise); 727 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionSurprise", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionSurprise); 728 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionSurprise", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionSurprise); 729 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionSurprise", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionSurprise); 730 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionSurprise", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionSurprise); 731 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionSurprise", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionSurprise); 732 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionSurprise", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionSurprise); 733 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionSurprise", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionSurprise); 734 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionSurprise", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionSurprise); 735 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionSad", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionSad); 736 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionSad", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionSad); 737 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionSad", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionSad); 738 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionSad", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionSad); 739 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionSad", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionSad); 740 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionSad", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionSad); 741 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionSad", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionSad); 742 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionSad", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionSad); 743 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionSad", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionSad); 744 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionSad", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionSad); 745 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionSad", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionSad); 746 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionSad", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionSad); 747 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionFear", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionFear); 748 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionFear", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionFear); 749 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionFear", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionFear); 750 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionFear", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionFear); 751 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionFear", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionFear); 752 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionFear", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionFear); 753 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionFear", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionFear); 754 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionFear", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionFear); 755 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionFear", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionFear); 756 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionFear", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionFear); 757 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionFear", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionFear); 758 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionFear", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionFear); 759 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionNeutral", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionNeutral); 760 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionNeutral", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionNeutral); 761 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionNeutral", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionNeutral); 762 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionNeutral", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionNeutral); 763 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionNeutral", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionNeutral); 764 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionNeutral", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionNeutral); 765 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionNeutral", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionNeutral); 766 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionNeutral", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionNeutral); 767 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionNeutral", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionNeutral); 768 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionNeutral", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionNeutral); 769 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionNeutral", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionNeutral); 770 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionNeutral", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionNeutral); 771 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionPuzzled", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionPuzzled); 772 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionPuzzled", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionPuzzled); 773 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionPuzzled", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionPuzzled); 774 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionPuzzled", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionPuzzled); 775 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionPuzzled", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionPuzzled); 776 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionPuzzled", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionPuzzled); 777 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionPuzzled", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionPuzzled); 778 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionPuzzled", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionPuzzled); 779 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionPuzzled", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionPuzzled); 780 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionPuzzled", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionPuzzled); 781 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionPuzzled", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionPuzzled); 782 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionPuzzled", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionPuzzled); 783 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionDisgusted", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionDisgusted); 784 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionDisgusted", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionDisgusted); 785 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionDisgusted", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionDisgusted); 786 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionDisgusted", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionDisgusted); 787 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionDisgusted", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionDisgusted); 788 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionDisgusted", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionDisgusted); 789 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionDisgusted", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionDisgusted); 790 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionDisgusted", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionDisgusted); 791 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionDisgusted", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionDisgusted); 792 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionDisgusted", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionDisgusted); 793 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionDisgusted", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionDisgusted); 794 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionDisgusted", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionDisgusted); 795 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionCombatAnger", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionCombatAnger); 796 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionCombatAnger", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionCombatAnger); 797 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionCombatAnger", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionCombatAnger); 798 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionCombatAnger", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionCombatAnger); 799 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionCombatAnger", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionCombatAnger); 800 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionCombatAnger", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionCombatAnger); 801 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionCombatAnger", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionCombatAnger); 802 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionCombatAnger", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionCombatAnger); 803 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionCombatAnger", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionCombatAnger); 804 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionCombatAnger", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionCombatAnger); 805 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionCombatAnger", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionCombatAnger); 806 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionCombatAnger", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionCombatAnger); 807 | a_vm->RegisterFunction("GetFEyeHeadingMinOffsetEmotionCombatShout", "MFGFIX_Settings", GetFEyeHeadingMinOffsetEmotionCombatShout); 808 | a_vm->RegisterFunction("SetFEyeHeadingMinOffsetEmotionCombatShout", "MFGFIX_Settings", SetFEyeHeadingMinOffsetEmotionCombatShout); 809 | a_vm->RegisterFunction("GetFEyeHeadingMaxOffsetEmotionCombatShout", "MFGFIX_Settings", GetFEyeHeadingMaxOffsetEmotionCombatShout); 810 | a_vm->RegisterFunction("SetFEyeHeadingMaxOffsetEmotionCombatShout", "MFGFIX_Settings", SetFEyeHeadingMaxOffsetEmotionCombatShout); 811 | a_vm->RegisterFunction("GetFEyePitchMinOffsetEmotionCombatShout", "MFGFIX_Settings", GetFEyePitchMinOffsetEmotionCombatShout); 812 | a_vm->RegisterFunction("SetFEyePitchMinOffsetEmotionCombatShout", "MFGFIX_Settings", SetFEyePitchMinOffsetEmotionCombatShout); 813 | a_vm->RegisterFunction("GetFEyePitchMaxOffsetEmotionCombatShout", "MFGFIX_Settings", GetFEyePitchMaxOffsetEmotionCombatShout); 814 | a_vm->RegisterFunction("SetFEyePitchMaxOffsetEmotionCombatShout", "MFGFIX_Settings", SetFEyePitchMaxOffsetEmotionCombatShout); 815 | a_vm->RegisterFunction("GetFEyeOffsetDelayMinEmotionCombatShout", "MFGFIX_Settings", GetFEyeOffsetDelayMinEmotionCombatShout); 816 | a_vm->RegisterFunction("SetFEyeOffsetDelayMinEmotionCombatShout", "MFGFIX_Settings", SetFEyeOffsetDelayMinEmotionCombatShout); 817 | a_vm->RegisterFunction("GetFEyeOffsetDelayMaxEmotionCombatShout", "MFGFIX_Settings", GetFEyeOffsetDelayMaxEmotionCombatShout); 818 | a_vm->RegisterFunction("SetFEyeOffsetDelayMaxEmotionCombatShout", "MFGFIX_Settings", SetFEyeOffsetDelayMaxEmotionCombatShout); 819 | 820 | return true; 821 | }); 822 | } 823 | } -------------------------------------------------------------------------------- /src/mfgfix/SettingsPapyrus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MfgFix::SettingsPapyrus 4 | { 5 | void Register(); 6 | } -------------------------------------------------------------------------------- /src/mfgfix/mfgfixinit.cpp: -------------------------------------------------------------------------------- 1 | #include "mfgfixinit.h" 2 | #include "Settings.h" 3 | #include "BSFaceGenAnimationData.h" 4 | #include "ConsoleCommands.h" 5 | #include "SettingsPapyrus.h" 6 | #include "MfgConsoleFunc.h" 7 | #include "Offsets.h" 8 | 9 | 10 | namespace MfgFix 11 | { 12 | void Init() 13 | { 14 | Settings::Get().Read(); 15 | 16 | BSFaceGenAnimationData::Init(); 17 | ConsoleCommands::Init(); 18 | 19 | // Papyrus 20 | SettingsPapyrus::Register(); 21 | MfgConsoleFunc::Register(); 22 | 23 | // Misc 24 | 25 | // allow expression change for dead npcs 26 | REL::safe_fill(Offsets::BSFaceGenAnimationData::sub_3DB770.address() + 0x004A, 0x90, 0x0D); 27 | // fix papyrus function SetExpressionOverride that didn't work with aiMood 0 28 | REL::safe_write(Offsets::Papyrus::Actor::SetExpressionOverride.address() + 0x001A, static_cast(0x9001)); 29 | REL::safe_write(Offsets::Papyrus::Actor::SetExpressionOverride.address() + 0x002A, static_cast(0x10)); 30 | // disable code that sometimes cause ctd because of missing check for null parent node 31 | REL::safe_fill(Offsets::BSFaceGenNiNode::sub_3F0C90.address() + 0x0395, 0x90, 0x0F); 32 | } 33 | } -------------------------------------------------------------------------------- /src/mfgfix/mfgfixinit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MfgFix 4 | { 5 | void Init(); 6 | } -------------------------------------------------------------------------------- /src/pch.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrelo1/mfgfix/270485ce10cbe20047b06abf27bb68553a454cff/src/pch.cpp -------------------------------------------------------------------------------- /src/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/Skyrim.h" 4 | #include "SKSE/SKSE.h" 5 | #include 6 | 7 | #define NOMINMAX 8 | #include 9 | #include "Detours/include/detours.h" 10 | 11 | using namespace std::literals; 12 | 13 | #include "version.h" -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Version 4 | { 5 | inline constexpr std::size_t MAJOR = 1; 6 | inline constexpr std::size_t MINOR = 6; 7 | inline constexpr std::size_t PATCH = 1; 8 | inline constexpr auto NAME = "1.6.1"sv; 9 | inline constexpr auto PROJECT = "mfgfix"sv; 10 | } -------------------------------------------------------------------------------- /src/version.rc: -------------------------------------------------------------------------------- 1 | #include "winres.h" 2 | 3 | VS_VERSION_INFO VERSIONINFO 4 | FILEVERSION 1,6,1,0 5 | PRODUCTVERSION 1,6,1,0 6 | FILEFLAGSMASK 0x3fL 7 | #ifdef _DEBUG 8 | FILEFLAGS 0x1L 9 | #else 10 | FILEFLAGS 0x0L 11 | #endif 12 | FILEOS 0x40004L 13 | FILETYPE 0x2L 14 | FILESUBTYPE 0x0L 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904b0" 19 | BEGIN 20 | VALUE "FileVersion", "1.6.1.0" 21 | VALUE "InternalName", "mfgfix.dll" 22 | VALUE "LegalCopyright", "MIT License" 23 | VALUE "OriginalFilename", "mfgfix.dll" 24 | VALUE "ProductName", "mfgfix" 25 | VALUE "ProductVersion", "1.6.1.0" 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END --------------------------------------------------------------------------------