$definemacro: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Add other uses for macros outside basics. Add boolean statements examples for macros. Tip $continue, $prepend, $append which allows to expand macros. Fixes "Macro Nesting" example)
Line 3: Line 3:
== Syntax ==
== Syntax ==


<source lang=php>
  $definemacro (macroname) [arg_name1] [arg_name2] [...] \\
  $definemacro (macroname) [arg_name1] [arg_name2] [...] \\
</source>


* Defines a string substation macro.  
* Defines a string substation macro.  
Line 12: Line 14:
== Examples ==
== Examples ==


<source lang=php>
  $definemacro testmacro seqname filename endframe \\
  $definemacro testmacro seqname filename endframe \\
  $sequence $seqname$01 $filename$ { \\
  $sequence $seqname$01 $filename$ { \\
Line 19: Line 22:
  }
  }


Then, to use the macro, do:
// Then, to use the macro, do:
  $testmacro small_flinch "npc flinch 01" 20
  $testmacro small_flinch "npc flinch 01" 20
</source>


Another example:


  $definemacro makeidlenoise idleNoiseName fileName \\
Despite [[$sequence]] and [[$animation]], macros do objectively behave to avoid repetitions. As for [[$jigglebone]] example:
  $sequence $idleNoiseName$ {\\
 
      $fileName$ \\
<source lang=php>
      subtract $idleNoiseName$ 0 \\
  $definemacro JiggleGeneric6 BoneName PitchMin PitchMax YawMin YawMax \\
      iklock lfoot 1 0 iklock rfoot 1 0 \\
  $jigglebone $BoneName$ { \\
      delta \\
  is_flexible { \\
      hidden \\
  length 64 \\
      realtime \\
  tip_mass 200 \\
  pitch_stiffness 50 \\
  pitch_damping 7 \\
  yaw_stiffness 50 \\
  yaw_damping 7 \\
  along_stiffness 100 \\
  along_damping 0 \\
  pitch_constraint $PitchMin$ $PitchMax$ \\
  yaw_constraint $YawMin$ $YawMax$ \\
  } \\
} \\
 
// then execute the above macro
$JiggleGeneric6 Hair_0 -11 16 -30 30
$JiggleGeneric6 Hair_1 -15 15 -30 30
$JiggleGeneric6 Hair_2 -15 15 -30 30
// [...]
</source>
 
 
We may use macros to create shortcuts for [[$sequence]] and [[$animation]] options. {{Tip|For this case, create and call macros inside brace brackets to avoid syntax issues}}
 
<source lang=php>
// $lockhands is a whole macro which behave as shortcut for two line ik repetition used by many viewmodels animations
$definemacro lockhands \\
{ \\
  ikrule "rhand" touch "ValveBiped.weapon_bone" usesource \\
  ikrule "lhand" touch "ValveBiped.weapon_bone" usesource \\
} \\
 
// $freehands release it ik rules, may used for reload, fridget and many other animation sequences
$definemacro freehands \\
{ \\
  ikrule "rhand" release \\
  ikrule "lhand" release \\
} \\
 
$sequence idle_1 idle loop fixuploop -15 15 { $lockhands }
 
// we $freehands for reload
$sequence reload reload3 {
  ACT_VM_RELOAD 1
  fadein 0 fadeout 0.8
  fixuploop -15 15
  frames 0 84
  { $freehands }
  }
  }
</source>
$makeidlenoise idleNoise03 "Idle03"
$makeidlenoise idleNoise04 "Idle04_v32"


== Macro Nesting ==
== Macro Nesting ==
Line 41: Line 87:
You can execute macros from within macros. This is useful if you need to execute a series of commands several times. In this example we use it to create blend spaces for each weapon.
You can execute macros from within macros. This is useful if you need to execute a series of commands several times. In this example we use it to create blend spaces for each weapon.


  $definemacro makerundirections direction weapon \\
<source lang=php>
  $animation run_$direction$ ani/run_$direction$ { \\
  $definemacro MakeRunDirection direction weapon \\
LX LY \\
  $animation a_run_$direction$ run_$direction$ LX LY worldspaceblend a_run_$weapon$_C \\
worldspaceblend a_run_$weapon$_pose \\
} \\
 
