| summaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'content/learn')
| -rw-r--r-- | content/learn/01.start/_index.md | 43 | ||||
| -rw-r--r-- | content/learn/02.choices/_index.md | 71 | ||||
| -rw-r--r-- | content/learn/03.variables/default.md | 90 | ||||
| -rw-r--r-- | content/learn/04.sequences/default.md | 123 | ||||
| -rw-r--r-- | content/learn/05.files/default.md | 113 | ||||
| -rw-r--r-- | content/learn/06.pointers/default.md | 171 | ||||
| -rw-r--r-- | content/learn/07.structures/default.md | 201 | ||||
| -rw-r--r-- | content/learn/08.collections/default.md | 408 | ||||
| -rw-r--r-- | content/learn/09.lambdas/default.md | 366 | ||||
| -rw-r--r-- | content/learn/10.conditions/default.md | 402 | ||||
| -rw-r--r-- | content/learn/_index.md | 8 |
11 files changed, 1996 insertions, 0 deletions
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. |


