/**
* The main living inherit. This inherits all the files
* needed to be in a living object.
* @author Pinkfish
* @changed Removed the effects inherit/code, because
* /std/container already inherits all that.
* - Sandoz, April 2003.
*/
#include <dirs.h>
#include <drinks.h>
#include <living.h>
#include <tune.h>
#include <position.h>
inherit "/std/container";
inherit "/std/living/armour";
inherit "/std/living/body";
inherit "/std/living/carrying";
inherit "/std/living/combat";
inherit "/std/living/force";
inherit "/std/living/gender";
inherit "/std/living/health";
inherit "/std/living/holding";
inherit "/std/living/money";
inherit "/std/living/skills";
inherit "/std/living/spells";
inherit "/std/living/stats";
inherit "/std/living/respond_cmd";
#define VERBOSE_TYPES ({"combat", "look", "score", "names", \
"htell", "hsay", "finger"})
private int alignment;
private string msgout;
private string msgin;
private string mmsgout;
private string mmsgin;
private string destmsg;
private string deity;
private mixed facing;
private mapping verbose;
private nosave int handicap;
private nosave object dragging, *followers, *to_drop;
private nosave mixed it_them;
void return_to_default_position(int leaving);
void set_position(string name);
void set_position_on(mixed ob);
void set_position_multiple(int mult);
void set_position_type(string type);
object query_position_on();
/*
* What position are they in? Standing, sitting, lying, froging?
*/
private nosave string position;
private nosave mixed default_position;
private /* This will force an object to not use the position from the room. */
nosave int always_use_default_position;
/* in case they are standing on something or something... */
private nosave mixed position_on;
void create() {
string t;
container::create();
armour::create();
combat::create();
health::create();
holding::create();
skills::create();
spells::create();
respond_cmd::create();
enable_commands();
reset_can_export_inventory();
reset_effects();
msgin = "$N arrive$s from $F.";
msgout = "$N leave$s $T.";
mmsgin = "$N appear$s out of the ground.";
mmsgout = "$N disappear$s in a puff of smoke.";
destmsg = "$N destruct$s $O.";
followers = ({ });
to_drop = ({ });
verbose = ([ ]);
foreach( t in VERBOSE_TYPES)
verbose[t] = 1;
facing = ({ 0, ({ "north", "northeast", "east", "southeast", "south",
"southwest", "west", "northwest" }),
({ "up", "down" }) });
it_them = ({ TO });
position = STANDING;
} /* create() */
/**
* This method returns the pronoun string of the living object.
* A pronoun is "he", "she", "it".
* @return the pronoun string
*/
string query_pronoun() { return gender::query_pronoun(); }
/**
* This method returns the prossessive string of the living object.
* A possessive is "her", "his", "its".
* @return the possessive string
*/
string query_possessive() { return gender::query_possessive(); }
/**
* This method returns the objective string of the living object.
* An objective is "her", "him", "it".
* @return the objective string
*/
string query_objective() { return gender::query_objective(); }
/** @ignore yes */
int query_weight() {
if( TO->query_property("dead") )
return 0;
return stats::query_weight();
} /* query_weight() */
/**
* This method returns the actual weight of the living object.
* This is useful when you need to know the real weight of a ghost,
* as ghosts weight nothing themselves.
* @return the actual weight of the living
*/
int query_actual_weight() { return stats::query_weight(); }
/**
* This method returns the current burden level of the living
* object. This is returned as a percentage of the maximum
* weight that the living can carry.
* @return the burden level (0-100)
*/
int query_burden() {
int burden;
object thing;
mapping hands;
update_loc_weight();
burden = query_loc_weight();
foreach( thing in query_wearing() )
burden -= (int)thing->query_complete_weight() / 2;
hands = ([ ]);
foreach( thing in query_holding() )
if( objectp( thing ) )
hands[ thing ]++;
foreach( thing in keys( hands ) )
burden += (int)thing->query_complete_weight() / hands[ thing ];
if( !query_max_weight() ) {
TO->reset_carry_cap();
return 50;
}
return ( 100 * burden ) / query_max_weight();
} /* query_burden() */
/**
* This method returns the current handicap of the living
* object.
* @return the current handicap.
* @see calc_burden()
*/
int query_handicap() { return handicap; }
/**
* This method calculates the current handicap of the living
* object. The handicap is based on the burden of the
* person, the more burdened the higher the handicap. The
* handicap is 1 point of dexterity for every 25% burdened.
* @see query_handicap()
* @see query_burden()
*/
void calc_burden() {
int new_handicap;
new_handicap = ( query_burden() / 25 ) - 1;
if( new_handicap < 0 )
new_handicap = 0;
if( handicap != new_handicap ) {
adjust_bonus_dex( handicap - new_handicap );
handicap = new_handicap;
}
} /* calc_burden() */
/**
* This method returns the string representation of the current
* burden level.
* @return the burden string
* @see calc_burden()
* @see query_burden()
*/
string burden_string() {
switch( handicap ) {
case 0 :
return "unburdened";
case 1 :
return "burdened";
case 2 :
return "heavily burdened";
case 3 :
return "very heavily burdened";
default :
return "incredibly heavily burdened";
}
} /* burden_string() */
/** @ignore yes */
int remove_armour( object thing ) {
int i;
i = ::remove_armour( thing );
if( !i && sizeof( all_inventory() ) > MAX_INVEN ) {
remove_call_out("test_number_of_items");
to_drop += ({ thing });
call_out("test_number_of_items", 5 + random( 5 ) );
}
return i;
} /* remove_armour() */
/**
* This method adds any commands needed by the living inherit.
*/
void living_commands() { combat_commands(); }
/**
* This method handles the cannot get flags. This is placed
* into the living object so that things which are marked as
* being unable to be picked up can still be put into normal
* containers. The upwards checking of containers stops here.
* This should make it so that objects marked as unable to be
* picked up cannot be put into objects in the players
* inventory.
* @return 1 if the object can be added, 0 if not.
*/
int test_add( object ob, int flag ) { return !flag; }
/**
* This method handles the cannot drop flags. This is placed
* into the living object so that things which are marked as
* being unable to be dropped can still be remove from normal
* containers. This does all sorts of other exciting checks
* now.
* @return 1 if the object can be added, 0 if not.
*/
int test_remove( object ob, int flag, mixed dest ) {
object thing;
if( flag )
return 0;
if( !TP || TP == TO )
return !flag;
if( stringp( dest ) )
thing = find_object( dest );
if( objectp( dest ) ) {
thing = dest;
dest = file_name( dest );
}
if( thing->query_corpse() || dest == "/room/rubbish" )
return !flag;
/*
* True theft commands should return 1 to query_theft_command().
* Things like the ritual "fumble" and the command "disarm" should return -1.
*/
if( sizeof( filter( previous_object( -1 ),
(: $1->query_theft_command() :) ) ) )
return !flag;
/* We should now only be considering things like "get", "take" and "palm". */
if( !query_property( PASSED_OUT ) )
return 0;
if( !pk_check( TP, TO ) ) {
event( ENV( TP ), "theft", TP, TO, ({ ob }) );
return !flag;
}
write("An unseen force stays your hand.\n");
return 0;
} /* test_remove() */
/**
* This method returns the current alignment of the living
* object.
* @return the current alignment
* @see set_al()
* @see adjust_al()
* @see adjust_alignment()
* @see align_string()
*/
int query_al() { return alignment; }
/**
* This method sets the current alignment of the living
* object.
* @param number the new alignment for the object
* @see query_al()
* @see adjust_al()
* @see adjust_alignment()
* @see align_string()
*/
void set_al( int number ) { alignment = number; }
/**
* This method adjusts the current alignment of the living
* object.
* @param number the amount to change the alignment by
* @return the new alignment
* @see query_al()
* @see set_al()
* @see adjust_alignment()
* @see align_string()
*/
int adjust_al( int number ) {
alignment += number;
if( alignment < -MAX_AL )
alignment = -MAX_AL;
if( alignment > MAX_AL )
alignment = MAX_AL;
return alignment;
} /* adjust_al() */
/**
* This method adjusts the current alignment of the living
* object. This is called when an object dies and handles the
* mangling of the change value based on the current alignment and
* the alignment of the thing dieing.
* @param number the amount to change the alignment by
* @return the new alignment
* @see query_al()
* @see adjust_al()
* @see set_al()
* @see align_string()
*/
int adjust_alignment( int number ) {
int change;
// To become more evil you must kill something that is at least 20%
// good as you are evil and vice versa.
change = -( number + alignment / 5 );
// This stops the changes being too extreme. Increase this for smaller
// changes, decrease it for larger ones.
change /= 20;
// Now wasn't that nice and easy? :-)
return adjust_al( change );
} /* adjust_alignment() */
/**
* This method returns the string associated with the current
* alignment of the living object.
* @return the string associated with the alignment
* @see query_al()
* @see adjust_al()
* @see adjust_alignment()
* @see set_al()
*/
string align_string() {
switch ( alignment ) {
case -MAX_AL .. -5201 : return "Lumen Incarnate"; break;
case -5200 .. -5001 : return "extremely good"; break;
case -5000 .. -2501 : return "very good"; break;
case -2500 .. -1251 : return "quite good"; break;
case -1250 .. -601 : return "fairly good"; break;
case -600 .. -301 : return "barely good"; break;
case -300 .. 300 : return "neutral"; break;
case 301 .. 600 : return "barely evil"; break;
case 601 .. 1250 : return "fairly evil"; break;
case 1251 .. 2500 : return "quite evil"; break;
case 2501 .. 4800 : return "very evil"; break;
case 4801 .. 5000 : return "extremely evil"; break;
default : return "Elytra Incarnate"; break;
}
} /* align_string() */
/**
* This method returns the current deity the living object is
* worshipping.
* @return the current deity
* @see /handlers/diety_handler
* @see set_deity()
*/
string query_deity() { return deity; }
/**
* This method sets the current deity the living object is
* worshipping.
* @param word the new deity
* @see /handlers/diety_handler
* @see query_deity()
*/
void set_deity( string word ) { deity = word; }
/**
* This is the method used to query the current message to use when
* entering a room. A $N in the string will be expanded to the
* name and a $F will be expanded to the from direction.
* @return the message to print when entering a room.
* @see /handlers/room_handler
* @see query_msgout()
* @see set_msgin()
*/
string query_msgin() { return msgin; }
/**
* This is the method used to query the current message to use when
* exiting a room. A $N in the string will be expanded to the
* name and a $T will be expanded to the to direction.
* @return the message to print when entering a room.
* @see /handlers/room_handler
* @see query_msgin()
* @see set_msgout()
*/
string query_msgout() { return msgout; }
/**
* This is the method used to set the current message to use when
* entering a room. A $N in the string will be expanded to the
* name and a $F will be expanded to the from direction.
* @param str the message to print when entering a room
* @see /handlers/room_handler
* @see query_msgin()
* @see set_msgout()
*/
int set_msgin(string str) {
if( strsrch( str, "$N" ) == -1 || strsrch( str, "$F" ) == -1 )
return 0;
msgin = str;
return 1;
} /* set_msgin() */
/**
* This is the method used to query the current message to use when
* exiting a room. A $N in the string will be expanded to the
* name and a $T will be expanded to the to direction.
* @return the message to print when entering a room.
* @see /handlers/room_handler
* @see query_msgout()
* @see set_msgin()
*/
int set_msgout(string str) {
if( strsrch( str, "$N" ) == -1 || strsrch( str, "$T" ) == -1 )
return 0;
msgout = str;
return 1;
} /* set_msgout() */
/**
* THis is the message to be used when the person is teleported.
* @return the in message when they teleport
*/
string query_mmsgin() { return mmsgin; }
/**
* THis is the message to be used when the person is teleported.
* @return the out message when they teleport
*/
string query_mmsgout() { return mmsgout; }
/**
* This is the message that is returned when they dest something.
* @return the dest message
*/
string query_destmsg() { return destmsg; }
/**
* The teleport in message. Sets the message to be seen when
* a player telerpots into the room.
* @param str the message to be seen
*/
int set_mmsgin(string str) {
if( strsrch( str, "$N" ) == -1 )
return 0;
mmsgin = str;
return 1;
} /* set_mmsgin() */
/**
* The dest message. Used when the cre dests something.
* @param str the message to be seen
*/
int set_destmsg( string str ) {
if( strsrch( str, "$N" ) == -1 )
return 0;
if( strsrch( str, "$O" ) == -1 )
return 0;
destmsg = str;
return 1;
} /* set_destmsg() */
/**
* Sets the teleport out message. If the player teleports out, this
* is the message seen.
* @param str the teleport message
*/
int set_mmsgout(string str) {
if( strsrch( str, "$N" ) == -1 )
return 0;
mmsgout = str;
return 1;
} /* set_mmsgout() */
mixed query_facing() { return copy( facing ); }
void set_facing( mixed args ) { facing = args; }
string find_rel( string word, int from ) {
int i;
if( ( i = member_array( word, facing[ 1 ] ) ) != -1 ) {
i = ( i + 8 - facing[ 0 ] ) % 8;
return REL_DIRS[ 3 * i + from ];
}
if( ( i = member_array( word, facing[ 2 ] ) ) != -1 )
return ({ "up", "down" })[ i ];
return word;
} /* find_rel() */
string find_abs( string word ) {
int i;
if( ( i = member_array( word, REL_DIRS ) ) != -1 ) {
i = ( i / 3 + facing[ 0 ]) % 8;
return facing[ 1 ][ i ];
}
if( ( i = member_array( word, ({ "up", "down" }) ) ) != -1 )
return facing[ 2 ][ i ];
return word;
} /* find_rel() */
string reorient_rel( string word ) {
int i;
if( ( i = member_array( word, REL_DIRS ) ) != -1 ) {
i = ( i / 3 + facing[ 0 ] ) % 8;
facing[ 0 ] = i;
return facing[ 1 ][ i ];
}
if( ( i = member_array( word, ({ "up", "down" }) ) ) != -1 )
return facing[ 2 ][ i ];
return word;
} /* reorient_rel() */
void set_dragging( object thing ) { dragging = thing; }
object query_dragging() { return dragging; }
void reset_dragging() { dragging = 0; }
int room_look() {
if( query_property( UNKNOWN_MOVE ) || !( interactive( TO ) ||
TO->query_slave() ) )
return 0;
/* These need to be evaluated immediately, hence the bypass_queue() call. */
if( !mapp(verbose) )
verbose = ([ ]);
if( verbose && verbose["look"] ) {
TO->ignore_from_history("look");
TO->bypass_queue();
command("look");
} else {
TO->ignore_from_history("glance");
TO->bypass_queue();
command("glance");
}
return 1;
} /* room_look() */
/**
* This method returns the current verbose mode setting of the player.
* @param the type of verbosity, by default it will return the normal stuff.
* @return the verbose mode of the player
*/
int query_verbose(string type) {
if( !verbose || !mapp(verbose) )
verbose = ([ ]);
return verbose[type];
} /* query_verbose() */
/**
* This method sets the verbosity for a given type.
*/
void set_verbose( string type, int val ) {
if( !verbose || !mapp(verbose) )
verbose = ([ ]);
if( member_array(type, VERBOSE_TYPES) != -1 )
verbose[type] = val;
} /* set_verbose() */
/**
* This method returns the current verbose/brief types.
*/
string *query_verbose_types() { return VERBOSE_TYPES; }
varargs int move_with_look( mixed dest, string messin, string messout ) {
return_to_default_position(1);
if( (int)TO->move( dest, messin, messout ) )
return 0;
room_look();
return_to_default_position(1);
return 1;
} /* move_with_look() */
/**
* This method is called whenever someone enters a command.
* It is here that the exits of the room are checked to see
* if the command entered is a move command.
* @param word the command entered
* @param verb no idea
* @param thing the object moving, not really used
* @return 1 if the command matched an exit and the move
* was successful, 0 if not
*/
varargs int exit_command( string word, mixed verb, object thing ) {
string special_mess, *bits, *exits, old;
int ret;
if( !environment() )
return 0;
if( !verb ) {
bits = explode( word, " " ) - ({ "", 0 });
verb = implode( bits, " ");
if( sizeof( bits ) > 1 )
word = implode( bits[ 1 .. ], " " );
else
word = "";
} else {
if( pointerp( verb ) ) {
special_mess = verb[ 1 ];
verb = verb[ 0 ];
}
bits = explode( verb, " " ) - ({ "", 0 });
if( sizeof( bits ) > 1 )
word = implode( bits[ 1 .. ], " " );
else
word = "";
}
if( LENGTHEN[ verb ] )
verb = LENGTHEN[ verb ];
if( !exits = (string *)environment()->query_exits() )
return 0;
if( member_array( verb, exits ) != -1 ) {
if( environment()->query_relative( verb ) )
return 0;
if( (ABS_FACING)[ verb ] )
facing[ 0 ] = (ABS_FACING)[ verb ] % 8;
} else {
verb = reorient_rel( verb );
if( member_array( verb, exits ) == -1 )
return 0;
}
if( !thing )
thing = TO;
old = thing->query_current_verb();
thing->set_current_verb( verb );
ret = (int)ROOM_H->exit_move( verb, word, special_mess, thing );
thing->set_current_verb( old );
return ret;
} /* exit_command() */
void become_flummoxed() {
int will;
will = query_int() * query_wis();
if( will < random( WILL_POWER ) )
TO->interrupt_ritual();
if( will < random( WILL_POWER ) )
TO->interrupt_spell();
if( will < random( WILL_POWER ) )
TO->stop_all_fight();
} /* become_flummoxed() */
/**
* This method is called when the creature wimpies.
* @return 1 if the wimpying was successful, 0 if not.
*/
int run_away() {
int i;
object tp;
mixed direcs;
direcs = (mixed)ENV(TO)->query_dest_dir();
tp = TP;
set_this_player(TO);
while( sizeof( direcs ) ) {
i = random( sizeof( direcs ) / 2 ) * 2;
if( exit_command(direcs[i]) ) {
set_this_player(tp);
return 1;
}
direcs = delete( direcs, i, 2 );
}
set_this_player(tp);
return 0;
} /* run_away() */
/** @ignore yes */
mixed stats() {
return container::stats() + stats::stats() + ({
({ "max_hp", max_hp }),
({ "hp", hp }),
({ "max_gp", max_gp }),
({ "gp", gp }),
({ "alcohol", drink_info[ D_ALCOHOL ] }),
({ "food", drink_info[ D_FOOD ] }),
({ "drink", drink_info[ D_DRINK ] }),
({ "gender", query_gender_string() }),
({ "alignment", TO->query_al() }),
({ "deity", deity }),
({ "total money", query_value() }),
({ "xp", query_xp() }),
}) + armour::stats() + combat::stats();
} /* stats() */
/**
* This method returns the current array used for calculating 'it' and
* 'them' in the find_match code.
* @return the array of objects matching them
* @see /secure/simul_efun->find_match()
* @see set_it_them()
*/
mixed query_it_them() { return it_them; }
/**
* This method sets the current array used for calculating 'it' and
* 'them' in the find_match code.
* @param args the new array of objects
* @see /secure/simul_efun->find_match()
* @see query_it_them()
*/
void set_it_them( mixed args ) { it_them = args; }
/**
* This method adds a follower to the living object. A follower will
* happily follow around the person in front. Used in the follow
* command.
* @param ob the object to follow us
* @see remove_follower()
* @see query_followers()
* @return 1 on success, 0 on failure
*/
int add_follower( object ob ) {
if( ob == TO )
return 0;
if( member_array( ob, followers ) == -1 )
followers += ({ ob });
return 1;
} /* add_follower() */
/**
* This method removes a follower from the living object. A follower will
* happily follow around the person in front. Used in the unfollow
* and lose commands.
* @param ob the object to remove from the follow list
* @see add_follower()
* @see query_followers()
* @return 1 on success, 0 on failure
*/
int remove_follower(object ob) {
int i;
if( ( i = member_array( ob, followers ) ) != -1 ) {
followers = delete( followers, i, 1 );
return 1;
}
return 0;
} /* remove_follower() */
/**
* This is a method to check to see if this object can actually follow
* the person they are following.
* @param thing the thing following us
* @param verb the direction they are going to
* @param special any special stuff
* @return 1 if we are allowed to go there, 0 otherwise
*/
int check_doing_follow(object thing, string verb, string special) {
return 1;
} /* check_doing_follow() */
/**
* This method returns the current room of the object. This was needed
* previously to use in things like unique_array, before function
* pointers came into existance.
* @return the environment of the object
*/
object query_current_room() { return environment(); }
/**
* This method returns the current list of followers to the living
* object.
* @see add_follower()
* @see remove_follower()
*/
mixed query_followers() { return copy(followers); }
/** @ignore yes */
varargs void adjust_money(mixed amt, string type) {
return money::adjust_money(amt, type);
} /* adjust_money() */
/** @ignore yes */
mixed query_money_array() {
return money::query_money_array();
} /* query_money_array() */
/** @ignore yes */
int query_money(string type) {
return money::query_money(type);
} /* query_money() */
/** @ignore yes */
int query_value() { return money::query_value(); }
/** @ignore yes */
void event_enter( object thing, string mess, object from ) {
if( ENV( thing ) == TO ) {
call_out( "calc_burden", 1 );
if( sizeof( all_inventory() ) > MAX_INVEN ) {
remove_call_out( "test_number_of_items" );
to_drop += ({ thing });
call_out( "test_number_of_items", 5 + random( 5 ) );
}
}
} /* event_enter() */
/** @ignore yes */
void event_exit( object thing, string mess, object to ) {
if( ENV( thing ) == TO )
call_out("calc_burden", 1 );
} /* event_exit() */
/** @ignore yes */
void test_number_of_items() {
int i, how_many;
object thing, *things;
how_many = sizeof( all_inventory() - query_armours() ) -
( MAX_INVEN + query_dex() );
if( how_many < 1 ) {
to_drop = ({ });
return;
}
things = ({ });
for( i = 0; ( i < how_many ) && ( i < sizeof( to_drop ) ); i++ ) {
thing = to_drop[ i ];
if( !thing )
continue;
if( ENV( thing ) != TO || !thing->short() || thing->drop() ||
thing->query_property("cannot fumble") )
continue;
if( !(int)thing->move( environment() ) )
things += ({ thing });
}
to_drop = ({ });
if( !sizeof( things ) )
return;
tell_object( TO, "Whoops! You tried to carry too many things "+
"and fumbled "+ query_multiple_short( things ) +".\n" );
TO->dest_hide_shadow();
tell_room( environment(), the_short()+" juggles around "+
query_possessive() +" stuff and fumbles "+
query_multiple_short( things ) +".\n", TO );
} /* test_number_of_items() */
/** @ignore yes */
object *find_inv_match( string words, object looker ) {
return sort_array( container::find_inv_match( words, looker ),
(: ( member_array( $1, query_holding() ) != -1 ? -1 : 0 ) :) );
} /* find_inv_match() */
/** @ignore yes */
int attack_by(object ob) {
return_to_default_position(0);
return ::attack_by(ob);
} /* attack_by() */
/** @ignore yes */
int attack_ob(object ob) {
return_to_default_position(0);
return ::attack_ob(ob);
} /* attack_ob() */
/**
* This method sets the always the flag to always use the default position.
* If this is set then rooms cannot override the position message which is
* displayed by the object.
* @param flag if we should always use the default position
* @see query_always_use_default_position()
* @see set_default_position()
* @see return_to_default_position()
*/
void set_always_use_default_position(int flag) {
always_use_default_position = flag;
} /* set_always_use_default_position() */
/**
* This method sets the always the flag to always use the default position.
* If this is set then rooms cannot override the position message which is
* displayed by the object.
* @return the always use default position flag
* @see set_always_use_default_position()
* @see set_default_position()
* @see return_to_default_position()
*/
int query_always_use_default_position() {
return always_use_default_position;
} /* query_always_use_default_position() */
/**
* This method sets the default position of the object. This is used to
* allow things to default to some other exciting off beat and froopy
* default position. The value returned by this is the command code
* used to put the object back into the default position or an
* array which contains three or one elements, the first is the string
* to use as the position, the second and third (if they exist) are
* the string to tell the person when changing and the string to tell
* everyone else when changing position.
* @return the default position
* @see set_default_position()
* @see return_to_default_position()
* @see set_always_use_default_position()
*/
string query_default_position() {
mixed pos;
if( stringp(default_position) &&
default_position->query_position_command() ) {
pos = default_position;
} else if( pointerp(default_position) &&
( sizeof(default_position) == POSITION_MESS_SIZE ||
sizeof(default_position) == POSITION_ONLY_TYPE_SIZE ) ) {
pos = default_position;
} else if( functionp(default_position) ) {
pos = default_position;
}
if( !pos )
pos = STANDING_CMD;
return pos;
} /* query_default_position() */
/**
* This sets the default position of the object. This is used to
* allow things to default to some other exciting off beat and froopy
* default position. The paramater to this is the command code
* used to put the object back into the default position or an
* array which contains three or one elements, the first is the string
* to use as the position, the second and third (if they exist) are
* the string to tell the person when changing and the string to tell
* everyone else when changing position. The paramer can also be
* a function pointer, if it is then it will be evaluated and
* have two parameters passed into the function. The first is
* the object returing to the position and the second is the leaving
* flag.
* <p>
* Please note! After setting the position you will need to
* make the object return to the default position to use it.
* <p>
* A second note! A room can also define a query_default_position()
* function which will be called, if this returns a value (and the
* override flag is not set) then that will be used for the default
* position.
* @param str the new default position
* @see query_default_position()
* @see set_always_use_default_position()
* @see /obj/monster()->set_cannot_change_position()
* @see return_to_default_position()
* @example
* set_default_position("/cmds/living/kneel");
* @example
* set_default_position(({ "running" }));
* @example
* set_default_position(({ "fishing",
* "You start to fish.\n",
* the_short() + " starts to fish.\n" }));
* @example
* npc->set_default_position(({ "running" }));
* npc->return_to_default_position();
*/
void set_default_position(mixed str) {
if( stringp(str) && str->query_position_command() &&
str != STANDING_CMD ) {
default_position = str;
} else if( !str || str == STANDING_CMD ) {
default_position = 0;
} else if( pointerp(str) && ( sizeof(str) == POSITION_ONLY_TYPE_SIZE ||
sizeof(str) == POSITION_MESS_SIZE ) ) {
default_position = str;
} else if( functionp(str) ) {
default_position = str;
}
} /* set_default_position() */
/**
* This method returns the living object to its default position.
* @param leaving this is if we are leaving the room
* @see set_default_position()
* @see query_default_position()
* @see set_always_use_default_position()
*/
void return_to_default_position(int leaving) {
mixed pos;
/* See if we are being forced to always use the set default position. */
if( query_always_use_default_position() ) {
pos = query_default_position();
} else {
/* See if the room has a default position they wish to tell us about. */
pos = 0;
if( environment() )
pos = environment()->query_default_position(TO);
if( !pos )
pos = query_default_position();
}
if( functionp(pos) ) {
if( !evaluate( pos, TO, leaving ) ) {
pos = 0;
/* See if the environment has any special conditions */
if( environment() )
pos = environment()->query_default_position(TO);
if( !pos )
pos = STANDING_CMD;
}
}
if( stringp(pos) ) {
/* If we are not standing up... Stand up... */
if( position != pos->query_position_type() ||
( leaving && query_position_on() ) ) {
if( leaving ) {
catch( pos->position_floor(TO) );
} else {
/*
* If they are not leaving, just get them to stand up or
* whatever, this way people can fight on chairs and
* stuff...
*/
catch( pos->position(TO) );
}
}
} else if( pointerp(pos) && position != pos[POSITION_TYPE_INDEX] ) {
/* If it is a pointer, then we do something special... */
if( sizeof(pos) > 1 ) {
if( pos[POSITION_ME_MESS_INDEX] )
tell_object(TO, pos[POSITION_ME_MESS_INDEX]);
if( pos[POSITION_REST_MESS] )
tell_room(environment(), pos[POSITION_REST_MESS], TO);
}
set_position( pos[POSITION_TYPE_INDEX] );
set_position_on(0);
set_position_type(0);
set_position_multiple(0);
}
} /* return_to_default_position() */
/**
* This sets the current position of the object.
* @param name the string to use for the position
* @see query_position()
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position_on()
* @see set_position_multiple()
* @see set_position_type()
*/
void set_position(string name) {
position = name;
} /* set_position() */
/**
* This queries the current position of the object.
* @return the current position of the living
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_on()
* @see set_position_multiple()
* @see set_position_type()
*/
string query_position() {
return position;
} /* query_position() */
/**
* This sets the current object which is being referenced as being
* 'on', 'beside' or 'at'.
* @param ob the object being referenced
* @see query_position()
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_multiple()
* @see set_position_type()
*/
void set_position_on(mixed ob) {
if( !position_on )
position_on = allocate(POSITION_ARRAY_SIZE);
position_on[POS_ON_OBJECT] = ob;
} /* set_position_on() */
/**
* This sets fact that the object being referenced is one of many. So
* you get something more like 'xx is sitting on one of the couches'.
* @param mult 0 if non-multiple, 1 if multiple
* @see query_position()
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_multiple()
* @see set_position_type()
*/
void set_position_multiple(int mult) {
if( !position_on )
position_on = allocate(POSITION_ARRAY_SIZE);
position_on[POS_MULTIPLE] = mult;
} /* set_position_multiple() */
/**
* This returns fact that the object being referenced is one of many. So
* you get something more like 'xx is sitting on one of the couches'.
* @return 0 if non-multiple, 1 if multiple
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_on()
* @see set_position_multiple()
* @see set_position_type()
*/
int query_position_multiple() {
if( !position_on )
return 0;
return position_on[POS_MULTIPLE];
} /* query_position_multiple() */
/**
* This sets way the object is being referenced. The 'on', 'at', 'beside'
* or whatever strings.
* @param type the new type string
* @see query_position()
* @see query_position_on()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_on()
* @see set_position_multiple()
*/
void set_position_type(string type) {
if( !position_on )
position_on = allocate(POSITION_ARRAY_SIZE);
position_on[POS_TYPE] = type;
} /* set_position_type() */
/**
* This returns way the object is being referenced.
* The 'on', 'at', 'beside'
* or whatever strings.
* @return the current type string
* @see query_position()
* @see query_position_on()
* @see query_position_multiple()
* @see set_position()
* @see set_position_on()
* @see set_position_multiple()
* @see set_position_type()
*/
string query_position_type() {
if( !position_on || !position_on[POS_TYPE] )
return "on";
return position_on[POS_TYPE];
} /* query_position_type() */
/**
* This queries the current object being referenced. This can be an
* object or a string.
* @return the current object being referenced
* @see query_position()
* @see query_position_multiple()
* @see query_position_type()
* @see set_position()
* @see set_position_on()
* @see set_position_multiple()
* @see set_position_type()
*/
object query_position_on() {
if( !position_on )
return 0;
return position_on[POS_ON_OBJECT];
} /* query_position_on() */
/**
* This method returns the short description of the object
* we are referencing.
* @return the short description of the object, "" if none
* @see query_position_on()
* @see set_position_on()
* @see query_position_long()
*/
string query_position_on_short() {
if( !position_on || !position_on[POS_ON_OBJECT] )
return "";
if( stringp(position_on[POS_ON_OBJECT]) )
return position_on[POS_ON_OBJECT];
return position_on[POS_ON_OBJECT]->the_short();
} /* query_position_on_short() */
/**
* This method returns the string used in the long description of the
* living object.
* @return the long description of the position
* @see query_position_type()
* @see query_position_on_short()
*/
string query_position_long() {
if( position != STANDING || position_on ) {
if( position_on ) {
return query_pronoun() + " is " + query_position_type() + " "+
query_position_on_short()+".\n";
}
return query_pronoun()+" is "+position+" on the floor.\n";
}
return "";
} /* query_position_long() */
/**
* This method returns the description used in the inventory listing
* code.
* @return the string used in inventory listings
* @see query_position_long()
* @see query_position_on_short()
* @see query_position_type()
*/
string query_position_short() {
if( !position_on || !position_on[POS_ON_OBJECT] )
return position;
return position + " " + query_position_type() + " " +
query_position_on_short();
} /* query_position_short() */
/**
* This method returns 1 if the creature is trapped, ie cannot walk.
* By default, a creature is free to walk, hence the normal return
* value of 0. If you shadow this method, including a message about
* why the player cannot move move is a good idea.
* @return 0 means creature is free to move, 1 that it is trapped.
* @see no_use_doors, exit_command
*/
int cannot_walk() { return 0; }
/**
* This method returns 1 if the creature shouldn't be able to use
* closed doors.
* By default, any creature is able to move through closed doors
* by opening them, so the default value is 0.
* If you shadow this method, including a message about why the
* player cannot move in a particular direction, is a good idea.
* @return 0 means creature is free to move through closed doors,
* 1 that it cannot.
* @see cannot_walk, exit_command
*/
int no_use_doors() { return 0; }
/**
* This method can be shadowed by all forms of magical and
* religious shields so that the shields command will give
* the player a nice description.
* The first element in the array should contain the description
* as shown to the player, the second element should contain the
* description shown to others.
* @example ({ "You have a nice shield.", "He has a nice shield." })
* @return Array with description of shield.
*/
string *query_arcane_shields() { return ({ }); }
/** @ignore yes */
int can_find_match_reference_inside_object( object thing, object looker ) {
if( member_array(thing, query_wearing_hidden( looker, 0 ) ) != -1 )
return 0;
return 1;
} /* can_find_match_reference_inside_object() */
/** @ignore yes */
void dest_me() {
LIVING_H->living_dested();
::dest_me();
} /* dest_me() */
/** @ignore yes */
void heart_beat() {
stats::heart_beat();
combat::heart_beat();
} /* heart_beat() */