Esempio n. 1
0
/**
 * Calculate the number of pack slots used by the current gear.
 *
 * Note that this function does not check that there are adequate slots in the
 * quiver, just the total quantity of missiles.
 */
int pack_slots_used(struct player *p)
{
	struct object *obj;
	int quiver_slots = 0, pack_slots = 0, quiver_ammo = 0;
	int maxsize = z_info->stack_size;

	for (obj = p->gear; obj; obj = obj->next) {
		/* Equipment doesn't count */
		if (object_is_equipped(p->body, obj)) continue;

		/* Check if it could be in the quiver */
		if (tval_is_ammo(obj))
			if (quiver_slots < z_info->quiver_size) {
				quiver_slots++;
				quiver_ammo += obj->number;
				continue;
			}

		/* Count regular slots */
		pack_slots++;
	}

	/* Full slots */
	pack_slots += quiver_ammo / maxsize;

	/* Plus one for any remainder */
	if (quiver_ammo % maxsize) pack_slots++;

	return pack_slots;
}
Esempio n. 2
0
/**
 * Check to see if an item is stackable in the inventory
 */
bool inven_stack_okay(const object_type *o_ptr)
{
	struct object *gear_obj;
	int new_number;
	bool extra_slot;

	/* Check for similarity */
	for (gear_obj = player->gear; gear_obj; gear_obj = gear_obj->next) {
		/* Skip equipped items and non-objects */
		if (object_is_equipped(player->body, gear_obj))
			continue;
		if (!gear_obj)
			continue;

		/* Check if the two items can be combined */
		if (object_similar(gear_obj, o_ptr, OSTACK_PACK))
			break;
	}

	/* Definite no */
	if (!gear_obj) return FALSE;

	/* Add it and see what happens */
	gear_obj->number += o_ptr->number;
	extra_slot = (gear_obj->number > z_info->stack_size);
	new_number = pack_slots_used(player);
	gear_obj->number -= o_ptr->number;

	/* Analyse the results */
	if (new_number + (extra_slot ? 1 : 0) > z_info->pack_size)
		return FALSE;

	return TRUE;
}
Esempio n. 3
0
/**
 * Convert a gear object into a one character label.
 */
char gear_to_label(struct object *obj)
{
	int i;

	/* Equipment is easy */
	if (object_is_equipped(player->body, obj)) {
		return I2A(equipped_item_slot(player->body, obj));
	}

	/* Check the quiver */
	for (i = 0; i < z_info->quiver_size; i++) {
		if (player->upkeep->quiver[i] == obj) {
			return I2D(i);
		}
	}

	/* Check the inventory */
	for (i = 0; i < z_info->pack_size; i++) {
		if (player->upkeep->inven[i] == obj) {
			return I2A(i);
		}
	}

	return '\0';
}
Esempio n. 4
0
/**
 * Calculate the number of pack slots used by the current gear.
 *
 * Note that this function does not check that there are adequate slots in the
 * quiver, just the total quantity of missiles.
 */
int pack_slots_used(struct player *p)
{
	struct object *obj;
	int quiver_slots = 0;
	int pack_slots = 0;
	int quiver_ammo = 0;

	for (obj = p->gear; obj; obj = obj->next) {
		/* Equipment doesn't count */
		if (!object_is_equipped(p->body, obj)) {
			/* Check if it could be in the quiver */
			if (tval_is_ammo(obj) && quiver_slots < z_info->quiver_size) {
				quiver_slots++;
				quiver_ammo += obj->number;
			} else {
				/* Count regular slots */
				pack_slots++;
			}
		}
	}

	/* Full slots */
	pack_slots += quiver_ammo / z_info->quiver_slot_size;

	/* Plus one for any remainder */
	if (quiver_ammo % z_info->quiver_slot_size) {
		pack_slots++;
	}

	return pack_slots;
}
Esempio n. 5
0
/**
 * Recharge activatable objects in the player's equipment
 * and rods in the inventory and on the ground.
 */
