Exemplo n.º 1
0
const char *square_apparent_name(struct chunk *c, struct player *p, int y, int x) {
	int f = f_info[c->squares[y][x].feat].mimic;

	if (!square_ismark(c, y, x) && !player_can_see_bold(y, x))
		return "unknown_grid";

	return f_info[f].name;
}
Exemplo n.º 2
0
/**
 * True if the player's current target is in LOS.
 */
bool target_sighted(void)
{
	return target_okay() &&
			panel_contains(target_y, target_x) &&
			 /* either the target is a grid and is visible, or it is a monster
			  * that is visible */
			((!target_who && player_can_see_bold(target_y, target_x)) ||
			 (target_who && mflag_has(target_who->mflag, MFLAG_VISIBLE)));
}
Exemplo n.º 3
0
/*
 * Examine a grid, return a keypress.
 *
 * The "mode" argument contains the "TARGET_LOOK" bit flag, which
 * indicates that the "space" key should scan through the contents
 * of the grid, instead of simply returning immediately.  This lets
 * the "look" command get complete information, without making the
 * "target" command annoying.
 *
 * The "info" argument contains the "commands" which should be shown
 * inside the "[xxx]" text.  This string must never be empty, or grids
 * containing monsters will be displayed with an extra comma.
 *
 * Note that if a monster is in the grid, we update both the monster
 * recall info and the health bar info to track that monster.
 *
 * This function correctly handles multiple objects per grid, and objects
 * and terrain features in the same grid, though the latter never happens.
 *
 * This function must handle blindness/hallucination.
 */
