예제 #1
0
/**
 * Update the player's knowledge of the objects on a grid in the current level
 */
void square_know_pile(struct chunk *c, int y, int x)
{
	struct object *obj;

	if (c != cave) return;

	object_lists_check_integrity(c, player->cave);

	/* Know every item on this grid, greater knowledge for the player grid */
	for (obj = square_object(c, y, x); obj; obj = obj->next) {
		object_see(player, obj);
		if ((y == player->py) && (x == player->px)) {
			object_touch(player, obj);
		}
	}

	/* Remove known location of anything not on this grid */
	obj = square_object(player->cave, y, x);
	while (obj) {
		struct object *next = obj->next;
		assert(c->objects[obj->oidx]);
		if (!square_holds_object(c, y, x, c->objects[obj->oidx])) {
			struct object *original = c->objects[obj->oidx];
			square_excise_object(player->cave, y, x, obj);
			obj->iy = 0;
			obj->ix = 0;

			/* Delete objects which no longer exist anywhere */
			if (obj->notice & OBJ_NOTICE_IMAGINED) {
				delist_object(player->cave, obj);
				object_delete(&obj);
				original->known = NULL;
				delist_object(c, original);
				object_delete(&original);
			}
		}
		obj = next;
	}
}
예제 #2
0
/**
 * Pick up everything on the floor that requires no player action
 */
int do_autopickup(void)
{
	int py = player->py;
	int px = player->px;

	struct object *obj, *next;

	/* Objects picked up.  Used to determine time cost of command. */
	byte objs_picked_up = 0;

	/* Nothing to pick up -- return */
	if (!square_object(cave, py, px))
		return 0;

	/* Always pickup gold, effortlessly */
	player_pickup_gold();

	/* Scan the remaining objects */
	obj = square_object(cave, py, px);
	while (obj) {
		next = obj->next;

		/* Ignore all hidden objects and non-objects */
		if (!ignore_item_ok(obj)) {
			/* Hack -- disturb */
			disturb(player, 0);

			/* Automatically pick up items into the backpack */
			if (auto_pickup_okay(obj)) {
				/* Pick up the object with message */
				player_pickup_aux(obj, TRUE);
				objs_picked_up++;
			}
		}
		obj = next;
	}

	return objs_picked_up;
}
예제 #3
0
파일: obj-pile.c 프로젝트: fizzix/angband
/**
 * This will push objects off a square.
 *
 * The methodology is to load all objects on the square into a queue. Replace
 * the previous square with a type that does not allow for objects. Drop the
 * objects. Last, put the square back to its original type.
 */
void push_object(int y, int x)
{
	/* Save the original terrain feature */
	struct feature *feat_old = square_feat(cave, y, x);

	struct object *obj = square_object(cave, y, x);

	struct queue *queue = q_new(z_info->floor_size);

	bool glyph = square_iswarded(cave, y, x);

	/* Push all objects on the square, stripped of pile info, into the queue */
	while (obj) {
		struct object *next = obj->next;
		q_push_ptr(queue, obj);

		/* Orphan the object */
		obj->next = NULL;
		obj->prev = NULL;
		obj->iy = 0;
		obj->ix = 0;

		/* Next object */
		obj = next;
	}

	/* Disassociate the objects from the square */
	cave->squares[y][x].obj = NULL;

	/* Set feature to an open door */
	square_force_floor(cave, y, x);
	square_add_door(cave, y, x, false);

	/* Drop objects back onto the floor */
	while (q_len(queue) > 0) {
		/* Take object from the queue */
		obj = q_pop_ptr(queue);

		/* Drop the object */
		drop_near(cave, &obj, 0, y, x, false);
	}

	/* Reset cave feature and rune if needed */
	square_set_feat(cave, y, x, feat_old->fidx);
	if (glyph)
		square_add_ward(cave, y, x);

	q_free(queue);
}
예제 #4
0
파일: trap.c 프로젝트: Daedelus01/angband
/**
 * Determine if a cave grid is allowed to have player traps in it.
 */
bool square_player_trap_allowed(struct chunk *c, int y, int x)
{
    /*
     * We currently forbid multiple traps in a grid under normal conditions.
     * If this changes, various bits of code elsewhere will have to change too.
     */
    if (square_istrap(c, y, x))
		return FALSE;

    /* We currently forbid traps in a grid with objects. */
    if (square_object(c, y, x))
		return FALSE;

    /* Check the feature trap flag */
    return (tf_has(f_info[c->squares[y][x].feat].flags, TF_TRAP));
}
예제 #5
0
파일: trap.c 프로젝트: magnate/angband
/**
 * Determine if a cave grid is allowed to have player traps in it.
 */
bool square_player_trap_allowed(struct chunk *c, int y, int x)
{
    /*
     * We currently forbid multiple traps in a grid under normal conditions.
     * If this changes, various bits of code elsewhere will have to change too.
     */
    if (square_istrap(c, y, x))
		return false;

    /* We currently forbid traps in a grid with objects. */
    if (square_object(c, y, x))
		return false;

    /* Check it's a trappable square */
    return (square_istrappable(c, y, x));
}
예제 #6
0
/**
 * Pick up objects at the player's request
 */
void do_cmd_pickup(struct command *cmd)
{
	int energy_cost;
	struct object *obj = square_object(cave, player->py, player->px);

	/* Autopickup first */
	energy_cost = do_autopickup() * z_info->move_energy / 10;

	/* Pick up floor objects with a menu for multiple objects */
	energy_cost += player_pickup_item(obj, FALSE) * z_info->move_energy / 10;

	/* Limit */
	if (energy_cost > z_info->move_energy) energy_cost = z_info->move_energy;

	/* Charge this amount of energy. */
	player->upkeep->energy_use = energy_cost;
}
예제 #7
0
/**
 * Memorize interesting viewable object/features in the given grid
 *
 * This function should only be called on "legal" grids.
 *
 * This function will memorize the object and/or feature in the given grid,
 * if they are (1) see-able and (2) interesting.  Note that all objects are
 * interesting, all terrain features except floors (and invisible traps) are
 * interesting, and floors (and invisible traps) are interesting sometimes
 * (depending on various options involving the illumination of floor grids).
 *
 * The automatic memorization of all objects and non-floor terrain features
 * as soon as they are displayed allows incredible amounts of optimization
 * in various places, especially "map_info()" and this function itself.
 *
 * Note that the memorization of objects is completely separate from the
 * memorization of terrain features, preventing annoying floor memorization
 * when a detected object is picked up from a dark floor, and object
 * memorization when an object is dropped into a floor grid which is
 * memorized but out-of-sight.
 *
 * This function should be called every time the "memorization" of a grid
 * (or the object in a grid) is called into question, such as when an object
 * is created in a grid, when a terrain feature "changes" from "floor" to
 * "non-floor", and when any grid becomes "see-able" for any reason.
 *
 * This function is called primarily from the "update_view()" function, for
 * each grid which becomes newly "see-able".
 */
