Advanced Choicescript

A guide to more advanced features in the ChoiceScript programming language. Please post on the ChoiceScript forum if you have questions about this document.

Don’t Start Here!

Be sure to read our basic ChoiceScript Introduction page before reading this advanced documentation

Even More Commands

  • *image: This command inserts an image. Place the image in the “mygame” folder, and type the name of the image file, like this:

      *image beauty.jpg

    If you like, you can specify the alignment ("left", "right", or "none") after the image name, like this:

      *image beauty.jpg left

    By default, the image appears centered on a line by itself, but if you align the image left or right, the text will flow around the image. (In CSS terms, the image will "float" left or right.) If you want the image to appear left-aligned on a line by itself, use "none."

    If your image is important to understanding the story (e.g. it has words on it the player needs to read), then you should type an alternate description after the alignment. This text will be accessible to users who can't see the image, e.g. visually impaired users.

      *image beauty.jpg left Beauty
  • *line_break: Put just one line break in your text, like a <br> in HTML. Normally you shouldn't use this command; just press your Enter key twice and ChoiceScript will automatically insert a paragraph break. But ChoiceScript will automatically glue lines together unless they have a paragraph break; when you want something smaller than a paragraph break, just a single line break, use *line_break.

      So
      this
      is
      all
      one
      line.
     
      But this is a new paragraph.
     
      And this
      *line_break
      is two lines.

    That code would display like this:

    So this is all one line

    But this is a new paragraph.

    And this
    is two lines

  • *input_number: Just like *input_text, but only numbers are allowed in the text box. Specify a variable name as well as a minimum and a maximum.

      How many coins?
      *input_number coins 0 30
     
      You asked for ${coins} coins.
  • *rand: Set a variable to a random number. You set the minimum and maximum, we do the rest. For example, this would set the variable die_roll to a value from 1 to 6 inclusive:
      *rand die_roll 1 6

    Beware! Randomness can make your game much harder to test and debug, and the benefits of randomness are often overrated. From the first-time player's perspective, there's no difference between a non-random secret number and a randomized number. (The difference only becomes apparent when you play the game multiple times, which many people never do, particularly for longer games.)

    For these reasons, we recommend using randomness sparingly, perhaps even as a last resort.

  • *stat_chart: Use this command to create a table of stats, suitable for displaying when the player clicks the "Show Stats" button. This command is so complicated it deserves a page all by itself. Customizing the ChoiceScript Stats Screen

  • *bug: This command causes the game to stop and crash with a specific error message. More information is available in our guide to testing ChoiceScript games automatically.

      *if someone_murdered and (victim = "none")
        *bug Someone was murdered, but there's no victim!
  • *redirect_scene: This command behaves kinda like *goto_scene, but you can only use it on the stats screen. On the stats screen, the game is in "stats mode," and so the button at the top of the screen says "Return to the game" instead of "Stats." Stats mode is like the Matrix; it's not the real world. In stats mode, *goto_scene stays in stats mode, and it doesn't affect the main game. If you "Return to the game," you'll be right back in "game mode" in the chapter where you left off, like waking from a dream. Use *redirect_scene on the stats screen to *goto_scene in the main game.

