Doe's Main IF Page
Inform Glulx/Glk for Duncies
Unglklib
Storybook Kingdom of IF
An Iffy Theory
IF Art Gallery
My Games
IF Review Conspiracy
IFRC Archive at Brass Lantern
Parsifal
|
Other's Tips
Inform tutorials/resources.
(updated 5/11/02)
Doe's Tips
My Inform primer and sample code.
Why reinvent the wheel? Or spin it, going around in circles? For years I have
squirreling away posts from raif -- those I considered the best Inform
programming tips. So now I am sharing my nuts. When my
hard disk crashed a couple of years I lost some, but I still have quite a few.
They appear as originally posted: question, answer, and credit (who
asked/answered). This uses a
JavaScript
search engine (frames) to search the
articles I hoarded. Think of it as a mini-Google, focused exclusively Inform.
Note:
Q&As are usually intermediate to tricky Inform programing, not newbie Q&As.
Currently there are
50
articles. Enter nothing to list all. If you have problems loading a specific
article, push the GO button again.
(Click "Best of Raif" for search engine.)
INTRODUCTORY
Inform 6 Home Page
One of the best ways to
learn
Inform is to study the source code to Graham Nelson's example games.
Especially, "Toyshop," which has code for a matchbook, writing on a
blackboard, a driveable car, timers, daemons, and more. Sit at the feet of the
master, little cricket, oohhmmm. Dr. Nelson's pages have been updated and have a classy new look.
The Inform FAQ
The Inform FAQ by Roger Firth, along with others, answers some very useful
newbie questions. The answers at the end also cover
more complicated programming problems. After Roger corners the FAQ arena he
plans to never volunteer for anything ever again.
Int Fic Inform Tips
I don't know why Lucian P. Smith hides this page so well, but then I am
confused about what "Interactive Fictions Patterns" are too. However,
I do know that six people contributed to a
very nice and UNCONFUSING newbies' introduction to Inform.
Inform for Beginners
(Old)
By Jeff Johnson, covers much same ground as Int Fic, some in more detail, some
less, plus some additional things. BTW - Who is Jeff? Is he still
around? I haven't seen any posts by him. One of those unexplained
mysteries of life, I guess, like Turkish
delight. Maybe he IS missing, this guide comes to a screeching halt
3/4th of the way through.
Inform Programing
(Old)
This is a quick overview of Inform by Andrew Clover. While not really an
in-depth tutorial, there is one helpful page answering some basic programming
questions. But I
wonder how he got to use Dr. Nelson's home page's graphic. Must have
connections.
9/27/99 It has been pointed out to me this is page rather dated and also,
sadly, unfinished.
For help with which files to download to get you up and running with
Inform, visit,
Help! Where do I download Interactive Fiction stuff?
by Jonadab, instead.
INTERMEDIATE
Zarf's Handy Inform Tricks
Currently there isn't much here (six tricks on
11/06/02), but, hey, it's Zarf! -- so who cares? About one half are ways
to fix bugs, the other half are tips on ways to do something tricky and Zarfian
(hmmm, maybe that's synonymous).
Inform Z/Glulx Troubleshooting
Emily Short's Inform tips page covers tricky things she has learned the hard way about regular Inform and Inform Glulx. You can really benefit from her experience.
Alice: An Inform Tutorial
This tutorial by Gareth Rees is on Graham Nelson's web page. It is based on
Rees' "Through the Looking Glass," which was originally written in
Inform 5.5. But Dr. Nelson has upgraded it (somewhat) for Inform 6. It takes
you step-by-step through the creation of the game, in three stages. Rees is an
advanced programmer, so all but the first stage may be too complicated for the
newbie. This link appears to be broken.
Inform Developer's Guide
By Jim Fisher, this site has several articles by him and others covering
various Inform programming problems -- from intermediate to advanced.
Informatory
Keep getting confused by Inform's mathematical operants? (So similar to c, but
not c.) Check here. By
Roger Firth, this "quick reference" is intended to be a supplement to
the Inform manual. It
offers brief summaries of the common Inform 6 commands and is also
downloadable. Of course, it helps to read the manual first (hint, hint).
InfLight - an overview of Inform debugging
Another page from Roger Firth, a great one on Inform debugging. Do you
have compiling errors? Find out why and how to fix them. Also covers
various debugging tools.
ADVANCED/ALL
Raif's (Rec.Arts.Int-Fiction) Frequently Asked Questions
Or maybe instead of learning you need help with a weird problem -- possibly Vile Zero Errors From Hell. (Who named those errors
that? Wasn't it the author of this FAQ?) In section 4.6, David Glasser outlines
the problem and its solutions. You can also find a discussion of text editors,
etc. I am very glad Glasser included vzeh, on the other hand, if he named it,
he OWED everyone a explanation. :-) Also check out Zarf's (Andrew Plotkin's)
The Vile Zero Errors from Hell.
Library Contributions at the IF Archive
Wait a minute! Maybe some tricky programming you can't figure out has already
done and is right under your nose, only you don't realize it. So break down and
download
ALL the library "add-ons" if you haven't already. Also bump on over
to the
contributed source code for games
and download all of them as well. You also might check out Inform 5.5, some
contributed include (.h) files were never updated. Yah! Fill up your hard disk!
(Actually, text files take up very little room.)
Last, but NOT least, read the
The Inform Designer's Manual
(new
fourth edition, available in PDF format). Commonly referred to as the "DM," the manual is always your best
reference
to Inform. No, the D does not stand for what you call it when you are hopping
mad because you unable to solve something. Instead of cursing, visit
Rec.Arts.Int-Fiction
(requires newsreader). Or search
Google.
My Inform Primer
This primer is a "sort of" Inform tutorial.
(This needs an update -- in writing and format and -- but otherwise everything
is still relevant.)
Updated 11/12/99.
Lower Case Room Names
Useful Find Hidden Objects Routine
An Elevator
A Two-Way Window
Invisiclues Hint System
Add To Scope Problems
Note:
If copying code, you will have to replace all the HTML
"<"
and ">"s with < and >. Also, all the following code has
been tested.
Use the same as print (name) location; or print (name) noun; -- print
(lowercase) location; To make upper case, change 'A' to 'a', 'Z' to 'z' and
('a' - 'A') to ('A' - 'a').
There might be instances where one would want a room name returned lower case
from routine, or to appear in all lower/upper case on the status line.
Array name_buffer->64;
[ lowercase n i;
name_buffer-->0 = 0;
@output_stream 3 name_buffer;
print (name) n;
@output_stream -3;
for (:i < (name_buffer-->0): i++ )
{ if (name_buffer->(i+2) >= 'A' && name_buffer->(i+2) <= 'Z')
name_buffer->(i+2) = name_buffer->(i+2) + ('a' - 'A');
print (char) name_buffer->(i+2);
}
];
When player searches and finds a hidden object,
this automatically puts it in the player's "hands."
If the player's hands are full, it puts a carried object
in the sack object to make room for the new object in
the player's hands (if the sack is carried and has enough
room). Or it just puts the new object in the location.
In other words -- this keeps a hidden object out of the
object tree until it is found during a search. Then it picks
up the new object automatically, if the player or sack has room.
! Example:
!
! Object bureau "bureau"
! with blah blah,
! before
! [; Search : If (self hasnt general)
! { give self general;
! Findobject(key);
! "You find a key."; }
! ];
[ FindObject item j k;
k = NCarried();
if ((k+1) > player.capacity) ! if more than player can carry
{ if (SACK_OBJECT notin player)
{ move item to location; ! no sack, move to location
rtrue;
}
k = 0; ! otherwise find object can remove from
objectloop (j in player) ! player and put in sack (to make room)
if (j ~= SACK_OBJECT && j hasnt worn && j hasnt light)
k = j;
if (k ~= 0) ! move object in player to sack
{ if (SACK_OBJECT hasnt open) give SACK_OBJECT open;
keep_silent=1; <Insert k SACK_OBJECT> keep_silent=0;
if (k in SACK_OBJECT) ! move newly found object to player
{ give item moved;
move item to player;
rtrue;
}
}
move item to location; ! no carried object that is moveable
rtrue; ! so move newly found object to location
}
give item moved; ! player capacity not exceeded
move item to player; ! so move newly found object to player
rtrue;
];
!From Gareth Rees' Christminister.
[ NCarried i j;
objectloop(i in player)
if (i hasnt worn) j++;
return j;
];
This is an "old fashioned" elevator. There are two sets of doors.
Those inside the elevator and those outside the elevator. Those outside must
have a copy on
each floor. This is so the player can go to any floor (using the stairs) and
find the
elevator doors closed on all the floors, except the one where the button was
just pushed. I lifted this directly from an unreleased game of mine and think
it is the easiest way to code an elevator. It is quite expandable for more
floors and, of course, can be new without rattling doors.
If using this code in a game, I would appreciate credit since this is lifted
from an unreleased game of mine. (When my game appears I don't want people
thinking I copied YOU. Hehe.)
Object elevator "Elevator"
has light
with name "elevator",
cur_floor 2,
time_left 0,
description
[; print_ret "You are in an old-fashioned elevator. Three buttons on the
wall are labeled ~1~, ~2~ and ~3~. On a panel over the
southern elevator doors, the ~", self.cur_floor, "~ is lit.";
],
s_to e_doors,
time_out
[; keep_silent=1; <Open e_doors>; keep_silent=0;
if (player in self)
print_ret "Rattle. The ~", self.cur_floor, "~ on the panel
lights up and the elevator doors slide open.";
if (location==lobby or second_floor or third_floor)
{ if (location.number == self.cur_floor)
print "^Rattle. The metal doors on the northern wall slide open.^";
}
rtrue;
];
Elevator_button -> one_butt "one"
has concealed
with name "one" "1",
number 1;
Elevator_button -> two_butt "two"
has concealed
with name "two" "2",
number 2;
Elevator_button -> three_butt "three"
has concealed
with name "three" "3",
number 3;
Object -> e_doors "elevator doors"
has door static open
with name "elevator" "doors",
when_open "The elevator doors are open.",
when_closed "The elevator doors are closed.",
door_dir s_to,
door_to
[; switch(elevator.cur_floor)
{ 1 : return lobby;
2 : return second_floor;
3 : return third_floor;
}
],
before
[; Close : switch(elevator.cur_floor)
{ 1 : give ff_doors ~open;
2 : give sf_doors ~open;
3 : give tf_doors ~open;
}
Open : switch(elevator.cur_floor)
{ 1 : give ff_doors open;
2 : give sf_doors open;
3 : give tf_doors open;
}
];
The above opens both the inside and outside doors. The inside doors are part of
the elevator.
Below is the outside doors class.
class sliding_doors
has door
with name "doors" "metal",
when_open "The sliding doors to the elevator are open.",
when_closed "The sliding metal doors are closed.",
door_dir n_to,
door_to elevator;
An instance of the outside doors class, on the first floor. Duplicate for
additional floors.
Sliding_doors -> ff_doors "metal doors";
There also has to be an outside button object (class instance) on each floor
that is similar to the buttons inside the elevator. This is the first floor
button.
Elevator_button -> call1_butt "call button"
with name "call",
number 1;
How the elevator button works.
class elevator_button
class button_class
with
number 0,
before
[ i j k; Push : i = self.number;
j = elevator.cur_floor;
if (i == j) "Nothing happens.";
if (i > j) k = i - j;
else k = j - i;
keep_silent=1; <Close e_doors>; keep_silent=0;
elevator.cur_floor = i;
StartTimer(elevator, k);
if (self==one_butt or two_butt or three_butt)
"Rattle. The doors slide close and the elevator
starts moving."; ! inside button pushed
"You hear a distant rattling, then a faint
grating sound."; ! outside button pushed
];
A simple, unopenable two-way (visibility-wise) window. This uses the lowercase
routine from above.
class is_window
has concealed static openable
with name "window",
! inside and outside locations of a window
inside_wind 0,
outside_wind 0,
before
[; Examine,
Open : print "The window";
if (self has pluralname) print "s are ";
else print " is ";
"painted shut.";
Search : if (location == self.outside_wind)
{ print "Through the ", (name) self, ", you can see the ",
(lowercase) self.inside_wind;
if (child(self.inside_wind)~=0)
{ print ". You can also see ";
WriteListFrom(child(self.inside_wind),
ENGLISH_BIT + RECURSE_BIT + TERSE_BIT + CONCEAL_BIT);
" inside.";
}
".";
}
print "Through the ", (name) self, ", you can see the ",
(lowercase) self.outside_wind;
if (child(self.outside_wind)~=0)
{ print ". You can also see ";
WriteListFrom(child(self.outside_wind),
ENGLISH_BIT + RECURSE_BIT + TERSE_BIT + CONCEAL_BIT);
" outside.";
}
".";
];
Object library_wind "library window"
class is_window
with name "library",
inside_wind library,
outside_wind lawn,
found_in library lawn;
This uses a hint class. One hint is seen at a time, except for previously seen
hints, which will be shown without the need to hit the "h" key again. Works
with Graham Nelson's menus.h or L. Ross Raszewski's altmenu.h. Hints should
appear in the menu help system.
class Hintobj
with hints_seen 0,
hint_done 0,
the_hints "Put list of hints here (in the object of this class).",
description
[; self.showhints(); rtrue;
],
showhints
[ max i k;
max = (self.#the_hints / 2);
for (i = 1: (i <= max): i++)
{ if ((i==1) && ((max > 1) && (self.hints_seen < max)))
print "There are ", (LanguageNumber) max, " increasingly clear \
hints. Press H for another hint, any other key to quit.^^^";
print "(", i, "/", max, ") ";
print (string) (self.&the_hints-->(i-1));
new_line; new_line;
! How many times through this loop? That is the number of the current
! hint. Starting with 1 = 0 hints_seen.
if (self.hints_seen == (i-1)) self.hints_seen = self.hints_seen + 1;
! Only call read_char if currently on the last hint seen and
! skip on the very last hint.
if ((i < max) && (i == self.hints_seen))
{ @read_char 1 0 0 k;
if (k ~= 'H' or 'h') return;
}
}
];
The following puts hints (at appropriate time in game play) on the help screen.
Hint_done
double checks that a completed hint is not inadvertently put back on on the
help screen. Basically it just pops a new hint into the Hint Object, which is a
menu. Readying a hint takes place in game code:
! after
! [; Take : if (self hasnt general
! { give self general;
! HintReady(Hint1);
! "You pick up the axe.";
! }
! ];
[ HintReady h;
if ((h.hint_done == 0) && (h hasnt general))
{ give h general;
move h to Hints;
}
];
Removes old hints. This never need be called. Depends how sensitive one wants
one's hint system. Old hints can remain on the help screen. Would also be
called in game code for each hint.
[ HintDone h;
if (~~(h.hint_done))
{ h.hint_done = 1;
if (h in Hints) remove h;
}
];
This is a hint example. This Menu would be part of a larger menu help system.
Notice there are no commas between the the_hints.
Menu -> Hints "Hints";
Option Hint1 "How do I get the kitten out of the tree?"
class Hintobj
with the_hints "Try chopping down the tree."
"Too destructive? Try a garden hose."
"No hose? Read raif for other ways to get the kitten down.";
Basically parent does not work on objects that are added to scope. It returns
nothing. It won't return the object that contains the add_to_scope object as
its parent. This occurs
through out the whole library, since ObjectScopedBySomething is only called
twice, in Verblibm.h. Most of the time this will probably not matter or even
be desired behavior. However, sometimes it definitely is NOT. Also, I
personally, think parent should always return something for an object in the
tree, until one has reached the top object. I found this "bug" when
updating outofrch.h. My "fix" for IndirectlyContains (which relies on
parent) comes from that:
[ ScopedContains o1 o2 o3;
while (o2~=0)
{ if (o1==o2) rtrue;
o3 = ObjectScopedBySomething(o2); ! added line
if (o3 == 0) o2 = parent(o2); ! these two lines slightly changed
else o2 = o3;
}
rfalse;
];
! Example:
if (ScopedContains(remote, button))
"The button is part of the remote control.";
Another way around this is never to use add_to_scope, but do this instead:
Object owner "owner"
has transparent
with blah blah;
Object -> part1 "part one"
has static container openable;
Object -> part2 "part two"
has static;
Transparent makes the owner's subobjects accessible, while static keeps the
parts nontakeable, and both parent(part1) and parent(part2) will work correctly.
|