2022-07-31 18:55:11 +00:00
# pragma once
# include "CheckInvalidForms.h"
# include <SimpleIni.h>
2022-09-14 17:33:20 +00:00
# include <regex>
2022-07-31 18:55:11 +00:00
inline const SKSE : : LoadInterface * GetLoadInterface ( const SKSE : : LoadInterface * loadInterface = nullptr )
{
const static SKSE : : LoadInterface * singleton ;
if ( loadInterface ) {
singleton = loadInterface ;
}
return singleton ;
}
inline uint8_t NewGameCount ( bool increment = false )
{
static uint8_t g_NewGameStarted = 0 ;
if ( increment ) {
g_NewGameStarted + + ;
}
return g_NewGameStarted ;
}
inline void CheckIncompatibleMods ( )
{
2022-09-14 17:33:20 +00:00
bool bPrinted = false ;
if ( std : : filesystem : : exists ( " Data \\ SKSE \\ Plugins \\ EnderalVersion.ini " ) ) {
CSimpleIniA ini ;
ini . SetUnicode ( false ) ;
ini . SetMultiKey ( false ) ;
ini . LoadFile ( " Data/SKSE/Plugins/EnderalVersion.ini " ) ;
const char * version = ini . GetValue ( " " , " version " , " 2.0.x " ) ;
std : : regex version_expr ( " ^[ \\ d \\ .]+$ " ) ;
if ( std : : regex_match ( version , version_expr ) ) {
RE : : ConsoleLog : : GetSingleton ( ) - > Print ( std : : format ( " Loaded SureAI's Enderal: Forgotten Stories | Special Edition v{} by Eddoursul and contributors " , version ) . c_str ( ) ) ;
bPrinted = true ;
}
}
if ( ! bPrinted ) {
RE : : ConsoleLog : : GetSingleton ( ) - > Print ( " Loaded SureAI's Enderal: Forgotten Stories | Special Edition v2.0.x by Eddoursul and contributors " ) ;
}
2022-07-31 18:55:11 +00:00
CheckWorldspaces ( ) ;
2022-08-08 11:07:07 +00:00
CheckUnconvertedMap ( ) ;
2022-07-31 18:55:11 +00:00
CheckSkyrimCells ( ) ;
CheckEnderalCells ( ) ;
2022-09-08 09:24:27 +00:00
CheckEnderalContainers ( ) ;
CheckEnderalNPCs ( ) ;
2022-09-29 20:23:14 +00:00
CheckEnderalActivators ( ) ;
CheckEnderalStatics ( ) ;
2022-07-31 18:55:11 +00:00
}
2023-10-26 19:22:14 +00:00
inline bool PapyrusGlobalFunctionExists ( const char * scriptName , const char * funcName )
{
RE : : BSTSmartPointer < RE : : BSScript : : ObjectTypeInfo > typeInfoPtr ;
RE : : BSScript : : Internal : : VirtualMachine : : GetSingleton ( ) - > GetScriptObjectType ( RE : : BSFixedString ( scriptName ) , typeInfoPtr ) ;
auto functionCount = typeInfoPtr - > GetNumGlobalFuncs ( ) ;
auto functions = typeInfoPtr - > GetGlobalFuncIter ( ) ;
for ( uint32_t i = 0 ; i < functionCount ; i + + ) {
if ( functions [ i ] . func - > GetName ( ) . c_str ( ) = = funcName ) {
return true ;
}
}
return false ;
}
inline void CheckScriptVersions ( )
{
class ScriptVersionCallback : public RE : : BSScript : : IStackCallbackFunctor
{
private :
std : : uint32_t expectedVersion ;
const RE : : BSFixedString scriptName ;
const RE : : BSFixedString funcName = " _GetScriptVersion " ;
public :
ScriptVersionCallback ( const RE : : BSFixedString a_scriptName , int a_version ) :
scriptName ( a_scriptName ) ,
expectedVersion ( a_version )
{
if ( PapyrusGlobalFunctionExists ( scriptName . c_str ( ) , funcName . c_str ( ) ) ) {
const auto vm = RE : : BSScript : : Internal : : VirtualMachine : : GetSingleton ( ) ;
auto callbackPtr = RE : : BSTSmartPointer < RE : : BSScript : : IStackCallbackFunctor > ( this ) ;
vm - > DispatchStaticCall ( scriptName , funcName , RE : : MakeFunctionArguments ( ) , callbackPtr ) ;
} else {
auto a_script = scriptName ;
auto a_version = expectedVersion ;
SKSE : : GetTaskInterface ( ) - > AddTask ( [ a_script , a_version ] ( ) {
RE : : DebugMessageBox ( std : : format ( " Script {} is overwritten by a mod, incompatible with current version of Enderal. Expected version: {}, installed version: N/A. " , a_script . c_str ( ) , a_version ) . c_str ( ) ) ;
} ) ;
}
}
void operator ( ) ( RE : : BSScript : : Variable a_result )
{
if ( a_result . GetUInt ( ) ! = expectedVersion ) {
RE : : DebugMessageBox ( std : : format ( " Script {} is overwritten by a mod, incompatible with current version of Enderal. Expected version: {}, installed version: {}. " , scriptName . c_str ( ) , expectedVersion , a_result . GetUInt ( ) ) . c_str ( ) ) ;
}
}
bool CanSave ( ) { return false ; }
void SetObject ( const RE : : BSTSmartPointer < RE : : BSScript : : Object > & ) { }
} ;
RE : : BSTSmartPointer < ScriptVersionCallback > {
new ScriptVersionCallback ( " _00E_PlayerSetUpScript " , 1 )
} ;
RE : : BSTSmartPointer < ScriptVersionCallback > {
new ScriptVersionCallback ( " _00E_Theriantrophist_AlchemyControl " , 1 )
} ;
}
2022-07-31 18:55:11 +00:00
inline void LoadINI ( std : : map < std : : string , bool > * settings , const char * iniPath )
{
for ( auto it = settings - > begin ( ) ; it ! = settings - > end ( ) ; it + + ) {
logger : : info ( " [DEFAULT] {} = {} " , it - > first , it - > second ) ;
}
if ( ! std : : filesystem : : exists ( iniPath ) ) {
logger : : warn ( " {} does not exist, using default values. " , iniPath ) ;
return ;
}
try {
CSimpleIniA ini ;
ini . SetUnicode ( false ) ;
ini . SetMultiKey ( false ) ;
ini . LoadFile ( iniPath ) ;
std : : list < CSimpleIniA : : Entry > keysList ;
ini . GetAllKeys ( " " , keysList ) ;
bool bUpdateINI = false ;
for ( auto it = settings - > begin ( ) ; it ! = settings - > end ( ) ; it + + ) {
bool bExists = false ;
for ( const auto & k : keysList ) {
if ( it - > first = = k . pItem ) {
settings - > insert_or_assign ( k . pItem , ini . GetBoolValue ( " " , k . pItem , settings - > at ( k . pItem ) ) ) ;
logger : : info ( " [INI] {} = {} " , k . pItem , settings - > at ( k . pItem ) ) ;
bExists = true ;
break ;
}
}
if ( ! bExists ) {
ini . SetBoolValue ( " " , it - > first . c_str ( ) , it - > second ) ;
bUpdateINI = true ;
}
}
if ( bUpdateINI ) {
2023-10-25 23:18:56 +00:00
logger : : info ( " New settings detected, adding to EnderalSE.ini " ) ;
2022-07-31 18:55:11 +00:00
ini . SaveFile ( iniPath ) ;
}
} catch ( const std : : exception & e ) {
2022-09-01 09:20:08 +00:00
logger : : error ( " {} " , e . what ( ) ) ;
2022-07-31 18:55:11 +00:00
}
2023-12-15 14:17:45 +00:00
}
2023-12-15 20:39:41 +00:00
inline void CloseTweenMenu ( )
{
if ( RE : : UI : : GetSingleton ( ) - > IsMenuOpen ( RE : : TweenMenu : : MENU_NAME ) ) {
using func_t = decltype ( & CloseTweenMenu ) ;
REL : : Relocation < func_t > func { REL : : RelocationID ( 51839 , 52711 ) } ;
return func ( ) ;
}
}
2023-12-19 15:58:36 +00:00
inline float ComputeNeededExpPoints ( std : : uint32_t CurrentLevel , float Slope , float Mult , float fExpAcc = 1.0f , float fExpAcc_Level20 = 1.2f , float fExpAcc_Level30 = 1.5f , float fExpAcc_Level40 = 2.0f )
{
Mult * = fExpAcc ;
if ( CurrentLevel < = 20 ) {
return pow ( CurrentLevel , Slope ) * Mult ;
}
float result = pow ( 20 , Slope ) * Mult ;
if ( CurrentLevel < = 30 ) {
return result + ( pow ( CurrentLevel , Slope ) - pow ( 20 , Slope ) ) * Mult * fExpAcc_Level20 ;
}
if ( CurrentLevel < = 40 ) {
result + = ( pow ( 30 , Slope ) - pow ( 20 , Slope ) ) * Mult * fExpAcc_Level20 ;
result + = ( pow ( CurrentLevel , Slope ) - pow ( 30 , Slope ) ) * Mult * fExpAcc_Level30 ;
return result ;
}
result + = ( pow ( 30 , Slope ) - pow ( 20 , Slope ) ) * Mult * fExpAcc_Level20 ;
result + = ( pow ( 40 , Slope ) - pow ( 30 , Slope ) ) * Mult * fExpAcc_Level30 ;
result + = ( pow ( CurrentLevel , Slope ) - pow ( 40 , Slope ) ) * Mult * fExpAcc_Level40 ;
return result ;
2024-01-22 15:00:04 +00:00
}
inline std : : uint32_t GetItemCount ( RE : : TESObjectREFR * a_container , RE : : TESForm * a_form )
{
std : : int32_t iResult = 0 ;
auto invChanges = a_container - > GetInventoryChanges ( ) ;
if ( invChanges & & invChanges - > entryList ) {
for ( auto & entry : * invChanges - > entryList ) {
if ( entry & & entry - > object = = a_form ) {
if ( entry - > IsLeveled ( ) ) {
return entry - > countDelta > 0 ? entry - > countDelta : 0 ;
} else {
iResult = entry - > countDelta ;
break ;
}
}
}
}
auto container = a_container - > GetContainer ( ) ;
if ( container ) {
container - > ForEachContainerObject ( [ & ] ( RE : : ContainerObject & a_entry ) {
if ( a_entry . obj = = a_form ) {
iResult + = a_entry . count ;
return RE : : BSContainer : : ForEachResult : : kStop ;
}
return RE : : BSContainer : : ForEachResult : : kContinue ;
} ) ;
}
return iResult > 0 ? iResult : 0 ;
}
2024-01-24 17:12:06 +00:00
// Copied from Named Quicksaves by Ryan McKenzie (MIT)
inline RE : : BSFixedString GetPlayerHash ( )
{
char buf [ ] = " DEADBEEF " ;
auto saveData = RE : : BSWin32SaveDataSystemUtility : : GetSingleton ( ) ;
if ( saveData - > profileHash = = static_cast < std : : uint32_t > ( - 1 ) ) {
std : : snprintf ( buf , sizeof ( buf ) , " %08o " , 0 ) ;
} else {
std : : snprintf ( buf , sizeof ( buf ) , " %08X " , saveData - > profileHash ) ;
}
return buf ;
}
inline RE : : BSFixedString StringToHex ( RE : : BSFixedString a_string )
{
std : : string_view str ( a_string ) ;
std : : stringstream sstream ;
for ( auto ch : str ) {
sstream < < std : : uppercase < < std : : hex < < static_cast < int > ( ch ) ;
}
return sstream . str ( ) ;
}