Esempio n. 1
0
/**
 * Check if a monster should stagger or not.  Always stagger when confused,
 * but also deal with random movement for RAND_25 and _50 monsters.
 */
static bool monster_turn_should_stagger(struct monster *mon)
{
	struct monster_lore *lore = get_lore(mon->race);
	int chance = 0;

	/* Increase chance of being erratic for every level of confusion */
	int conf_level = monster_effect_level(mon, MON_TMD_CONF);
	while (conf_level) {
		int accuracy = 100 - chance;
		accuracy *= (100 - CONF_ERRATIC_CHANCE);
		accuracy /= 100;
		chance = 100 - accuracy;
		conf_level--;
	}

	/* RAND_25 and RAND_50 are cumulative */
	if (rf_has(mon->race->flags, RF_RAND_25)) {
		chance += 25;
		if (monster_is_visible(mon))
			rf_on(lore->flags, RF_RAND_25);
	}

	if (rf_has(mon->race->flags, RF_RAND_50)) {
		chance += 50;
		if (monster_is_visible(mon))
			rf_on(lore->flags, RF_RAND_50);
	}

	return randint0(100) < chance;
}
Esempio n. 2
0
/**
 * Check if a monster should stagger or not.  Always stagger when confused,
 * but also deal with random movement for RAND_25 and _50 monsters.
 */
static bool process_monster_should_stagger(struct monster *mon)
{
	struct monster_lore *lore = get_lore(mon->race);

	int chance = 0;

	/* Confused */
	if (mon->m_timed[MON_TMD_CONF])
		return true;

	/* RAND_25 and RAND_50 are cumulative */
	if (rf_has(mon->race->flags, RF_RAND_25)) {
		chance += 25;
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			rf_on(lore->flags, RF_RAND_25);
	}

	if (rf_has(mon->race->flags, RF_RAND_50)) {
		chance += 50;
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			rf_on(lore->flags, RF_RAND_50);
	}

	return randint0(100) < chance;
}
Esempio n. 3
0
/**
 * Extract the multiplier from a given object hitting a given monster.
 *
 * \param o_ptr is the object being used to attack
 * \param m_ptr is the monster being attacked
 * \param best_s_ptr is the best applicable slay_table entry, or NULL if no
 *  slay already known
 * \param real is whether this is a real attack (where we update lore) or a
 *  simulation (where we don't)
 * \param known_only is whether we are using all the object flags, or only
 * the ones we *already* know about
 */
void improve_attack_modifier(object_type *o_ptr, const monster_type
	*m_ptr, const struct slay **best_s_ptr, bool real, bool known_only)
{
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];
	bitflag f[OF_SIZE], known_f[OF_SIZE], note_f[OF_SIZE];
	int i;

	object_flags(o_ptr, f);
	object_flags_known(o_ptr, known_f);

	for (i = 0; i < SL_MAX; i++) {
		const struct slay *s_ptr = &slay_table[i];
		if ((known_only && !of_has(known_f, s_ptr->object_flag)) ||
				(!known_only && !of_has(f, s_ptr->object_flag))) continue;

		/* Disallow forbidden off-weapon slays/brands */
		if (wield_slot(o_ptr) > INVEN_BOW && wield_slot(o_ptr) < INVEN_TOTAL
 				&& !s_ptr->nonweap) continue;

		/* In a real attack, learn about monster resistance or slay match if:
		 * EITHER the slay flag on the object is known,
		 * OR the monster is vulnerable to the slay/brand
		 */
		if (real && (of_has(known_f, s_ptr->object_flag) || (s_ptr->monster_flag
				&& rf_has(r_ptr->flags,	s_ptr->monster_flag)) ||
				(s_ptr->resist_flag && !rf_has(r_ptr->flags,
				s_ptr->resist_flag)) || (s_ptr->vuln_flag &&
				rf_has(r_ptr->flags, s_ptr->vuln_flag)))) {

			/* notice any brand or slay that would affect monster */
			of_wipe(note_f);
			of_on(note_f, s_ptr->object_flag);
			object_notice_slays(o_ptr, note_f);

			if (m_ptr->ml && s_ptr->monster_flag)
				rf_on(l_ptr->flags, s_ptr->monster_flag);

			if (m_ptr->ml && s_ptr->resist_flag)
				rf_on(l_ptr->flags, s_ptr->resist_flag);

			if (m_ptr->ml && s_ptr->vuln_flag)
				rf_on(l_ptr->flags, s_ptr->vuln_flag);
		}

		/* If the monster doesn't resist or the slay flag matches */
		if ((s_ptr->brand && !rf_has(r_ptr->flags, s_ptr->resist_flag)) ||
				(s_ptr->monster_flag && rf_has(r_ptr->flags,
				s_ptr->monster_flag)) || (s_ptr->vuln_flag &&
				rf_has(r_ptr->flags, s_ptr->vuln_flag))) {

			/* compare multipliers to determine best attack */
			if ((*best_s_ptr == NULL) || ((*best_s_ptr)->mult < s_ptr->mult))
				*best_s_ptr = s_ptr;
		}
	}
}
Esempio n. 4
0
/**
 * Extract the multiplier from a given object hitting a given monster.
 *
 * If there is a slay or brand in effect, change the verb for hitting
 * to something interesting ('burn', 'smite', etc.).  Also, note which
 * flags had an effect in o_ptr->known_flags[].
 *
 * \param o_ptr is the object being used to attack
 * \param m_ptr is the monster being attacked
 * \param best_s_ptr is the best applicable slay_table entry, or NULL if no
 *  slay already known
 *
 */
void improve_attack_modifier(object_type *o_ptr, const monster_type *m_ptr, const slay_t **best_s_ptr)
{
	const slay_t *s_ptr;

	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	bitflag f[OF_SIZE], known_f[OF_SIZE];
	object_flags(o_ptr, f);
	object_flags_known(o_ptr, known_f);

	for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++)
	{
		if (!of_has(f, s_ptr->slay_flag)) continue;

		/* Learn about monster resistance/vulnerability IF:
		 * 1) The slay flag on the object is known OR
		 * 2) The monster does not possess the appropriate resistance flag OR
		 * 3) The monster does possess the appropriate vulnerability flag
		 */
		if (of_has(known_f, s_ptr->slay_flag) ||
		    (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) ||
		    (s_ptr->resist_flag && !rf_has(r_ptr->flags, s_ptr->resist_flag)))
		{
			if (m_ptr->ml && s_ptr->monster_flag)
			{
				rf_on(l_ptr->flags, s_ptr->monster_flag);
			}

			if (m_ptr->ml && s_ptr->resist_flag)
			{
				rf_on(l_ptr->flags, s_ptr->resist_flag);
			}
		}

		/* If the monster doesn't match or the slay flag does */
		if ((s_ptr->brand && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || 
		    rf_has(r_ptr->flags, s_ptr->monster_flag))
		{
			/* notice any brand or slay that would affect the monster */
			object_notice_slay(o_ptr, s_ptr->slay_flag);

			/* compare multipliers to determine best attack, would be more complex for O-style brands */
			if ((*best_s_ptr == NULL) || ((*best_s_ptr)->mult < s_ptr->mult))
				*best_s_ptr = s_ptr;
		}
	}
}
Esempio n. 5
0
/**
 * Try to push past / kill another monster.  Returns true on success.
 */
