/* -*- LPC -*- */ /* * $Locker: pinkfish $ * $Id: living.c,v 1.73 2003/04/30 18:22:59 ceres Exp pinkfish $ * */ /** * The main living inherit. This inherits all the files * needed to be in a living object. * @author Pinkfish */ #include <dirs.h> #include <drinks.h> #include <living.h> #include <move_failures.h> #include <player.h> #include <tune.h> #include <position.h> #include <obj_parser.h> inherit "/std/container"; inherit "/std/living/armour"; 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/crafts"; inherit "/std/living/stats"; inherit "/std/living/respond_cmd"; inherit "/std/living/nationality"; #define VERBOSE_TYPES ({"combat", "look", "score", "names", "htell", "finger", "errors", "quit"}) //The maximum amount of religious favour you can have. #define MAX_FAVOUR 100 class living_data { int handicap; int burden; object* followers; class obj_match_context it_them; object* to_drop; int burden_call; } class messages { string msgout; string msgin; string mmsgout; string mmsgin; } private int alignment; private class messages _messages; private mixed *facing; private mapping verbose; private mapping abs_facing = ABS_FACING; private mapping lengthen = LENGTHEN; //Got religion? private string deity; //Your deity of choice. private mapping deity_favour; //A mapping of deity ratings. //private nosave object _dragging; private nosave class living_data _liv_data; //private nosave int _handicap; //private nosave object *_followers; //private nosave class obj_match_context _it_them; //private nosave object* _to_drop; //private nosave int _burden_call; 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(); protected mixed command(string); /* * 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; _liv_data = new(class living_data); _messages = new(class messages); crafts::create(); 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(); _messages->msgin = "$N arrive$s from $F."; _messages->msgout = "$N leave$s $T."; _messages->mmsgin = "$N appear$s out of the ground."; _messages->mmsgout = "$N disappear$s in a puff of smoke."; _liv_data->followers = ({ }); verbose = ([ ]); set_max_items(50); _liv_data->to_drop = ({ }); foreach(t in VERBOSE_TYPES) { verbose[t] = 1; } facing = ({ 0, ({ "north", "northeast", "east", "southeast", "south", "southwest", "west", "northwest" }), ({ "up", "down" }) }); position = STANDING; add_adjective("living"); } /* create() */ /** @ignore yes */ void heart_beat() { stats::heart_beat(); combat::heart_beat(); } /** * 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(); } /* 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(); } /* 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(); } /* query_objective() */ /** @ignore yes */ varargs int query_weight(int actual) { if(!actual && this_object()->query_property("dead")) return 0; 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() { return _liv_data->burden; } /* query_burden() */ /** * This method returns the current handicap of the living * object. * @return the current handicap. * @see calc_burden() */ int query_handicap() { return _liv_data->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; int burden; object thing; mapping hands; _liv_data->burden_call = 0; 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()) { this_object()->reset_carry_cap(); _liv_data->burden = 50; } else _liv_data->burden = (100 * burden) / query_max_weight(); new_handicap = (_liv_data->burden / 25) - 1; if(new_handicap < 0) new_handicap = 0; if ( _liv_data->handicap != new_handicap ) { adjust_bonus_dex( _liv_data->handicap - new_handicap ); _liv_data->handicap = new_handicap; } } /** * 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 (_liv_data->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() */ /** * This method adds any commands needed by the living inherit. */ void living_commands() { #if efun_defined(add_action) add_action( "exit_command", "*", 1 ); #endif } /* living_commands() */ /** * This method allows you to make the living object eat something. * @param food the food object to eat */ void eat_this( object food ) { this_object()->bypass_queue(); command( "eat " + file_name( food ) ); } /* eat_this() */ /** * 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) { if(sizeof(all_inventory(this_object())) > query_max_items()) return 0; 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 ( !this_player() || ( this_player() == this_object() ) ) { 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_array( 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( this_player(), this_object() ) ) { event( environment( this_player() ), "theft", this_player(), this_object(), 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 .. -5001 : return "extremely good"; break; case -5000 .. -2501 : return "very good"; break; case -2500 .. -1251 : return "quite good"; break; case -1250 .. -601 : return "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 "evil"; break; case 1251 .. 2500 : return "quite evil"; break; case 2501 .. 5000 : return "very evil"; break; default : return "extremely evil"; break; } } /* align_string() */ /** * This method returns the current deity the living object is * worshipping. * @return the current deity * @see /obj/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 /obj/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 /obj/handlers/room_handler * @see query_msgout() * @see set_msgin() */ string query_msgin() { return _messages->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 /obj/handlers/room_handler * @see query_msgin() * @see set_msgout() */ string query_msgout() { return _messages->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 /obj/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; } _messages->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 /obj/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; } _messages->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 _messages->mmsgin; } /** * THis is the message to be used when the person is teleported. * @return the out message when they teleport */ string query_mmsgout() { return _messages->mmsgout; } /** * 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; } _messages->mmsgin = str; return 1; } /* set_mmsgin() */ /** * 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; } _messages->mmsgout = str; return 1; } /* set_mmsgout() */ mixed *query_facing() { return copy( facing ); } /** * The facing array is a list of directions and two integers which determine * which way we face. The layout is:<br> * ({ facing, ({ dirs }), up_down_facing, ({ up_down_dirs }) }) * @param args the facing arguments */ void set_facing( mixed *args ) { facing = args; } /** * This method finds the relative direction from the passed in direction. * @param word the exit name ('east', 'west',...) * @param from the offset to find the exit from * @return the relative direction */ string find_rel( string word, int from ) { int i; i = member_array( word, facing[ 1 ] ); if ( i != -1 ) { i = ( i + 8 - facing[ 0 ] ) % 8; return REL_DIRS[ 3 * i + from ]; } i = member_array( word, facing[ 2 ] ); if ( i != -1 ) { return ({ "up", "down" })[ i ]; } return word; } /* find_rel() */ /** * Finds the absolute direction from the input relative direction. * @param word the exit name ('left', 'right', ...) * @return the absolute direction */ string find_abs( string word ) { int i; i = member_array( word, REL_DIRS ); if ( i != -1 ) { i = ( i / 3 + facing[ 0 ]) % 8; return facing[ 1 ][ i ]; } i = member_array( word, ({ "up", "down" }) ); if ( i != -1 ) { return facing[ 2 ][ i ]; } return word; } /* find_rel() */ /** * This method takes in a relative direction and reorients us in the correct * way to go in that direction. This also updates our facing so we are * facing in the specified relative direction. * @param word the direction to look up * @return the real direction */ string reorient_rel( string word ) { int i; i = member_array( word, REL_DIRS ); if ( i != -1 ) { i = ( i / 3 + facing[ 0 ] ) % 8; facing[ 0 ] = i; return facing[ 1 ][ i ]; } i = member_array( word, ({ "up", "down" }) ); if ( i != -1 ) { return facing[ 2 ][ i ]; } return word; } /* reorient_rel() */ /** * This method takes in a absolute direction and reorients us in the correct * way to go in that direction. * @param word the direction to look up */ void reorient_abs( string verb ) { if ((ABS_FACING)[verb]) { facing[0] = (ABS_FACING)[verb] % 8; } } /* reorient_rel() */ /** * This method sets the object for us to drag when we try and leave. * @param thing the object to drag off */ void set_dragging( object thing ) { add_property("dragging", thing); } /** * This method returns the object we are dragging. * @return the thing we are dragging */ object query_dragging() { return query_property("dragging"); } /** * This method resets the object we are dragging. */ void reset_dragging() { add_property("dragging", 0); } /** * This is used by the movement system to look in the room when we move. * It does checks for verbose and other checks before doing the look. */ int room_look() { if ( query_property( UNKNOWN_MOVE ) || !( interactive( this_object() ) || this_object()->query_slave() ) ) return 0; /* These need to be evaluated immediately, hence the bypass_queue() call. */ if(!mapp(verbose)) verbose = ([ ]); if(verbose && verbose["look"]) { this_object()->ignore_from_history( "look" ); this_object()->bypass_queue(); command( "look" ); } else { this_object()->ignore_from_history( "glance" ); this_object()->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; } } /** * 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)this_object()->move( dest, messin, messout ) != MOVE_OK ) return 0; room_look(); return_to_default_position(1); return 1; } /* move_with_look() */ varargs int exit_command( string word, mixed verb, object thing, int redirection ) { string special_mess, *bits, *exits, redirect; int temp; if ( !environment() ) { return 0; } if ( !verb ) { verb = word; bits = explode( word, " " ); if ( sizeof( bits ) > 1 ) { word = implode( bits[ 1 .. ], " " ); } else { word = ""; } } else { if ( pointerp( verb ) ) { special_mess = verb[ 1 ]; verb = verb[ 0 ]; } bits = explode( verb, " " ); if ( sizeof( bits ) > 1 ) { word = implode( bits[ 1 .. ], " " ); } else { word = ""; } } if ( lengthen[ verb ] ) { verb = lengthen[ verb ]; } exits = (string *)environment()->query_exits(); if ( !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 { if (member_array(find_abs(verb), exits ) == -1 ) { return 0; } verb = reorient_rel(verb); } if ( !thing ) { thing = this_object(); } //If the player has redirection enabled! //Redirection returns a string which is an alternative exit to try. //It calls exit_command to do all of the proper checks before hand, //it blocks recursion by way of a flag which is passed as the fourth arg //in exit command. if ( !redirection ) { if ( stringp( redirect = thing->query_exit_redirection( word ) ) ) { if ( temp = this_object()->exit_command( verb, redirect, thing, 1 ) ) return temp; } } return (int)"/obj/handlers/room_handler"->exit_move( verb, word, special_mess, thing ); } /* exit_command() */ void become_flummoxed() { int will; will = query_int() * query_wis(); if ( will < random( WILL_POWER ) ) this_object()->interrupt_ritual(); if ( will < random( WILL_POWER ) ) this_object()->interrupt_spell(); if ( will < random( WILL_POWER ) ) this_object()->stop_all_fight(); } /* become_flummoxed() */ int run_away() { int i; object old_env; mixed *direcs; direcs = (mixed *)environment()->query_dest_dir(this_object()); old_env = environment(); while ( sizeof( direcs ) ) { i = random( sizeof( direcs ) / 2 ) * 2; if ( exit_command( direcs[i] ) ) { event( old_env, "run_away", direcs[ i ], direcs[ i + 1 ] ); return 1; } direcs = delete( direcs, i, 2 ); } return 0; } /* run_away() */ /* Now handled in test_remove(). int cannot_get_stuff() { return !query_property( PASSED_OUT ); } */ /** @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", this_object()->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() */ class obj_match_context query_it_them() { return _liv_data->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( class obj_match_context args) { _liv_data->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 == this_object()) { return 0; } if (member_array(ob, _liv_data->followers) == -1) { _liv_data->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; i = member_array(ob, _liv_data->followers); if (i != -1) { _liv_data->followers = delete(_liv_data->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(_liv_data->followers - ({ 0 })); } /** @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(); } void do_burden_call() { if(_liv_data->burden_call) remove_call_out(_liv_data->burden_call); _liv_data->burden_call = call_out("calc_burden", 1); } int query_burden_limit() { if (this_object()->query_creator()) { return MAX_CREATOR_INVEN; } else { return MAX_INVEN; } } /* query_burden_limit() */ /** @ignore yes */ void event_enter( object thing, string mess, object from ) { if(environment( thing ) == this_object()) { do_burden_call(); if(sizeof(all_inventory()) > query_burden_limit() ) { _liv_data->to_drop += ({ thing }); remove_call_out("test_number_of_items"); call_out("test_number_of_items", 5 + random(5)); } } } /** @ignore yes */ void event_exit( object thing, string mess, object to ) { if(environment(thing) == this_object()) { do_burden_call(); } } /** @ignore yes */ void test_number_of_items() { int how_many; object thing, *things, *dropped; things = all_inventory() - query_armours() - query_holding(); how_many = sizeof(things) - query_burden_limit(); if ( how_many < 1 ) { return; } _liv_data->to_drop -= ({ 0 }); dropped = ({ }); while(how_many > 0 && sizeof(things)) { if (sizeof(_liv_data->to_drop)) { thing = _liv_data->to_drop[random(sizeof(_liv_data->to_drop))]; } else { thing = things[random(sizeof(things))]; } things -= ({ thing }); _liv_data->to_drop -= ({ thing }); if(!thing || !thing->short() || thing->drop() || thing->query_property("cannot fumble") || thing->id("coin") || environment(thing) != this_object()) { continue; } if((int)thing->move(environment()) == MOVE_OK) { how_many--; dropped += ({ thing }); } } _liv_data->to_drop = ({ }); if(sizeof(dropped)) { tell_object( this_object(), "Whoops! You tried to carry too many " "things and fumbled "+ query_multiple_short( dropped ) +".\n" ); this_object()->dest_hide_shadow(); tell_room( environment(), capitalize( the_short() ) +" juggles "+ "around "+ query_possessive() +" stuff and fumbles "+ query_multiple_short( dropped ) +".\n", this_object() ); } } /** * This forces a burden recalculation. This should also be used to * force a recalcuation of the number of items someone can carry. */ void force_burden_recalculate() { do_burden_call(); remove_call_out("test_number_of_items"); call_out("test_number_of_items", 5 + random(5)); } /** @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(1); */ 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(this_object()); } if (!pos) { pos = query_default_position(); } } if (functionp(pos)) { if (!evaluate(pos, this_object(), leaving)) { pos = 0; /* See if the environment has any special conditions */ if (environment()) { pos = environment()->query_default_position(this_object()); } 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(this_object())); } 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(this_object())); } } } 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(this_object(), pos[POSITION_ME_MESS_INDEX]); } if (pos[POSITION_REST_MESS]) { tell_room(environment(), pos[POSITION_REST_MESS], this_object()); } } 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. * @param verb the exit direction that the player is trying to move. * @param dest_other the destination information for the exit. * @see /std/room->query_dest_other() * @return 0 means creature is free to move, 1 that it is trapped. */ varargs int cannot_walk( string verb, mixed *dest_other) { 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() */ /** * If there is no mapping for deity favour, or if the God is not mentioned, * return 0 as 'no favour'. * Otherwise return the favour amount. * @args God Name of God */ int query_deity_favour( string god ) { if ( !mapp( deity_favour ) ) return 0; if ( !undefinedp( deity_favour[ god ] ) ) return 0; return deity_favour[ god ]; } /** * Adjust the favour rating for 'god' by amount. * A +ve amount is good favour, a negative is bad. */ void adjust_deity_favour( string god, int amount ) { if ( !mapp( deity_favour ) ) deity_favour = ([ ]); if ( !undefinedp( deity_favour[ god ] ) ) deity_favour[ god ] = amount; deity_favour[ god ] += amount; if ( deity_favour[ god ] > MAX_FAVOUR ) deity_favour[ god ] = MAX_FAVOUR; if ( deity_favour[ god ] < -MAX_FAVOUR ) deity_favour[ god ] = -MAX_FAVOUR; return; } /** * Return the deity favour mapping. */ mapping query_all_deity_favour() { return deity_favour; }