From 30fc0f1eaf3721f255f2eaf2abb0db33f3a66c98 Mon Sep 17 00:00:00 2001 From: Norbyte Date: Wed, 16 Oct 2019 19:16:49 +0200 Subject: [PATCH] Add CharacterGetPermanentBoost and CharacterSetPermanentBoost APIs --- APIDocs.md | 35 ++++++++- OsiInterface/Functions/CharacterFunctions.cpp | 73 +++++++++++++++++++ OsiInterface/Functions/FunctionLibrary.cpp | 1 + OsiInterface/Functions/FunctionLibrary.h | 1 + OsiInterface/OsiInterface.vcxproj | 1 + OsiInterface/OsiInterface.vcxproj.filters | 3 + 6 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 OsiInterface/Functions/CharacterFunctions.cpp diff --git a/APIDocs.md b/APIDocs.md index a3b3f0b9..a62bfca6 100644 --- a/APIDocs.md +++ b/APIDocs.md @@ -500,6 +500,37 @@ Updates the total lifetime of the specified game action. ** TODO Documentation ** +# Character functions + +## Permanent Boosts +Permanent Boosts are stat bonuses or stat reductions that are applied to an item. They are permanent, i.e. are stored in the savegame. + +The following stats are supported: SummonLifelinkModifier, Strength, Memory, Intelligence, Movement, MovementSpeedBoost, Finesse, Wits, Constitution, FireResistance, EarthResistance, WaterResistance, AirResistance, PoisonResistance, ShadowResistance, Willpower, Bodybuilding, PiercingResistance, PhysicalResistance, CorrosiveResistance, MagicResistance, CustomResistance, Sight, Hearing, FOV, APMaximum, APStart, APRecovery, CriticalChance, Initiative, Vitality, VitalityBoost, MagicPoints, Level, Gain, Armor, MagicArmor, ArmorBoost, MagicArmorBoost, ArmorBoostGrowthPerLevel, MagicArmorBoostGrowthPerLevel, DamageBoost, DamageBoostGrowthPerLevel, Accuracy, Dodge, MaxResistance, LifeSteal, Weight, ChanceToHitBoost, RangeBoost, APCostBoost, SPCostBoost, MaxSummons, BonusWeaponDamageMultiplier. + +**Limitations:** +Permanent boosts don't show up immediately because of how client-server communication works in the game. To ensure that boosts are visible on the client boosts must be synced by performing a no-op call to `CharacterAddAttribute`. Example: + +```c +... +NRD_CharacterGetPermanentBoostInt(_Character, "PoisonResistance", _Resistance) +AND +IntegerSum(_Resistance, 10, _NewResistance) +THEN +NRD_CharacterSetPermanentBoostInt(_Character, "PoisonResistance", _NewResistance); +CharacterAddAttribute(_Character, "Dummy", 0); // Force boost sync +``` + + +### CharacterGetPermanentBoost +`query NRD_CharacterGetPermanentBoostInt([in](CHARACTERGUID)_Character, [in](STRING)_Stat, [out](INTEGER)_Value)` + +Returns the permanent boost value applied to the specified character. `_Stat` must be one of the values listed above. + + +### CharacterSetPermanentBoost +`call NRD_CharacterSetPermanentBoostInt((CHARACTERGUID)_Character, (STRING)_Stat, (INTEGER)_Value)` + +Updates the permanent boost value of `_Stat` to the specified value . `_Stat` must be one of the values listed above. Both positive and negative boost values are supported. # Item functions @@ -604,8 +635,8 @@ Returns the permanent boost value applied to the specified item. `_Stat` must be ### ItemSetPermanentBoost -`query NRD_ItemGetPermanentBoostInt([in](ITEMGUID)_Item, [in](STRING)_Stat, [out](INTEGER)_Value)` -`query NRD_ItemGetPermanentBoostReal([in](ITEMGUID)_Item, [in](STRING)_Stat, [out](REAL)_Value)` +`call NRD_ItemSetPermanentBoostInt((GUIDSTRING)_Item, (STRING)_Stat, (INTEGER)_Value)` +`call NRD_ItemSetPermanentBoostReal((GUIDSTRING)_Item, (STRING)_Stat, (REAL)_Value)` Updates the permanent boost value of `_Stat` to the specified value . `_Stat` must be one of the values listed above. Both positive and negative boost values are supported. diff --git a/OsiInterface/Functions/CharacterFunctions.cpp b/OsiInterface/Functions/CharacterFunctions.cpp new file mode 100644 index 00000000..33bfba13 --- /dev/null +++ b/OsiInterface/Functions/CharacterFunctions.cpp @@ -0,0 +1,73 @@ +#include +#include "FunctionLibrary.h" +#include +#include "PropertyMaps.h" + +namespace osidbg +{ + namespace func + { + template + bool CharacterGetPermanentBoost(OsiArgumentDesc & args) + { + auto character = FindCharacterByNameGuid(args.Get(0).String); + if (character == nullptr) return false; + + if (character->Stats == nullptr + || character->Stats->DynamicStats == nullptr + || character->Stats->DynamicStatsEnd - character->Stats->DynamicStats < 2) { + OsiError("Character has no permanent boost stats!"); + return false; + } + + auto permanentBoosts = character->Stats->DynamicStats[1]; + return OsirisPropertyMapGet(gCharacterDynamicStatPropertyMap, permanentBoosts, args, 1, Type); + } + + template + void CharacterSetPermanentBoost(OsiArgumentDesc const & args) + { + auto character = FindCharacterByNameGuid(args.Get(0).String); + if (character == nullptr) return; + + if (character->Stats == nullptr + || character->Stats->DynamicStats == nullptr + || character->Stats->DynamicStatsEnd - character->Stats->DynamicStats < 2) { + OsiError("Character has no permanent boost stats!"); + return; + } + + auto permanentBoosts = character->Stats->DynamicStats[1]; + OsirisPropertyMapSet(gCharacterDynamicStatPropertyMap, permanentBoosts, args, 1, Type); + } + } + + void CustomFunctionLibrary::RegisterCharacterFunctions() + { + auto & functionMgr = osiris_.GetCustomFunctionManager(); + + auto characterGetPermanentBoostInt = std::make_unique( + "NRD_CharacterGetPermanentBoostInt", + std::vector{ + { "Character", ValueType::CharacterGuid, FunctionArgumentDirection::In }, + { "Stat", ValueType::String, FunctionArgumentDirection::In }, + { "Value", ValueType::Integer, FunctionArgumentDirection::Out }, + }, + &func::CharacterGetPermanentBoost + ); + functionMgr.Register(std::move(characterGetPermanentBoostInt)); + + + auto characterSetPermanentBoostInt = std::make_unique( + "NRD_CharacterSetPermanentBoostInt", + std::vector{ + { "Character", ValueType::CharacterGuid, FunctionArgumentDirection::In }, + { "Stat", ValueType::String, FunctionArgumentDirection::In }, + { "Value", ValueType::Integer, FunctionArgumentDirection::In }, + }, + &func::CharacterSetPermanentBoost + ); + functionMgr.Register(std::move(characterSetPermanentBoostInt)); + } + +} diff --git a/OsiInterface/Functions/FunctionLibrary.cpp b/OsiInterface/Functions/FunctionLibrary.cpp index 064d055d..bb9ff966 100644 --- a/OsiInterface/Functions/FunctionLibrary.cpp +++ b/OsiInterface/Functions/FunctionLibrary.cpp @@ -61,6 +61,7 @@ namespace osidbg RegisterHitFunctions(); RegisterPlayerFunctions(); RegisterItemFunctions(); + RegisterCharacterFunctions(); auto & functionMgr = osiris_.GetCustomFunctionManager(); diff --git a/OsiInterface/Functions/FunctionLibrary.h b/OsiInterface/Functions/FunctionLibrary.h index 54475342..76b45b07 100644 --- a/OsiInterface/Functions/FunctionLibrary.h +++ b/OsiInterface/Functions/FunctionLibrary.h @@ -42,6 +42,7 @@ namespace osidbg void RegisterHitFunctions(); void RegisterPlayerFunctions(); void RegisterItemFunctions(); + void RegisterCharacterFunctions(); void PostStartup(); diff --git a/OsiInterface/OsiInterface.vcxproj b/OsiInterface/OsiInterface.vcxproj index 8a323e0d..ab26621e 100644 --- a/OsiInterface/OsiInterface.vcxproj +++ b/OsiInterface/OsiInterface.vcxproj @@ -422,6 +422,7 @@ copy /Y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\Divinity + diff --git a/OsiInterface/OsiInterface.vcxproj.filters b/OsiInterface/OsiInterface.vcxproj.filters index 4f0ce079..856a8378 100644 --- a/OsiInterface/OsiInterface.vcxproj.filters +++ b/OsiInterface/OsiInterface.vcxproj.filters @@ -167,6 +167,9 @@ Source Files + + Source Files\Functions +