static bool process_monster_try_push(struct chunk *c, struct monster *mon,
									 const char *m_name, int nx, int ny)
{
	struct monster *mon1 = square_monster(c, ny, nx);
	struct monster_lore *lore = get_lore(mon->race);

	/* Kill weaker monsters */
	int kill_ok = rf_has(mon->race->flags, RF_KILL_BODY);

	/* Move weaker monsters if they can swap places */
	/* (not in a wall) */
	int move_ok = (rf_has(mon->race->flags, RF_MOVE_BODY) &&
				   square_ispassable(c, mon->fy, mon->fx));

	if (compare_monsters(mon, mon1) > 0) {
		/* Learn about pushing and shoving */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE)) {
			rf_on(lore->flags, RF_KILL_BODY);
			rf_on(lore->flags, RF_MOVE_BODY);
		}

		if (kill_ok || move_ok) {
			/* Get the names of the monsters involved */
			char n_name[80];
			monster_desc(n_name, sizeof(n_name), mon1, MDESC_IND_HID);

			/* Reveal mimics */
			if (is_mimicking(mon1))
				become_aware(mon1);

			/* Note if visible */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
				mflag_has(mon->mflag, MFLAG_VIEW))
				msg("%s %s %s.", m_name,
					kill_ok ? "tramples over" : "pushes past", n_name);

			/* Monster ate another monster */
			if (kill_ok)
				delete_monster(ny, nx);

			monster_swap(mon->fy, mon->fx, ny, nx);
			return true;
		} 
	}

	return false;
}
Esempio n. 6
0
/**
 * React to slays which hurt a monster
 * 
 * \param obj_flags is the set of flags we're testing for slays
 * \param mon_flags is the set of flags we're adjusting as a result
 */
void react_to_slay(bitflag *obj_flags, bitflag *mon_flags)
{
	int i;
	for (i = 0; i < SL_MAX; i++) {
		const struct slay *s_ptr = &slay_table[i];
		if (of_has(obj_flags, s_ptr->object_flag) && s_ptr->monster_flag)
			rf_on(mon_flags, s_ptr->monster_flag);
	}
}
Esempio n. 7
0
/**
 * Attempt to reproduce, if possible.  All monsters are checked here for
 * lore purposes, the unfit fail.
 */
static bool process_monster_multiply(struct chunk *c, struct monster *m_ptr)
{
	int oy = m_ptr->fy;
	int ox = m_ptr->fx;

	int k = 0, y, x;

	monster_lore *l_ptr = get_lore(m_ptr->race);

	/* Too many breeders on the level already */
	if (num_repro >= z_info->repro_monster_max) return FALSE;

	/* Count the adjacent monsters */
	for (y = oy - 1; y <= m_ptr->fy + 1; y++)
		for (x = ox - 1; x <= m_ptr->fx + 1; x++)
			if (c->squares[y][x].mon > 0) k++;

	/* Multiply slower in crowded areas */
	if ((k < 4) && (k == 0 || one_in_(k * z_info->repro_monster_rate))) {
		/* Successful breeding attempt, learn about that now */
		if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE))
			rf_on(l_ptr->flags, RF_MULTIPLY);

		/* Leave now if not a breeder */
		if (!rf_has(m_ptr->race->flags, RF_MULTIPLY))
			return FALSE;

		/* Try to multiply */
		if (multiply_monster(m_ptr)) {
			/* Make a sound */
			if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE))
				sound(MSG_MULTIPLY);

			/* Multiplying takes energy */
			return TRUE;
		}
	}

	return FALSE;
}
Esempio n. 8
0
/**
 * Attempt to reproduce, if possible.  All monsters are checked here for
 * lore purposes, the unfit fail.
 */
static bool monster_turn_multiply(struct chunk *c, struct monster *mon)
{
	int k = 0, y, x;

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

	/* Too many breeders on the level already */
	if (num_repro >= z_info->repro_monster_max) return false;

	/* Count the adjacent monsters */
	for (y = mon->fy - 1; y <= mon->fy + 1; y++)
		for (x = mon->fx - 1; x <= mon->fx + 1; x++)
			if (c->squares[y][x].mon > 0) k++;

	/* Multiply slower in crowded areas */
	if ((k < 4) && (k == 0 || one_in_(k * z_info->repro_monster_rate))) {
		/* Successful breeding attempt, learn about that now */
		if (monster_is_visible(mon))
			rf_on(lore->flags, RF_MULTIPLY);

		/* Leave now if not a breeder */
		if (!rf_has(mon->race->flags, RF_MULTIPLY))
			return false;

		/* Try to multiply */
		if (multiply_monster(c, mon)) {
			/* Make a sound */
			if (monster_is_visible(mon))
				sound(MSG_MULTIPLY);

			/* Multiplying takes energy */
			return true;
		}
	}

	return false;
}
Esempio n. 9
0
/**
 * Grab all objects from the grid.
 */
void process_monster_grab_objects(struct chunk *c, struct monster *mon, 
		const char *m_name, int nx, int ny)
{
	struct monster_lore *lore = get_lore(mon->race);
	struct object *obj;
	bool visible = mflag_has(mon->mflag, MFLAG_VISIBLE);

	/* Learn about item pickup behavior */
	for (obj = square_object(c, ny, nx); obj; obj = obj->next) {
		if (!tval_is_money(obj) && visible) {
			rf_on(lore->flags, RF_TAKE_ITEM);
			rf_on(lore->flags, RF_KILL_ITEM);
			break;
		}
	}

	/* Abort if can't pickup/kill */
	if (!rf_has(mon->race->flags, RF_TAKE_ITEM) &&
		!rf_has(mon->race->flags, RF_KILL_ITEM)) {
		return;
	}

	/* Take or kill objects on the floor */
	obj = square_object(c, ny, nx);
	while (obj) {
		char o_name[80];
		bool safe = obj->artifact ? true : false;
		struct object *next = obj->next;

		/* Skip gold */
		if (tval_is_money(obj)) {
			obj = next;
			continue;
		}

		/* Skip mimicked objects */
		if (obj->mimicking_m_idx) {
			obj = next;
			continue;
		}

		/* Get the object name */
		object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);

		/* React to objects that hurt the monster */
		if (react_to_slay(obj, mon))
			safe = true;

		/* Try to pick up, or crush */
		if (safe) {
			/* Only give a message for "take_item" */
			if (rf_has(mon->race->flags, RF_TAKE_ITEM) && visible &&
				square_isview(c, ny, nx) && !ignore_item_ok(obj)) {
				/* Dump a message */
				msg("%s tries to pick up %s, but fails.", m_name, o_name);
			}
		} else if (rf_has(mon->race->flags, RF_TAKE_ITEM)) {
			/* Describe observable situations */
			if (square_isseen(c, ny, nx) && !ignore_item_ok(obj))
				msg("%s picks up %s.", m_name, o_name);

			/* Carry the object */
			square_excise_object(c, ny, nx, obj);
			monster_carry(c, mon, obj);
			square_note_spot(c, ny, nx);
			square_light_spot(c, ny, nx);
		} else {
			/* Describe observable situations */
			if (square_isseen(c, ny, nx) && !ignore_item_ok(obj))
				msgt(MSG_DESTROY, "%s crushes %s.", m_name, o_name);

			/* Delete the object */
			square_excise_object(c, ny, nx, obj);
			delist_object(c, obj);
			object_delete(&obj);
			square_note_spot(c, ny, nx);
			square_light_spot(c, ny, nx);
		}

		/* Next object */
		obj = next;
	}
}
Esempio n. 10
0
/**
 * Work out if a monster can move through the grid, if necessary bashing 
 * down doors in the way.
 *
 * Returns true if the monster is able to move through the grid.
 */
