the-infocom-files / trinity

Trinity
24 stars 5 forks source link

GENERIC-WIRE-F doesn't work as intended #60

Open eriktorbjorn opened 4 years ago

eriktorbjorn commented 4 years ago

One trick Trinity uses in several places is that if multiple objects match the one you've typed, the GENERIC routine for those objects is set up to pick the object that matches P-IT-OBJECT, if any of them does. Usually (at least so far) it's just two objects, but with GENERIC-WIRE-F it gets a bit more complicated because it has four. This is how it does it:

     <SET LEN <GET .TABLE 0>>
     <COND (<ZERO? .LEN>
        <RFALSE>)
           (<INTBL? ,P-IT-OBJECT <REST .TABLE 1> .LEN>
        <RETURN ,P-IT-OBJECT>)
           (T
        <RFALSE>)>>

But it doesn't work. It doesn't match the "it" wire, no matter what.

<INTBL? ,P-IT-OBJECT <REST .TABLE 1> .LEN> compiles to

        ADD TABLE,1 >STACK
        INTBL? P-IT-OBJECT,STACK,LEN >STACK \FALSE

I think that means that it passes the table, minus the first byte as parameter to INTBL?. But TABLE is a word table. If I change it to <REST .TABLE 2> it works. Unfortunately, REST isn't documented in any of the original ZIL manuals, as far as I can tell, but I assume this is a bug in Trinity, not a bug in ZILF or Frotz.

ZoBoRf commented 4 years ago

The "MDL Programming Language" (https://mdl-language.readthedocs.io/en/latest/07-structured-objects/#713-rest-1) states: <REST structured fix> evaluates to structured without its first fix elements. fix is optional, 1 by default.

From "The Zork Implementation Language" (can be found on the http://www.ifwiki.org/index.php/PAX_USB_Drive file zil.doc):

Table Operations

        GET     V       2       Returns the nth (argument-2) element of
                                argument-1
        PUT     V       3       Set the nth (argument-2) element of argument-1
                                to argument-3
        GETB    V       2)      Like NTH and PUT, but return the nth byte
        PUTB    V       3)      of a table, rather than the nth word of a table
        SIZEPT  V       1       Returns the size of a property table, which
                                was returned by GETPT.

        REST    V       2       Rest the table (argument-1) by argument-2
                                BYTES!  To rest a table by one element, the
                                second argument should be 2.
        BACK    V       2       Inverse of REST.
eriktorbjorn commented 4 years ago

Ok, so my guess that <REST .TABLE 1> should be <REST .TABLE 2> seems to be correct, then? I thought I had checked the PAX drive stuff, but I guess the "REST" got lost in all the "RESTART" and "RESTORE" noise when I searched for it. Thanks for the pointer!

ZoBoRf commented 4 years ago

Ok, so my guess that <REST .TABLE 1> should be <REST .TABLE 2> seems to be correct, then? I thought I had checked the PAX drive stuff, but I guess the "REST" got lost in all the "RESTART" and "RESTORE" noise when I searched for it. Thanks for the pointer!

If .TABLE is interpreted as a table of 2-byte entries, then you need in ZIL <READ .TABLE 2> to snipp the first off. The MDL semantics differs here. Try to use 2 instead of 1 in the original code.

eriktorbjorn commented 4 years ago

At least in the case I tested, the table was a WORD table. I already tried changing it to <REST .TABLE 2> and it worked. I just wanted to make sure it was the Right Thing™ to do.

taradinoc commented 4 years ago

From "The Zork Implementation Language" (can be found on the http://www.ifwiki.org/index.php/PAX_USB_Drive file zil.doc):

Table Operations

        GET     V       2       Returns the nth (argument-2) element of
                                argument-1
        PUT     V       3       Set the nth (argument-2) element of argument-1
                                to argument-3
        GETB    V       2)      Like NTH and PUT, but return the nth byte
        PUTB    V       3)      of a table, rather than the nth word of a table
        SIZEPT  V       1       Returns the size of a property table, which
                                was returned by GETPT.

        REST    V       2       Rest the table (argument-1) by argument-2
                                BYTES!  To rest a table by one element, the
                                second argument should be 2.
        BACK    V       2       Inverse of REST.

FWIW, I've extracted this file from the PAX USB archives and uploaded it to https://pastebin.com/htGaEuey

eriktorbjorn commented 4 years ago

Thanks. That's the same information ZoBoRf posted earlier, though. I found out about the PAX drive fairly recently, and spent some time following the instructions on how to decode it. But somehow I missed that zil.doc file.

By the way, just to rule out Frotz and ZILF bugs once and for all here - not that I really thought there were any - I have now verified that the same bug happens in the official Trinity release, using Infocom's DOS interpreter.