Scripting Actions and Animations
There are two basic things that occur in GUIs:
1. The user clicks an element that causes an action
2. The action sends commands, performs a separate script, or starts an animation
In order to make this happen, windowDefs have to contain scripts. To add scripting to a windowDef in the GUI editor, select the windowDefs and hit ctrl + Enter. Scripts are then entered in the window that pops up. Multiple scripting functions can be entered in the window, so a scripting window could contain scripts, for example, for onMouseEnter, onMouseExit, and onAction (see below for more information on specific scripting functions).
The syntax for scripting elements looks like the following example:
OnScriptElementName { command “windowname::parameter” “value” ; }
Common Script Commands
Set and Transition
The two most common script commands are set and transition. Both are used to set or change values of a windowDef flag. Scripts can change the flags of the windowDef that contains the script or other windowDefs as well. If the script is changing the flags of its own windowDef, the “windowname::flag” syntax can be dropped and only the flag is needed (see examples below).
The following are some examples with the “set” command syntax.
set “visible” “0” ;
This turns off the visibility of the windowDef that contains the script.
set “foo::visible” “1” ;
This enables the visibility of the windowDef named “foo”.
set “cmd” “close” ;
This sends a command to close the GUI.
Commands can be sent as if the user typed them into the console:
consolecmd “si_map mp/q4dm1” ;
This specific command sets the server map to be mp/q4dm1
Transition is used to change one flag value to another over time. This is often used for mouseover color changes and windowDef size changes but can be used for other cases as well. The transition command requires two values to transition between and a time to perform the transition in milliseconds.The following are some examples with the “transition” command syntax.
transition “matcolor” “1,1,1,1” “1,1,0,1” “100” ;
This transitions the color of the image in a windowDef from white to yellow over 100 milliseconds. The following performs the same function but only transitions the windowDef's alpha color:
transition “matcolor_w” “1” “0” “100” ;
The following transitions the size of a windowDef from 640 x 480 to 300 x 300 over 500 milliseconds.
transition “rect” “0,0,640,480” “0,0,300,300” “500” ;
setFocus
setFocus is used mostly in console menus. This command is used to set the mouse focus of a specific windowDef. The syntax is as follows:
setFocus “windowname” ;
Stoptransitions
The stoptransitions command is used to halt an animation or transition. This is similar to setting the notime flag, but the main difference is that setting notime will allow the animation to finish all of its onTime steps, whereas stoptransitions will break out of the onTime or the transition statements altogether. The following example illustrates its context:
windowDef button1 { rect 0,0,100,100 visible 1 onMouseEnter { // highlights the button transition "matcolor_w" "0.5" "1" "150" ; } onMouseExit { // unhighlights the button transition "matcolor_w" "1" "0.5" "150" ; } onAction { // halts all animations and transitions when the player selects the button stoptransitions "button1" ; } }
Noninteractive
The noninteractive command is used to make the entire GUI noninteractive until the flag has been set to 0, making it interactive again:
Noninteractive "1" ;
Scripting Functions
onMouseEnter
Specifies actions to happen when the player mouses over the windowDef.
onMouseExit
Specifies actions to happen when the player mouses out of the windowDef.
onAction
Specifies actions to happen when the player clicks on the windowDef.
onESC
Usually defined in the Desktop (for console menus, this is also defined in other windowDefs). Defines the actions to be performed when the player hits the ESC key. (For Xenon menus where this is used in windowDefs, it defines the actions to happen when the player hits the B button.)
onNamedEvent
- Defines the actions to be performed when a named event is called. The named event can be defined in the Desktop or it can be a named event in the code that gets called by the GUI.
OnJoyUp, onJoyDown, onJoyRight, onJoyLeft
- Used for Xbox 360 GUIs. Defines the actions to happen when the player uses the D-pad.
onJoyButton1, onJoyButton2, onJoyRShoulder, onJoyLShoulder
- Used for Xbox 360 GUIs. Defines the actions to happen when the player presses the X button, the Y button, the right shoulder and left shoulder buttons respectively.
onJoyBack
- Used for console GUIs. This is a more generic version of the onESC script and is executed when the player presses the B button on the controller.
Scripting Function Syntax
The following example shows what a scripting window might look like for a windowDef that will perform actions when the player mouses over it, away from it, and presses it, causing two commands to perform:
windowDef button1 { rect 0,0,200,100 visible 1 backcolor 1,1,0,1 text "button 1" textscale 0.26 font "fonts/lowpixel" onMouseEnter { transition “button1::backcolor” “1,1,0,1” “1,1,1,1” “100” ; } onMouseExit { transition “button1::backcolor” “1,1,1,1” “1,1,0,1” “100” ; } onAction { set “cmd” "play guisound_beep2; runscript map_hangar1::fire " ; } }
onTime and Animations
GUIs often use animations to transition between screens or to animate background elements, and in the Quake 4 GUI system onTime is used to define animations that will occur in specified time steps. onTime is used just like any other scripting element in a windowDef:
windowDef foo { rect 0,0,1,1 visible 0 notime 0 onTime 0 { // statements here to execute } }
Note: windowDefs do not have to be visible for their onTime scripts to run. It's common to house animations in small windowDefs with rect properties set to 0,0,1,1, make them invisible, and then use the resettime command to make them run (see resettime below).
The syntax can be written in one of two ways. The following two examples both do the same thing: they cause “foo”’s backcolor to change from white with full alpha to white with zero alpha, then back to full alpha, then back to zero alpha, and finally back to full alpha.
Example 1
onTime 0 { transition “foo::backcolor_w” “1” “0” “100” ; } onTime 100 { transition “foo::backcolor_w” “0” “1” “100” ; } onTime 200 { transition “foo::backcolor_w” “1” “0” “100” ; } onTime 300 { transition “foo::backcolor_w” “0” “1” “100” ; }
Example 2
OnTime 0 { transition “foo::backcolor_w” “1” “0” “100” ; } onTime +100 { transition “foo::backcolor_w” “0” “1” “100” ; } onTime +100 { transition “foo::backcolor_w” “1” “0” “100” ; } onTime +100 { transition “foo::backcolor_w” “0” “1” “100” ; }
In the first example, the times are hard-defined in the scripting. In the second example, each onTime performs its next action +X seconds after the previously defined action. Deciding which syntax to use depends on what you want to accomplish. The second type of syntax is usually easier to use for very large animations where you may need to tweak individual time steps and it would be inconvenient to adjust all of the times in your onTime script.
Animations can be looped through the resettime command. The resettime command can be used at the end of an onTime script or it can be sent from another script just like the set command. When used outside of the animation loop itself, such as from another windowDef, the resettime command will start an animation from the beginning.
The following is an example of the “white full alpha to white with zero alpha” animation looped with the resettime command:
onTime 0 { transition “windowname::backcolor” “1,1,1,1” “1,1,10” “100” ; } onTime 100 { transition “windowname::backcolor” “1,1,1,0” “1,1,1,1” “100” ; } onTime 200 { resettime “0” ; }
The following example would reset the time of an animation in a windowDef named "foo" from another windowDef's onAction script:
onAction { resettime “foo” “0” ; }
Looping animations can also be stopped with the notime flag. If you want an animation to stop when the player clicks on a windowDef somewhere in the GUI, the syntax would be as follows:
onAction { set “windowname::notime” “1” ; }
notime can also be set as a windowDef's flag to keep the animation from running until the resettime command has been issued:
windowDef animation_alpha { rect 0,0,1,1 visible 0 notime 1 onTime 0 { transition "foo::matcolor_w" "1" "0" "100" ; } }
If Statements
If and else if statements can be used in the GUI system. Their syntax is basic. The following example uses an if statement to check a desktop float and then executes a command based on that value:
if ("desktop::float1" == 0) { set "foo::backcolor" "1,0,0,1" ; } else if("desktop::float1" == 1) { set "foo::backcolor" "1,1,1,1" ; } else { set "foo::backcolor" "1,1,0,1" ; }
If statements can be more advanced and check for ranges of values as well. You can check for values greater than, less than, or greater/less than Or == to values. You can also check for Not values as well. Greater than or equal to is represented by >= while Not equal to is represented by != Here is an example of advanced value checking.
if ("desktop::float1" >= 5) { set "foo::backcolor" "1,0,0,1" ; } else if("desktop::float1" <= 2) { set "foo::backcolor" "1,1,1,1" ; } else if("desktop::float1" != 8) { set "foo::backcolor" "1,0,1,1" ; } else { set "foo::backcolor" "1,1,0,1" ; }
They can also be used to check And cases and Or cases. And cases are sets of checks seperated by && while Or cases are seperated by ||
if ("desktop::float1" == 0 && "desktop::float2" == 0) { set "foo::backcolor" "1,0,0,1" ; } else if ("desktop::float1" == 2 || "desktop::float2" == 2 || "desktop::float3" == 2) { set "foo::backcolor" "1,1,1,1" ; } else { set "foo::backcolor" "1,1,0,1" ; }