Open eriktorbjorn opened 5 years ago
Looking at the Mini-Zork II message I saw, that may have had the same bug after all:
>WAIT
Time passes...
The balloon ascends.
Volcano By Wide Ledge, in the basket
You are about 200 feet up, very near the rim of the volcano. To the west is
a wide ledge.
There is a yellow sphere here.
There is a blue label here.
I.e. the objects aren't listed as being in the basket.
I did get another crash, but I think it may have been caused by this bug. I was in brief mode at the time when I saw this:
>NORTH
North End of Garden
There is a beautiful unicorn here cropping grass.
There is a Fatal error: Store out of dynamic memory
[Hit any key to exit.]
So does the "fantasize" spell work "better" in brief mode than in verbose mode? Worth investigating, perhaps?
Edit: The unicorn has OPENBIT
, so it's probably related to there being a "container" in the room.
This one is still confusing me. But it looks like it will only print fantasies if there is an open container in the room. It will then print the fantasy as if it's part of the room's inventory, but it will (or at least may?) also print the container's contents as if is part of the room's inventory. E.g.
>LOOK
Inside the Barrow
You are inside an ancient barrow hidden deep within a dark forest. The barrow
opens into a narrow tunnel at its southern end. You can see a faint glow at the
far end.
There is a dented steel box here.
The steel box contains:
A fancy violin
>LOOK
Inside the Barrow
You are inside an ancient barrow hidden deep within a dark forest. The barrow
opens into a narrow tunnel at its southern end. You can see a faint glow at the
far end.
There is a dented steel box here.
There is a gold ingot here.
There is a Stradivarius here.
Of course, in this example I have fixed the crash but it still does not seem right.
I just realized that Zarf's repository contains an earlier version (identified as Release 22 with Mac-specific tweaks). I guess I should take a closer look at that one, though I don't have the time right now.
Edit: At the very least, Release 22 doesn't depend on there being a container in the room, and it doesn't seem to mess up printing the contents of containers if there is. There are two loops in PRINT-CONT
. In Release 22, the hallucination is printed in the second loop. In the most recent version, it's printed in the first loop. I need to look closer at this...
If I understand the old PRINT-CONT
correctly, though I'm sure this description leaves out some corner cases:
The routine keeps track of which LEVEL
the objects are listed at. Objects in the room are listed at level -1. There is also a "verbose" flag (V?
) but I'm not sure it fills any function.
It works in two passes, unless it's printing the player's inventory in which case the first pass is skipped.
The first pass prints the description of all untouched objects. If the object has NDESCBIT
, no description is printed. If the object can be looked into (e.g. it's an open container), and its parent does not have a DESCFCN
, its contents are listed with PRINT-CONT
at level 0. (It's during this pass that the new code, incorrectly it seems, prints hallucinations.)
In the second pass, the adventurer any any vehicle he's in are skipped. Invisible objects and objects with NDESCBIT
are also left out. Unless it's printing the player's inventory, untouched objects with FDESC
are left out (since they were printed by the first pass). If it's the first object to be listed, a "firster" may be printed (e.g. "Sitting on the object is:"). If a firster is printed, the level is increased by one. The object is then printed by DESCRIBE-OBJECT
, which uses the level to tell if and how much the text should be indented. If the object can be seen into, the level is increased by one and the contents is listed with PRINT-CONT
.
Once the second pass runs out of objects, it may print a hallucination (if the current level is 0) and the contents of the player's vehicle (at the current level plus 1).
Phew!
So what does that mean? Well, for one thing it means that there will never be hallucinations in a room unless it contains other objects, and at least one of them has to be printed by the second pass (i.e. if the room only contains untouched objects with FDESC
, there will be no hallucination because then the level will still be -1.)
Hallucinations only appear to be part of the room's inventory, not of any container in the room.
Indentation can sometimes be a bit odd. For instance:
>LOOK
Gazebo
This is a gazebo in the midst of a formal garden. It is cool and restful here. A
tea table adorns the center of the gazebo.
Sitting on the table is:
A matchbook
A china teapot
A place mat
A newspaper
A letter opener
>DROP SWORD
Dropped.
>LOOK
Gazebo
This is a gazebo in the midst of a formal garden. It is cool and restful here. A
tea table adorns the center of the gazebo.
An Elvish sword of great antiquity is here.
Sitting on the table is:
A matchbook
A china teapot
A place mat
A newspaper
A letter opener
That's probably because the presence of the sword causes LEVEL
to be increased from -1 to 0. So the contents of the table is listed at higher level than it was before. What if I had dropped a container instead?
Gazebo
This is a gazebo in the midst of a formal garden. It is cool and restful here. A
tea table adorns the center of the gazebo.
There is a dented steel box here.
The steel box contains:
A fancy violin
Sitting on the table is:
A matchbook
A china teapot
A place mat
A newspaper
A letter opener
Putting the box on the table works fine, though:
Gazebo
This is a gazebo in the midst of a formal garden. It is cool and restful here. A
tea table adorns the center of the gazebo.
Sitting on the table is:
A steel box
The steel box contains:
A fancy violin
A matchbook
A china teapot
A place mat
A newspaper
A letter opener
If I can duplicate these cases with the new code, and make the hallucinations work, I'd say I'm in pretty good shape.
The indentation seems to have been fixed in later games. E.g. this is what part of the routine looks like in Zork II:
(<AND <FIRST? .Y> <SEE-INSIDE? .Y>>
<SET LEVEL <+ .LEVEL 1>>
<PRINT-CONT .Y .V? .LEVEL>)>)>
The zork-substrate code looks like this:
(<AND <FIRST? .Y> <SEE-INSIDE? .Y>>
<SET LEVEL <+ .LEVEL 1>> ;"not in Zork III"
<PRINT-CONT .Y .V? .LEVEL>
<SET LEVEL <- .LEVEL 1>> ;"not in Zork III")>)>
But that seems to indent the object listing in the same odd way. In Planetfall, it looks like this:
(<AND <FIRST? .Y> <SEE-INSIDE? .Y>>
<PRINT-CONT .Y .V? .LEVEL>)>)>
And the indentation seems to work just fine there. I'll probably file a new bug report later, when I've investigated this a bit further.
So if I understand things correctly, this is what PRINT-CONT
should look like to both fix the Fantasize spell and the strange indentation:
<ROUTINE PRINT-CONT (OBJ "OPTIONAL" (V? <>) (LEVEL 0)
"AUX" Y 1ST? SHIT AV STR (PV? <>) (INV? <>))
<COND (<NOT <SET Y <FIRST? .OBJ>>> <RTRUE>)>
<COND (<AND <SET AV <LOC ,WINNER>> <FSET? .AV ,VEHBIT>>
T)
(ELSE <SET AV <>>)>
<SET 1ST? T>
<SET SHIT T>
<COND (<EQUAL? ,WINNER .OBJ <LOC .OBJ>>
<SET INV? T>)
(ELSE
<REPEAT ()
<COND (<NOT .Y> <RETURN>)
(<EQUAL? .Y .AV> <SET PV? T>)
(<EQUAL? .Y ,WINNER>)
(<AND <NOT <FSET? .Y ,INVISIBLE>>
<NOT <FSET? .Y ,TOUCHBIT>>
<SET STR <GETP .Y ,P?FDESC>>>
<COND (<NOT <FSET? .Y ,NDESCBIT>>
<TELL .STR CR>
<SET SHIT <>>
;<SET 1ST? <>>)>
<COND (<AND <SEE-INSIDE? .Y>
<NOT <GETP <LOC .Y> ,P?DESCFCN>>
<FIRST? .Y>>
<COND (<PRINT-CONT .Y .V? 0>
<SET 1ST? <>>)>)>)>
<SET Y <NEXT? .Y>>>)>
<SET Y <FIRST? .OBJ>>
<REPEAT ()
<COND (<NOT .Y>
%<COND (<==? ,ZORK-NUMBER 2>
'<COND (<AND <0? .LEVEL>
<EQUAL? ,SPELL? ,S-FANTASIZE>
<PROB 20>>
<TELL "There is a "
<PICK-ONE ,FANTASIES>
" here." CR>
<SET 1ST? <>>)>)>
<COND (<AND .PV? .AV <FIRST? .AV>>
<SET LEVEL <+ .LEVEL 1>> ;"not in Zork III"
<PRINT-CONT .AV .V? .LEVEL>)>
<RETURN>)
(<EQUAL? .Y .AV ,ADVENTURER>)
(<AND <NOT <FSET? .Y ,INVISIBLE>>
<OR .INV?
<FSET? .Y ,TOUCHBIT>
<NOT <GETP .Y ,P?FDESC>>>>
<COND (<NOT <FSET? .Y ,NDESCBIT>>
<COND (.1ST?
<COND (<FIRSTER .OBJ .LEVEL>
<COND (<L? .LEVEL 0>
<SET LEVEL 0>)>)>
<SET LEVEL <+ 1 .LEVEL>>
<SET 1ST? <>>)>
<COND (<L? .LEVEL 0> <SET LEVEL 0>)>
<DESCRIBE-OBJECT .Y .V? .LEVEL>)
(<AND <FIRST? .Y> <SEE-INSIDE? .Y>>
<PRINT-CONT .Y .V? .LEVEL>)>)>
<SET Y <NEXT? .Y>>>
<COND (<AND .1ST? .SHIT> <RFALSE>) (T <RTRUE>)>>
And, as stated earlier, FANTASIES
has to be changed to:
<GLOBAL FANTASIES
<LTABLE 0 "pile of jewels" "gold ingot" "basilisk"
"bulging chest" "yellow sphere" "grue"
"convention of wizards" "copy of ZORK I">>
Or, if people prefer to read it as a diff, these are the two changes I made. The first one moves the printing of the hallucinations to the second loop, like in zork2-mac-r22. I think this matches the original behavior, and perhaps even the original intention:
@@ -1759,19 +1759,7 @@ long description (fdesc or ldesc), otherwise will print short."
<SET INV? T>)
(ELSE
<REPEAT ()
- <COND %<COND (<==? ,ZORK-NUMBER 2>
- '(<NOT .Y>
- <COND (<AND <0? .LEVEL>
- <==? ,SPELL? ,S-FANTASIZE>
- <PROB 20>>
- <TELL "There is a "
- <PICK-ONE ,FANTASIES>
- " here." CR>
- <SET 1ST? <>>)>
- <RETURN>))
- (ELSE
- '(<NOT .Y>
- <RETURN>))>
+ <COND (<NOT .Y> <RETURN>)
(<EQUAL? .Y .AV> <SET PV? T>)
(<EQUAL? .Y ,WINNER>)
(<AND <NOT <FSET? .Y ,INVISIBLE>>
@@ -1790,6 +1778,14 @@ long description (fdesc or ldesc), otherwise will print short."
<SET Y <FIRST? .OBJ>>
<REPEAT ()
<COND (<NOT .Y>
+ %<COND (<==? ,ZORK-NUMBER 2>
+ '<COND (<AND <0? .LEVEL>
+ <EQUAL? ,SPELL? ,S-FANTASIZE>
+ <PROB 20>>
+ <TELL "There is a "
+ <PICK-ONE ,FANTASIES>
+ " here." CR>
+ <SET 1ST? <>>)>)>
<COND (<AND .PV? .AV <FIRST? .AV>>
<SET LEVEL <+ .LEVEL 1>> ;"not in Zork III"
<PRINT-CONT .AV .V? .LEVEL>)>
The second change removes some fiddling with the LEVEL
variable to match later games. This seems to fix the sometimes strange indentation when printing the contents of containers in the room.
@@ -1805,9 +1805,7 @@ long description (fdesc or ldesc), otherwise will print short."
<COND (<L? .LEVEL 0> <SET LEVEL 0>)>
<DESCRIBE-OBJECT .Y .V? .LEVEL>)
(<AND <FIRST? .Y> <SEE-INSIDE? .Y>>
- <SET LEVEL <+ .LEVEL 1>> ;"not in Zork III"
- <PRINT-CONT .Y .V? .LEVEL>
- <SET LEVEL <- .LEVEL 1>> ;"not in Zork III")>)>
+ <PRINT-CONT .Y .V? .LEVEL>)>)>
<SET Y <NEXT? .Y>>>
<COND (<AND .1ST? .SHIT> <RFALSE>) (T <RTRUE>)>>
There are details of this code that I do not fully understand, but this is as good as I'm likely to get it by myself.
One of the Wizard's spells, "Fantasize", is supposed to make you hallucinate. This is handled in the
PRINT-CONT
routine, like so:I'm not quite sure about the meaning of this, but
Y
is the object it would usually print a description for. So maybe that means that the hallucination is always added as the last object?LEVEL
may have something to do with how deeply nested the object list is. It's -1 when showing the contents of a room, and 0 when showing the contents of a container. Is the hallucination really only meant to affect containers?Either way, if you manage to trigger a hallucination, Frotz will crash with the fatal error "Store out of dynamic memory". That's because of how
PICK-ONE
andFANTASIES
work. The table has to be anLTABLE
, which it is, but it also uses the first element for something that I can't quite figure out. So every other suchLTABLE
puts 0 as its first element. ButFANTASIES
doesn't.So at the very least, to fix this we need to change
FANTASIES
to:To test this, I also added the following debug code:
Because waiting for the Wizard to cast that spell on you is very slow and tedious.
But even with that, something's wrong. Normally, it would print:
But now, when fantasizing, it prints something like:
(I did see hallucinating work as intended once in Mini-Zork II, but it strikes me that this may have been because I was in the balloon basket, i.e. in a vehicle.)
I'm not sure how it worked it older versions. If, indeed, it worked at all. In fact, in Release 48 there are no references at all to the
FANTASIES
table.