Esempio n. 1
0
/**
 * Wake a monster or reduce its depth of sleep
 *
 * Chance of waking up is dependent only on the player's stealth, but the
 * amount of sleep reduction takes into account the monster's distance from
 * the player.  Currently straight line distance is used; possibly this
 * should take into account dungeon structure.
 */
static void monster_reduce_sleep(struct chunk *c, struct monster *mon)
{
	bool woke_up = false;
	int stealth = player->state.skills[SKILL_STEALTH];
	int player_noise = 1 << (30 - stealth);
	int notice = randint0(1024);
	struct monster_lore *lore = get_lore(mon->race);

	/* Aggravation */
	if (player_of_has(player, OF_AGGRAVATE)) {
		char m_name[80];

		/* Wake the monster */
		mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false);

		/* Get the monster name */
		monster_desc(m_name, sizeof(m_name), mon,
					 MDESC_CAPITAL | MDESC_IND_HID);

		/* Notify the player if aware */
		if (monster_is_obvious(mon))
			msg("%s wakes up.", m_name);

		woke_up = true;

	} else if ((notice * notice * notice) <= player_noise) {
		int sleep_reduction = 1;
		int local_noise = c->noise.grids[mon->fy][mon->fx];

		/* Test - wake up faster in hearing distance of the player 
		 * Note no dependence on stealth for now */
		if ((local_noise > 0) && (local_noise < 50)) {
			sleep_reduction = (100 / local_noise);
		}

		/* Note a complete wakeup */
		if (mon->m_timed[MON_TMD_SLEEP] <= sleep_reduction) {
			woke_up = true;
		}

		/* Monster wakes up a bit */
		mon_dec_timed(mon, MON_TMD_SLEEP, sleep_reduction, MON_TMD_FLG_NOTIFY,
					  false);

		/* Update knowledge */
		if (monster_is_obvious(mon)) {
			if (!woke_up && lore->ignore < UCHAR_MAX)
				lore->ignore++;
			else if (woke_up && lore->wake < UCHAR_MAX)
				lore->wake++;
			lore_update(mon->race, lore);
		}
	}
}
Esempio n. 2
0
/**
 * Process a monster's timed effects, e.g. decrease them.
 *
 * Returns true if the monster is skipping its turn.
 */
static bool process_monster_timed(struct chunk *c, struct monster *mon)
{
	struct monster_lore *lore = get_lore(mon->race);

	/* Handle "sleep" */
	if (mon->m_timed[MON_TMD_SLEEP]) {
		bool woke_up = false;

		/* Anti-stealth */
		int notice = randint0(1024);

		/* Aggravation */
		if (player_of_has(player, OF_AGGRAVATE)) {
			char m_name[80];

			/* Wake the monster */
			mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false);

			/* Get the monster name */
			monster_desc(m_name, sizeof(m_name), mon,
						 MDESC_CAPITAL | MDESC_IND_HID);

			/* Notify the player if aware */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
				!mflag_has(mon->mflag, MFLAG_UNAWARE))
				msg("%s wakes up.", m_name);

			woke_up = true;

		} else if ((notice * notice * notice) <= player->state.noise) {
			/* See if monster "notices" player */
			int d = 1;

			/* Wake up faster near the player */
			if (mon->cdis < 50) d = (100 / mon->cdis);

			/* Note a complete wakeup */
			if (mon->m_timed[MON_TMD_SLEEP] <= d) woke_up = true;

			/* Monster wakes up a bit */
			mon_dec_timed(mon, MON_TMD_SLEEP, d, MON_TMD_FLG_NOTIFY, false);

			/* Update knowledge */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
				!mflag_has(mon->mflag, MFLAG_UNAWARE)) {
				if (!woke_up && lore->ignore < UCHAR_MAX)
					lore->ignore++;
				else if (woke_up && lore->wake < UCHAR_MAX)
					lore->wake++;
				lore_update(mon->race, lore);
			}
		}

		/* Sleeping monsters don't recover in any other ways */
		/* If the monster just woke up, then it doesn't act */
		return true;
	}

	if (mon->m_timed[MON_TMD_FAST])
		mon_dec_timed(mon, MON_TMD_FAST, 1, 0, false);

	if (mon->m_timed[MON_TMD_SLOW])
		mon_dec_timed(mon, MON_TMD_SLOW, 1, 0, false);

	if (mon->m_timed[MON_TMD_STUN]) {
		int d = 1;

		/* Make a "saving throw" against stun */
		if (randint0(5000) <= mon->race->level * mon->race->level)
			/* Recover fully */
			d = mon->m_timed[MON_TMD_STUN];

		/* Hack -- Recover from stun */
		mon_dec_timed(mon, MON_TMD_STUN, d, MON_TMD_FLG_NOTIFY, false);
	}

	if (mon->m_timed[MON_TMD_CONF]) {
		int d = randint1(mon->race->level / 10 + 1);
		mon_dec_timed(mon, MON_TMD_CONF, d, MON_TMD_FLG_NOTIFY, false);
	}

	if (mon->m_timed[MON_TMD_FEAR]) {
		int d = randint1(mon->race->level / 10 + 1);
		mon_dec_timed(mon, MON_TMD_FEAR, d, MON_TMD_FLG_NOTIFY, false);
	}

	/* Don't do anything if stunned */
	return mon->m_timed[MON_TMD_STUN] ? true : false;
}
Esempio n. 3
0
/**
 * Process a monster's timed effects, e.g. decrease them.
 *
 * Returns TRUE if the monster is skipping its turn.
 */
