#Bryan's Learning of Twine
*A compendium of Harlowe 3 examples by the webmaster of (link-rerun:"williammillerservices.com")[(open-url:"http://williammillerservices.com")].*
* [[Style Passage Based on Tags->CustomPassage]]
* [[The Show Macro->DemoShowMacro]]
* [[Rolling dice->RollDice]]
* [[Macro to randomize capitalization->Random Capitalization]]
* [[Macro to describe potions->Describe Potion Macro]]
* [[Macro for fancy time->Fancy Time]]
* [[Macro for ghostly laughter->Ghostly Laughter]]
* [[Examples of CSS borders->Border Examples]]
* [[Link repeat example->Link Repeat]]
* [[Using the Nth macro->Using Nth]]
* [[In a galaxy far, far away...->LongAgo]]
* [[Saving and Loading your game->SavingLoading]]
* [[text styles->Text Styles]]
* [[the link: macro->LinkMacro]]
* [[embedding a link in `(link:)`-revealed text->InitHiddenLink]]
* [[using the `(display:)` macro with detail passages->AlienRestaurant]]
* [[Named hook example->NamedHook]]
* [[Opening a game in Stasis->Stasis]]
* (font: "Courier")[Story Arc]: Stasis -> [[Catalyst]] -> [[Climax]] -> Stasis
* [[Story arc description->Story Arc]]
* [[Pacing description->Pacing]]
* [[Example of Using a Timer->Dragonslayer]]
* [[Example of Countdown->Rocket]]
* [[Waiting a couple turns for a photo to develop->Kodak]]
* [[Example of hovering revealing transparent text->Hover1]]
* [[Example of x-rotated text->Hover2]]
* [[Example of y-rotated text->Hover3]]
* [[Examples shows Turns Taken at end of game->EndGame1]]
* [[Example of customizing text based on # passage visits->VisitRoom]]
* [[Using the `(either:)` macro->EitherMacro]]
* [[Send player to a random passage->SendToRand]]
* [[Using the `(random:)` macro->RandomDemo]]
* [[Demo of the `(click-replace:)` vs `(click:)` macro->ClickReplace]]
* [[Demo of printing items in an array using `joined`->Cauldron]]
* [[Demo of going back to previous passage->Go Back]]
* [[Demo setter links->DemoSetterLink]]
* [[Creating a datamap->Create Datamap]]
---
(font:"monospace")[(v6m-print:(passage:)'s source)]\
(append:?sidebar)[(icon-fullscreen:)(icon-restart:)]\
(enchant:?link,(t8n-depart:"dissolve")+(t8n-time:0.4s))(link: 'Words you want hyperlinked.')[New words that appear and replace the hyperlinked words.] The wall has a bookcase filled with dusty (link: 'books.')[books whose spines are each dotted with arcane symbols.] The nifty `(link:)` macro allows players to get as much or as little description as desired. (link: 'When using the `(link:)` macro...')[When using the `(link:)` macro, remember to additionally use the [[link->LinkMacro]] syntax, to enable a way to continue your story by moving the player out of the current passage.]
> [[Return to Index of Examples->Start]]In front of the bed is a well-worn rug that seems like it's seen better days. You kneel down and gently (link: "lift the rug.")[lift the rug, revealing a hinged trap door underneath. Do you [[open the trap door->Start]] and see where it leads? Or do you leave the door and go back [[downstairs->Start]]?]Every table is occupied by [[squid-like aliens->Aliens]] dining in pairs. An aquarium filled with [[neon-blue fish->Aquarium]] divides the restaurant. The only empty table is set with the expected [[plate->Plate]], [[silverware->Silverware]], and [[napkin->Napkin]], but also has a [[strange box->Meal Box]] with dozens of knobs sticking out of the top, a [[bowl->Meal Bowl]] filled with tiny metal balls, and a [[stick->Meal Stick]] with a suction cup on the end. Hmm, lots to investigate here. Or, you could [[leave->Start]] the restaurant.You try not to stare at the alien couple seated at the table nearest the door, but it's impossible not to gape at their undulating tentacles. They sense you staring, and turn to stare back at ... YOU.
(display: "AlienRestaurant")The aquarium contains colored lights of different hues. Prismatic light filters to the surface, glittering off scaled, exotic fish and the crystalline coral growths dotting the bottom of the tank.
(display: "AlienRestaurant")Plate description goes here.
(display: "AlienRestaurant")Silverware description goes here.
(display: "AlienRestaurant")Meal box description goes here.
(display: "AlienRestaurant")Meal bowl description goes here.
(display: "AlienRestaurant")Meal stick description goes here.
(display: "AlienRestaurant")Napkins description goes here.
(display: "AlienRestaurant")You reach into your satchel, feeling around for your magic wand...
Where is it? It has to be [in here somewhere,]<think| you think. (click: ?think)[But you realize that you left it on your workbench next to your spellbook!]{<!--This long passage sets the scene and provides stasis. Despite the rocking boat, this establishes a time of internal steadiness (stasis) for your player’s character. The opening is a snapshot or a peek into the character’s world.-->
You turn your face into the wind and adjust the bag over your shoulder as
you head to the remote island where your great-grandfather, Count Emil, buried a piece of your family's great fortune many years ago.}
You set sail from Hirtshals a few days ago. You know from your great-grandfather's notes, which contain the coordinates for the uninhabited island where he hid the treasure, that you'll know you are close when you see Risin og Kellingin -- the giant and the witch -- the name for the two large rocks jutting out of the water.
You scan the horizon for pirates. Though the Viking pirate encampments died out hundreds of years ago, there have been stories, told in the local pubs, about unmanned ghost longships floating on the water, their wooden planks being bleached by the sun.
They're just stories, right?
Anyway, pirates are the reason your great-grandfather hid this treasure in the first place. If there are any lurking around, they can have the priceless jewelry and the gold bars your great-grandfather buried there. You're after only one thing: your great-grandmother Katrine's locket. She disappeared not long after your grandfather was born, and Emil always said that the locket he buried there held the key to the mystery. One word, engraved inside the locket, by now forgotten so many generations later, will tell you what happened to your great-grandmother.
That's your treasure.
You look up at the lookout nest above you. Do you want to [[climb up->Lookout Nest]] to see if you can get a better view, or [[stay on the deck->Stay on Deck]]Double-click this passage to edit it.Double-click this passage to edit it.There will be many passages in the catalyst section of the story; in fact, the vast majority of your story will take place between the catalyst and the climax. To limit the number of endings you need to write, feel free to tie off a few threads early while carrying other storylines through the story arc to their end. The Catalyst is known, in other parlance, as the Rising Action.
> [[Back to the index->Start]]The climax is the story’s dramatic conclusion. The word climax comes from the Greek word for “ladder.” Think of this as a moment of heightened tension. Will things work out, or will they fall apart for the player character? If the catalyst is the problem, the climax is the solution, attempting to bring back the steadiness of stasis.
> [[Back to the index->Start]]As the writer, you’re guiding the player through a story, from the flat plateau of stasis to the dip of catalyst to the climb toward climax, and finally back to the plateau of stasis again.
> [[Back to the index->Start]]It’s important to think about the aspect of time in a story. Time inside a story is called *pacing*, and the purpose of time in a story is to create tension. Of course, there are ways to do this outside the story, such as counting moves, but you also need to think about ways you can convey that time is passing inside a story and that the passing of time matters. Set a deadline for your character; it will pique the player’s interest because now there is something at stake: Will the character resolve the conflict in time?
> [[Back to the index->Start]]The dragon's indrawn breath stirs the grass and sounds like a grating bellows.
(live: 4s)[Urine runs down your leg as dragonfear grips you.]
(live: 8s)[Your struggle mightily to break free of your paralysis.]
(live: 12s)[The reek of sulfur is overpowering and acrid smoke escapes the dragon's nostrils.]
(live: 16s)[The dragon's claws sink into the ground and its scaled neck extends. Immolation is imminent!]
(live: 20s)[(goto: "YouAreToast")]
> [[Slay the dragon->Start]]You are dead within the first two seconds that the dragon's fiery breath engulfs you.
> [[Back to the index->Start]]The maintenance vehicle in which you're riding pulls up to the launch pad, and you thank the driver before negotiating your way into the rocket's cockpit.
> [[Buckle Up]] for Ignition(set: $counter to 10)
Seconds remaining before launch: |amount>[$counter]
{
(live: 1s)[
(set: $counter to it - 1)
(if: $counter is 0)[(go-to: "Blastoff")]
(replace: ?amount)[$counter]
]
}You blastoff! Minutes later, you are in [[orbit->Start]].(enchant: "waiting", (hover-style:(text-color:'cornsilk')))
You're in your dark room, (if: (count: (history:), "Kodak") <= 2)[[[waiting->Kodak]] for your photo to develop.](else:)[and notice that the photo is finally [[ready->Start]].]
(text-colour:transparent)+(hover-style:(text-color:red))[The butler] killed Marcus O'Fogarty.
> [[Back to the index->Start]]
####(text-rotate:45)[The Sloping Sands of Silmur]
###### an adventure in the arid desert
> [[Back to the index->Start]](text-rotate-y:45)+(size:1.5)[FOUND A LOST SOCK!]
> [[Back to the index->Start]]It took you (print: (history:)'s length) turns to finish the game.
> [[Back to the index->Start]](if: (count: (history:), "VisitRoom") is 0)[Hmm, this is the first time you've been in this passage.](else:)[You've been here before.]
(if: (count: (history:), "VisitRoom") is 5)[You've been in this passage 5 times before.]
> [[visit this passage again->VisitRoom]]
> [[return to the Index->Start]] The `(either:)` macro can display randomized text or transport the player to a randomly chosen passage:
(set: $ghostSighting to (either: "mirror", "window", "doorway", "shadows", "fog"))
(text-colour: yellow)[You see a ghostly apparition in the (print: $ghostSighting).]
Twine randomly chooses one option and prints the word (or words if there are multiple words) enclosed inside one of the sets of quotation marks. The example above shows only a single word—mirror, window, doorway, shadows, or fog—in each set of quotation marks. But you can also place many words between the quotation marks to, for example, have the Twine game print whole sentences randomly. For instance, you could type this to have the description of the room change every time a person reenters the passage:
(text-colour: yellow)[You walk into the bedroom and see (either: "a four-poster bed covered in a soft, white blanket", "an empty space where a bed should be", "a child-sized bed in the shape of a pirate ship", "a mattress on the floor").]
Try refreshing the page a few times, and note how the sentences in yellow above change because of the use of the `(either:)` macro.
> [[return to the Index->Start]] (set: $roomName to (either: "Dark Room", "Water Room", "Small Room"))
You run through the door into the room and feel yourself falling through the [[floor->$roomName]].
You fell through the floor into this small room.
> [[return to the Index->Start]] You fell through the floor into this watery room.
> [[return to the Index->Start]] You fell through the floor into this dark room.
> [[return to the Index->Start]] You pick up the dice and weigh them in your hand. They feel lighter than usual.
You toss them onto the table and look at the results: a (random: 2,12).
> [[re-roll->RandomDemo]]
> [[return to the Index->Start]] {(set: $bag to (array: "a small pewter cauldron", "a silver spoon", "a book of matches"))
You come to the stream that Alden warned you about. It doesn't look particularly wild, and the spot in front of you looks shallow. Do you want to risk [[crossing the stream->Cross Stream]], or do you want to take the safer, [[longer path->Town]] to the next town and see if you can cross at the Dilly Bridge?}
[[Check bag->Bag]]
> [[return to the Index->Start]] The following demonstrates the `(click-replace:)` macro:
[You turn on the light in the room.]<light|(click-replace: ?light)[There is only a smooth expanse where the light switch used to be.]
By contrast, the `(click:)` macro in use:
[You turn on the light in the room. ]<party|(click: ?party)[Wow, it's a surprise party!]
> [[return to the Index->Start]] A very mean-looking troll demands an item in exchange for permitting you to cross the bridge.
(if: $bag contains "a silver spoon")[(set: $bag to $bag - (array: "a silver spoon"))Sadly, you hand over your silver spoon.](else:)[Since you don't have the spoon, you backtrack hurriedly. No way are you going to tangle with a bridge troll!]
[[Check bag->Bag]]
> [[return to the Index->Start]] (if: $bag contains "a feather")[](else:)[(set: $bag to $bag + (array: "a feather"))You pick up a beautiful feather from the side of the road and place it in your bag.] You continue walking into town and navigate to the [[Cross Stream<-Dilly Bridge]].
[[Check bag->Bag]]
> [[return to the Index->Start]] (if: $bag's length is 0)[Your bag is empty.](else:)[Your bag contains the following:]
(print: (joined: "\n", ...$bag))
(link-goto: "Return to Story", (history:)'s last)Demonstrates how to back up to the previous passage:
(link-goto: "previous passage", (history:)'s last)
Let's demonstrate a setter link:
Whatever you decide will seal your fate. Do you choose the (link: "sword")
[(set: $personality to "warrior")(goto: "Start Journey")] or the (link: "feather")
[(set: $personality to "peacemaker")(goto: "Start Journey")]?
> [[return to the Index->Start]]Your journey has begun. You are a $personality.
> [[return to the Index->Start]]Double-click this passage to edit it.To create a datamap, we do the following:
(set: $character1 to (datamap:))You step into the circle and place your hand on the promise stone. "I will go on the journey."
{
(set: $character1 to it + (datamap: "Class", "Wizard"))
(set: $character1 to it + (datamap: "Age", "29"))
(set: $character1 to it + (datamap: "Intelligence", "17"))
(set: $character1's "Item" to "Staff")
(set: $character1's "Hitpoints" to 80)We just added some name/value pairs to the datamap.}
{We decided we don't need "Age" so we trashed it.
(move: $character1's "Age" into $trash)}
Here is `$character1`:
(print: $character1)
(if: $character1's "Class" is "Wizard")[You cast a spell!](else:)[It's a shame you're not a spellcaster!] (if: $character1's "Hitpoints" > 75)[You appear to be in good health.]
> [[return to the Index->Start]](text-style: "italic")[Italics], (text-style: "bold")[bold], (text-style: "underline")[underlined], (text-style: "strike")[strikethrough], (text-style: "mark")[highlighted], (text-style: "blink")[blinking], (text-style: "rumble")[Rumbling], (text-style: "fade-in-out")[Fade In/Out], (text-style: "shudder")[Shuddering], (text-style: "blur")[Blurred], (text-style: "blurrier")[Blurrier], (text-style: "smear")[Smeared], (text-style: "mirror")[Mirrored], (text-style: "upside-down")[Upside down]
<span style="font-size: 200%">These words are very big.</span> These words are normal. <span style="font-size: 50%">And these words are very small.</span> (text-color: "#CC0000")[These words are in red.] (text-color: "#FF6600")[Now orange, ](text-color: "#FFCC00")[now yellow, ](text-color: "#009900")[now green, ](text-color: "#0000FF")[now blue, ](text-color: "#6600CC")[and now purple.] (text-color: "aliceblue")[Aliceblue]. (text-color: "olive")[Olive.]
> [[return to the Index->Start]] To set up your Harlowe 3 game so that it can save and load games:
First, in the game's starting passage, add the following code:
(text-color: red)[
`(set: $justLoaded to false)`]
Next, create a passage named HeaderInfo and give it the header tag. Edit it and put the following into the passage:
(v6m: )+(text-color: red)[
{
(link: "Save game")[
(if: (save-game: "SlotAA"))[Game was saved!](else:)
[Unable to save...]
]<br>
(if: (saved-games:) contains "SlotAA")[
(link: "Load game")[(load-game: "SlotAA")(set: $justLoaded to true)]
](else:)[Couldn't find saved game 'SlotAA']
}
(if: $justLoaded is true)[Loaded game successfully.(set: $justLoaded to false)]
<hr>
]
> [[return to the Index->Start]] (if: (count: (history:), "LongAgo") is 0)[
(live: 1s)[<pre>Long ago...</pre>]
(live: 3s)[<pre> in a galaxy far, far away...</pre>]
(live: 6s)[(go-to: "LongAgo")]
](else:)[
Star Wars!
(live: 2s)[<pre>Help me, Obi-Wan... </pre>](live: 5s)[<pre>You're my only hope!</pre>]]
(live: 7s)[(go-to: "Start")] "none", "bold", "italic", "underline", "double-underline", "wavy-underline", "strike", "double-strike", "wavy-strike", "superscript", "subscript", "blink", "shudder", "mark", "condense", "expand", "outline", "shadow", "emboss", "smear", "blur", "blurrier", "mirror", "upside-down", "fade-in-out", "rumble", "sway", "buoy" or "fidget".(nth: (min: 3, visit), "This is the first time you've been in this passage.", "You feel as if you've been here before.", "Ah, yes, another cavern you frequent. It feels like home.")
(link: "Return to this passage again")[(goto: 'Using Nth')]{
<!-- Initialise range of colours -->
(set:$colours to (a:"red", "green", "silver"))
(set:$colour_index to 1)
(set:$colour to $colours's $colour_index)
}The dress is (link-repeat:"[$colour]<colourhook|")[{
<!-- Pick new colour, then replace description inside the link. -->
(set:$colour_index to (it % $colours's length) + 1)
(set:$colour to $colours's $colour_index)
(replace:?colourhook)[$colour]
}], you're bored, and you just know it'll make them green with envy. Wanna steal it?
[[Back to the index->Start]](b4r:"dotted")[I love you!
I want to be your wife!]
(b4r:'solid')+(corner-radius:8)[Hasn't this gone on too long?]
(b4r:'solid')+(corner-radius:12)[Shouldn't you tell them the truth?]
(b4r:'solid')+(corner-radius:16)[//That you're not really who you say you are??//]
(box:"=XX=", 2)[Chapter complete
Str increased to 3
Wis increased to 4]
> [[Back to the index->Start]](set:$ghostlyLaughter to (macro: num-type _o, [
(output: )+(text-rotate:(random:0,360))+(text-colour:(hsla:0, 1, 0.5, _o))[Hah!]
]))
($ghostlyLaughter:0.9) ($ghostlyLaughter:0.5) ($ghostlyLaughter:0.3)
> [[Back to the index->Start]](set: $fancyTimeName to (macro: [
(set: _timeOfDay to (history: )'s length % 24 + 1)
(output-data: (a:
"midnight", "dreamshour", "wolfshour", "dark's end", "lightbreak", "afterdawn", "early rise", "awakening",
"early warming", "joyshour", "first lunch", "shadow's end", "zenith", "shadow's birth", "second lunch", "hopeshour", "early cooling",
"lightfade", "sundown", "dark's birth", "supper", "early rest", "slumbering", "catshour"
)'s (_timeOfDay))
]))
It is now ($fancyTimeName:).
> [[Back to the index->Start]](set: $describePotion to (macro: dm-type _potion, [
(size:0.7)+(box:"=XXXXX=")+(border:"solid")+(output:)[\
##(print:_potion's name)
|==
''Hue'': (print:_potion's hue)
''Smell'': (print:_potion's smell)
''Flask'': (print:_potion's flask)
''Effect'': (print: _potion's effect)
==|
//(print: _potion's desc)//
]
]))
($describePotion: (dm:
"name", "Vasca's Dreambrew",
"hue", "Puce",
"smell", "Strong acidic honey",
"flask", "Conical, green glass, corked",
"effect", "The drinker will, upon sleeping, revisit the last dream they had, exactly as it was.",
"desc", "Though Vasca was famed in life for her more practical potions, this brew is still sought after"
+ " by soothsayers and dream-scryers alike.",
))
> [[Back to the index->Start]](set: $randomCaps to (macro: str-type _str, [
(output-data:
(folded: _char making _out via _out + (either:(lowercase:_char),(uppercase:_char)),
..._str)
)
]))
($randomCaps:"I think my voice module is a little bit very broken.")
> [[Back to the index->Start]]<!-- Let's roll some 3d6: -->
> [[Back to the index->Start]]When I was a little bitty baby |extra)[ my momma used to rock me in my cradle, ]in them old cotton fields (link-reveal: "back home.")[(show: ?extra)]
> [[Return to Index of Examples->Start]]There is a spooky tree in this forest
<div class="aliens">When you look at it, it disappears.</div>
But you’re sure it’s there.
Let's go to the [[desert->CustomPassage2]].Now we're in the desert.
> [[Return to Index of Examples->Start]]