static ui_event_data target_set_interactive_aux(int y, int x, int mode, cptr info, bool list_floor_objects)
{
	s16b this_o_idx, next_o_idx = 0;
	s16b this_x_idx, next_x_idx = 0;

	cptr s1, s2, s3;

	bool floored;

	u16b feat;

	ui_event_data query;

	char out_val[256];

	char coords[20];

	/* Describe the square location */
	coords_desc(coords, sizeof(coords), y, x);

	/* Repeat forever */
	while (1)
	{
		int i;

		char feat_name[80];
		/* Terrain suffix for monsters and objects */
		char terrain_suffix[200];

		/* Temporary array of visible effects */
		s16b x_seen[50];
		u16b size_x_seen = 0;

		/* Paranoia */
		query.key = ' ';

		/* Default */
		s1 = "You see ";
		s2 = "";
		s3 = "on ";


		/* The player */
		if (cave_m_idx[y][x] < 0)
		{
			/* Description */
			s1 = "You are ";

			/* Preposition */
			s2 = "on ";
		}

		/* Feature (apply "mimic") */
		feat = f_info[cave_feat[y][x]].f_mimic;

		/* Require knowledge about grid, or ability to see grid */
		if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x))
		{
			/* Forget feature */
			feat = FEAT_NONE;
		}

		else
		{
			/* Hack -- track the current feature */
			feature_kind_track(feat);

			/* Window stuff */
			p_ptr->redraw |= (PR_FEATURE);
		}

		/* Pick a prefix */
		if (*s2 && (!feat_ff1_match(feat, FF1_MOVE) ||
			!feat_ff1_match(feat, FF1_LOS) ||
			feat_ff1_match(feat, FF1_SHOP | FF1_DOOR) ||
			feat_ff2_match(feat, FF2_SHALLOW | FF2_DEEP) ||
			feat_ff3_match(feat, FF3_NEED_TREE)))
		{
			s3 = "in ";
		}

		/* Get a default name */
		if (feat <= FEAT_NONE)
		{
			my_strcpy(feat_name, "an unknown grid", sizeof(feat_name));
		}
		/* Get the real name */
		else
		{
			feature_desc(feat_name, sizeof (feat_name), feat, TRUE, FALSE);
		}

		/* List all effects in the grid */
		for (this_x_idx = cave_x_idx[y][x]; this_x_idx; this_x_idx = next_x_idx)
		{
			effect_type *x_ptr;

			/* Get the effect */
			x_ptr = &x_list[this_x_idx];

			/* Get the next effect */
			next_x_idx = x_ptr->next_x_idx;

			/* Describe it, if not hidden */
			if (!(x_ptr->x_flags & (EF1_HIDDEN)) && x_ptr->x_f_idx)
			{
				/* Check for available space */
				if (size_x_seen < N_ELEMENTS(x_seen))
				{
					x_seen[size_x_seen++] = x_ptr->x_f_idx;
				}
			}
		}

		/* Prepare the terrain suffix for monsters and objects */
		my_strcpy(terrain_suffix, format(" %s%s", s3, feat_name), sizeof(terrain_suffix));

		/* Concat the collected effect names */
		for (i = 0; i < size_x_seen; i++)
		{
			char x_name[80];

			/* Obtain an object description */
			feature_desc(x_name, sizeof(x_name), x_seen[i], TRUE, TRUE);

			/* First effect */
			if (i == 0)
			{
				if ((feat == FEAT_NONE) || !feat_ff1_match(feat, FF1_MOVE) ||
					cave_any_trap_bold(y, x))
				{
					/* Basic info */
					my_strcat(terrain_suffix, format(" with %s", x_name),
						sizeof(terrain_suffix));
				}
				else
				{
					/* Basic info */
					my_strcat(terrain_suffix, format(" beneath %s", x_name),
						sizeof(terrain_suffix));
				}
			}

			/* Basic info */
			else if (i < (size_x_seen - 1))
			{
				my_strcat(terrain_suffix, format(", %s", x_name), sizeof(terrain_suffix));
			}

			/* Basic info */
			else
			{
				my_strcat(terrain_suffix, format(" and %s", x_name), sizeof(terrain_suffix));
			}
		}

		/* Ignore the terrain suffix if certain things happen */
		if ((size_x_seen == 0) && (feat <= FEAT_FLOOR))
		{
			terrain_suffix[0] = '\0';
		}

		/* Hack -- hallucination */
		if (p_ptr->timed[TMD_IMAGE])
		{
			cptr name = "something strange";

			/* Display a message */
			if (p_ptr->wizard)
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s, [%s] %s (%d:%d).", s1, s2, name, info, coords, y, x);
			}
			else
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s [%s], %s.", s1, s2, name, info, coords);
			}

			prt(out_val, 0, 0);
			move_cursor_relative(y, x);

			query = inkey_ex();

			/* Stop on everything but "return" */
			if ((query.key != '\n') && (query.key != '\r')) break;

			/* Repeat forever */
			continue;
		}

		/* Actual monsters */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			/* Visible */
			if (m_ptr->ml)
			{
				bool recall = FALSE;

				char m_name[80];

				if (m_ptr->mimic_k_idx)
				{
					/*get the description*/
					mimic_desc_object(m_name, sizeof(m_name), m_ptr->mimic_k_idx);
				}

				else
				{
					/* Get the monster name ("a kobold") */
					monster_desc(m_name, sizeof(m_name), m_ptr, 0x08);

					/* Hack -- track this monster race */
					monster_race_track(m_ptr->r_idx);

					/* Hack -- health bar for this monster */
					health_track(cave_m_idx[y][x]);

					/*Track the feature*/
					feature_kind_track(cave_feat[y][x]);

					/* Window stuff */
					p_ptr->redraw |= (PR_FEATURE);

					/* Hack -- handle stuff */
					handle_stuff();
				}

				/* Interact */
				while (1)
				{
					if (recall)	button_add("[CLEAR_RECALL]", 'r');
					else 		button_add("[RECALL]", 'r');
					if (cave_o_idx[y][x] > 0)button_add("[VIEW_FLOOR]", 'f');
					event_signal(EVENT_MOUSEBUTTONS);

					/* Recall, but not mimics */
					if ((recall) && (!(m_ptr->mimic_k_idx)))
					{
						/* Save screen */
						screen_save();

						/* Recall on screen */
						screen_roff(m_ptr->r_idx);

						/* Hack -- Complete the prompt (again) */
						Term_addstr(-1, TERM_WHITE, format(" [r,%s]", info));

						/* Command */
						query = inkey_ex();

						/* Load screen */
						screen_load();
					}

					/* Normal */
					else
					{

						/* Basic info */
						strnfmt(out_val, sizeof(out_val),
							"%s%s%s", s1, s2, m_name);

						/* Describe the monster, unless a mimic */
						if (!(m_ptr->mimic_k_idx))
						{
							char buf[80];

							look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]);

							/* Monster state, terrain suffix, options  */
							my_strcat(out_val, format(" (%s)%s [r,%s]",
								buf, terrain_suffix, info),
								sizeof(out_val));
						}

						/* Mimics */
						else
						{
							/* Terrain suffix, options */
							my_strcat(out_val,
								format("%s [I,%s]", terrain_suffix,
								info), sizeof(out_val));
						}

						/* Wizards want coordinates */
						if (p_ptr->wizard)
						{
							my_strcat(out_val, format(" (%d:%d)", y, x),
								sizeof(out_val));
						}

						prt(out_val, 0, 0);

						/* Place cursor */
						move_cursor_relative(y, x);

						/* Command */
						query = inkey_ex();
					}

					button_kill('r');
					button_kill('f');
					event_signal(EVENT_MOUSEBUTTONS);

					/* Handle fake object recall */
					if (m_ptr->mimic_k_idx)
					{
						object_type body;
						object_type *o_ptr = &body;

						/* Validate input first */
						if (query.key != 'I') break;

						/* Paranoia */
						object_wipe(o_ptr);

						/* Prepare */
						object_prep(o_ptr, m_ptr->mimic_k_idx);

						/* Fake history */
						object_history(o_ptr, ORIGIN_FLOOR, 0);

						/* Clear prompt. Place cursor */
						prt("", 0, 0);

						/* Show the fake info - EXPERIMENTAL */
						object_info_screen(o_ptr);
					}
					/* Regular monsters */
					else
					{
						/* Normal commands */
						if (query.key != 'r') break;

						/* Toggle recall */
						recall = !recall;
					}
				}

				/* Stop on everything but "return"/"space", or floor */
				if ((query.key != '\n') && (query.key != '\r') &&
					(query.key != ' ') && (query.key != 'f')) break;

				/* continue with 'f' only if there are floor items....*/
				if ((query.key == 'f') && (!cave_o_idx[y][x])) break;

				/* Sometimes stop at "space" key */
				if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

				/* Change the intro */
				s1 = "It is ";

				/* Hack -- take account of gender */
				if (r_ptr->flags1 & (RF1_FEMALE)) s1 = "She is ";
				else if (r_ptr->flags1 & (RF1_MALE)) s1 = "He is ";

				/* Use a preposition */
				s2 = "carrying ";

				/* Scan all objects being carried */
				for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
				{
					char o_name[80];

					object_type *o_ptr;

					/* Get the object */
					o_ptr = &o_list[this_o_idx];

					/* Get the next object */
					next_o_idx = o_ptr->next_o_idx;

					/*Don't let the player see certain objects (used for vault treasure)*/
					if ((o_ptr->ident & (IDENT_HIDE_CARRY)) && (!p_ptr->wizard) &&
						(!cheat_peek))	 continue;

					/* Obtain an object description */
					object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL);

					/* Describe the object */
					strnfmt(out_val, sizeof(out_val),
						"%s%s%s [%s]", s1, s2, o_name, info);

					/* Wizards want coordinates */
					if (p_ptr->wizard)
					{
						my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val));
					}

					prt(out_val, 0, 0);
					move_cursor_relative(y, x);
					query = inkey_ex();

					/* Stop on everything but "return"/"space" */
					if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

					/* Sometimes stop at "space" key */
					if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

					/* Change the intro */
					s2 = "also carrying ";
				}

				/* Double break */
				if (this_o_idx) break;

				/* Use a preposition */
				s2 = "on ";
			}
		}

		/* Assume not floored */
		floored = FALSE;

		/* Scan all objects in the grid */
		if (TRUE)
		{
			int floor_list[MAX_FLOOR_STACK];
			int floor_num;

			track_object(-floor_list[0]);
			handle_stuff();

			/* Scan for floor objects */
			floor_num = scan_floor(floor_list, MAX_FLOOR_STACK, y, x, 0x02);

			/* Actual pile */
			if (floor_num > 1)
			{
				/* Floored */
				floored = TRUE;

				/* Describe */
				while (1)
				{
					/* Basic info */
					strnfmt(out_val, sizeof(out_val),
						"%s%sa pile of %d objects%s [r,%s]", s1, s2,
						floor_num, terrain_suffix, info);

					/* Wizards want coordinates */
					if (p_ptr->wizard)
					{
						my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val));
					}

					prt(out_val, 0, 0);

					if (list_floor_objects)
					{
						/* Save screen */
						screen_save();

						/* Display */
						show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD));
					}
					move_cursor_relative(y, x);
					query = inkey_ex();

					if (list_floor_objects)
					{
						screen_load();
					}

					/* Display objects */
					if (query.key == 'r')
					{
						int pos;

						pos = query.key - 'a';
						if (0 <= pos && pos < floor_num)
						{
							track_object(-floor_list[pos]);
							handle_stuff();
						}
					}

					/* Done */
					break;
				}

				/* Stop on everything but "return"/"space" */
				if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

				/* Sometimes stop at "space" key */
				if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

				/* Change the intro */
				s1 = "It is ";

				/* Preposition */
				s2 = "on ";
			}
		}

		/* Scan all objects in the grid */
		for (this_o_idx = cave_o_idx[y][x]; this_o_idx; this_o_idx = next_o_idx)
		{
			object_type *o_ptr;

			/* Get the object */
			o_ptr = &o_list[this_o_idx];

			/* Get the next object */
			next_o_idx = o_ptr->next_o_idx;

			/* Skip objects if floored */
			if (floored) continue;

			/* Describe it */
			if (o_ptr->marked)
			{
				char o_name[80];

				/* Obtain an object description */
				object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL);

				/* Basic info */
				strnfmt(out_val, sizeof(out_val), "%s%s%s%s [I,%s]",
					s1, s2, o_name, terrain_suffix, info);

				/* Wizards want coordinates */
				if (p_ptr->wizard)
				{
					my_strcat(out_val, format(" (%d:%d)", y, x),
						sizeof(out_val));
				}

				/* Show object. Handle object recall */
				while (TRUE)
				{
					/* Print the prompt */
					prt(out_val, 0, 0);

					/* Move cursor to that location */
					move_cursor_relative(y, x);

					/* Read input key */
					query = inkey_ex();

					/* No object recall */
					if (query.key != 'I') break;

					/* Object recall. Clear the first line */
					prt("", 0, 0);

					/* Do it */
					object_info_screen(o_ptr);
				}

				/* Stop on everything but "return"/"space" */
				if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

				/* Sometimes stop at "space" key */
				if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

				/* Change the intro */
				s1 = "It is ";

				/* Plurals */
				if (o_ptr->number != 1) s1 = "They are ";

				/* Preposition */
				s2 = "on ";
			}
		}

		/* Double break */
		if (this_o_idx) break;

		/* Display terrain */
		if (TRUE)
		{
			u16b temp_feat;
			bool enable_recall;
			bool show_recall = FALSE;
			char temp_name[80];

			/*
			 * Display terrain and effects
			 */
			for (i = 0; i <= size_x_seen; i++)
			{
				/* Hack - This is the mark for the feature stored in cave_feat */
				if (i == size_x_seen)
				{
				       	temp_feat = feat;

					/* Just copy the feature name */
					my_strcpy(temp_name, feat_name, sizeof(temp_name));
				}
				/* Any other value is an effect stored x_list */
				else
				{
					temp_feat = x_seen[i];

					/* Get the effect's name */
					feature_desc(temp_name, sizeof(temp_name), temp_feat, TRUE, TRUE);
				}

				/* Don't display feature recall if the grid is unknown */
				enable_recall = (temp_feat != FEAT_NONE);

				/* Handle recall */
				while (TRUE)
				{

					/* Handle recall mode */
					if (show_recall && enable_recall)
					{
						/* Save screen */
						screen_save();

						/* Recall feature on screen */
						screen_feature_roff(temp_feat);
					}

					/* Display a message */
					strnfmt(out_val, sizeof(out_val),
						"%s%s%s [%s%s]%s", s1, s2, temp_name,
						(enable_recall ? "r,": ""), info,
						(i < size_x_seen) ? " (more)": "");

					/* Wizards want coordinates */
					if (p_ptr->wizard)
					{
						my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val));
					}

					/*Track this feature*/
					feature_kind_track(temp_feat);

					/* Hack -- handle stuff */
					handle_stuff();

					prt(out_val, 0, 0);
					move_cursor_relative(y, x);
					query = inkey_ex();

					/* Load screen if necessary */
					if (show_recall && enable_recall)
					{
						screen_load();
					}

					/* Stop on everything but the recall command, if enabled */
					if (!enable_recall || (query.key != 'r')) break;

					/* Toggle recall */
					show_recall = !show_recall;
				}

				/* Stop on everything but "return"/"space" */
				if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;
			}
		}

		/* Hack -- handle stuff */
		handle_stuff();

		/* Stop on everything but "return" */
		if ((query.key != '\n') && (query.key != '\r')) break;
	}

	/* Keep going */
	return (query);
}
Exemplo n.º 4
0
/*
 * Draw a visible path over the squares between (x1,y1) and (x2,y2).
 * The path consists of "*", which are white except where there is a
 * monster, object or feature in the grid.
 *
 * This routine has (at least) three weaknesses:
 * - remembered objects/walls which are no longer present are not shown,
 * - squares which (e.g.) the player has walked through in the dark are
 *   treated as unknown space.
 * - walls which appear strange due to hallucination aren't treated correctly.
 *
 * The first two result from information being lost from the dungeon arrays,
 * which requires changes elsewhere
 */
