/* Copyright (c) 1999, 2000 by Kevin Forchione.  All Rights Reserved. */
/*
 *  TADS ADV.T/STD.T LIBRARY EXTENSION
 *  DOORS.T				
 *  version 1.0
 *
 *      This module implements a floatingItem object that behaves like 
 *      two TADS doorways. This implementation is easier to work with 
 *      and modify than the earlier doorItem class.
 *
 *----------------------------------------------------------------------
 *  REQUIREMENTS
 *
 *      + HTML TADS 2.5.0 or later
 *      + Requires ADV.T and STD.T
 *      + Should be #included after ADV.T and STD.T.
 *
 *----------------------------------------------------------------------
 *  IMPORTANT LIBRARY INTERFACE AND MODIFICATION
 *
 *      None.
 *
 *----------------------------------------------------------------------
 *  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
 *
 *	    23-Oct-99:	Creation.
 */

#define __DOORS_MODULE_


#pragma C+

/*
 *  door: floatingItem, fixeditem, obstacle
 *
 *  A door is an obstacle that impedes progress when it is closed.
 *  Unlike the doorway, a door is a floatingItem and should not have its
 *  location attribute coded. Instead, use the foundin list to indicate
 *  the rooms in which the door is to be found. 
 *
 *  To make a simple two-sided door you need only code both room
 *  objects in the foundin list of the door: 
 *
 *      foundin = [ hallway, kitchen ]
 *  
 *  To make a one-sided door, code the foundin list with the room
 *  object in which the door is to be found, and the doorto list
 *  with the room object to which the door leads:
 *
 *      foundin = hallway 
 *      doorto = kitchen 
 *
 *  If you want a door that returns rooms different from those it is
 *  found in, simply code both the foundin list and doorto list 
 *  accordingly, each element of the doorto list must have a 
 *  corresponding foundin element:
 *
 *      foundin = [ hallway, kitchen ]
 *      doorto = [ foyer, hallway ]
 *
 *  From the hallway the door leads to the foyer, but from the kitchen
 *  it leads to the hallway.
 */
class door: doorway, floatingItem
    foundin = []
    doorto = nil
    location =
    {
        local f, actor, loc, dloc, foundList;
        
        if (self.foundin == nil)
            return nil;
            
        actor = parserGetObj(PO_ACTOR);
        if (actor == nil)
            actor = parserGetMe();

        loc = actor;
        while(loc)
        {
            dloc = loc;
            loc = loc.location;
        }
        
        //
        //  convert self.foundin into a list
        //
        switch(proptype(self, &foundin))
        {
            case DTY_NIL:
                foundList = [];
                break;
            case DTY_OBJECT:
                foundList = [ self.foundin ];
                break;
            case DTY_LIST:
                foundList = self.foundin;
                break;
            default:
                return nil;
        }
        
        if (find(foundList, dloc))
            return dloc;
        else
            return nil;        
    }
    findDest(actor) = 
    {
        local f, loc, foundList, destList;       
            
        loc = self.location;
        
        //
        //  convert self.foundin into a list
        //
        switch(proptype(self, &foundin))
        {
            case DTY_NIL:
                foundList = [];
                break;
            case DTY_OBJECT:
                foundList = [ self.foundin ];
                break;
            case DTY_LIST:
                foundList = self.foundin;
                break;
            default:
                return nil;
        }
        
        //
        //  convert self.doorto into a list
        //
        switch(proptype(self, &doorto))
        {
            case DTY_NIL:
                destList = [];
                break;
            case DTY_OBJECT:
                destList = [ self.doorto ];
                break;
            case DTY_LIST:
                destList = self.doorto;
                break;
            default:
                return nil;
        }
        
        //
        //  door is linked to room directions, but no foundin
        //  list exists. Simply return the noexit message.
        //
        if (length(foundList) == 0)
        {
            return self.noexit;
        }
          
        //
        //  We don't have a doorto list. Use the foundin list,
        //  which must have 2 elements.
        //
        if (length(destList) == 0)
        {  
            if (length(foundList) != 2)
            {
                "\n[TADS-DOORS-001] When omitting the           
                doorto list, the foundin list should 
                contain 2 elements.\n";
                return nil;
            }
            if (loc == foundList[1])
                return foundList[2];
            else
                return foundList[1];
        }
        
        //
        //  We have a doorto list, each element should correspond to
        //  an element in the foundin list.
        //
        if (length(foundList) != length(destList))
        {
            "\n[TADS-DOORS-002] <<self.thedesc>> requires a
            corresponding doorto element for each foundin 
            element.\n";
            return nil;
        }
        
        //
        //  Search for the actor location in the foundin list.
        //
        f = find(foundList, loc);
        
        //
        //  Door isn't in the actor location. return noexit.
        //
        if (f == nil)
        {
            return self.noexit;
        }
       
        //
        //  return the corresponding doorto element
        //
        return destList[f];
    }
    destination =
    {
        local actor = parserGetObj(PO_ACTOR);
        
        if (actor == nil)
            actor = parserGetMe();
            
        //
        //  The door location is nil or the actor's location doesn't
        //  match any object in the foundin list
        //
        if (self.location == nil)
            return self.noexit;
            
        if (self.isopen)
            return self.findDest(actor);
        else if (!self.islocked
            && !self.noAutoOpen)
        {
            self.setIsopen(true);
            "(Opening << self.thedesc >>)\n";
            return self.findDest(actor);
        }
        else
        {
            "%You%'ll have to open << self.thedesc >> first. ";
            setit(self);
            return nil;
        }
    }    
    setIsopen(setting) =
    {
        /* update my status */
        self.isopen = setting;
    }
    setIslocked(setting) =
    {
        /* update my status */
        self.islocked = setting;
    }
    noexit = { "%You% can't go that way. "; return nil; }
; 

/*
 *  lockableDoor: door
 *
 *  This is just a normal door with the islockable and
 *  islocked properties set to true.  Fill in the other
 *  properties (foundin and doorto) as usual.  If
 *  the door has a key, set property mykey to the key object.
 */
class lockableDoor: door
    islockable = true
    islocked = true
;

#pragma C-
