/* ************************************************************************ * File: fight.c , Combat module. Part of DIKUMUD * * Usage: Combat system and messages. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include <stdio.h> #include <string.h> #include <assert.h> #include <malloc.h> #include <stdlib.h> #include "structs.h" #include "utils.h" #include "comm.h" #include "handler.h" #include "interpreter.h" #include "db.h" #include "spells.h" #define NTAUNT 14 static char *taunt[]={ "HOORAY!! I just killed %s!", "HA HA %s! You stink!", "I am happy to report that %s is dead!", "Long live %s! HA, HA, HA!!", "HA! Looks like %s just kicked the bucket!", "Bid a fond farewell to poor old dead %s!", "My sympathies to the %s family!", "Our friend %s has bitten the proverbial bullet!", "Looks like a quick trip to the Temple for %s!", "I sure hope %s likes reading that menu!", "My old pal %s just bought the farm!", "Funeral services for %s will be held at the city dump!", "Farewell to dear old %s, who won't be missed!", "Die %s, die!" }; /* 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 index_data *mob_index; extern struct weapon_spell_list wsplist[]; extern int pcdeaths,mobdeaths; 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); void rescuesub(struct char_data *ch, struct char_data *victim); /* 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 */ {"blast", "blasts"}, {"splat", "splats"}, {"spank", "spanks"}, /* TYPE_STING */ {"crush", "crushes"}, /* TYPE_CRUSH */ {"burn" , "burns"} }; /* The Fight related routines */ void weapon_effects(struct char_data *ch, struct char_data *vict, struct obj_data *weapon); 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, "r"))){ perror("read messages"); 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."); 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; if(!(ch->specials.fighting)) return; 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 3 #define MAX_PC_CORPSE_TIME 48 #define MAX_POOF_TIME 8 void make_corpse(struct char_data *ch) { struct obj_data *corpse, *o, *xo; struct obj_data *money; char buf[MAX_STRING_LENGTH]; int i; #ifdef NEEDS_STRDUP char *strdup(char *source); #endif struct obj_data *create_money( int amount ); struct extra_descr_data *new_descr; if(!IS_NPC(ch)){ if(GET_LEVEL(ch) >= (IMO>>4)){ i=number(0,MAX_WEAR-1); CREATE(corpse, struct obj_data, 1); clear_object(corpse); corpse->obj_flags.wear_flags=1; corpse->obj_flags.weight=1000; corpse->name = strdup("gravestone"); corpse->in_room = NOWHERE; corpse->item_number = NOWHERE; sprintf(buf,"A Gravestone for %s",GET_NAME(ch)); corpse->short_description = strdup(buf); sprintf(buf,"%s's gravestone is here.",GET_NAME(ch)); corpse->description = strdup(buf); CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = strdup("gravestone"); sprintf(buf,"It reads: Here lies %s, poor soul.\n\r",GET_NAME(ch)); new_descr->description = strdup(buf); new_descr->next = corpse->ex_description; corpse->ex_description = new_descr; corpse->next = object_list; object_list = corpse; obj_to_room(corpse, ch->in_room); } return; } /* Old corpse system here. */ CREATE(corpse, struct obj_data, 1); clear_object(corpse); corpse->item_number = NOWHERE; corpse->in_room = NOWHERE; sprintf(buf,"corpse %s",GET_NAME(ch)); corpse->name = strdup(buf); sprintf(buf, "Corpse of %s is lying here.", (IS_NPC(ch) ? ch->player.short_descr : GET_NAME(ch))); corpse->description = strdup(buf); sprintf(buf, "Corpse of %s", (IS_NPC(ch) ? ch->player.short_descr : GET_NAME(ch))); corpse->short_description = strdup(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.extra_flags = ITEM_NO_PUT_IN; corpse->obj_flags.value[0] = 0; /* You can't store stuff in a corpse */ corpse->obj_flags.value[2] = mob_index[ch->nr].virtual; corpse->obj_flags.value[3] = 1; /* corpse identifyer */ corpse->obj_flags.weight = GET_WEIGHT(ch)+IS_CARRYING_W(ch); 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 (xo=ch->equipment[i]){ obj_to_obj(unequip_char(ch, i), corpse); if(IS_SET(xo->obj_flags.extra_flags,ITEM_POOF)){ SET_BIT(xo->obj_flags.extra_flags,ITEM_POOFSOON); if(GET_ITEM_TYPE(xo) == ITEM_WEAPON) xo->obj_flags.timer=24*number(1,7); else if(GET_ITEM_TYPE(xo) == ITEM_BOMB) { xo->obj_flags.timer = number(6,24); } else { xo->obj_flags.timer=MAX_POOF_TIME; } } } 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); for(o=corpse->contains;o;o=xo){ xo=o->next_content; if(GET_ITEM_TYPE(o)==ITEM_BOMB){ obj_from_obj(o); obj_to_room(o,ch->in_room); act("An explosive device rolls out of the corpse.",FALSE,ch,0,0,TO_ROOM); } } } /* When ch kills victim */ void change_alignment(struct char_data *ch, struct char_data *victim) { int al; if(IS_AFFECTED(ch,AFF_HOLDALIGN)) return; al=(7*GET_ALIGNMENT(ch)-GET_ALIGNMENT(victim))/8; if(al < -1000) al = -1000; if(al > 1000) al = 1000; GET_ALIGNMENT(ch)=al; } 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) { int i,j,n; struct char_data *tmp; if (ch->specials.fighting) stop_fighting(ch); death_cry(ch); if(IS_NPC(ch)) mobdeaths++; else pcdeaths++; if(IS_SET(ch->specials.act,ACT_TRIBBLE)){ n = ch->nr; j=number(0,10)>>2; for(i=0;i<j;i++){ tmp = read_mobile(n,0); if(tmp) char_to_room(tmp,ch->in_room); } } else { make_corpse(ch); } if(IS_NPC(ch)) extract_char(ch); else{ ch->points.gold>>=1; do_rent(ch,0,0); } } void die(struct char_data *ch) { int pen; struct affected_type *hjp; if(!IS_NPC(ch)){ gain_exp(ch, -(int)(GET_EXP(ch)>>1)); GET_META(ch) /= 2; pen = 1 + ch->points.max_hit/50; if (pen < 0) return; ch->points.max_hit -= pen; pen = 1 + ch->points.max_mana/50; if (pen < 0) return; ch->points.max_mana -= pen; pen = 1 + ch->points.max_move/50; if (pen < 0) return; ch->points.max_move -= pen; for(hjp = ch->affected; hjp; hjp = hjp->next) affect_remove(ch, hjp ); } raw_kill(ch); } void group_gain(struct char_data *ch, struct char_data *victim, int levsum) { char buf[256]; int share, shareunit, t; struct char_data *k; struct follow_type *f; if(!levsum) return; shareunit = GET_EXP(victim)/levsum; if (!(k=ch->master)) k=ch; if (IS_AFFECTED(k, AFF_GROUP) && (k->in_room == ch->in_room)) { if(levsum > 0){ t = GET_LEVEL(k); share = shareunit * t; } else share = 0; sprintf(buf, "You receive your share of experience, which is worth %d.", share); act(buf, 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)){ if(levsum > 0){ t = GET_LEVEL(f->follower); share = shareunit * t; } else share = 0; sprintf(buf,"You receive your share of experience, which is worth %d.", share); act(buf,FALSE,f->follower,0,0,TO_CHAR); gain_exp(f->follower,share); change_alignment(f->follower, victim); } } } char *rep_string(char *str, char *weapon, int dam) { static char buf[256]; static char tmp[32]; 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 */ sprintf(tmp," (%d Dam).",dam); strcat(buf,tmp); return(buf); } void dam_message(int dam, struct char_data *ch, struct char_data *victim, int w_type) { struct obj_data *wield; char *buf; int t; static struct dam_weapon_type { char *to_room; char *to_char; char *to_victim; } dam_weapons[] = { {"$n misses $N with $s #W", "You miss $N with your #W", "$n misses you with $s #W" }, /* 0 */ {"$n tickles $N with $s #W", "You tickle $N as you #W $M", "$n tickles you as $e #W you" }, /* 1 */ {"$n barely #W $N", "You barely #W $N", "$n barely #W you"}, /* 2 */ {"$n #W $N", "You #W $N", "$n #W you"}, /* 3 */ {"$n #W $N hard", "You #W $N hard", "$n #W you hard"}, {"$n #W $N very hard", "You #W $N very hard", "$n #W you very hard"}, /* 5 */ {"$n #W $N extremely hard", "You #W $N extremely hard", "$n #W you extremely hard"}, {"$n MASSACRES $N with $s #W", "You MASSACRE $N with your #W", "$n MASSACRES you with $s #W"}, /* 7 */ {"$n PULVERIZES $N with $s #W", "You PULVERIZE $N with your #W", "$n PULVERIZES you with $s #W"}, {"$n ANNIHILATES $N with $s #W", "You ANNIHILATE $N with your #W", "$n ANNIHILATES you with $s #W"}, {"$n OBLITERATES $N with $s #W", "You OBLITERATE $N with your #W", "$n OBLITERATES you with $s #W"}, /* 10 */ {"$n DISINTEGRATES $N with $s #W", "You DISINTEGRATE $N with your #W", "$n DISINTEGRATES you with $s #W"}, {"$n BIFURCATES $N with $s #W", "You BIFURCATE $N with your #W", "$n BIFURCATES you with $s #W"}, /* 12 */ {"$n VARIEGATES $N with $s #W", "You VARIEGATE $N with your #W", "$n VARIEGATES you with $s #W"}, {"$n LAMINATES $N with $s #W", "You LAMINATE $N with your #W", "$n LAMINATES you with $s #W"}, /* 14 */ {"$n MASTICATES $N with $s #W", "You MASTICATE $N with your #W", "$n MASTICATES you with $s #W"}, {"$n REGURGITATES $N with $s #W", "You REGURGITATE $N with your #W", "$n REGURGITATES you with $s #W"} }; w_type -= TYPE_HIT; /* Change to base of table with text */ wield = ch->equipment[WIELD]; if (dam == 0) { t=0; } else if (dam <= 2) { t=1; } else if (dam <= 4) { t=2; } else if (dam <= 8) { t=3; } else if (dam <= 12) { t=4; } else if (dam <= 18) { t=5; } else if (dam <= 26) { t=6; } else if (dam <= 36) { t=7; } else if (dam <= 48) { t=8; } else if (dam <= 64) { t=9; } else if (dam <= 99) { t=10; } else if (dam <= 399) { t=11; } else if (dam <= 1599) { t=12; } else if (dam <= 4999) { t=13; } else if (dam <= 19999) { t=14; } else if (dam <= 99999) { t=15; } else { t=16; } buf=rep_string(dam_weapons[t].to_room,attack_hit_text[w_type].singular,dam); act(buf,FALSE,ch,wield,victim,TO_NOTVICT); buf=rep_string(dam_weapons[t].to_char,attack_hit_text[w_type].singular,dam); act(buf,FALSE,ch,wield,victim,TO_CHAR); buf=rep_string(dam_weapons[t].to_victim,attack_hit_text[w_type].singular,dam); act(buf,FALSE,ch,wield,victim,TO_VICT); } int getlevelsum(struct char_data *ch) { struct char_data *ldr; struct follow_type *f; int room,t,levsum=0; room = ch->in_room; ldr = (ch->master) ? ch->master : ch; if(IS_AFFECTED(ldr,AFF_GROUP) && (ldr->in_room == room)){ t=GET_LEVEL(ldr); levsum=t; } for(f=ldr->followers; f; f=f->next) if(IS_AFFECTED(f->follower,AFF_GROUP) && (f->follower->in_room == room)){ t=GET_LEVEL(f->follower); levsum+=t; } return(levsum); } void damage(struct char_data *ch, struct char_data *victim, int dam, int attacktype) { struct char_data *tmp; struct affected_type *aff; char buf[MAX_STRING_LENGTH]; struct message_type *messages; int i,j,k,nr,max_hit,exp,levdam; extern int nokillflag; int hit_limit(struct char_data *ch); bool lootflag; if(!victim) return; if(IS_NPC(ch)==IS_NPC(victim)){ if(!IS_NPC(ch)){ if(nokillflag && !IS_SET(world[ch->in_room].room_flags,PK_ROOM)) return; } else { SET_BIT(ch->specials.act,ACT_SMART); } } if(IS_SET(world[ch->in_room].room_flags,LAWFUL)) return; if(GET_POS(victim) <= POSITION_DEAD){ stop_fighting(ch); return; } if (ch->in_room != victim->in_room) { if(ch->specials.fighting == victim) stop_fighting(ch); return; } if(IS_AFFECTED(ch, AFF_CHARM) && (ch->master==victim)){ send_to_char("Hurt your master?\n\r",ch); return; } if((GET_LEVEL(victim)>=IMO) && !IS_NPC(victim)) 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,6) && 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(IS_AFFECTED(ch,AFF_CHARM) && IS_NPC(ch) && !IS_NPC(victim) && ch->master){ stop_fighting(ch); affect_from_char(ch,SPELL_CHARM_PERSON); if(IS_SET(ch->specials.affected_by,AFF_CHARM)) REMOVE_BIT(ch->specials.affected_by,AFF_CHARM | AFF_GROUP); if(ch->in_room == ch->master->in_room) hit(ch,ch->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 >>= 1; if(attacktype < 100){ if((attacktype < MAXSPELL) || (attacktype >= SPELL_MAGIC_MISSILE_WPN)){ if(GET_INT(ch) > 75) dam=dam+(dam*(GET_INT(ch)-75))/50; if(k=victim->specials.magres){ if(k > 100) k=100; if(dam < 1000000){ dam -= (k*dam)/100; } else { dam -= k*(dam/100); } } } } dam=MIN(GET_HIT(victim)+13,dam); if(dam < 0) dam=0; GET_HIT(victim)-=dam; if(IS_NPC(victim) && (ch != victim)) gain_exp(ch,dam); update_pos(victim); if ((attacktype >= TYPE_HIT) && (attacktype < TYPE_SHOOT)) { if (!ch->equipment[WIELD]) { dam_message(dam, ch, victim, TYPE_HIT); } else { dam_message(dam, ch, victim, attacktype); } } else if(attacktype != TYPE_SHOOT) { 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) >= IMO)) { 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 has been mortally wounded, and begins to stink.", TRUE, victim, 0, 0, TO_ROOM); act("You are mortally wounded, and begin to stink.", 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 could regain consciousness again.", TRUE, victim, 0, 0, TO_ROOM); act("You're stunned, but could regain consciousness 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(GET_HIT(victim) < (max_hit/5)) if(IS_NPC(victim)) if(IS_SET(victim->specials.act, ACT_WIMPY)){ if(GET_POS(victim) == POSITION_SITTING) do_stand(victim, "", 0); do_flee(victim, "", 0); } else { for(tmp=world[victim->in_room].people;tmp;tmp=tmp->next_in_room) if((tmp!=victim)&&(IS_NPC(tmp))&& (tmp->specials.fighting==victim->specials.fighting)&& (IS_SET(tmp->specials.act, ACT_HELPER))&& (GET_HIT(tmp) > (GET_HIT(victim)<<1))&& (GET_HIT(tmp) > 0)&& (GET_HIT(victim) > 0)){ rescuesub(tmp,victim); break; } } break; } if(!IS_NPC(victim) && !(victim->desc)) { 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); GET_MANA(victim) = GET_MOVE(victim) = 0; } } if (GET_POS(victim) < POSITION_MORTALLYW) 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)){ if (IS_AFFECTED(ch, AFF_GROUP)) { group_gain(ch,victim,getlevelsum(ch)); } else { exp = GET_EXP(victim); gain_exp(ch,exp); sprintf(buf,"You get %d experience point(s).\n\r",exp); send_to_char(buf,ch); change_alignment(ch,victim); } if(!IS_NPC(ch)) (ch->points.kills)++; } if (!IS_NPC(victim)) { (victim->points.deaths)++; sprintf(buf, "%s killed (%d) by %s at %s", GET_NAME(victim), attacktype, (IS_NPC(ch) ? ch->player.short_descr : GET_NAME(ch)), world[victim->in_room].name); log(buf); if(IS_NPC(ch)){ sprintf(buf,taunt[number(0,NTAUNT)],GET_NAME(victim)); do_shout(ch,buf,0); } } lootflag = IS_NPC(victim) && !IS_NPC(ch) && IS_SET(ch->specials.act, PLR_AUTOLOOT); die(victim); if(lootflag){ struct obj_data *o; if(o = get_obj_in_list_vis(ch,"corpse",world[ch->in_room].contents)) do_get(ch,"all corpse",0); } } } 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,lo,hi,i; int off,def,loff,ldef; int bam,dam,sum,ff,n; char buf[256]; extern int mischance,hitchance; if (ch->in_room != victim->in_room) { if(ch->specials.fighting == victim) stop_fighting(ch); return; } lo=WIELD; if((type==TYPE_UNDEFINED)&&(held=ch->equipment[HOLD])&& (held->obj_flags.type_flag == ITEM_WEAPON)) hi=HOLD; else hi=WIELD; for(i=lo;i<=hi;i++){ if (ch->equipment[i] && (ch->equipment[i]->obj_flags.type_flag == ITEM_WEAPON)) { wielded = ch->equipment[i]; switch (wielded->obj_flags.value[3]) { case 2 : w_type = TYPE_WHIP; break; case 3 : w_type = TYPE_SLASH; break; case 4 : w_type = TYPE_BLAST; break; case 5 : w_type = TYPE_SPLAT; break; case 6 : w_type = TYPE_SPANK; break; case 7 : w_type = TYPE_BLUDGEON; break; case 8 : w_type = TYPE_CRUSH; break; case 9 : w_type = TYPE_BURN; break; 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; } n=number(0,99); if(n < mischance){ sum=(-1); } else if(n > hitchance){ sum=1; } else { loff = GET_LEVEL(ch); ldef = GET_LEVEL(victim); off = loff + GET_STR(ch) + GET_DEX(ch) + GET_HITROLL(ch); def = ldef + GET_STR(victim) + GET_DEX(victim) + GET_AC(victim); sum = 1 + number(0,loff) + off - def; } if (AWAKE(victim) && (sum < 0)){ if (type == SKILL_BACKSTAB) damage(ch,victim,0,SKILL_BACKSTAB); else damage(ch,victim,0,w_type); } else { dam = GET_DAMROLL(ch) + GET_STR(ch) - GET_CON(victim); if(dam < 1) dam=1; if (IS_NPC(ch)) dam += dice(ch->specials.damnodice, ch->specials.damsizedice); else dam += 1; if(wielded){ dam += dice(wielded->obj_flags.value[1],wielded->obj_flags.value[2]); if(IS_SET(wielded->obj_flags.extra_flags,ITEM_SFX)){ ff=(ch->specials.fighting != NULL); weapon_effects(ch,victim,wielded); if(ch->specials.fighting){ if(ch->specials.fighting->in_room != ch->in_room) return; } else { if(ff) return; } } } if (GET_POS(victim) < POSITION_FIGHTING) dam *= 1+(POSITION_FIGHTING-GET_POS(victim))/3; dam = MAX(1, dam); /* Not less than 0 damage */ if (type == SKILL_BACKSTAB) { bam = 2+(GET_LEVEL(ch)/10); dam *= bam; 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); } } } void weapon_effects(struct char_data *ch, struct char_data *vict, struct obj_data *weapon) { int n,w,l,s; n=weapon->obj_flags.value[0]; if(!wsplist[n].spellfun) return; w=GET_WIS(ch); if(number(wsplist[n].lo,wsplist[n].hi) < w){ s=wsplist[n].shift; l=(s) ? wsplist[n].lev+(w>>s) : wsplist[n].lev; (*wsplist[n].spellfun)(l,ch,vict,weapon); } }