TADS 3 Questions

Greetings,

Firstly, I am thinking of developing an IF/RPG hybrid (I know, doomed to fail, you think), and have yet to choose a development language, although TADS 3 is looking very cool to my very geeky brain.

Secondly, what a great job has been done on the documentation for TADS 3. A few of the questions listed below I’ve already found answers to, simply by exploring (in a haphazard manner) the various documents in the Author’s Kit. I have indicated which ones have already been answered with (Yes/No!) - no No’s yet!.

Thirdly, the RPG side of this project requires a different way of designing. For instance, I will need to make master object templates, and then populate instances of these objects throughout the game world, often dynamically during run-time. That is just one example of what I mean by “different way of designing”. (Traditional IF, I presume, requires single instances of very detailed objects, whereas an RPG (in my view) would require many instances of an object in various states.) Also, several gamist mechanisms will need to be employed, which serve to simplify reality rather than to exemplify it.

Fourthly, I don’t expect anyone to give me detailed instructions on how to achieve everything listed below (although, I certainly don’t forbid it!). A simple yes/no would be cool, and perhaps a keyword or two (in relation to a positive answer) so I can search the documentation.

  1. Can I create my own types (classes in TADS)? b[/b]
  2. Can I dynamically add/remove those types to objects during play?
  3. Can an over-ridden method in a sub-type defer to (call) the same method of it’s parent?
    [list]i.e. In C# I can do a ‘base.SomeMethod’
  4. Can I check for user-defined types in logic statements?
    i.e. if IsOfType(obj, type)
  5. Can I iterate over subsets of objects based on type? b[/b]
  6. Can I iterate over objects within a certain context? (Like within a given room, container, inventory, etc.)
  7. Can I check for the existence of properties and methods on an object?
    i.e. if HasProperty(obj, property) OR if HasMethod(obj, property)
  8. Can I dynamically create/destroy objects during play?
  9. Do implicit actions cause actors to take a turn?
    i.e. ‘eat apple’

(taking it first) [NPC takes a turn here]
You eat it. [NPC takes another turn here]

  1. Is there a way to turn off all implicit actions?
  2. If so, can I store the last [possibly a set] of implicit actions?
    I ask this because I’d like to implement the following:

‘eat apple’
You’d have to take it first.
‘do so’
You take the apple.
‘continue’
You eat the apple.

OR

‘eat apple’
You’d have to take it first.
‘do so and continue’
You take and eat the apple.

Optionally, I would like the player to be able to utilize a command such as “/auto actions on” to re-assert implicit actions.

Does something like this exist in the Adv3 library already, or will I be forced to have fun creating it myself? (I require this for turn-based combat, and for other tactical considerations.)
12. Can I dynamically change the scope of rooms/objects via some function/method?
i.e. obj.InScope(false | true) OR SetScope(obj, false | true)
13. Is an object aware of when it comes into and goes out of scope?
i.e.
someobject: someClass
{
[list]InScope () {
}
OutScope () {
}
}[/list:u]
14. Can I redirect a verb on an object to another verb? b[/b]
i.e. ‘undo screws’ -> ‘remove screws’ [/list:u]

People more experienced than I in T3 will be along to answer your questions, but I have to say that is my favorite quote of the week. Welcome to Intfiction Jonathan :slight_smile: .

I’m not aware of a way to do this. Even if it’s possible, there might be a better way to implement what you want to do.

Yes, by calling inherited()

Yes. if(object.ofKind(MyClass))

Yes. Foreach(local cur in me.contents)

Properties and methods that don’t exist on an object will return true to the following condition: (Me.nonexistantMethod(‘an argument’)==nil)

Not sure if there’s a better check than that.

Yes. Destruction is via a java-style garbage collector.

No.

Yes.

I’m not sure it’s quite as simple as your example, but yes. I think this is probably the same method you’d be interested in for 12.

Probably, but I don’t know how. _tryImplicitAction() in exec.t might be the place to start - or more basically, look at the “Custom Preconditions” section of the Technical Manual.

You can use “obj.setSuperclassList(listOfClasses)”. Since you want to add or remove a single superclass, not change the entire list, you’d probably want to do something like this:

