[ZILF] Changing a printed name (code example)

After the idle discussion about how to implement Craverly Heights in ZIL (particularly the name-changing paperwork), Jesse and Henrik have come up with a compact way to introduce that convenience in ZILF.

Starting with Suspended, some Infocom games had various ways behind the scenes to change the printed name. Learning ZIL mentions the SDESC property, but the Infocom approaches were not consistent and the ZILF stdlib does not implement SDESC.

But they came up with this brief example which introduces an SDESC function similar in spirit to the (implemented) DESCFCN and shows it off, with a map which changes names and a compass which does not:

<VERSION XZIP>
<CONSTANT RELEASEID 1>

<CONSTANT GAME-BANNER "Test - Extended descriptions">

<INSERT-FILE "zillib/parser">

;"SDESCFCN - Extension"
<PROPDEF SDESCFCN <>>

<DEFMAC PRINTD ("ARGS" OBJ)
<FORM NEW-PRINTD !.OBJ>>

<ROUTINE NEW-PRINTD (OBJ)
<COND (<T? <GETP .OBJ ,P?SDESCFCN>> <APPLY <GETP .OBJ ,P?SDESCFCN>>)
(ELSE <PRINTD!-SOME-NEW-OBLIST-NAME .OBJ>)>>

<ROUTINE GO ()
<CRLF>
<INIT-STATUS-LINE>
<V-VERSION> <CRLF>
<SETG HERE ,FOREST>
<MOVE ,PLAYER ,HERE>
<V-LOOK>
<MAIN-LOOP>>

<ROOM FOREST
(DESC "Forest")
(IN ROOMS)
(LDESC "You are lost in the woods.")
(FLAGS LIGHTBIT)>

<OBJECT MAP
(IN FOREST)
(SYNONYM MAP)
(DESC "map")
(SDESCFCN MAPDESC-F)
(FLAGS TAKEBIT)>

<OBJECT COMPASS
(IN FOREST)
(SYNONYM COMPASS)
(DESC "compass")
(FLAGS TAKEBIT)>

<ROUTINE MAPDESC-F ()
<COND (<1? <RANDOM 2>> <TELL "curious map">)
(ELSE <TELL "strange map">)>>
5 Likes

To explain a bit what is going on here:

The PROPDEF tells the compiler that an OBJECT can have the property SDESCFCN.

The DEFMAC is defining a macro that during compilation intercepts all calls to the Zcode-builtin PRINTD.

The ROUTINE NEW-PRINTD checks if the object has the property SDESCFCN and calls it if it is there, otherwise it defaults back to Zcode-builtin.

3 Likes

While we’re talking over here, I notice that you prefer to do an explicit T? check, but the resulting .z5s from both of these pieces of code are identical:

<COND (<T? <GETP .OBJ ,P?SDESCFCN>> <APPLY <GETP .OBJ ,P?SDESCFCN>>)
(ELSE <PRINTD!-SOME-NEW-OBLIST-NAME .OBJ>)>>

and

<COND (<GETP .OBJ ,P?SDESCFCN> <APPLY <GETP .OBJ ,P?SDESCFCN>>)
(ELSE <PRINTD!-SOME-NEW-OBLIST-NAME .OBJ>)>>

So it’s just a legibility/explicitness preference, yes? Making it extra-clear to a casual reader that nothing is being gotten by that first GETP other than a true-or-false?

Good catch!

I tend not to be so compact in my coding… I’m still not fully comfortable with the LISP style of indentation and lines full of closing brackets. I often format my code ALGOL-style because I find it easier to read.

Here’s an implementation of such an object in I6, with the added bonus that the game will recognize the last printed name when used in player input too, while not recognizing the alternate name. This has great potential to drive the player mad.

Object -> Map "map"
	with
		number 0,
		short_name [;
			if(random(2) < 2) {
				print "curious ";
				self.number = 'curious';
			} else {
				print "strange ";
				self.number = 'strange';
			}	
		],
		parse_name [ w1 w2;
			w1 = NextWord();
			w2 = NextWord();
			if(w1 == self.number && w2 == 'map')
				return 2;
			if(w1 == 'map')
				return 1;
		];

