#pragma strict_types #pragma save_types #pragma combine_strings #include <mudlib.h> inherit LIVING; #include <monster.spc> #include <spell.h> /* Must come after monster.spc */ #define HEALING_TIME 60 /* 60 hearbeats */ #define STOLEN_TIME 180 /* 180 heart beats call reset(1) */ #define FILE_SIZE (int)"obj/master"->master_file_size status move_at_reset; /* True will make the monster wander at reset. */ status aggressive; /* True will make monster attack on sight. */ int stolen; /* has something been stolen */ int healing; /* heart_beats since last healing */ string *chat_head; /* list of chat strings. */ int chat_chance; /* chance at each heart beat to chat */ string *a_chat_head; /* list of attack chats */ int a_chat_chance; /* chance at each heart beat to use attack chat */ string *l_chat_head; /* list of chats spoken in language */ string chat_language; /* language chats spoken in */ int l_chat_chance; /* chance each heart beat to chat */ object dead_ob; /* alternative objects to call fn */ object init_ob; object heart_ob; int random_pick; /* Chance to pick up items every heart_beat. */ int wander; /* wander at this many heart beats */ int wander_time; /* Counter for wandering */ int new_spell_chance; /* chance each heart beat to cast spell */ string *new_spells; /* list of 'player' spell commands */ int spell_chance; /* chance each heart beat to cast spell */ mixed *default_spell; /* specialized spell of monster */ int steal_chance; /* chance per init to steal */ status no_kill_flag; /* won't allow attacks on monster */ static string skill_cmd; /* current skill command */ /***************************************************************************/ void reset(status arg) { #ifdef NATIVE_MODE arg = 1; #else ::reset(arg); #endif /* native */ if(arg) { if(stolen) { if(environment()) environment()->reset(1); } stolen = 0; if(move_at_reset) random_move(); return; } #ifdef NATIVE_MODE } void create() { ::create(); #endif /* native */ is_npc = 1; enable_commands(); add_class("fighter"); /* all monsters start off as a fighter, add or subtract the ones u want */ add_action("communicate","say"); add_action("skills", "", 1); default_spell = allocate(SPELL_ALLOCATE); } /*************************************************************************/ /* sets */ object set_heart_ob(object ob) { return heart_ob = ob; } object set_dead_ob(object ob) { return dead_ob = ob; } object set_init_ob(object ob) { return init_ob = ob; } int set_random_pick(int r) { return random_pick = r; } int set_steal_chance(int s) { return steal_chance = s; } int query_steal_chance() { return steal_chance; } status set_no_kill_flag(status s) { return no_kill_flag = (s) ? 1 : 0; } status set_move_at_reset(status i) { return move_at_reset = (i) ? 1 : 0; } status set_aggressive(status a) { return aggressive = (a) ? 1 : 0; } string set_name(string n) { set_living_name(lower_case(n)); set_short(capitalize(n)); set_alt_name(lower_case(n)); return ::set_name(capitalize(n)); } /*** set level will automatically set monster to bare minimum requirements ***/ void set_level(int l) { int *monster_exp; if(!intp(l) || l < 1) l = 1; level = l; combat = l; dexterity = l; strength = l; charisma = l; intelligence = l; wisdom = l; constitution = l; /*** set thief skills ***/ if(query_class("thief")) { stealth = l; locks = l; steal = l; climb = l; backstab = l; appraisal = l; traps = l; } /*** set fighting skills ***/ if(query_class("fighter")) { two_weapon = l; unarmed = l; multi_attack = l; multi_opponent = l; } /*** set cleric skills ***/ if(query_class("cleric")) { healing_sphere = l; necromancy_sphere = l; combat_sphere = l; stellar_sphere = l; protection_sphere = l; nature_sphere = l; divination_sphere = l; heal_cleric(l*2); } /*** set mage skills ***/ if(query_class("mage")) { illusion = l; charm = l; conjuration = l; abjuration = l; necromancy = l; evocation = l; divination = l; alteration = l; heal_mage(l*2); } /*** set psionicist skills ***/ /* if(query_class("psionicist")) { clairsentient = l; psycokinetic = l; psycoportive = l; psycometabolic = l; telepathic = l; metapsionic = l; max_psionic_points = 6 * l; } */ heal_self(10000); /*** set weapon class ***/ set_right_wc(l+5); if(query_right_wc() > 30) set_right_wc(30); /*** set armour class ***/ if(l < 14) armour_class = l/2 + 3; else armour_class = l - 3; if(armour_class > 17) armour_class = 17; /*** set hit points and spells points? ***/ if(l < 5) hp = l * 10 + 40; else if(l < 10) hp = l * 50 - 150; else if(l < 15) hp = l * 100 - 600; else if(l < 20) hp = l * 200 - 2000; else if(l < 25) hp = l * 300 - 3900; else hp = 3500; max_hp = hp; /*** set experience points ***/ monster_exp = ({ 676, 1014, 1522, 2283, 3425, 5138, 7707, 11561, 17341, 26012, 39018, 58527, 87791, 131687, 197530, 296296, 444444, 666666, 1000000, 1500000,2000000,2500000,3000000,3500000, 4000000, 4500000 }); if(l > sizeof(monster_exp) - 1) { experience = monster_exp[sizeof(monster_exp) - 1]; experience += (l - (sizeof(monster_exp) - 1)) * 500000; } else experience = monster_exp[l]; /*** high level monsters do additional damage ***/ if(l > 15) { spell_chance = ((l - 14)*10 > 75) ? 75 : (l - 14)*10; TARGET_MSG = "A fireball erupts, cast directly at you!\n"; ROOM_MSG = "@@query_name:$this_player()$@@ casts a fireball at "+ "@@query_name:$this_object()$@@.\n"; IMMUNE_TYPE = "fire"; SPELL_TYPE = "evocation"; SPELL_DAM = (l - 14) * 5 + random((l - 14) * 5); SPELL_LEVEL = l; SPELL_COST = 2; /* spell strength runs out eventually */ } } void add_class(string str) { ::add_class(str); /*** set thief skills ***/ if(query_class("thief")) { stealth = level; locks = level; steal = level; climb = level; backstab = level; appraisal = level; traps = level; } /*** set fighting skills ***/ if(query_class("fighter")) { two_weapon = level; unarmed = level; multi_attack = level; multi_opponent = level; } /*** set cleric skills ***/ if(query_class("cleric")) { healing_sphere = level; necromancy_sphere = level; combat_sphere = level; stellar_sphere = level; protection_sphere = level; nature_sphere = level; divination_sphere = level; heal_cleric(level*2); } /*** set mage skills ***/ if(query_class("mage")) { illusion = level; charm = level; conjuration = level; abjuration = level; necromancy = level; evocation = level; divination = level; alteration = level; heal_mage(level*2); } /*** set psionicist skills ***/ /* if(query_class("psionicist")) { clairsentient = level; psycokinetic = level; psycoportive = level; psycometabolic = level; telepathic = level; metapsionic = level; max_psionic_points = 6 * level; } */ } void set_wander(int chance, int time) { wander = time; set_heart_beat(1); } /************************************/ /* old way for spells */ int set_chance(int c) { return spell_chance = c; } int set_spell_dam(int d) { return SPELL_DAM = d; } string set_spell_mess1(string m) { return TARGET_MSG = m; } string set_spell_mess2(string m) { return ROOM_MSG = m; } string set_spell_type(string t) { return IMMUNE_TYPE = t; } string set_spell_skill_type(string str) { string *spell_skills; spell_skills = ({ "healing_sphere", "necromancy_sphere", "combat_sphere", "stellar_sphere", "protection_sphere", "nature_sphere", "divination_sphere", "illusion", "charm", "conjuration", "abjuration", "necromancy", "evocation", "divination", "alteration", }); if(!str || member_array(str, spell_skills) == -1) { str = spell_skills[random(sizeof(spell_skills))]; } return SPELL_TYPE = str; } /**************************************/ /* new way */ void set_spell(mixed *arr) { int i; default_spell = allocate(SPELL_ALLOCATE); for(i = 0; i < sizeof(arr); i++) { if(!stringp(arr[i])) continue; switch(arr[i]) { case "target": TARGET = arr[++i]; break; case "name": case "spellname": SPELL_NAME = arr[++i]; break; case "school": case "sphere": SPELL_TYPE = arr[++i]; break; case "cost": SPELL_COST = arr[++i]; break; case "damage": SPELL_DAM = arr[++i]; break; case "msg target": TARGET_MSG = arr[++i]; break; case "msg room": ROOM_MSG = arr[++i]; break; case "msg caster": CASTER_MSG = arr[++i]; break; #ifdef OLD_AREA_EFFECT case "area": AREA_EFFECT = this_object(); break; #else case "area": AREA_EFFECT = all_inventory(environment()); break; #endif case "immune": IMMUNE_TYPE = arr[++i]; break; case "level": case "spell level": SPELL_LEVEL = arr[++i]; break; case "spell object": SPELL_OBJ = arr[++i]; break; case "time": case "cast time": SPELL_TIME = arr[++i]; break; case "casting msg": PREPARE_MSG = arr[++i]; break; case "casting msg room": PREP_MSG_ROOM = arr[++i]; break; case "component": COMPONENT = arr[++i]; break; case "passive": PASSIVE = 1; break; case "aggressive": PASSIVE = 0; break; case "chance": spell_chance = arr[++i]; break; } } } /* can call player spells */ void load_spells(int c, string *s) { sizeof(s); new_spells = s; new_spell_chance = c; } /*************************************************************************/ /* query */ status query_no_kill_flag() { return no_kill_flag; } /***********************************************************************/ /* heart beat */ static status filter_players(object ob) { if(living(ob) && !ob->query_npc()) return 1; return 0; } void heart_beat() { int player_here; string cmd; object *inv; if(!environment()) { set_heart_beat(0); return; } adj_age(1); if(heart_ob) heart_ob->monster_heart_beat(); inv = all_inventory(environment()); player_here = sizeof(filter_array(inv,"filter_players",this_object())); if(stolen) { if(stolen++ > STOLEN_TIME) reset(1); } if(!player_here) { if(hp < max_hp) { if(healing++ > HEALING_TIME) { healing = 0; heal_self(1); } } else if(!wander && !stolen) { set_heart_beat(0); return; } if(wander) { if(wander_time++ > wander && !random(4)) { random_move(); } } return; } if(primary_attack && present(primary_attack, environment())) { if(a_chat_chance > random(100) + 1) { tell_room(environment(), a_chat_head[random(sizeof(a_chat_head))]); } if(spell_chance > random(100) + 1) { if(objectp(SPELL_TYPE)) { /* wand */ if((int)SPELL_TYPE->query_charges() > SPELL_COST) { set_loaded_spell(default_spell); SPELL_TYPE->adj_charges(-SPELL_COST); } } else if(query(SPELL_TYPE+"_points") > SPELL_COST) { set_loaded_spell(default_spell); call_other(this_object(),"adj_"+SPELL_TYPE+"_points",-SPELL_COST); } } if(new_spell_chance > random(100) + 1) { } if(query_wimpy() && hp < max_hp/5) random_move(); } else { if(chat_chance > random(100) + 1) { tell_room(environment(), chat_head[random(sizeof(chat_head))]); } if(l_chat_chance > random(100) + 1) { command("say "+l_chat_head[random(sizeof(l_chat_head))]); } } if(random_pick > random(100) + 1) { pick_any_obj(); } attack(); } /**************************************************************************/ status init_command(string cmd) { status cmd_flag; if(sscanf(cmd, "%s %s", skill_cmd, cmd)) { cmd = skill_cmd +" "+ cmd; } else { skill_cmd = cmd; } cmd_flag = command(cmd, this_object()); skill_cmd = 0; return cmd_flag; } /***************************************************************************/ /*** Load Chats and Attack chats. ***/ void load_chat(int chance, string *strs) { if(!sizeof(strs)) return; /* Just ensure that it is an array. */ chat_head = strs; chat_chance = chance; } void load_a_chat(int chance, string *strs) { if(!sizeof(strs)) return; /* Just ensure that it is an array. */ a_chat_head = strs; a_chat_chance = chance; } /*** Load language chat - Zilanthius ***/ void load_l_chat(int chance, string lang, string *strs) { if(!sizeof(strs)) return; /* Just ensure that it is an array. */ l_chat_head = strs; l_chat_chance = chance; chat_language = lang; if(!chat_language){ if(race) chat_language = lower_case(race); else chat_language = "common"; } } /****************************************************************************/ status second_life() { if(dead_ob) return (status)dead_ob->monster_died(this_object()); } /****************************************************************************/ void pick_any_obj () { object ob; int weight; ob = first_inventory(environment()); while (ob) { if(ob->get() && ob->short()) { weight = (int)ob->query_weight(); if(!add_weight(weight)) { say (query_name()+" tries to take "+ob->short()+" but fails.\n"); return; } #ifdef NATIVE_MODE ob->move(this_object()); #else move_object(ob, this_object()); #endif /* NATIVE_MODE */ say(query_name() +" takes "+ ob->short() +".\n"); return; } ob = next_inventory(ob); } } /************************************************************************/ void init() { string who; ::init(); if(this_player() == this_object()) return; if(init_ob && init_ob->monster_init(this_object())) return; if(primary_attack) set_heart_beat(1); /* Turn on heart beat */ if(!this_player()->query_npc()) { if(!this_player()->query_entering()) { who = (string)this_player()->query_name(1); if(!sec_att_names) sec_att_names = ({}); if(member_array(who, sec_att_names) != -1 || (who && member_array(capitalize(who), sec_att_names) != -1)){ add_secondary_attacker(this_player()); } } set_heart_beat(1); if(aggressive) { string rname; rname = (string)this_player()->query_name(1); if(query_class("thief")) stealth_on = 1; /* needed for bs */ if(this_player()->query_stealth_on()) { if(sizeof(compare("stealth","intelligence", ({ this_object(), })))) { if(query_class("thief")) { skill_cmd = "backstab"; command("backstab "+ rname, this_object()); skill_cmd = 0; } add_secondary_attacker(this_player()); /* get ready to attack */ } } else if(this_player()->query_invis()) { if(sizeof(compare("invis","intelligence", ({ this_object(), })))) { if(query_class("thief")) { skill_cmd = "backstab"; command("backstab "+ rname, this_object()); skill_cmd = 0; } add_secondary_attacker(this_player()); /* get ready to attack */ } } else { if(query_class("thief")) { skill_cmd = "backstab"; command("backstab "+ rname, this_object()); skill_cmd = 0; } add_secondary_attacker(this_player()); /* get ready to attack */ } } else { /* not aggressive */ if(query_class("thief") && random(100) < steal_chance) { steal_from_player(this_player(),0); } } } } /*** stealing from a monster, call "steal" if something is stolen... ***/ void steal() { stolen = 1; set_heart_beat(1); } void steal_from_player(object who, mixed item) { object *inv; int i; string item_name; if(!item) { inv = all_inventory(this_player()); if(!(i = sizeof(inv))) return; i = random(i); if(!(item_name = (string)inv[i]->query_name())) return; } else if(objectp(item)) { item_name = (string)item->query_name(1); } else if(stringp(item)) { item_name = item; } else { return; } skill_cmd = "steal"; command("steal "+ item_name +" from "+ (string)who->query_name(1)); skill_cmd = 0; } /************************************************************************/ /* load function added by Crombie, Sept 8, 1993 */ void load_monster(mixed name, int lev, string race) { int i, size; if(!stringp(name)) { for(i = 0, size = sizeof(name); i < size; i++) { if(!stringp(name[i])) continue; switch(name[i]) { case "name": set_name(name[++i]); break; case "level": set_level(name[++i]); break; case "alias": set_alias(name[++i]); break; case "race": set_race(name[++i]); break; case "hp": set_hp(name[++i]); break; case "exp": set_exp(name[++i]); break; case "al": set_al(name[++i]); break; case "short": set_short(name[++i]); break; case "long": set_long(name[++i]); break; case "altname": set_alt_name(name[++i]); break; case "alt_name" : set_alt_name(name[++i]); break; case "wc": set_right_wc(name[++i]); break; case "ac": set_ac(name[++i]); break; case "aggressive": set_aggressive(1); break; case "whimpy": set_wimpy(1); break; case "move_at_reset": set_move_at_reset(1); break; case "chance": set_chance(name[++i]); break; case "heart_ob": set_heart_ob(this_object()); break; case "mess1": set_spell_mess1(name[++i]); break; case "spell_mess1": set_spell_mess1(name[++i]); break; case "mess2": set_spell_mess2(name[++i]); break; case "spell_mess2": set_spell_mess2(name[++i]); break; case "dam": set_spell_dam(name[++i]); break; case "spell_dam": set_spell_dam(name[++i]); break; case "spell_type": set_spell_type(name[++i]); break; case "spell_skill_type": set_spell_skill_type(name[++i]); break; case "gender": set_gender(name[++i]); break; case "deadob": set_dead_ob(this_object()); break; case "randompick": set_random_pick(name[++i]); break; case "init_command" : init_command(name[++i]); break; case "random_pick": set_random_pick(name[++i]); break; case "magic_resist" : set_magic_resist(name[++i]); break; case "add_money" : add_money(name[++i]); break; case "money" : add_money(name[++i]); break; } } } else { set_name(name); set_level(lev); set_race(race); } } /*********************************************************************/ int hit_player(int dmg) { if(environment(this_player())->query_no_fight()) { if(this_player()) this_player()->stop_fight(this_object()); stop_fight(this_player()); write("Fighting is Not Allowed Here.\n"); return 0; } return ::hit_player(dmg); } /*********************************************************************/ /* monster skill commands */ status skills(string str) { string verb; int i; verb = query_verb(); /* verb must match current skill command */ if(verb != skill_cmd) { skill_cmd = 0; return 0; } skill_cmd = 0; for(i = 0; i < sizeof(classes); i++) { if(FILE_SIZE("/skills/"+ classes[i] +"/"+ verb +".c") > 0) { if(call_other("skills/"+ classes[i] +"/"+ verb,verb,str)) return 1; } } return 0; }