/* Copyright (c) 2000 by Kevin Forchione. All Rights Reserved. */ /* * TADS ADV.T/STD.T LIBRARY EXTENSION * WALLS.T * version 1.1 * * walls.t implements walls, celings, and floors for actor * locations. Simply #include the module after sense.t and your * rooms will have walls, etc. Rooms with the attribute isOutside * set to true will not have walls or ceilings. * *---------------------------------------------------------------------- * REQUIREMENTS * * + HTML TADS 2.5.1 or later * + Requires ADV.T and STD.T * + Requires SENSE.T 3.1 * + Should be #included after SENSE.T * *---------------------------------------------------------------------- * IMPORTANT LIBRARY INTERFACE AND MODIFICATION * * This module modifies the functioning of the following ADV.T * listing functions: * * Module performs the following process: * * 1. Define the abstract class * a. Setup instance * b. Check requiresInstance * c. Check for cleanup * d. Clean up * 2. Define walls, ceiling, and floor classes * 3. Put abstract objects in scope * 4. Disambiguate abstract / non-abstract objects * 5. Redirect command from abstract to instance * 6. Delete the instance * * In addition this module modifies the following in Sense.t: * * + deepverb validXo() * + deepverb disambigXobj() * + deepverb cantReach() * *---------------------------------------------------------------------- * COPYRIGHT NOTICE * * You may modify and use this file in any way you want, provided that * if you redistribute modified copies of this file in source form, the * copies must include the original copyright notice (including this * paragraph), and must be clearly marked as modified from the original * version. * *------------------------------------------------------------------------------ * REVISION HISTORY * * 26-Jan-2000 Creation. * 30-Jan-2000 Modified creation location of instances. * Modified floor to move objects to the room instead * of the floor contents, except for actors sitting or * lying on the floor. */ #define __WALLS_MODULE_ #ifndef __SENSE_MODULE_ #error THIS MODULE REQUIRES THAT YOU #INCLUDE SENSE.T #endif #pragma C+ /*====================================================================== * A B S T R A C T C L A S S *====================================================================*/ class abstract: object isabstract = true /* * Setup an instance of our abstract object. This object is not * considered abstract. It is moved into the actor's location and * the clean-up daemon is started. */ newAbstract(actor) = { local obj, loc; if (self.requiresInstance(actor)) { obj = new self; loc = scopeCeiling(actor, nil, &access_reachable); obj.moveInto(loc); obj.isabstract = nil; notify(obj, &checkForCleanup, 0); } else obj = self; return obj; } /* * Used to check if the actor's location requires an instance of * the abstract. If not then the "You don't see any foo..." message * is displayed. */ requiresInstance(actor) = { return true; } /* * Don't delete the object if it is holding things or the actor * location == this object or the object is being referenced by a * command. Because daemons run before endCommand we do not delete * the object if either it or its class is referenced by a command * to allow for endCommand() each_turn style processing. */ checkForCleanup = { if (length(self.contents) > 0 || command.actorPtr.location == self || (command.dobjPtr && isclass(self, command.dobjPtr)) || (command.dobjPtr && self == command.dobjPtr) || (command.iobjPtr && isclass(self, command.iobjPtr)) || (command.iobjPtr && self == command.iobjPtr)) return; else self.cleanup; } /* * unnotify the daemon for this object, move it into nil (to clean * up the object tree) and then delete it. */ cleanup = { unnotify(self, &checkForCleanup); self.moveInto(nil); delete self; } ; /*====================================================================== * W A L L S A N D C E I L I N G *====================================================================*/ /* * class wall: abstract, decoration * * The wall class has been defined as an abstract decoration, which * means that most actions will be regarded as unimportant. * * This class defines requires instance to check the actor.location * isOutside attribute. If the attribute is true then we don't require * an instance of wall; otherwise one is dynamically created. */ class wall: abstract, decoration requiresInstance(actor) = { if (actor.location.isOutside) return nil; return true; } ; northWall: wall adjective = 'north' 'n' noun = 'wall' sdesc = "north wall" isNorthWall = true ; southWall: wall adjective = 'south' 's' noun = 'wall' sdesc = "south wall" isSouthWall = true ; eastWall: wall adjective = 'east' 'e' noun = 'wall' sdesc = "east wall" isEastWall = true ; westWall: wall adjective = 'west' 'w' noun = 'wall' sdesc = "west wall" isWestWall = true ; neWall: wall adjective = 'northeast' 'north-east' 'ne' noun = 'wall' sdesc = "northeast wall" isNeWall = true ; nwWall: wall adjective = 'northwest' 'north-west' 'nw' noun = 'wall' sdesc = "northwest wall" isNwWall = true ; seWall: wall adjective = 'southeast' 'south-east' 'se' noun = 'wall' sdesc = "southeast wall" isSeWall = true ; swWall: wall adjective = 'southwest' 'south-west' 'sw' noun = 'wall' sdesc = "southwest wall" isSwWall = true ; ceiling: wall noun = 'ceiling' sdesc = "ceiling" adesc = "the ceiling" isCeiling = true ; /*====================================================================== * T H E F L O O R *====================================================================*/ /* * floor: abstract, fixeditem, surface * * The floor is treated slightly differently because we can sit on it * and put things on it. The actor doesn't actually walk on the floor, * and it will behave like a nestedroom when they enter it. */ floor: abstract, fixeditem, surface noun = 'floor' 'ground' sdesc = "floor" adesc = "the floor" isenterable = true isFloor = true ldesc = { "It lies beneath you. "; if (itemcnt(self.location.contents)) { "%You% see%s% <> here. "; listcontcont(self.location); } } ioPutOn(actor, dobj) = { dobj.doDrop(actor); } ioPutIn(actor, dobj) = { dobj.doDrop(actor); } ioThrowAt(actor, dobj) = { "Thrown. "; dobj.moveInto(actor.location); } ; /*====================================================================== * D E E P V E R B M O D I F I C A T I O N S *====================================================================*/ modify deepverb /* put abstract direct objects into scope */ replace validDo(actor, obj, seqno) = { command.dobjPtr = obj; if (obj.isabstract) return true; if (testScope(actor, obj)) return true; else return (testScope(actor, obj, self.dorequires)); } /* put abstract indirect objects into scope */ replace validIo(actor, obj, seqno) = { command.iobjPtr = obj; if (obj.isabstract) return true; if (testScope(actor, obj)) return true; else return (testScope(actor, obj, self.iorequires)); } /* if abstract has same vocab remove it */ disambigDobj(actor, prep, dobj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent) = { local i, j, len, cnt = 0, abslist = [], newlist = []; local vi = [], vj = []; if (!isAmbiguous) return objlist; len = length(objlist); for (i = 1; i <= len; ++i) { for (j = i+1; j <= len; ++j) { vi = [], vj = []; if (objlist[i] == objlist[j]) continue; vi += getwords(objlist[i], &adjective); vi += getwords(objlist[i], &noun); vi += getwords(objlist[i], &plural); vj += getwords(objlist[j], &adjective); vj += getwords(objlist[j], &noun); vj += getwords(objlist[j], &plural); if (vi == vj) { if (objlist[i] == theFloor) abslist += objlist[i]; else if (objlist[j] == theFloor) abslist += objlist[j]; else if (objlist[i].isabstract) abslist += objlist[i]; else if (objlist[j].isabstract) abslist += objlist[j]; } } } objlist -= abslist; return objlist; } /* if abstract has same vocab remove it */ disambigIobj(actor, prep, dobj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent) = { return self.disambigDobj(actor, prep, dobj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent); } /* modify to handle command redirection for abstract objects */ replace cantReach(actor, dolist, iolist, prep) = { local i, list, cmdWords; if (dolist != nil) { list = dolist; cmdWords = getCmdPhrase(dolist[1], global.cmdList); if (cmdWords == nil) command.cantReachWords = objwords(1); else command.cantReachWords = cmdWords; } else { list = iolist; cmdWords = getCmdPhrase(iolist[1], global.cmdList); if (cmdWords == nil) command.cantReachWords = objwords(2); else command.cantReachWords = cmdWords; } if (self.cantSenseActor(actor)) return; for (i = 1; i <= length(list); ++i) { if (dolist) { if (list[i].isabstract) self.cantSenseDoAbstract(actor, list[i], prep); else self.cantSenseDoRedirect(actor, list[i], prep); } else { if (list[i].isabstract) self.cantSenseIoAbstract(actor, list[i], prep); else self.cantSenseIoRedirect(actor, list[i], prep); } } } /* create dynamic object in actor's location and redirect command */ cantSenseDoAbstract(actor, obj, prep) = { local ret; local newobj = obj.newAbstract(actor); if (newobj.isabstract) self.cantSenseDoRedirect(actor, obj, prep); else { ret = execCommand(actor, self, newobj, prep, command.iobjPtr); command.dobjPtr = obj; if (ret == EC_ABORT) abort; exit; } } /* create dynamic object in actor's location and redirect command */ cantSenseIoAbstract(actor, obj, prep) = { local ret; local newobj = obj.newAbstract(actor); if (newobj.isabstract) self.cantSenseIoRedirect(actor, obj, prep); else { ret = execCommand(actor, self, command.dobjPtr, prep, newobj); command.iobjPtr = obj; if (ret == EC_ABORT) abort; exit; } } ;