[ZILF] Extending to Owned Items

Hi, I know this is a really broad question, but I wanted to ask about how you would implement a feature into ZILF for ease of use. I’m thinking of how you can have objects (be it actual objects, like keys and such, or other things, like body parts like their hair) so that it (the game) automatically understands that object as being owned (in some way) by that actor.
For example say we had a female character, Jane, who had brown hair and has a key.

> Look at Jane's hair.
Filler-text-description-of-hair.

> Look at her hair.
Filler-text-description-of-hair.

> Look at her key.
Filler-key-text.

> Look at Jane's key.
Filler-key-text.

I imagine in some way this feature could be realized by having some code (perhaps in take and drop) which modifies the object’s adjective table to include the name of the owner and their pronoun? Still not sure how exactly this would work though, but I am curious as to the broad strokes of how such a feature would be implemented.

2 Likes

My approach would be to modify the REFERS? routine to understand a new kind of adjective. If .A isn’t in the object’s ADJECTIVE property, but it is a known “possessive” adjective, check whether the object is owned by the corresponding actor, and count it as a match if so.

For example, if you don’t mind hardcoding the actor, you could replace the condition

<IN-PB/WTBL? .O ,P?ADJECTIVE .A>

with something like

<OR <IN-PB/WTBL? .O ,P?ADJECTIVE .A>
    <AND <==? .A ,W?JANE\'S>
         <OR <==? <GETP .O ,P?OWNER> ,JANE> ;"it belongs to Jane"
             <HELD? .O ,JANE>>>>            ;"Jane is holding it"

And then use <VOC "JANE'S" ADJ> to add the word to the dictionary if it isn’t used anywhere else.

1 Like

Extending that to work with LOOK AT HER KEY would be a bit trickier, but basically you’d recognize one or more(*) possessive forms of each pronoun, and match the object’s owner against the tables of antecedents maintained by the pronoun system.


(*) e.g., HER is sometimes possessive, but HERS is always possessive.

2 Likes

So if I wanted to try to implement this feature, and I wanted it to be general, would you recommend the REFERS? route? Additionally, how might I be able to remove an adjective from an object’s adjective table?
(Note: I’m thinking of making a flag, OWNABLEBIT to denote an object’s adjective table will be modified if that object is owned.)

Also, and I apologize to be berating you with questions, but I started to dig into the implementation of exits (as I’d like to learn how exactly you implemented the syntax for exists with those additional keywords.) I noticed that it looks like you get the property table for the exit and get its length to tell you which exit it most likely is. My question is, you can’t use any word instead of those specific keywords (namely TO IF ELSE and so on.) How would one define these new keywords so that new property syntaxes can be defined?

1 Like

Yes.

The easiest way is to just overwrite it with zero, since property sizes can’t easily be changed. One reason to modify REFERS? instead is to avoid having to add and remove adjectives to each object as their ownership changes.

The compiler has a built-in PROPDEF for directions, which the game can override if needed. The documentation for PROPDEF in @heasm66’s ZILF Reference Guide includes this example:

;"Complex PROPDEF (DIRECTIONS from Zork Zero)"
<PROPDEF DIRECTIONS <>
(DIR TO R:ROOM = (UEXIT 1) (REXIT <ROOM .R>))
(DIR S:STRING = (NEXIT 2) (NEXITSTR <STRING .S>))
(DIR SORRY S:STRING = (NEXIT 2) (NEXITSTR <STRING .S>))
(DIR PER F:FCN = (FEXIT 3) (FEXITFCN <WORD .F>) <BYTE 0>)
(DIR TO R:ROOM IF F:GLOBAL "OPT" ELSE S:STRING = (CEXIT 4) (REXIT <ROOM .R>) (CEXITFLAG <GLOBAL .F>) (CEXITSTR <STRING .S>))
(DIR TO R:ROOM IF O:OBJECT IS OPEN "OPT" ELSE S:STRING = (DEXIT 5) (DEXITOBJ <OBJECT .O>) (DEXITSTR <STRING .S>) (DEXITRM <ROOM .R>))> 

For really unique property syntaxes, you can define a PROPSPEC function (as in pseudo.zil.) to parse and rewrite the property values before the compiler sees them.

2 Likes

