Beispiel #1
0
/**
 * Remove an amount of an object from the floor, returning a detached object
 * which can be used - it is assumed that the object is on the player grid.
 *
 * Optionally describe what remains.
 */
struct object *floor_object_for_use(struct object *obj, int num, bool message,
									bool *none_left)
{
	struct object *usable;
	char name[80];

	/* Bounds check */
	num = MIN(num, obj->number);

	/* Split off a usable object if necessary */
	if (obj->number > num) {
		usable = object_split(obj, num);
	} else {
		usable = obj;
		square_excise_object(player->cave, usable->iy, usable->ix,
							 usable->known);
		delist_object(player->cave, usable->known);
		square_excise_object(cave, usable->iy, usable->ix, usable);
		delist_object(cave, usable);
		*none_left = true;

		/* Stop tracking item */
		if (tracked_object_is(player->upkeep, obj))
			track_object(player->upkeep, NULL);

		/* Inventory has changed, so disable repeat command */ 
		cmd_disable_repeat();
	}

	/* Object no longer has a location */
	usable->known->iy = 0;
	usable->known->ix = 0;
	usable->iy = 0;
	usable->ix = 0;

	/* Housekeeping */
	player->upkeep->update |= (PU_BONUS | PU_INVEN);
	player->upkeep->notice |= (PN_COMBINE);
	player->upkeep->redraw |= (PR_INVEN | PR_EQUIP);

	/* Print a message if requested and there is anything left */
	if (message) {
		if (usable == obj)
			obj->number = 0;

		/* Get a description */
		object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL);

		if (usable == obj)
			obj->number = num;

		/* Print a message */
		msg("You see %s.", name);
	}

	return usable;
}
Beispiel #2
0
/**
 * Let the floor carry an object, deleting old ignored items if necessary.
 * The calling function must deal with the dropped object on failure.
 *
 * Optionally put the object at the top or bottom of the pile
 */
bool floor_carry(struct chunk *c, int y, int x, struct object *drop, bool last)
{
	int n = 0;
	struct object *obj, *ignore = floor_get_oldest_ignored(y, x);

	/* Fail if the square can't hold objects */
	if (!square_isobjectholding(c, y, x))
		return false;

	/* Scan objects in that grid for combination */
	for (obj = square_object(c, y, x); obj; obj = obj->next) {
		/* Check for combination */
		if (object_similar(obj, drop, OSTACK_FLOOR)) {
			/* Combine the items */
			object_absorb(obj, drop);

			/* Result */
			return true;
		}

		/* Count objects */
		n++;
	}

	/* The stack is already too large */
	if (n >= z_info->floor_size || (!OPT(player, birth_stacking) && n)) {
		/* Delete the oldest ignored object */
		if (ignore) {
			square_excise_object(c, y, x, ignore);
			delist_object(c, ignore);
			object_delete(&ignore);
		} else
			return false;
	}

	/* Location */
	drop->iy = y;
	drop->ix = x;

	/* Forget monster */
	drop->held_m_idx = 0;

	/* Link to the first or last object in the pile */
	if (last)
		pile_insert_end(&c->squares[y][x].obj, drop);
	else
		pile_insert(&c->squares[y][x].obj, drop);

	/* Record in the level list */
	list_object(c, drop);

	/* Redraw */
	square_note_spot(c, y, x);
	square_light_spot(c, y, x);

	/* Result */
	return true;
}
Beispiel #3
0
/**
 * Delete an object when the floor fails to carry it, and attempt to remove
 * it from the object list
 */
