TADS Programming - Clothing As in previous files I have removed the asterisks used to show REMS, I'm sure it will be clear where they should be - Sue This source code is (C)1994 Jonathan D. Feinberg. See below for permission to distribute. clothing.t: smarter clothingItem This file modifies the standard adv.t file to provide a slightly more realistic feel for the clothingItem class. To enjoy the benefits of this modified class requires very little work on your part beyond what you already need to do to implement clothingItem objects; indeed, existing code that uses vanilla clothingItem objects will work the same as ever, without "fixes." clothing.t provides three new features: 1) Custom messages for donning and doffing clothes, warning the user that clothes are already worn, and describing the state of the clothing in the inventory command. If you do not provide custom messages, the default messages are supplied for you. 2) Clothing "families," within which only one item at a time may be worn. My sample code gives two theater masks. In the real world, you aren't going to wear more than one mask at a time. Other possible uses include uniforms, hats, etc. If you do not specify a family number, the clothing will have default behavior. 3) The "autoTakeOff" property which enables you to control whether, when the player either drops a clothingItem which isworn, or puts on a clothingItem in a family that has an isworn member already, the isworn item is automatically removed as a convenience to the user. I advocate leaving it true. I provide it to make it easy to force the player to take off certain pieces of equipment manually, like, say, scuba gear. CUSTOM MESSAGES Please see the property definitions below for the expected formats of these messages. The default values of these properties are copied from adv.t. beingWornDescEvaluated in inventory lists after the item's adesc when its isworn property is true. (See listcont, below) putOnDescEvaluated when the player puts the item on. takeOffDescEvaluated when the player takes the item off. mustTakeOffDescEvaluated when the player must first remove the item to perform some action (only shown if autoTakeOff is nil. alreadyOnDesc Evaluated when the player tries to wear something he/she is already wearing. notOnDesc Evaluated when the player tries to unwear something he/she is not wearing. autoTakeOffDescEvaluated when the self.checkDrop method takes off a worn piece of clothing. FAMILIES Simply give the family property of your clothing item a non-zero integer that it will share with other members of its family, but not with other families. An obvious way to do so is to subclass clothingItem, give the child class a family number, and create objects of that subclass that will automatically belong to that family. ADDS: clothingItem.family clothingItem.putOnDesc clothingItem.autoTakeOff clothingItem.takeOffDesc clothingItem.otherMemberWorn clothingItem.mustTakeOffDesc clothingItem.beingWornDesc clothingItem.notOnDesc clothingItem.autoTakeOffDesc REPLACES: clothingItem.checkDrop clothingItem.verDoUnwear clothingItem.verDoWear clothingItem.doUnwear clothingItem.doWear function listcont I encourage you to use this code in your own TADS games. I would appreciate a note from you if you use this code, or even if you see it and have comments or suggestions. Please include my name in the credits for your game. Please include this file in its entirety in any distribution of your source code. Please clearly mark any alterations you have made to my code. By the way, I got the idea for this modification from my brief experience at LambdaMOO before it mysteriously vanished. I like that you can create obects that appear to have required a lot of programming by just changing a few messages around. Anybody know where LambdaMOO is? jdf@panix.com 2/23/94 - Given to Neil K. Guy for testing. Thanks, Neil! 2/28/94 - First public release. modify clothingItem family property An integer that defines which clothing family this item is in. Items with family == 0 have the usual behavior (can be worn at the same time as each other). family = 0 otherMemberWorn method Determines whether any other member of this item's family isworn. Returns either nil (nothing else being worn) or the object being worn. otherMemberWorn = { local obj; if (self.family = 0) // You can wear as many 0's as you like return( nil ); for (obj := firstobj( clothingItem ); obj <> nil; obj := nextobj( obj)) { if (obj.family <> self.family) continue; else if (obj = self) continue; else if (obj.isworn) return( obj ); } return( nil ); } descriptions Evaluated when the player takes certain actions. See above. beingWornDesc = "(being worn)" putOnDesc = { "Okay, %you're% now wearing "; self.thedesc; ". "; } takeOffDesc = { "Okay, %you're% no longer wearing "; self.thedesc; ". "; } mustTakeOffDesc = { "%You% will have to remove "; self.thedesc; " first. "; } alreadyOnDesc = { "%You're% already wearing "; self.thedesc; ". "; } notOnDesc = { "%You're% not wearing "; self.thedesc; ". "; } autoTakeOffDesc = { "(Taking off "; self.thedesc; " first)\n"; } autoTakeOff = true replace checkDrop = { if ( self.isworn ) { if (autoTakeOff) { self.autoTakeOffDesc; self.isworn := nil; } else { self.mustTakeOffDesc; exit; } } } replace verDoWear( actor ) = { if ( self.isworn ) { self.alreadyOnDesc; } else if ( not actor.isCarrying( self )) { "%You% %do%n't have "; self.thedesc; ". "; } } replace doWear( actor ) = { local wornObject := self.otherMemberWorn; if (wornObject <> nil) wornObject.checkDrop; self.putOnDesc; self.isworn := true; } replace verDoUnwear( actor ) = { if ( not self.isworn ) { self.notOnDesc; } } replace doUnwear( actor ) = { self.takeOffDesc; self.isworn := nil; } ; This replacement of the adv.t listcont(obj) function simply takes into account a clothing item's custom "(being worn)" message. I also couldn't resist rewriting it in K&Rish style. replace listcont: function( obj ) { local i, tot, list, cur, disptot; list := obj.contents; tot := length( list ); disptot := itemcnt( list ); for ( i := 1; i <= tot; ++i ) { cur := list[i]; if ( cur.isListed ) { if ( i > 1 ) { if ( i < disptot ) ", "; else if (i = 2) " and "; else ", and "; } cur.adesc; // list this object // The following line is the only important change to this function. if ( cur.isworn ) { " "; cur.beingWornDesc; } if ( cur.islamp and cur.islit ) " (providing light)"; } } } An example of this in use: -------------------------- #include "adv.t" #include "clothing.t" #include "std.t" The first two items are there to demonstrate clothingItem objects with default behavior--they use none of the new features. shirtItem: clothingItem sdesc = "Hawaiian shirt" ldesc = "This is a gaudy Hawaiian shirt, like those classically worn by tourists. Must have been a costume. " noun = 'shirt' adjective = 'Hawaiian' 'gaudy' location = startroom ; pantsItem: clothingItem // an unabashed Seinfeld reference sdesc = "pair of tan Dockers" ldesc = "This is a pair of casual pants, of the most boring shade of tan that you could possibly imagine. " noun = 'pants' 'dockers' 'jeans' 'slacks' adjective = 'pair of' 'tan' location = startroom ; Here, I subclass clothingItem to create a clothing family. I use the family feature, and I also provide a couple of custom messages to add some texture to the experience of using this kind of clothing. class maskItem: clothingItem family = 1 noun = 'mask' beingWornDesc = "(on your face)" putOnDesc = { "%You% gingerly place "; self.thedesc; " over %your% eyes. "; } takeOffDesc = { "%You% carefully remove "; self.thedesc; " from %your% face. "; } autoTakeOffDesc = { "(Carefully taking off "; self.thedesc; " first)\n"; } // Uncomment the next line to demonstrate autoTakeOff // autoTakeOff = nil ; tragicMask: maskItem sdesc = "tragic mask" ldesc ="This is a full tragic mask, of the sort described by Keith Johnstone in his book, \"Impro.\" " adjective = 'tragic' 'full' location = startroom ; comicMask: maskItem sdesc = "comic mask" ldesc = "This is a comic half-mask, of the sort described by Keith Johnstone in his book, \"Impro.\" " adjective = 'comic' 'half' location = startroom ; You may want to see yourself in costume... mirrorItem: fixeditem sdesc = "mirror" ldesc = "This full length mirror has an ornate wooden frame, and is quite something to behold. " noun = 'mirror' adjective = 'ornate' 'full length' location = startroom verDoTake( actor ) = { "The mirror is far too heavy to budge. Better to content yourself with looking in it. That what it's for. "; } verDoLookin( actor ) = {} doLookin( actor ) = { Me.doInspect( actor ); } ; startroom: room sdesc = "Theater" ldesc = "You are in a magnificent old theater, which has evidently seen better days; the few remaining lighting instruments are clearly beyond repair, and dust covers every visible surface. But you feel the power of this place in your spine.\nTo the side stands an old, large, and very ornate mirror. "; ; The following is just for fun. It is ugly, but it makes sense in the scenario. I am not proud of it. Back off, man. modify Me replace ldesc = { if (tragicMask.isworn) { "You look as if you were beset by all of the world's sorrows. "; if (shirtItem.isworn) { " This is in shocking contrast with the garish Hawaiian shirt you're sporting. "; if (pantsItem.isworn) " But those pants seem to match your expression. "; } else if (pantsItem.isworn) " This explains your choice of pants. "; } else if (comicMask.isworn) { "You look rather amused. "; if (shirtItem.isworn) { " Your expression matches your shirt quite well. "; if (pantsItem.isworn) " But those pants... I dunno. "; } else if (pantsItem.isworn) " This is in stark contrast with your stodgy pair of pants. "; } else pass ldesc; } ; - o -