CYS Script
by Ford
CYS Script is a custom scripting language thet powers the storygames of ChooseYourStory.com.
Table Of Contents
Data Types
Integer
A number with no fractional component. Integers are operated on in a signed 32-bit environment, ergo they’re limited to the range -2147483648 to 2147483647 (-231 to 231 - 1).
17
32
-1
-17
Random
Dice notation in the form of aDx, where a is the number of dice rolled and x is the number of sides on each die. Unlike the other data types, random is not a true “literal”, since its effective value is not directly represented by its notation. In fact, it’s technically a unique type of expression. Evaluates to a randomly generated integer between a and a · x (inclusive) at runtime.
1D20
4D6
2D10
String
A sequence of characters delimited (i.e., surrounded) by double quotes ("). Can contain any ASCII printable or newline character, except for the aforementioned double quotes. Characters outside of this range can be implemented via HTML character entities.
"Hello World"
"<br>"
"""
Boolean
A data type that can only be one of two values: TRUE or FALSE (also denoted as 1 or 0). The boolean is never written explicitly in code (i.e., it has no literal form). It is the result of a conditional expression and is only used in conditional statements.
Statements
The basic building block of any Choose Your Story script is the statement. Every script consists of one or more of these statements, which come in three flavors: Assignment
The most fundamental of the statements, assignment is used to set or change the value of a variable. Ultimately, for a given script to actually do anything, it needs to contain at least one instance of assignment.
New variables can be created simply by assigning them a value.
Assignment uses the assignment operator, a colon followed by an equal sign (:=). A lone equal sign (=) is, in contrast, a relational operator and is only used in conditions. Block
A block is a group of statements treated as a single statement. Blocks are most useful in conditional statements.
BEGIN %FOO := 1 %BAR := 2 END
Conditional
A conditional statement, also called an “IF statement”, evaluates a condition and then executes a statement depending on whether that condition is true.
If the result of the condition is TRUE (after being cast to a boolean if necessary), the statement directly following THEN (known as the “consequent”) is run. If the result is FALSE and an ELSE is present, the statement following ELSE (known as the “alternative”) is run. Otherwise, the system moves on to processing the next statement.
Note: Conditional statements accept only a single statement as the consequent or alternative. For multiple statements, enclose them in a block.
Conditional expressions also follow an order of operations:
- Parentheses
- Mathematical expressions
- Logical NOT
- Relational greater than and less than
- Relational equality and inequality
- Logical AND
- Logical OR
Relational Operators
The relational operators compare two values, evaluating whether or not the operation is true. There are six relational operators, one for each equality and inequality relation: =, !=, >, <, >=, and <=.
The equality and inequality operators (= and !=) are considered “strict”, meaning that data type is taken into account and no type casting takes place. They return boolean values TRUE or FALSE.
17 = 17 ? TRUE 17 = "17" ? FALSE 17 != "17" ? TRUE
The greater/less than operators (>, <, >=, and <=), however, are not strict. Since they require numerical values, strings are first cast to integers. The values they return are not acceptable with logical operators (AND, OR, and NOT), though they are still considered strictly equal to boolean TRUE and FALSE. If either side of one such operator is a boolean, a runtime error will occur as the system fails to cast booleans to integers. Logical Operators
Logical operators assess the boolean values of their arguments to return another boolean. CYSScript utilizes three logical operators: AND, OR, and NOT.
Logical AND returns TRUE if both its arguments are TRUE, and returns FALSE otherwise.
FALSE AND FALSE ? FALSE
TRUE AND FALSE ? FALSE
TRUE AND TRUE ? TRUE
Logical OR returns TRUE if either of its arguments are TRUE, and returns FALSE otherwise.
FALSE OR FALSE ? FALSE
TRUE OR FALSE ? TRUE
TRUE OR TRUE ? TRUE
Logical NOT returns the opposite value of its single argument.
NOT FALSE ? TRUE
NOT TRUE ? FALSE
Note: The logical operators only work if both of their arguments are booleans resulting from (in)equality operators. If not, AND and OR will return integer 0, and NOT simply returns its lone argument unaltered. Because of this, make sure never to use a logical operation on a relational operation containing >, <, >=, or <=.
1 AND 1 ? 0
(0 < 1) AND (1 > 0) ? 0
NOT 1 ? 1
Type Casting As there are multiple distinct types of data, a few issues arise when there are operations or comparisons made between them. Instead of simply disallowing operations between different data types, CYS Script attempts to convert those values into being the same type at runtime. This process is known as “type casting” or “type coercion”. Integer ? String As strings can contain numeric characters, integer to string conversion is simple. The integer simply becomes the string version of itself.
17 ? "17" -17 ? "-17"
String ? Integer String to integer conversion, however, is much more fickle, due to the greater number of possible characters in strings. A string becomes its integer equivalent if, after being trimmed of beginning and ending whitespace, it contains only valid integer characters within the 32-bit limit. Otherwise, it defaults to zero.
"17" ? 17 " 100 " ? 100 "100a" ? 0 "Hello World" ? 0 "2147483648" ? 0
Any ? Boolean Booleans can only either be TRUE or FALSE. Non-booleans will almost exclusively evaluate to a boolean TRUE, except in the case of an integer 0 or empty string "".
0 ? FALSE 1 ? TRUE "" ? FALSE "0" ? TRUE "Hello World" ? TRUE
Note: While values can be cast to booleans, booleans cannot be cast to any other value. A boolean argument on either side of an operation that requires non-booleans will cause a runtime error.
Variables A variable is a piece of data stored under a name, or “identifier”, whose value can be accessed, and sometimes redefined, during runtime. Each variable is prefixed with a “sigil”, either a % or $, that indicates, first, that it is a variable, and, second, which type of variable it is. User Variable A user variable, or simply "variable", is a value created by the author that stores an integer. Variables are named via the following scheme: percent sign sigil (%), followed by a capital letter, followed by any number of capital letters or numeric characters.
%FOO %BAR32 %FOOBARBAZQUX
The only data type user variables accept is the integer. Variables assigned non-integer values are automatically cast to integers. User variables can be “initialized”—that is to say, new variables can be defined—through assignment. Variables defined in the “Variables” section of the Advanced Editor are automatically initialized upon startup, and variables assessed in on-page coding are initialized on page load. Variables initialized through scripts can have names longer than ten characters. Uninitialized variables resolve to zero. Note: %SCORE is always pre-initialized, as it is required to display a player's score in their review. Note: Variables initialized on-page have far looser naming conventions, but this ultimately isn't useful as any scripts attempting to access them will be invalid. Destination A destination is a “constant”, meaning its value never changes. The resolved value of any destination is simply the string version of itself, meaning that the constant @NONE is treated the same as the string "@NONE". System Variable A system variable is prefixed with a dollar sign ($). New system variables cannot be created, but some can be assigned different values. $CHAPTERID An integer equal to the ID of the current chapter. This value is read-only; attempting to assign it a new value will create an invalid script. $PAGEID An integer equal to the ID of the current page. This value is read-only; attempting to assign it a new value will create an invalid script. $PAGETEXT Effective in page scripts, this variable is a string equal to the text content of the current page. $DEST Effective in link scripts, this variable can be used to change the page or chapter a link leads to. Accepts either a destination as a value or a destination in string format. Assigning nonexistent destinations results in a runtime error.
$DEST := @P1 $DEST := "@NONE" $DEST := "@P" + 1
$LINKTEXT## A group of variables that contain the text content of a page's links, written as $LINKTEXT followed by the numeric position of the link. These variables are per-page and are based on order instead of IDs—for any given page, the first link's text is accessed via $LINKTEXT1, the second with $LINKTEXT2, and so on; restricted/inactive links (visible or not) retain their position, and deleting a link does not create a gap in the variables. $LINKDEST## Seems to be read-only and always resolve to the destination @NONE. $ITEMSTATE## Not necessarily a single variable, but one for each item, these variables can be used to view or change which items are in the inventory. They are written in scripts as $ITEMSTATE followed directly by the numeric ID of the intended item. Each accepts either the value 0 (not in inventory) or 1 (in inventory). IF $ITEMUSED1 = 1 THEN $ITEMUSED2 := 1 Note: An $ITEMSTATE variable's value is not allowed to change in a link script (though it may, however tautological, be assigned its current value without issue). Doing so causes a runtime error. $ITEMUSED## Much like the $ITEMSTATE variables, there's one of these for every item. These variables can be used to view or change how many times the system considers them to have been "used". They are written in scripts as $ITEMUSED followed directly by the numeric ID of the intended item. Each accepts any integer value. $ITEMPAGEID## Seems to be read-only and always resolve to integer 0.
Expressions An expression is either a value or a mathematical operation that ultimately returns a value. The expressions referred to in this section are more technically referred to as “mathematical” expressions. A second type of expression, known as “conditional” or “boolean” expressions, return a TRUE or FALSE value and are solely used in conditional statements. Expressions allow the following mathematical operations: addition (+), subtraction (-), multiplication (*), and division (/). Expressions also allow bracketing via parentheses. Expressions follow the order of operations: Parentheses Multiplication and division Addition and subtraction
1 + 2 * 3 ? 7 (1 + 2) * 3 ? 9
Integer Expressions If a division operation between two integers results in a value with a fractional component, the value is always returned as an integer with the fractional part truncated. This occurs after every operation in a multi-operational expression, and this behavior may result in some erroneous math.
5 / 2 ? 2 -5 / 2 ? - 2 5 / 2 + 5 / 2 ? 4
Because of this behavior, a modulo operation (the remainder of a divided by n) can be performed with the following expression: (a - n * (a / n)) An operation between two integers that results in a value beyond the 32-bit limit causes the value to “overflow”, or wrap around to the opposite limit. The overflowed value of x can be calculated with the following operation (where “BitAnd” is a bitwise AND): ((x + 2³¹) BitAnd (2³² - 1)) - 2³¹ String Expressions An operation with a string on either side is always treated as concatenation, which chains the two together (regardless of the actual operator). In concatenation between an integer and a string, the integer is first cast to a string.
"Hello " + "World" ? "Hello World" "1" + "1" ? "11" "Your score is: " * 100 ? "Your score is: 100"