Doe's Main IF Page
Doe's Inform 6 Primer
Inform 6 Glulx/Glk for Duncies
Grokking Glk
(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 2/08)
Doe's Tips
My Inform tips 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 (Resources/Examples).
Also check out the the Beginner's Guide.
Sit at the feet of the
master, little cricket, oohhmmm.
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.
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.
David Cornelson's House
Come on over to his house! Well, sort of -- David Cornelson created a
series of example games using a house to illustrate
how to program in Inform 6. It is now recreated at the IF Wiki. The coding is
incremental so one can see
how to develop a game step by step from one location to several, from basics to
classes. Beware the pink Jarbigruen, though, it acts like a demented Furbie.
INTERMEDIATE
Infancy
Roger Firth wrote this overview of Inform 6 objects. It starts out simple and
and gets more and more complicated from there. Also look at his
InfAct
which does the same with NPCs (non-player characters). Of course, it helps to
read the Inform 6 Manual first (hint, hint).
Alice: An Inform Tutorial
This tutorial by Gareth Rees is based on
his "Through the Looking Glass," which was originally written in
Inform 5.5. But Dr. Nelson 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.
Zarf's Handy Inform Tricks
Currently there isn't much here (seven tricks as of
3/4/2004), 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.
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
The Vile Zero Errors from Hell
Or maybe instead of learning you need help with a weird problem -- possibly
the Vile Zero Errors From Hell. (Possibly named so by David Glasser. :-))
This is a Zarf page, and he explains it all very nicely. However, you
won't think it's very nice (or funny) if it happens to you, so watch out!
(Although, admittedly, vezhs don't hang out in dark tunnels and eat people.
They just kick around interpreters.)
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 Game Source Code
and download all of them as well. 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.
Doe's Inform 6 Primer
There is also my Inform 6 Primer, which, naturally is brilliant (though sadly,
not completely finished). It is a basic Inform tutorial.
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.
|