Esempio n. 1
0
/**
 * Determine the damage of a spell attack which ignores monster hp
 * (i.e. bolts and balls, including arrows/boulders/storms/etc.)
 *
 * \param spell is the attack type
 * \param rlev is the monster level of the attacker
 * \param aspect is the damage calc required (min, avg, max, random)
 */
static int nonhp_dam(int spell, int rlev, aspect dam_aspect)
{
	const struct mon_spell *rs_ptr = &mon_spell_table[spell];
	int dam;

	/* base damage is X + YdZ (m_bonus is not used) */
	dam = randcalc(rs_ptr->base_dam, 0, dam_aspect);

	/* rlev-dependent damage (m_bonus is used as a switch) */
	dam += (rlev * rs_ptr->rlev_dam.base / 100);

	if (rs_ptr->rlev_dam.m_bonus == 1) /* then rlev affects dice */
		dam += damcalc(MIN(1, rs_ptr->rlev_dam.dice * rlev / 100), 
				rs_ptr->rlev_dam.sides, dam_aspect);
	else /* rlev affects sides */
		dam += damcalc(rs_ptr->rlev_dam.dice, rs_ptr->rlev_dam.sides *
				rlev / 100, dam_aspect);

	return dam;
}
Esempio n. 2
0
/**
 * Apply side effects from a spell attack to the player
 *
 * \param spell is the attack type
 * \param dam is the amount of damage caused by the attack
 * \param m_idx is the attacking monster
 * \param rlev is its level
 * \param seen is whether @ can see it
 */