static void floor_carry_fail(struct object *drop, bool broke)
{
	struct object *known = drop->known;

	/* Delete completely */
	if (known) {
		char o_name[80];
		char *verb = broke ? VERB_AGREEMENT(drop->number, "breaks", "break")
			: VERB_AGREEMENT(drop->number, "disappears", "disappear");
		object_desc(o_name, sizeof(o_name), drop, ODESC_BASE);
		msg("The %s %s.", o_name, verb);
		if (known->iy && known->ix)
			square_excise_object(player->cave, known->iy, known->ix, known);
		delist_object(player->cave, known);
		object_delete(&known);
	}
	delist_object(cave, drop);
	object_delete(&drop);
}
Beispiel #4
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;
	}
}
Beispiel #5
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);
				delist_object(cave, obj);
				object_delete(&obj);
			}
		}
	}
}
Beispiel #6
0
/* 
 * A rewrite of monster death that gets rid of some features
 * That we don't want to deal with.  Namely, no notifying the
 * player and no generation of Morgoth artifacts
 * 
 * It also replaces drop near with a new function that drops all 
 * the items on the exact square that the monster was on.
 */
void monster_death_stats(int m_idx)
{
	struct object *obj;
	struct monster *mon;
	bool uniq;

	assert(m_idx > 0);
	mon = cave_monster(cave, m_idx);

	/* Check if monster is UNIQUE */
	uniq = rf_has(mon->race->flags,RF_UNIQUE);

	/* Mimicked objects will have already been counted as floor objects */
	mon->mimicked_obj = NULL;

	/* Drop objects being carried */
	obj = mon->held_obj;
	while (obj) {
		struct object *next = obj->next;

		/* Object no longer held */
		obj->held_m_idx = 0;

		/* Get data */
		get_obj_data(obj, mon->fy, mon->fx, true, uniq);

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

		/* Next */
		obj = next;
	}

	/* Forget objects */
	mon->held_obj = NULL;
}
Beispiel #7
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);
}
Beispiel #8
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;
	}
}
Beispiel #9
0
/**
 * Deletes a monster by index.
 *
 * When a monster is deleted, all of its objects are deleted.
 */
void delete_monster_idx(int m_idx)
{
	assert(m_idx > 0);

	struct monster *mon = cave_monster(cave, m_idx);

	int y = mon->fy;
	int x = mon->fx;
	assert(square_in_bounds(cave, y, x));

	/* Hack -- Reduce the racial counter */
	mon->race->cur_num--;

	/* Hack -- count the number of "reproducers" */
	if (rf_has(mon->race->flags, RF_MULTIPLY))
		num_repro--;

	/* Hack -- remove target monster */
	if (target_get_monster() == mon)
		target_set_monster(NULL);

	/* Hack -- remove tracked monster */
	if (player->upkeep->health_who == mon)
		health_track(player->upkeep, NULL);

	/* Monster is gone */
	cave->squares[y][x].mon = 0;

	/* Delete objects */
	struct object *obj = mon->held_obj;
	while (obj) {
		struct object *next = obj->next;

		/* Preserve unseen artifacts (we assume they were created as this
		 * monster's drop) - this will cause unintended behaviour in preserve
		 * off mode if monsters can pick up artifacts */
		if (obj->artifact && !(obj->known && obj->known->artifact))
			obj->artifact->created = false;

		/* Delete the object */
		delist_object(cave, obj);
		object_delete(&obj);
		obj = next;
	}

	/* Delete mimicked objects */
	if (mon->mimicked_obj) {
		square_excise_object(cave, y, x, mon->mimicked_obj);
		delist_object(cave, mon->mimicked_obj);
		object_delete(&mon->mimicked_obj);
	}

	/* Wipe the Monster */
	memset(mon, 0, sizeof(struct monster));

	/* Count monsters */
	cave->mon_cnt--;

	/* Visual update */
	square_light_spot(cave, y, x);
}
Beispiel #10
0
/**
 * Let an object fall to the ground at or near a location.
 *
 * The initial location is assumed to be "square_in_bounds_fully(cave, )".
 *
 * This function takes a parameter "chance".  This is the percentage
 * chance that the item will "disappear" instead of drop.  If the object
 * has been thrown, then this is the chance of disappearance on contact.
 *
 * This function will produce a description of a drop event under the player
 * when "verbose" is true.
 *
 * 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.
 *
 * Objects which fail to be carried by the floor are deleted.  This function
 * attempts to add successfully dropped objects to, and to remove failures
 * from, the object list (as dropped items may or may not be already listed).
 */
