예제 #1
0
파일: cave-map.c 프로젝트: lhz/angband
/**
 * Make map features known, except wall/lava surrounded by wall/lava
 */
void cave_known(struct player *p)
{
	int y, x;
	for (y = 0; y < cave->height; y++) {
		for (x = 0; x < cave->width; x++) {
			int d;
			int xx, yy;
			int count = 0;

			/* Check around the grid */
			for (d = 0; d < 8; d++) {
				/* Extract adjacent location */
				yy = y + ddy_ddd[d];
				xx = x + ddx_ddd[d];

				/* Don't count projectable or lava squares */
				if (!square_isprojectable(cave, yy, xx) ||
					square_isbright(cave, yy, xx))
					++count;
			}

			/* Internal walls not known */
			if (count < 8)
				p->cave->squares[y][x].feat = cave->squares[y][x].feat;
		}
	}
}
예제 #2
0
파일: cave-map.c 프로젝트: lhz/angband
/**
 * Illuminate or darken any room containing the given location.
 */
void light_room(int y1, int x1, bool light)
{
	int i, x, y;
	struct point_set *ps;

	ps = point_set_new(200);
	/* Add the initial grid */
	cave_room_aux(ps, y1, x1);

	/* While grids are in the queue, add their neighbors */
	for (i = 0; i < ps->n; i++)
	{
		x = ps->pts[i].x, y = ps->pts[i].y;

		/* Walls get lit, but stop light */
		if (!square_isprojectable(cave, y, x)) continue;

		/* Spread adjacent */
		cave_room_aux(ps, y + 1, x);
		cave_room_aux(ps, y - 1, x);
		cave_room_aux(ps, y, x + 1);
		cave_room_aux(ps, y, x - 1);

		/* Spread diagonal */
		cave_room_aux(ps, y + 1, x + 1);
		cave_room_aux(ps, y - 1, x - 1);
		cave_room_aux(ps, y - 1, x + 1);
		cave_room_aux(ps, y + 1, x - 1);
	}

	/* Now, lighten or darken them all at once */
	if (light) {
		cave_light(ps);
	} else {
		cave_unlight(ps);
	}
	point_set_dispose(ps);

	/* Fully update the visuals */
	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);

	/* Update stuff */
	update_stuff(player);
}
예제 #3
0
/**
 * True if the square is a wall square (impedes the player).
 *
 * This function is the logical negation of square_isprojectable().
 */
bool square_iswall(struct chunk *c, int y, int x) {
	assert(square_in_bounds(c, y, x));
	return !square_isprojectable(c, y, x);
}
예제 #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, struct loc *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 = path_g[i].y;
		int x = path_g[i].x;
		struct monster *mon = square_monster(cave, y, x);
		struct object *obj = square_object(cave, y, x);

		/*
		 * 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 (mon && mflag_has(mon->mflag, MFLAG_VISIBLE)) {
			/* Mimics act as objects */
			if (rf_has(mon->race->flags, RF_UNAWARE)) 
				colour = COLOUR_YELLOW;
			else
				/* Visible monsters are red. */
				colour = COLOUR_L_RED;
		} else if (obj && obj->marked)
			/* Known objects are yellow. */
			colour = COLOUR_YELLOW;

		else if ((!square_isprojectable(cave, y,x) && square_ismark(cave, y, x))
				 || square_isseen(cave, y, x))
			/* Known walls are blue. */
			colour = COLOUR_BLUE;

		else if (!square_ismark(cave, y, x) && !square_isseen(cave, y, x))
			/* Unknown squares are grey. */
			colour = COLOUR_L_DARK;

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

		/* Draw the path segment */
		(void)Term_addch(colour, L'*');
	}
	return i;
}
예제 #5
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;
	bool none_left = 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);

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

	/* Project along the path */
	for (i = 0; i < path_n; ++i) {
		struct monster *mon = NULL;
		int ny = path_g[i].y;
		int nx = path_g[i].x;
		bool see = square_isseen(cave, 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 */
		mon = square_monster(cave, y, x);
		if (mon) {
			int visible = mflag_has(mon->mflag, MFLAG_VISIBLE);

			bool fear = FALSE;
			const char *note_dies = monster_is_unusual(mon->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), mon, 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(mon->mflag, MFLAG_VISIBLE)) {
						monster_race_track(player->upkeep, mon->race);
						health_track(player->upkeep, mon);
					}
				}

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

		/* 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, &none_left);
	else
		missile = floor_object_for_use(obj, 1, TRUE, &none_left);

	/* Drop (or break) near that location */
	drop_near(cave, missile, breakage_chance(missile, hit_target), y, x, TRUE);
}