Roger Firth's IF pages

Home

InfLight -- Inform debugging

Email
Back up

If you've compiled with the D switch -- which is the default -- then you can use the debugging commands built into the Inform library. In this segment, we'll talk about commands which present information on the static state of your game, and allow some small modifications.

SHOWOBJ

SHOWOBJ displays the properties and attributes of an object (whether or not that object is currently in scope). So you could say:

 
Foyer of the Opera House

>SHOWOBJ HOOK
Object "small brass hook" (26) in "Cloakroom"
  has scenery supporter
  with name 'small' 'brass' 'hook' 'peg',
       description [...] (16978),

If you don't specify an object, SHOWOBJ displays the properties and attributes of your current location. This is useful because rooms often don't have a name property, thus preventing you from referring directly to them:

 
>SHOWOBJ
Object "Foyer of the Opera House" (24)
  has light visited
  with n_to "You've only just arrived, and besides, the weather outside seems
       to be getting worse." (20391),
       s_to Foyer bar (27),
       w_to Cloakroom (25),
       description "You are standing in a spacious hall, splendidly decorated in
       red and gold, with glittering chandeliers overhead. The entrance from the
       street is to the north, and there are doorways south and west." (20357),

Even so, you'll sometimes find it useful to be able to refer to rooms by name when fighting tricky problems; adding a name property to a room is easy enough:

 
Object  foyer "Foyer of the Opera House"
  with  name 'foyer',
        description
           "You are standing in a spacious hall...

TREE and SCOPE

The TREE command displays the names and numbers of all objects (generally a very long list), using indentation to reflect ownership:

 
>TREE
compass (6)
  the north wall
  the south wall
  the east wall
  the west wall
  the northeast wall
  the northwest wall
  the southeast wall
  the southwest wall
  the ceiling
  the floor
  the outside
  the inside
Darkness (19)
(Inform Parser) (21)
(Inform Library) (22)
(LibraryMessages) (23)
Foyer of the Opera House (24)
  yourself
    a velvet cloak (being worn)
Cloakroom (25)
  a small brass hook
Foyer bar (27)
  a scrawled message

More often, you're interested in only one part of the tree:

 
>TREE ME
yourself (20) (in Foyer of the Opera House 24)
  a velvet cloak (being worn)

>TREE CLOAK
a velvet cloak (28) (in yourself 20)

SCOPE lists those objects currently in scope:

 
>SCOPE
1: yourself (20)
2: a velvet cloak (28)

GOTO and GONEAR

To move the player directly from place to place, you can GOTO a room number (given by TREE or LIST ROOMS), or you can GONEAR an object -- something in that room, or the room itself if you've given it a name property:

 
>GOTO 27

Darkness
It is pitch dark, and you can't see a thing.

>GONEAR HOOK

Cloakroom
The walls of this small room were clearly once lined with hooks, though now only
one remains. The exit is a door to the east.

ABSTRACT and PURLOIN

To move objects around, use ABSTRACT or PURLOIN. These ignore scope and any attributes which might affect (or be affected by) a normal TAKE command, so you can re-arrange the scenery if you wish:

 
>ABSTRACT CLOAK TO HOOK
[Abstracted.]

>PURLOIN HOOK
[Purloined.]

>INV
You are carrying:
  a small brass hook
    a velvet cloak (being worn)

>SHOWOBJ HOOK
Object "small brass hook" (26) in "yourself"
  has moved scenery supporter
  with name 'small' 'brass' 'hook' 'peg',
       description [...] (18222),

LIST

SHOWOBJ, which works only on one object at once, is significantly enhanced by the LIST command provided by the ObjLstr.h package. Using it, you can execute SHOWOBJ on a whole range of objects. For example:

 
>LIST DIRS
Object "Foyer of the Opera House" (24)
  has light visited
  with n_to "You've only just arrived, and besides, the weather outside seems to
       be getting worse." (20391),
       s_to Foyer bar (27),
       w_to Cloakroom (25),
       -------------------------------------------------------------------------
Object "Cloakroom" (25)
  has light
  with e_to Foyer of the Opera House (24),
       -------------------------------------------------------------------------
Object "Foyer bar" (27)
  with n_to Foyer of the Opera House (24),
       -------------------------------------------------------------------------

Especially flexibly, you can select objects according to their properties, attributes, or both:

 
>LIST HAS SCENERY
Object "small brass hook" (26) in "Cloakroom"
  has scenery supporter
  with name 'small' 'brass' 'hook' 'peg',
       description [...] (18133),
       -------------------------------------------------------------------------
Object "scrawled message" (29) in "Foyer bar"
  has scenery
  with name 'message' 'sawdust' 'floor',
       description [...] (18221),
       number 0,
       -------------------------------------------------------------------------

>LIST WITH BEFORE AFTER
Object "yourself" (20) in "Foyer of the Opera House"
  has animate concealed proper transparent
  with before NULL,
       after NULL,
       life NULL,
       orders 0,
       description [...] (4955),
       describe NULL,
       number 0,
       time_out NULL,
       each_turn NULL,
       capacity 100,
       short_name [...] (4952),
       parse_name 0,
       -------------------------------------------------------------------------
Object "velvet cloak" (28) in "yourself"
  has clothing general moved worn
  with name 'handsome' 'dark' 'black' 'velvet' 'satin' 'cloak',
       before [...] (18202),
       after [...] (18218),
       description "A handsome cloak, of velvet trimmed with satin, and slightly
       spattered with raindrops. Its blackness is so deep that it almost seems
       to suck light from the room." (20479),
       -------------------------------------------------------------------------

