Esempio n. 1
0
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));
}
Esempio n. 2
0
/**
 * 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;
}
Esempio n. 3
0
/**
 * 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;
}
Esempio n. 4
0
/**
 * 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;
}
Esempio n. 5
0
/**
 * 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;
}
Esempio n. 6
0
/**
 * 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;
}
Esempio n. 7
0
/**
 * 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;
}
Esempio n. 8
0
/**
 * 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)]);
}
Esempio n. 9
0
/**
 * 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);
		}
	}
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
/**
 * 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);
}
Esempio n. 13
0
/**
 * 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);
}
Esempio n. 14
0
/**
 * 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);
}