2 Likes

Here’s one way to make the game only recognize the last printed name in ZIL, using @heasm66’s SDESCFCN feature:

<OBJECT MAP
    (IN FOREST)
    (SYNONYM MAP)
    (ADJECTIVE \,PLACEHOLDER)
    (DESC "map")
    (SDESCFCN MAPDESC-F)
    (FLAGS TAKEBIT)>

<VOC "CURIOUS" ADJ>
<VOC "STRANGE" ADJ>

<ROUTINE MAPDESC-F ("AUX" ADJ)
    <SET ADJ <COND (<1? <RANDOM 2>> ,W?CURIOUS)
                   (ELSE ,W?STRANGE)>>
    <PUTP ,MAP ,P?ADJECTIVE .ADJ>
    <TELL B .ADJ " map">>
2 Likes

It is axiomatic that anything tricky one needs to do in ZIL will not actually be documented in Learning ZIL.

2 Likes

Back in the “good old days” , when you wanted to do something more tricky that was not covered in “Learning ZIL”, there were probably some seasoned implementor in the cubicle next to you that you could ask (Disclaimer: I have no idea how the office at Infocom was organized).

Probably a grid of rooms, carefully aligned with Earth’s magnetic field and connected by a maze of twisty passages.

5 Likes

BBC paid them a visit some time in 1985, which may give some vague ideas: Micro Live 29th November 1985 part 1

It doesn’t say exactly when, just that it was “earlier this year”. According to the Infocom Fact Sheet they moved to 125 CambridgePark Drive in April 1985, and the images I got when searching for that address certainly does look a lot like the exterior shot in the video. So I guess they just moved in. Maybe that’s why the walls look so bare?

Edit: Jason Scott commented on the video three years ago, confirming it was the CambridgePark Drive office.

Great video!

I think the “regular technical meeting” would be the forum to raise questions about things that is not in “Learning ZIL”…

This is pretty apparent. I’ve browsed enough of the source code to recognize that although by no means is there a “uniform Infocom style”, there are some super-crazy outliers which to my eyes look nothing at all like other stuff, such as the offsite-developed Sherlock.

Hey, what if you wanted to have a bunch of adjectives (say two) change? Like it becomes a small curious map and big curious map (so big and small randomly change too). Is that possible at all?

Sure. The ADJECTIVE property can contain any number of adjectives, up to the platform limit on property sizes.

When it contains more than one, you can’t use GETP or PUTP to access them. Instead, use GETPT to get the address of the property data, PTSIZE to get the size of the property (in bytes), and GET or PUT to access the individual words, similarly to how you’d use .&, .#, and --> in Inform 6.

Something like this:

<OBJECT MAP
    (IN FOREST)
    (SYNONYM MAP)
    (ADJECTIVE \,PLACEHOLDER \,PLACEHOLDER)
    (DESC "map")
    (SDESCFCN MAPDESC-F)
    (FLAGS TAKEBIT)>

<VOC "BIG" ADJ>
<VOC "SMALL" ADJ>
<VOC "CURIOUS" ADJ>
<VOC "STRANGE" ADJ>

<ROUTINE MAPDESC-F ("AUX" ADJ1 ADJ2 PT)
    <SET ADJ1 <COND (<1? <RANDOM 2>> ,W?BIG)
                   (ELSE ,W?SMALL)>>
    <SET ADJ2 <COND (<1? <RANDOM 2>> ,W?CURIOUS)
                   (ELSE ,W?STRANGE)>>
    <SET PT <GETPT ,MAP ,P?ADJECTIVE>>
    <PUT .PT 0 .ADJ1>
    <PUT .PT 1 .ADJ2>
    <TELL B .ADJ1 " " B .ADJ2 " map">>

Also note: in V3, adjectives are stored as single bytes instead of words, so you’d use adjective numbers like ,A?CURIOUS instead of vocab word pointers like ,W?CURIOUS, and PUTB instead of PUT.

2 Likes

VOC is mentioned in the ZILF compiler test cases, which admittedly are the equivalent of the dark room down the broken stairs through the locked door marked “Beward of Leopard”.

2 Likes