I ran into another issue, I’m going down the path of writing a PROPSPEC (mostly because the property can have several values in it, like the pseudo objects) and the issue I am having is accessing the information needed. So for each value in the property list, it tries to produce a table containing a pair of a symbol (object name) and a string (response.)
So it looks, roughly like this:

<SET R 
   . . . 
   <MAPRET
   . . . 
  <PTABLE <PARSE <SPNAME .OBJ-NAME>> .STR>>>

;"Return the list of all these symbol-string pairs."
(<> <PTABLE !.R)>

However, the issue comes from taking this property and accessing and extracting both the string and object value that ought to be stored in that sub table. I also tried, instead of having <PTABLE <PARSE <SPNAME .OBJ-NAME>> ...> it being <PTABLE <FORM GVAL .OBJ-NAME> ...> but that didn’t seem to quite work either. How do I store the symbol (for the name of some object) into this table and be able to get it out with GET (or GETB or GET/B) so I can fiddle with the referenced object or the string?

Can you give a “before and after” example? That is, how do you want one of these properties to look when it’s used in an object definition, and what would it look like if you did the transformation by hand?

Sort of an esoteric property, but I’m just playing around. So basically I want to be able to have the description of an object change when looked at if the container (thing holding the object with this property) has some other object.
An Example:

(ALT-DESC 
        (OBJ-X "OBJ-X-HELD Response")
        (STRANGE-CUBE "You notice that since you've picked up the strange cube, this has begun to glow."))

So presumably what I would want the PTABLE to look like would be something like:

(ALT-DESC <PTABLE 
                 <PTABLE OBJ-X "OBJ-X-HELD Response">  
                <PTABLE STRANGE-CUBE  "You notice that since you've picked up the strange cube, this has begun to glow.">>)

Then since the property would look (roughly, I imagine, as the above example) I could just a combination of GET to get the particular PTABLE pair of ATOM-STRING and use GETB, and GET/B to extract the symbol that corresponds to the object needed to be checked (and I would then use GVAL or something to look up the atom) and then be able to print out the string.
I hope that makes any sort of sense, sorry if this is convoluted.

Here’s one possibility:

<DEFINE ALT-DESC-PROPSPEC (L)
    <LIST <>
          <MAPF ,PLTABLE
                <FUNCTION (M) <PLTABLE !.M>>
                <REST .L>>>>

<PUTPROP ALT-DESC PROPSPEC ALT-DESC-PROPSPEC>

Note, I’ve changed PTABLE to PLTABLE since you’ll need to be able to find the length at runtime (at least for the outer table).

How it works:

  • ALT-DESC-PROPSPEC is called with L set to the list defining an ALT-DESC, such as:
    (ALT-DESC (STRANGE-CUBE "You notice that since you've picked up the strange cube, this has begun to glow.")
              (RUSTY-TWINE "The rusty twine in your pocket fills you with confidence as you watch the gizmo's intricate rotations."))
    
  • The call to MAPF strips off the property name with REST, then transforms the remaining elements by piping them through an anonymous function.
  • The anonymous function makes a table out of each inner list by passing the list elements as arguments to PLTABLE.
  • MAPF collects the inner tables and passes them all as the arguments to PLTABLE one last time, creating an outer table.
  • Finally, LIST sticks a <> on the front to make the result look like a property definition again.

The resulting object has a single word in its ALT-DESC property, a pointer to a table (T?39 in this case):

?PTBL?ROTATING-GIZMO:: .TABLE
	.STRL "rotating gizmo"
	.PROP 1,P?ADJECTIVE
	.BYTE A?ROTATING
	.PROP 2,P?SYNONYM
	.WORD W?GIZMO
	.PROP 2,P?ALT-DESC
	.WORD T?39
	.BYTE 0
	.ENDT

That table contains a length word followed by pointers to the inner tables, and each inner table contains a length word followed by the object and string:

T?37:: .TABLE 6
	.WORD 2,STRANGE-CUBE,STR?32
	.ENDT

T?38:: .TABLE 6
	.WORD 2,RUSTY-TWINE,STR?33
	.ENDT

T?39:: .TABLE 6
	.WORD 2,T?37,T?38
	.ENDT

(Atoms don’t exist at runtime, so there’s no need to use GVAL to get the object. The first word of each inner table is the object number.)