static int draw_path(u16b path_n, u16b *path_g, char *c, byte *a, int y1, int x1, int cur_tar_y, int cur_tar_x)
{
	int i;
	bool on_screen;
	byte color_type;

	/* No path, so do nothing. */
	if (path_n < 1) return (FALSE);

	/* The starting square is never drawn, but notice if it is being
     * displayed. In theory, it could be the last such square.
     */
	on_screen = panel_contains(y1, x1);

	/* Draw the path. */
	for (i = 0; i < path_n; i++)
	{
		/* Find the co-ordinates on the level. */
		int y = GRID_Y(path_g[i]);
		int x = GRID_X(path_g[i]);

		byte this_a;
		char this_c;

		/*
		 * As path[] is a straight line and the screen is oblong,
		 * there is only section of path[] on-screen.
		 * If the square being drawn is visible, this is part of it.
		 * If none of it has been drawn, continue until some of it
		 * is found or the last square is reached.
		 * If some of it has been drawn, finish now as there are no
		 * more visible squares to draw.
		 *
		 */
		 if (panel_contains(y,x)) on_screen = TRUE;
		 else if (on_screen) break;
		 else continue;

	 	/* Find the position on-screen */
		move_cursor_relative(y,x);

		/* This square is being overwritten, so save the original. */
		Term_what(Term->scr->cx, Term->scr->cy, a+i, c+i);

		/* Choose a colour. */
		/* Visible monsters are orange. */
		if (cave_m_idx[y][x] && mon_list[cave_m_idx[y][x]].ml)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];

			/*mimics act as objects*/
			if (m_ptr->mimic_k_idx) color_type = TERM_YELLOW;
			else color_type = TERM_ORANGE;
		}

		/* Known objects are yellow. */
		else if (cave_o_idx[y][x] && o_list[cave_o_idx[y][x]].marked)
		{
			color_type = TERM_YELLOW;
    	}

		/* Effects are green */
		else if ((cave_x_idx[y][x] > 0) && (cave_info[y][x] & (CAVE_SEEN | CAVE_MARK)))
		{
			color_type = TERM_GREEN;
		}

		/* Known walls are blue. */
		else if (!cave_project_bold(y,x) &&
				((cave_info[y][x] & (CAVE_MARK)) ||	player_can_see_bold(y,x)))
		{
			color_type = TERM_BLUE;
		}
		/* Unknown squares are grey. */
		else if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x))
		{
			color_type = TERM_L_DARK;
		}
		/* Unoccupied squares are white. */
		else
		{
			color_type = TERM_WHITE;
		}

		/* ALways use red for the current target square */
		if ((cur_tar_y == y) && (cur_tar_x == x)) color_type = TERM_RED;

		/* Get the character */
		if (!use_graphics)
		{
			this_a = color_type;
			this_c = '*';
		}
		/* Graphics are being used */
		else
		{
			this_a = color_to_attr[TILE_BALL_INFO][color_type];
			this_c = color_to_char[TILE_BALL_INFO][color_type];
		}

		/* Visual effects -- Display */
		print_rel(this_c, this_a, y, x);
	}
	return i;
}
Exemplo n.º 5
0
/*
 * Examine a grid, return a keypress.
 *
 * The "mode" argument contains the "TARGET_LOOK" bit flag, which
 * indicates that the "space" key should scan through the contents
 * of the grid, instead of simply returning immediately.  This lets
 * the "look" command get complete information, without making the
 * "target" command annoying.
 *
 * The "info" argument contains the "commands" which should be shown
 * inside the "[xxx]" text.  This string must never be empty, or grids
 * containing monsters will be displayed with an extra comma.
 *
 * Note that if a monster is in the grid, we update both the monster
 * recall info and the health bar info to track that monster.
 *
 * This function correctly handles multiple objects per grid, and objects
 * and terrain features in the same grid, though the latter never happens.
 *
 * This function must handle blindness/hallucination.
 */
