Scripting

Each text-to-speech (TTS) alert, and each line of information displayed in the Timer screen, is composed of just text (in programming parlance also called a "string"). This text, or string, is often a combination of plain text and script.

For example, if you go to the Alerts screen, and tap "Alerts" at the top, then tap "Level Start", and tap "Edit", you'll see the Level Start alert is composed of a list of audio clips and TTS strings (blues riff, "Attention players!", etc.). The audio clips show the audio clip file name, and the TTS strings all start with a double quote character.

If you tap "Attention players!" and tap "Edit", you'll see the string is just:

Attention players!

This is an example of a TTS string that is just plain text with no script.

If you go back to the Edit Alert screen and tap the next TTS string, which starts with "{{ if: currentLevel.smallBlind > 0...", you'll see this TTS string is a little more complex:

{{ if: currentLevel.smallBlind > 0 }} The blinds have changed. The small blind is {{ currentLevel.smallBlind }}, and the big blind is {{ currentLevel.bigBlind }}

It is a combination of script and plain text. The script is any text inside of the double brackets {{ and }}. For example the first script block is: {{ if: currentLevel.smallBlind > 0 }}, then there is a section of plain text: "The blinds have changed. The small blind is", then another script block: {{ currentLevel.smallBlind }}, and more plain text: "and the big blind is", and finally another script block: {{ currentLevel.bigBlind }}.

There is a special format for a script block that determines whether or not the whole string is ignored or not, and that is if the script block starts with "if:". In an "if:" script block, if the script evaluates to false, zero, or nil, the whole string will be ignored — all of the plain text and script.

So, in the example above, if the expression "currentLevel.smallBlind > 0" evaluates to false, the whole TTS string will be ignored, and not spoken, or if it's a line in the Timer screen, it will not be shown.

Script blocks that do not start with "if:" are are evaluated, and the resulting value is used when speaking the TTS string (or displaying the screen in the Timer). In the example above, if the current level has a small blind of 20 and big blind of 40, the TTS system would read: "The blinds have changed. The small blind is 20, and the big blind is 40."

Here is an example used in the Timer screen's pre-game break, which shows the current seating at all tables:

{{
// Recursively builds a string of player names.
func listPlayers(players, i) {
  if i < players.count {
    s = ""
    if i > 0 { s = ", " }
    s = s + (i + 1) + "‑"
      + players[i].name
    s + listPlayers(players, i + 1)
  } else {
    ""
  }
}

// Recursively builds a string of tables and the players at each table.
func listTables(i) {
  if tables.count > i {
    t = tables[i]
    s = ""
    if t.players.count > 0 {
      s = "\\n\\n" + "⎯⎯ TABLE "
        + (i + 1) + " ⎯⎯\\n"
        + listPlayers(t.players, 0)
    }
    s + listTables(i + 1)
  } else {
    ""
  }
}

listTables(0)
}}

This example shows the use of functions, variables, if statements, and code comments. The scripting language is pretty simple — designed to be super fast at tokenizing, parsing, and evaluating the script, since for the timer screen all the scripts in the current screen are re-evaluated every time the tournament state changes, which is at least once every second when the timer is running! And, the scripting language designed to integrate closely with the Poker Timer objects.

(For more information about the Poker Timer objects that can be used in script, see Script Objects.)

The scripting language looks a bit like the Swift language (because I like Swift), but it is different in some key ways, and much much simpler. There are no statements, only expressions. An expression returns a value and can be used in place of any other expression. The curly brackets, { and }, create a sequence of expressions, and is itself an expression. Its value is what the last expression evaluates to.

Like in Swift, semicolons are not required, unless you want to have multiple expressions on the same line.

Functions are introduced with the keyword 'func'. After the keyword, there is optionally a function name (functions can be assigned to a variable, so the name is not required), and then there must be a (possibly empty) parenthesized list of argument names separated with commas. The function body is a sequence of expressions wrapped in {…}. There is no return statement (there are no statements) — the last expression evaluated in a function gives the value to return to its caller.

Even the if-then-else is an expression. In JavaScript you'd get that effect with the ternary operator:

a = foo() ? bar() : baz();             // JavaScript
a = if foo() { bar() } else { baz() }  // This scripting language

Brackets are required around the "then" expression, and the "else" expression, if it is present. When the else branch is not present and the condition is false, the result of the if expression is false. Speaking of which, false is a keyword which, along with the value 0 (or when a Poker Timer object's value is nil), denotes the only false values in the scripting language.

There's also a true keyword for completeness, but really everything which is not false will be interpreted as true in conditionals.

The supported data types are boolean (true or false), numbers (floating point), strings, and Poker Timer objects.

See the Script Objects page for more information about the Poker Timer objects that can be used in script.