/**
* 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>
string *immune_to, *wear_effects;
mixed type, *wear_remove_func;
nosave object worn_by;
void create() {
condition::create();
set_damage_chance(25);
immune_to = ({"cold", "sound", "gas", "mental"});
wear_effects = ({ });
} /* 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 ) {
if( !dark )
return cond_string();
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 || ({ }); }
/**
* 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:
* If the second argument is 0, then the item is being worn,
* and the first argument will be the person about to wear the item.
* If the second argument is 1, then the item is being removed,
* and the first argument will be the person about to remove the item.
* <p>
* NOTE: Do NOT use this_player() in this function, because it is not
* correct sometimes.
* @example
* inherit "/std/basic/wearable";
*
* void setup() {
* ...
* set_wear_remove_func( base_name(TO), "do_fluff");
* ...
* } /\* setup() *\/
*
* void do_fluff( object ob, int removed ) {
* if( removed ) {
* tell_object( ob, the_short()+" is being removed.\n");
* } else {
* tell_object( ob, 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() { return 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; }
/**
* 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.
* They will only be removed if the effect has the
* person_removing_item() function in it.
* @param effect the effect to add
* @see query_wear_effects()
* @see set_wear_effects()
* @see person_removing_item()
*/
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; }
/**
* 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 ) {
string wear_eff;
/* Do nothing if we are already worn by them. */
if( thing == worn_by )
return 1;
/* First remove any possible concealment off us */
TO->remove_hide_invis("concealed");
/* If there is a move function, then call it. */
if( wear_remove_func ) {
if( worn_by )
call_other( wear_remove_func[0], wear_remove_func[1],
worn_by, 1 );
if( thing )
call_other( wear_remove_func[0], wear_remove_func[1],
thing, 0 );
}
/* If there are some wear effects, set them up or remove them. */
if( sizeof( wear_effects ) ) {
foreach( wear_eff in wear_effects ) {
if( worn_by )
worn_by->taken_off( TO, wear_eff );
if( thing )
thing->add_effect( wear_eff, TO );
else
wear_eff->person_removing_item( TO, worn_by );
}
}
/*
* Call the functions on the object doing the wearing to remove or add
* the item.
*/
if( worn_by )
worn_by->now_removed( TO );
if( thing )
thing->now_worn( TO );
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; }
/**
* 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 ) {
string tmp;
if( pointerp( args ) )
foreach( tmp in args )
add_immune_to( tmp );
else if( stringp( args ) && 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 ) {
string tmp;
if( pointerp( args ) )
foreach( tmp in args )
remove_immune_to( tmp );
else if( stringp( args ) )
immune_to -= ({ args });
} /* 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()
*/
mixed query_type() { return type; }
/** @ignore yes */
private void log_bad_type( mixed bad_type ) {
string str;
if( !clonep(TO) )
return;
str = sprintf("BAD_TYPE %s (%s) = %O\n", file_name(),
TO->short(), bad_type );
log_file("BAD_TYPE", "%s", str );
/*
* This is *not* a spam. If you are creating a piece of
* clothing/armour I want it to tell you immediately that you have
* a bad type instead of it ending up in the game and then being
* logged a lot.
*/
if( TP && creatorp(TP) )
write(str);
} /* 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 ) {
if( !stringp( word ) && !pointerp( word ) )
return log_bad_type( word );
type = word;
if( stringp( word ) ) {
if( !CLOTHING_HANDLER->query_valid_type(word) )
log_bad_type( word );
return;
}
foreach( word in word ) {
if( !CLOTHING_HANDLER->query_valid_type(word) )
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( ENV(TO) )
ENV(TO)->wear_armour(TO);
} /* player_wear() */
/** @ignore yes */
void break_me() {
object env;
env = ENV(TO);
if( living(env) ) {
if( ENV(env) ) {
tell_room( ENV(env), env->poss_short()+" "+
TO->short()+" $V$0=breaks,break$V$!\n");
} else {
tell_object( env, env->poss_short()+" "+
TO->short()+" $V$0=breaks,break$V$!\n");
}
} else {
tell_room( env, TO->the_short()+" $V$0=breaks,break$V$!\n");
}
if( worn_by )
worn_by->remove_armour( TO );
condition::break_me();
} /* break_me() */
/** @ignore yes */
mixed stats() {
string *stuff, tmp;
stuff = condition::stats() +
({ ({ "type", ( pointerp(type) ? implode( type, ", ") : type ) }), });
foreach( tmp in wear_effects )
stuff += ({ ({"wear effect", tmp }) });
foreach( tmp in immune_to )
stuff += ({ ({"immune to", tmp }) });
return stuff;
} /* stats() */
/** @ignore yes */
mapping query_static_auto_load() {
mapping map;
map = ([
"condition" : condition::query_static_auto_load(),
"type" : type,
]);
if( sizeof(wear_remove_func) )
map["wear remove func"] = wear_remove_func;
return map;
} /* query_static_auto_load() */
/** @ignore yes */
mapping query_dynamic_auto_load() {
mapping map;
map = ([
"condition" : condition::query_dynamic_auto_load(),
"immune" : immune_to,
]);
if( worn_by )
map["worn"] = 1;
if( sizeof(wear_effects) )
map["wear effects"] = wear_effects;
return map;
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_static_arg( mapping map ) {
if( map["type"] )
type = map["type"];
if( pointerp( map["wear remove func"] ) &&
sizeof( map["wear remove func"] ) )
wear_remove_func = map["wear remove func"];
if( !undefinedp( map[ "condition" ] ) )
condition::init_static_arg( map["condition"] );
} /* init_static_arg() */
/** @ignore yes */
void init_dynamic_arg( mapping map ) {
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"] );
} /* init_dynamic_arg() */