void drop_near(struct chunk *c, struct object *dropped, int chance, int y,
			   int x, bool verbose)
{
	int i, k, n, d, s;

	int bs, bn;
	int by, bx;
	int dy, dx;
	int ty, tx;

	struct object *obj;

	char o_name[80];

	bool flag = false;

	/* Only called in the current level */
	assert(c == cave);

	/* Describe object */
	object_desc(o_name, sizeof(o_name), dropped, ODESC_BASE);

	/* Handle normal "breakage" */
	if (!dropped->artifact && (randint0(100) < chance)) {
		/* Message */
		msg("The %s %s.", o_name,
			VERB_AGREEMENT(dropped->number, "breaks", "break"));

		/* Failure */
		if (dropped->known) {
			delist_object(cave_k, dropped->known);
			object_delete(&dropped->known);
		}
		delist_object(c, dropped);
		object_delete(&dropped);
		return;
	}

	/* Score */
	bs = -1;

	/* Picker */
	bn = 0;

	/* Default */
	by = y;
	bx = x;

	/* Scan local grids */
	for (dy = -3; dy <= 3; dy++) {
		for (dx = -3; dx <= 3; dx++) {
			bool comb = false;

			/* Calculate actual distance */
			d = (dy * dy) + (dx * dx);

			/* Ignore distant grids */
			if (d > 10) continue;

			/* Location */
			ty = y + dy;
			tx = x + dx;

			/* Skip illegal grids */
			if (!square_in_bounds_fully(c, ty, tx)) continue;

			/* Require line of sight */
			if (!los(c, y, x, ty, tx)) continue;

			/* Require floor space */
			if (!square_isfloor(c, ty, tx)) continue;

			/* Require no trap or rune */
			if (square_isplayertrap(c, ty, tx) ||
				square_iswarded(c, ty, tx))
				continue;

			/* No objects */
			k = 0;
			n = 0;

			/* Scan objects in that grid */
			for (obj = square_object(c, ty, tx); obj; obj = obj->next) {
				/* Check for possible combination */
				if (object_similar(obj, dropped, OSTACK_FLOOR))
					comb = true;

				/* Count objects */
				if (!ignore_item_ok(obj))
					k++;
				else
					n++;
			}

			/* Add new object */
			if (!comb) k++;

			/* Option -- disallow stacking */
			if (OPT(birth_no_stacking) && (k > 1)) continue;

			/* Paranoia? */
			if ((k + n) > z_info->floor_size &&
				!floor_get_oldest_ignored(ty, tx)) continue;

			/* Calculate score */
			s = 1000 - (d + k * 5);

			/* Skip bad values */
			if (s < bs) continue;

			/* New best value */
			if (s > bs) bn = 0;

			/* Apply the randomizer to equivalent values */
			if ((++bn >= 2) && (randint0(bn) != 0)) continue;

			/* Keep score */
			bs = s;

			/* Track it */
			by = ty;
			bx = tx;

			/* Okay */
			flag = true;
		}
	}

	/* Handle lack of space */
	if (!flag && !dropped->artifact) {
		/* Message */
		msg("The %s %s.", o_name,
			VERB_AGREEMENT(dropped->number, "disappears", "disappear"));

		/* Debug */
		if (player->wizard) msg("Breakage (no floor space).");

		/* Failure */
		if (dropped->known) {
			delist_object(cave_k, dropped->known);
			object_delete(&dropped->known);
		}
		delist_object(c, dropped);
		object_delete(&dropped);
		return;
	}

	/* Find a grid */
	for (i = 0; !flag; i++) {
		/* Bounce around */
		if (i < 1000) {
			ty = rand_spread(by, 1);
			tx = rand_spread(bx, 1);
		} else {
			/* Random locations */
			ty = randint0(c->height);
			tx = randint0(c->width);
		}

		/* Require floor space */
		if (!square_canputitem(c, ty, tx)) continue;

		/* Bounce to that location */
		by = ty;
		bx = tx;

		/* Okay */
		flag = true;
	}

	/* Give it to the floor */
	if (!floor_carry(c, by, bx, dropped, false)) {
		/* Message */
		msg("The %s %s.", o_name,
			VERB_AGREEMENT(dropped->number, "disappears", "disappear"));

		/* Debug */
		if (player->wizard) msg("Breakage (too many objects).");

		if (dropped->artifact) dropped->artifact->created = false;

		/* Failure */
		if (dropped->known) {
			delist_object(cave_k, dropped->known);
			object_delete(&dropped->known);
		}
		delist_object(c, dropped);
		object_delete(&dropped);
		return;
	}

	/* Sound */
	sound(MSG_DROP);

	/* Message when an object falls under the player */
	if (verbose && (c->squares[by][bx].mon < 0))
		/* Check the item still exists and isn't ignored */
		if (c->objects[dropped->oidx] && !ignore_item_ok(dropped))
			msg("You feel something roll beneath your feet.");
}
Beispiel #11
0
/**
 * Update the player's knowledge of the objects on a grid in the current level
 */
