/*
* A general purpose monster. Clone this object,
* and call local functions to configure it.
*/
/*
* If you are going to copy this file, in the purpose of changing
* it a little to your own need, beware:
*
* First try one of the following:
*
* 1. Do clone_object(), and then configure it. This object is specially
* prepared for configuration.
*
* 2. If you still is not pleased with that, create a new empty
* object, and make an inheritance of this objet on the first line.
* This will automatically copy all variables and functions from the
* original object. Then, add the functions you want to change. The
* original function can still be accessed with '::' prepended on the name.
*
* The maintainer of this LPmud might become sad with you if you fail
* to do any of the above. Ask other wizards if you are doubtful.
*
* The reason of this, is that the above saves a lot of memory.
*/
#include "living.h"
/*
* The heart beat is always started in living.h when we are attacked.
*/
string short_desc, long_desc, alias, alt_name, race;
int move_at_reset, aggressive;
object kill_ob;
status healing; /* True if this monster is healing itself. */
string chat_head; /* Vector with all chat strings. */
int chat_chance;
string a_chat_head; /* Vector with all a_chat strings. */
int a_chat_chance;
object talk_ob;
string talk_func; /* Vector of functions. */
string talk_match; /* Vector of strings. */
string talk_type; /* Vector of types. */
string the_text;
int have_text;
object dead_ob;
object init_ob;
int random_pick;
int spell_chance, spell_damage;
string spell_mess1, spell_mess2;
object me;
object create_room;
random_move();
test_match();
heal_slowly();
pick_any_obj();
reset(arg)
{
if (arg) {
if (move_at_reset)
random_move();
return;
}
is_npc = 1;
enable_commands();
me = this_object();
create_room = environment(me);
}
random_move()
{
int n;
n = random(4);
if (n == 0)
command("west");
else if (n == 1)
command("east");
else if (n == 2)
command("south");
else if (n == 3)
command("north");
}
short() {
return short_desc;
}
long() {
write (long_desc);
}
id(str) { return str == name || str == alias || str == race || str == alt_name; }
heart_beat()
{
int c;
age += 1;
if(!test_if_any_here()) {
if(have_text && talk_ob) {
have_text = 0;
test_match(the_text);
} else {
set_heart_beat(0);
if (!healing)
heal_slowly();
return;
}
}
if (kill_ob && present(kill_ob, environment(this_object()))) {
if (random(2) == 1)
return; /* Delay attack some */
attack_object(kill_ob);
kill_ob = 0;
return;
}
if (attacker_ob && present(attacker_ob, environment(this_object())) &&
spell_chance > random(100)) {
say(spell_mess1 + "\n", attacker_ob);
tell_object(attacker_ob, spell_mess2 + "\n");
attacker_ob->hit_player(random(spell_damage));
}
attack();
if (attacker_ob && whimpy && hit_point < max_hp/5)
run_away();
if(chat_chance || a_chat_chance){
c = random(100);
if(attacker_ob && a_chat_head) {
if(c < a_chat_chance){
c = random(sizeof(a_chat_head));
tell_room(environment(), a_chat_head[c]);
}
} else {
if(c < chat_chance && chat_chance){
c = random(sizeof(chat_head));
tell_room(environment(), chat_head[c]);
}
}
}
if(random_pick) {
c = random(100);
if(c < random_pick)
pick_any_obj();
}
if(have_text && talk_ob) {
have_text = 0;
test_match(the_text);
}
}
can_put_and_get(str)
{
if (!str)
return 0;
return 1;
}
int busy_catch_tell;
catch_tell(str) {
if (busy_catch_tell)
return;
busy_catch_tell = 1;
if(talk_ob) {
if(have_text) {
test_match(the_text);
the_text = str;
} else {
the_text = str;
have_text = 1;
}
}
busy_catch_tell = 0;
}
/*
* Call the following functions to setup the monster.
* Call them in the order they appear.
*/
set_name(n) {
name = n;
set_living_name(n);
alignment = 0; /* Neutral monster */
cap_name = capitalize(n);
short_desc = cap_name;
long_desc = "You see nothing special.\n";
}
set_level(l) {
level = l;
Str = l; Int = l; Con = l; Dex = l;
weapon_class = level/2 + 3;
armour_class = level/4;
hit_point = 50 + (level - 1) * 8; /* Same as a player */
max_hp = hit_point;
spell_points = max_hp;
experience = "room/adv_guild"->query_cost(l-1);
/* This is for level 1 monsters. */
if (experience == 0)
experience = random(500);
}
/* Optional */
set_alias(a) { alias = a; }
/* Optional */
set_alt_name(a) { alt_name = a; }
/* Optional */
set_race(r) { race = r; }
/* optional */
set_hp(hp) { max_hp = hp; hit_point = hp; }
/* optional. Can only be lowered */
set_ep(ep) { if (ep < experience) experience = ep; }
/* optional */
set_al(al) { alignment = al; }
/* optional */
set_short(sh) { short_desc = sh; long_desc = short_desc + "\n";}
/* optional */
set_long(lo) { long_desc = lo; }
/* optional */
set_wc(wc) { if (wc > weapon_class) weapon_class = wc; }
/* optional */
set_ac(ac) { if (ac > armour_class) armour_class = ac; }
/* optional */
set_move_at_reset() { move_at_reset = 1; }
/* optional
* 0: Peaceful.
* 1: Attack on sight.
*/
set_aggressive(a) {
aggressive = a;
}
/*
* Now some functions for setting up spells !
*/
/*
* The percent chance of casting a spell.
*/
set_chance(c) {
spell_chance = c;
}
/* Message to the victim. */
set_spell_mess1(m) {
spell_mess1 = m;
}
set_spell_mess2(m) {
spell_mess2 = m;
}
set_spell_dam(d) {
spell_damage = d;
}
/* Set the frog curse. */
set_frog() {
frog = 1;
}
/* Set the whimpy mode */
set_whimpy() {
whimpy = 1;
}
/*
* Force the monster to do a command. The force_us() function isn't
* always good, because it checks the level of the caller, and this function
* can be called by a room.
*/
init_command(cmd) {
command(cmd);
}
load_chat(chance, strs) {
sizeof(strs); /* Just ensure that it is an array. */
chat_head = strs;
chat_chance = chance;
}
/* Load attack chat */
load_a_chat(chance, strs) {
sizeof(strs); /* Just ensure that it is an array. */
a_chat_head = strs;
a_chat_chance = chance;
}
/* Catch the talk */
set_match(ob, func, type, match) {
object old;
if (sizeof(func) != sizeof(type) || sizeof(match) != sizeof(type))
return;
talk_ob = ob;
talk_func = func;
talk_type = type;
talk_match = match;
say("talk match length " + sizeof(func) + "\n");
}
set_dead_ob(ob)
{
dead_ob = ob;
}
second_life()
{
if(dead_ob)
return dead_ob->monster_died(this_object());
}
set_random_pick(r)
{
random_pick = r;
}
pick_any_obj() {
object ob;
int weight;
ob = first_inventory(environment(this_object()));
while(ob) {
if (ob->get() && ob->short()) {
weight = ob->query_weight();
if (!add_weight(weight)) {
say(cap_name + " tries to take " + ob->short() +
" but fails.\n");
return;
}
move_object(ob, this_object());
say(cap_name + " takes " + ob->short() + ".\n");
if (ob->weapon_class())
ob->wield(ob->query_name());
else if (ob->armour_class())
ob->wear(ob->query_name());
return;
}
ob = next_inventory(ob);
}
}
set_init_ob(ob)
{
init_ob = ob;
}
init() {
create_room = environment(me);
if(this_player() == me)
return;
if(init_ob)
if(init_ob->monster_init(this_object()))
return;
if (attacker_ob) {
set_heart_beat(1); /* Turn on heart beat */
}
if(this_player() && !this_player()->query_npc()) {
set_heart_beat(1);
if (aggressive == 1)
kill_ob = this_player();
}
}
query_create_room() { return create_room; }
query_race() { return race; }
test_match(str) {
string who, str1, type, match, func;
int i;
while(i < sizeof(talk_match)) {
if (talk_type[i])
type = talk_type[i];
match = talk_match[i];
if (match == 0)
match = "";
if (talk_func[i])
func = talk_func[i];
if (sscanf(str,"%s " + type + match + " %s\n",who,str1) == 2 ||
sscanf(str,"%s " + type + match + "\n",who) == 1 ||
sscanf(str,"%s " + type + match + "%s\n",who,str1) == 2 ||
sscanf(str,"%s " + type + " " + match + "\n",who) == 1 ||
sscanf(str,"%s " + type + " " + match + " %s\n",who,str1) == 2)
{
return call_other(talk_ob, func, str);
}
i += 1;
}
}
/*
* The monster will heal itself slowly.
*/
heal_slowly() {
hit_point += 120 / (INTERVAL_BETWEEN_HEALING * 2);
if (hit_point > max_hp)
hit_point = max_hp;
spell_points += 120 / (INTERVAL_BETWEEN_HEALING * 2);
if (spell_points > max_hp)
spell_points = max_hp;
healing = 1;
if (hit_point < max_hp || spell_points < max_hp)
call_out("heal_slowly", 120);
else
healing = 0;
}