This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| topic:havok_behavior_editing [2025/02/25 15:07] – admin | topic:havok_behavior_editing [2025/02/27 00:44] (current) – admin | ||
|---|---|---|---|
| Line 89: | Line 89: | ||
| The env function gets info about the character from the game, it has the following syntax: | The env function gets info about the character from the game, it has the following syntax: | ||
| - | < | + | < |
| env(ID, args) | env(ID, args) | ||
| </ | </ | ||
| Line 103: | Line 103: | ||
| The function has the following syntax: | The function has the following syntax: | ||
| - | < | + | < |
| act(ID, args) | act(ID, args) | ||
| </ | </ | ||
| Line 114: | Line 114: | ||
| Most basic onUpdate functions have the following form: | Most basic onUpdate functions have the following form: | ||
| - | < | + | < |
| function SMSIName_onUpdate() | function SMSIName_onUpdate() | ||
| if SomeCommonFunction(args) == TRUE then | if SomeCommonFunction(args) == TRUE then | ||
| Line 126: | Line 126: | ||
| As an example the first one-handed r1 attack: | As an example the first one-handed r1 attack: | ||
| - | < | + | < |
| function AttackRightLight1_onUpdate() | function AttackRightLight1_onUpdate() | ||
| if AttackCommonFunction(" | if AttackCommonFunction(" | ||
| Line 159: | Line 159: | ||
| Once we have opened the behavior file we will want to find the CustomManualSelectorGenerator, | Once we have opened the behavior file we will want to find the CustomManualSelectorGenerator, | ||
| - | < | + | < |
| <hkparam name=" | <hkparam name=" | ||
| </ | </ | ||
| Line 165: | Line 165: | ||
| Thus an effective method for finding the CMSG you want is searching for: | Thus an effective method for finding the CMSG you want is searching for: | ||
| - | < | + | < |
| " | " | ||
| </ | </ | ||
| Line 194: | Line 194: | ||
| Here is the final version of our new hkbClipGenerator: | Here is the final version of our new hkbClipGenerator: | ||
| - | < | + | < |
| < | < | ||
| <hkparam name=" | <hkparam name=" | ||
| Line 285: | Line 285: | ||
| To finish setting up our new attack behavior we will set up its onUpdate function and trigger it from the onUpdate function of the preceding attack, which looks like this: | To finish setting up our new attack behavior we will set up its onUpdate function and trigger it from the onUpdate function of the preceding attack, which looks like this: | ||
| - | < | + | < |
| function AttackRightLight3_onUpdate() | function AttackRightLight3_onUpdate() | ||
| if AttackCommonFunction(" | if AttackCommonFunction(" | ||
| Line 297: | Line 297: | ||
| As we can see it consists of a single function call to AttackCommonFunction which has the following arguments: | As we can see it consists of a single function call to AttackCommonFunction which has the following arguments: | ||
| - | < | + | < |
| AttackCommonFunction(r1, | AttackCommonFunction(r1, | ||
| </ | </ | ||
| Line 307: | Line 307: | ||
| The [#env env] to check for the override tae section of the player' | The [#env env] to check for the override tae section of the player' | ||
| - | < | + | < |
| env(" | env(" | ||
| </ | </ | ||
| Line 313: | Line 313: | ||
| Since this is a right hand attack we want to get the right hand weapon' | Since this is a right hand attack we want to get the right hand weapon' | ||
| - | < | + | < |
| function AttackRightLight3_onUpdate() | function AttackRightLight3_onUpdate() | ||
| local r1 = " | local r1 = " | ||
| Line 329: | Line 329: | ||
| For two handed attacks, you need to account for the possibility of the player two-handing their left hand weapon, which can be accomplished using the following code: | For two handed attacks, you need to account for the possibility of the player two-handing their left hand weapon, which can be accomplished using the following code: | ||
| - | < | + | < |
| local hand = HAND_RIGHT | local hand = HAND_RIGHT | ||
| if c_Style == HAND_LEFT_BOTH then | if c_Style == HAND_LEFT_BOTH then | ||
| Line 338: | Line 338: | ||
| Now we want to set up the onUpdate function for our new behavior. Make sure to use the name of its hkbStateMachineStateInfo along with the " | Now we want to set up the onUpdate function for our new behavior. Make sure to use the name of its hkbStateMachineStateInfo along with the " | ||
| - | < | + | < |
| function AttackRightLight4_onUpdate() | function AttackRightLight4_onUpdate() | ||
| if AttackCommonFunction(" | if AttackCommonFunction(" | ||
| Line 391: | Line 391: | ||
| Looking at common_define we can see that each actionId has three corresponding global variables. One called " | Looking at common_define we can see that each actionId has three corresponding global variables. One called " | ||
| - | < | + | < |
| SWORDARTS_PARRY = 1 | SWORDARTS_PARRY = 1 | ||
| SWORDARTS_REQUEST_LEFT_PARRY = 101 | SWORDARTS_REQUEST_LEFT_PARRY = 101 | ||
| Line 399: | Line 399: | ||
| Thus for our new actionId 37 with name NewSwordArt we put the following: | Thus for our new actionId 37 with name NewSwordArt we put the following: | ||
| - | < | + | < |
| SWORDARTS_NEW = 37 | SWORDARTS_NEW = 37 | ||
| SWORDARTS_REQUEST_LEFT_NEW = 137 | SWORDARTS_REQUEST_LEFT_NEW = 137 | ||
| Line 409: | Line 409: | ||
| Unlike standard attacks, which weapon art to execute is not directly determined in onUpdate functions. Every CommonFunction calls ExecAttack, passing on its attack arguments which are set differently in each onUpdate function. ExecAttack in turn calls the GetAttackRequest function to determine which of the attacks to execute. GetAttackRequest checks which button is currently being pressed and returns the appropriate ATTACK_REQUEST, | Unlike standard attacks, which weapon art to execute is not directly determined in onUpdate functions. Every CommonFunction calls ExecAttack, passing on its attack arguments which are set differently in each onUpdate function. ExecAttack in turn calls the GetAttackRequest function to determine which of the attacks to execute. GetAttackRequest checks which button is currently being pressed and returns the appropriate ATTACK_REQUEST, | ||
| - | < | + | < |
| function GetSwordArtsRequest() | function GetSwordArtsRequest() | ||
| local style = c_Style | local style = c_Style | ||
| Line 432: | Line 432: | ||
| The variable arts_id corresponds to the actionId from the SwordArtsParam and thus our variable " | The variable arts_id corresponds to the actionId from the SwordArtsParam and thus our variable " | ||
| - | < | + | < |
| elseif request == SWORDARTS_REQUEST_RIGHT_NEW or request == SWORDARTS_REQUEST_LEFT_NEW then | elseif request == SWORDARTS_REQUEST_RIGHT_NEW or request == SWORDARTS_REQUEST_LEFT_NEW then | ||
| ExecEventAllBody(" | ExecEventAllBody(" | ||
| Line 441: | Line 441: | ||
| Finally we need to create an onUpdate function for our new weapon art, which unlike the update functions of regular attacks will call SwordArtsCommonFunction instead of AttackCommonFunction. | Finally we need to create an onUpdate function for our new weapon art, which unlike the update functions of regular attacks will call SwordArtsCommonFunction instead of AttackCommonFunction. | ||
| - | < | + | < |
| function ChargeContinue3_onUpdate() | function ChargeContinue3_onUpdate() | ||
| if SwordArtsCommonFunction(" | if SwordArtsCommonFunction(" | ||
| Line 482: | Line 482: | ||
| The function which sets the IsEnoughArtPoints variables in hks is called SetSwordArtsPointInfo. For our new followup attack, which is activated by pressing R2, we want to add the following condition under the " | The function which sets the IsEnoughArtPoints variables in hks is called SetSwordArtsPointInfo. For our new followup attack, which is activated by pressing R2, we want to add the following condition under the " | ||
| - | < | + | < |
| elseif IsNodeActive(" | elseif IsNodeActive(" | ||
| val = " | val = " | ||
| Line 531: | Line 531: | ||
| HalfBlend animations are triggered using the ExecEventHalfBlend function which has the following arguments: | HalfBlend animations are triggered using the ExecEventHalfBlend function which has the following arguments: | ||
| - | < | + | < |
| ExecEventHalfBlend(event_table, | ExecEventHalfBlend(event_table, | ||
| </ | </ | ||
| Line 539: | Line 539: | ||
| Event tables consist of the base event name and a state Id for every state machine between HalfBlend_SM and the behavior' | Event tables consist of the base event name and a state Id for every state machine between HalfBlend_SM and the behavior' | ||
| - | < | + | < |
| GESTURE_DEF0 = 22 | GESTURE_DEF0 = 22 | ||
| GESTURESTART_DEF1 = 0 | GESTURESTART_DEF1 = 0 | ||
| Line 547: | Line 547: | ||
| It is important that the stateIds are in hierarchical order because they are systematically assigned to the default state variables mentioned in the previous section by the function ExecEventHalfBlend. Looking at the ExecEventHalfBlend function we can also see the reason for the eventName naming scheme. | It is important that the stateIds are in hierarchical order because they are systematically assigned to the default state variables mentioned in the previous section by the function ExecEventHalfBlend. Looking at the ExecEventHalfBlend function we can also see the reason for the eventName naming scheme. | ||
| - | < | + | < |
| function ExecEventHalfBlend(event_table, | function ExecEventHalfBlend(event_table, | ||
| if blend_type == ALLBODY then | if blend_type == ALLBODY then | ||