/* _backstab.c
* /cmds/skills
* originally coded by ? on ?
* modified by Bohemund on 9 March 1994
* rewriten by Gregon@Nightmare June 1994
* in accordance with law and approval requests:
* only one attack
* socket available for items to attenuate backstab strength
* minor bugs eliminated
* can now aim for a limb and all damage is taken off some limb
*/
#include <std.h>
#define XX "%^BOLD%^RED%^"
inherit DAEMON;
int cmd_backstab(string str) {
string who, limb, vicname, bsname, *limbs, hitlimb,knifname;
object *weapons, *knives, victim, here, tmp_ob, *tmp_obs;
int i, damage, tmp, murder, dex, vicdex, prot;
if(!str) {
notify_fail("Correct syntax: backstab victim [limb]\n");
return 0;
}
if(this_player()->query_ghost()) {
notify_fail("You cannot do that in your present immaterial state.\n");
return 0;
}
if(this_player()->query_disabled()) return 1;
if(environment(this_player())->query_property("no attack")) {
notify_fail("You may not attack in this place.\n");
return 0;
}
if(murder=(int)this_player()->query_skill("murder") < 5) {
notify_fail("You aren't skilled enough to do that.\n");
return 0;
}
if(sscanf(str,"%s %s",who,limb)!=2) {
who=str;
limb=0;
}
if(!(victim = present(lower_case(who),here=environment(this_player())))) {
notify_fail("You don't see that target here.\n");
return 0;
}
if(victim == this_player()) {
notify_fail("Backstab yourself?\n");
return 0;
}
if(victim->query_ghost()) {
notify_fail("Backstab a ghost?\n");
return 0;
}
if(!living(victim)){
notify_fail("You would look pretty silly backstabbing that.\n");
return 0;
}
vicname=victim->query_cap_name();
if(limb && member_array(limb,limbs=(string *)victim->query_limbs()) == -1) {
notify_fail(vicname+" does not have a "+limb+".\n");
return 0;
}
if(victim->query_property("no backstab")) {
notify_fail(vicname+" is immune to your backstab.");
return 0;
}
knives = ({});
weapons = (object *)this_player()->query_wielded();
for(i=0, tmp = sizeof(weapons); i<tmp; i++) {
if((string)weapons[i]->query_type() != "knife") continue;
knives += ({ weapons[i] });
}
if(!sizeof(knives)) {
write("You are not well equipped for backstabbing.");
return 1;
}
this_player()->set_disabled();
if(member_array(victim, (object *)this_player()->query_hunted()) != -1 ||
member_array(victim, (object *)this_player()->query_attackers())!=-1) {
notify_fail("You have lost the element of surprise!\n");
return 0;
}
if(tmp_ob = (object)this_player()->query_current_attacker()) {
notify_fail(sprintf("You are already in combat with %s.",
(string)tmp_ob->query_cap_name()));
return 0;}
if(victim->is_player() && !interactive(victim)) return 0;
if(!this_player()->kill_ob(victim, 0)) return 1;
bsname=(string)this_player()->query_cap_name();
if((int)this_player()->query_stats("dexterity") + 5 <
(int)victim->query_stats("dexterity")){
message("my action", XX+vicname+" sees your attempted backstab and "
"evades it!%^RESET%^", this_player());
message("other action",XX+bsname+
" just tried to backstab you! Luckily, you are too fast for "+
this_player()->query_objective()+".", victim);
if(!victim->is_player()) victim->kill_ob(this_player(),0);
return 1;
}
message("my_action",XX+"You backstab "+vicname+"!",this_player());
tell_room(here,XX+bsname+" backstabs "+vicname+"!",
({ victim, this_player() }) );
message("other action",XX+bsname+" backstabs you!",victim);
//in an item set_property("no backstab", x) will cause the damage done by the
//backstab to be reduced by x percent
for(i=0;i<sizeof(tmp_obs=all_inventory(victim));i++) {
if(tmp=tmp_obs[i]->query_property("no backstab") && tmp > prot) tmp=prot;
}
damage = murder;
damage += (int)this_player()->query_sp()/5;
damage -= vicdex=(int)victim->query_stats("dexterity");
damage += dex=(int)this_player()->query_stats("dexterity");
damage += (int)this_player()->query_skill("knife");
this_player()->add_skill_points("murder",5);
this_player()->set_backstab(sizeof(knives));
for(i=0; i<sizeof(knives); i++) {
if(limb && random(100) < (murder-vicdex) ) hitlimb=limb;
else hitlimb=(string)victim->return_target_limb();
knifname=(string)knives[i]->query_short();
if(random(110)>((int)this_player()->mobility(0)+35+dex)) {
//almost the same way hits are determined in the game, with a slight bonus
//since have element of surprise
message("other_combat",XX+capitalize(knifname)+" barely misses your "+
hitlimb+".",victim);
message("my_combat", XX+"You miss "+ vicname+"'s "+hitlimb+" by inches.",
this_player());
tell_room(here,bsname+" barely misses "+vicname+"'s "+hitlimb+".",
({victim,this_player()}) );
}
else {
message("other_combat",XX+capitalize(knifname)+" tears into your "+
hitlimb+"!",victim);
message("my_combat",XX+"You slash into "+vicname+"'s "+hitlimb+" with "+
knifname+"!",this_player());
tell_room(here,bsname+" slashes "+vicname+"'s "+hitlimb+" with "+knifname+
"!",({this_player(),victim}) );
//damage tally done here and exacted with a socket for devices or monsters
//which can attenuate the damage
damage = damage/2 +random(damage/2);
damage -= victim->query_current_protection(hitlimb);
if(prot) damage-=damage/prot;
victim->do_damage(hitlimb,damage);
victim->check_on_limb(hitlimb);
}
}
this_player()->add_alignment(-5);
return 1;
}
void help() {
write("Syntax: backstab <enemy> [limb]\n\n"
"This command is used to initiate combat with the "
"monster or player you specify. Optionally, you can add a limb "
"to aim for on the victim.\n");
}