static void recharge_objects(void)
{
	int i;
	bool discharged_stack;
	struct object *obj;

	/* Recharge carried gear */
	for (obj = player->gear; obj; obj = obj->next) {
		/* Skip non-objects */
		assert(obj->kind);

		/* Recharge equipment */
		if (object_is_equipped(player->body, obj)) {
			/* Recharge activatable objects */
			if (recharge_timeout(obj)) {
				/* Message if an item recharged */
				recharged_notice(obj, true);

				/* Window stuff */
				player->upkeep->redraw |= (PR_EQUIP);
			}
		} else {
			/* Recharge the inventory */
			discharged_stack =
				(number_charging(obj) == obj->number) ? true : false;

			/* Recharge rods, and update if any rods are recharged */
			if (tval_can_have_timeout(obj) && recharge_timeout(obj)) {
				/* Entire stack is recharged */
				if (obj->timeout == 0)
					recharged_notice(obj, true);

				/* Previously exhausted stack has acquired a charge */
				else if (discharged_stack)
					recharged_notice(obj, false);

				/* Combine pack */
				player->upkeep->notice |= (PN_COMBINE);

				/* Redraw stuff */
				player->upkeep->redraw |= (PR_INVEN);
			}
		}
	}

	/* Recharge other level objects */
	for (i = 1; i < cave->obj_max; i++) {
		obj = cave->objects[i];
		if (!obj) continue;

		/* Recharge rods */
		if (tval_can_have_timeout(obj))
			recharge_timeout(obj);
	}
}
Esempio n. 6
0
/**
 * Drop all {ignore}able items.
 */
void ignore_drop(void)
{
	struct object *obj;

	/* Scan through the slots backwards */
	for (obj = gear_last_item(); obj; obj = obj->prev) {
		/* Skip non-objects and unignoreable objects */
		assert(obj->kind);
		if (!ignore_item_ok(obj)) continue;

		/* Check for !d (no drop) inscription */
		if (!check_for_inscrip(obj, "!d") && !check_for_inscrip(obj, "!*")) {
			/* Confirm the drop if the item is equipped. */
			if (object_is_equipped(player->body, obj)) {
				if (!verify_object("Really take off and drop", obj)) {
					/* Hack - inscribe the item with !d to prevent repeated
					 * confirmations. */
					const char *inscription = quark_str(obj->note);

					if (inscription == NULL) {
						obj->note = quark_add("!d");
					} else {
						char buffer[1024];
						my_strcpy(buffer, inscription, sizeof(buffer));
						my_strcat(buffer, "!d", sizeof(buffer));
						obj->note = quark_add(buffer);
					}

					continue;
				}
			}

			/* We're allowed to drop it. */
			if (!square_isshop(cave, player->py, player->px)) {
				player->upkeep->dropping = true;
				cmdq_push(CMD_DROP);
				cmd_set_arg_item(cmdq_peek(), "item", obj);
				cmd_set_arg_number(cmdq_peek(), "quantity", obj->number);
			}
		}
	}

	/* Update the gear */
	player->upkeep->update |= (PU_INVEN);

	/* Combine/reorder the pack */
	player->upkeep->notice |= (PN_COMBINE);
}
Esempio n. 7
0
/**
 * Drop (some of) a non-cursed inventory/equipment item "near" the current
 * location
 *
 * There are two cases here - a single object or entire stack is being dropped,
 * or part of a stack is being split off and dropped
 */
void inven_drop(struct object *obj, int amt)
{
	int py = player->py;
	int px = player->px;
	struct object *dropped;

	char o_name[80];
	char label;

	/* Error check */
	if (amt <= 0)
		return;

	/* Check it is still held, in case there were two drop commands queued
	 * for this item.  This is in theory not ideal, but in practice should
	 * be safe. */
	if (!pile_contains(player->gear, obj))
		return;

	/* Get where the object is now */
	label = gear_to_label(obj);

	/* Not too many */
	if (amt > obj->number) amt = obj->number;

	/* Take off equipment */
	if (object_is_equipped(player->body, obj))
		inven_takeoff(obj);

	/* Get the object */
	dropped = gear_object_for_use(obj, amt, TRUE);

	/* Describe the dropped object */
	object_desc(o_name, sizeof(o_name), dropped, ODESC_PREFIX | ODESC_FULL);

	/* Message */
	msg("You drop %s (%c).", o_name, label);

	/* Drop it near the player */
	drop_near(cave, dropped, 0, py, px, FALSE);

	event_signal(EVENT_INVENTORY);
	event_signal(EVENT_EQUIPMENT);
}
Esempio n. 8
0
/**
 * Drop (some of) a non-cursed inventory/equipment item "near" the current
 * location
 *
 * There are two cases here - a single object or entire stack is being dropped,
 * or part of a stack is being split off and dropped
 */