$definemacro makerun weapon activity \\
$animation a_run_$weapon$_pose ani/aimlayers/aimlayer_$weapon$ frame 5 5 \\
$makerundirections $weapon$ s \\
$makerundirections $weapon$ sw \\
$makerundirections $weapon$ w \\
$makerundirections $weapon$ nw \\
$makerundirections $weapon$ n \\
$makerundirections $weapon$ ne \\
$makerundirections $weapon$ e \\
$makerundirections $weapon$ se \\
   
   
  $animation a_run_$weapon$_C "jb3_skeleton.smd" { \\
$definemacro MakeRun weapon ACT \\
LX LY \\
  $animation a_run_$weapon$_C aimlayer_$weapon$ frame 5 5 \\
worldspaceblend a_$locomotion$_$weapon$_pose \\
$MakeRunDirection $weapon$ S \\
  } \\
$MakeRunDirection $weapon$ SW \\
  $sequence $locomotion$_$weapon$ { \\
$MakeRunDirection $weapon$ W \\
  a_run_$weapon$_SW a_run_$weapon$_S a_run_$weapon$_SE \\
$MakeRunDirection $weapon$ NW \\
  a_run_$weapon$_W a_run_$weapon$_C a_run_$weapon$_E  \\
$MakeRunDirection $weapon$ N \\
  a_run_$weapon$_NW a_run_$weapon$_N a_run_$weapon$_NE \\
$MakeRunDirection $weapon$ NE \\
  blendwidth 3 blend move_y -1 1 blend move_x -1 1 \\
  $MakeRunDirection $weapon$ E \\
  $MakeRunDirection $weapon$ SE \\
\\
$sequence run_$weapon$ { \\
  a_run_$weapon$_SW a_run_$weapon$_S a_run_$weapon$_SE \\
  a_run_$weapon$_W a_run_$weapon$_C a_run_$weapon$_E  \\
  a_run_$weapon$_NW a_run_$weapon$_N a_run_$weapon$_NE \\
  blendwidth 3 \\
blend move_x -1 1 \\
blend move_y -1 1 \\
  addlayer aimlayer_$weapon$ \\
  addlayer aimlayer_$weapon$ \\
  fadein 0.3 fadeout 0.5 loop \\
  fadein 0.3 fadeout 0.5 loop \\
  node "locomotion" \\
  node "run" \\
  $activity$ 1 \\
  $ACT$ 1 \\
} \\
} \\


  $makerun smg ACT_RUN_SMG
  $MakeRun smg     ACT_RUN_SMG
  $makerun pistol ACT_RUN_PISTOL
  $MakeRun pistol ACT_RUN_PISTOL
  $makerun crowbar ACT_RUN_CROWBAR
  $MakeRun crowbar ACT_RUN_CROWBAR
</source>


== Passing Macro Commands Down ==
== Passing Macro Commands Down ==
Line 81: Line 124:
You can also pass tokens down a macro nest. This is super useful if you want to create a top level interface for your commands, as well as creating macros that can be used with multiple skeletons.
You can also pass tokens down a macro nest. This is super useful if you want to create a top level interface for your commands, as well as creating macros that can be used with multiple skeletons.


<source lang=php>
  $definemacro makeholdtype weapon activity weights \\
  $definemacro makeholdtype weapon activity weights \\
  $makeaimlayer9frame $weapon$ \\
  $makeaimlayer9frame $weapon$ \\
Line 94: Line 138:
  $makeholdtype shotgun SHOTGUN weights_worldspaceblend
  $makeholdtype shotgun SHOTGUN weights_worldspaceblend
  $makeholdtype grenade GRENADE weights_worldspaceblend_dual
  $makeholdtype grenade GRENADE weights_worldspaceblend_dual
</source>
== Condition Statements ==
Due nature of how QC Code works, we can have a minimal [[boolean]] statements for macros with some cveats:
<source lang=php>
$definemacro GestureTouchAllLeftRightIK GestureName FileName BoneName All Left Right \\
$sequence $GestureName$ $FileName$ { \\
  if $All$  { ikrule "lhand" touch $BoneName$ usesource } \\
  if $All$  { ikrule "rhand" touch $BoneName$ usesource } \\
  if $Left$  { ikrule "lhand" touch $BoneName$ usesource } \\
  if $Left$  { ikrule "rhand" release } \\
  if $Right$ { ikrule "lhand" release } \\
  if $Right$ { ikrule "rhand" touch $BoneName$ usesource } \\
  iklock "rfoot" 1 0 iklock "lfoot" 1 0 \\
} \\
$GestureTouchAllLeftRightIK "gesture_touch_all"  gesture_fidget_00.dmx "ValveBiped.weapon_bone" 1 0 0
$GestureTouchAllLeftRightIK "gesture_touch_left"  gesture_fidget_01.dmx "ValveBiped.weapon_bone" 0 1 0
$GestureTouchAllLeftRightIK "gesture_touch_right" gesture_fidget_02.dmx "ValveBiped.weapon_bone" 0 0 1
</source>


