/*
* $Locker: $
* $Id: wearable.c,v 1.24 2003/05/21 03:44:06 ceres Exp $
*/
/**
* This file contains all the methods needed to make an object wearable
* by a player or an npc.
* @author Pinkfish
* @see /obj/armour.c
* @see /obj/clothing.c
*/
inherit "/std/basic/condition";
#include <clothing.h>
#include <move_failures.h>
private string *immune_to;
private string *wear_effects;
private mixed type;
private mixed *wear_remove_func;
nosave object worn_by;
void create() {
condition::create();
set_damage_chance( 25 );
immune_to = ({ "cold", "sound", "gas", "mental" });
wear_effects = ({ });
wear_remove_func = ({ });
} /* create() */
/**
* This method tells us if the object is wearable.
* In the case of a wearable object it will always return 1.
* @return always returns 1
*/
int query_wearable() { return 1; }
/** @ignore yes */
string long( string word, int dark ) {
switch ( dark ) {
case 0 :
return cond_string();
default :
return "";
}
} /* long() */
/**
* This method returns the current function associated with
* wearing and removing the item.
* @return the current function for wearing and removing the clothing
* @see set_wear_remove_func()
*/
mixed *query_wear_remove_func() {
return wear_remove_func;
} /* query_wear_remove_func() */
/**
* This method sets the current function associated with wearing and
* removing the item. The value of this function should be choosen
* carefully, using an object reference for the name will work but
* it will not then be able to restored from the save file. The same
* goes for using function pointers. It is better to use a real
* file name and a string function name.
* <p>
* The function will be called with two arguments, the first argument will
* be 0 if the object is being removed or the object which it is
* being worn by if it is non-zero. The second argument will always
* be the person who was wearing the item, or is about to wear the
* item.
* @example
* inherit "/std/basic/wearable";
*
* void setup() {
* ...
* set_wear_remove_func(base_name(this_object()), "do_fluff");
* ...
* } /\* setup() *\/
*
* void do_fluff(object ob, object player) {
* if (!ob) {
* write(capitalize(the_short()) + " is being removed.\n");
* } else {
* write(capitalize(the_short()) + " is being worn.\n");
* }
* } /\* do_fluff() *\/
* @param file the file to call the function on
* @param func the function to call
* @see query_wear_remove_func()
*/
void set_wear_remove_func( mixed file, string func ) {
wear_remove_func = ({ file, func });
} /* set_wear_remove_func() */
/**
* This method returns the list of effects to be added to the wearer when
* it is worn. These effects will automaticly be added when worn and
* removed when taken off.
* @return the list of effects to be added to the wearer when worn
* @see set_wear_effects()
* @see add_wear_effect()
*/
string *query_wear_effects() {
if(!wear_effects)
wear_effects = ({ });
return copy(wear_effects);
} /* query_wear_effects() */
/**
* This method sets the list of effects to be added to the wearer when it
* is worn. These effects will automaticly be added when worn and
* removed when taken off.
* @param effects the array of effects to be added to the wearer when worn
* @see query_wear_effects()
* @see add_wear_effect()
*/
void set_wear_effects( string *effects ) {
wear_effects = effects;
} /* set_wear_effects() */
/**
* This method adds a new wear effect to the current wear effect array. These effects will automaticly be added when worn and
* removed when taken off.
* @param effect the effect to add
* @see query_wear_effects()
* @see set_wear_effects()
*/
void add_wear_effect( string effect ) {
if ( member_array( effect, wear_effects ) == -1 ) {
wear_effects += ({ effect });
}
} /* add_wear_effect() */
/** @ignore yes */
void do_damage( string type, int amount ) {
if ( member_array( type, immune_to ) == -1 ) {
condition::do_damage( type, amount );
}
} /* do_damage() */
/**
* This method returns the person who is currently wearing the object.
* @return the current wearer of the object
* @see set_worn_by()
*/
object query_worn_by() {
return worn_by;
} /* query_worn_by() */
/**
* This method sets the object as being worn by the passed in object.
* It calls all the various worn functions and sets up or removes
* all the effects associated with the object.
* <p>
* If the object is alreadying being worn the wear_remove_function will
* be called with an argument of 0. The method taken_off will be
* called on the object wearing the object for all the effects associated
* with this object.
* <p>
* If the object is being set to be worn by someone the the wear_remove
* function will be called with an argument being the person who is to
* wear the object. All of the effects associated with the
* object will be added to the wearer.
* <p>
* This calls the method 'person_removing_item' on the effect when some
* one removes the item. This can be used to make sure the effects are
* taken off when the item is removed.
* @param thing the new person to wear the object (0 for worn by no one)
* @return 1 if successful, 0 on failure
* @see set_wear_remove_func()
* @see add_wear_effect()
*/
int set_worn_by( object thing ) {
int i;
/* Do nothing if we are already worn by them. */
if ( thing == worn_by ) {
return 1;
}
/* We need this thing check here because if thing is 0 we are removing the object! */
/* Taffyd */
if (thing && environment() != thing) {
return 0;
}
/* First remove any possible concealment off us */
this_object()->remove_hide_invis( "concealed" );
/* If there is a move function, then call it. */
if ( sizeof( wear_remove_func ) ) {
if ( !objectp( wear_remove_func[ 0 ] ) && !objectp( load_object( wear_remove_func[ 0 ] ) ) ) {
debug_printf( "Wear/Remove func is %O. Not called.\n", wear_remove_func );
return 0;
}
if ( worn_by ) {
call_other( wear_remove_func[ 0 ], wear_remove_func[ 1 ], 0, worn_by );
}
if ( thing ) {
call_other( wear_remove_func[ 0 ], wear_remove_func[ 1 ], thing, thing );
}
}
/* If there are some wear effects, set them up or remove them. */
if ( sizeof( wear_effects ) ) {
for ( i = 0; i < sizeof( wear_effects ); i++ ) {
if ( worn_by ) {
worn_by->taken_off( this_object(), wear_effects[ i ] );
}
if ( thing ) {
thing->add_effect( wear_effects[ i ], this_object() );
} else {
wear_effects[i]->person_removing_item(this_object(), worn_by);
}
}
}
/*
* Call the functions on the object doing the wearing to remove or add
* the item.
*/
if ( worn_by ) {
worn_by->now_removed( this_object() );
this_object()->add_adjective("worn");
this_object()->remove_adjective("unworn");
} else {
this_object()->remove_adjective("worn");
this_object()->add_adjective("unworn");
}
if ( thing ) {
thing->now_worn( this_object() );
}
worn_by = thing;
return 1;
} /* set_worn_by() */
/**
* This returns the list of types of damage that the object is immune to.
* @return the list of damage we are immune to
* @see /std/basic/condition.c
* @see add_immune_to()
* @see remove_immune_to()
*/
string *query_immune_to() {
return immune_to;
} /* query_immune_to() */
/**
* This adds a new type of damage that the object is immune to.
* The parameter can either be a string or an array of strings
* being the types of damage to be immune to.
* @param args the type of damage to be immune to
* @example
* inherit "/std/basic/wearable";
*
* void setup() {
* ...
* add_immune_to("sharp");
* ...
* } /\* setup() *\/
* @example
* inherit "/std/basic/wearable";
*
* void setup() {
* ...
* add_immune_to("sharp");
* ...
* } /\* setup() *\/
* @see remove_immune_to()
* @see query_immune_to()
*/
void add_immune_to( mixed args ) {
int i;
if ( pointerp( args ) ) {
for ( i = 0; i < sizeof( args ); i++ ) {
add_immune_to( args[ i ] );
}
} else {
if ( member_array( args, immune_to ) == -1 ) {
immune_to += ({ args });
}
}
} /* add_immune_to() */
/**
* This method removes a type of damage that the weapon is immune
* to.
* @param args the type(s) of damage to remove immunity too
* @see add_immune_to()
* @see query_immune_to()
*/
void remove_immune_to( mixed args ) {
int i;
if ( pointerp( args ) ) {
for ( i = 0; i < sizeof( args ); i++ ) {
remove_immune_to( args[ i ] );
}
} else {
i = member_array( args, immune_to );
if ( i != -1 ) {
immune_to = delete( immune_to, i, 1 );
}
}
} /* remove_immune_to() */
/**
* This method returns the current type(s) associated with the object.
* If this method returns a string then there is only one type for this
* object. If it returns a string then there is more than one
* type associated with an object. An example of something with more
* than one type is a skirt, which is a dress and a shirt at the
* same time.
* @return the current type of the item
* @see set_type()
*/
string query_type() {
return type;
} /* query_type() */
/** @ignore yes */
private void log_bad_type( mixed type ) {
string word, str;
if ( !clonep( this_object() ) ) {
return;
}
word = (string)this_object()->query_property( "virtual name" );
if ( word ) {
str = sprintf( "BAD_TYPE %s (%s) = %O\n", word,
(string)this_object()->query_short(), type );
} else {
str = sprintf( "BAD_TYPE %s (%s) = %O\n", file_name(),
(string)this_object()->query_short(), type );
}
if ( this_player()) {
write(str);
}
call_out("move", 2, "/room/broken");
} /* log_bad_type() */
/**
* This method sets the type(s) which are associated with the
* item. If the parameter is a string then a single type is associated
* with the item, if the parameter is an array then a list of types
* is associated with the object. If any of these types are not
* legal and error message will be produced.
* @param word the new type(s) to set for the object
* @see query_type()
*/
void set_type( mixed word ) {
int i;
if(!stringp(word) && !pointerp(word))
return log_bad_type(word);
type = word;
if(stringp(word)) {
if(CLOTHING_HANDLER->query_equivilant_type(word))
type = CLOTHING_HANDLER->query_equivilant_type(word);
if(!CLOTHING_HANDLER->query_valid_type(word))
log_bad_type( word );
return;
}
for(i=0; i<sizeof(word); i++) {
if(CLOTHING_HANDLER->query_equivilant_type(word[i]))
type[i] = CLOTHING_HANDLER->query_equivilant_type(word[i]);
if (!CLOTHING_HANDLER->query_valid_type(word[i]))
log_bad_type( word );
return;
}
} /* set_type() */
/** @ignore yes */
int modify_value( int amount ) {
return ( amount * ( 10 + ( 90 * query_cond() ) / query_max_cond() ) ) / 100;
} /* modify_value() */
/** @ignore yes */
void player_wear() {
if ( !environment() ) {
return;
}
environment()->wear_armour( this_object() );
} /* player_wear() */
/** @ignore yes */
void break_me() {
if ( !worn_by ) {
return condition::break_me();
}
tell_object( worn_by, "%^RED%^$C$"+ (string)this_object()->the_short() +
" breaks!%^RESET%^\n" );
tell_room( environment( worn_by ), (string)worn_by->the_short() +"'s "+
this_object()->short( 0 ) +" breaks!\n", worn_by );
worn_by->remove_armour( this_object() );
if((int)this_object()->move("/room/rubbish") != MOVE_OK)
move_object("/room/rubbish");
} /* break_me() */
/** @ignore yes */
mixed *stats() {
int i;
string *stuff;
stuff = condition::stats() +
({
({ "type", type }),
});
if ( sizeof( wear_effects ) ) {
for ( i = 0; i < sizeof( wear_effects ); i++ ) {
stuff += ({ ({ "wear effect", wear_effects[ i ] }) });
}
}
for ( i = 0; i < sizeof( immune_to ); i++ ) {
stuff += ({ ({ "immune to", immune_to[ i ] }) });
}
if (worn_by) {
stuff += ({ ({ "worn by", worn_by->short() }) });
}
return stuff;
} /* stats() */
/** @ignore yes */
mapping query_static_auto_load() {
return ([
"condition" : condition::query_static_auto_load(),
"type" : type,
"wear remove func" : wear_remove_func
]);
} /* query_static_auto_load() */
/** @ignore yes */
mapping query_dynamic_auto_load() {
return ([
"condition" : condition::query_dynamic_auto_load(),
"wear effects" : wear_effects,
"immune" : immune_to,
"worn" : ( worn_by != 0 )
]);
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_static_arg( mapping map ) {
if ( map[ "type" ] )
type = map[ "type" ];
if ( map[ "wear remove func" ] )
wear_remove_func = map[ "wear remove func" ];
if ( !undefinedp( map[ "condition" ] ) ) {
condition::init_static_arg( map[ "condition" ] );
}
#ifdef AFTER_1999_I_BELIEVE
else { /* if you read ths and it's 1999, remove this crap
* and only keep the call above :)
*/
if ( !undefinedp( map[ "max cond" ] ) )
max_cond = map[ "max cond" ];
if ( !undefinedp( map[ "damage chance" ] ) )
damage_chance = map[ "damage chance" ];
}
#endif
} /* init_static_arg() */
/** @ignore yes */
void init_dynamic_arg( mapping map, object ) {
if ( map[ "effect" ] )
wear_effects = ({ map[ "effect" ] });
if ( pointerp( map[ "wear effects" ] ) )
wear_effects = map[ "wear effects" ];
if ( map[ "immune" ] )
immune_to = map[ "immune" ];
if ( map[ "worn" ] )
call_out( "player_wear", 0 );
if ( !undefinedp( map[ "condition" ] ) ) {
condition::init_dynamic_arg( map[ "condition" ] );
}
#ifdef AFTER_1999_I_BELIEVE
} else { /* if you read this and it's 1999, remove this crap
* and only keep the call above :) */
cond = map[ "cond" ];
lowest_cond = map[ "lowest cond" ];
}
#endif
} /* init_dynamic_arg() */
/**
* Unset the wear_remove func.
*/
void remove_wear_remove_func() {
wear_remove_func = ({ });
}