Esempio n. 1
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. 2
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. 3
0
/**
 * Attempts to place a monster of the given race at the given location.
 *
 * If `sleep` is true, the monster is placed with its default sleep value,
 * which is given in monster.txt.
 *
 * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP,
 * ORIGIN_DROP_PIT, etc.)
 *
 * To give the player a sporting chance, some especially dangerous
 * monsters are marked as "FORCE_SLEEP" in monster.txt, which will
 * cause them to be placed with low energy. This helps ensure that
 * if such a monster suddenly appears in line-of-sight (due to a
 * summon, for instance), the player gets a chance to move before
 * they do.
 *
 * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
 *
 * This is the only function which may place a monster in the dungeon,
 * except for the savefile loading code, which calls place_monster()
 * directly.
 */
static bool place_new_monster_one(struct chunk *c, int y, int x,
								  struct monster_race *race, bool sleep,
								  byte origin)
{
	int i;

	struct monster *mon;
	struct monster monster_body;

	assert(square_in_bounds(c, y, x));
	assert(race && race->name);

	/* Not where monsters already are */
	if (square_monster(c, y, x))
		return false;

	/* Not where the player already is */
	if ((player->py == y) && (player->px == x))
		return false;

	/* Prevent monsters from being placed where they cannot walk, but allow other feature types */
	if (!square_is_monster_walkable(c, y, x))
		return false;

	/* No creation on glyph of warding */
	if (square_iswarded(c, y, x)) return false;

	/* "unique" monsters must be "unique" */
	if (rf_has(race->flags, RF_UNIQUE) && race->cur_num >= race->max_num)
		return (false);

	/* Depth monsters may NOT be created out of depth */
	if (rf_has(race->flags, RF_FORCE_DEPTH) && player->depth < race->level)
		return (false);

	/* Add to level feeling, note uniques for cheaters */
	c->mon_rating += race->level * race->level;

	/* Check out-of-depth-ness */
	if (race->level > c->depth) {
		if (rf_has(race->flags, RF_UNIQUE)) { /* OOD unique */
			if (OPT(player, cheat_hear))
				msg("Deep unique (%s).", race->name);
		} else { /* Normal monsters but OOD */
			if (OPT(player, cheat_hear))
				msg("Deep monster (%s).", race->name);
		}
		/* Boost rating by power per 10 levels OOD */
		c->mon_rating += (race->level - c->depth) * race->level * race->level;
	} else if (rf_has(race->flags, RF_UNIQUE) && OPT(player, cheat_hear))
		msg("Unique (%s).", race->name);

	/* Get local monster */
	mon = &monster_body;

	/* Clean out the monster */
	memset(mon, 0, sizeof(struct monster));

	/* Save the race */
	mon->race = race;

	/* Enforce sleeping if needed */
	if (sleep && race->sleep) {
		int val = race->sleep;
		mon->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10));
	}

	/* Uniques get a fixed amount of HP */
	if (rf_has(race->flags, RF_UNIQUE))
		mon->maxhp = race->avg_hp;
	else {
		mon->maxhp = mon_hp(race, RANDOMISE);
		mon->maxhp = MAX(mon->maxhp, 1);
	}

	/* And start out fully healthy */
	mon->hp = mon->maxhp;

	/* Extract the monster base speed */
	mon->mspeed = race->speed;

	/* Hack -- small racial variety */
	if (!rf_has(race->flags, RF_UNIQUE)) {
		/* Allow some small variation per monster */
		i = turn_energy(race->speed) / 10;
		if (i) mon->mspeed += rand_spread(0, i);
	}

	/* Give a random starting energy */
	mon->energy = (byte)randint0(50);

	/* Force monster to wait for player */
	if (rf_has(race->flags, RF_FORCE_SLEEP))
		mflag_on(mon->mflag, MFLAG_NICE);

	/* Radiate light? */
	if (rf_has(race->flags, RF_HAS_LIGHT))
		player->upkeep->update |= PU_UPDATE_VIEW;

	/* Is this obviously a monster? (Mimics etc. aren't) */
	if (rf_has(race->flags, RF_UNAWARE))
		mflag_on(mon->mflag, MFLAG_CAMOUFLAGE);
	else
		mflag_off(mon->mflag, MFLAG_CAMOUFLAGE);

	/* Set the color if necessary */
	if (rf_has(race->flags, RF_ATTR_RAND))
		mon->attr = randint1(BASIC_COLORS - 1);

	/* Place the monster in the dungeon */
	if (!place_monster(c, y, x, mon, origin))
		return (false);

	/* Success */
	return (true);
}
Esempio n. 4
0
/**
 * Attempts to place a monster of the given race at the given location.
 *
 * If `sleep` is true, the monster is placed with its default sleep value,
 * which is given in monster.txt.
 *
 * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP,
 * ORIGIN_DROP_PIT, etc.)
 *
 * To give the player a sporting chance, some especially dangerous
 * monsters are marked as "FORCE_SLEEP" in monster.txt, which will
 * cause them to be placed with low energy. This helps ensure that
 * if such a monster suddenly appears in line-of-sight (due to a
 * summon, for instance), the player gets a chance to move before
 * they do.
 *
 * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
 *
 * This is the only function which may place a monster in the dungeon,
 * except for the savefile loading code, which calls place_monster()
 * directly.
 */
