Workspace (REPL)

SkookumScript commands can be typed into the Console bottom view pane which is called the “workspace window” – 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.

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

If you attempt to run commands when the simulation is not running, various game data may not be available or the commands may queue until the game starts.

Several of the script examples on this page assume that you are using the SkookumScript plug-in for Unreal Engine 4 (UE4) and the example SkookumDemo project that comes with it. See the integration notes for Unreal Engine 4 for more information.

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 the workspace window, 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

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 workspace.sk file which is displayed in the Workspace window.

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

// Select this expression (or just have the caret on the line)
// and hit F4 (to evaluate on game runtime) or Shift+F4 to
// evaluate locally on the IDE.
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

Local IDE Commands
You can also run commands directly on the Skookum IDE (and not the game runtime) by pressing Shift+F4. This is very handy for simple math and other code that can run without using the game runtime.

Don’t call any Unreal Engine routines locally on the IDE since they can only be called in the game runtime. If you do call some engine command locally on the IDE an error box will come up – just select Continue or Ignore past the errors.

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
//-----------------------------------------
// 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 World
@@world

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

// Get the player pawn
player_pawn

// Instruct RoboChar1 to path towards the player
Pawn.named("RoboChar1")._path_to_actor(player_pawn)

// Get an actor by name, and find something out about it
Actor.named("RoboChar1").transform

// Play explosion sound at a given actor location
Actor.named("TargetPoint1")._play_sound("/Game/StarterContent/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

// Then select and reset when complete
robo_reset  // Reset the robots
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
// 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
Pawn.named("RoboChar1")._path_to_actor(player_pawn)
Pawn.named("RoboChar2")._path_to_actor(player_pawn)
Pawn.named("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
  [
  Pawn.named("RoboChar1")._path_to_actor(player_pawn)
  Pawn.named("RoboChar2")._path_to_actor(player_pawn)
  Pawn.named("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
  [
  Pawn.named("RoboChar1")._path_to_actor(player_pawn)
  Pawn.named("RoboChar2")._path_to_actor(player_pawn)
  Pawn.named("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)
  Pawn.named("RoboChar1")._path_to_actor(player_pawn)
  Pawn.named("RoboChar2")._path_to_actor(player_pawn)
  Pawn.named("RoboChar3")._path_to_actor(player_pawn)
  ]
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
Code from SkookumScript intro video
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// All robots path to player simultaneously
Enemy.instances%_path_to_actor(player_pawn)
player_pawn._boom

// Random robot goes boom
Enemy.instances.any._boom

robo_reset  // Reset the robots

player_pawn.transform

[3.0 + 4.5] / 3.5

_sentry_duty
_sentry_duty(false)
sentry_action

All commands entered into the workspace window of the console are run on an instance of a Skookum World object - it is the inferred this for any command.

You can also drag and drop a .sk file onto the Skookum IDE Console workspace window to execute any code contained in the file.