static ui_event_data target_set_interactive_aux(int y, int x, int mode)
{
	s16b this_o_idx = 0, next_o_idx = 0;

	cptr s1, s2, s3;

	bool boring;

	bool floored;

	int feat;

	int floor_list[MAX_FLOOR_STACK];
	int floor_num;

	ui_event_data query;

	char out_val[256];

	char coords[20];
	
	/* Describe the square location */
	coords_desc(coords, sizeof(coords), y, x);

	/* Repeat forever */
	while (1)
	{
		/* Paranoia */
		query.key = ' ';

		/* Assume boring */
		boring = TRUE;

		/* Default */
		s1 = "You see ";
		s2 = "";
		s3 = "";


		/* The player */
		if (cave_m_idx[y][x] < 0)
		{
			/* Description */
			s1 = "You are ";

			/* Preposition */
			s2 = "on ";
		}

		/* Hack -- hallucination */
		if (p_ptr->timed[TMD_IMAGE])
		{
			cptr name = "something strange";

			/* Display a message */
			if (p_ptr->wizard)
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x);
			}
			else
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s%s, %s.", s1, s2, s3, name, coords);
			}

			prt(out_val, 0, 0);
			move_cursor_relative(y, x);
			query = inkey_ex();

			/* Stop on everything but "return" */
			if ((query.key != '\n') && (query.key != '\r')) break;

			/* Repeat forever */
			continue;
		}

		/* Actual monsters */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			/* Visible */
			if (m_ptr->ml)
			{
				bool recall = FALSE;

				char m_name[80];

				/* Not boring */
				boring = FALSE;

				/* Get the monster name ("a kobold") */
				monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2);

				/* Hack -- track this monster race */
				monster_race_track(m_ptr->r_idx);

				/* Hack -- health bar for this monster */
				health_track(cave_m_idx[y][x]);

				/* Hack -- handle stuff */
				handle_stuff();

				/* Interact */
				while (1)
				{
					/* Recall */
					if (recall)
					{
						/* Save screen */
						screen_save();

						/* Recall on screen */
						screen_roff(m_ptr->r_idx);

						/* Command */
						query = inkey_ex();

						/* Load screen */
						screen_load();
					}

					/* Normal */
					else
					{
						char buf[80];

						/* Describe the monster */
						look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]);

						/* Describe, and prompt for recall */
						if (p_ptr->wizard)
						{
							strnfmt(out_val, sizeof(out_val),
									"%s%s%s%s (%s), %s (%d:%d).",
									s1, s2, s3, m_name, buf, coords, y, x);
						}
						else
						{
							strnfmt(out_val, sizeof(out_val),
									"%s%s%s%s (%s), %s.",
									s1, s2, s3, m_name, buf, coords);
						}

						prt(out_val, 0, 0);

						/* Place cursor */
						move_cursor_relative(y, x);

						/* Command */
						query = inkey_ex();
					}

					/* Normal commands */
					if (query.key != 'r') break;

					/* Toggle recall */
					recall = !recall;
				}

				/* Stop on everything but "return"/"space" */
				if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

				/* Sometimes stop at "space" key */
				if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

				/* Change the intro */
				s1 = "It is ";

				/* Hack -- take account of gender */
				if (rf_has(r_ptr->flags, RF_FEMALE)) s1 = "She is ";
				else if (rf_has(r_ptr->flags, RF_MALE)) s1 = "He is ";

				/* Use a preposition */
				s2 = "carrying ";

				/* Scan all objects being carried */
				for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
				{
					char o_name[80];

					object_type *o_ptr;

					/* Get the object */
					o_ptr = &o_list[this_o_idx];

					/* Get the next object */
					next_o_idx = o_ptr->next_o_idx;

					/* Obtain an object description */
					object_desc(o_name, sizeof(o_name), o_ptr,
								ODESC_PREFIX | ODESC_FULL);

					/* Describe the object */
					if (p_ptr->wizard)
					{
						strnfmt(out_val, sizeof(out_val),
								"%s%s%s%s, %s (%d:%d).",
								s1, s2, s3, o_name, coords, y, x);
					}
					else
					{
						strnfmt(out_val, sizeof(out_val),
								"%s%s%s%s, %s.", s1, s2, s3, o_name, coords);
					}

					prt(out_val, 0, 0);
					move_cursor_relative(y, x);
					query = inkey_ex();

					/* Stop on everything but "return"/"space" */
					if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

					/* Sometimes stop at "space" key */
					if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

					/* Change the intro */
					s2 = "also carrying ";
				}

				/* Double break */
				if (this_o_idx) break;

				/* Use a preposition */
				s2 = "on ";
			}
		}


		/* Assume not floored */
		floored = FALSE;

		floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x02);

		/* Scan all marked objects in the grid */
		if ((floor_num > 0) &&
		    (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px)))
		{
			/* Not boring */
			boring = FALSE;

			track_object(-floor_list[0]);
			handle_stuff();

			/* If there is more than one item... */
			if (floor_num > 1) while (1)
			{
				floored = TRUE;

				/* Describe the pile */
				if (p_ptr->wizard)
				{
					strnfmt(out_val, sizeof(out_val),
							"%s%s%sa pile of %d objects, %s (%d:%d).",
							s1, s2, s3, floor_num, coords, y, x);
				}
				else
				{
					strnfmt(out_val, sizeof(out_val),
							"%s%s%sa pile of %d objects, %s.",
							s1, s2, s3, floor_num, coords);
				}

				prt(out_val, 0, 0);
				move_cursor_relative(y, x);
				query = inkey_ex();

				/* Display objects */
				if (query.key == 'r')
				{
					int rdone = 0;
					int pos;
					while (!rdone)
					{
						/* Save screen */
						screen_save();

						/* Display */
						show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD));

						/* Describe the pile */
						prt(out_val, 0, 0);
						query = inkey_ex();

						/* Load screen */
						screen_load();

						pos = query.key - 'a';
						if (0 <= pos && pos < floor_num)
						{
							track_object(-floor_list[pos]);
							handle_stuff();
							continue;
						}
						rdone = 1;
					}

					/* Now that the user's done with the display loop, let's */
					/* the outer loop over again */
					continue;
				}

				/* Done */
				break;
			}
			/* Only one object to display */
			else
			{

				char o_name[80];

				/* Get the single object in the list */
				object_type *o_ptr = &o_list[floor_list[0]];

				/* Not boring */
				boring = FALSE;

				/* Obtain an object description */
				object_desc(o_name, sizeof(o_name), o_ptr,
							ODESC_PREFIX | ODESC_FULL);

				/* Describe the object */
				if (p_ptr->wizard)
				{
					strnfmt(out_val, sizeof(out_val),
							"%s%s%s%s, %s (%d:%d).",
							s1, s2, s3, o_name, coords, y, x);
				}
				else
				{
					strnfmt(out_val, sizeof(out_val),
							"%s%s%s%s, %s.", s1, s2, s3, o_name, coords);
				}

				prt(out_val, 0, 0);
				move_cursor_relative(y, x);
				query = inkey_ex();

				/* Stop on everything but "return"/"space" */
				if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;

				/* Sometimes stop at "space" key */
				if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break;

				/* Change the intro */
				s1 = "It is ";

				/* Plurals */
				if (o_ptr->number != 1) s1 = "They are ";

				/* Preposition */
				s2 = "on ";
			}

		}

		/* Double break */
		if (this_o_idx) break;


		/* Feature (apply "mimic") */
		feat = f_info[cave_feat[y][x]].mimic;

		/* Require knowledge about grid, or ability to see grid */
		if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x))
		{
			/* Forget feature */
			feat = FEAT_NONE;
		}

		/* Terrain feature if needed */
		if (boring || (feat > FEAT_INVIS))
		{
			cptr name = f_info[feat].name;

			/* Hack -- handle unknown grids */
			if (feat == FEAT_NONE) name = "unknown grid";

			/* Pick a prefix */
			if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in ";

			/* Pick proper indefinite article */
			s3 = (is_a_vowel(name[0])) ? "an " : "a ";

			/* Hack -- special introduction for store doors */
			if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL))
			{
				s3 = "the entrance to the ";
			}

			/* Display a message */
			if (p_ptr->wizard)
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x);
			}
			else
			{
				strnfmt(out_val, sizeof(out_val),
						"%s%s%s%s, %s.", s1, s2, s3, name, coords);
			}

			prt(out_val, 0, 0);
			move_cursor_relative(y, x);
			query = inkey_ex();

			/* Stop on everything but "return"/"space" */
			if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break;
		}

		/* Stop on everything but "return" */
		if ((query.key != '\n') && (query.key != '\r')) break;
	}

	/* Keep going */
	return (query);
}
Exemplo n.º 6
0
/**
 * This is a helper function used by do_cmd_throw and do_cmd_fire.
 *
 * It abstracts out the projectile path, display code, identify and clean up
 * logic, while using the 'attack' parameter to do work particular to each
 * kind of attack.
 */
static void ranged_helper(int item, int dir, int range, int shots, ranged_attack attack) {
	/* Get the ammo */
	object_type *o_ptr = object_from_item_idx(item);

	int i, j;
	byte missile_attr = object_attr(o_ptr);
	char missile_char = object_char(o_ptr);

	object_type object_type_body;
	object_type *i_ptr = &object_type_body;

	char o_name[80];

	int path_n;
	u16b path_g[256];

	int msec = op_ptr->delay_factor;

	/* Start at the player */
	int x = p_ptr->px;
	int y = p_ptr->py;

	/* Predict the "target" location */
	s16b ty = y + 99 * ddy[dir];
	s16b tx = x + 99 * ddx[dir];

	bool hit_target = FALSE;

	/* Check for target validity */
	if ((dir == 5) && target_okay()) {
		int taim;
		char msg[80];
		target_get(&tx, &ty);
		taim = distance(y, x, ty, tx);
		if (taim > range) {
			sprintf (msg, "Target out of range by %d squares. Fire anyway? ",
				taim - range);
			if (!get_check(msg)) return;
		}
	}

	/* Sound */
	sound(MSG_SHOOT);

	object_notice_on_firing(o_ptr);

	/* Describe the object */
	object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR);

	/* Actually "fire" the object -- Take a partial turn */
	p_ptr->energy_use = (100 / shots);

	/* Calculate the path */
	path_n = project_path(path_g, range, y, x, ty, tx, 0);

	/* Hack -- Handle stuff */
	handle_stuff(p_ptr);

	/* Start at the player */
	x = p_ptr->px;
	y = p_ptr->py;

	/* Project along the path */
	for (i = 0; i < path_n; ++i) {
		int ny = GRID_Y(path_g[i]);
		int nx = GRID_X(path_g[i]);

		/* Hack -- Stop before hitting walls */
		if (!cave_floor_bold(ny, nx)) break;

		/* Advance */
		x = nx;
		y = ny;

		/* Only do visuals if the player can "see" the missile */
		if (player_can_see_bold(y, x)) {
			print_rel(missile_char, missile_attr, y, x);
			move_cursor_relative(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff(p_ptr);

			Term_xtra(TERM_XTRA_DELAY, msec);
			cave_light_spot(cave, y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff(p_ptr);
		} else {
			/* Delay anyway for consistency */
			Term_xtra(TERM_XTRA_DELAY, msec);
		}

		/* Handle monster */
		if (cave->m_idx[y][x] > 0) break;
	}

	/* Try the attack on the monster at (x, y) if any */
	if (cave->m_idx[y][x] > 0) {
		monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]);
		monster_race *r_ptr = &r_info[m_ptr->r_idx];
		int visible = m_ptr->ml;

		bool fear = FALSE;
		char m_name[80];
		const char *note_dies = monster_is_unusual(r_ptr) ? " is destroyed." : " dies.";

		struct attack_result result = attack(o_ptr, y, x);
		int dmg = result.dmg;
		u32b msg_type = result.msg_type;
		const char *hit_verb = result.hit_verb;

		if (result.success) {
			hit_target = TRUE;

			/* Get "the monster" or "it" */
			monster_desc(m_name, sizeof(m_name), m_ptr, 0);
		
			object_notice_attack_plusses(o_ptr);
		
			/* No negative damage; change verb if no damage done */
			if (dmg <= 0) {
				dmg = 0;
				hit_verb = "fail to harm";
			}
		
			if (!visible) {
				/* Invisible monster */
				msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name);
			} else {
				/* Visible monster */
				if (msg_type == MSG_SHOOT_HIT)
					msgt(MSG_SHOOT_HIT, "The %s %s %s.", o_name, hit_verb, m_name);
				else if (msg_type == MSG_HIT_GOOD) {
					msgt(MSG_HIT_GOOD, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!");
				} else if (msg_type == MSG_HIT_GREAT) {
					msgt(MSG_HIT_GREAT, "The %s %s %s. %s", o_name, hit_verb, m_name,
						 "It was a great hit!");
				} else if (msg_type == MSG_HIT_SUPERB) {
					msgt(MSG_HIT_SUPERB, "The %s %s %s. %s", o_name, hit_verb, m_name,
						 "It was a superb hit!");
				}
		
				/* Track this monster */
				if (m_ptr->ml) monster_race_track(m_ptr->r_idx);
				if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]);
			}
		
			/* Complex message */
			if (p_ptr->wizard)
				msg("You do %d (out of %d) damage.", dmg, m_ptr->hp);
		
			/* Hit the monster, check for death */
			if (!mon_take_hit(cave->m_idx[y][x], dmg, &fear, note_dies)) {
				message_pain(cave->m_idx[y][x], dmg);
				if (fear && m_ptr->ml)
					add_monster_message(m_name, cave->m_idx[y][x], MON_MSG_FLEE_IN_TERROR, TRUE);
			}
		}
	}

	/* Obtain a local object */
	object_copy(i_ptr, o_ptr);
	object_split(i_ptr, o_ptr, 1);

	/* See if the ammunition broke or not */
	j = breakage_chance(i_ptr, hit_target);

	/* Drop (or break) near that location */
	drop_near(cave, i_ptr, j, y, x, TRUE);

	if (item >= 0) {
		/* The ammo is from the inventory */
		inven_item_increase(item, -1);
		inven_item_describe(item);
		inven_item_optimize(item);
	} else {
		/* The ammo is from the floor */
		floor_item_increase(0 - item, -1);
		floor_item_optimize(0 - item);
	}
}
Exemplo n.º 7
0
/**
 * Draw a visible path over the squares between (x1,y1) and (x2,y2).
 *
 * The path consists of "*", which are white except where there is a
 * monster, object or feature in the grid.
 *
 * This routine has (at least) three weaknesses:
 * - remembered objects/walls which are no longer present are not shown,
 * - squares which (e.g.) the player has walked through in the dark are
 *   treated as unknown space.
 * - walls which appear strange due to hallucination aren't treated correctly.
 *
 * The first two result from information being lost from the dungeon arrays,
 * which requires changes elsewhere
 */
