! ---------------------------------------------------------------------------- !
! CheckOut.h
! original 1.0 May00 by Roger Firth (
[email protected]) for Inform 6
!
! ---------------------------------------------------------------------------- !
! Installation: add the line:
!
! Include "CheckOut";
!
! anywhere in your game AFTER the Include "Parser" statement.
!
! ---------------------------------------------------------------------------- !
! Implements a debugging verb CHECKOUT which attempts to test all your rooms
! for asymmetric and one-way paths, on the basis that these /may/ represent
! errors in setting up the inter-room connections.
!
! Given two rooms Beach and Cliffs, the path between them is 'symmetric' if
! you can move (for example) NORTH from the Beach to get to the Cliffs, and
! then SOUTH from the Cliffs to return to the Beach. An 'asymmetric' path
! would be (for example) NORTH from the Beach to the Cliffs, while SOUTHEAST
! or WEST or DOWN (but not SOUTH) would take you back. Asymmetric paths are
! reported only where no symmetric path exists; if SOUTH, SOUTHEAST, WEST and
! DOWN all lead from the Cliffs to the Beach, no output is generated.
!
! A one-way path is (for example) NORTH from Beach to Cliffs, with no path
! returning to the Beach.
!
! All of this works by analysing the properties N_TO, NE_TO ... and DOOR_TO.
! Inform allows any of these to be a routine, but CheckOut has no way of
! determining what such a routine might return, and so treats it as though
! no exit was defined. Therefore, be prepared for some misleading reports.
!
! You can define a list of rooms to be skipped when analysing the paths;
! for example, a maze might deliberately contain many asymmetric paths which
! you don't wish to report on. Include a line like this immediately before
! you Include the file (don't forget the zero at the end of the list):
!
! Array SkipRoom --> room1 room2 ... roomN 0;
!
! ---------------------------------------------------------------------------- !
#ifdef DEBUG; message "Compiling CheckOut.h";
Constant ExitCount 12;
Array ExitProp --> n_to ne_to e_to se_to u_to in_to
s_to sw_to w_to nw_to d_to out_to;
Array ExitName --> "North" "NorthEast" "East" "SouthEast" "Up" "In"
"South" "SouthWest" "West" "NorthWest" "Down" "Out";
#ifndef SkipRoom;
Array SkipRoom --> 1;
#endif;
[ CheckOutSub obj dest i k;
objectloop(obj ofclass Object) { ! Loop through all Objects.
if ((obj <= InformLibrary) ||
(obj == LibraryMessages) || ! Ignore system objects,
(obj in 1) || ! those with a parent,
(parent(obj)) || ! and those in SkipRoom,
(OmitRoom(obj))) continue; ! leaving (mostly) rooms.
for (i=0 : i<ExitCount : i++) { ! Test all possible exit properties.
dest = GetExit(obj, i);
if (dest == 0) continue; ! Not a (checkable) exit.
if (dest == obj) { PrintExit(obj, i); print "itself^"; continue; }
if (GetExit(dest, (i+(ExitCount/2))%ExitCount) == obj) continue;
k = ScanExits(obj, dest); if (k < 0) continue;
PrintExit(obj, i); print (name) dest, ": ";
switch (k) {
0: print "no apparent return^";
1: print "one asymmetric return^";
default: print (number) k, " asymmetric returns^";
}
} ! end_FOR
} ! end_OBJECTLOOP
];
[ ScanExits obj dest j k;
k = 0;
for (j=0 : j<ExitCount : j++ )
if (GetExit(dest, j) == obj)
if (GetExit(obj, (j+(ExitCount/2))%ExitCount) == dest) return -1; else k++;
return k;
];
[ GetExit obj i;
switch (ExitType(obj, ExitProp-->i)) {
0: return 0; ! nowhere
1: return 0; ! routine
2: switch (ExitType(obj.(ExitProp-->i), door_to)) {
0: return 0; ! door to nowhere
1: return 0; ! door to routine
2: return 0; ! door to door!
3: return ((obj.(ExitProp-->i)).door_to); ! door to room
}
3: return obj.(ExitProp-->i); ! room
}
];
[ ExitType obj prop;
if (obj == 0 || prop == 0) return 0;
if (obj.#prop > 2 || obj.prop == NULL) return 0;
switch(metaclass(obj.prop)) {
nothing, Class, String: return 0;
Routine: return 1;
Object: if (obj.prop has door) return 2; else return 3;
}
];
[ PrintExit obj i;
print (name) obj, "->", (string) ExitName-->i, "->";
];
[ OmitRoom obj i;
i = 0;
while (SkipRoom-->i) if (SkipRoom-->(i++) == obj) rtrue;
rfalse;
];
Verb 'checkout' * -> CheckOut;
#endif;
! ---------------------------------------------------------------------------- !