| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-12-22 04:08:34 +0100 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-12-22 04:08:34 +0100 |
| commit | d0d6117176d68b2345d36e81ccdaa447e9caa724 (patch) | |
| tree | 6cb8f3e4735a695be8c0922434df4c60f7cf82c7 | |
Moving to Hugo.
55 files changed, 4499 insertions, 0 deletions
diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..61e69cd --- /dev/null +++ b/config.toml @@ -0,0 +1,12 @@ +baseURL = "https://tonkadur.of.tacticians.online/" +languageCode = "en-us" +title = "Tonkadur" +theme = "hugo-theme-learn" +[params] + custom_css = ["css/prism.css"] + +# For search functionality +[outputs] +home = [ "HTML", "RSS", "JSON"] + + diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..6d1c67a --- /dev/null +++ b/content/_index.md @@ -0,0 +1,56 @@ +--- +title: "Main" +--- +# Welcome to Tonkadur's website! +Tonkadur is a tool to create game narratives. + +### Find out all about Tonkadur + * **Plain-text format.** Just write in your favorite editor and use your usual tools. + * **Extensive description language (Fate).** You shouldn't feel restrained in what you can write. + * **Strong typing.** Reduce the likeliness of errors in your descriptions. + * **Very simple and small interpreted language (Wyrd).** Easily add support for Tonkadur to your engine. + * **LISP inspired syntax.** No weird symbols everywhere. No annoying indentation restrictions. + +Tonkadur provides a compiler from Fate to Wyrd, letting you freely describe +your stories using a feature rich language without having to worry about the +implications when it comes time to add support for it to your engine. + +### Sample: +{{< fatecode >}}(define_sequence in_your_room () + (ifelse + (is_member visited_your_room progress) + (text_effect narrator + You room is still a mess. You don't have time to clean things up, + though. + ) + (text_effect narrator + You room is a mess. You recall having been through every drawer while + preparing your bag yesterday. While still unclear on how you are + supposed to pack all the necessary things for what promises to be at + least a year-long journey inside a small backpack, you cannot avoid + but wasting more time contemplating the piles of items that didn't + make the cut. + ) + ) + (add visited_your_room progress) + (player_choice + ( + ( Look for healing items ) + (jump_to look_for_healing_items) + ) + ( + ( No time! Let's go adventuring! ) + (jump_to leave_your_room) + ) + ) +) +{{< /fatecode >}} + +### Known alternatives +* [Inkle's Ink](https://www.inklestudios.com/ink/). +* [Yarn Spinner](https://yarnspinner.dev/). +* [DLG](https://github.com/iLambda/language-dlg). Nowhere near as popular as the +other two alternatives, but its approach shares more similarities with Tonkadur. + + +### Syntax Highlight Test: diff --git a/content/fate_v1/_index.md b/content/fate_v1/_index.md new file mode 100644 index 0000000..8b90a7a --- /dev/null +++ b/content/fate_v1/_index.md @@ -0,0 +1,162 @@ +--- +title: "Fate (Version 1)" +menuTitle: "Fate" +--- + +When using Tonkadur, Fate is the language the author writes in. This language is +meant to provide the writer with as many tools as possible, so that they do not +feel constrained by the limitations of the language, nor find writing complex +narratives tedious. + +## A few warnings first + +Fate uses strong typing. This is intended to make detection of mistakes easier, +but may lead to some frustrations for authors only used to languages using +dynamic typing. + +Fate does not have any special features for multi-seating/multi-player +narratives. This is by design, as adding proper support for this would make the +underlying language more complex, and thus would make it harder to create an +interpreter for it. This is however something considered for an extension +(see +[this GitHub issue about it](https://github.com/nsensfel/tonkadur/issues/5)). + +You'll need to learn parentheses management, if you make anything complex. Fate +uses a LISP inspired syntax, so parentheses are everywhere. The syntax gives you +free reign over indentation, but so many parentheses does require at least some +discipline in order to be readable. + +Fate is meant to be compiled. This does add an extra step to your existing +process. + +Fate is very much a new language. There isn't many (any?) tools for it. + +If for some reason you want to perform memory allocation, there is no automatic +garbage collection, so you will have to free whatever you allocate. + +In what may seem weird for narrative scripting, Fate does not feature string +manipulation operations. Strings can be made into rich text, with complex +attributes, but you will not be able to use things like regular expressions +(or anything other than simple concatenation, really) with just the base +language. This is because of these operations would need to be implemented +directly by the interpreter anyway, and their use isn't actually common in +a narrative description, which would make requiring support for them of +any Tonkadur interpreter problematic. + +## Some nice features + +If you haven't closed the tab yet, here are some reasons why you *might* want +to use Fate. + +It *is* a LISP inspired syntax. If that's what you like, you might even enjoy +this take on it. There's no fiddling with indentation, no wondering what symbol +does what. It's all about parentheses indicating something is performed on a +list of other things. It's not a purely functional language, though. In fact, +it's a mix of both declarative and imperative programming: sequences (or +procedures) are imperative. Computations are functional. There are lambda +functions, but they're strongly typed. Collections and structures can only be +modified through specific instructions, so it's not quite really a LISP-like +language. + +There are pointers. Oh, come on, it's a plus, *right?* This makes it a lot +easier to refer to things. There's no pointer arithmetic, so you don't have to +worry about the scary stuff. Also, this lets you allocate memory, which is +useful when you want a unspecified amount of distinct instances of something. +Want to describe a story where the player can push a button as many time as +they choose, create a clone of a creature every time they do so, yet let them +fight any of these creature as their distinct instance? Well, with memory +allocation and pointers, it's easily done. Didn't you know? When writing a +narrative, the RAM's the limit. So yeah, maybe don't forget to `free` the +thousands of monster the player will no doubt create. + +You can do recursion. Wait! I *am* listing the nice features! Do people really +not like recursion and pointers? Oh, well... Still, you can do recursions with +both procedures and lambda functions. Not a fan of recursion? That's alright, +you also have imperative loops: `for`, `while`, `do_while`, and even +`for_each`. + +## The basics + +#### Procedures (or Sequences) and Instructions +Procedures are lists of instructions and things to display. Instructions can be +applied to values, but they themselves do not return any value. Any value not +part of an instruction found in a procedure is displayed. Any value being part +of an instruction is **not** displayed. + +One way to think about it is to consider procedures as being actually two types +of things: sequences and procedures. A sequence is then a scene in the story, +and a procedure is just a construct called upon to perform instructions. + +Procedures can take arguments. Values are passed by copy. + +Procedures can be called in two ways: a `call` or a `jump`. A `call` will +perform the procedure before continuing with the current sequence of +instructions. A `jump` will perform the procedure **instead of** the +**current** sequence of instructions. + +Procedures can be called before their definition. The compiler will simply tell +you if the definition ends up being incompatible or missing. + +#### Computations +Computations are operations returning a value. Computations do not modify +anything, they simply return the result of an operation. + +A special type of computation, called *lambda function*, allows the creation of +a computation that will be performed only when called upon. Those can take +parameters. What's the use of something as advanced in a narrative scripting +language? It's convenient when you want to express something like a character's +name who depends on what the player figured out. Sure, you *could* make each +instance of the name feature a series of tests to find which value to use, or +you could just use a lambda function and just put +`(eval name_of_mysterious_character)` to get the right value. + +One last thing about lambda functions, which really are the only potentially +complicated thing about computations: these *are* computations, so you can use +them as such. They also cannot modify anything, as they only contain +computations and not instructions. + +#### Declarations and First Level Instructions +Declarations and First Level Instructions are a special type of instruction +which can only be done from outside a procedure. This distinction means that, +for example, you cannot define a procedure from within a procedure. + +#### Events +Sometimes, you might need to communicate something to the interpreter which +cannot be expressed in Fate. For example, you might want to say: "pause for 30 +seconds", or "play this music". This kind of thing has been considered to not +be generic enough to mandate every interpreter supports it. Instead, events are +used. + +Events are first declared, by being given a name and a list of types +corresponding to the parameters they take. Then, the `(event ...)` instruction +can be used to indicate that a certain event should occur. This will pause the +execution, and make the interpreter react to the event before continuing. + +The effect of an event is purely the interpreter's responsibility. It cannot be +described in Fate. Thus, you will need to refer to the interpreter you use to +see what events are available. + +#### Types +The basic `string`, `int`, `float`, and `bool` types are what one would expect. + +`rich_text` corresponds to text decorations, see the text effect sub-section. + +Two collection types are available: `(list [TYPE])` is a list of `[TYPE]` +elements, and `(set [COMPARABLE])` is a set of `[COMPARABLE]` elements. + +`(ptr [TYPE])` is an address to a value of type `[TYPE]`. + +Structures can be defined. They may contain other structures, but cannot be +recursive: only already defined types can be used. Pointers cannot be used to +resolve this conundrum in this version of Fate, but it may be added in the next +version (see [this GitHub +issue](https://github.com/nsensfel/tonkadur/issues/6)). + +#### Player Choices +Inputs from the players are limited to the `(player_choice ...)` instruction. +It presents the player with `rich text` options to choose from, which execute +an associated list of instructions if chosen. + +More complicated inputs, such as retrieving a `string` or an `int` from the +player require the definition and use of events. + diff --git a/content/fate_v1/aliases/default.md b/content/fate_v1/aliases/default.md new file mode 100644 index 0000000..9a6bd8a --- /dev/null +++ b/content/fate_v1/aliases/default.md @@ -0,0 +1,41 @@ +--- +title: Aliases +--- +Nearly all computations and instructions have aliases, making it easier to +write in the language when not used to it. This page provides most of them. As +a general rule, all underscores (`_`) are optional, all `declare` can be +replaced by `define` and `def`. + +* `abs`: `absolute`. +* `and`: `/\`. +* `>=`: `greater_equal_than`, `ge`. +* `/`: `divide`, `div`. +* `=`: `==`, `equals`, `eq`. +* `declare_alias_type`: `declare_sub_type`, `typedef`. +* `declare_structure_type`: `declare_structure`, `declare_dict_type`, + `declare_dict`. +* `declare_event_type`: `declare_event`. +* `declare_sequence`: `declare_seq`, `declare_procedure`, `declare_proc`. +* `ignore_error`: `ignore_warning`. +* `free`: `release`, `destroy`. +* `implies`: `=>`, `->`. +* `is_member`: `contains`, `has`. +* `=<`: `<=`, `lower_equal_than`, `le`. +* `<`: `lower_than`, `lt`. +* `-`: `minus` +* `min`: `minimum`. +* `max`: `maximum`. +* `eval`: `evaluate`. +* `%`: `mod`, `modulo`. +* `new`: `reserve`, `create`. +* `not`: `~`, `!`. +* `add_element`: `add`. +* `one_in`: `exactly_one_in`, `exactly_one`, `one`. +* `remove_at`: `remove_element_at`, `remove_elem_at`. +* `set`: `set_value`, `set_val`, `set_variable`, `set_var`. +* `var`: `variable`. +* `visit`: `call`, `call_sequence`, `call_procedure`, `call_seq`, `call_proc`, + `visit_sequence`, `visit_procedure`, `visit_seq`, `visit_proc`. +* `jump_to`: `continue_as`, `continue_to`, `continue_with`, `jump`, `go_to`, + `exec`. And you can suffix `_proc`, `_procedure`, `_seq`, or `_sequence` to + any of these. diff --git a/content/fate_v1/computations/_index.md b/content/fate_v1/computations/_index.md new file mode 100644 index 0000000..9312712 --- /dev/null +++ b/content/fate_v1/computations/_index.md @@ -0,0 +1,138 @@ +--- +title: Computations +--- +Computations are values. They may read from the memory, but do not modify it +(with a single exception). + +### TEXT +{{< fatecode >}}(text [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} + +Returns a `text` node containing the text representation of `C0` ... `CN`. + +### VARIABLE | REFERENCE +{{< fatecode >}}(var {String}){{< /fatecode >}} + +Returns the value of the variable `{String}`, or a reference to it if +applicable. Structure members can be accessed by using `.` in `{String}`. + +### STRUCTURE FIELD ACCESS +{{< fatecode >}}{Structure Var Name}.{Field Name}{{< /fatecode >}} +{{< fatecode >}}(field [STRUCTURE VAR] {String}){{< /fatecode >}} + +Accesses the `{String}` field of the structure `<STRUCTURE_VAR>`. Using `.` to +access fields is recommended over the use of this operator. + +### STRUCTURE FIELD VALUE +{{< fatecode >}}(get_field [STRUCTURE] {String}){{< /fatecode >}} +Returns the value of the `{String}` field of the structure `[STRUCTURE]`. + +### TEMPORARY VARIABLES +{{< fatecode >}}(let (({V0 = String} [C0 = COMPUTATION]) ... ({VN = String} [CN = COMPUTATION])) [R = COMPUTATION]){{< /fatecode >}} + +Defines a hierarchical level and local variables `V0` ... `VN` with values `C0` ... `CN`, and returns the value of `[R]`. + +### CAST +{{< fatecode >}}(cast [TYPE] <COMPUTATION*>){{< /fatecode >}} + +Transforms `<COMPUTATION*>` into a value of type `[TYPE]`. Note that the variable +shorthand cannot be used for `<COMPUTATION*>`. The following type changes are +allowed: +* `[FLOAT]` to `[FLOAT]`, `[INT]`, and `[STRING]`. +* `[INT]` to `[FLOAT]`, `[INT]`, and `[STRING]`. +* `[BOOL]` to `[BOOL]` and `[STRING]`. +* `[STRING]` to `[BOOL]` (`true` and `false`), `[FLOAT]`, `[INT]`, and`[STRING]`. + +### RANDOM NUMBER +{{< fatecode >}}(rand [I0 = INT] [IN = INT]){{< /fatecode >}} + +Returns a random number between `I0` and `IN` (inclusive). + +## Basic Operators +### BOOL OPERATORS +{{< fatecode >}}(and [B0 = BOOL] ... [BN = BOOL]){{< /fatecode >}} + +Standard conjunction (minimum of 2 arguments). + +{{< fatecode >}}(or [B0 = BOOL] ... [BN = BOOL]){{< /fatecode >}} + +Standard disjunction (minimum of 2 arguments). + +{{< fatecode >}}(not [BOOL]){{< /fatecode >}} + +Standard negation. + +{{< fatecode >}}(implies [B0 = BOOL] [B1 = BOOL]){{< /fatecode >}} + +Standard implication. + + +{{< fatecode >}}(one_in [B0 = BOOL] ... [BN = BOOL]){{< /fatecode >}} + +true if, and only if, exactly one of the operands is true. + +### MATH OPERATORS +All operands must be of the same type, which is also the type returned by the +operation. + +{{< fatecode >}}(+ [N0 = NUMBER] ... [NN = NUMBER]){{< /fatecode >}} + +Standard addition (minimum of 2 arguments). + +{{< fatecode >}}(- [N0 = NUMBER] ... [NN = NUMBER]){{< /fatecode >}} + +Standard substraction (minimum of 2 arguments). + +{{< fatecode >}}(* [N0 = NUMBER] ... [NN = NUMBER]){{< /fatecode >}} + +Standard multiplication (minimum of 2 arguments). + +{{< fatecode >}}(/ [N0 = NUMBER] [N1 = NUMBER]){{< /fatecode >}} + +Standard division. Note that a division on integers is indeed a integer +division. + +{{< fatecode >}}(^ [N0 = NUMBER] [N1 = NUMBER]){{< /fatecode >}} + +Standard exponentiation. + +{{< fatecode >}}(% [I0 = INT] [I1 = INT]){{< /fatecode >}} + +Standard modulo operation. + +{{< fatecode >}}(min [N0 = NUMBER] ... [NN = NUMBER]){{< /fatecode >}} + +Lowest value among the operands. + +{{< fatecode >}}(max [N0 = NUMBER] ... [NN = NUMBER]){{< /fatecode >}} + +Highest value among the operands. + +{{< fatecode >}}(clamp [N0 = NUMBER] [N1 = NUMBER] [N2 = NUMBER]){{< /fatecode >}} + +Equivalent to `(min N0 (max N1 N2))`. + + +{{< fatecode >}}(abs [NUMBER]){{< /fatecode >}} + +Positive value of `[NUMBER]`. + +### COMPARISON OPERATORS +{{< fatecode >}}(= [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} + +True if, and only if, all operands are equal. + +{{< fatecode >}}(< [C0 = COMPARABLE] [C1 = COMPARABLE]){{< /fatecode >}} + +True if, and only if, `C0` is strictly lower than `C1`. + +{{< fatecode >}}(=< [C0 = COMPARABLE] [C1 = COMPARABLE]){{< /fatecode >}} + +True if, and only if, `C0` is lower or equal to/than `C1`. + +{{< fatecode >}}(> [C0 = COMPARABLE] [C1 = COMPARABLE]){{< /fatecode >}} + +True if, and only if, `C0` is strictly higher than `C1`. + +{{< fatecode >}}(>= [C0 = COMPARABLE] [C1 = COMPARABLE]){{< /fatecode >}} + +True if, and only if, `C0` is higher or equal to/than `C1`. diff --git a/content/fate_v1/computations/collections/_index.md b/content/fate_v1/computations/collections/_index.md new file mode 100644 index 0000000..63c62cc --- /dev/null +++ b/content/fate_v1/computations/collections/_index.md @@ -0,0 +1,98 @@ +--- +title: Collections +--- +### ACCESS +{{< fatecode >}}(access [COLLECTION|COLLECTION PTR] [INT]){{< /fatecode >}} + +Returns the value of the `[INT]`th element in `[COLLECTION|COLLECTION PTR]`. + +### ACCESS CONSTANT INDEX +{{< fatecode >}}[(COLLECTION|COLLECTION PTR) VAR].{Integer}{{< /fatecode >}} + +Returns a variable corresponding to the `[INT]`th element in +`[(COLLECTION|COLLECTION PTR) VAR]`. + +### ACCESS POINTER +{{< fatecode >}}(access_pointer [(COLLECTION|COLLECTION PTR) VAR] [INT]){{< /fatecode >}} + +Returns a pointer to the `[INT]`th element in `[(COLLECTION|COLLECTION PTR) +VAR]`. + +### ADD ELEMENT AT +{{< fatecode >}}(add_element_at [INT] [COMPUTATION*] [LIST]){{< /fatecode >}} + +Returns a copy of `[LIST]` with `[COMPUTATION*]` added at index `[INT]`. Note +that `[COMPUTATION*]` does not allow use of the variable shorthand. + +### ADD ELEMENT +{{< fatecode >}}(add_element [COMPUTATION*] [COLLECTION]){{< /fatecode >}} + +Returns a copy of `[COLLECTION]` with `[COMPUTATION*]` added. If `[COLLECTION]` +is a `[LIST]`, then the element is added at the end of the list. +Note that `[COMPUTATION*]` does not allow use of the variable shorthand. + +### ADDING MEMBERS +{{< fatecode >}}(add_all_elements [C0 = COLLECTION] [C1 = COLLECTION]){{< /fatecode >}} + +Returns a copy of `[C1]`, with all the elements of `[C2]` added. If `[C1]` +is a `[LIST]`, the new members are added at the end of the list. + +### COUNT +{{< fatecode >}}(count [COMPUTATION*] [COLLECTION]){{< /fatecode >}} + +Returns the number of occurrences of `[COMPUTATION*]` in `[COLLECTION]`. +Note that `[COMPUTATION*]` does not allow use of the variable shorthand. + +### INDEX OF +{{< fatecode >}}(index_of [COMPUTATION] [COLLECTION]){{< /fatecode >}} + +Returns the index of the first occurrence of `[COMPUTATION]` in `[COLLECTION]`, +starting at 0. + +### IS MEMBER +{{< fatecode >}}(is_member [COMPUTATION] [COLLECTION]){{< /fatecode >}} + +Returns true if, and only if, `[COMPUTATION]` is in `[COLLECTION]`. + +### SIZE +{{< fatecode >}}(size [COLLECTION]){{< /fatecode >}} + +Returns the size (`[INT]`) of `[COLLECTION]`. + +### IS EMPTY +{{< fatecode >}}(is_empty [COLLECTION]){{< /fatecode >}} + +Returns true if, and only if `[COLLECTION]` is empty. + +### FILTER ELEMENTS +{{< fatecode >}}(filter [LAMBDA BOOL (X)] [X COLLECTION]){{< /fatecode >}} +{{< fatecode >}}(filter [LAMBDA BOOL (X Y0 ... YN)] [X COLLECTION] [Y0 COMPUTATION*] ... [YN COMPUTATION*]){{< /fatecode >}} + +Returns a copy of `[X COLLECTION]` in which only the elements for which +`<LAMBDA BOOL (X)>` returns `true` remain. If the lambda function needs extra +parameters, use the second syntax, which adds those parameters at the end of the +`(filter ...)` call. Note that the variable shorthand cannot be used for these +extra parameters. + +### FILTER ELEMENTS (INDEXED) +{{< fatecode >}}(indexed_filter [LAMBDA BOOL (INT X)] [X COLLECTION]){{< /fatecode >}} +{{< fatecode >}}(indexed_filter [LAMBDA BOOL (INT X Y0 ... YN)] [X COLLECTION] [Y0 COMPUTATION*] ... [YN COMPUTATION*]){{< /fatecode >}} + +Returns a copy of `[INT X COLLECTION]` in which only the elements for which +`<LAMBDA BOOL (INT X)>` (with `INT` being the element's index) returns `true` +remain. If the lambda function needs extra parameters, use the second syntax, +which adds those parameters at the end of the `(indexed_filter ...)` call. Note +that the variable shorthand cannot be used for these extra parameters. + +### FOLD OVER COLLECTION +{{< fatecode >}}(foldl [LAMBDA X (X Y)] [X COMPUTATION*] [Y COLLECTION]){{< /fatecode >}} +{{< fatecode >}}(foldl [LAMBDA X (X Y Z0 ... ZN)] [X COMPUTATION*] [Y COLLECTION] [Z0 COMPUTATION*] ... [ZN COMPUTATION*]){{< /fatecode >}} +{{< fatecode >}}(foldr [LAMBDA X (X Y)> [X COMPUTATION*] [Y COLLECTION]){{< /fatecode >}} +{{< fatecode >}}(foldr [LAMBDA X (X Y Z0 ... ZN)] [X COMPUTATION*] [Y COLLECTION] [Z0 COMPUTATION*] ... [ZN COMPUTATION*]){{< /fatecode >}} + +Returns the result of iterating `<LAMBDA X (X Y)>` over `[Y COLLECTION]`, with +`[X COMPUTATION*]` being the initial value. The direction of the iteration is +by ascending index order when using `foldl`, and the opposite order when using +`foldr`. Extra parameters for the lambda function can be passed as extra +parameters of the call. Note that the variable shorthand cannot be used for +those extra parameters, nor for the initial value. diff --git a/content/fate_v1/computations/conditionals/_index.md b/content/fate_v1/computations/conditionals/_index.md new file mode 100644 index 0000000..2953489 --- /dev/null +++ b/content/fate_v1/computations/conditionals/_index.md @@ -0,0 +1,54 @@ +--- +title: Conditionals +--- +This page presents the computation operators that allow a choice depending on +some condition. All possible returned values must be of the same type. + +### IF-ELSE +{{< fatecode >}}(if_else [BOOL] [C0 = COMPUTATION] [C1 = COMPUTATION]){{< /fatecode >}} + +Returns `C0` is `[BOOL]` yields true, `C1` otherwise. + +### COND +{{< fatecode >}}(cond ([B0 = BOOL] [C0 = COMPUTATION]) ... ([BN = BOOL] [CN = COMPUTATION])){{< /fatecode >}} + +Returns `<Ci>`, such that `<Bi>` is the first to hold true. If there is not such +`Bi`, returns `[CN]`. + +### SWITCH +{{< fatecode >}}(switch [T = COMPUTATION] ([V0 = COMPUTATION] [C0 = COMPUTATION]) ... ([VN = BOOL] [CN = COMPUTATION]) [D = COMPUTATION]){{< /fatecode >}}a + +Returns the first `Ci` such that `Vi` is equal to `T`. If there is not such +`Vi`, returns `[D]`. + +## Examples +{{< fatecode >}}(cond + ((false) (false)) + ((false) (false)) + ((true) + (cond + ((false) (false)) + ((true) (not (is_member 3 test_list))) + ((true) (false)) + ) + ) +) +{{< /fatecode >}} + +{{< fatecode >}}(switch 3 + (0 (false)) + (1 (false)) + (3 (true)) + (2 (false)) + (false) +) +{{< /fatecode >}} + +{{< fatecode >}}(if_else (true) + (if_else (false) + (assert (false) FAILED: instruction ifelse E) + (set test_var (true)) + ) + (assert (false) FAILED: instruction ifelse F) +) +{{< /fatecode >}} diff --git a/content/fate_v1/computations/cons/_index.md b/content/fate_v1/computations/cons/_index.md new file mode 100644 index 0000000..5ece27b --- /dev/null +++ b/content/fate_v1/computations/cons/_index.md @@ -0,0 +1,22 @@ +--- +title: Cons +--- +Fate features a *construct* computation, making it possible to create an +anonymous structure by creating pairs of computations. Unlike collections, these +pairs do not have to be made of computations of the same type. + +### PAIRING +{{< fatecode >}}(cons [C0 = COMPUTATION*] [C1 = COMPUTATION*]){{< /fatecode >}} + +Returns the value corresponding to a pair made of `[C0]` and `[C1]`. Note that +the variable shorthand cannot be used for either parameter. + +### RETRIEVING THE FIRST ITEM +{{< fatecode >}}(car [CONS]){{< /fatecode >}} + +Returns the value corresponding to the first item in the `[CONS]` pair. + +### RETRIEVING THE SECOND ITEM +{{< fatecode >}}(cdr [CONS]){{< /fatecode >}} + +Returns the value corresponding to the second item in the `[CONS]` pair. diff --git a/content/fate_v1/computations/lambda_functions/_index.md b/content/fate_v1/computations/lambda_functions/_index.md new file mode 100644 index 0000000..35485a3 --- /dev/null +++ b/content/fate_v1/computations/lambda_functions/_index.md @@ -0,0 +1,30 @@ +--- +title: Lambda Functions +--- +Lambda functions are values that correspond to a computation not yet performed. +These can take arguments. Defining a lambda function returns the value that +corresponds to the function itself, the `eval` computation must be used to +obtain the value that the function computes. + +### DEFINITION +{{< fatecode >}}(lambda (([T0 = TYPE] {S0 = String}) ... ([TN = TYPE] {SN = String})) [COMPUTATION]){{< /fatecode >}} + +Returns a lambda function taking `S0` ... `SN` of types `T0` ... `TN` as +arguments and evaluating to `[COMPUTATION]`. + +### EVALUATION +{{< fatecode >}}(eval [REFERENCE] [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} + +Returns the result of evaluating the lambda function at `[REFERENCE]` given the +parameters `C0` ... `CN`. + +## Examples +{{< fatecode >}}(lambda ( (int i) ) + (+ (var i) 1) +) +{{< /fatecode >}} + +{{< fatecode >}}(lambda ( (int i) ) + (* (eval int_to_int (var i)) 2) +) +{{< /fatecode >}} diff --git a/content/fate_v1/computations/references/_index.md b/content/fate_v1/computations/references/_index.md new file mode 100644 index 0000000..ba5716a --- /dev/null +++ b/content/fate_v1/computations/references/_index.md @@ -0,0 +1,18 @@ +--- +title: References +--- +### VALUE ACCESS +{{< fatecode >}}(at [ADDRESS]){{< /fatecode >}} + +Returns the variable at `[ADDRESS]`. + +### ALLOCATION +{{< fatecode >}}(new [TYPE]){{< /fatecode >}} + +Returns the address of a new variable of type `[TYPE]`. Don't forget to call +`free` on it once you're done. + +### ADDRESS +{{< fatecode >}}(ptr [COMPUTATION VARIABLE]){{< /fatecode >}} + +Returns the address of `[COMPUTATION VARIABLE]`. diff --git a/content/fate_v1/computations/rich_text/_index.md b/content/fate_v1/computations/rich_text/_index.md new file mode 100644 index 0000000..7351a5c --- /dev/null +++ b/content/fate_v1/computations/rich_text/_index.md @@ -0,0 +1,11 @@ +--- +title: Rich Text +--- +### RICH TEXT +{{< fatecode >}}(rich_text [TEXT]){{< /fatecode >}} + +### ADD TEXT EFFECT +{{< fatecode >}}(add_text_effect ({String} [P0 = COMPUTATION] ... [PN = COMPUTATION]) [RICH TEXT]){{< /fatecode >}} + +### NEW LINE +{{< fatecode >}}(newline){{< /fatecode >}} diff --git a/content/fate_v1/declarations/_index.md b/content/fate_v1/declarations/_index.md new file mode 100644 index 0000000..013d404 --- /dev/null +++ b/content/fate_v1/declarations/_index.md @@ -0,0 +1,5 @@ +--- +title: "Declarations" +menuTitle: "Declarations" +chapter: true +--- diff --git a/content/fate_v1/declarations/events/_index.md b/content/fate_v1/declarations/events/_index.md new file mode 100644 index 0000000..5493cd7 --- /dev/null +++ b/content/fate_v1/declarations/events/_index.md @@ -0,0 +1,18 @@ +--- +title: Events +--- +Events are how a Fate narrative can communicate to the interpreter that +something which cannot be expressed in Fate needs to be performed. The execution +is paused until the event is resolved by the interpreter. To avoid mistakes, any +event type must be declared before use. + +#### EVENT +{{< fatecode >}}(declare_event_type {string} [C0 = TYPE] ... [CN = TYPE]){{< /fatecode >}} +**Effect:** An event with the name `{string}` and taking parameters of types +`[C0]`, ..., `[CN]` can be used. + +## Examples +* `(declare_event_type user_string_input rich_text (ptr string))` +* `(declare_event_type wait int)` +* `(declare_event_type set_background_to string)` +* `(declare_event_type rumble)` diff --git a/content/fate_v1/declarations/files/_index.md b/content/fate_v1/declarations/files/_index.md new file mode 100644 index 0000000..05c6836 --- /dev/null +++ b/content/fate_v1/declarations/files/_index.md @@ -0,0 +1,48 @@ +--- +title: File Management +--- +Fate narratives have one main file, but this file can use the contents of other +files, and these files in turn can also use the contents of other files. Three +issues arise then: some things must be declared before they are used, nothing +should be declared multiple times, and where are the files? + +The absolute path to each file is computed in order to detect whether it has +already been loaded. The given paths are expected to be relative. They are then +resolved by attempting access from the following, in order: the current file's +directory; the include directories passed as parameter to the executable; the +calling executable's directory. + +Dependency cycles will raise compiling errors. + +The first "instruction" on each file must be `(fate_version 1)`. Values cannot +be placed before either, obviously. + +{{< fatecode >}}(require {string}){{< /fatecode >}} + +**Effect:** If the file at `{string}` has not yet been loaded, load it. + +{{< fatecode >}}(include {string}){{< /fatecode >}} + +**Effect:** Load the `{string}`, even if it has already been loaded. + +#### Examples +* `(require bonus_sequence.fate)` +* `(include types/plant.fate)` +* `(require ../guild/merchants.fate)` +* `(include ../what/../are/../you/../doing/../there.fate)` +* `(require oh/../oh/../oh/../this_is_fine.fate)` + +Example of Fate file: +{{< fatecode >}};;; A story of great importance +(fate_version 1) + +(require include/events.fate) +(require include/text_effects.fate) + +(require scenes/the_holiday_forest.fate) + +`Twas a long time ago... Longer now that it seems... In a place that can't be +referenced here because I'm pretty sure the transcript is copyrighted. + +(jump_to not_the_tree_door_i_would_have_chosen) +{{< /fatecode >}} diff --git a/content/fate_v1/declarations/sequences/_index.md b/content/fate_v1/declarations/sequences/_index.md new file mode 100644 index 0000000..8bdb30e --- /dev/null +++ b/content/fate_v1/declarations/sequences/_index.md @@ -0,0 +1,113 @@ +--- +title: Sequences and Procedures +--- +Sequences and procedures are the same thing. These are named lists of +instructions and values, which can be called upon at any point where +instructions can be used. They can take parameters. + +Procedures do not return values. It is however possible to emulate something +similar, by passing a pointer as a parameter and storing a "return" value into +it. + +These are also intended to be used to describe scenes. + +The execution of a sequence can be terminated by using the `(done)` +instruction. The execution of the narrative can be terminated by using the +`(end)` instruction. + +Any value not part of an instruction will simply be displayed when it is +reached during the procedure's execution. + +Sequences can be used before their definition, the compiler will raise an error +if the use ends up being incorrect. + +Execution of a sequence can be started in two ways: `(call sequence_name)` will +execute the sequence then continue with the execution of the current +instruction list; `(jump_to sequence_name)` will replace the current +instruction list by the execution of the sequence. If one were to ignore +variables, the `(jump_to sequence_name)` instruction is similar to performing +`(call sequence_name) (done)`. + +{{< fatecode >}}(define_sequence {String} (([C0 = TYPE] {V0 = String}) ... ([CN = TYPE] {VN = String})) <I0 = INSTRUCTIONS|VALUE> ... <IM = INSTRUCTIONS|VALUE>){{< /fatecode >}} +**Effect:** Defines the sequence `{String}`, with variables `V0` ... `VN` of types `C0` ...`CN` as parameters, and instructions `I0` ... `IM` as content. + +**Acceptable Aliases:** `declare_sequence`, `def_seq`, `define_procedure`, `declare_procedure`, `def_proc`. + +#### Examples +{{< fatecode >}}(define_sequence in_your_room () + (ifelse + (is_member visited_your_room progress) + (text_effect narrator + You room is still a mess. You don't have time to clean things up, + though. + ) + (text_effect narrator + You room is a mess. You recall having been through every drawer while + preparing your bag yesterday. While still unclear on how you are + supposed to pack all the necessary things for what promises to be at + least a year-long journey inside a small backpack, you cannot avoid + but wasting more time contemplating the piles of items that didn't + make the cut. + ) + ) + (add visited_your_room progress) + (player_choice + ( + ( Look for healing items ) + (jump_to look_for_healing_items) + ) + ( + ( No time! Let's go adventuring! ) + (jump_to leave_your_room) + ) + ) +) +{{< /fatecode >}} + +{{< fatecode >}}(define_sequence index_of_loop + ( + ((ptr int) result_holder) + ((list int) collection) + (int target) + ) + (local int collection_size) + (local int i) + + (set collection_size (size collection)) + + (for (set i 0) (< (var i) (var collection_size)) (set i (+ (var i) 1)) + (if (= (access collection (var i)) (var target)) + ( + (set (at result_holder) (var i)) + (done) + ) + ) + ) + (set (at result_holder) -1) +) +{{< /fatecode >}} + + +{{< fatecode >}}(define_sequence index_of_jump + ( + ((ptr int) result_holder) + ((list int) collection) + (int target) + (int i) + (int collection_size) + ) + (ifelse (= (var i) (var collection_size)) + (set (at result_holder) -1) + (ifelse (= (access collection (var i)) (var target)) + (set (at result_holder) (var i)) + (jump index_of_jump + (var result_holder) + (var collection) + (var target) + (+ (var i) 1) + (var collection_size) + ) + ) + ) +) +{{< /fatecode >}} diff --git a/content/fate_v1/declarations/text_effects/_index.md b/content/fate_v1/declarations/text_effects/_index.md new file mode 100644 index 0000000..3bf7a08 --- /dev/null +++ b/content/fate_v1/declarations/text_effects/_index.md @@ -0,0 +1,31 @@ +--- +title: Text Effects +--- +Text effects are attributes that can be given to rich text elements. The +effects themselves can take parameters. To avoid errors that would be difficult +to detect, Tonkadur expects text effects to be declared before being used. +Note that multiple text effects can be applied to the same rich text elements, +so there is no need to create text effects that combine other text effects. + +Two text effects cannot have the same name, even if their parameter types +differ. + +Because text effects are handled by the interpreter, it is recommended to +overlay their use by lambda functions. This way, each interpreter can simply +expose its available text effects in a file, and the definition of the lambda +functions can thus be changed according to which interpreter is used without +having to go through the whole document. Furthermore, the name of text effects +exposed by the interpreter might not match the name that would make the most +sense to use within the narrative. + +### TEXT EFFECT +{{< fatecode >}}(declare_text_effect {Identifier} [T0 = TYPE] ... [TN = TYPE]){{< /fatecode >}} +Declares the text effect `{Identifier}`, with parameters of type `[T0]` ... +`[TN]`. + +## Examples +* `(declare_text_effect bold)` +* `(declare_text_effect speaker string)` +* `(declare_text_effect color int int int)` +* `(declare_text_effect font string)` +* `(declare_text_effect speaker_emotion string int)` diff --git a/content/fate_v1/declarations/types/_index.md b/content/fate_v1/declarations/types/_index.md new file mode 100644 index 0000000..9a3677f --- /dev/null +++ b/content/fate_v1/declarations/types/_index.md @@ -0,0 +1,61 @@ +--- +title: Types +--- +Fate is a strongly typed language. + +## Base Types +There are a few base types already defined: + +* `int`: an integer, which is a number *without* fractional component (e.g. `-3`, `0`, `3`). +* `float`: a number *with* a fractional component (e.g. `-3.14`, `0.0`, `3.9931`). +* `bool`: a Boolean (i.e. `(true)` or `(false)`). +* `string`: a list of characters, not including newlines (e.g. `bob`, + `something else`, `日本のもの`, or `الاشياء العربية`). This cannot include + computations: only hardcoded strings. + +* `text`: a list of computations, interpreted as text, which may have + attributes. + +Pointers are also available: +* `(ptr [TYPE])`: a pointer to a memory element of type `[TYPE]` (e.g. `(ptr int)`, `(ptr (ptr string))`). +If you are not familiar with pointers, a pointer is a value corresponding to an address containing a memory element. +Accessing the value of the pointer yields the address, accessing the value pointed to by the value of the pointer yields the memory element. +Pointers to pointers can be made, in which case that memory element is also an address to yet another memory element. +Pointers still have to point to a definite type. Unlike in C, you cannot create a pointer to an unspecified type. + +Two collection types are available: +* `(list [TYPE])` +* `(set [COMPARABLE TYPE])` + +Lambda computations are available: +* `(lambda <r = TYPE> (<a0 = TYPE> ... <an = TYPE>))` is a type corresponding + to a lambda function returning a value of type `r` and taking parameters of + types `a0` ... `an`. + +### Common Type Groupings +* `[NUMBER]` corresponds to `int`, `float`. +* `[COLLECTION]` corresponds to `(list [TYPE])` and `(set [COMPARABLE TYPE])`. +* `[PRIMITIVE]` `int`, `float`, `bool`, `string`, `rich_text`. +* `[COMPARABLE]` corresponds to `int`, `float`, `bool`, `string`, `rich_text`, + and `(ptr [TYPE])`. This indicates types for which operators such as `<` are + defined. + +## Defining Your Own Types + +### Aliasing +{{< fatecode >}}(declare_alias_type [TYPE] {String}){{< /fatecode >}}. +**Effect:** Declares the type `{String}`. If `[TYPE]` is not a `[PRIMITIVE]`, + `[TYPE]` and `{String}` are now two equivalent types. If `[TYPE]` is a + `[PRIMITIVE]`, `{String}` is a subtype of `[TYPE]`. + +### Structures +{{< fatecode >}}(declare_structure_type {String} (<t0 = TYPE> {f0 = String}) ... (<tn = TYPE> {fn = String})){{< /fatecode >}}. + +## Examples + +{{< fatecode >}}(define_structure_type player + (creature creature) + ((list (ptr item)) inventory) + (int money) +) +{{< /fatecode >}} diff --git a/content/fate_v1/declarations/variables/_index.md b/content/fate_v1/declarations/variables/_index.md new file mode 100644 index 0000000..153135c --- /dev/null +++ b/content/fate_v1/declarations/variables/_index.md @@ -0,0 +1,72 @@ +--- +title: Variables +--- +Variables are what hold values. Each variable has a type, which cannot be +changed. + +There are two variable scopes: local and global. A global variable can only be +declared outside of any sequence. A local variable can also be declared within a +sequence. Local variables can only be accessed within their context. In effect, +a local variable declared outside of a sequence cannot be accessed in any +sequence, and local variables cannot be accessed within lambda functions. Local +variables can override global variables within their context. + +The sole exception to accessing a local variable outside its context is done +through the use of pointers. Local variables live as long as the context +that declared them does. Accessed one through a pointer past that point is +likely to result in a runtime error and is, in any case, not to be done. + +Each sequence and lambda function defines its own context and thus does not +share local variable with the others. Instructions which themselves contain +instructions define hierarchies. Local variables defined within a hierarchical +level can be accessed in that level and inner level, but are not shared with +outer levels. For example: + +{{< fatecode >}}(if_else (var my_test) + ( + (local int my_var) ;; my_var (a) + (set my_var 32) + ) + ( + ;; my_var (a) is not defined here. + (local int my_var) ;; my_var (b) + (set my_var 42) + (if (var my_other_test) + ( + (local int my_other_var) + ;; Both my_other_var and my_var (b) are defined here + ) + ) + ;; only my_var (b) is defined here + ) +) +{{< /fatecode >}} + +Generic instruction lists do not generate a new level of hierarchy: + +{{< fatecode >}}( + (local int my_var) +) +;; my_var is still defined. +{{< /fatecode >}} + +### LOCAL VARIABLE +{{< fatecode >}}(local [TYPE] {Identifier}){{< /fatecode >}} +Declares the local variable `{Identifier}` of type `[TYPE]`. + +### GLOBAL VARIABLE +{{< fatecode >}}(global [TYPE] {Identifier}){{< /fatecode >}} +Declares the global variable `{Identifier}` of type `[TYPE]`. + +## Example +{{< fatecode >}}(local string name_of_dog) + +(global (ptr int) index_of_result) + +;; Here is an amusing use of variables: +(global int something_unexpected) +(local int something_unexpected) +;; something_unexpected will not be the same variable within processes (which +;; will use the global variable) and outside of them (which will use the local +;; variable). For code readability reasons, I do not recommend doing this. +{{< /fatecode >}} diff --git a/content/fate_v1/extensions/_index.md b/content/fate_v1/extensions/_index.md new file mode 100644 index 0000000..01f7127 --- /dev/null +++ b/content/fate_v1/extensions/_index.md @@ -0,0 +1,4 @@ +--- +title: Extensions +--- +This page not available yet, sorry. diff --git a/content/fate_v1/instructions/_index.md b/content/fate_v1/instructions/_index.md new file mode 100644 index 0000000..51066d1 --- /dev/null +++ b/content/fate_v1/instructions/_index.md @@ -0,0 +1,48 @@ +--- +title: Instructions +--- +Instructions do not return values, but modify the memory in some way or +interact with the interpreter. Computations are valid instructions, and will be +automatically converted into `[TEXT]` to be displayed. + +### ASSERT +{{< fatecode >}}(assert [BOOL] [TEXT]){{< /fatecode >}} + +Raises the exception `[TEXT]` to the interpreter if `[BOOL]` yields +false. + +### DONE +{{< fatecode >}}(done){{< /fatecode >}} + +Completes the execution of the current sequence. + +### END +{{< fatecode >}}(end){{< /fatecode >}} + +Completes the execution of the script. + +### SET VALUE +{{< fatecode >}}(set [REFERENCE] [COMPUTATION]){{< /fatecode >}} + +Gives the value `[COMPUTATION]` to `[REFERENCE]`. + +### VISIT SEQUENCE +{{< fatecode >}}(visit {String} [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} + +Visits the sequence named `{String}`, with `C0` ... `CN` as arguments. That +sequence does not need to already have been defined. Visiting a sequence means +that the execution of the current sequence continues once the visited sequence +has completed. + +### JUMP TO SEQUENCE +{{< fatecode >}}(jump_to {String} [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} + +Jumps to the sequence named `{String}`, with `C0` ... `CN` as arguments. That +sequence does not need to already have been defined. Jumping to a sequence means +that the execution of the current sequence is replaced by that of the target +sequence. + +### INSTRUCTION LIST +{{< fatecode >}}([C0 = INSTRUCTION] ... [CN = INSTRUCTION]){{< /fatecode >}} + +Instruction corresponding to the execution of `[C0]` ... `[CN]` in order. diff --git a/content/fate_v1/instructions/collections/_index.md b/content/fate_v1/instructions/collections/_index.md new file mode 100644 index 0000000..8d646ee --- /dev/null +++ b/content/fate_v1/instructions/collections/_index.md @@ -0,0 +1,72 @@ +--- +title: Collections +--- +Fate supports two types of collections: `[LIST]`, which are basic, unordered +lists; and `[SET]`, which are ordered lists, but only useable with +`[COMPARABLE]` elements. + +### ADDING A MEMBER +{{< fatecode >}}(add_element! [COMPUTATION*] [COLLECTION VAR]){{< /fatecode >}} + +Adds `[COMPUTATION*]` to `[COLLECTION VAR]`. If `[COLLECTION VAR]` is a +`[LIST]`, the new member is added at the end of the list. Note that +`[COMPUTATION*]` does not support use of the variable shorthand. + +### ADDING A MEMBER AT INDEX +{{< fatecode >}}(add_element_at! [INT] [COMPUTATION*] [LIST VAR]){{< /fatecode >}} + +Adds `[COMPUTATION*]` to `[LIST VAR]` at index `[INT]`. If `[INT]` is less than +0, the element is added at the start of the list, and if `[INT]` is greater or +equal to the size of the list, the element is added at the end of the list. Note +that `[COMPUTATION*]` does not support use of the variable shorthand. + +### ADDING MEMBERS +{{< fatecode >}}(add_all_elements! [COLLECTION] [COLLECTION VAR]){{< /fatecode >}} + +Adds all the elements of `[COLLECTION]` to `[COLLECTION VAR]`. If +`[COLLECTION VAR]` is a `[LIST]`, the new members are added at the end of the +list. + +### EMPTYING COLLECTIONS +{{< fatecode >}}(clear [COLLECTION]){{< /fatecode >}} + +Removes all members of `[COLLECTION]`. + +### REMOVING MEMBER +{{< fatecode >}}(remove [COMPUTATION] [COLLECTION]){{< /fatecode >}} + +Removes the first member of `[COLLECTION]` equal to `[COMPUTATION]`. + +### REMOVING MEMBERS +{{< fatecode >}}(remove_all [COMPUTATION] [COLLECTION]){{< /fatecode >}} + +Removes all instances of `[COMPUTATION]` from `[COLLECTION]`. + +### REMOVING AT INDEX +{{< fatecode >}}(remove_at [INT] [COLLECTION]){{< /fatecode >}} + +Removes the element of `[COLLECTION]` at `[INT]`. + +### REVERSING LISTS +{{< fatecode >}}(reverse [LIST]){{< /fatecode >}} + +Reverses the order of the members of `[LIST]`. + +### FILTER ELEMENTS +{{< fatecode >}}(filter! <LAMBDA BOOL (X)> [X COLLECTION VAR]){{< /fatecode >}} +{{< fatecode >}}(filter! <LAMBDA BOOL (X Y0 ... YN)> [X COLLECTION VAR] [Y0 COMPUTATION*] ... [YN COMPUTATION*]){{< /fatecode >}} +Modifies `[X COLLECTION VAR]` so that only the elements for which +`<LAMBDA BOOL (X)>` returns `true` remain. If the lambda function needs extra +parameters, use the second syntax, which adds those parameters at the end of the +`(filter! ...)` call. Note that the variable shorthand cannot be used for these +extra parameters. + +### FILTER ELEMENTS (INDEXED) +{{< fatecode >}}(indexed_filter! <LAMBDA BOOL (INT X)> [X COLLECTION VAR]){{< /fatecode >}} +{{< fatecode >}}(indexed_filter! <LAMBDA BOOL (INT X Y0 ... YN)> [X COLLECTION VAR] [Y0 COMPUTATION*] ... [YN COMPUTATION*]){{< /fatecode >}} +Modifies `[X COLLECTION VAR]` so that only the elements for which +`<LAMBDA BOOL (INT X)>` (with the `INT` being the element's index) returns +`true` remain. If the lambda function needs extra parameters, use the second +syntax, which adds those parameters at the end of the `(indexed_filter! ...)` +call. Note that the variable shorthand cannot be used for these extra +parameters. diff --git a/content/fate_v1/instructions/conditionals/_index.md b/content/fate_v1/instructions/conditionals/_index.md new file mode 100644 index 0000000..e129b1b --- /dev/null +++ b/content/fate_v1/instructions/conditionals/_index.md @@ -0,0 +1,27 @@ +--- +title: Conditionals +--- +Allow the control of whether to execute instructions or not according to a +computation. Every conditional branch defines its hierarchy level, from the +local variables' point of view. + +### IF +{{< fatecode >}}(if [BOOL] [INSTRUCTION]){{< /fatecode >}} + +Executes `[INSTRUCTION]` if, and only if, `[BOOL]` yields true. + +### IF-ELSE +{{< fatecode >}}(if_else [BOOL] <IF_TRUE = INSTRUCTION> <IF_FALSE = INSTRUCTION>){{< /fatecode >}} + +Executes `<IF_TRUE>` if `[BOOL]` yields true, but `<IF_FALSE>` if it does not. + +### COND +{{< fatecode >}}(cond ([C0 = BOOL] [I0 = INSTRUCTION]) ... ([CN = BOOL] [IN = INSTRUCTION])){{< /fatecode >}} + +Executes `[II]`, such that `[CI]` is the first listed boolean to yield true. + +### SWITCH +{{< fatecode >}}(switch [T = COMPUTATION] ([C0 = COMPUTATION] [I0 = INSTRUCTION]) ... ([CN = COMPUTATION] [IN = INSTRUCTION]) [DEFAULT = INSTRUCTION]){{< /fatecode >}} + +Executes `[II]`, such that `[CI]` is the first listed computation to be equal +to `[T]`. Executes `[DEFAULT]` if there is no such `[CI]`. diff --git a/content/fate_v1/instructions/loops/_index.md b/content/fate_v1/instructions/loops/_index.md new file mode 100644 index 0000000..03c0f3b --- /dev/null +++ b/content/fate_v1/instructions/loops/_index.md @@ -0,0 +1,34 @@ +--- +title: Loops +--- +Allow the repetition of a group of instructions according to a computation. +Every loop body defines its hierarchy level, from the local variables' point of +view. + +### WHILE +{{< fatecode >}}(while [BOOL] [I0 = INSTRUCTION] ... [IM = INSTRUCTION]){{< /fatecode >}} + +Executes `[I0]` ... `[IM]` if, and as long as, `[BOOL]` yields true. + +### DO WHILE +{{< fatecode >}}(do_while [BOOL] [I0 = INSTRUCTION] ... [IM = INSTRUCTION]){{< /fatecode >}} + +Executes `[I0]` ... `[IM]`, and does so again as long as, `[BOOL]` yields +true. + +### FOR +{{< fatecode >}}(for <pre = INSTRUCTION> [BOOL] <post = INSTRUCTION> [I0 = INSTRUCTION] ... [IM = INSTRUCTION]){{< /fatecode >}} + +Executes `<pre>`, then, if and as long as `[BOOL]` yields true, executes +`[I0]` ... `[IM]` followed by `<post>`. + +### FOR EACH +{{< fatecode >}}(foreach [COLLECTION] {String} [I0 = INSTRUCTION] ... [IM = INSTRUCTION]){{< /fatecode >}} + +Executes `[I0]` ... `[IM]` for each member of `[COLLECTION]`, in order. The current +member is stored in a new local variable named `{String}`. + +### BREAK +{{< fatecode >}}(break){{< /fatecode >}} + +Exits the current loop. diff --git a/content/fate_v1/instructions/player_choices/_index.md b/content/fate_v1/instructions/player_choices/_index.md new file mode 100644 index 0000000..a0dba20 --- /dev/null +++ b/content/fate_v1/instructions/player_choices/_index.md @@ -0,0 +1,31 @@ +--- +title: Player Choices +--- +Player choices are the main way to interact with the user, by presenting them +with a list of `[RICH TEXT]` choices, and executing a list of instructions +associated to the choice they have made. + +### CHOICE OPTION +{{< fatecode >}}([TEXT] [I0 = INSTRUCTION] ... [IN = INSTRUCTION]){{< /fatecode >}} + +Adds a choice showing `[RICH TEXT]` to the user, and executing `[I0]` ... `[IN]` +if chosen. + +### CHOICE PROMPT +{{< fatecode >}}(player_choice [C0 = CHOICE] ... [C1 = CHOICE]){{< /fatecode >}} + +Prompts the user to choose between `C0` ... `C1`. `[CHOICE]`. `[CHOICE]` is +either an option as shown above, a [conditional](../conditionals), or a +`for_each` (see [loops](../loops)) with `[CHOICE]` instead of `[INSTRUCTION]`. + +### INTEGER PROMPT +{{< fatecode >}}(prompt_integer [INT REFERENCE] [MIN = INT] [MAX = INT] [TEXT]){{< /fatecode >}} + +Prompts the user for an integer between `[MIN]` and `[MAX]` by displaying the +message `[TEXT]`. The result is stored in `[INT REFERENCE]`. + +### STRING PROMPT +{{< fatecode >}}(prompt_string [STRING REFERENCE] [MIN = INT] [MAX = INT] [TEXT]){{< /fatecode >}} + +Prompts the user for a string of size between `[MIN]` and `[MAX]` by displaying +the message `[TEXT]`. The result is stored in `[STRING REFERENCE]`. diff --git a/content/fate_v1/instructions/references/_index.md b/content/fate_v1/instructions/references/_index.md new file mode 100644 index 0000000..9beb132 --- /dev/null +++ b/content/fate_v1/instructions/references/_index.md @@ -0,0 +1,7 @@ +--- +title: References +--- +### DE-ALLOCATION +{{< fatecode >}}(free [POINTER]){{< /fatecode >}} + +Removes the memory element at `[POINTER]` from the memory. diff --git a/content/images/discord.svg b/content/images/discord.svg new file mode 100644 index 0000000..3d4cb8e --- /dev/null +++ b/content/images/discord.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + height="533.33331" + width="466.06668" + version="1.1" + id="Layer_1" + viewBox="-26.25 -50 88.358475 199.99999" + sodipodi:docname="discord.svg" + inkscape:version="0.92.4 5da689c313, 2019-01-14"> + <metadata + id="metadata1634"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs1632" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="958" + inkscape:window-height="528" + id="namedview1630" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="-0.6" + fit-margin-bottom="0" + inkscape:pagecheckerboard="true" + inkscape:zoom="0.25833333" + inkscape:cx="193.98448" + inkscape:cy="-43.010726" + inkscape:window-x="961" + inkscape:window-y="20" + inkscape:window-maximized="0" + inkscape:current-layer="Layer_1" /> + <style + id="style41">.st0{fill:#fff}</style> + <path + id="path43" + d="m -0.11388706,33.9 c -5.70000004,0 -10.19999994,5 -10.19999994,11.1 0,6.1 4.5999999,11.1 10.19999994,11.1 5.69999996,0 10.20000006,-5 10.20000006,-11.1 0.1,-6.1 -4.5000001,-11.1 -10.20000006,-11.1 z m 36.50000006,0 c -5.7,0 -10.2,5 -10.2,11.1 0,6.1 4.6,11.1 10.2,11.1 5.7,0 10.2,-5 10.2,-11.1 0,-6.1 -4.5,-11.1 -10.2,-11.1 z" + class="st0" + inkscape:connector-curvature="0" + style="fill:#ffffff" /> + <path + id="path45" + d="m 84.986113,-50 h -134 c -11.3,0 -20.5,9.2 -20.5,20.6 v 135.2 c 0,11.4 9.2,20.6 20.5,20.6 h 113.4 l -5.3,-18.5 12.8,11.9 12.1,11.2 21.499997,19 V -29.4 c 0,-11.4 -9.199997,-20.6 -20.499997,-20.6 z m -38.6,130.6 c 0,0 -3.6,-4.3 -6.6,-8.1 13.1,-3.7 18.1,-11.9 18.1,-11.9 -4.1,2.7 -8,4.6 -11.5,5.9 -5,2.1 -9.8,3.5 -14.5,4.3 -9.6,1.8 -18.4,1.3 -25.9000001,-0.1 -5.69999996,-1.1 -10.6,-2.7 -14.7,-4.3 -2.2999999,-0.9 -4.7999999,-2 -7.2999999,-3.4 -0.3,-0.2 -0.6,-0.3 -0.9,-0.5 -0.2,-0.1 -0.3,-0.2 -0.4,-0.3 -1.8,-1 -2.8,-1.7 -2.8,-1.7 0,0 4.8,8 17.4999999,11.8 -3,3.8 -6.7,8.3 -6.7,8.3 C -31.413887,79.9 -39.813887,65.4 -39.813887,65.4 c 0,-32.2 14.4,-58.3 14.4,-58.3 14.4,-10.8 28.0999999,-10.5 28.0999999,-10.5 l 1,1.2 C -14.313887,3 -22.613887,10.9 -22.613887,10.9 c 0,0 2.2,-1.2 5.9,-2.9 C -6.0138871,3.3 2.4861129,2 5.9861129,1.7 c 0.6,-0.1 1.1,-0.2 1.7,-0.2 6.1000001,-0.8 13.0000001,-1 20.2000001,-0.2 9.5,1.1 19.7,3.9 30.1,9.6 0,0 -7.9,-7.5 -24.9,-12.7 l 1.4,-1.6 c 0,0 13.7,-0.3 28.1,10.5 0,0 14.4,26.1 14.4,58.3 0,0 -8.5,14.5 -30.6,15.2 z" + class="st0" + inkscape:connector-curvature="0" + style="fill:#ffffff" /> +</svg> diff --git a/content/images/github.svg b/content/images/github.svg new file mode 100644 index 0000000..081fab1 --- /dev/null +++ b/content/images/github.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="11.493147mm" + height="11.209467mm" + viewBox="0 0 11.493147 11.209467" + version="1.1" + id="svg1567" + inkscape:version="0.92.4 5da689c313, 2019-01-14" + sodipodi:docname="github.svg"> + <defs + id="defs1561" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.35" + inkscape:cx="293.14789" + inkscape:cy="-998.81676" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:pagecheckerboard="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="958" + inkscape:window-height="1059" + inkscape:window-x="961" + inkscape:window-y="20" + inkscape:window-maximized="0" /> + <metadata + id="metadata1564"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(104.77634,126.6464)"> + <g + id="g1028" + transform="matrix(0.35277777,0,0,-0.35277777,-99.030291,-126.6464)"> + <path + d="m 0,0 c -8.995,0 -16.288,-7.293 -16.288,-16.29 0,-7.197 4.667,-13.302 11.14,-15.457 0.815,-0.149 1.112,0.354 1.112,0.786 0,0.386 -0.014,1.411 -0.022,2.77 -4.531,-0.984 -5.487,2.184 -5.487,2.184 -0.741,1.882 -1.809,2.383 -1.809,2.383 -1.479,1.01 0.112,0.99 0.112,0.99 1.635,-0.115 2.495,-1.679 2.495,-1.679 1.453,-2.489 3.813,-1.77 4.741,-1.353 0.148,1.052 0.568,1.77 1.034,2.177 -3.617,0.411 -7.42,1.809 -7.42,8.051 0,1.778 0.635,3.232 1.677,4.371 -0.168,0.412 -0.727,2.068 0.159,4.311 0,0 1.368,0.438 4.48,-1.67 1.299,0.362 2.693,0.542 4.078,0.548 1.383,-0.006 2.777,-0.186 4.078,-0.548 3.11,2.108 4.475,1.67 4.475,1.67 0.889,-2.243 0.33,-3.899 0.162,-4.311 1.044,-1.139 1.675,-2.593 1.675,-4.371 0,-6.258 -3.809,-7.635 -7.438,-8.038 0.585,-0.503 1.106,-1.497 1.106,-3.017 0,-2.177 -0.02,-3.934 -0.02,-4.468 0,-0.436 0.293,-0.943 1.12,-0.784 6.468,2.159 11.131,8.26 11.131,15.455 C 16.291,-7.293 8.997,0 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" + id="path1030" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/content/images/reddit.svg b/content/images/reddit.svg new file mode 100644 index 0000000..dd4332c --- /dev/null +++ b/content/images/reddit.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + height="317.92969" + width="317.92773" + stroke-miterlimit="1.4142" + viewBox="-39.158565 -22.4785 89.913733 53.599369" + version="1.1" + id="svg2284" + sodipodi:docname="reddit.svg" + style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41419995" + inkscape:version="0.92.4 5da689c313, 2019-01-14"> + <metadata + id="metadata2290"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs2288" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="958" + inkscape:window-height="528" + id="namedview2286" + showgrid="false" + inkscape:pagecheckerboard="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="0.73067701" + inkscape:cx="211.99214" + inkscape:cy="266.21581" + inkscape:window-x="961" + inkscape:window-y="20" + inkscape:window-maximized="0" + inkscape:current-layer="svg2284" /> + <path + style="fill:#ffffff;stroke-width:1" + d="M 5.7985782,-40.635958 A 44.957001,44.957001 0 0 0 -39.158565,4.3211838 44.957001,44.957001 0 0 0 5.7985782,49.278329 44.957001,44.957001 0 0 0 50.755169,4.3211838 44.957001,44.957001 0 0 0 5.7985782,-40.635958 Z m 18.7766088,17.81107 c 2.574999,0 4.667499,2.091948 4.667499,4.66695 0,2.576 -2.0925,4.668053 -4.667499,4.668053 -2.522,0 -4.559501,-1.98463 -4.667501,-4.45263 l -9.76419,-2.092366 -3.0043245,14.0560798 c 6.8669995,0.268001 13.0371745,2.359907 17.5431735,5.57890502 1.180001,-1.12699902 2.790343,-1.82391602 4.560341,-1.82391602 3.595002,0 6.544996,2.89699802 6.544996,6.544996 0,2.682001 -1.609149,4.9892 -3.862149,6.0092012 0.107001,0.643001 0.160738,1.340653 0.160738,1.984655 0,10.139 -11.749113,18.294392 -26.2341141,18.294392 -14.4849984,0 -26.2335599,-8.209392 -26.2335599,-18.294392 0,-0.698003 0.05274,-1.341654 0.160739,-1.984655 -2.254002,-1.0200012 -3.862704,-3.2730692 -3.862704,-5.9550682 0,-3.59499898 2.896997,-6.544996 6.544996,-6.544996 a 6.5883,6.5883 0 0 1 4.55979,1.82391602 C -8.4185833,-3.6187642 -2.1415118,-5.7107752 4.8324872,-5.9257742 L 8.1593955,-21.590901 c 0.052999,-0.321998 0.2142158,-0.589665 0.482214,-0.750665 0.215002,-0.160999 0.5369324,-0.21529 0.8589307,-0.16129 l 10.8899138,2.307236 c 0.751001,-1.556 2.360732,-2.629268 4.184733,-2.629268 z M -4.5014071,4.3211838 c -2.5760003,0 -4.668053,2.091948 -4.668053,4.666947 0,2.5750022 2.0920527,4.7210552 4.668053,4.6680532 2.5749991,0 4.66694716,-2.093051 4.66694716,-4.6680532 0,-2.574999 -2.09194806,-4.666947 -4.66694716,-4.666947 z m 20.5999711,0.05413 c -2.575,0 -4.666948,2.091948 -4.666948,4.666947 0,2.5750002 2.091948,4.6669482 4.666948,4.6669482 2.576,0 4.668052,-2.145948 4.668052,-4.6669482 0,-2.574999 -2.092052,-4.666947 -4.668052,-4.666947 z M -4.3948012,19.303032 c -0.3084996,0 -0.6174292,0.120249 -0.8589307,0.361247 -0.4819991,0.483 -0.4819991,1.233758 0,1.716759 3.1659996,3.164998 9.2818909,3.434065 11.1058888,3.434065 1.7700007,0 7.8863391,-0.215067 11.1053371,-3.434065 0.429,-0.483001 0.429,-1.233759 0,-1.716759 -0.483,-0.481999 -1.234309,-0.481999 -1.717307,0 -1.985,2.039003 -6.3300279,2.735874 -9.3880301,2.735874 -3.0579994,0 -7.3495789,-0.696871 -9.3885788,-2.735874 -0.2415016,-0.240998 -0.5498796,-0.361247 -0.8583793,-0.361247 z" + id="circle2278" + inkscape:connector-curvature="0" /> +</svg> diff --git a/content/images/tonkadur_logo_black.svg b/content/images/tonkadur_logo_black.svg new file mode 100644 index 0000000..3745257 --- /dev/null +++ b/content/images/tonkadur_logo_black.svg @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="51.232002mm" + height="16.4846mm" + viewBox="0 0 51.232002 16.4846" + version="1.1" + id="svg8" + inkscape:version="0.92.4 5da689c313, 2019-01-14" + sodipodi:docname="tonkadur_logo_black.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="65.374105" + inkscape:cy="9.8673039" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1918" + inkscape:window-height="1059" + inkscape:window-x="1" + inkscape:window-y="20" + inkscape:window-maximized="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-61.119356,-51.9597)"> + <flowRoot + xml:space="preserve" + id="flowRoot841" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="scale(0.26458333)"><flowRegion + id="flowRegion843"><rect + id="rect845" + width="73.571426" + height="125" + x="574.28571" + y="174.66254" /></flowRegion><flowPara + id="flowPara847"></flowPara></flowRoot> <g + id="g930"> + <text + id="text817" + y="63.331463" + x="67.892647" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.93140244px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + y="63.331463" + x="67.892647" + id="tspan815" + sodipodi:role="line">onkadur</tspan></text> + <text + id="text924" + y="68.4189" + x="61.043156" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;font-family:'Argos George';-inkscape-font-specification:'Argos George';stroke-width:0.26458332px" + y="68.4189" + x="61.043156" + id="tspan922" + sodipodi:role="line">T</tspan></text> + </g> + </g> +</svg> diff --git a/content/images/tonkadur_logo_black_as_path.svg b/content/images/tonkadur_logo_black_as_path.svg new file mode 100644 index 0000000..e09be31 --- /dev/null +++ b/content/images/tonkadur_logo_black_as_path.svg @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="51.232002mm" + height="16.4846mm" + viewBox="0 0 51.232002 16.4846" + version="1.1" + id="svg8" + inkscape:version="0.92.4 5da689c313, 2019-01-14" + sodipodi:docname="tonkadur_logo_black_as_path.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="65.374105" + inkscape:cy="9.8673039" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="958" + inkscape:window-height="1059" + inkscape:window-x="961" + inkscape:window-y="20" + inkscape:window-maximized="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-61.119356,-51.9597)"> + <flowRoot + xml:space="preserve" + id="flowRoot841" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="scale(0.26458333)"><flowRegion + id="flowRegion843"><rect + id="rect845" + width="73.571426" + height="125" + x="574.28571" + y="174.66254" /></flowRegion><flowPara + id="flowPara847" /></flowRoot> <g + id="g930"> + <g + aria-label="onkadur" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.93140244px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="text817"> + <path + d="m 67.985354,60.488438 q 0,-1.220646 0.818915,-2.085914 0.818914,-0.88072 2.02411,-0.88072 1.189743,0 2.03956,0.865269 0.865269,0.865268 0.865269,2.055012 0,0.957975 -0.556244,1.745988 -0.818915,1.14339 -2.441293,1.14339 -1.251549,0 -2.008658,-0.772561 -0.741659,-0.772561 -0.741659,-2.070464 z m 2.750317,-2.379487 q -0.695305,0.09271 -1.035232,1.004329 -0.231768,0.618049 -0.231768,1.514219 0,0.88072 0.370829,1.452415 0.432635,0.664403 1.267,0.664403 0.710757,0 1.081586,-0.664403 0.293573,-0.525341 0.293573,-1.297902 0,-0.664403 -0.216317,-1.189744 -0.278122,-0.710756 -0.849817,-0.710756 -0.139061,0 -0.355378,0.123609 -0.216317,0.12361 -0.231768,0.12361 v -0.494439 q 0.293573,-0.216317 0.478987,-0.478988 -0.139061,-0.0309 -0.278122,-0.04635 -0.154512,-0.01545 -0.293573,0 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path829" /> + <path + d="m 74.352222,57.954438 q 0.09271,0 0.818915,-0.154512 0.50989,-0.108158 0.788012,-0.108158 0.169963,0 0.324476,0.231768 0.07726,0.12361 0.216317,0.370829 0.200865,-0.278122 0.834365,-0.448085 0.540793,-0.154512 0.973427,-0.154512 0.849817,0 0.927073,0.01545 0.648952,0.0618 0.648952,0.772561 v 2.348585 q 0,0.803464 0.417183,1.63783 0.0309,0.07726 0.556244,0.988878 h -1.375159 q -0.664402,0 -0.865268,-0.911622 -0.09271,-0.417183 -0.09271,-1.421513 v -0.803463 q 0.01545,-0.108158 0.01545,-0.278122 0.04635,-1.931402 -0.726208,-1.931402 -0.370829,0 -0.834366,0.169963 -0.618048,0.216317 -0.618048,0.571695 v 3.1675 q 0,0.772561 0.293573,1.251549 h -1.761439 q 0.12361,-0.772561 0.12361,-2.843024 0,-1.00433 -0.0309,-1.962305 -0.216317,-0.04635 -0.309024,-0.09271 -0.324476,-0.154512 -0.324476,-0.417183 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path831" /> + <path + d="m 81.382286,55.18867 q 0.849817,-0.525341 1.792342,-1.467866 l -0.169964,5.979622 q 0.478988,-0.478988 1.282451,-0.757109 0.231769,-0.07726 1.452415,-0.386281 0.664402,-0.247219 0.911622,-0.896171 0.540793,0.355378 0.540793,0.896171 0,0.339927 -0.37083,0.50989 -0.247219,0.07726 -0.788012,0.12361 -0.540793,0.0309 -0.741658,0.108159 0.834365,1.931402 1.220646,2.642158 0.200866,0.355378 0.880719,1.483317 -0.432634,0.06181 -0.957975,0.06181 -1.050683,0 -1.483317,-1.297902 -0.463537,-1.359708 -0.988878,-2.549452 -0.478988,0.139061 -0.927073,0.494439 0.01545,0.834366 0.01545,1.653281 0.0309,0.988878 0.154512,1.637829 h -1.77689 q 0.01545,-0.01545 0.200866,-0.602597 0.09271,-0.293574 0.09271,-0.463537 v -2.456744 q 0,-0.231768 0,-0.494439 0.01545,-0.293573 0.01545,-0.309024 0.01545,-3.383817 -0.355378,-3.909159 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path833" /> + <path + d="m 88.144366,60.565695 q 0,-1.205196 0.710756,-2.055013 0.726207,-0.865268 1.9005,-0.865268 0.216317,0 0.618049,0.07726 0.417183,0.07726 0.6335,0.07726 0.309024,0 0.417183,-0.154512 0.818914,0.370829 1.406061,0.571695 -0.24722,1.050683 -0.24722,2.394939 0,1.761439 0.432634,2.688512 -0.169963,-0.0309 -0.525341,-0.108158 -0.339927,-0.07726 -0.540793,-0.07726 -0.324475,0 -0.788012,0.09271 -0.911622,0.185415 -1.267,0.185415 -1.236098,0 -1.993207,-0.772561 -0.75711,-0.788012 -0.75711,-2.055012 z m 3.136598,-2.441293 q -0.865269,0 -1.313354,0.679854 -0.370829,0.571695 -0.370829,1.483317 0,1.328804 0.772561,2.039561 0.525341,0.494439 1.004329,0.494439 0.788012,0 0.788012,-0.973427 V 58.912414 Q 91.914464,58.448877 91.86811,58.387073 91.651793,58.124402 91.280964,58.124402 Z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path835" /> + <path + d="m 100.17531,53.689902 q 0.21632,0.556244 0.20087,1.637829 -0.0155,0.618049 -0.0618,2.889378 -0.0618,2.14772 -0.0463,2.904829 0,0.185415 0.10816,0.788013 0.13906,0.834366 0.47899,1.328805 -0.71076,-0.12361 -1.313356,-0.12361 -0.417183,0 -1.174293,0.12361 -0.75711,0.108158 -1.097037,0.108158 H 97.08507 q -1.066134,0 -1.715086,-0.834366 -0.571695,-0.772561 -0.571695,-1.869597 0,-1.050683 0.556244,-1.977756 0.6335,-1.050683 1.622378,-1.050683 0.185415,0 0.262671,0.01545 0.370829,0.06181 0.896171,0.185414 0.448085,0.154513 0.757109,0.478988 v -0.741658 q 0.01545,-0.09271 0.01545,-0.216317 0.01545,-1.328805 -0.309025,-2.364037 0.417183,-0.309024 0.896171,-0.741658 0.262671,-0.24722 0.67985,-0.540793 z m -2.549448,4.511756 q -0.664402,0 -1.004329,0.741659 -0.262671,0.556243 -0.262671,1.313353 0,1.205195 0.24722,1.715086 0.355378,0.710756 1.282451,0.710756 0.50989,0 1.004329,-0.07726 v -3.553781 q 0,-0.38628 -0.463536,-0.6335 -0.401732,-0.216317 -0.803464,-0.216317 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path837" /> + <path + d="m 104.74332,57.84628 1.9314,0.0309 v 4.697171 q 0,0.401732 0.33993,0.741659 h -1.8696 v -0.293574 q 0,-0.216317 0.0155,-0.324475 0,-0.185415 -0.0155,-0.24722 l -0.58714,0.07726 q -0.20087,0.0309 -1.32881,0.571696 -0.44808,0.216317 -0.6335,0.216317 -0.78801,0 -0.78801,-0.679854 v -3.631037 q 0,-0.463536 -0.55624,-1.158841 h 1.63783 q 0.29357,0.417183 0.29357,0.679854 l -0.0309,3.801 q 0,0.293573 0.20086,0.293573 0.24722,-0.07726 1.01978,-0.386281 0.50989,-0.200866 0.86527,-0.200866 v -3.306561 q 0,-0.309024 -0.49444,-0.880719 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path839" /> + <path + d="m 109.94097,58.139853 q 0.64895,-0.448085 0.6953,-0.478988 0.50989,-0.293573 0.92708,-0.293573 0.78801,0 0.78801,0.772561 0,0.463537 -0.30903,0.741659 -0.30902,0.278122 -0.77256,0.278122 0.29358,-0.339927 0.29358,-0.540793 0,-0.169964 -0.20087,-0.278122 -0.18541,-0.108159 -0.38628,-0.108159 -0.67985,0 -1.03523,0.896171 -0.24722,0.6335 -0.24722,1.467866 0,0.88072 0.30902,1.591476 0.38628,0.865268 0.43264,1.14339 -1.28245,0 -1.63783,-0.231768 -0.46354,-0.309025 -0.46354,-1.436964 v -2.843024 q 0,-0.432634 -0.29357,-0.865269 -0.13906,-0.200865 -0.29358,-0.355378 0.35538,-0.04635 1.18975,-0.04635 h 0.27812 q 0.44809,0 0.55624,0.216317 0.10816,0.200866 0.16997,0.370829 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path841" /> + </g> + <g + aria-label="T" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="text924"> + <path + d="m 67.520156,52.3661 q 0.127,0 2.286,0.127 0.8636,0.0508 1.4224,0.0508 1.955799,0 3.860799,-0.5842 -0.1524,1.397 -1.2192,2.2606 -1.0668,0.8636 -2.489199,0.8636 -1.1938,0 -3.9116,-1.016 -2.7178,-1.0414 -3.81,-1.0414 -1.9304,0 -1.9304,1.9304 0,0.8128 0.6096,1.3716 0.3556,0.3302 1.3208,0.7874 -0.508,0.889 -0.7874,0.889 -1.0414,-0.3556 -1.4478,-1.143 -0.3048,-0.5842 -0.3048,-1.3716 0,-1.27 0.508,-1.9812 0.508,-0.7112 1.7018,-1.143 0.4064,-0.1524 1.524,-0.1524 1.1938,0 2.159,0.0762 0.1016,0 0.508,0.0762 z m -4.318,9.1694 q 0,-1.5494 0.9652,-3.81 1.0414,-2.3622 2.2352,-3.175 -0.9652,2.9718 -0.9652,4.2672 0,2.3622 1.1684,4.3942 1.7018,2.9972 5.1054,2.9972 0.635,0 1.549399,-0.3556 0.9398,-0.381 1.397,-0.4064 -0.8128,1.27 -2.565399,2.1336 -1.7272,0.8636 -3.302,0.8636 -1.778,0 -3.5306,-1.8288 -2.0574,-2.1336 -2.0574,-5.08 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;font-family:'Argos George';-inkscape-font-specification:'Argos George';stroke-width:0.26458332px" + id="path844" /> + </g> + </g> + </g> +</svg> diff --git a/content/images/tonkadur_logo_white.svg b/content/images/tonkadur_logo_white.svg new file mode 100644 index 0000000..f17e213 --- /dev/null +++ b/content/images/tonkadur_logo_white.svg @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="51.232002mm" + height="16.4846mm" + viewBox="0 0 51.232002 16.4846" + version="1.1" + id="svg8" + inkscape:version="0.92.4 5da689c313, 2019-01-14" + sodipodi:docname="tonkadur_logo_white.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="65.374106" + inkscape:cy="9.8673018" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1918" + inkscape:window-height="1059" + inkscape:window-x="1" + inkscape:window-y="20" + inkscape:window-maximized="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-61.119356,-51.9597)"> + <flowRoot + xml:space="preserve" + id="flowRoot841" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="scale(0.26458333)"><flowRegion + id="flowRegion843"><rect + id="rect845" + width="73.571426" + height="125" + x="574.28571" + y="174.66254" /></flowRegion><flowPara + id="flowPara847"></flowPara></flowRoot> <g + id="g930" + style="fill:#ffffff"> + <text + id="text817" + y="63.331463" + x="67.892647" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.93140244px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + y="63.331463" + x="67.892647" + id="tspan815" + sodipodi:role="line">onkadur</tspan></text> + <text + id="text924" + y="68.4189" + x="61.043156" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;stroke-width:0.26458332px" + y="68.4189" + x="61.043156" + id="tspan922" + sodipodi:role="line">T</tspan></text> + </g> + </g> +</svg> diff --git a/content/images/tonkadur_logo_white_as_path.svg b/content/images/tonkadur_logo_white_as_path.svg new file mode 100644 index 0000000..04c3039 --- /dev/null +++ b/content/images/tonkadur_logo_white_as_path.svg @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="51.232002mm" + height="16.4846mm" + viewBox="0 0 51.232002 16.4846" + version="1.1" + id="svg8" + inkscape:version="0.92.4 5da689c313, 2019-01-14" + sodipodi:docname="tonkadur_logo_white_as_path.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="65.374106" + inkscape:cy="9.8673018" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1918" + inkscape:window-height="1059" + inkscape:window-x="1" + inkscape:window-y="20" + inkscape:window-maximized="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-61.119356,-51.9597)"> + <flowRoot + xml:space="preserve" + id="flowRoot841" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + transform="scale(0.26458333)"><flowRegion + id="flowRegion843"><rect + id="rect845" + width="73.571426" + height="125" + x="574.28571" + y="174.66254" /></flowRegion><flowPara + id="flowPara847" /></flowRoot> <g + id="g930" + style="fill:#ffffff"> + <g + aria-label="onkadur" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.93140244px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="text817"> + <path + d="m 67.985354,60.488438 q 0,-1.220646 0.818915,-2.085914 0.818914,-0.88072 2.02411,-0.88072 1.189743,0 2.03956,0.865269 0.865269,0.865268 0.865269,2.055012 0,0.957975 -0.556244,1.745988 -0.818915,1.14339 -2.441293,1.14339 -1.251549,0 -2.008658,-0.772561 -0.741659,-0.772561 -0.741659,-2.070464 z m 2.750317,-2.379487 q -0.695305,0.09271 -1.035232,1.004329 -0.231768,0.618049 -0.231768,1.514219 0,0.88072 0.370829,1.452415 0.432635,0.664403 1.267,0.664403 0.710757,0 1.081586,-0.664403 0.293573,-0.525341 0.293573,-1.297902 0,-0.664403 -0.216317,-1.189744 -0.278122,-0.710756 -0.849817,-0.710756 -0.139061,0 -0.355378,0.123609 -0.216317,0.12361 -0.231768,0.12361 v -0.494439 q 0.293573,-0.216317 0.478987,-0.478988 -0.139061,-0.0309 -0.278122,-0.04635 -0.154512,-0.01545 -0.293573,0 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path829" /> + <path + d="m 74.352222,57.954438 q 0.09271,0 0.818915,-0.154512 0.50989,-0.108158 0.788012,-0.108158 0.169963,0 0.324476,0.231768 0.07726,0.12361 0.216317,0.370829 0.200865,-0.278122 0.834365,-0.448085 0.540793,-0.154512 0.973427,-0.154512 0.849817,0 0.927073,0.01545 0.648952,0.0618 0.648952,0.772561 v 2.348585 q 0,0.803464 0.417183,1.63783 0.0309,0.07726 0.556244,0.988878 h -1.375159 q -0.664402,0 -0.865268,-0.911622 -0.09271,-0.417183 -0.09271,-1.421513 v -0.803463 q 0.01545,-0.108158 0.01545,-0.278122 0.04635,-1.931402 -0.726208,-1.931402 -0.370829,0 -0.834366,0.169963 -0.618048,0.216317 -0.618048,0.571695 v 3.1675 q 0,0.772561 0.293573,1.251549 h -1.761439 q 0.12361,-0.772561 0.12361,-2.843024 0,-1.00433 -0.0309,-1.962305 -0.216317,-0.04635 -0.309024,-0.09271 -0.324476,-0.154512 -0.324476,-0.417183 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path831" /> + <path + d="m 81.382286,55.18867 q 0.849817,-0.525341 1.792342,-1.467866 l -0.169964,5.979622 q 0.478988,-0.478988 1.282451,-0.757109 0.231769,-0.07726 1.452415,-0.386281 0.664402,-0.247219 0.911622,-0.896171 0.540793,0.355378 0.540793,0.896171 0,0.339927 -0.37083,0.50989 -0.247219,0.07726 -0.788012,0.12361 -0.540793,0.0309 -0.741658,0.108159 0.834365,1.931402 1.220646,2.642158 0.200866,0.355378 0.880719,1.483317 -0.432634,0.06181 -0.957975,0.06181 -1.050683,0 -1.483317,-1.297902 -0.463537,-1.359708 -0.988878,-2.549452 -0.478988,0.139061 -0.927073,0.494439 0.01545,0.834366 0.01545,1.653281 0.0309,0.988878 0.154512,1.637829 h -1.77689 q 0.01545,-0.01545 0.200866,-0.602597 0.09271,-0.293574 0.09271,-0.463537 v -2.456744 q 0,-0.231768 0,-0.494439 0.01545,-0.293573 0.01545,-0.309024 0.01545,-3.383817 -0.355378,-3.909159 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path833" /> + <path + d="m 88.144366,60.565695 q 0,-1.205196 0.710756,-2.055013 0.726207,-0.865268 1.9005,-0.865268 0.216317,0 0.618049,0.07726 0.417183,0.07726 0.6335,0.07726 0.309024,0 0.417183,-0.154512 0.818914,0.370829 1.406061,0.571695 -0.24722,1.050683 -0.24722,2.394939 0,1.761439 0.432634,2.688512 -0.169963,-0.0309 -0.525341,-0.108158 -0.339927,-0.07726 -0.540793,-0.07726 -0.324475,0 -0.788012,0.09271 -0.911622,0.185415 -1.267,0.185415 -1.236098,0 -1.993207,-0.772561 -0.75711,-0.788012 -0.75711,-2.055012 z m 3.136598,-2.441293 q -0.865269,0 -1.313354,0.679854 -0.370829,0.571695 -0.370829,1.483317 0,1.328804 0.772561,2.039561 0.525341,0.494439 1.004329,0.494439 0.788012,0 0.788012,-0.973427 V 58.912414 Q 91.914464,58.448877 91.86811,58.387073 91.651793,58.124402 91.280964,58.124402 Z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path835" /> + <path + d="m 100.17531,53.689902 q 0.21632,0.556244 0.20087,1.637829 -0.0155,0.618049 -0.0618,2.889378 -0.0618,2.14772 -0.0463,2.904829 0,0.185415 0.10816,0.788013 0.13906,0.834366 0.47899,1.328805 -0.71076,-0.12361 -1.313356,-0.12361 -0.417183,0 -1.174293,0.12361 -0.75711,0.108158 -1.097037,0.108158 H 97.08507 q -1.066134,0 -1.715086,-0.834366 -0.571695,-0.772561 -0.571695,-1.869597 0,-1.050683 0.556244,-1.977756 0.6335,-1.050683 1.622378,-1.050683 0.185415,0 0.262671,0.01545 0.370829,0.06181 0.896171,0.185414 0.448085,0.154513 0.757109,0.478988 v -0.741658 q 0.01545,-0.09271 0.01545,-0.216317 0.01545,-1.328805 -0.309025,-2.364037 0.417183,-0.309024 0.896171,-0.741658 0.262671,-0.24722 0.67985,-0.540793 z m -2.549448,4.511756 q -0.664402,0 -1.004329,0.741659 -0.262671,0.556243 -0.262671,1.313353 0,1.205195 0.24722,1.715086 0.355378,0.710756 1.282451,0.710756 0.50989,0 1.004329,-0.07726 v -3.553781 q 0,-0.38628 -0.463536,-0.6335 -0.401732,-0.216317 -0.803464,-0.216317 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path837" /> + <path + d="m 104.74332,57.84628 1.9314,0.0309 v 4.697171 q 0,0.401732 0.33993,0.741659 h -1.8696 v -0.293574 q 0,-0.216317 0.0155,-0.324475 0,-0.185415 -0.0155,-0.24722 l -0.58714,0.07726 q -0.20087,0.0309 -1.32881,0.571696 -0.44808,0.216317 -0.6335,0.216317 -0.78801,0 -0.78801,-0.679854 v -3.631037 q 0,-0.463536 -0.55624,-1.158841 h 1.63783 q 0.29357,0.417183 0.29357,0.679854 l -0.0309,3.801 q 0,0.293573 0.20086,0.293573 0.24722,-0.07726 1.01978,-0.386281 0.50989,-0.200866 0.86527,-0.200866 v -3.306561 q 0,-0.309024 -0.49444,-0.880719 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path839" /> + <path + d="m 109.94097,58.139853 q 0.64895,-0.448085 0.6953,-0.478988 0.50989,-0.293573 0.92708,-0.293573 0.78801,0 0.78801,0.772561 0,0.463537 -0.30903,0.741659 -0.30902,0.278122 -0.77256,0.278122 0.29358,-0.339927 0.29358,-0.540793 0,-0.169964 -0.20087,-0.278122 -0.18541,-0.108159 -0.38628,-0.108159 -0.67985,0 -1.03523,0.896171 -0.24722,0.6335 -0.24722,1.467866 0,0.88072 0.30902,1.591476 0.38628,0.865268 0.43264,1.14339 -1.28245,0 -1.63783,-0.231768 -0.46354,-0.309025 -0.46354,-1.436964 v -2.843024 q 0,-0.432634 -0.29357,-0.865269 -0.13906,-0.200865 -0.29358,-0.355378 0.35538,-0.04635 1.18975,-0.04635 h 0.27812 q 0.44809,0 0.55624,0.216317 0.10816,0.200866 0.16997,0.370829 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15.45121956px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.78100002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + id="path841" /> + </g> + <g + aria-label="T" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:125%;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="text924"> + <path + d="m 67.520156,52.3661 q 0.127,0 2.286,0.127 0.8636,0.0508 1.4224,0.0508 1.955799,0 3.860799,-0.5842 -0.1524,1.397 -1.2192,2.2606 -1.0668,0.8636 -2.489199,0.8636 -1.1938,0 -3.9116,-1.016 -2.7178,-1.0414 -3.81,-1.0414 -1.9304,0 -1.9304,1.9304 0,0.8128 0.6096,1.3716 0.3556,0.3302 1.3208,0.7874 -0.508,0.889 -0.7874,0.889 -1.0414,-0.3556 -1.4478,-1.143 -0.3048,-0.5842 -0.3048,-1.3716 0,-1.27 0.508,-1.9812 0.508,-0.7112 1.7018,-1.143 0.4064,-0.1524 1.524,-0.1524 1.1938,0 2.159,0.0762 0.1016,0 0.508,0.0762 z m -4.318,9.1694 q 0,-1.5494 0.9652,-3.81 1.0414,-2.3622 2.2352,-3.175 -0.9652,2.9718 -0.9652,4.2672 0,2.3622 1.1684,4.3942 1.7018,2.9972 5.1054,2.9972 0.635,0 1.549399,-0.3556 0.9398,-0.381 1.397,-0.4064 -0.8128,1.27 -2.565399,2.1336 -1.7272,0.8636 -3.302,0.8636 -1.778,0 -3.5306,-1.8288 -2.0574,-2.1336 -2.0574,-5.08 z" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;font-family:'Argos George';-inkscape-font-specification:'Argos George';fill:#ffffff;stroke-width:0.26458332px" + id="path844" /> + </g> + </g> + </g> +</svg> diff --git a/content/learn/01.start/_index.md b/content/learn/01.start/_index.md new file mode 100644 index 0000000..1741772 --- /dev/null +++ b/content/learn/01.start/_index.md @@ -0,0 +1,43 @@ +--- +menuTitle: "Starting" +title: "Writing a story in Fate" +weight: 1 +--- +* Create a folder for your story. This is not mandatory, but helps keeping + track of the created files. +* Open up your favorite text editor, and write in `main.fate`: + +{{< fatecode >}}(fate_version 1) +Once upon a time, starting a story with these words wasn't considered +a cliche. Starting in a tavern might also not be seen as very +original. Having the main character be an street orphan, raised by +some mysterious sage all to end up as a mercenary with an uncommonly +strong sense of honor probably isn't going to lead to any praises for +novelty either. Maybe you should drink to that. +(newline) +Or maybe you shouldn't. This isn't your first mug. Not your second +either. Drinking to forget that you are a stereotypical hero isn't +going to solve anything. Worse, the alcoholic trait is part of the +image. +(newline) +As you contemplate your own pointless description, your gaze leaves +what turns out to be an already empty glass in your hand and finds the +barman. +(end) +{{< /fatecode >}} + +This is a very minimal story in Fate. Let's look at what is it made of: + +* The `(fate_version 1)` line must be at the top of every file. It is just + there to inform the compiler of the used language version. It has no effect on + the output. +* The text is mostly printed out as-is: newlines, tabs and spaces are + considered to be a single space. No matter how many of them follow. This + makes indentation have no effect on the output text. Furthermore such + characters preceding text are ignored. +* `(newline)` inserts a newline in the output. +* `(end)` signals the end of the story. It needs to be there. + +With this, you know how to make a static, purely textual story in Fate. Our poor +protagonist needs a refill, so we need to introduce +[Player Choices](/learn/choices) next. diff --git a/content/learn/02.choices/_index.md b/content/learn/02.choices/_index.md new file mode 100644 index 0000000..a5ba4d7 --- /dev/null +++ b/content/learn/02.choices/_index.md @@ -0,0 +1,71 @@ +--- +menuTitle: "Player Choices" +title: "Asking the Player" +weight: 2 +--- +In [the previous step](/learn/start), we saw a minimal text story written in Fate. +Now, we need to interact with the player. + +There are three ways to interact with the player: +* Asking them to choose between options. +* Prompting them for an integer. +* Prompting them for a string. + +The last two require notions that haven't been introduced yet, so let's give +the player a simple choice instead: + +**main.fate:** +{{< fatecode >}}(fate_version 1) +Once upon a time, starting a story with these words wasn't considered +a cliche. Starting in a tavern might also not be seen as very +original. Having the main character be an street orphan, raised by +some mysterious sage all to end up as a mercenary with an uncommonly +strong sense of honor probably isn't going to lead to any praises for +novelty either. Maybe you should drink to that. +(newline) +Or maybe you shouldn't. This isn't your first mug. Not your second +either. Drinking to forget that you are a stereotypical hero isn't +going to solve anything. Worse, the alcoholic trait is part of the +image. +(newline) +As you contemplate your own pointless description, your gaze leaves +what turns out to be an already empty glass in your hand and finds the +barman. + +(player_choice + ( + ( Ask the barman for a refill ) + Staring straight at the barman, you raise your glass and + proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + ) + ( + ( Fall asleep ) + Deciding to break away from the expected storyline, you promptly + fall asleep. + ) + ( + ( Resolve whether P=NP ) + Sadly, the output for this choice would require some concepts + that haven't been introduced yet, so let's never mention it + again. + ) +) + +(end) +{{< /fatecode >}} + +In this version, the player is able to interact with the story: once +`player_choice` is reached, the output stops and the player is presented with +options. Here, three choices are available. A choice is made of a label and a +list of instructions. The label is the text which is displayed to player (for +example `Fall asleep`). The list of instructions is what will be performed if +that choice is selected. Putting text where instructions are expected simply +outputs the text. In fact, all the content of the previous step was +instructions. Once a choice has been made and the instructions have been +performed, the story continues past the `player_choice` construct. + +But something critical is missing. Indeed, how can you get a refill without +money? Just how much money does our hero have? Will it be enough to quench that +terrible thirst? Let's [introduce variables](/learn/variables). diff --git a/content/learn/03.variables/default.md b/content/learn/03.variables/default.md new file mode 100644 index 0000000..6c2cdf4 --- /dev/null +++ b/content/learn/03.variables/default.md @@ -0,0 +1,90 @@ +--- +menuTitle: Variables +title: "Adding Variables" +weight: 3 +--- +In [the previous step](/learn/start), we introduced player choices. Dynamic +content is here, but it is not going far without variables. + +Fate is a strongly typed language, meaning that variables **must** be assigned +a precise type and cannot deviate from it. + +Variables have to be declared before being used. Let us keep things simple for +now, and declare variables using the `local` instruction. The alternative is +`global`. The difference between the two being about access from other +contexts, something that is introduced in the next chapter. + +We are trying to add a variable that corresponds to money. An `int` is thus +appropriate. + +**main.fate:** + + (fate_version 1) + + (local int hero_money) + (local int price_of_booze) + + (set hero_money 42) + (set price_of_booze 12) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + Staring straight at the barman, you raise your glass and + proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the + beer being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (set hero_money + (- (var hero_money) (var price_of_booze)) + ) + ) + ( + ( Fall asleep ) + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that + someone stole all your money. + (set hero_money 0) + ) + ) + + (end) + +* `(local int hero_money)` declares an `int` variable with the name + `hero_money`. +* `(set hero_money 42)` sets the value of the `hero_money` variable to 42. +* `(var price_of_booze)` returns the current value of the `price_of_booze` + variable. +* `(- (var hero_money) (var price_of_booze))` returns the result of subtracting + the value of `price_of_booze` to the value of `hero_money`. All operators + use a prefixed form. + +`local`, `set`, `player_choice`, and `end`, are instructions. Instructions do +not return any value. Thus, they do not add to the printed text. + +Having to continue the story from within the `player_choice` structure is going +to get tedious very fast. Let's [introduce sequences](/learn/sequences). diff --git a/content/learn/04.sequences/default.md b/content/learn/04.sequences/default.md new file mode 100644 index 0000000..cecbff8 --- /dev/null +++ b/content/learn/04.sequences/default.md @@ -0,0 +1,123 @@ +--- +menuTitle: Sequences +title: "Introducing Sequences" +weight: 4 +--- +In [the previous step](/learn/variables), we introduced variables. The story is +starting to have branches, but writing them from within a `player_choice` +construct is awkward. To resolve this, *sequences* are introduced. + +Sequences are named lists of instructions. They do *not* have to be defined +before being used, but the definition must be found at some point. Since +instructions do not return any value, neither do sequences. + +Sequences define their own context, meaning that `local` variables from outside +the sequence cannot be accessed and, conversely, `local` variables from the +sequence cannot be accessed outside of it. + +Entering a sequence can be done in two ways: +* By visiting, in which case the sequence is executed and the story continues. +* By jumping, in which case the sequence replaces the current story execution. + +When in doubt, prefer visiting to jumping, as the latter is mainly intended for +optimization purposes. + +Sequences can be entered again from themselves, making recursion possible. + +Sequences can take parameters. + + +**main.fate:** + + (fate_version 1) + + (global int hero_money) + + (set hero_money 42) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero_money) (var cost)) + ) + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + ) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero_money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + + (end) + +* `(visit get_a_refill)` makes a visit to the sequence `get_a_refill`. Since + that sequence does not take parameters, none need to be provided. +* `(jump_to fall_asleep)` stops the execution of the main instruction list and + proceeds to using the sequence `fall_asleep` instead. Here again, no + arguments are expected by `fall_asleep`. Notice how the `fall_asleep` sequence + ends with `(end)`: since there is no return from it, the original `(end)` + would not be reached and thus a new one is required to end the story. +* `(visit pay (var price_of_booze))` makes a visit to the `pay` sequence, which + does require a parameter. +* `(global int hero_money)` has replaced `(local int hero_money)`, because that + variable needs to be accessible from within the sequences. +* `(local int price_of_booze)` has been moved to the `get_a_refill` sequence, + as there is no reason to have it be defined across the whole story. +* The `pay` sequence cannot directly access the `price_of_booze` variable, as + it is `local` and from another sequence, hence the use of a parameter to + communicate the correct amount. + +With this, the `player_choice` have become much more readable. However, the file +itself is starting to become hard to read. The solution is then to [split the +content into multiple files](/learn/files). diff --git a/content/learn/05.files/default.md b/content/learn/05.files/default.md new file mode 100644 index 0000000..da78206 --- /dev/null +++ b/content/learn/05.files/default.md @@ -0,0 +1,113 @@ +--- +menuTitle: Files +title: "Splitting into Multiple Files" +weight: 5 +--- +In [the previous step](/learn/sequences), we introduced sequences. This made +branching the story easier, but having many sequences in a file made the flow +difficult to read. To resolve this, the content is going to be split into +multiple files. + +By using `(require path_to_file)`, the content of `path_to_file` is explored, +but only if that file has not already been explored. + +* Create a new file, `data.fate`, with the following content: + + (fate_version 1) + + (global int hero_money) + + (set hero_money 42) + +* Create a new file, `actions.fate`, with the following content: + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero_money) (var cost)) + ) + ) + +* Create a new file, `get_a_refill.fate`, with the following content: + + (fate_version 1) + + (require actions.fate) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + ) + +* Create a new file, `falling_asleep.fate`, with the following content: + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero_money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) + +With this, the story is much more easy to follow. Let's continue by looking +at [the actually-not-scary-at-all pointers](/learn/pointers). diff --git a/content/learn/06.pointers/default.md b/content/learn/06.pointers/default.md new file mode 100644 index 0000000..a4108bb --- /dev/null +++ b/content/learn/06.pointers/default.md @@ -0,0 +1,171 @@ +--- +menuTitle: Pointers +title: "Addressing Pointers" +weight: 6 +--- +In [the previous step](/learn/files), we split the story into multiple files +to make it more readable. Now, we'll see pointers, because they were needed for +two features that were glossed over in what was presented before: +* Using sequences as imperative procedures. +* Prompting the user for content. + +A pointer is a value that indicates a location in memory where some +data is stored. This can be used as a value that will tell some instruction +where to put data. + +Pointers have types. For example, `(ptr int)` is the type corresponding to +pointers to `int` data. + +To compute a pointer to a variable `v`, simply write `(ptr v)`. + +Given a pointer `p`, the variable being pointed to can be referred to using +`(at p)`. + +**data.fate:** + + (fate_version 1) + + (global int hero_money) + (global string hero_name) + + (set hero_money 42) + +**get_a_refill.fate:** + + (fate_version 1) + + (require data.fate) + (require actions.fate) + + (define_sequence lower_price_of_booze + ( + ((ptr int) price_pointer) + (int decrease) + ) + Great! The price of booze just lowered from (at price_pointer) + (set (at price_pointer) + (- + (at price_pointer) + (var decrease) + ) + ) + to (at price_pointer)! + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + (newline) + The barman sighs, then asks: + (prompt_string (ptr hero_name) 2 64 What is your name, then, hero?) + (var hero_name)? + (newline) + The barman looks surprised. + (newline) + (visit lower_price_of_booze (ptr price_of_booze) 4) + (newline) + "I have heard of you, (var hero_name)," the barman exclaims, "I have + a quest for you!" + (newline) + It's your turn to sigh. + (newline) + The barman hands you a bag, and says: + (newline) + "Take this pre-payment and head to the smithy." + (newline) + ) + +* `(prompt_string (ptr hero_name) 2 64 What is your name, then, hero?)` prompts + the player with `What is your name, then, hero?` and expects a string input + with a size between `2` and `64` characters. This input is stored at `(ptr + hero_name)`, which means that `hero_name` takes that value. +* The `lower_price_of_booze` sequence shows how pointers can be used to modify + variables outside of a sequence's range. +* `(var price_of_booze)` is equivalent to `(at (ptr price_of_booze))`. + +Our hero, who'll obviously end up being the lost heir of some royal family, +should already have good equipment. It would be useful to have a character +sheet, so [let's create one](/learn/structures). + +---- + +## Unchanged Files +**actions.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero_money) (var cost)) + ) + ) + +**falling_asleep.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero_money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) diff --git a/content/learn/07.structures/default.md b/content/learn/07.structures/default.md new file mode 100644 index 0000000..a87af08 --- /dev/null +++ b/content/learn/07.structures/default.md @@ -0,0 +1,201 @@ +--- +menuTitle: Structures +title: "Structuring the Data" +weight: 7 +--- +In [the previous step](/learn/pointers), we added pointers, which made it +possible to change data from other contexts/sequences. As we add more and more +data, it becomes clear that some structuring is needed. + +Structures are types. Types must be declared before being used. This also +prevents recursive types. + +The fields of a structure are initialized at the same time as the structure. + +Fields of a structure can be accessed in two ways: using the +`struct_var.field_name` notation, or the `(field struct_var field_name)` one. +If `struct_ptr` is a pointer to a structure, `struct_ptr.field_name` will also +work. + +To set the value of a structure's fields, one can use the `set` instruction or, +to set multiple fields at once, the `set_fields!` one. Note that omitting the +`!` at the end of `set_fields` is also valid Fate, but performs a computation +instead of a instruction: the structure is not modified, but a copy with the +modifications performed is returned. + +**data.fate:** + + (fate_version 1) + + (declare_structure weapon + (text name) + (int attack) + (int precision) + ) + + (declare_structure armor + (text name) + (int defense) + ) + + (declare_structure character + (string name) + (int money) + (weapon weapon) + (armor armor) + ) + + (global character hero) + + (set_fields! hero.weapon + (name (text "Legendary" sword)) + (attack 3) + (precision 50) + ) + + (set_fields! hero.armor + (name (text "Refined" attire)) + (defense 1) + ) + + (set hero.money 42) + +* `(text "Refined" attire)` generates a `text` value containing a textual + representation of the values passed as parameter. `"Refined" attire` is, by + itself, a `string`, and thus incompatible with the `text` field without a + conversion taking place. +* Because `hero_money` and `hero_name` have been removed in favor of a + structure, they should be replaced in the other files by `hero.money` and + `hero.name`. + +With this, it is time for our hero to get some proper gear, [let's see what +collection is available at the smithy](/learn/collections). + +---- + +## (Mostly) Unchanged Files + +**get_a_refill.fate:** + + (fate_version 1) + + (require data.fate) + (require actions.fate) + + (define_sequence lower_price_of_booze + ( + ((ptr int) price_pointer) + (int decrease) + ) + Great! The price of booze just lowered from (at price_pointer) + (set (at price_pointer) + (- + (at price_pointer) + (var decrease) + ) + ) + to (at price_pointer)! + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + (newline) + The barman sighs, then asks: + (prompt_string (ptr hero.name) 2 64 What is your name, then, hero?) + (var hero.name)? + (newline) + The barman looks surprised. + (newline) + (visit lower_price_of_booze (ptr price_of_booze) 4) + (newline) + "I have heard of you, (var hero.name)," the barman exclaims, "I have + a quest for you!" + (newline) + It's your turn to sigh. + (newline) + The barman hands you a bag, and says: + (newline) + "Take this pre-payment and head to the smithy." + (newline) + ) + +**actions.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero.money) (var cost)) + ) + ) + +**falling_asleep.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero.money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) diff --git a/content/learn/08.collections/default.md b/content/learn/08.collections/default.md new file mode 100644 index 0000000..b4bae98 --- /dev/null +++ b/content/learn/08.collections/default.md @@ -0,0 +1,408 @@ +--- +menuTitle: Collections +title: "Collections" +weight: 8 +--- +In [the previous step](/learn/structures), we added structures, which made +having some amounts of data more manageable. Still, what about when we need to +have hundreds of elements? Collections are here to manage that. + +Fate has three types of collections: +* Sets, which only contain a single instance of each element, can only be used + to store elements of one of the comparable types (`string`, `text`, `int`, + `float`, `bool`) and pointers. The elements are automatically sorted in + ascending order. +* Lists, which can be made for one of any type. +* Cons, which are pairs of two elements of any types. + +There are [quite a few computations](/fate_v1/computations/collections) and +[instructions](/fate_v1/instructions/collections) available to handle +collections. + +Let's add a new file, `smithy_inventory.fate`: + (fate_version 1) + + (require data.fate) + + (global (list (cons weapon int)) smithy_weapons) + (global (list (cons weapon int)) smithy_armors) + + (add! + (cons + (set_fields (default weapon) + (name (text An Iron Rod)) + (attack 10) + (precision 70) + ) + 176 + ) + smithy_weapons + ) + (add! + (cons + (set_fields (default weapon) + (name (text A Magnificient Brick)) + (attack 6) + (precision 90) + ) + 110 + ) + smithy_weapons + ) + + (add! + (cons + (set_fields (default armor) + (name (text A raincoat?!)) + (defense 7) + ) + 160 + ) + smithy_armors + ) + (add! + (cons + (set_fields (default armor) + (name (text A nice cape)) + (defense 3) + ) + 50 + ) + smithy_armors + ) + +We'll also need the actual smithy scene, so let's put in another file, +`smithy.fate`. + +**NOTE:** Don't worry if it looks awful at the moment, the next chapters are +going to introduce a lot of things to make it *much*, *much* easier to write. + +**smithy.fate:** + + (fate_version 1) + + (require smithy_inventory.fate) + + (define_sequence visit_smithy () + ;; This thing is going to show up every time, which isn't great. + As you approach the smithy, you notice that no one's there. All the + wares are out for selling. It's almost as if this story didn't need + more examples of lengthy dialogues. + (newline) + ;; We'll want to start here the next time we enter this sequence. + You have (var hero.money) coins. + (newline) + What will you look at? + (player_choice + ( + ( Let's see the weapons ) + (jump_to see_weapons) + ) + ( + ( Let's see the armors ) + (jump_to see_armors) + ) + ( + ( Nothing, let's go back to the bar ) + ) + ) + ) + + (define_sequence see_weapons () + ;; We'll soon replace this mess with something way better. + + (local text weapon_a_label) + (local text weapon_b_label) + + (visit get_weapon_label + (access smithy_weapons 0) + (ptr weapon_a_label) + ) + (visit get_weapon_label + (access smithy_weapons 1) + (ptr weapon_b_label) + ) + + (player_choice + ( + ( (var weapon_a_label) ) + (visit buy_weapon (access smithy_weapons 0)) + (jump_to visit_smithy) + ) + ( + ( (var weapon_a_label) ) + (visit buy_weapon (access smithy_weapons 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + (define_sequence see_armors () + ;; We'll soon replace this mess with something way better. + + (local text armor_a_label) + (local text armor_b_label) + + (visit get_armor_label + (access smithy_armors 0) + (ptr armor_a_label) + ) + (visit get_armor_label + (access smithy_armors 1) + (ptr armor_b_label) + ) + + (player_choice + ( + ( (var armor_a_label) ) + (visit buy_armor (access smithy_armors 0)) + (jump_to visit_smithy) + ) + ( + ( (var armor_a_label) ) + (visit buy_armor (access smithy_armors 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + ;; A terrible way to get labels + (define_sequence get_weapon_label + ( + ((cons weapon int) weapon_offer) + ((ptr text) label) + ) + (local weapon weapon) + (local int price) + + (set weapon (car weapon_offer)) + (set price (cdr weapon_offer)) + + (set (at label) + ( + Buy "(var weapon.name)" \(attack: (var weapon.attack), + precision: (var weapon.precision)\) for (var price) coins. + ) + ) + ) + + ;; A terrible way to get labels + (define_sequence get_armor_label + ( + ((cons armor int) armor_offer) + ((ptr text) label) + ) + (local armor armor) + (local int price) + + (set armor (car armor_offer)) + (set price (cdr armor_offer)) + + (set (at label) + ( + Buy "(var armor.name)" \(defense: (var armor.defense)\), + for (var price) coins. + ) + ) + ) + + (define_sequence buy_weapon ( ((cons weapon int) weapon) ) + ;; We can't even deny a sell yet... + (set hero.weapon (car weapon)) + Equipped (var hero.weapon.name). + (newline) + ) + + (define_sequence buy_armor ( ((cons armor int) armor) ) + ;; We can't even deny a sell yet... + (set hero.armor (car armor)) + Equipped (var hero.armor.name). + (newline) + ) + +* `(list (cons weapon int))` indicates a list of `weapon` and `int` pairs. +* `(add! something smithy_weapons)` adds `something` to the `smithy_weapons` + collection. Without the `!`, this would be a computation returning a copy of + `smithy_weapons` with the added weapon, but no modification of the + `smithy_weapons` collection itself would occur. +* `(cons something something_else)` creates a pair with these two elements. +* `(car weapon_offer)` returns the first element of the `weapon_offer` pair. +* `(cdr weapon_offer)` returns the second element of the `weapon_offer` pair. + +Overall, the `smithy.fate` file is a mess. Let's start cleaning it up. We'll +use loops, conditionals, and lambda functions to make it much cleaner. Let's +start with the least expected one: [lambda functions](/learn/lambdas). + +---- + +## Unchanged Files + +**data.fate:** + + (fate_version 1) + + (declare_structure weapon + (text name) + (int attack) + (int precision) + ) + + (declare_structure armor + (text name) + (int defense) + ) + + (declare_structure character + (string name) + (int money) + (weapon weapon) + (armor armor) + ) + + (global character hero) + + (set_fields! hero.weapon + (name (text "Legendary" sword)) + (attack 3) + (precision 50) + ) + + (set_fields! hero.armor + (name (text "Refined" attire)) + (defense 1) + ) + + (set hero.money 42) + +**get_a_refill.fate:** + + (fate_version 1) + + (require data.fate) + (require actions.fate) + + (define_sequence lower_price_of_booze + ( + ((ptr int) price_pointer) + (int decrease) + ) + Great! The price of booze just lowered from (at price_pointer) + (set (at price_pointer) + (- + (at price_pointer) + (var decrease) + ) + ) + to (at price_pointer)! + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + (newline) + The barman sighs, then asks: + (prompt_string (ptr hero.name) 2 64 What is your name, then, hero?) + (var hero.name)? + (newline) + The barman looks surprised. + (newline) + (visit lower_price_of_booze (ptr price_of_booze) 4) + (newline) + "I have heard of you, (var hero.name)," the barman exclaims, "I have + a quest for you!" + (newline) + It's your turn to sigh. + (newline) + The barman hands you a bag, and says: + (newline) + "Take this pre-payment and head to the smithy." + (newline) + ) + +**actions.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero.money) (var cost)) + ) + ) + +**falling_asleep.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero.money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) diff --git a/content/learn/09.lambdas/default.md b/content/learn/09.lambdas/default.md new file mode 100644 index 0000000..a2e6c24 --- /dev/null +++ b/content/learn/09.lambdas/default.md @@ -0,0 +1,366 @@ +--- +menuTitle: Lambda Functions +title: "Lambda Functions" +weight: 9 +--- +In [the previous step](/learn/collections), we added collections, which made +having large amounts of data possible. We also ended up with a really ugly file, +`smithy.fate`, which had way too much code to be readable. We'll start by +removing the label generation sequences. Instead, we'll use lambda functions. + +A lambda function is computation description that can be stored for later use. +It can also take parameters. Since it's a computation, it cannot alter the +memory by itself, nor can it contain any instructions. + +**smithy.fate:** + + (fate_version 1) + + (require smithy_inventory.fate) + + (global (lambda text ((cons weapon int))) get_weapon_offer_label) + (global (lambda text ((cons armor int))) get_armor_offer_label) + + (set get_weapon_offer_label + (lambda + ( ((cons weapon int) offer) ) + (let + ( + (weapon (car offer)) + (price (cdr offer)) + ) + (text + Buy "(var weapon.name)" \(attack: (var weapon.attack), + precision: (var weapon.precision)\) for (var price) coins. + ) + ) + ) + ) + + (set get_armor_offer_label + (lambda + ( ((cons armor int) offer) ) + (let + ( + (armor (car offer)) + (price (cdr offer)) + ) + (text + Buy "(var armor.name)" \(defense: (var armor.defense)\), + for (var price) coins. + ) + ) + ) + ) + + (define_sequence visit_smithy () + ;; This thing is going to show up every time, which isn't great. + As you approach the smithy, you notice that no one's there. All the + wares are out for selling. It's almost as if this story didn't need + more examples of lengthy dialogues. + (newline) + ;; We'll want to start here the next time we enter this sequence. + You have (var hero.money) coins. + (newline) + What will you look at? + (player_choice + ( + ( Let's see the weapons ) + (jump_to see_weapons) + ) + ( + ( Let's see the armors ) + (jump_to see_armors) + ) + ( + ( Nothing, let's go back to the bar ) + ) + ) + ) + + (define_sequence see_weapons () + ;; Still can be improved. + (player_choice + ( + ( (eval get_weapon_offer_label (access smithy_weapons 0)) ) + (visit buy_weapon (access smithy_weapons 0)) + (jump_to visit_smithy) + ) + ( + ( (eval get_weapon_offer_label (access smithy_weapons 1)) ) + (visit buy_weapon (access smithy_weapons 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + (define_sequence see_armors () + ;; Still can be improved. + (player_choice + ( + ( (eval get_armor_offer_label (access smithy_armors 0)) ) + (visit buy_armor (access smithy_armors 0)) + (jump_to visit_smithy) + ) + ( + ( (eval get_armor_offer_label (access smithy_armors 1)) ) + (visit buy_armor (access smithy_armors 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + (define_sequence buy_weapon ( ((cons weapon int) weapon) ) + ;; We can't even deny a sell yet... + (set hero.weapon (car weapon)) + Equipped (var hero.weapon.name). + (newline) + ) + + (define_sequence buy_armor ( ((cons armor int) armor) ) + ;; We can't even deny a sell yet... + (set hero.armor (car armor)) + Equipped (var hero.armor.name). + (newline) + ) + +* `(lambda return_type (param_type0 param_type1 ...))` is the type corresponding + to a lambda function returning a value of type `return_type` and taking as + parameters values of types `param_type0`, `param_type1`, ... +* `(eval variable_name param0 param1 ...)` computes and returns the result of + the lambda function stored in `variable_name` by giving it as parameter the + values `param0`, `param1`, ... +* `(let ( (name0 val0) ... ) computation)` computes and returns `computation` as + if `name0` was a defined variable of value `val0`. + +Lambda functions are *very* useful. They can be used to manipulate lists in many +ways. They can also be used to abstract away some complicated computation. + +This was a first step toward cleaning up `smithy.fate`. Next, we'll use +[conditions](/learn/conditions) to improve things further. + +---- + +## Unchanged Files + +**data.fate:** + + (fate_version 1) + + (declare_structure weapon + (text name) + (int attack) + (int precision) + ) + + (declare_structure armor + (text name) + (int defense) + ) + + (declare_structure character + (string name) + (int money) + (weapon weapon) + (armor armor) + ) + + (global character hero) + + (set_fields! hero.weapon + (name (text "Legendary" sword)) + (attack 3) + (precision 50) + ) + + (set_fields! hero.armor + (name (text "Refined" attire)) + (defense 1) + ) + + (set hero.money 42) + +**get_a_refill.fate:** + + (fate_version 1) + + (require data.fate) + (require actions.fate) + + (define_sequence lower_price_of_booze + ( + ((ptr int) price_pointer) + (int decrease) + ) + Great! The price of booze just lowered from (at price_pointer) + (set (at price_pointer) + (- + (at price_pointer) + (var decrease) + ) + ) + to (at price_pointer)! + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + (newline) + The barman sighs, then asks: + (prompt_string (ptr hero.name) 2 64 What is your name, then, hero?) + (var hero.name)? + (newline) + The barman looks surprised. + (newline) + (visit lower_price_of_booze (ptr price_of_booze) 4) + (newline) + "I have heard of you, (var hero.name)," the barman exclaims, "I have + a quest for you!" + (newline) + It's your turn to sigh. + (newline) + The barman hands you a bag, and says: + (newline) + "Take this pre-payment and head to the smithy." + (newline) + ) + +**actions.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero.money) (var cost)) + ) + ) + +**falling_asleep.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero.money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) + +**smithy_inventory.fate:** + (fate_version 1) + + (require data.fate) + + (global (list (cons weapon int)) smithy_weapons) + (global (list (cons weapon int)) smithy_armors) + + (add! + (cons + (set_fields (default weapon) + (name (text An Iron Rod)) + (attack 10) + (precision 70) + ) + 176 + ) + smithy_weapons + ) + (add! + (cons + (set_fields (default weapon) + (name (text A Magnificient Brick)) + (attack 6) + (precision 90) + ) + 110 + ) + smithy_weapons + ) + + (add! + (cons + (set_fields (default armor) + (name (text A raincoat?!)) + (defense 7) + ) + 160 + ) + smithy_armors + ) + (add! + (cons + (set_fields (default armor) + (name (text A nice cape)) + (defense 3) + ) + 50 + ) + smithy_armors + ) diff --git a/content/learn/10.conditions/default.md b/content/learn/10.conditions/default.md new file mode 100644 index 0000000..8a4f339 --- /dev/null +++ b/content/learn/10.conditions/default.md @@ -0,0 +1,402 @@ +--- +menuTitle: Conditionals +title: "Expressing Conditions" +weight: 10 +--- +In [the previous step](/learn/lambdas), we added lambda functions, which made +it possible to store computation descriptions for later use. The `smithy.fate` +is still a mess, and we couldn't handle the hero not having enough money for a +purchase. Let's add conditions to our story. + +Fate has quite a few conditional constructs. `if_else`, `switch`, and `cond` +can be used both as instruction and computation. `if` is only for instructions. +* `if_else` selects between two options according to a given `bool` value. +* `switch` has a list of options, each of which is associated to a value. + It selects the first listed option whose value is equal to the targeted + value. When used as a computation, a default option with no associated value + must be provided. +* `cond` has a list of options, each of which is associated to a `bool` + computation. The first listed option for which the computation yields `(true)` + is chosen. In the case of a computation, the last option is chosen even as a + default value. With instructions, if no option has its condition satisfied, + nothing happens. +* `if` is only for instructions, and applies its content only if the condition + is verified. + +All of these can be used within a `player_choice` to control what options are +available. + +**smithy.fate:** + + (fate_version 1) + + (require smithy_inventory.fate) + + (global (lambda text ((cons weapon int))) get_weapon_offer_label) + (global (lambda text ((cons armor int))) get_armor_offer_label) + + (set get_weapon_offer_label + (lambda + ( ((cons weapon int) offer) ) + (let + ( + (weapon (car offer)) + (price (cdr offer)) + ) + (text + Buy "(var weapon.name)" \(attack: (var weapon.attack), + precision: (var weapon.precision)\) for (var price) coins. + ) + ) + ) + ) + + (set get_armor_offer_label + (lambda + ( ((cons armor int) offer) ) + (let + ( + (armor (car offer)) + (price (cdr offer)) + ) + (text + Buy "(var armor.name)" \(defense: (var armor.defense)\), + for (var price) coins. + ) + ) + ) + ) + + (global bool has_visited_smithy) + + (set has_visited_smithy (false)) + + (define_sequence visit_smithy () + (if (not (var has_visited_smithy)) + As you approach the smithy, you notice that no one's there. All + the wares are out for selling. It's almost as if this story + didn't need more examples of lengthy dialogues. + (newline) + (set has_visited_smithy (true)) + ) + You have (var hero.money) coins. + (newline) + What will you look at? + (player_choice + ( + ( Let's see the weapons ) + (jump_to see_weapons) + ) + ( + ( Let's see the armors ) + (jump_to see_armors) + ) + ( + ( Nothing, let's go back to the bar ) + ) + ) + ) + + (define_sequence see_weapons () + ;; Still can be improved. + (player_choice + ( + ( (eval get_weapon_offer_label (access smithy_weapons 0)) ) + (visit buy_weapon (access smithy_weapons 0)) + (jump_to visit_smithy) + ) + ( + ( (eval get_weapon_offer_label (access smithy_weapons 1)) ) + (visit buy_weapon (access smithy_weapons 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + (define_sequence see_armors () + ;; Still can be improved. + (player_choice + ( + ( (eval get_armor_offer_label (access smithy_armors 0)) ) + (visit buy_armor (access smithy_armors 0)) + (jump_to visit_smithy) + ) + ( + ( (eval get_armor_offer_label (access smithy_armors 1)) ) + (visit buy_armor (access smithy_armors 1)) + (jump_to visit_smithy) + ) + ( + ( Nevermind ) + (jump_to visit_smithy) + ) + ) + ) + + (define_sequence buy_weapon ( ((cons weapon int) weapon) ) + ;; We can't even deny a sell yet... + (local int money_after) + + (set money_after (- (var hero.money) (cdr weapon))) + + (if_else (< (var money_after) 0) + ( + You can't afford that. + (newline) + You would need (abs (var money_after)) more coins. + ) + ( + (set hero.weapon (car weapon)) + (set hero.money (var money_after)) + Equipped (var hero.weapon.name). + ) + ) + (newline) + ) + + (define_sequence buy_armor ( ((cons armor int) armor) ) + ;; We can't even deny a sell yet... + (local int money_after) + + (set money_after (- (var hero.money) (cdr armor))) + + (if_else (< (var money_after) 0) + ( + You can't afford that. + (newline) + You would need (abs (var money_after)) more coins. + ) + ( + (set hero.armor (car armor)) + (set hero.money (var money_after)) + Equipped (var hero.armor.name). + ) + ) + (newline) + ) + + +This was a first step toward cleaning up `smithy.fate`. Next, we'll use +[conditions](/learn/conditions) to improve things further. + +---- + +## Unchanged Files + +**data.fate:** + + (fate_version 1) + + (declare_structure weapon + (text name) + (int attack) + (int precision) + ) + + (declare_structure armor + (text name) + (int defense) + ) + + (declare_structure character + (string name) + (int money) + (weapon weapon) + (armor armor) + ) + + (global character hero) + + (set_fields! hero.weapon + (name (text "Legendary" sword)) + (attack 3) + (precision 50) + ) + + (set_fields! hero.armor + (name (text "Refined" attire)) + (defense 1) + ) + + (set hero.money 42) + +**get_a_refill.fate:** + + (fate_version 1) + + (require data.fate) + (require actions.fate) + + (define_sequence lower_price_of_booze + ( + ((ptr int) price_pointer) + (int decrease) + ) + Great! The price of booze just lowered from (at price_pointer) + (set (at price_pointer) + (- + (at price_pointer) + (var decrease) + ) + ) + to (at price_pointer)! + ) + + (define_sequence get_a_refill () + (local int price_of_booze) + + (set price_of_booze 12) + + Staring straight at the barman, you raise your glass and proclaim: + (newline) + "This soon-to-be world savior needs more booze!" + (newline) + The barman's lack of reaction is disappointing, but seeing the beer + being poured does help improve the mood. + (newline) + Satisfied, you hand the barman (var price_of_booze) copper coins. + (visit pay (var price_of_booze)) + (newline) + The barman sighs, then asks: + (prompt_string (ptr hero.name) 2 64 What is your name, then, hero?) + (var hero.name)? + (newline) + The barman looks surprised. + (newline) + (visit lower_price_of_booze (ptr price_of_booze) 4) + (newline) + "I have heard of you, (var hero.name)," the barman exclaims, "I have + a quest for you!" + (newline) + It's your turn to sigh. + (newline) + The barman hands you a bag, and says: + (newline) + "Take this pre-payment and head to the smithy." + (newline) + ) + +**actions.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence pay ( (int cost) ) + (set hero_money + (- (var hero.money) (var cost)) + ) + ) + +**falling_asleep.fate:** + + (fate_version 1) + + (require data.fate) + + (define_sequence fall_asleep () + Deciding to break away from the expected storyline, you promptly + fall asleep. + (newline) + ... + (newline) + Upon waking up, your hard-trained reflexes inform you that someone + stole all your money. + (set hero.money 0) + (newline) + This set-back was more than you could take. You give up on this + barely coherent story. + (end) + ) + +**main.fate:** + + (fate_version 1) + + Once upon a time, starting a story with these words wasn't considered + a cliche. Starting in a tavern might also not be seen as very + original. Having the main character be an street orphan, raised by + some mysterious sage all to end up as a mercenary with an uncommonly + strong sense of honor probably isn't going to lead to any praises for + novelty either. Maybe you should drink to that. + (newline) + Or maybe you shouldn't. This isn't your first mug. Not your second + either. Drinking to forget that you are a stereotypical hero isn't + going to solve anything. Worse, the alcoholic trait is part of the + image. + (newline) + As you contemplate your own pointless description, your gaze leaves + what turns out to be an already empty glass in your hand and finds the + barman. + + (player_choice + ( + ( Ask the barman for a refill ) + (visit get_a_refill) + ) + ( + ( Fall asleep ) + (jump_to fall_asleep) + ) + ) + + (require get_a_refill.fate) + (require falling_asleep.fate) + + (end) + +**smithy_inventory.fate:** + (fate_version 1) + + (require data.fate) + + (global (list (cons weapon int)) smithy_weapons) + (global (list (cons weapon int)) smithy_armors) + + (add! + (cons + (set_fields (default weapon) + (name (text An Iron Rod)) + (attack 10) + (precision 70) + ) + 176 + ) + smithy_weapons + ) + (add! + (cons + (set_fields (default weapon) + (name (text A Magnificient Brick)) + (attack 6) + (precision 90) + ) + 110 + ) + smithy_weapons + ) + + (add! + (cons + (set_fields (default armor) + (name (text A raincoat?!)) + (defense 7) + ) + 160 + ) + smithy_armors + ) + (add! + (cons + (set_fields (default armor) + (name (text A nice cape)) + (defense 3) + ) + 50 + ) + smithy_armors + ) diff --git a/content/learn/_index.md b/content/learn/_index.md new file mode 100644 index 0000000..62706fc --- /dev/null +++ b/content/learn/_index.md @@ -0,0 +1,8 @@ +--- +title: "Starting" +menuTitle: "Learn" +chapter: true +--- +# Writing a story in Fate. +This chapter provides an example of narrative written in Fate. Concepts are +introduced progressively. diff --git a/content/made_with_tonkadur/_index.md b/content/made_with_tonkadur/_index.md new file mode 100644 index 0000000..4e1a654 --- /dev/null +++ b/content/made_with_tonkadur/_index.md @@ -0,0 +1,3 @@ +--- +title: Made with Tonkadur +--- diff --git a/content/made_with_tonkadur/closed_source/_index.md b/content/made_with_tonkadur/closed_source/_index.md new file mode 100644 index 0000000..5bb1e01 --- /dev/null +++ b/content/made_with_tonkadur/closed_source/_index.md @@ -0,0 +1,5 @@ +--- +title: Closed Source Games using Tonkadur +menuTitle: Closed Source Games +--- +!!!! This page **is** available, there's just nothing to list in there for now. diff --git a/content/made_with_tonkadur/open_source/_index.md b/content/made_with_tonkadur/open_source/_index.md new file mode 100644 index 0000000..0cc4bf9 --- /dev/null +++ b/content/made_with_tonkadur/open_source/_index.md @@ -0,0 +1,5 @@ +--- +menuTitle: Open Source Games +title: Open Source Games using Tonkadur +--- +!!!! This page **is** available, there's just nothing to list in there for now. diff --git a/content/setup/_index.md b/content/setup/_index.md new file mode 100644 index 0000000..1aad3fc --- /dev/null +++ b/content/setup/_index.md @@ -0,0 +1,75 @@ +--- +title: "Setup" +--- +# Setting Up Tonkadur +There are two parts to set up: the compiler, and the interpreter. The compiler +is provided and does not require any modification. The interpreter depends on +the software you wish to integrate Tonkadur to. Examples of interpreters are +available, but expect some modifications to be required. This should not prove +to be difficult however, as the whole approach is design with the idea of +keeping the interpreter small and simple. + +## Setting Up the Compiler + +### Installation +**Dependencies:** +* Java + +Download the latest release of Tonkadur on [this +page](https://github.com/nsensfel/tonkadur/releases). + +### Use +The Tonkadur compiler is invoked using `java -jar tonkadur.jar [option] <file>`. +`java -jar tonkadur.jar` will yield the complete list of valid options. + +`<file>` corresponds to a Fate file. By default, the generated Wyrd file will +have the same name with a suffix. + +## Setting Up the Interpreter +It is recommended to look up existing interpreters. Not only might you be able +to just use an existing one, but having examples of interpreters will help you +create your own if you can't find one that fits your needs. + +**Known open source Wyrd interpreters:** +* [nsensfel/tonkadur-python-interpreter](https://github.com/nsensfel/tonkadur-python-interpreter): A minimal Python3 interpreter, with JSON input. + +### Creating Your Own Interpreter +If you end up needing to create your own interpreter, here are some clues on how +to proceed. + +A Wyrd interpreter keeps track of: +* **The Memory:** typically a mapping of strings to values. These values may be +of any Wyrd type. +* **The Program Counter:** an integer corresponding to the next Wyrd instruction +to execute. +* **Available Choices:** A list of `RICH_TEXT`. +* **Last Chosen Choice:** Index of the last chosen choice. +* **The Code:** A list of instructions. + +Additionally, the following can be kept track of: +* **Types:** The default value for each type, making it easier to create new + memory elements of a given type. +* **Allocated Data Counter:** The number of dynamically allocated memory + elements, making it easy to generate unique names for new memory elements. + +A few pitfalls: +* **Copy values on assignment:** `(set_value a b)` does not make `a` become `b`, + but rather assigns a copy of the current value of `b` to `a`. +* **Addresses may be already computed:** An `address` computation can take an + address as its `address` parameter. In other words, while in most cases an + `address` computation is a string that must be put in a list to become an + actual address, it can also sometimes already be a list and must then stay + unchanged. +* **Beware of references:** When performing a computation that accesses memory + elements, be sure not to actually be returning the memory element itself after + it has been modified, but rather a modified copy of the memory element. This + is only problematic for memory elements whose type is modified by reference in + the interpreter's programming language. An example would be relative address + computation, which appends an element to a list. Computing a relative address + must not modify the base address, it only returns a list equivalent to the + base address but with an extra element. + +A set of tests can found on [this +page](https://github.com/nsensfel/tonkadur/tree/master/data/tests), and will let +you test your interpreter more easily. They have to be compiled to Wyrd first, +however. diff --git a/content/wyrd_v1/_index.md b/content/wyrd_v1/_index.md new file mode 100644 index 0000000..4d902e2 --- /dev/null +++ b/content/wyrd_v1/_index.md @@ -0,0 +1,56 @@ +--- +menuTitle: Wyrd +title: Wyrd (Version 1) +--- +Wyrd is the language in which the narrative is given to the game engine. It is +purposefully kept small and simple to facilitate porting Tonkadur to a new +engine. + +The memory is seen as a table mapping strings to values. These values may also +be tables. Thus a reference is a list of strings corresponding to a move from +one table to the next. + +The program is a list of instructions. These instructions may use computations +as parameters. They sometimes use hard-coded strings parameters as well. +Instructions cannot take instructions as parameters. Instructions are not +associated to any value. + +An integer, called _Program Counter_ is used to indicate the current +instruction. In most cases, this integer is incremented by one after every +instruction. There is an instruction to modify the value of the Program Counter, +which allows conditional jumps and loops to be described. + +Computations are values and operations returning values. These are solely used +as parameters of instructions. They do not alter memory (with one exception) +and do not interact with the Program Counter in any way. An execution cannot be +stopped during the evaluation of a computation: it is part of its parent +instruction and is thus completed exactly when that instruction is performed. +Computations may _read_ from the memory, as they may need to fetch the value +associated with an address or traverse tables. All computations have a return +type. + +Wyrd does not have the notion of sequence or that lambda functions. It does not +even associate player choices with lists of actions. It's all done by carefully +managing the Program Counter. + +Lambda functions are stored as an `INT` corresponding to a line in the program. + +## Types +* `ADDRESS` (or `POINTER`, or `REFERENCE`), a list of `STRING` (note: not a + `STRING COLLECTION`). +* `BOOL`. This should be changed to `BOOL` soon, for consistency's sake. +* `[SOMETHING] COLLECTION`, table mapping `STRING` to `[SOMETHING]`. +* `FLOAT`. +* `INT`. +* `RICH TEXT`, a list of `STRINGS` with attributes attached. +* `STRING`. +* `STRUCTURE` (or `DICTIONARY`), table mapping `STRING` to values of any type. +* `{String}`, a hard-coded string. + +#### Aliases sometimes used to refer to types +* `? ADDRESS`: an `ADDRESS` pointing to a particular type. +* `BASE TYPE`: `INT`, `FLOAT`, `BOOL`, `STRING`. +* `COMPARABLE`: `INT`, `FLOAT`, `BOOL`, `STRING`, `RICH TEXT`, `ADDRESS`. +* `COLLECTION`: any `? COLLECTION`. +* `COMPUTATION`: any type. +* `NUMBER`: `INT` or `FLOAT`. diff --git a/content/wyrd_v1/computations/_index.md b/content/wyrd_v1/computations/_index.md new file mode 100644 index 0000000..028a82e --- /dev/null +++ b/content/wyrd_v1/computations/_index.md @@ -0,0 +1,99 @@ +--- +title: Computations +--- +This page presents all the computations that can be performed in Wyrd. +Computations may access the current memory, but, with one exception, do not +change it. The one exception is `(new t)`. All computations return values. +The terms 'value' and 'computation' are interchangeable. + +## CONSTANT +{{< fatecode >}}(const [BASE TYPE] {string}){{< /fatecode >}} +Returns the `[BASE TYPE]` represented by `{string}`. + +## CAST +{{< fatecode >}}(cast [COMPUTATION] [BASE TYPE]){{< /fatecode >}} +Converts `[COMPUTATION]` to `[BASE TYPE]`, returns the result. + +Note: +* Converting from `FLOAT` to `INT` returns `floor(v)`. +* Converting from `BOOL` to `STRING` yields either `True` or `False`. + +The following must be supported: +* `[FLOAT]` to `[FLOAT]`, `[INT]`, and `[STRING]`. +* `[INT]` to `[FLOAT]`, `[INT]`, and `[STRING]`. +* `[BOOL]` to `[BOOL]` and `[STRING]`. +* `[STRING]` to `[BOOL]` (`true` and `false`), `[FLOAT]`, `[INT]`, and`[STRING]`. + +## IF-ELSE +{{< fatecode >}}(if_else [BOOL] [C0 = COMPUTATION] [C1 = COMPUTATION]){{< /fatecode >}} +Returns `C0` if `[BOOL]` holds _true_, `C1` otherwise. `C0` and `C1` both +have the same type. + +## EQUALS +{{< fatecode >}}(equals [C0 = COMPUTATION] [C1 = COMPUTATION]){{< /fatecode >}} +Returns a `BOOL`, _true_ if `C0` and `C1` hold the same value. `C0` and `C1` +are both of the same type. + +## MATHEMATICAL OPERATORS +{{< fatecode >}}(divide [C0 = NUMBER] [C1 = NUMBER]){{< /fatecode >}} + +{{< fatecode >}}(minus [C0 = NUMBER] [C1 = NUMBER]){{< /fatecode >}} + +{{< fatecode >}}(plus [C0 = NUMBER] [C1 = NUMBER]){{< /fatecode >}} + +{{< fatecode >}}(power [C0 = NUMBER] [C1 = NUMBER]){{< /fatecode >}} + +{{< fatecode >}}(times [C0 = NUMBER] [C1 = NUMBER]){{< /fatecode >}} +The operation returns a value of the same type as `C0` and `C1` (both `C0` and +`C1` are also of the same type). Thus, `(divide C0 C1)` is an integer division +(the remainder is discarded) if `C0` and `C1` are of type `INT`, and a standard +division if they are of type `FLOAT`. + +{{< fatecode >}}(rand [C0 = INT] [C1 = INT]){{< /fatecode >}} +Returns a random value between `C0` and `C1`, inclusive. Raises a runtime error +if `C0 > C1`. + +## MATHEMATICAL COMPARISON +{{< fatecode >}}(less_than [C0 = COMPARABLE] [C1 = COMPARABLE]){{< /fatecode >}} +Returns a `[BOOL]` indicating if `C0` is strictly less than `C1`. +`C0` and `C1` are both of the same type. + +## LOGICAL OPERATORS +{{< fatecode >}}(and [C0 = BOOL] [C1 = BOOL]){{< /fatecode >}} + +{{< fatecode >}}(not [C0 = BOOL]){{< /fatecode >}} + +## SIZE +{{< fatecode >}}(size [COLLECTION ADDRESS]){{< /fatecode >}} +Returns the number of elements held by the collection at +`[COLLECTION ADDRESS]`. + +## REFERENCES +{{< fatecode >}}(address [COMPUTATION]){{< /fatecode >}} +Returns an `ADDRESS` to the memory element at address `[COMPUTATION]`. Raises a +runtime error if `[COMPUTATION]` is not a memory element. + +{{< fatecode >}}(relative_address <R0 = (COLLECTION|STRUCTURE) ADDRESS> [STRING]){{< /fatecode >}} +Returns a `REFERENCE` to member `[STRING]` of `R0`. + +{{< fatecode >}}(value_of [ADDRESS]){{< /fatecode >}} +Returns the value held at the memory location `[ADDRESS]`. + +{{< fatecode >}}(new [TYPE]){{< /fatecode >}} +Returns an `[TYPE] ADDRESS` to a newly allocated memory element of +type `[TYPE]`. + +## RICH TEXT +{{< fatecode >}}(newline){{< /fatecode >}} +Returns a `RICH TEXT` value corresponding to a newline. + +{{< fatecode >}}(rich_text [S0 = STRING] ... [SN = STRING]){{< /fatecode >}} +Returns a single value `RICH TEXT` representing the elements `S0` ... `S1`. + +{{< fatecode >}}(add_rich_text_effect ({string} [V0 = COMPUTATION] ... [VN = COMPUTATION]) [RICH TEXT]){{< /fatecode >}} +Returns a `RICH TEXT` value of `[RICH TEXT]` with the given effect enabled. + +## LAST USER CHOICE +{{< fatecode >}}(get_last_user_choice){{< /fatecode >}} +Returns the number corresponding to the option last chosen by the user in a +`(resolve_choices)`, or `-1` if there is no such value. diff --git a/content/wyrd_v1/extensions/_index.md b/content/wyrd_v1/extensions/_index.md new file mode 100644 index 0000000..a21559c --- /dev/null +++ b/content/wyrd_v1/extensions/_index.md @@ -0,0 +1,4 @@ +--- +title: Extensions +--- +Not available in Version 1. diff --git a/content/wyrd_v1/instructions/_index.md b/content/wyrd_v1/instructions/_index.md new file mode 100644 index 0000000..9d43a5a --- /dev/null +++ b/content/wyrd_v1/instructions/_index.md @@ -0,0 +1,75 @@ +--- +title: Instructions +--- +This page presents all the instructions that can be performed in Wyrd. +Instructions do not return values. With one exception, all instructions increase +the Program Counter by 1. + + +## ADD CHOICE +{{< fatecode >}}(add_choice [RICH TEXT]){{< /fatecode >}} +Adds a new option for the next `resolve_choices` instruction. The new option +presents the player with `[RICH TEXT]`. + +## INTEGER PROMPT +{{< fatecode >}}(prompt_integer [INT REFERENCE] [MIN = INT] [MAX = INT] [RICH TEXT]){{< /fatecode >}} + +Prompts the user for an integer between `[MIN]` and `[MAX]` by displaying the +message `[RICH TEXT]`. The result is stored in `[INT REFERENCE]`. + +## STRING PROMPT +{{< fatecode >}}(prompt_string [STRING REFERENCE] [MIN = INT] [MAX = INT] [RICH TEXT]){{< /fatecode >}} + +Prompts the user for a string of size between `[MIN]` and `[MAX]` by displaying +the message `[RICH TEXT]`. The result is stored in `[STRING REFERENCE]`. + + +## ASSERT +{{< fatecode >}}(assert [BOOL] [RICH TEXT]){{< /fatecode >}} +If `[BOOL]` isn't _true_, raise a runtime error containing `[RICH TEXT]`. + + +## DISPLAY +{{< fatecode >}}(display [RICH TEXT]){{< /fatecode >}} +Displays `[RICH TEXT]` to the player. + + +## END +{{< fatecode >}}(end){{< /fatecode >}} +Marks the end of the narration. Interrupts the execution. + + +## EVENT CALL +{{< fatecode >}}(event_call {string} [C0 = COMPUTATION] ... [CN = COMPUTATION]){{< /fatecode >}} +Interrupts execution, informs the interpreter that the given event `{String}` +was triggered with the parameters `C0 ... CN`. + + +## REMOVE +{{< fatecode >}}(remove [ADDRESS]){{< /fatecode >}} +The memory at `[ADDRESS]` is freed. + + +## RESOLVE CHOICES +{{< fatecode >}}(resolve_choices){{< /fatecode >}} +Present the player with all options that where added using `add_choice` since +the last `resolve_choices`. The execution is paused and should be resumed by +the interpreter setting the Program Counter according to the chosen option. + + +## SET PC +{{< fatecode >}}(set_pc [INT]){{< /fatecode >}} +Sets the Program Counter to `[INT]`. The program counter is not automatically +increased by 1 in this case. + + +## SET VALUE +{{< fatecode >}}(set_value [ADDRESS] [COMPUTATION]){{< /fatecode >}} +Sets the memory pointed by `[ADDRESS]` to `[COMPUTATION]`. +`[COMPUTATION]` is passed by value, not reference (i.e. no aliasing can occur +without it being done explicitly through pointers). + +## INITIALIZE MEMORY ELEMENT +{{< fatecode >}}(initialize [ADDRESS] [TYPE]){{< /fatecode >}} +Initializes a memory element at `[ADDRESS]` with the default value for the type +`[TYPE]`. diff --git a/layouts/shortcodes/fatecode.html b/layouts/shortcodes/fatecode.html new file mode 100644 index 0000000..77bd69c --- /dev/null +++ b/layouts/shortcodes/fatecode.html @@ -0,0 +1,2 @@ +<!-- fatecode--> +<pre><code class="language-scheme match-braces rainbow-braces line-numbers">{{.Inner}}</code></pre> diff --git a/layouts/shortcodes/rawhtml.html b/layouts/shortcodes/rawhtml.html new file mode 100644 index 0000000..b90bea2 --- /dev/null +++ b/layouts/shortcodes/rawhtml.html @@ -0,0 +1,2 @@ +<!-- raw html --> +{{.Inner}} diff --git a/static/css/prism.css b/static/css/prism.css new file mode 100755 index 0000000..066264f --- /dev/null +++ b/static/css/prism.css @@ -0,0 +1,321 @@ +/* PrismJS 1.22.0 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=scheme&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard+match-braces */ +/** + * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML + * Based on https://github.com/chriskempson/tomorrow-theme + * @author Rose Pritchard + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #ccc; + background: none; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #2d2d2d; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #999; +} + +.token.punctuation { + color: #ccc; +} + +.token.tag, +.token.attr-name, +.token.namespace, +.token.deleted { + color: #e2777a; +} + +.token.function-name { + color: #6196cc; +} + +.token.boolean, +.token.number, +.token.function { + color: #f08d49; +} + +.token.property, +.token.class-name, +.token.constant, +.token.symbol { + color: #f8c555; +} + +.token.selector, +.token.important, +.token.atrule, +.token.keyword, +.token.builtin { + color: #cc99cd; +} + +.token.string, +.token.char, +.token.attr-value, +.token.regex, +.token.variable { + color: #7ec699; +} + +.token.operator, +.token.entity, +.token.url { + color: #67cdcc; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.inserted { + color: green; +} + +pre[data-line] { + position: relative; + padding: 1em 0 1em 3em; +} + +.line-highlight { + position: absolute; + left: 0; + right: 0; + padding: inherit 0; + margin-top: 1em; /* Same as .prism’s padding-top */ + + background: hsla(24, 20%, 50%,.08); + background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + + pointer-events: none; + + line-height: inherit; + white-space: pre; +} + + .line-highlight:before, + .line-highlight[data-end]:after { + content: attr(data-start); + position: absolute; + top: .4em; + left: .6em; + min-width: 1em; + padding: 0 .5em; + background-color: hsla(24, 20%, 50%,.4); + color: hsl(24, 20%, 95%); + font: bold 65%/1.5 sans-serif; + text-align: center; + vertical-align: .3em; + border-radius: 999px; + text-shadow: none; + box-shadow: 0 1px white; + } + + .line-highlight[data-end]:after { + content: attr(data-end); + top: auto; + bottom: .4em; + } + +.line-numbers .line-highlight:before, +.line-numbers .line-highlight:after { + content: none; +} + +pre[id].linkable-line-numbers span.line-numbers-rows { + pointer-events: all; +} +pre[id].linkable-line-numbers span.line-numbers-rows > span:before { + cursor: pointer; +} +pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before { + background-color: rgba(128, 128, 128, .2); +} + +pre[class*="language-"].line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} + +pre[class*="language-"].line-numbers > code { + position: relative; + white-space: inherit; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + border-right: 1px solid #999; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + +} + + .line-numbers-rows > span { + display: block; + counter-increment: linenumber; + } + + .line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; + } + +div.code-toolbar { + position: relative; +} + +div.code-toolbar > .toolbar { + position: absolute; + top: .3em; + right: .2em; + transition: opacity 0.3s ease-in-out; + opacity: 0; +} + +div.code-toolbar:hover > .toolbar { + opacity: 1; +} + +/* Separate line b/c rules are thrown out if selector is invalid. + IE11 and old Edge versions don't support :focus-within. */ +div.code-toolbar:focus-within > .toolbar { + opacity: 1; +} + +div.code-toolbar > .toolbar .toolbar-item { + display: inline-block; +} + +div.code-toolbar > .toolbar a { + cursor: pointer; +} + +div.code-toolbar > .toolbar button { + background: none; + border: 0; + color: inherit; + font: inherit; + line-height: normal; + overflow: visible; + padding: 0; + -webkit-user-select: none; /* for button */ + -moz-user-select: none; + -ms-user-select: none; +} + +div.code-toolbar > .toolbar a, +div.code-toolbar > .toolbar button, +div.code-toolbar > .toolbar span { + color: #bbb; + font-size: .8em; + padding: 0 .5em; + background: #f5f2f0; + background: rgba(224, 224, 224, 0.2); + box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); + border-radius: .5em; +} + +div.code-toolbar > .toolbar a:hover, +div.code-toolbar > .toolbar a:focus, +div.code-toolbar > .toolbar button:hover, +div.code-toolbar > .toolbar button:focus, +div.code-toolbar > .toolbar span:hover, +div.code-toolbar > .toolbar span:focus { + color: inherit; + text-decoration: none; +} + +.token.punctuation.brace-hover, +.token.punctuation.brace-selected { + outline: solid 1px; +} + +.rainbow-braces .token.punctuation.brace-level-1, +.rainbow-braces .token.punctuation.brace-level-5, +.rainbow-braces .token.punctuation.brace-level-9 { + color: #E50; + opacity: 1; +} +.rainbow-braces .token.punctuation.brace-level-2, +.rainbow-braces .token.punctuation.brace-level-6, +.rainbow-braces .token.punctuation.brace-level-10 { + color: #0B3; + opacity: 1; +} +.rainbow-braces .token.punctuation.brace-level-3, +.rainbow-braces .token.punctuation.brace-level-7, +.rainbow-braces .token.punctuation.brace-level-11 { + color: #26F; + opacity: 1; +} +.rainbow-braces .token.punctuation.brace-level-4, +.rainbow-braces .token.punctuation.brace-level-8, +.rainbow-braces .token.punctuation.brace-level-12 { + color: #E0E; + opacity: 1; +} + diff --git a/static/js/highlight.pack.js b/static/js/highlight.pack.js new file mode 100755 index 0000000..2c9deb0 --- /dev/null +++ b/static/js/highlight.pack.js @@ -0,0 +1,9 @@ +/* PrismJS 1.22.0 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=scheme&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard+match-braces */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,_={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof M?new M(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function t(e,r){var a,n;switch(r=r||{},_.util.type(e)){case"Object":if(n=_.util.objId(e),r[n])return r[n];for(var i in a={},r[n]=a,e)e.hasOwnProperty(i)&&(a[i]=t(e[i],r));return a;case"Array":return n=_.util.objId(e),r[n]?r[n]:(a=[],r[n]=a,e.forEach(function(e,n){a[n]=t(e,r)}),a);default:return e}},getLanguage:function(e){for(;e&&!c.test(e.className);)e=e.parentElement;return e?(e.className.match(c)||[,"none"])[1].toLowerCase():"none"},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(e){var n=(/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(e.stack)||[])[1];if(n){var t=document.getElementsByTagName("script");for(var r in t)if(t[r].src==n)return t[r]}return null}},isActive:function(e,n,t){for(var r="no-"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{extend:function(e,n){var t=_.util.clone(_.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(t,e,n,r){var a=(r=r||_.languages)[t],i={};for(var l in a)if(a.hasOwnProperty(l)){if(l==e)for(var o in n)n.hasOwnProperty(o)&&(i[o]=n[o]);n.hasOwnProperty(l)||(i[l]=a[l])}var s=r[t];return r[t]=i,_.languages.DFS(_.languages,function(e,n){n===s&&e!=t&&(this[e]=i)}),i},DFS:function e(n,t,r,a){a=a||{};var i=_.util.objId;for(var l in n)if(n.hasOwnProperty(l)){t.call(n,l,n[l],r||l);var o=n[l],s=_.util.type(o);"Object"!==s||a[i(o)]?"Array"!==s||a[i(o)]||(a[i(o)]=!0,e(o,t,l,a)):(a[i(o)]=!0,e(o,t,null,a))}}},plugins:{},highlightAll:function(e,n){_.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};_.hooks.run("before-highlightall",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),_.hooks.run("before-all-elements-highlight",r);for(var a,i=0;a=r.elements[i++];)_.highlightElement(a,!0===n,r.callback)},highlightElement:function(e,n,t){var r=_.util.getLanguage(e),a=_.languages[r];e.className=e.className.replace(c,"").replace(/\s+/g," ")+" language-"+r;var i=e.parentElement;i&&"pre"===i.nodeName.toLowerCase()&&(i.className=i.className.replace(c,"").replace(/\s+/g," ")+" language-"+r);var l={element:e,language:r,grammar:a,code:e.textContent};function o(e){l.highlightedCode=e,_.hooks.run("before-insert",l),l.element.innerHTML=l.highlightedCode,_.hooks.run("after-highlight",l),_.hooks.run("complete",l),t&&t.call(l.element)}if(_.hooks.run("before-sanity-check",l),!l.code)return _.hooks.run("complete",l),void(t&&t.call(l.element));if(_.hooks.run("before-highlight",l),l.grammar)if(n&&u.Worker){var s=new Worker(_.filename);s.onmessage=function(e){o(e.data)},s.postMessage(JSON.stringify({language:l.language,code:l.code,immediateClose:!0}))}else o(_.highlight(l.code,l.grammar,l.language));else o(_.util.encode(l.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};return _.hooks.run("before-tokenize",r),r.tokens=_.tokenize(r.code,r.grammar),_.hooks.run("after-tokenize",r),M.stringify(_.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new i;return z(a,a.head,e),function e(n,t,r,a,i,l){for(var o in r)if(r.hasOwnProperty(o)&&r[o]){var s=r[o];s=Array.isArray(s)?s:[s];for(var u=0;u<s.length;++u){if(l&&l.cause==o+","+u)return;var c=s[u],g=c.inside,f=!!c.lookbehind,h=!!c.greedy,d=c.alias;if(h&&!c.pattern.global){var v=c.pattern.toString().match(/[imsuy]*$/)[0];c.pattern=RegExp(c.pattern.source,v+"g")}for(var p=c.pattern||c,m=a.next,y=i;m!==t.tail&&!(l&&y>=l.reach);y+=m.value.length,m=m.next){var k=m.value;if(t.length>n.length)return;if(!(k instanceof M)){var b,x=1;if(h){if(!(b=W(p,y,n,f)))break;var w=b.index,A=b.index+b[0].length,P=y;for(P+=m.value.length;P<=w;)m=m.next,P+=m.value.length;if(P-=m.value.length,y=P,m.value instanceof M)continue;for(var S=m;S!==t.tail&&(P<A||"string"==typeof S.value);S=S.next)x++,P+=S.value.length;x--,k=n.slice(y,P),b.index-=y}else if(!(b=W(p,0,k,f)))continue;var w=b.index,E=b[0],O=k.slice(0,w),L=k.slice(w+E.length),N=y+k.length;l&&N>l.reach&&(l.reach=N);var j=m.prev;O&&(j=z(t,j,O),y+=O.length),I(t,j,x);var C=new M(o,g?_.tokenize(E,g):E,d,E);m=z(t,j,C),L&&z(t,m,L),1<x&&e(n,t,r,m.prev,y,{cause:o+","+u,reach:N})}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=_.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=_.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:M};function M(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function W(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function z(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function I(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;(n.next=r).prev=n,e.length-=a}if(u.Prism=_,M.stringify=function n(e,t){if("string"==typeof e)return e;if(Array.isArray(e)){var r="";return e.forEach(function(e){r+=n(e,t)}),r}var a={type:e.type,content:n(e.content,t),tag:"span",classes:["token",e.type],attributes:{},language:t},i=e.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),_.hooks.run("wrap",a);var l="";for(var o in a.attributes)l+=" "+o+'="'+(a.attributes[o]||"").replace(/"/g,""")+'"';return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+l+">"+a.content+"</"+a.tag+">"},!u.document)return u.addEventListener&&(_.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(_.highlight(r,_.languages[t],t)),a&&u.close()},!1)),_;var e=_.util.currentScript();function t(){_.manual||_.highlightAll()}if(e&&(_.filename=e.src,e.hasAttribute("data-manual")&&(_.manual=!0)),!_.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return _}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +Prism.languages.scheme={comment:/;.*|#;\s*\((?:[^()]|\([^()]*\))*\)|#\|(?:[^#|]|#(?!\|)|\|(?!#)|#\|(?:[^#|]|#(?!\|)|\|(?!#))*\|#)*\|#/,string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0},symbol:{pattern:/'[^()#'\s]+/,greedy:!0},character:{pattern:/#\\(?:[ux][a-fA-F\d]+\b|[-a-zA-Z]+\b|\S)/,greedy:!0,alias:"string"},"lambda-parameter":[{pattern:/((?:^|[^'`#])\(lambda\s+)(?:[^|()'\s]+|\|(?:[^\\|]|\\.)*\|)/,lookbehind:!0},{pattern:/((?:^|[^'`#])\(lambda\s+\()[^()']+/,lookbehind:!0}],keyword:{pattern:/((?:^|[^'`#])\()(?:begin|case(?:-lambda)?|cond(?:-expand)?|define(?:-library|-macro|-record-type|-syntax|-values)?|defmacro|delay(?:-force)?|do|else|export|except|guard|if|import|include(?:-ci|-library-declarations)?|lambda|let(?:rec)?(?:-syntax|-values|\*)?|let\*-values|only|parameterize|prefix|(?:quasi-?)?quote|rename|set!|syntax-(?:case|rules)|unless|unquote(?:-splicing)?|when)(?=[()\s]|$)/,lookbehind:!0},builtin:{pattern:/((?:^|[^'`#])\()(?:abs|and|append|apply|assoc|ass[qv]|binary-port\?|boolean=?\?|bytevector(?:-append|-copy|-copy!|-length|-u8-ref|-u8-set!|\?)?|caar|cadr|call-with-(?:current-continuation|port|values)|call\/cc|car|cdar|cddr|cdr|ceiling|char(?:->integer|-ready\?|\?|<\?|<=\?|=\?|>\?|>=\?)|close-(?:input-port|output-port|port)|complex\?|cons|current-(?:error|input|output)-port|denominator|dynamic-wind|eof-object\??|eq\?|equal\?|eqv\?|error|error-object(?:-irritants|-message|\?)|eval|even\?|exact(?:-integer-sqrt|-integer\?|\?)?|expt|features|file-error\?|floor(?:-quotient|-remainder|\/)?|flush-output-port|for-each|gcd|get-output-(?:bytevector|string)|inexact\??|input-port(?:-open\?|\?)|integer(?:->char|\?)|lcm|length|list(?:->string|->vector|-copy|-ref|-set!|-tail|\?)?|make-(?:bytevector|list|parameter|string|vector)|map|max|member|memq|memv|min|modulo|negative\?|newline|not|null\?|number(?:->string|\?)|numerator|odd\?|open-(?:input|output)-(?:bytevector|string)|or|output-port(?:-open\?|\?)|pair\?|peek-char|peek-u8|port\?|positive\?|procedure\?|quotient|raise|raise-continuable|rational\?|rationalize|read-(?:bytevector|bytevector!|char|error\?|line|string|u8)|real\?|remainder|reverse|round|set-c[ad]r!|square|string(?:->list|->number|->symbol|->utf8|->vector|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\?|<\?|<=\?|=\?|>\?|>=\?)?|substring|symbol(?:->string|\?|=\?)|syntax-error|textual-port\?|truncate(?:-quotient|-remainder|\/)?|u8-ready\?|utf8->string|values|vector(?:->list|->string|-append|-copy|-copy!|-fill!|-for-each|-length|-map|-ref|-set!|\?)?|with-exception-handler|write-(?:bytevector|char|string|u8)|zero\?)(?=[()\s]|$)/,lookbehind:!0},operator:{pattern:/((?:^|[^'`#])\()(?:[-+*%/]|[<>]=?|=>?)(?=[()\s]|$)/,lookbehind:!0},number:{pattern:RegExp(function(r){for(var e in r)r[e]=r[e].replace(/<[\w\s]+>/g,function(e){return"(?:"+r[e].trim()+")"});return r[e]}({"<ureal dec>":"\\d+(?:/\\d+)?|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?","<real dec>":"[+-]?<ureal dec>|[+-](?:inf|nan)\\.0","<imaginary dec>":"[+-](?:<ureal dec>|(?:inf|nan)\\.0)?i","<complex dec>":"<real dec>(?:@<real dec>|<imaginary dec>)?|<imaginary dec>","<num dec>":"(?:#d(?:#[ei])?|#[ei](?:#d)?)?<complex dec>","<ureal box>":"[0-9a-f]+(?:/[0-9a-f]+)?","<real box>":"[+-]?<ureal box>|[+-](?:inf|nan)\\.0","<imaginary box>":"[+-](?:<ureal box>|(?:inf|nan)\\.0)?i","<complex box>":"<real box>(?:@<real box>|<imaginary box>)?|<imaginary box>","<num box>":"#[box](?:#[ei])?|(?:#[ei])?#[box]<complex box>","<number>":"(^|[\\s()])(?:<num dec>|<num box>)(?=[()\\s]|$)"}),"i"),lookbehind:!0},boolean:{pattern:/(^|[\s()])#(?:[ft]|false|true)(?=[()\s]|$)/,lookbehind:!0},function:{pattern:/((?:^|[^'`#])\()(?:[^|()'\s]+|\|(?:[^\\|]|\\.)*\|)(?=[()\s]|$)/,lookbehind:!0},identifier:{pattern:/(^|[\s()])\|(?:[^\\|]|\\.)*\|(?=[()\s]|$)/,lookbehind:!0,greedy:!0},punctuation:/[()']/}; +!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector){var t,s=function(){if(void 0===t){var e=document.createElement("div");e.style.fontSize="13px",e.style.lineHeight="1.5",e.style.padding="0",e.style.border="0",e.innerHTML=" <br /> ",document.body.appendChild(e),t=38===e.offsetHeight,document.body.removeChild(e)}return t},l=!0,a=0;Prism.hooks.add("before-sanity-check",function(e){var t=e.element.parentNode,n=t&&t.getAttribute("data-line");if(t&&n&&/pre/i.test(t.nodeName)){var i=0;g(".line-highlight",t).forEach(function(e){i+=e.textContent.length,e.parentNode.removeChild(e)}),i&&/^( \n)+$/.test(e.code.slice(-i))&&(e.code=e.code.slice(0,-i))}}),Prism.hooks.add("complete",function e(t){var n=t.element.parentNode,i=n&&n.getAttribute("data-line");if(n&&i&&/pre/i.test(n.nodeName)){clearTimeout(a);var r=Prism.plugins.lineNumbers,o=t.plugins&&t.plugins.lineNumbers;if(b(n,"line-numbers")&&r&&!o)Prism.hooks.add("line-numbers",e);else u(n,i)(),a=setTimeout(c,1)}}),window.addEventListener("hashchange",c),window.addEventListener("resize",function(){g("pre[data-line]").map(function(e){return u(e)}).forEach(v)})}function g(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function b(e,t){return t=" "+t+" ",-1<(" "+e.className+" ").replace(/[\n\t]/g," ").indexOf(t)}function v(e){e()}function u(u,e,c){var t=(e="string"==typeof e?e:u.getAttribute("data-line")).replace(/\s+/g,"").split(",").filter(Boolean),d=+u.getAttribute("data-line-offset")||0,f=(s()?parseInt:parseFloat)(getComputedStyle(u).lineHeight),m=b(u,"line-numbers"),p=m?u:u.querySelector("code")||u,h=[];t.forEach(function(e){var t=e.split("-"),n=+t[0],i=+t[1]||n,r=u.querySelector('.line-highlight[data-range="'+e+'"]')||document.createElement("div");if(h.push(function(){r.setAttribute("aria-hidden","true"),r.setAttribute("data-range",e),r.className=(c||"")+" line-highlight"}),m&&Prism.plugins.lineNumbers){var o=Prism.plugins.lineNumbers.getLine(u,n),a=Prism.plugins.lineNumbers.getLine(u,i);if(o){var s=o.offsetTop+"px";h.push(function(){r.style.top=s})}if(a){var l=a.offsetTop-o.offsetTop+a.offsetHeight+"px";h.push(function(){r.style.height=l})}}else h.push(function(){r.setAttribute("data-start",n),n<i&&r.setAttribute("data-end",i),r.style.top=(n-d-1)*f+"px",r.textContent=new Array(i-n+2).join(" \n")});h.push(function(){p.appendChild(r)})});var i=u.id;if(m&&i){for(var n="linkable-line-numbers",r=!1,o=u;o;){if(b(o,n)){r=!0;break}o=o.parentElement}if(r){b(u,n)||h.push(function(){u.className=(u.className+" "+n).trim()});var a=parseInt(u.getAttribute("data-start")||"1");g(".line-numbers-rows > span",u).forEach(function(e,t){var n=t+a;e.onclick=function(){var e=i+"."+n;l=!1,location.hash=e,setTimeout(function(){l=!0},1)}})}}return function(){h.forEach(v)}}function c(){var e=location.hash.slice(1);g(".temporary.line-highlight").forEach(function(e){e.parentNode.removeChild(e)});var t=(e.match(/\.([\d,-]+)$/)||[,""])[1];if(t&&!document.getElementById(e)){var n=e.slice(0,e.lastIndexOf(".")),i=document.getElementById(n);if(i)i.hasAttribute("data-line")||i.setAttribute("data-line",""),u(i,t,"temporary ")(),l&&document.querySelector(".temporary.line-highlight").scrollIntoView()}}}(); +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var o="line-numbers",a=/\n(?!$)/g,e=Prism.plugins.lineNumbers={getLine:function(e,n){if("PRE"===e.tagName&&e.classList.contains(o)){var t=e.querySelector(".line-numbers-rows");if(t){var i=parseInt(e.getAttribute("data-start"),10)||1,r=i+(t.children.length-1);n<i&&(n=i),r<n&&(n=r);var s=n-i;return t.children[s]}}},resize:function(e){u([e])},assumeViewportIndependence:!0},t=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null},n=void 0;window.addEventListener("resize",function(){e.assumeViewportIndependence&&n===window.innerWidth||(n=window.innerWidth,u(Array.prototype.slice.call(document.querySelectorAll("pre."+o))))}),Prism.hooks.add("complete",function(e){if(e.code){var n=e.element,t=n.parentNode;if(t&&/pre/i.test(t.nodeName)&&!n.querySelector(".line-numbers-rows")&&Prism.util.isActive(n,o)){n.classList.remove(o),t.classList.add(o);var i,r=e.code.match(a),s=r?r.length+1:1,l=new Array(s+1).join("<span></span>");(i=document.createElement("span")).setAttribute("aria-hidden","true"),i.className="line-numbers-rows",i.innerHTML=l,t.hasAttribute("data-start")&&(t.style.counterReset="linenumber "+(parseInt(t.getAttribute("data-start"),10)-1)),e.element.appendChild(i),u([t]),Prism.hooks.run("line-numbers",e)}}}),Prism.hooks.add("line-numbers",function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0})}function u(e){if(0!=(e=e.filter(function(e){var n=t(e)["white-space"];return"pre-wrap"===n||"pre-line"===n})).length){var n=e.map(function(e){var n=e.querySelector("code"),t=e.querySelector(".line-numbers-rows");if(n&&t){var i=e.querySelector(".line-numbers-sizer"),r=n.textContent.split(a);i||((i=document.createElement("span")).className="line-numbers-sizer",n.appendChild(i)),i.innerHTML="0",i.style.display="block";var s=i.getBoundingClientRect().height;return i.innerHTML="",{element:e,lines:r,lineHeights:[],oneLinerHeight:s,sizer:i}}}).filter(Boolean);n.forEach(function(e){var i=e.sizer,n=e.lines,r=e.lineHeights,s=e.oneLinerHeight;r[n.length-1]=void 0,n.forEach(function(e,n){if(e&&1<e.length){var t=i.appendChild(document.createElement("span"));t.style.display="block",t.textContent=e}else r[n]=s})}),n.forEach(function(e){for(var n=e.sizer,t=e.lineHeights,i=0,r=0;r<t.length;r++)void 0===t[r]&&(t[r]=n.children[i++].getBoundingClientRect().height)}),n.forEach(function(e){var n=e.sizer,t=e.element.querySelector(".line-numbers-rows");n.style.display="none",n.innerHTML="",e.lineHeights.forEach(function(e,n){t.children[n].style.height=e+"px"})})}}}(); +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var i=[],l={},c=function(){};Prism.plugins.toolbar={};var e=Prism.plugins.toolbar.registerButton=function(e,n){var t;t="function"==typeof n?n:function(e){var t;return"function"==typeof n.onClick?((t=document.createElement("button")).type="button",t.addEventListener("click",function(){n.onClick.call(this,e)})):"string"==typeof n.url?(t=document.createElement("a")).href=n.url:t=document.createElement("span"),n.className&&t.classList.add(n.className),t.textContent=n.text,t},e in l?console.warn('There is a button with the key "'+e+'" registered already.'):i.push(l[e]=t)},t=Prism.plugins.toolbar.hook=function(a){var e=a.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&!e.parentNode.classList.contains("code-toolbar")){var t=document.createElement("div");t.classList.add("code-toolbar"),e.parentNode.insertBefore(t,e),t.appendChild(e);var r=document.createElement("div");r.classList.add("toolbar");var n=i,o=function(e){for(;e;){var t=e.getAttribute("data-toolbar-order");if(null!=t)return(t=t.trim()).length?t.split(/\s*,\s*/g):[];e=e.parentElement}}(a.element);o&&(n=o.map(function(e){return l[e]||c})),n.forEach(function(e){var t=e(a);if(t){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(t),r.appendChild(n)}}),t.appendChild(r)}};e("label",function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-label")){var n,a,r=t.getAttribute("data-label");try{a=document.querySelector("template#"+r)}catch(e){}return a?n=a.content:(t.hasAttribute("data-url")?(n=document.createElement("a")).href=t.getAttribute("data-url"):n=document.createElement("span"),n.textContent=r),n}}),Prism.hooks.add("complete",t)}}(); +!function(){if("undefined"!=typeof self&&self.Prism&&self.document)if(Prism.plugins.toolbar){var i=window.ClipboardJS||void 0;i||"function"!=typeof require||(i=require("clipboard"));var u=[];if(!i){var t=document.createElement("script"),e=document.querySelector("head");t.onload=function(){if(i=window.ClipboardJS)for(;u.length;)u.pop()()},t.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",e.appendChild(t)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(t){var e=document.createElement("button");e.textContent="Copy",e.setAttribute("type","button");var o=t.element;return i?n():u.push(n),e;function n(){var t=new i(e,{text:function(){return o.textContent}});t.on("success",function(){e.textContent="Copied!",r()}),t.on("error",function(){e.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){e.textContent="Copy"},5e3)}})}else console.warn("Copy to Clipboard plugin loaded before Toolbar plugin.")}(); +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var d={"(":")","[":"]","{":"}"},u={"(":"brace-round","[":"brace-square","{":"brace-curly"},f={"${":"{"},h=0,n=/^(pair-\d+-)(open|close)$/;Prism.hooks.add("complete",function(e){var t=e.element,n=t.parentElement;if(n&&"PRE"==n.tagName){var c=[];if(Prism.util.isActive(t,"match-braces")&&c.push("(","[","{"),0!=c.length){n.__listenerAdded||(n.addEventListener("mousedown",function(){var e=n.querySelector("code");Array.prototype.slice.call(e.querySelectorAll(".brace-selected")).forEach(function(e){e.classList.remove("brace-selected")})}),Object.defineProperty(n,"__listenerAdded",{value:!0}));var o=Array.prototype.slice.call(t.querySelectorAll("span.token.punctuation")),l=[];c.forEach(function(e){for(var t=d[e],n=u[e],c=[],r=[],s=0;s<o.length;s++){var a=o[s];if(0==a.childElementCount){var i=a.textContent;(i=f[i]||i)===e?(l.push({index:s,open:!0,element:a}),a.classList.add(n),a.classList.add("brace-open"),r.push(s)):i===t&&(l.push({index:s,open:!1,element:a}),a.classList.add(n),a.classList.add("brace-close"),r.length&&c.push([s,r.pop()]))}}c.forEach(function(e){var t="pair-"+h+++"-",n=o[e[0]],c=o[e[1]];n.id=t+"open",c.id=t+"close",[n,c].forEach(function(e){e.addEventListener("mouseenter",p),e.addEventListener("mouseleave",v),e.addEventListener("click",m)})})});var r=0;l.sort(function(e,t){return e.index-t.index}),l.forEach(function(e){e.open?(e.element.classList.add("brace-level-"+(r%12+1)),r++):(r=Math.max(0,r-1),e.element.classList.add("brace-level-"+(r%12+1)))})}}})}function e(e){var t=n.exec(e.id);return document.querySelector("#"+t[1]+("open"==t[2]?"close":"open"))}function p(){Prism.util.isActive(this,"brace-hover",!0)&&[this,e(this)].forEach(function(e){e.classList.add("brace-hover")})}function v(){[this,e(this)].forEach(function(e){e.classList.remove("brace-hover")})}function m(){Prism.util.isActive(this,"brace-select",!0)&&[this,e(this)].forEach(function(e){e.classList.add("brace-selected")})}}(); |


