/**
* This class keeps track of whether things are open or closed,
* locked or unlocked. Trap functions that are triggered when
* an object is opened or unlocked are also handled. When
* you need an object that is locked you should remember to
* use set_key() and set_difficulty(). When cloning an object
* and moving other objects inside it you should remember to
* make sure the object is open before moving things into it,
* and then close it if neccessary.
*
* @author Gototh
*/
#include <move_failures.h>
#define MAX_INVENT 40
#define C_CLOSED 1
#define C_TRANS 2
#define C_OPAQUE 1
#define LOCKED 1
#define CLOSED 2
#define CLOSED_LOCKED 3
int do_lock(object *obs);
int do_unlock(object *obs);
private int _locked;
private int _closed;
private string _pick_skill;
private nosave int _unlockable;
private nosave int _stuck;
private nosave int _trans;
private nosave int _difficulty;
private nosave int _autolock;
private nosave string _trap_open_func;
private nosave string _trap_lock_func;
private nosave object _trap_open_ob;
private nosave object _trap_lock_ob;
private nosave mixed _key;
/**
* @ignore yes
*/
void create() {
_difficulty = 5;
_pick_skill = "covert.lockpick.doors";
} /* create() */
/**
* This sets the object as being open. Note that to find out
* if an object is open we use query_closed() which will return
* 0 if the object is open.
*
* @see set_closed()
* @see query_closed()
*/
void set_open() {
if(_closed)
if(environment())
event(({environment(), TO}), "open", TP);
else if(TO->query_my_room())
event(({ TO->query_my_room(), TO}), "open", TP);
_closed = 0;
_locked = 0;
} /* set_open() */
/**
* This sets the object as being closed. If you are moving
* objects into the object, make sure that you do not set
* the object as closed and then try to move the objects in.
* Move the objects in and then close the object.
*
* @see set_open()
* @see query_closed()
*/
void set_closed() {
if(!_closed)
if(environment())
event(({environment(), TO}), "close", TP);
else if(TO->query_my_room())
event(({ TO->query_my_room(), TO }), "close", TP);
_closed = 1;
} /* set_closed() */
/**
* This function tells you whether an object is open or closed.
* It returns 1 if the object is closed, and 0 if the object is open.
*
* @return Return 1 if closed, 0 if open.
* @see set_open()
* @see set_closed()
*/
int query_closed() { return _closed; }
/**
* This function tells you whether an object is open or closed.
* It returns 1 if the object is open and 0 if the object is closed.
*
* @return Return 1 if open, 0 if closed.
* @see set_open()
* @see set_closed()
*/
int query_open() { return !_closed; }
/**
* This sets the object as being locked. Remember to set the
* object as being closed before using this. In most cases you
* should probably use set_key() to set the key which opens the
* lock and use set_difficulty() to set the skill level required
* to pick the lock.
*
* @see set_open()
* @see set_closed()
* @see set_key()
* @see set_difficulty()
*/
void set_locked() {
if(_closed) {
if(!_locked)
if(environment())
event(({environment(), TO}), "lock", TP);
else if(TO->query_my_room())
event(({TO->query_my_room(), TO}), "lock", TP);
_locked = 1;
}
} /* set_locked() */
/**
* This sets the object as being unlocked.
*
* @see set_locked()
*/
void set_unlocked() {
if(_locked)
if(environment())
event(({environment(), TO}), "unlock", TP);
else if(TO->query_my_room())
event(({TO->query_my_room(), TO}), "unlock", TP);
_locked = 0;
} /* set_unlocked() */
/**
* This tells us whether an object is locked. It returns 1 if
* the object is locked and 0 is the object is unlocked.
*
* @see set_locked()
* @see set_unlocked()
* @return Return 1 if locked and 0 if unlocked.
*/
int query_locked() { return _locked; }
/**
* This tells us whether an object is unlocked. It returns 1 if
* the object is unlocked and 0 is the object is locked.
*
* @see set_locked()
* @see set_unlocked()
* @return Return 1 if unlocked and 0 if locked.
*/
int query_unlocked() { return !_locked; }
/**
* This sets the object so that it will lock automatically when closed.
*/
void set_autolock(int number) { _autolock = number; }
/**
* This tells us whether an object will lock automatically when closed.
*
* @see set_autolock()
* @return 1 for true 0 for false;
*/
int query_autolock() { return _autolock; }
/**
* This method makes the object unlockable.
* @param 1 for unlockable, 0 for lockable
*/
void set_unlockable(int number) { _unlockable = number; }
/**
* This tells us whether the object can be locked or not.
* @see set_autolock()
* @return 1 for true 0 for false;
*/
int query_unlockable() { return _unlockable; }
/**
* This sets the property of the key that will unlock the object. This can
* be a string, or a function pointer which will evaluate to a string.
*
* @see set_locked()
* @param val The property the key must have to unlock the object.
*/
void set_key( mixed val ) {
if( stringp(val) || functionp(val) )
_key = val;
} /* set_key() */
/**
* This returns the property of the key that will unlock the
* object.
*
* @see set_key()
*/
string query_key() {
if( stringp(_key) )
return _key;
if( functionp(_key) )
return evaluate( _key );
return 0;
} /* query_key() */
/**
* This sets the skill that will be used when attempting to
* pick the lock. By default it is set to "covert.lockpick.safes"
* so it need only be changed if you want to check a different
* skill.
*
* @see query_pick_skill()
* @see set_difficulty()
* @param str The skill to use when picking the lock.
*/
void set_pick_skill(string str) {
_pick_skill = str;
} /* set_pick_skill() */
/**
* This returns the name of the skill which is used when
* determining if the object can be unlocked.
*
* @see set_pick_skill()
*/
string query_pick_skill() {
return _pick_skill;
} /* query_pick_skill() */
/**
* This sets how difficult the lock on an object is to pick.
* By default it is set to 200.
*
* @see query_difficulty()
* @param i The difficulty of the lock to pick.
*/
void set_difficulty(int i) {
_difficulty = i;
} /* set_difficulty() */
/**
* This returns the difficulty picking the lock on the object.
* By default it is set to 200 unless it has been changed with
* set_difficulty().
*
* @see set_difficulty()
*/
int query_difficulty() {
return _difficulty;
} /* query_difficulty() */
/**
* This can set an object as being stuck, or make it unstuck.
* Stuck objects cannot be opened, closed, locked or unlocked.
* Using set_stuck(1) will make the object stuck, and set_stuck(0)
* will unstick it.
*
* @see query_stuck()
* @param i Use 1 to make the object stuck, and 0 to unstick it.
*/
void set_stuck(int i) {
_stuck = i;
} /* set_stuck() */
/**
* This tells you whether an object is stuck or not. It will
* return 1 if the object is stuck, and 0 if the object is not
* stuck.
*
* @see set_stuck()
* @return Return 1 if the object is stuck, and 0 if it is not.
*/
int query_stuck() {
return _stuck;
} /* query_stuck() */
/**
* This sets the object as being transparent.
* A transparent object is one in which you can see the
* inventory even if it is closed.
*
* @see reset_transparent()
* @see query_transparent()
*/
void set_transparent() {
_trans = C_TRANS;
} /* set_transparent() */
/**
* This method removes the current objects transparent
* status.
* A transparent object is one in which you can see the
* inventory even if it is closed. This is also
* used for light propogration.
*
* @see set_transparent()
* @see query_transparent()
*/
void reset_transparent() {
_trans = 0;
} /* reset_transparent() */
/**
* This method returns the current transparent
* value of the object.
* A transparent object is one in which you can see the
* inventory even if it is closed. This is also
* used for light propogration.
*
* @see reset_transparent()
* @see query_transparent()
* @return 1 if the object is transparent
*/
int query_transparent() {
return _trans;
} /* query_transparent() */
/**
* This sets the function to be called when someone attempts to
* open the object. The function does not have to be in the
* object's file, and can be specified using the 'ob' paramater.
* In most cases the function will be stored in the same file,
* so use TO in these cases.
*
* The function will be called with a single string parameter of "open" or
* "close"
*
* @param ob The object in which the function is stored.
* @param func The function to be called.
* @see query_open_trap_func()
* @see query_open_trap_ob()
*/
void set_open_trap(object ob, string func) {
_trap_open_func = func;
_trap_open_ob = ob;
} /* set_open_trap() */
/**
* This returns the name of the function to be called when
* someone tries to open the object.
*
* @return The function to be called when the object is opened.
* @see set_open_trap()
* @see query_open_trap_ob()
*/
string query_open_trap_func() {
return _trap_open_func;
} /* query_open_trap_func() */
/**
* This returns the object on which the trap function is stored.
* The trap function is called when someone tries to open the
* the object.
*
* @return The function to be called when the object is opened.
* @see set_open_trap()
* @see query_open_trap_func()
*/
object query_open_trap_ob() {
return _trap_open_ob;
} /* query_open_trap_ob() */
/**
* This sets the function to be called when someone attempts to
* unlock the object. The function does not have to be in the
* object's file, and can be specified using the 'ob' paramater.
* In most cases the function will be stored in the same file,
* so use TO in these cases.
*
* The function will be called with a single string parameter of "lock",
* "unlock" or "pick"
*
* @param ob The object in which the function is stored.
* @param func The function to be called.
* @see query_lock_trap_func()
* @see query_lock_trap_ob()
*/
void set_lock_trap(object ob, string func) {
_trap_lock_func = func;
_trap_lock_ob = ob;
} /* set_unlock_trap() */
/**
* This returns the name of the function to be called when
* some attempts to unlock the object.
*
* @return The function to be called when someone attempts
* to unlock the object.
* @see set_open_trap()
* @see query_open_trap_ob()
*/
string query_lock_trap_func() {
return _trap_lock_func;
} /* query_lock_trap_func() */
/**
* This returns the object on which the trap function is stored.
* The trap function is called when someone tries to unlock the
* the object.
*
* @return The function to be called when the object is opened.
* @see set_open_trap()
* @see query_open_trap_func()
*/
object query_lock_trap_ob() {
return _trap_lock_ob;
} /* query_lock_trap_ob() */
/**
* This method returns the closed and locked status. The status is
* 0 if open and unlocked, 1 if locked, 2 if closed and 3 if closed
* and locked.
* @return closed and locked status
*/
int query_closed_locked_status() {
if (_closed && _locked) {
return CLOSED_LOCKED;
}
if (_closed) {
return CLOSED;
}
if (_locked) {
return LOCKED;
}
return 0;
} /* query_closed_locked_status() */
/**
* @ignore yes
*/
void init() {
add_command("open");
add_command("close");
if( _key ) {
add_command("lock");
add_command("unlock");
add_command("lock", "with <indirect:object:me>", (: do_lock($1) :) );
add_command("unlock", "with <indirect:object:me>", (: do_unlock($1) :) );
}
} /* init() */
/**
* @ignore yes
*/
string short_status() {
return "";
} /* short_status() */
/**
* @ignore yes
*/
string long_status() {
// If it is stuck in one state don't bother telling us the state.
if (query_stuck())
return "";
switch (query_closed_locked_status()) {
case CLOSED_LOCKED :
return "It is closed and locked.\n";
case CLOSED :
return "It is closed.\n";
default :
return "It is open.\n";
}
} /* long_status() */
/**
* @ignore yes
*/
int do_unlock(object *obs) {
if(!_locked || _stuck || !_closed || !_key) {
if(!_locked)
TP->add_failed_mess(TO,
"$D $V$0=isn't,aren't$V$ locked.\n", ({ }));
else if(_stuck)
TP->add_failed_mess(TO,
"$D $V$0=is,are$V$ stuck.\n", ({ }));
else if(!_closed)
TP->add_failed_mess(TO,
"$D $V$0=isn't,aren't$V$ closed.\n", ({ }));
else if(!_key)
TP->add_failed_mess(TO,
"$D $V$0=doesn't,don't$V$ have a key.\n", ({ }));
return 0;
}
if( query_key() != "by hand") {
if(!sizeof(obs))
obs = all_inventory(TP);
obs = filter_array(obs, (: $1->query_property( $2 ) :), query_key() );
if(sizeof(obs)) {
obs[0]->use_key(TO);
} else {
return 0;
}
}
if(_trap_lock_func && _trap_lock_ob) {
if(!call_other(_trap_lock_ob, _trap_lock_func, "unlock")) {
return 0;
}
}
set_unlocked();
return 1;
} /* do_unlock() */
/**
* @ignore yes
*/
int do_lock(object *obs) {
if(_locked || _stuck || !_closed || !_key) {
if(_locked)
TP->add_failed_mess(TO,
"$D $V$0=is,are$V$ already locked.\n", ({ }));
else if(_stuck)
TP->add_failed_mess(TO,
"$D $V$0=is,are$V$ stuck.\n", ({ }));
else if(!_closed)
TP->add_failed_mess(TO,
"$D $V$0=isn't,aren't$V$ closed.\n", ({ }));
else if(!_key)
TP->add_failed_mess(TO,
"$D $V$0=doesn't,don't$V$ have a key.\n", ({ }));
return 0;
}
if(!sizeof(obs))
obs = all_inventory(TP);
obs = filter_array(obs, (: $1->query_property( $2 ) :), _key);
if(sizeof(obs)) {
obs[0]->use_key(TO);
} else {
return 0;
}
if(_trap_lock_func && _trap_lock_ob) {
if(!call_other(_trap_lock_ob, _trap_lock_func, "lock")) {
return 0;
}
}
set_locked();
return 1;
} /* do_lock() */
/**
* @ignore yes
*/
int pick_lock(object player) {
if(_trap_lock_ob && !call_other(_trap_lock_ob, _trap_lock_func, "pick")) {
return 0;
}
set_locked();
return 1;
} /* pick_lock() */
/**
* This is called when someone successfully unlocks the object.
* If there is a trap, and the trap function returns true, the
* object will not be opened. If the trap function returns
* false, the object will still be opened even if the trap is
* sprung.
*
* @param player The player who is unlocking the object.
*
* @return Returns 1 if the object was unlocked, and 0 otherwise.
*/
int pick_unlock(object player) {
if(_trap_lock_ob && !call_other(_trap_lock_ob, _trap_lock_func, "pick")) {
return 0;
}
set_unlocked();
return 1;
} /* pick_unlock() */
/**
* @ignore yes
*/
int do_open() {
if(!_closed) {
TP->add_failed_mess(TO,
"$D $V$0=is,are$V$ already open.\n", ({ }));
return 0;
}
if(_stuck) {
TP->add_failed_mess(TO,
"$D $V$0=is,are$V$ stuck.\n", ({ }));
return 0;
}
if(_locked && !do_unlock(0)) {
TP->add_failed_mess(TO, "$D $V$0=is,are$V$ locked.\n", ({ }));
return 0;
}
if(_trap_open_func && _trap_open_ob) {
if(!call_other(_trap_open_ob, _trap_open_func, "open")) {
return 0;
}
}
set_open();
return 1;
} /* do_open() */
/**
* @ignore yes
*/
int do_close() {
if(_closed) {
TP->add_failed_mess(TO, "$D $V$0=is,are$V$ already closed.\n", ({ }));
return 0;
}
if(_stuck) {
TP->add_failed_mess(TO, "$D $V$0=is,are$V$ stuck.\n", ({ }));
return 0;
}
if(_trap_open_func && _trap_open_ob) {
if(!call_other(_trap_open_ob, _trap_open_func, "close")) {
return 0;
}
}
set_closed();
if(_autolock)
set_locked();
return 1;
} /* do_close() */
/**
* @ignore yes
*/
mixed *stats() {
return ({
({"closed", query_closed()}),
({"transparent", query_transparent()}),
({"key", query_key()}),
({"difficulty", query_difficulty()}),
({"locked", query_locked()}),
({"stuck", query_stuck()}),
({"unlockable", query_unlockable()}),
({"open trapped", _trap_open_func != 0}),
({"lock trapped", _trap_lock_func != 0}),
({"pick skill", query_pick_skill()}),});
} /* stats() */