void inven_drop(struct object *obj, int amt)
{
	int py = player->py;
	int px = player->px;
	struct object *dropped;

	char o_name[80];

	/* Error check */
	if (amt <= 0)
		return;

	/* This should not happen - ask for report */
	if (!pile_contains(player->gear, obj)) {
		/* Describe the dropped object */
		object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);

		msg("Bug - attempt to drop %s when not held!", o_name);
		return;
	}

	/* Not too many */
	if (amt > obj->number) amt = obj->number;

	/* Take off equipment */
	if (object_is_equipped(player->body, obj))
		inven_takeoff(obj);

	/* Get the object */
	dropped = gear_object_for_use(obj, amt, TRUE);

	/* Describe the dropped object */
	object_desc(o_name, sizeof(o_name), dropped, ODESC_PREFIX | ODESC_FULL);

	/* Message */
	msg("You drop %s (%c).", o_name, gear_to_label(obj));

	/* Drop it near the player */
	drop_near(cave, dropped, 0, py, px, FALSE);

	event_signal(EVENT_INVENTORY);
}
Esempio n. 9
0
/**
 * Calculate how much of an item is can be carried in the inventory or quiver.
 *
 * Optionally only return a positive value if there is already a similar object.
 */
int inven_carry_num(const struct object *obj, bool stack)
{
	struct object *gear_obj;
	int i, num_left = obj->number;

	/* Check for similarity */
	if (stack) {
		for (gear_obj = player->gear; gear_obj; gear_obj = gear_obj->next) {
			/* Skip equipped items and non-objects */
			if (object_is_equipped(player->body, gear_obj))
				continue;
			if (!gear_obj)
				continue;

			/* Check if the two items can be combined */
			if (object_stackable(gear_obj, obj, OSTACK_PACK))
				break;
		}

		/* No similar object, so no stacking */
		if (!gear_obj) return 0;
	}

	/* Free inventory slots, so there is definitely room */
	if (pack_slots_used(player) < z_info->pack_size) return obj->number;

	/* Absorb as many as we can in the quiver */
	num_left -= quiver_absorb_num(obj);

	/* See if we can add to a part full inventory slot */
	for (i = 0; i < z_info->pack_size; i++) {
		struct object *inven_obj = player->upkeep->inven[i];
		if (!inven_obj) continue;
		if (!object_stackable(inven_obj, obj, OSTACK_PACK)) continue;
		num_left -= z_info->stack_size - inven_obj->number;
	}

	/* Return the number we can absorb */
	num_left = MAX(num_left, 0);
	return obj->number - num_left;
}
Esempio n. 10
0
/**
 * Calculate how much of an item is can be carried in the inventory or quiver.
 *
 * Optionally only return a positive value if there is already a similar object.
 */
int inven_carry_num(const struct object *obj, bool stack)
{
	/* Check for similarity */
	if (stack) {
		struct object *gear_obj;

		for (gear_obj = player->gear; gear_obj; gear_obj = gear_obj->next) {
			if (!object_is_equipped(player->body, gear_obj) &&
					object_stackable(gear_obj, obj, OSTACK_PACK)) {
				break;
			}
		}

		/* No similar object, so no stacking */
		if (!gear_obj) {
			return 0;
		}
	}

	/* Free inventory slots, so there is definitely room */
	if (pack_slots_used(player) < z_info->pack_size) {
		return obj->number;
	} else {
		int i;

		/* Absorb as many as we can in the quiver */
		int num_left = obj->number - quiver_absorb_num(obj);

		/* See if we can add to a part full inventory slot */
		for (i = 0; i < z_info->pack_size; i++) {
			struct object *inven_obj = player->upkeep->inven[i];
			if (inven_obj && object_stackable(inven_obj, obj, OSTACK_PACK)) {
				num_left -= inven_obj->kind->base->max_stack - inven_obj->number;
			}
		}

		/* Return the number we can absorb */
		return obj->number - MAX(num_left, 0);
	}
}
Esempio n. 11
0
/**
 * Throw an object from the quiver, pack or floor.
 */
