TADS Programming - TIPS ON TADS From Jean Childs Imagine the scenario - "You are in a castle. There are jewels scattered all over the floor." (examine floor) "There's nothing on the ground." (put crown on floor) "Dropped" (examine floor) "There's nothing on the ground." Frustrating isn't it? The reason is ADV.t defines "the floor" as beditem, floatingItem with nouns 'floor' and 'ground'. As a beditem it inherits the property of being a surface so you can sit on it and put things on it. But it is one object that follows you around and therefore the program cannot allow you to actually put things on it. Instead it transfers 'put on' to 'drop'. When examining any surface, the program responds with a list of what is on it or tells you there is nothing on it. If you give the surface a description property ( ldesc ), this will override the program listing the contents and 'examine' will produce the description of the surface. As 'examine floor' will always respond with 'there's nothing on the ground', you might just as well give it a description. i.e. ldesc = { if ( Me.location = castle ) { "The floor is covered with jewels. "; } else { "%You% see nothing unusual. "; } } As the location of 'the floor' is a method, TADS does not allow you to modify the object. Therefore you must alter ADV.t or use replace. ******** I have read various hints on defining vehicles, but they tend to be trains or other vehicles with set courses. My first vehicle that I wanted to define just happened to be a boat that I wanted the player to row, in the direction of their choice, over an expanse of water. I had various attempts at this but I finally ended up with the following:- boat: vehicle, qcontainer, fixeditem I made the boat a fixeditem as, in my particular case, I didn't want the player to be able to carry it. I had a perfectly good reason for this and said so if the player tried to take it. I needed it to be a container so that the player could put things in it, but made it a qcontainer as in real life the player wouldn't be able to see what was lying in the bottom of a boat if they were ten feet away from it. isdroploc = true // anything dropped while in the boat // would land in it // and not in the location of the boat. isListed = true // A fixeditem is not normally listed. I felt it was necessary to give a description for the boat when the player examines it, rather than the program listing what was in it. ( The boat is an important object, not just a container. ) As this overrides the listing of the contents, the following was added:- verDoLookin( actor ) = {} doLookin( actor ) = { if ( self.contentsVisible and itemcnt( self.contents ) <> 0 ) { "In "; self.thedesc; " %you% see%s% "; listcont( self ); ". "; } else { "There's nothing in "; self.thedesc; ". "; } } The boat starts off on a beach and 'Jim's Logic' told me that you don't just sit in the boat and start rowing as you'd get covered with sand. The player has to launch the boat. verDoSiton( actor ) = {} doSiton( actor ) = { self.doEnter( actor ); } verDoEnter( actor ) = {} doEnter( actor ) = // gives two negative answers { if ( actor.location = self ) { "%You're% already sitting in "; self.thedesc; "! "; } else { "There would be no point sitting in a boat that is on the beach. You need to launch it first. "; // I've given the verb needed. } //Finding the right verb is } // not one of the puzzles. verDoLaunch( actor ) = {} doLaunch( actor ) = { if ( Me.location = boat ) "You're already in the boat. "; else { "You push the boat out onto the water then you climb into it.\b "; self.isListed := nil; // Stops the program telling // you that there is a boat here // when you're sitting in it. Me.moveInto( self ); self.moveInto( self.location.launchtoplace ); self.location.ldesc; } } So if the player was not already sitting in the boat, the above would put him/her into the boat. Each location where the boat could be launched from would have a launchtoplace set to a sea location. The boat is then moved to this location and a description of the new location is given. Let us suppose that before the player launched the boat, the sea was to the east of the land. Now, in the boat, the land is west of the boat. The description of the sea location tells the player this. So if he/she now typed 'west' it could be assumed that they wanted to go to the beach, and they would be told - "You are as close to the beach as you can row. If you want to go onto the beach you must first land the boat." Again I've given the player the necessary verb, but the condition relevant to the displaying of this message appears later in this article. The following property is added to the boat:- verDoLand( actor ) = {} doLand( actor ) = { if ( isclass( self.location, deepsea ) ) // checks to see // what type of sea // location - I'll explain in a mo { "%You% can't get out of the boat here. It's too deep."; } else if ( actor.location <> self ) { "%You're% not in "; self.thedesc; "! "; } else { "You climb out of the boat and pull it onto the beach.\b "; self.isListed := true; // you're no longer in the boat //so it needs to be shown as being here. self.moveInto( self.location.landplace ); // each sea //location that is near a beach //has a landplace property //set to the location for that beach. Me.moveInto( self.location ); if ( Me.location.isseen = nil ) // the normal { // location.isseen doesn't // work if you arrive on a // vehicle and Me.location.lookAround( true ); // checked when //landing. Me.location.isseen := true; } else Me.location.lookAround( nil ); } } Okay, you can now launch and land the boat, so let us get back in it. I defined two types of sea locations:- class shallowsea: room class deepsea: room This stopped the player from landing the boat when they were not near a beach. They would get the same responses if they typed 'out'. I then replaced the stand verb as this allowed the player to disembark and I didn't want them to do this using this verb. To the verb's action( actor ) I added:- if ( actor.isIn( boat ) ) "Sit down %you're% rocking the boat! "; My first attempt at moving the boat was to use 'row west', 'row east' etc., defining each one as a new verb. A lot of programming was involved in checking if movement was allowed in all directions for each location. Special properties had to set - rownorth as opposed to north. Also, while testing, I would often forget to use 'row' and the program would respond with "you're not going anywhere until you get out of the boat". The easiest way was to forget 'row'. So to boat I added:- verDoRow( actor ) = {} doRow( actor ) = { "This boat is user-friendly. Just type the direction that you would like to go. "; } By giving directional movement properties to the boat I could override the "you're not going anywhere" message. north = if ( self.location.north <> nil ) { "%You% row%s% the boat in a northerly direction. "; self.moveInto( self.location.north ); "\b";boat.location.ldesc; // location descriptions are not // automatically given when // moving vehicles } else if ( self.location = sea1 or self.location = sea2 ) { boat.tooclose; // this is the "You are as } //close to the beach as you can row" message. else { "something's gone wrong"; // This message should never } //appear. } This had to be done for each direction (eight in all) but proved to be less work than my previous attempt. The boat.tooclose was a property given to the boat. This saved me having to type in this message for all eight direction properties. tooclose = "You are as close to the beach as you can row. If you want to go onto the beach you must first land the boat. " There were other messages for directions that were not allowed. A problem that arose was the program also telling the player "You can't go that way.". This is due to the default property for all rooms. noexit = { "%You% can't go that way. "; return( nil ); } This was overcome by adding to the sea location classes:- class shallowsea: room noexit = { return( nil ); } ; class deepsea: room noexit = { return( nil ); } ; So a sea location could be simply:- sea6: deepsea sdesc = "By a Beach" ldesc = "You are in a boat, surrounded by water. There is a beach to the east. " north = sea5 west = sea7 // the other three directions would be south = sea8 // covered by messages in the boat properties nw = sea42 // and if you missed one you would get the sw = sea507 // "something's gone wrong" message. ; Being able to create your own classes of objects is useful. A problem arose in my game in that there was an awful lot of water that the player could examine, and a lot of sand. You have to allow the player to "examine sand". So for each beach location, you need a sand object. The easiest way of handling this was to create a class. class sanddec: decoration sdesc = "sand" noun = 'sand' ldesc = "The sand is fine." // plus any other ; // default properties sand5: sanddec // this is all that is required for location = beach5 // each sand object ; sand12: sanddec location = beach12 ldesc = "A message has been written in the sand." // this ; //overrides the default description This is suitable for sand as the player can access the beach from various angles but it is easier to move a sea location around with the boat, otherwise you will have to create a lot of sea descriptions. To finish I would like to pose a question, and I would be grateful to anyone who can supply an answer. In my game I have three actors who follow me everywhere, Tom, Dick and Harry. Their properties are defined so as to enable the player to command them. I have also defined a new verb:- igniteVerb: deepverb verb = 'ignite' 'light' sdesc = "light" ioAction( withPrep ) = 'IgniteWith' prepDefault = withPrep ; If I am carrying some matches - "light paper with matches" works. As does "ignite paper with matches". Providing Tom is carrying the matches, "Tom, ignite paper with matches" works. But, "Tom, light paper with matches" doesn't work. The response I get is "There's no verb in that sentence". Very strange! - o -