This is a site about creating interactive fiction using the Twine 2 program and the Harlowe story format.
(link-repeat: "Guide to using Twine 2")[(gotourl: "twine_guide.html")]
[[Common mistakes->mistakes]]
(link-repeat: "Cookbook")[(gotourl: "Cookbook.html")]
[[Example Games->Examples]]
[[Useful links->useful]]
[[Sandbox->sandbox]]
The Harlowe guide has been supersceded by the (print: window.gotoURL("official Harlowe manual", "http://twine2.neocities.org/")). You can still read the guide (link-repeat: "here")[(gotourl: "Harlowe.html")], but it's highly recommended you use the official manual which is both more comprehensive and up to date.
This site is soley about the Harlowe story format, though there are others available. A list of formats is [[here->story formats]]
This is [[version 3->versions]] of the site.
###Example stories
Here are some example stories, which demonstrate different features. They can be played online or be downloaded by right clicking the link and selecting 'save as...' (the exact option will depend on the browser).
Remember, after downloading a story you can import it into Twine to see its source.
####This site
This site was made using Twine. You can either save this page or right-click this (print: gotoURL("Link", "http://twine.analytical-engine.co.uk/index.html"))
####Two rooms
A simple game which just features 2 rooms. You're at a business convention but have lost your ID.
(print: gotoURL("Link", "stories/Two Rooms.html"))
####Stranded
You find yourself stranded on a desert island and must find the means to escape.
(print: gotoURL("Link", "stories/stranded.html"))
(unless: (passage:)'s tags contains "noheader")[{<div class="header"><div class="title">All about Twine 2 and Harlowe</div>
<div class="menubar">
[[Home->start]] | (link-repeat: "Twine 2")[(gotourl: "twine_guide.html")] | (link-repeat: "Cookbook")[(gotourl: "Cookbook.html")] | [[Examples]] | [[Links->useful]]
</div>
<div class="options">
(set: $url to "index.html?p=" + (passage:)'s name)
(print: "<a title = \"" + $url + "\" href = \"" + $url + "\">link to current passage</a>") |
(set: $sourcelist to (array: "View sourcecode", "Hide sourcecode"))
(set: $sourceindex to 1)
[(print: $sourcelist's $sourceindex)]<cl_link|
[(display: "sourcelink")]<cl_macro|
</div>
</div>
}
[]<src|]
###Story formats
Twine 2 comes with 3 formats installed
####Harlowe
The default format and the one that this tutorial uses. The official manual is (print: window.gotoURL("here", "http://twine2.neocities.org/")).
####Sugarcube
Sugarcube's syntax is closer to that of Twine 1 (it is available as a format in Twine 1.4 as well as 2). It also has more features than Harlowe. You can find documentation for the format (print: window.gotoURL("here", "http://www.motoslave.net/sugarcube/")).
####Snowman
Snowman is a minimal format which exposes most of its features through Javascript. You can find some instructions on its use (print: window.gotoURL("here", "https://bitbucket.org/klembot/snowman-2")).
(set: $prev to "text") (set: $next to "special") (display: "navigation")
###Multimedia
You may wish to add pictures, sounds or even video to a story. Harlowe doesn't include any provisions for this, but it can be done using html.
####Pictures
Pictures can be included using the img tag.
`<img src="http://twine.analytical-engine.co.uk/img/pic.jpg">`
<img src="http://twine.analytical-engine.co.uk/img/pic.jpg">
####Audio
<div class="exampleblock">`<audio src="media/drums.mp3" controls>
<p>Your browser does not support the audio element.</p>
</audio>`</div>
This will create an audio controller widget.
<audio src="media/drums.mp3" controls>
<p>Your browser does not support the audio element.</p>
</audio>
You're more likely to want to play a sound as soon as the player visits a passage. In which case replace `controls` with `autoplay`.
<div class="exampleblock">`<audio src="media/drums.mp3" autoplay>
<p>Your browser does not support the audio element.</p>
</audio>`</div>
[[passage with auto playing sound->audiopassage]]
Adding `loop` will make the sound repeat.
####Video
<div class="exampleblock">`<video src="http://twine.analytical-engine.co.uk/media/video.ogv" controls>
Your browser does not support the video element.
</video>`</div>
<video src="http://twine.analytical-engine.co.uk/media/video.ogv" controls>
Your browser does not support the video element.
</video>
Again, replacing controls with autoplay will produce an autoplaying video.
<div class="warningblock">Different browsers support different audio and video formats. Which means if you do include them the story might not work properly in some browsers.</div>
####Converting media into text
It's possible to convert any digital media into base 64 text. This allows it to be put into a normal twine passage. (link: "This site")[(gotoURL: "http://www.base64-image.de/")] handles the conversion for you.
Then to display a picture you would do `<img src="data:image/jpg;base64,-base 64 text goes here-">` (The site above provides an xhtml version which includes the above text).
It's best to put that in a seperate passage and when you want to show the picture, use the display macro.
The main advantage is there are no external files to transfer with the story. Also it means you can include media, even if the web host only allows html files to be uploaded.
(display: "navigation")
<audio src="media/drums.mp3" autoplay>
<p>Your browser does not support the audio element.</p>
</audio>
[[return to tutorial->multimedia]]
####Version 1:
Initial version
####Version 2:
* Added a version history
* Added links to the guide to the start page
* Added page about numbers and strings
* Added cookbook
* Moved instructions on Twine 2 to a seperate guide
* Added some missing macros
* Adjusted formatting and layout
* Improved descriptions for special passages
* Improved section on Javascript
* Added index
* It's now possible to start the guide on a specific page
** entering the URL: http://twine.analytical-engine.co.uk/index.html?p=Javascript will open to the page about Javascript
** If the passage doesn't exist it will go to the start passage.
* There is a link at the top of every page which gives the URL for that page (right click on it and select "copy link location")
* Made external links more obvious
** They have an icon next to them
** The url appears as a tool tip
* It's possible to view the sourcecode of any page.
* Added sandbox to try out twinescript macros
####Version 2.1:
* Added the remainder operator to numbers and strings page
* Improved the Javascript page
* Added section on `it` keyword to variables page
* Added cookbook recipe's for simple and advanced combat
* Add section about reading or writing named hooks to variables page
####Version 3
* Harlowe guide is now deprecated
* Twine 2 guide and Cookbook split into seperate files
* Reorganised the cookbook
* Added list of common mistakes
(set: $startPassage to window.getStartPassage())
(if: $startPassage is not "")[(goto: $startPassage)](else:)[(goto: "start")]
(click: ?cl_link)[
(if: $sourceindex is $sourcelist's length)[(set: $sourceindex to 1)]
(else:)[(set: $sourceindex += 1)]
(replace: ?cl_link)[(print: $sourcelist's $sourceindex)]
(replace: ?cl_macro)[(display: "sourcelink")]
(if: $sourceindex is 1)[(replace: ?src)[]](else:)[(replace: ?src)[(print: window.displaySource())]]
]
(print: window.gotoURL("The main Twine site", "http://twinery.org"))
(print: window.gotoURL("The Twine 2 manual", "http://twinery.org/wiki/twine2:guide"))
(print: window.gotoURL("The Harlowe manual", "http://twine2.neocities.org/"))
(print: window.gotoURL("The Twine wiki", "http://twinery.org/wiki"))
(print: window.gotoURL("The Twine forums", "http://twinery.org/forum"))
Note: The twine forums are a good place to ask for help if you're stuck, but always remember to state what format you're using. The answer to your problem can vary quite a lot depending on it.
(set: $data to (a: "", "Enter commands in the box below", "The output will be displayed here", "Entering '`(text-color: red)[I'm red]`' will display:", "`(text-color: red)[I'm red]`", "==>(text-color: red)[I'm red]","Currently datasets and datamaps won't display anything", "unless in a `(print:)` macro", "up and down arrows scroll through command history", "click exit when you've finished."))
<div class="outputbox">[(print: $data.join("\n"))]<textbox|</div>
<input type="text" name="textbox" size="120" onkeyup="if (event.keyCode == 13 || event.keyCode == 38 || event.keyCode == 40) {window.runText(event.keyCode, 'textbox');}">
[[exit->start]]
(live: 100ms)[(if: $inputText is not 0)[(set: $data to (subarray: $data ,3, 10))(set: $data to $data + (a: "`" + $inputText + "`", "==>" + $inputText))(replace: ?textbox)[(print: $data.join("\n"))](set: $inputText to 0)]]
###Common mistakes
This is a list of things that often trip people up
####Trying to print a boolean using the bare variable form
In most cases you can print the value a variable by just writing the variable. However this won't work if the variable holds a boolean (true/false) value.
<div class="code">`(set: $var to "test")`
(set: $var to "test")
`$var`
$var
`(set: $var to true)`
(set: $var to true)
`$var`
$var</div>
####Testing multiple conditions
If you want to test if a variable is between two values then the following will work:
<div class="code">`(if: $skill >5 and < 10)[yes](else:)[no]`</div>
However if you want to test if two variables both have the same value them the following:
<div class="code">`(if: $x and $y is 5)[yes](else:)[no]`</div>
Will produce an error. In this case you need to write both tests out in full:
<div class="code">`(if: $x is 5 and $y is 5)[yes](else:)[no]`</div>
####Testing less than, greater than, etc
Sometimes when people are using one of the relational operators, they use the is operator as well.
<div class="code">`(if: $val is > 2)[greater]`</div>
While this may seem correct when reading it out loud (if val is greater than 2), it will silently fail. If you need to test if a variable is greater than a value the correct syntax is:
<div class="code">`(if $val > 5)[...]`</div>
####Changing the value of a displayed variable
When printing a variable, Twine will read the value when it displays the page, but after that it is just a static element.
For example:
<div class="code">`(set: $score to 5)
$score
(link-repeat: "Increase score")[(set: $score to it + 1)]`</div>
When the player clicks the link, the value of score will go up by one, but that won't affect the previously displayed number. It will show 5 no matter what `$score` currently is.
<div class="output">(set: $score to 5)
$score
(link-repeat: "Increase score")[(set: $score to it + 1)]</div>
One way to fix this is to put the display of the score in a named hook and then use `(replace:)` to overwrite it.
<div class="code">`(set: $score2 to 5)
[$score2]<score|
(link-repeat: "Increase score")[(set: $score2 to it + 1)(replace: ?score)[$score2]]`</div>
<div class="code">(set: $score2 to 5)
[$score2]<score|
(link-repeat: "Increase score")[(set: $score2 to it + 1)(replace: ?score)[$score2]]</div>
####Trying to upload/run the wrong HTML files
If you're using the desktop version of Twine then it saves your stories as HTML files in the Documents/Twine/Stories folder. Despite having an html extension these are not valid web pages. If you try to load one of these files into a web browser it'll just show a blank page and uploading to a site like philome.la will give you an error.
In oder to create a file which can be uploaded and run in a web browser or uploaded to a sharing site you need to publish the story.
Note: Don't publish the story to the Documents/Twine/Stories folder, since that will confuse Twine.