$definemacro: Difference between revisions
(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> | |||
$definemacro | Despite [[$sequence]] and [[$animation]], macros do objectively behave to avoid repetitions. As for [[$jigglebone]] example: | ||
$ | |||
<source lang=php> | |||
$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 | |||
// [...] | |||
</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> | |||
== 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 | <source lang=php> | ||
$animation | $definemacro MakeRunDirection direction weapon \\ | ||
$animation a_run_$direction$ run_$direction$ LX LY worldspaceblend a_run_$weapon$_C \\ | |||
$animation 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 \\ | ||
a_run_$weapon$_SW | $MakeRunDirection $weapon$ NW \\ | ||
a_run_$weapon$_W a_run_$weapon$_C a_run_$weapon$_E \\ | $MakeRunDirection $weapon$ N \\ | ||
a_run_$weapon$_NW | $MakeRunDirection $weapon$ NE \\ | ||
blendwidth 3 blend | $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 " | node "run" \\ | ||
$ | $ACT$ 1 \\ | ||
} \\ | |||
$ | $MakeRun smg ACT_RUN_SMG | ||
$ | $MakeRun pistol ACT_RUN_PISTOL | ||
$ | $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.

// $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.