Note on the packaging of the source code and accompanying files. ---------------------------------------------------------------- The Polyadv code (Polyadventure) supersedes the old AD551 game (Adventure 551), and is currently packaged in two parts: 1. A zip archive in Windows format, containing the game source, walkthroughs, README and license information. Note that the filenames are no longer converted to upper case, but the end-of-line terminators are the Windows type i.e. . When unpacking the files to a Unix system, you are advised to use the unzip command with the -a option (to convert the line terminators to the Unix type i.e. just ), e.g. unzip -a polyadv310c.zip 2. The machine-independent game file - polyadv.gam. This should work on any platform, provided that you have a recent TADS 2 interpreter. License and Copyright Details ----------------------------- Polyadv A TADS game with complete source code Copyright (C) 1993 David M. Baggett and (C) 1999-2005 David J. Picton and (C) 1999, 2003 Bennett J. Standeven This source code is copylefted under the terms of the GNU Public License. Essentially, this means that you are free to do whatever you wish with this source code, provided you do not charge any money for it or for any derivative works. A copy of the GNU Public License should be included with this distribution. For information on how to play this and other TADS games, please refer to the file ftp://ftp.ifarchive.org/if-archive/games/playgame.FAQ Contributors ------------ Original 350-point TADS port (CCR): dmb In real life: David M. Baggett Internet: 551-point extensions, various bugfixes and enhancements, combined modes (701, 701+ points): djp In real life: David J. Picton Internet: djpicton@gmail.com 550, 580-point extensions bjs In real life: Bennett J. Standeven Internet: berry@pop.networkusa.net or bjstande@artsci.wustl.edu Feedback on the game, including bug reports should be sent to David Picton. Please note that we welcome ALL types of feedback on the game including suggestions for extensions and improvements to puzzles etc. What Have We Here? ------------------ This game is a remake of the first major adventure game ever written: Colossal Cave, otherwise known as "Adventure." The original Adventure was written in FORTRAN by Willie Crowther and Don Woods, and was modelled on a real cavern, called Bedquilt Cave, which is a part of Kentucky's Mammoth Cave system. In its original form, it only had a simple two-word command parser. Its descriptions were so vivid, however, that it captivated a generation of computer enthusiasts and quickly became part of the "hacker lore." References to Adventure crop up even today in games and other software. Several extended versions of Adventure were subsequently produced, and this port implements three of them - the 550-point, 551-point, and 580-point versions - in addition to the original 350-point game. A 701-point mode, which combines both versions, is also available, together with a 701+ point mode with brand new extensions. Special commands of the form GAME, e.g. GAME550, allow you to select the version to play. The 550-point game was originally written in Fortran by David Platt in 1979. It contains many new rooms, extensions and puzzles, and differs from the original game in one important respect. There is an element of game design; a series of puzzles must be solved, each dependent on the last, in order to explore some of new areas of the cave. In contrast, the original game gives you almost complete access to the whole cave once you've dealt with the snake. The 551-point game derives from a 501-point version produced by David Long at Stanford who rewrote portions of the program to provide a more sophisticated parser, and greatly expanded the cave. A castle problem was added in 1984 by an anonymous writer, increasing the total number of points to 551 points. Most of the 'original' rooms are the same as in the 350-point version, but some treasures have been changed or relocated, and a few directions have been altered. Like the 550-point game, the 551-point game requires that you solve crucial puzzles in order to see certain parts of the cave. However, it is much less 'linear' - there is more freedom to choose the order in which the puzzles are to be solved. The 580-point game was originally written by Mike Goetz in 1982, for the CP/M operating system. It expands slightly on the 550-point version, adding one new area, with two treasures, and a few items to use in this area. Adventure was such a significant event in computerdom that it spawned a whole genre of games, made even more popular by Infocom in the 1980's. The MIT hackers who formed Infocom took the Adventure concept and added some powerful new technology to it: sentence parsing. Their first game, Zork, was clearly very much inspired by Crowther and Woods' original, but seemed more intelligent and was easier to play because (like the 551-point version) it could accept simple sentences instead of just two-word directives. Eventually affordable computers got to be powerful enough to support general text adventure authoring packages, and by 1992 there were already nearly a dozen systems for would-be adventure authors to choose from. This remake was written with TADS, one such adventure writing system, and was developed from David Baggett's Colossal Cave Revisited. It was first extended by David Picton to include the 551-point extensions (plus a few embellishments, e.g. more uses for the rod). Bennett Standeven then implemented the extensions for the 550-point mode, and David Picton subsequently added the 701-point mode. Still later, Bennett Standeven ported the 580-point mode, and David Picton released a new 701+ mode with completely new extensions, literally adding a new dimension to the game. Thus Polyadv gives a new generation of adventurers an opportunity to play the various versions in a format they will feel comfortable with. Today's text adventurers have been "spoiled" by the nice sentence parsing that most games have these days, and other useful features like the ability to examine objects. It is the hope of the authors that this reimplementation will make the original Adventure games -- classics that still shine today -- accessible to a wider audience. Implementation Details and Philosophy ------------------------------------- We have tried to be faithful to the spirit of the original games throughout the project. To start off on the right foot, David Baggett went back to Donald Ekman's excellent PC port of what seemed to be the original DEC-10 FORTRAN source code. Don told him he typed a significant portion of that source in from a paper listing -- now that's devotion! In any case, few changes had to be made to get the game running under DOS, so the source used for the original CCR was largely "untainted." David Picton based the extensions for the 551-point game on the Fortran sources by Doug McDonald. The treasures and locations are almost completely faithful to the original, except for the addition of a few new rooms in the area of the East End of the Long Hall. Several game extensions enhance the gameplay; in particular, the sack is now a 'sack of holding' into which items are placed automatically when necessary. New optional game features make it possible to increase your weight limit, enhance the magic powers of the rod, and protect yourself against the dwarves' knives. Look out for reading material which might give clues to these features ... Bennett Standeven implemented the extensions for the 550-point game, based on the UNIX C port by Ken Wellsch. The treasures, locations and magic words etc. are all faithful to the original, and almost all of the game features have been implemented. For example, the troll will reject a certain treasure if you use it as payment more than once. There are a few minor additions to the original game. For example, the vending machine has been upgraded to accept all coins, and (as with the 551-point version) you can now protect yourself against the dwarves' attacks. David Picton subsequently developed the combined 701-point mode, which contains all the treasures and rooms of the 550-point and 551-point games (except the 551-point endgame). It is interesting to note that there are relatively few conflicts between the two versions, so little new coding was needed to connect both sets of extended areas to the original 350-point rooms. The areas of conflict were: the room NE of the Hall of the Mountain King (resolved by making the Morion Room lead on to the Throne Room), the north-of-reservoir room (different but reached by the same route, resolved by combining the characteristics of the 550-point and 551-point rooms), the sword-in-the-stone puzzle (resolved by keeping both swords in the game) and the endgame (for which the combined game uses only the 550-point version). Most of the work involved new coding to permit 550-point items to interact with 551-point NPCs, and vice versa. Note that the 701-point inventory handling follows the 551-point pattern (you are limited to seven items carried in hand, but containers are provided; strength-enhancing actions will increase the weight limit but not the total bulk of items which may be carried.) Note that some puzzles which are optional in the 551-point game are compulsory in the 701-point version; in particular, you will need to enhance the powers of the rod to complete the extensions from the 550-point game. The extensions for the 580-point game are based on Mike Goetz' original code. Again, the treasures, locations, and magic words are highly faithful to the original. The 701+ point mode is an extension of the 701-point mode by David Picton. You play an adventurer with something extra - a sixth sense which allows you to make crucial discoveries which previous adventurers have missed. Note that it is possible to finish the game with a declared 'maximum score' of 701 points, 781 points or even 793 points, depending on the discoveries which you make. Retrofitting such old games onto a more sophisticated game engine created a few philosophical problems. Games these days are expected to have "decorations;" little bits of scenery mentioned in the room descriptions that you can't actually do anything with, but make the setting feel more real. The original 350-point Adventure didn't have many decorations, and the two-word parser prevented players from trying things like "look under y2 rock," "put the rod in the stream," etc. Later extended versions of Adventure did have more sophisticated partsers. In particular, the 551-point game allowed commands like 'put axe in sack' although some modern features were missing - in particular, most objects could not be examined. In other cases - particularly the 660- and 770-point games - the parser has retained the verb-noun model (precluding commands like 'unlock grate with keys') but is modern in other respects; objects can be examined, multiple objects (e.g. 'take axe and lamp', 'drop all') are supported, and more scenery objects are provided. The approach we took was to add decorations in every reasonable place. Where appropriate descriptions exist in the original game, we used them, even to the extent of making bits of room descriptions serve double duty. The new sentence parser created similar problems for game play. Whereas in the original you had to say "throw axe" to attack something, you can now do things like "attack bear with lamp." There is no analogue to this in the original 350-point game; "throw lamp" would be interpreted as a request to drop the object. An attempt has been made to stay consistent with the overall tone of the originals, but there are some differences; in particular, "throw" is no longer synonymous with "drop" and an object must be thrown AT something; if this doesn't make sense, the command will be rejected. However, the old-style two-word commands will often work, because the parser can usually choose an appropriate default. For example, "throw axe" will usually default to "at the dwarf" provided that you have the axe and there is at least one dwarf at your location, and "unlock grate" will default to "with the keys" if they are present at your location. Prompting for the indirect object will still occur if more than one possibility might be considered, e.g. if you say "throw axe" when a dwarf and the troll are both present. From the beginning we wanted walkthroughs for the originals to still work in the TADS implementation; this is largely true now, though there are a few exceptions. Since the parser is no longer limited to two-word commands, it now requires that certain actions (e.g. opening the clam) be described more precisely to prevent accidental solving. There are still a few unimplemented features. For example, the 550-point mode doesn't yet allow you to throw objects into fissures and chasms. Hints to Programmers Who Want to Modify Polyadv ----------------------------------------------- Polyadv isn't meant to be an unchanging mass of archival source code. On the contrary, we hope that people will add new features, objects and locations. If you do add things, please let us know so we can incorporate the changes into the official distribution. Modifying any large program is daunting at first. Fortunately, you shouldn't have to pay much attention to the grungy details of most of it, since we've tried our best to make it easy to modify. With this is mind, here are a few tips to make building and changing Polyadv simpler: * Have a suitable compiler, preferably the latest version. The current version has been compiled and tested using version 2.5.9 but should work with compilers/interpreters from 2.5.0 onwards. Earlier versions of the TADS run-time won't support all the language and parser features used in the code. A number of people have complained that Polyadv won't compile under the DOS version of the TADS compiler. It does appear that the game is now too large to compile under the DOS version, so you're advised to use the Windows or Unix version instead. * Make new extensions optional. This has been implemented in Polyadv using flags to the "global" object in ccr-std.t that enable or disable new code, objects and locations. At present the code supports six game modes - the original 350-point mode, the 550-, 580- and 551-point extended modes, the combined 701-point mode, and a new extended version of the 701 point game (701+ point). * Use the 'modify' and 'replace' statements where appropriate. The recommended practice - now used in Polyadv - is to use the standard adv.t file from the TADS distribution, then to apply user customizations using replace and modify statements. The separation of user modifications from standard code then makes it much easier to upgrade to a new version of adv.t. A similar approach would be useful when extending the game, allowing the new code to be separated completely from the original code. * Use (or at least follow) the makefile. Depending on the operating system, some of the options in the Makefile are important and you may get mystifying error messages if you don't specify them. Under MS-DOS, be sure to compile with the -mp option set large enough, and make sure you make the cache small enough (with the -m option). * Use the existing classes whenever possible. Classes are already defined to make your life easy, and Polyadv now makes more use of the standard classes as defined in the adv.t library. In particular, class item is now used for portable non-treasure items, fixeditem for immovable objects, room for lighted rooms and darkroom for dark rooms. For reasons of clarity, all rooms should be defined with either 'room' or 'darkroom' as the first class in the list. The CCR_item, CCR_room, lightroom and CCR_decoration classes have been abolished. * When defining new classes or puzzles, copy an existing similar implementation and then modify it to suit your needs. Starting from scratch is always harder than updating already-working code. * Note the following nonstandard features of the implementation. o Code should not assume that the actor is always Me. This isn't true in Polyadv (for example, the bear responds to travel verbs, and locations of objects may sometimes have to be evaluated from the viewpoint of a dwarf or pirate). Methods which don't receive the actor as an argument should obtain the current actor as follows: local actor := getActor(&prop); where &prop is the appropriate actor property in the global object: &travelActor (the actor currently being moved by travelTo methods) ¤tActor (when determining the location of a multiple-location object) &verbActor (for other purposes; indicates the actor for the current verb) Usually all three will be the same but there may be some exceptions; for example, a verb issued by the player might issue Bear.travelTo(...) which would change global.travelActor and global.currentActor to Bear. o Note the extended argument list of the travelTo method. In particular, the second argument represents a property to be executed within the travelTo method, instead of being evaluated beforehand. The advantage of this approach is that the travelTo method can now set the relevant global variables, global.travelActor and global.currentActor, before the travel properties are evaluated. Thus the following form: actor.travelTo(actor.location, &east); is now preferred to: actor.travelTo(actor.location.east); The following classes are defined in Polyadv, in addition to the standard set: advmods.t class owntrans - a nestedroom which defines its own Transdindection methods. An example is the sandstone block. ccr-item.t class CCR_treasure_item (takepoints/depositpoints must be defined, usually by a method, due to the varying scoring schemes used in different game versions) class initmess (items with a special initial description - these use a heredesc until they have been moved, when they become normal portable items.) class condlisted (items which have isListed set when they are carried in hand or in a container, but use the heredesc property when dropped in a room) class liquidcont (container for liquids) class contliquid (liquid in a container; if there are 'm' containers and 'n' types of liquid, the number of contliquid objects is 'm * n'. However, they won't necessarily appear in all game versions. For example, wine does not make an appearance in the 550-point game.) class canpick (for items which the player may attempt to pick) class coinitem (item which may be used in the vending machine) class unfixeditem (special class which will make an object portable if given in the class list before any fixeditem classes) class portable_chairitem (a portable item on which one could sit) class portable_beditem (a portable item on which one could sit or lie) ccr-itm11.t class protect_ring - for an object which protects you against the dwarves' knives. class pendantItem - for all Transindection pendants (excluding the discolored disk which cannot be worn) ccr-endg.t class objpile (pile of objects in endgame) class endgame_clone (subclass of CCR_item, object which appears in an endgame pile) class endgame_liquidcont (subclass of liquidcont, see endgame_clone) ccr-npc.t, ccr-npc1.t etc: class NPC (for dwarves, pirate only) class Chaser (for NPC's which follow you in extended versions, e.g. the Wumpus, the Gooseberry Goblins, and the Blob) class feedable (for NPC's which we might attempt to feed) ccr-room.t class CCR_doorway - for non-lockable doors. class CCR_lockableDoorway - subclass for lockable doors. Special methods in the above classes handle all the special Polyadv customizations: different messages for different keys, doors which can't be unlocked during a security alert or cave closure condition, and sets of more than two doors which all represent the same object. class CCR_alike_maze_room (for 'all-alike' maze) class NoNPC (room where dwarves and pirate can't go) class CCR_dead_end_room (generic dead end) class Outside (i.e. outside the cave) class Indoor (indoor locations outside the cave) class NotFarIn (inside cave but not far in) class makecontents - floating items (mostly of an omnipresent type, such as your hands) which can be added to contents lists at the preinit stage. See below. class floatingdecoration - objects which are present in more than one location, defined by a loclist. If the current actor is in one of the listed rooms, the location method returns the relevant room. Otherwise it returns the first element in the loclist. class picklock - for items with locks which the player may attempt to pick. class roomliquid - a liquid which is available in a room. class Streamitem - subclass of roomliquid. For bodies of water (of which there are now several) class rfd (room feature decoration) - subclass of floatingdecoration (with a terse default ldesc) class unfixeditem - special class to override fixeditem, for example when defining portable chairs and beds. This class should appear at the end of the class list. (N.B. this is a subset of fixeditem, so don't test for self.isclass(fixeditem) to determine whether an object is a fixed item. Test the isfixed property instead.) class upclimable, downclimbable - for objects like stairs which you can climb up or down. class picklock - for objects (e.g. the chest, doors) with a lock. class Blueberries - for blueberry bushes (551-point game) ccr-rm1.t class Featurelesspit - for the (now-not-quite-so) featureless pits in the 551-point game. class CCR_boothitem - for phone booths class CCR_boothdoor class CCR_phoneitem ccr-rm2.t class CCR_ice_tunnel - for rooms in the ice tunnel maze ccr-verb.t class versionrestart - class for restart verbs. If you add a new game version, you'll need to add one of these. class MagicWord - a magic word. The omegapsical_order and omegaps701_order properties are for the Cylindrical Room puzzle in the 550-point and 701-point endgames. class magicTravelVerb - a travel word with a magic effect (Note that 'plover' is regarded as magic by Polyadv but not by some other versions of Adventure, so its use in the Cylindrical Room puzzle has been made optional). class wizardVerb - a 'wizard mode' verb. For game-testing. These verbs only work when the game is compiled for debugging or with #define WIZARD; otherwise they are disallowed by the player character's actorAction method. class numberedVerb - used by certain wizard mode verbs with a disambigDobj method, and (in some cases) the ability to specify a number to distinguish between objects e.g. 'gonear chasm number 2'. class VaultKeyVerb - a magic word used for opening the safe in the 550-point game. * Note the following properties for rooms (N.B. there are other properties which are normally set by defining classes) analevel - the Transindection coordinate of a room. Nonzero values are set for many of the rooms in the 701+ point extensions. brasskey - the version of the brass key item which is seen in a particular location. (small_key by default, large_key in rooms where the player is small, tiny_key in rooms where the player is large). contloc - for scoring objects, this is the location or object in which an object's container must be placed. Unless the oldkeep property of the object is set to true, this property is ignored in the 350-, 550- and 580-point versions of the game. createloc - the location of dynamically-created objects. depositpoints - the points awarded when an item is deposited in the correct location and is no longer in the player's possession. Due to differing scoring systems, this is usually a method rather than a simple value. floordesc - description of room's floor (if hasfloordesc is set) hasfloor - if true, the floor will be called the 'floor'; if nil, the 'ground'. hasfloordesc - if true, the floordesc method will be used to describe the room's floor. isfissureroom - set to true at the locations of the fissure in the Hall of Mists, where the rod can be used to create a bridge. (Not set at the Green-level fissure, where rods are used in a different way.) isolated - set to true when a room with analevel=0 (Red level) can only be reached with the aid of Transindection movements. istoproom - set to true when a room is contained in another room (e.g. the pantry in the building) but is to be regarded as a top-level room when the player is inside. nofloor - true if the room has no floor. outercontloc - for a scoring object, this is the required location of an outer container (e.g. the wine must be placed in the cask (targloc=cask), the cask must be in the chest (contloc=treasure_chest) and the chest must be in the building (outercontloc=Inside_Building). Unless the oldkeep property of the object is set to true, this property is ignored in the 350-, 550- and 580-point versions of the game. roomdroploc - location of room to which an object will fall (e.g. when objects fall down to a lower room) smashdrop - if true, fragile objects dropped in this room will break (used when objects will drop to a lower room; the vase will shatter and the vial will release its contents.) softfloor - a room has a soft floor, so fragile items can be safely be dropped. takepoints - the points scored when an object is first taken. Due to differing scoring systems this is usually a method rather than a simple value. targloc - for a scoring object, this is the room or container in which an object must be deposited before its full score is given. Unless the oldkeep property of the object is set to true, this property is ignored in the 350-, 550- and 580-point versions of the game (which hardcode the target location to the building). transmove(prop) - where prop can be a destination room or a property pointer for a travel method (by default, evaluated relative to the top-level room). Used in transindection travel and also size-changing travel outside the elfin door. If a player is in a transportable vehicle (isfixed=nil or istransportable=true) the player will be conveyed in the vehicle. version_NoNPCs - optional method for a room, returning 'true' if the dwarves and pirates are to be excluded from the room in a particular game version. * Note also the following properties for actors roomMoveTravel(&moveprop,dest) or roomMoveTravel(&moveprop,dest,&prop) Move the actor to another room to another, along with any portable items in the room. If the actor is in a nestedroom (e.g. standing on the rug), convey the actor in the nestedroom. The moveprop argument should be one of &moveme (always convey the nestedroom) or &transmove (convey the nestedroom only if it is 'transportable': isfixed=nil or istransportable=true). The optional third argument is a travel property; if it is given, the destination room will be dest.&prop. vehicleTravel(&moveprop,dest) or vehicleTravel(&moveprop,dest,&prop) Move the player or convey the player in a nestedroom in which the player is located. See roomMoveTravel. posture - set by the code to one of 'sitting', 'standing' or 'lying' to indicate the posture of a player when in a nestedroom. * Note the following properties and methods, mainly for items accepts_item(dobj) - Method for containers, returning true if an object is suitable for the container, nil otherwise. This method is required for 'sack of holding' objects so that items which won't go into the container can be silently excluded. bothsides - for items, reachable from both sides of the dragon. contname - the short name for a liquidcont item e.g. "bottle" emptydesc - sdesc to be used for an empty liquidcont item e.g. "small empty bottle" hasoil, haswater, haswine - for objects of type liquidcont, one of these properties can be set to true to indicate that the container is filled with the relevant liquid. isInside(location) - this evaluates to true if the item is inside 'location', regardless of visibility. (The standard isIn() method returns nil when the item is hidden inside a closed container.) islighted - returns true if the object is in a lighted room or container. isListedinRoom - indicates that an object is to be listed in the room description when it's in the room's contents list. By default this is the same as isListed, but certain special classes (initmess, condlisted) set isListedinRoom to nil and use a heredesc method instead. See the description of the modified nrmLkAround routine below. quickdest - for doors, returns the destination of the door, or nil if the player can't go through without explicitly opening the door beforehand. quickdest(loc) - evaluates the doordest as seen by an actor in the room defined by loc. doordestOK - for doors, indicates that a doordest method is safe for use by quickdest. list - when an object or class is used for dynamic object creation, this property will contain a list of the dynamically-created objects. mass - the weight of an object in the 551-point and 701-point game. The weight is set to 0 in the 350-point and 701-point games which only take into account the bulk of the objects which are carried. misfit(io) - for lockable items, issues a message according to the key which the player has attempted to use. For example, the set of keys produces a different message from a single key. moved - if true, indicates that an item has been moved from its initial position. (Note that if an 'initmess' object has to be put in place during the game, its moved property should be set to nil so that it will display its initial description.) nosack - true if an object is not to be placed automatically into a 'sack of holding' objclass - in the construct method for dynamically-created items, this property is set to the class e.g. fresh_batteries. sdescbase - for liquidcont methods, this is the base for the sdesc when the bottle is full. For example, if sdescbase is "small bottle" the sdesc (when the bottle contains water) evaluates to "small bottle of water" * Note the following functions asknum(prompt,errorstring) - function to prompt for a number addmass(list) - like addweight but includes items which are worn. droploc(location) - the room to which an object goes when dropped getActor(&prop) - retrieve the actor. This function is useful in methods for which the actor is not passed as an argument. nestcontents - lists the contents of an object including nested containers (used in score checking) obj_switch(oldkey,newkey) - switches two objects (used for the brass key which can be one of three objects) room_move(oldroom,newroom) - moves all nonfixed items from oldroom to newroom. sack_of_holding(actor, o, lftbulk) - implements a 'sack of holding' like the Curses rucksack. Returns 'true' if the object 'o' could be placed in an appropriate container. The optional lftbulk parameter is supplied as the bulk available to the player (see advmods.t for examples). testtake(actor,object) - function to attempt to take an object during the processing of a command where an 'implied take' is appropriate. Returns true if the object could be taken, nil otherwise. Takeable items with the noImpliedTake property return true without attempting to take the object. toplocation(item) - returns the 'top-level' room in which the item is situated. The search for the top level will be terminated if a room has the istoproom property set to true. truetop(item) - returns the true top-level room in which item is situated. vertesttake(actor,object) - function to be called during verification to check that an object is capable of being taken. Returns true for fixed items, nil for non-fixed. The appropriate verDoTake method is invoked except for objects for which noImpliedTake is true. * Note that the handling of items with multiple locations has been improved. For efficiency reasons, many items are no longer handled as floating objects - instead, they are installed in contents lists alongside objects with normal location properties: o Items in class floatingdecoration, in which the loclist property contains a list of rooms in which is the object is to be found. If the loclist property needs to be changed, you are advised NOT to set the loclist property directly. Instead, you should use the special moveLoclist method to ensure that all the rooms' contents lists will be updated. The loclist property should NOT be changed directly; instead, the special moveLoclist method should be invoked to update the rooms' contents lists. * Note that it is OK for loclist to include rooms which aren't in the game version being played. * Care must be taken if the player can enter the object. (For an example, see the location method for In_Safe). o Other floating items in the makecontents class. This is intended for objects which can sensibly be placed in the contents lists of rooms at the preinit stage. The location method should return the player's location if the object is present at that location, or nil otherwise. The location method must not * depend on anything which might vary from one game to the next, e.g. the game version or time of day * change during the execution of a game The list 'global.noall' specifies objects which are not to be included when you use ALL in a command. This is mainly intended for omnipresent items like your hands, the floor and the air, which are now all included in the contents lists of rooms. * Take care when checking whether a room, container or surface is empty. The contents list may contain invisible objects of class makecontents, so you may not get the right result if you check the length of the contents list. Instead, you should use the itemcnt function to check for listed items. * When coding new rooms, follow the convention that significant fixeditems will appear in the room description whether or not it is in 'brief' or 'verbose' mode. To achieve this, give the object a 'heredesc' property (which should normally start with P(); I();) instead of incorporating its description into the room's ldesc property. The modified nrmLkAround method (see below) will then always list the item. * Set global.debug to true to get extra information about room connections and NPC movement at run-time. The game will check its connections to make sure everything's OK at run-time. Add new debugging code enabled by this flag for your own extensions. * The room.nrmLkAround method has been customized in a number of ways. The order of printing is now: Room title Verbose room description (when listing is in 'verbose' mode e.g. when a room is first seen or the LOOK command is used) heredesc methods for fixed items (including floating items which don't appear in the room's contents list but whose location method evaluates to the room) and and for portable items which have the has_heredesc property set to true. Each heredesc method should start with P(); I(); so that the text will appear as a separate indented paragraph. In Polyadv these descriptions are always printed, even in 'brief' mode. Non-treasure items (except those with isListedinRoom= nil) Treasure items (ditto) Contents lists of containers and surfaces actorDesc methods for actors, including 'floating' actors. These should also be methods starting with P(); I(); to ensure that each description starts a new paragraph. If you want the actor description to appear earlier, set actorDesc to {} and define a heredesc instead. Some Ideas ---------- Here are a few things that we considered doing ourselves, but decided to leave as exercises. Some of the ideas for the original CCR (e.g. hints) have now been implemented, but others have been left as an exercise. (Yeah, that's the ticket.) They range from fairly trivial to incredibly time-consuming: * Make the NPC code more faithful to the original. For example, dwarves should block your way when you try to return to your previous location. (The trick here is to work out the player's intended destination without actually going there. To avoid unwanted side effects, you wouldn't be able to evaluate the travel property e.g. &north when it's a method. The exithints property might be useful here.) The pirate code could also be made more like the original, in which the pirate would 'shadow' the player until a treasure was found, then pounce! * Make the NPC movement code faster. * Implement more "extended" versions of the game, e.g. the 430-point and/or 440-point versions. The complete source and database for the 440-point game have recently been rediscovered - see vscheme.txt, and Mike Arnautov has recently released the 660-point game. Note that old versions of Adventure generally came without copyright statements and have in practice been regarded as 'public domain' (although the legality of this view is questionable.) However, more recent versions usually do come with a copyright statement - please read it and contact the author if you are in any doubt. * Add your own NPC's, puzzles, or locations. * Port TADS to new machines so that Polyadv has a wider audience. (Contact Mike Roberts for more info.) Whatever you do, please send us your changes! Special commands for game testing --------------------------------- If your game is compiled for debugging, certain special 'wizard mode' commands are made available to the player. These include: PURLOIN - obtain an item 'from thin air' PURLOIN - obtain a given item. PURLOIN NUMBER - obtain the nth object which matches the noun phrase, e.g. PURLOIN RING NUMBER 3. SUMMON Make a dwarf, pirate or Chaser NPC appear at your location. BANISH - banish the NPC. PIRLOC - show the locations of the pirate and dwarves. GONEAR - go to the room containing GONEAR NUMBER - see PURLOIN. LOCSEL This command only affects the next GONEAR command, and does nothing unless the object has a loclist. If it does, the specifies the loclist element to use. By default, the first loclist element is used. Example: LOCSEL 3. GONEAR JUNCTION LAMPLIFE - display the number of turns left in your lamp. LAMPLIFE - set the lifetime of your lamp. NUM-DWARVES - set the number of dwarves to . This command is only effective if it is issued early in the game, before the dwarves have started in motion. NUM-PIRATES - as above, for the pirates. (By default there is only one but there is provision for larger numbers). SCORETOTAL - display the total score. See also -------- The file vscheme.txt has details about the game version handling and numbering scheme. This has been expanded to give advice about the production of new versions which are extensions of existing ones (for example, the 580-point version is an extension of the 550-point version, and a few simple defaults allow the 580-point game to inherit all the 550-point extensions automatically.)