Roger Firth's IF pages | ![]() |
InfLight -- Inform debugging | ![]() |
![]() |
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 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...
|
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) |
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. |
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),
|
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),
-------------------------------------------------------------------------
|
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 |
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.