| /* EXTEND.T - An Extension Set for TADS | |
| * | |
| * by Neil deMause (neild@echonyc.com), 3/26/96 | |
| * | |
| * In the course of writing two games using TADS | |
| * (MacWesleyan/PC University and Lost New York) | |
| * I've compiled a collection of modifications to the | |
| * basic ADV.T library that make programming a lot | |
| * less painful. (Okay, *some* programming a lot less | |
| * painful.) Included are many new verbs, a couple of | |
| * new object classes, some useful functions, and a | |
| * couple of fixes for parser oddities in ADV.T. Pick | |
| * and choose from among these as you like; they're | |
| * all for public consumption. | |
| * | |
| * All questions or comments regarding this code | |
| * should be directed to me at the above address. | |
| * | |
| * This code is freeware. Do with it as you will. | |
| */ | |
| /* NOTIFY - Notifying when you earn points | |
| * | |
| * This adds the verb "notify", which toggles back and | |
| * forth between on and off. When on, the message | |
| * | |
| * ***You have just gained X points.*** | |
| * | |
| * is printed each time incscore() is run. Notification | |
| * is off by default; add the line | |
| * | |
| * notified=true | |
| * | |
| * to the global object if you want the default to be | |
| * notification on. | |
| */ | |
| replace incscore: function( amount ) | |
| { | |
| global.score := global.score + amount; | |
| scoreStatus( global.score, global.turnsofar ); | |
| global.addthis:=amount; | |
| if (global.notified) notify(global,&tellscore,1); | |
| } | |
| notifyVerb:deepverb | |
| sdesc="notify" | |
| action(actor)= | |
| { | |
| if (not global.notified) | |
| { | |
| "Notification turned on."; | |
| global.notified:=true; | |
| } | |
| else | |
| { | |
| "Notification turned off."; | |
| global.notified:=nil; | |
| } | |
| } | |
| verb='notify' | |
| ; | |
| modify global | |
| /* I also make the default mode for my games | |
| * "verbose", just because I like it that way. | |
| */ | |
| verbose = true | |
| tellscore={"\b***You have just gained <<self.addthis>> points.***";} | |
| ; | |
| /* ISINSIDE - Search an object's entire contents hierarchy | |
| * | |
| * This function enables you to determine if one | |
| * object contains another, even if the contained object | |
| * is buried several levels deep. Actually, it works | |
| * from the bottom up -- cycling through the | |
| * contained item's location hierarchy until it either | |
| * hits the desired container, or nil, in which case it | |
| * stops. | |
| * | |
| * Here's how to use it: Say you have a puzzle where | |
| * carrying a gun through an airport metal detector | |
| * will set off an alarm. Obviously, you want this to | |
| * occur even if the player is carrying the gun in their | |
| * bag, or their pocket, or even hidden inside a | |
| * hollowed-out book in a secret compartment in their | |
| * briefcase. To check on this, include the following | |
| * code: | |
| * | |
| * if (isinside(gun,Me)) alarm.ring; | |
| * | |
| * isinside() returns true if the item is anywhere within | |
| * the location, nil otherwise. | |
| */ | |
| isinside: function(item,loc) | |
| { | |
| if (item.location=loc) return(true); | |
| else if (item.location) return(isinside(item.location,loc)); | |
| else return(nil); | |
| } | |
| /* MOVEFROMTO - Bulk relocation | |
| * | |
| * Dan Shiovitz deserves all the credit for this one; I | |
| * was looking for a way to move the entire contents | |
| * of one object to another, and he came up with this | |
| * nifty code. | |
| */ | |
| moveFromTo: function (from, to) | |
| { | |
| local l, i; | |
| l := from.contents; | |
| for (i := 1; i <= length(l); ++i) | |
| { | |
| l[i].moveInto(to); | |
| } | |
| } | |
| /* DISABLING "ALL" | |
| * | |
| * Another one that isn't my doing, though I've | |
| * unfortunately forgotten who on rec.arts.int-fiction | |
| * provided this code, long ago. I've changed the | |
| * defaults for take, drop, and put to allow the use of | |
| * "all" (which seems logical); adding "allowall=true" | |
| * to other verbs will let you use "all" with them as well. | |
| */ | |
| modify deepverb | |
| doDefault (actor, prep, iobj) = | |
| { | |
| if (self.allowall=nil) | |
| { | |
| if (objwords(1) = ['A']) | |
| { | |
| global.allMessage := 'You can\'t use "all" with this verb.'; | |
| return []; | |
| } | |
| pass doDefault; | |
| } | |
| else pass doDefault; | |
| } | |
| ; | |
| parseError: function (str, num) | |
| { | |
| // if there's an allMessage waiting, use it instead of the default | |
| if (global.allMessage <> nil) | |
| { | |
| local r; | |
| r := global.allMessage; | |
| global.allMessage := nil; | |
| return r; | |
| } | |
| else | |
| return nil; | |
| } | |
| modify takeVerb | |
| allowall=true | |
| ; | |
| modify dropVerb | |
| allowall=true | |
| ioAction(onPrep)='PutOn' //while we're at it... | |
| ; | |
| modify putVerb | |
| allowall=true | |
| ; | |
| /* PLATFORMITEM - Neither chair nor bed... | |
| * | |
| * I once beta-tested a game where if you sat on the | |
| * toilet then tried to leave, you got the response | |
| * "You're not going anywhere until you get out of | |
| * the toilet!" If that toilet had been a platformItem, | |
| * much embarrassment could have been avoided. | |
| * (See also doUnboard under "modify thing".) | |
| */ | |
| class platformItem:chairitem | |
| statusPrep='on' | |
| noexit = | |
| { | |
| "%You're% not going anywhere until %you% | |
| get%s% off of <<thedesc>>. "; | |
| return( nil ); | |
| } | |
| ; | |
| /* VERBS! - I got a million of 'em... | |
| * | |
| * These are some of the verbs I use the most often, | |
| * along with new ioActions for some verb- | |
| * preposition pairs that ADV.T doesn't recognize, | |
| * and the prepositions "for" and "against", which | |
| * ADV.T inexplicably omits. | |
| */ | |
| modify throwVerb | |
| ioAction(thruPrep) = 'ThrowThru' | |
| ioAction(onPrep) = 'PutOn' | |
| ; | |
| liftVerb:deepverb | |
| verb='lift' 'raise' | |
| sdesc="lift" | |
| doAction='Lift' | |
| ; | |
| smellVerb:deepverb | |
| verb='smell' | |
| sdesc="smell" | |
| doAction='Smell' | |
| ; | |
| modify openVerb | |
| ioAction(withPrep)='OpenWith' | |
| ; | |
| modify class openable | |
| doOpenWith(actor,io)= | |
| { | |
| "I don't know how to open <<self.adesc>> with <<io.adesc>>."; | |
| } | |
| ; | |
| modify inVerb | |
| verb='jump in' | |
| ; | |
| modify climbVerb | |
| ioAction(thruPrep)='ClimbThru' | |
| ; | |
| againstPrep:Prep | |
| preposition='against' | |
| sdesc="against" | |
| ; | |
| forPrep:Prep | |
| preposition='for' | |
| sdesc="for" | |
| ; | |
| modify askVerb | |
| ioAction(forPrep)='AskFor' | |
| ; | |
| listenverb:deepverb | |
| verb='listen' | |
| sdesc="listen" | |
| action(actor)={Me.location.listendesc;} //add a listendesc | |
| ; //for any location | |
| //where "listen" | |
| //should get a | |
| //specific response | |
| listentoverb:deepverb | |
| verb='listen to' | |
| sdesc="listen to" | |
| doAction='ListenTo' | |
| ; | |
| /* "Empty" requires a modification for the container | |
| * class, using moveFromTo() | |
| */ | |
| emptyVerb:deepverb | |
| verb='empty' | |
| sdesc="empty" | |
| doAction='Empty' | |
| ; | |
| modify container | |
| verDoEmpty(actor)={} | |
| doEmpty(actor)= | |
| { | |
| if (not self.isopen) "\^<<self.thedesc>> is closed."; | |
| else | |
| { | |
| "You empty the contents of <<self.thedesc>> onto the ground."; | |
| moveFromTo (self, Me.location); | |
| } | |
| } | |
| ; | |
| /*Of course, now we need to code in default responses for many of these new verbs...*/ | |
| modify thing | |
| verDoSmell(actor)={} | |
| doSmell(actor)={self.smelldesc;} | |
| smelldesc="\^<<self.thedesc>> doesn't smell like anything in particular." | |
| /*Fixes a TADS bug that creates responses like "Okay, you're no longer in the toilet."*/ | |
| doUnboard( actor ) = | |
| { | |
| if ( self.fastenitem ) | |
| { | |
| "%You%'ll have to unfasten "; actor.location.fastenitem.thedesc; | |
| " first. "; | |
| } | |
| else | |
| { | |
| "Okay, %you're% no longer <<self.statusPrep>> "; self.thedesc; ". "; | |
| self.leaveRoom( actor ); | |
| actor.moveInto( self.location ); | |
| } | |
| } | |
| verDoTouch(actor)={} | |
| doTouch(actor)=self.touchdesc | |
| touchdesc="It feels just like <<self.adesc>>." | |
| listendesc={"You don't hear anything.";} | |
| verDoListenTo(actor)={} | |
| doListenTo(actor)={"<<self.listendesc>>";} | |
| verDoFind(actor)={"You'll have to find that on your own.";} | |
| verIoAskFor(actor)={} | |
| ioAskFor(actor,dobj)= | |
| { | |
| dobj.doAskFor(actor,self); //redirects the action to the | |
| } //person you're asking | |
| ; | |
| /* UNLISTEDITEM - Not fixed, but not listed | |
| * | |
| * Often you (well, I) want to have an item that you | |
| * can take, but that is included in the room | |
| * description rather than listed separately. This item | |
| * is unlisted until you take it, after which it behaves | |
| * like a regular item. (But be sure to include code in | |
| * your ldesc removing it from the room description once it's | |
| * taken as well.) | |
| */ | |
| class unlisteditem:item | |
| isListed=nil | |
| doTake(actor)={self.isListed:=true; pass doTake;} | |
| ; | |
| /* INTANGIBLE - For things like smells, sounds, etc., a special | |
| * class. | |
| */ | |
| class intangible:fixeditem | |
| verDoTake(actor)={"That can't be taken.";} | |
| verDoTakeWith(actor,io)={"That can't be taken.";} | |
| verDoMove(actor)={"That can't be moved.";} | |
| verDoTouch(actor)={"That can't be touched.";} | |
| verDoTouchWith(actor,io)={"That can't be touched.";} | |
| ldesc="That's not visible." | |
| verDoLookbehind(actor)="That's not visible." | |
| verDoAttack(actor)={"That can't be attacked.";} | |
| verDoAttackWith(actor)={"That can't be attacked.";} | |
| verIoPutOn(actor)={"You can't put anything on that.";} | |
| ; | |
| /* A whole bunch of modifications to the basic Actor class. | |
| */ | |
| modify Actor | |
| /*This automatically translates "ask actor for object" as "actor, give object to me," which can avoid a lot of unnecessary coding.*/ | |
| verDoAskFor(actor,io)={} | |
| doAskFor(actor,io)={self.actorAction(giveVerb,io,toPrep,Me);} | |
| /*Likewise, this translates "actor, tell me about item" as "ask actor about item."*/ | |
| actorAction(v,d,p,i)={if (v=tellVerb and d=Me and p=aboutPrep) {self.doAskAbout(i); exit;}} | |
| listendesc="\^<<self.thedesc>> isn't saying anything!" | |
| disavow="\^<<self.thedesc>> looks confused." | |
| ldesc="\^<<self.thedesc>> looks just like <<self.adesc>>." | |
| verDoLookin(actor)={"I don't know how to look in <<self.thedesc>>.";} | |
| verDoSearch(actor)={"How rude!";} | |
| ioGiveTo(actor, dobj) = | |
| { | |
| "\^<<self.thedesc>> doesn't want it."; | |
| } | |
| ; | |
| /* Another ADV.T bug - currently, asking someone about a | |
| * distantItem gives the odd response "It's too far away." | |
| */ | |
| modify distantItem | |
| dobjGen(a, v, i, p) = | |
| { | |
| if (v <> inspectVerb and v <> askVerb and v <> tellVerb) | |
| { | |
| "It's too far away."; | |
| exit; | |
| } | |
| } | |
| ; | |
| /* FULL - Giving a detailed score | |
| * | |
| * Inform has (built-in, I believe) an easy way to | |
| * give a listing of all the actions that have earned | |
| * you points. The following code adds the same | |
| * functionality to TADS. | |
| * | |
| fullVerb:deepverb | |
| verb= 'full' | |
| action(actor)= | |
| { | |
| if (global.score=0) "You have no points."; | |
| else | |
| { | |
| "You have earned the following:\b"; | |
| /* In here is where you insert the list of actions that | |
| * can earn the player points. For example, if the player | |
| * gets 5 points for finding the magic carrot peeler, and | |
| * 1 points for each carrot they peel with it, you would | |
| * insert the following: | |
| * | |
| * if (global.scPeeler) "\n5 points for finding the carrot peeler"; | |
| * if (global.scCarrots>0) "\n<<global.scCarrots>> points for peeling | |
| * carrots"; | |
| * | |
| * You also, naturally, need to add the appropriate code in | |
| * the place where the actual puzzle is solved -- so that at | |
| * the same time you call incscore(5) for finding the carrot | |
| * peeler, you also set scPeeler:=true. (I just do a search | |
| * for "incscore" through the entire game once I'm done, and | |
| * insert the proper code next to each instance.) | |
| * | |
| "\bTotal score: <<global.score>>"; | |
| } | |
| } | |
| ; | |
Xet Storage Details
- Size:
- 10.8 kB
- Xet hash:
- 8af795cc72e5d93a54ea62676ef59d7273e5e504c7663d5d352403b4341594fe
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.