| +-------------------------------+ | |
| A TADS Tip Sheet, version 0.3b | |
| +-------------------------------+ | |
| TADS, Michael J. Roberts' Text Adventure Development System, is a very | |
| powerful and flexible programming system for developing text adventures. | |
| (interactive fiction) However with that power comes a good deal of | |
| complexity. Here are some tips that I've come up with over the past four | |
| years of TADS authoring. And I thought that there may well be beginning | |
| TADS authors out there who could use some of these tips. Feel free to | |
| mail me with any suggestions for new tips or, indeed, corrections. I can | |
| be reached at tela@tela.bc.ca. | |
| Note that this tip sheet was originally written prior to the publication of | |
| the TADS 2.2 Release Notes. Some of the material in this tipsheet is | |
| actually explained, in far more detail, in those notes, especially the | |
| rewritten Book of the Parser. | |
| - N. K. Guy, tela design. (http://www.tela.bc.ca/tela/) | |
| RESTRICTIONS: | |
| You may distribute, modify and copy this file as much as you like, | |
| but it cannot be bought or sold. Please include this notice and a | |
| list of any changes you made if you choose to redistribute it. | |
| STANDARD PARANOID ANTI-LITIGATION STUFF: | |
| I believe that the information contained in this document is reasonably | |
| accurate. However, I make *no* guarantees of *any kind* that the | |
| document is error free or will meet your needs or anything like that. | |
| You assume full risk for using or not using any information in this | |
| file. If you find something wrong, please mail me a correction and I'll | |
| fix it. I hope that's all that needs to be said on this point. | |
| Also, any mention made within this document of commercial or shareware | |
| products is purely for informational purposes, and does not imply an | |
| endorsement of any kind by anybody. | |
| VERSION HISTORY: | |
| Version 0.1. Written 4/26/93 N. K. Guy (tela@tela.bc.ca) | |
| updated to 0.1a. (banana tree example code fixed) 3/18/94 | |
| updated to 0.2 to reflect TADS 2.2.1.0 Freeware 10/19/96 | |
| updated to 0.3. Added the #pragma C+ and setit() issues, TADS Page URL. 10/28/96 | |
| updated to 0.3a. Added the numberedObject stuff. 1/15/97 | |
| updated to 0.3b. Added Ditch Day, hiddenItem/obstacle and moveInto bits. 12/23/97 | |
| WHAT IS TADS? | |
| TADS, the Text Adventure Development System, is a particularly groovy | |
| system for programming text adventure games (sometimes called | |
| "interactive fiction") on a variety of computer platforms. TADS and Graham | |
| Nelson's Inform are the two most powerful and most popular development | |
| systems for writing text adventures currently available at time of writing. | |
| TADS was originally a shareware package written and published by High | |
| Energy Software. However, in mid 1996 TADS author Michael J. Roberts | |
| publicly announced that TADS was to become a freeware product and that | |
| High Energy Software would be shutting down the bulletin board system | |
| that it used to support the program. He has made good on his promise, | |
| and has even freely released the source code that makes up the program. | |
| You no longer have to pay anyone to use TADS - it's totally free! | |
| However, Mike Roberts retains copyright to the TADS system, so you can't | |
| go and change it or try (operative word here is try) and make lots of | |
| money off it without his permission. | |
| For more information on TADS have a look at the unofficial TADS page: | |
| http://www.tela.bc.ca/tela/tads/ | |
| WHERE CAN I GET IT? | |
| You can find the latest and greatest version of TADS in a variety of | |
| places, including, if you have access to Internet FTP: | |
| ftp://ftp.gmd.de/if-archive/programming/tads/ | |
| This site, the Interactive Fiction Archive (if-archive) is at GMD, the | |
| German National Research Centre for Information Technology. It's run by | |
| volunteer maintainers Volker Blasius and David Kinder, to whom we all | |
| owe a debt of gratitude. Note that if you don't live in Germany and find | |
| the connection to be rather slow, or if you want to be a good | |
| net.citizen and minimize your use of overtaxed international links, you | |
| can access the if-archive at a number of mirror sites. For example, US | |
| users may want to try Washington University's mirror at wu-archive: | |
| ftp://ftp.wustl.edu/doc/misc/if-archive/programming/tads/ | |
| European users outside Germany could try the Finnish University and | |
| Research Network's mirror: | |
| ftp://ftp.funet.fi/pub/misc/if-archive/programming/tads/ | |
| Additionally, if you have access to Usenet news and you're interested in | |
| discussions on the topic of writing interactive fiction, check out the | |
| newsgroup: | |
| news:rec.arts.int-fiction. | |
| For discussions on the topic of playing interactive fiction games, check | |
| out the newsgroup: | |
| news:rec.games.int-fiction. | |
| +---------+ | |
| Some Tips | |
| +---------+ | |
| READ THE MANUAL. | |
| TADS has a great manual. A wondrous manual. Michael J. Roberts clearly | |
| poured half his soul and an awful lot of time into writing it. Read it. | |
| Worship it. This may be something of an obvious tip, but spending time | |
| with it will minimize time wasted later on figuring out why something | |
| won't work. | |
| The manual is available in two forms at time of writing. The first is | |
| typeset using TeX, the powerful and deeply arcane typesetting language | |
| popular within the academic community. If you have a program that can | |
| display TeX files (or, more accurately, that can convert the TeX files | |
| into DVI files for display purposes) then you might want to get that. The | |
| TeX files can be found at: | |
| ftp://ftp.gmd.de/if-archive/programming/tads/manuals/ | |
| The second is an HTML (HyperText Markup Language) translation of the TeX | |
| files for Web browsers, converted by yours truly. This version is on the | |
| Web at: | |
| http://www.tela.bc.ca/tela/tads-manual/ | |
| I'll probably upload it to the GMD if-archive as well. And I'm sure the | |
| TeX files will be converted into all kinds of other formats over the | |
| next while. | |
| READ THE TADVER.* FILES. | |
| Your copy of TADS should have come with a file called TADSVER.xxx, | |
| where xxx is the operating system you use. This file is extremely | |
| handy - it lists all the new features and fixed problems with the | |
| latest versions of TADS. There are many useful new features that have | |
| been added to TADS since the version 2 manual was released, and this | |
| file documents them. No TADS user should be without it! | |
| Note that there are two versions of the TADSVER file - one that | |
| lists all of the new features up to version 2.1 or so, (TADSV200.xxx) | |
| and another file that lists the changes from 2.1 onwards. I've put the | |
| most recent version of the Macintosh TADSVER file online at: | |
| http://www.tela.bc.ca/tela/tads-manual/tadsver-mac.html | |
| READ SOME SOURCE CODE. | |
| One of the best ways to learn how to program is, in my opinion, to find | |
| some well-written source code and play with it for hours on end. You can | |
| learn a lot through doing this. Tearing someone else's source apart and | |
| modifying it for your own ends is a very educational activity. | |
| TADS used to ship with the full source for a small game, Ditch Day Drifter, | |
| which illustrates many important basic features of TADS. Unfortunately | |
| somewhere along the way the Ditch Day code got left out of the standard | |
| TADS distribution. If you never got a copy, there's one at this URL: | |
| ftp://ftp.gmd.de/if-archive/games/tads/ditchday.zip | |
| And if you are on the Internet and have access to the treasure trove of stuff | |
| in the if-archive at ftp.gmd.de, check out the sample source code | |
| available there. For instance, there is an Examples directory in the TADS | |
| programming area that contains a number of small source code examples | |
| written by many TADS authors. A lot of these examples are written | |
| specifically to teach people about various principles of game design. | |
| Others are written to implement commonly-used features. For example, I | |
| wrote a little set of modules that I find very useful for testing games | |
| in progress. That file, wizard.t, is available in the examples directory. | |
| Another useful file is bugs.t by Stephen Granade, which provides patches | |
| for some minor bugs in the adv.t TADS libraries. | |
| ftp://ftp.gmd.de/if-archive/programming/tads/examples/ | |
| In addition to the mini code examples there is original TADS source to a | |
| number of complete full-length games on ftp.gmd.de as well. For example, | |
| Dave Baggett, in a deeply admirable selfless gesture, has ported the | |
| classic Colossal Cave (ie: "Adventure") game to TADS and published the | |
| source code in order to help train future generations of TADS authors. | |
| He's also made the source to his epic game "Legend" available. 1995 | |
| Interactive Fiction Contest winner Magnus Olsson has put the source to | |
| his winning entry "Uncle Zebulon's Will" in the same directory, and TADS | |
| author Michael J. Roberts has put his games "Deep Space Drifter" and | |
| "Perdition's Flames" online as well. | |
| ftp://ftp.gmd.de/if-archive/games/source/tads/ | |
| There are also a lot of other files in the if-archive that, although not | |
| directly related to TADS, nevertheless contain extremely useful | |
| information. For example, Graham Nelson's Inform compiler, which | |
| generates games compatible with the classic Z-machine system designed by | |
| Infocom, has a well-written manual that contains a lot of useful tips | |
| that can be used by any text adventure author. Check out his fascinating | |
| "Craft of Adventure" document. | |
| ftp://ftp.wustl.edu/doc/misc/if-archive/info/ | |
| Now let's get into some of the technical tips. | |
| *NEVER* MODIFY GAME STATE IN VERIFY METHODS. | |
| This is a very very common problem. The way TADS uses the "verify" | |
| method in a verb can be quite confusing, and it can lead to a lot of | |
| problems. Verify methods are object methods that start with "ver". | |
| Basically, remember that TADS doesn't use the verify method solely | |
| to see if an item can be verbed appropriately. It also uses the *same | |
| method* as part of its disambiguation routine. When it does so it | |
| silently calls the method. That means it calls it, but suppresses any | |
| text that the message may try to produce. If any text is produced and | |
| hidden then the game knows that the item in question can't be verbed by | |
| the verb. | |
| The upshot of all this is that if you change the state of the game | |
| somehow and don't simply display text you can really get strange | |
| things happening when that verify method is triggered inadventently | |
| by a disambiguation routine. | |
| Here's a concrete example. This is bad: | |
| badMagicTurkey: item | |
| sdesc = "magic turkey" | |
| [ etc. etc. ] | |
| verDoTouch( actor ) = | |
| { | |
| "Good heavens! The magical turkey vanishes | |
| in a cloud of tangerine-coloured vapour! "; | |
| self.moveInto( nil ); | |
| } | |
| ; | |
| The code is bad because the disambiguation function might call that | |
| verify method sometime, and if it does so it'll suppress the text but | |
| modify the game state by moving the turkey into nil. Thus our turkey may | |
| suddenly vanish for no readily apparent reason, and the player won't be | |
| notified when it does. The fix? Simply do this: | |
| goodMagicTurkey: item | |
| [ etc. etc. ] | |
| verDoTouch( actor ) = {} | |
| doTouch( actor ) = | |
| { | |
| "Good heavens! The magical turkey vanishes | |
| in a cloud of tangerine-coloured vapour! "; | |
| self.moveInto( nil ); | |
| } | |
| ; | |
| Since our verify method has simply an empty method the runtime just | |
| moves on to the actual verb method and executes it. No problems. | |
| Check out pages 36-39 of the TADS manual (a crucial section, by the | |
| way) and particularly page 39 for more details. This is the section | |
| titled "Disambiguation" in Chapter 4. | |
| *NEVER* SET OBJECT LOCATIONS MANUALLY AT RUNTIME. | |
| This is actually explained in chapter 4 of the manual, but I feel it's | |
| worth repeating here. | |
| It's OK to specify an item's location manually in the initial game | |
| definition. For example, this is cool, insofar as euphoniums can possibly | |
| be considered to be cool: | |
| Euphonium: item | |
| location = bandRoom | |
| ; | |
| What you *don't* want to do is set an item's location manually like that | |
| within code that is executed during game play. Doing so totally messes | |
| things up, because then the contents property of the container within which | |
| the item is located is not updated correctly. So the following code is bad: | |
| Euphonium.location := Wastebasket; | |
| Instead, you want to use the moveInto() method, like this: | |
| Euphonium.moveInto( Wastebasket ); | |
| That keeps everything neatly synched up. | |
| COMMON COMPILER ERRORS. | |
| Some of the most common compile-time errors result from forgetting | |
| to add a semicolon or not closing parentheses properly. As | |
| explained on page 201 of the manual, the compiler will try to skip | |
| ahead to the next code object if it encounters a problem. Thus if | |
| you end up with an endless string of compile-time errors appearing | |
| on your screen when you try and compile you can usually safely | |
| ignore most of the errors - it was likely the first one that caused | |
| all the problems. | |
| Another common problem is accidentally adding a semicolon after an | |
| if statement, thus: | |
| if ( elvis.isDead ); | |
| { | |
| say( 'No kidding. ' ); | |
| } | |
| This will cause a compile-time error as the semicolon after the | |
| if(); statement will tell the compiler that the if statement is | |
| complete. | |
| Yet another easily made error is to name a local variable the same name | |
| as a function. You can't do that. | |
| COMMON RUNTIME ERRORS. | |
| If you forget to return a value from a method or function you'll get | |
| the dreaded 1010 error. This could also mean that you've asked the | |
| game to evaluate a property that doesn't exist. For instance, if | |
| you have something like this: | |
| if ( Me.location.isUpstairs ) | |
| and Me.location = nil, you'll have problems because TADS will try to | |
| figure out the isUpstairs property of a non-existent object. You'd be | |
| better off doing this: | |
| if ( Me.location and Me.location.isUpstairs ) | |
| Another common problem involves the number of arguments you send to a | |
| function. Let's say you've invented a nice function like this: | |
| superDuperFunction: function( parm1, parm2, parm3 ) | |
| { | |
| // ingenious code in here. | |
| } | |
| Now if you call your function using this code: | |
| superDuperFunction( nil, true, nil, nil ); | |
| you'll get the annoying TADS-1026 error. The same error will occur if | |
| you call a method with the wrong number of arguments. | |
| TO MODIFY ADV.T OR NOT TO MODIFY ADV.T? | |
| That is the question. This is one of those perennial Difficult | |
| Decisions that TADS authors have to face. There are essentially three | |
| basic approaches as I see it. | |
| 1) Don't touch adv.t at all. The only changes made are done through | |
| TADS 2.1's "modify" and "replace" features. | |
| Pros: game doesn't break when a new version of adv.t is released. | |
| Cons: as your game gets complex it gets confusing tracking all the | |
| patches you've made to adv.t. | |
| 2) Modify adv.t as needed, brazenly ignoring "modify" and "replace." | |
| Pros: the game can include a myriad features that go beyond the | |
| fairly basic adv.t defaults. | |
| Cons: it's a lot more work to maintain as every single time a new | |
| version of adv.t is released you've got to go through manually and | |
| check every bit of code to make sure it still works. | |
| 3) Skip adv.t altogether and use WorldClass instead. | |
| Pros & Cons: See next section. | |
| Either way it's good practice to document thoroughly any changes you | |
| make to either adv.t or std.t or both. | |
| TAKE A LOOK AT WORLDCLASS. | |
| David Baggett, half of the Adventions team famous for the Unnkulian | |
| Unventures, has designed a complete replacement class library system for | |
| TADS. WorldClass replaces the standard adv.t and std.t TADS libraries | |
| altogether. | |
| WorldClass is an extremely powerful and flexible class library system | |
| that lets you do some pretty impressive stuff. It's much more consistent | |
| in structure and naming, and supports a lot of very useful concepts. For | |
| instance, it lets you treat all five senses equally in a game, and can | |
| handle abstractions like knowledge of items. | |
| There are two disadvantages to WorldClass as I see it, however. The | |
| first is that it's considerably slower than adv.t on old machines. If | |
| you have a reasonably modern computer, this won't be an issue, but if | |
| you have a really ancient clunker (eg: Mac Plus, IBM PC AT) then you'll | |
| find WorldClass games take a long time thinking between moves. This is | |
| because all items in the game are considered, rather than just those in | |
| your immediate surroundings. This means that cool stuff like knowledge | |
| classes are supported, but does slow things down. | |
| Second, WorldClass is quite a bit more complicated than adv.t. It lets | |
| you do a lot more than adv.t, but does have a steeper learning curve as | |
| a result. If you want to knock off a quick mini game, you might want to | |
| stick with adv.t. But if your ambitions are a bit higher, consider | |
| spending the time to learn what WorldClass can do for you! | |
| WorldClass, including Paul Gilbert's excellent manual, is in the | |
| if-archive at: | |
| ftp://ftp.gmd.de/if-archive/programming/tads/worldclass/ | |
| Or you can check the WorldClass Programming Page: | |
| http://www.df.lth.se/~mol/progtadsworldclass.html | |
| CASE IS NORMALLY SIGNIFICANT. | |
| When you *play* a TADS game you can enter commands in upper, lower or | |
| mixed case and everything works fine. However, TADS *code* is | |
| normally case sensitive. If you're having problems with a variable | |
| or object name not being recognized double-check to make sure that | |
| the capitalization is consistent. Common problems involve | |
| properties like "islit" or "isseen" and methods like "verDoTake" and the | |
| like. WorldClass is considerably more consistent than adv.t on this | |
| score. | |
| Newer versions of the compiler do permit case insensitivity, but | |
| you'll likely find your game won't compile with this option turned | |
| on unless you check your entire source code for case issues. | |
| CHECK OUT THE TADS DEBUGGER. | |
| One of the coolest things about TADS is that it has a fabulous source | |
| code debugger. This was one of the major perks for buying the shareware | |
| version of TADS back when it was shareware. And now that TADS has gone | |
| freeware the debugger is freely available at your disposal. At least, if | |
| you use Macintosh or MS-DOS computers it is. At time of writing the | |
| debugger wasn't available for any other platforms, but since the source | |
| code is available I'm sure busy hands are at work as we speak, porting | |
| the program to every platform under the sun. | |
| So be sure to check the thing out if you can get your hands on it. It | |
| lets you run a game and step and trace through the source, making it | |
| really easy to find bugs. You can even go in and change variables and | |
| stuff, making it quite simple to test your code. The Mac version is | |
| particularly nice, as it uses multiple windows to display the game, the | |
| command line for the debugger and the source code. In fact, at time of | |
| writing the Macintosh is the best platform for writing TADS games with | |
| (in my opinion) for this very reason. | |
| DON'T USE "THING". | |
| Never create an object of type "thing". You'll get a runtime error | |
| if the player tries to pick it up. Always create an object of type | |
| "item" if you want something small and takeable. An item with "thing" as | |
| its class is, of course, just fine. | |
| LOCAL STATEMENTS. | |
| Local statements must be the first statements to appear in a block | |
| of code. Otherwise you get a "general syntax error." As mentioned | |
| in the manual on page 71, the only kind of code that can precede a | |
| local statement is another local statement. Thus, this next code | |
| segment won't compile because its local statement is preceded by | |
| something else: | |
| superFunction: function | |
| { | |
| "Hello there! "; | |
| local burp := true; | |
| } | |
| This (admittedly rather pointless) function will work flawlessly | |
| if you put the local statement at the top, before any other statements | |
| within the brackets. | |
| WHY THE HECK WON'T FLOATING ITEMS, HIDDEN ITEMS OR OBSTACLES WORK? | |
| In all likelihood you've defined something in the game as being a floating | |
| item, hidden item or obstacle without also defining it as being a member of | |
| whatever class it needs to be. In other words, this won't work: | |
| tree: floatingItem | |
| but this will: | |
| tree: fixeditem, floatingItem | |
| (of course, it may sound like a bit of a contradiction in terms to have a | |
| tree that's both fixed and floating, but there you go.) | |
| If you look in adv.t you'll notice that floatingItems and hiddenItems and | |
| obstacles are all defined as objects rather than items. That means they | |
| contain no code of any kind. The class is being used as a marker class | |
| rather than one from which code is inherited. | |
| Note that if you've coded your stuff correctly and it still doesn't work | |
| then it's possible that you neglected to include the preinit() code that | |
| sets up the list of all floating and hidden items in the game. | |
| WHENCE DOUBLE-QUOTED STRINGS? | |
| By "double-quoted" I mean strings of text that are delineated by | |
| quotation marks rather than apostrophes. There's a crucial difference. | |
| TADS displays the former whenever it sees them but won't display the | |
| latter unless you explicitly use the say() function. In other words, | |
| this won't work: | |
| if ( self.colour = "red" ) | |
| self.colour; | |
| The runtime will automatically display the word "red" whenever it | |
| evaluates this piece of code. You probably don't want that. Instead | |
| you should do this: | |
| if ( self.colour = 'red' ) | |
| say( self.colour ); | |
| Why does TADS have this unusual double-quoted string concept? Well, | |
| because it's very useful. Adventure games are constantly displaying | |
| text. It'd be extremely tedious to have to say something like | |
| "printf( 'blah blah' );" or whatever all the time just to get words | |
| on the screen. Double-quoted TADS strings are a useful shortcut. | |
| This is explained on page 21 of the printed manual. | |
| "OF" IS A SPECIAL WORD IN OLDER TADS VERSIONS. | |
| As described on page 32 of the manual, the word "of" is a special word | |
| that gets removed by the parser in older versions of TADS. If you want | |
| to use it in some other context (say, "accuse Ronald of murder") then be | |
| sure to upgrade to version 2.2, which lets you use "of" as a preposition | |
| and removes the previously hardcoded restriction. | |
| PLURAL AND SINGULAR PROBLEMS. | |
| Let's say you have an object somewhere with a noun of "blinds". | |
| Let's say you also have another object elsewhere with a plural of | |
| "blinds". Now you won't be able to refer to the item with only a | |
| noun set to "blinds" - you'll get the "I don't see that here" | |
| message. Both have to be either noun only or plural only. | |
| CONDITIONAL VOCABULARY. | |
| TADS doesn't permit conditional vocabulary in noun and adjective | |
| definitions. It sets up a table of vocabulary words at compile time. So | |
| something like this is not legal: | |
| noun = | |
| { | |
| if ( self.isBig ) | |
| return( 'big' ); | |
| else | |
| return( 'small' ); | |
| } | |
| However, starting with version 2.2 you can add and delete words at will | |
| using the addword() and delword() built-in functions. These don't let you | |
| set up conditional code like the example above, but do let you add and | |
| delete vocabulary words at runtime. Very handy feature! | |
| (note however that there is a bug in the Macintosh version of the TADS | |
| runtime at time of writing. If you add a word using addword() and then | |
| undo that move then the word is not removed as it should be.) | |
| SPACES AFTER STRINGS. | |
| It's usually good form to add an extra space after a string of text, | |
| thus: | |
| ldesc = "It's an ordinary turnip. " | |
| instead of: | |
| ldesc = "It's an ordinary turnip." | |
| Why? Well you never know what text might be displayed next. If, say, | |
| a daemon displays some text without first printing a "\b"; sequence | |
| to add a blank line you'll get your sentences running together. | |
| Adding a blank space prevents this from happening. | |
| TADS IS OBJECT-ORIENTED. | |
| It really is! Don't code up objects with endless case statements and | |
| if-else statements when you can inherit properties and methods from | |
| classes. You'll find the code is much more elegant and easy to | |
| understand and often takes up less room as well. Thus, this following | |
| piece of code is a Really Clunky Way to do things: | |
| bananaTree: fixeditem, floatingItem | |
| sdesc = | |
| { | |
| switch( Me.location ) | |
| { | |
| case Forest: | |
| "big"; | |
| break; | |
| case Greenhouse: | |
| "small"; | |
| break; | |
| case Jungle: | |
| "enormous"; | |
| break; | |
| } | |
| " banana tree"; | |
| } | |
| [ etc etc ] | |
| locationOK = true | |
| location = | |
| { | |
| if ( Me.location = Forest or Me.location = Greenhouse | |
| or Me.location = Jungle ) | |
| return( Me.location ); | |
| } | |
| ; | |
| This is a somewhat better way to do the same sort of thing: | |
| bananaTree: fixeditem, floatingItem | |
| sdesc = | |
| { | |
| Me.location.bananaTreeString; | |
| " banana tree"; | |
| } | |
| [ etc etc ] | |
| locationOK = true | |
| location = | |
| { | |
| if ( Me.location.hasBananaTree ) | |
| return( Me.location ); | |
| } | |
| ; | |
| Then you could set the hasBananaTree property to nil in the "room" | |
| class, so that all other rooms would inherit this nil value. | |
| Special locations could have the property set to true. Likewise, | |
| those special locations could have their bananaTreeString | |
| properties set to display the appropriate message. | |
| What's the advantage of doing it this way? Well, putting special | |
| case code into special rooms means you don't have to hardcode a | |
| whole pile of unwieldy conditional coding into the floating item. | |
| Also, special case stuff (ie: the forest having a tree or whatever) | |
| is associated with special case locations. | |
| (note: this isn't the world's greatest piece of sample code as it | |
| has one major inconsistency in it. That is, unless you've also | |
| modified the chair item class in adv.t to pass the hasBananaTree | |
| value through, the tree will mysteriously vanish if you sit down on | |
| anything. Just something to keep in mind!) | |
| BREAKING OUT OF THE RUNTIME. | |
| Sometimes TADS gets stuck and only displays an error message instead | |
| of accepting input. Other times you type something but absolutely | |
| nothing is displayed - the game just returns you to the > prompt. | |
| These usually indicate a bug in your TADS code. In either case | |
| typing the special command $$ABEND in the runtime window should | |
| force the runtime to quit. | |
| BEWARE CONTROL CHARACTERS. | |
| It seems that accidentally embedding a control character in your TADS | |
| source will often cause the compiler to bomb. If you're getting | |
| mysterious compiler errors from a piece of code that looks perfectly | |
| legitimate, you might have accidentally typed an invisible control | |
| character into your code - maybe your finger slipped off the shift key | |
| or something. | |
| In cases like this it's a good idea to run your source through a filter | |
| program to eliminate any possible control characters before trying to | |
| figure out why an otherwise reasonable-looking piece of code isn't | |
| working. For example, Macintosh users of BBEdit can use that text | |
| editor's "Zap Gremlins" feature to toast all control characters. | |
| BEWARE OF #pragma C+ | |
| Remember that TADS supports two different styles of operators - its own | |
| style, and the style used in C. There are some similarities and some | |
| differences between these two styles. | |
| TADS lets you choose which style of operator you want. If you include | |
| the header "#pragma C+" at the start of each source code file then the | |
| compiler will use C style operators. If you don't include this header | |
| or include the header "#pragma C-" then TADS will use its default style. | |
| The thing to beware of is that some examples of TADS coding out there | |
| use the traditional style and some the C style. The vast majority of the | |
| code I've seen uses the traditional style, but I've noticed a handful of | |
| code examples (usually written by Mike Roberts in his documentation) | |
| that use the C style. This can lead to problems if you copy a chunk of | |
| code that uses one style operator and paste it into another file that | |
| uses the other style. | |
| So, let's say you see some code that includes this line: | |
| if ( v == inspectVerb ) | |
| That was written in the C style. The traditional TADS operator style | |
| would have read like this: | |
| if ( v = inspectVerb ) | |
| Likewise, you might see some code that looks like this: | |
| if ( self.value != nil ) | |
| The traditional TADS way to code that is: | |
| if ( self.value <> nil ) | |
| The other common problem operator is the assignment operator. In the C | |
| style it's this: | |
| trombone.noiseValue = true; | |
| but in the traditional TADS style it's this: | |
| trombone.noiseValue := true; | |
| So be sure to check which operator method the code you're using is | |
| written in. If the code contains the line #pragma C+ at the start then | |
| you know for sure it's written in the C style. However if it doesn't | |
| have anything then you're best off checking the code carefully to make | |
| sure that it is, in fact, written in the traditional TADS style. Some of | |
| the operators are compatible between styles - but others are not and | |
| will cause the compiler to choke. | |
| The C style operators are described in detail in the TADS 2.2 Release | |
| Notes. | |
| ADD IN THE DEBUG FUNCTIONS | |
| The standard debugTrace() function simply lets you enter the debugger's | |
| command line mode when you're running it. It's useful, but recent | |
| versions of TADS support a much niftier extension to the function. This | |
| extension turns on a diagnostic mode when you're playing a game. Even | |
| more usefully, this diagnostic mode works with the standard runtime as | |
| well as with the debugger program. | |
| The diagnostic mode works like this. Let's say it's turned on and you | |
| type the command: | |
| >examine the iron bench | |
| The runtime then displays the following extra information: | |
| . Checking words: | |
| ... examine (verb) | |
| ... the (article) | |
| ... iron (adj) | |
| ... bench (noun) | |
| . Checking for actor | |
| . Reading noun phrase | |
| ... iron (treating as adjective) | |
| ... bench (treating as noun) | |
| ... found objects matching vocabulary: | |
| ..... white wooden bench | |
| ..... cast iron bench | |
| . executing verb: examine | |
| .. setting it: cast iron bench | |
| The runtime then displays the normal response to the command; in this | |
| case: | |
| You're looking at the cold cast iron frame of an old-fashioned park | |
| bench. It seems to have been painted recently with glossy black enamel. | |
| Note all the useful information. The game breaks down the command, | |
| telling you which words it's treating as nouns or adjectives, then lists | |
| all the objects in the game that match the supplied input. In this case | |
| my game contains two items that have 'bench' as a noun, but the game | |
| disambiguates further and only selects the cast iron one. It also | |
| performs a setit() on the bench item. | |
| To add this handy feature to your game just add the following verbs: | |
| debugonVerb: sysverb | |
| verb = 'debugon' | |
| action( actor ) = | |
| { | |
| if ( debugTrace( 1, true ) ) | |
| "Debug diagnostic mode engaged. "; | |
| abort; | |
| } | |
| ; | |
| debugoffVerb: sysverb | |
| verb = 'debugoff' | |
| action( actor ) = | |
| { | |
| if ( debugTrace( 1, nil ) ) | |
| "Debug diagnostic mode disengaged. "; | |
| abort; | |
| } | |
| ; | |
| This problem with setit() is due to be fixed in the next version of the | |
| TADS runtime. | |
| "it" IS A PROBLEM WITH numObj AND strObj OBJECTS | |
| Here's an obscure one. Let's say you have a method in a numObj | |
| or strObj object. Here's a silly example of this: | |
| narfVerb: deepverb | |
| verb = 'narf' | |
| sdesc = "narf" | |
| doAction = 'Narf' | |
| ; | |
| numObj: basicNumObj; | |
| verDoNarf( actor ) = {} | |
| doNarf( actor ) = | |
| { | |
| local i, len; | |
| len := self.value; | |
| if ( len = 0 ) | |
| "No narf. "; | |
| else | |
| { | |
| "\b\t"; | |
| for ( i := 1 ; i <= len ; ++i ) | |
| "Narf! "; | |
| } | |
| } | |
| This pointless piece of code works like this: | |
| >narf 4 | |
| Narf! Narf! Narf! Narf! | |
| The problem is that TADS will then set the value of "it" to numObj. | |
| Which means that if the player types, say, "examine it" after issuing | |
| the "narf" command, nothing will happen: | |
| >narf 3 | |
| Narf! Narf! Narf! | |
| >examine it | |
| > | |
| This occurs because the numObj object hasn't got any verb methods | |
| defined for any common verbs. Exactly the same thing will happen with | |
| strObj objects, thus: | |
| >say "hello" | |
| You say "hello." | |
| >eat it | |
| > | |
| The easiest way to deal with this problem is to put the line setit( nil ); | |
| into your doNarf method. This resets the value of "it" to nil, safely | |
| avoiding the whole mess. | |
| A more complex solution is to create a universally accessible floating | |
| item that has no vocabulary words associated with it, then setting 'it' | |
| to be that object. This allows for fancy tricks like this: | |
| >say "hello" | |
| Okay. You say "hello." | |
| >x them | |
| I'm not sure what you're referring to by "them," because the last thing | |
| you referred to was the text "hello." | |
| WHERE IS THE NUMBEREDOBJECT CODE? | |
| The code for handling numbered objects seems to be missing from | |
| the 2.2.1 adv.t distribution. Here it is. | |
| /* | |
| * numbered_cleanup: function | |
| * This function is used as a fuse to delete objects created by the | |
| * "numberedObject" class in reponse to calls to its newNumbered | |
| * method. Whenever that method creates a new object, it sets up a fuse | |
| * call to this function to delete the object at the end of the turn in | |
| * which it created the object. | |
| */ | |
| numbered_cleanup: function( obj ) | |
| { | |
| delete obj; | |
| } | |
| /* | |
| * numberedObject: object | |
| * This class can be added to a class list for an object to allow it to | |
| * be used as a generic numbered object. You can create a single object | |
| * with this class, and then the player can refer to that object with | |
| * any number. For example, you can create a single "button" object | |
| * that the player can refer to with "button 100'' or "button 1000'' | |
| * or any other number. If you want to limit the range of acceptable | |
| * numbers, override the "num_is_valid" method so that it displays | |
| * an appropriate error message and returns "nil" for invalid numbers. | |
| * If you want to use a separate object to handle references to the object | |
| * with a plural ("look at buttons"), override "newNumberedPlural" to | |
| * return the object to handle these references; by default, the original | |
| * object is used to handle plurals. | |
| */ | |
| class numberedObject: object | |
| adjective = '#' | |
| anyvalue( n ) = { return n; } | |
| clean_up = { delete self; } | |
| newNumberedPlural( a, v ) = { return self; } | |
| newNumbered( a, v, n ) = | |
| { | |
| local obj; | |
| if ( n = nil ) return self.newNumberedPlural( a, v ); | |
| if ( not self.num_is_valid( n ) ) return nil; | |
| obj := new self; | |
| obj.value := n; | |
| setfuse( numbered_cleanup, 0, obj ); | |
| return obj; | |
| } | |
| num_is_valid( n ) = | |
| { | |
| if ( n = 0 ) | |
| { | |
| "There aren't zero "; self.pluraldesc; " here! "; | |
| return nil; | |
| } | |
| else if ( n > self.maxNum ) | |
| { | |
| "There aren't that many "; self.pluraldesc; "! "; | |
| return nil; | |
| } | |
| else | |
| return true; | |
| } | |
| dobjGen( a, v, i, p ) = | |
| { | |
| if ( self.value = nil ) | |
| { | |
| "You'll have to be more specific about which one you mean. "; | |
| exit; | |
| } | |
| } | |
| iobjGen( a, v, d, p ) = { self.dobjGen( a, v, d, p ); } | |
| maxNum = 10 | |
| ; | |
| +--------------+ | |
| Macintosh Tips | |
| +--------------+ | |
| Here are some tips for the users of the Macintosh version of TADS. | |
| I don't normally do compilation on the DOS or UNIX or other flavours | |
| of TADS so I'm not going to include any tips for those platforms | |
| unless someone sends me some. | |
| COMPILER BOMBS. | |
| If you have a very large game and you're having problems with the | |
| compiler crashing when you try to compile, it's possible you don't | |
| have enough memory allocated. Try increasing the amount of memory | |
| set aside for the compiler by changing the setting in the "Get | |
| Info" box. 1500 K is usually enough for even a big game. | |
| MULTIFINDER OR SYSTEM 7.x. | |
| Don't forget that TADS can run in the background under MultiFinder | |
| or under System 7.x. However once TADS has finished loading in the | |
| files and starts the actual compilation it'll lock up your Mac for | |
| the duration of the compile. | |
| TEXT EDITOR. | |
| If you're struggling with editing code on a word processor or | |
| something, take a look at some of the freeware and shareware text | |
| editors out there. There are quite a few, including Edit II and | |
| Alpha. Probably one of the best (IMHO) is BBEdit, however. | |
| BBEdit itself is now payware, but there's still a freeware "Lite" | |
| (sic) version available. Any version is ideal for editing TADS | |
| code. They do bracket and brace balancing, semi-automatic | |
| formatting, GREP search and replace, no wordwrap and a thousand and | |
| one other features. Try to find version 2.2.2 which, unlike the | |
| newer BBEdit Lite, can do file comparisons. This function, | |
| analogous to a "diff" utility, is an extremely nice way to compare | |
| older versions of source with the new. Of course obsessive hackers | |
| can check out the port of emacs... | |
| COMMAND-PERIOD. | |
| Don't forget that TADS can now break out of endless loops by hitting | |
| command-period, like all good Mac programs do. | |
| Note that the HTML version of this file normally lives at: | |
| http://www.tela.bc.ca/tela/tads/authoring/tads-tip-sheet.html | |
Xet Storage Details
- Size:
- 36.7 kB
- Xet hash:
- 4cf5f2d63dbc9dc111a7c743ed9e23292582f3ee709a9f7e4786deeed21d8705
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.