Tads3 Youtube tutorials, dobjFor/iobjFor, & various

Hi, I’m really trying hard to learn Tads3. And then I came up with this idea. Wouldn’t it be great if there were some Tads3 tutorials on youtube?
I find other programming tutorials on youtube easier to understand than when just reading the manuals; Just a really easy one, where one could go through building a simple game and the interface perhaps. If anyone experienced is interested in doing that, I think that would be great for the community and I will definitely be watching it!

Besides that, I’m pondering this over and over… I can’t seem to understand when to use either dobjFor(…) or iobjFor(…)
The way I’ve understood it(, and this may be totally wrong by the way): Is that x.dobjFor is equivalent to y.iobjFor in some cases(?)
Like for instance in a game I am trying to write now, you start out bound to chair. To make things simple you are already carrying a knife.

Will the code for handling “cutting the rope” either be in the rope’s iobjFor(CutWith) or the knife’s dobjFor(CutWith)?
This is unclear to me, I do not know which to choose from. Is the result equal?
Right now the code for the knife and the rope looks like this:

[code]
Knife: Thing ‘knife’ ‘knife’ @me "It is a sharp knife. "
iobjFor(CutWith)
{
verify()
{
if(gDobj == Rope || gDobj == CuttedRope)
{
if (gDobj.cutted) illogicalAlready(’{The dobj/he} is already cut!’);

            }
            else inherited;
        }
    }
;

Rope: Thing, Fixture 'rope' 'rope' @me "It's a thick rope. "
    cutted = nil
    dobjFor(CutWith)
    {
        action() {
            //"{The dobj/he}";
            if(gIobj == Knife) {
                me.bound = nil;
                cutted = true;
                Rope.moveInto(nil);
                CuttedRope.moveInto(Cellar);
                
                "You cut the rope with {the iobj/he}. It falls down on the floor round the chair. ";
            }
        }
    }
;[/code]

It works, but I’m not really happy with it. Any improvements are welcomed.

I’m also trying to make the character unable to move or doing anything not realistic while being bound to the chair. But do I really have to go through each action for that. Like:

SturdyChair: Chair, Heavy 'chair' 'chair' @Cellar "It's a sturdy oak chair. " 
        roomBeforeAction() {
            if (me.bound) {
                if (gActionIn(Stand, StandOn, Sit, SitOn, GetOutOf, GetOffOf, GetOut, Out, Jump)) {
                    "You cannot do anything while being bound to the chair. ";
                    exit;
              }
           }
        } 

(The above seems rather inefficient.)

I’ve read the manuals, but I am still not getting it. I am an experienced Inform6 programmer, so that may be part of the problem, i.e I’m coming from a totally different coding paradigm.

Thankful for any explanations.

I am also a beginner on TADS 3, so take everything I say with a grain of salt, but I think I can comment a little bit on this question.

I believe you are correct that both Knife.iobjFor(CutWith) and Rope.dobjFor(CutWith) can achieve what you want, and which way you choose depends on the other parts of your game – do you have more things to use you knife on, or do you have more tools to cut rope with?

As your code shows, you are already using Knife.iobjFor(CutWith) to handle cutting the already-cut rope, and since you implement the cut rope with a new object, it makes more sense to use Knife.iobjFor(CutWith) for your cutting purpose, as the Rope object will be gone soon and you still have the Knife object around to cut other stuff with. So you might as well put all the code in one place. Does this make sense?

Yes, that makes perfect sense. I was on the right track then. Now the code is much easier to read:

		modify Thing
						been_cut = nil;

		Knife: Thing 'knife' 'knife' @me "It is a sharp knife. " 
				iobjFor(CutWith) {
						verify() {
								if(gDobj == Rope || gDobj == Rope_Cut) {
										if (gDobj.been_cut) illogicalAlready('{The dobj/he} is already cut!');
								}
								else inherited;
						}
						action() {
								if(gDobj == Rope) {
										me.bound = nil;
										been_cut = true;
										Rope.moveInto(nil);
										Rope_Cut.moveInto(Cellar);
										"You cut the rope with {the iobj/he}. It falls down on the floor round the chair. ";
										exit;
								}
						}            
				}
		;
		me: Actor 'me' 'you' @SturdyChair
				posture = sitting
				bound = true;

		Rope: Thing, Fixture 'rope' 'rope' @me "It's a thick rope. "  been_cut = nil;
		Rope_Cut: Thing 'cut been_cut rope' 'been_cut rope' "A thick rope. been_cut in half. " been_cut = true;

