/**
 * Monster has innate spells
 */
bool monster_has_innate_spells(const struct monster *mon)
{
	bitflag innate_spells[RSF_SIZE];
	create_mon_spell_mask(innate_spells, RST_INNATE, RST_NONE);
	rsf_inter(innate_spells, mon->race->spell_flags);
	return rsf_is_empty(innate_spells) ? false : true;
}
/**
 * Monster has damaging breath
 */
bool monster_breathes(const struct monster *mon)
{
	bitflag breaths[RSF_SIZE];
	create_mon_spell_mask(breaths, RST_BREATH, RST_NONE);
	rsf_inter(breaths, mon->race->spell_flags);
	return rsf_is_empty(breaths) ? false : true;
}
/**
 * Monster has frequent and good archery attacks
 */
bool monster_loves_archery(const struct monster *mon)
{
	bitflag shooting[RSF_SIZE];
	create_mon_spell_mask(shooting, RST_ARCHERY, RST_NONE);
	rsf_inter(shooting, mon->race->spell_flags);
	if (rsf_is_empty(shooting)) return false;
	return (mon->race->freq_innate < 4) ? true : false;
}
Exemple #4
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);
}
Exemple #5
0
/**
 * Creatures can cast spells, shoot missiles, and breathe.
 *
 * Returns "true" if a spell (or whatever) was (successfully) cast.
 *
 * XXX XXX XXX This function could use some work, but remember to
 * keep it as optimized as possible, while retaining generic code.
 *
 * Verify the various "blind-ness" checks in the code.
 *
 * XXX XXX XXX Note that several effects should really not be "seen"
 * if the player is blind.
 *
 * Perhaps monsters should breathe at locations *near* the player,
 * since this would allow them to inflict "partial" damage.
 *
 * Perhaps smart monsters should decline to use "bolt" spells if
 * there is a monster in the way, unless they wish to kill it.
 *
 * It will not be possible to "correctly" handle the case in which a
 * monster attempts to attack a location which is thought to contain
 * the player, but which in fact is nowhere near the player, since this
 * might induce all sorts of messages about the attack itself, and about
 * the effects of the attack, which the player might or might not be in
 * a position to observe.  Thus, for simplicity, it is probably best to
 * only allow "faulty" attacks by a monster if one of the important grids
 * (probably the initial or final grid) is in fact in view of the player.
 * It may be necessary to actually prevent spell attacks except when the
 * monster actually has line of sight to the player.  Note that a monster
 * could be left in a bizarre situation after the player ducked behind a
 * pillar and then teleported away, for example.
 *
 * Note that this function attempts to optimize the use of spells for the
 * cases in which the monster has no spells, or has spells but cannot use
 * them, or has spells but they will have no "useful" effect.  Note that
 * this function has been an efficiency bottleneck in the past.
 *
 * Note the special "MFLAG_NICE" flag, which prevents a monster from using
 * any spell attacks until the player has had a single chance to move.
 */
