Building a CustomMessages Object (adv3lite)

Here’s something I don’t understand about the messaging system. Some messages are handled within the object, using handles familiar from adv3, but others use the DMsg or BMsg definitions, which are handled and must be customized in an entirely different way. For starters, the difference between the two types of messaging seems a bit arbitrary. But that’s not the key issue.

In the former category we have things like shouldNotKissMsg and shouldNotAttackMsg. In the latter category, we have items like [taste nothing] and [feel nothing], both of which are DMsg strings.

The issue is this: I would like to customize some of the latter for particular objects. And there doesn’t seem to be a way to do this using the messaging system. In particular, if the player types ‘taste Bob’, one rude response might be appropriate, while ‘taste bowling ball’ might call for something entirely different.

I can indeed create a CustomMessages list. But I can’t do this in a CustomMessages:

active = (gDobj == bob)

Nor this:

active = (gDobj.ofKind(Actor))

Either of these produces a nil object reference when the game first tries to run. This is probably because CustomMessages lists are assembled during preinit, and at that time gDobj has no meaning. I don’t know what the solution would be, at the library level.

Yes, I can create a dobjFor(Taste), a dobjFor(Feel), and so forth, either by modifying Actor or by attaching them to individual NPCs. That solves the problem at the output level (that is, when the game is running). But it more or less defeats the concept of having defined messages that can be customized.

Am I just misunderstanding something about CustomMessages?

Well, yes there is: for taste and feel you can just override tasteDesc and feelDesc on the object concerned with whather custom message you like. The [taste nothing] and [feel nothing] DMsgs are simply fallback messages to use when tasteDesc and feelDesc aren’t defined on an object. So, for example, you can just do this:

bob: Actor 'Bob;tall;man;him'
   "He's a tall man. "
   tasteDesc = "You doubt Bob would appreciate that. "
;

Alternatively, if you want to rule out tasting Bob with such a message you could do this:

bob: Actor 'Bob;tall;man;him'
   "He's a tall man. "
   isTasteable = nil
   cannotTasteMsg = 'You doubt Bob would appreciate that. '
;

I just had a look at the “Messages” page in the Library Manual, and I didn’t see a reference to this kind of usage. (I searched for the string “desc”.) I did see this:

From what you’re saying now, though, “principal mechanism” and “virtually all” are perhaps accurate but misleading. And the section on CustomMessages objects in that page doesn’t seem to suggest the simple solution – it goes straight to a more complex mechanism (which, as I’ve now discovered, appears to have some significant, and undocumented, restrictions on the usage of the active property).

I’m going to study this part of the library some more. I’m not suggesting that it be altered in any way; I suspect it’s probably very well thought out. I’m just suggesting that there are more facets to the question of customizing output messages than are explained on that page, or in Learning, pp. 188-191. If the wiki gets going, I’ll probably write an article about messages and put it up there.

Even the adv3Lite library is sufficiently complex that it’s difficult to say everything at once with every kind of qualification, but suggestions for improvements to the documentation are, of course, always welcome. The use of smellDesc etc. is documented both in the Sensory Properties section of the Things Chapter of the adv3Lite Library Manual and in Section 16.1 in Chapter 16 in Learning TADS 3 with adv3Lite.

The purpose of the Messages chapter, to which you refer, is really to explain how the BMsg()/DMsg() mechanism works, the point being that most of the messages output by the library use one or the other to generate the library’s default responses (rather than just using a single-quoted or double-quoted string in the raw). This is a bit different from object properties that can be used by game authors to customize responses on individual objects. Perhaps that needs to be made clearer in the Messages chapter? I suppose I had assumed that people would have read the Thing chapter before the Messages chapter (and so would have been alerted to the use of various object properties to customize output) and I didn’t want to burden people with too much repetition and nuance, which beyond a certain amount can make a text more cumbersome rather than clearer, but perhaps I got the balance wrong here?

Given the amount of work you’ve done, it would be churlish indeed for anyone to suggest that you’ve gotten anything wrong! But my general rule of thumb for writing manuals is that cross-referencing is always a good idea, because you can’t rely on your readers reading the documentation in any particular order. Most readers of manuals dive into the middle, seeking a page where a particular answer is to be found.

I can’t tell you how many times I’ve gotten frustrated with manuals for music software (an area where, even in retirement, I spend a fair amount of time) in which the page I turn to doesn’t even tell me which drop-down menu a command is to be found in. The name of the menu is 20 pages back, and it’s not repeated, because the author of the manual assumes that the manual will be read from cover to cover, like a novel. (Music software manuals are also notorious for not using nearly enough screen images. Screenshots wouldn’t do much for a TADS document.)

So yes, I suppose a short overview of the various ways to deploy messages might be useful at the top of the Messages page. (a) Intercept the action within the object itself using a dobjFor(), and write a verify() or check() routine with your own preferred message. (b) Do the same thing on a class, have the check routine call a message property that’s a double-quoted string, and then write a different message property into any object that needs to customize it. © Use ‘debug messages’ to find out what library message is being output, and then write a CustomMessages object to customize that message in some or all circumstances.

Thank you for your tact! Producing documentation can indeed sometimes feel a somewhat thankless task, but it is useful to have feedback since, as I’m sure you’ll appreciate, it isn’t always obvious to the documentation author what other people will make of what he or she writes.

I can see the value of cross-referencing, but I don’t want to put in too much duplication of material that’s already covered elsewhere. To that end I’ve added a paragraph to the end of the “Messages” section of the Messages chapter that reads:

First, though, it’s worth emphasising that the DMsg() and BMsg() mechanisms are primarily intended for library messages, i.e. messages that the library uses to provide a default response (such as “Taken” or “You can’t attach the widget to anything”) when a game author hasn’t provided a more specific response. There may be occasions when game authors want to customize these default messages, so it’s useful to know how these mechanisms work, but note that this isn’t the way you’d normally go about customizing specific responses on specific objects (such as “You gingerly pick up the vase” or “The cheese smells exceptionally ripe”). For that kind of thing you’d typically just override an appropriate message property (or method) with your own string (e.g. smellDesc = "The cheese smells exceptionally ripe. "), using, for example, one of the properties provided for the purpose on the Thing class or one of the methods described in the discussion of Action Results.