STYCHES documentation

An example game script walkthrough

We are going to build a game script now that has a few rooms connected by stairs and a lift and then introduce a puzzle for the player to solve. This is only a small part of a full game but should give you a good grounding in the way that Styches is used to define a piece of IF.
NOTE: You will notice that we quickly fall into saying ‘pick up the box’ or ‘switch on the torch’; of course nothing of the sort is happening – all that actually happens is some attributes and variables get set to various numbers and values. However, it is probably worth noting that this sort of thinking (manipulating objects and entering rooms etc) probably helps!
The game will be set in an old hotel; we are stuck inside and need to find the way out. None of this is particularly inspired, but is simply a vehicle for us to try out various links and commands.
The 'map' of the hotel only contains 4 rooms as follows:

Now let’s see how to turn that 'map' into a Styches script.
Firstly, we need to open our favourite text editor and enter the following:
#start:{=|$liftlocation|#Landing}{CALL|#Hallway}{=|$Location|#Hallway}
;
Remember that the paragraph named '#start' is the first paragraph to be interpreted when a game starts. The 'start' paragraph we have defined above has 3 commands and therefore does 3 things.
Firstly, we create a variable (variables all start with '$') which we have named '$liftlocation'. We will use this variable to track whether the lift is currently in the hallway or the landing. The actual value of the variable is the text '#Landing' which we will find very useful later on in the script, as we shall see.
Secondly, we use the CALL command to read and interpret the paragraph named '#Hallway'. This will (we haven't written that paragraph yet, but we will in a second, so please believe us) describe the hallway to the player as well as interpret any links and commands contained within that paragraph.
Thirdly, we set the special variable '$Location' to be '#Hallway'. Styches uses this special location variable internally to track where the player is on our 'map' as well as to track the location of objects and so on. By setting it ourselves to a given value, we are effectively teleporting the play to that location. Setting the $Location value doesn't cause Styches to process the location paragraph, so that is why we called it explicitly in the previous command.
Since we have just referred to it, let’s make a start on the #Hallway paragraph:
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap.
;
So far, so good; since there are no commands or links in the #Hallway paragraph yet, all the text will be printed out for the player to see.
Now, let’s add a link to the paragraph describing the landing:
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. A [rickety staircase leads upwards,#Landing] into the gloom.
;
So now we have the text followed by a link. If the player selects the link, then Styches will read the named paragraph and interpret it, changing the displayed page for the player. In this case, the highlighted text will be 'rickety staircase leads upwards' and if the player selects it, the paragraph called '#Landing' will be processed.
Since we've just spoken about it, why don't we write that paragraph right now; there shouldn't be any surprises in this paragraph.
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway].
;

If we saved our game script now and tried it, we would actually have something that was consistent and worked. We would start in the hallway and we could go up and down the stairs to our hearts content. However, I think you can see this isn't exactly riveting stuff, so let continue and try to make things a bit more interesting for the player.
Let’s go back and add some more commands to the end of #Hallway and #Landing paragraphs so they now read:
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. A [rickety staircase leads upwards,#Landing] into the gloom. {CALL|CheckLift}
;
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway]. {CALL|CheckLift}
;
We've added a call to another paragraph. Styches will read that paragraph and process it, adding any output text to the page as it goes. Let's write that paragraph now; this is where things start to get interesting...
CheckLift:{if|$liftlocation EQUALS $Location|{CALL|LiftHere}|{CALL|LiftNotHere}}
;
First thing to notice is that the paragraph name does not begin with a '#'. That is because the player can never 'be' at this paragraph and objects can't exist here. Secondly, the paragraph contains a single 'if' command. This 'if' command checks to see if the contents of the variable called $liftlocation and the contents of the internal variable '$Location' are the same. You will recall that we created the variable $liftlocation in our #start paragraph are set its content to '#Landing'.
Also not that we use 'EQUAL' and not '=' for our comparison Therefore, if the players location was the landing, the $Location variable would contain '#Landing' and therefore this test would be true. If the player location was the hallway (or anywhere else for that matter), then this test would be false. Let's define that paragraph now.
LiftNotHere:Some closed doors, obviously for a lift, are here and next to them is a [small button,CallLift].
;

What we effectively saying here is if we process this paragraph (because the variable '$liftlocation' doesn't equal our current location) then output to the page that there are closed doors and a button. The button is a link which when selected by the player will process a paragraph called 'CallLift'.
For completeness, let’s define the 'LiftHere' paragraph as well:
LiftHere:Open doors lead [into a small lift,#In_the_Lift].
;

Here we are describing what the player reads if the $liftlocation and $Location variables are the same, which is that the player can elect to enter the lift by selecting the 'into the lift' link. If the player does select that link, then the current location will change to '#In_the_Lift', so we need a paragraph for that too.
#In_the_Lift:The lift is a small rusty metal box with peeling paint and a decided lack of maintenance. On the wall is a single button and above that is what looks like an alarm panel. You can [press the button,PressLiftButton] or [exit the lift,ExitLift].{FINISH}
;

Just 2 links which will process some new paragraphs if selected by the player. However, you might remember that much earlier, we said that Styches looks for links that will move to a new location (by looking at whether the link starts with a ‘#’? Well since neither of these links do that, Styches would add a ‘(or return…)’ link unless we tell it not to; the {FINISH} command does just that. Here is the first of the links:
PressLiftButton:{CALL|LiftMovement}
;
LiftMovement:Off in the distance you can hear machinery wheeze into life. The doors slide slowly shut and then you feel the lift rattle {if|$liftlocation EQUALS #Hallway|upwards{=|$liftlocation|#Landing}|downwards{=|$liftlocation|#Hallway}}. You hear a distant 'ping' and finally the doors creak open.{CALL|#In_the_Lift}
;

You will notice here we have nested some commands. We check to see if the lift location is the hallway and if it is, we print out 'upwards' AND we then execute the command to set the lift location to the landing. If the lift location was NOT the hallway, then we would output 'downwards' and then set the lift location variable to #Hallway. From the logic we have included in the script so far, you can deduce that the variable $liftlocation can only have 2 values; it is either '#Hallway# or '#Landing'. Finally start a new line (using the backslash) and we re-describe the current location so that the player gets the description of the lift again, including the 'exit' and 'press the button' links. If we hadn't included this, then Styches would have added a 'Continue...' link and if the player had selected that, then the current location would be processed. It amounts to the same thing and is really a question of style that is up to you as an author regarding which you prefer.
ExitLift:You gratefully step out of what you firmly believe to be a deathtrap.{=|$Location|$liftlocation}{CALL|$Location}
;

When the player selects the 'exit the lift' link in the '#In_the_Lift' paragraph, we output 'You gratefully.....' and then we set the players current location to be the same as the variable $liftlocation. You will see that above we change the variable $liftlocation if the player presses the button inside the lift; therefore when the player exits the lift, we can set their location to be wherever the lift is.
We still have one paragraph which we haven't yet defined; that was referred to in the 'LiftNotHere' paragraph. This paragaph should make the lift 'appear':
CallLift:{=|$liftlocation|$Location}Off in the distance some machinery whirrs slowly into life. There is a worrying amount of groaning and creaking but after a while and with a pathetic 'ping' the doors slowly lurch open. {CALL|$Location}
;

We change the value of $liftlocation to be the same as the players current location. We then print some text out AND we describe the current location. Since the $liftlocation is now the same as our location, the description will be different; if you re-read the paragraph for 'CheckLift' you will see that the $liftlocation and $Location variables are the same and so the test output on the page now reflects this. Try it and see!
The whole script now looks like this:
#start:{=|$liftlocation|#Landing}{CALL|#Hallway}{=|$Location|#Hallway}
;
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. A [rickety staircase leads upwards,#Landing] into the gloom. {CALL|CheckLift}
;
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway]. {CALL|CheckLift}
;
#In_the_Lift:The lift is a small rusty metal box with peeling paint and a decided lack of maintenance. On the wall is a single button and above that is what looks like an alarm panel. You can [press the button,PressLiftButton] or [exit the lift,ExitLift].{FINISH}
;
CheckLift:{if|$liftlocation EQUALS $Location|{CALL|LiftHere}|{CALL|LiftNotHere}}
;
LiftNotHere:Some closed doors, obviously for a lift, are here and next to them is a [small button,CallLift].
;
LiftHere:Open doors lead [into a small lift,#In_the_Lift].
;
PressLiftButton:{CALL|LiftMovement}
;
LiftMovement:Off in the distance you can hear machinery wheeze into life. The doors slide slowly shut and then you feel the lift rattle {if|$liftlocation EQUALS #Hallway|upwards{=|$liftlocation|#Landing}|downwards{=|$liftlocation|#Hallway}}. You hear a distant 'ping' and finally the doors creak open.{CALL|#In_the_Lift}
;
ExitLift:You gratefully step out of what you firmly believe to be a deathtrap.{=|$Location|$liftlocation}{CALL|$Location}
;
CallLift:{=|$liftlocation|$Location}Off in the distance some machinery whirrs slowly into life. There is a worrying amount of groaning and creaking but after a while and with a pathetic 'ping' the doors slowly lurch open. {CALL|$Location}
;

Now, let’s spice things up a bit by adding an object to the game. To create an object we use the CREATE command. We'll put this inside the '#start' paragraph so that the object is created right at the start of the game.
#start:{=|$liftlocation|#Landing}{CREATE|box|name:large wooden crate|location:#Hallway}{CALL|#Hallway}{=|$Location|#Hallway}
;

Notice that we put the CREATE command before the CALL; if we had reversed the order, the hallway description would have been printed on the page but the box wouldn't have been listed since it didn't exist until after we printed the description. Refer to the documentation on the command 'CREATE' for full details of all of the various attributes that an object can take. For the moment we have simply created an object and placed it in the location '#Hallway'. If you run the script now, you will see that after the description of the hallway, the box is listed. Try it and see.
If you try to interact with the box however, you'll discover that it simply outputs 'take' and nothing happens. That is because every game script that uses objects must have a few default paragraphs that define the default actions for taking, examining, using and dropping objects. Let’s define those now:
take:You pick up the {PRINT|$this}.{TAKE|$this}
;

The variable '$this' is set to whichever object the player is currently interacting with; this allows us to write one 'take' paragraph that will be the default for all objects. The same is true for 'examine' and 'drop'. The default action for an object can be overridden for each object if required. This is covered in more detail in the section on Objects. Create the paragraphs for 'drop' and 'examine' now:
drop:{DROP|$this}You put the {PRINT|$this} down.
;
use:There doesn't appear to be a use for the {PRINT|$this} here.
;
examine:You see nothing special about the {PRINT|$this}.
;

These are our defaults; if we don't define any special paragraphs for taking, examining or dropping an object, then these paragraphs will be used. If you run the game script now, you will see that we can interact, albeit fairly trivially, with the box.
To prove this point and show that the defaults are used for all objects unless overridden, let’s create a couple more objects now and distribute them round our map:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift}
{CREATE|torch|location:#Landing}

{CALL|#Hallway}{=|$Location|#Hallway}
;

Firstly, note that we’ve started to spread the #start paragraph across several lines in our script, using the single backslash at the end of each line to show that the next line is a continuation of this one. We did this to make the script slightly more readable (OK – we understand that the scripts are exactly dead easy to read, but this helps a bit)
Things to note are that we created a 'coin1' object whose name is 'gold coin'; we'll see why this is in a moment.
We created an object called 'torch'; since we didn't give it an explicit 'name' attribute, its name defaults to the same as the object (in this case, 'torch').
If you run the game script now, you will see that there are now 3 objects which you can take and drop anywhere you like around the very small map. Also notice that if you drop something in the lift, then if will 'move' as the lift moves - OK; we all know that nothing of the sort happens but it looks like that is what is happening to the player :)
What is the use of a torch if we can't turn it on and off? Let’s see how we can achieve that in script terms. Firstly, let's change the CREATE statement for the torch to refer to paragraphs that get run when the torch is 'used'. Please refer to the documentation on creating objects for a complete list of attributes and their use.
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit}
{CALL|#Hallway}{=|$Location|#Hallway}
;

Of course we need to write those paragraphs otherwise nothing will happen if the player selects them.
switchontorch:You flick the switch and the torch flickers into life.{USE|torch}
;
switchofftorch:You flick the switch and the torch goes dark.{CEASE|torch}
;


Now, we could just leave it like that, but then what's the use of a working torch if we can't use it? So, let's add a fourth room to the map which comes off the landing:
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway] and a [doorway leads off,#Maintenance_Room]. {CALL|CheckLift}
;
#Maintenance_Room:{IF|torch ISVISIBLEANDBEINGUSED||It is very dark in here. You can make out the [doorway,#Landing] back out to the landing but that is all.{STOP}}The maintenance room has been ransacked before and although litter and debris are liberally strewn about, there is little of note. A [door leads back out to the landing,#Landing].
;

The first change is to the #Landing paragraph so that we have a new link to another location called 'Maintenance Room'.
The maintenance room paragraph is a bit more complex, so let’s see what is happening:
The '{IF|xxxx VISIBLEUSING...' test is true if we can see the object AND it is being used. We use 'VISIBLEUSING' since that checks to see if the object is either possessed by the player OR is in the current location. Therefore if the player enters the maintenance room and drops the torch there, this test will still be true. If we had used 'USING' as the test, then when the player drops the torch (in this instance), then the test would have returned false, which is not the logic we want. Please play around with this to see how the logic would change.
The second thing to notice about this test is that if the result of 'VISIBLEUSING' is true, we don't do anything. We only do something if the test is false; if you are used to programming then this is equivalent to saying 'if not true....'. In our case, if the torch isn't on and either possessed by the player or in the current location, we are going to print out 'It's dark in here....'. The STOP command tells Styches to cancel any further processing or the paragraph which includes printing the list of objects in a location. If we hadn't included the STOP, then the output would have been:
"It is very dark in here. You can make out the doorway back out to the landing but that is all. The maintenance room has been ransacked before and although litter and debris are liberally strewn about, there is little to see. A door leads back out to the landing.
With the STOP in place, we only get one description (It is very dark...) or the other (The maintenance room has...)
Here is the complete script we have developed to this point:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit}
{CALL|#Hallway}{=|$Location|#Hallway}
;
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. A [rickety staircase leads upwards,#Landing] into the gloom.{CALL|CheckLift}
;
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway] and a [doorway leads off,#Maintenance_Room]. {CALL|CheckLift}
;
#In_the_Lift:The lift is a small rusty metal box with peeling paint and a decided lack of maintenance. On the wall is a single button and above that is what looks like an alarm panel. You can [press the button,PressLiftButton] or [exit the lift,ExitLift].{FINISH}
;
#Maintenance_Room:{IF|torch ISVISIBLEANDBEINGUSED||It is very dark in here. You can make out the [doorway,#Landing] back out to the landing but that is all.{STOP}}The maintenance room has been ransacked before and although litter and debris are liberally strewn about, there is little of note. A [door leads back out to the landing,#Landing].
;
#Finished:Well done - you have escaped!{COMPLETE}{STOP}
;
#Hallway.#Landing:{IF|box ISPOSSESSED|Oh no... As you struggle up the stairs with the box, it slips from your grasp and slides back down to the bottom.<br />{DROP|box}}
;
CheckLift:{if|$liftlocation EQUALS $Location|{CALL|LiftHere}|{CALL|LiftNotHere}}
;
LiftNotHere:Some closed doors, obviously for a lift, are here and next to them is a [small button,CallLift].
;
LiftHere:Open doors lead [into a small lift,#In_the_Lift].
;
PressLiftButton:{CALL|LiftMovement}
;
LiftMovement:Off in the distance you can hear machinery wheeze into life. The doors slide slowly shut and then you feel the lift rattle {if|$liftlocation EQUALS #Hallway|upwards{=|$liftlocation|#Landing}|downwards{=|$liftlocation|#Hallway}}. You hear a distant 'ping' and finally the doors creak open.{CALL|#In_the_Lift}
;
ExitLift:You gratefully step out of what you firmly believe to be a deathtrap.{=|$Location|$liftlocation}{CALL|$Location}
;
CallLift:{=|$liftlocation|$Location}Off in the distance some machinery whirrs slowly into life. There is a worry amount of groaning and creaking but after a while and with a pathetic 'ping' the doors slowly lurch open. {CALL|$Location}
;
take:You pick up the {PRINT|$this}.{TAKE|$this}
;
drop:{DROP|$this}You put the {PRINT|$this} down.
;
use:There doesn't appear to be a use for the {PRINT|$this} here.
;
examine:You see nothing special about the {PRINT|$this}.
;
switchontorch:You flick the switch and the torch flickers into life.{USE|torch}
;
switchofftorch:You flick the switch and the torch goes dark.{CEASE|torch}
;

Try running the script now; you should see that turning the torch on and off works and that you get 2 different outputs when entering the maintenance room. Also, try turning the torch on and off while in the maintenance room....; did it act the way you thought it might?
Now let’s add some form of battery life to the torch; we will create a variable to track the battery and while the torch is on, we can decrease the life. Once the variable reaches 0, we will turn the torch off. Therefore, when we start the game, let’s create a special attribute for our torch called 'BatteryLife' and give it an initial value of 25:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|BatteryLife:25}
;

By default, if you drop something that is being used, it is 'ceased' (i.e. stop being used); we can override that behavior by setting the 'KEEPUSING' attribute against the object. In our case, the torch would still be 'on' if we dropped it, so we'll change the definition of the torch to have that attribute:
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|KEEPUSING:Y|BatteryLife:25}
;

Earlier, we mentioned that there are 2 paragraphs that are run every time a paragraph is processed. They are called 'alwaysbefore' and 'alwaysafter'. 'alwaysbefore' is run before the main paragraph and 'alwaysafter'...well...you get the picture. In this case we are going to implement the 'alwaysafter' paragraph and have it call another paragrpah if the torch is being used:
alwaysafter:{IF|torch ISBEINGUSED|{CALL|torchusage}}
;
torchusage:{-|torch.BatteryLife|1}{IF|torch.BatteryLife <= 0|{CEASE|torch}}
;

Here we are saying, if the torch is being used (i.e. switched on), then subtract 1 from the variable. Then, if the variable has reached 0, set the torch to 'not used' by calling the CEASE command. This is all well and good, but what if the player then goes and 'uses' the torch again; it will turn on again. Let’s stop that happening by amending the 'switchontorch' paragraph:
switchontorch:{IF|$batterylife > 0|You flick the switch and the torch flickers into life.{USE:torch}|You flick the switch several times, but the torch refuses to come on.}
;

We've simply added a test to that paragraph that checks to see if the variable 'batterylife' is more than 0; if so, turn on the torch, otherwise, output some text showing that the torch won't work.
It seems a bit unfair on the player to have the torch run out without any warning, so let’s add some logic to the 'alwaysafter' paragraph that gives them a hint.
torchusage:{-|torch.BatteryLife|1}{IF|torch.BatteryLife <= 0|{CEASE|torch}}{IF|torch.BatteryLife = 0|<>The torch goes out.|{IF|torch.BatteryLife < 5|The torch looks significantly dimmer and is about to expire.|{IF|torch.BatteryLife < 12|The torch is much dimmer.}}}
;

Now, once the variable reaches 12, we start telling the player and when it reaches 5 the message gets more pointed.
Remember just a bit ago, we set the torch up so that if we dropped it, it stayed 'on'? What happens if we drop the torch and then go to a different location? You could try it by testing the script now. You should find that turning the torch on, dropping it and then going to a different location, the 'battery low' messages started being printed even though the torch was nowhere in sight? Let’s address that:
torchusage:{-|torch.BatteryLife|1}{IF|torch.BatteryLife <= 0|{CEASE|torch}}{IF|torch ISVISIBLE|{IF|torch.BatteryLife = 0|<br>The torch goes out.|{IF|torch.BatteryLife < 5|<BR>The torch looks significantly dimmer and is about to expire.|{IF|torch.BatteryLife < 12|<br>The torch is much dimmer.}}}}
;

Now this is all very confusing to look at: perhaps an easier view would be the following pseudo-code:
If USING torch then
    subtract 1 from $batterylife
    if batterylife = 0 then
        stop using torch
    if the torch is visible then
        if batterylife = 0
            print 'the torch has gone out.'
        else
            if batterylife <= 5 then
                print 'the torch is very dim and about to go out.'
            else
                if batteylife <= 12 then
                    print 'The torch is getting dimmer all the time.'

This sort of logic isn't easy to follow, I admit, but you can always split it up into separate paragraphs if that makes life easier. Please remember that this is a demonstration of the features of the script engine and you don't have to make things as complex in your own game, until you feel comfortable with it.
We are going to step things up now, since if you've made it this far, then most of the rest of the script only needs explanation when we introduce new commands and concepts. In essence wat we are going to do now is expand the description of the maintenance room to include a small key which can't be removed, change the crate so that is has a padlock (which the key can unlock).
OK; now we can unlock the box, let’s put something inside it. Styches doesn't really have a concept of 'inside' (or any other relation between objects), BUT we can list objects in any location we like (which can include objects) using the LIST command and we can set an objects location to anything we like. Therefore, let’s put a gold coin inside the box:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift|PLURAL:gold coins}
{CREATE|coin2|name:gold coin|location:box|PLURAL:gold coins}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|KEEPUSING:Y|BatteryLife:25}
{CALL|#Hallway}{=|$Location|#Hallway}
;

You will notice that the new coin has exactly the same name as the initial one we defined; in this case, whenever those items are in the same location (either a location or the special location 'PLAYER') then the 2 are added together to become a single item with a 'count' of 2. If we defined 4 coins all the same, once they were all picked up then there would be a single 'gold coin' with a count of 4. This is both a blessing and a curse; you can litter the game with the same item (use the same 'name' attribute to make items the same) which can be collected and their location will be made the same and the count adjusted as they are collected. However, when it comes to 'spending' or 'using' them, you don't know which object to manipulate. Here is an example:
coin1: location:room, count:1
coin2: location:PLAYER, count:1
If we pick up (TAKE) coin1, then coin1 will be destroyed and the list of objects will be:
coin2:location:PLAYER, count:2
If we drop (DROP) coin2, then coin2 will be destroyed and the list of objects will be:
coin1:location:room, count:2
If we subsequently take coin2, the list wil be:
coin1:location:PLAYER, count:2The way round this is to have a 'special' object that is in the player’s possession at the start of the game, BUT with a count of 0 (zero). This won't be listed in the inventory until the count > 0. When things are dropped, the object will continue to exist, but with a count of 0 again. Thus your game logic can check against that object being carried and so on. Let’s introduce that concept to our game script:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway}
{CREATE|coin1|name:gold coin|location:#In_the_Lift|PLURAL:gold coins}
{CREATE|coin2|name:gold coin|location:box|PLURAL:gold coins}
{CREATE|coinscarried|name:gold coin|location:PLAYER|COUNT:0|PLURAL:gold coins}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|KEEPUSING:Y|BatteryLife:25}
{CALL|#Hallway}{=|$Location|#Hallway}
;

To check if there is anything at a location (in this case, inside the box), we can use the 'dotted notation' for an object AND we can use the wildcard object '*' to match any object. This test will be true if the location of any object is 'box':

{IF|*.count.LOCATED.box > 0|.......}


We can use this functionality to see if there is anything 'inside' the box when we unlock it. What? You mean we haven't talked about locking and unlocking the box?? Well, our mistake; let's sort that out right now.
To track the state of the box, we can use an attribute that we create just for this object. Lets call it 'STATE'. We’ll use STATE as a numerical value that can be used to keep a track of the status of an object and what different values mean is entirely up to you. We are going to keep it simple here and have 2 states for the box: 0 means the box is locked and 1 means it is unlocked. When the game starts, we want the box to be locked, so we change the CREATE command for the box to include the new attribute and set its initial value to 0:
{CREATE|box|name:large wooden crate|location:#Hallway|state:0}

Earlier, we created a set of 'default' paragraphs for take, drop, examine etc. We can override those on a per-object basis is we want to, so let's do that for the box now so that if it is 'examined', we run a specific paragraph:
{CREATE|box|name:large wooden crate|location:#Hallway|state:0|EXAMINEPARAGRAPH:examinebox}

Of course, we need to define that paragraph:
examinebox:A closer look at the crate shows it is {CASE|box.state|locked with a large brass padlock.{IF|$Location EQUALS #Maintenance_Room| You can [try the key in the padlock,unlockbox].}|closed. You can [open it,openbox] if you wish{IF|$Location EQUALS #Maintenance_Room| or you can [lock the padlock,lockbox]}.|open{IF|*.count.NUMBERLOCATED.box > 0| and {LIST|box} inside.|, but empty.} You can [close the crate,closebox] if you wish.}
;
Not much surprising here; if the create is locked, just say 'locked' otherwise say it is unlocked followed by, if anything has a location of 'box', a list of objects whose location is 'box' otherwise say it is empty.
Obviously what is missing now is a way of unlocking the crate (or in script terms, changing the state of the box from 0 to 1). Therefore we will add a brass key to the description of the maintenance room and to make things a bit trickier for the player, let’s not have it as an object that can be taken etc but just as a paragraph that looks to see if the player has the crate and if they do, allow them to unlock it if it isn't already unlocked. Have a think about what that might look like before looking at how we did it below:
#Maintenance_Room:{IF|torch ISVISIBLEANDBEINGUSED||It is very dark in here. You can make out the [doorway,#Landing] back out to the landing but that is all.{STOP}}The maintenance room has been ransacked before and although litter and debris are liberally strewn about, there is little of note except for a [brass key,examinekey] which is sitting on an old workbench. A [door leads back out to the landing,#Landing].
;
examinebox:A closer look at the crate shows it is {CASE|box.state|locked with a large brass padlock.{IF|$Location EQUALS #Maintenance_Room| You can [try the key in the padlock,unlockbox].}|closed. You can [open it,openbox] if you wish{IF|$Location EQUALS #Maintenance_Room| or you can [lock the padlock,lockbox]}.|open{IF|*.count.NUMBERLOCATED.box > 0| and {LIST|box} inside.|, but empty.} You can [close the crate,closebox] if you wish.}
;
unlockbox:The key is a perfect fit and the lock springs open.{=|box.state|1}
;
lockbox:You refasten the padlock and lock it with the key.{=|box.state|0}
;
openbox:You lift the lid of the crate{IF|*.count.NUMBERLOCATED.box > 0| and you see {LIST|box} inside.|, but can see that inside it is empty.}{=|box.state|2}
;
closebox:You gently lower the lid of the crate.{=|box.state|1}
;
examinekey:The brass key is attached to a length of chain which in turn is secured to the wall. You quickly realise that it is firmly secured and can't be removed from the room. {IF|box ISPOSSESSED|It looks like this is an exact match for the padlock on he crate.{CASE|box.state| You can [try it in the padlock,unlockbox]| You can [try it in the padlock,lockbox]|}.|You place it back on the workbench.}
;
How did you do? Probably, you came up with a similar idea, but if not, try your idea out and see if you get the same result. There are many ways to achieve the same result in Styches and none of them is right or wrong; it's just about what makes sense to you as the author.
Just a few changes ago, we made the paragraph that gets processed when the player examines the box a 'special' one. Now we can unlock the box, we can try out that functionality. Have a go at it. Did you find that you can only open the crate if you are carrying it AND have the torch AND the torch is switched on AND you are in the maintenance room? Once you've done that, what happens when you examine the crate? You should find that now you can take the coin that is inside the box. Do that and then examine the crate again; does the description change to show the crate is empty? It should....!
Now we are going to throw in a complete curve ball; we want to limit the number of things that the player can carry, just to make life a bit annoying for them AND we are going to limit the weight that the lift can carry. We could just count the number of things the player has in their inventory and when it reaches a limit, tell them that they can't carry any more. However, that's not terribly realistic (tongue well and truly in cheek), so instead we want to give each object a unique weight and use that as the basis; thus we can have some objects that are heavier than others etc. To achieve this, we are going to give every object in the game an attribute that we are going to invent. We shall call this attribute WEIGHT and use it to (drum roll please...) represent the weight of each object. We can then use this in our game script to test and therefore achieve our desired outcome. Firstly, let's just give everything a weight by amending our CREATE commands in the #start paragraph:
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway|state:0|EXAMINEPARAGRAPH:examinebox|WEIGHT:8}
{CREATE|coin1|name:gold coin|location:#In_the_Lift|PLURAL:gold coins|WEIGHT:2}
{CREATE|coin2|name:gold coin|location:box|PLURAL:gold coins|WEIGHT:2}
{CREATE|coinscarried|name:gold coin|location:PLAYER|COUNT:0|PLURAL:gold coins|WEIGHT:2}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|KEEPUSING:Y|BatteryLife:25|WEIGHT:5}
{CALL|#Hallway}{=|$Location|#Hallway}
;

As per normal, this is no use unless we actually use the weight to drive out game logic. Remember when we pick things up, the 'take' paragraph is always interpreted (we have no special cases in the game, although we could: see the documentation of CREATE). Therefore, if we changed this paragraph to check if the total weight of things we want to carry is less than our maximum carrying capacity. Here is our new 'take' paragraph:
take:{=|$temp|*.WEIGHT.SUMPOSSESSED}{+|$temp|$this.WEIGHT}{IF|$temp <= 10|You pick up the {PRINT|$this}.{TAKE|$this}|Try though you might, you just can't carry the {PRINT|$this} as well.}
;

*.WEIGHT.SUMPOSSESSED gives the value of the weight attribute of all the objects that currently have a location of PLAYER. Therefore all we are doing here is setting a temporary variable to the value of everything the player is carrying, adding on the weight of what they are trying to pick up and then testing to see if the combined weight is less than 10. If it is, we do what we always did when the player takes an object, otherwise we print out a message saying that the player would be carrying too much. Make sense? If you try the script out now, you should find that the crate is so heavy that you can't pick it and the torch up (their combined weight is 13, which is not less than 10) and so on.
Let’s change the lift logic slightly now so that if the weight of the objects in the lift when the player presses the button is greater or equal to 8, it won't work. Here is our changed paragraph:
PressLiftButton:{IF|*.WEIGHT.SUMVISIBLE < 8|{CALL|LiftMovement}|{CALL|LiftTooHeavy}}
;
Remember, *.WEIGHT.SUMVISIBLE will return the total weight of all the objects that the player is carrying AND the objects that are in the ‘room’; in this case, the lift.
And let’s describe what the player sees if they try to move the lift while in it and it is too heavy:
LiftTooHeavy:Off in the distance you can hear machinery wheeze into life. This is closely followed by an assortment of twangs, pings, thwaps and the horrid sound of mechanical parts taking too much strain. This is followed by a terrible buzzing noise and the alarm panel flashes a feeble red notice. Closer examination reveals (beneath the grime) a label that pronounces 'Maximum Weight Exceeded'. Finally the panel stops flashing and the annoying buzzing stops.
;
To force the player to work out the box-in-the-lift puzzle (it's only a very minor puzzle, but hey-ho), let's quickly add a new paragraph that stops the player carrying the box up the stairs:
#Hallway.#Landing:{IF|box ISPOSSESSED|Oh no... As you struggle up the stairs with the box, it slips from your grasp and slides back down to the bottom.<br />{DROP|box}}
;

This is a 'transitional' paragraph that is run when moving between locations; the location you are moving from is given first (#Hallway in this case} and the destination location is given second. In this instance, #Landing. Thus, when the player tries to move from the hallway to the landing, if they are carrying the box, we print out a message and then drop the box. When this paragraph is run, the current location is still the 'from' location, so if (for instance) we drop something, it will end up at the original location and not the destination.
We are nearly finished now (phew, do I hear you say??); we have a script that handles object weight, has a lift that only works when the weight in it is less than a certain amount, have a working torch with battery life, have a locked crate and have a dark room. What we don't have is a way of 'winning' the game. Right at the start we said that the goal of the game was to escape from the hotel. Given that we have 2 gold coins in the game and one is hidden inside the box, we can use that as our trigger to allow the player to win. (OK; I admit I knew that all along when we introduced the coins etc, but didn't want to confuse things any more than they are already!). If we put a door in the hallway along with a coin slot then we can code some logic in the script that lets the player put coins into the slot in order to 'win'. Here is the start of that process:
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. At one end of the hall is an impressive [front door,examinefrontdoor] and placed just next to it on the wall is a [small metal plate,examineplate] with a slot cut into it. A [rickety staircase leads upwards,#Landing] into the gloom. {CALL|CheckLift}
;

You can see reference to 2 new paragraphs here:'examinefrontdoor' and 'examineplate'. Let’s define them now:
examinefrontdoor:The front door is ornately carved and made from some heavy and dense hard wood. One thing you can be certain of is that it is most definitely locked shut.
;
examineplate:The slot looks just the right size to feed coins into. Peering really closely you can read in tiny letters 'Exit Toll: 2 gold coins'. There is also a coin reject button but pressing this has no effect. {IF|carriedgold ISPOSSESSED|Do you want to [feed coins into the slot,feedcoins]?}
;

And now we need a 'feedcoins' paragraph: remember we can only get to the 'feedcoins' paragraph is the player has at least 1 coin, so they either have 1 or 2:
feedcoins:{IF|carriedgold.count.SUMPOSSESSED = 2|As you feed the second coin into the slot, there is a distinct 'clunk' and the front door swings gently open.\You stagger out into the sunshine, free at last.\{=|$Location|#Finish}{CALL|#Finish}|You put the coin in the slot and hear it rattle down inside some mechanism or another. You wait a while, but nothing seems to happen so eventually you press the 'reject' button and retrieve your coin.}
;
#Finish:{COMPLETE}Congratulations. You have escaped from the hotel.
;

Hopefully, by now you can see what the script is doing; if the player has 2 coins, then describe the scene and then move the player to a location called '#Finish'. This location has the special command COMPLETE which stops the player looking at their inventory or saving the game. It also stops the 'Continue...' link being added to the page. We could, of course, add a lot of extra text here and we could also offer to restart the game, but I'm guessing that if you've stuck it out this far, you can work out how to do that now.
So, that's it - the whole script finished and ready to go. Here is the final version in all its glory:


alwaysafter:{IF|torch ISBEINGUSED|{CALL|torchusage}}
;
alwaysbefore:{IF|$Location EQUALS #Finished|{STOP}}
;
//
#start:{=|$liftlocation|#Landing}
{CREATE|box|name:large wooden crate|location:#Hallway|state:0|EXAMINEPARAGRAPH:examinebox|WEIGHT:8}
{CREATE|coin1|name:gold coin|location:#In_the_Lift|PLURAL:gold coins|WEIGHT:2}
{CREATE|coin2|name:gold coin|location:box|PLURAL:gold coins|WEIGHT:2}
{CREATE|coinscarried|name:gold coin|location:PLAYER|COUNT:0|PLURAL:gold coins|WEIGHT:2}
{CREATE|torch|location:#Landing|USEPARAGRAPH:switchontorch|USELABEL:Switch on|CEASEPARAGRAPH:switchofftorch|CEASELABEL:Switch off|USEVERB:lit|KEEPUSING:Y|BatteryLife:25|WEIGHT:5}
{CALL|#Hallway}{=|$Location|#Hallway}
;
#Hallway:You are standing in a dusty and dowdy entrance hall. Cobwebs adorn most surfaces and have acted as a very efficient dust trap. At one end of the hall is an impressive [front door,examinefrontdoor] and placed just next to it on the wall is a [small metal plate,examineplate] with a slot cut into it. A [rickety staircase leads upwards,#Landing] into the gloom. {CALL|CheckLift}
;
#Landing:The small landing reeks of former glory, now well faded into the past. Some stairs [lead downwards,#Hallway] and a [doorway leads off,#Maintenance_Room]. {CALL|CheckLift}
;
#In_the_Lift:The lift is a small rusty metal box with peeling paint and a decided lack of maintenance. On the wall is a single button and above that is what looks like an alarm panel. You can [press the button,PressLiftButton] or [exit the lift,ExitLift].{FINISH}
;
#Maintenance_Room:{IF|torch ISVISIBLEANDBEINGUSED||It is very dark in here. You can make out the [doorway,#Landing] back out to the landing but that is all.{STOP}}The maintenance room has been ransacked before and although litter and debris are liberally strewn about, there is little of note except for a [brass key,examinekey] which is sitting on an old workbench. A [door leads back out to the landing,#Landing].
;
#Finished:Well done - you have escaped!{COMPLETE}{STOP}
;
//
#Hallway.#Landing:{IF|box ISPOSSESSED|Oh no... As you struggle up the stairs with the box, it slips from your grasp and slides back down to the bottom.<br />{DROP|box}}
;
//
CheckLift:{if|$liftlocation EQUALS $Location|{CALL|LiftHere}|{CALL|LiftNotHere}}
;
LiftNotHere:Some closed doors, obviously for a lift, are here and next to them is a [small button,CallLift].
;
LiftHere:Open doors lead [into a small lift,#In_the_Lift].
;
PressLiftButton:{IF|*.WEIGHT.SUMVISIBLE < 8|{CALL|LiftMovement}|{CALL|LiftTooHeavy}}
;
LiftMovement:Off in the distance you can hear machinery wheeze into life. The doors slide slowly shut and then you feel the lift rattle {if|$liftlocation EQUALS #Hallway|upwards{=|$liftlocation|#Landing}|downwards{=|$liftlocation|#Hallway}}. You hear a distant 'ping' and finally the doors creak open.{CALL|#In_the_Lift}
;
LiftTooHeavy:Off in the distance you can hear machinery wheeze into life. This is closely followed by an assortment of twangs, pings, thwaps and the horrid sound of mechanical parts taking too much strain. This is followed by a terrible buzzing noise and the alarm panel flashes a feeble red notice. Closer examination reveals (beneath the grime) a label that pronounces 'Maximum Weight Exceeded'. Finally the panel stops flashing and the annoying buzzing stops.
;
ExitLift:You gratefully step out of what you firmly believe to be a deathtrap.{=|$Location|$liftlocation}{CALL|$Location}
;
CallLift:{=|$liftlocation|$Location}Off in the distance some machinery whirrs slowly into life. There is a worry amount of groaning and creaking but after a while and with a pathetic 'ping' the doors slowly lurch open. {CALL|$Location}
;
//
take:{=|$temp|*.WEIGHT.SUMPOSSESSED}{+|$temp|$this.WEIGHT}{IF|$temp <= 10|You pick up the {PRINT|$this}.{TAKE|$this}|Try though you might, you just can't carry the {PRINT|$this} as well.}
;
drop:{DROP|$this}You put the {PRINT|$this} down.
;
use:There doesn't appear to be a use for the {PRINT|$this} here.
;
examine:You see nothing special about the {PRINT|$this}.
;
//
switchontorch:{IF|torch.BatteryLife > 0|You flick the switch and the torch flickers into life.{USE|torch}|You flick the switch several times but the torch fails to light up.}
;
switchofftorch:You flick the switch and the torch goes dark.{CEASE|torch}
;
//
examinebox:A closer look at the crate shows it is {CASE|box.state|locked with a large brass padlock.{IF|$Location EQUALS #Maintenance_Room| You can [try the key in the padlock,unlockbox].}|closed. You can [open it,openbox] if you wish{IF|$Location EQUALS #Maintenance_Room| or you can [lock the padlock,lockbox]}.|open{IF|*.count.NUMBERLOCATED.box > 0| and {LIST|box} inside.|, but empty.} You can [close the crate,closebox] if you wish.}
;
unlockbox:The key is a perfect fit and the lock springs open.{=|box.state|1}
;
lockbox:You refasten the padlock and lock it with the key.{=|box.state|0}
;
openbox:You lift the lid of the crate{IF|*.count.NUMBERLOCATED.box > 0| and you see {LIST|box} inside.|, but can see that inside it is empty.}{=|box.state|2}
;
closebox:You gently lower the lid of the crate.{=|box.state|1}
;
//
examinekey:The brass key is attached to a length of chain which in turn is secured to the wall. You quickly realise that it is firmly secured and can't be removed from the room. {IF|box ISPOSSESSED|It looks like this is an exact match for the padlock on he crate.{CASE|box.state| You can [try it in the padlock,unlockbox]| You can [try it in the padlock,lockbox]|}.|You place it back on the workbench.}
;
//
torchusage:{-|torch.BatteryLife|1}{IF|torch.BatteryLife <= 0|{CEASE|torch}}{IF|torch ISVISIBLE|{IF|torch.BatteryLife = 0|<br>The torch goes out.|{IF|torch.BatteryLife < 5|<BR>The torch looks significantly dimmer and is about to expire.|{IF|torch.BatteryLife < 12|<br>The torch is much dimmer.}}}}
;
//
examinefrontdoor:The front door is ornately carved and made from some heavy and dense hard wood. One thing you can be certain of is that it is most definitely locked shut.
;
examineplate:Looking more closely at the metal plate, you notice a small label that reads <q>Insert 2 coins as payment</q> and there is a button labelled <q>return</q>. {IF|coinscarried.numberpossessed > 0|Do you want to [try feeding coins into the slot,feedcoins]?}
;
feedcoins:{IF|coinscarried.numberpossessed = 2|You place the coins into the slot one after the other. As the second coin rattles into the mechanism, you hear a load 'clunk' and the front door swings open. You stagger happily into the sunshine outside.<br><br>{=|$Location|#Finished}{CALL|#Finished}|You place the coin in the slot, but after a short while, you realise nothing is going to happen and press the 'return' button to retrieve your coin.}
;