/*
* Psychedelic but trivial example world for WorldClass.
* This isn't intended to check WorldClass correctness; it just shows
* off a few of the neat things WorldClass supports.
*
* Useful playtesting verbs:
*
*      locate <object>
*      warpto <location>
*      gimme  <object>
*
* You can usually answer "all" to disambiguation queries without
* causing too much mayhem.  :)
*
*/
#include <world.t>

#define NOW

#ifdef  NOW
//
// Note: the following coin stuff is only temporary.
// It will be replaced by a better example once we fix
// a TADS bug.
//
class Coin: Item
       isequivalent = true     // equivalent to everything else of class Coin
       sdesc = "coin"
       location = startroom
       noun = 'coin'
       plural = 'coins'
;
coin1: Coin
       noun = 'coin'
       plural = 'coins'
;
coin2: Coin
       noun = 'coin'
       plural = 'coins'
;
coinproducer: Button, Fixture
       location = startroom
       noun = 'button'
       heredesc = "Inexplicably, there is a button here."
       doPush(actor) = {
               local   x;
               x := new Coin;

               "A coin suddenly appears out of nowhere!";
       }
;
#endif

//
// If you want to do your own special preinit tasks, replace
// userpreinit. In it, you should do any compile-time housekeeping or
// setup.
//
// Do NOT replace or modify the WorldClass preinit function.
// Use this instead.
//
replace userpreinit: function
{
}

//
// If you want to change the standard game startup behavior,
// replace userinit, copy the standard code from the WorldClass
// version, and make your changes.
//
// Do NOT replace or modify the WorldClass init function.
// Use this instead.
//
// (The version here is identical to the WorldClass version.
// It's only included here to illustrate how you'd make a different
// version.)
//
replace userinit: function
{
       //
       // Print the intro unless we're restarting.
       //
       if (global.restarting = nil) {
               "\b\b\b\b\b\b\b\b";
               intro();
       }

       //
       // NOTE: We have to set global.lastactor explicitly here,
       // because no command has been executed yet.  (Normally,
       // global.lastactor is set in the Verb disamiguation code.)
       //
       global.lastactor := Me;

       //
       // Note funny syntax:
       //
       Me.location.enter(Me);
}

//
// Just like with ADV.T, the player character object should be
// named "Me".  WorldClass doesn't rely on this much, however.
// In general, WorldClass makes no distinction between Me and
// other actors.
//
Me: Player
       //
       // These three methods must be correctly defined, or
       // WorldClass will get confused:
       //
       location = bed
       locationtype = 'on'
       position = 'sitting'

       noun = 'me' 'self' 'myself'

       //
       // To make eating, drinking, and/or sleeping
       // required for the player's continued survival,
       // don't make the following methods nil.  (See
       // the definition of the Player class for details.)
       //
       starvationcheck = nil
       dehydrationcheck = nil
       sleepcheck = nil
;

