exits.t | documentation |
#charset "us-ascii" /* * Copyright (c) 2002, 2006 by Michael J. Roberts * * Based on exitslister.t, copyright 2002 by Steve Breslin and * incorporated by permission. * * TADS 3 Library - Exits Lister * * This module provides an automatic exit lister that shows the apparent * exits from the player character's location. The automatic exit lister * can optionally provide these main features: * * - An "exits" verb lets the player explicitly show the list of apparent * exits, along with the name of the room to which each exit connects. * * - Exits can be shown automatically as part of the room description. * This extra information can be controlled by the player through the * "exits on" and "exits off" command. * * - Exits can be shown automatically when an actor tries to go in a * direction where no exit exists, as a helpful reminder of which * directions are valid. */ /* include the library header */ #include "adv3.h" /* ------------------------------------------------------------------------ */ /* * The main exits lister. */ exitLister: PreinitObject /* preinitialization */ execute() { /* install myself as the global exit lister object */ gExitLister = self; } /* * Flag: use "verbose" listing style for exit lists in room * descriptions. When this is set to true, we'll show a * sentence-style list of exits ("Obvious exits lead east to the * living room, south, and up."). When this is set to nil, we'll use * a terse style, enclosing the message in the default system * message's brackets ("[Obvious exits: East, West]"). * * Verbose-style room descriptions tend to fit well with a room * description's prose, but at the expense of looking redundant with * the exit list that's usually built into each room's custom * descriptive text to begin with. Some authors prefer the terse * style precisely because it doesn't look like more prose * description, but looks like a separate bit of information being * offered. * * This is an author-configured setting; the library does not provide * a command to let the player control this setting. */ roomDescVerbose = nil /* * Flag: show automatic exit listings on attempts to move in * directions that don't allow travel. Enable this by default, * since most players appreciate having the exit list called out * separately from the room description (where any mention of exits * might be buried in lots of other text) in place of an unspecific * "you can't go that way". * * This is an author-configured setting; the library does not provide * a command to let the player control this setting. */ enableReminder = true /* * Flag: enable the automatic exit reminder even when the room * description exit listing is enabled. When this is nil, we will * NOT show a reminder with "can't go that way" messages when the * room description exit list is enabled - this is the default, * because it can be a little much to have the list of exits shown so * frequently. Some authors might prefer to show the reminder * unconditionally, though, so this option is offered. * * This is an author-configured setting; the library does not provide * a command to let the player control this setting. */ enableReminderAlways = nil /* * Flag: use hyperlinks in the directions mentioned in room * description exit lists, so that players can click on the direction * name in the listing to enter the direction command. */ enableHyperlinks = true /* flag: we've explained how the exits on/off command works */ exitsOnOffExplained = nil /* * Determine if the "reminder" is enabled. The reminder is the list * of exits we show along with a "can't go that way" message, to * reminder the player of the valid exits when an invalid one is * attempted. */ isReminderEnabled() { /* * The reminder is enabled if enableReminderAlways is true, OR if * enableReminder is true AND exitsMode.inRoomDesc is nil. */ return (enableReminderAlways || (enableReminder && !exitsMode.inRoomDesc)); } /* * Get the exit lister we use for room descriptions. */ getRoomDescLister() { /* use the verbose or terse lister, according to the configuration */ return roomDescVerbose ? lookAroundExitLister : lookAroundTerseExitLister; } /* perform the "exits" command to show exits on explicit request */ showExitsCommand() { /* show exits for the current actor */ showExits(gActor); /* * if we haven't explained how to turn exit listing on and off, * do so now */ if (!exitsOnOffExplained) { gLibMessages.explainExitsOnOff; exitsOnOffExplained = true; } } /* * Perform an EXITS ON/OFF/STATUS/LOOK command. 'stat' indicates * whether we're turning on (true) or off (nil) the statusline exit * listing; 'look' indicates whether we're turning the room * description listing on or off. */ exitsOnOffCommand(stat, look) { /* set the new status */ exitsMode.inStatusLine = stat; exitsMode.inRoomDesc = look; /* confirm the new status */ gLibMessages.exitsOnOffOkay(stat, look); /* * If we haven't already explained how the EXITS ON/OFF command * works, don't bother explaining it now, since they obviously * know how it works if they've actually used it. */ exitsOnOffExplained = true; } /* show the list of exits from an actor's current location */ showExits(actor) { /* show exits from the actor's location */ showExitsFrom(actor, actor.location); } /* show an exit list display in the status line, if desired */ showStatuslineExits() { /* if statusline exit displays are enabled, show the exit list */ if (exitsMode.inStatusLine) showExitsWithLister(gPlayerChar, gPlayerChar.location, statuslineExitLister, gPlayerChar.location .wouldBeLitFor(gPlayerChar)); } /* * Calculate the contribution of the exits list to the height of the * status line, in lines of text. If we're not configured to display * the exits list in the status line, then the contribution is zero; * otherwise, we'll estimate how much space we need to display the * exit list. */ getStatuslineExitsHeight() { /* * if we're enabled, our standard display takes up one line; if * we're disabled, we don't contribute anything to the status * line's vertical extent */ if (exitsMode.inStatusLine) return 1; else return 0; } /* show exits as part of a room description */ lookAroundShowExits(actor, loc, illum) { /* if room exit displays are enabled, show the exits */ if (exitsMode.inRoomDesc) showExitsWithLister(actor, loc, getRoomDescLister, illum); } /* show exits as part of a "cannot go that way" error */ cannotGoShowExits(actor, loc) { /* if we want to show the reminder, show it */ if (isReminderEnabled()) showExitsWithLister(actor, loc, explicitExitLister, loc.wouldBeLitFor(actor)); } /* show the list of exits from a given location for a given actor */ showExitsFrom(actor, loc) { /* show exits with our standard lister */ showExitsWithLister(actor, loc, explicitExitLister, loc.wouldBeLitFor(actor)); } /* * Show the list of exits using a specific lister. * * 'actor' is the actor for whom the display is being generated. * 'loc' is the location whose exit list is to be shown; this need * not be the same as the actor's current location. 'lister' is the * Lister object that will show the list of DestInfo objects that we * create to represent the exit list. * * 'locIsLit' indicates whether or not the ambient illumination, for * the actor's visual senses, is sufficient that the actor would be * able to see if the actor were in the new location. We take this * as a parameter so that we don't have to re-compute the * information if the caller has already computed it for other * reasons (such as showing a room description). If the caller * hasn't otherwise computed the value, it can be easily computed as * loc.wouldBeLitFor(actor). */ showExitsWithLister(actor, loc, lister, locIsLit) { local destList; local showDest; local options; /* * Ask the lister if it shows the destination names. We need to * know because we want to consolidate exits that go to the same * place if and only if we're going to show the destination in * the listing; if we're not showing the destination, there's no * reason to consolidate. */ showDest = lister.listerShowsDest; /* we have no option flags for the lister yet */ options = 0; /* run through all of the directions used in the game */ destList = new Vector(Direction.allDirections.length()); foreach (local dir in Direction.allDirections) { local conn; /* * If the actor's location has a connector in this * direction, and the connector is apparent, add it to the * list. * * If the actor is in the dark, we can only see the * connector if the connector is visible in the dark. If * the actor isn't in the dark, we can show all of the * connectors. */ if ((conn = loc.getTravelConnector(dir, actor)) != nil && conn.isConnectorApparent(loc, actor) && conn.isConnectorListed && (locIsLit || conn.isConnectorVisibleInDark(loc, actor))) { local dest; local destName = nil; local destIsBack; /* * We have an apparent connection in this direction, so * add it to our list. First, check to see if we know * the destination. */ dest = conn.getApparentDestination(loc, actor); /* note if this is the "back to" connector for the actor */ destIsBack = (conn == actor.lastTravelBack); /* * If we know the destination, and they want to include * destination names where possible, get the name. If * there's a name to show, include the name. */ if (dest != nil && showDest && (destName = dest.getDestName(actor, loc)) != nil) { local orig; /* * we are going to show a destination name for this * item, so set the special option flag to let the * lister know that this is the case */ options |= ExitLister.hasDestNameFlag; /* * if this is the back-to connector, note that we * know the name of the back-to location */ if (destIsBack) options |= ExitLister.hasBackNameFlag; /* * If this destination name already appears in the * list, don't include this one in the list. * Instead, add this direction to the 'others' list * for the existing entry, so that we will show each * known destination only once. */ orig = destList.valWhich({x: x.dest_ == dest}); if (orig != nil) { /* * this same destination name is already present * - add this direction to the existing entry's * list of other directions going to the same * place */ orig.others_ += dir; /* * if this is the back-to connector, note it in * the original destination item */ if (destIsBack) orig.destIsBack_ = true; /* * don't add this direction to the main list, * since we don't want to list the destination * redundantly */ continue; } } /* add it to our list */ destList.append(new DestInfo(dir, dest, destName, destIsBack)); } } /* show the list */ lister.showListAll(destList.toList(), options, 0); } ; /* * A destination tracker. This keeps track of a direction and the * apparent destination in that direction. */ class DestInfo: object construct(dir, dest, destName, destIsBack) { /* remember the direction, destination, and destination name */ dir_ = dir; dest_ = dest; destName_ = destName; destIsBack_ = destIsBack; } /* the direction of travel */ dir_ = nil /* the destination room object */ dest_ = nil /* the name of the destination */ destName_ = nil /* flag: this is the "back to" destination */ destIsBack_ = nil /* list of other directions that go to our same destination */ others_ = [] ; /* * Settings item - show defaults in status line */ exitsMode: SettingsItem /* our ID */ settingID = 'adv3.exits' /* show our description */ settingDesc = (gLibMessages.currentExitsSettings(inStatusLine, inRoomDesc)) /* convert to text */ settingToText() { /* just return the two binary variables */ return (inStatusLine ? 'on' : 'off') + ',' + (inRoomDesc ? 'on' : 'off'); } settingFromText(str) { /* parse out our format */ if (rexMatch('<space>*(<alpha>+)<space>*,<space>*(<alpha>+)', str.toLower()) != nil) { /* pull out the two variables from the regexp groups */ inStatusLine = (rexGroup(1)[3] == 'on'); inRoomDesc = (rexGroup(2)[3] == 'on'); } } /* * Our value is in two parts. inStatusLine controls whether or not * we show the exit list in the status line; inRoomDesc controls the * exit listing in room descriptions. */ inStatusLine = true inRoomDesc = nil ;
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