void square_note_spot(struct chunk *c, int y, int x)
{
	object_type *obj;

	/* Require "seen" flag */
	if (!square_isseen(c, y, x))
		return;

	for (obj = square_object(c, y, x); obj; obj = obj->next)
		obj->marked = MARK_SEEN;

	if (square_ismark(c, y, x))
		return;

	/* Memorize this grid */
	sqinfo_on(c->squares[y][x].info, SQUARE_MARK);
}
예제 #8
0
/**
 * Light up the dungeon using "claravoyance"
 *
 * This function "illuminates" every grid in the dungeon, memorizes all
 * "objects" (or notes the existence of an object "if" full is TRUE),
 * and memorizes all grids as with magic mapping.
 */
void wiz_light(struct chunk *c, bool full)
{
	int i, y, x;

	/* Scan all grids */
	for (y = 1; y < c->height - 1; y++) {
		for (x = 1; x < c->width - 1; x++) {
			struct object *obj;

			/* Process all non-walls */
			if (!square_seemslikewall(c, y, x)) {
				/* Scan all neighbors */
				for (i = 0; i < 9; i++) {
					int yy = y + ddy_ddd[i];
					int xx = x + ddx_ddd[i];

					/* Perma-light the grid */
					sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW);

					/* Memorize normal features */
					if (!square_isfloor(c, yy, xx) || 
						square_isvisibletrap(c, yy, xx)) {
						sqinfo_on(c->squares[yy][xx].info, SQUARE_MARK);
						cave_k->squares[yy][xx].feat = c->squares[yy][xx].feat;
					}
				}
			}

			/* Memorize objects */
			for (obj = square_object(cave, y, x); obj; obj = obj->next) {
				/* Skip dead objects */
				assert(obj->kind);

				/* Memorize it */
				if (obj->marked < MARK_SEEN)
					obj->marked = full ? MARK_SEEN : MARK_AWARE;
			}
		}
	}

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

	/* Redraw whole map, monster list */
	player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST);
}
예제 #9
0
/**
 * Determine if a given location may be "destroyed"
 *
 * Used by destruction spells, and for placing stairs, etc.
 */
bool square_changeable(struct chunk *c, int y, int x)
{
	object_type *obj;

	/* Forbid perma-grids */
	if (square_isperm(c, y, x) || square_isshop(c, y, x) ||
		square_isstairs(c, y, x))
		return (FALSE);

	/* Check objects */
	for (obj = square_object(c, y, x); obj; obj = obj->next)
		/* Forbid artifact grids */
		if (obj->artifact) return (FALSE);

	/* Accept */
	return (TRUE);
}
예제 #10
0
/**
 * Scans the dungeon for objects
 */
static void scan_for_objects(void)
{ 
	int y, x;

	for (y = 1; y < cave->height - 1; y++) {
		for (x = 1; x < cave->width - 1; x++) {
			struct object *obj;

			while ((obj = square_object(cave, y, x))) {
				/* Get data on the object */
				get_obj_data(obj, y, x, FALSE, FALSE);

				/* Delete the object */
				square_excise_object(cave, y, x, obj);
				object_delete(&obj);
			}
		}
	}
}
예제 #11
0
/**
 * Search for traps or secret doors
 */
static void search(void)
{
	int py = player->py;
	int px = player->px;
	int y, x;
	struct object *obj;

	/* Various conditions mean no searching */
	if (player->timed[TMD_BLIND] || no_light() ||
		player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE])
		return;

	/* Search the nearby grids, which are always in bounds */
	for (y = (py - 1); y <= (py + 1); y++) {
		for (x = (px - 1); x <= (px + 1); x++) {
			/* Traps */
			if (square_issecrettrap(cave, y, x)) {
				if (square_reveal_trap(cave, y, x, true))
					disturb(player, 0);
			}

			/* Secret doors */
			if (square_issecretdoor(cave, y, x)) {
				msg("You have found a secret door.");
				place_closed_door(cave, y, x);
				disturb(player, 0);
			}

			/* Traps on chests */
			for (obj = square_object(cave, y, x); obj; obj = obj->next) {
				if (!obj->known || !is_trapped_chest(obj))
					continue;

				if (obj->known->pval != obj->pval) {
					msg("You have discovered a trap on the chest!");
					obj->known->pval = obj->pval;
					disturb(player, 0);
				}
			}
		}
	}
}
예제 #12
0
/**
 * Put a rune autoinscription on all available objects
 */
void rune_autoinscribe(int i)
{
	struct object *obj;
	int py = player->py;
	int px = player->px;

	/* Check the player knows the rune */
	if (!player_knows_rune(player, i)) {
		return;
	}

	/* Autoinscribe each object on the ground */
	if (cave)
		for (obj = square_object(cave, py, px); obj; obj = obj->next)
			if (object_has_rune(obj, i))
				rune_add_autoinscription(obj, i);

	/* Autoinscribe each object in the inventory */
	for (obj = player->gear; obj; obj = obj->next)
		if (object_has_rune(obj, i))
			rune_add_autoinscription(obj, i);
}
예제 #13
0
/**
 * Determine if a given location is "interesting"
 */
bool target_accept(int y, int x)
{
	struct loc grid = loc(x, y);
	struct object *obj;

	/* Player grids are always interesting */
	if (square(cave, grid).mon < 0) return true;

	/* Handle hallucination */
	if (player->timed[TMD_IMAGE]) return false;

	/* Obvious monsters */
	if (square(cave, grid).mon > 0) {
		struct monster *mon = square_monster(cave, grid);
		if (monster_is_obvious(mon)) {
			return true;
		}
	}

	/* Traps */
	if (square_isvisibletrap(cave, grid)) return true;

	/* Scan all objects in the grid */
	for (obj = square_object(player->cave, grid); obj; obj = obj->next) {
		/* Memorized object */
		if ((obj->kind == unknown_item_kind) || !ignore_known_item_ok(obj)) {
			return true;
		}
	}

	/* Interesting memorized features */
	if (square_isknown(cave, grid) && square_isinteresting(cave, grid)) {
		return true;
	}

	/* Nope */
	return false;
}
예제 #14
0
파일: target.c 프로젝트: myshkin/angband
/**
 * Determine if a given location is "interesting"
 */
