Choices DSL

Choices example

The Choices DSL is a very powerful way to give your users a choice between various options in a dedicated popup window.

  1. Getting started
  2. Syntax & basic usage
  3. Cancellable
  4. Customization
    1. Icon
    2. Title
    3. Button colors

Getting started

Some information you may need:

  • The Choices DSL requires a CommonEngine engine or a derivative/extension of said engine. It relies heavily on the choice function provided by these engines
  • While you could perfectly only use the choice function provided in CommonEngine, it is not a very pleasant experience, and does not provide many features either. You should definitely use the Choices DSL instead.

The choices DSL allows you to do two things:

  • Set a value depending on a user’s choice
  • Perform an action depending on a user’s choice

Both are very similar and only differ in how you declare the result.

Syntax & basic usage

The basic syntax of the Choices DSL is as follows:

choices {
    text { "Here are the different choices you can make" }

    choice("First choice") does {
        ...
    }
    choice("Second choice") does {
        ...
    }

    choice("Third choice") does {
        ...
    }
}

And… That’s it! You can place this bit of code in either an option’s does block, in a node’s onNodeReached block, or pretty much anywhere else.

The does block of each choice specifies what should be done when the specific choice is chosen.

You can also use the choices DSL to define a value depending on what the user chooses. Notice that the function in this case is named fromChoices and not choices

val wanted: String = fromChoices {
    text { "What do you want?" }

    choice("A smoothie") yields "smoothie"
    choice("A soda") yields "soda"
    choice("Water") yields "a glass of perfection"
}

The wanted variable will then contain either "smoothie", "soda" or "a glass of perfection". The fromChoices can be used with all object types, not just Strings: you can use it with booleans, integers, … The only requirement is that Kotlin must have a way to know which type to expect. Here, we explicitly specify the type next to the variable declaration.

Here is a more complete example which additionally shows what was chosen. Notice that, in order to access the result elsewhere, we’re using a var at the file level.

// If we're only using the choices DSL, a requireEngine call is not required.
// However, it is highly recommended so that the story fails immediately, as
// using the choices DSL effectively makes the story require a CommonEngine
val eng = requireEngine<CommonEngine>()

var whatWasChosen = "" // The default value is a string here

story {
    title = "Dilemma"
    
    node(1) {
        body { "Click on the option!" }
        option {"Click here to choose!" } does {
            whatWasChosen = fromChoices {
                text { "What do you want to have?" }
                choice("Something hot!") yields "fire"
                choice("Something cold!") yields "ice"
                choice("Something... muddy?") yields "earth"
                choice("Something breathable!") yields "air"
            }
            nodeRef(2)
        }
    }

    node(2) {
        body { "You chose $whatWasChosen!" }
    }
}

Cancellable

By default, there is no way to cancel a choices dialog. You can specify that a choices dialog box should be cancellable by adding cancellable in the choices block. If you are using choices, this is very easy:

choices {
    cancellable
    text { "Here are the different choices you can make" }

    choice("First choice") does {
        ...
    }
    ...
}

You can also specify an action to perform if the choices box is cancelled using a doIfCancelled block, although this is not required:

choices {
    cancellable
    ...
    doIfCancelled {
        ...
    }
}

If you are using fromChoices, the idea is the same, except that you have to specify a yieldIfCancelled. From our previous example:

whatWasChosen = fromChoices {
    cancellable
    text { "What do you want to have?" }
    choice("Something hot!") yields "fire"
    choice("Something cold!") yields "ice"
    choice("Something... muddy?") yields "earth"
    choice("Something breathable!") yields "air"
    yieldIfCancelled {
        "nothing, apparently"
    }
}

If you forget to specify a yieldIfCancelled, you will get an error. The rule is that fromChoices must always return some value, even if it is cancelled.

Advanced

The yields function also supports lambdas if you need some “dynamic” way of choosing which value to return, like an if. For example: choice("My choice") yields { if(something) 1 else -1 }

Customization

Options and choices boxes can be easily customized with various components in the Choices DSL.

Icon

You can add an icon to the dialog box.

choices {
    icon { ... }
    ...
}

Inside the icon block, you can either specify:

  • A String, the meaning of which depends on your player. For StoryFX, this string corresponds to an icon name from Ikonli, either from this set or this one. The string should contain what is in the “Name” column.
  • A Resource, using the usual resources["resourcename.example"] syntax, which points to an image.
  • null to indicate that there is no icon. This is the default.

Title

You can set a title for the dialog box, which will replace the default one.

choices {
    title { "My title" }
    ...
}

Button colors

You can change the background colors of the buttons, and set whether the text should be white or black.

choices {
    choice("My beautiful choice") withColor "darkred" withWhiteText true
    choice("My other choice") withColor "lime"
}

The color chosen can be any CSS color. In StoryFX, the supported named colors are listed here.

By default, withWhiteText is set to false to show black text over the background. You should set it to true if your background color is dark enough for the text to become unreadable.