Workbench (REPL) widgets

SkookumScript commands can be typed into a command console which is called the “workbench” – a form of a “read evaluate print loop” (REPL). Select commands (including multiple or part lines) and press F4 to run them while the game is connected and the simulation is running.

The initial workbench

The Workbench widgets in their initial state. Note the lock symbol on the tutorial workbench icon indicating that it is read-only.

Commands are often grown and tested in a workbench before they are wrapped up into reusable routines. People also swap around handy code snippets via chat, email, posting online, etc.

Several of the script examples on this page assume that you are using the SkookumScript Unreal Engine 4 Plugin and the example SkookumDemo project that comes with it though many of the examples will work for any project. See the Unreal Engine 4 Plugin installation and setup instructions for more information.

Ensure that the simulation is running when you evaluate commands. If the simulation is not running, various game data may not be available or the commands may queue until the game starts.

A simple command to test things out when your game is running in the UE4 editor and the game is ready to receive commands from the IDE:

player_pawn.actor_location

Paste/type the command into a workbench, have the caret on the line or select/highlight the text and hit F4. The location of the player should be printed in the log and will look something like this:

(770, -345, 322.25)

Make sure the game simulation is running when you run most Skookum commands. No game objects are created/available when just in editor mode. To get mouse control when the game has captured it and you want to use the mouse to click on the Skookum IDE, etc. - press Shift+F1 in the Unreal Editor.

Here is something a little more interesting:

// Make the player go boom
player_pawn._boom

// Make all Pawn objects go boom
Pawn.instances%_boom

Work through the “Tutorial Workbench”

Unfamiliar with SkookumScript? Take a moment and read through these examples illustrating some basic concepts of SkookumScript. These examples can be found already entered in the Tutorial Workbench on the SkookumIDE. (The examples are loaded by the Tutorial Workbench from the tutorial-workbench.sk file.)

Core SkookumScript Principles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//-----------------------------------------
// Simple Math

// Select this expression (or just have the caret on the line)
// and hit F4 (to evaluate on game runtime)
4 + 5

// The result will be printed in the IDE log window.
// Alt+Insert         - pastes the last result
// Alt+Control+Insert - copies the last result to the clipboard

// Do the same with any of these:
3.0 + 4.5
6 < 4
7 ~= 8 // Not equal
// SkookumScript has no operator precedence! Use [square]
// brackets to group sub-expressions.
[2 + 2] = 4

All commands entered into a workbench are run on an instance of the SkookumScript project’s default Master Mind object - it is the inferred this for any command. So when you execute code it looks for routines and data in the project’s default Master Mind object. Every project can have its own customized Mind object.

Variables!
1
2
3
4
5
6
7
8
// The exclamation mark ! indicates that something “new” is being
// created. This creates variable 'bob' and binds it to the
// Integer 9 and bob has the type Integer
!bob : 9
// re-assigns the value 7 to bob, bob stays an Integer  
bob := 7
// re-binds bob to "Hello World!" - bob type is now a String!
bob : "Hello World!"
Randomness, class types and lists
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// SkookumScript is a strongly typed language, BUT variables can
// have multiple possible types! The compiler will remember the
// possible types a variable can have, and make sure all types
// are always compatible

// The type of var is now <Integer|String>
// Note that when a method (function) takes no arguments, you can
// omit the parentheses: method() = method
!var: if @@random.coin_toss [42] else ["stuff"]

// Lists of stuff
{1 2 3 4 5}.reverse                // Reverses the order of this list's elements
{1 -2 3 -4}%negate                 // Applies the method 'negate' to all elements of the list, returns the result
{1 -2 3 -4}.do[item.negate]        // Runs some code - a 'closure' - on each element of the list
{1 2 3}.do[item++ unless item = 2] // unless is short for 'if not'
{3 4 5 8}.select[item.pow2?]       // Make new list based on a selection criteria (again that code in square brackets is a closure)
{3 4 5 8}.reject[item.pow2?]       // Make new list by rejecting some elements of the original list
{"A" "B" "C" "D"}.any              // Select random element from list
{3 4 5}.any?[item.pow2?]           // Test if _any_ element from list satisfies a condition
{3 4 5}.all?[item.pow2?]           // Test if _all_ element from list satisfies a condition, false here
{2 4 8}.all?[item.pow2?]           // Same, true in this case
Loops and control statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Do something four times
4.do[println("Hello World!")]
// Conditional
if 6>9 [println("Six is greater than nine!")]
// if statement can be used as an expression (so can everything)
println(if 5>4 ["Correct"] else ["Not correct"])
// "elseif"
!a: 8
if a=7  [println("a is 7")]
   a=8  [println("a is 8")]
   else [println("a is neither 7 nor 8")]
// when is another way of expressing a conditional    
println("Tail!") when @@random.coin_toss
// unless = "when not"
println("Head!") unless @@random.coin_toss
Coroutines!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//-----------------------------------------
// Coroutines are the secret sauce of SkookumScript.
// IMPORTANT: The IDE must be connected to the running game for
// this to work when hitting F4. Check in the top right corner
// that it says something like "SkookumDemo: runtime connected".

// Waits 2 seconds then returns
_wait(2)

// Waits 1 second four times and prints "Tick!" after each wait
4._do [_wait(1) println("Tick!")]

// Wait random time between .1 and 2 seconds
_wait(@@random.uniform_range(.1 2))

// Wait one simulation frame
_wait
Vector math examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//-----------------------------------------
// SkookumScript comes with built-in vector math types
// Hit Shift+Ctrl+Tab to bring up the class browser
// Check out the classes Vector2, Vector3, Vector4, Rotation,
// RotationAngles, Transform, Color

