A little Souvenir


Missions in Skylarks are driven by a custom scripting language called Souvenir. It began development in 2016 as a dialect of Ink, but quickly developed its own syntax and feature set influenced by Renpy and Erlang.

Here's a minimal Souvenir script:

> Hello world! 

Placing this script in assets/missions will print "Hello world!" to the in-flight message log as soon as the player starts a new game. Lines starting with > are called quotes and use a similar syntax to quote blocks in Markdown, chosen here to avoid problems with unescaped or unbalanced quotation marks.

Printing text when the game begins is not often useful. For more complex behavior, we need control flow and message handlers.

> Do the same thing
:: loop_start
> over and
-> loop_start

The line starting with :: declares a label named loop_start. The last line jumps back to this label, resulting in an infinite loop.

Running this script will quickly fill up the in-flight log, but other lines of text might appear interspersed with its output. Souvenir is designed as an actor system in which many "actors" can execute different scripts concurrently. Actor execution is timesliced so that an infinite loop can't freeze the game; in fact, each actor can only print one quote per frame.

Execution can be interrupted by messages, which are the primary means of communication in the actor model. The script below installs a message handler with the on keyword. When this script receives a message with the subject #stop_doing_that, it will jump to loop_end instead of loop_start:

> Do the same thing
:: loop_start
on #stop_doing_that
    -> loop_end
;;
> over and
-> loop_start
:: loop_end
> finally stop.

Note that jumping to a label uninstalls all handlers; the handler in this example therefore must be installed after the :: loop_start label to have any effect. Actors cannot receive messages without first installing a corresponding handler. If the game tries to send this actor a different message, such as #keep_going, it will be rejected. The game detects rejected messages and can use them for control flow. Some messages are broadcast to all actors that can receive them; others will only be sent to the first such actor. In Skylarks, the latter type of message always has a name beginning with #hook_, but this is a convention; it is not enforced by the Souvenir runtime.

Quotes can be attributed to a speaker by binding actor references to variables:

let Alice = spawn("alice.svr")
let Bob = spawn("bob.svr")
Alice > Hello world.
Bob > Right back at you.

Proper nouns are conventionally capitalized in English, so names of local variables are likewise capitalized (with Pascal-style CamelCase) in Souvenir as well. Functions and labels are instead named with snake_case. Global variables are distinguished with a sigil $, and can be named in $lower or $UPPER snake case to scope them to the player's current save file or persistent save data, respectively.

All variables must be declared before they are used. Local variables declared inside a block statement, or the body of a label, go out of scope at the end of that block. Local variables declared before a label, at the top level of a script, remain in scope for the rest of the script.

(Note: These rules are not set in stone. In the future, we may change how persistent globals work, or introduce new syntax for declaring script-scoped locals.)

Globals are usually declared with the global keyword, and automatically get a default value of 0:

global $pi 

Global variables cannot refer to entities, data structures, or arbitrary strings. By default, they can only hold integers:

$pi = 3 

Alternatively, a global can be declared as an enum, which can hold any of a predefined set of symbols:

enum $metallurgical_epoch
    #stone
    #bronze
    #iron
    #atomic
;;

The default value of an enum is the first symbol in the list. There is not currently a way to assign a custom default value to either type of global.

The values of local variables can be interpolated into quotes:

> "You've got, what, {AmmoCount} bullets? That won't be enough, {Player}." 

We plan to extend interpolation to allow more complex expressions, random phrase substitutions, and various other features.

This is just a taste so far. Some of Souvenir's most important features are not yet usable. Even the syntax is not stable. We expect to have a lot more to say about Souvenir and Skylarks in spring of 2023.

Get Skylarks

Leave a comment

Log in with itch.io to leave a comment.