/* * Attack the player via physical attacks. */ bool make_attack_normal(int m_idx) { monster_type *m_ptr = &mon_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; int ap_cnt; int i, k, tmp, ac, rlev; int do_cut, do_stun; s32b gold; object_type *o_ptr; char o_name[80]; char m_name[80]; char ddesc[80]; bool blinked; /* 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); /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Get the "died from" information (i.e. "a kobold") */ monster_desc(ddesc, sizeof(ddesc), m_ptr, 0x88); /* Assume no blink */ blinked = FALSE; /* Scan through all blows */ for (ap_cnt = 0; ap_cnt < MONSTER_BLOW_MAX; 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; /* 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_HALLU: power = 10; break; } /* Monster hits player */ if (!effect || check_hit(power, rlev)) { /* Always disturbing */ disturb(1, 0); /* 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) { l_ptr->flags3 |= (RF3_EVIL); } /* Message */ msg_format("%^s is repelled.", m_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; break; } case RBM_TOUCH: { act = "touches you."; break; } case RBM_PUNCH: { act = "punches you."; do_stun = 1; break; } case RBM_KICK: { act = "kicks you."; do_stun = 1; break; } case RBM_CLAW: { act = "claws you."; do_cut = 1; break; } case RBM_BITE: { act = "bites you."; do_cut = 1; break; } case RBM_STING: { act = "stings you."; break; } case RBM_XXX1: { act = "XXX1's you."; break; } case RBM_BUTT: { act = "butts you."; do_stun = 1; break; } case RBM_CRUSH: { act = "crushes you."; do_stun = 1; break; } case RBM_ENGULF: { act = "engulfs you."; break; } case RBM_XXX2: { act = "XXX2's you."; break; } case RBM_CRAWL: { act = "crawls on you."; break; } case RBM_DROOL: { act = "drools on you."; break; } case RBM_SPIT: { act = "spits on you."; break; } case RBM_XXX3: { act = "XXX3's on you."; break; } case RBM_GAZE: { act = "gazes at you."; break; } case RBM_WAIL: { act = "wails at you."; break; } case RBM_SPORE: { act = "releases spores at you."; break; } case RBM_XXX4: { act = "projects XXX4's at you."; break; } case RBM_BEG: { act = "begs you for money."; break; } case RBM_INSULT: { act = desc_insult[rand_int(MAX_DESC_INSULT)]; break; } case RBM_MOAN: { act = desc_moan[rand_int(MAX_DESC_MOAN)]; break; } case RBM_XXX5: { act = "XXX5's you."; break; } } /* Message */ if (act) msg_format("%^s %s", m_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 */ take_hit(damage, ddesc); break; } case RBE_POISON: { /* Take 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_RES_POIS); break; } case RBE_UN_BONUS: { /* Take 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_RES_DISEN); break; } case RBE_UN_POWER: { /* Take 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 = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) && (o_ptr->pval > 0)) { /* Calculate healed hitpoints */ int heal = rlev * o_ptr->pval * o_ptr->number; /* Don't heal more than max hp */ heal = MIN(heal, m_ptr->maxhp - m_ptr->hp); /* Message */ msg_print("Energy drains from your pack!"); /* Obvious */ obvious = TRUE; /* Heal */ m_ptr->hp += heal; /* Redraw (later) if needed */ if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); /* 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 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!"); } /* Redraw gold */ p_ptr->redraw |= (PR_GOLD); /* Window stuff */ p_ptr->window |= (PW_PLAYER_0 | PW_PLAYER_1); /* Blink away */ blinked = TRUE; } break; } case RBE_EAT_ITEM: { /* Take 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++) { object_type *i_ptr; object_type object_type_body; /* Pick an item */ i = rand_int(INVEN_PACK); /* Obtain the item */ o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Skip artifacts */ if (artifact_p(o_ptr)) continue; /* Get a description */ object_desc(o_name, sizeof(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)); /* Get local object */ i_ptr = &object_type_body; /* Obtain local object */ object_copy(i_ptr, o_ptr); /* Modify number */ i_ptr->number = 1; /* Carry the object */ (void)monster_carry(m_idx, i_ptr); /* Steal the items */ inven_item_increase(i, -1); inven_item_optimize(i); /* Obvious */ obvious = TRUE; /* Blink away */ blinked = TRUE; /* Done */ break; } break; } case RBE_EAT_FOOD: { /* Take 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 = &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, sizeof(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 */ inven_item_increase(i, -1); inven_item_optimize(i); /* Obvious */ obvious = TRUE; /* Done */ break; } break; } case RBE_EAT_LITE: { /* Take damage */ take_hit(damage, ddesc); /* Get the lite */ o_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_RES_ACID); break; } case RBE_ELEC: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are struck by electricity!"); /* Take damage (special) */ elec_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_ELEC); break; } case RBE_FIRE: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are enveloped in flames!"); /* Take damage (special) */ fire_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_FIRE); break; } case RBE_COLD: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered with frost!"); /* Take damage (special) */ cold_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_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_RES_BLIND); break; } case RBE_CONFUSE: { /* Take damage */ take_hit(damage, ddesc); /* Increase "confused" */ if (!p_ptr->resist_confu) { if (set_confused(p_ptr->confused + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_CONFU); 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_RES_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(p_ptr->paralyzed + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_FREE); break; } case RBE_LOSE_STR: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_STR)) obvious = TRUE; break; } case RBE_LOSE_INT: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_INT)) obvious = TRUE; break; } case RBE_LOSE_WIS: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_WIS)) obvious = TRUE; break; } case RBE_LOSE_DEX: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_DEX)) obvious = TRUE; break; } case RBE_LOSE_CON: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CON)) obvious = TRUE; break; } case RBE_LOSE_CHR: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CHR)) obvious = TRUE; break; } case RBE_LOSE_ALL: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stats) */ if (do_dec_stat(A_STR)) obvious = TRUE; if (do_dec_stat(A_DEX)) obvious = TRUE; if (do_dec_stat(A_CON)) obvious = TRUE; if (do_dec_stat(A_INT)) obvious = TRUE; if (do_dec_stat(A_WIS)) obvious = TRUE; if (do_dec_stat(A_CHR)) 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) 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_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_RES_CHAOS); 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; /* 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; /* 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); } } /* 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_XXX2: /* Visible monsters */ if (m_ptr->ml) { /* Disturbing */ disturb(1, 0); /* 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 || (l_ptr->blows[ap_cnt] > 10)) { /* Count attacks of this type */ if (l_ptr->blows[ap_cnt] < MAX_UCHAR) { l_ptr->blows[ap_cnt]++; } } } } /* Blink away */ if (blinked) { msg_print("There is a puff of smoke!"); teleport_away(m_idx, MAX_SIGHT * 2 + 5); } /* Always notice cause of death */ if (p_ptr->is_dead && (l_ptr->deaths < MAX_SHORT)) { l_ptr->deaths++; } /* Assume we attacked */ return (TRUE); }
/** * Handle player hitting a real trap. Rewritten in Oangband to allow a * greater variety of traps, with effects controlled by dungeon level. * To allow a trap to choose one of a variety of effects consistantly, * the quick RNG is often used, and xy coordinates input as a seed value. */ extern void hit_trap(int y, int x) { int i, j, k, num; int dam = 0; int nastyness, selection; feature_type *f_ptr = &f_info[cave_feat[y][x]]; cptr name = f_ptr->name; /* Use the "simple" RNG to insure that traps are consistant. */ Rand_quick = TRUE; /* Use the coordinates of the trap to seed the RNG. */ Rand_value = y * x; /* Disturb the player */ disturb(0, 0); /* Analyze XXX XXX XXX */ switch (cave_feat[y][x]) { /* trap door. */ case FEAT_TRAP_HEAD + 0x00: { Rand_quick = FALSE; /* Paranoia -NRM- */ if (((stage_map[p_ptr->stage][STAGE_TYPE] == CAVE) || (stage_map[p_ptr->stage][STAGE_TYPE] == VALLEY)) && (!stage_map[p_ptr->stage][DOWN])) { cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); msg_print("The trap fails!"); break; } msg_print("You fall through a trap door!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently down to the next level."); } else { dam = damroll(2, 8); take_hit(dam, name); } /* Remember where we came from */ p_ptr->last_stage = p_ptr->stage; if (!stage_map[p_ptr->stage][DOWN]) { /* Set the ways forward and back */ stage_map[255][UP] = p_ptr->stage; stage_map[p_ptr->stage][DOWN] = 255; stage_map[255][DEPTH] = p_ptr->depth + 1; } /* New stage */ p_ptr->stage = stage_map[p_ptr->stage][DOWN]; /* New depth */ p_ptr->depth = stage_map[p_ptr->stage][DEPTH]; /* Leaving */ p_ptr->leaving = TRUE; Rand_quick = TRUE; break; } /* pits. */ case FEAT_TRAP_HEAD + 0x01: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(20) == 1) nastyness += 20; else if (randint1(5) == 1) nastyness += 10; /* Player is now in pit. */ monster_swap(p_ptr->py, p_ptr->px, y, x); /* Center on player. */ y = p_ptr->py; x = p_ptr->px; /* pit of daggers. */ if ((nastyness > 80) && (randint1(3) != 3)) { msg_print("You fall into a pit of daggers!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid setting off the daggers."); } else { /* a trap of morgul. */ if (randint1(6) == 1) { Rand_quick = FALSE; msg_print ("A single coldly gleaming dagger pierces you deeply!"); msg_print ("You feel a deadly chill slowly withering your soul."); /* activate the Black Breath. */ p_ptr->black_breath = TRUE; /* lots of damage. */ dam = damroll(20, 15); /* undead may be attracted. */ if (randint1(2) == 1) { msg_print ("Undead suddenly appear and call you to them!"); k = randint1(3) + 2; for (i = 0; i < k; i++) { summon_specific(y, x, FALSE, p_ptr->depth, SUMMON_UNDEAD); } } /* morgul-traps are one-time only. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); Rand_quick = TRUE; } else { Rand_quick = FALSE; /* activate the ordinary daggers. */ msg_print("Daggers pierce you everywhere!"); k = randint1(10) + 5; for (i = 0; i < k; i++) { dam += damroll(3, 4); } Rand_quick = TRUE; } /* cut the player. */ (void) inc_timed(TMD_CUT, randint1(dam), TRUE); /* Take the damage. */ take_hit(dam, name); } } /* poisoned spiked pit. */ else if ((nastyness > 55) && (randint1(3) != 3)) { msg_print("You fall into a spiked pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid touching the spikes."); } else { Rand_quick = FALSE; /* Base damage */ dam = damroll(2, 6); /* Extra spike damage */ if (randint0(100) < 85) { bool was_poisoned; msg_print("You are impaled on poisonous spikes!"); dam = dam * (randint1(6) + 3); (void) inc_timed(TMD_CUT, randint1(dam), TRUE); was_poisoned = pois_hit(dam); if (!was_poisoned) msg_print("The poison does not affect you!"); } /* Take the damage */ take_hit(dam, name); Rand_quick = TRUE; } } /* spiked pit. */ else if ((nastyness > 30) && (randint1(3) != 3)) { msg_print("You fall into a spiked pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid touching the spikes."); } else { Rand_quick = FALSE; /* Base damage */ dam = damroll(2, 6); /* Extra spike damage */ if (randint0(100) < 85) { msg_print("You are impaled!"); dam = dam * (2 + randint1(4)); (void) inc_timed(TMD_CUT, randint1(dam), TRUE); } /* Take the damage */ take_hit(dam, name); Rand_quick = TRUE; } } /* ordinary pit in all other cases. */ else { msg_print("You fall into a pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the bottom of the pit."); } else { Rand_quick = FALSE; dam = damroll(2, 6); take_hit(dam, name); Rand_quick = TRUE; } } break; } /* stat-reducing dart traps. */ case FEAT_TRAP_HEAD + 0x02: { /* decide if the dart hits. */ if (check_trap_hit(50 + p_ptr->depth)) { /* select a stat to drain. */ selection = randint0(6); Rand_quick = FALSE; msg_print("A small dart hits you!"); dam = damroll(1, 4); take_hit(dam, name); /* Determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); /* decide how much to drain the stat by. */ if ((nastyness > 50) && (randint1(3) == 1)) { num = randint1(4); } else num = 1; /* drain the stat. */ for (i = 0; i < num; i++) { (void) do_dec_stat(selection); } Rand_quick = TRUE; } else { msg_print("A small dart barely misses you."); } break; } /* discolored spots. */ case FEAT_TRAP_HEAD + 0x03: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(5) == 1) nastyness += 10; /* pick a elemental attack type. */ selection = randint1(4); /* electicity trap. */ if (selection == 1) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are struck by lightning!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You get zapped!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; elec_dam(dam, "an electricity trap"); Rand_quick = TRUE; } /* frost trap. */ if (selection == 2) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are lost within a blizzard!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are coated in frost!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; cold_dam(dam, "a frost trap"); Rand_quick = TRUE; } /* fire trap. */ if (selection == 3) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are enveloped in a column of fire!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are surrounded by flames!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; fire_dam(dam, "a fire trap"); Rand_quick = TRUE; } /* acid trap. */ if (selection == 4) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("A cauldron of acid is tipped over your head!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are splashed with acid!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; acid_dam(dam, "an acid trap"); Rand_quick = TRUE; } break; } /* gas traps. */ case FEAT_TRAP_HEAD + 0x04: { selection = randint1(4); /* blinding trap. */ if (selection == 1) { msg_print("You are surrounded by a black gas!"); if (!p_ptr->state.no_blind) { Rand_quick = FALSE; (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE); Rand_quick = TRUE; } } else notice_obj(OF_SEEING, 0); /* confusing trap. */ if (selection == 2) { msg_print ("You are surrounded by a gas of scintillating colors!"); if (!p_resist_good(P_RES_CONFU)) { Rand_quick = FALSE; (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); Rand_quick = TRUE; } else notice_other(IF_RES_CONFU, 0); } /* poisoning trap. */ if (selection == 3) { msg_print("You are surrounded by a pungent green gas!"); Rand_quick = FALSE; pois_hit(25); Rand_quick = TRUE; } /* sleeping trap. */ if (selection == 4) { msg_print("You are surrounded by a strange white mist!"); if (!p_ptr->state.free_act) { (void) inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE); } else notice_obj(OF_FREE_ACT, 0); } break; } /* summoning traps. */ case FEAT_TRAP_HEAD + 0x05: { sound(MSG_SUM_MONSTER); /* sometimes summon thieves. */ if ((p_ptr->depth > 8) && (randint1(5) == 1)) { msg_print("You have aroused a den of thieves!"); Rand_quick = FALSE; num = 2 + randint1(3); for (i = 0; i < num; i++) { (void) summon_specific(y, x, FALSE, p_ptr->depth, SUMMON_THIEF); } Rand_quick = TRUE; } /* sometimes summon a nasty unique. */ else if (randint1(8) == 1) { msg_print("You are enveloped in a cloud of smoke!"); Rand_quick = FALSE; (void) summon_specific(y, x, FALSE, p_ptr->depth + 5, SUMMON_UNIQUE); Rand_quick = TRUE; } /* otherwise, the ordinary summon monsters. */ else { msg_print("You are enveloped in a cloud of smoke!"); Rand_quick = FALSE; num = 2 + randint1(3); for (i = 0; i < num; i++) { (void) summon_specific(y, x, FALSE, p_ptr->depth, 0); } Rand_quick = TRUE; } /* these are all one-time traps. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); break; } /* dungeon alteration traps. */ case FEAT_TRAP_HEAD + 0x06: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(5) == 1) nastyness += 10; /* make room for alterations. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); /* Everything truely random from here on. */ Rand_quick = FALSE; /* dungeon destruction trap. */ if ((nastyness > 60) && (randint1(12) == 1)) { msg_print ("A ear-splitting howl shatters your mind as the dungeon is smashed by hammer blows!"); (void) destroy_level(FALSE); /* the player is hard-hit. */ (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE); (void) inc_timed(TMD_STUN, randint1(50) + 50, TRUE); dam = damroll(15, 15); take_hit(dam, name); } /* earthquake trap. */ else if ((nastyness > 20) && (randint1(4) == 1)) { msg_print("A tremor shakes the earth around you"); earthquake(y, x, 10, FALSE); } /* falling rock trap. */ else if ((nastyness > 4) && (randint1(2) == 1)) { msg_print("A rock falls on your head."); dam = damroll(2, 10); take_hit(dam, name); (void) inc_timed(TMD_STUN, randint1(10) + 10, TRUE); } /* a few pebbles. */ else { msg_print("A bunch of pebbles rain down on you."); dam = damroll(1, 8); take_hit(dam, name); } Rand_quick = TRUE; break; } /* various char and equipment-alteration traps, lumped together to * avoid any one effect being too common (some of them can be rather * nasty). */ case FEAT_TRAP_HEAD + 0x07: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint0(100); /* these are all one-time traps. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); /* Everything truely random from here on. */ Rand_quick = FALSE; /* trap of drain wands. */ if (nastyness < 15) { /* Hold the object information. */ object_type *o_ptr; /* Find an item */ for (i = 0; i < 20; i++) { /* Pick an item */ i = randint0(INVEN_PACK - p_ptr->pack_size_reduce); /* Obtain the item */ o_ptr = &p_ptr->inventory[i]; /* use "num" to decide if a item can be uncharged. By * default, assume it can't. */ num = 0; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs/rods */ if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_ROD)) { /* case of charged wands/staffs. */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) && (o_ptr->pval)) num = 1; /* case of charged rods. */ if ((o_ptr->tval == TV_ROD) && (o_ptr->timeout < randcalc(o_ptr->time, 0, MINIMISE))) num = 1; if (num == 1) { /* Message */ msg_print("Energy drains from your pack!"); /* Uncharge */ if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) o_ptr->pval = 0; if (o_ptr->tval == TV_ROD) o_ptr->timeout = randcalc(o_ptr->time, 0, RANDOMISE) * o_ptr->number * 2; /* Combine / Reorder the pack */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* not more than one inventory slot effected. */ break; } else continue; } } } /* trap of forgetting. */ else if (nastyness < 35) { if (check_save(100)) { msg_print("You hang on to your memories!"); } else if (lose_all_info()) { msg_print("Your memories fade away."); } } /* trap of alter reality. */ else if (nastyness < 50) { if (OPT(adult_ironman)) msg_print("Nothing happens."); else { msg_print("The world changes!"); /* Leaving */ p_ptr->leaving = TRUE; } } /* trap of remold player. */ else if (nastyness < 75) { int max1, cur1, max2, cur2, ii, jj; msg_print("You feel yourself being twisted by wild magic!"); if (check_save(100)) { msg_print("You resist the effects!"); } else { msg_print("Your body starts to scramble..."); /* Pick a pair of stats */ ii = randint0(6); for (jj = ii; jj == ii; jj = randint0(6)) /* loop */ ; max1 = p_ptr->stat_max[ii]; cur1 = p_ptr->stat_cur[ii]; max2 = p_ptr->stat_max[jj]; cur2 = p_ptr->stat_cur[jj]; p_ptr->stat_max[ii] = max2; p_ptr->stat_cur[ii] = cur2; p_ptr->stat_max[jj] = max1; p_ptr->stat_cur[jj] = cur1; p_ptr->update |= (PU_BONUS); } } /* time ball trap. */ else if (nastyness < 90) { msg_print("You feel time itself assault you!"); /* Target the player with a radius 0 ball attack. */ fire_meteor(0, GF_TIME, p_ptr->py, p_ptr->px, 75, 0, TRUE); } /* trap of bugs gone berserk. */ else { /* explain what the dickens is going on. */ msg_print("GRUESOME Gnawing Bugs leap out at you!"); if (!p_resist_good(P_RES_CONFU)) { (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); } else notice_other(IF_RES_CONFU, 0); if (!p_resist_good(P_RES_CHAOS)) { (void) inc_timed(TMD_IMAGE, randint1(40), TRUE); } else notice_other(IF_RES_CHAOS, 0); /* XXX (hard coded) summon 3-6 bugs. */ k = randint1(4) + 2; for (i = 0; i < k; ++i) { /* Look for a location */ for (j = 0; j < 20; ++j) { /* Pick a (scattered) distance. */ int d = (j / 10) + randint1(3); /* Pick a location */ scatter(&y, &x, y, x, d, 0); /* Require passable terrain */ if (!cave_passable_bold(y, x)) continue; /* Hack -- no summon on glyph of warding */ if (cave_feat[y][x] == FEAT_RUNE_PROTECT) continue; /* Okay */ break; } /* Attempt to place the awake bug */ place_monster_aux(y, x, 453, FALSE, TRUE); } /* herald the arrival of bugs. */ msg_print("AAAAAAAHHHH! THEY'RE EVERYWHERE!"); } Rand_quick = TRUE; break; } /* teleport trap */ case FEAT_TRAP_HEAD + 0x08: { if (stage_map[p_ptr->stage][STAGE_TYPE] >= CAVE) msg_print("You teleport across the dungeon."); else msg_print("You teleport across the wilderness."); Rand_quick = FALSE; teleport_player(250, FALSE); Rand_quick = TRUE; break; } /* murder holes. */ case FEAT_TRAP_HEAD + 0x09: { /* hold the object info. */ object_type *o_ptr; object_type object_type_body; /* hold the missile type and name. */ int sval = 0; int tval = 0; cptr missile_name = ""; /* Determine the missile type and base damage. */ if (randint1(3) == 1) { if (p_ptr->depth < 40) { missile_name = "shot"; dam = damroll(2, 3); tval = TV_SHOT; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker shot"; dam = damroll(3, 7); tval = TV_SHOT; sval = SV_AMMO_HEAVY; } } else if (randint1(2) == 1) { if (p_ptr->depth < 55) { missile_name = "arrow"; dam = damroll(2, 4); tval = TV_ARROW; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker arrow"; dam = damroll(3, 9); tval = TV_ARROW; sval = SV_AMMO_HEAVY; } } else { if (p_ptr->depth < 65) { missile_name = "bolt"; dam = damroll(2, 5); tval = TV_BOLT; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker bolt"; dam = damroll(3, 11); tval = TV_BOLT; sval = SV_AMMO_HEAVY; } } /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { msg_format("A %s hits you from above.", missile_name); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was well-aimed!"); dam *= 1 + randint1(2); } if (randint1(2) == 1) { msg_print("It gouges you!"); dam = 3 * dam / 2; /* cut the player. */ (void) inc_timed(TMD_CUT, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_format("A %s wizzes by your head.", missile_name); /* these will eventually run out of ammo. */ Rand_quick = FALSE; if (randint0(8) == 0) { cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); } Rand_quick = TRUE; /* Get local object */ o_ptr = &object_type_body; /* Make a missile, identify it, and drop it near the player. */ object_prep(o_ptr, lookup_kind(tval, sval), MINIMISE); object_aware(o_ptr); object_known(o_ptr); drop_near(o_ptr, -1, y, x, TRUE); break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0A: { /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { /* Take damage */ dam = damroll(3, 5); msg_print("A branch hits you from above."); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was heavy!"); dam = 3 * dam / 2; /* stun the player. */ (void) inc_timed(TMD_STUN, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_print("A falling branch just misses you."); /* No more */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_TREE); break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0B: { /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { /* Take damage */ dam = damroll(3, 5); msg_print("A branch hits you from above."); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was heavy!"); dam = 3 * dam / 2; /* stun the player. */ (void) inc_timed(TMD_STUN, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_print("A falling branch just misses you."); /* No more */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_TREE2); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0C: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0D: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0E: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0F: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } } /* Revert to usage of the complex RNG. */ Rand_quick = FALSE; }