/* ************************************************************************ * File: fight.c , Combat module. Part of DIKUMUD * * Usage: Combat system and messages. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include "os.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "handler.h" #include "interpreter.h" #include "db.h" #include "limits.h" #include "spells.h" #include "prototypes.h" /* Structures */ struct char_data *combat_list = 0; /* head of l-list of fighting chars */ struct char_data *combat_next_dude = 0; /* Next dude global trick */ /* External structures */ extern struct room_data *world; extern struct message_list fight_messages[MAX_MESSAGES]; extern struct obj_data *object_list; /* External procedures */ char *fread_string (FILE * f1); void stop_follower (struct char_data *ch); void do_flee (struct char_data *ch, char *argument, int cmd); void hit (struct char_data *ch, struct char_data *victim, int type); /* Weapon attack texts */ struct attack_hit_type attack_hit_text[] = { {"hit", "hits"}, /* TYPE_HIT */ {"pound", "pounds"}, /* TYPE_BLUDGEON */ {"pierce", "pierces"}, /* TYPE_PIERCE */ {"slash", "slashes"}, /* TYPE_SLASH */ {"whip", "whips"}, /* TYPE_WHIP */ {"claw", "claws"}, /* TYPE_CLAW */ {"bite", "bites"}, /* TYPE_BITE */ {"sting", "stings"}, /* TYPE_STING */ {"crush", "crushes"} /* TYPE_CRUSH */ }; /* The Fight related routines */ void appear (struct char_data *ch) { act ("$n slowly fade into existence.", FALSE, ch, 0, 0, TO_ROOM); if (affected_by_spell (ch, SPELL_INVISIBLE)) affect_from_char (ch, SPELL_INVISIBLE); REMOVE_BIT (ch->specials.affected_by, AFF_INVISIBLE); } void load_messages (void) { FILE *f1; int i, type; struct message_type *messages; char chk[100]; if (!(f1 = fopen (MESS_FILE, "rb"))) { perror ("read messages"); WIN32CLEANUP exit (0); } for (i = 0; i < MAX_MESSAGES; i++) { fight_messages[i].a_type = 0; fight_messages[i].number_of_attacks = 0; fight_messages[i].msg = 0; } fscanf (f1, " %s \n", chk); while (*chk == 'M') { fscanf (f1, " %d\n", &type); for (i = 0; (i < MAX_MESSAGES) && (fight_messages[i].a_type != type) && (fight_messages[i].a_type); i++); if (i >= MAX_MESSAGES) { log ("Too many combat messages."); WIN32CLEANUP exit (0); } CREATE (messages, struct message_type, 1); fight_messages[i].number_of_attacks++; fight_messages[i].a_type = type; messages->next = fight_messages[i].msg; fight_messages[i].msg = messages; messages->die_msg.attacker_msg = fread_string (f1); messages->die_msg.victim_msg = fread_string (f1); messages->die_msg.room_msg = fread_string (f1); messages->miss_msg.attacker_msg = fread_string (f1); messages->miss_msg.victim_msg = fread_string (f1); messages->miss_msg.room_msg = fread_string (f1); messages->hit_msg.attacker_msg = fread_string (f1); messages->hit_msg.victim_msg = fread_string (f1); messages->hit_msg.room_msg = fread_string (f1); messages->god_msg.attacker_msg = fread_string (f1); messages->god_msg.victim_msg = fread_string (f1); messages->god_msg.room_msg = fread_string (f1); fscanf (f1, " %s \n", chk); } fclose (f1); } void update_pos (struct char_data *victim) { if ((GET_HIT (victim) > 0) && (GET_POS (victim) > POSITION_STUNNED)) return; else if (GET_HIT (victim) > 0) GET_POS (victim) = POSITION_STANDING; else if (GET_HIT (victim) <= -11) GET_POS (victim) = POSITION_DEAD; else if (GET_HIT (victim) <= -6) GET_POS (victim) = POSITION_MORTALLYW; else if (GET_HIT (victim) <= -3) GET_POS (victim) = POSITION_INCAP; else GET_POS (victim) = POSITION_STUNNED; } /* start one char fighting another (yes, it is horrible, I know... ) */ void set_fighting (struct char_data *ch, struct char_data *vict) { assert (!ch->specials.fighting); ch->next_fighting = combat_list; combat_list = ch; if (IS_AFFECTED (ch, AFF_SLEEP)) affect_from_char (ch, SPELL_SLEEP); ch->specials.fighting = vict; GET_POS (ch) = POSITION_FIGHTING; } /* remove a char from the list of fighting chars */ void stop_fighting (struct char_data *ch) { struct char_data *tmp; assert (ch->specials.fighting); if (ch == combat_next_dude) combat_next_dude = ch->next_fighting; if (combat_list == ch) combat_list = ch->next_fighting; else { for (tmp = combat_list; tmp && (tmp->next_fighting != ch); tmp = tmp->next_fighting); if (!tmp) { log ("Char fighting not found Error (fight.c, stop_fighting)"); abort (); } tmp->next_fighting = ch->next_fighting; } ch->next_fighting = 0; ch->specials.fighting = 0; GET_POS (ch) = POSITION_STANDING; update_pos (ch); } #define MAX_NPC_CORPSE_TIME 5 #define MAX_PC_CORPSE_TIME 10 void make_corpse (struct char_data *ch) { struct obj_data *corpse, *o; struct obj_data *money; char buf[MAX_STRING_LENGTH]; int i; char *str_dup (char *source); struct obj_data *create_money (int amount); CREATE (corpse, struct obj_data, 1); clear_object (corpse); corpse->item_number = NOWHERE; corpse->in_room = NOWHERE; corpse->name = str_dup ("corpse"); sprintf (buf, "Corpse of %s is lying here.", (IS_NPC (ch) ? ch->player.short_descr : GET_NAME (ch))); corpse->description = str_dup (buf); sprintf (buf, "Corpse of %s", (IS_NPC (ch) ? ch->player.short_descr : GET_NAME (ch))); corpse->short_description = str_dup (buf); corpse->contains = ch->carrying; if ((GET_GOLD (ch) > 0) && (IS_NPC (ch) || (ch->desc))) { money = create_money (GET_GOLD (ch)); GET_GOLD (ch) = 0; obj_to_obj (money, corpse); } corpse->obj_flags.type_flag = ITEM_CONTAINER; corpse->obj_flags.wear_flags = ITEM_TAKE; corpse->obj_flags.value[0] = 0; /* You can't store stuff in a corpse */ corpse->obj_flags.value[3] = 1; /* corpse identifyer */ corpse->obj_flags.weight = GET_WEIGHT (ch) + IS_CARRYING_W (ch); corpse->obj_flags.cost_per_day = 100000; if (IS_NPC (ch)) corpse->obj_flags.timer = MAX_NPC_CORPSE_TIME; else corpse->obj_flags.timer = MAX_PC_CORPSE_TIME; for (i = 0; i < MAX_WEAR; i++) if (ch->equipment[i]) obj_to_obj (unequip_char (ch, i), corpse); ch->carrying = 0; IS_CARRYING_N (ch) = 0; IS_CARRYING_W (ch) = 0; corpse->next = object_list; object_list = corpse; for (o = corpse->contains; o; o->in_obj = corpse, o = o->next_content); object_list_new_owner (corpse, 0); obj_to_room (corpse, ch->in_room); } /* When ch kills victim */ void change_alignment (struct char_data *ch, struct char_data *victim) { int align; if ((align = GET_ALIGNMENT (ch) - GET_ALIGNMENT (victim)) > 0) { if (align > 650) GET_ALIGNMENT (ch) = MIN (1000, GET_ALIGNMENT (ch) + ((align - 650) / 4)); else GET_ALIGNMENT (ch) /= 2; } else { if (align < -650) GET_ALIGNMENT (ch) = MAX (-1000, GET_ALIGNMENT (ch) + ((align + 650) / 4)); else GET_ALIGNMENT (ch) /= 2; } } void death_cry (struct char_data *ch) { struct char_data *victim; int door, was_in; act ("Your blood freezes as you hear $ns death cry.", FALSE, ch, 0, 0, TO_ROOM); was_in = ch->in_room; for (door = 0; door <= 5; door++) { if (CAN_GO (ch, door)) { ch->in_room = world[was_in].dir_option[door]->to_room; act ("Your blood freezes as you hear someones death cry.", FALSE, ch, 0, 0, TO_ROOM); ch->in_room = was_in; } } } void raw_kill (struct char_data *ch) { if (ch->specials.fighting) stop_fighting (ch); death_cry (ch); make_corpse (ch); affect_total (ch); extract_char (ch); } void die (struct char_data *ch) { gain_exp (ch, -(GET_EXP (ch) / 2)); raw_kill (ch); } void group_gain (struct char_data *ch, struct char_data *victim) { char buf[256]; int no_members, share; struct char_data *k; struct follow_type *f; if (!(k = ch->master)) k = ch; if (IS_AFFECTED (k, AFF_GROUP) && (k->in_room == ch->in_room)) no_members = 1; else no_members = 0; for (f = k->followers; f; f = f->next) if (IS_AFFECTED (f->follower, AFF_GROUP) && (f->follower->in_room == ch->in_room)) no_members++; if (no_members >= 1) share = MIN (450000 / no_members, (GET_EXP (victim) / 3) / no_members); else share = 0; if (IS_AFFECTED (k, AFF_GROUP) && (k->in_room == ch->in_room)) { act ("You receive your share of experience.", FALSE, k, 0, 0, TO_CHAR); gain_exp (k, share); change_alignment (k, victim); } for (f = k->followers; f; f = f->next) { if (IS_AFFECTED (f->follower, AFF_GROUP) && (f->follower->in_room == ch->in_room)) { act ("You receive your share of experience.", FALSE, f->follower, 0, 0, TO_CHAR); gain_exp (f->follower, share); change_alignment (f->follower, victim); } } } char *replace_string (char *str, char *weapon) { static char buf[256]; char *cp; cp = buf; for (; *str; str++) { if (*str == '#') { switch (*(++str)) { case 'W': for (; *weapon; *(cp++) = *(weapon++)); break; default: *(cp++) = '#'; break; } } else { *(cp++) = *str; } *cp = 0; } /* For */ return (buf); } void dam_message (int dam, struct char_data *ch, struct char_data *victim, int w_type) { struct obj_data *wield; char *buf; static struct dam_weapon_type { char *to_room; char *to_char; char *to_victim; } dam_weapons[] = { { "$n misses $N with $s #W.", /* 0 */ "You miss $N with your #W.", "$n miss you with $s #W."}, { "$n tickles $N with $s #W.", /* 1.. 2 */ "You tickle $N as you #W $M.", "$n tickle you as $e #W you."}, { "$n barely #W $N.", /* 3.. 4 */ "You barely #W $N.", "$n barely #W you."}, { "$n #W $N.", /* 5.. 6 */ "You #W $N.", "$n #W you."}, { "$n #W $N hard.", /* 7..10 */ "You #W $N hard.", "$n #W you hard."}, { "$n #W $N very hard.", /* 11..14 */ "You #W $N very hard.", "$n #W you very hard."}, { "$n #W $N extremely hard.", /* 15..20 */ "You #W $N extremely hard.", "$n #W you extremely hard."}, { "$n massacre $N to small fragments with $s #W.", /* > 20 */ "You massacre $N to small fragments with your #W.", "$n massacre you to small fragments with $s #W."} }; w_type -= TYPE_HIT; /* Change to base of table with text */ wield = ch->equipment[WIELD]; if (dam == 0) { buf = replace_string (dam_weapons[0].to_room, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[0].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[0].to_victim, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 2) { buf = replace_string (dam_weapons[1].to_room, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[1].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[1].to_victim, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 4) { buf = replace_string (dam_weapons[2].to_room, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[2].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[2].to_victim, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 6) { buf = replace_string (dam_weapons[3].to_room, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[3].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[3].to_victim, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 10) { buf = replace_string (dam_weapons[4].to_room, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[4].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[4].to_victim, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 15) { buf = replace_string (dam_weapons[5].to_room, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[5].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[5].to_victim, attack_hit_text[w_type].plural); act (buf, FALSE, ch, wield, victim, TO_VICT); } else if (dam <= 20) { buf = replace_string (dam_weapons[6].to_room, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[6].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[6].to_victim, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_VICT); } else { buf = replace_string (dam_weapons[7].to_room, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_NOTVICT); buf = replace_string (dam_weapons[7].to_char, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_CHAR); buf = replace_string (dam_weapons[7].to_victim, attack_hit_text[w_type].singular); act (buf, FALSE, ch, wield, victim, TO_VICT); } } void damage (struct char_data *ch, struct char_data *victim, int dam, int attacktype) { char buf[MAX_STRING_LENGTH]; struct message_type *messages; int i, j, nr, max_hit, exp; int hit_limit (struct char_data *ch); assert (GET_POS (victim) > POSITION_DEAD); if ((GET_LEVEL (victim) > 20) && !IS_NPC (victim)) /* You can't damage an immortal! */ dam = 0; if (victim != ch) { if (GET_POS (victim) > POSITION_STUNNED) { if (!(victim->specials.fighting)) set_fighting (victim, ch); GET_POS (victim) = POSITION_FIGHTING; } if (GET_POS (ch) > POSITION_STUNNED) { if (!(ch->specials.fighting)) set_fighting (ch, victim); if (IS_NPC (ch) && IS_NPC (victim) && victim->master && !number (0, 10) && IS_AFFECTED (victim, AFF_CHARM) && (victim->master->in_room == ch->in_room)) { if (ch->specials.fighting) stop_fighting (ch); hit (ch, victim->master, TYPE_UNDEFINED); return; } } } if (victim->master == ch) stop_follower (victim); if (IS_AFFECTED (ch, AFF_INVISIBLE)) appear (ch); if (IS_AFFECTED (victim, AFF_SANCTUARY)) dam = MIN (dam, 18); /* Max 18 damage when sanctuary */ dam = MIN (dam, 100); dam = MAX (dam, 0); GET_HIT (victim) -= dam; if (ch != victim) gain_exp (ch, GET_LEVEL (victim) * dam); update_pos (victim); if ((attacktype >= TYPE_HIT) && (attacktype <= TYPE_SLASH)) { if (!ch->equipment[WIELD]) { dam_message (dam, ch, victim, TYPE_HIT); } else { dam_message (dam, ch, victim, attacktype); } } else { for (i = 0; i < MAX_MESSAGES; i++) { if (fight_messages[i].a_type == attacktype) { nr = dice (1, fight_messages[i].number_of_attacks); for (j = 1, messages = fight_messages[i].msg; (j < nr) && (messages); j++) messages = messages->next; if (!IS_NPC (victim) && (GET_LEVEL (victim) > 20)) { act (messages->god_msg.attacker_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_CHAR); act (messages->god_msg.victim_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_VICT); act (messages->god_msg.room_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_NOTVICT); } else if (dam != 0) { if (GET_POS (victim) == POSITION_DEAD) { act (messages->die_msg.attacker_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_CHAR); act (messages->die_msg.victim_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_VICT); act (messages->die_msg.room_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_NOTVICT); } else { act (messages->hit_msg.attacker_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_CHAR); act (messages->hit_msg.victim_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_VICT); act (messages->hit_msg.room_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_NOTVICT); } } else { /* Dam == 0 */ act (messages->miss_msg.attacker_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_CHAR); act (messages->miss_msg.victim_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_VICT); act (messages->miss_msg.room_msg, FALSE, ch, ch->equipment[WIELD], victim, TO_NOTVICT); } } } } switch (GET_POS (victim)) { case POSITION_MORTALLYW: act ("$n is mortally wounded, and will die soon, if not aided.", TRUE, victim, 0, 0, TO_ROOM); act ("You are mortally wounded, and will die soon, if not aided.", FALSE, victim, 0, 0, TO_CHAR); break; case POSITION_INCAP: act ("$n is incapacitated and will slowly die, if not aided.", TRUE, victim, 0, 0, TO_ROOM); act ("You are incapacitated an will slowly die, if not aided.", FALSE, victim, 0, 0, TO_CHAR); break; case POSITION_STUNNED: act ("$n is stunned, but will probably regain conscience again.", TRUE, victim, 0, 0, TO_ROOM); act ("You're stunned, but will probably regain conscience again.", FALSE, victim, 0, 0, TO_CHAR); break; case POSITION_DEAD: act ("$n is dead! R.I.P.", TRUE, victim, 0, 0, TO_ROOM); act ("You are dead! Sorry...", FALSE, victim, 0, 0, TO_CHAR); break; default: /* >= POSITION SLEEPING */ max_hit = hit_limit (victim); if (dam > (max_hit / 5)) act ("That Really did HURT!", FALSE, victim, 0, 0, TO_CHAR); if (GET_HIT (victim) < (max_hit / 5)) { act ("You wish that your wounds would stop BLEEDING that much!", FALSE, victim, 0, 0, TO_CHAR); if (IS_NPC (victim)) if (IS_SET (victim->specials.act, ACT_WIMPY)) do_flee (victim, "", 0); } break; } if (!IS_NPC (victim) && !(victim->desc)) { do_flee (victim, "", 0); if (!victim->specials.fighting) { act ("$n is rescued by divine forces.", FALSE, victim, 0, 0, TO_ROOM); victim->specials.was_in_room = victim->in_room; char_from_room (victim); char_to_room (victim, 0); } } if (GET_POS (victim) < POSITION_STUNNED) if (ch->specials.fighting == victim) stop_fighting (ch); if (!AWAKE (victim)) if (victim->specials.fighting) stop_fighting (victim); if (GET_POS (victim) == POSITION_DEAD) { if (IS_NPC (victim) || victim->desc) if (IS_AFFECTED (ch, AFF_GROUP)) { group_gain (ch, victim); } else { /* Calculate level-difference bonus */ exp = GET_EXP (victim) / 3; if (IS_NPC (ch)) exp += (exp * MIN (4, (GET_LEVEL (victim) - GET_LEVEL (ch)))) >> 3; else exp += (exp * MIN (8, (GET_LEVEL (victim) - GET_LEVEL (ch)))) >> 3; exp = MAX (exp, 1); gain_exp (ch, exp); change_alignment (ch, victim); } if (!IS_NPC (victim)) { sprintf (buf, "%s killed by %s at %s", GET_NAME (victim), (IS_NPC (ch) ? ch->player.short_descr : GET_NAME (ch)), world[victim->in_room].name); log (buf); } die (victim); } } void hit (struct char_data *ch, struct char_data *victim, int type) { struct obj_data *wielded = 0; struct obj_data *held = 0; int w_type; int victim_ac, calc_thaco; int dam; byte diceroll; extern int thaco[4][25]; extern byte backstab_mult[]; extern struct str_app_type str_app[]; extern struct dex_app_type dex_app[]; if (ch->in_room != victim->in_room) { log ("NOT SAME ROOM WHEN FIGHTING!"); return; } if (ch->equipment[HOLD]) held = ch->equipment[HOLD]; if (ch->equipment[WIELD] && (ch->equipment[WIELD]->obj_flags.type_flag == ITEM_WEAPON)) { wielded = ch->equipment[WIELD]; switch (wielded->obj_flags.value[3]) { case 0: case 1: case 2: w_type = TYPE_WHIP; break; case 3: w_type = TYPE_SLASH; break; case 4: case 5: case 6: w_type = TYPE_CRUSH; break; case 7: w_type = TYPE_BLUDGEON; break; case 8: case 9: case 10: case 11: w_type = TYPE_PIERCE; break; default: w_type = TYPE_HIT; break; } } else { if (IS_NPC (ch) && (ch->specials.attack_type >= TYPE_HIT)) w_type = ch->specials.attack_type; else w_type = TYPE_HIT; } /* Calculate the raw armor including magic armor */ /* The lower AC, the better */ if (!IS_NPC (ch)) calc_thaco = thaco[GET_CLASS (ch) - 1][(int)GET_LEVEL (ch)]; else /* THAC0 for monsters is set in the HitRoll */ calc_thaco = 20; calc_thaco -= str_app[STRENGTH_APPLY_INDEX (ch)].tohit; calc_thaco -= GET_HITROLL (ch); diceroll = number (1, 20); victim_ac = GET_AC (victim) / 10; if (AWAKE (victim)) victim_ac += dex_app[GET_DEX (victim)].defensive; victim_ac = MAX (-10, victim_ac); /* -10 is lowest */ if ((diceroll < 20) && AWAKE (victim) && ((diceroll == 1) || ((calc_thaco - diceroll) > victim_ac))) { if (type == SKILL_BACKSTAB) damage (ch, victim, 0, SKILL_BACKSTAB); else damage (ch, victim, 0, w_type); } else { dam = str_app[STRENGTH_APPLY_INDEX (ch)].todam; dam += GET_DAMROLL (ch); if (!wielded) { if (IS_NPC (ch)) dam += dice (ch->specials.damnodice, ch->specials.damsizedice); else dam += number (0, 2); /* Max. 2 dam with bare hands */ } else { dam += dice (wielded->obj_flags.value[1], wielded->obj_flags.value[2]); } if (GET_POS (victim) < POSITION_FIGHTING) dam *= 1 + (POSITION_FIGHTING - GET_POS (victim)) / 3; /* Position sitting x 1.33 */ /* Position resting x 1.66 */ /* Position sleeping x 2.00 */ /* Position stunned x 2.33 */ /* Position incap x 2.66 */ /* Position mortally x 3.00 */ dam = MAX (1, dam); /* Not less than 0 damage */ if (type == SKILL_BACKSTAB) { dam *= backstab_mult[(int)GET_LEVEL (ch)]; damage (ch, victim, dam, SKILL_BACKSTAB); } else damage (ch, victim, dam, w_type); } } /* control the fights going on */ void perform_violence (void) { struct char_data *ch; for (ch = combat_list; ch; ch = combat_next_dude) { combat_next_dude = ch->next_fighting; assert (ch->specials.fighting); if (AWAKE (ch) && (ch->in_room == ch->specials.fighting->in_room)) { hit (ch, ch->specials.fighting, TYPE_UNDEFINED); } else { /* Not in same room */ stop_fighting (ch); } } }