bool make_attack_spell(struct monster *mon)
{
	int chance, thrown_spell, rlev, failrate;

	bitflag f[RSF_SIZE];

	struct monster_lore *lore = get_lore(mon->race);

	char m_name[80], m_poss[80], ddesc[80];

	/* Player position */
	int px = player->px;
	int py = player->py;

	/* Extract the blind-ness */
	bool blind = (player->timed[TMD_BLIND] ? true : false);

	/* Extract the "see-able-ness" */
	bool seen = (!blind && mflag_has(mon->mflag, MFLAG_VISIBLE));

	/* Assume "normal" target */
	bool normal = true;

	/* Cannot cast spells when confused */
	if (mon->m_timed[MON_TMD_CONF]) return (false);

	/* Cannot cast spells when nice */
	if (mflag_has(mon->mflag, MFLAG_NICE)) return false;

	/* Hack -- Extract the spell probability */
	chance = (mon->race->freq_innate + mon->race->freq_spell) / 2;

	/* Not allowed to cast spells */
	if (!chance) return false;

	/* Only do spells occasionally */
	if (randint0(100) >= chance) return false;

	/* Hack -- require projectable player */
	if (normal) {
		/* Check range */
		if (mon->cdis > z_info->max_range)
			return false;

		/* Check path */
		if (!projectable(cave, mon->fy, mon->fx, py, px, PROJECT_NONE))
			return false;
	}

	/* Extract the monster level */
	rlev = ((mon->race->level >= 1) ? mon->race->level : 1);

	/* Extract the racial spell flags */
	rsf_copy(f, mon->race->spell_flags);

	/* Allow "desperate" spells */
	if (rf_has(mon->race->flags, RF_SMART) &&
	    mon->hp < mon->maxhp / 10 &&
	    randint0(100) < 50)

		/* Require intelligent spells */
		ignore_spells(f, RST_BOLT | RST_BALL | RST_BREATH | RST_ATTACK | RST_INNATE);

	/* Remove the "ineffective" spells */
	remove_bad_spells(mon, f);

	/* Check whether summons and bolts are worth it. */
	if (!rf_has(mon->race->flags, RF_STUPID)) {
		/* Check for a clean bolt shot */
		if (test_spells(f, RST_BOLT) &&
			!projectable(cave, mon->fy, mon->fx, py, px, PROJECT_STOP))

			/* Remove spells that will only hurt friends */
			ignore_spells(f, RST_BOLT);

		/* Check for a possible summon */
		if (!(summon_possible(mon->fy, mon->fx)))

			/* Remove summoning spells */
			ignore_spells(f, RST_SUMMON);
	}

	/* No spells left */
	if (rsf_is_empty(f)) return false;

	/* Get the monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);

	/* Get the monster possessive ("his"/"her"/"its") */
	monster_desc(m_poss, sizeof(m_poss), mon, MDESC_PRO_VIS | MDESC_POSS);

	/* Get the "died from" name */
	monster_desc(ddesc, sizeof(ddesc), mon, MDESC_DIED_FROM);

	/* Choose a spell to cast */
	thrown_spell = choose_attack_spell(f);

	/* Abort if no spell was chosen */
	if (!thrown_spell) return false;

	/* If we see an unaware monster try to cast a spell, become aware of it */
	if (mflag_has(mon->mflag, MFLAG_UNAWARE))
		become_aware(mon);

	/* Calculate spell failure rate */
	failrate = 25 - (rlev + 3) / 4;
	if (mon->m_timed[MON_TMD_FEAR])
		failrate += 20;

	/* Stupid monsters will never fail (for jellies and such) */
	if (rf_has(mon->race->flags, RF_STUPID))
		failrate = 0;

	/* Check for spell failure (innate attacks never fail) */
	if (!mon_spell_is_innate(thrown_spell) && (randint0(100) < failrate)) {
		/* Message */
		msg("%s tries to cast a spell, but fails.", m_name);

		return true;
	}

	/* Cast the spell. */
	disturb(player, 1);
	do_mon_spell(thrown_spell, mon, seen);

	/* Remember what the monster did to us */
	if (seen) {
		rsf_on(lore->spell_flags, thrown_spell);

		/* Innate spell */
		if (mon_spell_is_innate(thrown_spell)) {
			if (lore->cast_innate < UCHAR_MAX)
				lore->cast_innate++;
		} else {
			/* Bolt or Ball, or Special spell */
			if (lore->cast_spell < UCHAR_MAX)
				lore->cast_spell++;
		}
	}

	/* Always take note of monsters that kill you */
	if (player->is_dead && (lore->deaths < SHRT_MAX)) {
		lore->deaths++;
	}

	/* Record any new info */
	lore_update(mon->race, lore);

	/* A spell was cast */
	return true;
}
/**
 * Monster has spells
 */
bool monster_has_spells(const struct monster *mon)
{
	return rsf_is_empty(mon->race->spell_flags) ? false : true;
}