TADS3 game, my experiences

Hi there,

I have recently been coding my first IF game using TADS 3 (I have posted it to this board in the beta testing section).

The game code works (after correcting a few bugs and errors), but I was a bit dissatisfied. I found I was using a lot of flags and my code was looking a bit like spaghetti.

Also I wanted something like events which get triggered when a condition becomes true but I couldn’t find that in TADS, only fuses and daemons.

I ended up making extensive use of afterTravel and roomBeforeAction which also didn’t seem ideal.

Cheers, I thought I would share my experience. Any replies welcome

– KezL

It’s hard to answer, because your question is rather vague. It is quite normal that game uses lots of flags to indicate events that happened using gReveal/gRevealed macros, but I’ve used afterTravel and roomBeforeAction only once or twice in my game. Spaghetti code is definitely not desired and TADS has many features to mitigate this problem. Maybe you could post a small sample of your code to illustrate particular problem?

Hi there, thanks for replying

I have attached a small piece of code, for a room object. I found early on in my project that this kind of use of roomBeforeAction and afterTravel and then used it throughout my game. Then later on I began to wonder if it was bad style. Anyway, it would be great if you could have a look at the code sample and perhaps give any alternative ways of going about things.

Cheers – KezL
sample.txt (4.85 KB)

In text adventure games you need lots of flags to mark events that happened, such as that someone did something or seen something, like your doneUnlock, moneyHide etc. That’s normal, every substantial game needs lots of test. For example in my game (24 locations, 380 objects, 3 NPC, 200 conversation topics 21000 lines of code) I have more than 200 places where I read or write such boolean flags.

You can declare properties on different objects, like you did, but TADS has a special mechanism for this purpose called “revealing” (Learning T3, chapter 7.1.3). It is very similar to yours, but it has some convenience features. At any time you want to set some flag, you can use gReveal(‘some-tag’) macro and set some flag identified by arbitrary string name. Difference is that the mechanism is global, so you won’t need to remember on which object you declared the property. You can also reveal some flag by including special tag <.reveal some-name> directly into text string being printed, so the flag can be set on the same place you write about the event.

When you need to test some flag, there is gReveled macro you can use in if statment or assign the value to isActive property of some conversation topic. Sometimes you want to activate some hint topic in built in help, there you can use openWhenReveled = ‘some-tag’ property. Of course you can test same flag (it’s global) on several different places. Few assorted examples:

verify() { if(isIn(slot) && gRevealed('rover-driving') && !gRevealed('rover-destination')) illogicalNow('Teď určitě nechceš zastavit. '); }

"<.p>Už je docela blízko, raději bys měl jít odsud pryč, abys nebyl přistižen v místech, kde nemáš co dělat.<.reveal robot-solved2> ";

"Jsi <<if treadmillDial.countMax > 0>>hodně<<else>>trochu<<end>> zadýchaný. Ještě štěstí, že se <<if gRevealed('ship-landed')>>tu dá pohybovat skoro bez námahy.<<else>>v beztíži dá lodí jen proplouvat. ";

[code]+++ AltTopic
"<.p>Borisi, oslovil jsi technika, co moje připojení k síti přes
tablet?

    <.p><q>Za co mě máš?</q> odvětil, <q>když makám, tak makám. Máš to dávno
    hotové a kdybys místo zbytečného vyptávání vyzkoušel třeba vyhledat
    asteroid, tak jsi mě nemusel rušit.</q> "

isActive = gRevealed('database-access')

;
[/code]

++ Goal 'Jak se řídí loď?' [ 'Povětšinu času ji řídí autopilot a na tobě je jen dozor nad přístroji na palubní desce, které můžeš prozkoumat. ' ] openWhenRevealed = 'me-driving' closeWhenRevealed = 'ship-landed' ;

Often you need to uncover several objects at once, like your ropeLadder1.discover(); ropeLadder2.discover(); TADS has two similar, but slightly different mechanisms to bring objects to game at some point in the time. You seem to use Hidden objects, but there is also a PresentLater mix-in class (see TourGuide or Reference guide). PresentLater has one distinct feature that you can flag many objects with same string identifier plKey = ‘some-tag’ and then reveal all such object at once by calling for example PresentLater.makePresentByKey(‘some-tag’);

You seem to set unnecesary flag ropeLadder2.isThere = true; You can always test if(ropeLadder2.discovered) in such case, thre are also many properties of Thing derived objects, like item.moved, item.seen whose can be handy.

I don’t know how deeply you model your NPCs, you seem to only play some conversation during afterTravel, but when you make some Person you can not only assign lots of conversation topics to them so the player can ask them about everything, but you can give them so called AgendaItems (Learning T3, chapter 14.8) which allows the NPC to do their own things when some occasion occures, like this example from Eric’s book:

+ bobAngryAgenda: AgendaItem isReady = (bob.canSee(mavis)) invokeItem() { "<q>You hypocritical old woman!</q> Bob storms at Mavis. <q>You sit there like some stern old maiden aunt, but I know just what you were in your youth – you were a <i>trollope</i>! "; isDone = true; } ;

You’ll see that it acts like some sort of “event” - as soon as NPC can see other character the agenda is triggered, like when the character enters a room. You can do some event system by yourself, for example look to Eric and Jim’s game Mrs. Peppers Nasty Secret whose source is available, there is system for displaying tips to the players which are processed and showed as soon as some condition is fulfilled.

TADS even has some sensory object, like sound so instead of another flag outsideGuestRoomDoor.voicesInside = true; you can just make present sound object at the right place for example by setting its isEmanating property to some gReveled test.

I’m not sure how well I’ve fitted into your game given small sample, but at least you have some pointers for your study. I’ve also suggested several times to read source code of Return to Ditch Day game by Mike Roberts (TADS author) which showcases many TADS features and more over shows good habits of programming in TADS.

Hi there,

Thanks for your message. I will certainly be studying the games and the parts of TADS that you mentioned. I probably won’t be modifying my existing game, but when I start my next game I will be putting into practice the methods you suggested.

I have found the process of writing an IF game to be rewarding and have had some friendly responses from people on this site.

I am probably now going to upload my game to IFDB or another archive. It is likely that it still needs some more playtesting.

Cheers, – KezL