Socially Distant OS
  • Docs
  • API
Search Results for

    Show / Hide Table of Contents
    • Accessibility
      • In-Game TTS
    • Development and Modding: Getting started
      • Building from source
      • Contribution guidelines
      • Project structure
      • Code style guide
    • Game scripting (sdsh)
      • The Basics
    • Game Framework
      • Event Bus
      • Playing Audio
    • Story Scripting
      • Career Mode Narrative Objects
      • Narrative Identifiers
      • News Articles
    • User Interface
      • UI Overview
      • Signals
      • List Adapters
      • Optimizing UI for Performance
      • Advanced UI features
        • Visual Styles

    The Basics of sdsh

    Socially Distant is heavily narrative-driven. Almost all of the game's main story is told through encounters with non-player characters, as well as through missions. These in-game encounters are written in a subset of Bash called sdsh. This is also the same language used to parse commands in the in-game command shell.

    Why would I want to write sdsh?

    Consider a mission where the player must hack into a network, download a file from a device inside the network, then delete the file from the hacked device.

    There are three theoretical ways this mission could be programmed into the game. It could be written in C# directly, allowing it to have full access to the game's API. It could be written in a data markup language like YAML or JSON, and thus written in a data-driven way. Or, it could be written in an embedded scripting language like Lua, or, well, sdsh.

    Missions can be highly dynamic, meaning data-driven design can be a lot more challenging to deal with. Allowing a mission to be written in C# means it has to be compiled into the game, making it harder to iterate on the game's story telling. Using an embedded scripting language means the mission can be re-loaded on the fly after a change, while also allowing the mission to do basic programmer things within reason.

    Furthermore, the game already needs sdsh because a command shell is an integral part of gameplay.

    Missions, as well as other in-game encounters, are also long-lasting tasks the game needs to execute over a long period of time. This means they either need to be asynchronous or run on a background thread. The sdsh interpreter is designed to be ran asynchronously, while the language itself hides this away from you as a writer or programmer. This makes sdsh perfect for scripting missions.

    How to write sdsh

    Use the in-game terminal to play around with these code examples.

    Run a command

    Commands are everything! They tell the game to do things.

    For example, this command opens this website in the user's browser:

    man
    

    Run a command with parameters

    Many commands accept or require you to specify parameters that control their behaviour. Each parameter is separated by whitespace.

    echo Hello world!
    

    String literals

    Strings of text in sdsh are surrounded in apostrophes (single-quotes).

    echo 'This is a string of text.'
    

    If you need to use an apostrophe within a string, you can escape it with a backslash.

    echo 'I\'m Ritchie.'
    

    Text expressions

    Text expressions allow you to insert variables and other expressions inside a string of text. Text expressions are surrounded by double-quotes.

    USER='ritchie'
    echo "Hello, $USER!"
    

    Variables

    You can define a variable like this: NAME=expression

    VAR1=ritchie
    VAR2=is
    VAR3=here
    

    And you can access the value of a variable like this $NAME

    echo $VAR1 $VAR2 $VAR3
    

    You can also access a variable's value like this: ${NAME}

    echo ${NAME}s
    

    Writing to a file

    You can write the output of a command to a file, like this:

    echo Hello world! > ~/hello.txt
    

    Or, you can write to the end of an existing file, like this:

    echo Hello world! >> ~/hello.txt
    

    Piping

    You can use the output of one command as the input of another command. This is called piping. You can use piping to make a cow say some wise words.

    fortune | cowsay
    

    Reading a file and using it as input

    You can also use the contents of a file as the input of a command. You can have the contents of a file read aloud to you, like this:

    speak < ~/hello.txt
    

    Command expansion

    Command expansion allows you to treat the output of a command as if it were text. You can then store this text as a variable, or pass it as a parameter to another command.

    COWFORTUNE=$(fortune | cowsay)
    echo $COWFORTUNE
    

    Environment variables

    You can export any variable as an environment variable using the export keyword. Use this to customize your prompt.

    export PS1='My Cool Prompt >>> '
    

    Functions

    Use functions to group a list of commands together into a single command you can use later.

    function cowfortune() {
      fortune | cowsay
    } 
    
    cowfortune
    

    You don't need the function keyword, adding it is a stylistic choice.

    cowfortune() { fortune | cowsay }
    

    Function Parameters

    You can pass parameters to functions just like you do other commands. Function parameters are accessed by numbered variables, $0 is the name of the function itself.

    function hello() {
      echo "Hello, $1!";
    }
    
    hello ritchie
    

    Run multiple things at once

    You can run two commands at once with the & operator. This command makes the game wait 5 seconds while reading some text from a file.

    (speak < ~/hello.txt) & sleep 5000
    

    Run one command after another, on the same line

    You can use a semi-colon to separate two commands on the same line. This code saves a random fortune to a file, prints the file to the screen, then reads it aloud.

    fortune > ~/hello.txt; cat ~/hello.txt; speak < ~/hello.txt
    

    Run a command only if a previous command succeeds

    You can use the && operator to run the right-hand command if the left-hand command completed without error.

    fortune > ~/hello.txt && cat ~/hello.txt && speak < ~/hello.txt
    

    Conditional expressions

    Use the if command to run a set of commands if a given command runs successfully.

    if file ~/hello.txt
    then
      speak < ~/hello.txt
    fi
    

    If you prefer the then keyword on the same line as the condition, don't forget a semi-colon before then.

    if file ~/hello.txt; then
      speak < ~/hello.txt
    fi
    

    You can also check if the condition command didn't succeed:

    if ! file ~/hello.txt
    then
      echo 'File not found!'
    fi
    

    Or, run one set of commands on success and another on failure:

    if file ~/hello.txt
    then
      speak < ~/hello.txt
    else
      echo 'File not found!'
    fi
    

    You can use the elif command in a similar way to else, except it will only run its commands if this secondary condition succeeds.

    if file ~/hello.txt
    then
      speak < ~/hello.txt
    elif file ~/world.txt
      speak < ~/world.txt
    else
      echo 'File not found!'
    fi
    

    Loops

    You can repeat a set of commands while a condition is true, using the while command.

    while true;
    do
      echo "Infinite loop."
    done
    

    Text matching

    You can use the case command to match a string of text against a set of patterns, running a set of commands based on what pattern matches first.

    VARIABLE=ritchie
    case $VARIABLE
      ritchie)
        echo Ritchie is here
        ;;
      hari)
        echo A wild evil skeleton appears...
        ;;
      *)
        echo Someone unknown showed up. Their name is $VARIABLE
        ;;
    esac
    

    When defining a pattern, preceding whitespace is ignored and a closing parenthesis marks the end of the pattern. When defining the commands to run for a given pattern, use the double-semi-colon (;;) to mark the end of the pattern's commands and the start of a new pattern. Use esac after the end of the last pattern to mark the end of the case command.

    An asterisk (*) acts as a wildcard inside patterns.

    In this article
    Back to top Generated by DocFX