Authors: Vawser
This tutorial is for Dark Souls III.
The same concepts can be applied with Elden Ring and Sekiro behavior files, however HKXPack does not currently support these two games.
For Elden Ring, you can use HKLib, this however will require a C# program to make use of the library and is not covered in this tutorial.
To complete this tutorial, the following tools are needed:
HKS: means Havok Script, these files are denoted by the .hks file extension. HavokParam: a section with a decompiled behavior file within <hkparam> tags. HavokObject: a section with a decompiled behavior file within <hkobject> tags.
A havok variable functions similarly to a variable as in any other programming language. However, it's usefulness is that it permits the transfer of information for a HavokScript (such as c0000.hks) into a Behavior file (such as the one contains in c0000.behbnd.dcx).
This allows any of the attributes used within the various Havok classes (such as HavokParam, HavokObject, HavokClipGenerator, etc) to be affected by the c0000.hks.
For example, allowing the 'playbackSpeed' attribute within a HavokClipGenerator to be altered, allowing for animation speed to be controlled within a HavokScript, allowing for dynamic modification of animation speed.
First, you will need to unpack the behavior file. During this tutorial, we will be editing the player behavior file, which is c0000.behbnd.dcx. However, this tutorial can be applied to any character behavior file.
To define a havok variable, you will need to extend four HavokParam lists within the behavior file. These are:
To do this, simply search for the word within the file. This will bring you to the list within the HavokObject. To extend each list, duplicate the last entry at the bottom of the list, and increment the numelements value by 1. Repeat as necessary if implementing more than one variable.
Additionally, you need to define the Havok Variable within the variablenameid.txt file (folder: Game/action/).
Remeber to increment the Num value at the top of the file.
Each variable info entry is represented by the following (or a variant of):
<hkobject> <hkparam name="role"> <hkobject class="hkbRoleAttribute" name="role" signature="0xfecef669"> <hkparam name="role">ROLE_DEFAULT</hkparam> <hkparam name="flags">FLAG_NONE</hkparam> </hkobject> </hkparam> <hkparam name="type">VARIABLE_TYPE_REAL</hkparam> </hkobject>
The function of the role attributes (“role” and “flags”) is not known, and these values remain the same within all entries: ROLE_DEFAULT and FLAG_NONE
The function of the typing attribute (type) is to define the data type of the variable. The following data types are used:
VARIABLE_TYPE_REAL VARIABLE_TYPE_INT8 VARIABLE_TYPE_INT16 VARIABLE_TYPE_INT32 VARIABLE_TYPE_BOOL VARIABLE_TYPE_POINTER VARIABLE_TYPE_VECTOR4 VARIABLE_TYPE_QUATERNION
In most cases you will either want VARIABLE_TYPE_REAL for a decimal/float number, or one of the VARIABLE_TYPE_INT types.
Each variable bounds entry is represented by the following (or a variant of):
<hkobject> <hkparam name="min"> <hkobject class="hkbVariableValue" name="min" signature="0xb99bd6a"> <hkparam name="value">0</hkparam> </hkobject> </hkparam> <hkparam name="max"> <hkobject class="hkbVariableValue" name="max" signature="0xb99bd6a"> <hkparam name="value">1</hkparam> </hkobject> </hkparam> </hkobject>
The function of the “min” and “max” attributes here is to definethe minimum and maximum value the variable will support.
Each word variable value entry is represented by the following (or a variant of):
<hkobject> <hkparam name="value">0</hkparam> </hkobject>
The function of the “value” attribute here is to define the default value used by the variable.
Each variable name entry is represented by the following (or a variant of):
<hkcstring>WeaponAnimSpeed</hkcstring>
This is the string that is used within HavokScript with the SetHavokVariable command.
Having setup a Havok Variable, you now need to make use of it. To do this, you will need to create a HavokVariableBindingSet (hkbVariableBindingSet).
A variable binding set entry should look similar to the following, substituting the #ID, #MEMBERNAME and #VARINDEX text with the appropriate values.
<hkobject class="hkbVariableBindingSet" name="#ID" signature="0xe942f339"> <hkparam name="bindings" numelements="1"> <hkobject> <hkparam name="memberPath">#MEMBERNAME</hkparam> <hkparam name="variableIndex">#VARINDEX</hkparam> <hkparam name="bitIndex">255</hkparam> <hkparam name="bindingType">BINDING_TYPE_VARIABLE</hkparam> </hkobject> </hkparam> <hkparam name="indexOfBindingToEnable">-1</hkparam> </hkobject>
#ID is the ID that every havok class object requires. Make sure it is unique.
#VARINDEX is the index position of the variable string within the variableNames list.
For example, the first entry has an index of 0, the next 1, etc. This means the last entry will be (numelements - 1).
#MEMBERNAME is the attribute name (for example: 'playbackSpeed').
In some circumstances, the attribute may be nested within a sublist. To point towards such an attribute, you need to add :<index>/<attribute>, where index is the index of the Havok class object that the attribute resides in. (Example: hands:0/controlData/targetPosition).
Having defined a hkbVariableBindingSet, you can now point to it in any Havok class object by adding it's unique ID to the variableBindingSet attribute of the target Havok class object.
Here is an example of using where a Havok Variable within the name of “WeaponAnimSpeed” has been defined at the 223 index.
Added hkbVariableBindingSet:
<hkobject class="hkbVariableBindingSet" name="#14995" signature="0xe942f339"> <hkparam name="bindings" numelements="1"> <hkobject> <hkparam name="memberPath">playbackSpeed</hkparam> <hkparam name="variableIndex">223</hkparam> <hkparam name="bitIndex">255</hkparam> <hkparam name="bindingType">BINDING_TYPE_VARIABLE</hkparam> </hkobject> </hkparam> <hkparam name="indexOfBindingToEnable">-1</hkparam> </hkobject>
Usage in hkbClipGenerator:
<hkobject class="hkbClipGenerator" name="#530" signature="0xd4cc9f6"> <hkparam name="variableBindingSet">#14995</hkparam> <hkparam name="userData">0</hkparam> <hkparam name="name">a020_030000_hkx_AutoSet_00</hkparam> <hkparam name="animationBundleName"/> <hkparam name="animationName">a020_030000</hkparam> <hkparam name="triggers">null</hkparam> <hkparam name="userPartitionMask">0</hkparam> <hkparam name="cropStartAmountLocalTime">0.0</hkparam> <hkparam name="cropEndAmountLocalTime">0.0</hkparam> <hkparam name="startTime">0.0</hkparam> <hkparam name="playbackSpeed">1.0</hkparam> <hkparam name="enforcedDuration">0.0</hkparam> <hkparam name="userControlledTimeFraction">0.0</hkparam> <hkparam name="animationBindingIndex">65535</hkparam> <hkparam name="mode">MODE_SINGLE_PLAY</hkparam> <hkparam name="flags">0</hkparam> </hkobject>
You should now:
Having done the following, the Havok Variable is now in place for usage within the c0000.hks file.
For exaple, you can now add the following code to set the animation speed of all hkbClipGenerators that make use of the hkbVariableBindingSet that targets playbackSpeed and uses the WeaponAnimSpeed variable.
SetVariable("WeaponAnimSpeed", 0.5)
This will multiple the playbackSpeed of all the hkbClipGenerators that use the hkbVariableBindingSet we setup by 0.5, causing them to play at 50% speed.
You can then combine this with conditions to create new in-game effects, here for example a ring could provide +10% weapon swing speed:
--- 111121 is the SpEffect given by the ring if env(GetSpEffectID, 111121) == TRUE then SetVariable("WeaponAnimSpeed", 1.1) end