static bool process_monster_timed(struct chunk *c, struct monster *m_ptr)
{
	monster_lore *l_ptr = get_lore(m_ptr->race);

	/* Handle "sleep" */
	if (m_ptr->m_timed[MON_TMD_SLEEP]) {
		bool woke_up = FALSE;

		/* Anti-stealth */
		int notice = randint0(1024);

		/* Aggravation */
		if (player_of_has(player, OF_AGGRAVATE)) {
			/* Wake the monster and notify player */
			mon_clear_timed(m_ptr, MON_TMD_SLEEP, MON_TMD_FLG_NOTIFY, FALSE);
			woke_up = TRUE;

		/* Hack See if monster "notices" player */
		} else if ((notice * notice * notice) <= player->state.noise) {
			int d = 1;

			/* Wake up faster near the player */
			if (m_ptr->cdis < 50) d = (100 / m_ptr->cdis);

			/* Note a complete wakeup */
			if (m_ptr->m_timed[MON_TMD_SLEEP] <= d) woke_up = TRUE;

			/* Monster wakes up a bit */
			mon_dec_timed(m_ptr, MON_TMD_SLEEP, d, MON_TMD_FLG_NOTIFY, FALSE);

			/* Update knowledge */
			if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) &&
				!mflag_has(m_ptr->mflag, MFLAG_UNAWARE)) {
				if (!woke_up && l_ptr->ignore < MAX_UCHAR)
					l_ptr->ignore++;
				else if (woke_up && l_ptr->wake < MAX_UCHAR)
					l_ptr->wake++;
				lore_update(m_ptr->race, l_ptr);
			}
		}

		/* Update the health bar */
		if (woke_up && mflag_has(m_ptr->mflag, MFLAG_VISIBLE) &&
			!mflag_has(m_ptr->mflag, MFLAG_UNAWARE) &&
			player->upkeep->health_who == m_ptr)
			player->upkeep->redraw |= (PR_HEALTH);

		/* Sleeping monsters don't recover in any other ways */
		/* If the monster just woke up, then it doesn't act */
		return TRUE;
	}

	if (m_ptr->m_timed[MON_TMD_FAST])
		mon_dec_timed(m_ptr, MON_TMD_FAST, 1, 0, FALSE);

	if (m_ptr->m_timed[MON_TMD_SLOW])
		mon_dec_timed(m_ptr, MON_TMD_SLOW, 1, 0, FALSE);

	if (m_ptr->m_timed[MON_TMD_STUN]) {
		int d = 1;

		/* Make a "saving throw" against stun */
		if (randint0(5000) <= m_ptr->race->level * m_ptr->race->level)
			/* Recover fully */
			d = m_ptr->m_timed[MON_TMD_STUN];

		/* Hack -- Recover from stun */
		mon_dec_timed(m_ptr, MON_TMD_STUN, d, MON_TMD_FLG_NOTIFY, FALSE);
	}

	if (m_ptr->m_timed[MON_TMD_CONF]) {
		int d = randint1(m_ptr->race->level / 10 + 1);
		mon_dec_timed(m_ptr, MON_TMD_CONF, d, MON_TMD_FLG_NOTIFY, FALSE);
	}

	if (m_ptr->m_timed[MON_TMD_FEAR]) {
		int d = randint1(m_ptr->race->level / 10 + 1);
		mon_dec_timed(m_ptr, MON_TMD_FEAR, d, MON_TMD_FLG_NOTIFY, FALSE);
	}

	/* Don't do anything if stunned */
	return m_ptr->m_timed[MON_TMD_STUN] ? TRUE : FALSE;
}
Esempio n. 4
0
/**
 * Attack the player via physical attacks.
 */