bool target_accept(int y, int x)
{
	object_type *obj;

	/* Player grids are always interesting */
	if (cave->squares[y][x].mon < 0) return (TRUE);

	/* Handle hallucination */
	if (player->timed[TMD_IMAGE]) return (FALSE);

	/* Visible monsters */
	if (cave->squares[y][x].mon > 0) {
		monster_type *m_ptr = square_monster(cave, y, x);

		/* Visible monsters */
		if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) &&
			!mflag_has(m_ptr->mflag, MFLAG_UNAWARE))
			return (TRUE);
	}

    /* Traps */
    if (square_isvisibletrap(cave, y, x))
		return(TRUE);

	/* Scan all objects in the grid */
	for (obj = square_object(cave, y, x); obj; obj = obj->next)
		/* Memorized object */
		if (obj->marked && !ignore_item_ok(obj)) return (TRUE);

	/* Interesting memorized features */
	if (square_ismark(cave, y, x) && !square_isboring(cave, y, x))
		return (TRUE);

	/* Nope */
	return (FALSE);
}
예제 #15
0
파일: target.c 프로젝트: Axydlbaaxr/angband
/**
 * Determine if a given location is "interesting"
 */
bool target_accept(int y, int x)
{
	struct object *obj;

	/* Player grids are always interesting */
	if (cave->squares[y][x].mon < 0) return (true);

	/* Handle hallucination */
	if (player->timed[TMD_IMAGE]) return (false);

	/* Visible monsters */
	if (cave->squares[y][x].mon > 0) {
		struct monster *mon = square_monster(cave, y, x);

		/* Visible monsters */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
			!mflag_has(mon->mflag, MFLAG_UNAWARE))
			return (true);
	}

	/* Traps */
	if (square_isvisibletrap(cave, y, x))
		return(true);

	/* Scan all objects in the grid */
	for (obj = square_object(cave_k, y, x); obj; obj = obj->next)
		/* Memorized object */
		if (!ignore_known_item_ok(obj)) return (true);

	/* Interesting memorized features */
	if (square_isknown(cave, y, x) && square_isinteresting(cave, y, x))
		return (true);

	/* Nope */
	return (false);
}
예제 #16
0
/**
 * Return TRUE if the given object is on the floor at this grid
 */
bool square_holds_object(struct chunk *c, int y, int x, struct object *obj) {
	return pile_contains(square_object(c, y, x), obj);
}
예제 #17
0
/**
 * True if the square is empty (an open square without any items).
 */
bool square_isempty(struct chunk *c, int y, int x) {
	if (square_isplayertrap(c, y, x)) return FALSE;
	return square_isopen(c, y, x) && !square_object(c, y, x);
}
예제 #18
0
파일: mon-move.c 프로젝트: myshkin/angband
/**
 * 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;
	}
}
예제 #19
0
/**
 * True if the square is a floor square without items.
 */
bool square_canputitem(struct chunk *c, int y, int x) {
	return square_isfloor(c, y, x) && !square_object(c, y, x);
}
예제 #20
0
/**
 * Update the current "run" path
 *
 * Return TRUE if the running should be stopped
 */
static bool run_test(void)
{
	int py = player->py;
	int px = player->px;

	int prev_dir;
	int new_dir;

	int row, col;
	int i, max, inv;
	int option, option2;


	/* No options yet */
	option = 0;
	option2 = 0;

	/* Where we came from */
	prev_dir = run_old_dir;


	/* Range of newly adjacent grids */
	max = (prev_dir & 0x01) + 1;


	/* Look at every newly adjacent square. */
	for (i = -max; i <= max; i++) {
		struct object *obj;

		/* New direction */
		new_dir = cycle[chome[prev_dir] + i];

		/* New location */
		row = py + ddy[new_dir];
		col = px + ddx[new_dir];


		/* Visible monsters abort running */
		if (cave->squares[row][col].mon > 0) {
			monster_type *m_ptr = square_monster(cave, row, col);

			/* Visible monster */
			if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) return (TRUE);
		}

		/* Visible objects abort running */
		for (obj = square_object(cave, row, col); obj; obj = obj->next)
			/* Visible object */
			if (obj->marked && !ignore_item_ok(obj)) return (TRUE);

		/* Assume unknown */
		inv = TRUE;

		/* Check memorized grids */
		if (square_ismark(cave, row, col)) {
			bool notice = square_noticeable(cave, row, col);

			/* Interesting feature */
			if (notice) return (TRUE);

			/* The grid is "visible" */
			inv = FALSE;
		}

		/* Analyze unknown grids and floors */
		if (inv || square_ispassable(cave, row, col)) {
			/* Looking for open area */
			if (run_open_area) {
				/* Nothing */
			} else if (!option) {
				/* The first new direction. */
				option = new_dir;
			} else if (option2) {
				/* Three new directions. Stop running. */
				return (TRUE);
			} else if (option != cycle[chome[prev_dir] + i - 1]) {
				/* Two non-adjacent new directions.  Stop running. */
				return (TRUE);
			} else if (new_dir & 0x01) {
				/* Two new (adjacent) directions (case 1) */
				option2 = new_dir;
			} else {
				/* Two new (adjacent) directions (case 2) */
				option2 = option;
				option = new_dir;
			}
		} else { /* Obstacle, while looking for open area */
			if (run_open_area) {
				if (i < 0) {
					/* Break to the right */
					run_break_right = TRUE;
				} else if (i > 0) {
					/* Break to the left */
					run_break_left = TRUE;
				}
			}
		}
	}


	/* Look at every soon to be newly adjacent square. */
	for (i = -max; i <= max; i++) {		
		/* New direction */
		new_dir = cycle[chome[prev_dir] + i];
		
		/* New location */
		row = py + ddy[prev_dir] + ddy[new_dir];
		col = px + ddx[prev_dir] + ddx[new_dir];
		
		/* HACK: Ugh. Sometimes we come up with illegal bounds. This will
		 * treat the symptom but not the disease. */
		if (row >= cave->height || col >= cave->width) continue;
		if (row < 0 || col < 0) continue;

		/* Visible monsters abort running */
		if (cave->squares[row][col].mon > 0) {
			monster_type *m_ptr = square_monster(cave, row, col);
			
			/* Visible monster */
			if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) && !is_mimicking(m_ptr))
				return (TRUE);
		}
	}

	/* Looking for open area */
	if (run_open_area) {
		/* Hack -- look again */
		for (i = -max; i < 0; i++) {
			new_dir = cycle[chome[prev_dir] + i];

			row = py + ddy[new_dir];
			col = px + ddx[new_dir];

			/* Unknown grid or non-wall */
			/* Was: square_ispassable(cave, row, col) */
			if (!square_ismark(cave, row, col) ||
			    (square_ispassable(cave, row, col))) {
				/* Looking to break right */
				if (run_break_right) {
					return (TRUE);
				}
			} else { /* Obstacle */
				/* Looking to break left */
				if (run_break_left) {
					return (TRUE);
				}
			}
		}

		/* Hack -- look again */
		for (i = max; i > 0; i--) {
			new_dir = cycle[chome[prev_dir] + i];

			row = py + ddy[new_dir];
			col = px + ddx[new_dir];

			/* Unknown grid or non-wall */
			/* Was: square_ispassable(cave, row, col) */
			if (!square_ismark(cave, row, col) ||
			    (square_ispassable(cave, row, col))) {
				/* Looking to break left */
				if (run_break_left) {
					return (TRUE);
				}
			} else { /* Obstacle */
				/* Looking to break right */
				if (run_break_right) {
					return (TRUE);
				}
			}
		}
	} else { /* Not looking for open area */
		/* No options */
		if (!option) {
			return (TRUE);
		} else if (!option2) { /* One option */
			/* Primary option */
			run_cur_dir = option;

			/* No other options */
			run_old_dir = option;
		} else { /* Two options, examining corners */
			/* Primary option */
			run_cur_dir = option;

			/* Hack -- allow curving */
			run_old_dir = option2;
		}
	}


	/* About to hit a known wall, stop */
	if (see_wall(run_cur_dir, py, px))
		return (TRUE);


	/* Failure */
	return (FALSE);
}
예제 #21
0
/**
 * Handle "target" and "look".
 *
 * Note that this code can be called from "get_aim_dir()".
 *
 * Currently, when "flag" is true, that is, when
 * "interesting" grids are being used, and a directional key is used, we
 * only scroll by a single panel, in the direction requested, and check
 * for any interesting grids on that panel.  The "correct" solution would
 * actually involve scanning a larger set of grids, including ones in
 * panels which are adjacent to the one currently scanned, but this is
 * overkill for this function.  XXX XXX
 *
 * Hack -- targetting/observing an "outer border grid" may induce
 * problems, so this is not currently allowed.
 *
 * The player can use the direction keys to move among "interesting"
 * grids in a heuristic manner, or the "space", "+", and "-" keys to
 * move through the "interesting" grids in a sequential manner, or
 * can enter "location" mode, and use the direction keys to move one
 * grid at a time in any direction.  The "t" (set target) command will
 * only target a monster (as opposed to a location) if the monster is
 * target_able and the "interesting" mode is being used.
 *
 * The current grid is described using the "look" method above, and
 * a new command may be entered at any time, but note that if the
 * "TARGET_LOOK" bit flag is set (or if we are in "location" mode,
 * where "space" has no obvious meaning) then "space" will scan
 * through the description of the current grid until done, instead
 * of immediately jumping to the next "interesting" grid.  This
 * allows the "target" command to retain its old semantics.
 *
 * The "*", "+", and "-" keys may always be used to jump immediately
 * to the next (or previous) interesting grid, in the proper mode.
 *
 * The "return" key may always be used to scan through a complete
 * grid description (forever).
 *
 * This command will cancel any old target, even if used from
 * inside the "look" command.
 *
 *
 * 'mode' is one of TARGET_LOOK or TARGET_KILL.
 * 'x' and 'y' are the initial position of the target to be highlighted,
 * or -1 if no location is specified.
 * Returns TRUE if a target has been successfully set, FALSE otherwise.
 */