static bool monster_turn_can_move(struct chunk *c, struct monster *mon,
		const char *m_name, int nx, int ny, bool *did_something)
{
	struct monster_lore *lore = get_lore(mon->race);

	/* Dangerous terrain in the way */
	if (monster_hates_grid(c, mon, ny, nx)) {
		return false;
	}

	/* Floor is open? */
	if (square_ispassable(c, ny, nx)) {
		return true;
	}

	/* Permanent wall in the way */
	if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) {
		return false;
	}

	/* Normal wall, door, or secret door in the way */

	/* There's some kind of feature in the way, so learn about
	 * kill-wall and pass-wall now */
	if (monster_is_visible(mon)) {
		rf_on(lore->flags, RF_PASS_WALL);
		rf_on(lore->flags, RF_KILL_WALL);
	}

	/* Monster may be able to deal with walls and doors */
	if (rf_has(mon->race->flags, RF_PASS_WALL)) {
		return true;
	} else if (rf_has(mon->race->flags, RF_KILL_WALL)) {
		/* Remove the wall */
		square_destroy_wall(c, ny, nx);

		/* Note changes to viewable region */
		if (square_isview(c, ny, nx))
			player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);

		return true;
	} else if (square_iscloseddoor(c, ny, nx) ||
			   square_issecretdoor(c, ny, nx)) {
		bool can_open = rf_has(mon->race->flags, RF_OPEN_DOOR);
		bool can_bash = rf_has(mon->race->flags, RF_BASH_DOOR);
		bool will_bash = false;

		/* Take a turn */
		*did_something = true;

		/* Learn about door abilities */
		if (monster_is_visible(mon)) {
			rf_on(lore->flags, RF_OPEN_DOOR);
			rf_on(lore->flags, RF_BASH_DOOR);
		}

		/* If creature can open or bash doors, make a choice */
		if (can_open) {
			/* Sometimes bash anyway (impatient) */
			if (can_bash) {
				will_bash = one_in_(2) ? true : false;
			}
		} else if (can_bash) {
			/* Only choice */
			will_bash = true;
		} else {
			/* Door is an insurmountable obstacle */
			return false;
		}

		/* Now outcome depends on type of door */
		if (square_islockeddoor(c, ny, nx)) {
			/* Locked door -- test monster strength against door strength */
			int k = square_door_power(c, ny, nx);
			if (randint0(mon->hp / 10) > k) {
				if (will_bash) {
					msg("%s slams against the door.", m_name);
				} else {
					msg("%s fiddles with the lock.", m_name);
				}

				/* Reduce the power of the door by one */
				square_set_door_lock(c, ny, nx, k - 1);
			}
		} else {
			/* Closed or secret door -- always open or bash */
			if (square_isview(c, ny, nx))
				player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);

			if (will_bash) {
				square_smash_door(c, ny, nx);

				msg("You hear a door burst open!");
				disturb(player, 0);

				/* Fall into doorway */
				return true;
			} else {
				square_open_door(c, ny, nx);
			}
		}
	}

	return false;
}
Esempio n. 11
0
/**
 * Work out if a monster can move through the grid, if necessary bashing 
 * down doors in the way.
 *
 * Returns true if the monster is able to move through the grid.
 */
static bool process_monster_can_move(struct chunk *c, struct monster *mon,
		const char *m_name, int nx, int ny, bool *did_something)
{
	struct monster_lore *lore = get_lore(mon->race);

	/* Only fiery creatures can handle lava */
	if (square_isfiery(c, ny, nx) && !rf_has(mon->race->flags, RF_IM_FIRE))
		return false;

	/* Floor is open? */
	if (square_ispassable(c, ny, nx))
		return true;

	/* Permanent wall in the way */
	if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx))
		return false;

	/* Normal wall, door, or secret door in the way */

	/* There's some kind of feature in the way, so learn about
	 * kill-wall and pass-wall now */
	if (mflag_has(mon->mflag, MFLAG_VISIBLE)) {
		rf_on(lore->flags, RF_PASS_WALL);
		rf_on(lore->flags, RF_KILL_WALL);
	}

	/* Monster may be able to deal with walls and doors */
	if (rf_has(mon->race->flags, RF_PASS_WALL)) {
		return true;
	} else if (rf_has(mon->race->flags, RF_KILL_WALL)) {
		/* Remove the wall */
		square_destroy_wall(c, ny, nx);

		/* Note changes to viewable region */
		if (square_isview(c, ny, nx))
			player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);

		/* Fully update the flow since terrain changed */
		player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW);

		return true;
	} else if (square_iscloseddoor(c, ny, nx) ||
			   square_issecretdoor(c, ny, nx)) {
		bool may_bash = rf_has(mon->race->flags, RF_BASH_DOOR) && one_in_(2);

		/* Take a turn */
		*did_something = true;

		/* Learn about door abilities */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE)) {
			rf_on(lore->flags, RF_OPEN_DOOR);
			rf_on(lore->flags, RF_BASH_DOOR);
		}

		/* Creature can open or bash doors */
		if (!rf_has(mon->race->flags, RF_OPEN_DOOR) &&
			!rf_has(mon->race->flags, RF_BASH_DOOR))
			return false;

		/* Stuck door -- try to unlock it */
		if (square_islockeddoor(c, ny, nx)) {
			int k = square_door_power(c, ny, nx);

			if (randint0(mon->hp / 10) > k) {
				if (may_bash)
					msg("%s slams against the door.", m_name);
				else
					msg("%s fiddles with the lock.", m_name);

				/* Reduce the power of the door by one */
				square_set_door_lock(c, ny, nx, k - 1);
			}
		} else {
			/* Handle viewable doors */
			if (square_isview(c, ny, nx))
				player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);

			/* Closed or secret door -- open or bash if allowed */
			if (may_bash) {
				square_smash_door(c, ny, nx);

				msg("You hear a door burst open!");
				disturb(player, 0);

				/* Fall into doorway */
				return true;
			} else if (rf_has(mon->race->flags, RF_OPEN_DOOR)) {
				square_open_door(c, ny, nx);
			}
		}
	}

	return false;
}
Esempio n. 12
0
/*
 * Attack the monster at the given location
 *
 * If no "weapon" is available, then "punch" the monster one time.
 *
 * We get blows until energy drops below that required for another blow, or
 * until the target monster dies. We use a wrapper to work out the number of
 * blows. We don't allow @ to spend more than 100 energy in one go, to avoid
 * slower monsters getting double moves.
 */
