Small IF Logo

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
Inform Programming Tips


Contents


Other's Tips
Inform tutorials/resources.
(updated 2/08)

Doe's Tips
My Inform tips and sample code.


Others' Tips


Go To Best of Raif Search Engine
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 Tips


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 "&lt;" and "&gt;"s with < and >. Also, all the following code has been tested.




Lower (& Upper) Case Room (Object) Names

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);
  }

];


A Useful Routine to Find Hidden Objects

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;
];


An Elevator (Three Floors)

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
];


Two-Way Window


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;


Yet Another Invisiclues Type Hint System


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.";


Add To Scope Problems


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.


Infotips Table of Contents (Top)

Email any questions or suggestions for additional links to: doeadeer3@aol.com.

IF Logo Graphic Copyright ? 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 by Marnie Parker. All rights reserved.
Copy or redistribution prohibited.