bool target_set_interactive(int mode, int x, int y)
{
	int py = player->py;
	int px = player->px;

	int path_n;
	struct loc path_g[256];

	int i, d, m, t, bd;
	int wid, hgt, help_prompt_loc;

	bool done = FALSE;
	bool flag = TRUE;
	bool help = FALSE;

	ui_event press;

	/* These are used for displaying the path to the target */
	wchar_t *path_char = mem_zalloc(z_info->max_range * sizeof(wchar_t));
	int *path_attr = mem_zalloc(z_info->max_range * sizeof(int));
	struct point_set *targets;

	/* If we haven't been given an initial location, start on the
	   player, otherwise  honour it by going into "free targetting" mode. */
	if (x == -1 || y == -1) {
		x = player->px;
		y = player->py;
	} else {
		flag = FALSE;
	}

	/* Cancel target */
	target_set_monster(0);

	/* Calculate the window location for the help prompt */
	Term_get_size(&wid, &hgt);
	help_prompt_loc = hgt - 1;
	
	/* Display the help prompt */
	prt("Press '?' for help.", help_prompt_loc, 0);

	/* Prepare the target set */
	targets = target_get_monsters(mode);

	/* Start near the player */
	m = 0;

	/* Interact */
	while (!done) {
		bool path_drawn = FALSE;
		
		/* Interesting grids if chosen and there are any, otherwise arbitrary */
		if (flag && point_set_size(targets)) {
			y = targets->pts[m].y;
			x = targets->pts[m].x;

			/* Adjust panel if needed */
			if (adjust_panel_help(y, x, help)) handle_stuff(player);
		
			/* Update help */
			if (help) {
				bool good_target = target_able(square_monster(cave, y, x));
				target_display_help(good_target,
									!(flag && point_set_size(targets)));
			}

			/* Find the path. */
			path_n = project_path(path_g, z_info->max_range, py, px, y, x,
								  PROJECT_THRU);

			/* Draw the path in "target" mode. If there is one */
			if (mode & (TARGET_KILL))
				path_drawn = draw_path(path_n, path_g, path_char, path_attr,
									   py, px);

			/* Describe and Prompt */
			press = target_set_interactive_aux(y, x, mode);

			/* Remove the path */
			if (path_drawn) load_path(path_n, path_g, path_char, path_attr);

			/* Assume no "direction" */
			d = 0;


			/* Analyze */
			if (press.type == EVT_MOUSE) {
				if (press.mouse.button == 3) {
					/* give the target selection command */
					press.mouse.button = 2;
					press.mouse.mods = KC_MOD_CONTROL;
				}
				if (press.mouse.button == 2) {
					y = KEY_GRID_Y(press);
					x = KEY_GRID_X(press);
					if (press.mouse.mods & KC_MOD_CONTROL) {
						/* same as keyboard target selection command below */
						struct monster *m = square_monster(cave, y, x);

						if (target_able(m)) {
							/* Set up target information */
							monster_race_track(player->upkeep, m->race);
							health_track(player->upkeep, m);
							target_set_monster(m);
							done = TRUE;
						} else {
							bell("Illegal target!");
						}
					} else if (press.mouse.mods & KC_MOD_ALT) {
						/* go to spot - same as 'g' command below */
						cmdq_push(CMD_PATHFIND);
						cmd_set_arg_point(cmdq_peek(), "point", y, x);
						done = TRUE;
					} else {
						/* cancel look mode */
						done = TRUE;
					}
				} else {
					y = KEY_GRID_Y(press);
					x = KEY_GRID_X(press);
					if (square_monster(cave, y, x) ||
						square_object(cave, y, x)) {
							/* reset the flag, to make sure we stay in this
							 * mode if something is actually there */
						flag = FALSE;
						/* scan the interesting list and see if there is
						 * anything here */
						for (i = 0; i < point_set_size(targets); i++) {
							if ((y == targets->pts[i].y) &&
								(x == targets->pts[i].x)) {
								m = i;
								flag = TRUE;
								break;
							}
						}
					} else {
						flag = FALSE;
					}
				}
			} else
				switch (press.key.code)
				{
					case ESCAPE:
					case 'q':
					{
						done = TRUE;
						break;
					}

					case ' ':
					case '*':
					case '+':
					{
						if (++m == point_set_size(targets))
							m = 0;

						break;
					}

					case '-':
					{
						if (m-- == 0)
							m = point_set_size(targets) - 1;

						break;
					}

					case 'p':
					{
						/* Recenter around player */
						verify_panel();

						/* Handle stuff */
						handle_stuff(player);

						y = player->py;
						x = player->px;
					}

					case 'o':
					{
						flag = FALSE;
						break;
					}

					case 'm':
					{
						break;
					}

					case 't':
					case '5':
					case '0':
					case '.':
					{
						struct monster *m = square_monster(cave, y, x);

						if (target_able(m)) {
							health_track(player->upkeep, m);
							target_set_monster(m);
							done = TRUE;
						} else {
							bell("Illegal target!");
						}
						break;
					}

					case 'g':
					{
						cmdq_push(CMD_PATHFIND);
						cmd_set_arg_point(cmdq_peek(), "point", y, x);
						done = TRUE;
						break;
					}
				
					case '?':
					{
						help = !help;
					
						/* Redraw main window */
						player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP);
						Term_clear();
						handle_stuff(player);
						if (!help)
							prt("Press '?' for help.", help_prompt_loc, 0);
					
						break;
					}

					default:
					{
						/* Extract direction */
						d = target_dir(press.key);

						/* Oops */
						if (!d) bell("Illegal command for target mode!");

						break;
					}
				}

			/* Hack -- move around */
			if (d) {
				int old_y = targets->pts[m].y;
				int old_x = targets->pts[m].x;

				/* Find a new monster */
				i = target_pick(old_y, old_x, ddy[d], ddx[d], targets);

				/* Scroll to find interesting grid */
				if (i < 0) {
					int old_wy = Term->offset_y;
					int old_wx = Term->offset_x;

					/* Change if legal */
					if (change_panel(d)) {
						/* Recalculate interesting grids */
						point_set_dispose(targets);
						targets = target_get_monsters(mode);

						/* Find a new monster */
						i = target_pick(old_y, old_x, ddy[d], ddx[d], targets);

						/* Restore panel if needed */
						if ((i < 0) && modify_panel(Term, old_wy, old_wx)) {
							/* Recalculate interesting grids */
							point_set_dispose(targets);
							targets = target_get_monsters(mode);
						}

						/* Handle stuff */
						handle_stuff(player);
					}
				}

				/* Use interesting grid if found */
				if (i >= 0) m = i;
			}
		} else {
			/* Update help */
			if (help) {
				bool good_target = target_able(square_monster(cave, y, x));
				target_display_help(good_target,
									!(flag && point_set_size(targets)));
			}

			/* Find the path. */
			path_n = project_path(path_g, z_info->max_range, py, px, y, x,
								  PROJECT_THRU);

			/* Draw the path in "target" mode. If there is one */
			if (mode & (TARGET_KILL))
				path_drawn = draw_path (path_n, path_g, path_char, path_attr,
										py, px);

			/* Describe and Prompt (enable "TARGET_LOOK") */
			press = target_set_interactive_aux(y, x, mode | TARGET_LOOK);

			/* Remove the path */
			if (path_drawn)  load_path(path_n, path_g, path_char, path_attr);

			/* Assume no direction */
			d = 0;

			/* Analyze the keypress */
			if (press.type == EVT_MOUSE) {
				if (press.mouse.button == 3) {
					/* give the target selection command */
					press.mouse.button = 2;
					press.mouse.mods = KC_MOD_CONTROL;
				}
				if (press.mouse.button == 2) {
					if (mode & (TARGET_KILL)) {
						if ((y == KEY_GRID_Y(press)) 
								&& (x == KEY_GRID_X(press))) {
							d = -1;
						}
					}
					y = KEY_GRID_Y(press);
					x = KEY_GRID_X(press);
					if (press.mouse.mods & KC_MOD_CONTROL) {
						/* same as keyboard target selection command below */
						target_set_location(y, x);
						done = TRUE;
					} else if (press.mouse.mods & KC_MOD_ALT) {
						/* go to spot - same as 'g' command below */
						cmdq_push(CMD_PATHFIND);
						cmd_set_arg_point(cmdq_peek(), "point", y, x);
						done = TRUE;
					} else {
						/* cancel look mode */
						done = TRUE;
						if (d == -1) {
							target_set_location(y, x);
							d = 0;
						}
					}
				} else {
					int dungeon_hgt = cave->height;
					int dungeon_wid = cave->width;

					y = KEY_GRID_Y(press);
					x = KEY_GRID_X(press);
				  
					if (press.mouse.y <= 1) {
						/* move the screen north */
						y--;
					} else if (press.mouse.y >= (Term->hgt - 2)) {
						/* move the screen south */
						y++;
					} else if (press.mouse.x <= COL_MAP) {
						/* move the screen in west */
						x--;
					} else if (press.mouse.x >= (Term->wid - 2)) {
						/* move the screen east */
						x++;
					}
          
					if (y < 0) y = 0;
					if (x < 0) x = 0;
					if (y >= dungeon_hgt-1) y = dungeon_hgt-1;
					if (x >= dungeon_wid-1) x = dungeon_wid-1;

					/* Adjust panel if needed */
					if (adjust_panel_help(y, x, help)) {
						/* Handle stuff */
						handle_stuff(player);

						/* Recalculate interesting grids */
						point_set_dispose(targets);
						targets = target_get_monsters(mode);
					}

					if (square_monster(cave, y, x) ||
						square_object(cave, y, x)) {
						/* scan the interesting list and see if there in
						 * anything here */
						for (i = 0; i < point_set_size(targets); i++) {
							if ((y == targets->pts[i].y) &&
								(x == targets->pts[i].x)) {
								m = i;
								flag = TRUE;
								break;
							}
						}
					} else {
						flag = FALSE;
					}
				}
			} else
				switch (press.key.code)
				{
					case ESCAPE:
					case 'q':
					{
						done = TRUE;
						break;
					}

					case ' ':
					case '*':
					case '+':
					case '-':
					{
						break;
					}

					case 'p':
					{
						/* Recenter around player */
						verify_panel();

						/* Handle stuff */
						handle_stuff(player);

						y = player->py;
						x = player->px;
					}

					case 'o':
					{
						break;
					}

					case 'm':
					{
						flag = TRUE;

						m = 0;
						bd = 999;

						/* Pick a nearby monster */
						for (i = 0; i < point_set_size(targets); i++) {
							t = distance(y, x, targets->pts[i].y,
										 targets->pts[i].x);

							/* Pick closest */
							if (t < bd) {
								m = i;
								bd = t;
							}
						}

						/* Nothing interesting */
						if (bd == 999) flag = FALSE;

						break;
					}

					case 't':
					case '5':
					case '0':
					case '.':
					{
						target_set_location(y, x);
						done = TRUE;
						break;
					}

					case 'g':
					{
						cmdq_push(CMD_PATHFIND);
						cmd_set_arg_point(cmdq_peek(), "point", y, x);
						done = TRUE;
						break;
					}

					case '?':
					{
						help = !help;

						/* Redraw main window */
						player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP);
						Term_clear();
						handle_stuff(player);
						if (!help)
							prt("Press '?' for help.", help_prompt_loc, 0);
					
						break;
					}

					default:
					{
						/* Extract a direction */
						d = target_dir(press.key);

						/* Oops */
						if (!d) bell("Illegal command for target mode!");

						break;
					}
				}

			/* Handle "direction" */
			if (d) {
				int dungeon_hgt = cave->height;
				int dungeon_wid = cave->width;

				/* Move */
				x += ddx[d];
				y += ddy[d];

				/* Slide into legality */
				if (x >= dungeon_wid - 1) x--;
				else if (x <= 0) x++;

				/* Slide into legality */
				if (y >= dungeon_hgt - 1) y--;
				else if (y <= 0) y++;

				/* Adjust panel if needed */
				if (adjust_panel_help(y, x, help)) {
					/* Handle stuff */
					handle_stuff(player);

					/* Recalculate interesting grids */
					point_set_dispose(targets);
					targets = target_get_monsters(mode);
				}
			}
		}
	}

	/* Forget */
	point_set_dispose(targets);

	/* Redraw as necessary */
	if (help) {
		player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP);
		Term_clear();
	} else {
		prt("", 0, 0);
		prt("", help_prompt_loc, 0);
		player->upkeep->redraw |= (PR_DEPTH | PR_STATUS);
	}

	/* Recenter around player */
	verify_panel();

	/* Handle stuff */
	handle_stuff(player);

	mem_free(path_attr);
	mem_free(path_char);

	/* Failure to set target */
	if (!target_is_set()) return (FALSE);

	/* Success */
	return (TRUE);
}
예제 #22
0
/**
 * This function takes a grid location (x, y) and extracts information the
 * player is allowed to know about it, filling in the grid_data structure
 * passed in 'g'.
 *
 * The information filled in is as follows:
 *  - g->f_idx is filled in with the terrain's feature type, or FEAT_NONE
 *    if the player doesn't know anything about the grid.  The function
 *    makes use of the "mimic" field in terrain in order to allow one
 *    feature to look like another (hiding secret doors, invisible traps,
 *    etc).  This will return the terrain type the player "Knows" about,
 *    not necessarily the real terrain.
 *  - g->m_idx is set to the monster index, or 0 if there is none (or the
 *    player doesn't know it).
 *  - g->first_kind is set to the object_kind of the first object in a grid
 *    that the player knows about, or NULL for no objects.
 *  - g->muliple_objects is TRUE if there is more than one object in the
 *    grid that the player knows and cares about (to facilitate any special
 *    floor stack symbol that might be used).
 *  - g->in_view is TRUE if the player can currently see the grid - this can
 *    be used to indicate field-of-view, such as through the OPT(view_bright_light)
 *    option.
 *  - g->lighting is set to indicate the lighting level for the grid:
 *    LIGHTING_DARK for unlit grids, LIGHTING_LIT for inherently light
 *    grids (lit rooms, etc), LIGHTING_TORCH for grids lit by the player's
 *    light source, and LIGHTING_LOS for grids in the player's line of sight.
 *    Note that lighting is always LIGHTING_LIT for known "interesting" grids
 *    like walls.
 *  - g->is_player is TRUE if the player is on the given grid.
 *  - g->hallucinate is TRUE if the player is hallucinating something "strange"
 *    for this grid - this should pick a random monster to show if the m_idx
 *    is non-zero, and a random object if first_kind is non-zero.
 * 
 * NOTES:
 * This is called pretty frequently, whenever a grid on the map display
 * needs updating, so don't overcomplicate it.
 *
 * Terrain is remembered separately from objects and monsters, so can be
 * shown even when the player can't "see" it.  This leads to things like
 * doors out of the player's view still change from closed to open and so on.
 *
 * TODO:
 * Hallucination is currently disabled (it was a display-level hack before,
 * and we need it to be a knowledge-level hack).  The idea is that objects
 * may turn into different objects, monsters into different monsters, and
 * terrain may be objects, monsters, or stay the same.
 */
