// /std/living/body.c // from the Nightmare mudlib // the code for the limbs system used by the Nightmare mudlib // based on the TMI LOS system by Brian with help from Buddha // written by Descartes of Borg september 1992 #include <std.h> #include <daemons.h> #include <objects.h> inherit CONTAINER; mixed *deaths; mapping player_data, magic, severed, healing, body; static mapping wielded; static string target_limb; string *limbs; int all_my_fingers; static int num_wielded; private int heal_rate; void set_wielding_limbs(string *str); int check_on_limb(string limb); string *query_wielding_limbs(); string type_ok(string type, string limb); void init_limb_data(); void set_fingers(int x); int query_fingers(); void set_max_hp(int hp); void set_hp(int hp); void add_hp(int x); void set_max_sp(int x); void set_sp(int x); void add_sp(int x); void add_mp(int x); void set_max_mp(int x); void set_mp(int x); object query_current_attacker(); void set_overall_ac(int ac); void set_ac(string limb_name, int ac); int add_limb(string limb_name, string limb_ref, int max_dam, int curr_dam, int limb_ac); int remove_limb(string limb_name); int query_max_sp(); int query_max_hp(); int query_hp(); int query_sp(); int query_max_mp(); int query_mp(); int query_ac(string limb_name); int do_damage(string limb_name, int damage); string query_reference(string limb); string equip_weapon_to_limb(object weap, string limb1, string limb2); string equip_armour_to_limb(object arm, string *limb); object query_weapon(string limb); object query_armour(string limb); int remove_armour_from_limb(object arm, string *limb); int remove_weapon_from_limb(object ob); string *query_limbs(); string return_limb(); string return_target_limb(); int query_is_limb(string limb); // This function initializes the variables // This should only be called when there is NO limb data yet void init_limb_data() { if(!player_data) player_data = ([ "general":([ "hp":1, "max_hp":50, "sp":1, "max_sp":1])]); body = ([]); limbs = ({}); wielded = ([]); severed = ([]); healing = ([]); magic = ([]); } void set_max_hp(int hp) { player_data["general"]["max_hp"] = hp; } void set_hp(int hp) { if(!query_max_hp()) player_data["general"]["max_hp"] = hp; if(hp> query_max_hp()) { if(this_object()->is_player()) player_data["general"]["hp"] = query_max_hp(); else { player_data["general"]["max_hp"] = hp; player_data["general"]["hp"] = hp; } } else player_data["general"]["hp"] = hp; } void add_hp(int x) { player_data["general"]["hp"] += x; if(player_data["general"]["hp"] > player_data["general"]["max_hp"]) player_data["general"]["hp"] = player_data["general"]["max_hp"]; if(player_data["general"]["hp"] < 1) player_data["general"]["hp"] = 1; } void set_max_sp(int x) { player_data["general"]["max_sp"] = x; } void set_sp(int x) { if(!query_max_sp()) set_max_sp(x); if(x > query_max_sp()) player_data["general"]["sp"] = query_max_sp(); else player_data["general"]["sp"] = x; } void add_sp(int x) { if(!player_data["general"]["sp"]) set_sp(x); else player_data["general"]["sp"] += x; if(player_data["general"]["sp"] > query_max_sp()) player_data["general"]["sp"] = query_max_sp(); if(player_data["general"]["sp"] < -200) player_data["general"]["sp"] = -200; } void set_max_mp(int x) { if(!magic) magic = ([]); magic["max points"] = x; } int query_max_mp() { return magic["max points"]; } void set_mp(int x) { if(!query_max_mp()) magic["max points"] = x; if(x > query_max_mp()) { if(this_object()->is_player()) { magic["points"] = magic["max points"]; } else { magic["max points"] = x; magic["points"] = x; } } else magic["points"] = x; if(magic["points"] < 0) magic["points"] = 0; } void add_mp(int x) { if(!magic) magic = ([ "points":0, "max points":0 ]); magic["points"] += x; if(magic["points"] > magic["max points"]) magic["points"] = magic["max points"]; if(magic["points"] < -200) magic["points"] = -200; } int query_mp() { return magic["points"]; } // This function is only for lazy wizzes to use when creating monsters!! void set_overall_ac(int x) { int i; for(i=0; i<sizeof(limbs); i++) { if(limbs[i] != "torso") set_ac(limbs[i], x); else set_ac("torso", (2*x)); } } void set_ac(string limb_name, int ac) { body[limb_name]["ac"] = ac; } // This function adds limbs to a player or monster // The values passed to it mean the following: // limb_name: The name of the limb being added // limb_ref: The name of other limbs that should be lost when this // limb is lost, or FATAL is losing it is fatal, or "" if nothing // else should happen. // max_dam: The maximum damage the limb can take before being lost // curr_dam: How much damage has been done to the limb thus far. This // allows you to create wounded monsters. // limb_ac: How much protection the limb has. By setting it to >0, you // set it's natural ac // NOTE: In order to make a creature with 4 arms, each arm must have a // distinctive name, like "lower right arm", "right arm", "lower left // arm", "lower right arm" int add_limb(string limb_name, string limb_ref, int max_dam, int curr_dam, int limb_ac) { body[limb_name] = ([ "limb_ref": limb_ref, "max_dam": max_dam, "damage": curr_dam, "ac": limb_ac ]); if(!limbs) limbs = ({}); limbs += ({ limb_name }); body[limb_name]["armour"] = ({}); body[limb_name]["armour_ob"] = ({}); body[limb_name]["weapons"] = 0; if(!severed) return 1; if(severed[limb_name]) map_delete(severed, limb_name); return 1; } void augment_body(int x) { int tmp; int dam, i; string b_type; if((string)this_object()->query_race() == "satyr") { if(member_array("left foot", limbs) != -1) { remove_limb("left foot"); map_delete(severed, "left foot"); } if(member_array("right foot", limbs) != -1) { remove_limb("right foot"); map_delete(severed, "right foot"); } if(severed && severed["left foot"]) map_delete(severed, "left foot"); if(severed && severed["right foot"]) map_delete(severed, "right foot"); } b_type = this_object()->query_body_type(); if(b_type != 0) // must be a monster added by Val June 30, 1993 { for(i=0, tmp = sizeof(limbs); i<tmp; i++) body[limbs[i]]["max_dam"] = query_max_hp()/((int)RACE_D->query_max_mon_dam(limbs[i],b_type)); return; } for(i=0, tmp = sizeof(limbs); i<tmp; i++) body[limbs[i]]["max_dam"] = query_max_hp()/((int)RACE_D->query_max_dam(limbs[i], (string)this_object()->query_race())); } // This function removes a limb int remove_limb(string limb_name) { if(body[limb_name]) { severed[limb_name] = body[limb_name]["limb_ref"]; map_delete(body, limb_name); limbs -= ({ limb_name }); return 1; } return 0; } // This function returns a random limb string return_limb() { return limbs[random(sizeof(limbs))]; } // This function returns a random limb, giving weight to // those limbs that can take the most damage string return_target_limb() { string tmp_lmb; int res, i, count; if(target_limb && !query_is_limb(target_limb)) target_limb = 0; if(target_limb) { tmp_lmb = target_limb; target_limb = 0; if(random(120) > (int)this_object()->query_skill("defense")) return tmp_lmb; } count = member_array("torso", limbs); i = 0; while(i++ < ((sizeof(limbs))/2)) if( (res=random(sizeof(limbs))) == count ) break; return limbs[res]; } string *query_limbs() { return limbs; } int query_is_limb(string limb) { if(member_array(limb, limbs) != -1) return 1; else return 0; } int query_max_hp() { return player_data["general"]["max_hp"]; } int query_sp() { if(!player_data["general"]["sp"]) return 0; return player_data["general"]["sp"]; } int query_max_sp() { if(!player_data["general"]["max_sp"]) return 0; return player_data["general"]["max_sp"]; } int query_hp() { return player_data["general"]["hp"]; } int query_max_dam(string limb) { if(body[limb]) return body[limb]["max_dam"]; } int query_dam(string limb) { if(body[limb]) return body[limb]["damage"]; } string query_reference(string limb) { if(body[limb]) return body[limb]["limb_ref"]; } int do_damage(string limb, int damage) { if(body[limb]) { body[limb]["damage"] += damage; player_data["general"]["hp"] -= damage; if(body[limb]["damage"] < 0) body[limb]["damage"] = 0; if(player_data["general"]["max_hp"]<player_data["general"]["hp"]) player_data["general"]["hp"] = player_data["general"]["max_hp"]; message("status", sprintf("hp: %d sp: %d mp: %d", query_hp(), query_sp(), query_mp()), this_object()); return damage; } return 0; } int query_ac(string limb) { int tmp_ac, i; if(!body) return 0; if(!body[limb]) return 0; tmp_ac = 0; i = sizeof(body[limb]["armour_ob"]); while(i--) tmp_ac += (body[limb]["armour_ob"][i] ? (int)body[limb]["armour_ob"][i]->query_ac() : 0); return tmp_ac; } string equip_weapon_to_limb(object weap, string limb1, string limb2) { if(member_array(limb1, limbs) == -1) return "You have no "+limb1+"!\n"; if(wielded[limb1]) return "You are already wielding something in your "+limb1+"!\n"; if(member_array("shield", body[limb1]["armour"]) != -1) return "You cannot wield a weapon while wearing a shield in your "+limb1+".\n"; if(!body[limb1]["wieldable"]) return "You cannot wield a weapon with a "+limb1+"!\n"; if(limb2) { if(limb2==limb1) return "You are wielding something with your "+limb2+".\n"; if(!body[limb2]) return "You do not have a "+limb2+"!\n"; if(wielded[limb2]) return "You are wielding something with your "+limb2+".\n"; if(member_array("shield", body[limb2]["armour"]) != -1) return "You cannot wield a weapon where you wear a shield.\n"; if(!body[limb2]["wieldable"]) return "You cannot wield anything with your "+limb2+".\n"; body[limb2]["ac"] += (int)weap->query_ac(); body[limb2]["weapons"] = weap; wielded[limb2] = weap; } body[limb1]["ac"] += (int)weap->query_ac(); body[limb1]["weapons"] = weap; wielded[limb1] = weap; num_wielded ++; return 0; } string equip_armour_to_limb(object arm, string *limb) { int i; function f; string y, type; type = (string)arm->query_type(); i = sizeof(limb); while(i--) if(y=type_ok(type, limb[i])) return y; if(functionp(f = (mixed)arm->query_wear()) && !((*f)())) return "NO"; i = sizeof(limb); while(i--) { body[limb[i]]["ac"] += (int)arm->query_ac(); body[limb[i]]["armour"] += ({type}); body[limb[i]]["armour_ob"] += ({ arm }); } return 0; } string type_ok(string type, string limb) { int worn, x, i; if(!body[limb]) return "You have no "+limb+"!\n"; if(member_array(type, body[limb]["armour"]) != -1) worn = 1; else worn = 0; switch(type) { case "shield": if(worn) return "You are already wearing a shield!\n"; else if(wielded[limb]) return "You cannot wear a shield while you are wielding a weapon in your "+limb+".\n"; else return 0; break; case "body armour": if(member_array("armour", body[limb]["armour"]) != -1) return "You cannot wear regular armuur with body armour.\n"; else if(worn) return "You are already wearing body armour!\n"; else return 0; break; case "ring": i = 0; x = sizeof(body[limb]["armour"]); while(x--) if(body[limb]["armour"][x] == "ring") i++; if(i > all_my_fingers-1) return "You do not have that many fingers on your "+limb+".\n"; else return 0; break; case "armour": if(member_array("body armour", body[limb]["armour"]) != -1) return "You may not wear body armour and armour at the same time.\n"; else if(worn) return "You may only wear one piece of body armour at a time.\n"; else return 0; break; default: if(worn) return "You may only wear one armour of type "+type+" at a time.\n"; else return 0; break; } return "Error in wearing armour.\n"; } string *query_armour(string limb) { if(body[limb]) return body[limb]["armour"]; else return 0; } int remove_weapon_from_limb(object ob) { int i; string *ind; ind = keys(wielded); for(i=0; i<sizeof(ind); i++) { if(wielded[ind[i]] == ob) { map_delete(wielded, ind[i]); body[ind[i]]["armour"] -= ({ "weapon" }); body[ind[i]]["armour_ob"] -= ({ ob }); body[ind[i]]["weapons"] = 0; } } num_wielded --; return 1; } int remove_armour_from_limb(object arm, string *limb) { int i, arm_class; string type; arm_class = (int)arm->query_ac(); type = (string)arm->query_type(); for(i=0; i<sizeof(limb); i++) { if(!body) continue; if(!body[limb[i]]) continue; if(member_array(type, body[limb[i]]["armour"]) != -1) body[limb[i]]["armour"] -= ({ type }); body[limb[i]]["ac"] -= arm_class; body[limb[i]]["armour_ob"] -= ({ arm }); } return 1; } void set_fingers(int x) { all_my_fingers = x; } int query_fingers() { return all_my_fingers; } void set_wielding_limbs( string *str) { int i; for(i=0; i<sizeof(str); i++) { if(member_array(str[i], limbs) == -1) continue; body[str[i]]["wieldable"] = 1; } } void add_wielding_limb(string str) { if(member_array(str, limbs) == -1) return; body[str]["wieldable"] = 1; } string *query_wielding_limbs() { string *tmp; int i; tmp = ({}); for(i=0; i<sizeof(limbs); i++) { if(body[limbs[i]]["wieldable"]) tmp += ({ limbs[i] }); } return tmp; } void fix_limbs() { int i; for(i=0; i<sizeof(limbs); i++) { body[limbs[i]]["armour"] = ({}); body[limbs[i]]["armour_ob"] = ({}); body[limbs[i]]["ac"] = 0; body[limbs[i]]["weapon"] = 0; } wielded = ([]); } string *query_severed_limbs() { if(!severed) return ({}); else return keys(severed); } object *query_wielded() { return (wielded ? values(wielded) : ({})); } object query_weapon(string limb) { if(!wielded) return 0; if(!wielded[limb]) return 0; return wielded[limb]; } // initialize the variables void init_complex_body() { target_limb = ""; if(!heal_rate) heal_rate = 2; } void heal(int x) { int i; if(player_data["general"]["hp"] < 1) return; add_hp(x); add_mp(x); add_sp(2*x); for(i=0; i<sizeof(limbs); i++) { body[limbs[i]]["damage"] -= x; if(body[limbs[i]]["damage"] < 0) body[limbs[i]]["damage"] = 0; } } void heal_limb(string str, int x) { if(member_array(str, limbs) == -1) return; if(!body[str]) return; body[str]["damage"] -= x; if(body[str]["damage"] < 0) body[str]["damage"] = 0; } int set_heal_rate(int x) { heal_rate = x; return x; } int query_heal_rate() { return heal_rate; } int severed_limb(string limb) { int temp; string childlimb; if(!body[limb]) return 0; childlimb = body[limb]["limb_ref"]; if(childlimb == "FATAL") { player_data["general"]["hp"] = -1; return 2; } if(childlimb == "") { remove_limb(limb); return 1; } if(!body[childlimb]) { remove_limb(limb); return 1; } temp = body[childlimb]["damage"]; if(temp < body[childlimb]["max_dam"]) { do_damage(childlimb, body[childlimb]["max_dam"]+25); check_on_limb(childlimb); } remove_limb(limb); return 1; } int check_on_limb(string limb) { object weap; object *arm; string *locations; int i; object old_limb; if(!body[limb]) return 0; if(body[limb]["damage"] > body[limb]["max_dam"]) { if(creatorp(this_object())) { message("my_combat", sprintf("If you were not immortal, you would " "lose your %s right now!", limb), this_object()); body[limb]["damage"] = body[limb]["max_dam"] - 1; return 1; } if(limb == "torso") message("my_combat", "A mortal blow is dealt to your body!", this_object()); else message("my_combat", sprintf("Your %s is severed!",limb), this_object()); if(limb == "torso") tell_object(environment(this_object()),this_object()->query_cap_name()+" is dealt a mortal blow to the torso!", this_object()); else tell_room(environment(this_object()),this_object()->query_cap_name()+" has "+this_object()->query_possessive()+" "+limb+" severed!", this_object()); weap = wielded[limb]; if(weap) { remove_weapon_from_limb(weap); weap->set_not_equipped(); } arm = body[limb]["armour_ob"]; if(arm) { for(i = 0; i<sizeof(arm); i++) { remove_armour_from_limb(arm[i], (string *)arm[i]->query_actual_limbs()); arm[i]->set_not_equipped(); } } old_limb = new(OB_BODY_PART); old_limb->set_limb(query_cap_name(), limb); old_limb->move(environment(this_object())); if(weap) weap->move(old_limb); if(arm) { for(i=0; i<sizeof(arm); i++) { arm[i]->move(old_limb); } } player_data["general"]["hp"] -= 25; heal_rate = -3; return severed_limb(limb); } return 1; } void add_kill(string str) { int x; if(!str) return; if(!player_data["kills"]) player_data["kills"] = ({}); if(member_array((x=(int)PLAYER_D->add_kill(str)), player_data["kills"]) != -1 || x== -1) return; player_data["kills"] += ({ x }); } int *query_kills() { return player_data["kills"]; } void add_death(string str) { if(!str) return; if(!deaths) deaths = ({ ({str, time()}) }); else deaths += ({ ({ str, time() }) }); } mixed *query_deaths() { return deaths; } void clear_kills() { player_data["kills"] = ({}); } void set_target_limb(string str) { if(!stringp(str)) return; if(member_array(str, limbs) == -1) return; target_limb = str; } void set_max_dam(string limb, int x) { if(userp(this_object())) return; body[limb]["max_dam"] = x; } object query_current_attacker() { return 0; }