Occurrences (or daemons) in ScottKit

Last time we looked at how ScottKit games handle the player’s actions. But sometimes you need actions to happen independently of what the user does. If you’re in a frozen wilderness, maybe there’s ten percent chance each turn of freezing to death; or if there’s a thief here and you’re carrying a crown, he might steal it.

That’s what we’re going to look at this time. Here’s the map for today’s version of the game we’re working on:

Changes to the map

First, there are two new rooms since last time: a throne-room, which is where we’re going to deposit the treasure; and a crypt, where the key now starts, inconveniently guarded by a vampire.

Then there are two new items: the vampire, and a cross which will of course come in useful in dealing with him.

(We won’t bother listing the code for these room-and-item changes — if you’ve followed the earlier stages in this tutorial, you’ll already know how to set up rooms and items.)

Occurrences

Now we need to set up the new actions that happen by themselves. In ScottKit, we call these occurrences. (In some other systems, I believe they are called daemons.)

As with actions, a ScottKit file can define any number of occurrences. Each turn, before the user submits a command, the game runs down the list of defined occurrences and executes all those whose conditions are satisfied. (This is an important difference from actions, in which only the first matching action fires.)

An occurrence is introduced by the keyword occur, which may optionally be followed by a percentage indicating the chance of it happening. This is expressed as sequence of digits followed by a percentage sign (%).

Like an action, an occurrence may be followed by when and a list of conditions joined with and. The available conditions are exactly the same as those available for actions.

And also like actions, occurrences are followed by a sequence of action results — commands like get, goto, look, etc. Again, the available results are the same as those for actions.

Finally, and also like actions, occurrences can have a comment, which does not affect the behaviour of the action in any way but is written through to the compiled game file.

Putting it all together, typical occurrences look like this one (taken from Scott Adams’s own Adventureland):

occur 75% when carried FISH and !carried NET
	print "Fish have escaped back to the lake."
	put FISH lake
	comment "FISH ESCAPE"

Occurrences in the sample game

If we enter the presence of the vampire room while carrying the cross, he will shy away from it and we will be free to pick up the key. If we don’t have the cross, then he will look hungrily at us, and there’s a one-in-four chance that he will kill us outright. Finally, if we try to take the key while the vampire is threatening up (i.e. when we don’t have the cross), he won’t let us do it.

Here’s how that looks in code:

occur when here vampire and carried cross
	print "Vampire cowers away from the cross!"

occur when here vampire and !carried cross
	print "Vampire looks hungrily at me."

occur 25% when here vampire and !carried cross
	print "Vampire bites me!  I'm dead!"
	game_over
	comment "vampire can attack unless cross is carried"

action get key when here vampire and !carried cross
	print "I'm not going anywhere near that vampire!"

I hope all this looks obvious and intuitive.

The first and second occurrences here have no associated percentage, so they always fire when their conditions are met: in other words, when we’re with the vampire, he will always either cower away from the cross or look at us hungrily. The third occurrence has the same condition as the second, but also a 25% chance associated with it — so a quarter of the time that we see the second message, we will also be killed. (The sole action is there to prevent us from taking the key unless we’ve brought the cross with us: if its condition is not satisfied — e.g. because we have the cross — then the default GET action fires and we successfully take it.)

Note that the order of occurrences is important. If we swapped the second and third, so that the 25%-chance occurrence was evaluated first, then on the times when that one happened to fire, we would not see the “looks hungrily at me” message.

It’s rather rude game design to let the player walk blithely into a room that can punish him with instant death. To ameliorate that, we’ll add one more occurrence: when we’re in the room that leads to the vampire’s crypt, we’ll emit an occasional warning message:

occur 25% when at dungeon
	print "I smell something rotting to the north."

Putting it together

One thing we’ve not yet touched on is global settings that affect the game as a whole. We’ll look at these systematically another time, but let’s just toss a couple into the present version of the game.

Up till now, we’ve been using the default behaviour that the player begins in the first room to be defined. (This is a small exception to the earlier claim that the order of room definitions doesn’t matter.) But we can explicitly state which room we want to start in using start NAME.

And equally, we found that leaving treasures in the first room allowed us to score points for them. But typically, the treasury will be some other room. Again, we can designate a suitable room using treasury ROOM.