bool py_attack_real(int y, int x)
{
	int bonus, chance;

	monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	object_type *o_ptr;

	char m_name[80];

	bool fear = FALSE;

	bool do_quake = FALSE;
	bool dead = FALSE;

	u32b msg_type = 0;
	bool success = FALSE;
	
	const char *hit_verb = "ERROR";
	int dmg = 1;
	
	/* Default to punching for one damage */
	/* Maybe handle monster melee here -Simon */
	if(!rp_ptr->p_monster_index)
	{
		hit_verb = "punch";
		msg_type = MSG_HIT;
	}

	/*
	 * Hack -- if advanced innate attacks are disabled for this race, fall back
	 * on defaults <player>'s 1d1.
	 */
	 /* TODO: this -Simon */
	/* if (p_ptr->flags[NO_INNATE])
	{
			p_ptr = &r_info[0];
	} */


	/* 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(cave_m_idx[y][x]);

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

	/* Disturb the monster */
	wake_monster(m_ptr);

	/* Get the weapon */
	o_ptr = &p_ptr->inventory[INVEN_WIELD];
	
		/* Calculate the "attack quality" */
	bonus = p_ptr->state.to_h + o_ptr->to_h;
	chance = (p_ptr->state.skills[SKILL_TO_HIT_MELEE] + (bonus * BTH_PLUS_ADJ));

	/* Handle innate melee -Simon */
	if(!o_ptr->k_idx && rp_ptr->p_monster_index)
	{
		for (int num = 0; (num < MONSTER_BLOW_MAX) && !dead; num++)
		{
			const slay_t *best_s_ptr = NULL;
			int type = GF_ARROW, type2 = 0, i;
			int flg = PROJECT_KILL | PROJECT_STOP | PROJECT_HIDE; // | PROJECT_PASS; TODO: figure out what this is and implement it -Simon
			char *p = "";
						
			if (!r_info[rp_ptr->p_monster_index].blow[num].method && !dead)
				continue;
					
			/* Test for hit */
			if (test_hit(chance, r_info[m_ptr->r_idx].ac, m_ptr->ml))
			{
				int mul = 1;
				int k = 0;
				
				/* Get the method */
				switch (r_info[rp_ptr->p_monster_index].blow[num].method)
				{
					case RBM_HIT:	p = "hit"; break;
					case RBM_TOUCH:	p = "touch"; break;
					case RBM_PUNCH:	p = "punch"; break;
					case RBM_KICK:	p = "kick"; break;
					case RBM_CLAW:	p = "claw"; break;
					case RBM_BITE:	p = "bite"; break;
					case RBM_STING:	p = "sting"; break;
					case RBM_BUTT:	p = "butt"; break;
					case RBM_CRUSH:	p = "crush"; break;
					case RBM_ENGULF:p = "engulf"; break;
					case RBM_PECK:	p = "peck"; break;
					case RBM_CRAWL:	p = "crawl on"; break;
					case RBM_DROOL:	p = "drool on"; break;
					case RBM_SPIT:	p = "spit on"; break;
					case RBM_SLIME:	p = "slime"; break;
					case RBM_GAZE:	p = "gaze at"; break;
					case RBM_WAIL:	p = "wail at"; break;
					case RBM_SPORE:	p = "release spores at"; break;
					case RBM_BEG:	p = "beg for money"; break;
					case RBM_INSULT:	p = "insult"; break;
					default: p = "attack";
				}

				/* Get the effect */
				switch (r_info[rp_ptr->p_monster_index].blow[num].effect)
				{
					case RBE_HURT: type = GF_ARROW; break;
					case RBE_DISEASE: type = GF_POIS; mul = 2; break;
					case RBE_POISON: type = GF_POIS; mul = 2; break;
					case RBE_LOSE_MANA: type = GF_DISENCHANT; break;
					case RBE_UN_BONUS: type = GF_DISENCHANT; mul = 2; break;
					case RBE_UN_POWER: type = GF_DISENCHANT; mul = 2; break; /* ? */
					case RBE_EAT_LIGHT: type = GF_DARK; mul = 2; break;
					case RBE_ACID: type = GF_ACID; mul = 2; break;
					case RBE_ELEC: type = GF_ELEC; mul = 2; break;
					case RBE_FIRE: type = GF_FIRE; mul = 2; break;
					case RBE_COLD: type = GF_COLD; mul = 2; break;
					case RBE_BLIND: type2 = GF_OLD_CONF; break; /* ? */
					case RBE_CONFUSE: type2 = GF_OLD_CONF; break;
					case RBE_TERRIFY: type2 = GF_TURN_ALL; break; /* ? */
					case RBE_PARALYZE: type2 = GF_OLD_SLEEP; break; /* ? */
					/* Earthquake would be natural, but all monsters
					 * with RBE_SHATTER are already humanoids
					 */
					case RBE_SHATTER: type = GF_ARROW; break;
					case RBE_EXP_10: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_20: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_40: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_80: type = GF_NETHER; mul = 2; break;
					/* GF_CHAOS will polymorph, so it is bad */
					case RBE_HALLU: type = GF_DISENCHANT; mul = 2; break;
					default: type = GF_ARROW;
				}
			
				k = damroll(r_info[rp_ptr->p_monster_index].blow[num].d_dice, r_info[rp_ptr->p_monster_index].blow[num].d_side);
				/* Get the best attack from all slays or
				 * brands on all non-launcher equipment */
				for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
					improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr);
					
				if (best_s_ptr != NULL)
				{
					if (best_s_ptr->mult > mul)
					{
						p = best_s_ptr->melee_verb;
						mul = best_s_ptr->mult;
						if (best_s_ptr->resist_flag == RF_IM_ACID)
							type = GF_ACID;
						else if (best_s_ptr->resist_flag == RF_IM_ELEC)
							type = GF_ELEC;
						else if (best_s_ptr->resist_flag == RF_IM_FIRE)
							type = GF_FIRE;
						else if (best_s_ptr->resist_flag == RF_IM_COLD)
							type = GF_COLD;
						else if (best_s_ptr->resist_flag == RF_IM_POIS)
							type = GF_POIS;
					}
				}
				
				k *= mul;
				message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", p, m_name);
				/* Add to-dam bonus only if did some damage */
				if (k) k += p_ptr->state.to_d;
				if (k < 0) k = 0;
				
				/* Learn by use for other equipped items */
				wieldeds_notice_on_attack();
					
				/* If there is an extra effect, project it also, using 4*level as power */
				if (type2)
				{
					project(-1, 0, y, x, 4 * p_ptr->lev, type2, flg);
				}
							       
				/* Confusion attack */
				if (p_ptr->confusing)
				{
					/* Message */
					if (p_ptr->confusing)
						msg_print("Your limbs stop glowing.");
				
					/* Cancel glowing hands */
					p_ptr->confusing = FALSE;

					/* Confuse the monster */
					if (rf_has(r_ptr->flags, RF_NO_CONF))
					{
						if (m_ptr->ml)
						{
							rf_on(l_ptr->flags, RF_NO_CONF);
						}
						msg_format("%^s is unaffected.", m_name);
					}
					else if (randint0(100) < r_ptr->level)
					{
						msg_format("%^s appears slightly perplexed.", m_name);
					}
					else
					{
						msg_format("%^s appears confused.", m_name);
						m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
					}
				}
				
				/* Damage, check for fear and death */
				/* Makes elemental attacks do half their damage physically -Simon */
				if (type != GF_ARROW)
				{
					project(-1, 0, y, x, (k + 1)/2, type, flg);
					/* Make the physical portion TOP SECRET -Simon */
					flg &= ~(PROJECT_AWARE);
					project(-1, 0, y, x, k/2, GF_ARROW, flg);
				}
				else
					project(-1, 0, y, x, k, type, flg);
				/* Hack: check if the square is empty after we project the attack into it -Simon */
				dead = (cave_m_idx[y][x] == 0);
			
				/* Hack -- delay fear messages */
				if (fear && m_ptr->ml && !dead)
					message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name);
			}
			/* Player misses */
			else
			{
				/* Message */
				message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);
			}
		}	
		return (TRUE);
	}
	
	else
	{
		/* See if the player hit */
		success = test_hit(chance, r_ptr->ac, m_ptr->ml);

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

		/* Handle normal weapon */
		if (o_ptr->k_idx)
		{
			int i;
			const slay_t *best_s_ptr = NULL;

			hit_verb = "hit";

			/* Get the best attack from all slays or
			 * brands on all non-launcher equipment */
			for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
				improve_attack_modifier(&p_ptr->inventory[i], m_ptr,
				&best_s_ptr);

			improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr);
			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;

			if (p_ptr->state.impact && (dmg > 50))
				do_quake = TRUE;

			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 (do_quake)
				wieldeds_notice_flag(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)
			message_format(MSG_MISS, m_ptr->r_idx,
						   "You fail to harm %s.", m_name);
		else if (msg_type == MSG_HIT)
			message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.",
						   hit_verb, m_name);
		else if (msg_type == MSG_HIT_GOOD)
			message_format(MSG_HIT_GOOD, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a good hit!");
		else if (msg_type == MSG_HIT_GREAT)
			message_format(MSG_HIT_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a great hit!");
		else if (msg_type == MSG_HIT_SUPERB)
			message_format(MSG_HIT_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a superb hit!");
		else if (msg_type == MSG_HIT_HI_GREAT)
			message_format(MSG_HIT_HI_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *GREAT* hit!");
		else if (msg_type == MSG_HIT_HI_SUPERB)
			message_format(MSG_HIT_HI_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *SUPERB* hit!");

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

		/* Confusion attack */
		if (p_ptr->confusing)
		{
			/* Cancel glowing hands */
			p_ptr->confusing = FALSE;

			/* Message */
			msg_print("Your limbs stop glowing.");

			/* Update the lore */
			if (m_ptr->ml)
				rf_on(l_ptr->flags, RF_NO_CONF);

			/* Confuse the monster */
			if (rf_has(r_ptr->flags, RF_NO_CONF))
				msg_format("%^s is unaffected.", m_name);
			else if (randint0(100) < r_ptr->level)
				msg_format("%^s is unaffected.", m_name);
			else
			{
				msg_format("%^s appears confused.", m_name);
				m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
			}
		}

		/* Damage, check for fear and death */
		dead = mon_take_hit(cave_m_idx[y][x], dmg, &fear, NULL);

		/* Hack -- delay fear messages */
		if (fear && m_ptr->ml)
			message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!",
			m_name);

		/* Mega-Hack -- apply earthquake brand */
		if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10);

		return (dead);
	}
}
Esempio n. 13
0
/**
 * Determines whether the given monster successfully resists the given effect.
 *
 * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns false.
 * Then we determine if the monster resists the effect for some racial
 * reason. For example, the monster might have the NO_SLEEP flag, in which
 * case it always resists sleep. Or if it breathes chaos, it always resists
 * confusion. If the given monster doesn't resist for any of these reasons,
 * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`,
 * indicating that another monster caused this effect, then the chance of
 * success on the saving throw just depends on the monster's native depth.
 * Otherwise, the chance of success decreases as `timer` increases.
 *
 * Also marks the lore for any appropriate resists.
 */
static bool mon_resist_effect(const struct monster *mon, int ef_idx, int timer, u16b flag)
{
	struct mon_timed_effect *effect;
	int resist_chance;
	struct monster_lore *lore;

	assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX);
	assert(mon);

	effect = &effects[ef_idx];
	lore = get_lore(mon->race);
	
	/* Hasting never fails */
	if (ef_idx == MON_TMD_FAST) return (false);
	
	/* Some effects are marked to never fail */
	if (flag & MON_TMD_FLG_NOFAIL) return (false);

	/* A sleeping monster resists further sleeping */
	if (ef_idx == MON_TMD_SLEEP && mon->m_timed[ef_idx]) return (true);

	/* If the monster resists innately, learn about it */
	if (rf_has(mon->race->flags, effect->flag_resist)) {
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			rf_on(lore->flags, effect->flag_resist);

		return (true);
	}

	/* Monsters with specific breaths resist stunning */
	if (ef_idx == MON_TMD_STUN &&
		(rsf_has(mon->race->spell_flags, RSF_BR_SOUN) ||
		 rsf_has(mon->race->spell_flags, RSF_BR_WALL))) {
		/* Add the lore */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE)) {
			if (rsf_has(mon->race->spell_flags, RSF_BR_SOUN))
				rsf_on(lore->spell_flags, RSF_BR_SOUN);
			if (rsf_has(mon->race->spell_flags, RSF_BR_WALL))
				rsf_on(lore->spell_flags, RSF_BR_WALL);
		}

		return (true);
	}

	/* Monsters with specific breaths resist confusion */
	if ((ef_idx == MON_TMD_CONF) &&
		rsf_has(mon->race->spell_flags, RSF_BR_CHAO)) {
		/* Add the lore */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			if (rsf_has(mon->race->spell_flags, RSF_BR_CHAO))
				rsf_on(lore->spell_flags, RSF_BR_CHAO);

		return (true);
	}

	/* Inertia breathers resist slowing */
	if (ef_idx == MON_TMD_SLOW && rsf_has(mon->race->spell_flags, RSF_BR_INER)){
		rsf_on(lore->spell_flags, RSF_BR_INER);
		return (true);
	}

	/* Calculate the chance of the monster making its saving throw. */
	if (ef_idx == MON_TMD_SLEEP)
		timer /= 25; /* Hack - sleep uses much bigger numbers */

	if (flag & MON_TMD_MON_SOURCE)
		resist_chance = mon->race->level;
	else
		resist_chance = mon->race->level + 40 - (timer / 2);

	if (randint0(100) < resist_chance) return (true);

	/* Uniques are doubly hard to affect */
	if (rf_has(mon->race->flags, RF_UNIQUE))
		if (randint0(100) < resist_chance) return (true);

	return (false);
}
Esempio n. 14
0
/**
 * Determines whether the given monster successfully resists the given effect.
 *
 * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns FALSE.
 * Then we determine if the monster resists the effect for some racial
 * reason. For example, the monster might have the NO_SLEEP flag, in which
 * case it always resists sleep. Or if it breathes chaos, it always resists
 * confusion. If the given monster doesn't resist for any of these reasons,
 * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`,
 * indicating that another monster caused this effect, then the chance of
 * success on the saving throw just depends on the monster's native depth.
 * Otherwise, the chance of success decreases as `timer` increases.
 *
 * Also marks the lore for any appropriate resists.
 */
