static byte adj_energy(struct monster_race *race) { unsigned i = race->speed + (rsf_has(race->spell_flags,RSF_HASTE) ? 5 : 0); /* Fastest monster in the game is currently +30, but bounds check anyway */ return turn_energy(MIN(i, N_ELEMENTS(extract_energy) - 1)); }
/** * Test a spell bitflag for a type of spell. * Returns TRUE if any desired type is among the flagset * * \param f is the set of spell flags we're testing * \param type is the spell type(s) we're looking for */ bool test_spells(bitflag *f, enum mon_spell_type type) { const struct mon_spell *rs_ptr; for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) if (rsf_has(f, rs_ptr->index) && (rs_ptr->type & type)) return TRUE; return FALSE; }
/** * Set a spell bitflag to allow only a specific set of spell types. * * \param f is the set of spell flags we're pruning * \param type is the spell type(s) we're allowing */ void set_spells(bitflag *f, enum mon_spell_type type) { const struct mon_spell *rs_ptr; for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) if (rsf_has(f, rs_ptr->index) && !(rs_ptr->type & type)) rsf_off(f, rs_ptr->index); return; }
/** * Set a spell bitflag to ignore a specific set of spell types. * * \param f is the set of spell flags we're pruning * \param types is the spell type(s) we're ignoring */ void ignore_spells(bitflag *f, int types) { const struct mon_spell_info *info; for (info = mon_spell_types; info->index < RSF_MAX; info++) if (rsf_has(f, info->index) && (info->type & types)) rsf_off(f, info->index); return; }
/** * Test a spell bitflag for a type of spell. * Returns TRUE if any desired type is among the flagset * * \param f is the set of spell flags we're testing * \param types is the spell type(s) we're looking for */ bool test_spells(bitflag *f, int types) { const struct mon_spell_info *info; for (info = mon_spell_types; info->index < RSF_MAX; info++) if (rsf_has(f, info->index) && (info->type & types)) return TRUE; return FALSE; }
/** * Calculate a monster's maximum spell power. * * \param r_ptr is the monster we're studying * \param resist is the degree of resistance we're assuming to any * attack type (-1 = vulnerable ... 3 = immune) */ int best_spell_power(const monster_race *r_ptr, int resist) { const struct mon_spell *rs_ptr; const struct spell_effect *re_ptr; int dam = 0, best_dam = 0; /* Extract the monster level */ int rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) { if (rsf_has(r_ptr->spell_flags, rs_ptr->index)) { /* Get the maximum basic damage output of the spell (could be 0) */ dam = mon_spell_dam(rs_ptr->index, mon_hp(r_ptr, MAXIMISE), rlev, MAXIMISE); /* For all attack forms the player can save against, damage * is halved */ if (rs_ptr->save) dam /= 2; /* Adjust the real damage by the assumed resistance (if it is a * resistable type) */ if (rs_ptr->gf) dam = adjust_dam(p_ptr, rs_ptr->gf, dam, MAXIMISE, resist); /* Add the power ratings assigned to the various possible spell * effects (which is crucial for non-damaging spells) */ for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) { if ((re_ptr->method && (re_ptr->method == rs_ptr->index)) || (re_ptr->gf && (re_ptr->gf == rs_ptr->gf))) { /* First we adjust the real damage if necessary */ if (re_ptr->power.dice) dam = (dam * re_ptr->power.dice) / 100; /* Then we add any flat rating for this effect */ dam += re_ptr->power.base; /* Then we add any rlev-dependent rating */ if (re_ptr->power.m_bonus < 0) dam += re_ptr->power.sides / (rlev + 1); else if (re_ptr->power.m_bonus > 0) dam += (re_ptr->power.sides * rlev) / 100; } } /* Update the best_dam tracker */ if (dam > best_dam) best_dam = dam; } } return best_dam; }
/** * Calculate a monster's maximum spell power. * * \param race is the monster we're studying * \param resist is the degree of resistance we're assuming to any * attack type (-1 = vulnerable ... 3 = immune) */ int best_spell_power(const struct monster_race *race, int resist) { const struct mon_spell_info *info; int dam = 0, best_dam = 0; /* Extract the monster level */ int rlev = ((race->level >= 1) ? race->level : 1); for (info = mon_spell_types; info->index < RSF_MAX; info++) { if (rsf_has(race->spell_flags, info->index)) { /* Get the spell */ const struct monster_spell *spell = monster_spell_by_index(info->index); if (!spell) continue; /* Get the maximum basic damage output of the spell (could be 0) */ dam = mon_spell_dam(info->index, mon_hp(race, MAXIMISE), race, MAXIMISE); /* For all attack forms the player can save against, damage * is halved */ if (spell->save_message) dam /= 2; /* Adjust the real damage by the assumed resistance (if it is a * resistable type) */ if (monster_spell_is_projectable(info->index)) dam = adjust_dam(player, spell->effect->params[0], dam, MAXIMISE, 1); /* Add the power rating (crucial for non-damaging spells) */ /* First we adjust the real damage if necessary */ if (spell->power.dice) dam = (dam * spell->power.dice) / 100; /* Then we add any flat rating for this effect */ dam += spell->power.base; /* Then we add any rlev-dependent rating */ if (spell->power.m_bonus == 1) dam += (spell->power.sides * rlev) / 100; else if (spell->power.m_bonus == 2) dam += spell->power.sides / (rlev + 1); } /* Update the best_dam tracker */ if (dam > best_dam) best_dam = dam; } return best_dam; }
/** * Have a monster choose a spell to cast. * * Note that the monster's spell list has already had "useless" spells * (bolts that won't hit the player, summons without room, etc.) removed. * Perhaps that should be done by this function. * * Stupid monsters will just pick a spell randomly. Smart monsters * will choose more "intelligently". * * This function could be an efficiency bottleneck. */ static int choose_attack_spell(bitflag f[RSF_SIZE]) { int num = 0; byte spells[RSF_MAX]; int i; /* Extract all spells: "innate", "normal", "bizarre" */ for (i = FLAG_START, num = 0; i < RSF_MAX; i++) if (rsf_has(f, i)) spells[num++] = i; /* Paranoia */ if (num == 0) return 0; /* Pick at random */ return (spells[randint0(num)]); }
/** * Turn off spells with a side effect or a gf_type that is resisted by * something in flags, subject to intelligence and chance. * * \param spells is the set of spells we're pruning * \param flags is the set of object flags we're testing * \param pflags is the set of player flags we're testing * \param el is what we know about the monster's elemental resists * \param race is the monster type we're operating on */ void unset_spells(bitflag *spells, bitflag *flags, bitflag *pflags, struct element_info *el, const struct monster_race *race) { const struct mon_spell_info *info; bool smart = rf_has(race->flags, RF_SMART); for (info = mon_spell_types; info->index < RSF_MAX; info++) { const struct monster_spell *spell = monster_spell_by_index(info->index); const struct effect *effect; /* Ignore missing spells */ if (!spell) continue; if (!rsf_has(spells, info->index)) continue; /* Get the effect */ effect = spell->effect; /* First we test the elemental spells */ if (info->type & (RST_BOLT | RST_BALL | RST_BREATH)) { int element = effect->params[0]; int learn_chance = el[element].res_level * (smart ? 50 : 25); if (randint0(100) < learn_chance) rsf_off(spells, info->index); } else { /* Now others with resisted effects */ while (effect) { /* Timed effects */ if ((smart || !one_in_(3)) && (effect->index == EF_TIMED_INC) && of_has(flags, timed_protect_flag(effect->params[0]))) break; /* Mana drain */ if ((smart || one_in_(2)) && (effect->index == EF_DRAIN_MANA) && pf_has(pflags, PF_NO_MANA)) break; effect = effect->next; } if (effect) rsf_off(spells, info->index); } } }
static long eval_max_dam(struct monster_race *race, int ridx) { int rlev, i; int melee_dam = 0, atk_dam = 0, spell_dam = 0; int dam = 1; /* Extract the monster level, force 1 for town monsters */ rlev = ((race->level >= 1) ? race->level : 1); /* Assume single resist for the elemental attacks */ spell_dam = best_spell_power(race, 1); /* Hack - Apply over 10 rounds */ spell_dam *= 10; /* Scale for frequency and availability of mana / ammo */ if (spell_dam) { int freq = race->freq_spell; /* Hack -- always get 1 shot */ if (freq < 10) freq = 10; /* Adjust for frequency */ spell_dam = spell_dam * freq / 100; } /* Check attacks */ for (i = 0; i < z_info->mon_blows_max; i++) { int effect, method; random_value dice; if (!race->blow) break; /* Extract the attack infomation */ effect = race->blow[i].effect; method = race->blow[i].method; dice = race->blow[i].dice; /* Assume maximum damage */ atk_dam = eval_blow_effect(effect, dice, race->level); /* Factor for dangerous side effects */ if (monster_blow_method_stun(method)) { /* Stun definitely most dangerous*/ atk_dam *= 4; atk_dam /= 3; } else if (monster_blow_method_stun(method)) { /* Cut */ atk_dam *= 7; atk_dam /= 5; } /* Normal melee attack */ if (!rf_has(race->flags, RF_NEVER_BLOW)) { /* Keep a running total */ melee_dam += atk_dam; } } /* Apply damage over 10 rounds. We assume that the monster has to make * contact first. * Hack - speed has more impact on melee as has to stay in contact with * player. * Hack - this is except for pass wall and kill wall monsters which can * always get to the player. * Hack - use different values for huge monsters as they strike out to * range 2. */ if (flags_test(race->flags, RF_SIZE, RF_KILL_WALL, RF_PASS_WALL, FLAG_END)) melee_dam *= 10; else melee_dam = melee_dam * 3 + melee_dam * adj_energy(race) / 7; /* Scale based on attack accuracy. We make a massive number of * assumptions here and just use monster level. */ melee_dam = melee_dam * MIN(45 + rlev * 3, 95) / 100; /* Hack -- Monsters that multiply ignore the following reductions */ if (!rf_has(race->flags, RF_MULTIPLY)) { /*Reduce damamge potential for monsters that move randomly */ if (flags_test(race->flags, RF_SIZE, RF_RAND_25, RF_RAND_50, FLAG_END)) { int reduce = 100; if (rf_has(race->flags, RF_RAND_25)) reduce -= 25; if (rf_has(race->flags, RF_RAND_50)) reduce -= 50; /* Even moving randomly one in 8 times will hit the player */ reduce += (100 - reduce) / 8; /* Adjust the melee damage */ melee_dam = (melee_dam * reduce) / 100; } /* Monsters who can't move are much less of a combat threat */ if (rf_has(race->flags, RF_NEVER_MOVE)) { if (rsf_has(race->spell_flags, RSF_TELE_TO) || rsf_has(race->spell_flags, RSF_BLINK)) { /* Scale for frequency */ melee_dam = melee_dam / 5 + 4 * melee_dam * race->freq_spell / 500; /* Incorporate spell failure chance */ if (!rf_has(race->flags, RF_STUPID)) melee_dam = melee_dam / 5 + 4 * melee_dam * MIN(75 + (rlev + 3) / 4, 100) / 500; } else if (rf_has(race->flags, RF_INVISIBLE)) melee_dam /= 3; else melee_dam /= 5; } } /* But keep at a minimum */ if (melee_dam < 1) melee_dam = 1; /* Combine spell and melee damage */ dam = (spell_dam + melee_dam); highest_threat[ridx] = dam; final_spell_dam[ridx] = spell_dam; final_melee_dam[ridx] = melee_dam; /* Adjust for speed - monster at speed 120 will do double damage, monster * at speed 100 will do half, etc. Bonus for monsters who can haste self */ dam = (dam * adj_energy(race)) / 10; /* Adjust threat for speed -- multipliers are more threatening. */ if (rf_has(race->flags, RF_MULTIPLY)) highest_threat[ridx] = (highest_threat[ridx] * adj_energy(race)) / 5; /* Adjust threat for friends, this can be improved, but is probably good * enough for now. */ if (race->friends) highest_threat[ridx] *= 2; else if (race->friends_base) /* Friends base is weaker, because they are <= monster level */ highest_threat[ridx] = highest_threat[ridx] * 3 / 2; /* But keep at a minimum */ if (dam < 1) dam = 1; /* We're done */ return (dam); }
static long eval_hp_adjust(struct monster_race *race) { long hp; int resists = 1; int hide_bonus = 0; /* Get the monster base hitpoints */ hp = race->avg_hp; /* Never moves with no ranged attacks - high hit points count for less */ if (rf_has(race->flags, RF_NEVER_MOVE) && !(race->freq_innate || race->freq_spell)) { hp /= 2; if (hp < 1) hp = 1; } /* Just assume healers have more staying power */ if (rsf_has(race->spell_flags, RSF_HEAL)) hp = (hp * 6) / 5; /* Miscellaneous improvements */ if (rf_has(race->flags, RF_REGENERATE)) {hp *= 10; hp /= 9;} if (rf_has(race->flags, RF_PASS_WALL)) {hp *= 3; hp /= 2;} /* Calculate hide bonus */ if (rf_has(race->flags, RF_EMPTY_MIND)) hide_bonus += 2; else { if (rf_has(race->flags, RF_COLD_BLOOD)) hide_bonus += 1; if (rf_has(race->flags, RF_WEIRD_MIND)) hide_bonus += 1; } /* Invisibility */ if (rf_has(race->flags, RF_INVISIBLE)) hp = (hp * (race->level + hide_bonus + 1)) / MAX(1, race->level); /* Monsters that can teleport are a hassle, and can easily run away */ if (flags_test(race->spell_flags, RSF_SIZE, RSF_TPORT, RSF_TELE_AWAY, RSF_TELE_LEVEL, FLAG_END)) hp = (hp * 6) / 5; /* Monsters that multiply are tougher to kill */ if (rf_has(race->flags, RF_MULTIPLY)) hp *= 2; /* Monsters with resistances are harder to kill. * Therefore effective slays / brands against them are worth more. */ if (rf_has(race->flags, RF_IM_ACID)) resists += 2; if (rf_has(race->flags, RF_IM_FIRE)) resists += 2; if (rf_has(race->flags, RF_IM_COLD)) resists += 2; if (rf_has(race->flags, RF_IM_ELEC)) resists += 2; if (rf_has(race->flags, RF_IM_POIS)) resists += 2; /* Bonus for multiple basic resists and weapon resists */ if (resists >= 12) resists *= 6; else if (resists >= 10) resists *= 4; else if (resists >= 8) resists *= 3; else if (resists >= 6) resists *= 2; /* If quite resistant, reduce resists by defense holes */ if (resists >= 6) { if (rf_has(race->flags, RF_HURT_ROCK)) resists -= 1; if (rf_has(race->flags, RF_HURT_LIGHT)) resists -= 1; if (!rf_has(race->flags, RF_NO_SLEEP)) resists -= 3; if (!rf_has(race->flags, RF_NO_FEAR)) resists -= 2; if (!rf_has(race->flags, RF_NO_CONF)) resists -= 2; if (!rf_has(race->flags, RF_NO_STUN)) resists -= 1; if (resists < 5) resists = 5; } /* If quite resistant, bonus for high resists */ if (resists >= 3) { if (rf_has(race->flags, RF_IM_WATER)) resists += 1; if (rf_has(race->flags, RF_IM_NETHER)) resists += 1; if (rf_has(race->flags, RF_IM_NEXUS)) resists += 1; if (rf_has(race->flags, RF_IM_DISEN)) resists += 1; } /* Scale resists */ resists = resists * 25; /* Monster resistances */ if (resists < (race->ac + resists) / 3) hp += (hp * resists) / (150 + race->level); else hp += (hp * (race->ac + resists) / 3) / (150 + race->level); /* Boundary control */ if (hp < 1) hp = 1; return (hp); }
/** * Use various selection criteria (set elsewhere) to restrict monster * generation. * * This function is capable of selecting monsters by: * - racial symbol (may be any of the characters allowed) * - symbol color (may be any of up to four colors). * - racial flag(s) (monster may have any allowed flag) * - breath flag(s) (monster must have exactly the flags specified) * * Uniques may be forbidden, or allowed on rare occasions. * * Some situations (like the elemental war themed level) require special * processing; this is done in helper functions called from this one. */ static bool mon_select(int r_idx) { monster_race *r_ptr = &r_info[r_idx]; bool ok = FALSE; bitflag mon_breath[RSF_SIZE]; /* Require correct breath attack */ rsf_copy(mon_breath, r_ptr->spell_flags); flags_mask(mon_breath, RSF_SIZE, RSF_BREATH_MASK, FLAG_END); /* Special case: Elemental war themed level. */ if (p_ptr->themed_level == THEME_ELEMENTAL) { return (vault_aux_elemental(r_idx)); } /* Special case: Estolad themed level. */ if (p_ptr->themed_level == THEME_ESTOLAD) { if (!(rf_has(r_ptr->flags, RF_RACIAL))) return (FALSE); } /* Require that the monster symbol be correct. */ if (d_char_req[0] != '\0') { if (strchr(d_char_req, r_ptr->d_char) == 0) return (FALSE); } /* Require correct racial type. */ if (racial_flag_mask) { if (!(rf_has(r_ptr->flags, racial_flag_mask))) return (FALSE); /* Hack -- no invisible undead until deep. */ if ((p_ptr->danger < 40) && (rf_has(r_ptr->flags, RF_UNDEAD)) && (rf_has(r_ptr->flags, RF_INVISIBLE))) return (FALSE); } /* Require that monster breaths be exactly those specified. */ /* Exception for winged dragons */ if (!rsf_is_empty(breath_flag_mask)) { /* 'd'ragons */ if (!rsf_is_equal(mon_breath, breath_flag_mask) && (r_ptr->d_char != 'D')) return (FALSE); /* Winged 'D'ragons */ if (r_ptr->d_char == 'D') { if (!rsf_is_subset(mon_breath, breath_flag_mask)) return (FALSE); /* Hack - this deals with all current Ds that need excluding */ if (rsf_has(r_ptr->flags, RSF_BRTH_SOUND)) return (FALSE); } } /* Require that the monster color be correct. */ if (d_attr_req[0]) { /* Check all allowed colors, if given. */ if ((d_attr_req[0]) && (r_ptr->d_attr == d_attr_req[0])) ok = TRUE; if ((d_attr_req[1]) && (r_ptr->d_attr == d_attr_req[1])) ok = TRUE; if ((d_attr_req[2]) && (r_ptr->d_attr == d_attr_req[2])) ok = TRUE; if ((d_attr_req[3]) && (r_ptr->d_attr == d_attr_req[3])) ok = TRUE; /* Hack -- No multihued dragons allowed in the arcane dragon pit. */ if ((strchr(d_char_req, 'd') || strchr(d_char_req, 'D')) && (d_attr_req[0] == TERM_VIOLET) && (rf_has(r_ptr->flags, RSF_BRTH_ACID) || rf_has(r_ptr->flags, RSF_BRTH_ELEC) || rf_has(r_ptr->flags, RSF_BRTH_FIRE) || rf_has(r_ptr->flags, RSF_BRTH_COLD) || rf_has(r_ptr->flags, RSF_BRTH_POIS))) { return (FALSE); } /* Doesn't match any of the given colors? Not good. */ if (!ok) return (FALSE); } /* Usually decline unique monsters. */ if (rf_has(r_ptr->flags, RF_UNIQUE)) { if (!allow_unique) return (FALSE); else if (randint0(5) != 0) return (FALSE); } /* Okay */ return (TRUE); }
/** * Determines whether the given monster successfully resists the given effect. * * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns false. * Then we determine if the monster resists the effect for some racial * reason. For example, the monster might have the NO_SLEEP flag, in which * case it always resists sleep. Or if it breathes chaos, it always resists * confusion. If the given monster doesn't resist for any of these reasons, * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`, * indicating that another monster caused this effect, then the chance of * success on the saving throw just depends on the monster's native depth. * Otherwise, the chance of success decreases as `timer` increases. * * Also marks the lore for any appropriate resists. */ static bool mon_resist_effect(const struct monster *mon, int ef_idx, int timer, u16b flag) { struct mon_timed_effect *effect; int resist_chance; struct monster_lore *lore; assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX); assert(mon); effect = &effects[ef_idx]; lore = get_lore(mon->race); /* Hasting never fails */ if (ef_idx == MON_TMD_FAST) return (false); /* Some effects are marked to never fail */ if (flag & MON_TMD_FLG_NOFAIL) return (false); /* A sleeping monster resists further sleeping */ if (ef_idx == MON_TMD_SLEEP && mon->m_timed[ef_idx]) return (true); /* If the monster resists innately, learn about it */ if (rf_has(mon->race->flags, effect->flag_resist)) { if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, effect->flag_resist); return (true); } /* Monsters with specific breaths resist stunning */ if (ef_idx == MON_TMD_STUN && (rsf_has(mon->race->spell_flags, RSF_BR_SOUN) || rsf_has(mon->race->spell_flags, RSF_BR_WALL))) { /* Add the lore */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { if (rsf_has(mon->race->spell_flags, RSF_BR_SOUN)) rsf_on(lore->spell_flags, RSF_BR_SOUN); if (rsf_has(mon->race->spell_flags, RSF_BR_WALL)) rsf_on(lore->spell_flags, RSF_BR_WALL); } return (true); } /* Monsters with specific breaths resist confusion */ if ((ef_idx == MON_TMD_CONF) && rsf_has(mon->race->spell_flags, RSF_BR_CHAO)) { /* Add the lore */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) if (rsf_has(mon->race->spell_flags, RSF_BR_CHAO)) rsf_on(lore->spell_flags, RSF_BR_CHAO); return (true); } /* Inertia breathers resist slowing */ if (ef_idx == MON_TMD_SLOW && rsf_has(mon->race->spell_flags, RSF_BR_INER)){ rsf_on(lore->spell_flags, RSF_BR_INER); return (true); } /* Calculate the chance of the monster making its saving throw. */ if (ef_idx == MON_TMD_SLEEP) timer /= 25; /* Hack - sleep uses much bigger numbers */ if (flag & MON_TMD_MON_SOURCE) resist_chance = mon->race->level; else resist_chance = mon->race->level + 40 - (timer / 2); if (randint0(100) < resist_chance) return (true); /* Uniques are doubly hard to affect */ if (rf_has(mon->race->flags, RF_UNIQUE)) if (randint0(100) < resist_chance) return (true); return (false); }
/** * Determines whether the given monster successfully resists the given effect. * * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns FALSE. * Then we determine if the monster resists the effect for some racial * reason. For example, the monster might have the NO_SLEEP flag, in which * case it always resists sleep. Or if it breathes chaos, it always resists * confusion. If the given monster doesn't resist for any of these reasons, * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`, * indicating that another monster caused this effect, then the chance of * success on the saving throw just depends on the monster's native depth. * Otherwise, the chance of success decreases as `timer` increases. * * Also marks the lore for any appropriate resists. */ static bool mon_resist_effect(const monster_type *m_ptr, int ef_idx, int timer, u16b flag) { mon_timed_effect *effect; int resist_chance; const monster_race *r_ptr; monster_lore *l_ptr; assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX); effect = &effects[ef_idx]; assert(m_ptr); r_ptr = &r_info[m_ptr->r_idx]; l_ptr = &l_list[m_ptr->r_idx]; /* Hasting never fails */ if (ef_idx == MON_TMD_FAST) return (FALSE); /* Some effects are marked to never fail */ if (flag & MON_TMD_FLG_NOFAIL) return (FALSE); /* A sleeping monster resists further sleeping */ if (ef_idx == MON_TMD_SLEEP && m_ptr->m_timed[ef_idx]) return (TRUE); /* If the monster resists innately, learn about it */ if (rf_has(r_ptr->flags, effect->flag_resist)) { if (m_ptr->ml) rf_on(l_ptr->flags, effect->flag_resist); return (TRUE); } /* Monsters with specific breaths resist stunning*/ if (ef_idx == MON_TMD_STUN && (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN) || rsf_has(r_ptr->spell_flags, RSF_BR_WALL))) { /* Add the lore */ if (m_ptr->ml) { if (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN)) rsf_on(l_ptr->spell_flags, RSF_BR_SOUN); if (rsf_has(r_ptr->spell_flags, RSF_BR_WALL)) rsf_on(l_ptr->spell_flags, RSF_BR_WALL); } return (TRUE); } /* Monsters with specific breaths resist confusion */ if ((ef_idx == MON_TMD_CONF) && ((rsf_has(r_ptr->spell_flags, RSF_BR_CHAO)) || (rsf_has(r_ptr->spell_flags, RSF_BR_CONF))) ) { /* Add the lore */ if (m_ptr->ml) { if (rsf_has(r_ptr->spell_flags, RSF_BR_CHAO)) rsf_on(l_ptr->spell_flags, RSF_BR_CHAO); if (rsf_has(r_ptr->spell_flags, RSF_BR_CONF)) rsf_on(l_ptr->spell_flags, RSF_BR_CONF); } return (TRUE); } /* Inertia breathers resist slowing */ if (ef_idx == MON_TMD_SLOW && rsf_has(r_ptr->spell_flags, RSF_BR_INER)) { rsf_on(l_ptr->spell_flags, RSF_BR_INER); return (TRUE); } /* Calculate the chance of the monster making its saving throw. */ if (ef_idx == MON_TMD_SLEEP) timer /= 25; /* Hack - sleep uses much bigger numbers */ if (flag & MON_TMD_MON_SOURCE) resist_chance = r_ptr->level; else resist_chance = r_ptr->level + 40 - (timer / 2); if (randint0(100) < resist_chance) return (TRUE); /* Uniques are doubly hard to affect */ if (rf_has(r_ptr->flags, RF_UNIQUE)) if (randint0(100) < resist_chance) return (TRUE); return (FALSE); }