Oh, there's definitely more to love here.
The post One to Love by Michelle Monkou appeared first on HOT SAUCE REVIEWS.
from HOT SAUCE REVIEWS http://ift.tt/1c0KRsO
via IFTTT
Oh, there's definitely more to love here.
The post One to Love by Michelle Monkou appeared first on HOT SAUCE REVIEWS.
I’ve been working on a ChoiceScript project lately, and for the benefit of other ChoiceScript users, I thought I’d describe the debugging and testing techniques that I’m using.
If you’re not interested in using ChoiceScript, this is not the post for you, because it’s all technical from here.
This post … Keep reading →
Rising Angels: Reborn is a sci-fi mystery visual novel which shows that people can always change (for better or worse), that the vast reaches of space make for a great visual novel setting, and that some of the best VNs out there are free from small studios. The story follows Major Natalie Puccile, a Special […]
The post Visual Novel: Rising Angels: Reborn appeared first on .
Rising Angels: Reborn is a sci-fi mystery visual novel which shows that people can always change (for better or worse), that the vast reaches of space make for a great visual novel setting, and that some of the best VNs out there are free from small studios. The story follows Major Natalie Puccile, a Special […]
The post Visual Novel: Rising Angels: Reborn appeared first on .
The names of the characters are different, but it's the same book. I guess the author doesn't want to break what's not broken.
The post Beautiful Oblivion by Jamie McGuire appeared first on HOT SAUCE REVIEWS.
Hi there!
Last April 23th we had a different World Book Day, we gave a workshop at Apple Store Passeig de Grà cia, in the heart of Barcelona.
Giving a talk at Apple Store was a privilege for us and a great opportunity to present and explain all the keys of our gamebooks.
At 19:00h we started the workshop with a great gaming atmosphere among the audience.
We also played our gamebooks The Sinister Fairground and Necklace of Skulls with the attendees, discussing the characteristics of each of them.
Afterwards, the audience enjoyed and took part of a mini-gamebook, taking decisions, facing challenges and winning battles against dragons.
The workshop ended with very interesting questions from the attendees. We hope our answers have been helpful for the audience, otherwise you can write us at hello@cubusgames.com
See you soon!
“You’ve got to know when to hold ’em
Know when to fold ’em
Know when to walk away
And know when to run
You never count your money
When you’re sittin’ at the table
There’ll be time enough for countin’
When the dealin’s … Keep reading →
Bwahahaha at the title. Yucks at everything else.
The post War with the Evil Power Master by RA Montgomery appeared first on HOT SAUCE REVIEWS.
The results of the 2014 XYZZY Awards for excellence in interactive fiction were announced this evening at the usual gala ceremony on ifMUD. Congratulations to all the winners!
I am very pleased and proud that three IFComp entries — all top-ten finishers from last year, and all very different examples of IF — took home awards. In alphabetical order:
Creatures Such as We, by Lynnea Glasser (2nd place, IFComp 2014) won the Best NPCs award.
Fifteen Minutes, by Ade (6th place, IFComp 2014) won the Best Puzzle award.
With Those we Love Alive, by Porpentine and Brenda Neotenomie (5th place, IFComp 2014) won the Best Single NPC and Best Writing awards.
The larger nominees list honored other IFComp entries as well.
I offer especial congratulations to inkle’s amazing 80 Days as the winner of the coveted Best Game XYZZY award. This isn’t the first time a commercial game has taken this prize, but I would hazard a guess that it’s the most commercially successful game to do so, having received mainstream recognition in quarters far beyond the hobbyist community. As inkle co-founder (and 2001 IFComp winner) Jon Ingold said while accepting the award,
I’ve been making IF in this community and its fringes for 15 years or so, and it’s pretty remarkable how much the landscape has changed since those days - back when choice games were considered childish, simplistic. And a lot of us had the feeling that there was something really interesting in interactive fiction that was worth plugging away at despite the fact lots of people said there wasn’t.
We all said there was a thing here. And maybe there’s a thing here. And next year there might be another thing. And that’s a great place to be.
So — we got this. It’s going to be fine.
I agree. With just over five months to go until IFComp 2015, I look forward to our own next crop of great things.
Warning! Peen-hungry daughter of the POTUS is on the prowl! Okay, it's like that, but not really like that. Or something.
The post Various States of Undress: Carolina by Laura Simcox appeared first on HOT SAUCE REVIEWS.
Wait, did anyone say "perfect"? Not today, dear, not today.
The post The Perfect Mistress by Victoria Alexander appeared first on HOT SAUCE REVIEWS.
Joss Whedon once again proves that he's overrated when it comes to his ability as a writer and director.
The post Avengers: Age of Ultron (2015) appeared first on HOT SAUCE REVIEWS.
The real trouble is the presence of crappy gamebooks like this one.
The post Trouble on Planet Earth by RA Montgomery appeared first on HOT SAUCE REVIEWS.
I loathe the heroine. She should be a Mortal Kombat character so that I can perform repeated fatalities on her.
The post The Governess Club: Louisa by Ellie Macdonald appeared first on HOT SAUCE REVIEWS.
You’re sitting on your laptop in bed. You live in a dorm with your best friend Jenna. Games like Freshman Year are inherently personal. An autobiographical vignette by Nina Freeman, Freshman Year follows a night in the world of Nina as she goes out to a bar. Like many up and coming interactive experiences, your […]
The post Review: Freshman Year appeared first on .
We had a truly horrible winter in Boston (the worst in recorded history, actually), mostly compacted into the month of February. It seemed like spring would never come, and when I went on vacation last week, the snow was gone but the world was bare.
But I came back … Keep reading →
A whiny special snowflake and a doormat sex-mad bunny boiler, together in love. Just kill me already.
The post The Governess Club: Sara by Ellie Macdonald appeared first on HOT SAUCE REVIEWS.
Stripper zombie women vs four people. Now that's a party.
The post Stripperland (2011) appeared first on HOT SAUCE REVIEWS.
It's not bad at all, for a gamebook by RA Montgomery.
The post Prisoner of the Ant People by RA Montgomery appeared first on HOT SAUCE REVIEWS.
This story is doomed from the start, when the author becomes too fixated on the heroine's virtue over everything else.
The post Mine Tonight by Lisa Marie Perry appeared first on HOT SAUCE REVIEWS.
This is the third part of a series walking step-by-step through developing a game with Raconteur. In this post, I’ll explain Raconteur’s adaptive text features.
Let’s get right to it. I’ll be starting from the complete example from the last tutorial. So far, we’ve only seen situations that have a long String as their content
property:
situation 'go_right',
content: """
The tunnel opens up into a wide chamber, dominated by a bright
reflecting pool.
"""
optionText: 'Go right'
Until now, I’ve been hiding one of the key features of Raconteur: The fact that content
can not only be a simple string but also a function that returns a string. So we could rewrite this situation:
situation 'go_right',
content: () ->
"""
The tunnel opens up into a wide chamber, dominated by a bright
reflecting pool.
"""
optionText: 'Go right'
As we know, () ->
is CoffeeScript for a function declaration, with no named arguments. Everything indented right of that declaration is part of the function body, which in this case includes only the string. In CoffeeScript, the last expression in a function is taken as its return value, so that the function simply returns that string.
You can make that change to the full example from the last tutorial and run it, and you will find that nothing has changed. But it’s important to note the difference between using a function as a content
property, and using a String.
goldPieces = 500
situation 'count_gold',
content: """
You count your gold and find that you have #{goldPieces}gp.
"""
situation 'count_gold2',
content: () ->
"""
You count your gold and find that you have #{goldPieces}gp.
"""
On first glance those two situations may seem functionally identical, but they are actually doing quite different things. count_gold
is looking at the value of goldPieces
when the situation is created, and “baking” that value into its content
. Remember, the #{}
syntax in CoffeeScript is equivalent to evaluating the expression inside the brackets, converting it to a String, and then concatenating it inside the parent string. So the first situation will always say “500gp” no matter what happens to the value of goldPieces
.
The other situation will work as you might intuit that it should: Because the string has been wrapped in a function, it gets evaluated only when that function is run. So it will print the current value of goldPieces
, whatever it may be at the time when the situation is entered.
A content
function can do anything – including have side-effects – but the most common use of them is to construct text procedurally based on the story state. In the last tutorial, we blocked a path from the player if they didn’t pick up the lamp outside the cave; let’s say we wanted to acknowledge that they had the lamp in the other branch, too, without blocking it:
situation 'go_right',
content: (character) ->
poolAdj =
if character.sandbox.hasLamp then "bright reflecting" else "dark"
"""
The tunnel opens up into a wide chamber, dominated by a #{poolAdj}
pool. #{if character.sandbox.hasLamp then 'Flickering light from your
lamp bounces off the slick walls.' else 'It is very dark, and you all
but fall into the pool.'}
"""
optionText: 'Go right'
content
, as a function, gets passed the same Character
and System
objects that we saw previously, as well as the name of the previous expression.
Note how if
statements in CoffeeScript are themselves expressions, so they can be used inline inside a string interpolation, or as the left hand of an assignment statement. Note that an if-expression can evaluate to undefined
if there’s no else
branch:
day.beautiful = false
"Hello!#{if day.beautiful then ' What a beautiful day!'}"
# -> "Hello!undefined"
"Hello!#{if day.beautiful then ' What a beautiful day!' else ''}"
# -> "Hello!"
Another important thing about content
: Inside that function, the value of this
is set to the situation object itself. Situations can have custom defined own properties, so you can use this behaviour to encapsulate something about a situation:
situation 'examine_dog',
breed: 'dalmatian'
size: 'large'
colours: 'spotted'
content: () ->
"""
The dog is a #{this.size} #{this.breed}, covered in #{this.colours} fur.
"""
# -> The dog is a large dalmatian, covered in spotted fur.
This will prove useful when we start dealing with text iterators.
Text iterators are one of Raconteur’s convenience features, and the first one we’ll talk about that comes in a separate module from the main situation
module.
oneOf = require('raconteur/lib/oneOf.js')
oneOf()
is a factory, a function that builds a certain kind of object. Unlike a constructor, it’s not meant to be invoked with new
. And we’re only really interested in oneOf
objects for their particular methods. All this is to say that oneOf implements a way of creating variable text snippet that should be familiar to Inform 7 users. An example:
ring = oneOf('The phone rings.',
'The phone rings a second time.',
'The phone rings again.').stopping()
situation 'phone_rings',
content: () -> "#{ring()}"
choices: ['ignore_phone']
situation 'ignore_phone',
content: () -> "#{ring()}"
optionText: 'Ignore the phone'
choices: ['ignore_phone_again']
situation 'ignore_phone_again',
content: () -> "#{ring()}"
optionText: 'Let it ring'
This is a toy example, but it shows how oneOf
works. We create a oneOf object with by passing any number of strings as arguments to oneOf()
. Then we call the stopping()
method on that object to get a special function, a closure.
Each time you call that function, it’ll return one of your strings – until it runs out; then it’ll keep repeating that last one. The advantage of writing adaptive text this way is that you don’t have to separately keep track of state – the closure contains the text and tracks how many times it’s been invoked. oneOf
supplies five methods currently:
cycling
: The closure iterates over the list of snippets and returns each one in order, then goes back to the start when it runs out.stopping
: The closure iterates over the list of snippets and returns each one in order, then repeats the last item when it runs out.randomly
: The closure returns a random item from the list each time it’s called, except it will never return the same one twice in a row.trulyAtRandom
: Similar to randomly
, except it can return the same item twice in a row.inRandomOrder
: Works like cycling
, except the list is shuffled first. This guarantees that every item will be shown exactly once before the list repeats.Keep in mind: When you call one of the object methods, like cycling()
, you are creating a new function. So you should declare your snippets once and bind them to a name. And, similarly to the caveat above about function versus string content, you should use them inside functions, unless you intend to run them once and then keep the result indefinitely:
poolColor = oneOf('blue', 'green', 'red').trulyAtRandom()
# This pool will always be the same colour...
situation 'mystic_pool',
content:
"""
The pool shimmers with #{poolColor} light.
"""
# ...this one will vary each time it's visited.
situation 'mystic_pool',
content: () ->
"""
The pool shimmers with #{poolColor} light.
"""
Undum uses a particular way of retaining save games: It saves every player input, and then when a save is restored it essentially replays them in order to rebuild their game. This works perfectly well… as long as the results of every input are always the same, ie if the game is deterministic.
Of course, if you want to incorporate randomness into your game, then your game isn’t deterministic. To square that circle, Undum supplies the System.rnd
object. This object is a pseudorandom number generator which Undum itself initialises. Because the save game includes the random seed, save games can work. However, this architecture requires a bit of care on the part of the author to only use the Random
object supplied by Undum.
oneOf
is built ot use that object, but that means you have to initialise oneOf
objects that use randomness inside your undum.game.init
function, by passing system
into the factory methods:
snippets = {}
undum.game.init = (character, system) ->
snippets.randomColour = oneOf('green', 'red', 'blue').randomly(system)
We bind the closure to a name we can reach from our situations – here I’m making a snippets
object (local to main.coffee
) and binding my snippet to that, but I could just as well attach them to character.sandbox
.
randomly
, trulyAtRandom
, and inRandomOrder
all take a System
object as an argument. If you don’t initialise them with one, they’ll work – they’ll simply use the general Math.random()
pseudorandom number generator that JavaScript supplies. This means that every time a save is loaded, they’ll produce different results. This might be okay for testing, prototyping, or inconsequential text variations, but almost all of the time you want to initialise them properly with system
.
Text variations are a really powerful tool, and they give you a lot of flexibility in structuring your story. With text variations, you can ensure that the story is always calling back to previous story events; allow the player to return to previous situations without repetition; and have the same situation present itself differently depending on the state of the story.
One major use of this is to merge branches in a way that flows naturally with previous story events; the “bottleneck” will look different depending on what has happened previously in the story. Another use is to insert variations into a situation that gets revisited, such as a “hub” that the player might see several times over the course of the game.
In the next part of this tutorial, we will look at qualities and what they’re good for. But first, a few parting notes:
oneOf
isn’t just good for text; in fact, it’ll take arguments of any type. Mere Anarchy, for example, uses a similar technique to oneOf in various places, including to randomise the “sigil” images that show up at various points in the narrative.System.rnd
, which you can use to randomise things in your own functions.How many ways can the author portray Australians as freaks of the century? Many, many ways!
The post Pocket Apocalypse by Seanan McGuire appeared first on HOT SAUCE REVIEWS.
The author commits the greatest authorial crime ever: she fails to make me care even a little about her story.
The post Four Nights with the Duke by Eloisa James appeared first on HOT SAUCE REVIEWS.
Fast tunes for fast cars and hot people. Oh, and that song, which we'd all be sick of before the year is out.
The post Furious 7 by Various Artists appeared first on HOT SAUCE REVIEWS.
Despite its title, this isn't an erotic romp. It's a good old-fashioned story of two people falling in love. I like it.
The post Various States of Undress: Virginia by Laura Simcox appeared first on HOT SAUCE REVIEWS.
It is never about this book. It's all about the next book, when Lyon Whatshisname finally faces the firing squad.
The post It Started with a Scandal by Julie Anne Long appeared first on HOT SAUCE REVIEWS.
Last we left off, I had explained setting up Raconteur and writing a very basic Situation: Enough to make simple stories. This tutorial is going to delve a little deeper into using Undum and Raconteur to write more complex stories.
Background information on Raconteur.
The situation
factory that Raconteur uses will actually create a situation object that has all of the properties you pass on to it in your spec, but a good number of them are special. Today we’re going to look at four of them: before
, choices
, optionText
, and canView
. Let’s start with choices.
Last time, I showed how you could use explicit links to connect one situation to another. But there’s another way:
situation 'start',
content: """
You stand at the mouth of a damp, dark limestone cave. Two passages,
left and right, stretch out into the darkness.
"""
choices: ['go_left', 'go_right']
situation 'go_left',
content: """
The tunnel narrows dramatically as you enter it, forcing you to
squeeze in sideways between the slick limestone walls.
"""
optionText: 'Go left'
situation 'go_right',
content: """
The tunnel opens up into a wide chamber, dominated by a bright
reflecting pool.
"""
optionText: 'Go right'
Use this as the situations in a Raconteur main.coffee
story and run it, and you’ll see what happens:
What happened here? Raconteur and Undum have taken the list of situations you supplied in the choices
property of start
and used it to build a list of options that follows your situation’s content. So far, this is only a different presentation from just writing direct links. To find out what more we can do with this approach, we have to look into canView
and Undum’s implicit choice feature.
Let’s make a simple edit to one of our situations:
situation 'go_left',
content: """
The tunnel narrows dramatically as you enter it, forcing you to
squeeze in sideways between the slick limestone walls.
"""
optionText: 'Go left'
canView: () -> false
() ->
is CoffeeScript syntax for a function definition; canView is our first function. For those of you who come directly from JavaScript or other programming languages, here’s a quick refresher on CS functions:
hello_world = () -> # The parens are mandatory even if there's no arguments
console.log "Hello, world!" # Function calls in CoffeeScript only need
# parens if they have 0 arguments.
hello_world() # -> Prints "Hello, world!" to the console.
echo = (argument) -> # The argument list goes inside the parens
# Like in Python, indentation defines blocks in CoffeeScript
argument # CS is expression-based, so the last statement of a function
# is also its return value.
echo "Hello!" # -> returns "Hello!"
CoffeeScript’s cleaner function syntax is one of its selling points for writing IF stories. Add the line:
canView: () -> false
To the ‘go_left’ situation, and watch what happens when you run the game. Your list of options should only show the other option – “Go right”.
Whenever Undum is building a list of choices from a situation’s choices
array, it consults each situation listed to see how it should appear. It calls their optionText
property to get what text it should display. And it calls their canView
method, to find if it should display that option at all.
canView
should return true
or false
. If it returns true
(Or any “truthy” value), then the situation is displayed as an option.
canView
, like most situation methods, is passed three arguments: The Character
object, the System
object, and the name of the current situation. In our previous example, we didn’t bother to define arguments for our canView
method because it didn’t use any – it just returns false
, always.
Character
and System
are two objects that are never created or accessed directly in your code; instead, Undum passes it as an argument to various methods you define. System
holds most of the methods we use to interact with Undum’s low-level API, and will be the subject of another tutorial.
Character
holds most of your game state – qualities (the subject of another tutorial), and the “sandbox”. The sandbox is a general-purpose area for storing game state; initially, it’s just an empty object. We can safely modify the sandbox however we like:
situation 'start',
before: (character) ->
character.sandbox.hasLamp = false
content: """
You are standing at the mouth of a deep, dark cavern. There is a
brass lamp here.
"""
choices: ['brass_lamp', 'enter_cave']
before
is another property of Raconteur situations; in this case, it’s a function that gets called before content
is output. It’s a good place to put any initialisation code or side-effects of entering a situation. Normally, we would set the initial values of sandbox
properties inside our undum.game.init
function – but for the sake of this example, it’s fine to put it in before
. The function gets passed our usual three arguments – Character
, System
, and the name of the previous situation; but since we are only using the first one, we only need to define the first one – JavaScript doesn’t check that a function is called with the right number of arguments, so instead it just discards the other two.
Here are the other situations for this second example:
situation 'brass_lamp',
before: (character) ->
character.sandbox.hasLamp = true
content: """
You pick up the brass lamp and light it.
"""
choices: ['enter_cave']
optionText: 'Pick up the lamp'
situation 'enter_cave',
content: """
You walk into the dark cave. There are two passages, to the right and
left; the right one glows with a strange shimmer.
"""
optionText: 'Enter the cave'
choices: ['go_left', 'go_right']
situation 'go_left',
content: """
The tunnel narrows dramatically as you enter it, forcing you to
squeeze in sideways between the slick limestone walls.
"""
optionText: 'Go left'
canView: (character) -> character.sandbox.hasLamp
situation 'go_right',
content: """
The tunnel opens up into a wide chamber, dominated by a bright
reflecting pool.
"""
optionText: 'Go right'
If you run the complete example, you’ll note that you can only get to the left passage if you previously picked up the lamp. “go_left” has a canView
method that returns the value of character.sandbox.hasLamp
, which is normally false
, but gets set to true
if you visit the “pick up the lamp” passage. This simple mechanic – referencing whether a previous story event happened to shut off or open up passages of the story – is the basis of what Dan Fabulich calls delayed branching.
If you’ve gotten this far, congratulations: You can now use Raconteur and Undum to write games with complex branching stories similar to ChoiceScript stories, where events earlier in the narrative can impact events later even if the branches in between were “merged”.
In fact, you can use sandbox
to track more complex things than true/false conditions such as whether the lamp was picked up; you can store any value in a sandbox property. Consider the example of a dating sim: You can use the sandbox to track the feelings of the various love interests towards the player character, to decide which interactions will be available later on. You’ve officially gone beyond the point of what a pure CYOA book can do.
Before we wrap up, a few notes:
canChoose
method; if that method returns false
, then the option will be visible on an option list, but greyed out, and the player won’t be able to click on it.after
method. As the name implies, that method is just like before
, but it gets called after content is printed.optionText
is an exception to a number of things in Raconteur: It’s not Markdown, and it can’t be a function. In fact, it’s not even html; the optionText
on your situations has to be just plain text. This is an underlying limitation of Undum.My friends and I have written a CYOA podcast. The preview episode is available for download here. The podcast is called Pick Your Path and the first episode will be released on May 1. We'd love to hear what you think about it.
A story set in the Bahamas, and I'm ready to party. Long after the last page, I'm still waiting to party.
The post An Island Affair by Monica Richardson appeared first on HOT SAUCE REVIEWS.