CHECKOUT

While LIST tells you about all of your rooms, it doesn't perform any verification. For that, try my CheckOut.h package, which implements a single debugging command CHECKOUT. This looks at the paths between rooms -- well, those that are easy to analyse anyhow -- and reports on one-way and asymmetric paths (those where turning by 180 degrees doesn't bring you back to your starting point). Sometimes those are intentional, sometimes the result of errors in creating or editing the game's map. There's nothing to demonstrate here -- the example game is entirely symmetric -- but running it within the standard example Advent.inf produces a sizeable crop of reports:

 
At End Of Road
You are standing at the end of a road before a small brick building. Around you
is a forest. A small stream flows out of the building and down a gully.

>CHECKOUT
At End Of Road->North->In Forest: no apparent return
At Hill In Road->South->In Forest: no apparent return
In Forest->North->itself
In Forest->South->itself
In Forest->West->itself
In Forest->North->At End Of Road: no apparent return
In Forest->East->In A Valley: no apparent return
In Forest->South->In Forest: no apparent return
In Forest->West->In A Valley: no apparent return
In Forest->Down->In A Valley: no apparent return
At Slit In Streambed->East->In Forest: no apparent return
At Slit In Streambed->West->In Forest: no apparent return
Outside Grate->East->In Forest: no apparent return
Outside Grate->South->In Forest: no apparent return
Outside Grate->West->In Forest: no apparent return
At West End of Hall of Mists->Up->Maze: one asymmetric return
At West End of Hall of Mists->South->Maze: one asymmetric return
dots
At Fork in Path->NorthEast->At Junction With Warm Walls: one asymmetric return
At Junction With Warm Walls->South->At Fork in Path: one asymmetric return
SW End of Repository->Down->Outside Grate: no apparent return

DUMP

An alternative way of finding out the current state of your game is the DUMP command provided by my Dump.h package. Working at a somewhat lower level than the other commands in this segment, DUMP focuses on the Z-machine's storage allocation. You can inspect the game's memory map (including where the values can be found):

 
>DUMP
------  DYNAMIC (read/write)
00000:  Header:                 $0000
00040:  String pool:            $0040
00042:  32 Low strings:         $0018-->0
00082:  64 Abbreviations:       ($0018-->0)+64
00102:  Header extension:       $0036-->0
00000:  Alphabet:               $0034-->0
00000:  UniCode:                (($0036-->0)+6)-->0
0010A:  Property defaults:      $000A-->0
00188:  Object tree:            ($000A-->0)+126
0031E:  Common properties:      #cpv__start
005F4:  Class numbers:          #classes_tables
00600:  Identifier names:       #identifiers_table
0081C:  Array names:            #array_names_offset
0081E:  Individual properties:  #ipv__start
00836:  Global variables:       $000C-->0
00A16:  Arrays:                 #array__start
013DF:  Terminating chars:      $002E-->0
------  STATIC (read only)
013E0:  Grammars:               $000E-->0
01BAB:  Action pointers:        #actions_table
01CBB:  Preactions (not used):  #preactions_table
01CBD:  Adjectives (not used):  #adjectives_table
01CBD:  Dictionary:             $0008-->0
------  HIGH (no read/write)    $0004-->0
02978:  First unreadable byte:  #readable_memory_offset
02979:  Initial PC:             $0006-->0
02978:  Zcode:                  #code_offset (packed)
14D9C:  Static strings:         #strings_offset (packed)
17268:  Top of memory           $001A-->0 (packed)

a range of addresses:

 
>DUMP 0 $3F
00000:  059D0001 29782979 1CBD010A 083613E0
00010:  00123030 30333239 00425C9A 76620646
00020:  1E500050 001E0101 00000000 0F0E13DF
00030:  00000100 00000102 00000000 362E3231

or any of the Z-machine tables:

 
>DUMP HEADER

------------  Header
00000:    05  Z-machine version
00001:    9D  Interpreter flags: timed_keys/fixed_pitch/italic/bold/colour
00002:  0001  Game release
00004: 02978  ==>High memory
00006: 02979  ==>Initial PC
00008: 01CBD  ==>Dictionary
0000A: 0010A  ==>Objects
0000C: 00836  ==>Global variables
0000E: 013E0  ==>Static memory
00010:  0012  Game flags: undo/fixed_pitch/
00012: "000329" Game serial
00018: 00042  ==>Abbreviations
0001A: 17268  Length
0001C:  7662  Checksum
0001E:    06  Interpreter: IBM PC
0001F: "F"    Interpreter version
00020:    1E  Screen height (lines)
00021:    50  Screen width (chars)
00022:  0050  Screen height (units)
00024:  001E  Screen width (units)
00026:    01  Font width (units)
00027:    01  Font height (units)
00028:  0000  Routines offset / 8
0002A:  0000  Strings offset / 8
0002C:    0F  Background colour
0002D:    0E  Foreground colour
0002E: 013DF  ==>Terminating chars
00030:  0000  Pixels to stream 3
00032:    01 00  Interpreter conformance
00034: 00000  ==>Alphabet
00036: 00102  ==>Header extension
00038:  0000  -
0003A:  0000  -
0003C: "6.21" Inform version

To be honest, you rarely need to be this concerned with actual storage locations, but just occasionally it can be the only way to discover what's actually happening.


Moving on along, we next look at dynamic debugging -- watching it all go wrong.