//
// A Darkroom has no ambient light -- the player must have a Lightsource
// to see.  Darkness does not prevent the player from using any verbs
// that don't require the "cansee" capability.
//
// Note that "startroom" is an arbitrary name.  You can make it whatever
// you want.  WorldClass looks at Me.location (see above) to determine
// where the player starts.
//
startroom: Darkroom
       //
       // tdesc = "title desc"
       // This is what gets printed in the status line for the location.
       //
       // The reason we want separate sdesc's and tdesc's is that
       // the tdesc's are usually capitalized.  Furthermore, we
       // might want to implement "look west", which would tell
       // the player the name of the westward location.  We wouldn't
       // want this name to come out capitalized.
       //
       tdesc = "In a Very Boring Room"
       ldesc = {
               "This room is pretty boring, but there is a poster
               here. Head south and you're in another boring room.";
       }
       sdesc = "starting room"

       //
       // Rooms can have vocabulary too.  WorldClass doesn't
       // allow most verbs to apply to rooms, so naming conflicts
       // between rooms and objects are not a problem.  (See also
       // the "warpto" playtesting verb.)
       //
       noun = 'room'
       adjective = 'starting'

       //
       // Unless we say otherwise, a Room will get the standard
       // Ground.  (More precisely, Ground makes itself appear
       // in every room for which ground = true, which is the
       // default.)
       //
       // We want to have our own custom ground here, so we set
       // ground to be our own ground object.
       //
       // Note that if we wanted there to be no ground here at
       // all, we'd set ground to nil.
       //
       ground = floor

       //
       // Where the player goes from here
       //
       goSouth = room2

       //
       // The previous declaration sets the field goSouth to
       // the *object* room2.  WorldClass treats this as
       // equivalent to the following *code*:
       //
       //      goSouth(actor) = { return room2; }
       //
       // The benefit to using an object instead of code is that
       // you can change an object at run-time, but you can't
       // change code at run-time.
       //
       // The benefit to using code instead of an object is that
       // the code form gives you the actor who's travelling.
       // Note that other actors may traverse the world via
       // the travel methods too; in fact, future versions of
       // WorldClass will likely provide code to control actors
       // that will work just this way.
       //
       // Also, WorldClass recognizes verGo<direction> methods -- these
       // are analogous to verDo<verb> methods that TADS itself
       // supports.  If you don't define a verGo method at all,
       // WorldClass assumes you mean
       //
       //      verGo<direction>(actor) = {}
       //
       // in other words, that travel in the given direction is
       // always allowed.  This is usually want you want, so the
       // convention saves typing.  However, you may want to limit
       // passage via certain directions to certain actors; for
       // example, you might want to allow the player to go west
       // but not Droyd, the robot that follows the player around.
       // To do this, you'd define verGoWest accordingly:
       //
       //      verGoWest(actor) = {
       //              if (actor = Droyd)
       //                      "Droyd is too scared to go that way.";
       //      }
       //
       // The key point here is that the code to move Droyd can
       // silently check the verGoWest method and realize that
       // it shouldn't try to move Droyd west here.  Likewise, when
       // the player explicitly orders Droyd to go west with
       //
       //      >droyd, west
       //
       // the player will get the failure message above.
       //
;

//
// Here we define a carryable item.
// Note the WorldClass class naming convention: the first letter is
// capitalized.  No other letters are capialized, and underscore
// is never used.
//
// Note that since this item has locationtype of 'under',
// the player will never be able to access it, even though
// its location is startroom.  (By default, players can't get
// to things that are under or behind locations they're in.)
//
widget: Item
       sdesc = "widget"
       noun = 'widget'
       location = startroom

       //
       // When we don't want the default location type of "in",
       // we have to explicity set the locationtype field to
       // one of the following strings:
       //
       //      'on'
       //      'under'
       //      'behind'
       //
       // Note that these are *strings*, not numbers.  Internally,
       // WorldClass converts them to numbers, but users should
       // *never* use the numerical equivalents.
       //
       locationtype = 'under'
;

//
// Two things are illustrated in the next two declarations:
//
// 1) Use of the Attachable and Attachpoint classes
// 2) Importance of correct class ordering in declaration for
//    correct multiple inheritance.
//
// 1)
//
// An Attachable is something that can attach to other things.
// The other things it can attach to are given by the attachesto
// list.  The attachedto list describes which things the Attachable
// is *currently* attached to.
//
// The objects in the attachesto list must be Attachpoints.  Attachpoints
// are things that other things can attach *to*.  They have attachesto
// and attachedto lists just like Attachables.
//
// In this case, both items can be attached *and* attached *to* each
// other.  But this need not be the case -- one might define a chain
// (Attachable) and a fixed hook (Attachpoint) for the chain to attach to.
//
// An actor can only take an Attachable if the Attachable is takeable and
// if everything it is attached to is also takeable.
//
// 2)
//
// For multiple inheritance to work properly, you MUST list classes
// in the correct order.  Since many WorldClass classes are intended
// to work with multiple inheritance, this is very important.
//
// In general, you should put more specific classes to the left of
// less specific ones.  E.g.:
//
//      fishhook: Item, Attachable      WRONG
//      fishhook: Attachable, Item      RIGHT
//
fishhook: Attachable, Attachpoint, Item
       sdesc = "fishhook"
       noun = 'fishhook' 'hook'
       adjective = 'fish'
       location = table
       locationtype = 'on'
       attachedto = [string]
       attachesto = [string]
;
string: Attachable, Attachpoint, Item
       sdesc = "piece of string"
       noun = 'string' 'piece'
       location = table
       locationtype = 'on'
       attachedto = [fishhook]
       attachesto = [fishhook]
       tieable = true
;

