A look at TADS

Discuss text adventures here! The classics like those from Infocom, Magnetic Scrolls, Adventure International and Level 9 and the ones we're making today.

Moderators: AArdvark, Ice Cream Jonsey

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

A look at TADS

Post by Tdarcos » Mon Nov 28, 2016 4:28 pm

I've downloaded and installed the complete SDK for TADS which includes a wizard for creating a new game, text editor, help files and the wizard even includes all the source files needed to build a game.

After a few minutes looking around I can see how some of the things they do are accomplished. Some of this seems arcane, and not as intuitive as I wish it was.

Looks like more stuff is placed in code where as things like verbs and such are declaratives in Hugo. I'm getting some idea of how this works.

I think I might try Teleporting the game Tripkey over to TADS and see how much work it is to implement the original game.

About the only thing I find is a shane is that TADS is still a closed-source system. Hugo has been made completely open source.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Re: A look at TADS

Post by RealNC » Tue Nov 29, 2016 10:52 am

Tdarcos wrote:About the only thing I find is a shane is that TADS is still a closed-source system. Hugo has been made completely open source.
Since when is Hugo open source? Last time I looked, both TADS and Hugo use almost the same source code license.

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Re: A look at TADS

Post by Tdarcos » Tue Nov 29, 2016 8:38 pm

RealNC wrote:
Tdarcos wrote:About the only thing I find is a shane is that TADS is still a closed-source system. Hugo has been made completely open source.
Since when is Hugo open source? Last time I looked, both TADS and Hugo use almost the same source code license.
As far as I saw, the Hugo system includes the source files to the compiler and the run-time system. I did not notice the code for the editor/compiler or run-time system for TADS being included. I said "open source" meaning the source code, in a form you could recompile to verify or change, is available for Hugo as part of the download. I do not see this for TADS, it appears to be closed-source freeware..
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Wed Nov 30, 2016 12:45 am

All source code (VM and compiler) is available for download. You probably went to the binary download page and missed the rest of the download links.

Also, Mike Roberts has given permission to distribute the source code of the VM as well as parts of the compiler under the GPL. QTads and Gargoyle make use of this.

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Thu Dec 01, 2016 9:37 pm

RealNC wrote:All source code (VM and compiler) is available for download. You probably went to the binary download page and missed the rest of the download links.
That is exactly correct. I was wrong and I found it.

Now, on another matter, how do I set up a command that the player is not charged a command for using and doesn't allow UNDO? I want to create an additional score viewing command. The command works, but when it's used it charges the player for a command. SCORE and FULL SCORE do not.

I tried doing

Code: Select all

        includeInUndo = nil;
and while it compiles, it doesn't prevent the command from charging or trying to UNDO it.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Fri Dec 02, 2016 4:11 am

You can take a look at actions.t to see how the library does it. In the case of SCORE, the library uses DefineSystemAction() to define such actions and sets includeInUndo.

The code that is executed by the action should be placed in the execSystemAction() method. Example:

Code: Select all

DefineSystemAction(tdarcosScore)
    includeInUndo = nil

    execSystemAction()
    {
        // Your code here.
    }
;

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Fri Dec 02, 2016 10:51 am

RealNC wrote:You can take a look at actions.t to see how the library does it. In the case of SCORE, the library uses DefineSystemAction() to define such actions and sets includeInUndo.

The code that is executed by the action should be placed in the execSystemAction() method. Example:

Code: Select all

DefineSystemAction(tdarcosScore)
    includeInUndo = nil

    execSystemAction()
    {
        // Your code here.
    }
;
Yeah, when I changed it (original is commented out) now, it does not count it as a move.

Code: Select all

VerbRule(Scores)
    'scores' | ('show'|'sh'|'display'|'disp') 'scores' 
    : ScoresAction
    verbPhrase = 'display scores'
;


