/* 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); }