void chaos_warrior_reward(void)
{
    if (one_in_(6))
    {
        msg_format("%^s rewards you with a mutation!",
            chaos_patrons[p_ptr->chaos_patron]);

        mut_gain_random(NULL);
    }
    else
    {
        char        wrath_reason[32] = "";
        int         nasty_chance = 6;
        int         dummy = 0, dummy2 = 0;
        int         type, effect;
        int         count = 0;

        if (p_ptr->lev == 13) nasty_chance = 2;
        else if (!(p_ptr->lev % 13)) nasty_chance = 3;
        else if (!(p_ptr->lev % 14)) nasty_chance = 12;

        if (one_in_(nasty_chance))
            type = randint1(20); /* Allow the 'nasty' effects */
        else
            type = randint1(15) + 5; /* Or disallow them */

        if (type < 1) type = 1;
        if (type > 20) type = 20;
        type--;

        sprintf(wrath_reason, "the Wrath of %s",
            chaos_patrons[p_ptr->chaos_patron]);

        effect = chaos_rewards[p_ptr->chaos_patron][type];
        switch (effect)
        {
        case REW_POLY_SLF:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thou needst a new form, mortal!'");

            do_poly_self();
            break;
        case REW_GAIN_EXP:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Well done, mortal! Lead on!'");
            if (p_ptr->prace == RACE_ANDROID)
                msg_print("But, nothing happen.");
            else if (p_ptr->exp < PY_MAX_EXP)
            {
                s32b ee = (p_ptr->exp / 2) + 10;
                if (ee > 100000L) ee = 100000L;
                msg_print("You feel more experienced.");
                gain_exp(ee);
            }
            break;
        case REW_LOSE_EXP:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thou didst not deserve that, slave.'");

            if (p_ptr->prace == RACE_ANDROID)
                msg_print("But, nothing happen.");
            else
            {
                lose_exp(p_ptr->exp / 6);
            }
            break;
        case REW_GOOD_OBJ:
            msg_format("The voice of %s whispers:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Use my gift wisely.'");
            acquirement(py, px, 1, FALSE, FALSE);
            break;
        case REW_GREA_OBJ:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Use my gift wisely.'");

            acquirement(py, px, 1, TRUE, FALSE);
            break;
        case REW_CHAOS_WP:
        {
            object_type forge;

            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thy deed hath earned thee a worthy blade.'");

            dummy = TV_SWORD;
            switch (randint1(p_ptr->lev))
            {
                case 0: case 1:
                    dummy2 = SV_DAGGER;
                    break;
                case 2: case 3:
                    dummy2 = SV_MAIN_GAUCHE;
                    break;
                case 4:
                    dummy2 = SV_TANTO;
                    break;
                case 5: case 6:
                    dummy2 = SV_RAPIER;
                    break;
                case 7: case 8:
                    dummy2 = SV_SMALL_SWORD;
                    break;
                case 9: case 10:
                    dummy2 = SV_BASILLARD;
                    break;
                case 11: case 12: case 13:
                    dummy2 = SV_SHORT_SWORD;
                    break;
                case 14: case 15:
                    dummy2 = SV_SABRE;
                    break;
                case 16: case 17:
                    dummy2 = SV_CUTLASS;
                    break;
                case 18:
                    dummy2 = SV_WAKIZASHI;
                    break;
                case 19:
                    dummy2 = SV_KHOPESH;
                    break;
                case 20:
                    dummy2 = SV_TULWAR;
                    break;
                case 21:
                    dummy2 = SV_BROAD_SWORD;
                    break;
                case 22: case 23:
                    dummy2 = SV_LONG_SWORD;
                    break;
                case 24: case 25:
                    dummy2 = SV_SCIMITAR;
                    break;
                case 26:
                    dummy2 = SV_NINJATO;
                    break;
                case 27:
                    dummy2 = SV_KATANA;
                    break;
                case 28: case 29:
                    dummy2 = SV_BASTARD_SWORD;
                    break;
                case 30:
                    dummy2 = SV_GREAT_SCIMITAR;
                    break;
                case 31:
                    dummy2 = SV_CLAYMORE;
                    break;
                case 32:
                    dummy2 = SV_ESPADON;
                    break;
                case 33:
                    dummy2 = SV_TWO_HANDED_SWORD;
                    break;
                case 34:
                    dummy2 = SV_FLAMBERGE;
                    break;
                case 35:
                    dummy2 = SV_NO_DACHI;
                    break;
                case 36:
                    dummy2 = SV_EXECUTIONERS_SWORD;
                    break;
                case 37:
                    dummy2 = SV_ZWEIHANDER;
                    break;
                case 38:
                    dummy2 = SV_HAYABUSA;
                    break;
                default:
                    dummy2 = SV_BLADE_OF_CHAOS;
            }

            object_prep(&forge, lookup_kind(dummy, dummy2));
            forge.to_h = 3 + randint1(dun_level) % 10;
            forge.to_d = 3 + randint1(dun_level) % 10;
            one_resistance(&forge);
            forge.name2 = EGO_WEAPON_CHAOS;

            drop_near(&forge, -1, py, px);
            break;
        }
        case REW_GOOD_OBS:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thy deed hath earned thee a worthy reward.'");

            acquirement(py, px, randint1(2) + 1, FALSE, FALSE);
            break;
        case REW_GREA_OBS:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Behold, mortal, how generously I reward thy loyalty.'");

            acquirement(py, px, randint1(2) + 1, TRUE, FALSE);
            break;
        case REW_TY_CURSE:
            msg_format("The voice of %s thunders:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thou art growing arrogant, mortal.'");

            activate_ty_curse(FALSE, &count);
            break;
        case REW_SUMMON_M:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'My pets, destroy the arrogant mortal!'");
            for (dummy = 0; dummy < randint1(5) + 1; dummy++)
                summon_specific(0, py, px, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
            break;
        case REW_H_SUMMON:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thou needst worthier opponents!'");
            activate_hi_summon(py, px, FALSE);
            break;
        case REW_DO_HAVOC:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Death and destruction! This pleaseth me!'");
            call_chaos(100);
            break;
        case REW_GAIN_ABL:
            msg_format("The voice of %s rings out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Stay, mortal, and let me mold thee.'");
            if (one_in_(3) && !(chaos_stats[p_ptr->chaos_patron] < 0))
                do_inc_stat(chaos_stats[p_ptr->chaos_patron]);
            else
                do_inc_stat(randint0(6));
            break;
        case REW_LOSE_ABL:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'I grow tired of thee, mortal.'");

            if (one_in_(3) && !(chaos_stats[p_ptr->chaos_patron] < 0))
                do_dec_stat(chaos_stats[p_ptr->chaos_patron]);
            else
                do_dec_stat(randint0(6));
            break;
        case REW_RUIN_ABL:
            msg_format("The voice of %s thunders:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Thou needst a lesson in humility, mortal!'");
            msg_print("You feel less powerful!");

            for (dummy = 0; dummy < 6; dummy++)
                dec_stat(dummy, 10 + randint1(15), TRUE);
            break;
        case REW_POLY_WND:
            msg_format("You feel the power of %s touch you.", chaos_patrons[p_ptr->chaos_patron]);
            do_poly_wounds();
            break;
        case REW_AUGM_ABL:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Receive this modest gift from me!'");
            for (dummy = 0; dummy < 6; dummy++)
                do_inc_stat(dummy);
            break;
        case REW_HURT_LOT:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Suffer, pathetic fool!'");
            fire_ball(GF_DISINTEGRATE, 0, p_ptr->lev * 4, 4);
            take_hit(DAMAGE_NOESCAPE, p_ptr->lev * 4, wrath_reason, -1);
            break;
       case REW_HEAL_FUL:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Rise, my servant!'");
            restore_level();
            set_poisoned(0, TRUE);
            set_blind(0, TRUE);
            set_confused(0, TRUE);
            set_image(0, TRUE);
            set_stun(0, TRUE);
            set_cut(0, TRUE);
            hp_player(5000);
            for (dummy = 0; dummy < 6; dummy++)
                do_res_stat(dummy);
            break;
        case REW_CURSE_WP:
        {
            int slot = equip_random_slot(object_is_melee_weapon);
            if (slot)
            {
                msg_format("The voice of %s booms out:",
                    chaos_patrons[p_ptr->chaos_patron]);
                msg_print("'Thou reliest too much on thy weapon.'");
                curse_weapon(FALSE, slot);
            }
            break;
        }
        case REW_CURSE_AR:
        {
            int slot = equip_random_slot(object_is_armour);
            if (slot)
            {
                msg_format("The voice of %s booms out:",
                    chaos_patrons[p_ptr->chaos_patron]);
                msg_print("'Thou reliest too much on thine equipment.'");
                curse_armor(slot);
            }
            break;
        }
        case REW_PISS_OFF:
            msg_format("The voice of %s whispers:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Now thou shalt pay for annoying me.'");
            switch (randint1(4))
            {
                case 1:
                    activate_ty_curse(FALSE, &count);
                    break;
                case 2:
                    activate_hi_summon(py, px, FALSE);
                    break;
                case 3:
                    if (one_in_(2))
                    {
                        int slot = equip_random_slot(object_is_melee_weapon);
                        if (slot)
                            curse_weapon(FALSE, slot);
                    }
                    else
                    {
                        int slot = equip_random_slot(object_is_armour);
                        if (slot)
                            curse_armor(slot);
                    }
                    break;
                default:
                    for (dummy = 0; dummy < 6; dummy++)
                        dec_stat(dummy, 10 + randint1(15), TRUE);
                    break;
            }
            break;
        case REW_WRATH:
            msg_format("The voice of %s thunders:", chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Die, mortal!'");

            take_hit(DAMAGE_LOSELIFE, p_ptr->lev * 4, wrath_reason, -1);
            for (dummy = 0; dummy < 6; dummy++)
                dec_stat(dummy, 10 + randint1(15), FALSE);
            activate_hi_summon(py, px, FALSE);
            activate_ty_curse(FALSE, &count);
            if (one_in_(2))
            {
                int slot = equip_random_slot(object_is_melee_weapon);
                if (slot)
                    curse_weapon(FALSE, slot);
            }
            if (one_in_(2))
            {
                int slot = equip_random_slot(object_is_armour);
                if (slot)
                    curse_armor(slot);
            }
            break;
        case REW_DESTRUCT:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Death and destruction! This pleaseth me!'");
            destroy_area(py, px, 25, 3 * p_ptr->lev);
            break;
        case REW_GENOCIDE:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Let me relieve thee of thine oppressors!'");
            symbol_genocide(0, FALSE);
            break;
        case REW_MASS_GEN:
            msg_format("The voice of %s booms out:",
                chaos_patrons[p_ptr->chaos_patron]);
            msg_print("'Let me relieve thee of thine oppressors!'");
            mass_genocide(0, FALSE);
            break;
        case REW_DISPEL_C:
            msg_format("You can feel the power of %s assault your enemies!",
                chaos_patrons[p_ptr->chaos_patron]);
            dispel_monsters(p_ptr->lev * 4);
            break;
        case REW_IGNORE:
            msg_format("%s ignores you.",
                chaos_patrons[p_ptr->chaos_patron]);
            break;
        case REW_SER_DEMO:
            msg_format("%s rewards you with a demonic servant!",chaos_patrons[p_ptr->chaos_patron]);
            if (!summon_specific(-1, py, px, dun_level, SUMMON_DEMON, PM_FORCE_PET))
                msg_print("Nobody ever turns up...");
            break;
        case REW_SER_MONS:
            msg_format("%s rewards you with a servant!",chaos_patrons[p_ptr->chaos_patron]);
            if (!summon_specific(-1, py, px, dun_level, 0, PM_FORCE_PET))
                msg_print("Nobody ever turns up...");
            break;
        case REW_SER_UNDE:
            msg_format("%s rewards you with an undead servant!",chaos_patrons[p_ptr->chaos_patron]);
            if (!summon_specific(-1, py, px, dun_level, SUMMON_UNDEAD, PM_FORCE_PET))
                msg_print("Nobody ever turns up...");
            break;
        default:
            msg_format("The voice of %s stammers:", chaos_patrons[p_ptr->chaos_patron]);
            msg_format("'Uh... uh... the answer's %d/%d, what's the question?'", type, effect);
        }
    }
}
Beispiel #2
0
/*
 * Perform the basic "disarm" command
 *
 * Assume there is no monster blocking the destination
 *
 * Returns TRUE if repeated commands may continue
 */
static bool do_cmd_disarm_aux(int y, int x)
{
	int i, j, power;

	const char *name;

	bool more = FALSE;


	/* Verify legality */
	if (!do_cmd_disarm_test(y, x)) return (FALSE);


	/* Get the trap name */
	name = f_info[cave->feat[y][x]].name;

	/* Get the "disarm" factor */
	i = p_ptr->state.skills[SKILL_DISARM];

	/* Penalize some conditions */
	if (p_ptr->timed[TMD_BLIND] || no_light()) i = i / 10;
	if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) i = i / 10;

	/* XXX XXX XXX Variable power? */

	/* Extract trap "power" */
	power = 5;

	/* Extract the difficulty */
	j = i - power;

	/* Always have a small chance of success */
	if (j < 2) j = 2;

	/* Success */
	if (randint0(100) < j)
	{
		/* Message */
		msgt(MSG_DISARM, "You have disarmed the %s.", name);

		/* Reward */
		player_exp_gain(p_ptr, power);

		/* Forget the trap */
		cave->info[y][x] &= ~(CAVE_MARK);

		/* Remove the trap */
		cave_set_feat(cave, y, x, FEAT_FLOOR);
	}

	/* Failure -- Keep trying */
	else if ((i > 5) && (randint1(i) > 5))
	{
		flush();

		/* Message */
		msg("You failed to disarm the %s.", name);

		/* We may keep trying */
		more = TRUE;
	}

	/* Failure -- Set off the trap */
	else
	{
		/* Message */
		msg("You set off the %s!", name);

		/* Hit the trap */
		hit_trap(y, x);
	}

	/* Result */
	return (more);
}
Beispiel #3
0
/*
 * Allocate objects upon opening a chest
 *
 * Disperse treasures from the given chest, centered at (x,y).
 *
 * Small chests often contain "gold", while Large chests always contain
 * items.  Wooden chests contain 2 items, Iron chests contain 4 items,
 * and Steel chests contain 6 items.  The "value" of the items in a
 * chest is based on the level on which the chest is generated.
 */
static void chest_death(int y, int x, s16b o_idx)
{
	int number, value;

	bool tiny;

	object_type *o_ptr;

	object_type *i_ptr;
	object_type object_type_body;


	/* Get the chest */
	o_ptr = object_byid(o_idx);

	/* Small chests often hold "gold" */
	tiny = (o_ptr->sval < SV_CHEST_MIN_LARGE);

	/* Determine how much to drop (see above) */
	number = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2;

	/* Zero pval means empty chest */
	if (!o_ptr->pval[DEFAULT_PVAL]) number = 0;

	/* Determine the "value" of the items */
	value = o_ptr->origin_depth - 10 + 2 * o_ptr->sval;
	if (value < 1)
		value = 1;

	/* Drop some objects (non-chests) */
	for (; number > 0; --number)
	{
		/* Get local object */
		i_ptr = &object_type_body;

		/* Wipe the object */
		object_wipe(i_ptr);

		/* Small chests often drop gold */
		if (tiny && (randint0(100) < 75))
			make_gold(i_ptr, value, SV_GOLD_ANY);

		/* Otherwise drop an item, as long as it isn't a chest */
		else {
			if (!make_object(cave, i_ptr, value, FALSE, FALSE, NULL)) continue;
			if (i_ptr->tval == TV_CHEST) continue;
		}

		/* Record origin */
		i_ptr->origin = ORIGIN_CHEST;
		i_ptr->origin_depth = o_ptr->origin_depth;

		/* Drop it in the dungeon */
		drop_near(cave, i_ptr, 0, y, x, TRUE);
	}

	/* Empty */
	o_ptr->pval[DEFAULT_PVAL] = 0;

	/* Known */
	object_notice_everything(o_ptr);
}
Beispiel #4
0
/*
 * Search for hidden things.  Returns true if a search was attempted, returns
 * false when the player has a 0% chance of finding anything.  Prints messages
 * for negative confirmation when verbose mode is requested.
 */
bool search(bool verbose)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int y, x, chance;

	bool found = FALSE;

	object_type *o_ptr;


	/* Start with base search ability */
	chance = p_ptr->state.skills[SKILL_SEARCH];

	/* Penalize various conditions */
	if (p_ptr->timed[TMD_BLIND] || no_light()) chance = chance / 10;
	if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) chance = chance / 10;

	/* Prevent fruitless searches */
	if (chance <= 0)
	{
		if (verbose)
		{
			msg("You can't make out your surroundings well enough to search.");

			/* Cancel repeat */
			disturb(p_ptr, 0, 0);
		}

		return FALSE;
	}

	/* Search the nearby grids, which are always in bounds */
	for (y = (py - 1); y <= (py + 1); y++)
	{
		for (x = (px - 1); x <= (px + 1); x++)
		{
			/* Sometimes, notice things */
			if (randint0(100) < chance)
			{
				/* Invisible trap */
				if (cave->feat[y][x] == FEAT_INVIS)
				{
					found = TRUE;

					/* Pick a trap */
					pick_trap(y, x);

					/* Message */
					msg("You have found a trap.");

					/* Disturb */
					disturb(p_ptr, 0, 0);
				}

				/* Secret door */
				if (cave->feat[y][x] == FEAT_SECRET)
				{
					found = TRUE;

					/* Message */
					msg("You have found a secret door.");

					/* Pick a door */
					place_closed_door(cave, y, x);

					/* Disturb */
					disturb(p_ptr, 0, 0);
				}

				/* Scan all objects in the grid */
				for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
				{
					/* Skip non-chests */
					if (o_ptr->tval != TV_CHEST) continue;

					/* Skip disarmed chests */
					if (o_ptr->pval[DEFAULT_PVAL] <= 0) continue;

					/* Skip non-trapped chests */
					if (!chest_traps[o_ptr->pval[DEFAULT_PVAL]]) continue;

					/* Identify once */
					if (!object_is_known(o_ptr))
					{
						found = TRUE;

						/* Message */
						msg("You have discovered a trap on the chest!");

						/* Know the trap */
						object_notice_everything(o_ptr);

						/* Notice it */
						disturb(p_ptr, 0, 0);
					}
				}
			}
		}
	}

	if (verbose && !found)
	{
		if (chance >= 100)
			msg("There are no secrets here.");
		else
			msg("You found nothing.");
	}

	return TRUE;
}
Beispiel #5
0
/*
 * Do an effect, given an object.
 * Boost is the extent to which skill surpasses difficulty, used as % boost. It
 * ranges from 0 to 138.
 */
