/* monster.c */
#include <sys.h>
#include <weapon.h>
#include <armor.h>
#include <combat_def.h>
#include <flags.h>
#define TP(X) tell_player(this_object(),(X))
#define TPE(X) tell_room_except(location(this_object()),this_object(),(X))
#define TPE2(X) tell_room_except2(location(this_object()),this_object(), \
is_attacking,(X))
object me;
object is_attacking;
string name,short,long;
int alive,hp,max_hp,xp,level,flags,special,hit_bonus,dam_num_die,dam_die_size,
dam_bonus,hitreduce,damreduce,armor_hit,armor_dam,is_healing;
object weapon,possessor,last_location,owner;
string msg_array1[MAX_INTENSITY];
string msg_array2[MAX_INTENSITY];
string msg_array3[MAX_INTENSITY];
string msg_array4[MAX_INTENSITY];
string msg_array5[MAX_INTENSITY];
object armor_worn[NUM_PROT];
self_destruct() { destruct(this_object()); return 1; }
static autoheal() {
hp+=HEAL_AMOUNT;
if (hp>=max_hp) {
is_healing=0;
hp=max_hp;
} else
alarm(HEAL_DELAY,"autoheal");
}
set_hitreduce(arg) { hitreduce=arg; return 1; }
set_damreduce(arg) { damreduce=arg; return 1; }
get_hitreduce() { return hitreduce+armor_hit; }
get_damreduce() { return damreduce+armor_dam; }
replicate() {
object o;
int loop;
o=clone_object("/obj/monster");
call_other(o,"set_name",get_name());
call_other(o,"set_short",short);
call_other(o,"set_long",long);
call_other(o,"set_special",special);
call_other(o,"set_flags",flags);
call_other(o,"set_owner",owner);
call_other(o,"set_level",level);
call_other(o,"set_damage_bonus",dam_num_die,dam_die_size,dam_bonus);
call_other(o,"set_hit_bonus",hit_bonus);
call_other(o,"set_hp",max_hp);
call_other(o,"set_xp",xp);
call_other(o,"set_hitreduce",hitreduce);
call_other(o,"set_damreduce",damreduce);
loop=0;
while (loop<MAX_INTENSITY) {
call_other(o,"set_hit_msg",loop,msg_array1[loop],msg_array2[loop],
msg_array3[loop],msg_array4[loop],msg_array5[loop]);
loop++;
}
move_object(o,location(this_object()));
return o;
}
static do_exits(arg) {
object curr;
int count,pos;
string ename;
if (location(this_object())) curr=contents(location(this_object()));
while (curr) {
if (call_other(curr,"get_type")==TYPE_EXIT)
if (!(call_other(curr,"get_flags") & F_DARK)) {
if (!count) write("Obvious exits:");
ename=call_other(curr,"get_name");
pos=instr(ename,1,";");
if (pos)
write(" "+leftstr(ename,pos-1));
else
write(" "+ename);
count++;
}
curr=next_object(curr);
}
if (!count)
write("There are no obvious exits.\n");
else
write("\n");
return 1;
}
static do_wear(arg) {
string w_name;
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,this_object());
if (!arg) {
write("You don't have that.\n");
return 1;
}
if (call_other(arg,"get_type")!=TYPE_ARMOR) {
write("You can't wear that.\n");
return 1;
}
if (armor_worn[call_other(arg,"get_protection")]) {
write("You're already wearing something on your "+
make_prot(call_other(arg,"get_protection"))+".\n");
return 1;
}
w_name=call_other(arg,"get_short");
if (!call_other(arg,"wear")) {
write("You can't wear that.\n");
return 1;
}
write("You wear "+w_name+".\n");
TPE(get_short()+" wears "+w_name+".\n");
armor_worn[call_other(arg,"get_protection")]=arg;
recalc_armor();
return 1;
}
recalc_armor() {
int loop;
armor_hit=0;
armor_dam=0;
loop=0;
while (loop<NUM_PROT) {
if (armor_worn[loop]) {
armor_hit+=call_other(armor_worn[loop],"get_hitreduce");
armor_dam+=call_other(armor_worn[loop],"get_damreduce");
}
loop++;
}
}
force_unwear(p) {
if (armor_worn[p]!=caller_object()) return;
armor_worn[p]=0;
recalc_armor();
}
static do_unwear(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,this_object());
if (call_other(arg,"get_type")!=TYPE_ARMOR) {
write("You're not wearing that.\n");
return 1;
}
if (armor_worn[call_other(arg,"get_protection")]!=arg) {
write("You're not wearing that.\n");
return 1;
}
if (call_other(arg,"unwear")) {
write("You can't unwear that.\n");
return 1;
}
armor_worn[call_other(arg,"get_protection")]=0;
recalc_armor();
write("You unwear "+call_other(arg,"get_short")+".\n");
TPE(get_short()+" unwears "+call_other(arg,"get_short")+".\n");
return 1;
}
set_owner(x) { owner=x; return 1; }
get_owner() { return owner; }
set_hp(x) { hp=x; max_hp=x; return 1; }
set_xp(x) { xp=x; return 1; }
set_level(x) {
int loop;
if (x<1) x=1;
if (x>15) x=15;
loop=x;
xp=1;
while (--loop) {
xp*=2;
}
xp*=5;
level=x;
hitreduce=2*level-2;
hit_bonus=2*level-2;
max_hp=10+4*level;
hp=10+4*level;
return 1;
}
set_damage_bonus(x,y,z) {
dam_num_die=x;
dam_die_size=y;
dam_bonus=z;
return 1;
}
set_hit_bonus(x) { hit_bonus=x; return 1; }
get_hp() { return hp; }
get_xp() { return xp; }
get_level() { return level; }
stat() {
int loop;
tell_player(this_player(),"Object Type: MONSTER\n");
if (flags) tell_player(this_player(),"Flags: "+make_flags(flags)+"\n");
if (special) tell_player(this_player(),"Special: "+itoa(special)+"\n");
if (name)
tell_player(this_player(),"Name: "+get_name()+"\n");
if (short)
tell_player(this_player(),"Short: "+short+"\n");
if (long)
tell_player(this_player(),"Long: "+long+"\n");
if (alive)
tell_player(this_player(),"HP: "+itoa(hp)+"/"+itoa(max_hp)+
" XP: "+itoa(xp)+" Level: "+itoa(level)+"\n");
else
tell_player(this_player(),"HP: DEAD/"+itoa(max_hp)+" XP: "+
itoa(xp)+" Level: "+itoa(level)+"\n");
tell_player(this_player(),"HitBonus: "+itoa(hit_bonus)+" (With Weapon: "+
itoa(hit_bonus+(weapon?call_other(weapon,"get_hit_bonus"):0))+
")\n");
tell_player(this_player(),"Damage: "+itoa(dam_num_die)+"d"+
itoa(dam_die_size)+"+"+itoa(dam_bonus)+
" (With Weapon: "+(weapon?call_other(weapon,"get_damage"):
(itoa(dam_num_die)+"d"+itoa(dam_die_size)+"+"+itoa(dam_bonus)))
+")\n");
tell_player(this_player(),"HitReduce: "+itoa(hitreduce)+
" (With Armor: "+itoa(get_hitreduce())+")\n");
tell_player(this_player(),"DamReduce: "+itoa(damreduce)+
" (With Armor: "+itoa(get_damreduce())+")\n");
if (weapon)
tell_player(this_player(),"Wielding: "+make_num(weapon)+"\n");
loop=0;
if (is_attacking)
tell_player(this_player(),"Is Attacking: "+make_num(is_attacking)+"\n");
if (owner) tell_player(this_player(),"Owner: "+make_num(owner)+"\n");
if (possessor && priv(this_player()))
tell_player(this_player(),"Possessed By: "+make_num(possessor)+"\n");
loop=0;
while (loop<MAX_INTENSITY) {
if (msg_array1[loop] || msg_array2[loop] || msg_array3[loop] ||
msg_array4[loop] || msg_array5[loop])
tell_player(this_player(),call_other(atoo("/obj/weapon"),
"intensity_string",loop)+": "+
msg_array1[loop]+"*"+msg_array2[loop]+";"+
msg_array3[loop]+";"+
msg_array4[loop]+"*"+msg_array5[loop]+"\n");
loop++;
}
return 1;
}
id(arg) { return instr(name,1,";"+arg+";"); }
set_possessor(arg) {
if (!arg && possessor==caller_object()) {
possessor=0;
return 1;
}
if (arg!=caller_object()) return 0;
if (possessor && arg) return 0;
possessor=arg;
return 1;
}
force(arg) {
command(arg);
return 1;
}
set_name(arg) {
int pos;
name=";"+arg+";";
pos=instr(arg,1,";");
if (!short)
if (pos)
short="a "+leftstr(arg,pos-1);
else
short="a "+arg;
return 1;
}
set_flags(f) { flags=f; return 1; }
set_special(s) { special=s; return 1; }
get_flags() { return flags; }
get_special() { return special; }
do_say(arg) {
write("You say \""+arg+"\"\n");
TPE(short+" says \""+arg+"\"\n");
return 1;
}
do_pose(arg) {
write(short+" "+arg+"\n");
TPE(short+" "+arg+"\n");
return 1;
}
impending_attack() {
if (is_attacking) return xp;
is_attacking=caller_object();
attack(0);
return xp;
}
get_name() {
if (name)
return midstr(name,2,strlen(name)-2);
}
get_hit_msg1(intensity) {
string s;
if (weapon) s=call_other(weapon,"get_hit_msg1",intensity);
else s=msg_array1[intensity];
if (!s) s=get_def_hit_msg1(intensity);
return s;
}
get_hit_msg2(intensity) {
string s;
if (weapon) s=call_other(weapon,"get_hit_msg2",intensity);
else s=msg_array2[intensity];
if (!s) s=get_def_hit_msg2(intensity);
return s;
}
get_hit_msg3(intensity) {
string s;
if (weapon) s=call_other(weapon,"get_hit_msg3",intensity);
else s=msg_array3[intensity];
if (!s) s=get_def_hit_msg3(intensity);
return s;
}
get_hit_msg4(intensity) {
string s;
if (weapon) s=call_other(weapon,"get_hit_msg4",intensity);
else s=msg_array4[intensity];
if (!s) s=get_def_hit_msg4(intensity);
return s;
}
set_hit_msg(intensity,msg1,msg2,msg3,msg4,msg5) {
if (intensity<0 || intensity>=MAX_INTENSITY) return 0;
msg_array1[intensity]=msg1;
msg_array2[intensity]=msg2;
msg_array3[intensity]=msg3;
msg_array4[intensity]=msg4;
msg_array5[intensity]=msg5;
return 1;
}
get_hit_msg5(intensity) {
string s;
if (weapon) s=call_other(weapon,"get_hit_msg5",intensity);
else s=msg_array5[intensity];
if (!s) s=get_def_hit_msg5(intensity);
return s;
}
set_long(arg) { long=arg; return 1; }
get_long() {
if (long) return long;
else return "Little. Yellow. Different.";
}
move_player(dest,direction) {
if (location(this_object()))
TPE(short+" goes "+direction+".\n");
move_object(this_object(),dest);
look(0);
if (dest)
TPE(short+" has arrived.\n");
if (flags & F_HOSTILE) attack();
return 1;
}
look(arg) {
int contents_printed,curr;
string oname,t;
contents_printed=0;
t=arg;
if (arg) {
arg=present(arg,location(this_object()));
if (!arg) arg=present(t,this_object());
if (!arg && t=="me") arg=this_object();
if (!arg && t=="here") arg=location(this_object());
} else
if (!location(this_object())) {
write("You are in the void.\n");
return 1;
} else
arg=location(this_object());
if (!arg) {
write("You don't see that here.\n");
return 1;
}
if (arg==location(this_object())) {
oname=call_other(arg,"get_short");
if (oname) write(oname+"\n");
}
oname=call_other(arg,"get_long");
if (oname) write(oname+"\n");
curr=contents(arg);
if (!(call_other(arg,"get_flags") & F_DARK))
while (curr) {
if (curr!=this_object()) {
oname=call_other(curr,"get_short");
if (oname) {
if (!contents_printed) {
write("Contents:\n");
contents_printed=1;
}
write(oname+"\n");
}
}
curr=next_object(curr);
}
return 1;
}
get_type() { return TYPE_MONSTER; }
find_enemy() {
object curr;
curr=location(this_object());
if (!(flags & F_HOSTILE)) {
is_attacking=0;
return;
}
if (curr) {
curr=contents(curr);
while (curr) {
if (call_other(curr,"is_player") && call_other(curr,"is_living")) {
is_attacking=curr;
tell_player(curr,short+" starts attacking you.\n");
tell_room_except2(location(this_object()),curr,this_object(),
short+" starts attacking "+call_other(curr,
"get_short")+".\n");
listen("You start attacking "+call_other(curr,"get_short"));
return;
}
curr=next_object(curr);
}
}
is_attacking=0;
}
is_living() { return alive; }
get_short() { return short; }
set_short(arg) { short=arg; return 1; }
to_hit_bonus() {
int bonus;
if (weapon)
bonus=call_other(weapon,"get_hit_bonus",is_attacking);
else
bonus=0;
return bonus+hit_bonus;
}
damage_bonus() {
int bonus,loop;
if (weapon)
bonus=call_other(weapon,"get_damage_bonus",is_attacking);
else {
loop=0;
bonus=0;
while (loop++<dam_num_die) bonus+=random(dam_die_size)+1;
bonus+=dam_bonus;
}
return bonus;
}
static do_kill(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,location(this_object()));
if (!arg) {
write("You don't see that here.\n");
return 1;
}
if (!call_other(arg,"is_living")) {
write("You can't kill that, you bonehead.\n");
return 1;
}
if (arg==this_object()) {
write("PLEASE try to control your suicidal impulses.\n");
return 1;
}
if (arg==is_attacking) {
write("You're already attacking that. Chill.\n");
return 1;
}
write("You start attacking "+call_other(arg,"get_short")+".\n");
tell_player(arg,short+" starts attacking you.\n");
tell_room_except2(location(this_object()),arg,this_object(),short+
" starts attacking "+call_other(arg,"get_short")+".\n");
attack(arg);
return 1;
}
do_damage(amount) {
int retval,intensity;
object curr,next,corpse;
amount-=get_damreduce();
if (amount<0) amount=0;
retval=(amount>hp)?hp:amount;
hp-=amount;
if (!is_healing) {
is_healing=1;
alarm(HEAL_DELAY,"autoheal");
}
if (amount<I_PUNY_AMT)
intensity=I_PUNY;
else if (amount<I_WEAK_AMT)
intensity=I_WEAK;
else if (amount<I_POOR_AMT)
intensity=I_POOR;
else if (amount<I_AVERAGE_AMT)
intensity=I_AVERAGE;
else if (amount<I_GOOD_AMT)
intensity=I_GOOD;
else if (amount<I_VERYGOOD_AMT)
intensity=I_VERYGOOD;
else intensity=I_MASSACRE;
write(call_other(caller_object(),"get_short")+" "+
call_other(caller_object(),"get_hit_msg3",intensity)+"\n");
write("You have "+itoa((hp>0)?hp:0)+" hit points left.\n");
if (hp<1) {
write("You have died. That's okay, you're just a monster, anyways.\n");
corpse=clone_object("/obj/corpse");
call_other(corpse,"set_name",short);
move_object(corpse,location(this_object()));
hp=0;
alive=0;
is_attacking=0;
curr=contents(this_object());
if (flags & F_PERMANENT) {
last_location=location(this_object());
move_object(this_object(),0);
alarm(REINCARNATE_DELAY,"reincarnate");
while (curr) {
next=call_other(curr,"replicate");
if (next) move_object(next,last_location);
curr=next_object(curr);
}
} else {
while (curr) {
next=next_object(curr);
if (call_other(curr,"drop")) {
if (!call_other(curr,"dead_drop"))
move_object(curr,location(this_object()));
} else
move_object(curr,location(this_object()));
curr=next;
}
destruct(this_object());
}
}
return retval;
}
static reincarnate() {
hp=max_hp;
alive=1;
move_player(last_location,0);
}
attempt_hit(chance) {
return chance+50-call_other(caller_object(),"get_hitreduce")>random(100);
}
attack(enemy) {
int enemy_xp,intensity,dmg,tmp;
string ename;
if (enemy==this_object()) return;
if (is_attacking==this_object()) {
is_attacking=0;
return;
}
if (!alive) {
is_attacking=0;
return;
}
if (enemy)
if (is_attacking) {
is_attacking=enemy;
return;
} else
is_attacking=enemy;
if (!is_attacking)
find_enemy();
if (!is_attacking) return;
if (!call_other(is_attacking,"is_living")) find_enemy();
if (!is_attacking) return;
if (location(is_attacking)!=location(this_object()))
find_enemy();
if (!is_attacking) return;
ename=call_other(is_attacking,"get_short");
enemy_xp=call_other(is_attacking,"impending_attack");
if (!alive) return;
if (call_other(is_attacking,"attempt_hit",to_hit_bonus())) {
dmg=damage_bonus();
tmp=call_other(is_attacking,"do_damage",dmg);
if (dmg<I_PUNY_AMT) {
intensity=I_PUNY;
} else if (dmg<I_WEAK_AMT) {
intensity=I_WEAK;
} else if (dmg<I_POOR_AMT) {
intensity=I_POOR;
} else if (dmg<I_AVERAGE_AMT) {
intensity=I_AVERAGE;
} else if (dmg<I_GOOD_AMT) {
intensity=I_GOOD;
} else if (dmg<I_VERYGOOD_AMT) {
intensity=I_VERYGOOD;
} else {
intensity=I_MASSACRE;
}
TP(get_hit_msg1(intensity)+ename+get_hit_msg2(intensity)+"\n");
TPE2(short+" "+get_hit_msg4(intensity)+ename+get_hit_msg5(intensity)+"\n");
if (!call_other(is_attacking,"is_living")) {
TP("You have killed "+ename+"!\n");
TPE2(short+" has killed "+ename+"!\n");
find_enemy();
}
} else {
TP("You missed "+ename+".\n");
tell_player(is_attacking,short+" misses you.\n");
TPE2(short+" misses "+ename+".\n");
}
alarm(3,"attack");
}
static do_inventory(arg) {
int count;
object curr;
string oname;
count=0;
curr=contents(this_object());
while (curr) {
oname=call_other(curr,"get_short");
if (oname) {
if (!count) {
write("You are carrying:\n");
}
count++;
write(oname+"\n");
}
curr=next_object(curr);
}
if (!count)
write("You are empty-handed.\n");
return 1;
}
static do_score(arg) {
if (alive) {
write("HP: "+itoa(hp)+"/"+itoa(max_hp)+" Level: "+itoa(level)+
" XP: "+itoa(xp)+"\n");
} else
write("You are dead. This implies your score kinda SUCKS.\n");
return 1;
}
static do_huh(arg) {
write(HUH_STRING);
}
static do_get(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,location(this_object()));
if (!arg) {
write("You don't see that here.\n");
return 1;
}
if (!call_other(arg,"get")) {
write("You can't get "+call_other(arg,"get_short")+".\n");
return 1;
}
move_object(arg,this_object());
write("You get "+call_other(arg,"get_short")+".\n");
TPE(short+" gets "+call_other(arg,"get_short")+"\n");
move_object(arg,this_object());
return 1;
}
static do_drop(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,(this_object()));
if (!arg) {
write("You don't have that.\n");
return 1;
}
if (call_other(arg,"drop")) {
write("You can't drop "+call_other(arg,"get_short")+".\n");
return 1;
}
write("You drop "+call_other(arg,"get_short")+".\n");
TPE(short+" drops "+call_other(arg,"get_short")+"\n");
move_object(arg,location(this_object()));
return 1;
}
static do_wield(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,this_object());
if (!arg) {
write("You don't have that.\n");
return 1;
}
if (weapon) {
write("You are already wielding a weapon.\n");
return 1;
}
if (!call_other(arg,"wield")) {
write("You can't wield that.\n");
return 1;
}
write("You wield "+call_other(arg,"get_short")+".\n");
TPE(short+" wields "+call_other(arg,"get_short")+".\n");
weapon=arg;
return 1;
}
force_unwield() {
if (weapon!=caller_object()) return;
weapon=0;
}
static do_unwield(arg) {
if (!alive) {
write("You're too dead.\n");
return 1;
}
arg=present(arg,this_object());
if (arg!=weapon) {
write("You aren't wielding that.\n");
return 1;
}
if (call_other(arg,"unwield")) {
write("You can't unwield "+call_other(arg,"get_short")+".\n");
return 1;
}
weapon=0;
write("You unwield "+call_other(arg,"get_short")+".\n");
TPE(short+" unwields "+call_other(arg,"get_short")+".\n");
return 1;
}
static init() {
alive=1;
set_interactive();
max_hp=14;
hp=max_hp;
xp=5;
level=1;
dam_num_die=1;
dam_die_size=2;
me=this_object();
if (!prototype(me)) return;
add_xverb("","do_huh");
add_verb("say","do_say");
add_verb("pose","do_pose");
add_xverb(":","do_pose");
add_xverb("\"","do_say");
add_verb("i","do_inventory");
add_verb("inventory","do_inventory");
add_verb("l","look");
add_verb("look","look");
add_verb("drop","do_drop");
add_verb("get","do_get");
add_verb("take","do_take");
add_verb("wield","do_wield");
add_verb("unwield","do_unwield");
add_verb("kill","do_kill");
add_verb("score","do_score");
add_verb("exits","do_exits");
add_verb("wear","do_wear");
add_verb("unwear","do_unwear");
}
listen(arg) {
if (!is_attacking && (flags & F_HOSTILE)) attack();
if (possessor) call_other(possessor,"possession_report",arg);
}