== Caveats ==
== Caveats ==
Line 99: Line 164:
* You can not contain tokens within quotes. EX: "animations/$macroexample$_run" will not work; the compiler will read it as-is and look for "animations/$macroexample$_run.smd" instead of replacing it.
* You can not contain tokens within quotes. EX: "animations/$macroexample$_run" will not work; the compiler will read it as-is and look for "animations/$macroexample$_run.smd" instead of replacing it.
* You can use macro tokens when defining other macros as long as there is SOME text behind it. Ex: "$macroexamplecommand token1 token2 $macrotoken3$" will fail the compile with "macro expand overflow", but "$macroexamplecommand example token1 $macrotoken3$ token2" will work. You can also do "$macroexamplecommand example token1 token2 $macrotoken3$ dummy"
* You can use macro tokens when defining other macros as long as there is SOME text behind it. Ex: "$macroexamplecommand token1 token2 $macrotoken3$" will fail the compile with "macro expand overflow", but "$macroexamplecommand example token1 $macrotoken3$ token2" will work. You can also do "$macroexamplecommand example token1 token2 $macrotoken3$ dummy"
* You can use macros to define only [[$animation]] or [[$sequence]] options, however, the macro must be called inside brace brackets otherwise it can't be parsed properly.


== See also ==
== See also ==
* [[$definevariable]]
* [[$definevariable]]
* [[$continue]]
* [[$append]]
* [[$prepend]]


[[Category:QC Commands|definemacro]]__NOTOC__
[[Category:QC Commands|definemacro]]__NOTOC__

Revision as of 15:47, 24 March 2024

The $definemacro QC command defines a string substitution macro. A macro can be used as a short hand way to specify other QC commands. The macro creates a block a named block of text, that when referred to will virtually insert that text into the QC file, along with replacing the named parameters with the specified values.

Syntax

 $definemacro (macroname) [arg_name1] [arg_name2] [...] \\
  • Defines a string substation macro.
  • The macro definition begins on the next line, and all subsequent lines that end with \\ (two backslashes).
  • Arguments are referenced by surrounding them with $’s (i.e. $arg_name1$ ), and can be embedded inside of other words.
  • To use the macro, type $macroname and the next N tokens will be taken as arguments.

Examples

 $definemacro testmacro seqname filename endframe \\
 $sequence $seqname$01 $filename$ { \\
     frames 0 $endframe$ \\
     subtract $seqname$ 0 delta \\
     weightlist justbody \\
 }

 // Then, to use the macro, do:
 $testmacro small_flinch "npc flinch 01" 20


Despite $sequence and $animation, macros do objectively behave to avoid repetitions. As for $jigglebone example:

 $definemacro JiggleGeneric6 BoneName PitchMin PitchMax YawMin YawMax \\
 $jigglebone $BoneName$ { \\
  is_flexible { \\
   length 64 \\
   tip_mass 200 \\
   pitch_stiffness 50 \\
   pitch_damping 7 \\
   yaw_stiffness 50 \\
   yaw_damping 7 \\
   along_stiffness 100 \\
   along_damping 0 \\
   pitch_constraint $PitchMin$ $PitchMax$ \\
   yaw_constraint $YawMin$ $YawMax$ \\
  } \\
 } \\

 // then execute the above macro
 $JiggleGeneric6 Hair_0 -11 16 -30 30
 $JiggleGeneric6 Hair_1 -15 15 -30 30
 $JiggleGeneric6 Hair_2 -15 15 -30 30
 // [...]


We may use macros to create shortcuts for $sequence and $animation options.

Tip.pngTip:For this case, create and call macros inside brace brackets to avoid syntax issues
 // $lockhands is a whole macro which behave as shortcut for two line ik repetition used by many viewmodels animations
 $definemacro lockhands \\
 { \\
   ikrule "rhand" touch "ValveBiped.weapon_bone" usesource \\
   ikrule "lhand" touch "ValveBiped.weapon_bone" usesource \\
 } \\

 // $freehands release it ik rules, may used for reload, fridget and many other animation sequences
 $definemacro freehands \\
 { \\
   ikrule "rhand" release \\
   ikrule "lhand" release \\
 } \\

 $sequence idle_1 idle loop fixuploop -15 15 { $lockhands }

 // we $freehands for reload
 $sequence reload reload3 {
  ACT_VM_RELOAD 1
  fadein 0 fadeout 0.8
  fixuploop -15 15
  frames 0 84
  { $freehands }
 }

Macro Nesting