bool make_attack_normal(struct monster *mon, struct player *p)
{
	struct monster_lore *lore = get_lore(mon->race);
	int ap_cnt;
	int k, tmp, ac, rlev;
	char m_name[80];
	char ddesc[80];
	bool blinked;

	/* Not allowed to attack */
	if (rf_has(mon->race->flags, RF_NEVER_BLOW)) return (false);

	/* Total armor */
	ac = p->state.ac + p->state.to_a;

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


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

	/* Get the "died from" information (i.e. "a kobold") */
	monster_desc(ddesc, sizeof(ddesc), mon, MDESC_SHOW | MDESC_IND_VIS);

	/* Assume no blink */
	blinked = false;

	/* Scan through all blows */
	for (ap_cnt = 0; ap_cnt < z_info->mon_blows_max; ap_cnt++) {
		bool visible = false;
		bool obvious = false;
		bool do_break = false;

		int power = 0;
		int damage = 0;
		int do_cut = 0;
		int do_stun = 0;
		int sound_msg = MSG_GENERIC;

		const char *act = NULL;

		/* Extract the attack infomation */
		int effect = mon->race->blow[ap_cnt].effect;
		int method = mon->race->blow[ap_cnt].method;
		random_value dice = mon->race->blow[ap_cnt].dice;

		/* Hack -- no more attacks */
		if (!method) break;

		/* Handle "leaving" */
		if (p->is_dead || p->upkeep->generate_level) break;

		/* Extract visibility (before blink) */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE)) visible = true;

		/* Extract visibility from carrying light */
		if (rf_has(mon->race->flags, RF_HAS_LIGHT)) visible = true;

		/* Extract the attack "power" */
		power = monster_blow_effect_power(effect);

		/* Monster hits player */
		if (!effect || check_hit(p, power, rlev)) {
			melee_effect_handler_f effect_handler;

			/* Always disturbing */
			disturb(p, 1);

			/* Hack -- Apply "protection from evil" */
			if (p->timed[TMD_PROTEVIL] > 0) {
				/* Learn about the evil flag */
				if (mflag_has(mon->mflag, MFLAG_VISIBLE))
					rf_on(lore->flags, RF_EVIL);

				if (rf_has(mon->race->flags, RF_EVIL) && p->lev >= rlev &&
				    randint0(100) + p->lev > 50) {
					/* Message */
					msg("%s is repelled.", m_name);

					/* Hack -- Next attack */
					continue;
				}
			}

			/* Describe the attack method */
			act = monster_blow_method_action(method);
			do_cut = monster_blow_method_cut(method);
			do_stun = monster_blow_method_stun(method);
			sound_msg = monster_blow_method_message(method);

			/* Message */
			if (act)
				msgt(sound_msg, "%s %s", m_name, act);

			/* Hack -- assume all attacks are obvious */
			obvious = true;

			/* Roll dice */
			damage = randcalc(dice, rlev, RANDOMISE);

			/* Perform the actual effect. */
			effect_handler = melee_handler_for_blow_effect(effect);
			if (effect_handler != NULL) {
				melee_effect_handler_context_t context = {
					p,
					mon,
					rlev,
					method,
					ac,
					ddesc,
					obvious,
					blinked,
					do_break,
					damage,
				};

				effect_handler(&context);

				/* Save any changes made in the handler for later use. */
				obvious = context.obvious;
				blinked = context.blinked;
				damage = context.damage;
				do_break = context.do_break;
			} else {
				msg("ERROR: Effect handler not found for %d.", effect);
			}

			/* Don't cut or stun if player is dead */
			if (p->is_dead) {
				do_cut = false;
				do_stun = false;
			}

			/* Hack -- only one of cut or stun */
			if (do_cut && do_stun) {
				/* Cancel cut */
				if (randint0(100) < 50)
					do_cut = 0;

				/* Cancel stun */
				else
					do_stun = 0;
			}

			/* Handle cut */
			if (do_cut) {
				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(dice, rlev, damage);

				/* Roll for damage */
				switch (tmp) {
					case 0: k = 0; break;
					case 1: k = randint1(5); break;
					case 2: k = randint1(5) + 5; break;
					case 3: k = randint1(20) + 20; break;
					case 4: k = randint1(50) + 50; break;
					case 5: k = randint1(100) + 100; break;
					case 6: k = 300; break;
					default: k = 500; break;
				}

				/* Apply the cut */
				if (k) (void)player_inc_timed(p, TMD_CUT, k, true, true);
			}

			/* Handle stun */
			if (do_stun) {
				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(dice, rlev, damage);

				/* Roll for damage */
				switch (tmp) {
					case 0: k = 0; break;
					case 1: k = randint1(5); break;
					case 2: k = randint1(10) + 10; break;
					case 3: k = randint1(20) + 20; break;
					case 4: k = randint1(30) + 30; break;
					case 5: k = randint1(40) + 40; break;
					case 6: k = 100; break;
					default: k = 200; break;
				}

				/* Apply the stun */
				if (k)
					(void)player_inc_timed(p, TMD_STUN, k, true, true);
			}
		} else {
			/* Visible monster missed player, so notify if appropriate. */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
				monster_blow_method_miss(method)) {
				/* Disturbing */
				disturb(p, 1);
				msg("%s misses you.", m_name);
			}
		}

		/* Analyze "visible" monsters only */
		if (visible) {
			/* Count "obvious" attacks (and ones that cause damage) */
			if (obvious || damage || (lore->blows[ap_cnt].times_seen > 10)) {
				/* Count attacks of this type */
				if (lore->blows[ap_cnt].times_seen < UCHAR_MAX)
					lore->blows[ap_cnt].times_seen++;
			}
		}

		/* Skip the other blows if necessary */
		if (do_break) break;
	}

	/* Blink away */
	if (blinked) {
		char dice[5];
		msg("There is a puff of smoke!");
		strnfmt(dice, sizeof(dice), "%d", z_info->max_sight * 2 + 5);
		effect_simple(EF_TELEPORT, dice, 0, 0, 0, NULL);
	}

	/* Always notice cause of death */
	if (p->is_dead && (lore->deaths < SHRT_MAX))
		lore->deaths++;

	/* Learn lore */
	lore_update(mon->race, lore);

	/* Assume we attacked */
	return (true);
}
Esempio n. 5
0
/**
 * Creatures can cast spells, shoot missiles, and breathe.
 *
 * Returns "true" if a spell (or whatever) was (successfully) cast.
 *
 * XXX XXX XXX This function could use some work, but remember to
 * keep it as optimized as possible, while retaining generic code.
 *
 * Verify the various "blind-ness" checks in the code.
 *
 * XXX XXX XXX Note that several effects should really not be "seen"
 * if the player is blind.
 *
 * Perhaps monsters should breathe at locations *near* the player,
 * since this would allow them to inflict "partial" damage.
 *
 * Perhaps smart monsters should decline to use "bolt" spells if
 * there is a monster in the way, unless they wish to kill it.
 *
 * It will not be possible to "correctly" handle the case in which a
 * monster attempts to attack a location which is thought to contain
 * the player, but which in fact is nowhere near the player, since this
 * might induce all sorts of messages about the attack itself, and about
 * the effects of the attack, which the player might or might not be in
 * a position to observe.  Thus, for simplicity, it is probably best to
 * only allow "faulty" attacks by a monster if one of the important grids
 * (probably the initial or final grid) is in fact in view of the player.
 * It may be necessary to actually prevent spell attacks except when the
 * monster actually has line of sight to the player.  Note that a monster
 * could be left in a bizarre situation after the player ducked behind a
 * pillar and then teleported away, for example.
 *
 * Note that this function attempts to optimize the use of spells for the
 * cases in which the monster has no spells, or has spells but cannot use
 * them, or has spells but they will have no "useful" effect.  Note that
 * this function has been an efficiency bottleneck in the past.
 *
 * Note the special "MFLAG_NICE" flag, which prevents a monster from using
 * any spell attacks until the player has had a single chance to move.
 */
bool make_attack_spell(struct monster *mon)
{
	int chance, thrown_spell, rlev, failrate;

	bitflag f[RSF_SIZE];

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return true;
	}

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

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

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

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

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

	/* A spell was cast */
	return true;
}
Esempio n. 6
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);
}