//
// A Lightsource provides light, and can therefore illuminate
// Darkrooms.  There is currently only a binary distinction
// between light and dark; there is no concept of lighting *level*.
//
// A Clothing can be worn.
//
// Both of these classes have "properties".  These properties
// are explicitly handled in preinit, and are the names of
// methods that print things like "(providing light)", "(being worn)",
// etc.  Whenever WorldClass prints an object's description, it runs
// all the property methods in the object's properties list.  This
// has the effect of tacking on all the extra text.
//
hat: Lightsource, Clothing
       sdesc = "hat"
       noun = 'hat'
       location = Me
;

//
// Here we define an Item that makes noise.  This noise description
// will be printed in room descriptions.
//
bomb: Listablesound, Item
       sdesc = "mysterious black sphere"
       ldesc = {
               "A fuse is sticking out of the mysterious black sphere.
               Hmmm.";
       }
       noun = 'bomb' 'sphere' 'ball'
       adjective = 'mysterious' 'black'
       location = table
       locationtype = 'on'

       //
       // The description we use when we're listing this item's
       // sound in a room description.  We do *not* include the
       // subject here, because it may not be known.  (For example,
       // if the player can't see, he'll get "Something is ticking."
       // instead of "The mysterious black sphere is ticking.")
       //
       listlistendesc = {
               "is ticking.";
       }

       //
       // Like ldesc, but for sound.  Printed when the player
       // does "listen to ___".
       //
       listendesc = {
               "It seems to be making a ticking sound.";
       }
;

//
// Here we define a Part.  A Part is a component of another
// object.  It has no location of its own -- it is always located
// in the same place as its parent object.  Likewise, its locationtype
// is the same as its parent's at all times.
//
// Set the parent object with the partof method.
//
fuse: Part
       sdesc = "fuse"
       ldesc = {
               "It's just an ordinary fuse.  It's sticking out
               of the mysterious black sphere.";
       }
       noun = 'fuse'
       partof = bomb
;

//
// This declaration illustrates several things:
//
// 1) The Key class
// 2) The Edible class
// 3) Listablesmell class (see above; similar to Listablesound)
// 4) Footnoting
//
kee: Key, Edible, Listablesmell, Item
       sdesc = "cheez kee"
       ldesc = {
               //
               // Note the use of the note command.
               // You pass it the object that contains the
               // footnote method you want to associate with
               // this numbered footnote.  This object is
               // usually self, but need not be.  (You have to
               // put footnotes somewhere else if you have more
               // than one in an object.)
               //
               // If you do not set footnum to a number, a footnote
               // number will be assigned at run-time.  WorldClass
               // ensures that no specially numbered footnotes (i.e.,
               // ones for which you've set footnum to a certain
               // number) will get clobbered by footnotes that get
               // numbered at run-time.  (See the mouse's footnote
               // for an example of a hand-numbered footnote.)
               //
               "The Acme Cheez Kee (tm) is a freak of
               plastics "; note(self); ".";
       }
       noun = 'kee' 'key'
       adjective = 'cheez'
       location = table
       locationtype = 'on'

       //
       // These are like listlistendesc and listendesc -- see
       // the bomb object above.
       //
       listsmelldesc = {
               "smells awful!";
       }
       smelldesc = {
               "The cheez key smells totally disgusting!";
       }

       //
       // This method shows how to make takeability
       // vary according to some condition.
       //
       // NOTE that you must NOT change game state in these
       // methods (istakeable, issmellable, isaudible, etc.)
       // because, like the standard TADS ver methods, these
       // are called by WorldClass "behind the scenes."
       //
       // In fact, there is a direct connection between verDoTake
       // and istakeable:  In WorldClass, the standard istakeable
       // method (in Thing) is defined as follows:
       //
       //      istakeable(actor) = {
       //              Outhide(true);
       //              self.verDoTake(actor);
       //              if (Outhide(nil)) {
       //                      self.verDoTake(actor);
       //                      return nil;
       //              }
       //
       //              return true;
       //      }
       //
       // In other words, istakeable by default calls verDoTake
       // and sees if it prints anything.  If it does, it turns
       // output hiding off and calls verDoTake again to actually
       // display the message to the user.  If it doesn't print
       // anything, it returns true without printing anything.
       //
       // This provides a kind of philosophical backwards
       // compatibility with ADV.T, where we're used to overriding
       // verDoTake to make things untakeable.
       //
       // NOTE: In theory you can print text in istakeable and
       // still return true.  In practice, however, this is a bad
       // idea since you have no way of knowing how many times
       // istakeable will be checked.
       //
       // The discussion above applies equally to the other is...able
       // methods, like isvisible, isaudible, issmellable, istouchable,
       // etc.
       //
       complicated = {
               // check condition here
               return true;
       }
       istakeable(actor) = {
               if (not self.complicated) {
                       "You fool!  Only a madman would try to take a
                       Cheez Kee!";

                       return nil;
               }
               else
                       return true;
       }

       //
       // Footnote text is printed by the footnote method
       // in the object specified in the note function.
       //
       footnote = {
               "Tiny letters embossed on the Cheez Kee read
               \"Unlahkx Evreethyng -- Grate four dormz!\"";
       }