bool effect_do(effect_type effect, bool *ident, bool aware, int dir, int beam,
	int boost)
{
	int py = p_ptr->py;
	int px = p_ptr->px;
	int dam, chance;

	if (effect < 1 || effect > EF_MAX)
	{
		msg_print("Bad effect passed to do_effect().  Please report this bug.");
		return FALSE;
	}

	switch (effect)
	{
		case EF_POISON:
		{
			if (!p_ptr->state.resist_pois)
			{
				if (!p_ptr->timed[TMD_OPP_POIS] &&
					inc_timed(TMD_POISONED, damroll(2, 7)
					+ 10, TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_RES_POIS);

			return TRUE;
		}

		case EF_BLIND:
		{
			if (!p_ptr->state.resist_blind)
			{
				if (inc_timed(TMD_BLIND, damroll(4, 25) + 75,
					TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_RES_BLIND);

			return TRUE;
		}

		case EF_SCARE:
		{
			if (!p_ptr->state.resist_fear)
			{
				if (inc_timed(TMD_AFRAID, randint0(10) + 10,
					TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_RES_FEAR);

			return TRUE;
		}

		case EF_CONFUSE:
		{
			if (!p_ptr->state.resist_confu)
			{
				if (inc_timed(TMD_CONFUSED, damroll(4, 5) + 10,
					TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_RES_CONFU);

			return TRUE;
		}

		case EF_HALLUC:
		{
			if (!p_ptr->state.resist_chaos)
			{
				if (inc_timed(TMD_IMAGE, randint0(250) + 250,
					TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_RES_CHAOS);

			return TRUE;
		}

		case EF_PARALYZE:
		{
			if (!p_ptr->state.free_act)
			{
				if (inc_timed(TMD_PARALYZED, randint0(5) + 5,
					TRUE))
					*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_FREE_ACT);

			return TRUE;
		}

		case EF_SLOW:
		{
			if (inc_timed(TMD_SLOW, randint1(25) + 15, TRUE))
			*ident = TRUE;
			return TRUE;
		}

		case EF_CURE_POISON:
		{
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_BLINDNESS:
		{
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_PARANOIA:
		{
			if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_CONFUSION:
		{
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_MIND:
		{
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_IMAGE, TRUE)) *ident = TRUE;
			if (!p_ptr->state.resist_confu &&
				inc_timed(TMD_OPP_CONF, damroll(4, 10), TRUE))
			    	*ident = TRUE;
			return TRUE;
		}

		case EF_CURE_BODY:
		{
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			return TRUE;
		}


		case EF_CURE_LIGHT:
		{
			if (heal_player(15, 15)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (dec_timed(TMD_CUT, 20, TRUE)) *ident = TRUE;
			if (dec_timed(TMD_CONFUSED, 20, TRUE)) *ident = TRUE;

			return TRUE;
		}

		case EF_CURE_SERIOUS:
		{
			if (heal_player(20, 25)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;

			return TRUE;
		}

		case EF_CURE_CRITICAL:
		{
			if (heal_player(25, 30)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE;

			return TRUE;
		}

		case EF_CURE_FULL:
		{
			int amt = (p_ptr->mhp * 35) / 100;
			if (amt < 300) amt = 300;

			if (hp_player(amt)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_FULL2:
		{
			if (hp_player(1200)) *ident = TRUE;
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_TEMP:
		{
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL1:
		{
			if (hp_player(500)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL2:
		{
			if (hp_player(1000)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL3:
		{
			if (hp_player(500)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_GAIN_EXP:
		{
			if (p_ptr->exp < PY_MAX_EXP)
			{
				msg_print("You feel more experienced.");
				gain_exp(100000L);
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_LOSE_EXP:
		{
			if (!p_ptr->state.hold_life && (p_ptr->exp > 0))
			{
				msg_print("You feel your memories fade.");
				lose_exp(p_ptr->exp / 4);
				*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(OF_HOLD_LIFE);
			return TRUE;
		}

		case EF_RESTORE_EXP:
		{
			if (restore_level()) *ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_MANA:
		{
			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				msg_print("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_GAIN_STR:
		case EF_GAIN_INT:
		case EF_GAIN_WIS:
		case EF_GAIN_DEX:
		case EF_GAIN_CON:
		case EF_GAIN_CHR:
		{
			int stat = effect - EF_GAIN_STR;
			if (do_inc_stat(stat)) *ident = TRUE;
			return TRUE;
		}

		case EF_GAIN_ALL:
		{
			if (do_inc_stat(A_STR)) *ident = TRUE;
			if (do_inc_stat(A_INT)) *ident = TRUE;
			if (do_inc_stat(A_WIS)) *ident = TRUE;
			if (do_inc_stat(A_DEX)) *ident = TRUE;
			if (do_inc_stat(A_CON)) *ident = TRUE;
			if (do_inc_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_BRAWN:
		{
			/* Pick a random stat to decrease other than strength */
			int stat = randint0(A_MAX-1) + 1;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_STR);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_INTELLECT:
		{
			/* Pick a random stat to decrease other than intelligence */
			int stat = randint0(A_MAX-1);
			if (stat >= A_INT) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_INT);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_CONTEMPLATION:
		{
			/* Pick a random stat to decrease other than wisdom */
			int stat = randint0(A_MAX-1);
			if (stat >= A_WIS) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_WIS);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_TOUGHNESS:
		{
			/* Pick a random stat to decrease other than constitution */
			int stat = randint0(A_MAX-1);
			if (stat >= A_CON) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_CON);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_NIMBLENESS:
		{
			/* Pick a random stat to decrease other than dexterity */
			int stat = randint0(A_MAX-1);
			if (stat >= A_DEX) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_DEX);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_PLEASING:
		{
			/* Pick a random stat to decrease other than charisma */
			int stat = randint0(A_MAX-1);

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_CHR);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_LOSE_STR:
		case EF_LOSE_INT:
		case EF_LOSE_WIS:
		case EF_LOSE_DEX:
		case EF_LOSE_CON:
		case EF_LOSE_CHR:
		{
			int stat = effect - EF_LOSE_STR;

			take_hit(damroll(5, 5), "stat drain");
			(void)do_dec_stat(stat, FALSE);
			*ident = TRUE;

			return TRUE;
		}

		case EF_LOSE_CON2:
		{
			take_hit(damroll(10, 10), "poisonous food");
			(void)do_dec_stat(A_CON, FALSE);
			*ident = TRUE;

			return TRUE;
		}

		case EF_RESTORE_STR:
		case EF_RESTORE_INT:
		case EF_RESTORE_WIS:
		case EF_RESTORE_DEX:
		case EF_RESTORE_CON:
		case EF_RESTORE_CHR:
		{
			int stat = effect - EF_RESTORE_STR;
			if (do_res_stat(stat)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_NONORLYBIG:
		{
			msg_print("You feel life flow through your body!");
			restore_level();
			(void)clear_timed(TMD_POISONED, TRUE);
			(void)clear_timed(TMD_BLIND, TRUE);
			(void)clear_timed(TMD_CONFUSED, TRUE);
			(void)clear_timed(TMD_IMAGE, TRUE);
			(void)clear_timed(TMD_STUN, TRUE);
			(void)clear_timed(TMD_CUT, TRUE);
			(void)clear_timed(TMD_AMNESIA, TRUE);

			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;

			/* Recalculate max. hitpoints */
			update_stuff();

			hp_player(5000);

			*ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_ALL:
		{
			/* Life, above, also gives these effects */
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_ST_LEV:
		{
			if (restore_level()) *ident = TRUE;
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_TMD_INFRA:
		{
			if (inc_timed(TMD_SINFRA, 100 + damroll(4, 25), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_TMD_SINVIS:
		{
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (inc_timed(TMD_SINVIS, 12 + damroll(2, 6), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_TMD_ESP:
		{
			if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE;
			if (inc_timed(TMD_TELEPATHY, 12 + damroll(6, 6), TRUE))
				*ident = TRUE;
			return TRUE;
		}


		case EF_ENLIGHTENMENT:
		{
			msg_print("An image of your surroundings forms in your mind...");
			wiz_light();
			*ident = TRUE;
			return TRUE;
		}


		case EF_ENLIGHTENMENT2:
		{
			msg_print("You begin to feel more enlightened...");
			message_flush();
			wiz_light();
			(void)do_inc_stat(A_INT);
			(void)do_inc_stat(A_WIS);
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			(void)detect_treasure(TRUE);
			identify_pack();
			*ident = TRUE;
			return TRUE;
		}

		case EF_HERO:
		{
			if (hp_player(10)) *ident = TRUE;
			if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE;
			if (inc_timed(TMD_HERO, randint1(25) + 25, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_SHERO:
		{
			if (hp_player(30)) *ident = TRUE;
			if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE;
			if (inc_timed(TMD_SHERO, randint1(25) + 25, TRUE))
				*ident = TRUE;
			return TRUE;
		}


		case EF_RESIST_ACID:
		{
			if (inc_timed(TMD_OPP_ACID, randint1(10) + 10, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_ELEC:
		{
			if (inc_timed(TMD_OPP_ELEC, randint1(10) + 10, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_FIRE:
		{
			if (inc_timed(TMD_OPP_FIRE, randint1(10) + 10, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_COLD:
		{
			if (inc_timed(TMD_OPP_COLD, randint1(10) + 10, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_POIS:
		{
			if (inc_timed(TMD_OPP_POIS, randint1(10) + 10, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_ALL:
		{
			if (inc_timed(TMD_OPP_ACID, randint1(20) + 20, TRUE))
				*ident = TRUE;
			if (inc_timed(TMD_OPP_ELEC, randint1(20) + 20, TRUE))
				*ident = TRUE;
			if (inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE))
				*ident = TRUE;
			if (inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE))
				*ident = TRUE;
			if (inc_timed(TMD_OPP_POIS, randint1(20) + 20, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_TREASURE:
		{
			if (detect_treasure(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_TRAP:
		{
			if (detect_traps(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_DOORSTAIR:
		{
			if (detect_doorstairs(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_INVIS:
		{
			if (detect_monsters_invis(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_EVIL:
		{
			if (detect_monsters_evil(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_ALL:
		{
			if (detect_all(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_ENCHANT_TOHIT:
		{
			*ident = TRUE;
			if (!enchant_spell(1, 0, 0)) return FALSE;
			return TRUE;
		}

		case EF_ENCHANT_TODAM:
		{
			*ident = TRUE;
			if (!enchant_spell(0, 1, 0)) return FALSE;
			return TRUE;
		}

		case EF_ENCHANT_WEAPON:
		{
			*ident = TRUE;
			if (!enchant_spell(randint1(3), randint1(3), 0))
				return FALSE;
			return TRUE;
		}

		case EF_ENCHANT_ARMOR:
		{
			*ident = TRUE;
			if (!enchant_spell(0, 0, 1)) return FALSE;
			return TRUE;
		}

		case EF_ENCHANT_ARMOR2:
		{
			*ident = TRUE;
			if (!enchant_spell(0, 0, randint1(3) + 2)) return FALSE;
			return TRUE;
		}

		case EF_IDENTIFY:
		{
			*ident = TRUE;
			if (!ident_spell()) return FALSE;
			return TRUE;
		}

		case EF_REMOVE_CURSE:
		{
			if (remove_curse())
			{
				if (!p_ptr->timed[TMD_BLIND])
					msg_print("The air around your body glows blue for a moment...");
				else
					msg_print("You feel as if someone is watching over you.");

				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_REMOVE_CURSE2:
		{
			remove_all_curse();
			*ident = TRUE;
			return TRUE;
		}

		case EF_LIGHT:
		{
			if (light_area(damroll(2, 8), 2)) *ident = TRUE;
			return TRUE;
		}

		case EF_SUMMON_MON:
		{
			int i;
			sound(MSG_SUM_MONSTER);

			for (i = 0; i < randint1(3); i++)
			{
				if (summon_specific(py, px, p_ptr->depth, 0, 1))
					*ident = TRUE;
			}
			return TRUE;
		}

		case EF_SUMMON_UNDEAD:
		{
			int i;
			sound(MSG_SUM_UNDEAD);

			for (i = 0; i < randint1(3); i++)
			{
				if (summon_specific(py, px, p_ptr->depth,
					SUMMON_UNDEAD, 1))
					*ident = TRUE;
			}
			return TRUE;
		}

		case EF_TELE_PHASE:
		{
			teleport_player(10);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_LONG:
		{
			teleport_player(100);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_LEVEL:
		{
			(void)teleport_player_level();
			*ident = TRUE;
			return TRUE;
		}

		case EF_CONFUSING:
		{
			if (p_ptr->confusing == 0)
			{
				msg_print("Your hands begin to glow.");
				p_ptr->confusing = TRUE;
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_MAPPING:
		{
			map_area();
			*ident = TRUE;
			return TRUE;
		}

		case EF_RUNE:
		{
			warding_glyph();
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACQUIRE:
		{
			acquirement(py, px, p_ptr->depth, 1, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACQUIRE2:
		{
			acquirement(py, px, p_ptr->depth, randint1(2) + 1,
				TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ANNOY_MON:
		{
			msg_print("There is a high pitched humming noise.");
			aggravate_monsters(0);
			*ident = TRUE;
			return TRUE;
		}

		case EF_CREATE_TRAP:
		{
			/* Hack -- no traps in the town */
			if (p_ptr->depth == 0)
				return TRUE;

			trap_creation();
			msg_print("You hear a low-pitched whistling sound.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DESTROY_TDOORS:
		{
			if (destroy_doors_touch()) *ident = TRUE;
			return TRUE;
		}

		case EF_RECHARGE:
		{
			*ident = TRUE;
			if (!recharge(60)) return FALSE;
			return TRUE;
		}

		case EF_BANISHMENT:
		{
			*ident = TRUE;
			if (!banishment()) return FALSE;
			return TRUE;
		}

		case EF_DARKNESS:
		{
			if ((!p_ptr->state.resist_blind) && (!p_ptr->state.resist_dark))
				(void)inc_timed(TMD_BLIND, 3 + randint1(5), TRUE);

			unlight_area(10, 3);

			wieldeds_notice_flag(OF_RES_BLIND);
			wieldeds_notice_flag(OF_RES_DARK);

			*ident = TRUE;
			return TRUE;
		}

		case EF_PROTEVIL:
		{
			if (inc_timed(TMD_PROTEVIL, randint1(25) + 3 *
				p_ptr->lev, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_SATISFY:
		{
			if (set_food(PY_FOOD_MAX - 1)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURSE_WEAPON:
		{
			if (curse_weapon()) *ident = TRUE;
			return TRUE;
		}

		case EF_CURSE_ARMOR:
		{
			if (curse_armor()) *ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING:
		{
			if (inc_timed(TMD_BLESSED, randint1(12) + 6, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING2:
		{
			if (inc_timed(TMD_BLESSED, randint1(24) + 12, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING3:
		{
			if (inc_timed(TMD_BLESSED, randint1(48) + 24, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RECALL:
		{
			set_recall();
			*ident = TRUE;
			return TRUE;
		}

		case EF_DEEP_DESCENT:
		{
			int i, target_depth = p_ptr->depth;
			
			/* Calculate target depth */
			for (i = 2; i > 0; i--)
			{
				if (is_quest(target_depth)) break;
				if (target_depth >= MAX_DEPTH - 1) break;
				
				target_depth++;
			}

			if (target_depth > p_ptr->depth)
			{
				message(MSG_TPLEVEL, 0, "You sink through the floor...");
				dungeon_change_level(target_depth);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_LOSHASTE:
		{
			if (speed_monsters()) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSSLEEP:
		{
			if (sleep_monsters(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSSLOW:
		{
			if (slow_monsters()) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSCONF:
		{
			if (confuse_monsters(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSKILL:
		{
			(void)mass_banishment();
			*ident = TRUE;
			return TRUE;
		}

		case EF_EARTHQUAKES:
		{
			earthquake(py, px, 10);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DESTRUCTION2:
		{
			destroy_area(py, px, 15, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ILLUMINATION:
		{
			if (light_area(damroll(2, 15), 3)) *ident = TRUE;
			return TRUE;
		}

		case EF_CLAIRVOYANCE:
		{
			*ident = TRUE;
			wiz_light();
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			return TRUE;
		}

		case EF_PROBING:
		{
			*ident = probing();
			return TRUE;
		}

		case EF_STONE_TO_MUD:
		{
			if (wall_to_mud(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_CONFUSE2:
		{
			*ident = TRUE;
			confuse_monster(dir, 20, aware);
			return TRUE;
		}

		case EF_BIZARRE:
		{
			*ident = TRUE;
			ring_of_power(dir);
			return TRUE;
		}

		case EF_STAR_BALL:
		{
			int i;
			*ident = TRUE;
			for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i],
				(150 * (100 + boost) / 100), 3);
			return TRUE;
		}

		case EF_RAGE_BLESS_RESIST:
		{
			*ident = TRUE;
			(void)hp_player(30);
			(void)clear_timed(TMD_AFRAID, TRUE);
			(void)inc_timed(TMD_SHERO, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_BLESSED, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_OPP_ACID, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_OPP_ELEC, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_OPP_FIRE, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_OPP_COLD, randint1(50) + 50, TRUE);
			(void)inc_timed(TMD_OPP_POIS, randint1(50) + 50, TRUE);
			return TRUE;
		}

		case EF_SLEEPII:
		{
			*ident = TRUE;
			sleep_monsters_touch(aware);
			return TRUE;
		}

		case EF_RESTORE_LIFE:
		{
			*ident = TRUE;
			restore_level();
			return TRUE;
		}

		case EF_MISSILE:
		{
			*ident = TRUE;
			dam = damroll(3, 4) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_MISSILE, dir, dam);
			return TRUE;
		}

		case EF_DISPEL_EVIL:
		{
			*ident = TRUE;
			dam = p_ptr->lev * 5 * (100 + boost) / 100;
			dispel_evil(dam);
			return TRUE;
		}

		case EF_DISPEL_EVIL60:
		{
			dam = 60 * (100 + boost) / 100;
			if (dispel_evil(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISPEL_UNDEAD:
		{
			dam = 60 * (100 + boost) / 100;
			if (dispel_undead(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISPEL_ALL:
		{
			dam = 120 * (100 + boost) / 100;
			if (dispel_monsters(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_HASTE:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (set_timed(TMD_FAST, damroll(2, 10) + 20, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)inc_timed(TMD_FAST, 5, TRUE);
			}

			return TRUE;
		}

		case EF_HASTE1:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (set_timed(TMD_FAST, randint1(20) + 20, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)inc_timed(TMD_FAST, 5, TRUE);
			}

			return TRUE;
		}

		case EF_HASTE2:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (set_timed(TMD_FAST, randint1(75) + 75, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)inc_timed(TMD_FAST, 5, TRUE);
			}

			return TRUE;
		}


		case EF_FIRE_BOLT:
		{
			*ident = TRUE;
			dam = damroll(9, 8) * (100 + boost) / 100;
			fire_bolt(GF_FIRE, dir, dam);
			return TRUE;
		}

		case EF_FIRE_BOLT2:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_FIRE, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BOLT3:
		{
			dam = damroll(16, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_FIRE, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BOLT72:
		{
			dam = 72 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 2);
			return TRUE;
		}

		case EF_FIRE_BALL:
		{
			dam = 144 * (100 + boost) / 100;
			fire_ball(GF_FIRE, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BALL2:
		{
			dam = 120 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 3);
			return TRUE;
		}

		case EF_FIRE_BALL200:
		{
			dam = 200 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 3);
			return TRUE;
		}

		case EF_COLD_BOLT:
		{
			dam = damroll(6, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt_or_beam(beam, GF_COLD, dir, dam);
			return TRUE;
		}

		case EF_COLD_BOLT2:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_COLD, dir, dam);
			return TRUE;
		}

		case EF_COLD_BALL2:
		{
			dam = 200 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 3);
			return TRUE;
		}

		case EF_COLD_BALL50:
		{
			dam = 50 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			return TRUE;
		}

		case EF_COLD_BALL100:
		{
			dam = 100 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			return TRUE;
		}

		case EF_COLD_BALL160:
		{
			dam = 160 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 3);
			return TRUE;
		}

		case EF_ACID_BOLT:
		{
			dam = damroll(5, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_ACID, dir, dam);
			return TRUE;
		}

		case EF_ACID_BOLT2:
		{
			dam = damroll(10, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_ACID, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACID_BOLT3:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_ACID, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACID_BALL:
		{
			dam = 120 * (100 + boost) / 100;
			fire_ball(GF_ACID, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ELEC_BOLT:
		{
			dam = damroll(6, 6) * (100 + boost) / 100;
			*ident = TRUE;
			fire_beam(GF_ELEC, dir, dam);
			return TRUE;
		}

		case EF_ELEC_BALL:
		{
			dam = 64 * (100 + boost) / 100;
			fire_ball(GF_ELEC, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ELEC_BALL2:
		{
			dam = 250 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ELEC, dir, dam, 3);
			return TRUE;
		}


		case EF_ARROW:
		{
			dam = 150 * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_ARROW, dir, dam);
			return TRUE;
		}

		case EF_REM_FEAR_POIS:
		{
			*ident = TRUE;
			(void)clear_timed(TMD_AFRAID, TRUE);
			(void)clear_timed(TMD_POISONED, TRUE);
			return TRUE;
		}

		case EF_STINKING_CLOUD:
		{
			dam = 12 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_POIS, dir, dam, 3);
			return TRUE;
		}


		case EF_DRAIN_LIFE1:
		{
			dam = 90 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE2:
		{
			dam = 120 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE3:
		{
			dam = 150 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE4:
		{
			dam = 250 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_FIREBRAND:
		{
			*ident = TRUE;
			if (!brand_bolts()) return FALSE;
			return TRUE;
		}

		case EF_MANA_BOLT:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt(GF_MANA, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_MON_HEAL:
		{
			if (heal_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_HASTE:
		{
			if (speed_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SLOW:
		{
			if (slow_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_CONFUSE:
		{
			if (confuse_monster(dir, 10, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SLEEP:
		{
			if (sleep_monster(dir, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_CLONE:
		{
			if (clone_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SCARE:
		{
			if (fear_monster(dir, 10, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LIGHT_LINE:
		{
			msg_print("A line of shimmering blue light appears.");
			light_line(dir);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_OTHER:
		{
			if (teleport_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISARMING:
		{
			if (disarm_trap(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_TDOOR_DEST:
		{
			if (destroy_door(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_POLYMORPH:
		{
			if (poly_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_STARLIGHT:
		{
			int i;
			if (!p_ptr->timed[TMD_BLIND])
				msg_print("Light shoots in all directions!");
			for (i = 0; i < 8; i++) light_line(ddd[i]);
			*ident = TRUE;
			return TRUE;
		}

		case EF_STARLIGHT2:
		{
			int k;
			for (k = 0; k < 8; k++) strong_light_line(ddd[k]);
			*ident = TRUE;
			return TRUE;
		}

		case EF_BERSERKER:
		{
			if (inc_timed(TMD_SHERO, randint1(50) + 50, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_WONDER:
		{
			if (effect_wonder(dir, randint1(100) + p_ptr->lev / 5,
				beam)) *ident = TRUE;
			return TRUE;
		}

		case EF_WAND_BREATH:
		{
			/* table of random ball effects and their damages */
			const int breath_types[] = {
				GF_ACID, 200,
				GF_ELEC, 160,
				GF_FIRE, 200,
				GF_COLD, 160,
				GF_POIS, 120
			};
			/* pick a random (type, damage) tuple in the table */
			int which = 2 * randint0(sizeof(breath_types) / (2 * sizeof(int)));
			if (fire_ball(breath_types[which], dir, breath_types[which + 1], 3))
				*ident = TRUE;
			return TRUE;
		}

		case EF_STAFF_MAGI:
		{
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				*ident = TRUE;
				msg_print("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
			}
			return TRUE;
		}

		case EF_STAFF_HOLY:
		{
			dam = 120 * (100 + boost) / 100;
			if (dispel_evil(dam)) *ident = TRUE;
			if (inc_timed(TMD_PROTEVIL, randint1(25) + 3 *
				p_ptr->lev, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE;
			if (hp_player(50)) *ident = TRUE;
			if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE;
			if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_BREATH:
		{
			const int breath_types[] =
			{
				GF_FIRE, 80,
				GF_COLD, 80,
			};

			int which = 2 * randint0(N_ELEMENTS(breath_types) / 2);
			fire_ball(breath_types[which], dir, breath_types[which + 1], 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_GOOD:
		{
			msg_print("You feel less thirsty.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_DEATH:
		{
			msg_print("A feeling of Death flows through your body.");
			take_hit(5000, "a potion of Death");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_RUIN:
		{
			msg_print("Your nerves and muscles feel weak and lifeless!");
			take_hit(damroll(10, 10), "a potion of Ruination");
			(void)dec_stat(A_DEX, TRUE);
			(void)dec_stat(A_WIS, TRUE);
			(void)dec_stat(A_CON, TRUE);
			(void)dec_stat(A_STR, TRUE);
			(void)dec_stat(A_CHR, TRUE);
			(void)dec_stat(A_INT, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_DETONATE:
		{
			msg_print("Massive explosions rupture your body!");
			take_hit(damroll(50, 20), "a potion of Detonation");
			(void)inc_timed(TMD_STUN, 75, TRUE);
			(void)inc_timed(TMD_CUT, 5000, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_SALT:
		{
			msg_print("The potion makes you vomit!");
			(void)set_food(PY_FOOD_STARVE - 1);
			(void)clear_timed(TMD_POISONED, TRUE);
			(void)inc_timed(TMD_PARALYZED, 4, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FOOD_GOOD:
		{
			msg_print("That tastes good.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_FOOD_WAYBREAD:
		{
			msg_print("That tastes good.");
			(void)clear_timed(TMD_POISONED, TRUE);
			(void)hp_player(damroll(4, 8));
			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_EMERGENCY:
		{
			(void)set_timed(TMD_IMAGE, rand_spread(250, 50), TRUE);
			(void)set_timed(TMD_OPP_FIRE, rand_spread(30, 10), TRUE);
			(void)set_timed(TMD_OPP_COLD, rand_spread(30, 10), TRUE);
			(void)hp_player(200);
			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_TERROR:
		{
			if (set_timed(TMD_TERROR, rand_spread(100, 20), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_STONE:
		{
			if (set_timed(TMD_STONESKIN, rand_spread(80, 20), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_DEBILITY:
		{
			int stat = one_in_(2) ? A_STR : A_CON;

			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				msg_print("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
				*ident = TRUE;
			}

			(void)do_dec_stat(stat, FALSE);

			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_SPRINTING:
		{
			if (inc_timed(TMD_SPRINT, 100, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_PURGING:
		{
			(void)set_food(PY_FOOD_FAINT - 1);
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_RING_ACID:
		{
			dam = 70 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ACID, dir, dam, 2);
			inc_timed(TMD_OPP_ACID, randint1(20) + 20, TRUE);
			return TRUE;
		}

		case EF_RING_FLAMES:
		{
			dam = 80 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 2);
			inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE);
			return TRUE;
		}

		case EF_RING_ICE:
		{
			dam = 75 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE);
			return TRUE;
		}

		case EF_RING_LIGHTNING:
		{
			dam = 85 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ELEC, dir, dam, 2);
			inc_timed(TMD_OPP_ELEC, randint1(20) + 20, TRUE);
			return TRUE;
		}

		case EF_DRAGON_BLUE:
		{
			dam = 100 * (100 + boost) / 100;
			message_format(MSG_BR_ELEC, 0, "You breathe lightning.");
			fire_ball(GF_ELEC, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_GREEN:
		{
			dam = 150 * (100 + boost) / 100;
			message_format(MSG_BR_GAS, 0, "You breathe poison gas.");
			fire_ball(GF_POIS, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_RED:
		{
			dam = 200 * (100 + boost) / 100;
			message_format(MSG_BR_FIRE, 0, "You breathe fire.");
			fire_ball(GF_FIRE, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_MULTIHUED:
		{
			static const struct
			{
				int msg_sound;
				const char *msg;
				int typ;
			} mh[] =
			{
				{ MSG_BR_ELEC,  "lightning",  GF_ELEC },
				{ MSG_BR_FROST, "frost",      GF_COLD },
				{ MSG_BR_ACID,  "acid",       GF_ACID },
				{ MSG_BR_GAS,   "poison gas", GF_POIS },
				{ MSG_BR_FIRE,  "fire",       GF_FIRE }
			};

			int chance = randint0(5);
			dam = 250 * (100 + boost) / 100;
			message_format(mh[chance].msg_sound, 0, "You breathe %s.", mh[chance].msg);
			fire_ball(mh[chance].typ, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_BRONZE:
		{
			dam = 120 * (100 + boost) / 100;
			message_format(MSG_BR_CONF, 0, "You breathe confusion.");
			fire_ball(GF_CONFUSION, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_GOLD:
		{
			dam = 130 * (100 + boost) / 100;
			message_format(MSG_BR_SOUND, 0, "You breathe sound.");
			fire_ball(GF_SOUND, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_CHAOS:
		{
			dam = 220 * (100 + boost) / 100;
			chance = randint0(2);
			message_format((chance == 1 ? MSG_BR_CHAOS : MSG_BR_DISENCHANT), 0,
					"You breathe %s.",
					((chance == 1 ? "chaos" : "disenchantment")));
			fire_ball((chance == 1 ? GF_CHAOS : GF_DISENCHANT),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_LAW:
		{
			dam = 230 * (100 + boost) / 100;
			chance = randint0(2);
			message_format((chance == 1 ? MSG_BR_SOUND : MSG_BR_SHARDS), 0, "You breathe %s.",
			           ((chance == 1 ? "sound" : "shards")));
			fire_ball((chance == 1 ? GF_SOUND : GF_SHARD),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_BALANCE:
		{
			dam = 250 * (100 + boost) / 100;
			chance = randint0(4);
			msg_format("You breathe %s.",
			           ((chance == 1) ? "chaos" :
			            ((chance == 2) ? "disenchantment" :
			             ((chance == 3) ? "sound" : "shards"))));
			fire_ball(((chance == 1) ? GF_CHAOS :
			           ((chance == 2) ? GF_DISENCHANT :
			            ((chance == 3) ? GF_SOUND : GF_SHARD))),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_SHINING:
		{
			dam = 200 * (100 + boost) / 100;
			chance = randint0(2);
			message_format((chance == 0 ? MSG_BR_LIGHT : MSG_BR_DARK), 0, "You breathe %s.",
			        ((chance == 0 ? "light" : "darkness")));
			fire_ball((chance == 0 ? GF_LIGHT : GF_DARK), dir, dam,
				2);
			return TRUE;
		}

		case EF_DRAGON_POWER:
		{
			dam = 300 * (100 + boost) / 100;
			message_format(MSG_BR_ELEMENTS, 0, "You breathe the elements.");
			fire_ball(GF_MISSILE, dir, dam, 2);
			return TRUE;
		}

		case EF_TRAP_DOOR:
		case EF_TRAP_PIT:
		case EF_TRAP_PIT_SPIKES:
		case EF_TRAP_PIT_POISON:
		case EF_TRAP_RUNE_SUMMON:
		case EF_TRAP_RUNE_TELEPORT:
		case EF_TRAP_SPOT_FIRE:
		case EF_TRAP_SPOT_ACID:
		case EF_TRAP_DART_SLOW:
		case EF_TRAP_DART_LOSE_STR:
		case EF_TRAP_DART_LOSE_DEX:
		case EF_TRAP_DART_LOSE_CON:
		case EF_TRAP_GAS_BLIND:
		case EF_TRAP_GAS_CONFUSE:
		case EF_TRAP_GAS_POISON:
		case EF_TRAP_GAS_SLEEP:
		{
			break;
		}


		case EF_XXX:
		case EF_MAX:
			break;
	}

	/* Not used */
	msg_print("Effect not handled.");
	return FALSE;
}
Beispiel #6
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;
}
static int _random(int list[])
{
    if (spoiler_hack)
        return list[0];
    return list[randint0(_count(list))];
}
Beispiel #8
0
/**
 * Generate a random dungeon level
 *
 * Hack -- regenerate any "overflow" levels
 *
 * Hack -- allow auto-scumming via a gameplay option.
 *
 * Note that this function resets flow data and grid flags directly.
 * Note that this function does not reset features, monsters, or objects.  
 * Features are left to the town and dungeon generation functions, and 
 * wipe_m_list() and wipe_o_list() handle monsters and objects.
 */
void generate_cave(void)
{
    int y, x, num;

    level_hgt = DUNGEON_HGT;
    level_wid = DUNGEON_WID;
    clear_cave();

    /* The dungeon is not ready */
    character_dungeon = FALSE;

    /* Don't know feeling yet */
    do_feeling = FALSE;

    /* Assume level is not themed. */
    p_ptr->themed_level = 0;

    /* Generate */
    for (num = 0; TRUE; num++) {
	bool okay = TRUE;
	cptr why = NULL;

	/* Reset monsters and objects */
	o_max = 1;
	m_max = 1;


	/* Clear flags and flow information. */
	for (y = 0; y < DUNGEON_HGT; y++) {
	    for (x = 0; x < DUNGEON_WID; x++) {
		/* No flags */
		cave_wipe(cave_info[y][x]);

#ifdef MONSTER_FLOW
		/* No flow */
		cave_cost[y][x] = 0;
		cave_when[y][x] = 0;
#endif				/* MONSTER_FLOW */

	    }
	}


	/* Mega-Hack -- no player in dungeon yet */
	cave_m_idx[p_ptr->py][p_ptr->px] = 0;
	p_ptr->px = p_ptr->py = 0;

	/* Reset the monster generation level */
	monster_level = p_ptr->depth;

	/* Reset the object generation level */
	object_level = p_ptr->depth;

	/* Nothing good here yet */
	rating = 0;

	/* Only group is the player */
	group_id = 1;

	/* Set the number of wilderness "vaults" */
	wild_vaults = 0;
	if (p_ptr->depth > 10)
	    wild_vaults += randint0(2);
	if (p_ptr->depth > 20)
	    wild_vaults += randint0(2);
	if (p_ptr->depth > 30)
	    wild_vaults += randint0(2);
	if (p_ptr->depth > 40)
	    wild_vaults += randint0(2);
	if (no_vault())
	    wild_vaults = 0;

	/* Build the town */
	if (!p_ptr->depth) {
	    /* Make a town */
	    town_gen();
	}

	/* Not town */
	else {
	    /* It is possible for levels to be themed. */
	    if ((randint0(THEMED_LEVEL_CHANCE) == 0) && build_themed_level()) {
		/* Message. */
		if (OPT(cheat_room))
		    msg_print("Themed level");
	    }

	    /* Build a real stage */
	    else {
		switch (stage_map[p_ptr->stage][STAGE_TYPE]) {
		case CAVE:
		    {
			cave_gen();
			break;
		    }

		case VALLEY:
		    {
			valley_gen();
			break;
		    }

		case MOUNTAIN:
		    {
			mtn_gen();
			break;
		    }

		case MOUNTAINTOP:
		    {
			mtntop_gen();
			break;
		    }

		case FOREST:
		    {
			forest_gen();
			break;
		    }

		case SWAMP:
		    {
			swamp_gen();
			break;
		    }

		case RIVER:
		    {
			river_gen();
			break;
		    }

		case DESERT:
		    {
			desert_gen();
			break;
		    }

		case PLAIN:
		    {
			plain_gen();
		    }
		}
	    }
	}

	okay = TRUE;


	/* Extract the feeling */
	if (rating > 50 + p_ptr->depth)
	    feeling = 2;
	else if (rating > 40 + 4 * p_ptr->depth / 5)
	    feeling = 3;
	else if (rating > 30 + 3 * p_ptr->depth / 5)
	    feeling = 4;
	else if (rating > 20 + 2 * p_ptr->depth / 5)
	    feeling = 5;
	else if (rating > 15 + 1 * p_ptr->depth / 3)
	    feeling = 6;
	else if (rating > 10 + 1 * p_ptr->depth / 5)
	    feeling = 7;
	else if (rating > 5 + 1 * p_ptr->depth / 10)
	    feeling = 8;
	else if (rating > 0)
	    feeling = 9;
	else
	    feeling = 10;

	/* Hack -- no feeling in the town */
	if (!p_ptr->depth)
	    feeling = 0;


	/* Prevent object over-flow */
	if (o_max >= z_info->o_max) {
	    /* Message */
	    why = "too many objects";

	    /* Message */
	    okay = FALSE;
	}

	/* Prevent monster over-flow */
	if (m_max >= z_info->m_max) {
	    /* Message */
	    why = "too many monsters";

	    /* Message */
	    okay = FALSE;
	}

	/* Mega-Hack -- "auto-scum" */
	if (OPT(adult_auto_scum) && (num < 100) && !(p_ptr->themed_level)) {
	    int fudge = (no_vault()? 3 : 0);

	    /* Require "goodness" */
	    if ((feeling > fudge + 9)
		|| ((p_ptr->depth >= 5) && (feeling > fudge + 8))
		|| ((p_ptr->depth >= 10) && (feeling > fudge + 7))
		|| ((p_ptr->depth >= 20) && (feeling > fudge + 6))) {
		/* Give message to cheaters */
		if (OPT(cheat_room) || OPT(cheat_hear) || OPT(cheat_peek)
		    || OPT(cheat_xtra)) {
		    /* Message */
		    why = "boring level";
		}

		/* Try again */
		okay = FALSE;
	    }
	}

	/* Message */
	if ((OPT(cheat_room)) && (why))
	    msg_format("Generation restarted (%s)", why);

	/* Accept */
	if (okay)
	    break;

	/* Wipe the objects */
	wipe_o_list();

	/* Wipe the monsters */
	wipe_m_list();

	/* A themed level was generated */
	if (p_ptr->themed_level) {
	    /* Allow the themed level to be generated again */
	    p_ptr->themed_level_appeared &= ~(1L << (p_ptr->themed_level - 1));

	    /* This is not a themed level */
	    p_ptr->themed_level = 0;
	}
    }


    /* The dungeon is ready */
    character_dungeon = TRUE;

    /* Reset path_coord */
    p_ptr->path_coord = 0;

    /* Verify the panel */
    verify_panel();

    /* Apply illumination */
    illuminate();

    /* Reset the number of traps, runes, and thefts on the level. */
    num_trap_on_level = 0;
    number_of_thefts_on_level = 0;
    for (num = 0; num < RUNE_TAIL; num++)
	num_runes_on_level[num] = 0;
}
Beispiel #9
0
/**
 * Builds a store at a given pseudo-location
 *
 * As of 2.8.1 (?) the town is actually centered in the middle of a
 * complete level, and thus the top left corner of the town itself
 * is no longer at (0,0), but rather, at (qy,qx), so the constants
 * in the comments below should be mentally modified accordingly.
 *
 * As of 2.7.4 (?) the stores are placed in a more "user friendly"
 * configuration, such that the four "center" buildings always
 * have at least four grids between them, to allow easy running,
 * and the store doors tend to face the middle of town.
 *
 * The stores now lie inside boxes from 3-9 and 12-18 vertically,
 * and from 7-17, 21-31, 35-45, 49-59.  Note that there are thus
 * always at least 2 open grids between any disconnected walls.
 * 
 * The home only appears if it is the player's home town.
 *
 * Note the use of town_illuminate() to handle all "illumination"
 * and "memorization" issues.
 */
static void build_store(int n, int yy, int xx, int stage)
{
    int y, x, y0, x0, y1, x1, y2, x2, tmp;

    int qy = 0;
    int qx = 0;


    /* Find the "center" of the store */
    y0 = qy + yy * 9 + 6;
    x0 = qx + xx * 11 + 11;

    /* Determine the store boundaries */
    y1 = y0 - (1 + randint1((yy == 0) ? 2 : 1));
    y2 = y0 + (1 + randint1((yy == 1) ? 2 : 1));
    x1 = x0 - (1 + randint1(3));
    x2 = x0 + (1 + randint1(3));

    /* Build an invulnerable rectangular building */
    for (y = y1; y <= y2; y++) {
	for (x = x1; x <= x2; x++) {
	    /* Create the building (or not ... NRM) */
	    if ((n != 7) || (p_ptr->home == stage))
		cave_set_feat(y, x, FEAT_PERM_EXTRA);
	    else
		cave_set_feat(y, x, FEAT_FLOOR);
	}
    }

    /* Pick a door direction (S,N,E,W) */
    tmp = randint0(4);

    /* Re-roll "annoying" doors */
    if (((tmp == 0) && (yy == 1)) || ((tmp == 1) && (yy == 0))
	|| ((tmp == 2) && (xx == 3)) || ((tmp == 3) && (xx == 0))) {
	/* Pick a new direction */
	tmp = randint0(4);
    }

    /* Extract a "door location" */
    switch (tmp) {
	/* Bottom side */
    case 0:
	{
	    y = y2;
	    x = rand_range(x1, x2);
	    break;
	}

	/* Top side */
    case 1:
	{
	    y = y1;
	    x = rand_range(x1, x2);
	    break;
	}

	/* Right side */
    case 2:
	{
	    y = rand_range(y1, y2);
	    x = x2;
	    break;
	}

	/* Left side */
    default:
	{
	    y = rand_range(y1, y2);
	    x = x1;
	    break;
	}
    }

    /* Clear previous contents, add a store door */
    if ((n != 7) || (p_ptr->home == stage))
	cave_set_feat(y, x, FEAT_SHOP_HEAD + n);
    else
	cave_set_feat(y, x, FEAT_FLOOR);
}
int _get_random_counter(void)
{
    return randint0(MAX_WILD_COUNTERS);
}
Beispiel #11
0
/**
 * Generate the "consistent" town features, and place the player
 *
 * Hack -- play with the R.N.G. to always yield the same town
 * layout, including the size and shape of the buildings, the
 * locations of the doorways, and the location of the stairs.
 */
static void town_gen_hack(void)
{
    int i, y, x, k, n, py = 1, px = 1;

    int qy = DUNGEON_HGT / 3;
    int qx = DUNGEON_WID / 3;
    int stage = p_ptr->stage;
    int last_stage = p_ptr->last_stage;

    int rooms[MAX_STORES_BIG + 1];

    bool place = FALSE;
    bool major = FALSE;

    /* Hack -- Use the "simple" RNG */
    Rand_quick = TRUE;

    /* Hack -- Induce consistent town layout */
    for (i = 0; i < 10; i++)
	if (stage == towns[i])
	    Rand_value = seed_town[i];

    if (OPT(adult_dungeon))
	Rand_value = seed_town[0];

    /* Set major town flag if necessary */
    if ((stage > 150) || OPT(adult_dungeon))
	major = TRUE;

    /* Hack - reduce width for minor towns */
    if (!major)
	qx /= 2;

    /* Prepare an Array of "remaining stores", and count them */
    if (major)
	for (n = 0; n < MAX_STORES_BIG; n++)
	    rooms[n] = n;
    else {
	rooms[0] = 9;
	rooms[1] = 3;
	rooms[2] = 4;
	rooms[3] = 7;
	n = 4;
    }

    if (OPT(adult_dungeon))
	rooms[n++] = 9;

    /* No stores for ironmen away from home */
    if ((!OPT(adult_ironman)) || (p_ptr->stage == p_ptr->home)) {
	/* Place two rows of stores */
	for (y = 0; y < 2; y++) {
	    /* Place two, four or five stores per row */
	    for (x = 0; x < (OPT(adult_dungeon) ? 5 : 4); x++) {
		/* Pick a random unplaced store */
		k = ((n <= 1) ? 0 : randint0(n));

		/* Build that store at the proper location */
		build_store(rooms[k], y, x, stage);

		/* Shift the stores down, remove one store */
		rooms[k] = rooms[--n];

		/* Cut short if a minor town */
		if ((x > 0) && !major)
		    break;
	    }
	}
	/* Hack -- Build the 9th store.  Taken from Zangband */
	if (major && !OPT(adult_dungeon))
	    build_store(rooms[0], randint0(2), 4, stage);
    }

    if (OPT(adult_dungeon)) {
	/* Place the stairs */
	while (TRUE) {
	    /* Pick a location at least "three" from the outer walls */
	    y = 1 + rand_range(3, DUNGEON_HGT / 3 - 4);
	    x = 1 + rand_range(3, DUNGEON_WID / 3 - 4);

	    /* Require a "naked" floor grid */
	    if (cave_naked_bold(y, x))
		break;
	}

	/* Clear previous contents, add down stairs */
	cave_set_feat(y, x, FEAT_MORE);


	/* Place the player */
	player_place(y, x);
    }

    else {

	/* Place the paths */
	for (n = 2; n < 6; n++) {
	    /* Pick a path direction for the player if not obvious */
	    if (((!last_stage) || (last_stage == 255)) && (stage_map[stage][n]))
		last_stage = stage_map[stage][n];

	    /* Where did we come from? */
	    if ((last_stage) && (last_stage == stage_map[stage][n]))
		place = TRUE;

	    /* Pick a location at least "three" from the corners */
	    y = 1 + rand_range(3, qy - 4);
	    x = 1 + rand_range(3, qx - 4);

	    /* Shove it to the wall, place the path */
	    switch (n) {
	    case NORTH:
		{
		    y = 1;
		    if (stage_map[stage][n])
			cave_set_feat(y, x, FEAT_MORE_NORTH);
		    break;
		}
	    case EAST:
		{
		    x = qx - 2;
		    if (stage_map[stage][n])
			cave_set_feat(y, x, FEAT_MORE_EAST);
		    break;
		}
	    case SOUTH:
		{
		    y = qy - 2;
		    if (stage_map[stage][n])
			cave_set_feat(y, x, FEAT_MORE_SOUTH);
		    break;
		}
	    case WEST:
		{
		    x = 1;
		    if (stage_map[stage][n])
			cave_set_feat(y, x, FEAT_MORE_WEST);
		}
	    }
	    if (place) {
		py = y;
		px = x;
		place = FALSE;
	    }
	}

	/* Place the player */
	player_place(py, px);
    }

    /* Hack -- use the "complex" RNG */
    Rand_quick = FALSE;
}
bool imitator_cast(bool revenge)
{
    int             n = 0, j;
    int             chance;
    int             minfail = 0;
    int             plev = p_ptr->lev;
    monster_power   spell;
    bool            cast;

    if (p_ptr->confused)
    {
        msg_print("You are too confused!");
        return TRUE;
    }

    if (!p_ptr->mane_num)
    {
        msg_print("You don't remember any action!");
        return FALSE;
    }

    /* get power */
    if (!get_mane_power(&n, revenge)) return FALSE;

    spell = monster_powers[p_ptr->mane_spell[n]];

    /* Spell failure chance */
    chance = spell.manefail;

    /* Reduce failure rate by "effective" level adjustment */
    if (plev > spell.level) chance -= 3 * (plev - spell.level);

    /* Reduce failure rate by 1 stat and DEX adjustment */
    chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[spell.use_stat]] + adj_mag_stat[p_ptr->stat_ind[A_DEX]] - 2) / 2;

    if (spell.manedam) chance = chance * damage / spell.manedam;

    chance += p_ptr->to_m_chance;

    /* Extract the minimum failure rate */
    minfail = adj_mag_fail[p_ptr->stat_ind[spell.use_stat]];

    /* Minimum failure rate */
    if (chance < minfail) chance = minfail;

    /* Stunning makes spells harder */
    if (p_ptr->stun > 50) chance += 25;
    else if (p_ptr->stun) chance += 15;

    /* Always a 5 percent chance of working */
    if (chance > 95) chance = 95;

    /* Failed spell */
    if (randint0(100) < chance)
    {
        if (flush_failure) flush();
        msg_print("You failed to concentrate hard enough!");
        sound(SOUND_FAIL);
    }
    else
    {
        sound(SOUND_ZAP);
        cast = use_mane(p_ptr->mane_spell[n]);
        if (!cast) return FALSE;
    }

    p_ptr->mane_num--;
    for (j = n; j < p_ptr->mane_num;j++)
    {
        p_ptr->mane_spell[j] = p_ptr->mane_spell[j+1];
        p_ptr->mane_dam[j] = p_ptr->mane_dam[j+1];
    }

    energy_use = 100;
    p_ptr->redraw |= (PR_IMITATION);
    p_ptr->window |= (PW_PLAYER);
    p_ptr->window |= (PW_SPELL);
    return TRUE;
}
Beispiel #13
0
static bool cast_priest_spell(int spell, int dir)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int plev = p_ptr->lev;

	int amt;

	switch (spell)
	{
		case PRAYER_DETECT_EVIL:
		{
			(void)detect_monsters_evil(TRUE);
			break;
		}

		case PRAYER_CURE_LIGHT_WOUNDS:
		{
			(void)heal_player(15, 15);
			(void)player_dec_timed(p_ptr, TMD_CUT, 20, TRUE);
			(void)player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_BLESS:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(12) + 12, TRUE, TRUE);
			break;
		}

		case PRAYER_REMOVE_FEAR:
		{
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			break;
		}

		case PRAYER_CALL_LIGHT:
		{
			(void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1);
			break;
		}

		case PRAYER_FIND_TRAPS_DOORS:
		{
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			break;
		}

		case PRAYER_SLOW_POISON:
		{
			(void)player_set_timed(p_ptr, TMD_POISONED, p_ptr->timed[TMD_POISONED] / 2, TRUE);
			break;
		}

		case PRAYER_SCARE_MONSTER:
		{
			(void)fear_monster(dir, plev, TRUE);
			break;
		}

		case PRAYER_PORTAL:
		{
			teleport_player(plev * 3);
			break;
		}

		case PRAYER_CURE_SERIOUS_WOUNDS:
		{
			(void)heal_player(20, 25);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_CHANT:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(24) + 24, TRUE, TRUE);
			break;
		}

		case PRAYER_SANCTUARY:
		{
			(void)sleep_monsters_touch(TRUE);
			break;
		}

		case PRAYER_SATISFY_HUNGER:
		{
			player_set_food(p_ptr, PY_FOOD_MAX - 1);
			break;
		}
		
        /* Remove curse has been removed in 3.4 until curses are redone
		case PRAYER_REMOVE_CURSE:
		{
			remove_curse();
			break;
		}
		*/

		case PRAYER_RESIST_HEAT_COLD:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE);
			break;
		}

		case PRAYER_NEUTRALIZE_POISON:
		{
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			break;
		}

		case PRAYER_ORB_OF_DRAINING:
		{
			fire_ball(GF_HOLY_ORB, dir,
				(damroll(3, 6) + plev +
				 (player_has(PF_ZERO_FAIL)
					? (plev / 2)
					: (plev / 4))),	
				((plev < 30) ? 2 : 3));
			break;
		}

		case PRAYER_CURE_CRITICAL_WOUNDS:
		{
			(void)heal_player(25, 30);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_SENSE_INVISIBLE:
		{
			(void)player_inc_timed(p_ptr, TMD_SINVIS, randint1(24) + 24, TRUE, TRUE);
			break;
		}

		case PRAYER_PROTECTION_FROM_EVIL:
		{
			(void)player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE,
				TRUE);
			break;
		}

		case PRAYER_EARTHQUAKE:
		{
			earthquake(py, px, 10);
			break;
		}

		case PRAYER_SENSE_SURROUNDINGS:
		{
			map_area();
			break;
		}

		case PRAYER_CURE_MORTAL_WOUNDS:
		{
			(void)heal_player(30, 50);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_TURN_UNDEAD:
		{
			(void)turn_undead(TRUE);
			break;
		}

		case PRAYER_PRAYER:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(48) + 48, TRUE, TRUE);
			break;
		}

		case PRAYER_DISPEL_UNDEAD:
		{
			(void)dispel_undead(randint1(plev * 3));
			break;
		}

		case PRAYER_HEAL:
		{
			amt = (p_ptr->mhp * 35) / 100;
                        if (amt < 300) amt = 300;
			
			(void)hp_player(amt);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_DISPEL_EVIL:
		{
			(void)dispel_evil(randint1(plev * 3));
			break;
		}

		case PRAYER_GLYPH_OF_WARDING:
		{
			warding_glyph_spell();
			break;
		}

		case PRAYER_HOLY_WORD:
		{
			(void)dispel_evil(randint1(plev * 4));
			(void)hp_player(1000);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			break;
		}

		case PRAYER_DETECT_MONSTERS:
		{
			(void)detect_monsters_normal(TRUE);
			break;
		}

		case PRAYER_DETECTION:
		{
			(void)detect_all(TRUE);
			break;
		}

		case PRAYER_PERCEPTION:
		{
			return ident_spell();
		}

		case PRAYER_PROBING:
		{
			(void)probing();
			break;
		}

		case PRAYER_CLAIRVOYANCE:
		{
			wiz_light(FALSE);
			break;
		}

		case PRAYER_CURE_SERIOUS_WOUNDS2:
		{
			(void)heal_player(20, 25);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_CURE_MORTAL_WOUNDS2:
		{
			(void)heal_player(30, 50);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_HEALING:
		{
			(void)hp_player(2000);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			break;
		}

		case PRAYER_RESTORATION:
		{
			(void)do_res_stat(A_STR);
			(void)do_res_stat(A_INT);
			(void)do_res_stat(A_WIS);
			(void)do_res_stat(A_DEX);
			(void)do_res_stat(A_CON);
			break;
		}

		case PRAYER_REMEMBRANCE:
		{
			(void)restore_level();
			break;
		}

		case PRAYER_DISPEL_UNDEAD2:
		{
			(void)dispel_undead(randint1(plev * 4));
			break;
		}

		case PRAYER_DISPEL_EVIL2:
		{
			(void)dispel_evil(randint1(plev * 4));
			break;
		}

		case PRAYER_BANISH_EVIL:
		{
			if (banish_evil(100))
			{
				msg("The power of your god banishes evil!");
			}
			break;
		}

		case PRAYER_WORD_OF_DESTRUCTION:
		{
			destroy_area(py, px, 15, TRUE);
			break;
		}

		case PRAYER_ANNIHILATION:
		{
			drain_life(dir, 200);
			break;
		}

		case PRAYER_UNBARRING_WAYS:
		{
			(void)destroy_doors_touch();
			break;
		}

		case PRAYER_RECHARGING:
		{
			return recharge(20 + plev);
		}
		
        /* Dispel Curse has been removed in 3.4 until curses are redone 
		case PRAYER_DISPEL_CURSE:
		{
			(void)remove_all_curse();
			break;
		}
		*/
		
		case PRAYER_ENCHANT_WEAPON:
		{
			return enchant_spell(randint0(4) + 1, randint0(4) + 1, 0);
		}

		case PRAYER_ENCHANT_ARMOUR:
		{
			return enchant_spell(0, 0, randint0(3) + 2);
		}

		case PRAYER_ELEMENTAL_BRAND:
		{
			brand_weapon();
			break;
		}

		case PRAYER_BLINK:
		{
			teleport_player(10);
			break;
		}

		case PRAYER_TELEPORT_SELF:
		{
			teleport_player(plev * 8);
			break;
		}

		case PRAYER_TELEPORT_OTHER:
		{
			(void)teleport_monster(dir);
			break;
		}

		case PRAYER_TELEPORT_LEVEL:
		{
			(void)teleport_player_level();
			break;
		}

		case PRAYER_WORD_OF_RECALL:
		{
			return set_recall();
		}

		case PRAYER_ALTER_REALITY:
		{
			msg("The world changes!");

			/* Leaving */
			p_ptr->leaving = TRUE;

			break;
		}
	}

	/* Success */
	return (TRUE);
}
Beispiel #14
0
static bool cast_mage_spell(int spell, int dir)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int plev = p_ptr->lev;

	/* Hack -- chance of "beam" instead of "bolt" */
	int beam = beam_chance();

	/* Spells. */
	switch (spell)
	{
		case SPELL_MAGIC_MISSILE:
		{
			fire_bolt_or_beam(beam-10, GF_MISSILE, dir,
			                  damroll(3 + ((plev - 1) / 5), 4));
			break;
		}

		case SPELL_DETECT_MONSTERS:
		{
			(void)detect_monsters_normal(TRUE);
			break;
		}

		case SPELL_PHASE_DOOR:
		{
			teleport_player(10);
			break;
		}

		case SPELL_LIGHT_AREA:
		{
			(void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1);
			break;
		}

		case SPELL_OBJECT_DETECTION:
		{
			(void)detect_treasure(TRUE, TRUE);
			break;
		}

		case SPELL_CURE_LIGHT_WOUNDS:
		{

			heal_player(15, 15);
			player_dec_timed(p_ptr, TMD_CUT, 20, TRUE);
			player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE);
			player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case SPELL_FIND_TRAPS_DOORS:
		{
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			break;
		}

		case SPELL_STINKING_CLOUD:
		{
			fire_ball(GF_POIS, dir, 10 + (plev / 2), 2);
			break;
		}

		case SPELL_CONFUSE_MONSTER:
		{
			(void)confuse_monster(dir, plev, TRUE);
			break;
		}

		case SPELL_LIGHTNING_BOLT:
		{
			fire_beam(GF_ELEC, dir, damroll(3+((plev-5)/6), 6));
			break;
		}

		case SPELL_TRAP_DOOR_DESTRUCTION:
		{
			(void)destroy_doors_touch();
			break;
		}

		case SPELL_SLEEP_MONSTER:
		{
			(void)sleep_monster(dir, TRUE);
			break;
		}

		case SPELL_CURE_POISON:
		{
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			break;
		}

		case SPELL_TELEPORT_SELF:
		{
			teleport_player(plev * 5);
			break;
		}

		case SPELL_SPEAR_OF_LIGHT:
		{
			msg("A line of blue shimmering light appears.");
			light_line(dir);
			break;
		}

		case SPELL_FROST_BOLT:
		{
			fire_bolt_or_beam(beam-10, GF_COLD, dir,
			                  damroll(5+((plev-5)/4), 8));
			break;
		}

		case SPELL_TURN_STONE_TO_MUD:
		{
			(void)wall_to_mud(dir);
			break;
		}

		case SPELL_SATISFY_HUNGER:
		{
			player_set_food(p_ptr, PY_FOOD_MAX - 1);
			break;
		}

		case SPELL_RECHARGE_ITEM_I:
		{
			return recharge(2 + plev / 5);
		}

		case SPELL_WONDER:
		{
			(void)spell_wonder(dir);
			break;
		}

		case SPELL_POLYMORPH_OTHER:
		{
			(void)poly_monster(dir);
			break;
		}

		case SPELL_IDENTIFY:
		{
			return ident_spell();
		}

		case SPELL_MASS_SLEEP:
		{
			(void)sleep_monsters(TRUE);
			break;
		}

		case SPELL_FIRE_BOLT:
		{
			fire_bolt_or_beam(beam, GF_FIRE, dir,
			                  damroll(6+((plev-5)/4), 8));
			break;
		}

		case SPELL_SLOW_MONSTER:
		{
			(void)slow_monster(dir);
			break;
		}

		case SPELL_FROST_BALL:
		{
			fire_ball(GF_COLD, dir, 30 + (plev), 2);
			break;
		}

		case SPELL_RECHARGE_ITEM_II: /* greater recharging */
		{
			return recharge(50 + plev);
		}

		case SPELL_TELEPORT_OTHER:
		{
			(void)teleport_monster(dir);
			break;
		}

		case SPELL_BEDLAM:
		{
			fire_ball(GF_OLD_CONF, dir, plev, 4);
			break;
		}

		case SPELL_FIRE_BALL:
		{
			fire_ball(GF_FIRE, dir, 55 + (plev), 2);
			break;
		}

		case SPELL_WORD_OF_DESTRUCTION:
		{
			destroy_area(py, px, 15, TRUE);
			break;
		}

		case SPELL_BANISHMENT:
		{
			return banishment();
		}

		case SPELL_DOOR_CREATION:
		{
			(void)door_creation();
			break;
		}

		case SPELL_STAIR_CREATION:
		{
			(void)stair_creation();
			break;
		}

		case SPELL_TELEPORT_LEVEL:
		{
			(void)teleport_player_level();
			break;
		}

		case SPELL_EARTHQUAKE:
		{
			earthquake(py, px, 10);
			break;
		}

		case SPELL_WORD_OF_RECALL:
		{
			return set_recall();
		}

		case SPELL_ACID_BOLT:
		{
			fire_bolt_or_beam(beam, GF_ACID, dir, damroll(8+((plev-5)/4), 8));
			break;
		}

		case SPELL_CLOUD_KILL:
		{
			fire_ball(GF_POIS, dir, 40 + (plev / 2), 3);
			break;
		}

		case SPELL_ACID_BALL:
		{
			fire_ball(GF_ACID, dir, 40 + (plev), 2);
			break;
		}

		case SPELL_ICE_STORM:
		{
			fire_ball(GF_ICE, dir, 50 + (plev * 2), 3);
			break;
		}

		case SPELL_METEOR_SWARM:
		{
			fire_swarm(2 + plev / 20, GF_METEOR, dir, 30 + plev / 2, 1);
			break;
		}

		case SPELL_MANA_STORM:
		{
			fire_ball(GF_MANA, dir, 300 + (plev * 2), 3);
			break;
		}
		case SPELL_DETECT_INVISIBLE:
		{
			(void)detect_monsters_normal(TRUE);
			(void)detect_monsters_invis(TRUE);
			break;
		}

		case SPELL_TREASURE_DETECTION:
		{
			(void)detect_treasure(TRUE, FALSE);
			break;
		}

		case SPELL_SHOCK_WAVE:
		{
			fire_ball(GF_SOUND, dir, 10 + plev, 2);
			break;
		}

		case SPELL_EXPLOSION:
		{
			fire_ball(GF_SHARD, dir, 20 + (plev * 2), 2);
			break;
		}

		case SPELL_MASS_BANISHMENT:
		{
			(void)mass_banishment();
			break;
		}

		case SPELL_RESIST_FIRE:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_RESIST_COLD:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_ELEMENTAL_BRAND: /* elemental brand */
		{
			return brand_ammo();
		}

		case SPELL_RESIST_POISON:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_RESISTANCE:
		{
			int time = randint1(20) + 20;
			(void)player_inc_timed(p_ptr, TMD_OPP_ACID, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_ELEC, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_POIS, time, TRUE, TRUE);
			break;
		}

		case SPELL_HEROISM:
		{
			int dur = randint1(25) + 25;
			(void)hp_player(10);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_HERO, dur, TRUE, TRUE);
			break;
		}

		case SPELL_SHIELD:
		{
			(void)player_inc_timed(p_ptr, TMD_SHIELD, randint1(20) + 30, TRUE, TRUE);
			break;
		}

		case SPELL_BERSERKER:
		{
			int dur = randint1(25) + 25;
			(void)hp_player(30);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE);
			break;
		}

		case SPELL_HASTE_SELF:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				(void)player_set_timed(p_ptr, TMD_FAST, randint1(20) + plev, TRUE);
			}
			else
			{
				(void)player_inc_timed(p_ptr, TMD_FAST, randint1(5), TRUE, TRUE);
			}
			break;
		}

		case SPELL_RIFT:
		{
			fire_beam(GF_GRAVITY, dir,	40 + damroll(plev, 7));
			break;
		}

		case SPELL_REND_SOUL: /* rend soul */
		{
			fire_bolt_or_beam(beam / 4, GF_NETHER, dir, damroll(11, plev));
			break;
		}

		case SPELL_CHAOS_STRIKE: /* chaos strike */
		{
			fire_bolt_or_beam(beam, GF_CHAOS, dir, damroll(13, plev));
			break;
		}

		case SPELL_RUNE_OF_PROTECTION: /* rune of protection */
		{
			warding_glyph_spell();
			break;
		}

		case SPELL_ENCHANT_ARMOR: /* enchant armor */
		{
			return enchant_spell(0, 0, randint0(3) + plev / 20);
		}

		case SPELL_ENCHANT_WEAPON: /* enchant weapon */
		{
			return enchant_spell(randint0(4) + plev / 20,
			                     randint0(4) + plev / 20, 0);
		}
	}

	/* Success */
	return (TRUE);
}
Beispiel #15
0
/**
 * Creates a specific monster's drop, including any drops specified
 * in the monster.txt file.
 *
 * Returns true if anything is created, false if nothing is.
 */
static bool mon_create_drop(struct chunk *c, struct monster *mon, byte origin)
{
	struct monster_drop *drop;

	bool great, good, gold_ok, item_ok;
    bool extra_roll = false;
	bool any = false;

	int number = 0, level, j, monlevel;

	struct object *obj;
	
	assert(mon);

	great = (rf_has(mon->race->flags, RF_DROP_GREAT));
	good = great || (rf_has(mon->race->flags, RF_DROP_GOOD));
	gold_ok = (!rf_has(mon->race->flags, RF_ONLY_ITEM));
	item_ok = (!rf_has(mon->race->flags, RF_ONLY_GOLD));

	/* Determine how much we can drop */
	number = mon_create_drop_count(mon->race, false);

    /* Give added bonus for unique monters */
    monlevel = mon->race->level;
    if (rf_has(mon->race->flags, RF_UNIQUE)) {
        monlevel = MIN(monlevel + 15, monlevel * 2);
        extra_roll = true;
    }
    
	/* Take the best of (average of monster level and current depth)
	   and (monster level) - to reward fighting OOD monsters */
	level = MAX((monlevel + player->depth) / 2, monlevel);
    level = MIN(level, 100);

	/* Specified drops */
	for (drop = mon->race->drops; drop; drop = drop->next) {
		if ((unsigned int)randint0(100) >= drop->percent_chance)
			continue;

		/* Allocate by hand, prep, apply magic */
		obj = mem_zalloc(sizeof(*obj));
		if (drop->artifact) {
			object_prep(obj, lookup_kind(drop->artifact->tval,
				drop->artifact->sval), level, RANDOMISE);
			obj->artifact = drop->artifact;
			copy_artifact_data(obj, obj->artifact);
			obj->artifact->created = true;
		} else {
			object_prep(obj, drop->kind, level, RANDOMISE);
			apply_magic(obj, level, true, good, great, extra_roll);
		}

		/* Set origin details */
		obj->origin = origin;
		obj->origin_depth = player->depth;
		obj->origin_xtra = mon->race->ridx;
		obj->number = randint0(drop->max - drop->min) + drop->min;

		/* Try to carry */
		if (monster_carry(c, mon, obj)) {
			any = true;
		} else {
			obj->artifact->created = false;
			object_wipe(obj);
			mem_free(obj);
		}
	}

	/* Make some objects */
	for (j = 0; j < number; j++) {
		if (gold_ok && (!item_ok || (randint0(100) < 50))) {
			obj = make_gold(level, "any");
		} else {
			obj = make_object(c, level, good, great, extra_roll, NULL, 0);
			if (!obj) continue;
		}

		/* Set origin details */
		obj->origin = origin;
		obj->origin_depth = player->depth;
		obj->origin_xtra = mon->race->ridx;

		/* Try to carry */
		if (monster_carry(c, mon, obj)) {
			any = true;
		} else {
			obj->artifact->created = false;
			object_wipe(obj);
			mem_free(obj);
		}
	}

	return any;
}
Beispiel #16
0
/*
 * Get an "aiming direction" (1,2,3,4,6,7,8,9 or 5) from the user.
 *
 * Return TRUE if a direction was chosen, otherwise return FALSE.
 *
 * The direction "5" is special, and means "use current target".
 *
 * This function tracks and uses the "global direction", and uses
 * that as the "desired direction", if it is set.
 *
 * Note that "Force Target", if set, will pre-empt user interaction,
 * if there is a usable target already set.
 *
 * Currently this function applies confusion directly.
 */
bool get_aim_dir(int *dp)
{
    /* Global direction */
    int dir = 0;

    ui_event ke;

    const char *p;

    /* Initialize */
    (*dp) = 0;

    /* Hack -- auto-target if requested */
    if (OPT(use_old_target) && target_okay() && !dir)
	dir = 5;

    /* Ask until satisfied */
    while (!dir) {
	/* Choose a prompt */
	if (!target_okay())
	    p = "Direction ('*' or <click> to target, \"'\" for closest, Escape to cancel)? ";
	else
	    p = "Direction ('5' for target, '*' or <click> to re-target, Escape to cancel)? ";

	/* Get a command (or Cancel) */
	if (!get_com_ex(p, &ke))
	    break;

	if (ke.type == EVT_MOUSE) {
	    if (target_set_interactive
		(TARGET_KILL, KEY_GRID_X(ke), KEY_GRID_Y(ke)))
		dir = 5;
	} else if (ke.type == EVT_KBRD) {
	    if (ke.key.code == '*') {
		/* Set new target, use target if legal */
		if (target_set_interactive(TARGET_KILL, -1, -1))
		    dir = 5;
	    } else if (ke.key.code == '\'') {
		/* Set to closest target */
		if (target_set_closest(TARGET_KILL))
		    dir = 5;
	    } else if (ke.key.code == 't' || ke.key.code == '5' || ke.key.code == '0'
		       || ke.key.code == '.') {
		if (target_okay())
		    dir = 5;
	    } else {
		/* Possible direction */
		int keypresses_handled = 0;

		while (ke.key.code != 0) {
		    int this_dir;

		    /* XXX Ideally show and move the cursor here to indicate
		     * the currently "Pending" direction. XXX */
		    this_dir = target_dir(ke.key);

		    if (this_dir)
			dir = dir_transitions[dir][this_dir];
		    else
			break;

		    if (lazymove_delay == 0 || ++keypresses_handled > 1)
			break;

		    /* See if there's a second keypress within the defined
		     * period of time. */
		    inkey_scan = lazymove_delay;
		    ke = inkey_ex();
		}
	    }
	}

	/* Error */
	if (!dir)
	    bell("Illegal aim direction!");
    }

    /* No direction */
    if (!dir)
	return (FALSE);

    /* Save direction */
    (*dp) = dir;

    /* Check for confusion */
    if (p_ptr->timed[TMD_CONFUSED]) {
	/* Random direction */
	dir = ddd[randint0(8)];
    }

    /* Notice confusion */
    if ((*dp) != dir) {
	/* Warn the user */
	msg("You are confused.");
    }

    /* Save direction */
    (*dp) = dir;

    /* A "valid" direction was entered */
    return (TRUE);
}
Beispiel #17
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->power / 20;

	/* Check out-of-depth-ness */
	if (race->level > player->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 */
		c->mon_rating += (race->level - player->depth) * race->power / 200;
	} 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 */
	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_UNAWARE);
	else
		mflag_off(mon->mflag, MFLAG_UNAWARE);

	/* 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);
}
Beispiel #18
0
/**
 * Attack the monster at the given location with a single blow.
 */
static bool py_attack_real(int y, int x, bool *fear) {
	/* Information about the target of the attack */
	monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]);
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	char m_name[80];
	bool stop = FALSE;

	/* The weapon used */
	object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD];

	/* Information about the attack */
	int bonus = p_ptr->state.to_h + o_ptr->to_h;
	int chance = p_ptr->state.skills[SKILL_TO_HIT_MELEE] + bonus * BTH_PLUS_ADJ;
	bool do_quake = FALSE;
	bool success = FALSE;

	/* Default to punching for one damage */
	const char *hit_verb = "punch";
	int dmg = 1;
	u32b msg_type = MSG_HIT;

	/* Extract monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0);

	/* Auto-Recall if possible and visible */
	if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

	/* Track a new monster */
	if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]);

	/* Handle player fear (only for invisible monsters) */
	if (check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) {
		msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name);
		return FALSE;
	}

	/* Disturb the monster */
	mon_clear_timed(cave->m_idx[y][x], MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE);

	/* See if the player hit */
	success = test_hit(chance, r_ptr->ac, m_ptr->ml);

	/* If a miss, skip this hit */
	if (!success) {
		msgt(MSG_MISS, "You miss %s.", m_name);
		return FALSE;
	}

	/* Handle normal weapon */
	if (o_ptr->kind) {
		int i;
		const struct slay *best_s_ptr = NULL;

		hit_verb = "hit";

		/* Get the best attack from all slays or
		 * brands on all non-launcher equipment */
		for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) {
			struct object *obj = &p_ptr->inventory[i];
			if (obj->kind)
				improve_attack_modifier(obj, m_ptr, &best_s_ptr, TRUE, FALSE);
		}

		improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr, TRUE, FALSE);
		if (best_s_ptr != NULL)
			hit_verb = best_s_ptr->melee_verb;

		dmg = damroll(o_ptr->dd, o_ptr->ds);
		dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult;

		dmg += o_ptr->to_d;
		dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type);

		/* Learn by use for the weapon */
		object_notice_attack_plusses(o_ptr);

		if (check_state(p_ptr, OF_IMPACT, p_ptr->state.flags) && dmg > 50) {
			do_quake = TRUE;
			wieldeds_notice_flag(p_ptr, OF_IMPACT);
		}
	}

	/* Learn by use for other equipped items */
	wieldeds_notice_on_attack();

	/* Apply the player damage bonuses */
	dmg += p_ptr->state.to_d;

	/* No negative damage */
	if (dmg <= 0) dmg = 0;

	/* Tell the player what happened */
	if (dmg <= 0)
		msgt(MSG_MISS, "You fail to harm %s.", m_name);
	else if (msg_type == MSG_HIT)
		msgt(MSG_HIT, "You %s %s.", hit_verb, m_name);
	else if (msg_type == MSG_HIT_GOOD)
		msgt(MSG_HIT_GOOD, "You %s %s. %s", hit_verb, m_name, "It was a good hit!");
	else if (msg_type == MSG_HIT_GREAT)
		msgt(MSG_HIT_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a great hit!");
	else if (msg_type == MSG_HIT_SUPERB)
		msgt(MSG_HIT_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a superb hit!");
	else if (msg_type == MSG_HIT_HI_GREAT)
		msgt(MSG_HIT_HI_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a *GREAT* hit!");
	else if (msg_type == MSG_HIT_HI_SUPERB)
		msgt(MSG_HIT_HI_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a *SUPERB* hit!");

	/* Complex message */
	if (p_ptr->wizard)
		msg("You do %d (out of %d) damage.", dmg, m_ptr->hp);

	/* Confusion attack */
	if (p_ptr->confusing) {
		p_ptr->confusing = FALSE;
		msg("Your hands stop glowing.");

		mon_inc_timed(cave->m_idx[y][x], MON_TMD_CONF,
				(10 + randint0(p_ptr->lev) / 10), MON_TMD_FLG_NOTIFY);
	}

	/* Damage, check for fear and death */
	stop = mon_take_hit(cave->m_idx[y][x], dmg, fear, NULL);

	if (stop)
		(*fear) = FALSE;

	/* Apply earthquake brand */
	if (do_quake) {
		earthquake(p_ptr->py, p_ptr->px, 10);
		if (cave->m_idx[y][x] == 0) stop = TRUE;
	}

	return stop;
}
Beispiel #19
0
/**
 * Process a monster spell 
 *
 * \param spell is the monster spell flag (RSF_FOO)
 * \param m_idx is the attacking monster
 * \param seen is whether the player can see the monster at this moment
 */
void do_mon_spell(int spell, int m_idx, bool seen)
{
	const struct mon_spell *rs_ptr = &mon_spell_table[spell];

	monster_type *m_ptr = &mon_list[m_idx];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];

	char m_name[80], ddesc[80];

	bool hits = FALSE;

	int dam = 0, flag = 0, rad = 0;

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

	/* Get the monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0x00);

	/* See if it hits */
	if (rs_ptr->hit == 100) 
		hits = TRUE;
	else if (rs_ptr->hit == 0)
		hits = FALSE;
	else
		hits = check_hit(rs_ptr->hit, rlev);

	/* Tell the player what's going on */
	disturb(1,0);

	if (!seen)
		msg("Something %s.", rs_ptr->blind_verb);
	else if (!hits) {
		msg("%^s %s %s, but misses.", m_name, rs_ptr->verb,	rs_ptr->desc);
		return;
	} else if (rs_ptr->type & RST_BREATH)
		msgt(rs_ptr->msgt, "%^s breathes %s.", m_name, rs_ptr->desc);
	else 
		msg("%^s %s %s.", m_name, rs_ptr->verb, rs_ptr->desc);


	/* Try a saving throw if available */
	if (rs_ptr->save && randint0(100) < p_ptr->state.skills[SKILL_SAVE]) {
		msg("You avoid the effects!");
		return;
	}

	/* Calculate the damage */
	dam = mon_spell_dam(spell, m_ptr->hp, rlev, RANDOMISE);

	/* Get the "died from" name in case this attack kills @ */
	monster_desc(ddesc, sizeof(ddesc), m_ptr, MDESC_SHOW | MDESC_IND2);

	/* Display the attack, adjust for resists and apply effects */
	if (rs_ptr->type & RST_BOLT)
		flag = PROJECT_STOP | PROJECT_KILL;
	else if (rs_ptr->type & (RST_BALL | RST_BREATH)) {
		flag = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
		rad = rf_has(r_ptr->flags, RF_POWERFUL) ? 3 : 2;
	}

	if (rs_ptr->gf) {
		(void)project(m_idx, rad, p_ptr->py, p_ptr->px, dam, rs_ptr->gf, flag);
		monster_learn_resists(m_idx, rs_ptr->gf);
	}
	else /* Note that non-projectable attacks are unresistable */
		take_hit(dam, ddesc);

	do_side_effects(spell, dam, m_idx);

	return;
}
Beispiel #20
0
/*
 * do_cmd_cast calls this function if the player's class
 * is 'Blue-Mage'.
 */
bool do_cmd_cast_learned(void)
{
    int             n = 0;
    int             chance;
    int             minfail = 0;
    int             plev = p_ptr->lev;
    monster_power   spell;
    bool            cast;
    int             need_mana;


    /* not if confused */
    if (p_ptr->confused)
    {
        msg_print("You are too confused!");

        return TRUE;
    }

    /* get power */
    if (!get_learned_power(&n)) return FALSE;

    spell = monster_powers[n];

    need_mana = mod_need_mana(spell.smana, 0, REALM_NONE);

    /* Verify "dangerous" spells */
    if (need_mana > p_ptr->csp)
    {
        /* Warning */
        msg_print("You do not have enough mana to use this power.");


        if (!over_exert) return FALSE;

        /* Verify */
        if (!get_check("Attempt it anyway? ")) return FALSE;

    }

    /* Spell failure chance */
    chance = spell.fail;

    /* Reduce failure rate by "effective" level adjustment */
    if (plev > spell.level) chance -= 3 * (plev - spell.level);
    else chance += (spell.level - plev);

    /* Reduce failure rate by INT/WIS adjustment */
    chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_INT]] - 1);

    chance = mod_spell_chance_1(chance, REALM_NONE);

    /* Not enough mana to cast */
    if (need_mana > p_ptr->csp)
    {
        chance += 5 * (need_mana - p_ptr->csp);
    }

    /* Extract the minimum failure rate */
    minfail = adj_mag_fail[p_ptr->stat_ind[A_INT]];

    /* Minimum failure rate */
    if (chance < minfail) chance = minfail;

    /* Stunning makes spells harder */
    if (p_ptr->stun > 50) chance += 25;
    else if (p_ptr->stun) chance += 15;

    /* Always a 5 percent chance of working */
    if (chance > 95) chance = 95;

    chance = mod_spell_chance_2(chance, REALM_NONE);

    /* Failed spell */
    if (randint0(100) < chance)
    {
        if (flush_failure) flush();
        msg_print("You failed to concentrate hard enough!");

        sound(SOUND_FAIL);

        if (n >= MS_S_KIN)
            /* Cast the spell */
            cast = cast_learned_spell(n, FALSE);
    }
    else
    {
        sound(SOUND_ZAP);

        /* Cast the spell */
        cast = cast_learned_spell(n, TRUE);

        if (!cast) return FALSE;
    }

    /* Sufficient mana */
    if (need_mana <= p_ptr->csp)
    {
        /* Use some mana */
        p_ptr->csp -= need_mana;
    }
    else
    {
        int oops = need_mana;

        /* No mana left */
        p_ptr->csp = 0;
        p_ptr->csp_frac = 0;

        /* Message */
        msg_print("You faint from the effort!");


        /* Hack -- Bypass free action */
        (void)set_paralyzed(p_ptr->paralyzed + randint1(5 * oops + 1), FALSE);

        virtue_add(VIRTUE_KNOWLEDGE, -10);

        /* Damage CON (possibly permanently) */
        if (randint0(100) < 50)
        {
            bool perm = (randint0(100) < 25);

            /* Message */
            msg_print("You have damaged your health!");


            /* Reduce constitution */
            (void)dec_stat(A_CON, 15 + randint1(10), perm);
        }
    }

    /* Take a turn */
    energy_use = 100;

    /* Window stuff */
    p_ptr->redraw |= (PR_MANA);
    p_ptr->window |= (PW_SPELL);

    return TRUE;
}
Beispiel #21
0
/**
 * Place random stairs at (x, y).
 * \param c current chunk
 * \param y
 * \param x co-ordinates
 */
void place_random_stairs(struct chunk *c, int y, int x)
{
    int feat = randint0(100) < 50 ? FEAT_LESS : FEAT_MORE;
    if (square_canputitem(c, y, x) && !square_isplayertrap(c, y, x))
		place_stairs(c, y, x, feat);
}
Beispiel #22
0
/**
 * Helper function to place monsters that appear as friends or escorts
 */
 bool place_friends(struct chunk *c, int y, int x, struct monster_race *race, 
					struct monster_race *friends_race, int total, bool sleep,
					byte origin)
 {
	int level_difference, extra_chance, nx = 0, ny = 0;
	int j;
	bool is_unique, success = true;
	
	/* Find the difference between current dungeon depth and monster level */
	level_difference = player->depth - friends_race->level + 5;
	
	/* Handle unique monsters */
	is_unique = rf_has(friends_race->flags, RF_UNIQUE);
	
	/* Make sure the unique hasn't been killed already */
	if (is_unique){
		total = friends_race->cur_num < friends_race->max_num ? 1 : 0;
	}
	
	/* More than 4 levels OoD, no groups allowed */
	if (level_difference <= 0 && !is_unique){
		return false;
	}
	
	/* Reduce group size within 5 levels of natural depth*/
	if (level_difference < 10 && !is_unique){
		extra_chance = (total * level_difference) % 10;
		total = total * level_difference / 10;
		
		/* Instead of flooring the group value, we use the decimal place
		   as a chance of an extra monster */
		if (randint0(10) > extra_chance){
			total += 1;
		}
	}
	
	/* No monsters in this group */
	if (total <= 0){
		return false;
	}
	
	/* Handle friends same as original monster */
	if (race->ridx == friends_race->ridx){
		success = place_new_monster_group(c, y, x, race, sleep, total, origin);
		return success;
	}
	
	/* Find a nearby place to put the other groups */
	for (j = 0; j < 50; j++){
		scatter(c, &ny, &nx, y, x, GROUP_DISTANCE, false);
		if (square_isopen(c, ny, nx)) break;
	}
		
	/* Place the monsters */
	success = place_new_monster_one(c, ny, nx, friends_race, sleep, origin);
	if (total > 1)
		success = place_new_monster_group(c, ny, nx, friends_race, sleep, total,
										  origin);
	
	return success;
	
}
Beispiel #23
0
static void project_player_handler_INERTIA(project_player_handler_context_t *context)
{
	/* Slow */
	(void)player_inc_timed(player, TMD_SLOW, 4 + randint0(4), true, false);
}
Beispiel #24
0
/**
 * Decreases a monster's hit points by `dam` and handle monster death.
 *
 * Hack -- we "delay" fear messages by passing around a "fear" flag.
 *
 * We announce monster death (using an optional "death message" (`note`)
 * if given, and a otherwise a generic killed/destroyed message).
 * 
 * Returns true if the monster has been killed (and deleted).
 *
 * TODO: Consider decreasing monster experience over time, say, by using
 * "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))" instead
 * of simply "(m_exp * m_lev) / (p_lev)", to make the first monster
 * worth more than subsequent monsters.  This would also need to
 * induce changes in the monster recall code.  XXX XXX XXX
 **/
bool mon_take_hit(struct monster *mon, int dam, bool *fear, const char *note)
{
	s32b div, new_exp, new_exp_frac;
	struct monster_lore *lore = get_lore(mon->race);


	/* Redraw (later) if needed */
	if (player->upkeep->health_who == mon)
		player->upkeep->redraw |= (PR_HEALTH);

	/* Wake it up */
	mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false);

	/* Become aware of its presence */
	if (mflag_has(mon->mflag, MFLAG_UNAWARE))
		become_aware(mon);

	/* Hurt it */
	mon->hp -= dam;

	/* It is dead now */
	if (mon->hp < 0) {
		char m_name[80];
		char buf[80];

		/* Assume normal death sound */
		int soundfx = MSG_KILL;

		/* Play a special sound if the monster was unique */
		if (rf_has(mon->race->flags, RF_UNIQUE)) {
			if (mon->race->base == lookup_monster_base("Morgoth"))
				soundfx = MSG_KILL_KING;
			else
				soundfx = MSG_KILL_UNIQUE;
		}

		/* Extract monster name */
		monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT);

		/* Death message */
		if (note) {
			if (strlen(note) <= 1) {
				/* Death by Spell attack - messages handled by project_m() */
			} else {
				char *str = format("%s%s", m_name, note);
				my_strcap(str);

				/* Make sure to flush any monster messages first */
				notice_stuff(player);

				/* Death by Missile attack */
				msgt(soundfx, "%s", str);
			}
		} else {
			/* Make sure to flush any monster messages first */
			notice_stuff(player);

			if (!mflag_has(mon->mflag, MFLAG_VISIBLE))
				/* Death by physical attack -- invisible monster */
				msgt(soundfx, "You have killed %s.", m_name);
			else if (monster_is_unusual(mon->race))
				/* Death by Physical attack -- non-living monster */
				msgt(soundfx, "You have destroyed %s.", m_name);
			else
				/* Death by Physical attack -- living monster */
				msgt(soundfx, "You have slain %s.", m_name);
		}

		/* Player level */
		div = player->lev;

		/* Give some experience for the kill */
		new_exp = ((long)mon->race->mexp * mon->race->level) / div;

		/* Handle fractional experience */
		new_exp_frac = ((((long)mon->race->mexp * mon->race->level) % div)
		                * 0x10000L / div) + player->exp_frac;

		/* Keep track of experience */
		if (new_exp_frac >= 0x10000L) {
			new_exp++;
			player->exp_frac = (u16b)(new_exp_frac - 0x10000L);
		} else
			player->exp_frac = (u16b)new_exp_frac;

		/* When the player kills a Unique, it stays dead */
		if (rf_has(mon->race->flags, RF_UNIQUE)) {
			char unique_name[80];
			mon->race->max_num = 0;

			/* 
			 * This gets the correct name if we slay an invisible 
			 * unique and don't have See Invisible.
			 */
			monster_desc(unique_name, sizeof(unique_name), mon,
						 MDESC_DIED_FROM);

			/* Log the slaying of a unique */
			strnfmt(buf, sizeof(buf), "Killed %s", unique_name);
			history_add(buf, HIST_SLAY_UNIQUE, 0);
		}

		/* Gain experience */
		player_exp_gain(player, new_exp);

		/* Generate treasure */
		monster_death(mon, false);

		/* Recall even invisible uniques or winners */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE) ||
			rf_has(mon->race->flags, RF_UNIQUE)) {
			/* Count kills this life */
			if (lore->pkills < SHRT_MAX) lore->pkills++;

			/* Count kills in all lives */
			if (lore->tkills < SHRT_MAX) lore->tkills++;

			/* Update lore and tracking */
			lore_update(mon->race, lore);
			monster_race_track(player->upkeep, mon->race);
		}

		/* Delete the monster */
		delete_monster_idx(mon->midx);

		/* Not afraid */
		(*fear) = false;

		/* Monster is dead */
		return (true);
	}


	/* Mega-Hack -- Pain cancels fear */
	if (!(*fear) && mon->m_timed[MON_TMD_FEAR] && (dam > 0)) {
		int tmp = randint1(dam);

		/* Cure a little or all fear */
		if (tmp < mon->m_timed[MON_TMD_FEAR]) {
			/* Reduce fear */
			mon_dec_timed(mon, MON_TMD_FEAR, tmp, MON_TMD_FLG_NOMESSAGE,
				false);
		} else {
			/* Cure fear */
			mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE, false);

			/* No more fear */
			(*fear) = false;
		}
	}

	/* Sometimes a monster gets scared by damage */
	if (!mon->m_timed[MON_TMD_FEAR] && 
		!rf_has(mon->race->flags, RF_NO_FEAR) &&	dam > 0) {
		int percentage;

		/* Percentage of fully healthy */
		percentage = (100L * mon->hp) / mon->maxhp;

		/*
		 * Run (sometimes) if at 10% or less of max hit points,
		 * or (usually) when hit for half its current hit points
		 */
		if ((randint1(10) >= percentage) ||
		    ((dam >= mon->hp) && (randint0(100) < 80))) {
			int timer = randint1(10) + (((dam >= mon->hp) && (percentage > 7))
										? 20 : ((11 - percentage) * 5));

			/* Hack -- note fear */
			(*fear) = true;

			mon_inc_timed(mon, MON_TMD_FEAR, timer,
					MON_TMD_FLG_NOMESSAGE | MON_TMD_FLG_NOFAIL, false);
		}
	}


	/* Not dead yet */
	return (false);
}
Beispiel #25
0
/*
 * Attempt to disarm the chest at the given location
 *
 * Assume there is no monster blocking the destination
 *
 * Returns TRUE if repeated commands may continue
 */
bool do_cmd_disarm_chest(int y, int x, s16b o_idx)
{
	int i, j;

	bool more = FALSE;

	object_type *o_ptr = object_byid(o_idx);


	/* Get the "disarm" factor */
	i = p_ptr->state.skills[SKILL_DISARM];

	/* Penalize some conditions */
	if (p_ptr->timed[TMD_BLIND] || no_light()) i = i / 10;
	if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) i = i / 10;

	/* Extract the difficulty */
	j = i - o_ptr->pval[DEFAULT_PVAL];

	/* Always have a small chance of success */
	if (j < 2) j = 2;

	/* Must find the trap first. */
	if (!object_is_known(o_ptr))
	{
		msg("I don't see any traps.");
	}

	/* Already disarmed/unlocked or no traps */
	else if (!is_trapped_chest(o_ptr))
	{
		msg("The chest is not trapped.");
	}

	/* Success (get a lot of experience) */
	else if (randint0(100) < j)
	{
		msgt(MSG_DISARM, "You have disarmed the chest.");
		player_exp_gain(p_ptr, o_ptr->pval[DEFAULT_PVAL]);
		o_ptr->pval[DEFAULT_PVAL] = (0 - o_ptr->pval[DEFAULT_PVAL]);
	}

	/* Failure -- Keep trying */
	else if ((i > 5) && (randint1(i) > 5))
	{
		/* We may keep trying */
		more = TRUE;
		flush();
		msg("You failed to disarm the chest.");
	}

	/* Failure -- Set off the trap */
	else
	{
		msg("You set off a trap!");
		chest_trap(y, x, o_idx);
	}

	/* Result */
	return (more);
}
Beispiel #26
0
/**
 * Compacts and reorders the monster list.
 *
 * This function can be very dangerous, use with caution!
 *
 * When `num_to_compact` is 0, we just reorder the monsters into a more compact
 * order, eliminating any "holes" left by dead monsters. If `num_to_compact` is
 * positive, then we delete at least that many monsters and then reorder.
 * We try not to delete monsters that are high level or close to the player.
 * Each time we make a full pass through the monster list, if we haven't
 * deleted enough monsters, we relax our bounds a little to accept
 * monsters of a slightly higher level, and monsters slightly closer to
 * the player.
 */
void compact_monsters(int num_to_compact)
{
	int m_idx, num_compacted, iter;

	int max_lev, min_dis, chance;


	/* Message (only if compacting) */
	if (num_to_compact)
		msg("Compacting monsters...");


	/* Compact at least 'num_to_compact' objects */
	for (num_compacted = 0, iter = 1; num_compacted < num_to_compact; iter++) {
		/* Get more vicious each iteration */
		max_lev = 5 * iter;

		/* Get closer each iteration */
		min_dis = 5 * (20 - iter);

		/* Check all the monsters */
		for (m_idx = 1; m_idx < cave_monster_max(cave); m_idx++) {
			struct monster *mon = cave_monster(cave, m_idx);

			/* Skip "dead" monsters */
			if (!mon->race) continue;

			/* High level monsters start out "immune" */
			if (mon->race->level > max_lev) continue;

			/* Ignore nearby monsters */
			if ((min_dis > 0) && (mon->cdis < min_dis)) continue;

			/* Saving throw chance */
			chance = 90;

			/* Only compact "Quest" Monsters in emergencies */
			if (rf_has(mon->race->flags, RF_QUESTOR) && (iter < 1000))
				chance = 100;

			/* Try not to compact Unique Monsters */
			if (rf_has(mon->race->flags, RF_UNIQUE)) chance = 99;

			/* All monsters get a saving throw */
			if (randint0(100) < chance) continue;

			/* Delete the monster */
			delete_monster(mon->fy, mon->fx);

			/* Count the monster */
			num_compacted++;
		}
	}


	/* Excise dead monsters (backwards!) */
	for (m_idx = cave_monster_max(cave) - 1; m_idx >= 1; m_idx--) {
		struct monster *mon = cave_monster(cave, m_idx);

		/* Skip real monsters */
		if (mon->race) continue;

		/* Move last monster into open hole */
		compact_monsters_aux(cave_monster_max(cave) - 1, m_idx);

		/* Compress "cave->mon_max" */
		cave->mon_max--;
	}
}
Beispiel #27
0
/*
 * Perform the basic "bash" command
 *
 * Assume there is no monster blocking the destination
 *
 * Returns TRUE if repeated commands may continue
 */
static bool do_cmd_bash_aux(int y, int x)
{
	int bash, temp;

	bool more = FALSE;


	/* Verify legality */
	if (!do_cmd_bash_test(y, x)) return (FALSE);


	/* Message */
	msg("You smash into the door!");

	/* Hack -- Bash power based on strength */
	/* (Ranges from 3 to 20 to 100 to 200) */
	bash = adj_str_blow[p_ptr->state.stat_ind[A_STR]];

	/* Extract door power */
	temp = ((cave->feat[y][x] - FEAT_DOOR_HEAD) & 0x07);

	/* Compare bash power to door power */
	temp = (bash - (temp * 10));

	/* Hack -- always have a chance */
	if (temp < 1) temp = 1;

	/* Hack -- attempt to bash down the door */
	if (randint0(100) < temp)
	{
		/* Break down the door */
		if (randint0(100) < 50)
		{
			cave_set_feat(cave, y, x, FEAT_BROKEN);
		}

		/* Open the door */
		else
		{
			cave_set_feat(cave, y, x, FEAT_OPEN);
		}

		msgt(MSG_OPENDOOR, "The door crashes open!");

		/* Update the visuals */
		p_ptr->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
	}

	/* Saving throw against stun */
	else if (randint0(100) < adj_dex_safe[p_ptr->state.stat_ind[A_DEX]] +
	         p_ptr->lev) {
		msg("The door holds firm.");

		/* Allow repeated bashing */
		more = TRUE;
	}

	/* Low dexterity has bad consequences */
	else {
		msg("You are off-balance.");

		/* Lose balance ala stun */
		(void)player_inc_timed(p_ptr, TMD_STUN, 2 + randint0(2), TRUE, FALSE);
	}

	/* Result */
	return more;
}
Beispiel #28
0
/**
 * Chooses a monster race that seems "appropriate" to the given level
 *
 * This function uses the "prob2" field of the "monster allocation table",
 * and various local information, to calculate the "prob3" field of the
 * same table, which is then used to choose an "appropriate" monster, in
 * a relatively efficient manner.
 *
 * Note that "town" monsters will *only* be created in the town, and
 * "normal" monsters will *never* be created in the town, unless the
 * "level" is "modified", for example, by polymorph or summoning.
 *
 * There is a small chance (1/50) of "boosting" the given depth by
 * a small amount (up to four levels), except in the town.
 *
 * It is (slightly) more likely to acquire a monster of the given level
 * than one of a lower level.  This is done by choosing several monsters
 * appropriate to the given level and keeping the "hardest" one.
 *
 * Note that if no monsters are "appropriate", then this function will
 * fail, and return zero, but this should *almost* never happen.
 */
struct monster_race *get_mon_num(int level)
{
	int i, p;

	long total;

	struct monster_race *race;

	alloc_entry *table = alloc_race_table;

	/* Occasionally produce a nastier monster in the dungeon */
	if (level > 0 && one_in_(z_info->ood_monster_chance))
		level += MIN(level / 4 + 2, z_info->ood_monster_amount);

	total = 0L;

	/* Process probabilities */
	for (i = 0; i < alloc_race_size; i++) {
		time_t cur_time = time(NULL);
		struct tm *date = localtime(&cur_time);

		/* Monsters are sorted by depth */
		if (table[i].level > level) break;

		/* Default */
		table[i].prob3 = 0;

		/* No town monsters in dungeon */
		if ((level > 0) && (table[i].level <= 0)) continue;

		/* Get the chosen monster */
		race = &r_info[table[i].index];

		/* No seasonal monsters outside of Christmas */
		if (rf_has(race->flags, RF_SEASONAL) && 
			!(date->tm_mon == 11 && date->tm_mday >= 24 && date->tm_mday <= 26))
			continue;

		/* Only one copy of a a unique must be around at the same time */
		if (rf_has(race->flags, RF_UNIQUE) && 
				race->cur_num >= race->max_num)
			continue;

		/* Some monsters never appear out of depth */
		if (rf_has(race->flags, RF_FORCE_DEPTH) && race->level > player->depth)
			continue;

		/* Accept */
		table[i].prob3 = table[i].prob2;

		/* Total */
		total += table[i].prob3;
	}

	/* No legal monsters */
	if (total <= 0) return NULL;

	/* Pick a monster */
	race = get_mon_race_aux(total, table);

	/* Try for a "harder" monster once (50%) or twice (10%) */
	p = randint0(100);
	
	if (p < 60) {
		struct monster_race *old = race;

		/* Pick a new monster */
		race = get_mon_race_aux(total, table);

		/* Keep the deepest one */
		if (race->level < old->level) race = old;
	}

	/* Try for a "harder" monster twice (10%) */
	if (p < 10) {
		struct monster_race *old = race;

		/* Pick a monster */
		race = get_mon_race_aux(total, table);

		/* Keep the deepest one */
		if (race->level < old->level) race = old;
	}

	/* Result */
	return race;
}
Beispiel #29
0
/*
 * Attempt to open the given chest at the given location
 *
 * Assume there is no monster blocking the destination
 *
 * Returns TRUE if repeated commands may continue
 */
static bool do_cmd_open_chest(int y, int x, s16b o_idx)
{
	int i, j;

	bool flag = TRUE;

	bool more = FALSE;

	object_type *o_ptr = object_byid(o_idx);


	/* Attempt to unlock it */
	if (o_ptr->pval[DEFAULT_PVAL] > 0)
	{
		/* Assume locked, and thus not open */
		flag = FALSE;

		/* Get the "disarm" factor */
		i = p_ptr->state.skills[SKILL_DISARM];

		/* Penalize some conditions */
		if (p_ptr->timed[TMD_BLIND] || no_light()) i = i / 10;
		if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) i = i / 10;

		/* Extract the difficulty */
		j = i - o_ptr->pval[DEFAULT_PVAL];

		/* Always have a small chance of success */
		if (j < 2) j = 2;

		/* Success -- May still have traps */
		if (randint0(100) < j)
		{
			msgt(MSG_LOCKPICK, "You have picked the lock.");
			player_exp_gain(p_ptr, 1);
			flag = TRUE;
		}

		/* Failure -- Keep trying */
		else
		{
			/* We may continue repeating */
			more = TRUE;
			flush();
			msgt(MSG_LOCKPICK_FAIL, "You failed to pick the lock.");
		}
	}

	/* Allowed to open */
	if (flag)
	{
		/* Apply chest traps, if any */
		chest_trap(y, x, o_idx);

		/* Let the Chest drop items */
		chest_death(y, x, o_idx);

		/* Squelch chest if autosquelch calls for it */
		p_ptr->notice |= PN_SQUELCH;
		
	}

	/*
	 * empty chests were always squelched in squelch_item_okay so we
	 * might as well squelch it here
	 */
	if (o_ptr->pval[DEFAULT_PVAL] == 0) {
		o_ptr->ignore = TRUE;
	}
	
	/* Redraw chest, to be on the safe side (it may have been squelched) */
	cave_light_spot(cave, y, x);

	/* Refresh */
	Term_fresh();
	
	/* Result */
	return (more);
}
Beispiel #30
0
/**
 * Use W. Sheldon Simms' random name generator algorithm (Markov Chain stylee).
 * 
 * Generate a random word using the probability tables we built earlier.  
 * Relies on the A2I and I2A macros (and so the ASCII character set) and 
 * is_a_vowel (so the basic 5 English vowels).
 */
size_t randname_make(randname_type name_type, size_t min, size_t max,
					 char *word_buf, size_t buflen, const char ***sections)
{
	size_t lnum = 0;
	bool found_word = FALSE;

	static name_probs lprobs;
	static randname_type cached_type = RANDNAME_NUM_TYPES;

	assert(name_type > 0 && name_type < RANDNAME_NUM_TYPES);

	/* To allow for a terminating character */
	assert(buflen > max);

	/* We cache one set of probabilities, only regenerate when
	   the type changes.  It's as good a way as any for now.
	   Frankly, we could probably regenerate every time. */
	if (cached_type != name_type) {
		const char **wordlist = NULL;

		wordlist = sections[name_type];

		(void)memset(lprobs, 0, sizeof(name_probs));
		build_prob(lprobs, wordlist);

		cached_type = name_type;
	}
        
	/* Generate the actual word wanted. */
	while (!found_word) {
		char *cp = word_buf;
		int c_prev = S_WORD;
		int c_cur = S_WORD;
		int tries = 0;
		bool contains_vowel = FALSE;
		lnum = 0;

		/* We start the word again if we run out of space or have
		   had to have 10 goes to find a word that satisfies the
		   minimal conditions. */
		while (tries < 10 && lnum <= max && !found_word) {
			/* Pick the next letter based on a simple weighting
			  of which letters can follow the previous two */
			int r;
			int c_next = 0;

			assert(c_prev >= 0 && c_prev <= S_WORD);
			assert(c_cur >= 0 && c_cur <= S_WORD);

			r = randint0(lprobs[c_prev][c_cur][TOTAL]);

			while (r >= lprobs[c_prev][c_cur][c_next]) {
				r -= lprobs[c_prev][c_cur][c_next];
				c_next++;
			}

			assert(c_next <= E_WORD);
			assert(c_next >= 0);
            
			if (c_next == E_WORD) {
				/* If we've reached the end, we check if we've
				   met the simple conditions, otherwise have
				   another go at choosing a letter for this
				   position. */
				if (lnum >= min && contains_vowel) {
					*cp = '\0';
					found_word = TRUE;
				} else {
					tries++;
				}
			} else {
				/* Add the letter to the word and move on. */
				*cp = I2A(c_next);

				if (is_a_vowel(*cp))
					contains_vowel = TRUE;

				cp++;
				lnum++;
				assert(c_next <= S_WORD);
				assert(c_next >= 0);
				c_prev = c_cur;
				c_cur = c_next;
			}
		}
	}

	return lnum;
}