However, I’m used to inform’s attributes. In that case I would have given the object the attribute scenery at first, as I do not want the rope to be visible while being bound by it. But when it is cut, I want it not to have the scenery attribute anymore.
In tads3 there seems to be only classes, so I’m forced to define two objects instead. Or is there a better way?

What would be equivalent to this code below, in tads 3?

Attribute been_cut;
	Object Rope "rope"
		with 
			before[;
				Cut: 
					if(self hasnt been_cut)
					{
						give self been_cut;
						give self ~scenery;
						move self to Cellar;
						"You cut the rope. It falls down to the floor. ";
					}
					"But the rope has already been cut!";
			];

In many situations, you will need to use both iobjFor and dobjFor – but only one of the two should have an action() block. You will need the verify() and check() blocks on both the knife and the rope, in order to rule out actions that the player might try.

For instance, if the player happens to type the command CUT ROPE WITH BANANA, it makes sense for the rope’s CutWith dobjFor check() routine to object that the banana is too soft. For the same reason, if the player tries CUT DAVID WITH KNIFE, the knife’s CutWith iobjFor verify() or check() routine needs to explain to the player that cutting people with the knife would only make them hostile (or whatever). If the rope has already been cut, the rope object’s CutWith dobjFor verify() routine needs to remind the player that the rope has already been cut (using an illogicalAlready macro, if memory serves).

There’s one other wrinkle you need to be aware of. A verify() routine is called several times while the action is being worked out by the parser. During the preliminary stages of this process, the exact dobj and iobj may not have been worked out yet. For this reason, it’s very dangerous to put something like this in the rope’s dobjFor(CutWith):

if (gIobj == rustyKnife)

A better way to do it is:

if (gIobj && (gIobj == rustyKnife))
This test will only return true after the iobj is established. However, it’s probably better to wait to test gDobj and gIobj in the check() block, because by the time that’s reached, their identity is known.

Hope that helps.

In place of attributes (of which Inform 6 has a limited number), use local variables (of which there is an unlimited number). When you define the rope object, include this line:

hasBeenCut = nil

In the action() block for the CutWith verb, you can then set hasBeenCut to true.

That is a question I don’t know answer for. But if you haven’t, maybe you should have a look at Eric Eve’s “TADS 3 for Inform Users”. It’s such a common issue that I’m sure Eric have covered in his example games.

Doing a good video on any sort of programming is hard work, and the number of people interested in learning TADS 3 is very small. If you work your way patiently through Eric Eve’s tutorial books, which are included with the T3 distribution, you’ll learn as much as you’d pick up from 100 hours of video – and you’ll find it much easier to refer back to the book than to find a particular spot in a video!

I’m not saying a video would be a bad idea for some learners – it would be great. But it’s very unlikely anyone will ever do it, and if they did, it would be far less complete than the documentation.

The documentation itself is quite intimidating at first, because there’s a lot of it, and there’s no index. Part of the learning process is learning how to use the docs. The Library Reference Manual is a huge resource – but not when you’re first starting out. Or at least, that’s my experience. On the other hand, some of the articles in the Technical Manual (such as “How to Create Verbs”) are essential. You just have to poke around until you find the essential stuff.

Thanks Jim! Yes, I am aware of the attribute limit and usually I use local variables in inform as well because of this limit, but that does not really the issue here.
I’m more concerned with how I am to make an “invisible” object “visible”; Like the rope (that has not been cut) is of the class Fixture and therefore will not be seen when it is on the floor. Therefore am I forced to make two objects with different classes. Is there a way around this?

To be honest I don’t think that’s how Fixture class is supposed to be used. If you just want to hide the rope from the room description, you should just define it as a Thing, and set its “isListed” property to nil instead.

I had that idea because sometimes it feels more human to be listening to another human talking. It makes harder stuff easier to understand than to just read manual. It doesn’t have to be perfect. I think its main purpose should be to inspire the listener.

I’ve made a few chapters into the manuals but I’m drowning in it. I have almost completed the fourth chapter in learning Tads3, but I’m mostly confused at this stage. There’s a lot subclasses, with so few differences that it is just getting confusing and as a consequence of that I am losing interest, sadly enough :confused:
I was then determined to make a small game while learning (a serious attempt), and trying to make it fun again.
I was today watching other programming tutorials on the internet and it then dawned on me, that: “wow, I’m getting this much faster and I am really feeling inspired”

But you are probably right, that no one experienced would like to do it. Just wanted to share my idea here.

Ah, it was that easy then :slight_smile:
Thanks!

I believe the Hidden class is intended for precisely this situation.

Not really, because if you define it hidden you will not be able to interact with it, thus not be able to cut it with the knife. Therefore “isListed = nil” is better. I then restrict the actions permitted by the player through the chair object.

Thanks a lot for your feedback!