pov.t | documentation |
#charset "us-ascii" /* * Copyright (c) 2000, 2006 Michael J. Roberts. All Rights Reserved. * * TADS 3 Library - point of view * * This module provides definitions related to point of view and sensory * context. When we generate output, we do so with respect to a * particular point of view; different points of view can result in * different output, because of the viewer's distance from an object, for * example, or because of the presence of obscuring materials between the * viewer and the viewed object. We also generate output in a particular * sensory context, which controls whether or not a message that * describes an object with respect to a particular sense should be * generated at all; for example, if the viewer can't see an object * because of darkness or an obscuring layer of material, messages about * the object's visual appearance should not be generated. */ /* include the library header */ #include "adv3.h" /* ------------------------------------------------------------------------ */ /* * Call a function with a given sensory context. * * The sensory context specifies the source of any messages generated in * the course of the routine we invoke and the sense which those * messages use to convey information. If the player character cannot * sense the source object in the given sense, then we block all * messages generated while calling this function. * * If the source object is nil, this establishes a neutral sense context * in which all messages are visible. * * This can be used for processing events that are not directly * initiated by the player character, such as non-player character * activities or scheduled events (fuses and daemons). The idea is that * anything described in the course of calling our routine is physically * associated with the source object and relates to the given sense, so * if the player character cannot sense the source object, then the * player should not be aware of these happenings and thus should not * see the messages. * * Sense contexts are not nested in their effects - we will show or hide * the messages that our callback routine generates regardless of * whether or not messages are hidden by an enclosing sensory context. * So, this routine effectively switches to the new sense context for * the duration of the callback, eliminating the effect of any enclosing * context. However, we do restore the enclosing sense context before * returning, so there is no lasting net effect on the global sense * context. */ callWithSenseContext(source, sense, func) { return senseContext.withSenseContext(source, sense, func); } /* * Sense context output filter. When the sense context doesn't allow * the player character to sense whatever's going on, we'll block all * output; otherwise, we'll pass output through unchanged. */ senseContext: SwitchableCaptureFilter /* * Recalculate the current sense context. We will check to see if * the player character can sense the current sense context's source * object in the current sense context's sense, and show or hide * output from this point forward accordingly. This can be called * any time conditions change in such a way that the sense context * should be refigured. */ recalcSenseContext() { /* * simply invalidate the cached status; this will ensure that we * recalculate the status the next time we're called upon to * determine whether or not we need to block output */ cached_ = nil; } /* * Get our current blocking status. If we've already cached the * status, we'll return the cached status; otherwise, we'll compute * and cache the new blocking status, based on the current sensory * environment. */ isBlocking() { /* if we haven't cached the status, compute the new status */ if (!cached_) { /* calculate the new status based on the current environment */ isBlocking_ = shouldBlock(); /* we now have a valid cached status */ cached_ = true; } /* return the cached status */ return isBlocking_; } /* our current cached blocking status, and its validity */ isBlocking_ = nil cached_ = true /* * Calculate whether or not I should be blocking output according to * the current game state. Returns true if so, nil if not. */ shouldBlock() { /* * Determine if the new sense context allows messages to be * displayed. If there is no source object, we allow * everything; otherwise, we only allow messages if the player * character can sense the source object in the given sense. */ if (source_ == nil) { /* neutral sense context - allow messages */ return nil; } else { /* * Determine if the player character can sense the given * object. If the source can be sensed with any degree of * transparency other than 'opaque', allow the messages. */ return (libGlobal.playerChar.senseObj(sense_, source_) .trans == opaque); } } /* invoke a callback with a given sense context */ withSenseContext(source, sense, func) { local oldSource, oldSense; /* remember the old sense and source values */ oldSource = source_; oldSense = sense_; /* set up the new sense context */ setSenseContext(source, sense); /* make sure we restore the old status on the way out */ try { /* invoke the callback */ return (func)(); } finally { /* restore the old sense context */ setSenseContext(oldSource, oldSense); } } /* * Set a sense context. */ setSenseContext(source, sense) { /* remember the new setings */ source_ = source; sense_ = sense; /* calculate the new sensory status */ recalcSenseContext(); } /* the source object and sense of the sensory context */ sense_ = nil source_ = nil ; /* ------------------------------------------------------------------------ */ /* * Get the current point-of-view actor - this is the actor who's * performing the action (LOOK AROUND, EXAMINE, SMELL, etc) that's * generating the current description. */ getPOVActor() { return libGlobal.pointOfViewActor; } /* * Get the current point of view. In *most* cases, this is the same as * the point-of-view actor: the actor is looking around with its own * eyes, so it's the point of view. However, this can differ from the * actor when the actor is viewing the location being described through * an intermediary of some kind. For example, if an actor is observing a * remote room through a closed-circuit TV system, the point of view * would be the camera in the remote room (not the TV - the point of view * is intended to be the object that's physically absorbing the light * rays or other sensory equivalents). */ getPOV() { return libGlobal.pointOfView; } /* get the POV actor, returning the given default if there isn't one set */ getPOVActorDefault(dflt) { /* start with the global setting */ local val = libGlobal.pointOfViewActor; /* if that's not nil, return it; otherwise, return the default */ return (val != nil ? val : dflt); } /* get the POV, returning the given default if there isn't one set */ getPOVDefault(dflt) { /* start with the global setting */ local val = libGlobal.pointOfView; /* if that's not nil, return it; otherwise, return the default */ return (val != nil ? val : dflt); } /* * Change the point of view without altering the point-of-view stack */ setPOV(actor, pov) { /* set the new point of view */ libGlobal.pointOfViewActor = actor; libGlobal.pointOfView = pov; } /* * Set the root point of view. This doesn't affect the current point of * view unless there is no current point of view; this merely sets the * outermost default point of view. */ setRootPOV(actor, pov) { local stk = libGlobal.povStack; /* * if there's nothing in the stacked list, set the current point of * view; otherwise, just set the innermost stacked element */ if (stk.length() == 0) { /* there is no point of view, so set the current point of view */ libGlobal.pointOfViewActor = actor; libGlobal.pointOfView = pov; } else { /* set the innermost stacked point of view */ stk[1] = pov; stk[2] = actor; } } /* * Push the current point of view */ pushPOV(actor, pov) { /* stack the current one */ libGlobal.povStack.append(libGlobal.pointOfView); libGlobal.povStack.append(libGlobal.pointOfViewActor); /* set the new point of view */ setPOV(actor, pov); } /* * Pop the most recent point of view pushed */ popPOV() { local stk = libGlobal.povStack; local len; /* check if there's anything left on the stack */ len = stk.length(); if (len != 0) { /* take the most recent element off the stack */ libGlobal.pointOfViewActor = stk[len]; libGlobal.pointOfView = stk[len - 1]; /* take the actor and POV objects off the stack */ stk.removeRange(len - 1, len); } else { /* nothing on the stack - clear the point of view */ libGlobal.pointOfViewActor = nil; libGlobal.pointOfView = nil; } } /* * Clear the point of view and all stacked elements */ clearPOV() { local len; local stk = libGlobal.povStack; /* forget the current point of view */ setPOV(nil, nil); /* drop everything on the stack */ len = stk.length(); stk.removeRange(1, len); } /* * Call a function from a point of view. We'll set the new point of * view, call the function with the given arguments, then restore the * original point of view. */ callFromPOV(actor, pov, funcToCall, [args]) { /* push the new point of view */ pushPOV(actor, pov); /* make sure we pop the point of view no matter how we leave */ try { /* call the function */ (funcToCall)(args...); } finally { /* restore the enclosing point of view on the way out */ popPOV(); } }
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3
Generated on 5/16/2013 from TADS version 3.1.3