Advanced Techniques

  • Labeled buttons: By default, *finish buttons say "Next Chapter" and *page_break buttons say "Next". You can make the button say something else, instead:

      *page_break On with the show!
      *finish The show is over!

    We recommend no more than five words on button titles; more than that looks really weird on the screen, particularly on mobile screens.

  • More Conditional options: In addition to using *if on each line, you can also use nested blocks of conditionals. This technique is pretty advanced, because it's hard to get the indentation exactly right.

      *choice
        #Rattle my saber.
          They rattle back.
          *finish
        *if republican
          *if president
            #Declare open war.
              Congress refuses to approve funding.
              *finish
          *else
            #Ask other Republicans to help out.
              Talk radio is on your side.
              *finish
        *else
          *if president
            #Work with the United Nations.
              Russia vetoes your plan.
              *finish
          *else
            #Ask other Democrats to help out.
              They do their best, but the party is divided.
              *finish
    

  • *hide/disable_reuse Globally

    You can make all options non-reusable, by adding *hide_reuse or *disable_reuse to the top of your ChoiceScript file. Then you can use the *allow_reuse command to allow certain options to be reused.

      *hide_reuse
      *label start
      *choice
        #One.
          The loneliest number that you'll ever do.
          *goto start
        #Two.
          Two can be as bad as one.
          *goto start
        *allow_reuse #I can't decide!
          Well, think it over.
          *goto start
        #Done.
          OK!
          *finish
    

  • Integer math: You can round a variable to the nearest integer using round(). For example, this will set the variable "foo" to 3: *set foo round(2.5)

    You can also use the modulo operator calculate the remainder after taking a division. Modulo is pretty weird, but it's has two particularly interesting uses. First, you can check whether a number X is evenly divisible by a number Y by checking whether X modulo Y = 0. Second, you can use it to get the fractional part of a number X, the stuff that comes after the decimal point, by calculating X modulo 1. For example, 3.14 modulo 1 = 0.14.

  • Exponents and logarithms: You can use exponents like this: *set foo 3^7. That will set foo to 2,187 (three to the seventh power).

    You can also compute a logarithm (base 10) like this: *set foo log(1000). (You can always divide to use a different logarithm base e.g. *set foo log(2187)/log(3))

  • Text tricks:
    • Capitalize: You can capitalize just the first letter of a variable like this: Behold! $!{He} is capitalized. You can also capitalize an entire word like this: PRESIDENT $!!{name} RESIGNS IN SHAME
    • Bold and italic: You can write text in bold or italic like this: This is [b]bold[/b] and this is [i]italic[/i].
    • Using ${} in quoted strings: You can use variables in quoted strings, like this: *set name "Dr. ${last_name}"
    • Concatenation: You can join text together like this: *set murder "red"&"rum"..
    • Quotes: You can put quotes in your text by using backslashes, like this:
        *set joke "she said it was \"ironic\"!"

      If you write ${joke}, you'll get:

      she said it was "ironic"!

    • Backslashes: You can put backslashes in your text by using even more backslashes, like this:
        *set slashy "Here's one backslash: \\ and here's two backslashes: \\\\"

      If you write ${slashy}, you'll get:

      Here's one backslash: \ and here's two backslashes: \\

    • *print: This command is no longer necessary; it just prints the value of the variable you specify. Use ${} variable substitution instead.
    • Characters: You can extract the characters (letters/numerals) out of a variable, like this:
        *temp word "xyzzy"
        *temp first_letter word#1
        *temp second_letter word#2
        The first letter of the word "${word}" is ${first_letter} and the second letter of the word is ${second_letter}.

    • Counting characters: You can count the number of characters in a word like this:
        *temp word "plough"
        *temp word_length length(word)
        *temp last_letter word#word_length
        The word "${word}" is ${word_length} letters long, and so its last letter is ${last_letter}.

  • Goto label in another scene: You can use the *goto_scene label to go to a specific label in another scene, like this:

      *goto_scene invitations cordial

    That would go to the invitations.txt file and automatically *goto cordial at the start of the file.

  • Subroutines: Instead of the *goto command, you can use the *gosub command to go to a label, and then use the *return command to jump back to the line where you called *gosub.

      *choice
        #Happy.
          You're happy!
          *gosub saying
          Hopefully, you'll be happy for a very long time!
          *finish
        #Sad.
          You're sad.
          *gosub saying
          Maybe you'll be happier soon!
          *finish
      *label saying
      This, too, shall pass.
      *return
    

    If you choose "Happy," the game will write:

    You're happy! This, too, shall pass. Hopefully, you'll be happy for a very long time!

    It's great for snippets of code that you would have copied and pasted all over the place.

    "Subroutines" are tiny sub-programs that you run in the middle of your program. *gosub is so-called because it activates a subroutine. It is possible to nest subroutines, by using *gosub twice or more before using *return command.

      Start One,
      *gosub two
      End One.
      *finish
     
      *label two
      Start Two,
      *gosub three
      End Two.
      *return
     
      *label three
      Three.
      *return

    That code would display:

    Start One, Start Two, Three. End Two. End One.

    You can also use *gosub_scene to visit another scene file and then *return to the point where you left off. Like *goto_scene, you can also use *gosub_scene to visit a specific label in another file and then *return from it when you're finished.

      *gosub_scene invitations cordial

    WARNING: Generally speaking, the simpler your ChoiceScript is, the better. It's possible to abuse *gosub and *gosub_scene to create extremely complex programs. This is rarely a good idea; complex games aren't any more fun than simple games, but complex games are a lot harder to make. If you think you need a lot of subroutines, consider whether your game might be better if it were simpler.

  • Truly bizarre references: Probably only programmers will appreciate these. Beware! They add complexity without adding much value.
    • Curly parens: Put some text in curly braces and we'll turn it into the value of the named variable.

        *set honesty 30
        *set virtue "honesty"
        *set score {virtue}
        Your ${virtue} score is ${score}

      This would print:

      Your honesty score is 30

      You could also just write: Your ${virtue} score is ${{virtue}}.

    • Set by reference: Set a variable by name, e.g. *set {"leadership"} 30 sets leadership to 30. Use it in crazy code like this:

        *set virtue "courage"
        *set {virtue} 30

      This code would set courage to 30. If this still doesn't seem useful, consider that virtue could have been determined by earlier choices, so it might have set honesty to 30 instead. You can also use it with *rand, *input_text, and *input_number.

      Still not convinced? Don't worry about it; you'll probably never need it.

    • Goto a label by name:

        *temp superpower "invisibility"
        Your super power is:
        *goto {superpower}
        flight!
        *finish
        *label invisibility
        invisibility.

      You can also use this with *goto_scene and *gosub_scene. Beware that Quicktest effectively skips *goto_scene and *gosub_scene lines that use curly references. (Randomtest works fine.) If you have a file with a section that can only be reached using a curly referenced *goto_scene command, consider adding a section like this somewhere in your game, enumerating the possible destinations.

        *if false
          *gosub_scene checkpoint chap1
          *gosub_scene checkpoint chap2
          *gosub_scene checkpoint chap3


      Quicktest will "run" those lines to verify that the chap1, chap2, and chap3 labels exist in the checkpoint scene, and verify that those labels will be actually covered by Quicktest.

Questions?

Please post on the ChoiceScript forum if you have questions about this document.