static int draw_path(u16b path_n, u16b *path_g, wchar_t *c, int *a, int y1, int x1)
{
	int i;
	bool on_screen;

	/* No path, so do nothing. */
	if (path_n < 1) return 0;

	/* The starting square is never drawn, but notice if it is being
     * displayed. In theory, it could be the last such square.
     */
	on_screen = panel_contains(y1, x1);

	/* Draw the path. */
	for (i = 0; i < path_n; i++) {
		byte colour;

		/* Find the co-ordinates on the level. */
		int y = GRID_Y(path_g[i]);
		int x = GRID_X(path_g[i]);

		/*
		 * As path[] is a straight line and the screen is oblong,
		 * there is only section of path[] on-screen.
		 * If the square being drawn is visible, this is part of it.
		 * If none of it has been drawn, continue until some of it
		 * is found or the last square is reached.
		 * If some of it has been drawn, finish now as there are no
		 * more visible squares to draw.
		 */
		 if (panel_contains(y,x)) on_screen = TRUE;
		 else if (on_screen) break;
		 else continue;

	 	/* Find the position on-screen */
		move_cursor_relative(y,x);

		/* This square is being overwritten, so save the original. */
		Term_what(Term->scr->cx, Term->scr->cy, a+i, c+i);

		/* Choose a colour. */
		if (cave->m_idx[y][x] && cave_monster_at(cave, y, x)->ml) {
			/* Visible monsters are red. */
			monster_type *m_ptr = cave_monster_at(cave, y, x);

			/* Mimics act as objects */
			if (rf_has(m_ptr->race->flags, RF_UNAWARE)) 
				colour = TERM_YELLOW;
			else
				colour = TERM_L_RED;
		}

		else if (cave->o_idx[y][x] && object_byid(cave->o_idx[y][x])->marked)
			/* Known objects are yellow. */
			colour = TERM_YELLOW;

		else if (!cave_ispassable(cave, y,x) &&
				 ((cave->info[y][x] & (CAVE_MARK)) || player_can_see_bold(y,x)))
			/* Known walls are blue. */
			colour = TERM_BLUE;

		else if (!(cave->info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x))
			/* Unknown squares are grey. */
			colour = TERM_L_DARK;

		else
			/* Unoccupied squares are white. */
			colour = TERM_WHITE;

		/* Draw the path segment */
		(void)Term_addch(colour, L'*');
	}
	return i;
}
Exemplo n.º 8
0
/*
 * Perform the basic "tunnel" command
 *
 * Assumes that no monster is blocking the destination
 *
 * Uses "twall" (above) to do all "terrain feature changing".
 *
 * Returns TRUE if repeated commands may continue
 */
static bool do_cmd_tunnel_aux(int y, int x)
{
	bool more = FALSE;


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


	/* Sound XXX XXX XXX */
	/* sound(MSG_DIG); */

	/* Titanium */
	if (cave_feat[y][x] >= FEAT_PERM_EXTRA)
	{
		msg_print("This seems to be permanent rock.");
	}

	/* Granite */
	else if (cave_feat[y][x] >= FEAT_WALL_EXTRA)
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 40 + randint0(1600)) && twall(y, x))
		{
			msg_print("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg_print("You tunnel into the granite wall.");
			more = TRUE;
		}
	}

	/* Quartz / Magma */
	else if (cave_feat[y][x] >= FEAT_MAGMA)
	{
		bool okay = FALSE;
		bool gold = FALSE;
		bool hard = FALSE;

		/* Found gold */
		if (cave_feat[y][x] >= FEAT_MAGMA_H)
		{
			gold = TRUE;
		}

		/* Extract "quartz" flag XXX XXX XXX */
		if ((cave_feat[y][x] - FEAT_MAGMA) & 0x01)
		{
			hard = TRUE;
		}

		/* Quartz */
		if (hard)
		{
			okay = (p_ptr->state.skills[SKILL_DIGGING] > 20 + randint0(800));
		}

		/* Magma */
		else
		{
			okay = (p_ptr->state.skills[SKILL_DIGGING] > 10 + randint0(400));
		}

		/* Success */
		if (okay && twall(y, x))
		{
			/* Found treasure */
			if (gold)
			{
				/* Place some gold */
				place_gold(y, x, p_ptr->depth);

				/* Message */
				msg_print("You have found something!");
			}

			/* Found nothing */
			else
			{
				/* Message */
				msg_print("You have finished the tunnel.");
			}
		}

		/* Failure (quartz) */
		else if (hard)
		{
			/* Message, continue digging */
			msg_print("You tunnel into the quartz vein.");
			more = TRUE;
		}

		/* Failure (magma) */
		else
		{
			/* Message, continue digging */
			msg_print("You tunnel into the magma vein.");
			more = TRUE;
		}
	}

	/* Rubble */
	else if (cave_feat[y][x] == FEAT_RUBBLE)
	{
		/* Remove the rubble */
		if ((p_ptr->state.skills[SKILL_DIGGING] > randint0(200)) && twall(y, x))
		{
			/* Message */
			msg_print("You have removed the rubble.");

			/* Hack -- place an object */
			if (randint0(100) < 10)
			{
				/* Create a simple object */
				place_object(y, x, p_ptr->depth, FALSE, FALSE);

				/* Observe the new object */
				if (!squelch_item_ok(&o_list[cave_o_idx[y][x]]) &&
				    player_can_see_bold(y, x))
				{
					msg_print("You have found something!");
				}
			}
		}

		else
		{
			/* Message, keep digging */
			msg_print("You dig in the rubble.");
			more = TRUE;
		}
	}

	/* Secret doors */
	else if (cave_feat[y][x] >= FEAT_SECRET)
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 30 + randint0(1200)) && twall(y, x))
		{
			msg_print("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg_print("You tunnel into the granite wall.");
			more = TRUE;

			/* Occasional Search XXX XXX */
			if (randint0(100) < 25) search(FALSE);
		}
	}

	/* Doors */
	else
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 30 + randint0(1200)) && twall(y, x))
		{
			msg_print("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg_print("You tunnel into the door.");
			more = TRUE;
		}
	}

	/* Result */
	return (more);
}
Exemplo n.º 9
0
/**
 * This is a helper function used by do_cmd_throw and do_cmd_fire.
 *
 * It abstracts out the projectile path, display code, identify and clean up
 * logic, while using the 'attack' parameter to do work particular to each
 * kind of attack.
 */