void map_info(unsigned y, unsigned x, grid_data *g)
{
	object_type *obj;

	assert(x < (unsigned) cave->width);
	assert(y < (unsigned) cave->height);

	/* Default "clear" values, others will be set later where appropriate. */
	g->first_kind = NULL;
	g->trap = NULL;
	g->multiple_objects = FALSE;
	g->lighting = LIGHTING_DARK;
	g->unseen_object = FALSE;
	g->unseen_money = FALSE;

	/* Use real feature (remove later) */
	g->f_idx = cave->squares[y][x].feat;
	if (f_info[g->f_idx].mimic)
		g->f_idx = f_info[g->f_idx].mimic;

	g->in_view = (square_isseen(cave, y, x)) ? TRUE : FALSE;
	g->is_player = (cave->squares[y][x].mon < 0) ? TRUE : FALSE;
	g->m_idx = (g->is_player) ? 0 : cave->squares[y][x].mon;
	g->hallucinate = player->timed[TMD_IMAGE] ? TRUE : FALSE;
	g->trapborder = (square_isdedge(cave, y, x)) ? TRUE : FALSE;

	if (g->in_view) {
		g->lighting = LIGHTING_LOS;

		if (!square_isglow(cave, y, x) && OPT(view_yellow_light))
			g->lighting = LIGHTING_TORCH;

		/* Remember seen feature */
		cave_k->squares[y][x].feat = cave->squares[y][x].feat;
	} else if (!square_ismark(cave, y, x)) {
		g->f_idx = FEAT_NONE;
		//cave_k->squares[y][x].feat = FEAT_NONE;
	} else if (square_isglow(cave, y, x)) {
		g->lighting = LIGHTING_LIT;
	}

	/* Use known feature */
/*	g->f_idx = cave_k->squares[y][x].feat;
	if (f_info[g->f_idx].mimic)
		g->f_idx = f_info[g->f_idx].mimic;*/

    /* There is a trap in this square */
    if (square_istrap(cave, y, x) && square_ismark(cave, y, x)) {
		struct trap *trap = cave->squares[y][x].trap;

		/* Scan the square trap list */
		while (trap) {
			if (trf_has(trap->flags, TRF_TRAP) ||
				trf_has(trap->flags, TRF_RUNE)) {
				/* Accept the trap */
				g->trap = trap;
				break;
			}
			trap = trap->next;
		}
    }

	/* Objects */
	for (obj = square_object(cave, y, x); obj; obj = obj->next) {
		if (obj->marked == MARK_AWARE) {

			/* Distinguish between unseen money and objects */
			if (tval_is_money(obj)) {
				g->unseen_money = TRUE;
			} else {
				g->unseen_object = TRUE;
			}

		} else if (obj->marked == MARK_SEEN && !ignore_item_ok(obj)) {
			if (!g->first_kind) {
				g->first_kind = obj->kind;
			} else {
				g->multiple_objects = TRUE;
				break;
			}
		}
	}

	/* Monsters */
	if (g->m_idx > 0) {
		/* If the monster isn't "visible", make sure we don't list it.*/
		monster_type *m_ptr = cave_monster(cave, g->m_idx);
		if (!mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) g->m_idx = 0;
	}

	/* Rare random hallucination on non-outer walls */
	if (g->hallucinate && g->m_idx == 0 && g->first_kind == 0) {
		if (one_in_(128) && (int) g->f_idx != FEAT_PERM)
			g->m_idx = 1;
		else if (one_in_(128) && (int) g->f_idx != FEAT_PERM)
			/* if hallucinating, we just need first_kind to not be NULL */
			g->first_kind = k_info;
		else
			g->hallucinate = FALSE;
	}

	assert((int) g->f_idx <= FEAT_PASS_RUBBLE);
	if (!g->hallucinate)
		assert((int)g->m_idx < cave->mon_max);
	/* All other g fields are 'flags', mostly booleans. */
}
예제 #23
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;
	}
}
예제 #24
0
파일: obj-pile.c 프로젝트: fizzix/angband
/**
 * Find a grid near the given one for an object to fall on
 *
 * We check several locations to see if we can find a location at which
 * the object can combine, stack, or be placed.  Artifacts will try very
 * hard to be placed, including "teleporting" to a useful grid if needed.
 *
 * If no appropriate grid is found, the given grid is unchanged
 */