local listOfClasses = obj.getSuperclassList() // add or remove the superclass from listOfClasses // if adding, you'll have to remember to insert it in the right place in the list obj.setSuperclassList(listOfClasses)
Of course, like Pacian said, this may not be the best way to handle the problem you’re looking at. You can look up setSuperclassList in the Tour Guide for more information (and a warning about careless use of it…).

There is; it’s “obj.propDefined(prop)”. It works for both properties and methods. I haven’t checked (I’m away from home and don’t have TADS handy) but I’m pretty sure you need to give the argument as a reference, e.g. “obj.propDefined(&propertyName)” - that is, you need the ampersand before the property name.

See the System Manual’s chapter Object Definitions for more information.

Sounds like an interesting problem! Looking at the article on the Command Execution Cycle in the Technical Manual might give you an idea of how to go about this. It’s a long article - very in-depth - but you’ll probably only be interested in some of the sections.

Thanks for the greeting, and to Pacian and Emerald for your great responses.

Dynamic modification of classes:

I would like to be able to add/remove a collection of properties/methods from an object at run-time. Any way to do this? setSuperclassList leaves all the properties and methods on an object untouched when the class from which those properties and methods were inherited is removed from the super-class list.

For instance (pseudo-ish-code, still learning):

[code]+ rapier_1: SwordClass, ImbuedAndThereforeAMostPowerfulWeaponIndeedClass

