/* * $Id: fight.c 1021 2007-02-15 01:16:06Z zsuzsu $ */ /*************************************************************************** * ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR * * ANATOLIA has been brought to you by ANATOLIA consortium * * Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr * * Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr * * Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr * * D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr * * By using this code, you have agreed to follow the terms of the * * ANATOLIA license, in the file Anatolia/anatolia.licence * ***************************************************************************/ /*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * G* In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1995 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@pacinfo.com) * * Gabrielle Taylor (gtaylor@pacinfo.com) * * Brian Moore (rom@rom.efn.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ #include <sys/types.h> #include <limits.h> #include <stdio.h> #include <string.h> #include <time.h> #include <math.h> #if !defined (WIN32) # include <unistd.h> #endif #include "merc.h" #include "debug.h" #include "quest.h" #include "fight.h" #include "rating.h" #include "update.h" #include "mob_prog.h" #include "obj_prog.h" #include "waffects.h" #include "augment.h" #include "stats.h" DECLARE_DO_FUN(do_crush ); DECLARE_DO_FUN(do_emote ); DECLARE_DO_FUN(do_dismount ); DECLARE_DO_FUN(do_bash ); DECLARE_DO_FUN(do_berserk ); DECLARE_DO_FUN(do_disarm ); DECLARE_DO_FUN(do_kick ); DECLARE_DO_FUN(do_dirt ); DECLARE_DO_FUN(do_trip ); DECLARE_DO_FUN(do_tail ); DECLARE_DO_FUN(do_look_in ); DECLARE_DO_FUN(do_get ); DECLARE_DO_FUN(do_sacrifice ); DECLARE_DO_FUN(do_visible ); DECLARE_DO_FUN(do_recall ); DECLARE_DO_FUN(do_flee ); DECLARE_DO_FUN(do_clan ); DECLARE_DO_FUN(do_enslave ); DECLARE_DO_FUN(do_death_announce); DECLARE_SPEC_FUN(spec_breath_any ); DECLARE_SPEC_FUN(spec_breath_acid ); DECLARE_SPEC_FUN(spec_breath_fire ); DECLARE_SPEC_FUN(spec_breath_frost ); DECLARE_SPEC_FUN(spec_breath_gas ); DECLARE_SPEC_FUN(spec_breath_lightning ); DECLARE_SPEC_FUN(spec_cast_cleric ); DECLARE_SPEC_FUN(spec_cast_judge ); DECLARE_SPEC_FUN(spec_cast_mage ); /* * Local functions. */ void check_assist (CHAR_DATA *ch, CHAR_DATA *victim); bool check_dodge (CHAR_DATA *ch, CHAR_DATA *victim); bool check_parry (CHAR_DATA *ch, CHAR_DATA *victim, int loc); bool check_haft_block (CHAR_DATA *ch, CHAR_DATA *victim, int loc); bool check_tumble (CHAR_DATA *ch, CHAR_DATA *victim); bool check_shield_block (CHAR_DATA *ch, CHAR_DATA *victim, int loc); bool check_blink (CHAR_DATA *ch, CHAR_DATA *victim); bool check_space_between_beats (CHAR_DATA *ch, CHAR_DATA *victim); bool check_hand_block (CHAR_DATA *ch, CHAR_DATA *victim); void dam_message (CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, bool immune, int dam_type); void death_cry (CHAR_DATA *ch); void death_cry_org (CHAR_DATA *ch, int part); void group_gain (CHAR_DATA *ch, CHAR_DATA *victim); int xp_compute (CHAR_DATA *gch, CHAR_DATA *victim, int total_levels, int members, int morale); bool is_safe (CHAR_DATA *ch, CHAR_DATA *victim); OBJ_DATA *make_corpse (CHAR_DATA *ch); void strip_char (CHAR_DATA *ch); void one_hit (CHAR_DATA *ch, CHAR_DATA *victim, int dt, int loc); void mob_hit (CHAR_DATA *ch, CHAR_DATA *victim, int dt); void set_fighting (CHAR_DATA *ch, CHAR_DATA *victim); void disarm (CHAR_DATA *ch, CHAR_DATA *victim, int disarm_second); int critical_strike (CHAR_DATA *ch, CHAR_DATA *victim, int dam); void check_eq_damage (CHAR_DATA *ch, CHAR_DATA *victim, int loc); void check_shield_damage (CHAR_DATA *ch, CHAR_DATA *victim, int loc); void check_weapon_damage (CHAR_DATA *ch, CHAR_DATA *victim, int loc); int check_forest (CHAR_DATA *ch); void handle_witch_curse (CHAR_DATA *ch, CHAR_DATA *victim); bool handle_enslavement (CHAR_DATA *ch, CHAR_DATA *victim); bool handle_dishonor (CHAR_DATA *ch, CHAR_DATA *victim); void raw_duel_defeat (CHAR_DATA *ch, CHAR_DATA *victim); #define FOREST_ATTACK 1 #define FOREST_DEFENCE 2 #define FOREST_NONE 0 void handle_death (CHAR_DATA *ch, CHAR_DATA *victim); /* * Gets all money from the corpse. */ void get_gold_corpse(CHAR_DATA *ch, OBJ_DATA *corpse) { OBJ_DATA *tmp, *tmp_next; for (tmp = corpse->contains; tmp; tmp = tmp_next) { tmp_next = tmp->next_content; if (tmp->pIndexData->item_type == ITEM_MONEY) { get_obj(ch, tmp, corpse); } } } int check_forest(CHAR_DATA* ch) { AFFECT_DATA* paf; if (ch->in_room->sector_type != SECT_FOREST && ch->in_room->sector_type != SECT_HILLS && ch->in_room->sector_type != SECT_MOUNTAIN) return FOREST_NONE; for (paf = ch->affected; paf; paf = paf->next) { if (paf->type == gsn_forest_fighting) { if (paf->location == APPLY_AC) return FOREST_DEFENCE; else return FOREST_ATTACK; } } return FOREST_NONE; } /* * Control the fights going on. * Called periodically by update_handler. */ void violence_update(void) { CHAR_DATA *ch; CHAR_DATA *ch_next; CHAR_DATA *victim; OBJ_DATA *obj; OBJ_DATA *obj_next; for (ch = char_list; ch; ch = ch_next) { ch_next = ch->next; /* decrement the wait */ if (ch->desc == NULL) ch->wait = UMAX(0, ch->wait - PULSE_VIOLENCE); if ((victim = ch->fighting) == NULL || ch->in_room == NULL) continue; if (IS_AWAKE(ch) && ch->in_room == victim->in_room) multi_hit(ch, victim, TYPE_UNDEFINED); else stop_fighting(ch, FALSE); if ((victim = ch->fighting) == NULL) continue; if (!IS_NPC(victim)) ch->last_fought = victim; SET_FIGHT_TIME(ch); if (victim->in_room != ch->in_room) continue; for (obj = ch->carrying; obj; obj = obj_next) { obj_next = obj->next_content; if (ch->fighting == NULL) break; oprog_call(OPROG_FIGHT, obj, ch, NULL); } if ((victim = ch->fighting) == NULL || victim->in_room != ch->in_room) continue; /* * Fun for the whole family! */ check_assist(ch, victim); if (IS_NPC(ch)) { if (HAS_TRIGGER(ch, TRIG_FIGHT)) mp_percent_trigger(ch, victim, NULL, NULL, TRIG_FIGHT); if (HAS_TRIGGER(ch, TRIG_HPCNT)) mp_hprct_trigger(ch, victim); } } } /* for auto assisting */ void check_assist(CHAR_DATA *ch,CHAR_DATA *victim) { CHAR_DATA *rch, *rch_next; if (!victim || IS_DELETED(victim) || !ch || IS_DELETED(ch)) return; for (rch = ch->in_room->people; rch != NULL; rch = rch_next) { rch_next = rch->next_in_room; if (IS_AWAKE(rch) && rch->fighting == NULL) { /* quick check for ASSIST_PLAYER */ if (!IS_NPC(ch) && IS_NPC(rch) && IS_SET(rch->pIndexData->off_flags, ASSIST_PLAYERS) && rch->level + 6 > victim->level) { do_emote(rch, "screams and attacks!"); multi_hit(rch,victim,TYPE_UNDEFINED); continue; } /* PCs next */ if (!IS_NPC(rch) || IS_AFFECTED(rch, AFF_CHARM)) { if (((!IS_NPC(rch) && IS_SET(rch->conf_flags, PLR_CONF_AUTOASSIST)) || IS_AFFECTED(rch, AFF_CHARM)) && is_same_group(ch,rch) && !is_safe_nomessage(rch, victim) && !is_affected(rch, gsn_rnet_trap)) multi_hit (rch,victim,TYPE_UNDEFINED); continue; } if (!IS_NPC(ch) && RIDDEN(rch) == ch) { multi_hit(rch,victim,TYPE_UNDEFINED); continue; } /* now check the NPC cases */ if (IS_NPC(ch)) { if ((IS_NPC(rch) && IS_SET(rch->pIndexData->off_flags,ASSIST_ALL)) || (IS_NPC(rch) && rch->race == ch->race && IS_SET(rch->pIndexData->off_flags,ASSIST_RACE)) || (IS_NPC(rch) && IS_SET(rch->pIndexData->off_flags,ASSIST_ALIGN) && ((IS_GOOD(rch) && IS_GOOD(ch)) || (IS_EVIL(rch) && IS_EVIL(ch)) || (IS_NEUTRAL(rch) && IS_NEUTRAL(ch)))) || (rch->pIndexData == ch->pIndexData && IS_SET(rch->pIndexData->off_flags,ASSIST_VNUM))) { CHAR_DATA *vch; CHAR_DATA *target; int number; if (number_bits(1) == 0) continue; target = NULL; number = 0; for (vch = ch->in_room->people; vch; vch = vch->next_in_room) { if (can_see(rch,vch) && is_same_group(vch,victim) && number_range(0,number) == 0) { target = vch; number++; } } if (target != NULL) { do_emote(rch,"screams and attacks!"); multi_hit(rch,target,TYPE_UNDEFINED); } } } } } } /* * Do one group of attacks. */ void multi_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt) { int chance; int staff = 0; int dualstaff = 0; if (IS_DELETED(victim)) return; /* no attacks for stunnies -- just a check */ if (ch->position < POS_RESTING) return; #if 0 /* become CRIMINAL in Law rooms */ if (!IS_NPC(ch) && !IS_NPC(victim) && IS_SET(ch->in_room->room_flags, ROOM_LAW) && !IS_SET(victim->state_flags, STATE_WANTED) && !IS_SET(ch->state_flags, STATE_WANTED)) { char_puts("This room is under supervision of the law! " "Now you're {RCRIMINAL{x!\n", ch); SET_BIT(ch->state_flags, STATE_WANTED); } #endif /* ridden's adjustment */ if (RIDDEN(victim) && !IS_NPC(victim->mount)) { if (victim->mount->fighting == NULL || victim->mount->fighting == ch) victim = victim->mount; else do_dismount(victim->mount, str_empty); } if (IS_AFFECTED(ch,AFF_WEAK_STUN)) { act_puts("You are too stunned to respond $N's attack.", ch, NULL, victim, TO_CHAR, POS_FIGHTING); act_puts("$n is too stunned to respond your attack.", ch, NULL, victim, TO_VICT, POS_FIGHTING); REMOVE_BIT(ch->affected_by, AFF_WEAK_STUN); return; } if (IS_AFFECTED(ch,AFF_STUN)) { act_puts("You are too stunned to respond $N's attack.", ch, NULL, victim, TO_CHAR, POS_FIGHTING); act_puts("$n is too stunned to respond your attack.", ch, NULL, victim, TO_VICT, POS_FIGHTING); act_puts("$n seems to be stunned.", ch, NULL, victim, TO_NOTVICT, POS_FIGHTING); REMOVE_BIT(ch->affected_by, AFF_STUN); affect_bit_strip(ch, TO_AFFECTS, AFF_STUN); SET_BIT(ch->affected_by, AFF_WEAK_STUN); return; } if (IS_NPC(ch)) { mob_hit(ch, victim, dt); return; } one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim) return; if ((chance = get_skill(ch, gsn_area_attack)) && number_percent() < chance) { int count = 0, max_count; CHAR_DATA *vch, *vch_next; check_improve(ch, gsn_area_attack, TRUE, 6); if (LEVEL(ch) < 70) max_count = 1; else if (LEVEL(ch) < 80) max_count = 2; else if (LEVEL(ch) < 90) max_count = 3; else max_count = 4; for (vch = ch->in_room->people; vch; vch = vch_next) { vch_next = vch->next_in_room; if (vch != victim && vch->fighting == ch) { one_hit(ch, vch, dt, WEAR_WIELD); if (++count == max_count) break; } } } if (IS_AFFECTED(ch, AFF_HASTE)) one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim || dt == gsn_backstab || dt == gsn_cleave || dt == gsn_ambush || dt == gsn_dual_backstab || dt == gsn_circle || dt == gsn_assassinate || dt == gsn_vampiric_bite || dt == gsn_knife) return; if (get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_STAFF) staff = 4; if (get_eq_char(ch, WEAR_SECOND_WIELD) && get_eq_char(ch, WEAR_SECOND_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_STAFF) dualstaff = 4; chance = get_skill(ch, gsn_second_attack) / 2; chance += staff; if (number_percent() < chance) { one_hit(ch, victim, dt, WEAR_WIELD); check_improve(ch, gsn_second_attack, TRUE, 5); if (ch->fighting != victim) return; } chance = get_skill(ch,gsn_third_attack)/3; chance += staff; if (number_percent() < chance) { one_hit(ch, victim, dt, WEAR_WIELD); check_improve(ch, gsn_third_attack, TRUE, 6); if (ch->fighting != victim) return; } chance = get_skill(ch,gsn_fourth_attack)/6; chance += staff; if (number_percent() < chance) { one_hit(ch, victim, dt, WEAR_WIELD); check_improve(ch, gsn_fourth_attack, TRUE, 7); if (ch->fighting != victim) return; } chance = get_skill(ch,gsn_fifth_attack)/8; chance += staff; if (number_percent() < chance) { one_hit(ch, victim, dt, WEAR_WIELD); check_improve(ch,gsn_fifth_attack,TRUE,8); if (ch->fighting != victim) return; } if (check_forest(ch) == FOREST_ATTACK) { chance = get_skill(ch, gsn_forest_fighting); while (number_percent() < chance) { one_hit(ch, victim, dt, WEAR_WIELD); check_improve (ch, gsn_forest_fighting, TRUE, 8); if (ch->fighting != victim) return; chance /= 3; } } chance = get_skill(ch, gsn_second_weapon) / 2; chance += dualstaff; if (number_percent() < chance) if (get_eq_char(ch, WEAR_SECOND_WIELD)) { one_hit(ch, victim, dt, WEAR_SECOND_WIELD); check_improve(ch, gsn_second_weapon, TRUE, 2); if (ch->fighting != victim) return; } chance = get_skill(ch,gsn_secondary_attack) / 8; chance += dualstaff; if (number_percent() < chance) if (get_eq_char(ch, WEAR_SECOND_WIELD)) { one_hit(ch, victim, dt, WEAR_SECOND_WIELD); check_improve(ch, gsn_secondary_attack, TRUE, 2); if (ch->fighting != victim) return; } } /* procedure for all mobile attacks */ void mob_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt) { CHAR_DATA *vch, *vch_next; flag64_t act = ch->pIndexData->act; flag64_t off = ch->pIndexData->off_flags; /* no attack by ridden mobiles except spec_casts */ if (RIDDEN(ch)) { if (ch->fighting != victim) { stop_fighting(ch, FALSE); set_fighting(ch, victim); } return; } one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim) return; /* Area attack -- BALLS nasty! */ if (IS_SET(off, OFF_AREA_ATTACK)) { for (vch = ch->in_room->people; vch != NULL; vch = vch_next) { vch_next = vch->next_in_room; if ((vch != victim && vch->fighting == ch)) one_hit(ch, vch, dt, WEAR_WIELD); } } if (IS_AFFECTED(ch, AFF_HASTE) || IS_SET(off, OFF_FAST)) one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim || dt == gsn_backstab || dt == gsn_circle || dt == gsn_dual_backstab || dt == gsn_cleave || dt == gsn_ambush || dt == gsn_vampiric_bite || dt == gsn_knife) return; if (number_percent() < get_skill(ch, gsn_second_attack) / 2) { one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim) return; } if (number_percent() < get_skill(ch, gsn_third_attack) / 4) { one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim) return; } if (number_percent() < get_skill(ch, gsn_fourth_attack) / 6) { one_hit(ch, victim, dt, WEAR_WIELD); if (ch->fighting != victim) return; } /* PC waits */ if (ch->wait > 0) return; #if 0 switch (number_range(0, 2)) { case 1: if (IS_SET(act, ACT_MAGE)) { mob_cast_mage(ch, victim); return; } break; case 2: if (IS_SET(act, ACT_CLERIC)) { mob_cast_cleric(ch, victim); return; } break; } #endif /* now for the skills */ switch (number_range(0, 7)) { case 0: if (IS_SET(off, OFF_BASH)) do_bash(ch, str_empty); break; case 1: if (IS_SET(off, OFF_BERSERK) && !IS_AFFECTED(ch, AFF_BERSERK)) do_berserk(ch, str_empty); break; case 2: if (IS_SET(off, OFF_DISARM) || IS_SET(act, ACT_WARRIOR | ACT_THIEF)) { if (number_range(0, 1) && get_eq_char(victim, WEAR_SECOND_WIELD)) do_disarm(ch, "second"); else if (get_eq_char(victim, WEAR_WIELD)) do_disarm(ch, str_empty); } break; case 3: if (IS_SET(off, OFF_KICK)) do_kick(ch, str_empty); break; case 4: if (IS_SET(off, OFF_DIRT_KICK)) do_dirt(ch, str_empty); break; case 5: if (IS_SET(off, OFF_TAIL)) do_tail(ch, str_empty); break; case 6: if (IS_SET(off, OFF_TRIP)) do_trip(ch, str_empty); break; case 7: if (IS_SET(off, OFF_CRUSH)) do_crush(ch, str_empty); break; } } /** * ac reduces the amount of damage contributed by damroll */ int dam_damroll_vs_ac(CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *wield, int bonus) { int dam = 0; int sk = 0; int sn = 0; int ac = 0; int dam_type = (wield) ? attack_table[wield->value[ITEM_WEAPON_ATTACK_TYPE]].damage : attack_table[ch->dam_type].damage; switch(dam_type) { case DAM_PIERCE:ac = GET_AC(victim,AC_PIERCE); break; case DAM_BASH: ac = GET_AC(victim,AC_BASH); break; case DAM_SLASH: ac = GET_AC(victim,AC_SLASH); break; default: ac = GET_AC(victim,AC_EXOTIC); break; } sn = get_weapon_sn(wield); sk = get_weapon_skill(ch, sn); ac = UMIN(0, ac); dam = (GET_DAMROLL(ch) * UMAX(100, sk)/100) + bonus + ac; DEBUG(DEBUG_DAM_AC_REDUCT, "%s[dr: %d/sk:%d] vs %s[ac:%d] = %d dam_mod", CHAR_NAME(ch), GET_DAMROLL(ch), sk, CHAR_NAME(victim), ac, dam); return dam; } int get_dam_type(CHAR_DATA *ch, OBJ_DATA *wield, int *dt) { int dam_type; if (*dt == TYPE_UNDEFINED) { *dt = TYPE_HIT; if (wield && wield->pIndexData->item_type == ITEM_WEAPON) *dt += wield->value[ITEM_WEAPON_ATTACK_TYPE]; else *dt += ch->dam_type; } if (*dt < TYPE_HIT) if (wield) dam_type = attack_table[wield->value[ITEM_WEAPON_ATTACK_TYPE]].damage; else dam_type = attack_table[ch->dam_type].damage; else dam_type = attack_table[*dt - TYPE_HIT].damage; if (dam_type == TYPE_UNDEFINED) dam_type = DAM_BASH; return dam_type; } #define DAM_BASE 0 #define DAM_SHARP 1 #define DAM_NOSHIELD 2 #define DAM_ENHANCED 3 #define DAM_MASTER_HAND 4 #define DAM_MASTERING_SWORD 5 #define DAM_DOUBLE_GRIP 6 #define DAM_SLEEPING 7 #define DAM_NOT_FIGHTING 8 #define DAM_BACKSTAB 9 #define DAM_DUAL_BACKSTAB 10 #define DAM_DEATHBLOW 11 #define DAM_CLEAVE 12 #define DAM_AMBUSH 13 #define DAM_ASSASSINATE 14 #define DAM_CHARGE 15 #define DAM_CIRCLE 16 #define DAM_KNIFE 17 #define DAM_DRvAC_REAL 18 #define DAM_DRvAC_MOD 19 #define DAM_HIT_MAX 20 /* sum the damage up */ int damage_total(int* dam) { int sum = 0; int i; for (i = 0; i < DAM_HIT_MAX; i++) if (i != DAM_DRvAC_REAL) sum += dam[i]; return sum; } /* * Hit one guy once. */ void one_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt, int loc) { OBJ_DATA *wield; OBJ_DATA *dual = NULL; int dam2; int dam[DAM_HIT_MAX]; bool bonus[DAM_HIT_MAX]; bool modify_base = TRUE; int diceroll; int sn = 0, sk = 0, sk2 = 0; int dam_type; bool counter; bool result; int sercount; int dam_flags; class_t *cl; bool deathblow = FALSE; int chance = 0; int i; for (i = 0; i < DAM_HIT_MAX; i++) { dam[i] = 0; bonus[i] = TRUE; } sn = -1; counter = FALSE; if (IS_DELETED(victim) || IS_DELETED(ch)) return; /* just in case */ if (victim == ch || ch == NULL || victim == NULL) return; /* * Can't beat a dead char! * Guard against weird room-leavings. */ if (victim->position == POS_DEAD || ch->in_room != victim->in_room) return; /* * Figure out the type of damage message. */ wield = get_eq_char(ch, loc); dam_flags = DAMF_SHOW; if (loc == WEAR_SECOND_WIELD) dam_flags |= DAMF_SECOND; dam_type = get_dam_type(ch, wield, &dt); dual = get_eq_char(ch, WEAR_SECOND_WIELD); /* * don't double backstab if the second weapon isn't peircing */ if (dt == gsn_dual_backstab && !IS_NPC(ch) && (!dual || attack_table[dual->value[ITEM_WEAPON_ATTACK_TYPE]].damage != DAM_PIERCE)) { return; } /* get the weapon skill */ sn = get_weapon_sn(wield); sk = 20 + get_weapon_skill(ch, sn); if (get_skill(victim, gsn_armor_use) > 70) { check_improve(victim, gsn_armor_use, TRUE, 8); } if (!can_see(ch, victim)) { if ((sk2 = get_skill(ch, gsn_blind_fighting)) && number_percent() < sk2) check_improve(ch,gsn_blind_fighting,TRUE,16); } /* * The moment of excitement! */ while ((diceroll = number_bits(5)) >= 20) ; chance = tohit_chance(ch, victim, dt, loc); if (diceroll == 0 || (diceroll != 19 && diceroll < chance)) { /* Miss. */ damage(ch, victim, 0, dt, dam_type, dam_flags); tail_chain(); return; } /* special skill hits first */ /* vampiric bite *************************************************/ /* doesn't use weapon for damage */ if (dt == gsn_vampiric_bite) { sk = get_skill(ch, gsn_vampiric_bite); dam[DAM_BASE] = 2 * LEVEL(ch) * sk / 100; if (IS_NPC(victim)) dam[DAM_BASE] = (LEVEL(ch)/11 + 1) * dam[DAM_BASE] + LEVEL(ch); else dam[DAM_BASE] = (LEVEL(ch)/20 + 1) * dam[DAM_BASE] + LEVEL(ch); DEBUG(DEBUG_DAM_ONEHIT, "%s vbite base %d w/weapon %d", CHAR_NAME(ch), dam[DAM_BASE], (wield) ? dice(wield->value[ITEM_WEAPON_DICE_NUM], wield->value[ITEM_WEAPON_DICE_SIZE]) : 0 ); bonus[DAM_ENHANCED] = bonus[DAM_DEATHBLOW] = bonus[DAM_DOUBLE_GRIP] = FALSE; modify_base = FALSE; } /* dual backstab *************************************************/ else if ((dt == gsn_dual_backstab) && dual) { sk2 = 20 + get_weapon_skill(ch, get_weapon_sn(dual)); dam[DAM_BASE] = dice(dual->value[ITEM_WEAPON_DICE_NUM], dual->value[ITEM_WEAPON_DICE_SIZE]) * sk2 / 100; bonus[DAM_ENHANCED] = bonus[DAM_DEATHBLOW] = bonus[DAM_NOSHIELD] = bonus[DAM_DOUBLE_GRIP] = FALSE; modify_base = FALSE; } /* normal weapon hit *********************************************/ else if (wield != NULL) { if (sn != -1) check_improve(ch, sn, TRUE, 5); dam[DAM_BASE] = dice(wield->value[ITEM_WEAPON_DICE_NUM], wield->value[ITEM_WEAPON_DICE_SIZE]) * sk / 100; /* make sure putting a nerfed weapon in a mob's * hands doesn't nerf it */ if (IS_NPC(ch)) { dam2 = dice(ch->damage[DICE_NUMBER], ch->damage[DICE_TYPE]); dam[DAM_BASE] = (dam[DAM_BASE] > dam2) ? dam[DAM_BASE] : dam2; } } /* NPCs w/o weapons **********************************************/ else if (IS_NPC(ch)) { dam[DAM_BASE] = dice(ch->damage[DICE_NUMBER], ch->damage[DICE_TYPE]); } /* PC Hand damage *************************************************/ else { dam[DAM_BASE] = number_range(1 + 4 * sk / 100, LEVEL(ch) * sk / 100); if ((sk2 = get_skill(ch, gsn_master_hand)) && number_percent() < sk2) { check_improve(ch, gsn_master_hand, TRUE, 6); dam[DAM_MASTER_HAND] = dice(LEVEL(ch) / 20, LEVEL(ch) * sk2 / 100); } bonus[DAM_NOSHIELD] = bonus[DAM_DOUBLE_GRIP] = FALSE; } if (modify_base) dam[DAM_BASE] = dam[DAM_BASE] * MELEE_BASE_DAMAGE_MODIFIER /100; /*********** * bonuses * ***********/ /* no shield = more ***********************************************/ if (bonus[DAM_NOSHIELD]) { if (get_eq_char(ch, WEAR_SHIELD) == NULL) dam[DAM_NOSHIELD] = dam[DAM_BASE] * 1/20; } /* sharpness! *****************************************************/ if (bonus[DAM_SHARP] && wield && IS_WEAPON_STAT(wield, WEAPON_SHARP)) { int percent; if ((percent = number_percent()) <= (sk / 8)) dam[DAM_SHARP] = dam[DAM_BASE] + (dam[DAM_BASE] * 2 * percent / 100); } /* enhanced damage ************************************************/ if (bonus[DAM_ENHANCED] && (sk2 = get_skill(ch, gsn_enhanced_damage)) && (diceroll = number_percent()) <= sk2) { dam[DAM_ENHANCED] = dam[DAM_BASE] * diceroll * sk2 / 10000; check_improve(ch, gsn_enhanced_damage, TRUE, 6); cl = class_lookup(ch->class); if (!(cl == NULL) && ( str_cmp(cl->name, "ninja") || str_cmp(cl->name, "thief"))) dam[DAM_ENHANCED] /= 2; } /* bonus for double-gripping a one handed weapon *******************/ if (bonus[DAM_DOUBLE_GRIP] && wield && !IS_WEAPON_STAT(wield, WEAPON_TWO_HANDS) && get_skill(ch, gsn_double_grip) > 0) { check_improve(ch, gsn_double_grip, TRUE, 100); /*rare*/ dam[DAM_DOUBLE_GRIP] = dam[DAM_BASE] * 10/100; } /* mastering sword *************************************************/ if (bonus[DAM_MASTERING_SWORD] && (sn == gsn_katana || sn == gsn_longsword || sn == gsn_shortsword || sn == gsn_bastardsword) && (sk2 = get_skill(ch, gsn_mastering_sword)) && number_percent() <= sk2) { OBJ_DATA *katana; check_improve(ch, gsn_mastering_sword, TRUE, 6); dam[DAM_MASTERING_SWORD] = dam[DAM_BASE] * 20/100; if (((katana = get_eq_char(ch,WEAR_WIELD)) || (katana = get_eq_char(ch, WEAR_SECOND_WIELD))) && IS_WEAPON_STAT(katana, WEAPON_KATANA_QUEST) && strstr(mlstr_mval(katana->ed->description), ch->name)) { if ((katana->cost = ++katana->cost % 250) == 0) { AFFECT_DATA *paf = NULL, *af_toHit = NULL, *af_toDam = NULL; int old_toHit = 0; int old_toDam = 0; paf = katana->affected; while (paf != NULL) { if (paf->type == gsn_katana) switch (paf->location) { case APPLY_HITROLL: af_toHit = paf; break; case APPLY_DAMROLL: af_toDam = paf; break; default: DEBUG(DEBUG_BUG, "bad affect on %s's katana location %d type: %d mod: %d", ch->name, paf->location, paf->type, paf->modifier); } paf = paf->next; } if (af_toHit && af_toDam) { old_toHit = af_toHit->modifier; old_toDam = af_toDam->modifier; af_toHit->modifier = UMIN(af_toHit->modifier+1, ch->level / 3); af_toDam->modifier = UMIN(af_toDam->modifier+1, ch->level / 3); ch->hitroll += af_toHit->modifier - old_toHit; ch->damroll += af_toDam->modifier - old_toDam; act("$n's katana glows {Bblue{x.\n", ch, NULL, NULL, TO_ROOM); char_puts("Your katana glows {Bblue{x.\n",ch); } else { bug("quest katana - couldn't find toHit or toDam",0); } } } } /* sleeping victim **************************************************/ if (bonus[DAM_SLEEPING] && !IS_AWAKE(victim)) dam[DAM_SLEEPING] = damage_total(dam); /* not fighting *****************************************************/ else if (bonus[DAM_NOT_FIGHTING] && victim->position < POS_FIGHTING) dam[DAM_NOT_FIGHTING] = damage_total(dam) /2; /* counter **********************************************************/ sercount = number_percent(); if (dt == gsn_backstab || dt == gsn_vampiric_bite) sercount += 40; if (!IS_IMMORTAL(ch) && IS_PUMPED(ch)) sercount += 10; sercount *= 2; if (victim->fighting == NULL && !IS_NPC(victim) && !is_safe_nomessage(victim, ch) && !is_safe_nomessage(ch,victim) && (victim->position == POS_SITTING || victim->position == POS_STANDING) && dt != gsn_assassinate && (sercount <= get_skill(victim, gsn_counter))) { counter = TRUE; check_improve(victim,gsn_counter,TRUE,1); act("$N turns your attack against you!", ch, NULL, victim, TO_CHAR); act("You turn $n's attack against $m!", ch, NULL, victim, TO_VICT); act("$N turns $n's attack against $m!", ch, NULL, victim, TO_NOTVICT); ch->fighting = victim; } else if (!victim->fighting) check_improve(victim, gsn_counter, FALSE, 1); /************************************* * special weaponed attacks *************************************/ /* backstab ********************************************************/ if (dt == gsn_backstab && (IS_NPC(ch) || wield)) { /* is NPC don't need a wielded weapon*/ if (IS_NPC(victim)) dam[DAM_BACKSTAB] = damage_total(dam) * (LEVEL(ch) / 10 + 1); else dam[DAM_BACKSTAB] = damage_total(dam) * (LEVEL(ch) / 15 + 1); } /* dual backstab **************************************************/ else if (dt == gsn_dual_backstab) { if (IS_NPC(victim)) dam[DAM_DUAL_BACKSTAB] = damage_total(dam) * (LEVEL(ch) / 20); else dam[DAM_DUAL_BACKSTAB] = damage_total(dam) * (LEVEL(ch) / 30); } else if (dt == gsn_circle && wield) { dam[DAM_CIRCLE] = (LEVEL(ch)/30 + 1) * damage_total(dam); } else if (dt == gsn_knife && wield) { dam[DAM_KNIFE] = (LEVEL(ch)/25 + 1) * damage_total(dam); } /* ranger */ else if (dt == gsn_ambush) { if (IS_NPC(victim)) dam[DAM_AMBUSH] = (LEVEL(ch)/20) * damage_total(dam); else dam[DAM_AMBUSH] = (LEVEL(ch)/30) * damage_total(dam); } /* AP */ else if (dt == gsn_cleave && wield) { if (IS_NPC(victim) && number_percent() < (URANGE(4, 5+LEVEL(ch)-LEVEL(victim), 10) + (wield->value[ITEM_WEAPON_TYPE]==WEAPON_AXE) ? 2:0 + (get_curr_stat(ch,STAT_STR)-60)/8) && !counter && !IS_IMMORTAL(victim)) { act_puts("Your cleave chops $N IN HALF!", ch, NULL, victim, TO_CHAR, POS_RESTING); act_puts("$n's cleave chops you IN HALF!", ch, NULL, victim, TO_VICT, POS_RESTING); act_puts("$n's cleave chops $N IN HALF!", ch, NULL, victim, TO_NOTVICT, POS_RESTING); WAIT_STATE(ch, 2); handle_death(ch, victim); return; } else dam[DAM_CLEAVE] = damage_total(dam); } /* ninja */ else if (dt == gsn_assassinate) { if (IS_NPC(victim) && number_percent() <= URANGE(10, 20+(LEVEL(ch) - LEVEL(victim))*4, 50) && !counter && !IS_IMMORTAL(victim)) { act_puts("You {R+++ASSASSINATE+++{x $N!", ch, NULL, victim, TO_CHAR, POS_RESTING); act_puts("$n {R+++ASSASSINATES+++{x $N!", ch, NULL, victim, TO_NOTVICT, POS_RESTING); act_puts("$n {R+++ASSASSINATES+++{x you!", ch, NULL, victim, TO_VICT, POS_DEAD); check_improve(ch, gsn_assassinate, TRUE, 1); handle_death(ch, victim); return; } else { check_improve(ch, gsn_assassinate, FALSE, 1); dam[DAM_ASSASSINATE] = 2 * damage_total(dam); } } /* knight **********************************************************/ else if (dt == gsn_charge) { dam[DAM_CHARGE] = damage_total(dam) * LEVEL(ch) / 12; } /* death blow ******************************************************/ if (bonus[DAM_DEATHBLOW] && (sk2 = get_skill(ch, gsn_deathblow)) > 1) { if (number_percent() < (sk2/8)) { dam[DAM_DEATHBLOW] = dam[DAM_BASE] * 2/10; deathblow = TRUE; check_improve(ch, gsn_deathblow, TRUE, 10); } else check_improve(ch, gsn_deathblow, FALSE, 10); } dam[DAM_DRvAC_REAL] = dam_damroll_vs_ac(ch, victim, wield, 0); dam[DAM_DRvAC_MOD] = URANGE(-1/10 * damage_total(dam), dam[DAM_DRvAC_REAL], damage_total(dam) / 2); /* * damage from the hit ********************************************* */ if (counter) { result = damage(ch, ch, 2*damage_total(dam), dt, dam_type, DAMF_SHOW); multi_hit(victim, ch, TYPE_UNDEFINED); } else result = damage(ch, victim, damage_total(dam), dt, dam_type, dam_flags); DEBUG(DEBUG_MELEE, "%s[%d] %s %s[%d]: " "actual: %d tot: %d base: %d" " sharp: %d" " nosh: %d" " enha: %d" " mhan: %d" " mswd: %d" " slep: %d" " nfit: %d" " bs: %d" " dubs: %d" " dthb: %d" " clev: %d" " ambu: %d" " assa: %d" " chrg: %d" " circ: %d" " knif: %d" " dracR: %d" " dracM: %d", CHAR_NAME(ch), LEVEL(ch), (sn) ? skill_name(sn) : "melee", CHAR_NAME(victim), LEVEL(victim), result, damage_total(dam), dam[DAM_BASE], dam[DAM_SHARP], dam[DAM_NOSHIELD], dam[DAM_ENHANCED], dam[DAM_MASTER_HAND], dam[DAM_MASTERING_SWORD], dam[DAM_SLEEPING], dam[DAM_NOT_FIGHTING], dam[DAM_BACKSTAB], dam[DAM_DUAL_BACKSTAB], dam[DAM_DEATHBLOW], dam[DAM_CLEAVE], dam[DAM_AMBUSH], dam[DAM_ASSASSINATE], dam[DAM_CHARGE], dam[DAM_CIRCLE], dam[DAM_KNIFE], dam[DAM_DRvAC_REAL], dam[DAM_DRvAC_MOD]); /* * extra damage */ if (result && deathblow) { act("You really got your weight behind that one!", ch, NULL, NULL, TO_CHAR); act("$n's blow hits with extra force!", ch, NULL, NULL, TO_ROOM); } /* vampiric bite gives hp to ch from victim */ if (result && dt == gsn_vampiric_bite) { int hit_ga = UMIN((damage_total(dam) / 2), victim->max_hit); ch->hit += hit_ga; ch->hit = UMIN(ch->hit, ch->max_hit); update_pos(ch); char_puts("Your health increases as you suck " "your victim's blood.\n", ch); } /* but do we have a funky weapon? */ if (result && wield != NULL && ch->fighting == victim) { int extra_dam; if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_VORPAL)) { int chance; chance = get_skill(ch, get_weapon_sn(wield)) + get_curr_stat(ch, STAT_STR); if (chance > number_range(1, 200000) && !IS_IMMORTAL(victim)) { act("$p makes an huge arc in the air, " "chopping $n's head OFF!", victim, wield, NULL, TO_ROOM); act("$p whistles in the air, " "chopping your head OFF!", victim, wield, NULL, TO_CHAR); handle_death(ch, victim); return; } } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_POISON)) { int level; AFFECT_DATA *poison, af; if ((poison = affect_find(wield->affected, gsn_poison)) == NULL) level = wield->level; else level = poison->level; if (!saves_spell(level / 2,victim, DAM_POISON)) { char_puts("You feel poison coursing " "through your veins.", victim); act("$n is poisoned by the venom on $p.", victim, wield, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_poison; af.level = level * 3/4; af.duration = level / 2; af.location = APPLY_STR; af.modifier = -1; af.bitvector = AFF_POISON; affect_join(victim, &af); } /* weaken the poison if it's temporary */ if (poison != NULL) { poison->level = UMAX(0,poison->level - 2); poison->duration = UMAX(0,poison->duration - 1); if (poison->level == 0 || poison->duration == 0) act("The poison on $p has worn off.", ch, wield, NULL, TO_CHAR); } } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_HOLY) && IS_GOOD(ch) && IS_EVIL(victim)) { extra_dam = number_range(dam[DAM_BASE] * 1/5+1, dam[DAM_BASE] * 2 / 5+1); if (damage(ch, victim, extra_dam, 0, DAM_HOLY, DAMF_NONE)) { act("$n's flesh was burned with the holy aura of $p.", victim, wield, NULL, TO_ROOM); act_puts("Your flesh was burned with the holy aura of $p.", victim, wield, NULL, TO_CHAR, POS_DEAD); } } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_VAMPIRIC)) { int suck_heal = 0; extra_dam = number_range(dam[DAM_BASE]/7+1, dam[DAM_BASE] /5+1); if (IS_NPC(victim)) suck_heal = extra_dam /5; else suck_heal = extra_dam /2; if (damage(ch, victim, extra_dam, 0, DAM_NEGATIVE, DAMF_NONE)) { act("$p draws life from $n.", victim, wield, NULL, TO_ROOM); act("You feel $p drawing your life away.", victim, wield, NULL, TO_CHAR); if (ch->hit + suck_heal < ch->hit * 12/10) ch->hit += suck_heal; else suck_heal = 0; DEBUG(DEBUG_VAMPIRIC, "vampiric: %s[%d] %dhp(+%d)" " vs %s[%d] %dhp(-%d) with %s", ch->name, LEVEL(ch), ch->hit, suck_heal, victim->name, LEVEL(victim), victim->hit, extra_dam, wield->name); } } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_FLAMING)) { extra_dam = number_range(1,wield->level / 4 + 1); act("$n is burned by $p.", victim, wield, NULL, TO_ROOM); act("$p sears your flesh.", victim, wield, NULL, TO_CHAR); fire_effect((void *) victim, wield->level/2, extra_dam, TARGET_CHAR); damage(ch, victim, extra_dam, 0, DAM_FIRE, DAMF_NONE); } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_FROST)) { extra_dam = number_range(1,wield->level / 6 + 2); act("$p freezes $n.", victim, wield, NULL, TO_ROOM); act("The cold touch of $p surrounds you with ice.", victim, wield, NULL, TO_CHAR); cold_effect(victim, wield->level/2, extra_dam, TARGET_CHAR); damage(ch, victim, extra_dam, 0, DAM_COLD, DAMF_NONE); } if (victim->hit > 0 && IS_WEAPON_STAT(wield, WEAPON_SHOCKING)) { extra_dam = number_range(1, wield->level/5 + 2); act("$n is struck by lightning from $p.", victim, wield, NULL, TO_ROOM); act("You are shocked by $p.", victim, wield, NULL, TO_CHAR); shock_effect(victim, wield->level/2, extra_dam, TARGET_CHAR); damage(ch, victim, extra_dam, 0, DAM_LIGHTNING, DAMF_NONE); } } if (is_not_my_augment(ch, wield) && !IS_IMMORTAL(ch)) wield = augment_unauthorized_use(ch, wield); tail_chain(); } /* * handle_death - called from `damage' if `ch' has killed `victim' */ void handle_death(CHAR_DATA *ch, CHAR_DATA *victim) { bool vnpc = IS_NPC(victim); CHAR_DATA *gch = NULL; ROOM_INDEX_DATA *vroom = victim->in_room; bool is_duel = !IS_NPC(victim) && (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM)) && (IS_SET(victim->in_room->room_flags, ROOM_BATTLE_ARENA) || is_waffected(victim, WAFF_ARENA)); OBJ_DATA *corpse; class_t *cl; WORLD_AFFECT_DATA *waff; if (!is_duel) handle_dishonor(ch, victim); if (!is_duel && handle_enslavement(ch, victim)) { group_gain(ch, victim); return; } if (!IS_NPC(ch)) { if (!is_duel) { act("$n is DEAD!!", victim, NULL, NULL, TO_ROOM); char_puts("You have been KILLED!!\n\n", victim); victim->position = POS_DEAD; } else { act("$n is DEFEATED!", victim, NULL, NULL, TO_ROOM); char_puts("You have been DEFEATED!\n\n", victim); victim->position = POS_DEAD; } } /* world affect for gold drop bonus */ if (vnpc && !IS_SET(victim->affected_by, AFF_CHARM) && !IS_SET(victim->pIndexData->act, ACT_PET) && (waff = ch_waffected(ch, WAFF_GOLD)) != NULL) { if (number_percent() <= waff->chance) { victim->gold += (victim->pIndexData->wealth /100) * (waff->modifier / 100); } } group_gain(ch, victim); if (!is_duel) align_standing_death_gain(ch, victim); /* * Death trigger */ if (vnpc && HAS_TRIGGER(victim, TRIG_DEATH)) { victim->position = POS_STANDING; mp_percent_trigger(victim, ch, NULL, NULL, TRIG_DEATH); } /* if victim has witch cursed someone, cure them. */ if (!is_duel) handle_witch_curse(ch, victim); /* remove pk_ok victim was in anyone's list */ if (!is_duel) { for (gch = ch->in_room->people; gch; gch = gch->next_in_room) { if (!is_same_group(gch, ch) || IS_NPC(gch)) continue; delete_pk_ok(gch, victim); } } if (vnpc) wiznet("$N killed $t.", ch, mlstr_mval(victim->short_descr), WIZ_MOBDEATHS, 0, 0); else if (is_duel) wiznet_death(ch, victim, DEATH_DUEL); else wiznet_death(ch, victim, DEATH_KILL); if (is_duel) { raw_duel_defeat(ch, victim); return; } else corpse = raw_kill(ch, victim, is_duel); /* RT new auto commands */ if (!IS_NPC(ch) && vnpc && vroom == ch->in_room && corpse && can_see_obj(ch, corpse)) { if (HAS_SKILL(ch, gsn_vampire)) { act_puts("$n sucks {rblood{x from $N's corpse!!", ch, NULL,victim,TO_ROOM,POS_RESTING); char_puts("You suck {rblood{x " "from the corpse.\n\n", ch); gain_condition(ch, COND_BLOODLUST, 3); } if (IS_SET(ch->conf_flags, PLR_CONF_AUTOLOOK)) do_look_in(ch, "corpse"); if (corpse->contains) { /* corpse exists and not empty */ if (IS_SET(ch->conf_flags, PLR_CONF_AUTOLOOT)) { get_gold_corpse(ch, corpse); do_get(ch, "all corpse"); } else if (IS_SET(ch->conf_flags, PLR_CONF_AUTOGOLD)) get_gold_corpse(ch, corpse); } if (IS_SET(ch->conf_flags, PLR_CONF_AUTOSAC)) sac_obj(ch, corpse); } if (vnpc || victim->position == POS_STANDING || is_duel) return; /* Dying penalty: 2/3 way back. */ if (IS_SET(victim->state_flags, STATE_WANTED) && victim->level > 1) { REMOVE_BIT(victim->state_flags, STATE_WANTED); victim->level--; victim->pcdata->plevels++; victim->exp = exp_for_level(victim, victim->level); victim->exp_tl = 0; } else if (victim->exp_tl > 0) gain_exp(victim, -victim->exp_tl*2/3); /* dispatch the true lifers */ if (IS_SET(victim->acct_flags, ACCT_TRUE_LIFER)) { char buf[MAX_STRING_LENGTH]; if (victim->level > (LEVEL_HERO/2)) { act_puts( "{WZsuzsu{x descends from the heavens and whispers a solemn eulogy\n" "before carrying your soul in her arms, off to {WValhalla{x!\n", victim, NULL, NULL, TO_CHAR, POS_DEAD); act_puts( "{WZsuzsu{x descends from the heavens and whispers a solemn eulogy\n" "before carrying $N's soul in her arms, off to {WValhalla{x!", victim, NULL, NULL, TO_ROOM, POS_DEAD); } else { act_puts( "{WZsuzsu{x descends from the heavens, looks at the corpse, and sighs.\n", victim, NULL, NULL, TO_ALL, POS_DEAD); } snprintf(buf, sizeof(buf), "TrueLifer: %s[%d] (%s %s %s) died to %s.", victim->name, victim->level, clan_name(victim->clan), race_name(victim->race), class_name(victim), (ch!=victim) ? format_short(ch->short_descr, ch->name, NULL) : "Natural Causes"); wiznet(buf, ch, victim, WIZ_DEATHS, 0, 0); LOG(buf); snprintf(buf, sizeof(buf), "{W%s{x was {rkilled{x by %s.{x", victim->name, (ch!=victim) ? format_short(ch->short_descr, ch->name, NULL) : "Natural Causes"); do_death_announce(victim, buf); snprintf(buf, sizeof(buf), "%s %s[%d] (%s/%s/%s) XP:%d Quests:%d PK:%d MK:%s Mobs:%d died to %s[%d] - %s.", compact_date_str(current_time), victim->name, victim->level, clan_name(victim->clan), race_name(victim->race), class_name(victim), victim->exp, victim->pcdata->questcount, victim->pcdata->pk_kills, IS_SET(victim->acct_flags, ACCT_MULTIKILLER) ? "true" : "false", victim->pcdata->align_killed[0] + victim->pcdata->align_killed[1] + victim->pcdata->align_killed[2] + victim->pcdata->align_killed[3], (ch!=victim) ? format_short(ch->short_descr, ch->name, NULL) : "Natural Causes", (ch!=victim) ? ch->level : 0, (victim->desc) ? victim->desc->host : "unknown.ip"); if (!append_file(TRUELIFER_FILE, buf)) { LOG(buf); BUG("Couldn't open true lifer file: %s, death stored in logfile", TRUELIFER_FILE); } /* purge room of items if nobody there */ CHAR_DATA *prev = NULL; OBJ_DATA *obj = NULL, *obj_next = NULL; int count = 0; if (corpse && corpse->in_room) { for (prev = corpse->in_room->people; prev; prev = prev->next_in_room) { if (prev != victim && !IS_NPC(prev)) count++; } if (count == 0) { for (obj = corpse->in_room->contents; obj != NULL; obj = obj_next) { obj_next = obj->next_content; if (!IS_OBJ_STAT(obj, ITEM_NOPURGE) && obj->pIndexData->vnum != OBJ_VNUM_CORPSE_PC && obj->pIndexData->vnum != OBJ_VNUM_CORPSE_NPC && !IS_NULLSTR(obj->past_owner[0]) && !str_cmp(victim->name, obj->past_owner[0]) ) extract_obj(obj, 0); if (obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC) corpse = obj; } if (corpse) { for (obj = corpse->contains; obj; obj = obj_next) { obj_next = obj->next_content; extract_obj(obj, 0); } } } } delete_player(victim, "1 death limit for True Lifers"); return; } /* Die too much and is deleted ... :( */ if ((cl = class_lookup(victim->class)) && !CAN_FLEE(ch, cl)) { if (++victim->pcdata->death > cl->death_limit) { char msg[MAX_STRING_LENGTH]; snprintf(msg, sizeof(msg), "%d deaths limit for %s", cl->death_limit, cl->name); delete_player(victim, msg); return; } } else { if ((++victim->pcdata->death % 3) != 0) return; else if (--victim->perm_stat[STAT_CON] < 3) { delete_player(victim, "lack of CON"); return; } else char_puts("You feel your life power has decreased " "with this death.\n", victim); } } /* * Inflict damage from a hit. * dt - damage skill * rvalue = how much damage was done. */ int damage(CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, int dam_type, int dam_flags) { bool immune; int dam2; int loc; int sk = 0; bool was_asleep = FALSE; WORLD_AFFECT_DATA *waff; if (IS_DELETED(victim)) return FALSE; if (JUST_KILLED(victim)) return FALSE; if (victim != ch) { if(victim->position == POS_SLEEPING) { was_asleep = TRUE; } /* * Certain attacks are forbidden. * Most other attacks are returned. */ if (victim->position > POS_STUNNED) { if (victim->fighting == NULL) { if ((victim->in_room == ch->in_room || IS_NPC(victim)) && dt != gsn_spellbane) set_fighting(victim, ch); else { if (IS_AFFECTED(victim, AFF_SLEEP)) { REMOVE_BIT(victim->affected_by, AFF_SLEEP); affect_bit_strip(victim, TO_AFFECTS, AFF_SLEEP); } victim->position = POS_STANDING; } if (IS_NPC(victim) && HAS_TRIGGER(victim, TRIG_KILL)) mp_percent_trigger(victim, ch, NULL, NULL, TRIG_KILL); } if (victim->timer <= 4) { if ((victim->in_room == ch->in_room || IS_NPC(victim)) && dt != gsn_spellbane) victim->position = POS_FIGHTING; } else{ if (IS_AFFECTED(victim, AFF_SLEEP)) { REMOVE_BIT(victim->affected_by, AFF_SLEEP); affect_bit_strip(victim, TO_AFFECTS, AFF_SLEEP); } victim->position = POS_STANDING; } } if (victim->position > POS_STUNNED) { if (ch->fighting == NULL) { if ((victim->in_room == ch->in_room || IS_NPC(victim)) && dt != gsn_spellbane) set_fighting(ch, victim); else { if (IS_AFFECTED(victim, AFF_SLEEP)) { REMOVE_BIT(victim->affected_by, AFF_SLEEP); affect_bit_strip(victim, TO_AFFECTS, AFF_SLEEP); } victim->position = POS_STANDING; } } /* * If victim is charmed, ch might attack * victim's master. */ if (IS_NPC(ch) && IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM) && victim->master && victim->master->in_room == ch->in_room && !victim->master->fighting && number_bits(2) == 0) { stop_fighting(ch, FALSE); multi_hit(ch, victim->master, TYPE_UNDEFINED); return FALSE; } } /* * More charm and group stuff. */ if (victim->master == ch) stop_follower(victim); else if (!IS_NPC(victim) && victim->master != NULL && IS_AFFECTED(victim, AFF_CHARM)) stop_follower(victim); if (MOUNTED(victim) == ch || RIDDEN(victim) == ch) victim->riding = ch->riding = 0; } /* adjustment for strength */ if (dt >= TYPE_HIT && ch != victim) { if (is_affected(ch, gsn_giant_strength)) dam += dam * 0.10; if (is_affected(ch, gsn_dragon_strength)) dam += dam * 0.10; } /* * No one in combat can hide, be invis or camoed. */ do_visible(ch, str_empty); /* * Damage modifiers. * mortal_strike needs to go through magic protection */ if (!IS_SET(dam_flags, DAMF_NOREDUCTION)) { if (IS_AFFECTED(victim, AFF_SANCTUARY)) dam /= 2; if (dt != gsn_mortal_strike && IS_AFFECTED(victim, AFF_BLACK_SHROUD)) dam /= 2; if (dt != gsn_mortal_strike && IS_AFFECTED(victim, AFF_ENHANCED_ARMOR)) dam /= 2; if (IS_AFFECTED(victim, AFF_MINOR_SANCTUARY)) dam -= dam / 4; if (dt != gsn_mortal_strike && IS_AFFECTED(victim, AFF_MINOR_BLACK_SHROUD)) dam -= dam / 4; if (IS_AFFECTED(victim, AFF_PROTECT_EVIL) && IS_EVIL(ch)) dam -= dam / 5; if (IS_AFFECTED(victim, AFF_PROTECT_GOOD) && IS_GOOD(ch)) dam -= dam / 5; if (is_affected(victim,gsn_resistance)) dam -= dam / 4; if (is_affected(victim, gsn_intoxication)) dam -= dam / 10; } immune = FALSE; loc = IS_SET(dam_flags, DAMF_SECOND) ? WEAR_SECOND_WIELD : WEAR_WIELD; /* * Check for parry, and dodge. */ if (dt >= TYPE_HIT && ch != victim) { /* * some funny stuff */ if (IS_NPC(victim) && is_affected(victim, gsn_mirror)) { act("$n shatters into tiny fragments of glass.", victim, NULL, NULL, TO_ROOM); extract_char(victim, 0); return FALSE; } if (!was_asleep) { if (check_blink(ch, victim)) return FALSE; if (check_shield_block(ch, victim, loc)) return FALSE; if (check_parry(ch, victim, loc)) return FALSE; if (check_dodge(ch, victim)) return FALSE; if (check_tumble(ch, victim)) return FALSE; if (check_hand_block(ch, victim)) return FALSE; if (check_haft_block(ch, victim, loc)) return FALSE; /* if (check_space_between_beats(ch, victim)) return FALSE;*/ if ((sk = get_skill(ch, gsn_master_hand)) && get_eq_char(ch, WEAR_WIELD) == NULL && number_percent() < sk/5+LEVEL(ch)-LEVEL(victim)) { SET_BIT(victim->affected_by, AFF_WEAK_STUN); act_puts("You hit $N with a stunning " "force!", ch, NULL, victim, TO_CHAR, POS_DEAD); act_puts("$n hit you with a stunning " "force!", ch, NULL, victim, TO_VICT, POS_DEAD); act_puts("$n hits $N with a stunning " "force!", ch, NULL, victim, TO_NOTVICT, POS_DEAD); check_improve(ch, gsn_master_hand, TRUE, 6); } } } switch(check_immune(victim, dam_type)) { case IS_IMMUNE: immune = TRUE; dam = 0; break; case IS_RESISTANT: dam -= dam/3; break; case IS_VULNERABLE: dam += dam/3; break; } if (dam > 0 && dt >= TYPE_HIT && ch != victim) { if ((dam2 = critical_strike(ch, victim, dam)) != 0) dam = dam2; } /* * lance--negligible damage unless on horseback */ if (!IS_NPC(ch) &&!MOUNTED(ch) && get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_LANCE) { dam = 5; } /* * bows -- negligible damage in melee */ if (!IS_NPC(ch) && get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_BOW && ch->in_room == victim->in_room) dam = 5; if (IS_SET(dam_flags, DAMF_SHOW)) dam_message(ch, victim, dam, dt, immune, dam_type); if (dam == 0) return FALSE; if (dt >= TYPE_HIT && ch != victim) check_eq_damage(ch, victim, loc); /* * world affect to modify pvp damage * (but not the world for the damage) */ if (dam > 0 && (!IS_NPC(ch) || (IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM))) && !IS_NPC(victim) && (waff = ch_waffected(victim, WAFF_PVP_DAMAGE)) != NULL) { if (waff->modifier <= 0) { BUG("World Affect of PVP_DAMAGE would cause negative damage." " Setting to half damage."); waff->modifier = 50; } /* skills that are not affected by this */ if (dt != gsn_assassinate && dt != gsn_backstab && dt != gsn_dual_backstab && dt != gsn_ambush && dt != gsn_vampiric_bite) dam = dam * waff->modifier / 100; } /* * World affect to modify PC damage to NPCs */ else if (dam > 0 && !IS_NPC(ch) && IS_NPC(victim) && (waff = ch_waffected(victim, WAFF_PVM_DAMAGE)) != NULL) { if (waff->modifier <= 0) { BUG("World Affect of PVM_DAMAGE would cause negative damage." " Setting to double damage."); waff->modifier = 200; } dam = dam * waff->modifier / 100; } DEBUG(DEBUG_DAM, "%s[%d] vs %s[%d] %s for %d", mlstr_mval(ch->short_descr), LEVEL(ch), mlstr_mval(victim->short_descr), LEVEL(victim), dt >= TYPE_HIT ? "melee" : skill_name(dt), dam); /* * Hurt the victim. * Inform the victim of his new state. */ victim->hit -= dam; /* release charmed players from charm */ if (!IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM)) { act("The sting of pain breaks you from your charming daze.", victim, NULL, NULL, TO_CHAR); act("$n shakes $h headhead as clarity returns.", victim, NULL, NULL, TO_CHAR); REMOVE_BIT(victim->affected_by, AFF_CHARM); } if (IS_IMMORTAL(victim) && victim->hit < 1) victim->hit = 1; /*holy cloak stuff*/ if(dt >= TYPE_HIT && victim != ch && is_affected(victim, gsn_holy_cloak) && IS_EVIL(ch)) { act("You are burned by $n's holy cloak!", victim, NULL, ch, TO_VICT); act("$N is burned by your holy cloak!", victim, NULL, ch, TO_CHAR); act("$n is burned by $N's holy cloak!", ch, NULL, victim, TO_NOTVICT); damage(victim, ch, dam/5, gsn_holy_cloak, DAM_HOLY, DAMF_SHOW); } update_pos(victim); if(is_affected(victim, gsn_rnet_trap) && victim != ch && (dam >= victim->max_hit/10 || victim->position == POS_FIGHTING || victim->hit <= 3*victim->max_hit/4)) { affect_strip(victim, gsn_rnet_trap); char_puts("The net snaps, spilling you out to the ground!\n", victim); act("The net snaps, spilling $n out to the ground!", victim,NULL,NULL,TO_ROOM); } switch(victim->position) { case POS_MORTAL: if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break; act("$n is mortally wounded, and will die soon, if not aided.", victim, NULL, NULL, TO_ROOM); char_puts( "You are mortally wounded, and will die soon, if not aided.\n", victim); break; case POS_INCAP: if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break; act("$n is incapacitated and will slowly die, if not aided.", victim, NULL, NULL, TO_ROOM); char_puts( "You are incapacitated and will slowly die, if not aided.\n", victim); break; case POS_STUNNED: if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break; act("$n is stunned, but will probably recover.", victim, NULL, NULL, TO_ROOM); char_puts("You are stunned, but will probably recover.\n", victim); break; case POS_DEAD: break; default: if (dam_type == DAM_HUNGER || dam_type == DAM_THIRST) break; if (dam > victim->max_hit / 4) char_puts("That really did HURT!\n", victim); if (victim->hit < victim->max_hit / 4) char_puts("You sure are BLEEDING!\n", victim); break; } /* * Sleep spells and extremely wounded folks. */ if (!IS_AWAKE(victim) && victim->fighting) victim->fighting = NULL; /* * Payoff for killing things. */ if (victim->position == POS_DEAD) { handle_death(ch, victim); return dam; } if (victim == ch) return dam; /* * Take care of link dead people. */ if (!IS_NPC(victim) && victim->desc == NULL && !IS_SET(victim->comm, COMM_NOFLEE)) { if (number_range(0, victim->wait) == 0) { do_flee(victim, str_empty); return dam; } } /* * Wimp out? */ if (IS_NPC(victim) && dam > 0 && victim->wait < PULSE_VIOLENCE / 2) { flag64_t act = victim->pIndexData->act; if ((IS_SET(act, ACT_WIMPY) && number_bits(2) == 0 && victim->hit < victim->max_hit / 5) || (IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL && victim->master->in_room != victim->in_room) || (IS_AFFECTED(victim, AFF_FEAR) && !IS_SET(act, ACT_NOTRACK))) { do_flee(victim, str_empty); victim->last_fought = NULL; } } if (!IS_NPC(victim) && victim->hit > 0 && (victim->hit <= victim->wimpy || IS_AFFECTED(victim, AFF_FEAR)) && victim->wait < PULSE_VIOLENCE / 2) do_flee(victim, str_empty); tail_chain(); return dam; } static bool inline is_safe_raw(CHAR_DATA *ch, CHAR_DATA *victim) { /* CHAR_DATA *gch; char buf[ MAX_STRING_LENGTH ]; */ char groupflag; groupflag = 'n'; /* * ghosts are safe * this check must be done first to avoid * suicyco muttafuckas who recite 'leather-bound book' (#5743) * without any target specified * extracted NPCs are safe too */ if (!IS_NPC(victim)) { int clan; /* ghost cannot attack anyone */ if (ch != victim && !IS_NPC(ch) && IS_SET(ch->state_flags, STATE_GHOST)) return TRUE; /* clan defenders can attack anyone in their clan */ if (victim->in_room && (clan = victim->in_room->area->clan) && victim->clan != clan && ch->clan == clan) return FALSE; /* otherwise ghosts are safe */ if (IS_SET(victim->state_flags, STATE_GHOST)) return TRUE; } else if (victim->extracted) return TRUE; if (victim->fighting == ch || ch == victim || IS_IMMORTAL(ch)) return FALSE; /* handle ROOM_PEACE flags */ if ((victim->in_room && IS_SET(victim->in_room->room_flags, ROOM_PEACE)) || (ch->in_room && IS_SET(ch->in_room->room_flags, ROOM_PEACE))) return TRUE; /* handle ROOM_SAFE flags */ if ((victim->in_room && IS_SET(victim->in_room->room_flags, ROOM_SAFE)) || (ch->in_room && IS_SET(ch->in_room->room_flags, ROOM_SAFE))) return TRUE; /* link dead players whose adrenaline is not gushing are safe */ if (!IS_NPC(victim) && !IS_PUMPED(victim) && victim->desc == NULL) return TRUE; /* multiplay pkill reporting */ /* if ( !IS_NPC( ch ) && !IS_NPC( victim ) ) { sprintf( buf, "IS_SAFE: Check for %s grouped with", ch->name ); for ( gch = char_list; gch; gch = gch->next ) { if ( is_same_group( gch, ch ) && gch != ch ) { groupflag = 'y'; strcat( buf, " " ); strcat( buf, gch->name ); } } if ( groupflag == 'n' ) strcat( buf, " no one" ); strcat( buf, " on " ); strcat( buf, victim->name ); log( buf ); } */ if(IS_NPC(victim) && victim->invis_level > ch->level) return TRUE; return !in_PK(ch, victim); } /* * generic safe-checking function wrapper * * all the checks are done is_safe_raw to properly strip STATE_GHOST * flag if victim is not safe. add you checks there */ bool is_safe_nomessage(CHAR_DATA *ch, CHAR_DATA *victim) { bool safe; CHAR_DATA *mount; if (IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM) && ch->master && ch->in_room == ch->master->in_room) return is_safe_nomessage(ch->master, victim); if (IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM) && victim->master) return is_safe_nomessage(ch, victim->master); if ((mount = RIDDEN(victim))) return is_safe_nomessage(ch, mount); if ((safe = is_safe_raw(ch, victim)) || IS_NPC(ch)) return safe; if (victim != ch && IS_SET(ch->state_flags, STATE_GHOST)) { char_puts("You return to your normal form.\n", ch); REMOVE_BIT(ch->state_flags, STATE_GHOST); REMOVE_BIT(ch->affected_by, AFF_FLYING); REMOVE_BIT(ch->affected_by, AFF_PASS_DOOR); } return safe; } bool is_safe(CHAR_DATA *ch, CHAR_DATA *victim) { if (is_safe_nomessage(ch, victim)) { act("The gods protect $N.",ch,NULL,victim,TO_CHAR); act("The gods protect $N from $n.",ch,NULL,victim,TO_ROOM); return TRUE; } return FALSE; } bool is_safe_spell(CHAR_DATA *ch, CHAR_DATA *victim, bool area) { #if 0 if (ch == victim && !area) return TRUE; #endif if (area) { if (IS_IMMORTAL(victim) || is_same_group(ch, victim) || ch == victim || RIDDEN(ch) == victim || MOUNTED(ch) == victim) return TRUE; } return is_safe(ch, victim); } /* * Check for parry. */ bool check_parry(CHAR_DATA *ch, CHAR_DATA *victim, int loc) { int chance; if (!IS_AWAKE(victim)) return FALSE; chance = parry_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] parry %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent() >= chance) return FALSE; act("You parry $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE); act("$N parries your attack.", ch, NULL, victim, TO_CHAR | ACT_VERBOSE); check_weapon_damage(ch, victim, loc); if (number_percent() > chance) { /* size and weight */ chance += ch->carry_weight / 25; chance -= victim->carry_weight / 20; if (ch->size < victim->size) chance += (ch->size - victim->size) * 25; else chance += (ch->size - victim->size) * 10; /* stats */ chance += get_curr_stat(ch, STAT_STR)/4; chance -= get_curr_stat(victim, STAT_DEX)/3; if (IS_AFFECTED(ch, AFF_FLYING)) chance -= 10; /* speed */ if (IS_NPC(ch) && IS_SET(ch->pIndexData->off_flags, OFF_FAST)) chance += 10; if (IS_NPC(victim) && IS_SET(victim->pIndexData->off_flags, OFF_FAST)) chance -= 20; /* level */ chance += (LEVEL(ch) - LEVEL(victim)) * 2; if (!IS_NPC(victim) && !IS_NPC(ch) && chance > 0) DEBUG(DEBUG_EVADE, "%s[%d] parry-fall %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); /* now the attack */ if (number_percent() < (chance / 20 )) { act("You couldn't manage to keep your position!", ch, NULL, victim, TO_VICT); act("You fall down!", ch, NULL, victim, TO_VICT); act("$N couldn't manage to hold your attack " "and falls down!", ch, NULL, victim, TO_CHAR); act("$n stunning force makes $N fall down.", ch, NULL, victim, TO_NOTVICT); WAIT_STATE(victim, SKILL(gsn_bash)->beats); victim->position = POS_RESTING; } } check_improve(victim, gsn_parry, TRUE, 6); return TRUE; } /*********************** * Check for haft block.* * Coded by Thornan * ************************/ bool check_haft_block (CHAR_DATA * ch, CHAR_DATA * victim, int loc) { int chance; if (!IS_AWAKE (victim)) return FALSE; chance = haft_block_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] haft_block %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent () >= chance) return FALSE; act ("You use the haft of your weapon to block $n's attack.", ch, NULL, victim, TO_VICT); act ("$N uses the haft of $S weapon to block your attack.", ch, NULL, victim, TO_CHAR); check_improve (victim, gsn_haft_block, TRUE, 6); return TRUE; } /* * Check tumble: Checks to see if the victim has the tumble skill */ bool check_tumble(CHAR_DATA *ch, CHAR_DATA *victim) { int chance; if (!IS_AWAKE(victim)) return FALSE; chance = tumble_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] tumble %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent () <= chance) { act ("You spot $n's attack coming and tumble gracefully out the way.", ch, NULL, victim, TO_VICT); act ("$N spots your attack coming and rolls out of the way.", ch, NULL, victim, TO_CHAR); check_improve(victim, gsn_tumble, TRUE, 6); return TRUE; } else { check_improve(victim, gsn_tumble, FALSE, 6); return FALSE; } } /* * check blink */ bool check_blink(CHAR_DATA *ch, CHAR_DATA *victim) { int chance; if (!IS_SET(victim->conf_flags, PLR_CONF_BLINK)) return FALSE; chance = blink_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] blink %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent() >= chance || victim->mana < 10) return FALSE; victim->mana -= UMAX(victim->level / 10, 1); act("You blink out $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE); act("$N blinks out your attack.", ch, NULL, victim, TO_CHAR | ACT_VERBOSE); check_improve(victim, gsn_blink, TRUE, 6); return TRUE; } /* * Check for shield block. */ bool check_shield_block(CHAR_DATA *ch, CHAR_DATA *victim, int loc) { int chance; if (!IS_AWAKE(victim)) return FALSE; chance = shield_block_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch))/* && !IS_NPC(ch))*/ DEBUG(DEBUG_EVADE, "%s[%d] shield block %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent() < chance) { act("Your shield blocks $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE); act("$N deflects your attack with $S shield.", ch, NULL, victim, TO_CHAR | ACT_VERBOSE); check_shield_damage(ch, victim, loc); check_improve(victim, gsn_shield_block, TRUE, 6); return TRUE; } return FALSE; } /* * Check for hand block */ bool check_hand_block(CHAR_DATA *ch, CHAR_DATA *victim) { int chance; if (!IS_AWAKE(victim)) return FALSE; chance = hand_block_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] hand block %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent() < chance) { act("Your hand blocks $n's attack.", ch, NULL, victim, TO_VICT|ACT_VERBOSE); act("$N blocks your attack with $S hand.", ch, NULL, victim, TO_CHAR|ACT_VERBOSE); check_improve(victim, gsn_hand_block, TRUE, 6); return TRUE; } return FALSE; } /* * Check for dodge. */ bool check_dodge(CHAR_DATA *ch, CHAR_DATA *victim) { int chance; if (!IS_AWAKE(victim)) return FALSE; chance = dodge_chance(ch, victim); if (chance <= 0) return FALSE; if (!IS_NPC(victim) && !IS_NPC(ch)) DEBUG(DEBUG_EVADE, "%s[%d] dodge %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); if (number_percent() >= chance) return FALSE; act("You dodge $n's attack.", ch, NULL, victim, TO_VICT | ACT_VERBOSE); act("$N dodges your attack.", ch, NULL, victim, TO_CHAR | ACT_VERBOSE); check_improve(victim, gsn_dodge, TRUE, 6); return TRUE; } /* commented out -- not used due to bugs */ bool check_dodge_fail(CHAR_DATA *ch, CHAR_DATA *victim) { int chance = 0; if (number_percent() < get_skill(victim,gsn_dodge) / 20 && !(IS_AFFECTED(ch, AFF_FLYING) || ch->position < POS_FIGHTING)) { /* size */ if (victim->size < ch->size) /* bigger = harder to trip */ chance += (victim->size - ch->size) * 10; /* dex */ chance += get_curr_stat(victim, STAT_DEX); chance -= get_curr_stat(ch, STAT_DEX) * 3 / 2; if (IS_AFFECTED(victim, AFF_FLYING)) chance -= 10; /* speed */ if ((IS_NPC(victim) && IS_SET(victim->pIndexData->off_flags, OFF_FAST)) || IS_AFFECTED(victim, AFF_HASTE)) chance += 10; if ((IS_NPC(ch) && IS_SET(ch->pIndexData->off_flags, OFF_FAST)) || IS_AFFECTED(ch, AFF_HASTE)) chance -= 20; /* level */ chance += (victim->level - ch->level) * 2; chance = chance / 20; if (!IS_NPC(victim) && !IS_NPC(ch) && chance > 0) DEBUG(DEBUG_EVADE, "%s[%d] dodge-fall %d%% vs %s[%d]", victim->name, LEVEL(victim), chance, ch->name, LEVEL(ch)); /* now the attack */ if (number_percent() < chance) { act("$n lost his postion and fall down!", ch, NULL, victim, TO_VICT); act("As $N moves you lose your position fall down!", ch, NULL, victim, TO_CHAR); act("As $N dodges $N's attack, $N lost his position " "and falls down.", ch, NULL, victim, TO_NOTVICT); WAIT_STATE(ch, SKILL(gsn_trip)->beats); ch->position = POS_RESTING; } } check_improve(victim, gsn_dodge, TRUE, 6); return TRUE; } /* * Set position of a victim. */ void update_pos(CHAR_DATA *victim) { if (victim->hit > 0) { if (victim->position <= POS_STUNNED) { if (IS_AFFECTED(victim, AFF_SLEEP)) { REMOVE_BIT(victim->affected_by, AFF_SLEEP); affect_bit_strip(victim, TO_AFFECTS, AFF_SLEEP); } victim->position = POS_STANDING; } return; } if (IS_NPC(victim) && victim->hit < 1) { victim->position = POS_DEAD; return; } if (victim->hit <= -11) { victim->position = POS_DEAD; return; } if (victim->hit <= -6) victim->position = POS_MORTAL; else if (victim->hit <= -3) victim->position = POS_INCAP; else victim->position = POS_STUNNED; } /* * Start fights. */ void set_fighting(CHAR_DATA *ch, CHAR_DATA *victim) { if (ch->fighting != NULL) { bug("Set_fighting: already fighting", 0); return; } if (IS_AFFECTED(ch, AFF_SLEEP)) { REMOVE_BIT(ch->affected_by, AFF_SLEEP); affect_bit_strip(ch, TO_AFFECTS, AFF_SLEEP); } ch->fighting = victim; ch->position = POS_FIGHTING; } static void STOP_FIGHTING(CHAR_DATA *ch) { ch->fighting = NULL; ch->position = IS_NPC(ch) ? ch->default_pos : POS_STANDING; update_pos(ch); } /* * Stop fights. */ void stop_fighting(CHAR_DATA *ch, bool fBoth) { CHAR_DATA *fch; STOP_FIGHTING(ch); if (!fBoth) return; for (fch = char_list; fch; fch = fch->next) { if (fch->fighting == ch) STOP_FIGHTING(fch); } } /* * Make a corpse out of a character. */ OBJ_DATA * make_corpse(CHAR_DATA *ch) { OBJ_DATA *corpse; OBJ_DATA *obj; OBJ_DATA *obj_next; int i; if (IS_NPC(ch)) { corpse = create_obj_of(get_obj_index(OBJ_VNUM_CORPSE_NPC), ch->short_descr); corpse->timer = number_range(3, 6); if (ch->gold > 0 || ch->silver > 0) { OBJ_DATA *money = create_money(ch->gold, ch->silver); if (ch->gold > 500 || ch->silver > 50000) DEBUG(DEBUG_GOLD, "%s[%d] dropped %d gold %d silver upon death.", format_short(ch->short_descr, ch->name, NULL), ch->pIndexData->vnum, ch->gold, ch->silver); if (IS_SET(ch->form,FORM_INSTANT_DECAY)) obj_to_room(money, ch->in_room); else obj_to_obj(money, corpse); } } else { corpse = create_obj_of(get_obj_index(OBJ_VNUM_CORPSE_PC), ch->short_descr); if (IS_GOOD(ch)) i = 0; if (IS_EVIL(ch)) i = 2; else i = 1; corpse->timer= number_range(7, 10); corpse->altar = get_altar(ch); if (ch->gold > 0 || ch->silver > 0) obj_to_obj(create_money(ch->gold, ch->silver), corpse); } corpse->owner = mlstr_dup(ch->short_descr); corpse->level = ch->level; ch->gold = 0; ch->silver = 0; for (obj = ch->carrying; obj != NULL; obj = obj_next) { obj_next = obj->next_content; obj_from_char(obj); if (obj->pIndexData->item_type == ITEM_POTION) obj->timer = number_range(500,1000); if (obj->pIndexData->item_type == ITEM_SCROLL) obj->timer = number_range(1000,2500); if (IS_SET(obj->extra_flags,ITEM_ROT_DEATH)) { obj->timer = number_range(5,10); if (obj->pIndexData->item_type == ITEM_POTION) obj->timer += obj->level * 20; } REMOVE_BIT(obj->extra_flags,ITEM_VIS_DEATH); REMOVE_BIT(obj->extra_flags,ITEM_ROT_DEATH); if (IS_SET(obj->extra_flags, ITEM_INVENTORY) || (obj->pIndexData->limit != -1 && (obj->pIndexData->count > obj->pIndexData->limit))) { if (obj->pIndexData->limit > -1) DEBUG(DEBUG_LIMITED, "%s[%d] reclaim limited [%d-%d/%d] [%d] %s", ch->name, ch->level, obj->pIndexData->level, obj->pIndexData->count, obj->pIndexData->limit, obj->pIndexData->vnum, obj->pIndexData->name); extract_obj(obj, 0); continue; } else if (IS_SET(ch->form,FORM_INSTANT_DECAY)) obj_to_room(obj, ch->in_room); else obj_to_obj(obj, corpse); } obj_to_room(corpse, ch->in_room); return corpse; } /* this needs to parallel make_corpse() */ void strip_char(CHAR_DATA *ch) { OBJ_DATA *obj; OBJ_DATA *obj_next; OBJ_DATA *tattoo; OBJ_DATA *clanmark; BUG("stripping character"); tattoo = get_eq_char(ch, WEAR_TATTOO); clanmark = get_eq_char(ch, WEAR_CLANMARK); if (tattoo != NULL) obj_from_char(tattoo); if (clanmark != NULL) obj_from_char(clanmark); if (ch->gold > 0 || ch->silver > 0) { obj_to_room(create_money(ch->gold, ch->silver), ch->in_room); ch->gold = 0; ch->silver = 0; } for (obj = ch->carrying; obj != NULL; obj = obj_next) { obj_next = obj->next_content; obj_from_char(obj); if (obj->pIndexData->item_type == ITEM_POTION) obj->timer = number_range(500,1000); if (obj->pIndexData->item_type == ITEM_SCROLL) obj->timer = number_range(1000,2500); if (IS_SET(obj->extra_flags,ITEM_ROT_DEATH)) { obj->timer = number_range(5,10); if (obj->pIndexData->item_type == ITEM_POTION) obj->timer += obj->level * 20; } REMOVE_BIT(obj->extra_flags,ITEM_VIS_DEATH); REMOVE_BIT(obj->extra_flags,ITEM_ROT_DEATH); if (IS_SET(obj->extra_flags, ITEM_INVENTORY) || (obj->pIndexData->limit != -1 && (obj->pIndexData->count > obj->pIndexData->limit))) { if (obj->pIndexData->limit > -1) DEBUG(DEBUG_LIMITED, "%s[%d] reclaim limited [%d-%d/%d] [%d] %s", ch->name, ch->level, obj->pIndexData->level, obj->pIndexData->count, obj->pIndexData->limit, obj->pIndexData->vnum, obj->pIndexData->name); extract_obj(obj, 0); continue; } BUG("Object to room %s", obj->name); obj_to_room(obj, ch->in_room); } if (tattoo != NULL) { obj_to_char(tattoo, ch); equip_char(ch, tattoo, WEAR_TATTOO); } if (clanmark != NULL) { obj_to_char(clanmark, ch); equip_char(ch, clanmark, WEAR_CLANMARK); } } void death_cry(CHAR_DATA *ch) { death_cry_org(ch, -1); } /* * Improved Death_cry contributed by Diavolo. */ void death_cry_org(CHAR_DATA *ch, int part) { ROOM_INDEX_DATA *was_in_room; char *msg; int door; int vnum; vnum = 0; msg = "You hear $n's death cry."; if (part == -1) part = number_bits(4); switch (part) { case 0: msg = "$n hits the ground ... DEAD."; break; case 1: if (ch->material_descr == 0) { msg = "$n splatters blood on your armor."; break; } /* FALLTHRU */ case 2: if (IS_SET(ch->parts, PART_GUTS)) { msg = "$n spills $s guts all over the floor."; vnum = OBJ_VNUM_GUTS; } break; case 3: if (IS_SET(ch->parts, PART_HEAD)) { msg = "$n's severed head plops on the ground."; vnum = OBJ_VNUM_SEVERED_HEAD; } break; case 4: if (IS_SET(ch->parts, PART_HEART)) { msg = "$n's heart is torn from $s chest."; vnum = OBJ_VNUM_TORN_HEART; } break; case 5: if (IS_SET(ch->parts, PART_ARMS)) { msg = "$n's arm is sliced from $s dead body."; vnum = OBJ_VNUM_SLICED_ARM; } break; case 6: if (IS_SET(ch->parts, PART_LEGS)) { msg = "$n's leg is sliced from $s dead body."; vnum = OBJ_VNUM_SLICED_LEG; } break; case 7: if (IS_SET(ch->parts, PART_BRAINS)) { msg = "$n's head is shattered, and $s brains splash all over you."; vnum = OBJ_VNUM_BRAINS; } break; } act(msg, ch, NULL, NULL, TO_ROOM); if (vnum) { OBJ_DATA *obj; obj = create_obj_of(get_obj_index(vnum), ch->short_descr); obj->level = ch->level; obj->owner = mlstr_dup(ch->short_descr); obj->timer = number_range(4, 7); if (obj->pIndexData->item_type == ITEM_FOOD) { if (IS_SET(ch->form,FORM_POISON)) obj->value[ITEM_FOOD_POISON] = 1; else if (!IS_SET(ch->form,FORM_EDIBLE)) SET_BIT(obj->extra_flags, ITEM_NOT_EDIBLE); } obj_to_room(obj, ch->in_room); } if (IS_NPC(ch)) msg = "You hear something's death cry."; else msg = "You hear someone's death cry."; if ((was_in_room = ch->in_room)) { for (door = 0; door <= 5; door++) { EXIT_DATA *pexit; if ((pexit = was_in_room->exit[door]) != NULL && pexit->to_room.r != NULL && pexit->to_room.r != was_in_room) { ch->in_room = pexit->to_room.r; act(msg, ch, NULL, NULL, TO_ROOM); } } ch->in_room = was_in_room; } } /* * send defeated character back to altar w/ all affects stripped */ void raw_duel_defeat (CHAR_DATA *ch, CHAR_DATA *victim) { if (IS_NPC(ch)) remove_mind(ch, victim->name); stop_fighting(victim, TRUE); RESET_FIGHT_TIME(victim); while (victim->affected) affect_remove(victim, victim->affected); victim->affected_by = 0; victim->position = POS_RESTING; victim->hit = victim->max_hit / 10; victim->mana = victim->max_mana / 10; victim->move = victim->max_move; update_pos(victim); char_from_room(victim); char_to_room(victim, get_altar(victim)->room); WAIT_STATE(victim, PULSE_VIOLENCE * 1); } OBJ_DATA * raw_kill_org(CHAR_DATA *ch, CHAR_DATA *victim, int part, bool is_duel) { CHAR_DATA *tmp_ch, *tmp_ch_next; OBJ_DATA *obj,*obj_next; int i; OBJ_DATA *tattoo, *clanmark, *corpse; for (obj = victim->carrying;obj != NULL;obj = obj_next) { obj_next = obj->next_content; if (obj->wear_loc != WEAR_NONE && oprog_call(OPROG_DEATH, obj, victim, NULL)) { victim->position = POS_STANDING; return NULL; } } /* don't remember killed victims anymore */ if (IS_NPC(ch)) remove_mind(ch, victim->name); stop_fighting(victim, TRUE); if (!is_duel) rating_update(ch, victim); quest_handle_death(ch, victim); RESET_FIGHT_TIME(victim); victim->last_death_time = current_time; death_cry_org(victim, part); tattoo = get_eq_char(victim, WEAR_TATTOO); clanmark = get_eq_char(victim, WEAR_CLANMARK); if (tattoo != NULL) obj_from_char(tattoo); if (clanmark != NULL) obj_from_char(clanmark); corpse = make_corpse(victim); if (victim == ch || is_duel) corpse->killer = NULL; else { if (IS_NPC(ch) && ch->master != NULL && ch->in_room == ch->master->in_room) corpse->killer = mlstr_dup(ch->master->short_descr); else corpse->killer = mlstr_dup(ch->short_descr); } if (IS_NPC(victim)) { victim->pIndexData->killed++; extract_char(victim, 0); return corpse; } while (victim->affected) affect_remove(victim, victim->affected); victim->affected_by = 0; SET_BIT(victim->state_flags, STATE_GHOST); SET_BIT(victim->affected_by, AFF_FLYING); if (!is_duel && !IS_SET(victim->acct_flags, ACCT_TRUE_LIFER)) { char_puts("You turn into an invincible ghost for a few minutes.\n" "As long as you don't attack anything.\n", victim); SET_BIT(victim->affected_by, AFF_PASS_DOOR); } /*need to do something about pets first*/ if (is_duel) quest_cancel(victim); else disband_pets(victim); extract_char(victim, XC_F_INCOMPLETE); for (i = 0; i < 4; i++) victim->armor[i] = 100; victim->position = POS_RESTING; victim->hit = victim->max_hit / 10; victim->mana = victim->max_mana / 10; victim->move = victim->max_move; update_pos(victim); /* RT added to prevent infinite deaths */ REMOVE_BIT(victim->state_flags, STATE_BOUGHT_PET); victim->pcdata->condition[COND_THIRST] = 40; victim->pcdata->condition[COND_HUNGER] = 40; victim->pcdata->condition[COND_FULL] = 40; victim->pcdata->condition[COND_BLOODLUST] = 40; victim->pcdata->condition[COND_DESIRE] = 40; WAIT_STATE(victim, FIGHT_DELAY_TIME); if (tattoo != NULL) { obj_to_char(tattoo, victim); equip_char(victim, tattoo, WEAR_TATTOO); } if (clanmark != NULL) { obj_to_char(clanmark, victim); equip_char(victim, clanmark, WEAR_CLANMARK); } if (victim->level > 1) save_char_obj(victim, FALSE); /* * Calm down the tracking mobiles */ for (tmp_ch = npc_list; tmp_ch; tmp_ch = tmp_ch_next) { tmp_ch_next = tmp_ch->next; if (tmp_ch->last_fought == victim) tmp_ch->last_fought = NULL; remove_mind(tmp_ch, victim->name); if (tmp_ch->target == victim && tmp_ch->pIndexData->vnum == MOB_VNUM_STALKER) { doprintf(do_clan, tmp_ch, "%s is dead and I can leave the realm.", PERS(victim, tmp_ch)); extract_char(tmp_ch, 0); } } if (!IS_NPC(victim)) victim->pcdata->saved_stalkers = 0; return corpse; } void group_gain(CHAR_DATA *ch, CHAR_DATA *victim) { CHAR_DATA *lch; CHAR_DATA *gch; int xp; int members; int group_levels; int morale = 0; OBJ_DATA *obj = NULL; /* no exp for PKs or suicide */ if (!IS_NPC(victim) || victim == ch) return; /* no exp for killing summoned or bought pets */ if (IS_SET(victim->pIndexData->act, ACT_PET) || victim->pIndexData->vnum < 100 || victim->master || victim->leader) return; lch = ch->leader ? ch->leader : ch; members = 0; group_levels = 0; morale = 0; for (gch = ch->in_room->people; gch; gch = gch->next_in_room) { if (is_same_group(gch, ch)) { if (IS_NPC(gch)) { /* don't count WARLOCK | WITCH charmies */ if (gch->master && IS_SET(gch->pIndexData->act, ACT_SUMMONED) && !IS_SET(gch->pIndexData->act, ACT_PET) && is_same_group(gch->master, ch)) continue; if (gch->master && !IS_SET(gch->pIndexData->act, ACT_PET) && !IS_SET(gch->pIndexData->act, ACT_SUMMONED) && (gch->master->class == CLASS_WARLOCK || gch->master->class == CLASS_WITCH) && is_same_group(gch->master, ch)) continue; } else { if (ABS(gch->level - lch->level) <= 8) members++; } group_levels += gch->level; } } for (gch = ch->in_room->people; gch; gch = gch->next_in_room) { if (!is_same_group(gch, ch) || IS_NPC(gch)) continue; if (gch->level - lch->level > 8) { char_puts("You are too high for this group.\n", gch); continue; } if (gch->level - lch->level < -8) { char_puts("You are too low for this group.\n", gch); continue; } morale = (get_curr_stat(lch, STAT_CHA) + get_curr_stat(gch, STAT_CHA)) / 2; if (gch == lch && members > 1) morale+= 5; xp = xp_compute(gch, victim, group_levels, members, morale); if (gch->level < LEVEL_HERO) { if(IS_SET(ch->state_flags, STATE_NOEXP)) { char_puts("The gods forbid you to" " to gain experience!\n", ch); xp = 0; } else if (is_affected(gch, gsn_dishonor)) { char_puts("One without honor cannot" " advance in the way of the" " samurai.\n", ch); continue; } else { char_printf(gch, "You receive %d" " experience points.\n", xp); gain_exp(gch, xp); } } /* augmentation exp for the weapon or focus item */ else if ((!IS_IMMORTAL(ch) || IS_TRUSTED_IMP(ch)) && (obj = get_augment_obj(ch)) != NULL) { if(IS_SET(ch->state_flags, STATE_NOEXP)) { char_puts("The gods forbid you to" " to gain experience!\n", ch); xp = 0; } else if (is_affected(gch, gsn_dishonor)) { char_puts("One without honor cannot" " advance one's weapon.\n", ch); continue; } else { char_printf(ch, "%s gains %d experience points.\n", mlstr_mval(obj->short_descr), xp); gain_obj_exp(ch, obj, xp); } } if (IS_NEWBIE(gch) && gch->level == MAX_NEWBIE_LEVEL) { char_puts("Sorry, you have reached the maximum level for a newbie.\n" "If you feel you have learned enough about our realm please\n" "Delete this character and create an non-newbie character to\n" "experience everything this realm has to offer.\n", ch); } } } /* * Compute xp for a kill. * Also adjust alignment of killer. * Edit this function to change xp computations. */ int xp_compute(CHAR_DATA *gch, CHAR_DATA *victim, int total_levels, int members, int morale) { int xp; int base_exp; int level_range = victim->level - gch->level; WORLD_AFFECT_DATA *waff = NULL; int bonus_align = 0, bonus_morale = 0, bonus_waff = 0, bonus_group = 0, bonus_act = 0, group_split = 0, raw_exp = 0, i, killed_sum = 0; /* base exp */ switch (level_range) { case -9: base_exp = 1; break; case -8: base_exp = 10; break; case -7: base_exp = 20; break; case -6: base_exp = 30; break; case -5: base_exp = 40; break; case -4: base_exp = 50; break; case -3: base_exp = 60; break; case -2: base_exp = 75; break; case -1: base_exp = 87; break; case 0: base_exp = 100; break; case 1: base_exp = 115; break; case 2: base_exp = 130; break; case 3: base_exp = 140; break; case 4: base_exp = 150; break; default: /* the cap is for occations where for some * reason a hard mob is made easy */ if (level_range > 10) base_exp = 180 + 10 * (level_range - 4); else if (level_range > 4) base_exp = 150 + 20 * (level_range - 4); else base_exp = 0; if (level_range > 15 * (gch->level /30+1)) BUG("%s[%d]+%d defeated %s[%d] for %d exp!", gch->name, gch->level, members, victim->name, victim->level, base_exp); } bonus_act = 0; if (IS_NPC(victim) && level_range >= 1) { if (IS_SET(victim->pIndexData->affected_by, AFF_SANCTUARY) || IS_SET(victim->pIndexData->affected_by, AFF_BLACK_SHROUD)) bonus_act += 30; else if (IS_SET(victim->pIndexData->affected_by, AFF_MINOR_SANCTUARY) || IS_SET(victim->pIndexData->affected_by, AFF_MINOR_BLACK_SHROUD)) bonus_act += 15; if (IS_SET(victim->pIndexData->act, ACT_WARRIOR)) bonus_act += 15; if (victim->pIndexData->spec_fun == spec_cast_mage || victim->pIndexData->spec_fun == spec_cast_cleric) bonus_act += 20; else if (victim->pIndexData->spec_fun == spec_breath_any || victim->pIndexData->spec_fun == spec_breath_acid || victim->pIndexData->spec_fun == spec_breath_fire || victim->pIndexData->spec_fun == spec_breath_frost || victim->pIndexData->spec_fun == spec_breath_lightning || victim->pIndexData->spec_fun == spec_breath_gas) bonus_act += 35; } /* calculate exp multiplier */ if (IS_NPC(victim) && IS_SET(victim->pIndexData->act, ACT_NOALIGN)) xp = base_exp; else if ((IS_EVIL(gch) && IS_GOOD(victim)) || (IS_EVIL(victim) && IS_GOOD(gch))) xp = base_exp * 8/5; else if (IS_GOOD(gch) && IS_GOOD(victim)) xp = 0; else if (!IS_NEUTRAL(gch) && IS_NEUTRAL(victim)) xp = base_exp * 1.0; else if (IS_NEUTRAL(gch) && !IS_NEUTRAL(victim)) xp = base_exp * 1.3; else xp = base_exp; bonus_align = xp - base_exp; xp += bonus_act; /* morale */ if (morale < 50) xp += bonus_morale = xp * (morale - 50) * 3 / 100; else xp += bonus_morale = xp * (morale - 50) * 2 / 100; /* adjust for grouping */ xp = xp * gch->level/total_levels; group_split = xp; if (members == 2 || members == 3 || members == 4) { xp *= members; } bonus_group = xp - group_split; /* * WAFF_EXP - modifies experience gain */ bonus_waff = xp; if ((waff = ch_waffected(gch, WAFF_EXP)) != NULL) { if (number_percent() <= waff->chance) xp = xp * waff->modifier / 100; } bonus_waff = xp - bonus_waff; raw_exp = xp; /* randomize the rewards */ xp = number_range(xp * 3/4, xp * 5/4); #if 0 xp += (xp * (gch->max_hit - gch->hit)) / (gch->max_hit * 5); #endif DEBUG(DEBUG_EXP, "%s[%d]+%d(%d) killed %s[%d] for %dexp" " (raw %d - base %d align %d act %d morale %d split %d" " group %d waff %d)", gch->name, gch->level, members -1, total_levels, victim->name, victim->level, xp, raw_exp, base_exp, bonus_align, bonus_act, bonus_morale, group_split, bonus_group, bonus_waff); /* * Record of kills by Alignment */ if (IS_GOOD(victim)) gch->pcdata->align_killed[ALIGN_INDEX_GOOD]++; else if (IS_EVIL(victim)) gch->pcdata->align_killed[ALIGN_INDEX_EVIL]++; else if (IS_NEUTRAL(victim)) gch->pcdata->align_killed[ALIGN_INDEX_NEUTRAL]++; else gch->pcdata->align_killed[ALIGN_INDEX_NONE]++; for (i=0; i< ALIGN_INDEX_MAX; i++) killed_sum += gch->pcdata->align_killed[i]; if ((killed_sum % 100) == 0) char_printf(gch, "You have taken %d angelic, %d balanced and %d demonic souls up to now.\n", gch->pcdata->align_killed[ALIGN_INDEX_GOOD], gch->pcdata->align_killed[ALIGN_INDEX_NEUTRAL], gch->pcdata->align_killed[ALIGN_INDEX_EVIL]); if (IS_GOOD(gch) && IS_EVIL(victim) && gch->pcdata->align_killed[ALIGN_INDEX_EVIL] == 1000 && gch->perm_stat[STAT_CHA] < get_max_train(gch, STAT_CHA)) { char_puts("Word has spread of your good deeds.\n" "Your charisma has increased by {Yone{x!\n",gch); gch->perm_stat[STAT_CHA] += 1; } else if (IS_GOOD(gch) && IS_GOOD(victim) && gch->pcdata->align_killed[ALIGN_INDEX_GOOD] == 25 && gch->perm_stat[STAT_CHA] > 3) { char_puts("Word has spread of your evil deeds.\n" "Your charisma has decreased by {rone{x!\n",gch); gch->perm_stat[STAT_CHA] -= 1; } return xp; } void dam_message(CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, bool immune, int dam_type) { const char *vs; const char *vp; const char *msg_char; const char *msg_vict = NULL; const char *msg_notvict; const char *attack = str_empty; if (dam == 0) { vs = "miss"; vp = "misses"; } else if (dam <= 4) { vs = "{cscratch{x"; vp = "{cscratches{x"; } else if (dam <= 8) { vs = "{cgraze{x"; vp = "{cgrazes{x"; } else if (dam <= 12) { vs = "{chit{x"; vp = "{chits{x"; } else if (dam <= 16) { vs = "{cinjure{x"; vp = "{cinjures{x"; } else if (dam <= 20) { vs = "{cwound{x"; vp = "{cwounds{x"; } else if (dam <= 24) { vs = "{cmaul{x"; vp = "{cmauls{x"; } else if (dam <= 28) { vs = "{cdecimate{x"; vp = "{cdecimates{x"; } else if (dam <= 32) { vs = "{cdevastate{x"; vp = "{cdevastates{x"; } else if (dam <= 36) { vs = "{cmaim{x"; vp = "{cmaims{x"; } else if (dam <= 42) { vs = "{MMUTILATE{x"; vp = "{MMUTILATES{x"; } else if (dam <= 52) { vs = "{MDISEMBOWEL{x"; vp = "{MDISEMBOWELS{x"; } else if (dam <= 65) { vs = "{MDISMEMBER{x"; vp = "{MDISMEMBERS{x"; } else if (dam <= 80) { vs = "{MMASSACRE{x"; vp = "{MMASSACRES{x"; } else if (dam <= 100) { vs = "{MMANGLE{x"; vp = "{MMANGLES{x"; } else if (dam <= 130) { vs = "{y** DEMOLISH **{x"; vp = "{y** DEMOLISHES **{x"; } else if (dam <= 175) { vs = "{y*** DEVASTATE ***{x"; vp = "{y*** DEVASTATES ***{x"; } else if (dam <= 250) { vs = "{y== OBLITERATE =={x"; vp = "{y== OBLITERATES =={x"; } else if (dam <= 325) { vs = "{y=== ATOMIZE ==={x"; vp = "{y=== ATOMIZES ==={x"; } else if (dam <= 400) { vs = "{R>> ANNIHILATE <<{x"; vp = "{R>> ANNIHILATES <<{x"; } else if (dam <= 500) { vs = "{R>>> ERADICATE <<<{x"; vp = "{R>>> ERADICATES <<<{x"; } else if (dam <= 650) { vs = "{R-=> ELECTRONIZE <=-{x"; vp = "{R-=> ELECTRONIZES <=-{x"; } else if (dam <= 800) { vs = "{R-==> SKELETONIZE <==-{x"; vp = "{R-==> SKELETONIZES <==-{x"; } else if (dam <= 1000) { vs = "{R## NUKE ##{x"; vp = "{R## NUKES ##{x"; } else if (dam <= 1250) { vs = "{R### TERMINATE ###{x"; vp = "{R### TERMINATES ###{x"; } else if (dam <= 1500) { vs = "{R[*] TEAR UP [*]{x"; vp = "{R[*] TEARS UP [*]{x"; } else { vs = "{*{R[*] POWER HIT [*]{x"; vp = "{*{R[*] POWER HITS [*]{x"; } if (dt == TYPE_HIT || dt == TYPE_HUNGER) { if (ch == victim) { switch (dam_type) { case DAM_HUNGER: msg_notvict = "$n's hunger $u $mself!"; msg_char = "Your hunger $u yourself!"; break; case DAM_THIRST: msg_notvict = "$n's thirst $u $mself!"; msg_char = "Your thirst $u yourself!"; break; case DAM_LIGHT_V: msg_notvict = "The light of the room $u $n!"; msg_char = "The light of the room $u you!"; break; case DAM_RANGER_TRAP: msg_notvict = "The hidden spear $u $n!"; msg_char = "The hidden spear $u you!"; break; case DAM_TRAP_ROOM: msg_notvict = "The trap at room $u $n!"; msg_char = "The trap at room $u you!"; break; default: msg_notvict = "$n $u $mself!"; msg_char = "You $u yourself!"; break; } } else { msg_notvict = "$n $u $N."; msg_char = "You $u $N."; msg_vict = "$n $u you."; } } else { skill_t *sk; /* XXX */ #define MAX_DAMAGE_MESSAGE 40 if ((sk = skill_lookup(dt))) attack = sk->noun_damage; else if (dt >= TYPE_HIT && dt <= TYPE_HIT + MAX_DAMAGE_MESSAGE) attack = attack_table[dt - TYPE_HIT].noun; else { bug("Dam_message: bad dt %d.", dt); dt = TYPE_HIT; attack = attack_table[0].name; } if (immune) { if (ch == victim) { msg_notvict = "$n is unaffected by $s own $U."; msg_char = "Luckily, you are immune to that."; } else { msg_notvict = "$N is unaffected by $n's $U!"; msg_char = "$N is unaffected by your $U!"; msg_vict = "$n's $U is powerless against you."; } } else { vs = vp; if (ch == victim) { msg_notvict = "$n's $U $u $m."; msg_char = "Your $U $u you."; } else { msg_notvict = "$n's $U $u $N."; msg_char = "Your $U $u $N."; msg_vict = "$n's $U $u you."; } } } if (ch == victim) { act_puts3(msg_notvict, ch, vp, NULL, attack, TO_ROOM | ACT_TRANS, POS_RESTING); act_puts3(msg_char, ch, vs, NULL, attack, TO_CHAR | ACT_TRANS, POS_RESTING); } else { act_puts3(msg_notvict, ch, vp, victim, attack, TO_NOTVICT | ACT_TRANS, POS_RESTING); act_puts3(msg_char, ch, vs, victim, attack, TO_CHAR | ACT_TRANS, POS_RESTING); act_puts3(msg_vict, ch, vp, victim, attack, TO_VICT | ACT_TRANS, POS_RESTING); } } void do_kill(CHAR_DATA *ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int chance; one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { char_puts("Kill whom?\n", ch); return; } WAIT_STATE(ch, 1 * PULSE_VIOLENCE); if ((victim = get_char_room(ch, arg)) == NULL) { char_puts("They aren't here.\n", ch); return; } if (ch->position == POS_FIGHTING) { if (victim == ch->fighting) char_puts("You do the best you can!\n", ch); else if (victim->fighting != ch) char_puts("One battle at a time, please.\n",ch); else { char_puts("First dispatch the foe infront of you.\n",ch); } return; } if (!IS_NPC(victim)) { char_puts("You must MURDER a player.\n", ch); return; } if (victim == ch) { char_puts("You hit yourself. Ouch!\n", ch); multi_hit(ch, ch, TYPE_UNDEFINED); return; } if (IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim) { act("$N is your beloved master.", ch, NULL, victim, TO_CHAR); return; } if (is_safe(ch, victim)) return; if ((chance = get_skill(ch, gsn_mortal_strike)) && (get_eq_char(ch, WEAR_WIELD) || HAS_SKILL(ch, gsn_master_hand)) && ch->level > (victim->level - 5)) { chance /= 30; chance += 1 + (ch->level - victim->level) / 2; if (number_percent() < chance) { act_puts("Your flash strike instantly slays $N!", ch, NULL, victim, TO_CHAR, POS_RESTING); act_puts("$n flash strike instantly slays $N!", ch, NULL, victim, TO_NOTVICT, POS_RESTING); act_puts("$n flash strike instantly slays you!", ch, NULL, victim, TO_VICT, POS_DEAD); damage(ch, victim, (victim->hit + 1), gsn_mortal_strike, DAM_NONE, DAMF_SHOW); check_improve(ch, gsn_mortal_strike, TRUE, 1); return; } else check_improve(ch, gsn_mortal_strike, FALSE, 3); } multi_hit(ch, victim, TYPE_UNDEFINED); } void do_murde(CHAR_DATA *ch, const char *argument) { char_puts("If you want to MURDER, spell it out.\n", ch); return; } void do_murder(CHAR_DATA *ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int chance; one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { char_puts("Murder whom?\n", ch); return; } if (IS_AFFECTED(ch, AFF_CHARM) || (IS_NPC(ch) && (IS_SET(ch->pIndexData->act, ACT_PET) && !is_affected(ch, gsn_rebel)))) return; if ((victim = get_char_room(ch, arg)) == NULL) { WAIT_STATE(ch, MISSING_TARGET_DELAY); char_puts("They aren't here.\n", ch); return; } if (victim == ch) { char_puts("Suicide is a mortal sin.\n", ch); return; } if (IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim) { act("$N is your beloved master.", ch, NULL, victim, TO_CHAR); return; } if (ch->position == POS_FIGHTING) { char_puts("You do the best you can!\n", ch); return; } if (is_safe(ch, victim)) return; WAIT_STATE(ch, 1 * PULSE_VIOLENCE); if ((chance = get_skill(ch, gsn_mortal_strike)) && get_eq_char(ch, WEAR_WIELD) && LEVEL(ch) > (LEVEL(victim) - 5)) { chance /= 30; chance += 1 + (LEVEL(ch) - LEVEL(victim)) / 2; DEBUG(DEBUG_SKILL_MORTAL_STRIKE, "mortal_strike: %s[%d] vs %s[%d] %d%%", ch->name, LEVEL(ch), victim->name, LEVEL(victim), chance); if (number_percent() < chance) { act_puts("Your flash strike mortally wounds $N!", ch, NULL, victim, TO_CHAR, POS_RESTING); act_puts("$n flash strike mortally wounds $N!", ch, NULL, victim, TO_NOTVICT, POS_RESTING); act_puts("$n flash strike mortally wounds you!", ch, NULL, victim, TO_VICT, POS_DEAD); damage(ch, victim, (victim->hit/2), gsn_mortal_strike, DAM_NONE, DAMF_SHOW); check_improve(ch, gsn_mortal_strike, TRUE, 1); return; } else check_improve(ch, gsn_mortal_strike, FALSE, 3); } multi_hit(ch, victim, TYPE_UNDEFINED); } void do_flee(CHAR_DATA *ch, const char *argument) { ROOM_INDEX_DATA *was_in; ROOM_INDEX_DATA *now_in; CHAR_DATA *victim; int attempt; class_t *cl; if (RIDDEN(ch)) { char_puts("You should ask to your rider!\n", ch); return; } if (MOUNTED(ch)) do_dismount(ch, str_empty); if ((victim = ch->fighting) == NULL) { if (ch->position == POS_FIGHTING) ch->position = POS_STANDING; char_puts("You aren't fighting anyone.\n", ch); return; } if ((cl = class_lookup(ch->class)) && !CAN_FLEE(ch, cl)) { char_puts("Your honour doesn't let you flee, " "try dishonoring yourself.\n", ch); return; } WAIT_STATE(ch, PULSE_VIOLENCE/2); was_in = ch->in_room; for (attempt = 0; attempt < 6; attempt++) { EXIT_DATA *pexit; int door; door = number_door(); if ((pexit = was_in->exit[door]) == 0 || pexit->to_room.r == NULL || (IS_SET(pexit->exit_info, EX_CLOSED) && (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_NOPASS)) && !IS_TRUSTED(ch,ANGEL)) || (IS_SET(pexit->exit_info , EX_NOFLEE)) || (IS_NPC(ch) && IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB))) continue; move_char(ch, door, FALSE); if ((now_in = ch->in_room) == was_in) continue; ch->in_room = was_in; act("$n has fled!", ch, NULL, NULL, TO_ROOM); ch->in_room = now_in; if (!IS_NPC(ch)) { act_puts("You fled from combat!", ch, NULL, NULL, TO_CHAR, POS_DEAD); if (ch->level < LEVEL_HERO) { char_printf(ch, "You lose %d exps.\n", 10); gain_exp(ch, -10); } } else ch->last_fought = NULL; stop_fighting(ch, TRUE); return; } char_puts("PANIC! You couldn't escape!\n", ch); return; } void do_sla(CHAR_DATA *ch, const char *argument) { char_puts("If you want to SLAY, spell it out.\n", ch); return; } /*:======================================================================: *| John Strange Triad Mud | *| gambit@wvinter.net triad.telmaron.com 7777 | *:======================================================================: */ void do_slay (CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; argument = one_argument(argument, arg, sizeof(arg)); one_argument(argument, arg2, sizeof(arg2)); if ( arg[0] == '\0' ) { send_to_char( "Syntax: [Char] [Type]\n", ch ); send_to_char( "Types: Skin, Slit, Immolate," " Demon, Shatter, Slit, Deheart, Pounce.\n", ch); return; } if (( victim = get_char_room(ch, arg)) == NULL) { send_to_char( "They aren't here.\n\r", ch); return; } if (ch == victim) { send_to_char( "Suicide is a mortal sin.\n\r", ch ); return; } if (IS_IMMORTAL(victim)) { char_puts("You failed.\n", ch); return; } if (!str_prefix(arg2, "skin")) { act( "You rip the flesh from $N and send $S soul to the" " fiery depths of hell.", ch, NULL, victim, TO_CHAR ); act( "Your flesh has been torn from your bones and your" " bodyless soul now watches your bones incenerate" " in the fires of hell.", ch, NULL, victim, TO_VICT ); act( "$n rips the flesh off of $N, releasing $S soul into" " the fiery depths of hell.", ch, NULL, victim, TO_NOTVICT ); } else if (!str_prefix(arg2, "deheart")) { act( "You rip through $N's chest and pull out $S beating" " heart in your hand.", ch, NULL, victim, TO_CHAR ); act( "You feel a sharp pain as $n rips into your chest" " and pulls our your beating heart in $s hand.", ch, NULL, victim, TO_VICT ); act( "Specks of blood hit your face as $n rips through" " $N's chest pulling out $S's beating heart.", ch, NULL, victim, TO_NOTVICT ); } else if (!str_prefix(arg2, "immolate")) { act( "Your fireball turns $N into a blazing inferno.", ch, NULL, victim, TO_CHAR); act( "$n releases a searing fireball in your direction.", ch, NULL, victim, TO_VICT); act( "$n points at $N, who bursts into a flaming inferno.", ch, NULL, victim, TO_NOTVICT); } else if (!str_prefix(arg2, "shatter")) { act( "You freeze $N with a glance and shatter $S" " frozen corpse into tiny shards.", ch, NULL, victim, TO_CHAR ); act( "$n freezes you with a glance and shatters" " your frozen body into tiny shards.", ch, NULL, victim, TO_VICT ); act( "$n freezes $N with a glance and shatters" " $S frozen body into tiny shards.", ch, NULL, victim, TO_NOTVICT ); } else if (!str_prefix(arg2, "demon")) { act( "You gesture, and a slavering demon appears." " With a horrible grin, the foul creature" " turns on $N, who screams in panic before" " being eaten alive.", ch, NULL, victim, TO_CHAR ); act( "$n gestures, and a slavering demon appears." " The foul creature turns on you with a" " horrible grin. You scream in panic before" " being eaten alive.", ch, NULL, victim, TO_VICT ); act( "$n gestures, and a slavering demon appears." " With a horrible grin, the foul creature" " turns on $N, who screams in panic before" " being eaten alive.", ch, NULL, victim, TO_NOTVICT ); } else if (!str_prefix( arg2, "pounce")) { act( "Leaping upon $N with bared fangs, you tear open" " $S throat and toss the corpse to the ground...", ch, NULL, victim, TO_CHAR ); act( "In a heartbeat, $n rips $s fangs through your throat!" " Your blood sprays and pours to the ground as" " your life ends...", ch, NULL, victim, TO_VICT ); act( "Leaping suddenly, $n sinks $s fangs into $N's throat." " As blood sprays and gushes to the ground, $n" " tosses $N's dying body over $s shoulder.", ch, NULL, victim, TO_NOTVICT ); } else if (!str_prefix(arg2, "slit")) { act( "You calmly slit $N's throat.", ch, NULL, victim, TO_CHAR ); act( "$n reaches out with a clawed finger and" " calmly slits your throat.", ch, NULL, victim, TO_VICT ); act( "A claw extends from $n's hand as $e" " calmly slits $N's throat.", ch, NULL, victim, TO_NOTVICT ); } else { act("You slay $M in cold blood!", ch, NULL, victim, TO_CHAR); act("$n slays you in cold blood!", ch, NULL, victim, TO_VICT); act("$n slays $N in cold blood!", ch, NULL, victim, TO_NOTVICT); } wiznet_death(ch, victim, DEATH_SLAY); raw_kill(ch, victim, TRUE); } /* * Check for obj dodge. */ bool check_obj_dodge(CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj, int bonus) { int chance; if (!IS_AWAKE(victim) || MOUNTED(victim)) return FALSE; /* if (!IS_NPC(victim)) { if (victim->pcdata->clan_status) { act("You catch $p that had been shot to you.", ch, obj, victim, TO_VICT); act("$N catches $p that had been shot to $M.", ch, obj, victim, TO_CHAR); act("$n catches $p that had been shot to $m.", victim, obj, ch, TO_NOTVICT); obj_to_char(obj, victim); } return TRUE; } */ if (IS_NPC(victim)) chance = UMIN(30, victim->level); else { chance = get_skill(victim, gsn_dodge) / 2; /* chance for high dex. */ chance += 2 * (get_curr_stat(victim, STAT_DEX) - 20); } chance -= (bonus - 90); chance /= 2; if (number_percent() >= chance) return FALSE; if(obj->value[ITEM_WEAPON_TYPE] == WEAPON_DAGGER) { act("You dodge $p that had been thrown at you.", ch, obj, victim, TO_VICT); act("$N dodges $p that had been thrown at $M.", ch, obj, victim, TO_CHAR); act("$n dodges $p that had been thrown at $m.", victim, obj, ch, TO_NOTVICT); } else { act("You dodge $p that had been shot to you.", ch, obj, victim, TO_VICT); act("$N dodges $p that had been shot to $M.", ch, obj, victim, TO_CHAR); act("$n dodges $p that had been shot to $m.", victim, obj, ch, TO_NOTVICT); } obj_to_room(obj, victim->in_room); check_improve(victim, gsn_dodge, TRUE, 6); return TRUE; } void do_dishonor(CHAR_DATA *ch, const char *argument) { ROOM_INDEX_DATA *was_in; ROOM_INDEX_DATA *now_in; CHAR_DATA *gch; int attempt, level = 0, chlevel = 0; int sn_dishonor; int chance; bool dishonored = FALSE; AFFECT_DATA af; if (RIDDEN(ch)) { char_puts("You should ask to your rider!\n", ch); return; } if ((sn_dishonor = sn_lookup("dishonor")) < 0 || !HAS_SKILL(ch, sn_dishonor)) { char_puts("Which honor?\n", ch); return; } if (ch->fighting == NULL) { if (ch->position == POS_FIGHTING) ch->position = POS_STANDING; char_puts("You aren't fighting anyone.\n", ch); return; } for (gch = char_list; gch; gch = gch->next) { if ((is_same_group(gch, ch->fighting) && gch->in_room == ch->fighting->in_room) || gch->fighting == ch) level += IS_NPC(gch) ? gch->level * 2/3 : gch->level; if (is_same_group(gch, ch) && gch->in_room == ch->in_room) chlevel += IS_NPC(gch) ? gch->level * 3/4 : gch->level; } if ((ch->fighting->level - ch->level) < 5 + (ch->level / 20) && chlevel+2 > level) { dishonored = TRUE; } WAIT_STATE(ch, SKILL(gsn_dishonor)->beats); was_in = ch->in_room; chance = get_skill(ch, sn_dishonor); for (attempt = 0; attempt < 6; attempt++) { EXIT_DATA *pexit; int door; if (number_percent() >= chance) continue; door = number_door(); if ((pexit = was_in->exit[door]) == 0 || pexit->to_room.r == NULL || (IS_SET(pexit->exit_info, EX_CLOSED) && (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_NOPASS)) && !IS_TRUSTED(ch,ANGEL)) || IS_SET(pexit->exit_info, EX_NOFLEE) || (IS_NPC(ch) && IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB))) continue; move_char(ch, door, FALSE); if ((now_in = ch->in_room) == was_in) continue; ch->in_room = was_in; act("$n has dishonored $mself!", ch, NULL, NULL, TO_ROOM); ch->in_room = now_in; if (!IS_NPC(ch)) { if (dishonored) { char_puts("You have dishonored yourself" " by fleeing like a coward. " " You are no samurai!\n", ch); if (!is_affected(ch, gsn_dishonor)) { af.where = TO_AFFECTS; af.type = gsn_dishonor; af.level = ch->level; af.duration = -1; af.bitvector = 0; af.location = APPLY_LEVEL; af.modifier = -2; affect_to_char(ch, &af); af.location = APPLY_CHA; af.modifier = -3; affect_to_char(ch, &af); if (ch->level < LEVEL_HERO) { char_printf(ch, "You lose %d exps.\n", (ch->level /50 + 1) * 1000); gain_exp(ch, (ch->level /50+1) * -1000); } if ((!IS_NPC(ch->fighting) && number_percent() > 50) || (IS_NPC(ch->fighting) && number_percent() > 90)) { char_printf(ch, "You suffer a {rserious{x loss of face.\n"); ch->perm_stat[STAT_CHA]--; } } else { char_puts("Maybe you should" " reconsider your dedication" " to the bushido!\n",ch); } DEBUG(DEBUG_HONOR, "%s[%d](%d) dishonoring " "against level [%d](%d): dishonor", ch->name, ch->level, chlevel, ch->fighting->level, level); } else { char_puts("You tactically retreat from" " unsurmountable odds.\n", ch); if (ch->level < LEVEL_HERO) { char_printf(ch, "You lose %d exps.\n", ch->level); gain_exp(ch, -(ch->level)); } DEBUG(DEBUG_HONOR, "%s[%d](%d) dishonoring " "against level [%d](%d): retreat", ch->name, ch->level, chlevel, ch->fighting->level, level); } } else ch->last_fought = NULL; stop_fighting(ch, TRUE); if (MOUNTED(ch)) do_dismount(ch,str_empty); check_improve(ch, sn_dishonor, TRUE, 1); return; } DEBUG(DEBUG_HONOR, "%s[%d](%d) dishonoring " "against level [%d](%d): failed", ch->name, ch->level, chlevel, ch->fighting->level, level); char_puts("PANIC! You couldn't escape!\n", ch); check_improve(ch, sn_dishonor, FALSE, 1); } void do_surrender(CHAR_DATA *ch, const char *argument) { CHAR_DATA *mob; if (!IS_NPC(ch)) { char_puts("Huh?\n", ch); return; } if ((mob = ch->fighting) == NULL) { char_puts("But you're not fighting!\n", ch); return; } act("You surrender to $N!", ch, NULL, mob, TO_CHAR); act("$n surrenders to you!", ch, NULL, mob, TO_VICT); act("$n tries to surrender to $N!", ch, NULL, mob, TO_NOTVICT); stop_fighting(ch, TRUE); if (!IS_NPC(ch) && IS_NPC(mob) && (!HAS_TRIGGER(mob, TRIG_SURR) || !mp_percent_trigger(mob, ch, NULL, NULL, TRIG_SURR))) { act("$N seems to ignore your cowardly act!", ch, NULL, mob, TO_CHAR); multi_hit(mob, ch, TYPE_UNDEFINED); } } /* * handle_witch_curse - if the witch has died, the curse ends * by Zsuzsu */ void handle_witch_curse (CHAR_DATA *ch, CHAR_DATA *victim) { AFFECT_DATA *pAf = NULL; DESCRIPTOR_DATA *d; if (victim->cursed_by_witch) { act("You sense $N has succumb to {Ddeath{x.", victim->cursed_by_witch, NULL, victim, TO_CHAR); victim->cursed_by_witch = NULL; } for (d = descriptor_list; d; d = d->next) { CHAR_DATA *fch = d->character; if (fch != NULL && fch != victim && d->connected == CON_PLAYING && !IS_NPC(fch) && fch->cursed_by_witch == victim) { fch->cursed_by_witch = NULL; act("You feel $N's {Dcurse{x is lifted!", fch, NULL, victim, TO_CHAR); act("You sense $N has wrest $Mself free of your curse.", victim, NULL, fch, TO_CHAR); pAf = affect_find(fch->affected, gsn_witch_curse); affect_remove(fch, pAf); } } } /* * enslave someone instead of killing them if ch has autoenslave on. * and free slaves of the victim * * returns TRUE if enslavement occured * * by Zsuzsu */ bool handle_enslavement (CHAR_DATA *ch, CHAR_DATA *victim) { DESCRIPTOR_DATA *d; CHAR_DATA *enslaver = NULL; if (IS_NPC(victim)) return FALSE; enslaver = ch; /* if the pet did the kill */ if (IS_NPC(enslaver) && enslaver->master != NULL && !IS_SET(enslaver->master->state_flags, STATE_GHOST) && enslaver->in_room == enslaver->master->in_room) enslaver = enslaver->master; if (!IS_NPC(enslaver) && enslaver != victim && IS_SET(enslaver->conf_flags, PLR_CONF_AUTO_CLAN_SKILL) && get_skill(enslaver, gsn_enslave) > 0) { if (victim->pcdata->enslaver == NULL) { victim->hit = 0; victim->mana = 0; victim->move = 0; victim->position = POS_STUNNED; doprintf(do_enslave, enslaver, "%s", victim->name); /*SET_BIT(ch->affected_by, AFF_STUN);*/ /*SET_BIT(victim->state_flags, STATE_GHOST);*/ victim->last_death_time = current_time; stop_fighting(victim, TRUE); /* drop all objects on the floor */ strip_char(victim); act_puts("You are stripped of all your belongings.", victim, NULL, NULL, TO_CHAR, POS_DEAD); act("$n's belongings are stripped from $m and strewn on the ground.", victim, NULL, NULL, TO_ROOM); /* pets abandon you so you can't fight back * as quickly */ act_puts("Your pets seem to want to any part of you.", victim, NULL, NULL, TO_CHAR, POS_DEAD); disband_pets(victim); /* remove all affects */ while (victim->affected) affect_remove(victim, victim->affected); victim->affected_by = 0; wiznet_death(ch, victim, DEATH_ENSLAVED); rating_update(enslaver, victim); return TRUE; } else if (!str_cmp(enslaver->name, victim->pcdata->enslaver)) { /* attempting not to double credit people for enslavement kills*/ if (current_time - victim->last_death_time >= GHOST_DELAY_TIME / 3) rating_update(enslaver, victim); } else { char_printf(ch, "You just killed %s's property!", victim->pcdata->enslaver); } } /* free slaves */ /* free victim if the attacker was an enslaver */ if (get_skill(enslaver, gsn_enslave) > 0 && victim->pcdata->enslaver != NULL) { enslaver = get_char_world_unrestricted(victim->pcdata->enslaver); if (enslaver) doprintf(do_enslave, enslaver, "%s", victim->name); else { victim->pcdata->enslaver = NULL; act_puts("You are unleashed from bondage!", victim, NULL, NULL, TO_CHAR, POS_DEAD); } } /* free slaves of the victim */ /* can't just do this for those with the skill, because they * might be out of scion */ for (d = descriptor_list; d; d = d->next) { CHAR_DATA *fch = d->character; if (fch != NULL && fch != victim && d->connected == CON_PLAYING && !IS_NPC(fch) && !str_cmp(victim->name, fch->pcdata->enslaver)) { if (get_skill(victim, gsn_enslave) > 0) doprintf(do_enslave, victim, "%s", fch->name); else { fch->pcdata->enslaver = NULL; act_puts("You are unleashed from bondage!", fch, NULL, NULL, TO_CHAR, POS_DEAD); } } } return FALSE; } /* * handle_dishonor - checks to see if a samurai * has regained honor through solo combat * against superior odds (or PC peer). * * returns TRUE if honor was regained * FALSE for all other cases * * by Zsuzsu */ bool handle_dishonor (CHAR_DATA *ch, CHAR_DATA *victim) { CHAR_DATA *gch; int op_level = 0; AFFECT_DATA *paf; if (IS_NPC(ch) || !HAS_SKILL(ch, gsn_dishonor)) return FALSE; if (!is_affected(ch, gsn_dishonor)) return FALSE; for (gch = char_list; gch; gch = gch->next) { if (gch != ch && is_same_group(ch, gch) && ch->in_room == gch->in_room) return FALSE; if (is_same_group(victim, gch) && ch->in_room == gch->in_room) op_level += IS_NPC(gch) ? gch->level -1 : gch->level; } if (op_level >= ch->level) { while ((paf = affect_find(ch->affected, gsn_dishonor))) affect_remove(ch, paf); char_puts("You have regained your honor" " this day!\n", ch); if (op_level > ch->level+1 && number_percent() > 93) { char_printf(ch, "You {Ysave{x face.\n"); ch->perm_stat[STAT_CHA]++; } return TRUE; } return FALSE; } /* * determine the chance of any one character parrying * the attacks of another character * * this has been seperated from check_parry() mostly * so it can be called seperately to determine * battle odds of one character to another */ int parry_chance (CHAR_DATA *ch, CHAR_DATA *victim) { OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; OBJ_DATA *v_weapon; int chance; int i; if (IS_NPC(victim)) { chance = 40; if (IS_SET(victim->pIndexData->act, ACT_WARRIOR)) chance += 60; if (IS_SET(victim->pIndexData->act, ACT_THIEF)) chance += 30; if (IS_SET(victim->pIndexData->act, ACT_MAGE)) chance -= 20; } else { if (get_eq_char(victim, WEAR_WIELD) == NULL) return 0; chance = get_skill(victim, gsn_parry); } if (chance <= 0) return 0; chance = chance / 4; if (check_forest(victim) == FOREST_DEFENCE && (number_percent() < get_skill(victim, gsn_forest_fighting))) { chance = chance * 120 / 100; check_improve (victim, gsn_forest_fighting, TRUE, 7); } if (get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_FLAIL) chance /= 2; /* weapon modifications */ for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: chance += 4 / (i+1); break; case WEAPON_DAGGER: chance -= 4 / (i+1); break; } } if ((v_weapon = get_eq_char(victim, WEAR_WIELD)) != NULL) { switch (v_weapon->value[ITEM_WEAPON_TYPE]) { case WEAPON_SHORTSWORD: chance += 10; break; case WEAPON_DAGGER: chance -= 10; break; case WEAPON_AXE: chance += 10; break; } } chance += (LEVEL(victim) - LEVEL(ch)) / 2; /* stat modifications */ if (!IS_NPC(victim)) { chance += (get_curr_stat(victim, STAT_STR) -50) / 5; chance += (get_curr_stat(victim, STAT_DEX) -50) / 5; } /* affect modifications */ if (is_affected(victim, gsn_giant_strength)) chance += 1; if (is_affected(ch, gsn_giant_strength)) chance -= 1; if (is_affected(victim, gsn_dragon_strength)) chance += 1; if (is_affected(ch, gsn_dragon_strength)) chance -= 1; if (IS_AFFECTED(victim, AFF_HASTE)) chance += 1; if (IS_AFFECTED(ch, AFF_HASTE)) chance -= 1; chance = URANGE(0, chance, 50); return chance; } int dodge_chance (CHAR_DATA *ch, CHAR_DATA *victim) { OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; OBJ_DATA *v_weapon; int chance; int i; if (MOUNTED(victim)) return 0; if (IS_NPC(victim)) { if (victim->pIndexData->dodge < 1) { chance = 60; if (IS_SET(victim->pIndexData->act, ACT_WARRIOR)) chance += 40; if (IS_SET(victim->pIndexData->act, ACT_THIEF)) chance += 60; if (IS_SET(victim->pIndexData->act, ACT_MAGE)) chance -= 40; if (IS_SET(victim->pIndexData->off_flags, OFF_FAST)) chance += 20; } else chance = victim->pIndexData->dodge; } else { chance = get_skill(victim, gsn_dodge); } chance = chance / 4; if (chance <= 0) return 0; if (!IS_NPC(victim)) { chance += (get_curr_stat(ch, STAT_DEX)-55) / 4; if (ENCUMBERANCE(victim) > 35) chance -= (ENCUMBERANCE(victim) - 35)/2; if (ENCUMBERANCE(victim) > 75) chance -= (ENCUMBERANCE(victim) - 75); if (ENCUMBERANCE(victim) > 90) chance = 0; if (ENCUMBERANCE(victim) < 15) chance += (15 - ENCUMBERANCE(victim)) / 2; } if (chance <= 0) return 0; chance += (LEVEL(victim) - LEVEL(ch)) / 2; if (IS_AFFECTED(victim, AFF_HASTE)) chance += 2; if (IS_AFFECTED(ch, AFF_HASTE)) chance -= 2; if (check_forest(victim) == FOREST_DEFENCE && (get_skill(victim, gsn_forest_fighting) > number_percent())) { chance = chance * 120 / 100; check_improve (victim, gsn_forest_fighting, TRUE, 7); } /* weapon modifications */ for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: chance += 4 / (i+1); break; case WEAPON_DAGGER: chance -= 4 / (i+1); break; } } v_weapon = get_eq_char(victim, WEAR_WIELD); if (v_weapon != NULL) { switch (v_weapon->value[ITEM_WEAPON_TYPE]) { case WEAPON_AXE: chance -= 2; break; case WEAPON_DAGGER: chance += 2; break; } } chance = URANGE(0, chance, 50); return chance; } int shield_block_chance (CHAR_DATA *ch, CHAR_DATA *victim) { OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; int chance = 0; int i; if (!IS_NPC(victim) && get_eq_char(victim, WEAR_SHIELD) == NULL) return 0; if (IS_NPC(victim)) { if (get_eq_char(victim, WEAR_SHIELD)) chance = 50; if (IS_SET(victim->pIndexData->act, ACT_WARRIOR)) chance += 50; } else { chance = get_skill(victim, gsn_shield_block); if (chance <= 1) return 0; chance += (get_curr_stat(victim, STAT_STR) - 50)/ 2; } chance = chance / 4; if (chance <= 0) return 0; if (check_forest(victim) == FOREST_DEFENCE && (number_percent() < get_skill(victim, gsn_forest_fighting))) { chance = chance * 120 / 100; check_improve (victim, gsn_forest_fighting, TRUE, 7); } if (MOUNTED(victim)) chance = chance * 120 / 100; chance += (LEVEL(victim) - LEVEL(ch)) / 4; /* weapon modifications */ if (get_eq_char(ch, WEAR_WIELD) && get_eq_char(ch, WEAR_WIELD)->value[ITEM_WEAPON_TYPE] == WEAPON_WHIP) chance /= 2; for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: chance += 4 / (i+1); break; case WEAPON_DAGGER: chance -= 4 / (i+1); break; } } if (is_affected(victim, gsn_giant_strength)) chance += 2; if (is_affected(ch, gsn_giant_strength)) chance -= 2; if (is_affected(victim, gsn_dragon_strength)) chance += 2; if (is_affected(ch, gsn_dragon_strength)) chance -= 2; chance = URANGE(0, chance, 50); return chance; } int hand_block_chance (CHAR_DATA *ch, CHAR_DATA *victim) { OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; int chance; int i; if (IS_NPC(victim) || (get_eq_char(victim, WEAR_WIELD) && get_eq_char(victim, WEAR_SHIELD)) || (get_eq_char(victim, WEAR_WIELD) && get_eq_char(victim, WEAR_HOLD)) || (get_eq_char(victim, WEAR_WIELD) && get_eq_char(victim, WEAR_SECOND_WIELD)) || ((chance=get_skill(victim, gsn_hand_block)/5)<=0)) return 0; chance += (LEVEL(victim) - LEVEL(ch)); if (!IS_NPC(ch) && !IS_NPC(victim)) chance += (get_curr_stat(victim, STAT_DEX) - get_curr_stat(ch, STAT_DEX)) / 2; else if (!IS_NPC(victim)) chance += (get_curr_stat(victim, STAT_DEX) -60) / 4; /* weapon modifications */ for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: case WEAPON_STAFF: case WEAPON_DAGGER: chance += 4 / (i+1); break; } } chance = URANGE(0, chance, 40); return chance; } int haft_block_chance (CHAR_DATA *ch, CHAR_DATA *victim) { OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; OBJ_DATA *v_weapon; int chance; int i; if (IS_NPC (victim)) { if (!IS_SET(victim->pIndexData->act, ACT_WARRIOR)) chance = 0; else chance = UMAX(5, LEVEL(victim) - 45); } else { chance = get_skill (victim, gsn_haft_block) /10; } if (chance <= 0) return 0; if (get_eq_char (victim, WEAR_WIELD) == NULL) return 0; if (IS_AFFECTED (victim, AFF_BLIND)) { if (get_skill (victim, gsn_blind_fighting) == 0) chance /= 2; else { chance /= 2; chance += ((get_skill (victim, gsn_blind_fighting)) / 4); } } chance += (LEVEL(victim) - LEVEL(ch)) / 3; /* weapon modifications */ for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_DAGGER: chance -= 6 / (i+1); break; } } if ((v_weapon = get_eq_char(victim, WEAR_WIELD)) == NULL) { switch (v_weapon->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: case WEAPON_SPEAR: case WEAPON_STAFF: chance += 4; break; case WEAPON_DAGGER: chance = 0; break; } } chance = URANGE(0, chance, 30); return chance; } int tumble_chance (CHAR_DATA *ch, CHAR_DATA *victim) { int chance; OBJ_DATA *ch_weapons[2] = {get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECOND_WIELD)}; OBJ_DATA *v_weapon; int i; if (IS_NPC(victim)) return 0; if (get_eq_char (victim, WEAR_SHIELD) != NULL) return 0; chance = get_skill (victim, gsn_tumble) / 4; if (chance <= 0) return 0; chance = chance + (get_curr_stat (victim, STAT_DEX) / 2); chance = chance - (get_curr_stat (ch, STAT_DEX) / 2); if (IS_AFFECTED (victim, AFF_BLIND)) { if (get_skill (victim, gsn_blind_fighting) == 0) chance /= 2; else { chance /= 2; chance += ((get_skill(victim, gsn_blind_fighting)) / 7); } } chance += (LEVEL(victim) - LEVEL(ch)) / 2; if (ENCUMBERANCE(victim) > 35) chance -= (ENCUMBERANCE(victim) - 35) / 2; if (ENCUMBERANCE(victim) > 75) chance -= (ENCUMBERANCE(victim) - 85) / 2; else if (ENCUMBERANCE(victim) <= 15) chance += ENCUMBERANCE(victim) / 3; /* weapon modifications */ for (i = 0;i < 2;i++) { if (ch_weapons[i] == NULL) continue; switch (ch_weapons[i]->value[ITEM_WEAPON_TYPE]) { case WEAPON_POLEARM: chance += 4 / (i+1); break; case WEAPON_DAGGER: chance -= 4 / (i+1); break; } } v_weapon = get_eq_char(victim, WEAR_WIELD); chance = URANGE(0, chance, 80); return chance; } int blink_chance (CHAR_DATA *ch, CHAR_DATA *victim) { int chance; if (IS_NPC(victim)) { if (IS_SET(victim->pIndexData->act, ACT_MAGE) && LEVEL(victim) > 10) chance = 30; else chance = 0; } else chance = get_skill(victim, gsn_blink) / 2; if (chance <= 0) return 0; chance += LEVEL(victim) - LEVEL(ch); chance = URANGE(0, chance, 80); return chance; } /* * assess the chance someone will hit someone else with a certain attack */ int tohit_chance(CHAR_DATA *ch, CHAR_DATA *victim, int dt, int loc) { OBJ_DATA *wield; OBJ_DATA *dual = NULL; int victim_ac; int thac0; int thac0_00; int thac0_32; int sn, sk, sk2; int dam_type; bool counter; sn = -1; counter = FALSE; /* just in case */ if (victim == ch || ch == NULL || victim == NULL) return -1; /* * Figure out the type of damage message. */ wield = get_eq_char(ch, loc); dam_type = get_dam_type(ch, wield, &dt); dual = get_eq_char(ch, WEAR_SECOND_WIELD); /* * don't double backstab if the second weapon isn't peircing */ if (dt == gsn_dual_backstab && !IS_NPC(ch) && (!dual || attack_table[dual->value[ITEM_WEAPON_ATTACK_TYPE]].damage != DAM_PIERCE)) { return -1; } /* get the weapon skill */ sn = get_weapon_sn(wield); sk = 20 + get_weapon_skill(ch, sn); /* * Calculate to-hit-armor-class-0 versus armor. */ if (IS_NPC(ch)) { flag64_t act = ch->pIndexData->act; thac0_00 = 20; thac0_32 = -4; /* as good as a thief */ if (IS_SET(act, ACT_WARRIOR)) thac0_32 = -10; else if (IS_SET(act, ACT_THIEF)) thac0_32 = -4; else if (IS_SET(act, ACT_CLERIC)) thac0_32 = 2; else if (IS_SET(act, ACT_MAGE)) thac0_32 = 6; } else { class_t *cl; if ((cl = class_lookup(ch->class)) == NULL) return -1; thac0_00 = cl->thac0_00; thac0_32 = cl->thac0_32; } thac0 = interpolate(LEVEL(ch), thac0_00, thac0_32); if (thac0 < 0) thac0 = thac0/2; if (thac0 < -5) thac0 = -5 + (thac0 + 5) / 2; thac0 -= GET_HITROLL(ch) * sk / 100; thac0 += 5 * (100 - sk) / 100; if (dt == gsn_backstab) thac0 -= 10 * (100 - get_skill(ch, gsn_backstab)); else if (dt == gsn_dual_backstab) thac0 -= 10 * (100 - get_skill(ch, gsn_dual_backstab)); else if (dt == gsn_cleave) thac0 -= 10 * (100 - get_skill(ch, gsn_cleave)); else if (dt == gsn_ambush) thac0 -= 10 * (100 - get_skill(ch, gsn_ambush)); else if (dt == gsn_vampiric_bite) thac0 -= 10 * (100 - get_skill(ch, gsn_vampiric_bite)); else if (dt == gsn_charge) thac0 -= 10 * (100 - get_skill(ch, gsn_charge)); switch(dam_type) { case DAM_PIERCE:victim_ac = GET_AC(victim,AC_PIERCE)/10; break; case DAM_BASH: victim_ac = GET_AC(victim,AC_BASH)/10; break; case DAM_SLASH: victim_ac = GET_AC(victim,AC_SLASH)/10; break; default: victim_ac = GET_AC(victim,AC_EXOTIC)/10; break; } if (victim_ac < -15) victim_ac = (victim_ac + 15) / 5 - 15; if (get_skill(victim, gsn_armor_use) > 70) { victim_ac -= (victim->level) / 2; } if (!can_see(ch, victim)) { if ((sk2 = get_skill(ch, gsn_blind_fighting) == 0) || number_percent() >= sk2) victim_ac -= 4; } if (victim->position < POS_FIGHTING) victim_ac += 4; if (victim->position < POS_RESTING) victim_ac += 6; return thac0 - victim_ac; }