static void drop_find_grid(struct object *drop, int *y, int *x)
{
	int best_score = -1;
	int best_y = *y;
	int best_x = *x;
	int i, dy, dx;
	struct object *obj;

	/* Scan local grids */
	for (dy = -3; dy <= 3; dy++) {
		for (dx = -3; dx <= 3; dx++) {
			bool combine = false;
			int dist = (dy * dy) + (dx * dx);
			int ty = *y + dy;
			int tx = *x + dx;
			int num_shown = 0;
			int num_ignored = 0;
			int score;

			/* Lots of reasons to say no */
			if ((dist > 10) ||
				!square_in_bounds_fully(cave, ty, tx) ||
				!los(cave, *y, *x, ty, tx) ||
				!square_isfloor(cave, ty, tx) ||
				square_isplayertrap(cave, ty, tx) ||
				square_iswarded(cave, ty, tx))
				continue;

			/* Analyse the grid for carrying the new object */
			for (obj = square_object(cave, ty, tx); obj; obj = obj->next) {
				/* Check for possible combination */
				if (object_similar(obj, drop, OSTACK_FLOOR))
					combine = true;

				/* Count objects */
				if (!ignore_item_ok(obj))
					num_shown++;
				else
					num_ignored++;
			}
			if (!combine)
				num_shown++;

			/* Disallow if the stack size is too big */
			if ((OPT(player, birth_stacking) && (num_shown > 1)) ||
				((num_shown + num_ignored) > z_info->floor_size &&
				 !floor_get_oldest_ignored(ty, tx)))
				continue;

			/* Score the location based on how close and how full the grid is */
			score = 1000 - (dist + num_shown * 5);

			if ((score < best_score) || ((score == best_score) && one_in_(2)))
				continue;

			best_score = score;
			best_y = ty;
			best_x = tx;
		}
	}

	/* Return if we have a score, otherwise fail or try harder for artifacts */
	if (best_score >= 0) {
		*y = best_y;
		*x = best_x;
		return;
	} else if (!drop->artifact) {
		return;
	}
	for (i = 0; i < 2000; i++) {
		/* Start bouncing from grid to grid, stopping if we find an empty one */
		if (i < 1000) {
			best_y = rand_spread(best_y, 1);
			best_x = rand_spread(best_x, 1);
		} else {
			/* Now go to purely random locations */
			best_y = randint0(cave->height);
			best_x = randint0(cave->width);
		}
		if (square_canputitem(cave, best_y, best_x)) {
			*y = best_y;
			*x = best_x;
			return;
		}
	}
}
예제 #25
0
/**
 * Pick up objects and treasure on the floor.  -LM-
 *
 * Scan the list of objects in that floor grid. Pick up gold automatically.
 * Pick up objects automatically until backpack space is full if
 * auto-pickup option is on, otherwise, store objects on
 * floor in an array, and tally both how many there are and can be picked up.
 *
 * If not picking up anything, indicate objects on the floor.  Do the same
 * thing if we don't have room for anything.
 *
 * Pick up multiple objects using Tim Baker's menu system.   Recursively
 * call this function (forcing menus for any number of objects) until
 * objects are gone, backpack is full, or player is satisfied.
 *
 * We keep track of number of objects picked up to calculate time spent.
 * This tally is incremented even for automatic pickup, so we are careful
 * (in "dungeon.c" and elsewhere) to handle pickup as either a separate
 * automated move or a no-cost part of the stay still or 'g'et command.
 *
 * Note the lack of chance for the character to be disturbed by unmarked
 * objects.  They are truly "unknown".
 *
 * \param obj is the object to pick up.
 * \param menu is whether to present a menu to the player
 */