We’ll add both of these into the game file. And with that done, here’s the complete source code:

start dungeon
treasury throne

action score: score
action inventory: inventory
action look: look

room throne "gorgeously decorated throne room"
	exit south chamber

item sign "Sign says: leave treasure here, then say SCORE"

room chamber "square chamber"
	exit east dungeon
	exit north throne

item cross "Wooden cross"
	called "cross"

room dungeon "gloomy dungeon"
	exit west chamber
	exit north crypt

occur 25% when at dungeon
	print "I smell something rotting to the north."

item door "Locked door"

item key "Brass key"
	called "key"
	at crypt

item door2 "Open door leads south"
	nowhere

action open door when here door and !present key
	print "It's locked."

action open door when here door
	swap door door2
	print OK
	look

action go door when here door2
	goto cell
	look

room cell "dungeon cell"
	exit north dungeon

item coin "*Gold coin*"
	called "coin"

room crypt "damp, dismal crypt"
	exit south dungeon

item vampire "Vampire"

occur when here vampire and carried cross
	print "Vampire cowers away from the cross!"

occur when here vampire and !carried cross
	print "Vampire looks hungrily at me."

occur 25% when here vampire and !carried cross
	print "Vampire bites me!  I'm dead!"
	game_over
	comment "vampire can attack unless cross is carried"

action get key when here vampire and !carried cross
	print "I'm not going anywhere near that vampire!"

Now let’s take a look at how it plays.

There’s an additional complication this time, though: because of the random factor introduced by our new occurrences, we can’t tell whether any given excursion to the vampire’s crypt is going to kill us. We might use the same sequence of moves in two consecutive games only to find that it works the first time but not the second time.

We can fix this by supplying ScottKit with an explicit random seed, which tells it to use a reproducible sequence of random numbers. You supply this with the -s number command-line option: for example, -s 3456.

So here we go using random seed 2:

ringo:tutorial mike$ scottkit -s 2 -p t4.sck 
ScottKit, a Scott Adams game toolkit in Ruby.
(C) 2010-2017 Mike Taylor <mike@miketaylor.org.uk>
Distributed under the GNU GPL version 2 license,
Setting random seed 2

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Locked door

Tell me what to do ? n

I'm in a damp, dismal crypt
Obvious exits: South.
I can also see: Brass key, Vampire

Vampire looks hungrily at me.
Tell me what to do ? get key
I'm not going anywhere near that vampire!
Vampire looks hungrily at me.
Tell me what to do ? s

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Locked door

Tell me what to do ? w

I'm in a square chamber
Obvious exits: North, East.
I can also see: Wooden cross

Tell me what to do ? get cross
O.K.
Tell me what to do ? e

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Locked door

I smell something rotting to the north.
Tell me what to do ? n

I'm in a damp, dismal crypt
Obvious exits: South.
I can also see: Brass key, Vampire

Vampire cowers away from the cross!
Tell me what to do ? get key
O.K.
Vampire cowers away from the cross!
Tell me what to do ? s

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Locked door

Tell me what to do ? open door
OK

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Open door leads south

Tell me what to do ? go door

I'm in a dungeon cell
Obvious exits: North.
I can also see: *Gold coin*

Tell me what to do ? get coin
O.K.
Tell me what to do ? n

I'm in a gloomy dungeon
Obvious exits: North, West.
I can also see: Open door leads south

Tell me what to do ? w

I'm in a square chamber
Obvious exits: North, East.

Tell me what to do ? n

I'm in a gorgeously decorated throne room
Obvious exits: South.
I can also see: Sign says: leave treasure here, then say SCORE

Tell me what to do ? score
I've stored 0 treasures.  On a scale of 0 to 100, that rates 0.
Tell me what to do ? drop coin
O.K.
Tell me what to do ? score
I've stored 1 treasures.  On a scale of 0 to 100, that rates 100.
Well done.
The game is now over.
ringo:tutorial mike$ 

Next time: darkness and light!

Advertisements

3 responses to “Occurrences (or daemons) in ScottKit

  1. Pingback: Actions in ScottKit | The Reinvigorated Programmer

  2. Pingback: Darkness and light in ScottKit | The Reinvigorated Programmer

  3. Pingback: Boilerplate for ScottKit games: standard actions | The Reinvigorated Programmer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s