/* /lib/body.c * from the Dead Souls LPC Library * handles information regarding bodies as well as events which * affect them * created by Descartes of Borg 950121 * Version: @(#) body.c 1.24@(#) */ #include <lib.h> #include <config.h> #include <rooms.h> #include <daemons.h> #include <function.h> #include <medium.h> #include <position.h> #include <armor_types.h> #include <respiration_types.h> #include <terrain_types.h> #include <damage_types.h> #include <magic_protection.h> #include "include/body.h" #ifndef AUTO_ADVANCE #define AUTO_ADVANCE 0 #endif inherit LIB_POSITION; inherit LIB_UNDEAD; inherit LIB_CRAWL; inherit LIB_FLY; inherit LIB_SWIM; inherit LIB_MOUNT; inherit LIB_BODY_MASS; inherit LIB_PERSIST; #define COLLAPSE_AT 10.0 #ifndef SEVERABLE_LIMBS #define SEVERABLE_LIMBS 1 #endif private int HealthPoints, MagicPoints, ExperiencePoints; private int melee, godmode; private int Alcohol, Caffeine, Food, Drink, Poison, Sleeping, DeathEvents; private float StaminaPoints; private string Torso, Biter, keepalive; private mapping Fingers, Limbs, MissingLimbs; private static int Dying, LastHeal, Encumbrance; private static function Protect; private static mapping WornItems; private static class MagicProtection *Protection; static private int HeartModifier = 0; private static string PoliticalParty, BodyComposition; private static int Pacifist, rifleshot_wounds, gunshot_wounds, globalint1; private static int Size, BodyType; private int rifleshot_wounds, gunshot_wounds; string *ExtraChannels; mixed Agent; string GetRace(); static void create(){ PoliticalParty = "UNDECIDED"; rifleshot_wounds = 0; gunshot_wounds = 0; DeathEvents = 0; NewBody(0); Protect = 0; WornItems = ([]); Limbs = ([]); Food = Drink = 100; Alcohol = Caffeine = 0; HealthPoints = MagicPoints = 50; StaminaPoints = 50.0; ExperiencePoints = 50; Dying = 0; LastHeal = time(); Protection = ({}); ExtraChannels = ({}); } varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3){ //This function will hopefully get overridden where appropriate. write(capitalize(this_object()->GetShort())+" isn't buying anything from you."); return 1; } int GetMass(){ return body_mass::GetBodyMass(); } int GetSize(){ int size = RACES_D->GetRaceSize(GetRace()); if(Size) return Size; return size; } int GetBodyType(){ int body_type = RACES_D->GetRaceBodyType(GetRace()); if(BodyType) return BodyType; return body_type; } int SetMass(int i){ return body_mass::SetBodyMass(i); } int SetSize(int i){ return Size = i; } int SetBodyType(int i){ return BodyType = i; } int GetEncumbrance(){ int encumbrance = 0; object *stuff = filter(all_inventory(this_object()), (: !($1->GetWorn()) :) ); if(!(ENABLE_ENCUMBRANCE) || inherits(LIB_NPC,this_object()) ) return encumbrance; if(sizeof(stuff)) foreach(object item in stuff) encumbrance += (item->GetMass())/2; if(sizeof(stuff)) encumbrance += sizeof(stuff); return encumbrance; } string SetBodyComposition(string str){ if(!str) return ""; else BodyComposition = str; return BodyComposition; } string GetBodyComposition(){ return BodyComposition; } int GetPacifist(){ return Pacifist; } int SetPacifist(int i){ if(!i) Pacifist = 0; else Pacifist = 1; return Pacifist; } int SetCanBite(int i){ if(i) Biter = "yes"; else Biter = "no"; return i; } int GetCanBite(){ if(sizeof(Biter)){ if(Biter == "yes") return 1; else return 0; } else return RACES_D->GetBitingRace(this_object()->GetRace()); } string *AddExtraChannels(string *chans){ foreach(string chan in chans){ if(member_array(chan,this_player()->GetChannels()) == -1){ ExtraChannels += ({ chan }); } } return ExtraChannels; } string *RemoveExtraChannels(string *chans){ foreach(string chan in chans){ if(member_array(chan,this_player()->GetChannels()) != -1){ ExtraChannels -= ({ chan }); } } return ExtraChannels; } string *GetExtraChannels(){ return ExtraChannels; } string *SetExtraChannels(string *chans){ ExtraChannels = chans; return ExtraChannels; } mixed direct_turn_liv(){ if( GetUndead() ){ return 1; } else { return "You cannot turn the living!"; } } void eventCheckEnvironment(){ object env = environment(); int i; int restype; float j,k; if(!userp(this_object()) && !clonep(this_object())) return; restype = this_object()->GetRespiration(); j = percent(GetHealthPoints(), GetMaxHealthPoints()); k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ this_object()->eventCollapse(); } if(RACES_D->GetLimblessRace(this_object()->GetRace()) && this_object()->GetPosition() == POSITION_STANDING){ this_object()->SetPosition(POSITION_FLOATING); } if(!env) return; if(env->GetMedium() == MEDIUM_AIR && this_object()->GetPosition() != POSITION_FLYING){ if(!(this_object()->CanFly())){ this_object()->SetPosition(POSITION_FLOATING); call_out("eventFall", 1); } else this_object()->eventFly(); } else if((env->GetTerrainType() & (T_SEAFLOOR | T_SPACE | T_UNDERWATER)) && this_object()->GetPosition() == POSITION_FLYING){ this_object()->SetPosition(POSITION_FLOATING); } else if((env->GetMedium() == MEDIUM_WATER || env->GetMedium() == MEDIUM_SURFACE) && this_object()->GetPosition() != POSITION_SWIMMING){ if(!(this_object()->GetPosition() == POSITION_FLYING && environment()->GetMedium() == MEDIUM_SURFACE)){ if(!(environment()->GetTerrainType() & (T_SEAFLOOR)) && this_object()->CanSwim()){ if(this_object()->GetPosition() != POSITION_FLOATING){ this_object()->eventSwim(); } } else if(!(environment()->GetTerrainType() & (T_SEAFLOOR))){ this_object()->SetPosition(POSITION_FLOATING); call_out("eventSink", 1); } } } if(env->GetMedium() == MEDIUM_SPACE){ this_object()->SetPosition(POSITION_FLOATING); if(restype != R_VACUUM){ if(!this_object()->CanBreathe()){ eventPrint("You are asphyxiating."); this_object()->eventReceiveDamage("Outer space", ANOXIA, 200, 1); } } } else if(env->GetMedium() == MEDIUM_WATER){ if(restype != R_VACUUM && restype != R_WATER){ if(!this_object()->CanBreathe()){ eventPrint("You are drowning."); this_object()->eventReceiveDamage("Water", ANOXIA, 100, 1); } } } else if(restype == R_WATER && env->GetMedium() != MEDIUM_WATER){ if(!this_object()->CanBreathe()){ eventPrint("You are asphyxiating."); this_object()->eventReceiveDamage("Air", ANOXIA, 100, 1); } } if( (i = env->GetPoisonGas()) > 0 ){ if( GetResistance(GAS) != "immune" ){ eventPrint("You choke on the poisonous gases."); this_object()->eventReceiveDamage("Poison gas", GAS, i, 1); } } } static void heart_beat(){ int i; undead::heart_beat(); if(!GetDying()){ if( i = sizeof(Protection) ){ while(i--) if( Protection[i]->time && (--Protection[i]->time < 1) ) RemoveMagicProtection(i); } eventCheckEnvironment(); eventCheckHealing(); if(!stringp(hobbled(this_player()))){ this_object()->eventCollapse(); } } } void eventReconnect(){ LastHeal = time(); } void ParseHook(string str){ parse_sentence(str); } /************ /lib/body.c Modal Methods Section ************/ mixed CanRemoveItem(object ob){ return 1; } /************ /lib/body.c Events Section ************/ private void checkCollapse(){ float h = percent(GetHealthPoints(), GetMaxHealthPoints()); float i = percent(GetStaminaPoints(), GetMaxStaminaPoints()); if( h < COLLAPSE_AT || i < COLLAPSE_AT ){ SetParalyzed(3, (: checkCollapse :)); return; } this_object()->eventPrint("You feel some strength returning."); } varargs int eventCollapse(int noparalyze){ int position = GetPosition(); int medium; if(environment()) medium = environment()->GetMedium(); if(!this_object() || !environment()) return 0; foreach(object ob in all_inventory(environment())){ if(inherits(LIB_CHAIR,ob) || inherits(LIB_BED,ob) ){ ob->eventReleaseStand(this_object()); } } if(medium == MEDIUM_LAND){ if( position == POSITION_LYING ){ return 1; } send_messages("collapse", "$agent_name $agent_verb to the ground.", this_object(), 0, environment()); SetPosition(POSITION_LYING); if(!noparalyze) SetParalyzed(3, (: checkCollapse :)); return 1; } if( position == POSITION_FLOATING ){ return 1; } send_messages("go", "$agent_name $agent_verb limp.", this_object(), 0, environment()); SetPosition(POSITION_FLOATING); if(!noparalyze) SetParalyzed(3, (: checkCollapse :)); return 1; } void eventCheckHealing(){ int x, y, lead; object dude; dude = this_object(); lead = dude->GetLead(); if(lead && !present("firearms_wound", dude)){ object wound = new(LIB_WOUND); if(wound) wound->eventMove(dude); } if(interactive() && !environment()){ this_object()->eventMove(ROOM_START); } //This resets the parser counter. this_object()->DoneTrying(); if(HealthPoints < 1 && !this_object()->GetDying()){ this_object()->SetDying(1); this_object()->eventDie(previous_object()); return; } if(AUTO_ADVANCE && interactive() && !this_object()->GetDying()){ PLAYERS_D->CheckAdvance(this_object()); } x = GetHeartRate() * 10; if(dude->GetSleeping() > 0 && dude->GetPosition() != POSITION_LYING && dude->GetPosition() != POSITION_SITTING){ dude->eventCollapse(); } if(dude->GetInCombat()){ if(dude->GetInvis()) dude->SetInvis(0); if(!interactive(dude) && !RACES_D->GetLimblessRace(dude->GetRace())){ dude->SetAutoStand(1); } } if(!inherits(LIB_VEHICLE,this_object())){ if( (y = time() - LastHeal) >= x ){ LastHeal = time(); do { eventCompleteHeal(GetHealRate()); } while( (y = y - x) >= x ); if( Alcohol > 0 ){ Alcohol--; if( !Alcohol ){ message("my_action", "You are left with a pounding headache.", this_object()); AddHealthPoints(-(random(3) + 1)); } else if( !GetSleeping() && random(100) < 8 ){ string verb, adv; switch(random(5)){ case 0: verb = "burp"; adv = "rudely"; break; case 1: verb = "look"; adv = "ill"; break; case 2: verb = "hiccup"; adv = "loudly"; break; case 3: verb = "stumble"; adv = "clumsily"; break; case 4: verb = "appear"; adv = "drunk"; break; } message("my_action", "You " + verb + " " + adv + ".", this_object()); message("other_action", GetName() + " " + pluralize(verb) + " " + adv + ".", environment(), ({ this_object() })); } } if( Sleeping > 0 ){ Sleeping--; if( !Sleeping || dude->GetInCombat() ){ Sleeping = 0; message("my_action", "You wake up!", this_object()); message("other_action", GetName() + " wakes up from " + possessive(this_object()) + " deep sleep.", environment(this_object()), ({ this_object() })); } else if( random(100) < 8 ){ message("my_action", "You snore.", this_object()); message("other_action", (string)this_player()->GetName() + " snores loudly.", environment(this_object()), ({ this_object() })); } } if( Caffeine > 0 ) Caffeine--; if( Food > 0 ) Food--; if( Drink > 0 ) Drink--; } } } void eventCompleteHeal(int x){ eventHealDamage(x, 1, GetLimbs()); AddMagicPoints(x + 1); AddStaminaPoints(x); } mixed eventFall(){ object env = environment(); object *riders; string dest; if( !env ){ return 0; } if( GetPosition() == POSITION_LYING ){ return 0; } if( env->GetMedium() == MEDIUM_AIR ){ return position::eventFall(); } dest = env->GetGround(); if(!dest){ int p; int was_undead = GetUndead(); eventMove(dest); this_object()->eventCollapse(); foreach(string limb in GetLimbs()){ int hp = GetHealthPoints(limb); p = random(hp); this_object()->eventReceiveDamage("Deceleration sickness", BLUNT, p, 0, ({ limb })); if( Dying || (was_undead != GetUndead()) ){ break; } } riders = get_livings(this_object()); if(sizeof(riders)){ foreach(object passenger in riders){ passenger->eventReceiveDamage("Deceleration sickness", BLUNT, p, 0, ({ passenger->GetTorso() })); } } } } /* varargs int eventHealDamage(int x, int internal, mixed limbs) * int x - amount of damage being healed, negatives illegal (required) * int internal - internal damage flag (optional) * mixed limbs - limb or limbs affected by the heal event (optional) * * defaults * internal defaults to 0 * limbs defaults to 0 * * description * this event is triggered whenever something performs a healing action * on the body * * if the internal flag is set then overall health is healed. * if limbs are specified then the specified limbs are healed. * if the internal flag is NOT set and NO limbs are specified (default) * then both overall health as well as the health of all limbs are healed. * * returns the actual amount of healing done or -1 if an error occurs */ varargs int eventHealDamage(int x, int internal, mixed limbs){ if(!limbs && !internal){ limbs = GetLimbs(); internal = 1; } else if(stringp(limbs)){ limbs = ({ limbs }); } if(!limbs){ limbs = ({}); } if( !arrayp(limbs)){ error("Bad argument 3 to eventHealDamage().\n"); } if(internal){ AddHealthPoints(x); } map(limbs, (: AddHealthPoints($(x), $1) :)); return x; } /* varargs int eventReceiveDamage(mixed agent, int type, int x, * int internal, mixed limbs) * object agent - the thing responsible for this damage (required) * int type - the damage type(s) being done (required) * int x - the amount of damage being done, negatives illegal (required) * int internal - flag for internal or external damage (optional) * mixed limbs - limbs to which damage has been done (optional) * * defaults * internal defaults to 0 * limbs defaults to 0 * * description * handles sorting out damage events which happen to the body * It assumes some agent is acting as the cause of this event, an * agent being some sort of being as the cause of the event * the previous_object() is considered to be doing the actual damage * what does the damage is different than the agent in the sense * that a knife does damage and a living thing is the agent * can't get into more detail without getting philosophical, which is * beyond the scope of a comment * "x" amount of damage gets attempted, modified by varying things like * armor and natural resistence to this type of damage * the internal flag with no limbs specified means that the damage * is taken solely to the overall health * if the internal flag is set with limbs, the damage is both internal and * done to named limbs * if no internal flag is set and no limbs are specified, damage is done to * all limbs * if no internal flag is set and limbs are specified, then damage is done * only to the specified limbs * NOTE: internal damage is not modified by armor worn * * returns the average actual amount of damage done */ varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs){ string tmp = GetResistance(type); string agentname; int fp, basedam; if(agent && stringp(agent)){ agentname = agent; agent = 0; } if(objectp(agent)){ if(estatep(agent) && !estatep(this_object())) return 0; if(!estatep(agent) && estatep(this_object())) return 0; } basedam = x; if(godmode) x = 0; switch(tmp){ case "low": x = (3*x)/4; break; case "medium": x /= 2; break; case "high": x /= 4; break; case "immune": x = 0; break; } if( fp = functionp(Protect) ){ if( !(fp & FP_OWNER_DESTED) ){ function f; f = Protect; Protect = 0; x -= evaluate(f, this_object(), agent, type, x, limbs); } } x = eventCheckProtection(agent, type, x); if( !limbs ){ if( internal ){ AddHealthPoints(-x, 0, (agent || agentname)); return x; } else { limbs = GetLimbs(); } } else if( stringp(limbs) ){ limbs = ({ limbs }); } else if( !arrayp(limbs) ){ return -1; } if( internal ){ AddHealthPoints(-x, 0, (agent || agentname)); return x; } else { int i, y, maxi; y = 0; for(i=0, maxi = sizeof(limbs); i < maxi; i++){ object *obs; int j, z; z = x; if(!Limbs[limbs[i]]){ /* no limb, no damage */ y += z; continue; } if(!(j = sizeof(obs = GetWorn(limbs[i])))){ /* no armor */ y += z; /* add to total damage */ if( !AddHealthPoints(-z, limbs[i], (agent || agentname)) ){ call_out("RemoveLimb",0,limbs[i], (agent || agentname)); } continue; } while(j--){ int tmpdam; tmpdam = (int)obs[j]->eventReceiveDamage((agent || agentname), type, z, 0, limbs[i]); z -= tmpdam; if(z < 1){ } if(z < 1){ } else { y += z; if(!AddHealthPoints(-z, limbs[i], agent)){ call_out("RemoveLimb",0,limbs[i], (agent || agentname)); } } } y = y / (maxi ? maxi : 1); if( y ){ AddHealthPoints(-y, 0, (agent || agentname)); AddStaminaPoints(-y/2); } return y; } AddHealthPoints(-x, 0, agent); AddStaminaPoints(-x/2); if(HealthPoints < 1 && !this_object()->GetDying()){ this_object()->SetDying(1); call_out("eventDie", 0, (agent || agentname)); } return x; } } /* int eventCheckProtection(object agent, int type, int damage) * * agent : object doing the damage * type : damage type(s) * damage : original amount damage being done * * This function cycles through any magic protection found, reducing * damage accordingly. * * returns modified damage */ int eventCheckProtection(object agent, int type, int damage){ int i, y; if( !i = sizeof(Protection) ) return damage; while(i--){ int x; if( (type & Protection[i]->bits) != type ) continue; if( Protection[i]->absorb ){ if( (x = (Protection[i]->absorb - damage)) < 1 ){ x = Protection[i]->absorb; RemoveMagicProtection(i); damage -= x; if( damage < 1 ) return 0; continue; } Protection[i]->absorb -= damage; } else if( Protection[i]->protect ) x = (random(Protection[i]->protect / 2) + (Protection[i]->protect / 2)); else { RemoveMagicProtection(i); continue; } if( y = functionp(Protection[i]->hit) ){ if( y == FP_OWNER_DESTED ){ RemoveMagicProtection(i); continue; } else x = (int)evaluate(Protection[i]->hit, this_object(), agent, x, Protection[i]); } damage -= x; if( damage < 1 ) return 0; } return damage; } mixed eventReceiveThrow(object who, object what){ int x; if( what->GetClass() > 1 ){ int mod = who->GetSkillLevel("projectile attack") + who->GetStatLevel("strength"); x = what->eventStrike(this_object()) * 3; x = (x*mod)/100; if( what->GetWeaponType() != "projectile" ){ x = x/4; } x = this_object()->eventReceiveDamage(who, what->GetDamageType(), x, 0, GetRandomLimb("torso")); if( x > 0 ){ who->AddSkillPoints("projectile attack", x); } } else { x = 0; } if( x < 1 ){ environment()->eventPrint(GetName() + " catches " + possessive_noun(who->GetName()) + " " + what->GetKeyName() + ".", ({ this_object(), who })); eventPrint("You catch " + possessive_noun(who->GetName()) + " " + what->GetKeyName() + "."); who->eventPrint(GetName() + " catches your " + what->GetKeyName() + "."); } else { environment()->eventPrint(GetName() + " takes damage from " + possessive_noun(who->GetName()) + " " + what->GetKeyName() + ".", ({ this_object(), who })); eventPrint("You take damage from " + possessive_noun(who->GetName()) + " " + what->GetKeyName() + "."); who->eventPrint(GetName() + " takes damage from your " + what->GetKeyName() + "."); } what->eventMove(this_object()); return 1; } /* varargs int eventDie(mixed agent) * mixed agent - the agent responsible for the death (optional) * * description * Kills the owner of this body if not already dying * * returns true if the thing is dying */ varargs int eventDie(mixed agent){ int x; string killer, death_annc; object crime_scene; if(DeathEvents) return 1; DeathEvents = 1; this_object()->SetDying(0); if(agent && stringp(agent)) killer = agent; else { if(!agent || !objectp(agent)) killer = "UNKNOWN"; else killer = agent->GetName(); } if(RACES_D->GetNonMeatRace(GetRace())) death_annc = killer + " has destroyed "+ this_object()->GetName()+"."; else if(!this_object()->GetUndead()) death_annc = killer + " has slain "+ this_object()->GetName()+"."; else death_annc = killer + " has destroyed "+ this_object()->GetName()+"."; //tc("death_annc: "+death_annc,"white"); CHAT_D->eventSendChannel("SYSTEM","death",death_annc,0); if( Sleeping > 0 ) Sleeping = 0; if( agent && objectp(agent) ){ if( x ) agent->eventDestroyEnemy(this_object()); else agent->eventKillEnemy(this_object()); } crime_scene = environment(); if( crime_scene ){ object *obs; string *currs; object ob; string curr; int i; object *riders = GetRiders(); //I'd like to move the living body out first, but for now this //misfeature stays. if(riders && sizeof(riders)){ foreach(object rider in riders) eventBuck(rider); } if(GetRace() == "android" || GetRace() == "bot" || inherits(LIB_VEHICLE,this_object())) ob = new(LIB_BOT_CORPSE); else if(member_array(GetRace(), RACES_D->GetNonMeatRaces()) != -1){ ob = crime_scene; if(GetBodyComposition()){ ob = new(LIB_CLAY); ob->SetComposition(GetBodyComposition()); } } else { ob = new(LIB_CORPSE); ob->SetCorpse(this_object()); } if(ob != crime_scene) ob->eventMove(crime_scene); obs = filter(all_inventory(), (: !((int)$1->GetRetainOnDeath()) :)); i = sizeof(obs); obs->eventMove(ob); currs = (string *)this_object()->GetCurrencies() || ({}); foreach(curr in currs){ object pile; int amt; if( amt = (int)this_object()->GetCurrency(curr) ){ pile = new(LIB_PILE); pile->SetPile(curr, amt); pile->eventMove(ob); this_object()->AddCurrency(curr, -amt); } } } SetUndead(!(x = GetUndead())); evaluate( function(){ Dying = 0; }); flush_messages(); return 1; } /* int eventRemoveItem(object ob) * object ob - the item being removed * * Removes a worn or wielded item from the list * * returns 1 on success, 0 on failure */ int eventRemoveItem(object ob){ string limb; foreach(limb in keys(WornItems)){ if( !WornItems[limb] ) continue; if( member_array(ob, WornItems[limb]) != -1){ WornItems[limb] -= ({ ob }); } } return 1; } /* int eventWear(object ob, mixed limbs) * object ob - the item being worn (wielded) * mixed limbs - string or array of limbs on which it is being worn * * description * marks the limbs "limbs" as being protected by the armor "ob" * * returns 1 if successful, 0 if failure */ int eventWear(object ob, mixed limbs){ string limb,s1; string *target_limb; target_limb = ({}); if( stringp(limbs) ){ limbs = ({ limbs }); } if( CanWear(ob, limbs) != 1 ){ return 0; } #if 0 if(!inherits(LIB_WEAPON, ob)){ foreach(limb in limbs){ if(sscanf(limb,"%s foot",s1) || sscanf(limb,"%s hand",s1) ){ if(!sizeof(GetWorn(limb))) target_limb = ({ limb }); } } } #endif if(sizeof(target_limb) && sizeof(limbs) == 1) limbs = target_limb; foreach(limb in limbs){ if( !WornItems[limb] ) WornItems[limb] = ({ ob }); else WornItems[limb] += ({ ob }); } return 1; } string *GetEquippedLimbs(){ string *equipped_limbs = ({}); object *wornstuff = filter(all_inventory(this_object()), (: $1->GetWorn() :) ); foreach(object item in wornstuff){ equipped_limbs += item->GetWorn(); } return equipped_limbs; } /************ /lib/body.c Data manipulation functions *************/ void NewBody(string race){ if(!race) Limbs = ([ (Torso = "ooze") : ([ "parent" : 0, "children" : ({}), "health" : 50, "class" : 1, "armors" : 0 ]) ]); else Limbs = ([]); MissingLimbs = ([]); Fingers = ([]); } /* int CanWear(object armor, string *limbs) * object armor - the piece of armor being checked * string *limbs - the limbs on which the armor wants to be worn * a nested array indicates that just one of the included limbs * must be satisfied * * description * checks to see if a particular armor can be worn * * returns 1 if the armor can be worn on those limbs * returns 0 if the armor cannot be worn there for any reason * */ mixed CanWear(object ob, string *limbs){ string limb, verb_pr, verb_pt, short; int type, bad_types, i, maxi; if( !ob ) return 0; short = (string)ob->GetShort(); if( !(type = (int)ob->GetArmorType()) ) return capitalize(short) + " cannot be worn!"; if( type & A_WEAPON ){ verb_pr = "wield"; verb_pt = "wielded"; } else { verb_pr = "wear"; verb_pt = "worn"; } if( !limbs || !(maxi = sizeof(limbs)) ) return "Where should " + short + " be "+ verb_pt + "?"; if( (string *)ob->GetWorn() ) return "It is already being " + verb_pt + "."; // Verify that the the item can be worn on each limb specified by limbs. i = 0; foreach(limb in limbs){ // Nested arrays indicate that only one of the elements in the nested // array must be satisfied. Check for one valid limb, and replace the // nested array with the valid limb, if found. if( arrayp(limb) ){ string limb2; string validLimb = 0; int leastRings = -1; if(!sizeof(limb)) error("Bad limb specification to CanWear().\n"); // Iterate through the nested array. foreach(limb2 in limb){ string* wornItems; // The limb will be valid if: // o The body has the named limb capable of wearing the armor type. // o There are no armors of the same type on that limb, except // for rings, which can have up to GetFingers() of that type worn. if(!Limbs[limb2] || !(Limbs[limb2]["armors"] & type)) continue; wornItems = WornItems[limb2]; // If the item is a ring, attempt to distribute the rings evenly // across the available hands. if(type == A_RING){ int currentRings; if(!sizeof(wornItems)) currentRings = 0; else currentRings = sizeof(filter(wornItems, (:(int)$1->GetArmorType() == A_RING:))); if(currentRings >= leastRings && leastRings != -1) continue; leastRings = currentRings; if(currentRings >= GetFingers(limb2)) continue; } else if(wornItems){ object wornItem; int tmpType = 0; foreach(wornItem in wornItems) if(wornItem) tmpType |= (int)wornItem->GetArmorType(); if(tmpType & type) continue; } validLimb = limb2; } if(validLimb) limbs[i] = validLimb; else return "You cannot " + verb_pr + " that."; } else { if(!GetLimb(limb)){ string ret = "Try a different body part."; string *hands = GetWieldingLimbs(); if(type & A_RING && sizeof(hands)){ ret = "Try: wear " + ob->GetKeyName() + " on "+ hands[0]; } return ret; } globalint1 = Limbs[limb]["armors"]; if( !Limbs[limb] ) return "You have no " + limb + "."; if( !(globalint1 & type) ){ if( type & A_WEAPON ) return "You cannot wield with " + limb + "."; else return "You cannot wear " + short + " on your " + limb + "."; } } i++; } switch(type){ case A_RING: if(maxi != 1) return "You can only wear " + short + " on one limb."; if( !WornItems[limbs[0]] ) return 1; /* nothing there, ring ok */ /* count # worn rings */ i = sizeof(filter(WornItems[limbs[0]], (: (int)$1->GetArmorType() == A_RING :))); if(i >= GetFingers(limbs[0])) return "You are already wearing too many rings there."; else return 1; /* ok */ case A_GLOVE: if(maxi != 1) if( GetFingers(limbs[0]) > (int)ob->GetFingers() ){ return capitalize(short) + " does not seem to fit well on " "your " + limbs[0] + "."; } bad_types = A_GLOVE | A_LONG_GLOVE | A_SOCK | A_LONG_SOCK; break; case A_LONG_GLOVE: if(maxi != 2) return capitalize(short) + " should be worn on two limbs."; if( limbs[0] == Limbs[limbs[1]]["parent"] ){ /* which is hand? */ /* more fingers than this armor can stand */ if(GetFingers(limbs[1]) > (int)ob->GetFingers()) return capitalize(short) + " does not seem to fit well on " "your " + limbs[1] + "."; } else if(limbs[1] == Limbs[limbs[0]]["parent"]){ /* ok, first limb is hand, check it */ if(GetFingers(limbs[0]) > (int)ob->GetFingers()) return capitalize(short) + " does not seem to fit well on " "your " + limbs[1] + "."; } else return "Your " + limbs[0] + " is not connected to your " + limbs[1] + "."; bad_types = A_GLOVE | A_LONG_GLOVE; break; case A_BOOT: case A_SOCK: if(maxi != 1) capitalize(short) + " may only be worn on one limb."; if(type == A_SOCK) bad_types = A_SOCK | A_LONG_SOCK; else bad_types = A_BOOT | A_LONG_BOOT; break; case A_LONG_BOOT: case A_LONG_SOCK: if(maxi != 2) return capitalize(short) + " must be worn only on two limbs."; if(limbs[0] != Limbs[limbs[1]]["parent"] && limbs[1] != Limbs[limbs[0]]["parent"]) return "Your " + limbs[0] + " is not connected to your " + limbs[1] + "."; if(type == A_LONG_SOCK) bad_types = A_LONG_SOCK | A_SOCK; else bad_types = A_BOOT | A_LONG_BOOT; break; case A_HELMET: case A_VEST: case A_AMULET: case A_VISOR: case A_BELT: case A_COLLAR: if(maxi != 1) return capitalize(short) + " may only be worn on one limb."; bad_types = type; break; case A_PANTS: case A_SHIRT: bad_types = type; break; case A_CLOAK: bad_types = type; break; case A_SHIELD: bad_types = A_SHIELD | A_WEAPON; break; #if 0 foreach(limb in limbs){ object worn_item; int tmp = 0; if( !WornItems[limb] ) continue; /* no armors, no prob */ if( !Limbs[limb]["parent"] ) continue; /* torso ok for 2 */ foreach(worn_item in WornItems[limb]) { if( !worn_item ) continue; tmp |= (int)worn_item->GetArmorType(); } /* not gonna allow 2 shields or a shield and weapon here */ if( tmp & (A_SHIELD | A_WEAPON) ) return "You cannot wear " + short + " there right now."; } return 1; /* ok */ #endif case A_WEAPON: foreach(limb in limbs){ object worn_item; int tmp = 0; if( !WornItems[limb] ) continue; /* nothing there, ok */ foreach(worn_item in WornItems[limb]){ if( !worn_item ) continue; tmp += (int)worn_item->GetArmorType(); } /* again, not allowing 2 weapons or a shield and weapon */ if(tmp & (A_SHIELD | A_WEAPON)) return "You cannot wield " + short + " there right now."; } return 1; /* ok */ case A_ARMOR: case A_BODY_ARMOR: bad_types = A_ARMOR | A_BODY_ARMOR; break; case A_COLLAR: bad_types = A_COLLAR | A_AMULET; break; case A_CUSTOM: bad_types = A_CUSTOM; break; default: return 0; /* not any illegal stuff */ } foreach(limb in limbs){ object worn_item; int tmp = 0; if( !WornItems[limb] ) continue; /* no preventing types */ foreach( worn_item in WornItems[limb] ){ if( !worn_item ) continue; tmp |= (int)worn_item->GetArmorType(); } if(tmp & bad_types){ return "You cannot " + verb_pr + " " + short + " there right now."; } } return 1; /* ok */ } mixed CanManipulate(){ string *prehensile_limbs = this_object()->GetWieldingLimbs(); if(!sizeof(prehensile_limbs)){ say(this_object()->GetName()+" looks helpless without prehensile appendages."); return "You lack prehensile limbs with which to do that."; } return 1; } int CanFly(){ float j = percent(GetHealthPoints(), GetMaxHealthPoints()); float k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); string clipped = identify(this_object()->GetMissingLimbs()); if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ return 0; } if(creatorp(this_object())) return 1; if(!RACES_D->CanFly(this_object()->GetRace())){ return 0; } if(!clipped || !sizeof(clipped)) return 1; if(!grepp(lower_case(clipped),"wing")) return 1; if(this_object()->GetStaminaPoints() < 5) return 0; return 0; } int CanSwim(){ float j = percent(GetHealthPoints(), GetMaxHealthPoints()); float k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ return 0; } if(creatorp(this_object())) return 1; if(sizeof(this_object()->GetMissingLimbs())) return 0; if(!RACES_D->CanSwim(this_object()->GetRace())){ return 0; } if(this_object()->GetStaminaPoints() < 5) return 0; return 1; } /* int AddLimb(string limb, string parent, int classes, int *armors) * string limb - the limb being added (required) * string parent - the limb to which this one is being attached (required) * int classes - rating of the limb's strength (optional) * int *armors - the types of armors which can be worn here (optional) * * defaults * classes defaults to 1 * armors defaults to ({}) * * description * adds the named limb to the body, attached at the named point * the limb classes starts at 1 for a torso (strongest) * to whatever the documentation rates as the weakest * * returns 1 on success, 0 on failure */ varargs int AddLimb(string limb, string parent, int classes, int *armors){ int arm = 0; if(!limb || Limbs[limb] || (parent && !Limbs[parent])) return 0; if(armors){ int i; i = sizeof(armors); while(i--) arm |= armors[i]; } if(MissingLimbs[limb]) map_delete(MissingLimbs, limb); if( parent ) Limbs[parent]["children"] += ({ limb }); else Torso = limb; if( !classes ) classes = 5; Limbs[limb] = ([ "parent" : parent, "children" : ({}), "class" : classes, "armors" : arm ]); Limbs[limb]["health"] = GetMaxHealthPoints(limb); return 1; } int HealLimb(string limb){ Limbs[limb]["health"] = GetMaxHealthPoints(limb); return Limbs[limb]["health"]; } // Restore Limb has been bugfixed and modified to // handle missing parents and missing children. To restore // a limb, RestoreLimb("right arm") will restore the arm only. // To restore the arm plus its children (in this case, a // hand) use RestoreLimb("right arm",1) and this will enable // the recursive restore of the limb. Trying to restore // a limb will fail if the parent is missing. varargs int RestoreLimb(string limb, int recurse){ if( !MissingLimbs[limb] ) return 0; if(!sizeof(Limbs[MissingLimbs[limb]["parent"]])) return 0; Limbs[limb] = MissingLimbs[limb]; map_delete(MissingLimbs, limb); Limbs[limb]["health"] = GetMaxHealthPoints(limb); // This ensures that the parent of the current limb has this // limb added to its children array. if(member_array(limb,Limbs[Limbs[limb]["parent"]]["children"]) == -1){ Limbs[Limbs[limb]["parent"]]["children"] += ({ limb }); } if(recurse && sizeof(MissingLimbs)){ string *kinder = ({}); foreach(string key, mixed val in MissingLimbs){ if(MissingLimbs[key]["parent"] == limb) kinder += ({ key }); } if(sizeof(kinder)){ foreach(string element in kinder) this_object()->RestoreLimb(element, 1); } } return 1; } /* int DestLimb(string limb) * string limb - the limb being removed * * description * removes a limb from the limbs mapping. The limb isn't marked as mising, * and the monster doesn't die even if you remove a fatal limb. Useful for * removing limbs from standard race types. Removing the torso isn't allowed. * * returns -1 on error, 0 on failure, 1 on success */ int DestLimb(string limb){ string *kiddies; int i; if(!limb || !Limbs[limb]) return -1; if(!Limbs[limb]["parent"]){ return -1; } Limbs[Limbs[limb]["parent"]]["children"] -= ({ limb }); if( (i = sizeof(kiddies = Limbs[limb]["children"])) ) while(i--) DestLimb(kiddies[i]); map_delete(Limbs, limb); return 1; } /* int this_object()->RemoveLimb(string limb, object agent) * string limb - the limb being removed * object agent - the agent who is responsible for the limb removal * * description * removes a limb from the limbs mapping and stores vital data in the * missing limbs mapping * * returns -1 on error, 0 on failure, 1 on success */ varargs int RemoveLimb(string limb, mixed agent, int quiet){ string *kiddies; string limbname,adjname,templimbname, agentname; int i; if(agent && stringp(agent)){ agentname = agent; agent = 0; } if(limb == this_object()->GetTorso() || limb == "neck") return 0; if(godmode || !SEVERABLE_LIMBS) return 0; if( sscanf(limb, "%s %s", adjname, templimbname) == 2 ) limbname=templimbname; else limbname=limb; if(!limb || !Limbs[limb]) return -1; if(!Limbs[limb]["parent"] || Limbs[limb]["class"] == 1){ object objict; if(!quiet){ message("environment", possessive_noun(GetName()) + " " + limb + " is severed!", environment(), ({ this_object() })); message("environment", "Your "+ limb + " is severed!", this_object()); } if(GetRace() == "golem"){ objict = new(LIB_CLAY); if(GetBodyComposition()) objict->SetComposition(GetBodyComposition()); } else { if(GetRace() == "android" || GetRace() == "bot" || inherits(LIB_VEHICLE,this_object())) objict = new(LIB_BOT_LIMB); else objict = new(LIB_LIMB); objict->SetLimb(limb, GetCapName(), GetRace()); } objict->eventMove(environment()); i = sizeof(WornItems[limb]); while(i--){ WornItems[limb][i]->SetWorn(0); WornItems[limb][i]->eventMove(objict); } while( i = sizeof(WornItems[limb]) ) eventRemoveItem(WornItems[limb][i]); if( !this_object()->GetDying() ){ this_object()->SetDying(1); Agent = agent; call_out("eventDie", 0, (Agent ? Agent : agentname)); } return 0; } MissingLimbs[limb] = copy(Limbs[limb]); Limbs[Limbs[limb]["parent"]]["children"] -= ({ limb }); if( (i = sizeof(kiddies = Limbs[limb]["children"])) ) while(i--) this_object()->RemoveLimb(kiddies[i], agent,quiet); map_delete(Limbs, limb); if( environment() ){ object ob; if(!quiet){ message("environment", possessive_noun(GetName()) + " " + limb + " is severed!", environment(), ({ this_object() })); message("environment", "Your "+ limb + " is severed!", this_object()); } if(GetRace() == "golem"){ ob = new(LIB_CLAY); if(GetBodyComposition()) ob->SetComposition(GetBodyComposition()); } else { if(GetRace() == "android" || GetRace() == "bot" || inherits(LIB_VEHICLE,this_object())) ob = new(LIB_BOT_LIMB); else ob = new(LIB_LIMB); ob->SetLimb(limb, GetCapName(), GetRace()); } ob->eventMove(environment()); i = sizeof(WornItems[limb]); while(i--){ int number_of_slots = sizeof(WornItems[limb][i]->GetWorn()); WornItems[limb][i]->SetWorn(0); if(number_of_slots == 1) WornItems[limb][i]->eventMove(ob); else WornItems[limb][i]->eventMove(this_object()); } while( i = sizeof(WornItems[limb]) ) eventRemoveItem(WornItems[limb][i]); } return 1; } mapping GetLimb(string limb){ if(!limb || !Limbs[limb]) return 0; else return copy(Limbs[limb]); } /* string GetRandomLimb(string targ) * string targ - the targetted limb * * description * returns a random limb weighted towards the targetted limb */ string GetRandomLimb(string targ){ string array limbs; if( !targ ){ targ = GetTorso(); } if( member_array(targ, (limbs=keys(Limbs))) == -1){ targ= GetTorso(); /* no target or illegal target, weight torso */ } targ = (limbs + (targ ? ({ targ, targ }) : ({})))[random(sizeof(limbs)+2)]; return targ; } string GetTorso(){ string *limbs; int i; i = sizeof(limbs = keys(Limbs)); while(i--){ if(!Limbs[limbs[i]]["parent"]){ return limbs[i]; } } return 0; } string array GetLimbs(){ return (Limbs ? keys(Limbs) : 0); } int GetLimbClass(string limb){ return Limbs[limb]["class"]; } string GetLimbParent(string limb){ return Limbs[limb]["parent"]; } //The following function courtesy of Garfield @ M*U*D string GetMissingLimbParent(string limb){ return MissingLimbs[limb]["parent"]; } //The following function courtesy of Garfield @ M*U*D string *GetMissingLimbParents(string limb){ string *limbs; limbs = ({ limb }); while(memberp(keys(MissingLimbs),GetMissingLimbParent(limbs[0]))){ limbs = ({ GetMissingLimbParent(limbs[0]) }) + limbs; } return limbs; } string array GetLimbChildren(string limb){ return Limbs[limb]["children"] + ({}); } mapping GetMissingLimb(string limb){ return (limb ? copy(MissingLimbs[limb]) : 0); } // This function courtesy of Garfield // and Javelin at M*U*D int eventCompareLimbs(string limb1, string limb2){ if (memberp(GetMissingLimbParents(limb1), limb2)){ return 1; } if (memberp(GetMissingLimbParents(limb2), limb1)){ return -1; } return strcmp(limb1, limb2); } // New comparison functionality courtesy of // Garfield and Javelin at M*U*D varargs string array GetMissingLimbs(int not_default){ if(not_default){ string *tmp_arr = ({}); if(sizeof(keys(MissingLimbs))){ tmp_arr = sort_array(keys(MissingLimbs), (: eventCompareLimbs :) ); } return tmp_arr; } else return keys(MissingLimbs); } string GetLong(string nom){ string *limbs; string *exempt; string str; float h; str = ""; exempt = ({"bot","android","tree","plant","vehicle","strider","mech"}); if(!(this_object()->GetNoCondition())){ if(member_array(this_object()->GetRace(),exempt) == -1 && !this_object()->GetUndead() ){ str = "The "+this_object()->GetGender()+" "; str += this_object()->GetRace(); h = percent(GetHealthPoints(), GetMaxHealthPoints()); if( h < 10.0 ) str += " is mortally wounded.\n"; else if( h < 20.0 ) str += " is near death.\n"; else if( h < 30.0 ) str += " is severely injured.\n"; else if( h < 40.0 ) str += " is badly injured.\n"; else if( h < 50.0 ) str += " is hurt.\n"; else if( h < 60.0 ) str += " is slightly injured.\n"; else if( h < 70.0 ) str += " has some cuts and bruises.\n"; else if( h < 80.0 ) str += " is in decent shape.\n"; else if( h < 90.0 ) str += " is quite keen.\n"; else str += " is in top condition.\n"; } } if(this_object()->GetUndead()){ str = capitalize(nominative(this_object()))+" has been killed, and "; str += "is one of the Walking Undead.\n"; } limbs = GetMissingLimbs(); if(!(GetRace() == "android") && !(GetRace() == "bot") && !inherits(LIB_VEHICLE,this_object())){ if( sizeof(limbs) ){ int i, maxi; str += capitalize(nom) + " is missing " + add_article(limbs[0]); for(i=1, maxi = sizeof(limbs); i<maxi; i++){ if( i < maxi-1 ) str += ", " + add_article(limbs[i]); else { if( maxi > 2 ) str += ","; str += " and " + add_article(limbs[i]); } } str += ".\n"; } } return str; } string array GetWieldingLimbs(){ return filter(keys(Limbs), (: (Limbs[$1]["armors"] & A_WEAPON) :)); } /* int AddFingers(string limb, int x) * string limb - the limb to which fingers will be added * int x - the number of fingers being added, can be negative * * description * adds the given number of fingers to the given limb * * returns the total number of fingers after addition */ varargs int AddFingers(string limb, int x){ if((Fingers[limb] += x) < 1) Fingers[limb] = 1; return Fingers[limb]; } int GetFingers(string limb){ return Fingers[limb]; } varargs object *GetWorn(string limb){ if(!limb){ object *ret = ({}); string *limbs; int i; i = sizeof(limbs = keys(Limbs)); while(i--) if(WornItems[limbs[i]]) ret += ({ WornItems[limbs[i]] }); return distinct_array(ret); } else if(!WornItems[limb]) return ({}); else return (WornItems[limb] + ({})); } varargs mixed GetWielded(string limb){ if(!limb){ object *ret = ({}); string *limbs; int i; i = sizeof(limbs = keys(Limbs)); while(i--){ if(!WornItems[limbs[i]]) continue; else ret += filter(WornItems[limbs[i]], (: (int)$1->GetArmorType() == A_WEAPON :)); } return distinct_array(ret); } else if(!WornItems[limb]) return 0; else { object *ret; ret = filter(WornItems[limb], (: (int)$1->GetArmorType() == A_WEAPON :)); if(sizeof(ret)) return ret[0]; else return 0; } } /* varargs static int AddHealthPoints(int x, string limb, object agent) * int x - number of points being added, may be negative (required) * string limb - the limb to which health is being added (optional) * object agent - the living responsible for this damage * * defaults * limb defaults to 0 * * description * if the value of limb is not zero, then "x" number of health points will * be added to limb "limb" * if he value is 0, then the overall health points will be modified * * returns the remaining number of health points for the limb in question * or for the overall health points */ varargs static int AddHealthPoints(int x, string limb, mixed agent){ int y = 0; string agentname; if(agent && stringp(agent)){ agentname = agent; agent = 0; } if(godmode && x < 1) return 0; if( limb ){ if( !Limbs[limb] ) return -1; y = GetMaxHealthPoints(limb); if(y < 1) return y; if((Limbs[limb]["health"] += x) < 1) Limbs[limb]["health"] = 0; else if(Limbs[limb]["health"] > y) Limbs[limb]["health"] = y; return Limbs[limb]["health"]; } else { if((HealthPoints += x) < 1) HealthPoints = 0; else if(HealthPoints > (y = GetMaxHealthPoints())) HealthPoints = y; if( HealthPoints < 1 ){ if( !this_object()->GetDying()){ this_object()->SetDying(1); Agent = agent; call_out("eventDie", 0, (agent || agentname)); } } else { float h = percent(GetHealthPoints(), GetMaxHealthPoints()); if( h < COLLAPSE_AT ){ eventCollapse(); } } return HealthPoints; } } varargs int GetHealthPoints(string limb){ if(limb){ if(!Limbs[limb]) return -1; else return Limbs[limb]["health"]; } else return HealthPoints; } varargs int GetMaxHealthPoints(string limb){ return 0; } /* int AddMagicPoints(int x) * int x - the number of magic points being added, may be negative * * description * adds magic points to the body * * returns the remaining magic points */ int AddMagicPoints(int x){ int y; if((MagicPoints += x) < 1) MagicPoints = 0; else if(MagicPoints > (y = GetMaxMagicPoints())) MagicPoints = y; return MagicPoints; } int GetMagicPoints(){ return MagicPoints; } int GetMaxMagicPoints(){ return 0; } /* int AddStaminaPoints(int x) * int x - number of stamina points being added * * description * adds "x" stamina points, can be negative * * returns the remaining number of stamina points */ int AddLead(string ammo,int number){ if( !intp(number) ) error("Bad argument 2 to AddLead().\n"); if( !stringp(ammo) ) error("Bad argument 1 to AddLead().\n"); if( ammo == "gunshot_wounds" ) gunshot_wounds += number; if( ammo == "rifleshot_wounds" ) rifleshot_wounds += number; if( rifleshot_wounds + gunshot_wounds < 0 ){ gunshot_wounds = 0; rifleshot_wounds = 0; } return 1; } varargs int GetLead(string ammo){ int number; number = 0; if(!ammo || !stringp(ammo)){ number = gunshot_wounds + rifleshot_wounds; return number; } if(ammo == "gunshot_wounds") return gunshot_wounds; if(ammo == "rifleshot_wounds") return rifleshot_wounds; return 0; } float AddStaminaPoints(mixed x){ float y; if( !intp(x) && !floatp(x) ) error("Bad argument 1 to AddStaminaPoints().\n"); if( intp(x) ) x = to_float(x); if((StaminaPoints += x) < 0.1) StaminaPoints = 0.0; else if(StaminaPoints > (y = GetMaxStaminaPoints())) StaminaPoints = y; return StaminaPoints; } int GetStaminaPoints(){ return to_int(StaminaPoints); } float GetMaxStaminaPoints(){ return 0; } int AddExperiencePoints(mixed x){ if( !intp(x)) error("Bad argument 1 to AddExperiencePoints().\n"); if((ExperiencePoints += x) < 0) ExperiencePoints = 0; return ExperiencePoints; } int GetExperiencePoints(){ return ExperiencePoints; } int AddMagicProtection(class MagicProtection cl){ if( ( !cl->absorb && !(cl->protect && cl->time) ) || ( cl->hit && !functionp(cl->hit) ) || ( cl->end && !functionp(cl->end) ) || ( !cl->bits ) ){ error("Illegal class setting passed to AddMagicProtection.\n"); return 0; } cl->timestamp = time(); Protection += ({ cl }); return 1; } class MagicProtection array GetMagicProtection(){ return Protection; } int RemoveMagicProtection(int i){ if( i > sizeof(Protection) - 1 ) return 0; if( Protection[i]->end ){ if( !(functionp(Protection[i]->end) & FP_OWNER_DESTED) ){ evaluate(Protection[i]->end, this_object()); } } Protection -= ({ Protection[i] }); return 1; } // This is for creatures that do not use weapons. // I had to crank down unarmed combat for humanoids, // so if your npc's are, say, dumb animals, be sure // to include "SetMelee(1)" so they can fight // Note that fighters are an exception to this. // int SetMelee(int i){ melee = i; return melee; } int GetMelee(){ return melee; } int GetDying(){ return Dying; } int SetDying(int x){ if(x) Dying = 1; else Dying = 0; return Dying; } int SetSleeping(int x){ if(RACES_D->GetNonMeatRace(GetRace()) || GetRace() == "elf") return 0; return (Sleeping = x); } int GetSleeping(){ return Sleeping; } int AddAlcohol(int x){ int i = Alcohol + x; if(RACES_D->GetNonMeatRace(GetRace())) return 0; if(i < 0) i = 0; return (Alcohol = i); } int GetAlcohol(){ return Alcohol; } int AddCaffeine(int x){ if(RACES_D->GetNonMeatRace(GetRace())) return 0; return (Caffeine += x); } int GetCaffeine(){ return Caffeine; } int AddDrink(int x){ return (Drink += x); } int GetDrink(){ return Drink; } int AddFood(int x){ return (Food += x); } int GetFood(){ return Food; } int AddPoison(int x){ Poison += x; if( Poison < 1 ){ Poison = 0; } return Poison; } int GetPoison(){ return Poison; } string GetResistance(int type){ return "none"; } string GetRace(){ return 0; } string GetName(){ return 0; } string GetCapName(){ return 0; } int GetHeartRate(){ int rate; rate = (GetAlcohol() - GetCaffeine()); if( rate > 50 ) rate = 6; else if( rate > 25 ) rate = 5; else if( rate > 0 ) rate = 4; else if( rate > -25 ) rate = 3; else rate = 2; rate += HeartModifier; if( rate < 1 ){ rate = 1; } else if( rate > 10 ){ rate = 10; } return rate; } int GetHealRate(){ int heal, mod = 1; int lead = GetLead(); object dude = this_object(); heal = 1 - (GetPoison() / 5); heal += ( (GetDrink() + GetFood()) || 1 ) / 40; if(GetSleeping()) mod++; if(GetAlcohol() > 10) mod++; if(dude->GetStatLevel("strength") > 50) mod++; if(dude->GetStatLevel("durability") > 50) mod++; if(dude->GetStatLevel("luck") > random(100)) mod++; if(dude->GetSkillLevel("faith") > 10) mod++; mod = heal * to_float(mod * 0.1); heal += mod; if(lead && interactive(dude)){ if(lead < 5) heal /= (lead + 1); else heal = 0; } return heal; } string GetHealthShort(){ string cl, sh; float h; if( !(sh = this_object()->GetShort()) ) return 0; h = percent(GetHealthPoints(), GetMaxHealthPoints()); if( this_object()->GetNoCondition() || h > 90.0 ) cl = "%^BOLD%^GREEN%^"; else if( h > 75.0 ) cl = "%^GREEN%^"; else if( h > 50.0 ) cl = "%^BOLD%^BLUE%^"; else if( h > 35.0 ) cl = "%^BLUE%^"; else if( h > 20.0 ) cl = "%^BOLD%^RED%^"; else cl = "%^RED%^"; return cl + capitalize(sh); } mixed SetProtect(function f){ return (Protect = f); } function GetProtect(){ return Protect; } int GetHeartModifier(){ return HeartModifier; } varargs int AddHeartModifier(int x, int t){ HeartModifier += x; if( t > 0 ){ call_out((: AddHeartModifier(-$(x)) :), t); } return HeartModifier; } int AddHP(int hp){ if(hp < 1 && godmode) return 0; AddHealthPoints(hp); return hp; } string GetAffectLong(){ object dude; string ret; int alclevel; dude = this_object(); alclevel = dude->GetAlcohol(); ret = ""; if(dude->GetSleeping() > 0){ ret += dude->GetName()+" is asleep.\n"; } else if(alclevel > 10){ if(alclevel < 20) ret += dude->GetName()+" looks tipsy.\n"; else if(alclevel < 50) ret += dude->GetName()+" looks drunk.\n"; else if(alclevel < 70) ret += dude->GetName()+" is very drunk.\n"; else ret += dude->GetName()+" is completely wasted drunk.\n"; } return ret; } int GetDeathEvents(){ return DeathEvents; } int SetDeathEvents(int i){ if(!i) DeathEvents = 0; else DeathEvents = 1; return DeathEvents; } int SetGodMode(int i){ if(!this_player()) return 0; if(archp(this_object()) && !archp(this_player())) return 0; if(!archp(this_object()) && this_player() != this_object()) return 0; if(i) godmode = 1; else godmode = 0; return godmode; } int GetGodMode(){ return godmode; } string SetKeepalive(string str){ keepalive = str; } string GetKeepalive(){ return keepalive; }