You can execute macros from within macros. This is useful if you need to execute a series of commands several times. In this example we use it to create blend spaces for each weapon.

 $definemacro MakeRunDirection direction weapon \\
 $animation a_run_$direction$ run_$direction$ LX LY worldspaceblend a_run_$weapon$_C \\
 
 $definemacro MakeRun weapon ACT \\
 $animation a_run_$weapon$_C aimlayer_$weapon$ frame 5 5 \\
 $MakeRunDirection $weapon$ S \\
 $MakeRunDirection $weapon$ SW \\
 $MakeRunDirection $weapon$ W \\
 $MakeRunDirection $weapon$ NW \\
 $MakeRunDirection $weapon$ N \\
 $MakeRunDirection $weapon$ NE \\
 $MakeRunDirection $weapon$ E \\
 $MakeRunDirection $weapon$ SE \\
 \\
 $sequence run_$weapon$ { \\
 	a_run_$weapon$_SW	a_run_$weapon$_S	a_run_$weapon$_SE \\
 	a_run_$weapon$_W	a_run_$weapon$_C  	a_run_$weapon$_E  \\
 	a_run_$weapon$_NW	a_run_$weapon$_N	a_run_$weapon$_NE \\
 	blendwidth 3 \\
 	blend move_x -1 1 \\
 	blend move_y -1 1 \\
 	addlayer aimlayer_$weapon$ \\
 	fadein 0.3 fadeout 0.5 loop \\
 	node "run" \\
 	$ACT$ 1 \\
 } \\

 $MakeRun smg     ACT_RUN_SMG
 $MakeRun pistol  ACT_RUN_PISTOL
 $MakeRun crowbar ACT_RUN_CROWBAR

Passing Macro Commands Down

You can also pass tokens down a macro nest. This is super useful if you want to create a top level interface for your commands, as well as creating macros that can be used with multiple skeletons.

 $definemacro makeholdtype weapon activity weights \\
 $makeaimlayer9frame $weapon$ \\
 $makeidle $weapon$ ACT_IDLE_$activity$ \\
 $MakeLocomotion run $weapon$ ACT_RUN_$activity$ $weights$ \\
 $MakeLocomotion crouch $weapon$ ACT_CWALK_$activity$ $weights$ \\
 $MakeLocomotion swim $weapon$ ACT_SWIM_$activity$ $weights$ \\

 $makeholdtype pistol_twohand PISTOL_TWOHAND weights_worldspaceblend
 $makeholdtype smg SMG weights_worldspaceblend
 $makeholdtype rifle RIFLE weights_worldspaceblend
 $makeholdtype physcannon PHYSCANNON weights_worldspaceblend
 $makeholdtype shotgun SHOTGUN weights_worldspaceblend
 $makeholdtype grenade GRENADE weights_worldspaceblend_dual

Condition Statements

Due nature of how QC Code works, we can have a minimal boolean statements for macros with some cveats:

$definemacro GestureTouchAllLeftRightIK GestureName FileName BoneName All Left Right \\
$sequence $GestureName$ $FileName$ { \\
   if $All$   { ikrule "lhand" touch $BoneName$ usesource } \\
   if $All$   { ikrule "rhand" touch $BoneName$ usesource } \\
   if $Left$  { ikrule "lhand" touch $BoneName$ usesource } \\
   if $Left$  { ikrule "rhand" release } \\
   if $Right$ { ikrule "lhand" release } \\
   if $Right$ { ikrule "rhand" touch $BoneName$ usesource } \\
   iklock "rfoot" 1 0 iklock "lfoot" 1 0 \\
 } \\

 $GestureTouchAllLeftRightIK "gesture_touch_all"   gesture_fidget_00.dmx "ValveBiped.weapon_bone" 1 0 0
 $GestureTouchAllLeftRightIK "gesture_touch_left"  gesture_fidget_01.dmx "ValveBiped.weapon_bone" 0 1 0
 $GestureTouchAllLeftRightIK "gesture_touch_right" gesture_fidget_02.dmx "ValveBiped.weapon_bone" 0 0 1

Caveats

  • You can not contain tokens within quotes. EX: "animations/$macroexample$_run" will not work; the compiler will read it as-is and look for "animations/$macroexample$_run.smd" instead of replacing it.
  • You can use macro tokens when defining other macros as long as there is SOME text behind it. Ex: "$macroexamplecommand token1 token2 $macrotoken3$" will fail the compile with "macro expand overflow", but "$macroexamplecommand example token1 $macrotoken3$ token2" will work. You can also do "$macroexamplecommand example token1 token2 $macrotoken3$ dummy"
  • You can use macros to define only $animation or $sequence options, however, the macro must be called inside brace brackets otherwise it can't be parsed properly.

See also