static bool place_new_monster_one(int y, int x, monster_race *race, 
		bool sleep, byte origin)
{
	int i;

	struct monster *mon;
	struct monster monster_body;

	assert(cave_in_bounds(cave, y, x));
	assert(race && race->name);

	/* Require empty space */
	if (!cave_isempty(cave, y, x)) return (FALSE);

	/* No creation on glyph of warding */
	if (cave_iswarded(cave, y, x)) return FALSE;

	/* "unique" monsters must be "unique" */
	if (rf_has(race->flags, RF_UNIQUE) && race->cur_num >= race->max_num)
		return (FALSE);

	/* Depth monsters may NOT be created out of depth */
	if (rf_has(race->flags, RF_FORCE_DEPTH) && p_ptr->depth < race->level)
		return (FALSE);

	/* Add to level feeling */
	cave->mon_rating += race->power / 20;

	/* Check out-of-depth-ness */
	if (race->level > p_ptr->depth) {
		if (rf_has(race->flags, RF_UNIQUE)) { /* OOD unique */
			if (OPT(cheat_hear))
				msg("Deep unique (%s).", race->name);
		} else { /* Normal monsters but OOD */
			if (OPT(cheat_hear))
				msg("Deep monster (%s).", race->name);
		}
		/* Boost rating by power per 10 levels OOD */
		cave->mon_rating += (race->level - p_ptr->depth) * race->power / 200;
	}
	/* Note uniques for cheaters */
	else if (rf_has(race->flags, RF_UNIQUE) && OPT(cheat_hear))
		msg("Unique (%s).", race->name);

	/* Get local monster */
	mon = &monster_body;

	/* Clean out the monster */
	(void)WIPE(mon, monster_type);

	/* Save the race */
	mon->race = race;

	/* Enforce sleeping if needed */
	if (sleep && race->sleep) {
		int val = race->sleep;
		mon->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10));
	}

	/* Uniques get a fixed amount of HP */
	if (rf_has(race->flags, RF_UNIQUE))
		mon->maxhp = race->avg_hp;
	else {
		mon->maxhp = mon_hp(race, RANDOMISE);
		mon->maxhp = MAX(mon->maxhp, 1);
	}

	/* And start out fully healthy */
	mon->hp = mon->maxhp;

	/* Extract the monster base speed */
	mon->mspeed = race->speed;

	/* Hack -- small racial variety */
	if (!rf_has(race->flags, RF_UNIQUE)) {
		/* Allow some small variation per monster */
		i = extract_energy[race->speed] / 10;
		if (i) mon->mspeed += rand_spread(0, i);
	}

	/* Give a random starting energy */
	mon->energy = (byte)randint0(50);

	/* Force monster to wait for player */
	if (rf_has(race->flags, RF_FORCE_SLEEP))
		mon->mflag |= (MFLAG_NICE);

	/* Radiate light? */
	if (rf_has(race->flags, RF_HAS_LIGHT))
		p_ptr->update |= PU_UPDATE_VIEW;
	
	/* Is this obviously a monster? (Mimics etc. aren't) */
	if (rf_has(race->flags, RF_UNAWARE)) 
		mon->unaware = TRUE;
	else
		mon->unaware = FALSE;

	/* Set the color if necessary */
	if (rf_has(race->flags, RF_ATTR_RAND))
		mon->attr = randint1(BASIC_COLORS - 1);

	/* Place the monster in the dungeon */
	if (!place_monster(y, x, mon, origin))
		return (FALSE);

	/* Success */
	return (TRUE);
}