//DefineIAction(Scores)
//    execAction()
DefineSystemAction(Scores)
    includeInUndo = nil
    execSystemAction()
   {
That was perfect.

Now, I've got another problem. The TV in the living room (among other devices), I am eventually going to want to PLUG IN TV, PLUG TV IN, or PLUG TV IN SOCKET (I'll leave the socket object for later). So I tried making the TV an object under Control_Center with

Code: Select all

+ TV:  RestrictedSurface, PlugAttachable  'tv television set' 'television set'
    "34 Inch LCD HD-TV mounted on the wall. "
  
;   
I removed all the dobj items because they never worked, I couldn't get it to allow me to do what I wanted. I even tried defining a replacement PLUG command (and subsequently UNPLUG) but that didn't seem to work either.

The thing I notice about HUGO was that the Run-Time Library (RTL) didn't really care what your objects were. If you either put in a general processing procedure for the verb or a method in the object, it allowed any object to accept any verb if you put the code in for it, but in TADS they apparently don't give you this freedom. Some verbs are restricted to certain classes of Object/Thing.

I mean, I'm getting to the point of thinking I have to do something ugly, either replace one of the system files with a customized one (while leaving the original) or edit the original to allow me to do what I want.

I'll take it either way, that of a general routine that I have to inspect the direct (for PLUG TV IN), and direct and indirect (PLUG VENDING MACHINE INTO SOCKET) objects to discover if it's the TV and the SOCKET (or the MICROWAVE OVEN, VENDING MACHINE, REFRIGERATOR, etc.) or that I have the particular code on the direct object to check the indirect object, e.g. PLUG MICROWAVE INTO EXTINGUISHER will not work, of course. (But USE EXTINGUISHER ON REFRIGERATOR will, but that's a different routine.)

If I didn't say so before, thanks for your help. This has been fun to see how this new system works, even if it is somewhat difficult to learn. Even very good reference materials don't always tell you everything to know. I think it might also help if you knew of any places where some TADS adventures are available where they left the source code in order to get a better handle on this. Good writing in any context begins with reading what other people wrote and how they solved the problems.

Whether that's writing a work of fiction or a computer program (which this definitely is, even if the RTL does a lot of the heavy lifting) , good writing begins with reading.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Fri Dec 02, 2016 10:55 am

As to my last item, http://www.ifarchive.org/indexes/if-arc ... Xtads.html has about 30 games written in TADS which it implies have source, so I'll take a look at some and see what I find.

But I appreciate the help I get. Thank you.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Fri Dec 02, 2016 11:39 am

I'm looking at several of the games and despite the archive claiming they are TADS 3, they seem toi be TADS 2 sources. I suspect the systems are not the same and based pn trying a few, I've come to the conclusion the new language is not upwards compatible with the old.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Fri Dec 02, 2016 6:24 pm

I would recommend one of the books (or several of them) from here:

http://www.tads.org/t3doc/doc/index.htm

For PLUG, you need to learn about direct and indirect objects in a command (when you plug something into something, you have two objects in play, the direct one (dobj) and the indirect one (iobj), and you need to know where to write the action handler depending on whether the object is the direct or indirect one (PLUG TV INTO WALL vs PLUG WALL INTO TV.)

Also, you should read more about the Tads language, especially about the "modify" and "replace" keywords. You should never replace system files in Tads. If you want to modify or add something to them, you use "modify" or "replace".

Roody_Yogurt
Posts: 1993
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt » Fri Dec 02, 2016 6:35 pm

That directory you mentioned is a mix of TADS 2 and TADS 3 games. Besides explicitly-marked TADS 3 games like EricGift.zip, Return to Ditch Day, and Fate.zip, I believe It (it_src.zip) also was TADS 3. There may be some others buried in there, too.

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Fri Dec 02, 2016 11:11 pm

RealNC wrote:I would recommend one of the books (or several of them) from here:

http://www.tads.org/t3doc/doc/index.htm
That's the TADS bookshelf and it comes included in the download with the SDK and are accessible via the HELP menu in the IDE ("TADS Workbench"). In fact, I use these documents in the library all the time to figure out how to do things or how to convert the specifications and code from Hugo to TADS.

In fact, the IDE that TADS 3 provides is something I wish I had had when I was using Hugo, it would have made it much easier to program in. I was seriously thinking of doing one and if I had this was the sort of thing I would have wanted to have.

It's slick, polished and very useful. Especially the location-sensitive error messages. Click on the compile error in the log window and in almost every case it will go to the exact line where the error is located. The only time it can't is when two places create an identical reference that apparently can't be diagnosed until "linkage" time as opposed to compile time. Nonetheless it's a huge improvement in productivity and to do better you'd have to go to something representing overkill, like if they developed a plugin for Eclipse to edit TADS code, where it not only brought up your files and libraries, but partially processed the code so if you wanted to find where an object or verb was defined it would be in the object explorer.
For PLUG, you need to learn about direct and indirect objects in a command (when you plug something into something, you have two objects in play, the direct one (dobj) and the indirect one (iobj), and you need to know where to write the action handler depending on whether the object is the direct or indirect one (PLUG TV INTO WALL vs PLUG WALL INTO TV.)
Yeah, I know, the dobjFor(Verb) and iobjFor(Verb) methods attached to the object named as the direct object, depending on whether there is an indirect object, to handle the command defined as the identifier "verb". But I was doing something wrong because I could not get it to work.

Now this did:

Code: Select all

+ TV:  RestrictedSurface, PlugAttachable  'tv television set' 'television set'
    "34 Inch LCD HD-TV mounted on the wall. "
  
;   

++ cablebox: Thing, Attachable, PlugAttachable 'cable box' 'cable box'
    "Cable box connected to the TV"
    attachedObjects = [TV]    
    dobjFor(Take) { check() { failCheck('You can\'t take the \\self.name\\. 
        It is connected to the TV, and you lack the tools to disconnect it.'); }}    
;    
(In the above example \ replaces the symbols "<" and ">" because this BBS software doesn't like it when they show up in code examples. "Self.name" becomes "Self" if I leave the double greater than and less than symbols.)

When someone tries to TAKE the CABLE BOX they get that message instead of the standard one.
Also, you should read more about the Tads language, especially about the "modify" and "replace" keywords. You should never replace system files in Tads. If you want to modify or add something to them, you use "modify" or "replace".
Right, as I said, changing a system file is "ugly" and like violence, it should only be invoked as a last resort. When the language has the capacity to override things then, it is not their only resort and eliminates the need to do that.

Sounds like Modify and Replace are probably what I might use if I can't figure out how to do what I want to do.

I will note here that I decided to port Tripkey over to TADS in order to get my feet wet in a system where I knew what the program I was porting already did. I did not want to try this with something brand new. I made that mistake once with Open Office when I took a gig writing a manual for a software program and they wanted the document in DOC format, which Open Office supports (as opposed to a conversion from Word Perfect 8, which is what I've been using for about 20 years. I have never used Microsoft Word, so I'm not used to its idiosyncrasies and bugs, which Open Office tries to emulate.)

Whatever behavior TADS has WRT Tripkey, I'll know if it matches what happens in Hugo or if it acts in a different way. And thus I will learn how it works.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Sat Dec 03, 2016 12:11 am

TADS is vastly different to Hugo. Most things don't just convert over from Hugo, and if you try to use TADS that way, you will most likely end up doing it wrong.

Also, it might be a good idea to not use adv3 (the standard library), which is huge and has a very complex class hierarchy. You might want to try "adv3lite" instead:

http://users.ox.ac.uk/~manc0049/TADSGuide/adv3Lite.htm

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Sun Dec 04, 2016 7:37 pm

I'll have to look at Adv3lite later, it's something like several hundred files and 3 megabytes in size.

But I'm getting to the point that I am getting disgusted with TADS because of the shitty restrictions it imposes on writing a game.

If someone types in UNPLUG TOILET and the implementer included a dobjFor(Unplug) method in the toilet object, then run the fucking method! If I put a handler in an object presumably I want to handle that verb used on that object, and goddammit let me do so!

Apparently I can't do this for some classes, it does not allow me to just handle the verb for that item, instead of just presuming that if I have a non-nil verb dobjFor/iobjFor method and a check(), verify() or action() then let me do whatever I specified.

The more I see of TADS the more I realize how better Hugo is for implementing a story. This system has a really good IDE but the goddamn compiler and libraries make you have to fight them to accomplish anything. All I want to do is use some commands on some objects, let the RTL handle the simple things, but goddammit when I want to be able to do something just let me!

Why is it that if I define a handler for a particular verb in the object the system refuses to accept it? I sometimes have to jump through hoops to get the system to allow me to get my story to work. I shouldn't have to keep writing overrides for the verbs I want to use, if I put a routine in the object for that verb, the verb's processor should just let the object do it.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

Roody_Yogurt
Posts: 1993
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt » Sun Dec 04, 2016 7:46 pm

TADS needs you, Commander!

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Sun Dec 04, 2016 7:54 pm

RTFM.

User avatar
Tdarcos
Posts: 5201
Joined: Fri May 16, 2008 9:25 am
Location: University Park, Maryland
Contact:

Post by Tdarcos » Tue Dec 06, 2016 4:55 am

RealNC wrote:RTFM.
I have. I did. And it doesn't fucking work! I put in a dummy routine on an object for a particular verb, so the action() initiator will show a message if that is executed and when I try something like "trip ac" (throw the breaker for the air conditioner in the meter room) I still get the "you can't do that" message. Apparently I'm doing something wrong and from what the books say and other objects where it does work, I'm doing something wrong and I can't figure out what it is. And it's frustrating.
The lessons of history teach us - if they teach us anything - that no one learns the lessons of history. tdarcos@tdarcos.com

User avatar
RealNC
Posts: 1356
Joined: Wed Mar 07, 2012 4:32 am

Post by RealNC » Wed Dec 07, 2016 12:05 am

Yes, you are correct. It's broken. It doesn't work as intended. Nobody noticed this before, weird.

Well, either that, or you didn't really RTFM.

User avatar
pinback
Posts: 13128
Joined: Sat Apr 27, 2002 3:00 pm
Contact:

Post by pinback » Wed Dec 07, 2016 7:35 am

Tdarcos wrote:
RealNC wrote:RTFM.
I have. I did. And it doesn't fucking work! I put in a dummy routine on an object for a particular verb, so the action() initiator will show a message if that is executed and when I try something like "trip ac" (throw the breaker for the air conditioner in the meter room) I still get the "you can't do that" message. Apparently I'm doing something wrong and from what the books say and other objects where it does work, I'm doing something wrong and I can't figure out what it is. And it's frustrating.
Post a code snippet that isn't working that you think should be working. I have never used TADS, and I guarantee you I will be able to point out what you're doing wrong, and where the manual explains what you're doing wrong, within 15 minutes.
Above all else... We shall go on... And continue!

User avatar
Ice Cream Jonsey
Posts: 21620
Joined: Sat Apr 27, 2002 2:44 pm
Location: Colorado
Contact:

Post by Ice Cream Jonsey » Thu Dec 08, 2016 10:08 pm

pinback wrote:
Tdarcos wrote:
RealNC wrote:RTFM.
I have. I did. And it doesn't fucking work! I put in a dummy routine on an object for a particular verb, so the action() initiator will show a message if that is executed and when I try something like "trip ac" (throw the breaker for the air conditioner in the meter room) I still get the "you can't do that" message. Apparently I'm doing something wrong and from what the books say and other objects where it does work, I'm doing something wrong and I can't figure out what it is. And it's frustrating.
Post a code snippet that isn't working that you think should be working. I have never used TADS, and I guarantee you I will be able to point out what you're doing wrong, and where the manual explains what you're doing wrong, within 15 minutes.
If Pinner can't, I will put a $100 donation to the Blue Cross / Blue Shield in your name, Paul. That's how confident I am.
the dark and gritty...Ice Cream Jonsey!

Post Reply