static byte player_pickup_item(struct object *obj, bool menu)
{
	int py = player->py;
	int px = player->px;

	struct object *current = NULL;

	int floor_max = z_info->floor_size + 1;
	struct object **floor_list = mem_zalloc(floor_max * sizeof(*floor_list));
	int floor_num = 0;

	int i;
	int can_pickup = 0;
	bool call_function_again = FALSE;

	bool domsg = TRUE;

	/* Objects picked up.  Used to determine time cost of command. */
	byte objs_picked_up = 0;

	/* Always pickup gold, effortlessly */
	player_pickup_gold();

	/* Nothing else to pick up -- return */
	if (!square_object(cave, py, px)) {
		mem_free(floor_list);
		return objs_picked_up;
	}

	/* Tally objects that can be picked up.*/
	floor_num = scan_floor(floor_list, floor_max, py, px, 0x08, NULL);
	for (i = 0; i < floor_num; i++)
	    if (inven_carry_okay(floor_list[i]))
			can_pickup++;
	
	if (!can_pickup) {
	    /* Can't pick up, but probably want to know what's there. */
	    event_signal(EVENT_SEEFLOOR);
		mem_free(floor_list);
	    return objs_picked_up;
	}

	/* Use the item that we are given, if it is on the floor. */
	if (square_holds_object(cave, py, px, obj))
		current = obj;

	/* Use a menu interface for multiple objects, or pickup single objects */
	if (!menu && !current) {
		if (floor_num > 1)
			menu = TRUE;
		else
			current = floor_list[0];
	}

	/* Display a list if requested. */
	if (menu && !current) {
		const char *q, *s;
		struct object *obj1;

		/* Get an object or exit. */
		q = "Get which item?";
		s = "You see nothing there.";
		if (!get_item(&obj1, q, s, CMD_PICKUP, inven_carry_okay, USE_FLOOR)) {
			mem_free(floor_list);
			return (objs_picked_up);
		}

		current = obj1;
		call_function_again = TRUE;

		/* With a list, we do not need explicit pickup messages */
		domsg = FALSE;
	}

	/* Pick up object, if legal */
	if (current) {
		/* Pick up the object */
		player_pickup_aux(current, domsg);

		/* Indicate an object picked up. */
		objs_picked_up = 1;
	}

	/*
	 * If requested, call this function recursively.  Count objects picked
	 * up.  Force the display of a menu in all cases.
	 */
	if (call_function_again)
		objs_picked_up += player_pickup_item(NULL, TRUE);

	mem_free(floor_list);

	/* Indicate how many objects have been picked up. */
	return (objs_picked_up);
}
예제 #26
0
/**
 * Pick up all gold at the player's current location.
 */