;
//
// A thermos that's lockable (for some reason)
//
// A Lockable can only be opened with its key, given by the key field.
//
// An Openable is a Container that can open and close.  A Container
// can have things *in* it.  When an Openable is closed, it does
// not pass sight, smell, sound, etc. through itself.  See the
// Openable class definition for more info on this.  (Try putting
// the Lightsource into the thermos, then close the thermos.  The
// light won't be able to escape, and you won't be able to see.)
//
// A Qfront can have things *behind* it.  The Q denotes that it
// won't list the things that are behind it in room descriptions;
// only when the player explicitly *looks* behind it with a
// "look behind ___" command.  Other Holders (things that can
// have things in, on, under, or behind them) have "Q" variants too.
//
thermos: Lockable, Openable, Qfront, Item
       key = kee
       sdesc = "plastic thermos"
       noun = 'thermos'
       adjective = 'plastic'
       location = startroom
       locationtype = 'in'
;

//
// We'll make the floor vibrate in the starting room.
// To call attention to this fact, we'll make the object
// a Listabletouch.
//
floor: Listabletouch, Floor
       sdesc = "ground"
       noun = 'ground' 'floor'
       adjective = 'warm' 'vibrating'
       location = startroom
       locationtype = 'in'

       //
       // Since this is a Floor, which is in turn
       // an Everywhere, it will not get listed in
       // a room description by default.
       //
       // When the contents listing function knows it hasn't
       // listed an object in the visual contents listing,
       // it won't refer to that object by name.
       //
       // This means thatwhen we do a "listen" in the room,
       // we'll get "Something is vibrating violently here."
       // instead of "The ground is vibrating violently here."
       //
       // To force the contents lister to name the object,
       // we have to set alwaysname(actor) to return true.
       //
       // (Of course, you can make naming the object conditional
       // on something -- you don't have to return true all
       // the time.)
       //
       alwaysname(actor) = { return true; }

       touchdesc = "The ground here is warm, and is vibrating."
       listtouchdesc = "is vibrating violently here."
;

//
// A Transparent Container always passes light, whether it's open or not.
//
jar: Transparent, Openable, Item
       isopen = true
       sdesc = "jar"
       noun = 'jar'
       location = thermos
       locationtype = 'in'
;
lumenberries: Edible, Item
       sdesc = "lumenberries"
       isplural = true
       noun = 'lumenberries' 'berries'
       adjective = 'lumen'
       location = thermos
       locationtype = 'in'
;
mouse: Item
       sdesc = "happy little mouse <<note(self)>>"
       noun = 'mouse'
       adjective = 'happy' 'little'
       location = table
       locationtype = 'under'

       touchdesc = {
               "The mouse is warm and furry.";
       }

       //
       // A hand-numbered footnote.
       //
       footnum = 1
       footnote = {
               "Probably looking for some Cheez...";
       }
;

//
// Things can be nowhere.  In this case, set location = nil and
// locationtype to 'in'.  If you don't explicitly set locationtype,
// WorldClass will assume it's 'in'.  If you move things to nil,
// they automatically get put 'in' nil.  But style dictates that
// you should always do
//
//      obj.movein(nil);
//
// to move something nowhere.  Don't do
//
//      obj.moveunder(nil);     // BAD STYLE!
//
// or
//
//      obj.movebehind(nil);    // BAD STYLE!
//
// or
//
//      obj.moveon(nil);        // BAD STYLE!
//
// (Note the distinction between these move methods in WorldClass,
// whereas in ADV.T you always use moveInto.  You need to pay attention
// to containment types when using WorldClass!)
//
kee2: Key, Edible, Item
       sdesc = "spam kee"
       noun = 'kee' 'key'
       adjective = 'spam'
       location = nil