static bool mon_resist_effect(const monster_type *m_ptr, int ef_idx, int timer, u16b flag)
{
	mon_timed_effect *effect;
	int resist_chance;
	const monster_race *r_ptr;
	monster_lore *l_ptr;

	assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX);
	effect = &effects[ef_idx];

	assert(m_ptr);
	r_ptr = &r_info[m_ptr->r_idx];
	l_ptr = &l_list[m_ptr->r_idx];
	
	/* Hasting never fails */
	if (ef_idx == MON_TMD_FAST) return (FALSE);
	
	/* Some effects are marked to never fail */
	if (flag & MON_TMD_FLG_NOFAIL) return (FALSE);

	/* A sleeping monster resists further sleeping */
	if (ef_idx == MON_TMD_SLEEP && m_ptr->m_timed[ef_idx]) return (TRUE);

	/* If the monster resists innately, learn about it */
	if (rf_has(r_ptr->flags, effect->flag_resist)) {
		if (m_ptr->ml)
			rf_on(l_ptr->flags, effect->flag_resist);

		return (TRUE);
	}

	/* Monsters with specific breaths resist stunning*/
	if (ef_idx == MON_TMD_STUN && (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN) ||
			rsf_has(r_ptr->spell_flags, RSF_BR_WALL)))
	{
		/* Add the lore */
		if (m_ptr->ml)
		{
			if (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN))
				rsf_on(l_ptr->spell_flags, RSF_BR_SOUN);
			if (rsf_has(r_ptr->spell_flags, RSF_BR_WALL))
				rsf_on(l_ptr->spell_flags, RSF_BR_WALL);
		}

		return (TRUE);
	}

	/* Monsters with specific breaths resist confusion */
	if ((ef_idx == MON_TMD_CONF) &&
		((rsf_has(r_ptr->spell_flags, RSF_BR_CHAO)) ||
		 (rsf_has(r_ptr->spell_flags, RSF_BR_CONF))) )
	{
		/* Add the lore */
		if (m_ptr->ml)
		{
			if (rsf_has(r_ptr->spell_flags, RSF_BR_CHAO))
				rsf_on(l_ptr->spell_flags, RSF_BR_CHAO);
			if (rsf_has(r_ptr->spell_flags, RSF_BR_CONF))
				rsf_on(l_ptr->spell_flags, RSF_BR_CONF);
		}

		return (TRUE);
	}

	/* Inertia breathers resist slowing */
	if (ef_idx == MON_TMD_SLOW && rsf_has(r_ptr->spell_flags, RSF_BR_INER))
	{
		rsf_on(l_ptr->spell_flags, RSF_BR_INER);
		return (TRUE);
	}

	/* Calculate the chance of the monster making its saving throw. */
	if (ef_idx == MON_TMD_SLEEP)
		timer /= 25; /* Hack - sleep uses much bigger numbers */

	if (flag & MON_TMD_MON_SOURCE)
		resist_chance = r_ptr->level;
	else
		resist_chance = r_ptr->level + 40 - (timer / 2);

	if (randint0(100) < resist_chance) return (TRUE);

	/* Uniques are doubly hard to affect */
	if (rf_has(r_ptr->flags, RF_UNIQUE))
		if (randint0(100) < resist_chance) return (TRUE);

	return (FALSE);
}
Esempio n. 15
0
/**
 * Grab all objects from the grid.
 */