void floor_pile_know(struct chunk *c, int y, int x)
{
	struct object *obj;

	if (c != cave) return;

	object_lists_check_integrity();

	/* Know every item on this grid */
	for (obj = square_object(c, y, x); obj; obj = obj->next) {
		struct object *known_obj = cave_k->objects[obj->oidx];

		/* Make new known objects, fully know sensed ones, relocate old ones */
		if (known_obj == NULL) {
			/* Make and/or list the new object */
			struct object *new_obj;

			/* Check whether we need to make a new one or list the old one */
			if (obj->known) {
				new_obj = obj->known;
			} else {
				new_obj = object_new();
				obj->known = new_obj;
				object_set_base_known(obj);
			}
			cave_k->objects[obj->oidx] = new_obj;
			new_obj->oidx = obj->oidx;

			/* Attach it to the current floor pile */
			new_obj->iy = y;
			new_obj->ix = x;
			new_obj->number = obj->number;
			if (!square_holds_object(cave_k, y, x, new_obj))
				pile_insert_end(&cave_k->squares[y][x].obj, new_obj);
		} else if (known_obj->kind != obj->kind) {
			int iy = known_obj->iy;
			int ix = known_obj->ix;

			/* Make sure knowledge is correct */
			assert(known_obj == obj->known);

			/* Detach from any old pile (possibly the correct one) */
			if (iy && ix && square_holds_object(cave_k, iy, ix, known_obj))
				square_excise_object(cave_k, iy, ix, known_obj);

			/* Copy over actual details */
			object_set_base_known(obj);

			/* Attach it to the current floor pile */
			known_obj->iy = y;
			known_obj->ix = x;
			known_obj->held_m_idx = 0;
			if (!square_holds_object(cave_k, y, x, known_obj))
				pile_insert_end(&cave_k->squares[y][x].obj, known_obj);
		} else if (!square_holds_object(cave_k, y, x, known_obj)) {
			int iy = known_obj->iy;
			int ix = known_obj->ix;

			/* Make sure knowledge is correct */
			assert(known_obj == obj->known);
			known_obj->number = obj->number;

			/* Detach from any old pile */
			if (iy && ix && square_holds_object(cave_k, iy, ix, known_obj))
				square_excise_object(cave_k, iy, ix, known_obj);

			/* Attach it to the current floor pile */
			known_obj->iy = y;
			known_obj->ix = x;
			known_obj->held_m_idx = 0;
			pile_insert_end(&cave_k->squares[y][x].obj, known_obj);
		}
	}

	/* Remove known location of anything not on this grid */
	obj = square_object(cave_k, 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(cave_k, y, x, obj);
			obj->iy = 0;
			obj->ix = 0;

			/* Delete objects which no longer exist anywhere */
			if (obj->notice & OBJ_NOTICE_IMAGINED) {
				delist_object(cave_k, obj);
				object_delete(&obj);
				original->known = NULL;
				delist_object(c, original);
				object_delete(&original);
			}
		}
		obj = next;
	}
}