// /std/living.c
// from the Nightmare mudlib
// inheritable code for living things
// created by Descartes of Borg september 1992
#include <security.h>
#include <daemons.h>
#include <party.h>
#include <dirs.h>
#include <flags.h>
#include <rooms.h>
#include <living.h>
#define TIME_TO_HEAL 10
#define HEALING_FORMULA (stats["strength"]+stats["constitution"]+stats["dexterity"]+stats["charisma"])*6
int invis, ok_to_heal;
static int forced, sight_bonus, spiritual, physical;
string description;
static string party;
static string *search_path;
private string gender;
mapping stats;
static mapping stat_bonus;
mapping languages;
static mapping language_bonus;
string primary_language;
static private mixed *__BeforeLocked;
int __PlayerAge;
static private int __Locked, __LastAged;
int __PlayerKiller;
mapping language_exp;
int query_age();
void set_stats(string str, int x);
void set_alignment(int x);
void add_alignment(int x);
void adj_alignment(int x);
void adjust_biorhythms();
void set_invis();
string query_client();
int query_physical();
int query_outlaw();
int query_spiritual();
int query_alignment();
int query_stats(string str);
int query_base_stats(string stat);
int query_poisoning();
void add_poisoning(int x);
string query_gender();
void set_gender(string str);
string query_objective();
string query_possessive();
string query_subjective();
int query_intox();
int query_stuffed();
int query_quenched();
int query_invis();
string query_party();
string query_long(string unused);
static void init_path();
void create() {
combat::create();
__PlayerAge = 0;
__LastAged = time();
}
void heart_beat() {
int x;
if(x = time() - __LastAged) {
__PlayerAge += x;
__LastAged = time();
}
}
static void init_living() {
add_action("cmd_hook", "", 1);
add_action("cmd_lock", "lock");
init_path();
init_attack();
}
static void init_path() {
string tmp;
search_path = ({ DIR_MORTAL_CMDS, DIR_SECURE_MORTAL_CMDS, DIR_CLASS_CMDS });
if(tmp = (string)this_object()->query_guild())
search_path += ({ DIR_GUILD_CMDS+"/"+tmp });
if(ambassadorp(this_object()) || creatorp(this_object()))
search_path += ({ DIR_AMBASSADOR_CMDS, DIR_SECURE_AMBASSADOR_CMDS });
if(high_mortalp(this_object()) || creatorp(this_object()))
search_path += ({ DIR_HM_CMDS });
if(creatorp(this_object())) {
search_path += ({ DIR_CREATOR_CMDS, DIR_SECURE_CREATOR_CMDS });
if(file_size(user_path(query_name()) + "bin") == -2)
search_path += ({ user_path(query_name())+"bin" });
if(archp(this_object()))
search_path += ({ DIR_ADMIN_CMDS, DIR_SECURE_ADMIN_CMDS });
}
}
static void init_stats() { stats = ([]); }
nomask static int cmd_hook(string cmd) {
string file, verb;
if(__Locked) {
message("prompt", sprintf("\n(%s) Password: ", mud_name()),
this_object());
return 1;
}
if( (verb = query_verb()) != "quit" && query_paralyzed()) {
message("my_action", sprintf("%s", (string)this_player()->query_paralyze_message()),
this_player());
return 1;
}
if(!(file = (string)CMD_D->find_cmd(verb, search_path))) {
if(!((int)SOUL_D->do_cmd(verb, cmd))) {
if((int)CHAT_D->do_chat(verb, cmd)) return 1;
else {
if(query_client()) receive("<error>");
return 0;
}
}
else return 1;
}
if(!((int)call_other(file, "cmd_"+verb, cmd))) {
if(query_client()) receive("<error>");
return 0;
}
else return 1;
}
int force_me(string cmd) {
string tmp;
int res;
if(creatorp(this_object()) && !((int)master()->valid_apply(({query_name()}))))
return 0;
forced = 1;
res = command(cmd);
forced = 0;
return res;
}
void reduce_stats() {
string *ind;
int i;
if(!stats) return;
ind = keys(stats);
for(i=0; i<sizeof(ind); i++)
if(random(101)>50) set_stats(ind[i], query_base_stats(ind[i])-1);
}
void do_healing(int x) {
int tmp;
if(this_object() && this_object()->is_player()) {
tmp = query_physical();
if(tmp >1) tmp = 1;
else if(tmp < -1) tmp = -1;
add_hp(tmp);
tmp = query_spiritual();
if(tmp > 1) tmp = 1;
else if(tmp < -1) tmp = -1;
add_mp(tmp);
}
if(query_invis()) add_sp(-random(5));
heal(query_heal_rate());
if(this_object()->is_player() && !creatorp(this_object()) && query_invis())
heal(-(random(3)));
if(x<1) set_heal_rate(2);
else if(x<20) set_heal_rate(3);
else if(x<50) set_heal_rate(4);
else if(x<85) set_heal_rate(5);
else if(x<150) set_heal_rate(6);
else if(x<210) set_heal_rate(7);
else set_heal_rate(8);
adjust_biorhythms();
if(query_poisoning()) set_heal_rate(-(query_poisoning()/9+1));
ok_to_heal = query_age() + TIME_TO_HEAL;
}
int calculate_healing() {
int borg;
string msg;
if(query_intox()) {
healing["intox"] --;
if(healing["intox"] < 0) healing["intox"] = 0;
if(!healing["intox"]) {
write("Suddenly you get a bad headache.");
add_hp(-random(6));
}
else if(3> random(101)) {
borg = random(4);
switch(borg) {
case 0: msg = "stumble"; break;
case 1: msg = "hiccup"; break;
case 2: msg = "look"; break;
case 3: msg = "burp"; break;
}
write("You "+msg+(msg=="look" ? " drunk." : "."));
say(query_cap_name()+" "+msg+"s "+(msg == "look" ? " drunk." : "."));
}
}
if(query_stuffed()) {
healing["stuffed"]--;
if(healing["stuffed"] < 0) healing["stuffed"] = 0;
}
if(query_quenched()) {
healing["quenched"]--;
if(healing["quenched"] < 0) healing["quenched"] = 0;
}
if(query_poisoning() && !this_object()->is_player()) add_poisoning(-1);
return query_intox()+query_stuffed()+query_quenched();
}
void set_party(string str) {
party = str;
}
void add_poisoning(int x) {
if(!healing) healing = ([]);
healing["poisoning"] += x;
if(healing["poisoning"] < 0) healing["poisoning"] = 0;
}
void set_stats(string str, int x) {
if(stats[str] && stats[str] != x) {
log_file("stats", query_name()+" went from "+stats[str]+" to "+x+
" in "+str+" ("+ctime(time())+")\n");
log_file("stats", "PRIV: "+query_privs(previous_object())+" ("+
file_name(previous_object())+")\n");
}
stats[str] = x;
if(str == "constitution") {
player_data["general"]["max_hp"] = 50 + 10*stats["constitution"];
augment_body(x);
}
if(str == "intelligence") magic["max points"] = 50+10*x;
if(str == "strength")
set_max_encumbrance(x*200);
if(str == "dexterity") set_max_sp(x*7);
}
void delete_search_path(string dir) {
if(member_array(dir, search_path) != -1) search_path -= ({ dir });
}
void add_exp(int x) {
if(x>0 && query_party()) {
PARTY_OB->calculate_exp(party, x, previous_object());
return;
}
player_data["general"]["experience"] += x;
if(x > 1000) {
log_file("exp",
query_name()+" received "+x+" exp from "+ (string)previous_object()->query_name()+"\n");
log_file("exp",
"(PRIV: "+query_privs(previous_object())+" "+file_name(previous_object())+": "+
ctime(time())+"\n");
}
if(creatorp(this_object()) || !this_object()->is_player()) return;
}
void fix_exp(int x, object tmp) {
player_data["general"]["experience"] += x;
if(x> 600) {
log_file("exp",
query_name()+" received "+x+" exp in party: "+party+" from "+
(string)tmp->query_short()+"\n");
log_file("exp",
"(PRIV: "+query_privs(tmp)+" "+file_name(tmp)+"): "+ctime(time())+"\n");
}
if(creatorp(this_object()) || !this_object()->is_player()) return;
}
void add_alignment(int x) {
if(x>40) x = 40;
else if(x<-40) x = -40;
player_data["general"]["alignment"] += x;
if(query_alignment() > 1500) player_data["general"]["alignment"] = 1500;
if(query_alignment()< -1500) player_data["general"]["alignment"] = -1500;
}
void adj_alignment(int x) {
add_alignment(x/200-x/50);
}
int add_intox(int x) {
if(x>0) x = x*3 + x/2;
if(x+healing["intox"] > HEALING_FORMULA) return 0;
else healing["intox"] += x;
if(healing["intox"] < 0) healing["intox"] = 0;
return 1;
}
int add_stuffed(int x) {
if(x>0) x = x*3;
if(x+healing["stuffed"] > HEALING_FORMULA) return 0;
else healing["stuffed"] += x;
if(healing["stuffed"] < 0) healing["stuffed"] = 0;
return 1;
}
int add_quenched(int x) {
if(x>0) x = x*3;
if(x+healing["quenched"] > HEALING_FORMULA) return 0;
else healing["quenched"] += x;
if(healing["quenched"] < 0) healing["quenched"] = 0;
return 1;
}
void add_stat_bonus(string stat, int amount) {
if(!stat_bonus) stat_bonus = ([]);
if(stat_bonus[stat]) stat_bonus[stat] += amount;
else stat_bonus[stat] = amount;
if(!stat_bonus[stat]) map_delete(stat_bonus, stat);
}
string query_long(string unused) {
object *inv;
string *tmp;
string pre, stuff, extra, reg, short;
int i, x;
if(this_object()->query_ghost()) return "An ethereal presence.\n";
reg = "";
pre = "You look over the "+query_gender()+" "+(string)this_object()->query_race()+".\n";
if(combat::query_long("junk")) pre += ::query_long("junk")+"\n";
if(description) pre += query_cap_name()+" "+description+"\n";
if(severed) tmp = keys(severed);
if(tmp && sizeof(tmp)) {
reg += query_cap_name()+" is missing a "+tmp[0];
if(sizeof(tmp) > 1) {
if(sizeof(tmp) != 2) reg += ",";
for(i=1; i<sizeof(tmp); i++) {
if(i== sizeof(tmp)-1) reg += " and a ";
reg += " " +tmp[i];
if(i != sizeof(tmp)-1) reg +=",";
}
}
reg += ".\n";
}
else reg += query_cap_name() + " has no missing limbs.\n";
x = ((player_data["general"]["hp"]*100)/player_data["general"]["max_hp"]);
reg += capitalize(query_subjective());
if(x>90) reg += " is in top shape.\n";
else if(x>75) reg += " is in decent shape.\n";
else if(x>60) reg += " is slightly injured.\n";
else if(x>45) reg += " is hurting.\n";
else if(x>30) reg += " is badly injured.\n";
else if(x>15) reg += " is terribly injured.\n";
else reg += " is near death.\n";
if(userp(this_object()) && query_outlaw())
reg += query_cap_name() + " wears the mark of Cain.\n";
stuff = "";
extra = "";
inv = all_inventory(this_object());
if(sizeof(inv)) {
for(i=0; i<sizeof(inv); i++) {
if(inv[i]->extra_look()) extra += (string)inv[i]->extra_look();
if(inv[i]->query_invis()) continue;
short = (string)inv[i]->query_short();
if(short && short != "") stuff += short + "\n";
}
}
if(extra != "") pre = pre + extra;
if(stuff == "") reg += capitalize(query_subjective())+" is empty handed.\n";
else reg += capitalize(query_subjective())+" is carrying:\n"+stuff;
reg = pre + reg;
return reg;
}
int query_stats(string stat) {
int x;
if(stat_bonus) x= stat_bonus[stat];
else x = 0;
return stats[stat] + x;
}
int query_base_stats(string stat) {
if(!stats || !stats[stat]) return 0;
else return stats[stat];
}
nomask int query_forced() { return forced; }
string *query_search_path() {
return search_path + ({});
}
int query_exp() { return player_data["general"]["experience"]; }
int query_alignment() { return player_data["general"]["alignment"]; }
int query_intox() {
if(healing) return healing["intox"];
else return 0;
}
int query_stuffed() {
if(healing) return healing["stuffed"];
else return 0;
}
int query_quenched() {
if(healing) return healing["quenched"];
else return 0;
}
int query_poisoning() {
if(healing) return healing["poisoning"];
else return 0;
}
string query_party() { return party; }
string query_al_title() {
int al;
al = player_data["general"]["alignment"];
if(al > 1000) return "saintly";
else if(al >750) return "righteous";
else if(al >500) return "good";
else if(al > 280) return "benevolent";
else if(al > 135) return "nice";
else if(al > -135) return "neutral";
else if(al > -280) return "mean";
else if(al > -500) return "malevolent";
else if(al > -750) return "bad";
else if(al > -1000) return "evil";
else return "demonic";
}
int query_sight_bonus() { return sight_bonus; }
int query_age() { return __PlayerAge; }
string *query_all_stats() { return keys(stats); }
void set_description(string str) { description = str; }
string query_description() { return description; }
int remove() {
int i;
object *inv;
inv = all_inventory(this_object());
for(i=0; i<sizeof(inv); i++) {
if(!inv[i]) continue;
if(inv[i]->drop() && inv[i]) inv[i]->remove();
/* Some objects call remove() in drop() */
}
::remove();
}
void adjust_biorhythms() {
float freq, temps;
temps = to_float(query_age()/1000);
freq = to_float( (int)this_object()->query_stats("wisdom"));
spiritual = to_int( 5.0 * sin(freq*temps) );
freq = to_float( (int)this_object()->query_stats("strength") );
physical = to_int( 5.0 * sin(freq*temps) );
}
int query_spiritual() { return spiritual; }
int query_physical() { return physical; }
string query_primary_lang() { return primary_language; }
void set_primary_lang(string str) { primary_language = str; }
// language system added by Valodin in August 1993
int query_temp_lang_bonus(string lang)
{
if(!language_bonus)
return 0;
if(!language_bonus[lang])
return 0;
return language_bonus[lang];
}
int query_real_lang_prof(string lang)
{
if(!languages)
return 0;
if(!languages[lang])
return 0;
return languages[lang];
}
int query_lang_prof(string lang)
{
int ret;
ret = query_real_lang_prof(lang);
ret += query_temp_lang_bonus(lang);
if(ret > 10) ret = 10;
if(ret < 0) ret = 0;
return ret;
}
int set_lang_prof(string lang, int i)
{
if(!languages)
languages = ([]);
if(i > 10)
i = 10;
languages[lang] = i;
return languages[lang];
}
int add_temp_lang_bonus(string lang, int i)
{
if(!language_bonus)
language_bonus = ([]);
if(!language_bonus[lang])
language_bonus[lang] = i;
else
language_bonus[lang] += i;
return query_lang_prof(lang);
}
string *query_all_languages()
{
string *ret;
if(!languages)
ret = ({});
else
ret = keys(languages);
if(!language_bonus)
return ret;
ret += keys(language_bonus);
return distinct_array(ret);
}
int remove_language(string lang)
{
if(!languages || !languages[lang])
return 0;
map_delete(languages, lang);
return 1;
}
// each mapping element is an array of two ints
// The first is the number of language points amassed. When this reaches
// (lang_prof + 1) ^ 4, the language prof advances and the language points
// are decreased. The second number is the number of excess exp points
// have been spent. When exp is spent, it is converted to lang_pts based
// on intelligence. it takes (40 - int) exp pts to make one lang_pt
// -Valodin
void learn_language(string lang, int exp)
{
int tot_exp, tmp, goal, lang_pts, intel_fac;
if(!language_exp)
language_exp = ([]);
if(!language_exp[lang])
language_exp[lang] = ({ 0, 0});
tot_exp = exp + language_exp[lang][1];
intel_fac = 40 - query_stats("intelligence");
if(intel_fac < 1)
intel_fac = 1;
lang_pts = tot_exp / intel_fac;
tot_exp = tot_exp % intel_fac;
language_exp[lang][0] += lang_pts;
language_exp[lang][1] = tot_exp;
tmp = query_lang_prof(lang) + 1;
if(tmp > 10)
tmp = 10;
while((goal = tmp * tmp * tmp * tmp) <= language_exp[lang][0])
{
set_lang_prof(lang, tmp);
language_exp[lang][0] -= goal;
tmp++;
if(tmp > 10)
tmp = 10;
}
}
int *query_lang_exp(string lang)
{
if(!language_exp)
return ({ 0, 0 });
if(!language_exp[lang])
return ({ 0, 0});
return language_exp[lang];
}
void set_gender(string str) {
if(str != "male" && str != "female" && str != "neuter") return;
gender = str;
}
string query_gender() { return (gender ? gender : "neuter"); }
string query_subjective() { return nominative(gender); }
string query_possessive() { return possessive(gender); }
string query_objective() { return objective(gender); }
static int cmd_lock(string str) {
if(str != "terminal") return 0;
__BeforeLocked = ({ environment(this_player()),
file_name(environment(this_player())) });
__Locked = 1;
move(ROOM_LOCKED);
message("prompt", "%^INITTERM%^\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
"("+mud_name()+") Password: ", this_object());
input_to("unlock", I_NOECHO | I_NOESC);
return 1;
}
static void unlock(string str) {
if((string)this_object()->query_password() !=
crypt(str, (string)this_object()->query_password())) {
message("prompt", sprintf("\n(%s) Password: ", mud_name()),
this_object());
input_to("unlock", I_NOECHO | I_NOESC);
return;
}
__Locked = 0;
if(!__BeforeLocked[0] || move(__BeforeLocked[0]) ||
move(__BeforeLocked[1])) move(ROOM_START);
this_object()->empty_cue();
__BeforeLocked = ({});
return;
}
int query_locked() { return __Locked; }
void set_outlaw(int x) {
if(!userp(this_object())) return;
log_file("pkflag", sprintf("%s had PK flag set to %d by %s, "
" PRIV: %s\n", query_name(), x, file_name(previous_object()),
query_privs(previous_object(0))));
__PlayerKiller = x;
}
int query_outlaw() { return __PlayerKiller; }
string query_client() { return 0; }