示例#1
0
/**
 * Called from project() to affect the player
 *
 * Called for projections with the PROJECT_PLAY flag set, which includes
 * bolt, beam, ball and breath effects.
 *
 * \param src is the origin of the effect
 * \param r is the distance from the centre of the effect
 * \param y the coordinates of the grid being handled
 * \param x the coordinates of the grid being handled
 * \param dam is the "damage" from the effect at distance r from the centre
 * \param typ is the projection (PROJ_) type
 * \return whether the effects were obvious
 *
 * If "r" is non-zero, then the blast was centered elsewhere; the damage
 * is reduced in project() before being passed in here.  This can happen if a
 * monster breathes at the player and hits a wall instead.
 *
 * We assume the player is aware of some effect, and always return "true".
 */
bool project_p(struct source origin, int r, int y, int x, int dam, int typ)
{
	bool blind = (player->timed[TMD_BLIND] ? true : false);
	bool seen = !blind;
	bool obvious = true;

	/* Monster or trap name (for damage) */
	char killer[80];

	project_player_handler_f player_handler = player_handlers[typ];
	project_player_handler_context_t context = {
		origin,
		r,
		y,
		x,
		dam,
		typ,
		obvious,
	};

	/* No player here */
	if (!square_isplayer(cave, y, x)) {
		return false;
	}

	switch (origin.what) {
		case SRC_PLAYER:
			/* Never affect projector */
			return false;

		case SRC_MONSTER: {
			struct monster *mon = cave_monster(cave, origin.which.monster);

			/* Check it is visible */
			if (!monster_is_visible(mon))
				seen = false;

			/* Get the monster's real name */
			monster_desc(killer, sizeof(killer), mon, MDESC_DIED_FROM);

			break;
		}

		case SRC_TRAP: {
			struct trap *trap = origin.which.trap;

			/* Get the trap name */
			strnfmt(killer, sizeof(killer), "a %s", trap->kind->desc);

			break;
		}

		case SRC_OBJECT: {
			struct object *obj = origin.which.object;
			object_desc(killer, sizeof(killer), obj, ODESC_PREFIX | ODESC_BASE);
			break;
		}

		case SRC_NONE: {
			/* Assume the caller has set the killer variable */
			break;
		}
	}

	/* Let player know what is going on */
	if (!seen) {
		msg("You are hit by %s!", projections[typ].blind_desc);
	}

	/* Adjust damage for resistance, immunity or vulnerability, and apply it */
	dam = adjust_dam(player,
						typ,
						dam,
						RANDOMISE,
					 player->state.el_info[typ].res_level,
					 true);
	if (dam) {
		take_hit(player, dam, killer);
	}

	/* Handle side effects */
	if (player_handler != NULL && player->is_dead == false) {
		player_handler(&context);
	}

	/* Disturb */
	disturb(player, 1);

	/* Return "Anything seen?" */
	return context.obvious;
}
示例#2
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);
}