From c112636c7151b5f398faca95d2826c739578af3d Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Sat, 6 Jun 2020 01:00:27 +0200 Subject: [PATCH] [docs] Reindent all examples in Writing With Ink --- Documentation/WritingWithInk.md | 1589 ++++++++++++++++--------------- 1 file changed, 795 insertions(+), 794 deletions(-) diff --git a/Documentation/WritingWithInk.md b/Documentation/WritingWithInk.md index c8c7790c..5ea4e0a9 100644 --- a/Documentation/WritingWithInk.md +++ b/Documentation/WritingWithInk.md @@ -45,13 +45,13 @@ The simplest mark-up is a comment. **ink** supports two kinds of comment. There' ``` ink "What do you make of this?" she asked. - + // Something unprintable... - + "I couldn't possibly comment," I replied. - + /* - ... or an unlimited block of text +... or an unlimited block of text */ ``` @@ -82,8 +82,8 @@ If no other flow instructions are given, once made, the choice will flow into th ``` ink Hello world! -* Hello back! - Nice to hear from you! + * Hello back! + Nice to hear from you! ``` This produces the following game: @@ -105,8 +105,8 @@ Some games separate the text of a choice from its outcome. In **ink**, if the ch ``` ink Hello world! -* [Hello back!] - Nice to hear from you! + * [Hello back!] + Nice to hear from you! ``` produces: @@ -125,8 +125,8 @@ The square brackets in fact divide up the option content. What's before is print ``` ink Hello world! -* Hello [back!] right back to you! - Nice to hear from you! + * Hello [back!] right back to you! + Nice to hear from you! ``` produces: @@ -143,8 +143,8 @@ This is most useful when writing dialogue choices: ``` ink "What's that?" my master asked. -* "I am somewhat tired[."]," I repeated. - "Really," he responded. "How deleterious." + * "I am somewhat tired[."]," I repeated. + "Really," he responded. "How deleterious." ``` produces: @@ -163,12 +163,12 @@ To make choices really choices, we need to provide alternatives. We can do this ``` ink "What's that?" my master asked. -* "I am somewhat tired[."]," I repeated. - "Really," he responded. "How deleterious." -* "Nothing, Monsieur!"[] I replied. - "Very good, then." -* "I said, this journey is appalling[."] and I want no more of it." - "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve." + * "I am somewhat tired[."]," I repeated. + "Really," he responded. "How deleterious." + * "Nothing, Monsieur!"[] I replied. + "Very good, then." + * "I said, this journey is appalling[."] and I want no more of it." + "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve." ``` This produces the following game: @@ -209,7 +209,7 @@ The start of a knot is a header; the content that follows will be inside that kn ``` ink === back_in_london === - + We arrived into London at 9.45pm exactly. ``` @@ -221,7 +221,7 @@ The simplest knotty script is: ``` ink -> top_knot - + === top_knot === Hello world! ``` @@ -256,10 +256,10 @@ You can tell the story to move from one knot to another using `->`, a "divert ar ``` ink === back_in_london === - + We arrived into London at 9.45pm exactly. -> hurry_home - + === hurry_home === We hurried home to Savile Row as fast as we could. ``` @@ -271,7 +271,7 @@ Diverts are intended to be seamless and can even happen mid-sentence: ``` ink === hurry_home === We hurried home to Savile Row -> as_fast_as_we_could - + === as_fast_as_we_could === as fast as we could. ``` @@ -290,11 +290,11 @@ The default behaviour inserts line-breaks before every new line of content. In s === hurry_home === We hurried home <> -> to_savile_row - + === to_savile_row === to Savile Row -> as_fast_as_we_could - + === as_fast_as_we_could === <> as fast as we could. ``` @@ -317,13 +317,13 @@ Combining knots, options and diverts gives us the basic structure of a choose-yo ``` ink === paragraph_1 === You stand by the wall of Analand, sword in hand. -* [Open the gate] -> paragraph_2 -* [Smash down the gate] -> paragraph_3 -* [Turn back and go home] -> paragraph_4 + * [Open the gate] -> paragraph_2 + * [Smash down the gate] -> paragraph_3 + * [Turn back and go home] -> paragraph_4 === paragraph_2 === You open the gate, and step out onto the path. - + ... ``` @@ -333,23 +333,23 @@ Using diverts, the writer can branch the flow, and join it back up again, withou ``` ink === back_in_london === - + We arrived into London at 9.45pm exactly. - -* "There is not a moment to lose!"[] I declared. - -> hurry_outside -* "Monsieur, let us savour this moment!"[] I declared. - My master clouted me firmly around the head and dragged me out of the door. - -> dragged_outside - -* [We hurried home] -> hurry_outside - + * "There is not a moment to lose!"[] I declared. + -> hurry_outside + + * "Monsieur, let us savour this moment!"[] I declared. + My master clouted me firmly around the head and dragged me out of the door. + -> dragged_outside + + * [We hurried home] -> hurry_outside + === hurry_outside === We hurried home to Savile Row -> as_fast_as_we_could - - + + === dragged_outside === He insisted that we hurried home to Savile Row -> as_fast_as_we_could @@ -461,12 +461,12 @@ From inside a knot, you don't need to use the full address for a stitch. === the_orient_express === = in_first_class - I settled my master. +I settled my master. * [Move to third class] -> in_third_class = in_third_class - I put myself in third. +I put myself in third. ``` This means stitches and knots can't share names, but several knots can contain the same stitch name. (So both the Orient Express and the SS Mongolia can have first class.) @@ -544,7 +544,7 @@ A fallback choice is simply a "choice without choice text": And, in a slight abuse of syntax, we can make a default choice with content in it, using an "choice then arrow": ``` ink -* -> +* -> Mulder never could explain how he got out of that burning box car. -> season_2 ``` @@ -554,11 +554,11 @@ Adding this into the previous example gives us: ``` ink === find_help === - - You search desperately for a friendly face in the crowd. + +You search desperately for a friendly face in the crowd. * The woman in the hat[?] pushes you roughly aside. -> find_help * The man with the briefcase[?] looks disgusted as you stumble past him. -> find_help - * -> + * -> But it is too late: you collapse onto the station platform. This is the end. -> END ``` @@ -600,10 +600,10 @@ The 'once-only' behaviour is not always what we want, of course, so we have a se Default choices can be sticky too. ``` ink -=== conversation_loop +=== conversation_loop * [Talk about the weather] -> chat_weather * [Talk about the children] -> chat_children - + -> sit_in_silence_again + + -> sit_in_silence_again ``` ### Conditional Choices @@ -613,10 +613,10 @@ You can also turn choices on and off by hand. **ink** has quite a lot of logic a Every knot/stitch in the game has a unique address (so it can be diverted to), and we use the same address to test if that piece of content has been seen. ``` ink -* { not visit_paris } [Go to Paris] -> visit_paris -+ { visit_paris } [Return to Paris] -> visit_paris + * { not visit_paris } [Go to Paris] -> visit_paris + + { visit_paris } [Return to Paris] -> visit_paris -* { visit_paris.met_estelle } [ Telephone Mme Estelle ] -> phone_estelle + * { visit_paris.met_estelle } [ Telephone Mme Estelle ] -> phone_estelle ``` Note that the test `knot_name` is true if *any* stitch inside that knot has been seen. @@ -628,9 +628,9 @@ Note also that conditionals don't override the once-only behaviour of options, s You can use several logical tests on an option; if you do, *all* the tests must all be passed for the option to appear. ``` ink -* { not visit_paris } [Go to Paris] -> visit_paris -+ { visit_paris } { not bored_of_paris } - [Return to Paris] -> visit_paris + * { not visit_paris } [Go to Paris] -> visit_paris + + { visit_paris } { not bored_of_paris } + [Return to Paris] -> visit_paris ``` #### Logical operators: AND and OR @@ -638,7 +638,7 @@ You can use several logical tests on an option; if you do, *all* the tests must The above "multiple conditions" are really just conditions with an the usual programming AND operator. Ink supports `and` (also written as `&&`) and `or` (also written as `||`) in the usual way, as well as brackets. ``` ink -* { not (visit_paris or visit_rome) && (visit_london || visit_new_york) } [ Wait. Go where? I'm confused. ] -> visit_someplace + * { not (visit_paris or visit_rome) && (visit_london || visit_new_york) } [ Wait. Go where? I'm confused. ] -> visit_someplace ``` For non-programmers `X and Y` means both X and Y must be true. `X or Y` means either or both. We don't have a `xor`. @@ -659,7 +659,6 @@ If it's non-zero, it'll return true in a test like the one above, but you can al ``` ink * {seen_clue > 3} [Flat-out arrest Mr Jefferson] - ``` #### Advanced: more logic @@ -739,7 +738,7 @@ I {waited.|waited some more.|snoozed.|woke up and waited more.|gave up and left. They can also be used inside choice text: ``` ink -+ "Hello, {&Master|Monsieur Fogg|you|brown-eyes}!"[] I declared. ++ "Hello, {&Master|Monsieur Fogg|you|brown-eyes}!"[] I declared. ``` (...with one caveat; you can't start an option's text with a `{`, as it'll look like a conditional.) @@ -754,15 +753,15 @@ Here's a one-knot version of whack-a-mole. Note we use once-only options, and a ``` ink === whack_a_mole === - {I heft the hammer.|{~Missed!|Nothing!|No good. Where is he?|Ah-ha! Got him! -> END}} - The {&mole|{&nasty|blasted|foul} {&creature|rodent}} is {in here somewhere|hiding somewhere|still at large|laughing at me|still unwhacked|doomed}. <> - {!I'll show him!|But this time he won't escape!} - * [{&Hit|Smash|Try} top-left] -> whack_a_mole - * [{&Whallop|Splat|Whack} top-right] -> whack_a_mole - * [{&Blast|Hammer} middle] -> whack_a_mole - * [{&Clobber|Bosh} bottom-left] -> whack_a_mole - * [{&Nail|Thump} bottom-right] -> whack_a_mole - * [] Then you collapse from hunger. The mole has defeated you! +{I heft the hammer.|{~Missed!|Nothing!|No good. Where is he?|Ah-ha! Got him! -> END}} +The {&mole|{&nasty|blasted|foul} {&creature|rodent}} is {in here somewhere|hiding somewhere|still at large|laughing at me|still unwhacked|doomed}. <> +{!I'll show him!|But this time he won't escape!} + * [{&Hit|Smash|Try} top-left] -> whack_a_mole + * [{&Whallop|Splat|Whack} top-right] -> whack_a_mole + * [{&Blast|Hammer} middle] -> whack_a_mole + * [{&Clobber|Bosh} bottom-left] -> whack_a_mole + * [{&Nail|Thump} bottom-right] -> whack_a_mole + * [] Then you collapse from hunger. The mole has defeated you! -> END ``` @@ -808,13 +807,13 @@ Ah-ha! Got him! And here's a bit of lifestyle advice. Note the sticky choice - the lure of the television will never fade: ``` ink -=== turn_on_television === +=== turn_on_television === I turned on the television {for the first time|for the second time|again|once more}, but there was {nothing good on, so I turned it off again|still nothing worth watching|even less to hold my interest than before|nothing but rubbish|a program about sharks and I don't like sharks|nothing on}. -+ [Try it again] -> turn_on_television -* [Go outside instead] -> go_outside_instead - - === go_outside_instead === - -> END + + [Try it again] -> turn_on_television + * [Go outside instead] -> go_outside_instead + +=== go_outside_instead === +-> END ``` @@ -874,8 +873,8 @@ The convention is to name these in capital letters. ``` ink * {false} Option A -* {true} Option B -* {CHOICE_COUNT() == 1} Option C +* {true} Option B +* {CHOICE_COUNT() == 1} Option C ``` produces two options, B and C. This can be useful for controlling how many options a player gets on a turn. @@ -891,8 +890,8 @@ This returns the number of game turns since the game began. A value of 0 means "was seen as part of the current chunk". A value of -1 means "has never been seen". Any other positive value means it has been seen that many turns ago. ``` ink -* {TURNS_SINCE(-> sleeping.intro) > 10} You are feeling tired... -> sleeping -* {TURNS_SINCE(-> laugh) == 0} You try to stop laughing. +* {TURNS_SINCE(-> sleeping.intro) > 10} You are feeling tired... -> sleeping +* {TURNS_SINCE(-> laugh) == 0} You try to stop laughing. ``` Note that the parameter passed to `TURNS_SINCE` is a "divert target", not simply the knot address itself (because the knot address is a number - the read count - not a location in the story...) @@ -953,7 +952,7 @@ Let's go back to the first multi-choice example at the top of this document. * "I am somewhat tired[."]," I repeated. "Really," he responded. "How deleterious." * "Nothing, Monsieur!"[] I replied. - * "I said, this journey is appalling[."] and I want no more of it." + * "I said, this journey is appalling[."] and I want no more of it." "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve." ``` @@ -965,8 +964,8 @@ In a real game, all three of these options might well lead to the same conclusio "Really," he responded. "How deleterious." * "Nothing, Monsieur!"[] I replied. "Very good, then." - * "I said, this journey is appalling[."] and I want no more of it." - "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve." + * "I said, this journey is appalling[."] and I want no more of it." + "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve." - With that Monsieur Fogg left the room. ``` @@ -991,20 +990,20 @@ With that Monsieur Fogg left the room. We can string these gather-and-branch sections together to make branchy sequences that always run forwards. ``` ink -=== escape === +=== escape === I ran through the forest, the dogs snapping at my heels. - - * I checked the jewels[] were still in my pocket, and the feel of them brought a spring to my step. <> - - * I did not pause for breath[] but kept on running. <> + + * I checked the jewels[] were still in my pocket, and the feel of them brought a spring to my step. <> + + * I did not pause for breath[] but kept on running. <> * I cheered with joy. <> - -- The road could not be much further! Mackie would have the engine running, and then I'd be safe. - + +- The road could not be much further! Mackie would have the engine running, and then I'd be safe. + * I reached the road and looked about[]. And would you believe it? - * I should interrupt to say Mackie is normally very reliable[]. He's never once let me down. Or rather, never once, previously to that night. - + * I should interrupt to say Mackie is normally very reliable[]. He's never once let me down. Or rather, never once, previously to that night. + - The road was empty. Mackie was nowhere to be seen. ``` @@ -1032,9 +1031,9 @@ This section comes with a warning. Nested weaves are very powerful and very comp Consider the following scene: ``` ink -- "Well, Poirot? Murder or suicide?" -* "Murder!" -* "Suicide!" +- "Well, Poirot? Murder or suicide?" + * "Murder!" + * "Suicide!" - Ms. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. ``` @@ -1044,14 +1043,14 @@ We can add new options via a set of nested sub-choices. We tell the script that ``` ink -- "Well, Poirot? Murder or suicide?" +- "Well, Poirot? Murder or suicide?" * "Murder!" - "And who did it?" - * * "Detective-Inspector Japp!" - * * "Captain Hastings!" - * * "Myself!" - * "Suicide!" - - Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. + "And who did it?" + * * "Detective-Inspector Japp!" + * * "Captain Hastings!" + * * "Myself!" + * "Suicide!" +- Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. ``` (Note that it's good style to also indent the lines to show the nesting, but the compiler doesn't mind.) @@ -1059,17 +1058,17 @@ We can add new options via a set of nested sub-choices. We tell the script that And should we want to add new sub-options to the other route, we do that in similar fashion. ``` ink -- "Well, Poirot? Murder or suicide?" +- "Well, Poirot? Murder or suicide?" * "Murder!" - "And who did it?" - * * "Detective-Inspector Japp!" - * * "Captain Hastings!" - * * "Myself!" - * "Suicide!" + "And who did it?" + * * "Detective-Inspector Japp!" + * * "Captain Hastings!" + * * "Myself!" + * "Suicide!" "Really, Poirot? Are you quite sure?" - * * "Quite sure." - * * "It is perfectly obvious." - - Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. + * * "Quite sure." + * * "It is perfectly obvious." +- Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. ``` Now, that initial choice of accusation will lead to specific follow-up questions - but either way, the flow will come back together at the gather point, for Mrs. Christie's cameo appearance. @@ -1081,20 +1080,20 @@ But what if we want a more extended sub-scene? Sometimes, it's not a question of expanding the number of options, but having more than one additional beat of story. We can do this by nesting gather points as well as options. ``` ink -- "Well, Poirot? Murder or suicide?" - * "Murder!" - "And who did it?" - * * "Detective-Inspector Japp!" - * * "Captain Hastings!" - * * "Myself!" - - - "You must be joking!" - * * "Mon ami, I am deadly serious." - * * "If only..." - * "Suicide!" - "Really, Poirot? Are you quite sure?" - * * "Quite sure." - * * "It is perfectly obvious." - - Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. +- "Well, Poirot? Murder or suicide?" + * "Murder!" + "And who did it?" + * * "Detective-Inspector Japp!" + * * "Captain Hastings!" + * * "Myself!" + - - "You must be joking!" + * * "Mon ami, I am deadly serious." + * * "If only..." + * "Suicide!" + "Really, Poirot? Are you quite sure?" + * * "Quite sure." + * * "It is perfectly obvious." +- Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed. ``` If the player chooses the "murder" option, they'll have two choices in a row on their sub-branch - a whole flat weave, just for them. @@ -1113,12 +1112,12 @@ Above, we used two levels of nesting; the main flow, and the sub-flow. But there ``` ink - "Tell us a tale, Captain!" * "Very well, you sea-dogs. Here's a tale..." - * * "It was a dark and stormy night..." - * * * "...and the crew were restless..." - * * * * "... and they said to their Captain..." - * * * * * "...Tell us a tale Captain!" + * * "It was a dark and stormy night..." + * * * "...and the crew were restless..." + * * * * "... and they said to their Captain..." + * * * * * "...Tell us a tale Captain!" * "No, it's past your bed-time." - - To a man, the crew began to yawn. +- To a man, the crew began to yawn. ``` After a while, this sub-nesting gets hard to read and manipulate, so it's good style to divert away to a new stitch if a side-choice goes unwieldy. @@ -1130,24 +1129,24 @@ But, in theory at least, you could write your entire story as a single weave. Here's a longer example: ``` ink -- I looked at Monsieur Fogg -* ... and I could contain myself no longer. - 'What is the purpose of our journey, Monsieur?' - 'A wager,' he replied. - * * 'A wager!'[] I returned. - He nodded. - * * * 'But surely that is foolishness!' - * * * 'A most serious matter then!' - - - - He nodded again. +- I looked at Monsieur Fogg + * ... and I could contain myself no longer. + 'What is the purpose of our journey, Monsieur?' + 'A wager,' he replied. + * * 'A wager!'[] I returned. + He nodded. + * * * 'But surely that is foolishness!' + * * * 'A most serious matter then!' + - - - He nodded again. * * * 'But can we win?' - 'That is what we will endeavour to find out,' he answered. + 'That is what we will endeavour to find out,' he answered. * * * 'A modest wager, I trust?' - 'Twenty thousand pounds,' he replied, quite flatly. - * * * I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <> - * * 'Ah[.'],' I replied, uncertain what I thought. - - - After that, <> -* ... but I said nothing[] and <> -- we passed the day in silence. + 'Twenty thousand pounds,' he replied, quite flatly. + * * * I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <> + * * 'Ah[.'],' I replied, uncertain what I thought. + - - After that, <> + * ... but I said nothing[] and <> +- we passed the day in silence. - -> END ``` @@ -1218,7 +1217,7 @@ But should we want to remember what the player has seen, we can - we add in labe Gather points at any nested level can be labelled using brackets. ``` ink -- (top) +- (top) ``` Once labelled, gather points can be diverted to, or tested for in conditionals, just like knots and stitches. This means you can use previous decisions to alter later outcomes inside the weave, while still keeping all the advantages of a clear, reliable forward-flow. @@ -1230,20 +1229,20 @@ These addresses can be used in conditional tests, which can be useful for creati ``` ink === meet_guard === The guard frowns at you. - -* (greet) [Greet him] - 'Greetings.' -* (get_out) 'Get out of my way[.'],' you tell the guard. - -- 'Hmm,' replies the guard. -* {greet} 'Having a nice day?' // only if you greeted him - -* 'Hmm?'[] you reply. - -* {get_out} [Shove him aside] // only if you threatened him - You shove him sharply. He stares in reply, and draws his sword! - -> fight_guard // this route diverts out of the weave + * (greet) [Greet him] + 'Greetings.' + * (get_out) 'Get out of my way[.'],' you tell the guard. + +- 'Hmm,' replies the guard. + + * {greet} 'Having a nice day?' // only if you greeted him + + * 'Hmm?'[] you reply. + + * {get_out} [Shove him aside] // only if you threatened him + You shove him sharply. He stares in reply, and draws his sword! + -> fight_guard // this route diverts out of the weave - 'Mff,' the guard replies, and then offers you a paper bag. 'Toffee?' ``` @@ -1256,7 +1255,7 @@ Inside the same block of weave, you can simply use the label name; from outside ``` ink === knot === = stitch_one - - (gatherpoint) Some content. +- (gatherpoint) Some content. = stitch_two * {stitch_one.gatherpoint} Option ``` @@ -1266,12 +1265,12 @@ or pointing into another knot: ``` ink === knot_one === - (gather_one) - * {knot_two.stitch_two.gather_two} Option - + * {knot_two.stitch_two.gather_two} Option + === knot_two === -= stitch_two - - (gather_two) - * {knot_one.gather_one} Option += stitch_two +- (gather_two) + * {knot_one.gather_one} Option ``` @@ -1283,8 +1282,8 @@ In truth, all content in ink is a weave, even if there are no gathers in sight. === fight_guard === ... = throw_something -* (rock) [Throw rock at guard] -> throw -* (sand) [Throw sand at guard] -> throw + * (rock) [Throw rock at guard] -> throw + * (sand) [Throw sand at guard] -> throw = throw You hurl {throw_something.rock:a rock|a handful of sand} at the guard. @@ -1296,7 +1295,7 @@ You hurl {throw_something.rock:a rock|a handful of sand} at the guard. Labelling allows us to create loops inside weaves. Here's a standard pattern for asking questions of an NPC. ``` ink -- (opts) +- (opts) * 'Can I get a uniform from somewhere?'[] you ask the cheerful guard. 'Sure. In the locker.' He grins. 'Don't think it'll fit you, though.' * 'Tell me about the security system.' @@ -1306,12 +1305,12 @@ Labelling allows us to create loops inside weaves. Here's a standard pattern for // We require the player to ask at least one question * {loop} [Enough talking] -> done -- (loop) +- (loop) // loop a few times before the guard gets bored { -> opts | -> opts | } He scratches his head. 'Well, can't stand around talking all day,' he declares. -- (done) +- (done) You thank the guard, and move away. ``` @@ -1321,15 +1320,15 @@ Labelling allows us to create loops inside weaves. Here's a standard pattern for Options can also be diverted to: but the divert goes to the output of having chosen that choice, *as though the choice had been chosen*. So the content printed will ignore square bracketed text, and if the option is once-only, it will be marked as used up. ``` ink -- (opts) -* [Pull a face] - You pull a face, and the soldier comes at you! -> shove +- (opts) + * [Pull a face] + You pull a face, and the soldier comes at you! -> shove -* (shove) [Shove the guard aside] You shove the guard to one side, but he comes back swinging. + * (shove) [Shove the guard aside] You shove the guard to one side, but he comes back swinging. -* {shove} [Grapple and fight] -> fight_the_guard - -- -> opts + * {shove} [Grapple and fight] -> fight_the_guard + +- -> opts ``` produces: @@ -1351,11 +1350,11 @@ You pull a face, and the soldier comes at you! You shove the guard to one side, The following is valid, and frequently useful. ``` ink -* "Are you quite well, Monsieur?"[] I asked. - - - (quitewell) "Quite well," he replied. -* "How did you do at the crossword, Monsieur?"[] I asked. - -> quitewell -* I said nothing[] and neither did my Master. + * "Are you quite well, Monsieur?"[] I asked. + - - (quitewell) "Quite well," he replied. + * "How did you do at the crossword, Monsieur?"[] I asked. + -> quitewell + * I said nothing[] and neither did my Master. - We feel into companionable silence once more. ``` @@ -1396,9 +1395,9 @@ We can test global variables to control options, and provide conditional text, i ``` ink === the_train === - The train jolted and rattled. { mood > 0:I was feeling positive enough, however, and did not mind the odd bump|It was more than I could bear}. +The train jolted and rattled. { mood > 0:I was feeling positive enough, however, and did not mind the odd bump|It was more than I could bear}. * { not knows_about_wager } 'But, Monsieur, why are we travelling?'[] I asked. - * { knows_about_wager} I contemplated our strange adventure[]. Would it be possible? + * { knows_about_wager} I contemplated our strange adventure[]. Would it be possible? ``` #### Advanced: storing diverts as variables @@ -1406,12 +1405,12 @@ We can test global variables to control options, and provide conditional text, i A "divert" statement is actually a type of value in itself, and can be stored, altered, and diverted to. ``` ink -VAR current_epilogue = -> everybody_dies - +VAR current_epilogue = -> everybody_dies + === continue_or_quit === Give up now, or keep trying to save your Kingdom? -* [Keep trying!] -> more_hopeless_introspection -* [Give up] -> current_epilogue + * [Keep trying!] -> more_hopeless_introspection + * [Give up] -> current_epilogue ``` @@ -1444,7 +1443,7 @@ It might be noticed that above we refered to variables as being able to contain VAR a_colour = "" ~ a_colour = "{~red|blue|green|yellow}" - + {a_colour} ``` @@ -1678,33 +1677,33 @@ You can even put options inside conditional blocks: There's one other class of multiline block, which expands on the alternatives system from above. The following are all valid and do what you might expect: ``` ink - // Sequence: go through the alternatives, and stick on last +// Sequence: go through the alternatives, and stick on last { stopping: - I entered the casino. - - I entered the casino again. - - Once more, I went inside. + - I entered the casino again. + - Once more, I went inside. } - + // Shuffle: show one at random At the table, I drew a card. <> { shuffle: - - Ace of Hearts. - - King of Spades. - - 2 of Diamonds. + - Ace of Hearts. + - King of Spades. + - 2 of Diamonds. 'You lose this time!' crowed the croupier. } - + // Cycle: show each in turn, and then cycle { cycle: - - I held my breath. - - I waited impatiently. - - I paused. + - I held my breath. + - I waited impatiently. + - I paused. } - + // Once: show each, once, in turn, until all have been shown { once: - - Would my luck hold? - - Could I win the hand? + - Would my luck hold? + - Could I win the hand? } ``` @@ -1717,9 +1716,9 @@ There are two other versions of shuffle: `shuffle once` which will shuffle the content, play through it, and then do nothing. ``` ink -{ shuffle once: -- The sun was hot. -- It was a hot day. +{ shuffle once: + - The sun was hot. + - It was a hot day. } ``` @@ -1727,9 +1726,9 @@ There are two other versions of shuffle: ``` ink { shuffle stopping: -- A silver BMW roars past. -- A bright yellow Mustang takes the turn. -- There are like, cars, here. + - A silver BMW roars past. + - A bright yellow Mustang takes the turn. + - There are like, cars, here. } ``` @@ -1774,9 +1773,9 @@ A particularly useful form of temporary variable is a parameter. Any knot or sti -> accuse("myself") === accuse(who) === - "I accuse {who}!" Poirot declared. - "Really?" Japp replied. "{who == "myself":You did it?|{who}?}" - "And why not?" Poirot shot back. +"I accuse {who}!" Poirot declared. +"Really?" Japp replied. "{who == "myself":You did it?|{who}?}" +"And why not?" Poirot shot back. ``` @@ -1816,7 +1815,7 @@ Knot/stitch addresses are a type of value, indicated by a `->` character, and ca You lie down and close your eyes. -> generic_sleep (-> waking_in_the_hut) -=== generic_sleep (-> waking) +=== generic_sleep (-> waking) You sleep perchance to dream etc. etc. -> waking @@ -1965,62 +1964,62 @@ The maximum of 2^5 and 3^3 is 32. The following example is long, but appears in pretty much every inkle game to date. (Recall that a hyphenated line inside multiline curly braces indicates either "a condition to test" or, if the curly brace began with a variable, "a value to compare against".) ``` ink - === function print_num(x) === - { - - x >= 1000: - {print_num(x / 1000)} thousand { x mod 1000 > 0:{print_num(x mod 1000)}} - - x >= 100: - {print_num(x / 100)} hundred { x mod 100 > 0:and {print_num(x mod 100)}} - - x == 0: - zero - - else: - { x >= 20: - { x / 10: - - 2: twenty - - 3: thirty - - 4: forty - - 5: fifty - - 6: sixty - - 7: seventy - - 8: eighty - - 9: ninety - } - { x mod 10 > 0:<>-<>} - } - { x < 10 || x > 20: - { x mod 10: - - 1: one - - 2: two - - 3: three - - 4: four - - 5: five - - 6: six - - 7: seven - - 8: eight - - 9: nine - } - - else: - { x: - - 10: ten - - 11: eleven - - 12: twelve - - 13: thirteen - - 14: fourteen - - 15: fifteen - - 16: sixteen - - 17: seventeen - - 18: eighteen - - 19: nineteen - } - } - } +=== function print_num(x) === +{ + - x >= 1000: + {print_num(x / 1000)} thousand { x mod 1000 > 0:{print_num(x mod 1000)}} + - x >= 100: + {print_num(x / 100)} hundred { x mod 100 > 0:and {print_num(x mod 100)}} + - x == 0: + zero + - else: + { x >= 20: + { x / 10: + - 2: twenty + - 3: thirty + - 4: forty + - 5: fifty + - 6: sixty + - 7: seventy + - 8: eighty + - 9: ninety + } + { x mod 10 > 0:<>-<>} + } + { x < 10 || x > 20: + { x mod 10: + - 1: one + - 2: two + - 3: three + - 4: four + - 5: five + - 6: six + - 7: seven + - 8: eight + - 9: nine + } + - else: + { x: + - 10: ten + - 11: eleven + - 12: twelve + - 13: thirteen + - 14: fourteen + - 15: fifteen + - 16: sixteen + - 17: seventeen + - 18: eighteen + - 19: nineteen + } + } +} ``` which enables us to write things like: ``` ink ~ price = 15 - + I pulled out {print_num(price)} coins from my pocket and slowly counted them. "Oh, never mind," the trader replied. "I'll take half." And she took {print_num(price / 2)}, and pushed the rest back over to me. ``` @@ -2035,7 +2034,7 @@ For instance, most **inkle** stories include the following: ``` ink === function alter(ref x, k) === - ~ x = x + k +~ x = x + k ``` Lines such as: @@ -2055,8 +2054,8 @@ then become: which are slightly easier to read, and (more usefully) can be done inline for maximum compactness. ``` ink -* I ate a biscuit[] and felt refreshed. {alter(health, 2)} -* I gave a biscuit to Monsieur Fogg[] and he wolfed it down most undecorously. {alter(foggs_health, 1)} + * I ate a biscuit[] and felt refreshed. {alter(health, 2)} + * I gave a biscuit to Monsieur Fogg[] and he wolfed it down most undecorously. {alter(foggs_health, 1)} - <> Then we continued on our way. ``` @@ -2078,14 +2077,14 @@ Sometimes, it's convenient to define constants to be strings, so you can print t CONST HASTINGS = "Hastings" CONST POIROT = "Poirot" CONST JAPP = "Japp" - + VAR current_chief_suspect = HASTINGS - + === review_evidence === - { found_japps_bloodied_glove: - ~ current_chief_suspect = POIROT - } - Current Suspect: {current_chief_suspect} +{ found_japps_bloodied_glove: + ~ current_chief_suspect = POIROT +} +Current Suspect: {current_chief_suspect} ``` Sometimes giving them values is useful: @@ -2135,11 +2134,11 @@ But this flat structure makes certain things difficult: for example, imagine a g ``` ink === crossing_the_date_line === -* "Monsieur!"[] I declared with sudden horror. "I have just realised. We have crossed the international date line!" + * "Monsieur!"[] I declared with sudden horror. "I have just realised. We have crossed the international date line!" - Monsieur Fogg barely lifted an eyebrow. "I have adjusted for it." -* I mopped the sweat from my brow[]. A relief! -* I nodded, becalmed[]. Of course he had! -* I cursed, under my breath[]. Once again, I had been belittled! + * I mopped the sweat from my brow[]. A relief! + * I nodded, becalmed[]. Of course he had! + * I cursed, under my breath[]. Once again, I had been belittled! ``` ...but it can happen at several different places in the story. We don't want to have to write copies of the content for each different place, but when the content is finished it needs to know where to return to. We can do this using parameters: @@ -2147,24 +2146,24 @@ But this flat structure makes certain things difficult: for example, imagine a g ``` ink === crossing_the_date_line(-> return_to) === ... -- -> return_to +- -> return_to -... + ... === outside_honolulu === We arrived at the large island of Honolulu. -- (postscript) +- (postscript) -> crossing_the_date_line(-> done) -- (done) +- (done) -> END -... - + ... + === outside_pitcairn_island === The boat sailed along the water towards the tiny island. -- (postscript) +- (postscript) -> crossing_the_date_line(-> done) -- (done) +- (done) -> END ``` @@ -2187,10 +2186,11 @@ This means "do the crossing_the_date_line story, then continue from here". Inside the tunnel itself, the syntax is simplified from the parameterised example: all we do is end the tunnel using the `->->` statement which means, essentially, "go on". ``` ink -=== crossing_the_date_line === +=== crossing_the_date_line === // this is a tunnel! ... -- ->-> + +- ->-> ``` Note that tunnel knots aren't declared as such, so the compiler won't check that tunnels really do end in `->->` statements, except at run-time. So you will need to write carefully to ensure that all the flows into a tunnel really do come out again. @@ -2198,7 +2198,7 @@ Note that tunnel knots aren't declared as such, so the compiler won't check that Tunnels can also be chained together, or finish on a normal divert: ``` ink -... +... // this runs the tunnel, then diverts to 'done' -> crossing_the_date_line -> done ... @@ -2214,25 +2214,25 @@ Tunnels can be nested, so the following is valid: ``` ink === plains === = night_time - The dark grass is soft under your feet. +The dark grass is soft under your feet. + [Sleep] -> sleep_here -> wake_here -> day_time = day_time - It is time to move on. - +It is time to move on. + === wake_here === - You wake as the sun rises. +You wake as the sun rises. + [Eat something] -> eat_something -> + [Make a move] - - ->-> + - ->-> === sleep_here === - You lie down and try to close your eyes. - -> monster_attacks -> - Then it is time to sleep. - -> dream -> - ->-> +You lie down and try to close your eyes. +-> monster_attacks -> +Then it is time to sleep. +-> dream -> +->-> ``` ... and so on. @@ -2368,11 +2368,11 @@ In cases where we want to mark the end of a thread, we use `-> DONE`: meaning "t The example at the start of this section will generate a warning; it can be fixed as follows: ``` ink - == thread_example == - I had a headache; threading is hard to get your head around. - <- conversation - <- walking - -> DONE +== thread_example == +I had a headache; threading is hard to get your head around. +<- conversation +<- walking +-> DONE ``` The extra DONE tells ink that the flow here has ended and it should rely on the threads for the next part of the story. @@ -2391,51 +2391,51 @@ Threads can be used to add the same choice into lots of different places. When u ``` ink === outside_the_house The front step. The house smells. Of murder. And lavender. -- (top) +- (top) <- review_case_notes(-> top) * [Go through the front door] I stepped inside the house. -> the_hallway - * [Sniff the air] + * [Sniff the air] I hate lavender. It makes me think of soap, and soap makes me think about my marriage. -> top === the_hallway The hallway. Front door open to the street. Little bureau. -- (top) +- (top) <- review_case_notes(-> top) * [Go through the front door] I stepped out into the cool sunshine. -> outside_the_house - * [Open the bureau] + * [Open the bureau] Keys. More keys. Even more keys. How many locks do these people need? -> top === review_case_notes(-> go_back_to) -+ {not done || TURNS_SINCE(-> done) > 10} - [Review my case notes] - // the conditional ensures you don't get the option to check repeatedly - {I|Once again, I} flicked through the notes I'd made so far. Still not obvious suspects. -- (done) -> go_back_to + + {not done || TURNS_SINCE(-> done) > 10} + [Review my case notes] + // the conditional ensures you don't get the option to check repeatedly + {I|Once again, I} flicked through the notes I'd made so far. Still not obvious suspects. +- (done) -> go_back_to ``` Note this is different than a tunnel, which runs the same block of content but doesn't give a player a choice. So a layout like: ``` ink -<- childhood_memories(-> next) -* [Look out of the window] - I daydreamed as we rolled along... - - (next) Then the whistle blew... +<- childhood_memories(-> next) + * [Look out of the window] + I daydreamed as we rolled along... +- (next) Then the whistle blew... ``` might do exactly the same thing as: ``` ink -* [Remember my childhood] - -> think_back -> -* [Look out of the window] - I daydreamed as we rolled along... -- (next) Then the whistle blew... + * [Remember my childhood] + -> think_back -> + * [Look out of the window] + I daydreamed as we rolled along... +- (next) Then the whistle blew... ``` but as soon as the option being threaded in includes multiple choices, or conditional logic on choices (or any text content, of course!), the thread version becomes more practical. @@ -2446,11 +2446,11 @@ but as soon as the option being threaded in includes multiple choices, or condit A game which uses ink as a script rather than a literal output might often generate very large numbers of parallel choices, intended to be filtered by the player via some other in-game interaction - such as walking around an environment. Threads can be useful in these cases simply to divide up choices. ``` ink -=== the_kitchen -- (top) -<- drawers(-> top) -<- cupboards(-> top) -<- room_exits +=== the_kitchen +- (top) + <- drawers(-> top) + <- cupboards(-> top) + <- room_exits = drawers (-> goback) // choices about the drawers... ... @@ -2528,7 +2528,7 @@ LIST kettleState = cold, (boiling), recently_boiled The above example is fine for the kettle, but what if we have a pot on the stove as well? We can then define a list of states, but put them into variables - and as many variables as we want. ``` ink -LIST daysOfTheWeek = Monday, Tuesday, Wednesday, Thursday, Friday +LIST daysOfTheWeek = Monday, Tuesday, Wednesday, Thursday, Friday VAR today = Monday VAR tomorrow = Tuesday ``` @@ -2541,13 +2541,13 @@ This allows us to use the same state machine in multiple places. LIST heatedWaterStates = cold, boiling, recently_boiled VAR kettleState = cold VAR potState = cold - -* {kettleState == cold} [Turn on kettle] - The kettle begins to boil and bubble. - ~ kettleState = boiling -* {potState == cold} [Light stove] - The water in the pot begins to boil and bubble. - ~ potState = boiling + + * {kettleState == cold} [Turn on kettle] + The kettle begins to boil and bubble. + ~ kettleState = boiling + * {potState == cold} [Light stove] + The water in the pot begins to boil and bubble. + ~ potState = boiling ``` But what if we add a microwave as well? We might want start generalising our functionality a bit: @@ -2557,17 +2557,17 @@ LIST heatedWaterStates = cold, boiling, recently_boiled VAR kettleState = cold VAR potState = cold VAR microwaveState = cold - + === function boilSomething(ref thingToBoil, nameOfThing) - The {nameOfThing} begins to heat up. - ~ thingToBoil = boiling - +The {nameOfThing} begins to heat up. +~ thingToBoil = boiling + === do_cooking -* {kettleState == cold} [Turn on kettle] - {boilSomething(kettleState, "kettle")} -* {potState == cold} [Light stove] - {boilSomething(potState, "pot")} * {microwaveState == cold} [Turn on microwave] - {boilSomething(microwaveState, "microwave")} + * {kettleState == cold} [Turn on kettle] + {boilSomething(kettleState, "kettle")} + * {potState == cold} [Light stove] + {boilSomething(potState, "pot")} * {microwaveState == cold} [Turn on microwave] + {boilSomething(microwaveState, "microwave")} ``` or even... @@ -2577,18 +2577,18 @@ LIST heatedWaterStates = cold, boiling, recently_boiled VAR kettleState = cold VAR potState = cold VAR microwaveState = cold - + === cook_with(nameOfThing, ref thingToBoil) -+ {thingToBoil == cold} [Turn on {nameOfThing}] - The {nameOfThing} begins to heat up. - ~ thingToBoil = boiling - -> do_cooking.done - + + {thingToBoil == cold} [Turn on {nameOfThing}] + The {nameOfThing} begins to heat up. + ~ thingToBoil = boiling + -> do_cooking.done + === do_cooking <- cook_with("kettle", kettleState) <- cook_with("pot", potState) <- cook_with("microwave", microwaveState) -- (done) +- (done) ``` Note that the "heatedWaterStates" list is still available as well, and can still be tested, and take a value. @@ -2598,9 +2598,9 @@ Note that the "heatedWaterStates" list is still available as well, and can still Reusing lists brings with it ambiguity. If we have: ``` ink -LIST colours = red, green, blue, purple +LIST colours = red, green, blue, purple LIST moods = mad, happy, blue - + VAR status = blue ``` @@ -2609,7 +2609,7 @@ VAR status = blue We resolve these using a `.` syntax similar to that used for knots and stitches. ``` ink -VAR status = colours.blue +VAR status = colours.blue ``` ...and the compiler will issue an error until you specify. @@ -2630,7 +2630,7 @@ Note the "family name" of the state, and the variable containing a state, are to One surprising feature is the statement ``` ink -LIST statesOfGrace = ambiguous, saintly, fallen +LIST statesOfGrace = ambiguous, saintly, fallen ``` actually does two things simultaneously: it creates three values, `ambiguous`, `saintly` and `fallen`, and gives them the name-parent `statesOfGrace` if needed; and it creates a variable called `statesOfGrace`. @@ -2690,7 +2690,7 @@ The lecturer has {LIST_VALUE(deafening) - LIST_VALUE(lecturersVolume)} notches s You can go the other way by using the list's name as a function: ``` ink -LIST Numbers = one, two, three +LIST Numbers = one, two, three VAR score = one ~ score = Numbers(2) // score will be "two" ``` @@ -2721,7 +2721,7 @@ A list variable is not a variable containing a number. Rather, a list is like th Maybe no one is in: ``` ink -LIST DoctorsInSurgery = Adams, Bernard, Cartwright, Denver, Eamonn +LIST DoctorsInSurgery = Adams, Bernard, Cartwright, Denver, Eamonn ``` Maybe everyone is: @@ -2733,7 +2733,7 @@ LIST DoctorsInSurgery = (Adams), (Bernard), (Cartwright), (Denver), (Eamonn) Or maybe some are and some aren't: ``` ink -LIST DoctorsInSurgery = (Adams), Bernard, (Cartwright), Denver, Eamonn +LIST DoctorsInSurgery = (Adams), Bernard, (Cartwright), Denver, Eamonn ``` Names in brackets are included in the initial state of the list. @@ -2765,7 +2765,8 @@ We can assign the empty list to clear a list out: List entries can be added and removed, singly or collectively. ``` ink -~ DoctorsInSurgery = DoctorsInSurgery + Adams ~ DoctorsInSurgery += Adams // this is the same as the above +~ DoctorsInSurgery = DoctorsInSurgery + Adams +~ DoctorsInSurgery += Adams // this is the same as the above ~ DoctorsInSurgery -= Eamonn ~ DoctorsInSurgery += (Eamonn, Denver) ~ DoctorsInSurgery -= (Adams, Eamonn, Denver) @@ -2779,12 +2780,12 @@ Trying to add an entry that's already in the list does nothing. Trying to remove We have a few basic ways of getting information about what's in a list: ``` ink -LIST DoctorsInSurgery = (Adams), Bernard, (Cartwright), Denver, Eamonn - -{LIST_COUNT(DoctorsInSurgery)} // "2" -{LIST_MIN(DoctorsInSurgery)} // "Adams" -{LIST_MAX(DoctorsInSurgery)} // "Cartwright" -{LIST_RANDOM(DoctorsInSurgery)} // "Adams" or "Cartwright" +LIST DoctorsInSurgery = (Adams), Bernard, (Cartwright), Denver, Eamonn + +{LIST_COUNT(DoctorsInSurgery)} // "2" +{LIST_MIN(DoctorsInSurgery)} // "Adams" +{LIST_MAX(DoctorsInSurgery)} // "Cartwright" +{LIST_RANDOM(DoctorsInSurgery)} // "Adams" or "Cartwright" ``` #### Testing for emptiness @@ -2849,8 +2850,8 @@ does not mean neither Adams nor Bernard is present, only that they are not *both The simplest use of a multi-valued list is for tracking "game flags" tidily. ``` ink -LIST Facts = (Fogg_is_fairly_odd), first_name_phileas, (Fogg_is_English) - +LIST Facts = (Fogg_is_fairly_odd), first_name_phileas, (Fogg_is_English) + {Facts ? Fogg_is_fairly_odd:I smiled politely.|I frowned. Was he a lunatic?} '{Facts ? first_name_phileas:Phileas|Monsieur}, really!' I cried. ``` @@ -2858,7 +2859,7 @@ LIST Facts = (Fogg_is_fairly_odd), first_name_phileas, (Fogg_is_English) In particular, it allows us to test for multiple game flags in a single line. ``` ink -{ Facts ? (Fogg_is_English, Fogg_is_fairly_odd): +{ Facts ? (Fogg_is_English, Fogg_is_fairly_odd): <> 'I know Englishmen are strange, but this is *incredible*!' } @@ -2869,27 +2870,27 @@ In particular, it allows us to test for multiple game flags in a single line. We're overdue a fuller example, so here's one. ``` ink -LIST DoctorsInSurgery = (Adams), Bernard, Cartwright, (Denver), Eamonn - +LIST DoctorsInSurgery = (Adams), Bernard, Cartwright, (Denver), Eamonn + -> waiting_room - + === function whos_in_today() - In the surgery today are {DoctorsInSurgery}. - +In the surgery today are {DoctorsInSurgery}. + === function doctorEnters(who) - { DoctorsInSurgery !? who: - ~ DoctorsInSurgery += who - Dr {who} arrives in a fluster. - } - +{ DoctorsInSurgery !? who: + ~ DoctorsInSurgery += who + Dr {who} arrives in a fluster. +} + === function doctorLeaves(who) - { DoctorsInSurgery ? who: - ~ DoctorsInSurgery -= who - Dr {who} leaves for lunch. - } - +{ DoctorsInSurgery ? who: + ~ DoctorsInSurgery -= who + Dr {who} leaves for lunch. +} + === waiting_room - {whos_in_today()} +{whos_in_today()} * [Time passes...] {doctorLeaves(Adams)} {doctorEnters(Cartwright)} {doctorEnters(Eamonn)} {whos_in_today()} @@ -2912,20 +2913,20 @@ In the surgery today are Cartwright, Denver, Eamonn. The basic list print is not especially attractive for use in-game. The following is better: ``` ink -=== function listWithCommas(list, if_empty) - {LIST_COUNT(list): - - 2: - {LIST_MIN(list)} and {listWithCommas(list - LIST_MIN(list), if_empty)} - - 1: - {list} - - 0: - {if_empty} - - else: - {LIST_MIN(list)}, {listWithCommas(list - LIST_MIN(list), if_empty)} - } +=== function listWithCommas(list, if_empty) +{LIST_COUNT(list): + - 2: + {LIST_MIN(list)} and {listWithCommas(list - LIST_MIN(list), if_empty)} + - 1: + {list} + - 0: + {if_empty} + - else: + {LIST_MIN(list)}, {listWithCommas(list - LIST_MIN(list), if_empty)} +} LIST favouriteDinosaurs = (stegosaurs), brachiosaur, (anklyosaurus), (pleiosaur) - + My favourite dinosaurs are {listWithCommas(favouriteDinosaurs, "all extinct")}. ``` @@ -2933,8 +2934,8 @@ It's probably also useful to have an is/are function to hand: ``` ink === function isAre(list) - {LIST_COUNT(list) == 1:is|are} - +{LIST_COUNT(list) == 1:is|are} + My favourite dinosaurs {isAre(favouriteDinosaurs)} {listWithCommas(favouriteDinosaurs, "all extinct")}. ``` @@ -2954,17 +2955,17 @@ Lists don't *have* to contain multiple values. If you want to use a list as a st Note that `LIST_COUNT`, `LIST_MIN` and `LIST_MAX` are refering to who's in/out of the list, not the full set of *possible* doctors. We can access that using ``` ink -LIST_ALL(element of list) +LIST_ALL(element of list) ``` or ``` ink LIST_ALL(list containing elements of a list) - + {LIST_ALL(DoctorsInSurgery)} // Adams, Bernard, Cartwright, Denver, Eamonn {LIST_COUNT(LIST_ALL(DoctorsInSurgery))} // "5" -{LIST_MIN(LIST_ALL(Eamonn))} // "Adams" +{LIST_MIN(LIST_ALL(Eamonn))} // "Adams" ``` Note that printing a list using `{...}` produces a bare-bones representation of the list; the values as words, delimited by commas. @@ -2976,7 +2977,7 @@ If you really need to, you can make an empty list that knows what type of list i ``` ink LIST ValueList = first_value, second_value, third_value VAR myList = () - + ~ myList = ValueList() ``` @@ -2991,7 +2992,7 @@ You'll then be able to do: You can also retrieve just a "slice" of the full list, using the `LIST_RANGE` function. ``` ink -LIST_RANGE(list_name, min_value, max_value) +LIST_RANGE(list_name, min_value, max_value) ``` ### Example: Tower of Hanoi @@ -3004,96 +3005,96 @@ LIST Discs = one, two, three, four, five, six, seven VAR post1 = () VAR post2 = () VAR post3 = () - + ~ post1 = LIST_ALL(Discs) - + -> gameloop - + === function can_move(from_list, to_list) === - { - - LIST_COUNT(from_list) == 0: - // no discs to move - ~ return false - - LIST_COUNT(to_list) > 0 && LIST_MIN(from_list) > LIST_MIN(to_list): - // the moving disc is bigger than the smallest of the discs on the new tower - ~ return false - - else: - // nothing stands in your way! - ~ return true - - } - +{ + - LIST_COUNT(from_list) == 0: + // no discs to move + ~ return false + - LIST_COUNT(to_list) > 0 && LIST_MIN(from_list) > LIST_MIN(to_list): + // the moving disc is bigger than the smallest of the discs on the new tower + ~ return false + - else: + // nothing stands in your way! + ~ return true + +} + === function move_ring( ref from, ref to ) === - ~ temp whichRingToMove = LIST_MIN(from) - ~ from -= whichRingToMove - ~ to += whichRingToMove - +~ temp whichRingToMove = LIST_MIN(from) +~ from -= whichRingToMove +~ to += whichRingToMove + == function getListForTower(towerNum) - { towerNum: - - 1: ~ return post1 - - 2: ~ return post2 - - 3: ~ return post3 - } - +{ towerNum: + - 1: ~ return post1 + - 2: ~ return post2 + - 3: ~ return post3 +} + === function name(postNum) - the {postToPlace(postNum)} temple - +the {postToPlace(postNum)} temple + === function Name(postNum) - The {postToPlace(postNum)} temple - +The {postToPlace(postNum)} temple + === function postToPlace(postNum) - { postNum: - - 1: first - - 2: second - - 3: third - } - +{ postNum: + - 1: first + - 2: second + - 3: third +} + === function describe_pillar(listNum) == - ~ temp list = getListForTower(listNum) - { - - LIST_COUNT(list) == 0: - {Name(listNum)} is empty. - - LIST_COUNT(list) == 1: - The {list} ring lies on {name(listNum)}. - - else: - On {name(listNum)}, are the discs numbered {list}. - } - - +~ temp list = getListForTower(listNum) +{ + - LIST_COUNT(list) == 0: + {Name(listNum)} is empty. + - LIST_COUNT(list) == 1: + The {list} ring lies on {name(listNum)}. + - else: + On {name(listNum)}, are the discs numbered {list}. +} + + === gameloop - Staring down from the heavens you see your followers finishing construction of the last of the great temples, ready to begin the work. -- (top) - + (describe) {true || TURNS_SINCE(-> describe) >= 2 || !describe} [ Regard the temples] - You regard each of the temples in turn. On each is stacked the rings of stone. {describe_pillar(1)} {describe_pillar(2)} {describe_pillar(3)} - <- move_post(1, 2, post1, post2) - <- move_post(2, 1, post2, post1) - <- move_post(1, 3, post1, post3) - <- move_post(3, 1, post3, post1) - <- move_post(3, 2, post3, post2) - <- move_post(2, 3, post2, post3) - -> DONE - +Staring down from the heavens you see your followers finishing construction of the last of the great temples, ready to begin the work. +- (top) + + (describe) {true || TURNS_SINCE(-> describe) >= 2 || !describe} [ Regard the temples] + You regard each of the temples in turn. On each is stacked the rings of stone. {describe_pillar(1)} {describe_pillar(2)} {describe_pillar(3)} + <- move_post(1, 2, post1, post2) + <- move_post(2, 1, post2, post1) + <- move_post(1, 3, post1, post3) + <- move_post(3, 1, post3, post1) + <- move_post(3, 2, post3, post2) + <- move_post(2, 3, post2, post3) + -> DONE + = move_post(from_post_num, to_post_num, ref from_post_list, ref to_post_list) - + { can_move(from_post_list, to_post_list) } - [ Move a ring from {name(from_post_num)} to {name(to_post_num)} ] - { move_ring(from_post_list, to_post_list) } - { stopping: - - The priests far below construct a great harness, and after many years of work, the great stone ring is lifted up into the air, and swung over to the next of the temples. - The ropes are slashed, and in the blink of an eye it falls once more. - - Your next decree is met with a great feast and many sacrifices. After the funeary smoke has cleared, work to shift the great stone ring begins in earnest. A generation grows and falls, and the ring falls into its ordained place. - - {cycle: - - Years pass as the ring is slowly moved. - - The priests below fight a war over what colour robes to wear, but while they fall and die, the work is still completed. - } - } - -> top + + { can_move(from_post_list, to_post_list) } + [ Move a ring from {name(from_post_num)} to {name(to_post_num)} ] + { move_ring(from_post_list, to_post_list) } + { stopping: + - The priests far below construct a great harness, and after many years of work, the great stone ring is lifted up into the air, and swung over to the next of the temples. + The ropes are slashed, and in the blink of an eye it falls once more. + - Your next decree is met with a great feast and many sacrifices. After the funeary smoke has cleared, work to shift the great stone ring begins in earnest. A generation grows and falls, and the ring falls into its ordained place. + - {cycle: + - Years pass as the ring is slowly moved. + - The priests below fight a war over what colour robes to wear, but while they fall and die, the work is still completed. + } + } + -> top ``` - + ## 5) Advanced List Operations -The above section covers basic comparisons. There are a few more powerful features as well, but - as anyone familiar with mathematical sets will know - things begin to get a bit fiddly. So this section comes with an 'advanced' warning. +The above section covers basic comparisons. There are a few more powerful features as well, but - as anyone familiar with mathematical sets will know - things begin to get a bit fiddly. So this section comes with an 'advanced' warning. A lot of the features in this section won't be necessary for most games. @@ -3123,9 +3124,9 @@ A list can be "inverted", which is the equivalent of going through the accommoda ``` ink LIST GuardsOnDuty = (Smith), (Jones), Carter, Braithwaite - + === function changingOfTheGuard - ~ GuardsOnDuty = LIST_INVERT(GuardsOnDuty) +~ GuardsOnDuty = LIST_INVERT(GuardsOnDuty) ``` @@ -3133,11 +3134,11 @@ Note that `LIST_INVERT` on an empty list will return a null value, if the game d ``` ink === function changingOfTheGuard - {!GuardsOnDuty: // "is GuardsOnDuty empty right now?" - ~ GuardsOnDuty = LIST_ALL(Smith) - - else: - ~ GuardsOnDuty = LIST_INVERT(GuardsOnDuty) - } +{!GuardsOnDuty: // "is GuardsOnDuty empty right now?" + ~ GuardsOnDuty = LIST_ALL(Smith) +- else: + ~ GuardsOnDuty = LIST_INVERT(GuardsOnDuty) +} ``` #### Footnote @@ -3167,8 +3168,8 @@ VAR actualValues = ( greed, nepotism, self_belief, delusions_of_godhood ) The result is a new list, so you can test it: ``` ink -{desiredValues ^ actualValues: The new president has at least one desirable quality.} - +{desiredValues ^ actualValues: The new president has at least one desirable quality.} + {LIST_COUNT(desiredValues ^ actualValues) == 1: Correction, the new president has only one desirable quality. {desiredValues ^ actualValues == self_belief: It's the scary one.}} @@ -3189,9 +3190,9 @@ This is our inception moment. The results are powerful, but also more like "real For instance, we might define: ``` ink -LIST Characters = Alfred, Batman, Robin +LIST Characters = Alfred, Batman, Robin LIST Props = champagne_glass, newspaper - + VAR BallroomContents = (Alfred, Batman, newspaper) VAR HallwayContents = (Robin, champagne_glass) ``` @@ -3200,14 +3201,14 @@ We could then describe the contents of any room by testing its state: ``` ink === function describe_room(roomState) - { roomState ? Alfred: Alfred is here, standing quietly in a corner. } { roomState ? Batman: Batman's presence dominates all. } { roomState ? Robin: Robin is all but forgotten. } - <> { roomState ? champagne_glass: A champagne glass lies discarded on the floor. } { roomState ? newspaper: On one table, a headline blares out WHO IS THE BATMAN? AND *WHO* IS HIS BARELY-REMEMBERED ASSISTANT? } +{ roomState ? Alfred: Alfred is here, standing quietly in a corner. } { roomState ? Batman: Batman's presence dominates all. } { roomState ? Robin: Robin is all but forgotten. } +<> { roomState ? champagne_glass: A champagne glass lies discarded on the floor. } { roomState ? newspaper: On one table, a headline blares out WHO IS THE BATMAN? AND *WHO* IS HIS BARELY-REMEMBERED ASSISTANT? } ``` So then: ``` ink -{ describe_room(BallroomContents) } +{ describe_room(BallroomContents) } ``` produces: @@ -3221,7 +3222,7 @@ On one table, a headline blares out WHO IS THE BATMAN? AND *WHO* IS HIS BARELY-R While: ``` ink -{ describe_room(HallwayContents) } +{ describe_room(HallwayContents) } ``` gives: @@ -3266,18 +3267,18 @@ VAR kettleState = off, cold These mixed states can make changing state a bit trickier, as the off/on above demonstrates, so the following helper function can be useful. ``` ink - === function changeStateTo(ref stateVariable, stateToReach) - // remove all states of this type - ~ stateVariable -= LIST_ALL(stateToReach) - // put back the state we want - ~ stateVariable += stateToReach +=== function changeStateTo(ref stateVariable, stateToReach) +// remove all states of this type +~ stateVariable -= LIST_ALL(stateToReach) +// put back the state we want +~ stateVariable += stateToReach ``` which enables code like: ``` ink - ~ changeState(kettleState, on) - ~ changeState(kettleState, warm) +~ changeState(kettleState, on) +~ changeState(kettleState, warm) ``` @@ -3286,23 +3287,23 @@ These mixed states can make changing state a bit trickier, as the off/on above d The queries given above mostly generalise nicely to multi-valued lists ``` ink - LIST Letters = a,b,c - LIST Numbers = one, two, three - - VAR mixedList = (a, three, c) - -{LIST_ALL(mixedList)} // a, one, b, two, c, three - {LIST_COUNT(mixedList)} // 3 - {LIST_MIN(mixedList)} // a - {LIST_MAX(mixedList)} // three or c, albeit unpredictably - - {mixedList ? (a,b) } // false - {mixedList ^ LIST_ALL(a)} // a, c - - { mixedList >= (one, a) } // true - { mixedList < (three) } // false - -{ LIST_INVERT(mixedList) } // one, b, two +LIST Letters = a,b,c +LIST Numbers = one, two, three + +VAR mixedList = (a, three, c) + +{LIST_ALL(mixedList)} // a, one, b, two, c, three +{LIST_COUNT(mixedList)} // 3 +{LIST_MIN(mixedList)} // a +{LIST_MAX(mixedList)} // three or c, albeit unpredictably + +{mixedList ? (a,b) } // false +{mixedList ^ LIST_ALL(a)} // a, c + +{ mixedList >= (one, a) } // true +{ mixedList < (three) } // false + +{ LIST_INVERT(mixedList) } // one, b, two ``` @@ -3311,361 +3312,361 @@ The queries given above mostly generalise nicely to multi-valued lists Finally, here's a long example, demonstrating a lot of ideas from this section in action. You might want to try playing it before reading through to better understand the various moving parts. ``` ink --> murder_scene - +-> murder_scene + // -// System: items can have various states +// System: items can have various states // Some are general, some specific to particular items // - + LIST OffOn = off, on LIST SeenUnseen = unseen, seen - + LIST GlassState = (none), steamed, steam_gone LIST BedState = (made_up), covers_shifted, covers_off, stain_visible - + // // System: inventory // - + LIST Inventory = (none), cane, knife - + === function get(x) - ~ Inventory += x +~ Inventory += x // // System: positioning things // Items can be put in and on places // - + LIST Supporters = on_desk, on_floor, on_bed, under_bed, held, with_joe - + === function move_to_supporter(ref item_state, new_supporter) === - ~ item_state -= LIST_ALL(Supporters) - ~ item_state += new_supporter - +~ item_state -= LIST_ALL(Supporters) +~ item_state += new_supporter + // // System: Incremental knowledge. // Each list is a chains of facts. Each fact supercedes the fact before it. // - + LIST BedKnowledge = (none), neatly_made, crumpled_duvet, hastily_remade, body_on_bed, murdered_in_bed, murdered_while_asleep LIST KnifeKnowledge = (none), prints_on_knife, joe_seen_prints_on_knife,joe_wants_better_prints, joe_got_better_prints LIST WindowKnowledge = (none), steam_on_glass, fingerprints_on_glass, fingerprints_on_glass_match_knife VAR knowledgeState = () - + === function learn(x) === - // learn this fact - ~ knowledgeState += x - +// learn this fact +~ knowledgeState += x + === function learnt(x) === - // have you learnt this fact, or indeed a stronger one - ~ return highest_state_for_set_of_state(x) >= x - +// have you learnt this fact, or indeed a stronger one +~ return highest_state_for_set_of_state(x) >= x + === function between(x, y) === - // are you between two ideas? Not necessarily in the same knowledge tree. - ~ return learnt(x) && not learnt(y) - +// are you between two ideas? Not necessarily in the same knowledge tree. +~ return learnt(x) && not learnt(y) + === function think(x) === - // is this your current "strongest" idea in this knowledge set? - ~ return highest_state_for_set_of_state(x) == x - +// is this your current "strongest" idea in this knowledge set? +~ return highest_state_for_set_of_state(x) == x + === function highest_state_for_set_of_state(x) === - ~ return LIST_MAX(knowledgeState ^ LIST_ALL(x)) - +~ return LIST_MAX(knowledgeState ^ LIST_ALL(x)) + === function did_learn(x) === - // did you learn this particular fact? - ~ return knowledgeState ? x - +// did you learn this particular fact? +~ return knowledgeState ? x + // // Set up the scene // - + VAR bedroomLightState = (off, on_desk) VAR knifeState = (under_bed) - + // // Content // - + === murder_scene === - The bedroom. This is where it happened. Now to look for clues. -- (top) - { bedroomLightState ? seen: <- seen_light } - <- compare_prints(-> top) - - * (dobed) [The bed...] - The bed was low to the ground, but not so low something might not roll underneath. It was still neatly made. - ~ learn(neatly_made) - - - (bedhub) - * * [Lift the bedcover] - I lifted back the bedcover. The duvet underneath was crumpled. - ~ learn(crumpled_duvet) - ~ BedState = covers_shifted - * * (uncover) {learnt(crumpled_duvet)} - [Remove the cover] - Careful not to disturb anything beneath, I removed the cover entirely. The duvet below was rumpled. - Not the work of the maid, who was conscientious to a point. Clearly this had been thrown on in a hurry. - ~ learn(hastily_remade) - ~ BedState = covers_off - * * (duvet) {BedState == covers_off} [ Pull back the duvet ] - I pulled back the duvet. Beneath it was a sheet, sticky with blood. - ~ BedState = stain_visible - ~ learn(body_on_bed) - Either the body had been moved here before being dragged to the floor - or this is was where the murder had taken place. - * * {!(BedState ? made_up)} [ Remake the bed ] - Carefully, I pulled the bedsheets back into place, trying to make it seem undisturbed. - ~ BedState = made_up - * * [Test the bed] - I pushed the bed with spread fingers. It creaked a little, but not so much as to be obnoxious. - * * (darkunder) [Look under the bed] - Lying down, I peered under the bed, but could make nothing out. - - * * {TURNS_SINCE(-> dobed) > 1} [Something else?] - I took a step back from the bed and looked around. - -> top - - - -> bedhub - - * {darkunder && bedroomLightState ? on_floor && bedroomLightState ? on} - [ Look under the bed ] - I peered under the bed. Something glinted back at me. - - - (reaching) - * * [ Reach for it ] - I fished with one arm under the bed, but whatever it was, it had been kicked far enough back that I couldn't get my fingers on it. - -> reaching - * * {Inventory ? cane} [Knock it with the cane] - -> knock_with_cane - - * * {reaching > 1 } [ Stand up ] - I stood up once more, and brushed my coat down. - -> top - - * (knock_with_cane) {reaching && TURNS_SINCE(-> reaching) >= 4 && Inventory ? cane } [Use the cane to reach under the bed ] - Positioning the cane above the carpet, I gave the glinting thing a sharp tap. It slid out from the under the foot of the bed. - ~ move_to_supporter( knifeState, on_floor ) - * * (standup) [Stand up] - Satisfied, I stood up, and saw I had knocked free a bloodied knife. - -> top - * * [Look under the bed once more] - Moving the cane aside, I looked under the bed once more, but there was nothing more there. - -> standup - - * {knifeState ? on_floor} [Pick up the knife] - Careful not to touch the handle, I lifted the blade from the carpet. - ~ get(knife) - - * {Inventory ? knife} [Look at the knife] - The blood was dry enough. Dry enough to show up partial prints on the hilt! - ~ learn(prints_on_knife) - - * [ The desk... ] - I turned my attention to the desk. A lamp sat in one corner, a neat, empty in-tray in the other. There was nothing else out. - Leaning against the desk was a wooden cane. - ~ bedroomLightState += seen - - - (deskstate) - * * (pickup_cane) {Inventory !? cane} [Pick up the cane ] - ~ get(cane) - I picked up the wooden cane. It was heavy, and unmarked. - - * * { bedroomLightState !? on } [Turn on the lamp] - -> operate_lamp -> - * * [Look at the in-tray ] - I regarded the in-tray, but there was nothing to be seen. Either the victim's papers were taken, or his line of work had seriously dried up. Or the in-tray was all for show. - + + (open) {open < 3} [Open a drawer] - I tried {a drawer at random|another drawer|a third drawer}. {Locked|Also locked|Unsurprisingly, locked as well}. - - * * {deskstate >= 2} [Something else?] - I took a step away from the desk once more. - -> top - - - -> deskstate - - * {(Inventory ? cane) && TURNS_SINCE(-> deskstate) <= 2} [Swoosh the cane] - I was still holding the cane: I gave it an experimental swoosh. It was heavy indeed, though not heavy enough to be used as a bludgeon. - But it might have been useful in self-defence. Why hadn't the victim reached for it? Knocked it over? - - * [The window...] - I went over to the window and peered out. A dismal view of the little brook that ran down beside the house. - - - (window_opts) - <- compare_prints(-> window_opts) - * * (downy) [Look down at the brook] - { GlassState ? steamed: - Through the steamed glass I couldn't see the brook. -> see_prints_on_glass -> window_opts - } - I watched the little stream rush past for a while. The house probably had damp but otherwise, it told me nothing. - * * (greasy) [Look at the glass] - { GlassState ? steamed: -> downy } - The glass in the window was greasy. No one had cleaned it in a while, inside or out. - * * { GlassState ? steamed && not see_prints_on_glass && downy && greasy } - [ Look at the steam ] - A cold day outside. Natural my breath should steam. -> see_prints_on_glass -> - + + {GlassState ? steam_gone} [ Breathe on the glass ] - I breathed gently on the glass once more. {learnt(fingerprints_on_glass): The fingerprints reappeared. } - ~ GlassState = steamed - - + + [Something else?] - { window_opts < 2 || learnt(fingerprints_on_glass) || GlassState ? steamed: - I looked away from the dreary glass. - {GlassState ? steamed: - ~ GlassState = steam_gone - <> The steam from my breath faded. - } - -> top - } - I leant back from the glass. My breath had steamed up the pane a little. - ~ GlassState = steamed - - - -> window_opts - - - - * {top >= 5} [Leave the room] - I'd seen enough. I {bedroomLightState ? on:switched off the lamp, then} turned and left the room. - -> joe_in_hall - - -> top - +The bedroom. This is where it happened. Now to look for clues. +- (top) + { bedroomLightState ? seen: <- seen_light } + <- compare_prints(-> top) + + * (dobed) [The bed...] + The bed was low to the ground, but not so low something might not roll underneath. It was still neatly made. + ~ learn(neatly_made) + - - (bedhub) + * * [Lift the bedcover] + I lifted back the bedcover. The duvet underneath was crumpled. + ~ learn(crumpled_duvet) + ~ BedState = covers_shifted + * * (uncover) {learnt(crumpled_duvet)} + [Remove the cover] + Careful not to disturb anything beneath, I removed the cover entirely. The duvet below was rumpled. + Not the work of the maid, who was conscientious to a point. Clearly this had been thrown on in a hurry. + ~ learn(hastily_remade) + ~ BedState = covers_off + * * (duvet) {BedState == covers_off} [ Pull back the duvet ] + I pulled back the duvet. Beneath it was a sheet, sticky with blood. + ~ BedState = stain_visible + ~ learn(body_on_bed) + Either the body had been moved here before being dragged to the floor - or this is was where the murder had taken place. + * * {!(BedState ? made_up)} [ Remake the bed ] + Carefully, I pulled the bedsheets back into place, trying to make it seem undisturbed. + ~ BedState = made_up + * * [Test the bed] + I pushed the bed with spread fingers. It creaked a little, but not so much as to be obnoxious. + * * (darkunder) [Look under the bed] + Lying down, I peered under the bed, but could make nothing out. + + * * {TURNS_SINCE(-> dobed) > 1} [Something else?] + I took a step back from the bed and looked around. + -> top + - - -> bedhub + + * {darkunder && bedroomLightState ? on_floor && bedroomLightState ? on} + [ Look under the bed ] + I peered under the bed. Something glinted back at me. + - - (reaching) + * * [ Reach for it ] + I fished with one arm under the bed, but whatever it was, it had been kicked far enough back that I couldn't get my fingers on it. + -> reaching + * * {Inventory ? cane} [Knock it with the cane] + -> knock_with_cane + + * * {reaching > 1 } [ Stand up ] + I stood up once more, and brushed my coat down. + -> top + + * (knock_with_cane) {reaching && TURNS_SINCE(-> reaching) >= 4 && Inventory ? cane } [Use the cane to reach under the bed ] + Positioning the cane above the carpet, I gave the glinting thing a sharp tap. It slid out from the under the foot of the bed. + ~ move_to_supporter( knifeState, on_floor ) + * * (standup) [Stand up] + Satisfied, I stood up, and saw I had knocked free a bloodied knife. + -> top + * * [Look under the bed once more] + Moving the cane aside, I looked under the bed once more, but there was nothing more there. + -> standup + + * {knifeState ? on_floor} [Pick up the knife] + Careful not to touch the handle, I lifted the blade from the carpet. + ~ get(knife) + + * {Inventory ? knife} [Look at the knife] + The blood was dry enough. Dry enough to show up partial prints on the hilt! + ~ learn(prints_on_knife) + + * [ The desk... ] + I turned my attention to the desk. A lamp sat in one corner, a neat, empty in-tray in the other. There was nothing else out. + Leaning against the desk was a wooden cane. + ~ bedroomLightState += seen + - - (deskstate) + * * (pickup_cane) {Inventory !? cane} [Pick up the cane ] + ~ get(cane) + I picked up the wooden cane. It was heavy, and unmarked. + + * * { bedroomLightState !? on } [Turn on the lamp] + -> operate_lamp -> + * * [Look at the in-tray ] + I regarded the in-tray, but there was nothing to be seen. Either the victim's papers were taken, or his line of work had seriously dried up. Or the in-tray was all for show. + + + (open) {open < 3} [Open a drawer] + I tried {a drawer at random|another drawer|a third drawer}. {Locked|Also locked|Unsurprisingly, locked as well}. + + * * {deskstate >= 2} [Something else?] + I took a step away from the desk once more. + -> top + - - -> deskstate + + * {(Inventory ? cane) && TURNS_SINCE(-> deskstate) <= 2} [Swoosh the cane] + I was still holding the cane: I gave it an experimental swoosh. It was heavy indeed, though not heavy enough to be used as a bludgeon. + But it might have been useful in self-defence. Why hadn't the victim reached for it? Knocked it over? + + * [The window...] + I went over to the window and peered out. A dismal view of the little brook that ran down beside the house. + - - (window_opts) + <- compare_prints(-> window_opts) + * * (downy) [Look down at the brook] + { GlassState ? steamed: + Through the steamed glass I couldn't see the brook. -> see_prints_on_glass -> window_opts + } + I watched the little stream rush past for a while. The house probably had damp but otherwise, it told me nothing. + * * (greasy) [Look at the glass] + { GlassState ? steamed: -> downy } + The glass in the window was greasy. No one had cleaned it in a while, inside or out. + * * { GlassState ? steamed && not see_prints_on_glass && downy && greasy } + [ Look at the steam ] + A cold day outside. Natural my breath should steam. -> see_prints_on_glass -> + + + {GlassState ? steam_gone} [ Breathe on the glass ] + I breathed gently on the glass once more. {learnt(fingerprints_on_glass): The fingerprints reappeared. } + ~ GlassState = steamed + + + + [Something else?] + { window_opts < 2 || learnt(fingerprints_on_glass) || GlassState ? steamed: + I looked away from the dreary glass. + {GlassState ? steamed: + ~ GlassState = steam_gone + <> The steam from my breath faded. + } + -> top + } + I leant back from the glass. My breath had steamed up the pane a little. + ~ GlassState = steamed + - - -> window_opts + + + + * {top >= 5} [Leave the room] + I'd seen enough. I {bedroomLightState ? on:switched off the lamp, then} turned and left the room. + -> joe_in_hall +- -> top + = see_prints_on_glass - ~ learn(fingerprints_on_glass) - {But I could see a few fingerprints, as though someone had leant their palm against it.|The fingerprints were quite clear and well-formed.} They faded as I watched. - ~ GlassState = steam_gone - ->-> - +~ learn(fingerprints_on_glass) +{But I could see a few fingerprints, as though someone had leant their palm against it.|The fingerprints were quite clear and well-formed.} They faded as I watched. +~ GlassState = steam_gone +->-> + = compare_prints (-> backto) - * {learnt(fingerprints_on_glass) && learnt(prints_on_knife) && !learnt(fingerprints_on_glass_match_knife)} [Compare the prints on the knife and the window ] - Holding the bloodied knife near the window, I breathed to bring out the prints once more, and compared them as best I could. - Hardly scientific, but they seemed very similar - very similiar indeed. - ~ learn(fingerprints_on_glass_match_knife) - -> backto - + * {learnt(fingerprints_on_glass) && learnt(prints_on_knife) && !learnt(fingerprints_on_glass_match_knife)} [Compare the prints on the knife and the window ] + Holding the bloodied knife near the window, I breathed to bring out the prints once more, and compared them as best I could. + Hardly scientific, but they seemed very similar - very similiar indeed. + ~ learn(fingerprints_on_glass_match_knife) + -> backto + = operate_lamp - I flicked the light switch. - { bedroomLightState ? on: - <> The bulb fell dark. - ~ bedroomLightState += off - ~ bedroomLightState -= on - - else: - { bedroomLightState ? on_floor: <> A little light spilled under the bed.} { bedroomLightState ? on_desk : <> The light gleamed on the polished tabletop. } - ~ bedroomLightState -= off - ~ bedroomLightState += on - } - ->-> - -= seen_light - * {!(bedroomLightState ? on)} [ Turn on lamp ] - -> operate_lamp -> - - * { !(bedroomLightState ? on_bed) && BedState ? stain_visible } - [ Move the light to the bed ] - ~ move_to_supporter(bedroomLightState, on_bed) - I moved the light over to the bloodstain and peered closely at it. It had soaked deeply into the fibres of the cotton sheet. - There was no doubt about it. This was where the blow had been struck. - ~ learn(murdered_in_bed) - - * { !(bedroomLightState ? on_desk) } {TURNS_SINCE(-> floorit) >= 2 } - [ Move the light back to the desk ] - ~ move_to_supporter(bedroomLightState, on_desk) - I moved the light back to the desk, setting it down where it had originally been. - * (floorit) { !(bedroomLightState ? on_floor) && darkunder } - [Move the light to the floor ] - ~ move_to_supporter(bedroomLightState, on_floor) - I picked the light up and set it down on the floor. - - -> top - +I flicked the light switch. +{ bedroomLightState ? on: + <> The bulb fell dark. + ~ bedroomLightState += off + ~ bedroomLightState -= on +- else: + { bedroomLightState ? on_floor: <> A little light spilled under the bed.} { bedroomLightState ? on_desk : <> The light gleamed on the polished tabletop. } + ~ bedroomLightState -= off + ~ bedroomLightState += on +} +->-> + += seen_light + * {!(bedroomLightState ? on)} [ Turn on lamp ] + -> operate_lamp -> + + * { !(bedroomLightState ? on_bed) && BedState ? stain_visible } + [ Move the light to the bed ] + ~ move_to_supporter(bedroomLightState, on_bed) + I moved the light over to the bloodstain and peered closely at it. It had soaked deeply into the fibres of the cotton sheet. + There was no doubt about it. This was where the blow had been struck. + ~ learn(murdered_in_bed) + + * { !(bedroomLightState ? on_desk) } {TURNS_SINCE(-> floorit) >= 2 } + [ Move the light back to the desk ] + ~ move_to_supporter(bedroomLightState, on_desk) + I moved the light back to the desk, setting it down where it had originally been. + * (floorit) { !(bedroomLightState ? on_floor) && darkunder } + [Move the light to the floor ] + ~ move_to_supporter(bedroomLightState, on_floor) + I picked the light up and set it down on the floor. +- -> top + === joe_in_hall - My police contact, Joe, was waiting in the hall. 'So?' he demanded. 'Did you find anything interesting?' -- (found) - * {found == 1} 'Nothing.' - He shrugged. 'Shame.' - -> done - * { Inventory ? knife } 'I found the murder weapon.' - 'Good going!' Joe replied with a grin. 'We thought the murderer had gotten rid of it. I'll bag that for you now.' - ~ move_to_supporter(knifeState, with_joe) - * {learnt(prints_on_knife)} { knifeState ? with_joe } - 'There are prints on the blade[.'],' I told him. - He regarded them carefully. - 'Hrm. Not very complete. It'll be hard to get a match from these.' - ~ learn(joe_seen_prints_on_knife) - * { learnt(fingerprints_on_glass_match_knife) && learnt(joe_seen_prints_on_knife) } - 'They match a set of prints on the window, too.' - 'Anyone could have touched the window,' Joe replied thoughtfully. 'But if they're more complete, they should help us get a decent match!' - ~ learn(joe_wants_better_prints) - * { between(body_on_bed, murdered_in_bed)} - 'The body was moved to the bed at some point[.'],' I told him. 'And then moved back to the floor.' - 'Why?' - * * 'I don't know.' - Joe nods. 'All right.' - * * 'Perhaps to get something from the floor?' - 'You wouldn't move a whole body for that.' - * * 'Perhaps he was killed in bed.' - 'It's just speculation at this point,' Joe remarks. - * { learnt(murdered_in_bed) } - 'The victim was murdered in bed, and then the body was moved to the floor.' - 'Why?' - * * 'I don't know.' - Joe nods. 'All right, then.' - * * 'Perhaps the murderer wanted to mislead us.' - 'How so?' - * * * 'They wanted us to think the victim was awake[.'], I replied thoughtfully. 'That they were meeting their attacker, rather than being stabbed in their sleep.' - * * * 'They wanted us to think there was some kind of struggle[.'],' I replied. 'That the victim wasn't simply stabbed in their sleep.' - - - - 'But if they were killed in bed, that's most likely what happened. Stabbed, while sleeping.' - ~ learn(murdered_while_asleep) - * * 'Perhaps the murderer hoped to clean up the scene.' - 'But they were disturbed? It's possible.' - - - * { found > 1} 'That's it.' - 'All right. It's a start,' Joe replied. - -> done - - -> found -- (done) - { - - between(joe_wants_better_prints, joe_got_better_prints): - ~ learn(joe_got_better_prints) - <> He moved for the door. 'I'll get those prints from the window now.' - - learnt(joe_seen_prints_on_knife): - <> 'I'll run those prints as best I can.' - - else: - <> 'Not much to go on.' - } - -> END +My police contact, Joe, was waiting in the hall. 'So?' he demanded. 'Did you find anything interesting?' +- (found) + * {found == 1} 'Nothing.' + He shrugged. 'Shame.' + -> done + * { Inventory ? knife } 'I found the murder weapon.' + 'Good going!' Joe replied with a grin. 'We thought the murderer had gotten rid of it. I'll bag that for you now.' + ~ move_to_supporter(knifeState, with_joe) + * {learnt(prints_on_knife)} { knifeState ? with_joe } + 'There are prints on the blade[.'],' I told him. + He regarded them carefully. + 'Hrm. Not very complete. It'll be hard to get a match from these.' + ~ learn(joe_seen_prints_on_knife) + * { learnt(fingerprints_on_glass_match_knife) && learnt(joe_seen_prints_on_knife) } + 'They match a set of prints on the window, too.' + 'Anyone could have touched the window,' Joe replied thoughtfully. 'But if they're more complete, they should help us get a decent match!' + ~ learn(joe_wants_better_prints) + * { between(body_on_bed, murdered_in_bed)} + 'The body was moved to the bed at some point[.'],' I told him. 'And then moved back to the floor.' + 'Why?' + * * 'I don't know.' + Joe nods. 'All right.' + * * 'Perhaps to get something from the floor?' + 'You wouldn't move a whole body for that.' + * * 'Perhaps he was killed in bed.' + 'It's just speculation at this point,' Joe remarks. + * { learnt(murdered_in_bed) } + 'The victim was murdered in bed, and then the body was moved to the floor.' + 'Why?' + * * 'I don't know.' + Joe nods. 'All right, then.' + * * 'Perhaps the murderer wanted to mislead us.' + 'How so?' + * * * 'They wanted us to think the victim was awake[.'], I replied thoughtfully. 'That they were meeting their attacker, rather than being stabbed in their sleep.' + * * * 'They wanted us to think there was some kind of struggle[.'],' I replied. 'That the victim wasn't simply stabbed in their sleep.' + - - - 'But if they were killed in bed, that's most likely what happened. Stabbed, while sleeping.' + ~ learn(murdered_while_asleep) + * * 'Perhaps the murderer hoped to clean up the scene.' + 'But they were disturbed? It's possible.' + + + * { found > 1} 'That's it.' + 'All right. It's a start,' Joe replied. + -> done +- -> found +- (done) + { + - between(joe_wants_better_prints, joe_got_better_prints): + ~ learn(joe_got_better_prints) + <> He moved for the door. 'I'll get those prints from the window now.' + - learnt(joe_seen_prints_on_knife): + <> 'I'll run those prints as best I can.' + - else: + <> 'Not much to go on.' +} + -> END ``` - + ## 8) Summary To summarise a difficult section, **ink**'s list construction provides: ### Flags -* Each list entry is an event -* Use `+=` to mark an event as having occurred -* Test using `?` and `!?` +* Each list entry is an event +* Use `+=` to mark an event as having occurred +* Test using `?` and `!?` Example: ``` ink -LIST GameEvents = foundSword, openedCasket, metGorgon +LIST GameEvents = foundSword, openedCasket, metGorgon { GameEvents ? openedCasket } { GameEvents ? (foundSword, metGorgon) } ~ GameEvents += metGorgon ``` ### State machines -* Each list entry is a state -* Use `=` to set the state; `++` and `--` to step forward or backward -* Test using `==`, `>` etc +* Each list entry is a state +* Use `=` to set the state; `++` and `--` to step forward or backward +* Test using `==`, `>` etc Example: ``` ink -LIST PancakeState = ingredients_gathered, batter_mix, pan_hot, pancakes_tossed, ready_to_eat +LIST PancakeState = ingredients_gathered, batter_mix, pan_hot, pancakes_tossed, ready_to_eat { PancakeState == batter_mix } { PancakeState < ready_to_eat } ~ PancakeState++ ``` ### Properties -* Each list is a different property, with values for the states that property can take (on or off, lit or unlit, etc) -* Change state by removing the old state, then adding in the new -* Test using `?` and `!?` +* Each list is a different property, with values for the states that property can take (on or off, lit or unlit, etc) +* Change state by removing the old state, then adding in the new +* Test using `?` and `!?` Example: