text which the interpreter ultimately displays. For example, the "William
Tell" game, in the form that we wrote it, starts like this:
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
Constant Story "William Tell";
Class Room
has light;
- ! ...
+ ...
You will never need to look at it in the form produced by the compiler::
#. In that folder, use your text editor to create this source file
``Heidi.inf``:
- .. code-block:: inform6
+ .. code-block:: inform
!% -SD
!============================================================================
character. On this line, the first ``!`` is part of the sequence (or
**string**) of characters to be displayed:
- .. code-block:: inform6
+ .. code-block:: inform
print "Hello world!"; ! <- is the start of this comment
space (except when the spaces are part of a character string). So, these
two rules tell us that we *could* have typed the source file like this:
- .. code-block:: inform6
+ .. code-block:: inform
Constant Story "Heidi";
Constant Headline
* Every game needs the three lines which ``Include`` the standard library
files -- that is, they merge those files' contents into your source file:
- .. code-block:: inform6
+ .. code-block:: inform
Include "Parser";
Include "VerbLib";
- ! ...
+ ...
Include "Grammar";
They always have to be in this order, with ``Parser`` and ``VerbLib``
* Every game needs to define an ``Initialise`` routine (note the British
spelling):
- .. code-block:: inform6
+ .. code-block:: inform
[ Initialise; ];
that's why we were able to take three lines to define the ``Headline``
constant
- .. code-block:: inform6
+ .. code-block:: inform
Constant Headline
"^A simple Inform example
this example none of them has four walls. So let's use Inform to define
those rooms. Here's a first attempt:
-.. code-block:: inform6
+.. code-block:: inform
Object "In front of a cottage"
with description
routes, we also need to explicitly add them to the room definitions in a
form that the game itself can make sense of. Like this:
-.. code-block:: inform6
+.. code-block:: inform
Object before_cottage "In front of a cottage"
with description
with the sketch map until you're comfortable that you understand how to
create simple rooms and define the connections between them.
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
Constant Story "Heidi";
bird and its nest are Inform objects. We'll start their definitions like
this:
-.. code-block:: inform6
+.. code-block:: inform
Object bird "baby bird"
with description "Too young to fly, the nestling tweets helplessly.",
appropriate to her, with a good chance of it being understood. We add a
line to each definition:
-.. code-block:: inform6
+.. code-block:: inform
Object bird "baby bird"
with description "Too young to fly, the nestling tweets helplessly.",
Furthermore, we label it as ``open``; this prevents the interpreter from
asking us to open it before putting in the bird.
-.. code-block:: inform6
+.. code-block:: inform
Object nest "bird's nest"
with description "The nest is carefully woven of twigs and moss.",
them. Let's say that the bird is found in the forest, while the nest is in
the clearing. This is how we set this up:
-.. code-block:: inform6
+.. code-block:: inform
Object bird "baby bird" forest
with description "Too young to fly, the nestling tweets helplessly.",
they're found. This means adding the bird just after the forest, and the
nest just after the clearing. Here's the middle piece of the source file:
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
! The game objects
The description of the clearing mentions a tall sycamore tree, up which the
player character supposedly "climbs". We'd better define it:
-.. code-block:: inform6
+.. code-block:: inform
Object tree "tall sycamore tree" clearing
with description
from being picked up by the player character. One final object: the branch
at the top of the tree. Again, not many surprises in this definition:
-.. code-block:: inform6
+.. code-block:: inform
Object branch "wide firm bough" top_of_tree
with description "It's flat enough to support a small object.",
object can't normally be both a ``container`` *and* a ``supporter``.)
And so here are our objects again:
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
! The game objects
put the bird into the nest first. One easy way to enforce this is by
adding a line near the top of the file:
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
Constant Story "Heidi";
place it on the branch; when that happens, the game should be over. This
is one way of making it happen:
-.. code-block:: inform6
+.. code-block:: inform
Object branch "wide firm bough" top_of_tree
with description "It's flat enough to support a small object.",
Reviewing the basics
======================
+.. highlight:: inform
+
.. epigraph::
| *G was a gamester, who had but ill-luck;*
need to substitute a more relevant response after LISTEN TO BIRD. Here's
how we do it:
-.. code-block:: inform6
+.. code-block:: inform
Object bird "baby bird" forest
with description "Too young to fly, the nestling tweets helplessly.",
though it hadn't been intercepted. Sometimes that's what you want it to
do, but not here: if instead we'd written this:
-.. code-block:: inform6
+.. code-block:: inform
Object bird "baby bird" forest
with description "Too young to fly, the nestling tweets helplessly.",
Again, that isn't perhaps the most appropriate response, but it's easy to
change:
-.. code-block:: inform6
+.. code-block:: inform
Object before_cottage "In front of a cottage"
with description
That's easy to fix; we can add a new ``cottage`` object, making it a piece
of ``scenery`` just like the ``tree``:
-.. code-block:: inform6
+.. code-block:: inform
Object cottage "tiny cottage" before_cottage
with description "It's small and simple, but you're very happy here.",
The situation here is similar to our LISTEN TO BIRD problem, and the
solution we adopt is similar as well:
-.. code-block:: inform6
+.. code-block:: inform
Object cottage "tiny cottage" before_cottage
with description "It's small and simple, but you're very happy here.",
to be achieved by that"). Yet another opportunity to use a ``before``
property, but now with a difference.
-.. code-block:: inform6
+.. code-block:: inform
Object tree "tall sycamore tree" clearing
with description
far, but instead for every ``Drop`` which takes place in our troublesome
``top_of_tree`` room. This is what we have to write:
-.. code-block:: inform6
+.. code-block:: inform
Object top_of_tree "At the top of the tree"
with description "You cling precariously to the trunk.",
unhelpful in these non-standard circumstances. If you prefer to hint at
what's just happened, you could use this alternative solution:
-.. code-block:: inform6
+.. code-block:: inform
Object top_of_tree "At the top of the tree"
with description "You cling precariously to the trunk.",
checked for the bird actually being in the nest; fortunately, that's easy
to do:
-.. code-block:: inform6
+.. code-block:: inform
Object branch "wide firm bough" top_of_tree
with description "It's flat enough to support a small object.",
William Tell: a tale is born
==============================
-.. highlight:: inform6
+.. highlight:: inform
.. epigraph::
A track heads to the northeast.",
has light;
- ! ...
+ ...
and we explained that just about *every* room needs that ``light``
attribute, or else the player would be literally in the dark. It's a bit
A track heads to the northeast.",
has ;
- ! ...
+ ...
We've done four things:
"Through the dense foliage, you glimpse a building to the west.
A track heads to the northeast.";
- ! ...
+ ...
You'll notice that, if an object has no block of attributes, the semicolon
which terminates its definition simply moves to the end of its last
Prop "south gate" street
with name 'south' 'southern' 'wooden' 'gate',
description "The large wooden gate in the town walls is wide open.",
- ! ...
+ ...
If players type EXAMINE GATE, they'll see "The large wooden gate..."; if
they type CLOSE GATE then the gate's ``before`` property will step in and
William Tell: the early years
===============================
-.. highlight:: inform6
+.. highlight:: inform
.. epigraph::
if (condition) {
statement;
statement;
- ! ...
+ ...
}
but other designers have their own preferences, including::
if (condition) {
statement;
statement;
- ! ...
+ ...
}
if (condition)
{ statement;
statement;
- ! ...
+ ...
}
if (condition)
{
statement;
statement;
- ! ...
+ ...
}
Although we've not yet needed to use it, now would probably be a good time
William Tell: in his prime
============================
-.. highlight:: inform6
+.. highlight:: inform
.. epigraph::
William Tell: the end is nigh
===============================
-.. highlight:: inform6
+.. highlight:: inform
.. epigraph::
The game starts with meek John Covarth walking down the street. We set
up the game as usual:
-.. code-block:: inform6
+.. code-block:: inform
!% -SD
!============================================================================
Almost everything is familar, apart from a few details:
-.. code-block:: inform6
+.. code-block:: inform
Constant MANUAL_PRONOUNS;
Constant MAX_SCORE 2;
of an equals sign ``=`` is optional with ``Constant``; these two lines
have identical effect:
-.. code-block:: inform6
+.. code-block:: inform
Constant ROOM_SCORE 1;
Inform provides for displaying strings of text. Until now, we have shown
you:
-.. code-block:: inform6
+.. code-block:: inform
print "And now for something completely different...^"; return true;
...
example games, this happens quite a lot, so there is a yet shorter way
of achieving the same result:
-.. code-block:: inform6
+.. code-block:: inform
"And now for something completely different...";
You'll notice that -- unusually for a room -- our ``street`` object has
a ``name`` property:
-.. code-block:: inform6
+.. code-block:: inform
Room street "On the street"
with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
big box on the sidewalk; therefore we define a ``container`` set in the
street, which players may enter:
-.. code-block:: inform6
+.. code-block:: inform
Appliance booth "phone booth" street
with name 'old' 'red' 'picturesque' 'phone' 'booth' 'cabin'
connection to the as-yet-undefined café room and a default message for
the movement which is not allowed):
-.. code-block:: inform6
+.. code-block:: inform
Room street "On the street"
with name city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
"No time now for exploring! You'll move much faster in your
Captain FATE costume.";
-.. todo::
-
- Notice how the syntax coloring thinks that the exclaimation point
- above is a comment. This is another problem with the built-in inform6
- syntax highlighter.
-
That takes care of entering the booth. But what about leaving it?
Players may type EXIT or OUT while they are inside an enterable
container and the interpreter will oblige but, again, they might type
inside the booth) and to the north we have the café. We may provide for
this condition in the room's ``before`` property:
-.. code-block:: inform6
+.. code-block:: inform
before [;
Go:
also refer to the café, so we express our bafflement and force the
player to try something else:
-.. code-block:: inform6
+.. code-block:: inform
n_to cafe,
s_to [; <<Enter booth>>; ],
can’t see outside the container, only the inside_description is
displayed. Take for instance the following (simplified) example:
-.. code-block:: inform6
+.. code-block:: inform
Room stage "On stage"
with description
value: instead of a string, we write an embedded routine. Here's the
(almost) finished room:
-.. code-block:: inform6
+.. code-block:: inform
Room street "On the street"
with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
The description while inside the booth mentions the sidewalk, which
might invite the player to EXAMINE it. No problem:
-.. code-block:: inform6
+.. code-block:: inform
Appliance "sidewalk" street
with name sidewalk' 'pavement' 'street',
looks from the *inside*); but while we are on the street we need
something else to describe it:
-.. code-block:: inform6
+.. code-block:: inform
Appliance outside_of_cafe "Benny's cafe" street
with name 'benny^s' 'cafe' 'entrance',
by defining the ``description`` property as any of these:
- .. code-block:: inform6
+ .. code-block:: inform
description
"The town's favourite for a quick snack, Benny's caf@'e has a 50's
in just one place of our code, because this helps clarity. To achieve
this, we redirect the street's ``n_to`` property thus:
-.. code-block:: inform6
+.. code-block:: inform
n_to [; <<Enter outside_of_cafe>>; ],
nicety that many players regard as important. For this mission, we make
use of the ``LibraryMessages`` object.
-.. code-block:: inform6
+.. code-block:: inform
Include "Parser";
number of the message to be displayed, so you can change the default
with a test like this:
-.. code-block:: inform6
+.. code-block:: inform
if (lm_n == 39)
"That's not something you need to refer to in order to SAVE the day.";
-.. todo::
-
- That block of code above should be colored. Is there a defect in the
- syntax highlighting code?
-
where 39 is the number for the standard message "That's not something
you need to refer to in the course of this game" -- displayed when the
player mentions a noun which is listed in a room's name property, as we
.. note::
- remember that when we are testing for different values of the
+ Remember that when we are testing for different values of the
same variable, we can also use the switch statement. For the
Miscellany entry, the following code would work just as nicely:
- .. code-block:: inform6
+ .. code-block:: inform
...
Miscellany:
We define the café room in simple form:
-.. code-block:: inform6
+.. code-block:: inform
Room cafe "Inside Benny's cafe"
with description
We've mentioned a counter:
-.. code-block:: inform6
+.. code-block:: inform
Appliance counter "counter" cafe
with name 'counter' 'bar',
arrows are the only acceptable contents (recollect that ``~~``, to be
read as "not", turns true into false and vice versa):
- .. code-block:: inform6
+ .. code-block:: inform
before [;
Drop,Give:
We've also mentioned some customers. These are treated as NPCs, reacting
to our hero’s performance.
-.. code-block:: inform6
+.. code-block:: inform
Object customers "customers" cafe
with name 'customers' 'people' 'customer' 'men' 'women',
something interesting only while the player stays in the right place
(and hasn’t wandered, say, back into the toilet):
-.. code-block:: inform6
+.. code-block:: inform
if (location ~= cafe) return;
café room from the toilet for the first time, the value of the property
should be zero, so the statement block under the test:
-.. code-block:: inform6
+.. code-block:: inform
if (self.number_of_comments == 0) {
self.number_of_comments = 1;
We want the customers to indulge in witticisms once they see the
costumed Captain, but not on a completely predictable basis.
-.. code-block:: inform6
+.. code-block:: inform
if (random(2) == 1) ...
As a consequence of all this, we add an ``after`` property to the café
room object:
-.. code-block:: inform6
+.. code-block:: inform
Room cafe "Inside Benny's cafe"
...
The first line:
-.. code-block:: inform6
+.. code-block:: inform
if (noun ~= s_obj) return false;
Door objects require some specific properties and attributes. Let's
first code a simple door:
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door "toilet door" cafe
name name 'red' 'toilet' 'door',
little bit complicated and you''ll have to define routines for most
properties:
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door "toilet door"
with name 'red' 'toilet' 'door',
property`` is the thing. We have already talked about the external name
defined as part of an object's header information:
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door "toilet door"
to refer to the door. With identical effect, this could also have been
coded thus:
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door
with short_name "toilet door",
information method is perfect in that case -- but if it needs to change,
it's easy to write a routine as the value of ``short_name``:
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door
with name 'red' 'toilet' 'door'
identifier within parentheses; that is, with no external name and no
``short_name`` property, we might see:
- .. code-block:: inform6
+ .. code-block:: inform
You open the (toilet_door).
of our ``print`` statement, and then the standard rules would display
the internal ID:
- .. code-block:: inform6
+ .. code-block:: inform
You open the door to the toilet(toilet_door).
worth a shot. Let's provide a few improvements to our toilet door in
``before`` and ``after`` properties:
-.. code-block:: inform6
+.. code-block:: inform
before [ ks;
Open:
standalone routine is declared between the routine’s name and the
semicolon:
-.. code-block:: inform6
+.. code-block:: inform
[ BeenToBefore this_room;
declared between the ``[`` starting marker of the routine and the
semicolon:
-.. code-block:: inform6
+.. code-block:: inform
before [ ks;
spaces -- which are usable only within the embedded routine. When we
assign it thus:
-.. code-block:: inform6
+.. code-block:: inform
ks = keep_silent;
``keep_silent`` to ``true``, make the desired silent actions, and we
assign:
-.. code-block:: inform6
+.. code-block:: inform
keep_silent = ks;
toilet. A dead end? No, the description mentions a scribbled note on its
surface. This one should offer no problem:
-.. code-block:: inform6
+.. code-block:: inform
Object "scribbled note" cafe
with name 'scribbled' 'note',
detail throughout the next chapter, here we present a basic definition,
largely so that the key has a parent object.
-.. code-block:: inform6
+.. code-block:: inform
Object benny "Benny" cafe
with name 'benny',
like TOUCH KEY and TASTE KEY . So, to prevent any interaction with the
key while it’s in Benny’s pockets, we define a ``before`` property.
-.. code-block:: inform6
+.. code-block:: inform
before [;
if (self in benny)
(In fact, the hat-on-a-pole ``Prop`` introduced on page 91 had this
all-exclusive ``before`` property:
-.. code-block:: inform6
+.. code-block:: inform
before [;
default:
they'll try to examine the toilet room from the outside, it takes very
little effort to offer a sensible output just in case:
-.. code-block:: inform6
+.. code-block:: inform
Object outside_of_toilet "toilet" cafe
with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
``pname.h`` right after it. ``Replace`` tells the compiler that we're
providing replacements for some standard routines.
-.. code-block:: inform6
+.. code-block:: inform
Constant Story "Captain Fate";
Constant Headline
Maybe specially highlight the lines using pname?
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door
with pname '.x' 'red' '.x' 'toilet' 'door',
while leaving the ``outside_of_toilet`` unchanged:
-.. code-block:: inform6
+.. code-block:: inform
Object outside_of_toilet "toilet" cafe
with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
about sums it all up; pretty simple to describe -- not so simple to
code. Remember Benny's basic definition from the previous chapter:
-.. code-block:: inform6
+.. code-block:: inform
Object benny "Benny" cafe
with name 'benny',
We can now add some complexity, beginning with a ``life`` property. In
generic form:
-.. code-block:: inform6
+.. code-block:: inform
life [;
Give: !... code for giving objects to Benny
We have seen some of these actions before. We'll take care of the easier
ones:
-.. code-block:: inform6
+.. code-block:: inform
Attack:
if (costume has worn) {
returned. The solution, yet again (this really is a most useful
capability), is more local property variables:
-.. code-block:: inform6
+.. code-block:: inform
Object benny "Benny" cafe
with name 'benny',
come to the ``Give`` action of the ``orders`` property, which deals with
commands like BENNY, GIVE ME THE KEY):
-.. code-block:: inform6
+.. code-block:: inform
Give:
switch (noun) {
the object offered to the NPC. Remember that we can use the ``switch``
statement as shorthand for:
-.. code-block:: inform6
+.. code-block:: inform
if (noun == costume) { whatever };
if (noun == clothes) { whatever };
like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is
similar to that of the ``life`` property:
-.. code-block:: inform6
+.. code-block:: inform
orders [; ! handles ASK BENNY FOR X and BENNY, GIVE ME XXX
Give:
We must revisit the café room object:
-.. code-block:: inform6
+.. code-block:: inform
Room cafe "Inside Benny's cafe"
with description
room before the movement actually takes place, a good moment to
interfere if we want to prevent escape. The first line:
-.. code-block:: inform6
+.. code-block:: inform
if (noun ~= s_obj) return false;
The first three are covered by the test:
-.. code-block:: inform6
+.. code-block:: inform
if (benny.coffee_not_paid == true || benny.key_not_returned == true) ...
We must not forget a couple of tiny details in the café room:
-.. code-block:: inform6
+.. code-block:: inform
Object food "Benny's snacks" cafe
with name 'food' 'pastry' 'pastries' 'sandwich' 'sandwiches' 'snack'
And a not-so-trivial object:
-.. code-block:: inform6
+.. code-block:: inform
Object coffee "cup of coffee" benny
with name 'cup' 'of' 'coffee' 'steaming' 'cappuccino'
There's not a lot about the toilet room and its contents, though there
will be some tricky side effects:
-.. code-block:: inform6
+.. code-block:: inform
Room toilet "Unisex toilet"
with description
mentioned in the room's description to aid players in their dressing
duties.
-.. code-block:: inform6
+.. code-block:: inform
Appliance light_switch "light switch" toilet
with name 'light' 'switch',
course, set or clear it manually like any other attribute, with the
``give`` statement:
-.. code-block:: inform6
+.. code-block:: inform
give self on;
and check if a ``switchable`` object is on or off with the test:
-.. code-block:: inform6
+.. code-block:: inform
if (light_switch has on) ...
A ``switchable`` object is OFF by default. However, you’ll notice that
the has line of the object definition includes ``~on`` :
-.. code-block:: inform6
+.. code-block:: inform
has switchable ~on;
Surely that’s saying "not-on"? Surely that's what would have happened
anyway if the line hadn't mentioned the attribute at all?
-.. code-block:: inform6
+.. code-block:: inform
has switchable;
object to account for this. A couple of lines in the after property will
suffice:
-.. code-block:: inform6
+.. code-block:: inform
after [ ks;
Unlock:
routines``" of our game -- after the ``Initialise`` routine, for
instance -- include the following lines:
-.. code-block:: inform6
+.. code-block:: inform
[ InScope person;
if (person == player && location == thedark && real_location == toilet) {
So the test:
-.. code-block:: inform6
+.. code-block:: inform
if (person == player && location == thedark && real_location == toilet) ...
have ``moved``. Here is the reworked ``InScope`` routine. There are a
couple of new concepts to look at:
-.. code-block:: inform6
+.. code-block:: inform
[ InScope person item;
if (person == player && location == thedark && real_location == toilet) {
What is the actual :samp:`{statement}` that we'll repeatedly execute?
-.. code-block:: inform6
+.. code-block:: inform
if (item has moved)
PlaceInScope(item);
This leaves us the clothing items themselves, which will require a few
tailored actions. Let's see first the ordinary garments of John Covarth:
-.. code-block:: inform6
+.. code-block:: inform
Object clothes "your clothes"
with name 'ordinary' 'street' 'clothes' 'clothing',
into ordinary clothes. So now we are dealing with a Captain Fate in full
costume:
-.. code-block:: inform6
+.. code-block:: inform
Object costume "your costume"
with name 'captain' 'captain^s' 'fate' 'fate^s' 'costume' 'suit',
lines to the ``Initialise`` routine to make sure that the player does
not start the game naked:
-.. code-block:: inform6
+.. code-block:: inform
[ Initialise;
#Ifdef DEBUG; pname_verify(); #Endif; ! suggested by pname.h
check for errors when using his library, and he tells us how to use it.
So we include the suggested lines into our ``Initialise`` routine:
-.. code-block:: inform6
+.. code-block:: inform
#Ifdef DEBUG; pname_verify(); #Endif;
"William Tell", to write our customised messages and assign them to
``deadflag`` values greater than 2.
-.. code-block:: inform6
+.. code-block:: inform
[ DeathMessage;
if (deadflag == 3) print "Your secret identity has been revealed";
of things. We have already seen that we need a verb CHANGE. We'll make
it really simple:
-.. code-block:: inform6
+.. code-block:: inform
[ ChangeSub;
if (noun has pluralname) print "They're";
``Give`` action in the orders property handles every input not already
specified:
-.. code-block:: inform6
+.. code-block:: inform
orders [;
Give:
Not so. The library grammar that deals with ASK BENNY FOR... is this
(specifically, the last line):
-.. code-block:: inform6
+.. code-block:: inform
Verb 'ask'
* creature 'about' topic -> Ask
undefined input from the player. We need to extend the existing ASK
grammar:
-.. code-block:: inform6
+.. code-block:: inform
Extend 'ask'
* creature 'for' topic -> AskFor;
We might need some custom syntax highlighting here
-.. code-block:: inform6
+.. code-block:: inform
statement;
Our games have used these statements, about half of the Inform
possibilities:
-.. code-block:: inform6
+.. code-block:: inform
give obj_id attribute;
give obj_id attribute attribute ... attribute;
Although our example games haven't needed to use them, these looping
statements are sometimes useful:
-.. code-block:: inform6
+.. code-block:: inform
break;
continue;
hold for now; they're not immediately relevant to everyday code and have
mostly to do with printing and formatting:
-.. code-block:: inform6
+.. code-block:: inform
box
font
``Object`` and ``Verb`` the full supported syntax is more sophisticated
than the basic form presented here:
-.. code-block:: inform6
+.. code-block:: inform
Class class_id
with property value,
There's only a handful of useful directives which we haven't needed to
use:
-.. code-block:: inform6
+.. code-block:: inform
Attribute attribute;
but there's a whole load which are of fairly low importance for now:
-.. code-block:: inform6
+.. code-block:: inform
Abbreviate
Array
You can create and initialise a property in an object's ``with`` segment:
-.. code-block:: inform6
+.. code-block:: inform
property, ! set to zero / false
In each case, the ``value`` is either a compile-time ``expression``, or
an embedded routine:
-.. code-block:: inform6
+.. code-block:: inform
property expression,
You can refer to the value of a property:
-.. code-block:: inform6
+.. code-block:: inform
self.property ! only within that same object
and you can test whether an object definition includes a given property:
-.. code-block:: inform6
+.. code-block:: inform
(obj_id provides property) ! is true or false
Standalone routines are defined like this:
-.. code-block:: inform6
+.. code-block:: inform
[ routine_id; statement; statement; ... statement; ];
and called like this:
-.. code-block:: inform6
+.. code-block:: inform
routine_id()
These are embedded as the value of an object's property:
-.. code-block:: inform6
+.. code-block:: inform
property [; statement; statement; ... statement; ],
and are usually called automatically by the library, or manually by:
-.. code-block:: inform6
+.. code-block:: inform
self.property() ! only within that same object
are automatically initialised to zero every time that the routine is
called:
-.. code-block:: inform6
+.. code-block:: inform
[ routine_id var_id var_id ... var_id; statement; statement; ... statement; ];
is simply to initialise the matching local variables to the argument
values rather than to zero:
-.. code-block:: inform6
+.. code-block:: inform
routine_id(expression, expression, ... expression)
Every routine returns a single value, which is supplied either
explicitly by some form of return statement:
-.. code-block:: inform6
+.. code-block:: inform
[ routine_id; statement; statement; ... return expr; ]; ! returns expr
``statements`` is one -- ``return``, ``print_ret``, ``"..."` or
``<<...>>`` -- that causes an explicit return, then:
-.. code-block:: inform6
+.. code-block:: inform
[ routine_id; statement; statement; ... statement; ];
returns ``true`` and
-.. code-block:: inform6
+.. code-block:: inform
property [; statement; statement; ... statement; ]
Here's an example standalone routine which returns the larger of its two
argument values:
-.. code-block:: inform6
+.. code-block:: inform
[ Max a b; if (a > b) return a; else return b; ];
and here are some examples of its use (note that the first example,
though legal, does nothing useful whatsoever):
-.. code-block:: inform6
+.. code-block:: inform
Max(x,y);
require the functionality which the routine provides. We've mentioned
these library routines:
-.. code-block:: inform6
+.. code-block:: inform
IndirectlyContains(parent_obj_id, obj_id)
in your source file, in which case the library calls it at an
appropriate time. We've mentioned these optional entry point routines:
-.. code-block:: inform6
+.. code-block:: inform
DeathMessage()
And this, the only mandatory one:
-.. code-block:: inform6
+.. code-block:: inform
Initialise()
with the rest of the community. This example, with the name changed, is
from a file in the Archive:
-.. code-block:: inform6
+.. code-block:: inform
[xxxx i j;
if (j==0) rtrue;
more comprehensible; we haven't actually tested that it (still) works,
though that second ``else`` looks suspicious:
-.. code-block:: inform6
+.. code-block:: inform
[ xxxx i j;
if (i in player || i has static or scenery || j == nothing) return true;
* These five lines all do the same thing:
- .. code-block:: inform6
+ .. code-block:: inform
return true;
return 1;
* These four lines all do the same thing:
- .. code-block:: inform6
+ .. code-block:: inform
return false;
return 0;
* These four lines all do the same thing:
- .. code-block:: inform6
+ .. code-block:: inform
print "string"; new_line; return true;
print "string^"; return true;
* These lines are the same:
- .. code-block:: inform6
+ .. code-block:: inform
print value1; print value2; print value3;
print value1, value2, value3;
* These lines are the same:
- .. code-block:: inform6
+ .. code-block:: inform
<action noun second>; return true;
<<action noun second>>;
* These lines are also the same:
- .. code-block:: inform6
+ .. code-block:: inform
print "^";
new_line;
* These ``if`` statements are equivalent:
- .. code-block:: inform6
+ .. code-block:: inform
if (MyVar == 1 || MyVar == 3 || MyVar == 7) ...
* These ``if`` statements are equivalent as well:
- .. code-block:: inform6
+ .. code-block:: inform
if (MyVar ~= 1 && MyVar ~= 3 && MyVar ~= 7) ...
if (MyVar ~= 1 or 3 or 7) ...
expression; all that matters is its value: zero (false) or anything
else (true). For example, these statements are equivalent:
- .. code-block:: inform6
+ .. code-block:: inform
if (MyVar ~= false) ...
if (~~(MyVar == false)) ...
contains ``true`` (1), *not* whether its value is anything other than
zero.
- .. code-block:: inform6
+ .. code-block:: inform
if (MyVar == true) ...
``++MyVar;`` work the same as ``MyVar = MyVar + 1;`` For example,
these lines are equivalent:
- .. code-block:: inform6
+ .. code-block:: inform
MyVar = MyVar + 1; if (MyVar == 3) ...
if (++MyVar == 3) ...
cases the value of ``MyVar`` afterwards is 3. As another example,
this code (from Helga in "William Tell"):
- .. code-block:: inform6
+ .. code-block:: inform
Talk: self.times_spoken_to = self.times_spoken_to + 1;
switch (self.times_spoken_to) {
could have been written more succinctly like this:
- .. code-block:: inform6
+ .. code-block:: inform
Talk: switch (++self.times_spoken_to) {
1: score++;
* Similarly, the statements ``MyVar--;`` and ``--MyVar;`` work the same
as ``MyVar = MyVar - 1;`` Again, these lines are equivalent:
- .. code-block:: inform6
+ .. code-block:: inform
MyVar = MyVar - 1; if (MyVar == 7) ...
if (--MyVar == 7) ...
``phrase_matched`` attribute). To create them, you would use these
directives near the start of your source file:
-.. code-block:: inform6
+.. code-block:: inform
Attribute attribute;
their placement at the start of the game, we're left with object
definitions starting like this:
-.. code-block:: inform6
+.. code-block:: inform
Room street "A street in Altdorf"
same object tree, using "arrows". That is, we could have defined those
parent-and-child objects as:
-.. code-block:: inform6
+.. code-block:: inform
Room below_square "Further along the street"
Furniture -> stall "fruit and vegetable stall"
potatoes and the other fruit and vegetables where actually *on* the
stall. Then we might have used:
-.. code-block:: inform6
+.. code-block:: inform
Room below_square "Further along the street"
Furniture -> stall "fruit and vegetable stall"
distinction: you can use double quotes in name properties and Verb
directives:
-.. code-block:: inform6
+.. code-block:: inform
NPC stallholder "Helga" below_square
with name "stallholder" "greengrocer" "monger" "shopkeeper" "merchant"
given line number. In this case, the error was caused by a semicolon
after the description string, instead of a comma:
-.. code-block:: inform6
+.. code-block:: inform
Prop "assorted stalls"
with name 'assorted' 'stalls',
before the rest of statements can be reached. This is not always as
evident as it looks, for instance in a case like this:
-.. code-block:: inform6
+.. code-block:: inform
if (steel_door has open) {
print_ret "The breeze blows out your lit match.";
a separate file, which you Include into a short master game file. For
example:
-.. code-block:: inform6
+.. code-block:: inform
!============================================================================
Constant Story "War and Peace";
the public. This is fortunately very easy to check, since the game
banner ends with the letter "D" if the game was compiled in Debug mode:
-.. code-block:: inform6
+.. code-block:: transcript
Captain Fate
A simple Inform example
and ``-X``. Some of the more useful switches are:
:samp:`-~S`
-
Set compiler Strict mode off. This deactivates some additional error
checking features when it reads your source file. Strict mode is on by
default.
:samp:`-v5 -v8`
-
Compile to this version of story file. Versions 5 (on by default) and
8 are the only ones you should ever care about; they produce,
respectively, story files with the extensions .z5 and .z8 . Version 5
similar to Version 5 but allows a 512 Kbytes file size.
:samp:`-D -X`
-
Include respectively the debugging verbs and the Infix debugger in the
story file (see "Debugging your game" on page 197).
:samp:`-h1 -h2`
-
Display help information about the compiler. ``-h1`` produces
information about file naming, and ``-h2`` about the available
switches.
:samp:`-n -j`
-
``-n`` displays the number of declared attributes, properties and
actions. ``-j`` lists objects as they are being read and constructed
in the story file.
:samp:`-s`
-
Offer game statistics. This provides a lot of information about your
game, including the number of objects, verbs, dictionary entries,
memory usage, etc., while at the same time indicating the maximum
nearing the limits of Inform.
:samp:`-r`
-
Record all the text of the game into a temporary file, useful to check
all your descriptions and messages by running them through a spelling
checker.
library. The last line, however, is the direct consequence of our
tailored ``Extend``:
- .. code-block:: inform6
+ .. code-block:: inform
Extend 'give'
* 'homage' 'to' noun -> Salute;
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, ".")
-from tools.int_fiction import Inform6Lexer
+from tools.inform import InformLexer
from tools.transcript import TranscriptLexer
# Setup function.
def setup(app):
- app.add_lexer('inform', Inform6Lexer())
+ app.add_lexer('inform', InformLexer())
app.add_lexer('transcript', TranscriptLexer())
# -- General configuration ------------------------------------------------
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'default'
+pygments_style = 'friendly'
# The default Pygments highlight language.
highlight_language = 'none'
--- /dev/null
+"""
+Inform 6 syntax highlighting.
+
+This is an ultra-minimal version compared to the standard Pygments Inform6
+lexer, but is much more forgiving of syntax errors. And it handles the
+exclamation-inside-string case properly.
+"""
+
+from pygments.lexer import RegexLexer
+from pygments.token import (Text, Comment, Operator, Keyword, Name,
+ String, Number, Punctuation, Token)
+
+objects = ["Class", "Nearby", "Object"]
+
+directives = ["Abbreviate", "Array", "Attribute", "Btrace", "Class",
+ "Constant", "Default", "Dictionary", "End", "Endif", "Etrace",
+ "Extend", "Fake_action", "Global", "Ifdef", "Iffalse",
+ "Ifndef", "Ifnot", "Iftrue", "Ifv3", "Ifv5", "Import",
+ "Include", "Link", "Listsymbols", "Listdict", "Listverbs",
+ "Lowstring", "Ltrace", "Message", "Nearby", "Nobtrace",
+ "Noetrace", "Noltrace", "Notrace", "Object", "Property",
+ "Release", "Replace", "Serial", "Statusline", "Stub",
+ "Switches", "System_file", "Trace", "Verb", "Version",
+ "Zcharacter"]
+
+defining = ["[", "array", "attribute", "class", "constant", "fake_action",
+ "global", "lowstring", "nearby", "object", "property"]
+
+attributes = ["absent", "animate", "clothing", "concealed", "container",
+ "door", "edible", "enterable", "female", "general", "light",
+ "lockable", "locked", "male", "moved", "neuter", "on", "open",
+ "openable", "pluralname", "proper", "scenery", "scored",
+ "static", "supporter", "switchable", "talkable", "transparent",
+ "visited", "workflag", "worn"]
+
+properties = ["n_to", "s_to", "e_to", "w_to", "ne_to", "se_to", "nw_to",
+ "sw_to", "u_to", "d_to", "in_to", "out_to", "add_to_scope",
+ "after", "article", "articles", "before", "cant_go", "capacity",
+ "daemon", "describe", "description", "door_dir", "door_to",
+ "each_turn", "found_in", "grammar", "initial",
+ "inside_description", "invent", "life", "list_together",
+ "name", "number", "orders", "parse_name", "plural",
+ "react_after", "react_before", "short_name", "short_name_indef",
+ "time_left", "time_out", "when_closed", "when_open", "when_on",
+ "when_off", "with_key"]
+
+keywords = ["box", "break", "continue", "do", "else", "font off", "font on",
+ "for", "give", "has", "hasnt", "if", "in", "inversion", "jump",
+ "move", "new_line", "notin", "objectloop", "ofclass", "or",
+ "print", "print_ret", "provides", "quit", "read", "remove",
+ "restore", "return", "rfalse", "rtrue", "save", "spaces",
+ "string", "style bold", "style fixed", "style reverse",
+ "style roman", "style underline", "switch", "to", "until",
+ "while", "with"]
+
+constants = ["false", "true"]
+
+def wordlist(list):
+ return "(" + "|".join(list) + r")\b"
+
+class InformLexer(RegexLexer):
+ """
+ Inform code lexer.
+ """
+
+ name = 'Inform 6'
+ aliases = ['inform', 'inform6', 'i6']
+ filenames = ['*.inf']
+ mimetypes = ['text/x-inform', 'application/x-inform']
+
+ tokens = {
+ 'root': [
+ (r'"', String.Double, 'stringdouble'),
+ (r"'", String.Single, 'stringsingle'),
+
+ (r'\n', Text),
+ (r'[^\S\n]+', Text),
+ (r'!.*$', Comment.Single),
+ (r'\\\n', Text),
+ (r'\\', Text),
+ (r'=', Operator),
+ (r"[A-Za-z_,]+:", Name.Label),
+ (r"<<\S+>>", Name.Label),
+
+ (wordlist(objects), Name.Class),
+ (wordlist(keywords), Token.Keyword.Reserved),
+ (wordlist(properties), Name.Builtin),
+ (wordlist(directives), Name.Entity),
+ (wordlist(attributes), Name.Attribute),
+ (wordlist(constants), Name.Constant),
+
+ (r'[a-zA-Z_][a-zA-Z0-9_.]*', Name),
+ (r'(\d+\.?\d*|\d*\.\d+)([eE][+-]?[0-9]+)?', Number.Float),
+ (r'\d+', Number.Integer),
+
+ (r'.', Punctuation),
+ ],
+
+ 'stringdouble': [
+ (r'"', String.Double, '#pop'),
+ (r'.', String.Double),
+ (r'\n', String.Double),
+ ],
+
+ 'stringsingle': [
+ (r"'", String.Single, '#pop'),
+ (r'.', String.Single),
+ ],
+ }