static void do_side_effects(int spell, int dam, int m_idx, bool seen)
{
	monster_type *m_ptr = cave_monster(cave, m_idx);
	monster_race *r_ptr = &r_info[m_ptr->r_idx];

	const struct spell_effect *re_ptr;
	const struct mon_spell *rs_ptr = &mon_spell_table[spell];

	int i, choice[99], dur = 0, j = 0, count = 0;
	s32b d = 0;

	bool sustain = FALSE, perma = FALSE, chosen[RSE_MAX] = { 0 };

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

	/* First we note all the effects we'll be doing. */
	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))) {

			/* If we have a choice of effects, we create a cum freq table */
			if (re_ptr->chance) {
				for (i = j; i < (j + re_ptr->chance); i++)
					choice[i] = re_ptr->index;
				j = i;
			}
			else
				chosen[re_ptr->index] = TRUE;
		}
	}

	/* If we have built a cum freq table, choose an effect from it */
	if (j)
		chosen[choice[randint0(j)]] = TRUE;

	/* Now we cycle through again to activate the chosen effects */
	for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) {
		if (chosen[re_ptr->index]) {

			/*
			 * Check for resistance - there are three possibilities:
			 * 1. Immunity to the attack type if side_immune is TRUE
			 * 2. Resistance to the attack type if it affords no immunity
			 * 3. Resistance to the specific side-effect
			 *
			 * TODO - add interesting messages to the RSE_ and GF_ tables
			 * to replace the generic ones below. (See #1376)
			 */
			if (re_ptr->res_flag)
				update_smart_learn(m_ptr, p_ptr, re_ptr->res_flag);

			if ((rs_ptr->gf && check_side_immune(rs_ptr->gf)) ||
					check_state(p_ptr, re_ptr->res_flag, p_ptr->state.flags)) {
				msg("You resist the effect!");
				continue;
			}

			/* Allow saving throw if available */
			if (re_ptr->save &&
					randint0(100) < p_ptr->state.skills[SKILL_SAVE]) {
				msg("You avoid the effect!");
				continue;
			}

			/* Implement the effect */
			if (re_ptr->timed) {

				/* Calculate base duration (m_bonus is not used) */
				dur = randcalc(re_ptr->base, 0, RANDOMISE);

				/* Calculate the damage-dependent duration (m_bonus is
				 * used as a cap) */
				dur += damcalc(re_ptr->dam.dice, re_ptr->dam.sides *
						dam / 100, RANDOMISE);

				if (re_ptr->dam.m_bonus && (dur > re_ptr->dam.m_bonus))
					dur = re_ptr->dam.m_bonus;

				/* Apply the effect - we have already checked for resistance */
				(void)player_inc_timed(p_ptr, re_ptr->flag, dur, TRUE, FALSE);

			} else {
				switch (re_ptr->flag) {
					case S_INV_DAM:
						if (dam > 0)
							inven_damage(p_ptr, re_ptr->gf, MIN(dam *
								randcalc(re_ptr->dam, 0, RANDOMISE), 300));
						break;

					case S_TELEPORT: /* m_bonus is used as a clev filter */
						if (!re_ptr->dam.m_bonus || 
								randint1(re_ptr->dam.m_bonus) > p_ptr->lev)
							teleport_player(randcalc(re_ptr->base, 0,
								RANDOMISE));
						break;

					case S_TELE_TO:
						teleport_player_to(m_ptr->fy, m_ptr->fx);
						break;

					case S_TELE_LEV:
						teleport_player_level();
						break;

					case S_TELE_SELF:
						teleport_away(m_ptr, randcalc(re_ptr->base, 0,
							RANDOMISE));
						break;

					case S_DRAIN_LIFE:
						d = re_ptr->base.base + (p_ptr->exp *
							re_ptr->base.sides / 100) * MON_DRAIN_LIFE;

						msg("You feel your life force draining away!");
						player_exp_lose(p_ptr, d, FALSE);
						break;

					case S_DRAIN_STAT: /* m_bonus is used as a flag */
						if (re_ptr->dam.m_bonus > 0)
							sustain = TRUE;

						if (abs(re_ptr->dam.m_bonus) > 1)
							perma = TRUE;

						drain_stats(randcalc(re_ptr->base, 0, RANDOMISE),
							sustain, perma);
						break;

					case S_SWAP_STAT:
						swap_stats();
						break;

					case S_DRAIN_ALL:
						msg("You're not as powerful as you used to be...");

						for (i = 0; i < A_MAX; i++)
							player_stat_dec(p_ptr, i, FALSE);
						break;

					case S_DISEN:
						(void)apply_disenchant(0);
						break;

					case S_DRAIN_MANA:
						drain_mana(m_idx, rlev, seen);
						break;

					case S_HEAL:
						heal_self(m_idx, rlev, seen);
						break;

					case S_DARKEN:
						(void)unlight_area(0, 3);
						break;

					case S_TRAPS:
						(void)trap_creation();
						break;

					case S_AGGRAVATE:
						aggravate_monsters(m_idx);
						break;

					case S_KIN:
						summon_kin_type = r_ptr->d_char;
					case S_MONSTER:	case S_MONSTERS:
					case S_SPIDER: case S_HOUND: case S_HYDRA: case S_AINU:
					case S_ANIMAL:
					case S_DEMON: case S_HI_DEMON:
					case S_UNDEAD: case S_HI_UNDEAD: case S_WRAITH:
					case S_DRAGON: case S_HI_DRAGON:
					case S_UNIQUE:
						count = summon_monster_aux(re_ptr->flag, m_idx, rlev, re_ptr->base.base);

						/* In the special case that uniques or wraiths were summoned but all were dead
							S_HI_UNDEAD is used instead */
						if ((!count) && ((re_ptr->flag == S_WRAITH) || (re_ptr->flag == S_UNIQUE)))
							count = summon_monster_aux(S_HI_UNDEAD, m_idx, rlev, re_ptr->base.base);

						if (count && p_ptr->timed[TMD_BLIND])
							msgt(rs_ptr->msgt, "You hear %s appear nearby.",
								(count > 1 ? "many things" : "something"));

					default:
						break;
				}		
			}
		}
	}
	return;
}
Esempio n. 3
0
/**
 * Apply side effects from a spell attack to the player
 *
 * \param spell is the attack type
 * \param dam is the amount of damage caused by the attack
 * \param m_idx is the attacking monster
 */