void process_monster_grab_objects(struct chunk *c, struct monster *m_ptr, 
		const char *m_name, int nx, int ny)
{
	monster_lore *l_ptr = get_lore(m_ptr->race);
	struct object *obj = square_object(c, ny, nx);

	bool is_item = obj ? TRUE : FALSE;;
	if (is_item && mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) {
		rf_on(l_ptr->flags, RF_TAKE_ITEM);
		rf_on(l_ptr->flags, RF_KILL_ITEM);
	}

	/* Abort if can't pickup/kill */
	if (!rf_has(m_ptr->race->flags, RF_TAKE_ITEM) &&
			!rf_has(m_ptr->race->flags, RF_KILL_ITEM)) {
		return;
	}

	/* Take or kill objects on the floor */
	while (obj) {
		char o_name[80];
		bool safe = obj->artifact ? TRUE : FALSE;
		struct object *next = obj->next;

		/* Skip gold */
		if (tval_is_money(obj)) {
			obj = next;
			continue;
		}

		/* Get the object name */
		object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);

		/* React to objects that hurt the monster */
		if (react_to_slay(obj, m_ptr))
			safe = TRUE;

		/* The object cannot be picked up by the monster */
		if (safe) {
			/* Only give a message for "take_item" */
			if (rf_has(m_ptr->race->flags, RF_TAKE_ITEM) &&
				mflag_has(m_ptr->mflag, MFLAG_VISIBLE) &&
				player_has_los_bold(ny, nx) && !ignore_item_ok(obj)) {
				/* Dump a message */
				msg("%s tries to pick up %s, but fails.", m_name, o_name);
			}

		/* Pick up the item */
		} else if (rf_has(m_ptr->race->flags, RF_TAKE_ITEM)) {
			/* Describe observable situations */
			if (player_has_los_bold(ny, nx) && !ignore_item_ok(obj))
				msg("%s picks up %s.", m_name, o_name);

			/* Carry the object */
			square_excise_object(c, ny, nx, obj);
			monster_carry(c, m_ptr, obj);

		/* Destroy the item */
		} else {
			/* Describe observable situations */
			if (player_has_los_bold(ny, nx) && !ignore_item_ok(obj))
				msgt(MSG_DESTROY, "%s crushes %s.", m_name, o_name);

			/* Delete the object */
			square_excise_object(c, ny, nx, obj);
			object_delete(obj);
		}

		/* Next object */
		obj = next;
	}
}
Esempio n. 16
0
/**
 * Process a monster
 *
 * In several cases, we directly update the monster lore
 *
 * Note that a monster is only allowed to "reproduce" if there
 * are a limited number of "reproducing" monsters on the current
 * level.  This should prevent the level from being "swamped" by
 * reproducing monsters.  It also allows a large mass of mice to
 * prevent a louse from multiplying, but this is a small price to
 * pay for a simple multiplication method.
 *
 * XXX Monster fear is slightly odd, in particular, monsters will
 * fixate on opening a door even if they cannot open it.  Actually,
 * the same thing happens to normal monsters when they hit a door
 *
 * In addition, monsters which *cannot* open or bash down a door
 * will still stand there trying to open it...  XXX XXX XXX
 *
 * Technically, need to check for monster in the way combined
 * with that monster being in a wall (or door?) XXX
 */
static void process_monster(struct chunk *c, struct monster *mon)
{
	struct monster_lore *lore = get_lore(mon->race);

	bool did_something = false;

	int i;
	int dir = 0;
	bool stagger = false;
	char m_name[80];

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

	/* Try to multiply - this can use up a turn */
	if (process_monster_multiply(c, mon))
		return;

	/* Attempt to cast a spell */
	if (make_attack_spell(mon)) return;

	/* Work out what kind of movement to use - AI or staggered movement */
	if (!process_monster_should_stagger(mon)) {
		if (!get_moves(c, mon, &dir)) return;
	} else {
		stagger = true;
	}

	/* Process moves */
	for (i = 0; i < 5 && !did_something; i++) {
		int oy = mon->fy;
		int ox = mon->fx;

		/* Get the direction (or stagger) */
		int d = (stagger ? ddd[randint0(8)] : side_dirs[dir][i]);

		/* Get the destination */
		int ny = oy + ddy[d];
		int nx = ox + ddx[d];

		/* Check if we can move */
		if (!process_monster_can_move(c, mon, m_name, nx, ny, &did_something))
			continue;

		/* Try to break the glyph if there is one.  This can happen multiple
		 * times per turn because failure does not break the loop */
		if (square_iswarded(c, ny, nx) &&
			!process_monster_glyph(c, mon, nx, ny))
			continue;

		/* The player is in the way. */
		if (square_isplayer(c, ny, nx)) {
			/* Learn about if the monster attacks */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE))
				rf_on(lore->flags, RF_NEVER_BLOW);

			/* Some monsters never attack */
			if (rf_has(mon->race->flags, RF_NEVER_BLOW))
				continue;

			/* Otherwise, attack the player */
			make_attack_normal(mon, player);

			did_something = true;
			break;
		} else {
			/* Some monsters never move */
			if (rf_has(mon->race->flags, RF_NEVER_MOVE)) {
				/* Learn about lack of movement */
				if (mflag_has(mon->mflag, MFLAG_VISIBLE))
					rf_on(lore->flags, RF_NEVER_MOVE);

				return;
			}
		}

		/* A monster is in the way, try to push past/kill */
		if (square_monster(c, ny, nx)) {
			did_something = process_monster_try_push(c, mon, m_name, nx, ny);
		} else {
			/* Otherwise we can just move */
			monster_swap(oy, ox, ny, nx);
			did_something = true;
		}

		/* Scan all objects in the grid, if we reached it */
		if (mon == square_monster(c, ny, nx)) {
			monster_desc(m_name, sizeof(m_name), mon,
						 MDESC_CAPITAL | MDESC_IND_HID);
			process_monster_grab_objects(c, mon, m_name, nx, ny);
		}
	}

	if (did_something) {
		/* Learn about no lack of movement */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			rf_on(lore->flags, RF_NEVER_MOVE);

		/* Possible disturb */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
			mflag_has(mon->mflag, MFLAG_VIEW) && OPT(player, disturb_near))
			disturb(player, 0);		
	}

	/* Hack -- get "bold" if out of options */
	if (!did_something && mon->m_timed[MON_TMD_FEAR])
		mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOTIFY, false);

	/* If we see an unaware monster do something, become aware of it */
	if (did_something && mflag_has(mon->mflag, MFLAG_UNAWARE))
		become_aware(mon);
}
Esempio n. 17
0
/*
 * read_scroll:
 *	Let the hero read a scroll
 */