static void ranged_helper(struct object *obj, int dir, int range, int shots,
						  ranged_attack attack)
{
	int i, j;

	char o_name[80];

	int path_n;
	struct loc path_g[256];

	/* Start at the player */
	int x = player->px;
	int y = player->py;

	/* Predict the "target" location */
	int ty = y + 99 * ddy[dir];
	int tx = x + 99 * ddx[dir];

	bool hit_target = FALSE;

	struct object *missile;

	/* Check for target validity */
	if ((dir == 5) && target_okay()) {
		int taim;
		target_get(&tx, &ty);
		taim = distance(y, x, ty, tx);
		if (taim > range) {
			char msg[80];
			strnfmt(msg, sizeof(msg),
					"Target out of range by %d squares. Fire anyway? ",
				taim - range);
			if (!get_check(msg)) return;
		}
	}

	/* Sound */
	sound(MSG_SHOOT);

	/* Describe the object */
	object_desc(o_name, sizeof(o_name), obj, ODESC_FULL | ODESC_SINGULAR);

	/* Actually "fire" the object -- Take a partial turn */
	player->upkeep->energy_use = (z_info->move_energy / shots);

	/* Calculate the path */
	path_n = project_path(path_g, range, y, x, ty, tx, 0);

	/* Hack -- Handle stuff */
	handle_stuff(player->upkeep);

	/* Start at the player */
	x = player->px;
	y = player->py;

	/* Project along the path */
	for (i = 0; i < path_n; ++i) {
		int ny = path_g[i].y;
		int nx = path_g[i].x;
		bool see = player_can_see_bold(ny, nx);

		/* Stop before hitting walls */
		if (!(square_ispassable(cave, ny, nx)) &&
			!(square_isprojectable(cave, ny, nx)))
			break;

		/* Advance */
		x = nx;
		y = ny;

		/* Tell the UI to display the missile */
		event_signal_missile(EVENT_MISSILE, obj, see, y, x);

		/* Try the attack on the monster at (x, y) if any */
		if (cave->squares[y][x].mon > 0) {
			monster_type *m_ptr = square_monster(cave, y, x);
			int visible = mflag_has(m_ptr->mflag, MFLAG_VISIBLE);

			bool fear = FALSE;
			const char *note_dies = monster_is_unusual(m_ptr->race) ? 
				" is destroyed." : " dies.";

			struct attack_result result = attack(obj, y, x);
			int dmg = result.dmg;
			u32b msg_type = result.msg_type;
			char hit_verb[20];
			my_strcpy(hit_verb, result.hit_verb, sizeof(hit_verb));
			mem_free(result.hit_verb);

			if (result.success) {
				hit_target = TRUE;

				object_notice_attack_plusses(obj);

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

				/* No negative damage; change verb if no damage done */
				if (dmg <= 0) {
					dmg = 0;
					msg_type = MSG_MISS;
					my_strcpy(hit_verb, "fails to harm", sizeof(hit_verb));
				}

				if (!visible) {
					/* Invisible monster */
					msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name);
				} else {
					for (j = 0; j < (int)N_ELEMENTS(ranged_hit_types); j++) {
						char m_name[80];
						const char *dmg_text = "";

						if (msg_type != ranged_hit_types[j].msg)
							continue;

						if (OPT(show_damage))
							dmg_text = format(" (%d)", dmg);

						monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_OBJE);

						if (ranged_hit_types[j].text)
							msgt(msg_type, "Your %s %s %s%s. %s", o_name, 
								 hit_verb, m_name, dmg_text, 
								 ranged_hit_types[j].text);
						else
							msgt(msg_type, "Your %s %s %s%s.", o_name, hit_verb,
								 m_name, dmg_text);
					}
					
					/* Track this monster */
					if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) {
						monster_race_track(player->upkeep, m_ptr->race);
						health_track(player->upkeep, m_ptr);
					}
				}

				/* Hit the monster, check for death */
				if (!mon_take_hit(m_ptr, dmg, &fear, note_dies)) {
					message_pain(m_ptr, dmg);
					if (fear && mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) {
						char m_name[80];
						monster_desc(m_name, sizeof(m_name), m_ptr, 
									 MDESC_DEFAULT);
						add_monster_message(m_name, m_ptr, 
											MON_MSG_FLEE_IN_TERROR, TRUE);
					}
				}
			}
		}

		/* Stop if non-projectable but passable */
		if (!(square_isprojectable(cave, ny, nx))) 
			break;
	}

	/* Get the missile */
	if (object_is_carried(player, obj))
		missile = gear_object_for_use(obj, 1, TRUE);
	else
		missile = floor_object_for_use(obj, 1, TRUE);

	/* Drop (or break) near that location */
	drop_near(cave, missile, breakage_chance(missile, hit_target), y, x, TRUE);
}
Exemplo n.º 10
0
/*
 * Fire an object from the pack or floor.
 *
 * You may only fire items that "match" your missile launcher.
 *
 * See "calc_bonuses()" for more calculations and such.
 *
 * Note that "firing" a missile is MUCH better than "throwing" it.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Objects are more likely to break if they "attempt" to hit a monster.
 *
 * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
 * The "extra shot" code works by decreasing the amount of energy
 * required to make each shot, spreading the shots out over time.
 *
 * Note that when firing missiles, the launcher multiplier is applied
 * after all the bonuses are added in, making multipliers very useful.
 *
 * Note that Bows of "Extra Might" get extra range and an extra bonus
 * for the damage multiplier.
 */