void do_cmd_throw(struct command *cmd) {
	int dir;
	int shots = 1;
	int str = adj_str_blow[player->state.stat_ind[STAT_STR]];
	ranged_attack attack = make_ranged_throw;

	int weight;
	int range;
	struct object *obj;

	/* Get arguments */
	if (cmd_get_item(cmd, "item", &obj,
			/* Prompt */ "Throw which item?",
			/* Error  */ "You have nothing to throw.",
			/* Filter */ NULL,
			/* Choice */ USE_QUIVER | USE_INVEN | USE_FLOOR | QUIVER_TAGS)
		!= CMD_OK)
		return;

	if (cmd_get_target(cmd, "target", &dir) == CMD_OK)
		player_confuse_dir(player, &dir, FALSE);
	else
		return;


	weight = MAX(obj->weight, 10);
	range = MIN(((str + 20) * 10) / weight, 10);

	/* Make sure the player isn't throwing wielded items */
	if (object_is_equipped(player->body, obj)) {
		msg("You have cannot throw wielded items.");
		return;
	}

	ranged_helper(obj, dir, range, shots, attack);
}
Esempio n. 12
0
/**
 * Destroys a type of item on a given percent chance.
 * The chance 'cperc' is in hundredths of a percent (1-in-10000)
 * Note that missiles are no longer necessarily all destroyed
 *
 * Returns number of items destroyed.
 */
int inven_damage(struct player *p, int type, int cperc)
{
	int j, k, amt;
	struct object *obj = p->gear;
	char o_name[80];
	bool damage;

	/* No chance means no damage */
	if (cperc <= 0)
		return 0;

	/* Count the casualties */
	k = 0;

	/* Scan through the gear */
	while (obj) {
		struct object *next = obj->next;
		if (object_is_equipped(p->body, obj)) {
			obj = next;
			continue;
		}

		/* Hack -- for now, skip artifacts */
		if (obj->artifact) {
			obj = next;
			continue;
		}

		/* Give this item slot a shot at death if it is vulnerable */
		if ((obj->el_info[type].flags & EL_INFO_HATES) &&
			!(obj->el_info[type].flags & EL_INFO_IGNORE)) {
			/* Chance to destroy this item */
			int chance = cperc;

			/* Track if it is damaged instead of destroyed */
			damage = false;

			/* Analyze the type to see if we just damage it
			 * - we also check for rods to reduce chance */
			if (tval_is_weapon(obj) && !tval_is_ammo(obj)) {
				/* Chance to damage it */
				if (randint0(10000) < cperc) {
					/* Damage the item */
					obj->to_h--;
					if (p->obj_k->to_h)
						obj->known->to_h = obj->to_h;
					obj->to_d--;
					if (p->obj_k->to_d)
						obj->known->to_d = obj->to_d;

					/* Damaged! */
					damage = true;
				} else {
					obj = next;
					continue;
				}
			} else if (tval_is_armor(obj)) {
				/* Chance to damage it */
				if (randint0(10000) < cperc) {
					/* Damage the item */
					obj->to_a--;
					if (p->obj_k->to_a)
						obj->known->to_a = obj->to_a;

					/* Damaged! */
					damage = true;
				} else {
					obj = next;
					continue;
				}
			} else if (tval_is_rod(obj)) {
				chance = (chance / 4);
			}


			/* Damage instead of destroy */
			if (damage) {
				p->upkeep->update |= (PU_BONUS);
				p->upkeep->redraw |= (PR_EQUIP);

				/* Casualty count */
				amt = obj->number;
			} else
				/* ... or count the casualties */
				for (amt = j = 0; j < obj->number; ++j)
					if (randint0(10000) < chance) amt++;

			/* Some casualities */
			if (amt) {
				struct object *destroyed;
				bool none_left = false;

				/* Get a description */
				object_desc(o_name, sizeof(o_name), obj, ODESC_BASE);

				/* Message */
				msgt(MSG_DESTROY, "%sour %s (%c) %s %s!",
				           ((obj->number > 1) ?
				            ((amt == obj->number) ? "All of y" :
				             (amt > 1 ? "Some of y" : "One of y")) : "Y"),
				           o_name, gear_to_label(obj),
				           ((amt > 1) ? "were" : "was"),
					   (damage ? "damaged" : "destroyed"));

				/* Damage already done? */
				if (damage)
					continue;

				/* Destroy "amt" items */
				destroyed = gear_object_for_use(obj, amt, false, &none_left);
				if (destroyed->known)
					object_delete(&destroyed->known);
				object_delete(&destroyed);

				/* Count the casualties */
				k += amt;
			}
		}
		obj = next;
	}

	/* Return the casualty count */
	return (k);
}
Esempio n. 13
0
/**
 * Drop (some of) a non-cursed inventory/equipment item "near" the current
 * location
 *
 * There are two cases here - a single object or entire stack is being dropped,
 * or part of a stack is being split off and dropped
 */