int read_scroll()
{
	struct object *obj;
	struct linked_list *item;
	int i, j, wh;
	unsigned long ch, nch;
	struct room *rp;
	struct linked_list *titem;
	char buf[LINLEN];
	bool bless, curse;

	if ((item = get_item("read", SCROLL)) == NULL)
		return 0;
	obj = OBJPTR(item);
	if (obj->o_type != SCROLL) {
		msg("Nothing to read.");
		after = FALSE;
		return 0;
	}
	msg("As you read the scroll, it vanishes.");
	wh = obj->o_which;
	bless = o_on(obj, ISBLESS);
	curse = o_on(obj, ISCURSED);
	del_pack(item);		/* Get rid of the thing */

	/*
	 * Calculate the effect it has on the hero
	 */
	switch(wh) {
	case S_KNOWALL:
		if (!curse) {
			idenpack();				/* identify all the pack */
			msg("You feel more knowledgable.");
			chg_abil(WIS,1,TRUE);
			s_know[S_KNOWALL] = TRUE;
		}
	when S_CONFUSE:
		if (!curse) {
			/*
			 * Scroll of monster confusion.  Give him that power.
			 */
			msg("Your hands begin to glow red.");
			player.t_flags |= CANHUH;
			s_know[S_CONFUSE] = TRUE;
		}
	when S_LIGHT:
		rp = player.t_room;
		if (!curse) {
			if (rp == NULL) {
				s_know[S_LIGHT] = TRUE;
				msg("The corridor glows and then fades.");
			}
			else {
				if (rf_on(rp,ISDARK)) {
					s_know[S_LIGHT] = TRUE;
					msg("The room is lit.");
					rp->r_flags &= ~ISDARK;
				}
				light(&hero);
				mvwaddch(cw, hero.y, hero.x, PLAYER);
			}
		}
	when S_ARMOR:
		if (!curse) {
			if (cur_armor != NULL && o_off(cur_armor,ISPROT)) {
				s_know[S_ARMOR] = TRUE;
				msg("Your armor glows faintly for a moment.");
				if (o_on(cur_armor,ISCURSED))
					cur_armor->o_ac = armors[cur_armor->o_which].a_class;
				else
					cur_armor->o_ac--;
				resoflg(cur_armor,ISCURSED);
			}
		}
	when S_HOLD:
		if (!curse) {
			/*
			 * Hold monster scroll.  Stop all monsters within 3 spaces
			 * from chasing after the hero.
			 */
			int x,y;
			struct linked_list *mon;

			for (x = hero.x - 3; x <= hero.x + 3; x++) {
				for (y = hero.y - 3; y <= hero.y + 3; y++) {
					if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) {
						if ((mon = find_mons(y, x)) != NULL) {
							struct thing *th;

							th = THINGPTR(mon);
							th->t_flags &= ~ISRUN;
							th->t_flags |= ISHELD;
							th->t_flags |= ISSTUCK;
						}
					}
				}
			}
		}
	when S_SLEEP:
		/*
		 * Scroll which makes you fall asleep
		 */
		if (!bless) {
			s_know[S_SLEEP] = TRUE;
			msg("You fall asleep.");
			player.t_nocmd += 4 + rnd(SLEEPTIME);
		}
	when S_CREATE:
		if (!bless) {
			if (makemons(mtlev[rnd(levcount)]->m_show))
				s_know[S_CREATE] = TRUE;
			else
				msg("You hear a faint cry of anguish in the distance.");
		}
	when S_IDENT:
		if (!curse) {
			msg("This scroll is an identify scroll");
			s_know[S_IDENT] = TRUE;
			whatis(NULL);
		}
	when S_MAP:
		if (curse)
			break;
		s_know[S_MAP] = TRUE;
		addmsg("Oh, now this scroll has a ");
		if (rnd(100) < 10 || bless) {
			addmsg("very detailed map on it.");
			endmsg();
			displevl();
		}
		else {
			addmsg("map on it.");
			endmsg();
			overwrite(stdscr, hw);
			for (i = 1; i < LINES - 2; i++) {
				for (j = 0; j < COLS; j++) {
					switch (nch = ch = mvwinch(hw, i, j)) {
						case SECRETDOOR:
							nch = DOOR;
							mvaddch(i, j, nch);
						case '-':
						case '|':
						case DOOR:
						case PASSAGE:
						case ' ':
						case STAIRS:
							if (mvwinch(mw, i, j) != ' ') {
								struct thing *it;
								struct linked_list *blah;

								blah = find_mons(i, j);
								if (blah != NULL) {
									it = THINGPTR(blah);
									if (it->t_oldch == ' ')
										it->t_oldch = nch;
								}
							}
							break;
						default:
							nch = ' ';
					}
					if (nch != ch)
						waddch(hw, nch);
				}
			}
			overlay(cw, hw);
			overwrite(hw, cw);
		}
	when S_GFIND:
		if (!curse) {
			int gtotal = 0;
			struct room *rp;

			wclear(hw);
			for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
				gtotal += rp->r_goldval;
				if (rp->r_goldval != 0 &&
				  mvinch(rp->r_gold.y,rp->r_gold.x) == GOLD)
					mvwaddch(hw,rp->r_gold.y,rp->r_gold.x,GOLD);
			}
			if (gtotal) {
				s_know[S_GFIND] = TRUE;
				msg("You begin to feel greedy and sense gold.");
				overlay(hw,cw);
			}
			else
				msg("You begin to feel a pull downward.");
		}
	when S_TELEP:
		if (!curse) {
			int rm;
			struct room *cur_room;

			cur_room = player.t_room;
			rm = teleport(rndspot, &player);
			if (cur_room != &rooms[rm])
				s_know[S_TELEP] = TRUE;
		}
	when S_ENCH:
		if (!curse) {
			if (cur_weapon == NULL || (cur_weapon != NULL &&
			  (o_on(cur_weapon,ISPROT) || cur_weapon->o_type != WEAPON)))
				msg("You feel a strange sense of loss.");
			else {
				s_know[S_ENCH] = TRUE;
				if (o_on(cur_weapon,ISCURSED)) {
					resoflg(cur_weapon,ISCURSED);
					cur_weapon->o_hplus = rnd(2);
					cur_weapon->o_dplus = rnd(2);
				}
				else {		/* weapon was not cursed here */
					if (rnd(100) < 50)
						cur_weapon->o_hplus += 1;
					else
						cur_weapon->o_dplus += 1;
				}
				setoflg(cur_weapon, ISKNOW);
				msg("Your %s glows blue for a moment.",
				  w_magic[cur_weapon->o_which].mi_name);
			}
		}
	when S_SCARE:
		/*
		 * A monster will refuse to step on a scare monster scroll
		 * if it is dropped.  Thus reading it is a mistake and produces
		 * laughter at the poor rogue's boo boo.
		 */
		msg("You hear maniacal laughter in the distance.");
	when S_REMOVE:
		if (!curse) {
			if (cur_armor != NULL && o_off(cur_armor,ISPROT))
				resoflg(cur_armor,ISCURSED);
			if (cur_weapon != NULL && o_off(cur_weapon,ISPROT))
				resoflg(cur_weapon,ISCURSED);
			if (cur_ring[LEFT]!=NULL && o_off(cur_ring[LEFT],ISPROT))
				resoflg(cur_ring[LEFT],ISCURSED);
			if (cur_ring[RIGHT]!=NULL && o_off(cur_ring[RIGHT],ISPROT))
				resoflg(cur_ring[RIGHT],ISCURSED);
			msg("You feel as if somebody is watching over you.");
			s_know[S_REMOVE] = TRUE;
		}
	when S_AGGR:
		if (!bless) {
			if (mlist != NULL) {
				aggravate();
				msg("You hear a high pitched humming noise.");
				s_know[S_AGGR] = TRUE;
			}
		}
	when S_NOP:
		msg("This scroll seems to be blank.");
	when S_GENOCIDE:
		if (!curse) {
			msg("You have been granted the boon of genocide.");
			genocide();
			s_know[S_GENOCIDE] = TRUE;
		}
	when S_DCURSE:
		if (!bless) {
			struct linked_list *ll;
			struct object *lb;

			msg("Your pack shudders.");
			for (ll = pack ; ll != NULL ; ll = next(ll)) {
				lb = OBJPTR(ll);
				if (o_off(lb,ISPROT)) {
					resoflg(lb, ISBLESS);
					setoflg(lb, ISCURSED);
				}
			}
		}
	when S_DLEVEL:
		if (!bless) {
			int much = rnd(9) - 4;

			if (much != 0) {
				level += much;
				if (level < 1)
					level = 1;
				mpos = 0;
				new_level(NORMLEV);		/* change levels */
				msg("You are whisked away to another region.");
				s_know[S_DLEVEL] = TRUE;
			}
		}
	when S_PROTECT:
		if (!curse) {
			struct linked_list *ll;
			struct object *lb;

			msg("You are granted the power of protection.");
			if ((ll = get_item("protect",0)) != NULL) {
				lb = OBJPTR(ll);
				setoflg(lb,ISPROT);
				mpos = 0;
				msg("Protected %s.",inv_name(lb,TRUE));
			}
			s_know[S_PROTECT] = TRUE;
		}
	when S_ALLENCH:
		if (!curse) {
			struct linked_list *ll;
			struct object *lb;
			int howmuch, ac, good;

			msg("You are granted the power of enchantment.");
			good = TRUE;
			if ((ll = get_item("enchant",0)) != NULL) {
				lb = OBJPTR(ll);
				resoflg(lb,ISCURSED);
				resoflg(lb,ISPROT);
				howmuch = rnd(3) + 1;
				switch(lb->o_type) {
					case RING:
						if (lb->o_ac < 0)
							lb->o_ac = 0;
						lb->o_ac += howmuch;
					when ARMOR:
						ac = armors[lb->o_which].a_class;
						if (lb->o_ac > ac)
							lb->o_ac = ac;
						lb->o_ac -= howmuch;
					when STICK:
						lb->o_charges += howmuch + 10;
					when WEAPON:
						if (lb->o_dplus < 0)
							lb->o_dplus = 0;
						if (lb->o_hplus < 0)
							lb->o_hplus = 0;
						lb->o_hplus += howmuch;
						lb->o_dplus += howmuch;
					otherwise:
						msg("You are injured as the scroll flashes & bursts into flames !!!");
						chg_hpt(-roll(6,6),FALSE,K_SCROLL);
						good = FALSE;
				}
				if (good) {
					mpos = 0;
					msg("Enchanted %s.",inv_name(lb,TRUE));
				}
			}
			s_know[S_ALLENCH] = TRUE;
		}
	when S_BLESS:
		if (!curse) {
			struct linked_list *ll;
			struct object *lb;

			msg("Your pack glistens brightly.");
			for (ll = pack ; ll != NULL ; ll = next(ll)) {
				whatis(ll);
				lb = OBJPTR(ll);
				resoflg(lb,ISCURSED);
				setoflg(lb,ISBLESS);
			}
		}
	when S_MAKEIT:
		if (!curse) {
			msg("You have been endowed with the power of creation.");
			s_know[S_MAKEIT] = TRUE;
			create_obj(TRUE);
		}
	when S_BAN: {
		int howdeep;
		char *ptr;

		if (bless) {
			if (level > 6) {
				howdeep = 1 + rnd(5);
				ptr = "elevated to the upper";
			}
			else {
				howdeep = -1;
				bless = FALSE;
			}
		}
		else {
			howdeep = level + 10 + rnd(20) + (curse * 20);
			ptr = "banished to the lower";
		}
		if ((!bless && level < howdeep) || bless) {
			level = howdeep;
			new_level(NORMLEV);
			mpos = 0;
			msg("You are %s regions.", ptr);
			s_know[S_BAN] = TRUE;
		}
	}
	when S_CWAND:
		if (!curse) {
			struct linked_list *ll;
			struct object *lb;
			bool wands = FALSE;

			for (ll = pack ; ll != NULL ; ll = next(ll)) {
				lb = OBJPTR(ll);
				if (lb->o_type == STICK) {
					whatis(ll);
					setoflg(lb, ISKNOW);
					resoflg(lb, ISCURSED);
					lb->o_charges += rnd(11) + 5;
					wands = TRUE;
				}
			}
			if (wands) {
				msg("Your sticks gleam.");
				s_know[wh] = TRUE;
			}
		}
	when S_LOCTRAP: {
		struct trap *trp;

		if (ntraps > 0) {
			for (trp = &traps[0]; trp < &traps[ntraps]; trp++)
				trp->tr_flags |= ISFOUND;
			look(FALSE);
			msg("You now recognize pitfalls.");
			s_know[S_LOCTRAP] = TRUE;
		}
	}
	otherwise:
		msg("What a puzzling scroll!");
		return 0;
	}