void do_cmd_fire(cmd_code code, cmd_arg args[])
{
	int dir, item;
	int i, j, y, x;
	s16b ty, tx;
	int tdam, tdis, thits;
	int bonus, chance;

	object_type *o_ptr;
	object_type *j_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	bool hit_body = FALSE;

	byte missile_attr;
	char missile_char;

	char o_name[80];

	u32b msg_type = 0;

	int path_n;
	u16b path_g[256];

	int msec = op_ptr->delay_factor * op_ptr->delay_factor;

	/* Get the "bow" */
	j_ptr = &p_ptr->inventory[INVEN_BOW];

	/* Require a usable launcher */
	if (!j_ptr->tval || !p_ptr->state.ammo_tval)
	{
		msg_print("You have nothing to fire with.");
		return;
	}

	/* Get item to fire and direction to fire in. */
	item = args[0].item;
	dir = args[1].direction;

	/* Check the item being fired is usable by the player. */
	if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
	{
		msg_format("That item is not within your reach.");
		return;
	}

	/* Get the object for the ammo */
	o_ptr = object_from_item_idx(item);

	/* Check the ammo can be used with the launcher */
	if (o_ptr->tval != p_ptr->state.ammo_tval)
	{
		msg_format("That ammo cannot be fired by your current weapon.");
		return;
	}

	/* Base range XXX XXX */
	tdis = 6 + 2 * p_ptr->state.ammo_mult;

	/* Start at the player */
	x = p_ptr->px;
	y = p_ptr->py;

	/* Predict the "target" location */
	ty = y + 99 * ddy[dir];
	tx = x + 99 * ddx[dir];

	/* Check for target validity */
	if ((dir == 5) && target_okay())
	{
		target_get(&tx, &ty);
		if (distance(y, x, ty, tx) > tdis)
		{
			if (!get_check("Target out of range.  Fire anyway? "))
				return;
		}
	}

	/* Sound */
	sound(MSG_SHOOT);

	object_notice_on_firing(o_ptr);

	/* Describe the object */
	object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR);

	/* Find the color and symbol for the object for throwing */
	missile_attr = object_attr(o_ptr);
	missile_char = object_char(o_ptr);

	/* Use the proper number of shots */
	thits = p_ptr->state.num_fire;

	/* Actually "fire" the object */
	bonus = (p_ptr->state.to_h + o_ptr->to_h + j_ptr->to_h);
	chance = p_ptr->state.skills[SKILL_TO_HIT_BOW] +
			(bonus * BTH_PLUS_ADJ);

	/* Take a (partial) turn */
	p_ptr->energy_use = (100 / thits);

	/* Calculate the path */
	path_n = project_path(path_g, tdis, y, x, ty, tx, 0);

	/* Hack -- Handle stuff */
	handle_stuff();

	/* Project along the path */
	for (i = 0; i < path_n; ++i)
	{
		int ny = GRID_Y(path_g[i]);
		int nx = GRID_X(path_g[i]);

		/* Hack -- Stop before hitting walls */
		if (!cave_floor_bold(ny, nx)) break;

		/* Advance */
		x = nx;
		y = ny;

		/* Only do visuals if the player can "see" the missile */
		if (player_can_see_bold(y, x))
		{
			/* Visual effects */
			print_rel(missile_char, missile_attr, y, x);
			move_cursor_relative(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();

			Term_xtra(TERM_XTRA_DELAY, msec);
			light_spot(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();
		}

		/* Delay anyway for consistency */
		else
		{
			/* Pause anyway, for consistancy */
			Term_xtra(TERM_XTRA_DELAY, msec);
		}

		/* Handle monster */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x);
			int visible = m_ptr->ml;
			int multiplier = 1;

			const char *hit_verb = "hits";
			const slay_t *best_s_ptr = NULL;

			/* Note the collision */
			hit_body = TRUE;

			/* Did we hit it (penalize distance travelled) */
			if (test_hit(chance2, r_ptr->ac, m_ptr->ml))
			{
				bool fear = FALSE;

				/* Assume a default death */
				cptr note_dies = " dies.";

				improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr);
				improve_attack_modifier(j_ptr, m_ptr, &best_s_ptr);
				if (best_s_ptr != NULL)
					hit_verb = best_s_ptr->range_verb;

				/* Some monsters get "destroyed" */
				if (monster_is_unusual(r_ptr))
				{
					/* Special note at death */
					note_dies = " is destroyed.";
				}

				/* Calculate multiplier */
				multiplier = p_ptr->state.ammo_mult;
				if (best_s_ptr != NULL) multiplier += best_s_ptr->mult;

				/* Apply damage: multiplier, slays, criticals, bonuses */
				tdam = damroll(o_ptr->dd, o_ptr->ds);
				tdam += o_ptr->to_d + j_ptr->to_d;
				tdam *= multiplier;
				tdam = critical_shot(o_ptr->weight, o_ptr->to_h, tdam, &msg_type);

				object_notice_attack_plusses(o_ptr);
				object_notice_attack_plusses(&p_ptr->inventory[INVEN_BOW]);

				/* No negative damage; change verb if no damage done */
				if (tdam <= 0)
				{
					tdam = 0;
					hit_verb = "fail to harm";
				}

				/* Handle unseen monster */
				if (!visible)
				{
					/* Invisible monster */
					message_format(MSG_SHOOT_HIT, 0, "The %s finds a mark.", o_name);
				}

				/* Handle visible monster */
				else
				{
					char m_name[80];

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

					/* Tell the player what happened */
					if (msg_type == MSG_SHOOT_HIT)
						message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name);
					else
					{
						if (msg_type == MSG_HIT_GOOD)
						{
							message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a good hit!");
						}
						else if (msg_type == MSG_HIT_GREAT)
						{
							message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a great hit!");
						}
						else if (msg_type == MSG_HIT_SUPERB)
						{
							message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a superb hit!");
						}
					}
					/* Hack -- Track this monster race */
					if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

					/* Hack -- Track this monster */
					if (m_ptr->ml) health_track(cave_m_idx[y][x]);

				}

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

				/* Hit the monster, check for death */
				if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies))
				{
					/* Dead monster */
				}

				/* No death */
				else
				{
					/* Message */
					message_pain(cave_m_idx[y][x], tdam);

					/* Take note */
					if (fear && m_ptr->ml)
					{
						char m_name[80];

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

						/* Message */
						message_format(MSG_FLEE, m_ptr->r_idx,
						               "%^s flees in terror!", m_name);
					}
				}
			}

			/* Stop looking */
			break;
		}
	}



	/* Get local object */
	i_ptr = &object_type_body;

	/* Obtain a local object */
	object_copy(i_ptr, o_ptr);

	/* Single object */
	i_ptr->number = 1;

	if (item >= 0)
	{
		inven_item_increase(item, -1);
		inven_item_describe(item);
		inven_item_optimize(item);
	}

	/* Reduce and describe floor item */
	else
	{
		floor_item_increase(0 - item, -1);
		floor_item_optimize(0 - item);
	}


	/* Chance of breakage (during attacks) */
	j = (hit_body ? breakage_chance(i_ptr) : 0);

	/* Drop (or break) near that location */
	drop_near(i_ptr, j, y, x, TRUE);
}
Exemplo n.º 11
0
/*
 * Throw an object from the pack or floor.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Should throwing a weapon do full damage?  Should it allow the magic
 * to hit bonus of the weapon to have an effect?  Should it ever cause
 * the item to be destroyed?  Should it do any damage at all?
 */
void do_cmd_throw(cmd_code code, cmd_arg args[])
{
	int dir, item;
	int i, j, y, x;
	s16b ty, tx;
	int chance, tdam, tdis;
	int weight;

	object_type *o_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	bool hit_body = FALSE;

	byte missile_attr;
	char missile_char;

	char o_name[80];

	u32b msg_type = 0;

	int path_n;
	u16b path_g[256];

	int msec = op_ptr->delay_factor * op_ptr->delay_factor;

	/* Get item to throw and direction in which to throw it. */
	item = args[0].item;
	dir = args[1].direction;

	/* Make sure the player isn't throwing wielded items */
	if (item >= INVEN_WIELD && item < QUIVER_START)
	{
		msg_print("You have cannot throw wielded items.");
		return;
	}

	/* Check the item being thrown is usable by the player. */
	if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
	{
		msg_format("That item is not within your reach.");
		return;
	}

	/* Get the object */
	o_ptr = object_from_item_idx(item);
	object_notice_on_firing(o_ptr);

	/* Get local object */
	i_ptr = &object_type_body;

	/* Obtain a local object */
	object_copy(i_ptr, o_ptr);

	/* Distribute the charges of rods/wands/staves between the stacks */
	distribute_charges(o_ptr, i_ptr, 1);

	/* Single object */
	i_ptr->number = 1;

	/* Reduce and describe inventory */
	if (item >= 0)
	{
		inven_item_increase(item, -1);
		inven_item_describe(item);
		inven_item_optimize(item);
	}

	/* Reduce and describe floor item */
	else
	{
		floor_item_increase(0 - item, -1);
		floor_item_optimize(0 - item);
	}


	/* Description */
	object_desc(o_name, sizeof(o_name), i_ptr, ODESC_FULL);

	/* Find the color and symbol for the object for throwing */
	missile_attr = object_attr(i_ptr);
	missile_char = object_char(i_ptr);


	/* Enforce a minimum "weight" of one pound */
	weight = ((i_ptr->weight > 10) ? i_ptr->weight : 10);

	/* Hack -- Distance -- Reward strength, penalize weight */
	tdis = (adj_str_blow[p_ptr->state.stat_ind[A_STR]] + 20) * 10 / weight;

	/* Max distance of 10 */
	if (tdis > 10) tdis = 10;

	/* Hack -- Base damage from thrown object */
	tdam = damroll(i_ptr->dd, i_ptr->ds);
	if (!tdam) tdam = 1;
	tdam += i_ptr->to_d;

	/* Chance of hitting */
	chance = (p_ptr->state.skills[SKILL_TO_HIT_THROW] + (p_ptr->state.to_h * BTH_PLUS_ADJ));


	/* Take a turn */
	p_ptr->energy_use = 100;


	/* Start at the player */
	y = p_ptr->py;
	x = p_ptr->px;

	/* Predict the "target" location */
	ty = p_ptr->py + 99 * ddy[dir];
	tx = p_ptr->px + 99 * ddx[dir];

	/* Check for "target request" */
	if ((dir == 5) && target_okay())
	{
		target_get(&tx, &ty);
	}

	/* Calculate the path */
	path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0);


	/* Hack -- Handle stuff */
	handle_stuff();

	/* Project along the path */
	for (i = 0; i < path_n; ++i)
	{
		int ny = GRID_Y(path_g[i]);
		int nx = GRID_X(path_g[i]);

		/* Hack -- Stop before hitting walls */
		if (!cave_floor_bold(ny, nx)) break;

		/* Advance */
		x = nx;
		y = ny;

		/* Only do visuals if the player can "see" the missile */
		if (player_can_see_bold(y, x))
		{
			/* Visual effects */
			print_rel(missile_char, missile_attr, y, x);
			move_cursor_relative(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();

			Term_xtra(TERM_XTRA_DELAY, msec);
			light_spot(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();
		}

		/* Delay anyway for consistency */
		else
		{
			/* Pause anyway, for consistancy */
			Term_xtra(TERM_XTRA_DELAY, msec);
		}

		/* Handle monster */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x);

			int visible = m_ptr->ml;

			/* Note the collision */
			hit_body = TRUE;

			/* Did we hit it (penalize range) */
			if (test_hit(chance2, r_ptr->ac, m_ptr->ml))
			{
				const char *hit_verb = "hits";
				bool fear = FALSE;
				const slay_t *best_s_ptr = NULL;

				/* Assume a default death */
				cptr note_dies = " dies.";

				/* Some monsters get "destroyed" */
				if (monster_is_unusual(r_ptr))
				{
					/* Special note at death */
					note_dies = " is destroyed.";
				}

				/* Apply special damage  - brought forward to fill in hit_verb XXX XXX XXX */
				improve_attack_modifier(i_ptr, m_ptr, &best_s_ptr);
				if (best_s_ptr != NULL)
				{
					tdam *= best_s_ptr->mult;
					hit_verb = best_s_ptr->range_verb;
				}
				/* Apply special damage XXX XXX XXX */
				tdam = critical_shot(i_ptr->weight, i_ptr->to_h, tdam, &msg_type);

				/* No negative damage; change verb if no damage done */
				if (tdam <= 0)
				{
					tdam = 0;
					hit_verb = "fail to harm";
				}

				/* Handle unseen monster */
				if (!visible)
				{
					/* Invisible monster */
					msg_format("The %s finds a mark.", o_name);
				}

				/* Handle visible monster */
				else
				{
					char m_name[80];

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

					/* Tell the player what happened */
					if (msg_type == MSG_SHOOT_HIT)
						message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name);
					else
					{
						if (msg_type == MSG_HIT_GOOD)
						{
							message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a good hit!");
						}
						else if (msg_type == MSG_HIT_GREAT)
						{
							message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a great hit!");
						}
						else if (msg_type == MSG_HIT_SUPERB)
						{
							message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a superb hit!");
						}
					}
					/* Hack -- Track this monster race */
					if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

					/* Hack -- Track this monster */
					if (m_ptr->ml) health_track(cave_m_idx[y][x]);
				}

				/* Learn the bonuses */
				/* XXX Eddie This is messed up, better done for firing, */
				/* should use that method [split last] instead */
				/* check if inven_optimize removed what o_ptr referenced */
				if (object_similar(i_ptr, o_ptr, OSTACK_PACK))
					object_notice_attack_plusses(o_ptr);
				object_notice_attack_plusses(i_ptr);

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

				/* Hit the monster, check for death */
				if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies))
				{
					/* Dead monster */
				}

				/* No death */
				else
				{
					/* Message */
					message_pain(cave_m_idx[y][x], tdam);

					/* Take note */
					if (fear && m_ptr->ml)
					{
						char m_name[80];

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

						/* Message */
						message_format(MSG_FLEE, m_ptr->r_idx,
						               "%^s flees in terror!", m_name);
					}
				}
			}

			/* Stop looking */
			break;
		}
	}

	/* Chance of breakage (during attacks) */
	j = (hit_body ? breakage_chance(i_ptr) : 0);

	/* Drop (or break) near that location */
	drop_near(i_ptr, j, y, x, TRUE);
}
Exemplo n.º 12
0
/*
 * Perform the basic "tunnel" command
 *
 * Assumes that no monster is blocking the destination
 *
 * Uses "twall" (above) to do all "terrain feature changing".
 *
 * Returns TRUE if repeated commands may continue
 */