static void do_side_effects(int spell, int dam, int m_idx)
{
	const struct spell_effect *re_ptr;
	const struct mon_spell *rs_ptr = &mon_spell_table[spell];
	monster_type *m_ptr = &mon_list[m_idx];
	int i, choice[99], dur = 0, j = 0;
	bool sustain = FALSE, perma = FALSE, chosen[RSE_MAX] = { 0 };
	s32b d = 0;

	/* First we note all the effects we'll be doing. */
	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))) {

			/* If we have a choice of effects, we create a cum freq table */
			if (re_ptr->chance) {
				for (i = j; i < (j + re_ptr->chance); i++)
					choice[i] = re_ptr->index;
				j = i;
			}
			else
				chosen[re_ptr->index] = TRUE;
		}
	}

	/* If we have built a cum freq table, choose an effect from it */
	if (j)
		chosen[choice[randint0(j)]] = TRUE;

	/* Now we cycle through again to activate the chosen effects */
	for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) {
		if (chosen[re_ptr->index]) {

			/*
			 * Check for resistance - there are three possibilities:
			 * 1. Immunity to the attack type if side_immune is TRUE
			 * 2. Resistance to the attack type if it affords no immunity
			 * 3. Resistance to the specific side-effect
			 *
			 * TODO - add interesting messages to the RSE_ and GF_ tables
			 * to replace the generic ones below.
			 */
			if ((rs_ptr->gf && check_side_immune(rs_ptr->gf)) ||
					p_ptr->state.flags[re_ptr->res_flag]) {
				msg("You resist the effect!");
				if (re_ptr->res_flag)
					wieldeds_notice_flag(re_ptr->res_flag);
				continue;
			}

			/* Allow saving throw if available */
			if (re_ptr->save &&
					randint0(100) < p_ptr->state.skills[SKILL_SAVE]) {
				msg("You avoid the effect!");
				continue;
			}

			/* Implement the effect */
			if (re_ptr->timed) {

				/* Calculate base duration (m_bonus is not used) */
				dur = randcalc(re_ptr->base, 0, RANDOMISE);

				/* Calculate the damage-dependent duration (m_bonus is
				 * used as a cap) */
				dur += damcalc(re_ptr->dam.dice, re_ptr->dam.sides *
						dam / 100, RANDOMISE);

				if (re_ptr->dam.m_bonus && (dur > re_ptr->dam.m_bonus))
					dur = re_ptr->dam.m_bonus;

				/* Apply the effect */
				(void)inc_timed(re_ptr->flag, dur, TRUE);

			} else {
				switch (re_ptr->flag) {
					case S_INV_DAM:
						if (dam > 0)
							inven_damage(re_ptr->gf, MIN(dam *
								randcalc(re_ptr->dam, 0, RANDOMISE), 300));
						break;

					case S_TELEPORT: /* m_bonus is used as a clev filter */
						if (!re_ptr->dam.m_bonus || 
								randint1(re_ptr->dam.m_bonus) > p_ptr->lev)
							teleport_player(randcalc(re_ptr->base, 0,
								RANDOMISE));
						break;

					case S_TELE_TO:
						teleport_player_to(m_ptr->fy, m_ptr->fx);
						break;

					case S_TELE_LEV:
						teleport_player_level();
						break;

					case S_DRAIN_LIFE:
						d = re_ptr->base.base + (p_ptr->exp *
							re_ptr->base.sides / 100) * MON_DRAIN_LIFE;						

						msg("You feel your life force draining away!");
						lose_exp(d);
						break;

					case S_DRAIN_STAT: /* m_bonus is used as a flag */
						if (re_ptr->dam.m_bonus > 0)
							sustain = TRUE;

						if (abs(re_ptr->dam.m_bonus) > 1)
							perma = TRUE;

						drain_stats(randcalc(re_ptr->base, 0, RANDOMISE),
							sustain, perma);
						break;

					case S_SWAP_STAT:
						swap_stats();
						break;

					case S_DRAIN_ALL:
						msg("You're not as powerful as you used to be...");

						for (i = 0; i < A_MAX; i++)
							player_stat_dec(p_ptr, i, FALSE);
						break;

					case S_DISEN:
						(void)apply_disenchant(0);
						break;

					case S_DRAIN_MANA:
					case S_HEAL:
					case S_BLINK:
					case S_DARKEN:
					case S_TRAPS:
					case S_AGGRAVATE:
					case S_KIN:
					case S_MONSTER:
					case S_MONSTERS:
						/* XXX Fixme */
					default:
						break;
				}		
			}
		}
	}
	return;
}