dobjFor(Lick)
{
verify()
{
if(!(object.ofKind(ImbuedAndThereforeAMostPowerfulWeaponIndeedClass))
illogicalAlready('You’re done with licking - and consequently demoting - powerful weaponry. ');
}

 action() 
 { 
        //remove ImbuedAndThereforeAMostPowerfulWeaponIndeedClass, along with all of it's properties and methods
        "You lick the god-like object.  A sudden and overwhelming sense of idiocy permeates your consciousness.  Owa tafu liam.";         
 } 

}
;

class ImbuedAndThereforeAMostPowerfulWeaponIndeedClass
{
doesQuintupleDamage
absorbsLife
devoursPizza
deniesExistence = ‘most assuredly’
considersAlgorithmicComplexityAHorriblyDryTopicForAfterDinnerDialogue

UponStrikingAnEnemy()
{
    "You feel smite-y."
}

} [/code]

I’m beginning to wonder if I should build an RPG extension first, before I even attempt to create an IF/RPG hybrid. I am wondering this because the world model of Adv3 seems to be quite intricate, and it may be better for me (in regards to both learning the library, and developing code-eye* for TADS) to tap into the class hierarchy on an ad-hoc basis. Does this make sense?

Process:
1. I want to achieve ThisFeature.
2. Check Adv3 for ThisFeature.
3. If ThisFeature.isIn(Adv3), { learn how ThisFeature is constrained in the model. }
4. If ThisFeature.toString = ‘not too interdependent’, { tap into built-in ThisFeature. }
5. If !ThisFeature.isIn(Adv3) | ThisFeature.toString = ‘a complex issue, forsooth’, { build my own, independent class for ThisFeature. }

*code-eye: to read source code as one might peruse the morning paper.

If you’re interested in RPG-ish attributes for an item, how about using objects to describe the attributes of the item? Changing the entire class just seems like a pretty brute force way to go about it.

For example, if you wanted the player to start with a weak wooden sword of fire -1, how about something like this:

[code]startingWeapon: Sword
madeFrom=Wood
damageModifier=-1
attributes=[Fire,Weak]
currentCondition=40
;

Wood: MaterialType
descriptor=‘wooden’
materialName=‘wood’
armorValue=1
weaponValue=2
weight=4
bestCondition=50
;[/code]
And so on, where each custom class defines some particular aspect of this or other items, and the attribute list contains miscellaneous objects or flags that you could check for in certain situations. The ‘conductor’ attribute would have various effects when facing a lightning monster or something - and varnishing a weak wooden sword could remove the Weak object from its attribute list.

Aha. Thanks. :slight_smile:

I don’t know of any way to do that, so I’d probably do something like Pacian’s code, putting an extra object or class in a property instead of the class list.

For instance, take the example you’ve given, of an imbued sword. I’d give the sword object a property called “enchantment” or some such, and set enchantment to be the ImbuedAndThereforeAMostPowerfulWeaponIndeedClass. (Since classes and objects in TADS 3 are almost identical in every way, you probably won’t actually need to create an instance of the class for this to work. You can just create instances for the occasions when you want to change the details of an enchantment.) Then, instead of calling “rapier.UponStrikingAnEnemy()”, you call “rapier.enchantment.UponStrikingAnEnemy()”. To remove the enchantment, you set “enchantment = nil”, and if you want to check whether the sword is enchanted, you can use “if (rapier.enchantment)”. And so on.

I just want to add to Pacian’s idea on designing objects – in RPGs especially, it’s very useful not to think of code objects being 1:1 with game objects. You can think of things this way for items, monsters, pretty much anything in the game, instead of creating elaborate class hierarchies and the like.

What do you mean by the terms “code object” and “game object”?

I see. Thanks for pointing me in this direction. I might have gone ahead and made things needlessly kludgy (and I still might, in other ways). Extensibility is the main issue, and the above method (assigning an object/class to a property) is nice. Hadn’t realized that variables were dynamically typed, speaking of which…

Why are “multi-methods” called, well, “multi-methods”? Unless I’m misinterpreting the system manual entry (which, I admit, may be the case), these are multi-functions, since they cannot be placed on objects. (Methods are functions tied to objects, whereas functions are parent-less, in my limited understanding.) This seems to be reinforced by the System’s Manual under Dynamic Objects, which states that:

So if constructors cannot be overloaded, I would assume any object method could not be overloaded either. In which case, my confusion as to why multi-methods are named as they are. (Hopefully I am misguided, and methods can be overloaded!)

Another thing: if I go ahead and create a new object at run-time [myObject = new hostileActor], the System’s Manual says that “Dynamic objects don’t have names, so you must refer to them through variables or properties.” Is there a way to assign a name (symbol) to a dynamically-created object, or an anonymous object for that matter?

“Because an anonymous object doesn’t have a symbol that you can use to refer to the object, you must use some other mechanism to manipulate the object. For example, you can use the firstObj() and nextObj() functions, since iterations with these functions include anonymous objects.” (System’s Manual, here).

firstObj() and nextObj() iterate over the entire game - is there a way to iterate in this fashion through the current scope only, or through specific containers? (EDIT: Nevermind ‘specific containers’; Pacian already indicated “Foreach(local cur in me.contents)” I assume, then, there is a way to loop through scope?).

This means that a single game object (e.g., a sword) could be made up of multiple code objects (a material object, a weapon object, an enchantment object, etcetera). The sword in the code could then be an instance of an item class with a properties attribute that contains material, weapon, enchantment, similar to what Pacian was talking about, but there would be no sword class in the code per se.

I think I see, though you may verify: all the particulars for the sword are abstracted into base objects, which the sword comprises via properties pointing to those objects.

No, you’re right - methods can’t be overloaded. At this point, anyway. (I keep meaning to email Mike and request he extend the feature to methods as well.) As for the name, my best guess as to why they’re called “multi-methods” rather than “multi-functions” is because they’re implemented as methods under the hood. (Which means it should be easy to extend the feature to methods as well - I hope?)

There’s no way to give a dynamically created object a permanent name, no.

You can get a list of things in scope by calling gAction.getScopeList(), but as its note in the Library Reference Manual explains, it may not include everything that’s in scope if you’ve been fiddling around with scope by adding objects that wouldn’t otherwise be in scope.

There are a couple of other ways you can handle this. firstObj() and nextObj(), of course. You can limit them to only return instances of a specific class, and since they’re implemented at the interpreter level, not the library level, they’re very fast. If you want to check whether the object they’ve given you is in scope, you can do “if (gAction.objInScope(obj))”. Unlike getScopeList(), objInScope(obj) should always be right about whether an object is in scope or not.

If you’re going to have a huge game with thousands of objects and you’re worried about slow-down if you’re iterating over so many objects, you can keep your own list to iterate over. It means more work for you, of course. For instance, say you want to keep a list of all the Smurfs in your game. You give the Smurf class a property called allSmurfs and set it to be an empty list. Use a PreinitObject to go through all the Smurfs in your game at start-up and add them to the list. (PreinitObjects run their code when you compile for release and the results are saved in the compiled game file, so you can use firstObj()/nextObj() here without worrying about players experiencing slowdown. They’re tremendously handy for doing tedious initial bookkeeping tasks.) Give the Smurf class a constructor that adds new Smurfs to the list, and in the code for Smurf death, remove the Smurf from the list. Then you can iterate over Smurf.allSmurfs instead of firstObj()/nextObj(). That’s a simple example, but you could extend it to create your own list of allMonstersWithEnchantedWeapons or whatever you want (of course, you’d have to account for all the ways a monster could lose its enchanted weapon).

This is probably also a good time to point out that “scope” in TADS 3 isn’t just one giant list. It’s specific to whichever action is being taken. So your NPC in the next room might be in scope for the CALL action, but out of scope for EXAMINE; in scope for SHOOT, but out of scope for PUNCH; and so on. This is why you check scope by calling gAction.objInScope(obj), rather than obj.objInScope().

Me too. Hope, that is.

…yes…

Excellent info there - thank you.

Interesting. Actions determine scope - brilliant. Where can I read more about this?

Two more questions - is it possible to:

  1. programmatically execute a command as though the player had typed it?
  2. load a TADS 3 snippet (say, from a string variable), and then execute that snippet during run-time?

The documentation doesn’t seem to have an article specifically explaining the ins and outs of scope yet. The Technical Manual has an article on Redefining Scope, which gives a very brief overview of scope before explaining a few ways of modifying it. You might also find the Tour Guide’s articles on SenseConnector and DistanceConnector useful; these classes are designed to make it easy to add the contents of other rooms to scope.

  1. You can start a new action with “newAction”, “newActorAction”, “nestedAction”, “nestedActorAction”, “replaceAction” or “replaceActorAction”. They’re all macros for more complicated commands; you can look them up in the Library Reference Manual to see the differences between them. The “Actor” variants allow you to specify which actor will take the action, while the plain variants use the current actor (gActor).

If, on the other hand, you want to be able to feed the parser an arbitrary string and have it turn the string into an action and perform the action… that’s more complicated. I’m sure it’s possible, though. I think I played about with it a bit once, but never quite got around to finishing it. You’d probably want to have a look at the Command Execution Cycle article in the Technical Manual to get an idea of where you’d jump in. The Library Reference Manual will help here too. If you’re using the TADS Workbench for Windows, set a few breakpoints in the library code and step through so you can see which properties and methods are doing what. My cursory examination of the library suggests that you’ll want to start by looking at readMainCommandTokens(which) and the section of Actor.executeActorTurn() which calls readMainCommandTokens.

  1. I don’t think you can do that, but there’s probably a better way of handling the problem anyway. You might be able to use an anonymous function or a reference to an existing function or method. What are you trying to accomplish?

Thanks.

Thank you. Specifically I am looking to restrict player and NPC action to ordered sets, where everyone gets an opportunity to perform one, and only one, action per turn. If anyone attempts to perform more than one action, the actions beyond the initial action are stored in a queue. The action queues are emptied out sequentially. NPC’s have access to their queues, and can alter them on the fly as they see fit. This allows them to plan several tactical moves in advance, and to respond to local, incremental (turn by turn) changes in state.

This may prove to be more work than I am willing to undertake - I’ll have to get a firm handle on how the library implements everything. For instance, the following is not ideal:

take the apple, the orange, and the banana
the apple: Done.
the orange: Done.
the banana: Done.

A fruit guardian walks into the room.

Rather, this would be more suitable:

take the apple, the orange, and the banana
the apple: Done.

A fruit guardian walks into the room.

(take the orange)
Done.

The fruit guardian draws his sword, advancing on you. (initiating combat)

In this latter case, the take action for the banana was aborted because the combat event was more important.

As of now, nothing in particular but everything in general. Besides this feature just being plain cool, I could foresee using it to create Actors who build their own internal logic as play progresses; unique to every play, even for identical transcripts (although similar, in that case, but not perfectly so). I suppose this could be achieved in other ways, using sets of actions, states, randomness, and so on.