void inven_drop(struct object *obj, int amt)
{
	int py = player->py;
	int px = player->px;
	struct object *dropped;
	bool none_left = false;
	bool quiver = false;

	char name[80];
	char label;

	/* Error check */
	if (amt <= 0)
		return;

	/* Check it is still held, in case there were two drop commands queued
	 * for this item.  This is in theory not ideal, but in practice should
	 * be safe. */
	if (!object_is_carried(player, obj))
		return;

	/* Get where the object is now */
	label = gear_to_label(obj);

	/* Is it in the quiver? */
	if (object_is_in_quiver(player, obj))
		quiver = true;

	/* Not too many */
	if (amt > obj->number) amt = obj->number;

	/* Take off equipment, don't combine */
	if (object_is_equipped(player->body, obj))
		inven_takeoff(obj);

	/* Get the object */
	dropped = gear_object_for_use(obj, amt, false, &none_left);

	/* Describe the dropped object */
	object_desc(name, sizeof(name), dropped, ODESC_PREFIX | ODESC_FULL);

	/* Message */
	msg("You drop %s (%c).", name, label);

	/* Describe what's left */
	if (dropped->artifact) {
		object_desc(name, sizeof(name), dropped,
					ODESC_FULL | ODESC_SINGULAR);
		msg("You no longer have the %s (%c).", name, label);
	} else if (none_left) {
		/* Play silly games to get the right description */
		int number = dropped->number;
		dropped->number = 0;
		object_desc(name, sizeof(name), dropped, ODESC_PREFIX | ODESC_FULL);
		msg("You have %s (%c).", name, label);
		dropped->number = number;
	} else {
		object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL);
		msg("You have %s (%c).", name, label);
	}

	/* Drop it near the player */
	drop_near(cave, &dropped, 0, py, px, false);

	/* Sound for quiver objects */
	if (quiver)
		sound(MSG_QUIVER);

	event_signal(EVENT_INVENTORY);
	event_signal(EVENT_EQUIPMENT);
}
Esempio n. 14
0
/**
 * Add an item to the players inventory.
 *
 * If the new item can combine with an existing item in the inventory,
 * it will do so, using object_similar() and object_absorb(), else,
 * the item will be placed into the first available gear array index.
 *
 * This function can be used to "over-fill" the player's pack, but only
 * once, and such an action must trigger the "overflow" code immediately.
 * Note that when the pack is being "over-filled", the new item must be
 * placed into the "overflow" slot, and the "overflow" must take place
 * before the pack is reordered, but (optionally) after the pack is
 * combined.  This may be tricky.  See "dungeon.c" for info.
 *
 * Note that this code removes any location information from the object once
 * it is placed into the inventory, but takes no responsibility for removing
 * the object from any other pile it was in.
 */
