/** * 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; }
/** * 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; }
/** * 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'; }
/** * 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; }
/** * 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); } }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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; }
/** * 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); } }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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; }
/** * 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); }