/* * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke * * This software may be copied and distributed for educational, research, and * not for profit purposes provided that this copyright and statement are * included in all such copies. */ #include "melee1.hpp" #include "angband.h" #include "cave.hpp" #include "cmd5.hpp" #include "mimic.hpp" #include "monster2.hpp" #include "monster3.hpp" #include "object1.hpp" #include "object2.hpp" #include "skills.hpp" #include "spells1.hpp" #include "spells2.hpp" #include "store.hpp" #include "util.hpp" #include "xtra1.hpp" #include "xtra2.hpp" #include using boost::algorithm::iequals; /* * Critical blow. All hits that do 95% of total possible damage, * and which also do at least 20 damage, or, sometimes, N damage. * This is used only to determine "cuts" and "stuns". */ static int monster_critical(int dice, int sides, int dam) { int max = 0; int total = dice * sides; /* Must do at least 95% of perfect */ if (dam < total * 19 / 20) return (0); /* Weak blows rarely work */ if ((dam < 20) && (rand_int(100) >= dam)) return (0); /* Perfect damage */ if (dam == total) max++; /* Super-charge */ if (dam >= 20) { while (rand_int(100) < 2) max++; } /* Critical damage */ if (dam > 45) return (6 + max); if (dam > 33) return (5 + max); if (dam > 25) return (4 + max); if (dam > 18) return (3 + max); if (dam > 11) return (2 + max); return (1 + max); } /* * Determine if a monster attack against the player succeeds. * Always miss 5% of the time, Always hit 5% of the time. * Otherwise, match monster power against player armor. */ static int check_hit(int power, int level) { int i, k, ac; /* Percentile dice */ k = rand_int(100); /* Hack -- Always miss or hit */ if (k < 10) return (k < 5); /* Calculate the "attack quality" */ i = (power + (level * 3)); /* Total armor */ ac = p_ptr->ac + p_ptr->to_a; /* Power and Level compete against Armor */ if ((i > 0) && (randint(i - luck( -10, 10)) > ((ac * 3) / 4))) return (TRUE); /* Assume miss */ return (FALSE); } /* * Hack -- possible "insult" messages */ static cptr desc_insult[] = { "insults you!", "insults your mother!", "jumps around you!", "humiliates you!", "defiles you!", "dances around you!", "makes obnoxious gestures!", "pokes you!!!" }; /* * Hack -- possible "insult" messages */ static cptr desc_moan[] = { "seems sad about something.", "asks if you have seen his dogs.", "tells you to get off his land.", "mumbles something about mushrooms.", /* Mathilde's sentence */ "giggles at you.", "asks you if you want to giggle with her.", "says she is always happy." }; /* * Get the "power" of an attack of given effect type. */ int get_attack_power(int effect) { switch (effect) { case RBE_HURT: return 60; case RBE_POISON: return 5; case RBE_UN_BONUS: return 20; case RBE_UN_POWER: return 15; case RBE_EAT_GOLD: return 5; case RBE_EAT_ITEM: return 5; case RBE_EAT_FOOD: return 5; case RBE_EAT_LITE: return 5; case RBE_ACID: return 0; case RBE_ELEC: return 10; case RBE_FIRE: return 10; case RBE_COLD: return 10; case RBE_BLIND: return 2; case RBE_CONFUSE: return 10; case RBE_TERRIFY: return 10; case RBE_PARALYZE: return 2; case RBE_LOSE_STR: return 0; case RBE_LOSE_DEX: return 0; case RBE_LOSE_CON: return 0; case RBE_LOSE_INT: return 0; case RBE_LOSE_WIS: return 0; case RBE_LOSE_CHR: return 0; case RBE_LOSE_ALL: return 2; case RBE_SHATTER: return 60; case RBE_EXP_10: return 5; case RBE_EXP_20: return 5; case RBE_EXP_40: return 5; case RBE_EXP_80: return 5; case RBE_DISEASE: return 5; case RBE_TIME: return 5; case RBE_SANITY: return 60; case RBE_HALLU: return 10; case RBE_PARASITE: return 5; case RBE_ABOMINATION: return 30; } /* Unknown effects have no power */ return 0; } /* * Attack the player via physical attacks. */ bool_ carried_make_attack_normal(int r_idx) { monster_race *r_ptr = &r_info[r_idx]; int ap_cnt; int k, tmp, ac, rlev; int do_cut, do_stun; char ddesc[80] = "your symbiote"; cptr sym_name = symbiote_name(TRUE); bool_ touched = FALSE, alive = TRUE; /* Not allowed to attack */ if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE); /* Total armor */ ac = p_ptr->ac + p_ptr->to_a; /* Extract the effective monster level */ rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); /* Scan through all four blows */ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++) { bool_ visible = FALSE; bool_ obvious = FALSE; int power = 0; int damage = 0; cptr act = NULL; /* Extract the attack infomation */ int effect = r_ptr->blow[ap_cnt].effect; int method = r_ptr->blow[ap_cnt].method; int d_dice = r_ptr->blow[ap_cnt].d_dice; int d_side = r_ptr->blow[ap_cnt].d_side; /* Hack -- no more attacks */ if (!method) break; /* Stop if player is dead or gone */ if (!alive || death) break; /* Handle "leaving" */ if (p_ptr->leaving) break; /* Extract visibility (before blink) */ visible = TRUE; /* Extract the attack "power" */ power = get_attack_power(effect); /* Monster hits player */ if (!effect || check_hit(power, rlev)) { /* Always disturbing */ disturb(1); /* Hack -- Apply "protection from evil" */ if ((p_ptr->protevil > 0) && (r_ptr->flags3 & (RF3_EVIL)) && (p_ptr->lev >= rlev) && ((rand_int(100) + p_ptr->lev) > 50)) { /* Remember the Evil-ness */ r_ptr->r_flags3 |= (RF3_EVIL); /* Message */ msg_format("%s is repelled.", sym_name); /* Hack -- Next attack */ continue; } /* Hack -- Apply "protection from good" */ if ((p_ptr->protgood > 0) && (r_ptr->flags3 & (RF3_GOOD)) && (p_ptr->lev >= rlev) && ((rand_int(100) + p_ptr->lev) > 50)) { /* Remember the Good-ness */ r_ptr->r_flags3 |= (RF3_GOOD); /* Message */ msg_format("%s is repelled.", sym_name); /* Hack -- Next attack */ continue; } /* Assume no cut or stun */ do_cut = do_stun = 0; /* Describe the attack method */ switch (method) { case RBM_HIT: { act = "hits you."; do_cut = do_stun = 1; touched = TRUE; sound(SOUND_HIT); break; } case RBM_TOUCH: { act = "touches you."; touched = TRUE; sound(SOUND_TOUCH); break; } case RBM_PUNCH: { act = "punches you."; touched = TRUE; do_stun = 1; sound(SOUND_HIT); break; } case RBM_KICK: { act = "kicks you."; touched = TRUE; do_stun = 1; sound(SOUND_HIT); break; } case RBM_CLAW: { act = "claws you."; touched = TRUE; do_cut = 1; sound(SOUND_CLAW); break; } case RBM_BITE: { act = "bites you."; do_cut = 1; touched = TRUE; sound(SOUND_BITE); break; } case RBM_STING: { act = "stings you."; touched = TRUE; sound(SOUND_STING); break; } case RBM_XXX1: { act = "XXX1's you."; break; } case RBM_BUTT: { act = "butts you."; do_stun = 1; touched = TRUE; sound(SOUND_HIT); break; } case RBM_CRUSH: { act = "crushes you."; do_stun = 1; touched = TRUE; sound(SOUND_CRUSH); break; } case RBM_ENGULF: { act = "engulfs you."; touched = TRUE; sound(SOUND_CRUSH); break; } case RBM_CHARGE: { act = "charges you."; touched = TRUE; sound(SOUND_BUY); /* Note! This is "charges", not "charges at". */ break; } case RBM_CRAWL: { act = "crawls on you."; touched = TRUE; sound(SOUND_SLIME); break; } case RBM_DROOL: { act = "drools on you."; sound(SOUND_SLIME); break; } case RBM_SPIT: { act = "spits on you."; sound(SOUND_SLIME); break; } case RBM_EXPLODE: { act = "explodes."; break; } case RBM_GAZE: { act = "gazes at you."; break; } case RBM_WAIL: { act = "wails at you."; sound(SOUND_WAIL); break; } case RBM_SPORE: { act = "releases spores at you."; sound(SOUND_SLIME); break; } case RBM_XXX4: { act = "projects XXX4's at you."; break; } case RBM_BEG: { act = "begs you for money."; sound(SOUND_MOAN); break; } case RBM_INSULT: { act = desc_insult[rand_int(8)]; sound(SOUND_MOAN); break; } case RBM_MOAN: { act = desc_moan[rand_int(4)]; sound(SOUND_MOAN); break; } case RBM_SHOW: { if (randint(3) == 1) act = "sings 'We are a happy family.'"; else act = "sings 'I love you, you love me.'"; sound(SOUND_SHOW); break; } } /* Message */ if (act) msg_format("%s %s", sym_name, act); /* Hack -- assume all attacks are obvious */ obvious = TRUE; /* Roll out the damage */ damage = damroll(d_dice, d_side); /* Apply appropriate damage */ switch (effect) { case 0: { /* Hack -- Assume obvious */ obvious = TRUE; /* Hack -- No damage */ damage = 0; break; } case RBE_HURT: { /* Obvious */ obvious = TRUE; /* Hack -- Player armor reduces total damage */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_ABOMINATION: { /* Obvious */ obvious = TRUE; /* Morph, but let mimicry skill have a chance to stop this */ if (magik(60 - get_skill(SKILL_MIMICRY))) { /* Message */ cmsg_print(TERM_VIOLET, "You feel the dark powers twisting your body!"); set_mimic(damage, resolve_mimic_name("Abomination"), 50); } else { /* Message */ cmsg_print(TERM_VIOLET, "You feel the dark powers trying to twisting your body, but they fail."); } break; } case RBE_SANITY: { obvious = TRUE; take_sanity_hit(damage, ddesc); break; } case RBE_POISON: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Take "poison" effect */ if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) { if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5)) { obvious = TRUE; } } break; } case RBE_UN_BONUS: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Allow complete resist */ if (!p_ptr->resist_disen) { /* Apply disenchantment */ if (apply_disenchant(0)) obvious = TRUE; } break; } case RBE_UN_POWER: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_EAT_GOLD: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_EAT_ITEM: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_EAT_FOOD: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_EAT_LITE: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } case RBE_ACID: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered in acid!"); /* Special damage */ carried_monster_hit = TRUE; acid_dam(damage, ddesc); break; } case RBE_ELEC: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are struck by electricity!"); /* Special damage */ carried_monster_hit = TRUE; elec_dam(damage, ddesc); break; } case RBE_FIRE: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are enveloped in flames!"); /* Special damage */ carried_monster_hit = TRUE; fire_dam(damage, ddesc); break; } case RBE_COLD: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered with frost!"); /* Special damage */ carried_monster_hit = TRUE; cold_dam(damage, ddesc); break; } case RBE_BLIND: { /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Increase "blind" */ if (!p_ptr->resist_blind) { if (set_blind(p_ptr->blind + 10 + randint(rlev))) { obvious = TRUE; } } break; } case RBE_CONFUSE: { /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Increase "confused" */ if (!p_ptr->resist_conf) { if (set_confused(p_ptr->confused + 3 + randint(rlev))) { obvious = TRUE; } } break; } case RBE_TERRIFY: { /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Increase "afraid" */ if (p_ptr->resist_fear) { msg_print("You stand your ground!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You stand your ground!"); obvious = TRUE; } else { if (set_afraid(p_ptr->afraid + 3 + randint(rlev))) { obvious = TRUE; } } break; } case RBE_PARALYZE: { /* Hack -- Prevent perma-paralysis via damage */ if (p_ptr->paralyzed && (damage < 1)) damage = 1; /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Increase "paralyzed" */ if (p_ptr->free_act) { msg_print("You are unaffected!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You resist the effects!"); obvious = TRUE; } else { if (set_paralyzed(3 + randint(rlev))) { obvious = TRUE; } } break; } case RBE_LOSE_STR: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_INT: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_WIS: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_DEX: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_CON: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_CHR: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_ALL: { /* Damage (physical) */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Damage (stats) */ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_SHATTER: { /* Obvious */ obvious = TRUE; /* Hack -- Reduce damage based on the player armor class */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Radius 8 earthquake centered at the monster */ if (damage > 23) { /* Prevent destruction of quest levels and town */ if (!is_quest(dun_level) && dun_level) earthquake(p_ptr->py, p_ptr->px, 8); } break; } case RBE_EXP_10: { /* Obvious */ obvious = TRUE; /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 95)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(10, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_20: { /* Obvious */ obvious = TRUE; /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 90)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_40: { /* Obvious */ obvious = TRUE; /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 75)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_80: { /* Obvious */ obvious = TRUE; /* Take damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 50)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_DISEASE: { /* Take some damage */ carried_monster_hit = TRUE; take_hit(damage, ddesc); /* Take "poison" effect */ if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) { if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5)) { obvious = TRUE; } } /* Damage CON (10% chance)*/ if (randint(100) < 11) { /* 1% chance for perm. damage */ bool_ perm = (randint(10) == 1); if (dec_stat(A_CON, randint(10), perm)) obvious = TRUE; } break; } case RBE_PARASITE: { /* Obvious */ obvious = TRUE; if (!p_ptr->parasite) set_parasite(damage, r_idx); break; } case RBE_HALLU: { /* Take damage */ take_hit(damage, ddesc); /* Increase "image" */ if (!p_ptr->resist_chaos) { if (set_image(p_ptr->image + 3 + randint(rlev / 2))) { obvious = TRUE; } } break; } case RBE_TIME: { switch (randint(10)) { case 1: case 2: case 3: case 4: case 5: { msg_print("You feel life has clocked back."); lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); break; } case 6: case 7: case 8: case 9: { int stat = rand_int(6); switch (stat) { case A_STR: act = "strong"; break; case A_INT: act = "bright"; break; case A_WIS: act = "wise"; break; case A_DEX: act = "agile"; break; case A_CON: act = "hardy"; break; case A_CHR: act = "beautiful"; break; } msg_format("You're not as %s as you used to be...", act); p_ptr->stat_cur[stat] = (p_ptr->stat_cur[stat] * 3) / 4; if (p_ptr->stat_cur[stat] < 3) p_ptr->stat_cur[stat] = 3; p_ptr->update |= (PU_BONUS); break; } case 10: { msg_print("You're not as powerful as you used to be..."); for (k = 0; k < 6; k++) { p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4; if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3; } p_ptr->update |= (PU_BONUS); break; } } carried_monster_hit = TRUE; take_hit(damage, ddesc); break; } } /* Hack -- only one of cut or stun */ if (do_cut && do_stun) { /* Cancel cut */ if (rand_int(100) < 50) { do_cut = 0; } /* Cancel stun */ else { do_stun = 0; } } /* Handle cut */ if (do_cut) { int k = 0; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(5) + 5; break; case 3: k = randint(20) + 20; break; case 4: k = randint(50) + 50; break; case 5: k = randint(100) + 100; break; case 6: k = 300; break; default: k = 500; break; } /* Apply the cut */ if (k) (void)set_cut(p_ptr->cut + k); } /* Handle stun */ if (do_stun) { int k = 0; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(10) + 10; break; case 3: k = randint(20) + 20; break; case 4: k = randint(30) + 30; break; case 5: k = randint(40) + 40; break; case 6: k = 100; break; default: k = 200; break; } /* Apply the stun */ if (k) (void)set_stun(p_ptr->stun + k); } if (touched) { if (p_ptr->sh_fire && alive) { r_ptr->r_flags3 |= RF3_IM_FIRE; } if (p_ptr->sh_elec && alive) { r_ptr->r_flags3 |= RF3_IM_ELEC; } touched = FALSE; } } /* Monster missed player */ else { /* Analyze failed attacks */ switch (method) { case RBM_HIT: case RBM_TOUCH: case RBM_PUNCH: case RBM_KICK: case RBM_CLAW: case RBM_BITE: case RBM_STING: case RBM_XXX1: case RBM_BUTT: case RBM_CRUSH: case RBM_ENGULF: case RBM_CHARGE: /* Disturbing */ disturb(1); /* Message */ msg_format("%s misses you.", sym_name); break; } } /* Analyze "visible" monsters only */ if (visible) { /* Count "obvious" attacks (and ones that cause damage) */ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10)) { /* Count attacks of this type */ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR) { r_ptr->r_blows[ap_cnt]++; } } } } /* Assume we attacked */ return (TRUE); } /* * Give unprotected player the Black Breath with a 1 in (chance) probability * */ void black_breath_attack(int chance) { if (!p_ptr->protundead && randint(chance) == 1) { msg_print("Your foe calls upon your soul!"); msg_print("You feel the Black Breath slowly draining you of life..."); p_ptr->black_breath = TRUE; } } /* * Attack the player via physical attacks. */ bool_ make_attack_normal(int m_idx, byte divis) { monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr = race_inf(m_ptr); int ap_cnt; int i, j, k, tmp, ac, rlev; int do_cut, do_stun, do_vampire; s32b gold; object_type *o_ptr; char o_name[80]; char m_name[80]; char ddesc[80]; bool_ blinked; bool_ touched = FALSE, fear = FALSE, alive = TRUE; bool_ explode = FALSE; /* Not allowed to attack */ if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE); /* ...nor if friendly */ if (is_friend(m_ptr) >= 0) { if (p_ptr->control == m_idx) swap_position(m_ptr->fy, m_ptr->fx); return FALSE; } /* Cannot attack the player if mortal and player fated to never die by the ... */ if ((r_ptr->flags7 & RF7_MORTAL) && (p_ptr->no_mortal)) return (FALSE); /* Total armor */ ac = p_ptr->ac + p_ptr->to_a; /* Extract the effective monster level */ rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1); /* Get the monster name (or "it") */ monster_desc(m_name, m_ptr, 0); /* Get the "died from" information (i.e. "a kobold") */ monster_desc(ddesc, m_ptr, 0x88); /* Assume no blink */ blinked = FALSE; /* Scan through all four blows */ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++) { bool_ visible = FALSE; bool_ obvious = FALSE; int power = 0; int damage = 0; cptr act = NULL; /* Extract the attack infomation */ int effect = m_ptr->blow[ap_cnt].effect; int method = m_ptr->blow[ap_cnt].method; int d_dice = m_ptr->blow[ap_cnt].d_dice; int d_side = m_ptr->blow[ap_cnt].d_side; /* Hack -- no more attacks */ if (!method) break; /* Stop if player is dead or gone */ if (!alive || death) break; /* Handle "leaving" */ if (p_ptr->leaving) break; /* Extract visibility (before blink) */ if (m_ptr->ml) visible = TRUE; /* Extract the attack "power" */ switch (effect) { case RBE_HURT: power = 60; break; case RBE_POISON: power = 5; break; case RBE_UN_BONUS: power = 20; break; case RBE_UN_POWER: power = 15; break; case RBE_EAT_GOLD: power = 5; break; case RBE_EAT_ITEM: power = 5; break; case RBE_EAT_FOOD: power = 5; break; case RBE_EAT_LITE: power = 5; break; case RBE_ACID: power = 0; break; case RBE_ELEC: power = 10; break; case RBE_FIRE: power = 10; break; case RBE_COLD: power = 10; break; case RBE_BLIND: power = 2; break; case RBE_CONFUSE: power = 10; break; case RBE_TERRIFY: power = 10; break; case RBE_PARALYZE: power = 2; break; case RBE_LOSE_STR: power = 0; break; case RBE_LOSE_DEX: power = 0; break; case RBE_LOSE_CON: power = 0; break; case RBE_LOSE_INT: power = 0; break; case RBE_LOSE_WIS: power = 0; break; case RBE_LOSE_CHR: power = 0; break; case RBE_LOSE_ALL: power = 2; break; case RBE_SHATTER: power = 60; break; case RBE_EXP_10: power = 5; break; case RBE_EXP_20: power = 5; break; case RBE_EXP_40: power = 5; break; case RBE_EXP_80: power = 5; break; case RBE_DISEASE: power = 5; break; case RBE_TIME: power = 5; break; case RBE_SANITY: power = 60; break; case RBE_HALLU: power = 10; break; case RBE_PARASITE: power = 5; break; case RBE_ABOMINATION: power = 20; break; } /* Monster hits player */ if (!effect || check_hit(power, rlev)) { int chance = p_ptr->dodge_chance - ((rlev * 5) / 6); /* Always disturbing */ disturb(1); if ((chance > 0) && magik(chance)) { char m_poss[80]; monster_desc(m_poss, m_ptr, 0x06); msg_format("You dodge %s attack!", m_poss); continue; } /* Eru can help you */ PRAY_GOD(GOD_ERU) { s32b chance = p_ptr->grace; if (chance > 50000) chance = 50000; chance -= rlev * 300; if ((randint(100000) < chance) && (r_ptr->flags3 & (RF3_EVIL))) { /* Remember the Evil-ness */ r_ptr->r_flags3 |= (RF3_EVIL); /* Message */ msg_format("The hand of Eru Iluvatar stops %s blow.", m_name); /* Hack -- Next attack */ continue; } } /* Hack -- Apply "protection from evil" */ if ((p_ptr->protevil > 0) && (r_ptr->flags3 & (RF3_EVIL)) && (p_ptr->lev >= rlev) && ((rand_int(100) + p_ptr->lev) > 50)) { /* Remember the Evil-ness */ if (m_ptr->ml) { r_ptr->r_flags3 |= (RF3_EVIL); } /* Message */ msg_format("%^s is repelled.", m_name); /* Hack -- Next attack */ continue; } /* Hack -- Apply "protection from good" */ if ((p_ptr->protgood > 0) && (r_ptr->flags3 & (RF3_GOOD)) && (p_ptr->lev >= rlev) && ((rand_int(100) + p_ptr->lev) > 50)) { /* Remember the Good-ness */ if (m_ptr->ml) { r_ptr->r_flags3 |= (RF3_GOOD); } /* Message */ msg_format("%^s is repelled.", m_name); /* Hack -- Next attack */ continue; } /* Assume no cut or stun */ do_cut = do_stun = do_vampire = 0; /* Describe the attack method */ switch (method) { case RBM_HIT: { act = "hits you."; do_cut = do_stun = 1; touched = TRUE; sound(SOUND_HIT); break; } case RBM_TOUCH: { act = "touches you."; touched = TRUE; sound(SOUND_TOUCH); break; } case RBM_PUNCH: { act = "punches you."; touched = TRUE; do_stun = 1; sound(SOUND_HIT); break; } case RBM_KICK: { act = "kicks you."; touched = TRUE; do_stun = 1; sound(SOUND_HIT); break; } case RBM_CLAW: { act = "claws you."; touched = TRUE; do_cut = 1; sound(SOUND_CLAW); break; } case RBM_BITE: { act = "bites you."; do_cut = 1; if (magik(5) && iequals(r_ptr->name, "vampire")) do_vampire = TRUE; touched = TRUE; sound(SOUND_BITE); break; } case RBM_STING: { act = "stings you."; touched = TRUE; sound(SOUND_STING); break; } case RBM_XXX1: { act = "XXX1's you."; break; } case RBM_BUTT: { act = "butts you."; do_stun = 1; touched = TRUE; sound(SOUND_HIT); break; } case RBM_CRUSH: { act = "crushes you."; do_stun = 1; touched = TRUE; sound(SOUND_CRUSH); break; } case RBM_ENGULF: { act = "engulfs you."; touched = TRUE; sound(SOUND_CRUSH); break; } case RBM_CHARGE: { act = "charges you."; touched = TRUE; sound(SOUND_BUY); /* Note! This is "charges", not "charges at". */ break; } case RBM_CRAWL: { act = "crawls on you."; touched = TRUE; sound(SOUND_SLIME); break; } case RBM_DROOL: { act = "drools on you."; sound(SOUND_SLIME); break; } case RBM_SPIT: { act = "spits on you."; sound(SOUND_SLIME); break; } case RBM_EXPLODE: { act = "explodes."; explode = TRUE; break; } case RBM_GAZE: { act = "gazes at you."; break; } case RBM_WAIL: { act = "wails at you."; sound(SOUND_WAIL); break; } case RBM_SPORE: { act = "releases spores at you."; sound(SOUND_SLIME); break; } case RBM_XXX4: { act = "projects XXX4's at you."; break; } case RBM_BEG: { act = "begs you for money."; sound(SOUND_MOAN); break; } case RBM_INSULT: { act = desc_insult[rand_int(8)]; sound(SOUND_MOAN); break; } case RBM_MOAN: { if (strstr(r_ptr->name, "Mathilde, the Science Student")) act = desc_moan[rand_int(3) + 4]; else act = desc_moan[rand_int(4)]; sound(SOUND_MOAN); break; } case RBM_SHOW: { if (randint(3) == 1) act = "sings 'We are a happy family.'"; else act = "sings 'I love you, you love me.'"; sound(SOUND_SHOW); break; } } /* Message */ if (act) msg_format("%^s %s", m_name, act); /* The undead can give the player the Black Breath with * a successful blow. Uniques have a better chance. -LM- * Nazgul have a 25% chance */ if (r_ptr->flags7 & RF7_NAZGUL) { black_breath_attack(4); } else if ((m_ptr->level >= 35) && (r_ptr->flags3 & (RF3_UNDEAD)) && (r_ptr->flags1 & (RF1_UNIQUE))) { black_breath_attack(300 - m_ptr->level); } else if ((m_ptr->level >= 40) && (r_ptr->flags3 & (RF3_UNDEAD))) { black_breath_attack(450 - m_ptr->level); } /* Hack -- assume all attacks are obvious */ obvious = TRUE; /* Roll out the damage */ damage = damroll(d_dice, d_side); /* Sometime reduce the damage */ damage /= divis; /* Apply appropriate damage */ switch (effect) { case 0: { /* Hack -- Assume obvious */ obvious = TRUE; /* Hack -- No damage */ damage = 0; break; } case RBE_HURT: { /* Obvious */ obvious = TRUE; /* Hack -- Player armor reduces total damage */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ take_hit(damage, ddesc); break; } case RBE_ABOMINATION: { /* Obvious */ obvious = TRUE; /* Morph, but let mimicry skill have a chance to stop this */ if (magik(60 - get_skill(SKILL_MIMICRY))) { /* Message */ cmsg_print(TERM_VIOLET, "You feel the dark powers twisting your body!"); set_mimic(damage, resolve_mimic_name("Abomination"), 50); } else { /* Message */ cmsg_print(TERM_VIOLET, "You feel the dark powers trying to twisting your body, but they fail."); } break; } case RBE_SANITY: { obvious = TRUE; take_sanity_hit(damage, ddesc); break; } case RBE_POISON: { /* Take some damage */ take_hit(damage, ddesc); /* Take "poison" effect */ if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) { if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5)) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_POIS); break; } case RBE_UN_BONUS: { /* Take some damage */ take_hit(damage, ddesc); /* Allow complete resist */ if (!p_ptr->resist_disen) { /* Apply disenchantment */ if (apply_disenchant(0)) obvious = TRUE; } /* Learn about the player */ update_smart_learn(m_idx, DRS_DISEN); break; } case RBE_UN_POWER: { /* Take some damage */ take_hit(damage, ddesc); /* Find an item */ for (k = 0; k < 10; k++) { /* Pick an item */ i = rand_int(INVEN_PACK); /* Obtain the item */ o_ptr = &p_ptr->inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs Hack -- don't let artifacts get drained */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) && (o_ptr->pval) && !artifact_p(o_ptr)) { /* Message */ msg_print("Energy drains from your pack!"); /* Obvious */ obvious = TRUE; /* Heal */ j = rlev; m_ptr->hp += j * o_ptr->pval * o_ptr->number; if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp; /* Redraw (later) if needed */ if (health_who == m_idx) p_ptr->redraw |= (PR_FRAME); /* Uncharge */ o_ptr->pval = 0; /* Combine / Reorder the pack */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Window stuff */ p_ptr->window |= (PW_INVEN); /* Done */ break; } } break; } case RBE_EAT_GOLD: { /* Take some damage */ take_hit(damage, ddesc); /* Obvious */ obvious = TRUE; /* Saving throw (unless paralyzed) based on dex and level */ if (!p_ptr->paralyzed && (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] + p_ptr->lev))) { /* Saving throw message */ msg_print("You quickly protect your money pouch!"); /* Occasional blink anyway */ if (rand_int(3)) blinked = TRUE; } /* Eat gold */ else { gold = (p_ptr->au / 10) + randint(25); if (gold < 2) gold = 2; if (gold > 5000) gold = (p_ptr->au / 20) + randint(3000); if (gold > p_ptr->au) gold = p_ptr->au; p_ptr->au -= gold; if (gold <= 0) { msg_print("Nothing was stolen."); } else if (p_ptr->au) { msg_print("Your purse feels lighter."); msg_format("%ld coins were stolen!", (long)gold); } else { msg_print("Your purse feels lighter."); msg_print("All of your coins were stolen!"); } while (gold > 0) { object_type forge, *j_ptr = &forge; /* Wipe the object */ object_wipe(j_ptr); /* Prepare a gold object */ object_prep(j_ptr, lookup_kind(TV_GOLD, 9)); /* Determine how much the treasure is "worth" */ j_ptr->pval = (gold >= 15000) ? 15000 : gold; monster_carry(m_ptr, m_idx, j_ptr); gold -= 15000; } /* Redraw gold */ p_ptr->redraw |= (PR_FRAME); /* Window stuff */ p_ptr->window |= (PW_PLAYER); /* Blink away */ blinked = TRUE; } break; } case RBE_EAT_ITEM: { /* Take some damage */ take_hit(damage, ddesc); /* Saving throw (unless paralyzed) based on dex and level */ if (!p_ptr->paralyzed && (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] + p_ptr->lev))) { /* Saving throw message */ msg_print("You grab hold of your backpack!"); /* Occasional "blink" anyway */ blinked = TRUE; /* Obvious */ obvious = TRUE; /* Done */ break; } /* Find an item */ for (k = 0; k < 10; k++) { /* Pick an item */ i = rand_int(INVEN_PACK); /* Obtain the item */ o_ptr = &p_ptr->inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Skip artifacts */ if (artifact_p(o_ptr) || o_ptr->art_name) continue; /* Get a description */ object_desc(o_name, o_ptr, FALSE, 3); /* Message */ msg_format("%sour %s (%c) was stolen!", ((o_ptr->number > 1) ? "One of y" : "Y"), o_name, index_to_label(i)); /* Copy into inventory of monster */ { s16b o_idx; /* Make an object */ o_idx = o_pop(); /* Success */ if (o_idx) { object_type *j_ptr; /* Get new object */ j_ptr = &o_list[o_idx]; /* Copy object */ object_copy(j_ptr, o_ptr); /* Modify number */ j_ptr->number = 1; /* Hack -- If a wand, allocate total * maximum timeouts or charges between those * stolen and those missed. -LM- */ if (o_ptr->tval == TV_WAND) { j_ptr->pval = o_ptr->pval / o_ptr->number; o_ptr->pval -= j_ptr->pval; } /* Forget mark */ j_ptr->marked = FALSE; /* Memorize monster */ j_ptr->held_m_idx = m_idx; /* Build stack */ j_ptr->next_o_idx = m_ptr->hold_o_idx; /* Build stack */ m_ptr->hold_o_idx = o_idx; } } /* Steal the items */ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE); /* Obvious */ obvious = TRUE; /* Blink away */ blinked = TRUE; /* Done */ break; } break; } case RBE_EAT_FOOD: { /* Take some damage */ take_hit(damage, ddesc); /* Steal some food */ for (k = 0; k < 10; k++) { /* Pick an item from the pack */ i = rand_int(INVEN_PACK); /* Get the item */ o_ptr = &p_ptr->inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Skip non-food objects */ if (o_ptr->tval != TV_FOOD) continue; /* Get a description */ object_desc(o_name, o_ptr, FALSE, 0); /* Message */ msg_format("%sour %s (%c) was eaten!", ((o_ptr->number > 1) ? "One of y" : "Y"), o_name, index_to_label(i)); /* Steal the items */ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE); /* Obvious */ obvious = TRUE; /* Done */ break; } break; } case RBE_EAT_LITE: { /* Take some damage */ take_hit(damage, ddesc); /* Access the lite */ o_ptr = &p_ptr->inventory[INVEN_LITE]; /* Drain fuel */ if ((o_ptr->pval > 0) && (!artifact_p(o_ptr))) { /* Reduce fuel */ o_ptr->pval -= (250 + randint(250)); if (o_ptr->pval < 1) o_ptr->pval = 1; /* Notice */ if (!p_ptr->blind) { msg_print("Your light dims."); obvious = TRUE; } /* Window stuff */ p_ptr->window |= (PW_EQUIP); } break; } case RBE_ACID: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered in acid!"); /* Special damage */ acid_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_ACID); break; } case RBE_ELEC: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are struck by electricity!"); /* Special damage */ elec_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_ELEC); break; } case RBE_FIRE: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are enveloped in flames!"); /* Special damage */ fire_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_FIRE); break; } case RBE_COLD: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered with frost!"); /* Special damage */ cold_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_COLD); break; } case RBE_BLIND: { /* Take damage */ take_hit(damage, ddesc); /* Increase "blind" */ if (!p_ptr->resist_blind) { if (set_blind(p_ptr->blind + 10 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_BLIND); break; } case RBE_CONFUSE: { /* Take damage */ take_hit(damage, ddesc); /* Increase "confused" */ if (!p_ptr->resist_conf) { if (set_confused(p_ptr->confused + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_CONF); break; } case RBE_TERRIFY: { /* Take damage */ take_hit(damage, ddesc); /* Increase "afraid" */ if (p_ptr->resist_fear) { msg_print("You stand your ground!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You stand your ground!"); obvious = TRUE; } else { if (set_afraid(p_ptr->afraid + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_FEAR); break; } case RBE_PARALYZE: { /* Hack -- Prevent perma-paralysis via damage */ if (p_ptr->paralyzed && (damage < 1)) damage = 1; /* Take damage */ take_hit(damage, ddesc); /* Increase "paralyzed" */ if (p_ptr->free_act) { msg_print("You are unaffected!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You resist the effects!"); obvious = TRUE; } else { if (set_paralyzed(3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_FREE); break; } case RBE_LOSE_STR: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_INT: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_WIS: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_DEX: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_CON: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_CHR: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_LOSE_ALL: { /* Damage (physical) */ take_hit(damage, ddesc); /* Damage (stats) */ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE; if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE; break; } case RBE_SHATTER: { /* Obvious */ obvious = TRUE; /* Hack -- Reduce damage based on the player armor class */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ take_hit(damage, ddesc); /* Radius 8 earthquake centered at the monster */ if (damage > 23) { /* Prevent destruction of quest levels and town */ if (!is_quest(dun_level) && dun_level) earthquake(m_ptr->fy, m_ptr->fx, 8); } break; } case RBE_EXP_10: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 95)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(10, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_20: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 90)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_40: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 75)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_80: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 50)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_DISEASE: { /* Take some damage */ take_hit(damage, ddesc); /* Take "poison" effect */ if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) { if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5)) { obvious = TRUE; } } /* Damage CON (10% chance)*/ if (randint(100) < 11) { /* 1% chance for perm. damage */ bool_ perm = (randint(10) == 1); if (dec_stat(A_CON, randint(10), perm)) obvious = TRUE; } break; } case RBE_HALLU: { /* Take damage */ take_hit(damage, ddesc); /* Increase "image" */ if (!p_ptr->resist_chaos) { if (set_image(p_ptr->image + 3 + randint(rlev / 2))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_CHAOS); break; } case RBE_TIME: { switch (randint(10)) { case 1: case 2: case 3: case 4: case 5: { msg_print("You feel life has clocked back."); lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); break; } case 6: case 7: case 8: case 9: { int stat = rand_int(6); switch (stat) { case A_STR: act = "strong"; break; case A_INT: act = "bright"; break; case A_WIS: act = "wise"; break; case A_DEX: act = "agile"; break; case A_CON: act = "hardy"; break; case A_CHR: act = "beautiful"; break; } msg_format("You're not as %s as you used to be...", act); p_ptr->stat_cur[stat] = (p_ptr->stat_cur[stat] * 3) / 4; if (p_ptr->stat_cur[stat] < 3) p_ptr->stat_cur[stat] = 3; p_ptr->update |= (PU_BONUS); break; } case 10: { msg_print("You're not as powerful as you used to be..."); for (k = 0; k < 6; k++) { p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4; if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3; } p_ptr->update |= (PU_BONUS); break; } } take_hit(damage, ddesc); break; } case RBE_PARASITE: { /* Obvious */ obvious = TRUE; if (!p_ptr->parasite) set_parasite(damage, m_ptr->r_idx); break; } } /* Hack -- only one of cut or stun */ if (do_cut && do_stun) { /* Cancel cut */ if (rand_int(100) < 50) { do_cut = 0; } /* Cancel stun */ else { do_stun = 0; } } /* Handle cut */ if (do_cut) { int k = 0; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(5) + 5; break; case 3: k = randint(20) + 20; break; case 4: k = randint(50) + 50; break; case 5: k = randint(100) + 100; break; case 6: k = 300; break; default: k = 500; break; } /* Apply the cut */ if (k) (void)set_cut(p_ptr->cut + k); } /* Handle stun */ if (do_stun) { int k = 0; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(10) + 10; break; case 3: k = randint(20) + 20; break; case 4: k = randint(30) + 30; break; case 5: k = randint(40) + 40; break; case 6: k = 100; break; default: k = 200; break; } /* Apply the stun */ if (k) (void)set_stun(p_ptr->stun + k); } /* Do vampiric thingies */ if (do_vampire) { /* Change to resist(but never total protection) */ /* if (magik(3) || (magik(m_ptr->level - (p_ptr->lev / 2)))) gain_corruption("Vampire");*/ } if (explode) { sound(SOUND_EXPLODE); if (mon_take_hit(m_idx, m_ptr->hp + 1, &fear, NULL)) { blinked = FALSE; alive = FALSE; } } if (touched) { if (p_ptr->sh_fire && alive) { if (!(r_ptr->flags3 & RF3_IM_FIRE)) { msg_format("%^s is suddenly very hot!", m_name); if (mon_take_hit(m_idx, damroll(2, 6), &fear, " turns into a pile of ash.")) { blinked = FALSE; alive = FALSE; } } else { if (m_ptr->ml) r_ptr->r_flags3 |= RF3_IM_FIRE; } } if (p_ptr->sh_elec && alive) { if (!(r_ptr->flags3 & RF3_IM_ELEC)) { msg_format("%^s gets zapped!", m_name); if (mon_take_hit(m_idx, damroll(2, 6), &fear, " turns into a pile of cinder.")) { blinked = FALSE; alive = FALSE; } } else { if (m_ptr->ml) r_ptr->r_flags3 |= RF3_IM_ELEC; } } if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_COUNTER) && alive) { msg_format("%^s gets bashed by your mystic shield!", m_name); if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear, " is bashed by your mystic shield.")) { blinked = FALSE; alive = FALSE; } } if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_FIRE) && alive) { if (!(r_ptr->flags3 & RF3_IM_FIRE)) { msg_format("%^s gets burned by your fiery shield!", m_name); if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear, " is burned by your fiery shield.")) { blinked = FALSE; alive = FALSE; } } else { if (m_ptr->ml) r_ptr->r_flags3 |= RF3_IM_FIRE; } } if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_GREAT_FIRE) && alive) { msg_format("%^s gets burned by your fiery shield!", m_name); if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear, " is burned by your fiery shield.")) { blinked = FALSE; alive = FALSE; } } if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_FEAR) && alive) { int tmp; if ((!(r_ptr->flags1 & RF1_UNIQUE)) && (damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2) - m_ptr->level > 0)) { msg_format("%^s gets scared away!", m_name); /* Increase fear */ tmp = m_ptr->monfear + p_ptr->shield_power_opt; fear = TRUE; /* Set fear */ m_ptr->monfear = (tmp < 200) ? tmp : 200; } } touched = FALSE; } } /* Monster missed player */ else { /* Analyze failed attacks */ switch (method) { case RBM_HIT: case RBM_TOUCH: case RBM_PUNCH: case RBM_KICK: case RBM_CLAW: case RBM_BITE: case RBM_STING: case RBM_XXX1: case RBM_BUTT: case RBM_CRUSH: case RBM_ENGULF: case RBM_CHARGE: /* Visible monsters */ if (m_ptr->ml) { /* Disturbing */ disturb(1); /* Message */ msg_format("%^s misses you.", m_name); } break; } } /* Analyze "visible" monsters only */ if (visible) { /* Count "obvious" attacks (and ones that cause damage) */ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10)) { /* Count attacks of this type */ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR) { r_ptr->r_blows[ap_cnt]++; } } } } /* Blink away */ if (blinked) { msg_print("The thief flees laughing!"); teleport_away(m_idx, MAX_SIGHT * 2 + 5); } /* Always notice cause of death */ if (death && (r_ptr->r_deaths < MAX_SHORT)) { r_ptr->r_deaths++; } if (m_ptr->ml && fear) { sound (SOUND_FLEE); msg_format("%^s flees in terror!", m_name); } /* Assume we attacked */ return (TRUE); }