void inven_carry(struct player *p, struct object *obj, bool absorb,
				 bool message)
{
	struct object *gear_obj;
	char o_name[80];

	/* Check for combining, if appropriate */
	if (absorb) {
		for (gear_obj = p->gear; gear_obj; gear_obj = gear_obj->next) {
			/* Can't stack equipment */
			if (object_is_equipped(p->body, gear_obj))
				continue;

			/* Check if the two items can be combined */
			if (object_similar(gear_obj, obj, OSTACK_PACK)) {
				/* Increase the weight */
				p->upkeep->total_weight += (obj->number * obj->weight);

				/* Combine the items, and their known versions */
				object_absorb(gear_obj->known, obj->known);
				obj->known = NULL;
				object_absorb(gear_obj, obj);

				/* Describe the combined object */
				object_desc(o_name, sizeof(o_name), gear_obj,
							ODESC_PREFIX | ODESC_FULL);

				/* Recalculate bonuses */
				p->upkeep->update |= (PU_BONUS | PU_INVEN);

				/* Redraw stuff */
				p->upkeep->redraw |= (PR_INVEN);

				/* Inventory will need updating */
				update_stuff(player);

				/* Optionally, display a message */
				if (message)
					msg("You have %s (%c).", o_name, gear_to_label(gear_obj));

				/* Sound for quiver objects */
				if (object_is_in_quiver(p, gear_obj))
					sound(MSG_QUIVER);

				/* Success */
				return;
			}
		}
	}

	/* Paranoia */
	assert(pack_slots_used(p) <= z_info->pack_size);

	/* Add to the end of the list */
	gear_insert_end(obj);

	/* Apply an autoinscription */
	apply_autoinscription(obj);

	/* Remove cave object details */
	obj->held_m_idx = 0;
	obj->iy = obj->ix = 0;
	obj->known->iy = obj->known->ix = 0;

	/* Update the inventory */
	p->upkeep->total_weight += (obj->number * obj->weight);
	p->upkeep->update |= (PU_BONUS | PU_INVEN);
	p->upkeep->notice |= (PN_COMBINE);
	p->upkeep->redraw |= (PR_INVEN);

	/* Inventory will need updating */
	update_stuff(player);

	/* Hobbits ID mushrooms on pickup, gnomes ID wands and staffs on pickup */
	if (!object_flavor_is_aware(obj)) {
		if (player_has(player, PF_KNOW_MUSHROOM) && tval_is_mushroom(obj)) {
			object_flavor_aware(obj);
			msg("Mushrooms for breakfast!");
		} else if (player_has(player, PF_KNOW_ZAPPER) && tval_is_zapper(obj))
			object_flavor_aware(obj);
	}

	/* Optionally, display a message */
	if (message) {
		/* Describe the object */
		object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);

		/* Message */
		msg("You have %s (%c).", o_name, gear_to_label(obj));
	}

	/* Sound for quiver objects */
	if (object_is_in_quiver(p, obj))
		sound(MSG_QUIVER);
}
Esempio n. 15
0
/**
 * Determine if an item can "absorb" a second item
 *
 * See "object_absorb()" for the actual "absorption" code.
 *
 * If permitted, we allow weapons/armor to stack, if "known".
 *
 * Missiles will combine if both stacks have the same "known" status.
 * This is done to make unidentified stacks of missiles useful.
 *
 * Food, potions, scrolls, and "easy know" items always stack.
 *
 * Chests, and activatable items, except rods, never stack (for various
 * reasons).
 */
bool object_stackable(const struct object *obj1, const struct object *obj2,
					  object_stack_t mode)
{
	int i;

	/* Equipment items don't stack */
	if (object_is_equipped(player->body, obj1))
		return false;
	if (object_is_equipped(player->body, obj2))
		return false;

	/* If either item is unknown, do not stack */
	if (mode & OSTACK_LIST && obj1->kind != obj1->known->kind) return false;
	if (mode & OSTACK_LIST && obj2->kind != obj2->known->kind) return false;

	/* Hack -- identical items cannot be stacked */
	if (obj1 == obj2) return false;

	/* Require identical object kinds */
	if (obj1->kind != obj2->kind) return false;

	/* Different flags don't stack */
	if (!of_is_equal(obj1->flags, obj2->flags)) return false;

	/* Different elements don't stack */
	for (i = 0; i < ELEM_MAX; i++) {
		if (obj1->el_info[i].res_level != obj2->el_info[i].res_level)
			return false;
		if ((obj1->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)) !=
			(obj2->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)))
			return false;
	}

	/* Artifacts never stack */
	if (obj1->artifact || obj2->artifact) return false;

	/* Analyze the items */
	if (tval_is_chest(obj1)) {
		/* Chests never stack */
		return false;
	}
	else if (tval_is_edible(obj1) || tval_is_potion(obj1) ||
		tval_is_scroll(obj1) || tval_is_rod(obj1)) {
		/* Food, potions, scrolls and rods all stack nicely,
		   since the kinds are identical, either both will be
		   aware or both will be unaware */
	} else if (tval_can_have_charges(obj1) || tval_is_money(obj1)) {
		/* Gold, staves and wands stack most of the time */
		/* Too much gold or too many charges */
		if (obj1->pval + obj2->pval > MAX_PVAL)
			return false;

		/* ... otherwise ok */
	} else if (tval_is_weapon(obj1) || tval_is_armor(obj1) ||
		tval_is_jewelry(obj1) || tval_is_light(obj1)) {
		bool obj1_is_known = object_fully_known((struct object *)obj1);
		bool obj2_is_known = object_fully_known((struct object *)obj2);

		/* Require identical values */
		if (obj1->ac != obj2->ac) return false;
		if (obj1->dd != obj2->dd) return false;
		if (obj1->ds != obj2->ds) return false;

		/* Require identical bonuses */
		if (obj1->to_h != obj2->to_h) return false;
		if (obj1->to_d != obj2->to_d) return false;
		if (obj1->to_a != obj2->to_a) return false;

		/* Require all identical modifiers */
		for (i = 0; i < OBJ_MOD_MAX; i++)
			if (obj1->modifiers[i] != obj2->modifiers[i])
				return (false);

		/* Require identical ego-item types */
		if (obj1->ego != obj2->ego) return false;

		/* Require identical curses */
		if (!curses_are_equal(obj1->curses, obj2->curses)) return false;

		/* Hack - Never stack recharging wearables ... */
		if ((obj1->timeout || obj2->timeout) &&
			!tval_is_light(obj1)) return false;

		/* ... and lights must have same amount of fuel */
		else if ((obj1->timeout != obj2->timeout) &&
				 tval_is_light(obj1)) return false;

		/* Prevent unIDd items stacking with IDd items in the object list */
		if (mode & OSTACK_LIST && (obj1_is_known != obj2_is_known))
			return false;
	} else {
		/* Anything else probably okay */
	}

	/* Require compatible inscriptions */
	if (obj1->note && obj2->note && (obj1->note != obj2->note))
		return false;

	/* They must be similar enough */
	return true;
}
Esempio n. 16
0
/**
 * Add an item to the players inventory.
 *
 * If the new item can combine with an existing item in the inventory,
 * it will do so, using object_similar() and object_absorb(), else,
 * the item will be placed into the first available gear array index.
 *
 * This function can be used to "over-fill" the player's pack, but only
 * once, and such an action must trigger the "overflow" code immediately.
 * Note that when the pack is being "over-filled", the new item must be
 * placed into the "overflow" slot, and the "overflow" must take place
 * before the pack is reordered, but (optionally) after the pack is
 * combined.  This may be tricky.  See "dungeon.c" for info.
 *
 * Note that this code removes any location information from the object once
 * it is placed into the inventory, but takes no responsibility for removing
 * the object from any other pile it was in.
 */
