/**
* A skin inherit for use with the skin command and in scraping/tanning.
* @author Sandoz, 08th September 2001.
*/
#include <bit.h>
#include <skin.h>
#define WEIGHT_SIZE_DIV 3
inherit OBJECT_OBJ;
private int decay, gender, tanned, scraped, hair_lost;
private string race, skin_type;
int query_scraped();
int query_softness();
int query_tanned();
int query_no_hair();
int query_hair_left();
int query_amount_scraped();
string query_size_string();
string query_gender_string();
string query_softness_string();
string query_scrape_string();
string query_preferred_item();
/** @ignore yes */
void create() {
::create();
race = "default";
skin_type = "skin";
add_extra_look(TO);
} /* create() */
/** @ignore yes */
int query_skin() { return 1; }
/** @ignore yes */
string upd_long() {
string str;
if( tanned && query_no_hair() ) {
str = "This is a $size$ piece of tanned $race$ skin that has been "
"scraped clean of all hair. It is $soft$ and would probably "
"be rather comfortable and look good if tailored into a $item$.";
} else if( tanned ) {
switch( query_hair_left() ) {
case 0..30:
str = "This is a $size$, $soft$, and somewhat worn and almost "
"hairless tanned $race$ $type$ - the result of poor "
"scraping and lack of tanning technique.";
break;
case 31..60:
str = "This $size$, $soft$, tanned $race$ $type$ appears to have "
"lost several larger patches of hair, though it would "
"probably still make itself useful if a $item$ was made "
"out of it.";
break;
case 61..90:
str = "This $size$, $soft$, tanned $race$ $type$ appears to have "
"lost some its the hair in places, although it would still "
"make itself useful if a $item$ was made out of it.";
break;
default:
str = "This $size$, $soft$, well tanned $race$ $type$ has most "
"of its hair left intact and looks rather warm, surely it "
"would make a great $item$.";
}
} else {
str = "This is a $size$ $type$ carefully cut from the corpse of "
"$who$. "+query_scrape_string()+".";
}
set_long( replace( str, ({ "$race$", race, "$type$", skin_type, "$who$",
( gender ? "a "+query_gender_string()+" "+race : add_a(race) ),
"$size$", query_size_string(), "$soft$", query_softness_string(),
"$item$", query_preferred_item() }) )+
"\n" );
} /* upd_long() */
/**
* This method returns a string description on how much of
* the skin has been scraped along with how much hair is left.
* @return the scraped description string
*/
string query_scrape_string() {
string hair;
switch( query_hair_left() ) {
case 0:
hair = "no hair left whatsoever";
break;
case 1..10:
hair = "a few patches of hair still intact";
break;
case 31..50:
hair = "several patches of hair intact";
break;
case 51..75:
hair = "a few patches of hair missing";
break;
case 76..95:
hair = "most of the hair still intact";
break;
default:
hair = "all of the hair nicely intact";
}
switch( query_amount_scraped() ) {
case 0..10:
return "It is mostly untouched with "+hair+", but could still "
"use quite a bit of scraping to make anything useful out of it";
case 11..40:
return "It has "+hair+", but could still use more scraping to make "
"anything useful out of it";
case 41..70:
return "It has "+hair+", but could still use a bit more scraping "
"to make it to anything useful";
case 71..99:
return "It has "+hair+", but could still use a tiny bit of scraping "
"before it is ready to be tanned";
default:
return "It has "+hair+" and has been scraped completely clean "
"of the grain layer, just waiting to be tanned";
}
} /* query_scraped_string() */
/**
* This method returns the size string of the skin,
* calculated from the weight of the skin.
* @return the size of skin as a string, calculated from the
* weight
*/
string query_size_string() {
int tmp;
tmp = ::query_weight();
if( ( tmp /= WEIGHT_SIZE_DIV ) < 1 )
tmp = 1;
switch(tmp) {
case 0..4:
return "tiny";
case 5..10:
return "small";
case 11..20:
return "fairly small";
case 21..40:
return "medium sized";
case 41..80:
return "fairly large";
case 81..160:
return "large";
default:
return "huge";
}
} /* query_size_string() */
/**
* This method returns the gender string of the pelt.
* This will be either male, female or neuter.
* @return the gender string
*/
string query_gender_string() {
switch( gender ) {
case 1: return "male";
case 2: return "female";
default: return "neuter";
}
} /* query_gender_string() */
/**
* This method returns the gender associated with the skin.
* @return the gender associated with the skin
*/
int query_gender() { return gender; }
/**
* This method queries the race of the skin.
* @return the race of the skin
*/
string query_race() { return race; }
/**
* This method returns the skin type - pelt, fur etc.
* @return the skin type
*/
string query_skin_type() { return skin_type; }
/**
* This method sets the skin type.
* @param _race the race of the creature the skin came off from
* @param _type the type of skin - pelt, fur, scales etc.
* @param _gender the gender of the creature the skin came off from
* @param _decay the current decay level of the skin
*/
void setup_skin( string _race, string _type, int _gender, int _decay ) {
if( undefinedp( SKIN_TYPES[_type] ) )
skin_type = "skin";
else
skin_type = _type;
race = _race;
gender = _gender;
if( _decay ) {
decay = _decay;
} else {
decay = 200;
}
set_name( skin_type );
set_short( race+" "+skin_type );
upd_long();
add_adjective( race );
BIT_CONTROLLER->add_bit(TO);
} /* setup_skin() */
/**
* This method returns the current decay level of the skin
* @return the current decay level
*/
int query_decay() { return decay; }
/**
* This method is called by the bits controller to do the actual
* decaying of the skin.
* @return 1 if it still exists, 0 if it has finished decaying
*/
int do_decay() {
int rate;
if( tanned ) {
BIT_CONTROLLER->remove_bit(TO);
decay = 0;
return 0;
}
if( !ENV(TO) ) {
move( "/room/rubbish" );
return 0;
}
rate = 1;
if( !query_scraped() )
rate += 2;
rate += (int)ENV(TO)->query_property( "decay rate" );
if( rate > 0 ) {
decay -= rate;
}
if( decay < 0 ) {
if( interactive(ENV(TO)) )
tell_object( ENV(TO), poss_short()+" decays to dust.\n");
move( "/room/rubbish" );
return 0;
}
upd_long();
return 1;
} /* do_decay() */
/** @ignore yes */
int query_weight() {
int base;
float weight;
weight = ( ( weight = ::query_weight() ) < 1 ? 1 : weight );
base = weight / ( query_tanned() ? 4 : 3 );
base = ( base < 1 ? 1 : base );
weight -= base;
weight = ( weight < 1 ? 1 : weight );
weight /= 200;
return to_int( base + weight * query_hair_left() +
weight * ( 100 - query_amount_scraped() ) );
} /* query_weight() */
/**
* This method returns the percentual softness of the skin.
* @return the softness percentage
*/
int query_softness() {
int tmp;
if( !tmp = SKIN_TYPES[skin_type][S_TAN] )
return 0;
return 100 - 100 * ( tmp - tanned ) / tmp;
} /* query_softness() */
/**
* This method returns the softness of the skin in a string format.
* @return the softness of the skin
*/
string query_softness_string() {
switch( query_softness() ) {
case 0..20:
return "quite hard";
case 21..40:
return "fairly hard";
case 41..60:
return "not too soft";
case 61..80:
return "fairly soft";
case 81..90:
return "quite soft";
default:
return "extremely soft";
}
} /* query_softness_string() */
/**
* This method returns the preferred cloting item to be
* made out of the skin based on its softness.
* @return the preferred clothing item
*/
string query_preferred_item() {
string ret;
switch( query_softness() ) {
case 0..20:
ret = "breastplate";
break;
case 21..40:
ret = "backpack";
break;
case 41..60:
ret = "pair of shoes";
break;
case 61..80:
ret = "hat";
break;
case 81..90:
ret = "jacket";
break;
default:
ret = "pair of gloves";
}
return ret + " or something similar";
} /* query_preferred_item() */
/**
* This method returns if the skin is tanned or not.
* @return 1 if the skin is tanned, 0 if not tanned
*/
int query_tanned() { return !( SKIN_TYPES[skin_type][S_TAN] - tanned ); }
/**
* This method is called when the skin is being tanned.
* It stops the decay of the skin and changes its short
* and extra look.
* @return 1 if the tanning was successful, 0 if the skin
* cannot be tanned or has already been tanned
*/
int do_tan() {
if( query_tanned() )
return 0;
/* skin will lose all hair with tanning */
if( skin_type == "skin" )
hair_lost = SKIN_TYPES[skin_type][S_HAIR];
remove_adjective("scraped");
add_adjective("tanned");
if( query_no_hair() && skin_type != "skin" ) {
set_name("leather");
call_out( (: set_short("piece of tanned leather") :), 3 );
remove_plural( pluralize(skin_type) );
add_plural("leathers");
add_adjective("piece of");
set_material("leather");
} else {
call_out( (: set_short("tanned "+race+" "+skin_type ) :), 3 );
}
BIT_CONTROLLER->remove_bit(TO);
tanned++;
decay = 0;
upd_long();
return 1;
} /* do_tan() */
/**
* This methods queries the max amount of hair this type of
* skin can have.
* @return the max amount hair the skin can have
*/
int query_max_hair() { return SKIN_TYPES[skin_type][S_HAIR]; }
/**
* This methods queries the amount of hair that has been
* scraped off or otherwise lost.
* @return the amount of hair lost
*/
int query_hair_lost() { return hair_lost; }
/**
* This methods queries the percentual amount of hair that is left.
* @return the percentual amount of hair left
*/
int query_hair_left() {
int tmp;
if( !tmp = query_max_hair() )
return 0;
return 100 * ( tmp - hair_lost ) / tmp;
} /* query_hair_left() */
/**
* This method queries if the skin has any hair left or not.
* @return 1 if the skin has some hair left, 0 if there is no
* hair left
*/
int query_no_hair() { return !( query_max_hair() - hair_lost ); }
/**
* This method queries if the skin has been successfully scraped.
* @return 1 if the skin has been successfully scraped, 0 if not
*/
int query_scraped() { return !( SKIN_TYPES[skin_type][S_SCRAPE] - scraped ); }
/**
* This method queries how much of the skin has been
* scraped, percentually.
* @return the amount of skin that has been scraped
*/
int query_amount_scraped() {
int tmp;
if( !tmp = SKIN_TYPES[skin_type][S_SCRAPE] )
return 0;
return 100 - 100 * ( tmp - scraped ) / tmp;
} /* query_amount_scraped() */
/**
* This method is called when the skin is being scraped.
* @return 1 if the scraping was successful, 0 if the skin
* has already been scraped
*/
int do_scrape( int _hair ) {
if( query_tanned() || ( query_scraped() &&
( _hair && ( !query_max_hair() || query_no_hair() ) ) ) )
return 0;
/* scrape off some hair */
if( _hair && !query_no_hair() ) {
hair_lost++;
}
/* scrape some more */
if( !query_scraped() )
scraped++;
/* scraped, fix the desc */
if( query_scraped() ) {
add_adjective("scraped");
call_out( (: set_short( "scraped "+race+" "+skin_type ) :), 3 );
}
upd_long();
return 1;
} /* do_scrape() */
/** @ignore yes */
void dest_me() {
BIT_CONTROLLER->remove_bit(TO);
::dest_me();
} /* dest_me() */
/** @ignore yes */
mapping query_dynamic_auto_load() {
mapping map;
if( !query_name() || query_name() == "object" )
return 0;
map = ([ "::" : ::query_dynamic_auto_load() ]);
if( gender )
map["gender"] = gender;
if( race )
map["race"] = race;
if( skin_type )
map["skin type"] = skin_type;
if( decay )
map["decay"] = decay;
if( tanned )
map["tanned"] = tanned;
if( scraped )
map["scraped"] = scraped;
if( hair_lost )
map["hair lost"] = hair_lost;
return map;
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_dynamic_arg( mapping map ) {
if( map["::"] )
::init_dynamic_arg( map["::"] );
if( map["gender"] )
gender = map["gender"];
if( map["race"] )
race = map["race"];
if( map["skin type"] )
skin_type = map["skin type"];
if( map["decay"] )
decay = map["decay"];
if( map["tanned"] )
tanned = map["tanned"];
if( map["scraped"] )
scraped = map["scraped"];
if( map["hair lost"] )
hair_lost = map["hair lost"];
BIT_CONTROLLER->add_bit(TO);
} /* init_dynamic_arg() */
/** @ignore yes */
mapping int_query_static_auto_load() {
return ([ "::" : ::int_query_static_auto_load() ]);
} /* int_query_static_auto_load() */
/** @ignore yes */
mapping query_static_auto_load() {
if( !query_name() || query_name() == "object" )
return 0;
if( file_name( TO )[ 0 .. 13 ] == "/obj/misc/skin" )
return int_query_static_auto_load();
return 0;
} /* query_static_auto_load() */
/** @ignore yes */
void init_static_arg( mapping map ) {
if( !mappingp( map ) )
return;
if( map["::"] )
::init_static_arg( map["::"] );
} /* init_static_arg() */
/** @ignore yes */
mixed *stats() {
mixed tmp;
tmp = ::stats();
tmp += ({
({ "gender", query_gender_string() }),
({ "race", race }),
({ "skin type", skin_type }),
({ "size", query_size_string() }),
({ "decay", decay }),
({ "tanned", query_tanned() }),
({ "softness", query_softness() }),
({ "scraped", query_scraped() }),
({ "amount scraped", query_amount_scraped() }),
({ "max hair", query_max_hair() }),
});
if( query_no_hair() )
return tmp + ({ ({ "no hair", query_no_hair() }) });
else
return tmp + ({ ({ "hair lost", hair_lost }),
({ "hair left", query_hair_left() }),
});
} /* stats() */
/** @ignore yes */
string extra_look() {
if( !tanned )
switch( decay ) {
case 0..10:
return "It is completely rotten.\n";
break;
case 11..50:
return "It is fairly rotten.\n";
break;
case 51..100:
return "It is somewhat decayed.\n";
break;
case 101..150:
return "It has started to decay in places.\n";
break;
default:
return "It looks quite fresh.\n";
}
} /* extra_look() */