// /std/monster.c // from the Nightmare mudlib // inheritable code for npc's // created by Descartes of Borg september 1992 #include <std.h> #include <move.h> #include <objects.h> #include <daemons.h> inherit LIVING; object tmp; static status heart_beat_on; int level; static int speed; static int moving; mapping emotes, speech, spells; string body_type; int __NextHeal; mixed __Aggressive; string __Race; private static mixed __Die; string *route; int position, patrol; int test_heart(); mixed query_aggressive(); void set_spell_chance(int x); void set_spells(string *arr); string return_chat(); string return_achat(); void set_exp(int x); void set_level(int x); int query_level(); void move_around(); void set_emotes(int x, string *arr, int att); void set_patrol(int i, string *str); void create() { ::create(); emotes = ([]); enable_commands(); init_limb_data(); init_stats(); init_skills(0); init_living(); set_heart_beat(heart_beat_on = 1); speed = 0; set_gender("neuter"); speech = ([]); spells = ([]); __NextHeal = time()+ 30; } void init() { mixed tmp; if(!heart_beat_on) { set_heart_beat(heart_beat_on = 1); while(__NextHeal < time()) { do_healing(calculate_healing()); __NextHeal += 30; } } if(this_player()->query_invis()) { if(creatorp(this_player())) return; if(random(101) < (int)this_player()->query_level()) return; } if(this_player()->query_ghost()) return; if(this_player()->is_player()) { if(tmp = query_aggressive()) { if(intp(tmp) && tmp > (int)this_player()->query_stats("charisma")) kill_ob(this_player(), 0); else if(stringp(tmp)) call_other(this_object(), tmp); } } } void set_name(string str) { set_living_name(str); ::set_name(str); if(query_level() < 1) set_level(1); } void heart_beat() { string *langs; string lang, pre; living::heart_beat(); ok_to_heal ++; if(__NextHeal > time()) calculate_healing(); else while(__NextHeal < time()) { do_healing(calculate_healing()); __NextHeal += 30; } continue_attack(); if(speed && moving >= speed) move_around(); else moving++; if(!query_current_attacker()) pre = ""; else pre = "attack "; if(emotes[pre+"chance"] > random(100)) if(this_object()) message("environment", emotes[pre+"msg"][random(sizeof(emotes[pre+"msg"]))], environment(this_object()), ({ this_object() }) ); if(sizeof(langs = keys(speech))) { lang = langs[random(sizeof(langs))]; if(this_object() && random(100) < speech[lang][pre+"chance"]) this_object()->force_me("speak in "+lang+" "+ speech[lang][pre+"msg"][random(sizeof(speech[lang][pre+"msg"]))]); } magic_round = 0; if(!test_heart()) set_heart_beat(heart_beat_on = 0); } void die(object ob) { object money_ob; object *contents; int i, tmp_size; string *currs; if(functionp(__Die)) { if(!((int)((*__Die)(ob)))) return; } else if(stringp(__Die)) message("other_action",__Die,environment(this_object()),({this_object()})); else message("other_action", query_cap_name()+ " drops %^RED%^dead%^RESET%^ before you.", environment(this_object()), ({ this_object() })); tmp = new(OB_CORPSE); tmp->set_name(query_cap_name()); tmp->copy_body(this_object()); tmp->move(environment(this_object())); tmp_size=sizeof(currs=query_currencies()); if(tmp_size) { money_ob = new("/std/obj/coins"); for(i=0; i<tmp_size; i++) { money_ob->add_money(currs[i], query_money(currs[i])); add_money(currs[i], -query_money(currs[i])); } money_ob->move(tmp); } contents = all_inventory(this_object()); for(i=0;i<sizeof(contents);i++) { if(contents[i]->move(tmp)) if(!contents[i]->remove()) destruct(contents[i]); } remove(); } int query_npc() { return 1; } varargs void move_player(mixed dest, string message) { object prev; string here,going,temp1,temp2,temp3; prev = environment(this_object()); here = file_name(prev); if (stringp(dest)) { if (sscanf(dest,"/%s",temp1)!=1) { sscanf(here,"/%s",temp1); going = ""; while(sscanf(temp1,"%s/%s",temp2,temp3)==2) { going = going + "/"+temp2; temp1 = temp3; } temp1 = dest; if (file_size(going+"/"+temp1+".c") != -1) { dest = going+"/"+temp1; } } } if(move(dest) == MOVE_OK) { message("other_action", query_cap_name()+" arrives.", environment(this_object()), ({ this_object() })); tell_room(prev, query_cap_name() + " leaves " + message + ".\n"); } } void set_patrol(int i, string *str) { speed = i; moving = 1; patrol = 1; route = ({}); route += str; position = 0; } /* Call_out taken out of move_around by Hanse 1/4/93 */ void move_around() { object env; string *enters; string *exits; if(!this_object()) return; if(env = environment(this_object())) { exits = (string*)environment(this_object())->query_exits(); enters = (string *)env->query_enters(); if(!sizeof(exits)) exits = 0; if(!sizeof(enters)) enters = 0; } else exits = 0; if(exits || enters) { if(patrol) { command(route[position]); ++position; if(position == sizeof(route)) position = 0; } else if(exits) command("go "+exits[random(sizeof(exits))]); else command("enter "+enters[random(sizeof(enters))]); } moving=0; } void set_moving(int i) { if(!heart_beat_on) set_heart_beat(heart_beat_on = 1); moving = 1; } void set_speed(int i) { speed = i; } void set_level(int x) { level = x; set_overall_ac(x + 1); set_max_hp(58 + (x * 65)); set_max_mp(58 + (x * 65)); set_max_sp(x*65); set_skill("melee", (x*4)); set_skill("attack", (x*4)); set_skill("defense", (x*4)); set_skill("blade", (x*4)); set_skill("knife", (x*4)); set_skill("blunt", (x*4)); set_skill("projectile", (x*4)); set_skill("two handed", (x*4)); set_stats("constitution", x*3/2); set_stats("strength", x*3/2); set_stats("intelligence", x*3/2); set_stats("wisdom", x*3/2); set_stats("dexterity", x*3/2); set_stats("charisma", x*3/2); set_exp( (int)ADVANCE_D->get_exp(x) ); set_mp(query_max_mp()); set_hp(query_max_hp()); set_sp(query_max_sp()); } int query_level() { return level; } // Added by Valodin, June 28, 1993 // Sets the body type to a certain race using the race daemon void set_body_type(string str) { mapping monster_bod; int mag, max_mag; string *mon_limbs; int i, max; if(!str || !RACE_D->is_monster_race(str)) str = "human"; mag = query_mp(); max_mag = query_max_mp(); init_limb_data(); monster_bod = (mapping)RACE_D->monster_body(str, query_max_hp()); for(i = 0, max = sizeof(mon_limbs = keys(monster_bod)); i < max; i++) add_limb(mon_limbs[i], monster_bod[mon_limbs[i]]["limb_ref"], monster_bod[mon_limbs[i]]["max_dam"], 0, 0); set_wielding_limbs((string *)RACE_D->query_monster_wielding_limbs(str)); set_fingers((int)RACE_D->query_monster_fingers(str)); body_type = str; set_mp(mag); set_max_mp(max_mag); } string query_body_type() { return body_type; } void set_spell_chance(int x) { if(!spells) spells = ([]); spells["chance"] = x; } void set_spells(string *arr) { if(!spells) spells = ([]); spells["commands"] = arr; } int query_spell_chance() { if(spells) return spells["chance"]; else return 0; } string *query_spells() { if(spells) return spells["commands"]; else return 0; } string get_random_spell() { if(!spells) return 0; if(sizeof(spells["commands"]) <2) return spells["commands"][0]; else return spells["commands"][random(sizeof(spells["commands"]))]; } void set_exp(int x) { if( x > (int)ADVANCE_D->get_exp(level) ) player_data["general"]["experience"] = (int)ADVANCE_D->get_exp(level); else player_data["general"]["experience"] = x; } // These two functions remain for backwards Nightmare 1.* and 2.* compat void set_chats(int x, string *arr) { set_emotes(x, arr, 0); } void set_achats(int x, string *arr) { set_emotes(x, arr, 1); } void set_emotes(int x, string *arr, int att) { emotes[(att ? "attack chance" : "chance")] = x; emotes[(att ? "attack msg" : "msg")] = arr; } mapping query_speech() { return speech; } void set_speech(int x, string lang, string *arr, int att) { if(!speech[lang]) speech[lang] = ([]); if(!speech[lang]["attack msg"]) speech[lang]["attack msg"] = ({}); if(!speech[lang]["msg"]) speech[lang]["msg"] = ({}); if(att) { speech[lang]["attack chance"] = x; speech[lang]["attack msg"] = arr; } else { speech[lang]["chance"] = x; speech[lang]["msg"] = arr; } } void set_alignment(int x) { player_data["general"]["alignment"] = x; } int test_heart() { object env; object *inv; int i; if(!this_object()) return 1; if(!(env = environment(this_object()))) return 0; if(query_current_attacker() || speed) return 1; i = sizeof(inv = all_inventory(env)); while(i--) if(interactive(inv[i]) || inv[i]->query("aggressive")) return 1; return 0; } int query_heart_status() { return heart_beat_on; } void receive_message(string cl, string msg) { this_object()->catch_tell(msg); } void set_languages(string *langs) { int i; i = sizeof(langs); while(i--) set_lang_prof(langs[i], 10); } void set_die(mixed val) { __Die = val; } mixed query_die() { return __Die; } void set_race(string str) { __Race = str; LANG_D->init_languages(this_object()); } string query_race() { return __Race; } void set_aggressive(mixed val) { __Aggressive = val; } mixed query_aggressive() { return __Aggressive; } string query_short() { return query_invis() ? 0 : living::query_short(); } int query_player_killer() { return 1; }