void inven_carry(struct player *p, struct object *obj, bool absorb,
				 bool message)
{
	bool combining = false;

	/* Check for combining, if appropriate */
	if (absorb) {
		struct object *combine_item = NULL;

		struct object *gear_obj = p->gear;
		while (combine_item == false && gear_obj) {
			if (!object_is_equipped(p->body, gear_obj) &&
					object_similar(gear_obj, obj, OSTACK_PACK)) {
				combine_item = gear_obj;
			}

			gear_obj = gear_obj->next;
		}

		if (combine_item) {
			/* Increase the weight */
			p->upkeep->total_weight += (obj->number * obj->weight);

			/* Combine the items, and their known versions */
			object_absorb(combine_item->known, obj->known);
			obj->known = NULL;
			object_absorb(combine_item, obj);

			obj = combine_item;
			combining = true;
		}
	}

	/* We didn't manage the find an object to combine with */
	if (!combining) {
		/* Paranoia */
		assert(pack_slots_used(p) <= z_info->pack_size);

		gear_insert_end(obj);
		apply_autoinscription(obj);

		/* Remove cave object details */
		obj->held_m_idx = 0;
		obj->grid = loc(0, 0);
		obj->known->grid = loc(0, 0);

		/* Update the inventory */
		p->upkeep->total_weight += (obj->number * obj->weight);
		p->upkeep->notice |= (PN_COMBINE);

		/* Hobbits ID mushrooms on pickup, gnomes ID wands and staffs on pickup */
		if (!object_flavor_is_aware(obj)) {
			if (player_has(player, PF_KNOW_MUSHROOM) && tval_is_mushroom(obj)) {
				object_flavor_aware(obj);
				msg("Mushrooms for breakfast!");
			} else if (player_has(player, PF_KNOW_ZAPPER) && tval_is_zapper(obj))
				object_flavor_aware(obj);
		}
	}

	p->upkeep->update |= (PU_BONUS | PU_INVEN);
	p->upkeep->redraw |= (PR_INVEN);
	update_stuff(player);

	if (message) {
		char o_name[80];
		object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);
		msg("You have %s (%c).", o_name, gear_to_label(obj));
	}

	if (object_is_in_quiver(p, obj))
		sound(MSG_QUIVER);
}