;

//
// A set of useful standard furniture classes is provided, including:
//
//      Table, Chair, Stool, Ledge, Bed, Desk, Shelf, Door
//
// Note that we also make the table and chair Fixtures.  This just
// means that their heredesc's should be printed in room descriptions.
// If we didn't make them Fixtures, we'd have to mention them
// explcitly in the room's ldesc.
//
// This table also shows how to use the movingout and movingin methods.
// The table just prints a message about each thing taken off of it.
//
table: Fixture, Table
       sdesc = "table"
       heredesc = {
               "A sturdy table stands in the middle of the room.";
       }
       noun = 'table'
       location = startroom

       //
       // As mentioned earlier, overriding verDoTake
       // is just as good as changing istakeable.  This
       // way (changing verDoTake) will be more readable
       // to those TADS programmers accustomed to ADV.T code.
       //
       verDoTake(actor) = {
               "The table's bolted to the floor.";
       }

       //
       // Don't let any actor put anything on the table
       // if the mouse is on the table.
       //
       movingout(obj, tolocation, toloctype) = {
               if (obj.locationtype = 'on')
                       "\^<<obj.subjthedesc>> <<obj.is>> moving off
                       the table. ";
       }
       movingin(obj, loctype) = {
               if (loctype = 'on')
                       "\^<<obj.subjthedesc>> <<obj.is>> moving onto
                       the table. ";
       }
;
chair: Fixture, Chair
       heredesc = {
               "There is a well-made wooden chair here.";
       }
       location = startroom
       noun = 'chair'

       //
       // A Chair is a Nestedroom, and by default Actors
       // can't reach things in the containing Room when
       // they're in a (contained) Nestedroom.
       //
       // There are two ways to overcome this:
       //
       // 1) Define a reachable list and put things in it.
       // 2) Set reachsurroundings = true
       //
       // Option 1 allows you to specify exactly which things
       // in the containing Room (or anywhere else, for that
       // matter) are reachable from the Nestedroom.  You can
       // put both objects (e.g., cheez kee) in the reachable
       // list and Containers.  If a Container appears in a
       // reachable list, everything contained in that Container
       // will also be reachable.  There is currently no way
       // to restrict the containment type to, for example 'under'.
       //
       // In this case, anything in, on, under, or behind the table
       // will be reachable from the chair.
       //
       reachable = [table]
;
bed: Fixture, Bed
       heredesc = {
               "An old, comfortable-looking bed is off to one side.";
       }
       location = startroom
       noun = 'bed'

       //
       // Option 2 in the list described in the definition of
       // the chair above.
       //
       // If you set reachsurroundings = true, then everything
       // in the Nestedroom's location will be accessible from
       // the Nestedroom.  This is often the simplest solution
       // since it restricts the player the least, and so is
       // least likely to cause any playability problems.
       //
       reachsurroundings = true
;

//
// A Decoration is a fixed object (i.e., one that is not takeable)
// that is not very important.  Unlike ADV.T, WorldClass does not
// say "that is not something important" whenever the player manipulates
// a Decoration -- the distinction between "Decoration" and "Thing"
// is mainly one of intent.
//
// For objects that really are totally unimportant (i.e., for which
// you want WorldClass to tell the player "that is not important"),
// use the Unimportant class.
//
poster: Decoration
       sdesc = "poster"
       noun = 'poster'
       ldesc = "It's just an ordinary poster."
       location = startroom
;

//
// Another room
//
room2: Room
       tdesc = "Another Stupid Room"
       ldesc = {
               "Gee, this place is boring!  If you go north, you'll
               probably wind up in another boring room.";
       }
       sdesc = "second room"

       noun = 'room2' 'room'
       adjective = 'second'

       goNorth = startroom
;

//
// Actors work like they do in ADV.T, but WorldClass Actors
// are somewhat more complex.  See the Actor class definition
// for details.
//
monk: Male, Actor
       sdesc = "monk"
       location = room2
       noun = 'monk'
       actordesc = {
               "There is an ancient monk here.";
       }
;

elderberries: Item
       sdesc = "elderberries"
       isplural = true
       noun = 'elderberries' 'berries'
       adjective = 'elder'
       location = monk
;