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