static void player_pickup_gold(void)
{
	s32b total_gold = 0L;
	char name[30] = "";

	struct object *obj = square_object(cave, player->py, player->px), *next;

	int sound_msg;
	bool verbal = FALSE;
	bool at_most_one = TRUE;

	/* Pick up all the ordinary gold objects */
	while (obj) {
		struct object_kind *kind = NULL;

		/* Get next object */
		next = obj->next;

		/* Ignore if not legal treasure */
		kind = lookup_kind(obj->tval, obj->sval);
		if (!tval_is_money(obj) || !kind) {
			obj = next;
			continue;
		}

		/* Multiple types if we have a second name, otherwise record the name */
		if (total_gold && !streq(kind->name, name))
			at_most_one = FALSE;
		else
			my_strcpy(name, kind->name, sizeof(name));

		/* Remember whether feedback message is in order */
		if (!ignore_item_ok(obj))
			verbal = TRUE;

		/* Increment total value */
		total_gold += (s32b)obj->pval;

		/* Delete the gold */
		square_excise_object(cave, player->py, player->px, obj);
		object_delete(obj);
		obj = next;
	}

	/* Pick up the gold, if present */
	if (total_gold) {
		char buf[100];

		/* Build a message */
		(void)strnfmt(buf, sizeof(buf),
					  "You have found %ld gold pieces worth of ",
					  (long)total_gold);

		/* One treasure type.. */
		if (at_most_one)
			my_strcat(buf, name, sizeof(buf));
		/* ... or more */
		else
			my_strcat(buf, "treasures", sizeof(buf));
		my_strcat(buf, ".", sizeof(buf));

		/* Determine which sound to play */
		if      (total_gold < 200) sound_msg = MSG_MONEY1;
		else if (total_gold < 600) sound_msg = MSG_MONEY2;
		else                       sound_msg = MSG_MONEY3;

		/* Display the message */
		if (verbal)
			msgt(sound_msg, "%s", buf);

		/* Add gold to purse */
		player->au += total_gold;

		/* Redraw gold */
		player->upkeep->redraw |= (PR_GOLD);
	}
}
예제 #27
0
/**
 * Excise an entire floor pile.
 */
void square_excise_pile(struct chunk *c, int y, int x) {
	object_pile_free(square_object(c, y, x));
	c->squares[y][x].obj = NULL;
}
예제 #28
0
/**
 * True if the square is empty (an open square without any items).
 */
bool square_isempty(struct chunk *c, int y, int x) {
	return square_isopen(c, y, x) && !square_object(c, y, x);
}
예제 #29
0
/**
 * Called from project() to affect objects
 *
 * Called for projections with the PROJECT_ITEM flag set, which includes
 * beam, ball and breath effects.
 *
 * \param who is the monster list index of the caster
 * \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 (GF_) type
 * \param protected_obj is an object that should not be affected by the 
 *        projection, typically the object that created it
 * \return whether the effects were obvious
 *
 * Note that this function determines if the player can see anything that
 * happens by taking into account: blindness, line-of-sight, and illumination.
 *
 * Hack -- effects on objects which are memorized but not in view are also seen.
 */
bool project_o(int who, int r, int y, int x, int dam, int typ,
			   const struct object *protected_obj)
{
	struct object *obj = square_object(cave, y, x);
	bool obvious = false;

	/* Scan all objects in the grid */
	while (obj) {
		bool ignore = false;
		bool do_kill = false;
		const char *note_kill = NULL;
		struct object *next = obj->next;
		project_object_handler_context_t context = {
			who,
			r,
			y,
			x,
			dam,
			typ,
			obj,
			obvious,
			do_kill,
			ignore,
			note_kill,
		};
		project_object_handler_f object_handler = object_handlers[typ];

		if (object_handler != NULL)
			object_handler(&context);

		obvious = context.obvious;
		do_kill = context.do_kill && (obj != protected_obj);
		ignore = context.ignore;
		note_kill = context.note_kill;

		/* Attempt to destroy the object */
		if (do_kill) {
			char o_name[80];

			/* Effect observed */
			if (obj->known && !ignore_item_ok(obj) &&
				square_isseen(cave, y, x)) {
				obvious = true;
				object_desc(o_name, sizeof(o_name), obj, ODESC_BASE);
			}

			/* Artifacts, and other objects, get to resist */
			if (obj->artifact || ignore) {
				/* Observe the resist */
				if (obvious && obj->known && !ignore_item_ok(obj))
					msg("The %s %s unaffected!", o_name,
						VERB_AGREEMENT(obj->number, "is", "are"));
			} else if (obj->mimicking_m_idx) {
				/* Reveal mimics */
				if (obvious)
					become_aware(cave_monster(cave, obj->mimicking_m_idx));
			} else {
				/* Describe if needed */
				if (obvious && obj->known && note_kill && !ignore_item_ok(obj))
					msgt(MSG_DESTROY, "The %s %s!", o_name, note_kill);

				/* Delete the object */
				square_excise_object(cave, y, x, obj);
				delist_object(cave, obj);
				object_delete(&obj);

				/* Redraw */
				square_note_spot(cave, y, x);
				square_light_spot(cave, y, x);
			}
		}

		/* Next object */
		obj = next;
	}

	/* Return "Anything seen?" */
	return (obvious);
}
예제 #30
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;
}