mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-22 14:33:51 +00:00
943 lines
36 KiB
INI
943 lines
36 KiB
INI
! ----------------------------------------------------------------------------
|
|
! Toyshop 961111 One of the standard Inform 6 example games
|
|
!
|
|
! This is not a real game. The main example game for Inform is "Advent",
|
|
! a port of Colossal Cave. Since that's something of an antique, and most
|
|
! of the objects in it are rather simple, this is a collection of more
|
|
! exotic features and peculiar objects. Note that "Advent" has plenty of
|
|
! interesting doors, a good lantern and bottled oil and water, so those
|
|
! won't be part of the Toyshop.
|
|
!
|
|
! Needs Inform 6 with library 6/1 or later to compile.
|
|
!
|
|
! To win, simply find 6 interesting things to do and leave by the main exit!
|
|
!
|
|
! Object Is an example of...
|
|
!
|
|
! >SA satchel Container into which the game silently puts things
|
|
! >HE helium balloon Something moving under the control of a daemon
|
|
! >CA little red car Vehicle, and pushable from place to place
|
|
! >PF padded floor Scenery present in several rooms at once
|
|
! >GR hand grenade Timed events: a grenade and its pin
|
|
! >MA matchbook Simple fire and matches; changing inventory styles
|
|
! >WC white candles A stock of objects identical to each other
|
|
! >GL white gloves Two independent objects which can behave as a pair
|
|
! >CO green cone Easy before and after rules
|
|
! >HW high window Starting and stopping daemons
|
|
! >BC bolted cupboard A typical locked container (with key)
|
|
! >GB glass box Container light can get through
|
|
! >SB steel box Container light can't get through
|
|
! >BL building blocks A complicated class definition; piles of objects
|
|
! >CH Christopher Someone you can talk to, and persuade to do things
|
|
! >OF Office Rules about moving in a particular direction
|
|
! >TB toothed bag A container with ideas about what it will allow
|
|
! >SL spirit level Something to put on top of things
|
|
! >BB blackboard A blackboard to write messages on
|
|
!
|
|
! (The code is marked with >SA and so on for easy access with a text editor)
|
|
! ----------------------------------------------------------------------------
|
|
Constant DEBUG;
|
|
Constant Story "TOYSHOP";
|
|
Constant Headline "^An Interactive Demonstration^
|
|
Copyright (c) 1994 by Graham Nelson. All rights given away.^";
|
|
Release 4;
|
|
Serial "961111"; ! This sets the serial date to the date of this source
|
|
! file, not to the date of compilation.
|
|
|
|
! Now we serve notice to Inform that we do not wish to use the standard
|
|
! routine for the Burn action, and will instead be defining our own:
|
|
|
|
Replace BurnSub;
|
|
|
|
! Next include the first of the three standard library files:
|
|
|
|
Include "Parser";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >SA Ungenerously, the player can only carry at most 4 things, but there's
|
|
! a satchel to carry other things around in...
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Constant MAX_CARRIED = 4;
|
|
Constant SACK_OBJECT = satchel;
|
|
|
|
Object satchel "satchel"
|
|
with description "Big and with a smile painted on it.",
|
|
name "satchel", article "your",
|
|
when_closed "Your satchel lies on the floor.",
|
|
when_open "Your satchel lies open on the floor.",
|
|
has container open openable;
|
|
|
|
! We're going to use the most elaborate scoring system the
|
|
! library provides (even though we're going to make the six tasks all
|
|
! score only 1 point each), so we define all this...
|
|
|
|
Constant TASKS_PROVIDED;
|
|
Constant NUMBER_TASKS = 6;
|
|
Array task_scores -> 1 1 1 1 1 1;
|
|
Constant MAX_SCORE = 6;
|
|
|
|
! And include the library of standard verbs and actions.
|
|
|
|
Include "VerbLib";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! Off we go into the Toyshop...
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Class Toyroom
|
|
has light;
|
|
|
|
Toyroom Toyshop "Toyshop"
|
|
with description
|
|
"The centre of a long east-west hall. Shelves are lined
|
|
with toys, painted clowns face you from the walls and
|
|
the floor is lightly padded with colourful mats. A doorway
|
|
leads north, with a red warning triangle above it.",
|
|
name "clowns" "painted" "shelves" "triangle",
|
|
e_to East_End, w_to West_End, n_to Danger_Zone;
|
|
|
|
Object -> chair "high chair"
|
|
with name "chair" "high"
|
|
has supporter enterable;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >HE The balloon is completely self-contained as a piece of code, except
|
|
! that it does not set itself going (though even this could have been
|
|
! arranged): it is set going in the Initialise() routine.
|
|
!
|
|
! Notice that the "after" for Drop takes away the "moved" attribute.
|
|
! This is one way to ensure that the "initial" message will always be
|
|
! the one displayed. (Alternatively, we could have given it a "describe"
|
|
! property.)
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> balloon "helium balloon"
|
|
with description "Blue, with a yellow smile.",
|
|
name "helium" "balloon" "blue" "string",
|
|
initial "A balloon nestles on the ceiling, its long string hanging.",
|
|
before
|
|
[; Attack: remove self; StopDaemon(self);
|
|
"Easily, you burst the balloon. Pop!^^
|
|
Shame it was irreplaceable, really.";
|
|
],
|
|
after
|
|
[; Take: "You take the balloon by its string. It's buoyant!";
|
|
Drop: give balloon ~moved;
|
|
"The balloon rises gracefully to the ceiling.";
|
|
],
|
|
daemon
|
|
[ from_room to_room;
|
|
if (random(3)~=1) rfalse;
|
|
from_room=parent(self);
|
|
if (from_room==East_End or West_End) to_room=Toyshop;
|
|
if (from_room==Toyshop)
|
|
{ if (random(2)==1) to_room=East_End;
|
|
else to_room=West_End;
|
|
}
|
|
if (to_room==0) rfalse;
|
|
move self to to_room;
|
|
if (location==from_room)
|
|
"^A breeze blows the balloon away to the ", (name) to_room, ".";
|
|
if (location==to_room)
|
|
"^A breeze blows the balloon in from the ", (name) from_room, ".";
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >CA There are two exceptions to the ordinary before/after rules, for
|
|
! vehicles and things which can be pushed from place to place: this car
|
|
! demonstrates both at once.
|
|
!
|
|
! The "before" for PushDir (push in a named direction) must call
|
|
! AllowPushDir and then return true to signify that the push is legal.
|
|
!
|
|
! The "before" for Go must return true to signify that travelling in
|
|
! the object is legal. (Note that it must also be enterable.)
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> car "little red car"
|
|
with name "little" "red" "car" "kar1",
|
|
description "Large enough to sit inside. Among the controls is a
|
|
prominent on/off switch. The numberplate is KAR 1.",
|
|
when_on "The red car sits here, its engine still running.",
|
|
when_off "A little red car is parked here.",
|
|
before
|
|
[; PushDir: AllowPushDir(); rtrue;
|
|
Go: if (car has on) { Achieved(1); "Brmm! Brmm!"; }
|
|
print "(The ignition is off at the moment.)^";
|
|
],
|
|
after
|
|
[; PushDir: "The car rolls very slowly as you push it.";
|
|
],
|
|
has switchable enterable static container open;
|
|
|
|
Object -> -> "small note"
|
|
with name "small" "note",
|
|
description
|
|
" !!!! FROBOZZ MAGIC CAR COMPANY !!!!^
|
|
^Hello, Driver!^
|
|
^Instructions for use:^
|
|
^Switch on the ignition and off you go!^
|
|
^Warranty:^
|
|
^This car is guaranteed against all defects for a period of
|
|
76 milliseconds from date of purchase or until used,
|
|
whichever comes first.^
|
|
^Good Luck!";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >PF An example of an object spread across several (three) rooms:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object padded_floor "padded floor"
|
|
with name "padded" "floor" "mats" "padding",
|
|
description "To protect little children and adventurers.",
|
|
before
|
|
[; Take: "It is protected from little children and adventurers.";
|
|
],
|
|
found_in East_End Toyshop West_End
|
|
has scenery;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Toyroom Danger_Zone "Danger Zone"
|
|
with description
|
|
"This is the Danger Zone, which you should know better
|
|
than to go into. A single door leads back south.",
|
|
s_to Toyshop;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >GR A classic example of a timer (or, as some people call them and
|
|
! appropriately so in this case, a fuse). To demonstrate stopping
|
|
! a timer before the alarm (and for fun), there is also a pin:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> grenade "nasty-looking hand grenade"
|
|
with name "hand" "grenade" "nasty" "nasty-looking",
|
|
initial "A nasty-looking hand grenade (there is no other kind)
|
|
rolls about irresponsibly on the floor.",
|
|
description "Not recommended for children under 90.",
|
|
before
|
|
[; Pull: if (self has general) "Too late for that.";
|
|
StartTimer(self, 5); give self general;
|
|
move the_pin to player;
|
|
"You pull the pin out, an irrevocable act.";
|
|
],
|
|
time_left 0,
|
|
time_out
|
|
[; deadflag=1;
|
|
"^An immense explosion suddenly demolishes the toyshop!^^
|
|
Will you never learn?";
|
|
],
|
|
has transparent;
|
|
|
|
Object -> -> the_pin "pin"
|
|
with name "pin",
|
|
description "The pin is designed to be easy to pull.",
|
|
before
|
|
[; Take, Pull: if (self in grenade) <<Pull grenade>>;
|
|
Insert:
|
|
if (self notin grenade && second==grenade)
|
|
{ StopTimer(grenade); move self to grenade;
|
|
give grenade ~general;
|
|
"Amazing! You got the pin back into the grenade!";
|
|
}
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >MA This is a matchbook of five matches, which is quite simple in that you
|
|
! can only actually have one match at a time: otherwise, it's quite
|
|
! a full implementation. Note that the inventory lines for the match
|
|
! and the matchbook are coded here. Note also that the "match" object
|
|
! returns to the book even when the book is empty, so that the parser
|
|
! will still understand requests for matches - which the "before" rule,
|
|
! which automatically removes matches when needed, can then turn down.
|
|
!
|
|
! The matchbook has a daemon whose job is to tidy up lost matches. One
|
|
! might expect this rule to be coded with an "after" routine, to trap
|
|
! the player dropping matches. But suppose there were a magpie in the
|
|
! game, and it flew down and stole the match but left the matchbook!
|
|
! As it happens there isn't, but this is better form.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> matchbook "matchbook"
|
|
with name "matchbook" "book" "matches",
|
|
number 5,
|
|
before
|
|
[; Burn: if (match has light)
|
|
{ remove match; remove matchbook;
|
|
"What a waste of matches!";
|
|
}
|
|
],
|
|
invent
|
|
[; if (inventory_stage==2)
|
|
{ switch(self.number)
|
|
{ 0: print " (empty)";
|
|
1: print " (1 match left)";
|
|
default: print " (", self.number, " matches left)";
|
|
}
|
|
}
|
|
],
|
|
description
|
|
[; print "The cover advertisement reads
|
|
~Curses - Adventure of a Lunchtime~. The book ";
|
|
switch(self.number)
|
|
{ 0: "is empty.";
|
|
1: "has a single match left.";
|
|
default:
|
|
print_ret "contains ", self.number, " matches.";
|
|
}
|
|
],
|
|
daemon
|
|
[; if (match notin matchbook && match notin player)
|
|
{ move match to matchbook;
|
|
if (match has light)
|
|
{ give match ~light; StopTimer(match); }
|
|
StopDaemon(self);
|
|
}
|
|
],
|
|
has transparent;
|
|
|
|
Object -> -> match "match"
|
|
with parse_name
|
|
[ i j; if (self has light) j='burning'; else j='unlit';
|
|
while (NextWord()=='match' or j) i++;
|
|
return i;
|
|
],
|
|
article "an",
|
|
before
|
|
[ i; if (self in matchbook)
|
|
{ i=matchbook.number;
|
|
if (i==0) "There are no matches left in the book.";
|
|
i--; matchbook.number=i;
|
|
move self to player; StartDaemon(matchbook);
|
|
print "(taking a match from the book, which ";
|
|
if (i==0) print "is now empty)^";
|
|
if (i==1) print "has one more left)^";
|
|
if (i>1) print "has ", i, " left)^";
|
|
self.article = "an";
|
|
}
|
|
Take, Remove: if (self in player) "Done.";
|
|
Burn:
|
|
if (self has light) "The match is already alight.";
|
|
if (matchbook notin player)
|
|
"You need the matchbook to strike the match.";
|
|
give self light; StartTimer(self, 2+random(3));
|
|
self.article = "a";
|
|
"You strike the match.";
|
|
],
|
|
short_name
|
|
[; if (self has light) print "burning match";
|
|
else print "unlit match";
|
|
rtrue;
|
|
],
|
|
|
|
time_left,
|
|
time_out
|
|
[; move self to matchbook; give self ~light;
|
|
"^You drop the match as the flame reaches your finger.";
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >WC A box of eight candles.
|
|
!
|
|
! This is a simple way to code up duplicate objects. For one thing,
|
|
! > take candles
|
|
! does not quite behave as we would hope: it'll only pick up one candle
|
|
! (though "> take four candles" will work). See the "Block" class
|
|
! below for a way to make good.
|
|
!
|
|
! If we had needed a much greater number of candles, we could have used
|
|
! object creation and destruction during play. See the "Ticket" class
|
|
! from the "Balances" example game.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Class Candle
|
|
with name "wax" "candle" "candles",
|
|
short_name "wax candle", plural "wax candles",
|
|
description "It looks just like all the other candles.",
|
|
before
|
|
[; Burn: "Disappointingly, the wick refuses to burn."; ];
|
|
|
|
Object -> "grey tin box"
|
|
with name "tin" "box" "grey",
|
|
description
|
|
"A grey tin box of ~Major's Candles~.",
|
|
has container openable;
|
|
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
Candle -> ->;
|
|
|
|
Toyroom East_End "East End"
|
|
with name "dolls" "nurses",
|
|
description
|
|
"The eastern end of the toyshop is pink, and dolls and
|
|
nurses line the shelves right up to the high window.
|
|
A dark doorway leads to a northern side chamber.",
|
|
w_to Toyshop, n_to DarkRoom;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >GL The following example, suggested to the author by Richard Tucker,
|
|
! demonstrates an apparently tricky case of objects with associated
|
|
! sub-objects. The pair of white gloves behaves just like any other item
|
|
! of clothing - but the player can also use the left and right gloves
|
|
! independently, can take away or wear only one and so on. When they
|
|
! come back together (even in a cupboard, say, or on a mantelpiece)
|
|
! they are called a pair again.
|
|
!
|
|
! We can do this with only three objects, one daemon and one rule.
|
|
!
|
|
! When the gloves are together, and the player refers to an individual
|
|
! glove, the before rule splits up the pair and starts the daemon.
|
|
! Once active, the daemon tries every turn to re-join them into a pair.
|
|
! (If it succeeds, it turns itself off.)
|
|
!
|
|
! Note that the "pair of gloves" object has the "general" attribute exactly
|
|
! when the gloves are apart. Otherwise the pair-object contains both
|
|
! glove objects, and has "transparent" so that the parser knows the player
|
|
! can see and refer to them.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> gloves "white gloves"
|
|
with article "a pair of",
|
|
name "white" "gloves" "pair" "of",
|
|
daemon
|
|
[; if (parent(right_glove) ~= parent(left_glove)) return;
|
|
if ((left_glove has worn && right_glove hasnt worn)
|
|
|| (left_glove hasnt worn && right_glove has worn)) return;
|
|
if (left_glove has worn) give gloves worn; else give gloves ~worn;
|
|
move gloves to parent(right_glove); give gloves ~general;
|
|
|
|
move right_glove to gloves; move left_glove to gloves;
|
|
give right_glove ~worn; give left_glove ~worn;
|
|
|
|
StopDaemon(self);
|
|
],
|
|
has clothing transparent;
|
|
|
|
Class Glove
|
|
with article "the",
|
|
name "white" "glove",
|
|
before
|
|
[; if (self notin gloves) rfalse;
|
|
move left_glove to parent(gloves); move right_glove to parent(gloves);
|
|
if (gloves has worn)
|
|
{ give left_glove worn; give right_glove worn;
|
|
}
|
|
give gloves general; remove gloves;
|
|
StartDaemon(gloves);
|
|
],
|
|
has clothing;
|
|
|
|
Glove -> -> left_glove "left glove"
|
|
with description "White silk, monogrammed with a scarlet R.",
|
|
name "left";
|
|
Glove -> -> right_glove "right glove"
|
|
with description "White silk, monogrammed with a scarlet T.",
|
|
name "right";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! ...and that's all: the "gloves" code is self-contained.
|
|
!
|
|
! Exercise for the reader: hide a (sharp) jewel inside the left glove.
|
|
! (Alter the glove class to make them containers open only when not worn.
|
|
! Add two "after" rules to warn the player if there's something sharp
|
|
! to the touch, one for putting on the pair of gloves, one for putting on
|
|
! an individual glove.)
|
|
! ----------------------------------------------------------------------------
|
|
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >CO A traditional Inform example object:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> cone "green cone"
|
|
with name "green" "cone" "emerald" "marzipan",
|
|
describe
|
|
[; if (cone has moved)
|
|
"^A misshapen cone of green marzipan sits here.";
|
|
"^Nearby is an emerald green cone, one foot high.";
|
|
],
|
|
description "The cone seems to be made of emerald-coloured
|
|
marzipan.",
|
|
before
|
|
[; Eat: if (random(100) <= 30)
|
|
{ deadflag = 1;
|
|
"Unfortunately, you seem to be allergic to almonds.";
|
|
}
|
|
"You nibble at a corner of the cone.";
|
|
],
|
|
after
|
|
[; Take: "Taken. (Your hands are smeared with marzipan.)";
|
|
Drop: cone.description = "The cone is a vague green mess.";
|
|
"The cone drops to the floor and sags a little.";
|
|
],
|
|
has edible;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >HW It's the draught from this slightly-concealed window which propels the
|
|
! balloon:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> "high window"
|
|
with name "high" "window",
|
|
description
|
|
[; print "A narrow, high window ";
|
|
if (self has open) "through which a draught blows.";
|
|
"which is closed.";
|
|
],
|
|
after
|
|
[; Open: StartDaemon(balloon);
|
|
Close: Achieved(2); StopDaemon(balloon);
|
|
],
|
|
has scenery openable open;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >BC A typical locked container, containing a rather pathetic prize...
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> "bolted cupboard"
|
|
with name "bolted" "cupboard",
|
|
describe
|
|
[; if (self hasnt open) "^A shut cupboard is bolted to one wall.";
|
|
"^Bolted up on one wall is an open cupboard.";
|
|
],
|
|
with_key key
|
|
has locked container openable lockable static;
|
|
|
|
Object -> -> "boiled sweet"
|
|
with name "boiled" "sweet",
|
|
after
|
|
[; Eat: Achieved(0);
|
|
"It takes an irritatingly long time to eat.";
|
|
],
|
|
has edible;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >GB This is really to demonstrate "transparent". Shutting up the glowing
|
|
! >SB ball in the glass box does not make the room go dark: shutting it up
|
|
! in the steel box does. Also, you can examine things in the glass box
|
|
! even when the glass box is shut.
|
|
! (Note also that the Dark Room is explicitly told not to have "light",
|
|
! which it would otherwise inherit from the "Toyroom" class.)
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Toyroom DarkRoom "Dark Room"
|
|
with description "A featureless storage room, hardly worth illumination.",
|
|
cant_go "The only exit is back south.",
|
|
s_to East_End
|
|
has ~light;
|
|
|
|
Object -> "glass box with a lid"
|
|
with name "glass" "box" "with" "lid"
|
|
has container transparent openable open;
|
|
|
|
Object -> "steel box with a lid"
|
|
with name "steel" "box" "with" "lid"
|
|
has container openable open;
|
|
|
|
|
|
Toyroom West_End "West End"
|
|
with name "soldiers" "model" "aircraft" "planes",
|
|
description
|
|
"The western end of the toyshop is blue, and soldiers and
|
|
model aircraft line the shelves. A small office lies to
|
|
the south.",
|
|
e_to Toyshop, s_to Office;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >BL The class Block provides for stackable building blocks.
|
|
!
|
|
! Note that with the "describe" routine missing, the game would still
|
|
! correctly describe stacks of blocks: just a little less elegantly.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Class Block
|
|
with description "Just a child's building block, four inches on a side.",
|
|
|
|
! The parse_name routine below ensures that "take blocks"
|
|
! works correctly:
|
|
|
|
parse_name
|
|
[ i j;
|
|
for (::)
|
|
{ j=NextWord();
|
|
if (j=='block' or 'cube' or 'building' or (self.name)) i++;
|
|
else
|
|
{ if (j=='blocks' or 'cubes')
|
|
{ parser_action=##PluralFound; i++; }
|
|
else return i;
|
|
}
|
|
}
|
|
],
|
|
|
|
describe
|
|
[ c d e;
|
|
d = child(self);
|
|
while (d~=0 && d ofclass Block)
|
|
{ c++; e=d; d=child(d); }
|
|
if (c==0) rfalse;
|
|
print "^There is a pile of building blocks here, ";
|
|
while (c>=0)
|
|
{ print (address) e.name; ! Sneaky: print the "name" out
|
|
if (c>0) print " on "; ! using its dictionary address
|
|
c--; e=parent(e);
|
|
}
|
|
".";
|
|
],
|
|
before
|
|
[ c;
|
|
PutOn:
|
|
if (second ofclass Block)
|
|
{ if (child(second)~=0 && child(second) ofclass Block)
|
|
"There's no room on the top of one cube for two more, side
|
|
by side.";
|
|
}
|
|
else
|
|
print "(They're really intended
|
|
to be piled on top of each other.)^";
|
|
c=second; while (c ofclass Block) c=parent(c);
|
|
if (c~=location or mantelpiece) "Too unsteady a base.";
|
|
],
|
|
after
|
|
[ c stack;
|
|
PutOn:
|
|
stack=noun;
|
|
while (parent(stack) ofclass Block) { stack=parent(stack); c++; }
|
|
if (c<2)
|
|
{ if (Chris has general) rtrue;
|
|
rfalse;
|
|
}
|
|
if (c==2) "The pile of three cubes is unsteady, but viable.";
|
|
if (Chris has general)
|
|
{ Achieved(3);
|
|
"^Expertly he keeps the pile of four cubes stable.";
|
|
}
|
|
stack=noun;
|
|
while (parent(stack) ofclass Block)
|
|
{ c=stack; stack=parent(stack); move c to location; }
|
|
"The pile of four cubes wobbles, wobbles, steadies... and suddenly
|
|
collapses!";
|
|
Take:
|
|
stack=child(noun); if (stack==0) rfalse;
|
|
while (stack~=0)
|
|
{ c=stack; stack=child(stack); move c to location; }
|
|
"Your pile of cubes is collapsed as a result.";
|
|
],
|
|
has supporter;
|
|
|
|
Block -> "green cube"
|
|
with name "green";
|
|
Block -> "red cube"
|
|
with name "red";
|
|
Block -> "yellow cube"
|
|
with name "yellow";
|
|
Block -> "blue cube"
|
|
with name "blue";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >CH A guest appearance by my cousin Christopher, aged six (*), who plays
|
|
! with one thing at a time (easily forgetting which). Being "transparent"
|
|
! (no reflection on him!) means the parser allows the player to examine
|
|
! whatever he's playing with... but not to take it from him.
|
|
! (* In 1993, when this game was first written.)
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> Chris "Christopher"
|
|
with name "child" "boy" "chris" "christopher",
|
|
describe
|
|
[; print "^A boy called Christopher sits here";
|
|
if (child(Chris) ~= nothing)
|
|
print ", playing with ", (a) child(Chris);
|
|
".";
|
|
],
|
|
life
|
|
[ x;
|
|
Ask:
|
|
switch(second)
|
|
{ 'juggling', 'fluorescent', 'ball': "~That's mine!~";
|
|
'helium', 'balloon': "Christopher yawns.";
|
|
'cube', 'cubes': "~Bet I can make a higher tower than you.~";
|
|
'toys', 'toyshop': "~Isn't it fabulous here?~";
|
|
default: "~Dunno.~";
|
|
}
|
|
Answer:
|
|
switch(noun)
|
|
{ 'hello', 'hallo', 'hi':
|
|
"~Hello,~ says Christopher cheerfully.";
|
|
default: "Christopher seems preoccupied.";
|
|
}
|
|
Attack: remove self;
|
|
"Christopher makes a run for it, effortlessly slipping past you!";
|
|
Kiss: "~That's soppy, that is.~";
|
|
Give:
|
|
if (noun==balloon) "He's too bored by the balloon.";
|
|
x=child(Chris);
|
|
if (x~=0)
|
|
{ move x to location;
|
|
print "He forgets about ", (the) x, " and ";
|
|
}
|
|
else print "He ";
|
|
print "eagerly grabs ", (the) noun; move noun to Chris; ".";
|
|
],
|
|
orders
|
|
[; Drop: if (noun in Chris) "~Won't! It's mine!~";
|
|
Take: "Christopher can't be bothered.";
|
|
Give: if (second==player) "~Get your own!~";
|
|
Go: "~But I like it here!~";
|
|
PutOn: if (noun notin Chris) "He is mightily confused.";
|
|
if (~~(noun ofclass Block && second ofclass Block))
|
|
"He can't see the point of this.";
|
|
print "Christopher leans over with great concentration
|
|
and does so.^";
|
|
move noun to player; give self general;
|
|
<PutOn noun second>;
|
|
give self ~general; rtrue;
|
|
],
|
|
each_turn
|
|
[; if (random(3)~=1) rtrue;
|
|
print "^Christopher ";
|
|
switch(random(4))
|
|
{ 1: "yawns."; 2: "frowns.";
|
|
3: "stretches."; 4: "hums tonelessly.";
|
|
}
|
|
],
|
|
has animate proper transparent;
|
|
|
|
Object "fluorescent juggling ball" Chris
|
|
with initial "On the floor is a fluorescent juggling ball!",
|
|
name "fluorescent" "juggling" "ball",
|
|
description "It glows with soft light."
|
|
has light;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >OF A simple movement rule.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Toyroom Office "Office"
|
|
with description
|
|
"A small, grey office, with a broad stone mantelpiece.
|
|
In the east wall is a doorway marked ~Exit~, and the Toyshop,
|
|
of course, lies north.",
|
|
cant_go "The Toyshop floor lies north.",
|
|
n_to West_End,
|
|
e_to
|
|
[; if (score~=MAX_SCORE)
|
|
"A gong sounds. ~You cannot leave the Toyshop until
|
|
you have done six interesting things!~";
|
|
deadflag=2;
|
|
"A gong sounds. ~Congratulations! You may now leave the Toyshop
|
|
and begin writing your own Inform game!~";
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >TB A somewhat acquisitive container... but it can be taught to behave.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> "toothed bag"
|
|
with name "toothed" "bag",
|
|
initial "In one corner is a curious, toothed bag.",
|
|
description "A capacious bag with a toothed mouth.",
|
|
before
|
|
[; LetGo: "The bag defiantly bites itself
|
|
shut on your hand until you desist.";
|
|
],
|
|
after
|
|
[; Receive:
|
|
if (noun==cone)
|
|
{ self.before=0; self.after=0;
|
|
"The bag wriggles interminably as it tries
|
|
to eat the enormous mass of marzipan. That'll
|
|
teach it.";
|
|
}
|
|
"The bag wriggles hideously as it swallows ", (the) noun, ".";
|
|
],
|
|
has container open;
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >SL Which can be put on the mantelpiece: the first time this is done, the
|
|
! game randomly decides which end is higher, and sticks to this decision.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> -> spirit_level "spirit level"
|
|
with name "spirit" "level" "wood" "flask",
|
|
number 0,
|
|
description "A length of wood containing a flask of viscous
|
|
green liquid, in which a bubble is trapped.",
|
|
before
|
|
[; Examine:
|
|
if (spirit_level in mantelpiece)
|
|
{ print "The bubble is at the ";
|
|
if (self.number==1) "northeast end.";
|
|
"southeast end.";
|
|
}
|
|
],
|
|
after
|
|
[; PutOn: if (second~=mantelpiece) rfalse;
|
|
if (spirit_level hasnt general) self.number=random(2);
|
|
give spirit_level general; Achieved(4);
|
|
print "You put the spirit level on the mantelpiece,
|
|
and the bubble slowly drifts towards the ";
|
|
if (self.number==1) "northeast.";
|
|
"southwest.";
|
|
];
|
|
|
|
Object -> mantelpiece "mantelpiece"
|
|
with name "mantel" "mantle" "piece" "mantelpiece"
|
|
has scenery supporter;
|
|
|
|
Object -> -> key "iron key"
|
|
with name "iron" "key", article "an";
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! >BB A blackboard which can be written on or wiped clear.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
Object -> -> chalk "stick of chalk"
|
|
with name "stick" "of" "chalk";
|
|
|
|
Array boardtext string 64;
|
|
|
|
Object -> blackboard "blackboard"
|
|
with name "board" "blackboard" "black",
|
|
describe
|
|
[; <<Examine self>>; ],
|
|
before
|
|
[ i f;
|
|
Examine:
|
|
for (i=1:i<=boardtext->0:i++)
|
|
if (boardtext->i~=' ' or 0) f=1;
|
|
if (f==0)
|
|
{ print "^The office blackboard is wiped clean.^";
|
|
if (self hasnt general)
|
|
{ give self general;
|
|
"^[To write on it, try > write ~message...~]";
|
|
}
|
|
rtrue;
|
|
}
|
|
print "^The office blackboard bears the message:^ ";
|
|
for (i=1:i<=boardtext->0:i++)
|
|
{ f=boardtext->i;
|
|
if (f~=0) print (char) f;
|
|
}
|
|
new_line; rtrue;
|
|
Rub: for (i=1:i<=boardtext->0:i++) boardtext->i = ' ';
|
|
"You wipe the blackboard clean.";
|
|
],
|
|
has static;
|
|
|
|
Global from_char; Global to_char;
|
|
[ QuotedText i j f;
|
|
i = WordAddress(wn++); i=i-buffer;
|
|
if (buffer->i=='"')
|
|
{ for (j=i+1:j<=(buffer->1)+1:j++)
|
|
if (buffer->j=='"') f=j;
|
|
if (f==0) return -1;
|
|
from_char = i+1; to_char=f-1;
|
|
if (from_char>to_char) return -1;
|
|
while (buffer+f > WordAddress(wn)) wn++; wn++;
|
|
return 1;
|
|
}
|
|
return -1;
|
|
];
|
|
|
|
[ WriteSub i j;
|
|
if (chalk notin player) "You're holding nothing to write with.";
|
|
if (blackboard notin location) "The blackboard is elsewhere.";
|
|
for (i=from_char,j=1:i<=to_char && j<boardtext->0:i++,j++)
|
|
boardtext->j = buffer->i;
|
|
for (:j<boardtext->0:j++) boardtext->j=0;
|
|
Achieved(5);
|
|
<<Examine blackboard>>;
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! End of object definitions.
|
|
! ----------------------------------------------------------------------------
|
|
!
|
|
! Routines and Entry Points
|
|
!
|
|
! (Fuller examples of which can be found in the "Advent" example game.)
|
|
!
|
|
! Initialise() just sets up the initial state of the game.
|
|
! We are required to set "location" to the start location of the
|
|
! player; the rest is optional.
|
|
!
|
|
! StartDaemon(balloon) starts the process which blows the balloon back
|
|
! and forth.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
[ Initialise;
|
|
location=chair; move satchel to player;
|
|
|
|
print "^^^^^~What's so special about Inform,~ is the last thing you
|
|
remember saying to the mad alchemist. Big mistake...^^";
|
|
|
|
StartDaemon(balloon);
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! Print names of tasks out (when the library asks us to). Note that they
|
|
! are numbered from 0 to NUMBER_TASKS-1.
|
|
! ----------------------------------------------------------------------------
|
|
|
|
[ PrintTaskName achievement;
|
|
switch(achievement)
|
|
{ 0: "eating a sweet";
|
|
1: "driving the car";
|
|
2: "shutting out the draught";
|
|
3: "building a tower of four";
|
|
4: "seeing which way the mantelpiece leans";
|
|
5: "writing on the blackboard";
|
|
}
|
|
];
|
|
|
|
[ PrintRank;
|
|
print ", earning you the rank of ";
|
|
if (score >= 6) "Toyshop manager.";
|
|
if (score >= 5) "management trainee.";
|
|
if (score >= 4) "undergraduate.";
|
|
if (score >= 3) "schoolchild.";
|
|
if (score >= 2) "nursery-school child.";
|
|
if (score >= 1) "toddler.";
|
|
"newborn baby.";
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! Now (as promised earlier) we provide the replacement for BurnSub,
|
|
! specially adapted to the rules of the Toyshop:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
[ BurnSub;
|
|
if (match hasnt light) "You have no source of flame.";
|
|
if (noun has animate) <<Attack noun>>;
|
|
if (noun==padded_floor)
|
|
{ deadflag=1;
|
|
"A gong sounds, but before a sepulchral voice finishes clearing
|
|
its throat, the whole padded floor goes up in an inferno.";
|
|
}
|
|
"A gong sounds, and a sepulchral, rather disappointed voice says:
|
|
~It is forbidden to play with fire in the Toyshop.~";
|
|
];
|
|
|
|
! ----------------------------------------------------------------------------
|
|
! And we provide one new action, "Burst", which in fact just passes over to
|
|
! "Attack", plus one for writing on the board:
|
|
! ----------------------------------------------------------------------------
|
|
|
|
[ BurstSub; <<Attack noun>>; ];
|
|
|
|
Include "Grammar";
|
|
|
|
Verb "burst" "pop" "prick" "stab" "pierce"
|
|
* noun -> Burst;
|
|
|
|
Verb "write" * QuotedText -> Write;
|
|
|
|
! ----------------------------------------------------------------------------
|