/** * 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; }
void textui_obj_wield(object_type *o_ptr, int item) { int slot = wield_slot(o_ptr); /* Usually if the slot is taken we'll just replace the item in the slot, * but in some cases we need to ask the user which slot they actually * want to replace */ if (p_ptr->inventory[slot].k_idx) { if (o_ptr->tval == TV_RING) { cptr q = "Replace which ring? "; cptr s = "Error in obj_wield, please report"; item_tester_hook = obj_is_ring; if (!get_item(&slot, q, s, CMD_WIELD, USE_EQUIP)) return; } if (obj_is_ammo(o_ptr) && !object_similar(&p_ptr->inventory[slot], o_ptr, OSTACK_QUIVER)) { cptr q = "Replace which ammunition? "; cptr s = "Error in obj_wield, please report"; item_tester_hook = obj_is_ammo; if (!get_item(&slot, q, s, CMD_WIELD, USE_EQUIP)) return; } } cmd_insert(CMD_WIELD); cmd_set_arg_item(cmd_get_top(), 0, item); cmd_set_arg_number(cmd_get_top(), 1, slot); }
/* * Carry an object and delete it. */ static void py_pickup_aux(int o_idx, bool domsg) { int slot, quiver_slot = 0; char o_name[80]; object_type *o_ptr = object_byid(o_idx); /* Carry the object */ slot = inven_carry(p_ptr, o_ptr); /* Handle errors (paranoia) */ if (slot < 0) return; /* If we have picked up ammo which matches something in the quiver, note * that it so that we can wield it later (and suppress pick up message) */ if (obj_is_ammo(o_ptr)) { int i; for (i = QUIVER_START; i < QUIVER_END; i++) { if (!p_ptr->inventory[i].kind) continue; if (!object_similar(&p_ptr->inventory[i], o_ptr, OSTACK_QUIVER)) continue; quiver_slot = i; break; } } /* Get the new object */ o_ptr = &p_ptr->inventory[slot]; /* Set squelch status */ p_ptr->notice |= PN_SQUELCH; /* Automatically sense artifacts */ object_notice_artifact(o_ptr); /* Optionally, display a message */ if (domsg && !quiver_slot) { /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msg("You have %s (%c).", o_name, index_to_label(slot)); } /* Update object_idx if necessary */ if (p_ptr->object_idx == (0 - o_idx)) { track_object(slot); } /* Delete the object */ delete_object_idx(o_idx); /* If we have a quiver slot that this ammo matches, use it */ if (quiver_slot) wield_item(o_ptr, slot, quiver_slot); }
/** * 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; }
/** * Combine items in the pack, confirming no blank objects or gold */ void combine_pack(void) { struct object *obj1, *obj2, *prev; bool display_message = false; /* Combine the pack (backwards) */ obj1 = gear_last_item(); while (obj1) { assert(obj1->kind); assert(!tval_is_money(obj1)); prev = obj1->prev; /* Scan the items above that item */ for (obj2 = player->gear; obj2 && obj2 != obj1; obj2 = obj2->next) { assert(obj2->kind); /* Can we drop "obj1" onto "obj2"? */ if (object_similar(obj2, obj1, OSTACK_PACK)) { display_message = true; object_absorb(obj2->known, obj1->known); obj1->known = NULL; object_absorb(obj2, obj1); break; } else if (inven_can_stack_partial(obj2, obj1, OSTACK_PACK)) { /* Setting this to true spams the combine message. */ display_message = false; object_absorb_partial(obj2->known, obj1->known); object_absorb_partial(obj2, obj1); break; } } obj1 = prev; } calc_inventory(player->upkeep, player->gear, player->body); /* Redraw gear */ event_signal(EVENT_INVENTORY); event_signal(EVENT_EQUIPMENT); /* Message */ if (display_message) { msg("You combine some items in your pack."); /* Stop "repeat last command" from working. */ cmd_disable_repeat(); } }
/** * Combine items in the pack, confirming no blank objects or gold */ void combine_pack(void) { struct object *obj1, *obj2; bool display_message = FALSE; bool redraw = FALSE; /* Combine the pack (backwards) */ for (obj1 = gear_last_item(); obj1; obj1 = obj1->prev) { assert(obj1->kind); assert(!tval_is_money(obj1)); /* Scan the items above that item */ for (obj2 = player->gear; obj2 && obj2 != obj1; obj2 = obj2->next) { assert(obj2->kind); /* Can we drop "obj1" onto "obj2"? */ if (object_similar(obj2, obj1, OSTACK_PACK)) { display_message = TRUE; redraw = TRUE; object_absorb(obj2, obj1); } else if (inven_can_stack_partial(obj2, obj1, OSTACK_PACK)) { /* Setting this to TRUE spams the combine message. */ display_message = FALSE; redraw = TRUE; object_absorb_partial(obj2, obj1); break; } } } calc_inventory(player->upkeep, player->gear, player->body); /* Redraw stuff */ if (redraw) { player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); player->upkeep->update |= (PU_INVEN); } /* Message */ if (display_message) { msg("You combine some items in your pack."); /* Stop "repeat last command" from working. */ cmd_disable_repeat(); } }
/* * Check if we have space for an item in the pack without overflow */ bool inven_carry_okay(object_type *o_ptr) { if (has_flag(o_ptr, FLAG_GOLD_VALUE)) return FALSE; /* Empty slot? */ if (inventory_limit(INVEN_INVEN) > flag_max_key(get_inven(p_ptr, INVEN_INVEN))) return (TRUE); /* Similar slot? */ for_inventory(p_ptr, j_ptr, INVEN_INVEN, INVEN_PACK); { /* Check if the two items can be combined */ if (object_similar(j_ptr, o_ptr)) return (TRUE); } end_inventory(); /* Nope */ return (FALSE); } /* inven_carry_okay() */
/* Wield or wear an item */ void do_cmd_wield(cmd_code code, cmd_arg args[]) { object_type *equip_o_ptr; char o_name[80]; unsigned n; int item = args[0].item; int slot = args[1].number; object_type *o_ptr = object_from_item_idx(item); if (!item_is_available(item, NULL, USE_INVEN | USE_FLOOR)) { msg("You do not have that item to wield."); return; } /* Check the slot */ if (!slot_can_wield_item(slot, o_ptr)) { msg("You cannot wield that item there."); return; } equip_o_ptr = &p_ptr->inventory[slot]; /* If the slot is open, wield and be done */ if (!equip_o_ptr->kind) { wield_item(o_ptr, item, slot); return; } /* If the slot is in the quiver and objects can be combined */ if (obj_is_ammo(equip_o_ptr) && object_similar(equip_o_ptr, o_ptr, OSTACK_QUIVER)) { wield_item(o_ptr, item, slot); return; } /* Prevent wielding into a cursed slot */ if (cursed_p(equip_o_ptr->flags)) { object_desc(o_name, sizeof(o_name), equip_o_ptr, ODESC_BASE); msg("The %s you are %s appears to be cursed.", o_name, describe_use(slot)); return; } /* "!t" checks for taking off */ n = check_for_inscrip(equip_o_ptr, "!t"); while (n--) { /* Prompt */ object_desc(o_name, sizeof(o_name), equip_o_ptr, ODESC_PREFIX | ODESC_FULL); /* Forget it */ if (!get_check(format("Really take off %s? ", o_name))) return; } wield_item(o_ptr, item, slot); }
/* * Wield or wear a single item from the pack or floor */ void wield_item(object_type *o_ptr, int item, int slot) { object_type object_type_body; object_type *i_ptr = &object_type_body; const char *fmt; char o_name[80]; bool combined_ammo = FALSE; bool track_wielded_item = FALSE; int num = 1; /* If we are stacking ammo in the quiver */ if (obj_is_ammo(o_ptr)) { num = o_ptr->number; combined_ammo = object_similar(o_ptr, &p_ptr->inventory[slot], OSTACK_QUIVER); } /* Take a turn */ p_ptr->energy_use = 100; /* Obtain local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = num; /* Update object_idx if necessary, once object is in slot */ if (p_ptr->object_idx == item) { track_wielded_item = TRUE; } /* Decrease the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -num); inven_item_optimize(item); } /* Decrease the item (from the floor) */ else { floor_item_increase(0 - item, -num); floor_item_optimize(0 - item); } /* Get the wield slot */ o_ptr = &p_ptr->inventory[slot]; if (combined_ammo) { /* Add the new ammo to the already-quiver-ed ammo */ object_absorb(o_ptr, i_ptr); } else { /* Take off existing item */ if (o_ptr->kind) (void)inven_takeoff(slot, 255); /* If we are wielding ammo we may need to "open" the slot by shifting * later ammo up the quiver; this is because we already called the * inven_item_optimize() function. */ if (slot >= QUIVER_START) open_quiver_slot(slot); /* Wear the new stuff */ object_copy(o_ptr, i_ptr); /* Increment the equip counter by hand */ p_ptr->equip_cnt++; } /* Increase the weight */ p_ptr->total_weight += i_ptr->weight * num; /* Track object if necessary */ if (track_wielded_item) { track_object(slot); } /* Do any ID-on-wield */ object_notice_on_wield(o_ptr); /* Where is the item now */ if (slot == INVEN_WIELD) fmt = "You are wielding %s (%c)."; else if (slot == INVEN_BOW) fmt = "You are shooting with %s (%c)."; else if (slot == INVEN_LIGHT) fmt = "Your light source is %s (%c)."; else if (combined_ammo) fmt = "You combine %s in your quiver (%c)."; else if (slot >= QUIVER_START && slot < QUIVER_END) fmt = "You add %s to your quiver (%c)."; else fmt = "You are wearing %s (%c)."; /* Describe the result */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msgt(MSG_WIELD, fmt, o_name, index_to_label(slot)); /* Cursed! */ if (cursed_p(o_ptr->flags)) { /* Warn the player */ msgt(MSG_CURSED, "Oops! It feels deathly cold!"); /* Sense the object */ object_notice_curses(o_ptr); } /* Save quiver size */ save_quiver_size(p_ptr); /* See if we have to overflow the pack */ pack_overflow(); /* Recalculate bonuses, torch, mana */ p_ptr->notice |= PN_SORT_QUIVER; p_ptr->update |= (PU_BONUS | PU_TORCH | PU_MANA); p_ptr->redraw |= (PR_INVEN | PR_EQUIP); }
/** * 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; } } }
/** * 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."); }
/* * Wield or wear a single item from the pack or floor */ void do_cmd_wield(object_type *default_o_ptr, int default_item) { int item, slot; object_type *o_ptr; object_type *i_ptr; object_type object_type_body; cptr act; cptr q, s; int i, quantity, original_quantity; bool weapon_less_effective = FALSE; bool grants_two_weapon = FALSE; char o_name[80]; bool combine = FALSE; // use specified item if possible if (default_o_ptr != NULL) { o_ptr = default_o_ptr; item = default_item; } /* Get an item */ else { /* Restrict the choices */ item_tester_hook = item_tester_hook_wear; /* Get an item */ q = "Wear/Wield which item? "; s = "You have nothing you can wear or wield."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } else { o_ptr = &o_list[0 - item]; } } // remember how many there were original_quantity = o_ptr->number; // Check whether it would be too heavy if ((item < 0) && (p_ptr->total_weight + o_ptr->weight > weight_limit()*3/2)) { /* Describe it */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3); if (o_ptr->k_idx) msg_format("You cannot lift %s.", o_name); /* Abort */ return; } /* Check the slot */ slot = wield_slot(o_ptr); /* Ask for ring to replace */ if ((o_ptr->tval == TV_RING) && inventory[INVEN_LEFT].k_idx && inventory[INVEN_RIGHT].k_idx) { /* Restrict the choices */ item_tester_tval = TV_RING; /* Choose a ring from the equipment only */ q = "Replace which ring? "; s = "Oops."; if (!get_item(&slot, q, s, USE_EQUIP)) return; } // Special cases for merging arrows if (object_similar(&inventory[INVEN_QUIVER1], o_ptr)) { slot = INVEN_QUIVER1; combine = TRUE; } else if (object_similar(&inventory[INVEN_QUIVER2], o_ptr)) { slot = INVEN_QUIVER2; combine = TRUE; } /* Ask for arrow set to replace */ else if ((o_ptr->tval == TV_ARROW) && inventory[INVEN_QUIVER1].k_idx && inventory[INVEN_QUIVER2].k_idx) { /* Restrict the choices */ item_tester_tval = TV_ARROW; /* Choose a set of arrows from the equipment only */ q = "Replace which set of arrows? "; s = "Oops."; if (!get_item(&slot, q, s, USE_EQUIP)) return; } // Ask about two weapon fighting if necessary for (i = 0; i < o_ptr->abilities; i++) { if ((o_ptr->skilltype[i] == S_MEL) && (o_ptr->abilitynum[i] == MEL_TWO_WEAPON) && object_known_p(o_ptr)) { grants_two_weapon = TRUE; } } if ((p_ptr->active_ability[S_MEL][MEL_TWO_WEAPON] || grants_two_weapon) && ((o_ptr->tval == TV_SWORD) || (o_ptr->tval == TV_POLEARM) || (o_ptr->tval == TV_HAFTED) || (o_ptr->tval == TV_DIGGING))) { if (!(k_info[o_ptr->k_idx].flags3 & (TR3_TWO_HANDED))) { if (get_check("Do you wish to wield it in your off-hand? ")) { slot = INVEN_ARM; } } } /* Prevent wielding into a cursed slot */ if (cursed_p(&inventory[slot])) { /* Describe it */ object_desc(o_name, sizeof(o_name), &inventory[slot], FALSE, 0); /* Message */ msg_format("The %s you are %s appears to be cursed.", o_name, describe_use(slot)); /* Cancel the command */ return; } /* Deal with wielding of two-handed weapons when already using a shield */ if ((k_info[o_ptr->k_idx].flags3 & (TR3_TWO_HANDED)) && (inventory[INVEN_ARM].k_idx)) { if (cursed_p(&inventory[INVEN_ARM])) { if (inventory[INVEN_ARM].tval == TV_SHIELD) { msg_print("You would need to remove your shield, but it appears to be cursed."); } else { msg_print("You would need to put down your off-hand weapon, but it appears to be cursed."); } /* Cancel the command */ return; } // warn about dropping item in left hand if ((item < 0) && (&inventory[INVEN_PACK-1])->tval) { /* Flush input */ flush(); if (inventory[INVEN_ARM].tval == TV_SHIELD) { if (!get_check("This would require removing (and dropping) your shield. Proceed? ")) { /* Cancel the command */ return; } } else { msg_print("This would require removing (and dropping) your off-hand weapon."); if (!get_check("Proceed? ")) { /* Cancel the command */ return; } } } } /* Deal with wielding of shield or second weapon when already wielding a two handed weapon */ if ((slot == INVEN_ARM) && (k_info[inventory[INVEN_WIELD].k_idx].flags3 & (TR3_TWO_HANDED))) { if (cursed_p(&inventory[INVEN_WIELD])) { msg_print("You would need to put down your weapon, but it appears to be cursed."); /* Cancel the command */ return; } // warn about dropping item in left hand if ((item < 0) && (&inventory[INVEN_PACK-1])->tval) { /* Flush input */ flush(); if (inventory[INVEN_ARM].tval == TV_SHIELD) { if (!get_check("This would require removing (and dropping) your weapon. Proceed? ")) { /* Cancel the command */ return; } } else { msg_print("This would require removing (and dropping) your weapon."); if (!get_check("Proceed? ")) { /* Cancel the command */ return; } } } } /* Deal with wielding of shield or second weapon when already wielding a hand and a half weapon */ if ((slot == INVEN_ARM) && (k_info[inventory[INVEN_WIELD].k_idx].flags3 & (TR3_HAND_AND_A_HALF)) && (!inventory[INVEN_ARM].k_idx)) { weapon_less_effective = TRUE; } /* Take a turn */ p_ptr->energy_use = 100; // store the action type p_ptr->previous_action[0] = ACTION_MISC; /* Get local object */ i_ptr = &object_type_body; /* Obtain local object */ object_copy(i_ptr, o_ptr); // Handle quantity differently for arrows if (i_ptr->tval == TV_ARROW) { if (combine) quantity = MIN(o_ptr->number, MAX_STACK_SIZE - 1 - (&inventory[slot])->number); else quantity = o_ptr->number; } else { quantity = 1; } /* Modify quantity */ i_ptr->number = quantity; /* Decrease the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -quantity); inven_item_optimize(item); } /* Decrease the item (from the floor) */ else { floor_item_increase(0 - item, -quantity); floor_item_optimize(0 - item); } /* Get the wield slot */ o_ptr = &inventory[slot]; /* Take off existing item */ if (o_ptr->k_idx && !combine) { /* Take off existing item */ (void)inven_takeoff(slot, 255); } /* Deal with wielding of two-handed weapons when already using a shield */ if ((k_info[i_ptr->k_idx].flags3 & (TR3_TWO_HANDED)) && (inventory[INVEN_ARM].k_idx)) { /* Take off shield */ check_pack_overflow(); (void)inven_takeoff(INVEN_ARM, 255); } /* Deal with wielding of shield or second weapon when already wielding a two handed weapon */ if ((slot == INVEN_ARM) && (k_info[inventory[INVEN_WIELD].k_idx].flags3 & (TR3_TWO_HANDED))) { /* Stop wielding two handed weapon */ (void)inven_takeoff(INVEN_WIELD, 255); } /* Combine the new stuff into the equipment */ if (combine) { msg_print("You combine them with some that are already in your quiver."); object_absorb(o_ptr, i_ptr); } /* Wear the new stuff */ else { object_copy(o_ptr, i_ptr); } /* Increment the equip counter by hand */ if (!combine) p_ptr->equip_cnt++; /* Where is the item now */ if ((slot == INVEN_WIELD) || ((slot == INVEN_ARM) && (o_ptr->tval != TV_SHIELD))) { act = "You are wielding"; } else if (slot == INVEN_BOW) { act = "You are shooting with"; } else if (slot == INVEN_LITE) { act = "Your light source is"; } else if ((slot == INVEN_QUIVER1) || (slot == INVEN_QUIVER2)) { act = "In your quiver you have"; } else { act = "You are wearing"; } /* Describe the result */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3); /* Message */ msg_format("%s %s (%c).", act, o_name, index_to_label(slot)); // Deal with wielding from the floor if (item < 0) { /* Forget monster */ o_ptr->held_m_idx = 0; /* Forget location */ o_ptr->iy = o_ptr->ix = 0; // Break the truce if picking up an item from the floor break_truce(FALSE); // Special effects when picking up all the items from the floor if (i_ptr->number == original_quantity) { /* No longer marked */ o_ptr->marked = FALSE; } } /* Cursed! */ if (cursed_p(o_ptr)) { /* Warn the player */ msg_print("You have a very bad feeling about this..."); /* Remove special inscription, if any */ if (o_ptr->discount >= INSCRIP_NULL) o_ptr->discount = 0; /* Sense the object if allowed */ if (o_ptr->discount == 0) o_ptr->discount = INSCRIP_CURSED; /* The object has been "sensed" */ o_ptr->ident |= (IDENT_SENSE); } if (weapon_less_effective) { /* Describe it */ object_desc(o_name, sizeof(o_name), &inventory[INVEN_WIELD], FALSE, 0); /* Message */ msg_format("You are no longer able to wield your %s as effectively.", o_name); } ident_on_wield(o_ptr); // activate all of its new abilities for (i = 0; i < o_ptr->abilities; i++) { if (!p_ptr->have_ability[o_ptr->skilltype[i]][o_ptr->abilitynum[i]]) { p_ptr->have_ability[o_ptr->skilltype[i]][o_ptr->abilitynum[i]] = TRUE; p_ptr->active_ability[o_ptr->skilltype[i]][o_ptr->abilitynum[i]] = TRUE; } } /* Recalculate bonuses */ p_ptr->update |= (PU_BONUS); /* Recalculate mana */ p_ptr->update |= (PU_MANA); /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER_0); p_ptr->redraw |= (PR_EQUIPPY | PR_RESIST); }
/* * Throw an object from the pack or floor. * * Note: "unseen" monsters are very hard to hit. * * Should throwing a weapon do full damage? Should it allow the magic * to hit bonus of the weapon to have an effect? Should it ever cause * the item to be destroyed? Should it do any damage at all? */ void do_cmd_throw(cmd_code code, cmd_arg args[]) { int dir, item; int i, j, y, x; s16b ty, tx; int chance, tdam, tdis; int weight; object_type *o_ptr; object_type *i_ptr; object_type object_type_body; bool hit_body = FALSE; byte missile_attr; char missile_char; char o_name[80]; u32b msg_type = 0; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor * op_ptr->delay_factor; /* Get item to throw and direction in which to throw it. */ item = args[0].item; dir = args[1].direction; /* Make sure the player isn't throwing wielded items */ if (item >= INVEN_WIELD && item < QUIVER_START) { msg_print("You have cannot throw wielded items."); return; } /* Check the item being thrown is usable by the player. */ if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR))) { msg_format("That item is not within your reach."); return; } /* Get the object */ o_ptr = object_from_item_idx(item); object_notice_on_firing(o_ptr); /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Distribute the charges of rods/wands/staves between the stacks */ distribute_charges(o_ptr, i_ptr, 1); /* Single object */ i_ptr->number = 1; /* Reduce and describe inventory */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Reduce and describe floor item */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Description */ object_desc(o_name, sizeof(o_name), i_ptr, ODESC_FULL); /* Find the color and symbol for the object for throwing */ missile_attr = object_attr(i_ptr); missile_char = object_char(i_ptr); /* Enforce a minimum "weight" of one pound */ weight = ((i_ptr->weight > 10) ? i_ptr->weight : 10); /* Hack -- Distance -- Reward strength, penalize weight */ tdis = (adj_str_blow[p_ptr->state.stat_ind[A_STR]] + 20) * 10 / weight; /* Max distance of 10 */ if (tdis > 10) tdis = 10; /* Hack -- Base damage from thrown object */ tdam = damroll(i_ptr->dd, i_ptr->ds); if (!tdam) tdam = 1; tdam += i_ptr->to_d; /* Chance of hitting */ chance = (p_ptr->state.skills[SKILL_TO_HIT_THROW] + (p_ptr->state.to_h * BTH_PLUS_ADJ)); /* Take a turn */ p_ptr->energy_use = 100; /* Start at the player */ y = p_ptr->py; x = p_ptr->px; /* Predict the "target" location */ ty = p_ptr->py + 99 * ddy[dir]; tx = p_ptr->px + 99 * ddx[dir]; /* Check for "target request" */ if ((dir == 5) && target_okay()) { target_get(&tx, &ty); } /* Calculate the path */ path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(); /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { /* Visual effects */ print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); Term_xtra(TERM_XTRA_DELAY, msec); light_spot(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); } /* Delay anyway for consistency */ else { /* Pause anyway, for consistancy */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x); int visible = m_ptr->ml; /* Note the collision */ hit_body = TRUE; /* Did we hit it (penalize range) */ if (test_hit(chance2, r_ptr->ac, m_ptr->ml)) { const char *hit_verb = "hits"; bool fear = FALSE; const slay_t *best_s_ptr = NULL; /* Assume a default death */ cptr note_dies = " dies."; /* Some monsters get "destroyed" */ if (monster_is_unusual(r_ptr)) { /* Special note at death */ note_dies = " is destroyed."; } /* Apply special damage - brought forward to fill in hit_verb XXX XXX XXX */ improve_attack_modifier(i_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) { tdam *= best_s_ptr->mult; hit_verb = best_s_ptr->range_verb; } /* Apply special damage XXX XXX XXX */ tdam = critical_shot(i_ptr->weight, i_ptr->to_h, tdam, &msg_type); /* No negative damage; change verb if no damage done */ if (tdam <= 0) { tdam = 0; hit_verb = "fail to harm"; } /* Handle unseen monster */ if (!visible) { /* Invisible monster */ msg_format("The %s finds a mark.", o_name); } /* Handle visible monster */ else { char m_name[80]; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Tell the player what happened */ if (msg_type == MSG_SHOOT_HIT) message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name); else { if (msg_type == MSG_HIT_GOOD) { message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } } /* Hack -- Track this monster race */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Hack -- Track this monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); } /* Learn the bonuses */ /* XXX Eddie This is messed up, better done for firing, */ /* should use that method [split last] instead */ /* check if inven_optimize removed what o_ptr referenced */ if (object_similar(i_ptr, o_ptr, OSTACK_PACK)) object_notice_attack_plusses(o_ptr); object_notice_attack_plusses(i_ptr); /* Complex message */ if (p_ptr->wizard) msg_format("You do %d (out of %d) damage.", tdam, m_ptr->hp); /* Hit the monster, check for death */ if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies)) { /* Dead monster */ } /* No death */ else { /* Message */ message_pain(cave_m_idx[y][x], tdam); /* Take note */ if (fear && m_ptr->ml) { char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } } } /* Stop looking */ break; } } /* Chance of breakage (during attacks) */ j = (hit_body ? breakage_chance(i_ptr) : 0); /* Drop (or break) near that location */ drop_near(i_ptr, j, y, x, TRUE); }
/* * Let an object fall to the ground at or near a location. * * The initial location is assumed to be "in_bounds()". * * 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. * * Hack -- this function uses "chance" to determine if it should produce * some form of "description" of the drop event (under the player). * * 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. */ s16b drop_near(object_type *j_ptr, s32b chance, s32b y, s32b x) { s32b i, k, d, s; s32b bs, bn; s32b by, bx; s32b dy, dx; s32b ty, tx; s16b o_idx = 0; cave_type *c_ptr; char o_name[80]; bool flag = FALSE; bool plural = FALSE; /* Extract plural */ if (j_ptr->number != 1) plural = TRUE; /* Describe object */ object_desc(o_name, j_ptr, FALSE, 0); /* Handle normal "breakage" */ if (!(j_ptr->art_name || artifact_p(j_ptr)) && (rand_int(100) < chance)) { /* Message */ msg_format("The %s disappear%s.", o_name, (plural ? "" : "s")); /* Debug */ if (wizard) msg_print("(breakage)"); delete_object(j_ptr); /* Failure */ return (0); } /* Score */ bs = -1; /* Picker */ bn = 0; /* Default */ by = y; bx = x; /* Scan local grids */ for (dy = -3; dy <= 3; dy++) { /* Scan local grids */ 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 (!in_bounds(ty, tx)) continue; /* Require line of sight */ if (!los(y, x, ty, tx)) continue; /* Obtain grid */ c_ptr = &cave[ty][tx]; /* Require floor space (or shallow terrain) -KMW- */ if (!has_flag(&f_info[c_ptr->feat], FLAG_FLOOR)) continue; /* No traps */ if (flag_used(&c_ptr->activations)) continue; /* No objects */ k = 0; /* Scan objects in that grid */ for_inventory_slot(&c_ptr->inventory, o_ptr); { /* Check for possible combination */ if (object_similar(o_ptr, j_ptr)) comb = TRUE; /* Count objects */ k++; } end_inventory_slot(); /* Add new object */ if (!comb) k++; /* Paranoia */ if (k >= inventory_limit_inven(&c_ptr->inventory)) 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) && (rand_int(bn) != 0)) continue; /* Keep score */ bs = s; /* Track it */ by = ty; bx = tx; /* Okay */ flag = TRUE; } } /* Handle lack of space */ if (!flag && !(artifact_p(j_ptr) || j_ptr->art_name)) { /* Message */ msg_format("The %s disappear%s.", o_name, (plural ? "" : "s")); /* Debug */ if (wizard) msg_print("(no floor space)"); delete_object(j_ptr); /* Failure */ return (0); } /* Find a grid */ for (i = 0; !flag; i++) { /* Bounce around */ if (i < 1000) { ty = rand_spread(by, 1); tx = rand_spread(bx, 1); } /* Random locations */ else { ty = rand_int(cur_hgt); tx = rand_int(cur_wid); } /* Grid */ c_ptr = &cave[ty][tx]; /* Require floor space */ if (!has_flag(&f_info[c_ptr->feat], FLAG_FLOOR) || has_flag(&f_info[c_ptr->feat], FLAG_NO_WALK)) continue; /* Bounce to that location */ by = ty; bx = tx; /* Require floor space */ if (!cave_clean_bold(by, bx)) continue; /* Okay */ flag = TRUE; } j_ptr->iy = by; j_ptr->ix = bx; j_ptr->held_m_idx = 0; /* Grid */ c_ptr = &cave[by][bx]; /* Carry */ o_idx = inven_carry_inven(&c_ptr->inventory, j_ptr, FALSE); /* * j_ptr might have been merged into an existing object and then * deleted, so re-get the object. */ j_ptr = get_object(item_slot_to_item(o_idx)); /* Note the spot */ note_spot(by, bx); /* Draw the spot */ lite_spot(by, bx); /* Mega-Hack -- no message if "dropped" by player */ /* Message when an object falls under the player */ if (chance && (by == p_ptr->py) && (bx == p_ptr->px)) { msg_print("You feel something roll beneath your feet."); /* Sound */ sound(SOUND_DROP); } process_hooks(HOOK_DROPPED_NEAR, "(O,b,d,d,d,d)", j_ptr, chance, y, x, by, bx); /* XXX XXX XXX */ /* Result */ return (o_idx); }
/** * 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); }
/** * Carry an object and delete it. */ extern void py_pickup_aux(int o_idx, bool msg) { int slot, quiver_slot = 0; char o_name[120]; object_type *o_ptr = &o_list[o_idx]; object_type *i_ptr = &p_ptr->inventory[INVEN_LIGHT]; bitflag f[OF_SIZE], obvious_mask[OF_SIZE]; flags_init(obvious_mask, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); of_copy(f, o_ptr->flags_obj); /* Carry the object */ slot = inven_carry(p_ptr, o_ptr); /* Handle errors (paranoia) */ if (slot < 0) return; /* If we have picked up ammo which matches something in the quiver, note * that it so that we can wield it later (and suppress pick up message) */ if (obj_is_quiver_obj(o_ptr)) { int i; for (i = QUIVER_START; i < QUIVER_END; i++) { if (!p_ptr->inventory[i].k_idx) continue; if (!object_similar(&p_ptr->inventory[i], o_ptr, OSTACK_QUIVER)) continue; quiver_slot = i; break; } } /* Get the object again */ o_ptr = &p_ptr->inventory[slot]; /* Set squelch status */ p_ptr->notice |= PN_SQUELCH; /* Stone of Lore gives id on pickup */ if (!object_known_p(o_ptr)) { if (i_ptr->sval == SV_STONE_LORE) identify_object(o_ptr); /* Otherwise pseudo-ID */ else { bool heavy = FALSE; int feel; /* Heavy sensing */ heavy = (player_has(PF_PSEUDO_ID_HEAVY)); /* Type of feeling */ feel = (heavy ? value_check_aux1(o_ptr) : value_check_aux2(o_ptr)); /* We have "felt" it */ o_ptr->ident |= (IDENT_SENSE); /* Inscribe it textually */ o_ptr->feel = feel; /* Set squelch flag as appropriate */ p_ptr->notice |= PN_SQUELCH; } } /* Log artifacts if found */ if (artifact_p(o_ptr)) history_add_artifact(o_ptr->name1, object_is_known(o_ptr), TRUE); /* Notice dice and other obvious stuff */ notice_other(IF_DD_DS, slot + 1); (void) of_inter(f, obvious_mask); of_union(o_ptr->id_obj, f); /* Average things are average */ if ((o_ptr->feel == FEEL_AVERAGE) && (is_weapon(o_ptr) || is_armour(o_ptr))){ notice_other(IF_AC, slot + 1); notice_other(IF_TO_A, slot + 1); notice_other(IF_TO_H, slot + 1); notice_other(IF_TO_D, slot + 1); } /* Recalculate the bonuses */ p_ptr->update |= (PU_BONUS); /* Optionally, display a message */ if (msg && !quiver_slot) { /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Message */ msg_format("You have %s (%c).", o_name, index_to_label(slot)); } /* Delete the object */ delete_object_idx(o_idx); /* If we have a quiver slot that this item matches, use it */ if (quiver_slot) wield_item(o_ptr, slot, quiver_slot); }
/** * 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); }