Esempio n. 18
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);
}
/*
 * \brief Function sets the RF in RX state.
 *
 * \param none
 *
 * \return none
 */
void rf_receive(void)
{
    uint16_t while_counter = 0;
    if(rf_flags_check(RFF_ON) == 0)
    {
        rf_on();
    }
    /*If not yet in RX state set it*/
    if(rf_flags_check(RFF_RX) == 0)
    {
        platform_enter_critical();
        /*Wait while receiving data*/
        while(rf_if_read_trx_state() == BUSY_RX_AACK)
        {
            while_counter++;
            if(while_counter == 0xffff)
            {
                break;
            }
        }
        //TODO: rf_if_delay_function(50);
        /*Wake up from sleep state*/
        if(rf_if_read_trx_state() == 0x00 || rf_if_read_trx_state() == 0x1f)
        {
            rf_if_disable_slptr();
            rf_poll_trx_state_change(TRX_OFF);
        }

        rf_if_change_trx_state(PLL_ON);

        if(rf_mode == RF_MODE_SNIFFER)
        {
            rf_if_change_trx_state(RX_ON);
        }
        else
        {
            /*ACK is always received in promiscuous mode to bypass address filters*/
            if(rf_rx_mode)
            {
                rf_rx_mode = 0;
                rf_if_enable_promiscuous_mode();
            }
            else
            {
                rf_if_disable_promiscuous_mode();
            }
            rf_if_change_trx_state(RX_AACK_ON);
        }
        /*If calibration timer was unable to calibrate the RF, run calibration now*/
        if(!rf_tuned)
        {
            /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/
            rf_if_calibration();
            /*RF is tuned now*/
            rf_tuned = 1;
        }

        rf_channel_set(rf_phy_channel);
        rf_flags_set(RFF_RX);
        rf_if_enable_rx_end_interrupt();
        platform_exit_critical();
    }
    /*Stop the running CCA process*/
    if(rf_flags_check(RFF_CCA))
        rf_cca_abort();
}
Esempio n. 20
0
/**
 * Work out if a monster can move through the grid, if necessary bashing 
 * down doors in the way.
 *
 * Returns TRUE if the monster is able to move through the grid.
 */
static bool process_monster_can_move(struct chunk *c, struct monster *m_ptr,
		const char *m_name, int nx, int ny, bool *did_something)
{
	monster_lore *l_ptr = get_lore(m_ptr->race);

	/* Floor is open? */
	if (square_ispassable(c, ny, nx))
		return TRUE;

	/* Permanent wall in the way */
	if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx))
		return FALSE;

	/* Normal wall, door, or secret door in the way */

	/* There's some kind of feature in the way, so learn about
	 * kill-wall and pass-wall now */
	if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) {
		rf_on(l_ptr->flags, RF_PASS_WALL);
		rf_on(l_ptr->flags, RF_KILL_WALL);
	}

	/* Monster moves through walls (and doors) */
	if (rf_has(m_ptr->race->flags, RF_PASS_WALL)) 
		return TRUE;

	/* Monster destroys walls (and doors) */
	else if (rf_has(m_ptr->race->flags, RF_KILL_WALL)) {
		/* Forget the wall */
		sqinfo_off(c->squares[ny][nx].info, SQUARE_MARK);

		/* Notice */
		square_destroy_wall(c, ny, nx);

		/* Note changes to viewable region */
		if (player_has_los_bold(ny, nx))
			player->upkeep->update |= PU_UPDATE_VIEW;

		/* Update the flow, since walls affect flow */
		player->upkeep->update |= PU_UPDATE_FLOW;

		return TRUE;
	}

	/* Handle doors and secret doors */
	else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) {
		bool may_bash = rf_has(m_ptr->race->flags, RF_BASH_DOOR) && one_in_(2);

		/* Take a turn */
		*did_something = TRUE;

		/* Learn about door abilities */
		if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) {
			rf_on(l_ptr->flags, RF_OPEN_DOOR);
			rf_on(l_ptr->flags, RF_BASH_DOOR);
		}

		/* Creature can open or bash doors */
		if (!rf_has(m_ptr->race->flags, RF_OPEN_DOOR) && !rf_has(m_ptr->race->flags, RF_BASH_DOOR))
			return FALSE;

		/* Stuck door -- try to unlock it */
		if (square_islockeddoor(c, ny, nx)) {
			int k = square_door_power(c, ny, nx);

			if (randint0(m_ptr->hp / 10) > k) {
				if (may_bash)
					msg("%s slams against the door.", m_name);
				else
					msg("%s fiddles with the lock.", m_name);

				/* Reduce the power of the door by one */
				square_set_door_lock(c, ny, nx, k - 1);
			}
		} else {
			/* Handle viewable doors */
			if (player_has_los_bold(ny, nx))
				player->upkeep->update |= PU_UPDATE_VIEW;

			/* Closed or secret door -- open or bash if allowed */
			if (may_bash) {
				square_smash_door(c, ny, nx);

				msg("You hear a door burst open!");
				disturb(player, 0);

				/* Fall into doorway */
				return TRUE;
			} else if (rf_has(m_ptr->race->flags, RF_OPEN_DOOR)) {
				square_open_door(c, ny, nx);
			}
		}
	}

	return FALSE;
}