static bool do_cmd_tunnel_aux(int y, int x)
{
	bool more = FALSE;


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


	/* Sound XXX XXX XXX */
	/* sound(MSG_DIG); */

	/* Titanium */
	if (cave_isperm(cave, y, x))
	{
		msg("This seems to be permanent rock.");
	}

	/* Granite */
	else if (cave_isrock(cave, y, x))
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 40 + randint0(1600)) && twall(y, x))
		{
			msg("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg("You tunnel into the granite wall.");
			more = TRUE;
		}
	}

	/* Quartz / Magma */
	else if (cave_ismagma(cave, y, x) || cave_isquartz(cave, y, x))
	{
		bool okay = FALSE;
		bool gold = FALSE;
		bool hard = FALSE;

		/* Found gold */
		if (cave_hasgoldvein(cave, y, x))
			gold = TRUE;

		/* Extract "quartz" flag XXX XXX XXX */
		if (cave_isquartz(cave, y, x))
			hard = TRUE;

		/* Quartz */
		if (hard)
			okay = (p_ptr->state.skills[SKILL_DIGGING] > 20 + randint0(800));
		/* Magma */
		else
			okay = (p_ptr->state.skills[SKILL_DIGGING] > 10 + randint0(400));

		/* Success */
		if (okay && twall(y, x))
		{
			/* Found treasure */
			if (gold)
			{
				/* Place some gold */
				place_gold(cave, y, x, p_ptr->depth, ORIGIN_FLOOR);

				/* Message */
				msg("You have found something!");
			}

			/* Found nothing */
			else
			{
				/* Message */
				msg("You have finished the tunnel.");
			}
		}

		/* Failure (quartz) */
		else if (hard)
		{
			/* Message, continue digging */
			msg("You tunnel into the quartz vein.");
			more = TRUE;
		}

		/* Failure (magma) */
		else
		{
			/* Message, continue digging */
			msg("You tunnel into the magma vein.");
			more = TRUE;
		}
	}

	/* Rubble */
	else if (cave_isrubble(cave, y, x))
	{
		/* Remove the rubble */
		if ((p_ptr->state.skills[SKILL_DIGGING] > randint0(200)) && twall(y, x))
		{
			/* Message */
			msg("You have removed the rubble.");

			/* Hack -- place an object */
			if (randint0(100) < 10)	{
				/* Create a simple object */
				place_object(cave, y, x, p_ptr->depth, FALSE, FALSE,
					ORIGIN_RUBBLE, 0);

				/* Observe the new object */
				if (!squelch_item_ok(object_byid(cave->o_idx[y][x])) &&
					    player_can_see_bold(y, x))
					msg("You have found something!");
			}
		}

		else
		{
			/* Message, keep digging */
			msg("You dig in the rubble.");
			more = TRUE;
		}
	}

	/* Secret doors */
	else if (cave_issecretdoor(cave, y, x))
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 30 + randint0(1200)) && twall(y, x))
		{
			msg("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg("You tunnel into the granite wall.");
			more = TRUE;

			/* Occasional Search XXX XXX */
			if (randint0(100) < 25) search(FALSE);
		}
	}

	/* Doors */
	else
	{
		/* Tunnel */
		if ((p_ptr->state.skills[SKILL_DIGGING] > 30 + randint0(1200)) && twall(y, x))
		{
			msg("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
			/* We may continue tunelling */
			msg("You tunnel into the door.");
			more = TRUE;
		}
	}

	/* Result */
	return (more);
}
Exemplo n.º 13
0
static void _greater_whirlwind_attack_spell(int cmd, variant *res)
{
    switch (cmd)
    {
    case SPELL_NAME:
        var_set_string(res, "Greater Ambush");
        break;
    case SPELL_DESC:
        var_set_string(res, "Perform a massive ambush on nearby monsters.");
        break;
    case SPELL_CAST:
    {
        int              i, x, y;
        cave_type       *c_ptr;
        monster_type    *m_ptr;

/*       cba
        d218l
        e3@7k
        f456j
         ghi  */

        typedef struct _offset_t { int dx; int dy; } _offset;
        static _offset offsets[] = {
            { 0, -1},
            {-1, -1},
            {-1,  0},
            {-1,  1},
            { 0,  1},
            { 1,  1},
            { 1,  0},
            { 1, -1},
            { 1, -2},
            { 0, -2},
            {-1, -2},
            {-2, -1},
            {-2,  0},
            {-2,  1},
            {-1,  2},
            { 0,  2},
            { 1,  2},
            { 2,  1},
            { 2,  0},
            { 2, -1},
            { 0,  0}, /* sentinel */
        };

        for (i = 0;; i++)
        {
            _offset offset = offsets[i];
            if (offset.dx == 0 && offset.dy == 0) break;

            y = py + offset.dy;
            x = px + offset.dx;

            if (!in_bounds(y, x)) continue;
            if (!projectable(py, px, y, x)) continue;

            c_ptr = &cave[y][x];

            if (!c_ptr->m_idx) continue;

            m_ptr = &m_list[c_ptr->m_idx];

            if (m_ptr->ml || cave_have_flag_bold(y, x, FF_PROJECT))
            {
                int msec = delay_factor * delay_factor * delay_factor;

                if (panel_contains(y, x) && player_can_see_bold(y, x))
                {
                    char c = 0x30;
                    byte a = TERM_WHITE;

                    print_rel(c, a, y, x);
                    move_cursor_relative(y, x);
                    Term_fresh();
                    Term_xtra(TERM_XTRA_DELAY, msec);
                    lite_spot(y, x);
                    Term_fresh();
                }
                else
                    Term_xtra(TERM_XTRA_DELAY, msec);

                py_attack(y, x, 0);
            }
        }
        var_set_bool(res, TRUE);
        break;
    }
    default:
        default_spell(cmd, res);
        break;
    }
}