In the course of creating my first (and as yet, only) TADS game I came across a number of pitfalls, gotchas, aha’s, etc. I was too stressed at the time to systematize them and benefit the public with my discoveries, but I’m going to make an attempt to do so now.
Perhaps at some point these can be better catalogued and maybe make their way into a cookbook somewhere (@jnelson ?), but at least for now, I am going to dump them here in the random order that I encounter them as I go back and peruse my files.
I grant that many of these observations may have only a small window of applicability or interest, but for the greater good of TADS I’m going to just dump anything I learned, so I hope somebody can find something useful!
I happen to be sick right now with some unforeseen time on my hands, and that’s why I have time to get this started. Presuming that I can find the time, I hope to make succeeding posts in this thread with more dumps as I slowly wade through my source code and notes files.
This first post is but a nibble of all that may potentially come after, but I’m going to post it now just so I can see the thing started.
(I’m afraid that many, if not most of these will be adv3 specific, but there may be a little bit of Lite overlap.)
Thanks!
RANDOM TADBITS #1
Text printed in afterAction
will suppress defaultReport
s. Standard TAKE, DROP, PUT responses, among several other verbs, and acknowledgments of entering or leaving NestedRoom
s are all wrapped in defaultReport
.
This being the case, if you have "Somewhere, a bell rings. "
written in an in-scope afterAction
, you will end up with:
>take kiwi
Somewhere, a bell rings.
To avoid this, wrap everything printed in an afterAction
in an extraReport
macro (unless the message is meant to supplant any possible defaultReport
s!)
If you use ofKind
in a static
expression of a class
or modify Class
property, beware that ofKind
will only take into consideration the superclasses of the class you are then dealing with! For instance, this won’t work:
modify Thing
isCombustible = static ofKind(WoodenItem) || ofKind(ClothItem)
;
because Thing
is not a WoodenItem
. One way to get around this would be:
modify Thing
isCombustible = nil
initializeThing() {
inherited();
if(ofKind(WoodenItem) || ofKind(ClothItem))
isCombustible = true;
}
;
Out of the box, you can’t define cannotGoThroughClosedDoorMsg
on a Door
instance to override the default message, the way you can modify most "cannotVerbMsg"s. You have to
modify playerActionMessages
cannotGoThroughClosedDoorMsg(door) {
if(door==myDoor) return 'My message. ';
else return inherited(door);
}
Alternatively, you could
modify Door
cannotTravel {
if (gActor.canSee(self) && !isOpen) {
if(propDefined(&cannotGoThroughClosedDoorMsg))
reportFailure(cannotGoThroughClosedDoorMsg);
else
reportFailure(&cannotGoThroughClosedDoorMsg, self);
}
else inherited();
}
;
and then you could define the messages on each Door
object.
Printed text (without conditions) in a beforeAction
or roomBeforeAction
will appear twice (or more, if you have accompanying Actor
s!) when the action is directional travel. This is because of the way the library handles travel: there is a TravelAction
involved as well as a TravelViaAction
. Make sure your text is surrounded by the proper “if’s” in order to be printed.
One of the most elementary lessons for a TADS learner is to remember to call inherited
when overriding methods (if you are adding statements rather than replacing the method). Be particularly aware in the situation of creating a Thing
-based class and modifying the construct
method… if you don’t call inherited
the object won’t respond to any vocab words! The normal constructor calls initializeThing
which gives vocabulary to the object.
class Apple: Thing 'apple*apples' 'apple' "It's a <<variety>> apple. "
varieties = ['Winesap','Jonathan','McIntosh']
variety = nil
construct {
local v = rand(varieties);
variety = v;
initializeVocabWith(v);
}
;
// Yikes! Without "inherited", we won't be able to refer to these as "apple"!
The order in which pre-room-title reports appear:
.1. Implicit action announcements
2. Sidekick NPC implicit action announcements
3/4. PushTravel messages
3/4. Messages wrapped in reportBefore
?. GuidedInTravelState.sayDeparting
5. accompanying actor npcTravelDesc
6. travelDesc
7. enteringRoom (text printed within)
I didn’t rigorously test this, but I suspect that PushTravel messages and reportBefore
messages will appear in the reverse order that they are reached through code execution. For instance, if a reportBefore
occurs both in dobjFor(TravelVia)
and enteringRoom
in the same command, the message from enteringRoom
will appear first because the code reached it last.
roomDaemon
is responsible for calling a Room
’s atmosphereList
. It can be handy, however, to monitor or control other things as well. But one pitfall to avoid is assuming that a given location’s roomDaemon
is called on every turn of the game! The only roomDaemon
which is called on a given turn is the one for the PC’s location. Therefore roomDaemon
is not suitable for monitoring or tracking info about a location that needs to happen in the background as well, i.e. the PC is not there.
If you have an Actor
and you want to customize their obeyCommand
method, be aware that gDobj
is not in effect yet in the action execution cycle. In order to make statements conditional upon the direct object, you need to use getResolvedDobjList
, thus:
obeyCommand(issuingActor, action) {
if(action.ofKind(SomeAction) &&
action.getResolvedDobjList().indexOf(someObject))
return true;
else return inherited(issuingActor, action);
}
It can be a surprise to find that when you customize an Actor
’s specialDesc
, your custom desc is not used if that Actor
is in a NestedRoom
. This is because the call is triggered by showSpecialDescInContents
and not the basic showSpecialDesc
. For regular Thing
s, showSpecialDescInContents
does call their normal specialDesc
but for Actor
s, the method calls listActorPosture
. Therefore you have to override one of the involved methods to get the “specialDesc
” you want when the Actor
is in a NestedRoom
.