// Creates a 3D vector with x=1,y=2,z=3
// Note that commas are not required between function arguments
Vector3!xyz(1 2 3)

// Adds two vectors
Vector3!xyz(1 2 3) + Vector3!xyz(2 3 4)

// A handy class constant (static data member) of Vector3
Vector3.@@direction_up

// Creates a set of Euler angles to specify a rotation
RotationAngles!yaw_pitch_roll(60 0 0)

// A transform has a position, a rotation and a scale:
Transform!position_rotation_scale(
  Vector3!xyz(1 2 3)
  RotationAngles!yaw_pitch_roll(60 0 0).Rotation
  Vector3!xyz(1 1 1))

// We've got colors, too
Color.@@yellow
UE4 Engine bindings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//-----------------------------------------
// Ok now let's have some fun!
// NOTE: Make sure you have the project SkookumDemo running!

// Select the code below and hit F4 multiple times!!!
// Gets list of all Pawns in the world, and runs the coroutine
// _boom on them
Pawn.instances%_boom

// Click on the word _boom and hit Alt-G to see how it is
// implemented! Use your mouse previous and next buttons or
// Alt+<- Alt+-> to navigate back and fourth in the history.

// The currently active game world (or nil if the game is not running)
@@world

// Is the game running?
not @@world.nil?

// List of levels of the game world
@@world.@levels

// Get the player pawn
player_pawn

// Instruct RoboChar1 to path towards the player
Enemy@'RoboChar1'._path_to_actor(player_pawn)

// Get an actor by name, and find something out about it
// Note that if a class is not used before @ it assumes class Actor
@'RoboChar1'.transform

// Play explosion sound at a given actor location
@'TargetPoint1'._play_sound("/Game/ScriptLoaded/Audio/Explosion01.Explosion01")

// Draw text above player
player_pawn._draw_text("Play me!")

// Send random robot to player
Enemy.instances.any._path_to_actor(player_pawn)

// Play _boom effect on random enemy
Enemy.instances.any._boom

// Reset the robots to their corners
robo_reset
Time flow and concurrency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// The secret sauce of SkookumScript - elegantly and concisely
// describe concurrent and sequential behavior

//------------------------------------------
// Time flow example 1: Sequential
// Have each robot path to player one after the other
// then have player go boom.
// Select and run the next four lines
Enemy@'RoboChar1'._path_to_actor(player_pawn)
Enemy@'RoboChar2'._path_to_actor(player_pawn)
Enemy@'RoboChar3'._path_to_actor(player_pawn)
player_pawn._boom

// Then select and reset when complete
robo_reset


//------------------------------------------
// Time flow example 2: Synchronize
// Have each robot path to player simultaneously
// then have player go boom after they *all* arrive.
// Select and run the next seven lines
sync
  [
  Enemy@'RoboChar1'._path_to_actor(player_pawn)
  Enemy@'RoboChar2'._path_to_actor(player_pawn)
  Enemy@'RoboChar3'._path_to_actor(player_pawn)
  ]
player_pawn._boom

robo_reset  // Reset the robots


//------------------------------------------
// Time flow example 3: Race
// Have each robot path to player simultaneously
// then have player go boom when the *first* arrives.
// Select and run the next eight lines
race
  [
  Enemy@'RoboChar1'._path_to_actor(player_pawn)
  Enemy@'RoboChar2'._path_to_actor(player_pawn)
  Enemy@'RoboChar3'._path_to_actor(player_pawn)
  ]
Enemy.instances%path_stop // Stop movement of other robots
player_pawn._boom

robo_reset  // Reset the robots


//------------------------------------------
// Time flow example 4: Timeout
// Have each robot path to player simultaneously then
// have player go boom when the *first* arrives or when
// 1.5 seconds elapses.
// Select and run the next eight lines
race
  [
  _wait(1.5)
  Enemy@'RoboChar1'._path_to_actor(player_pawn)
  Enemy@'RoboChar2'._path_to_actor(player_pawn)
  Enemy@'RoboChar3'._path_to_actor(player_pawn)
  ]
Enemy.instances%path_stop // Stop movement of other robots
player_pawn._boom

robo_reset  // Reset the robots


//------------------------------------------
// Act on lists of objects using different timeflow

// Sequential: all robots boom one after the other then go to
// next line after the last completes
Enemy.instances._do[item._boom]

// Synchronize: All robots boom simultaneously then go to next
// line when *all* completed
Enemy.instances%_boom

// Race: All robots boom simultaneously then go to next line
// when *first* completed
Enemy.instances%>_boom


//------------------------------------------
// So here are the previous path commands rewritten using lists
// rather than specifying the robots individually.

// All robots path to player one after the other
// and boom player when last arrives
Enemy.instances._do[item._path_to_actor(player_pawn)]
player_pawn._boom

robo_reset  // Reset the robots


// All robots path to player simultaneously
// and boom player when the all arrive
Enemy.instances%_path_to_actor(player_pawn)
player_pawn._boom

robo_reset  // Reset the robots


// Have each robot path to player simultaneously
// and boom player when first arrives
Enemy.instances%>_path_to_actor(player_pawn)
player_pawn._boom

robo_reset  // Reset the robots
More UE4 examples
1
2
3
4
5
6
7
// Get averaged location of all enemies
GameLib.actor_array_average_location(Enemy.instances)

// Gets list of actors of class 'TargetPoint'
!actors: Actor{}
GameLib.all_actors_of_class(@@world TargetPoint.static_class actors)
actors

You can see more SkookumScript code examples at Rosetta Code which also shows the same examples in many other languages for comparison.