1 #include "inventory/inventory-object.h"
2 #include "core/window-redrawer.h"
3 #include "flavor/flavor-describer.h"
4 #include "floor/floor-object.h"
5 #include "inventory/inventory-slot-types.h"
6 #include "object-hook/hook-weapon.h"
7 #include "object/object-info.h"
8 #include "object/object-mark-types.h"
9 #include "object/object-stack.h"
10 #include "object/object-value.h"
11 #include "player-info/equipment-info.h"
12 #include "spell-realm/spells-craft.h"
13 #include "system/item-entity.h"
14 #include "system/player-type-definition.h"
15 #include "system/redrawing-flags-updater.h"
16 #include "util/object-sort.h"
17 #include "view/display-messages.h"
18 #include "view/object-describer.h"
20 void vary_item(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
23 inven_item_increase(player_ptr, item, num);
24 inven_item_describe(player_ptr, item);
25 inven_item_optimize(player_ptr, item);
29 floor_item_increase(player_ptr, 0 - item, num);
30 floor_item_describe(player_ptr, 0 - item);
31 floor_item_optimize(player_ptr, 0 - item);
35 * @brief アイテムを増減させ残り所持数メッセージを表示する /
36 * Increase the "number" of an item in the inventory
37 * @param player_ptr プレイヤーへの参照ポインタ
38 * @param item 所持数を増やしたいプレイヤーのアイテム所持スロット
41 void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
43 auto *o_ptr = &player_ptr->inventory_list[item];
57 auto &rfu = RedrawingFlagsUpdater::get_instance();
58 const auto flags_srf = {
59 StatusRedrawingFlag::BONUS,
60 StatusRedrawingFlag::MP,
61 StatusRedrawingFlag::COMBINATION,
63 rfu.set_flags(flags_srf);
64 const auto flags_swrf = {
65 SubWindowRedrawingFlag::INVENTORY,
66 SubWindowRedrawingFlag::EQUIPMENT,
68 rfu.set_flags(flags_swrf);
69 if (o_ptr->number || !player_ptr->ele_attack) {
73 if (!(item == INVEN_MAIN_HAND) && !(item == INVEN_SUB_HAND)) {
77 if (has_melee_weapon(player_ptr, enum2i(INVEN_MAIN_HAND + INVEN_SUB_HAND) - item)) {
81 set_ele_attack(player_ptr, 0, 0);
85 * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する /
86 * Erase an inventory slot if it has no more items
87 * @param player_ptr プレイヤーへの参照ポインタ
88 * @param item 消去したいプレイヤーのアイテム所持スロット
90 void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
92 auto *o_ptr = &player_ptr->inventory_list[item];
93 if (!o_ptr->is_valid()) {
100 auto &rfu = RedrawingFlagsUpdater::get_instance();
101 if (item >= INVEN_MAIN_HAND) {
102 player_ptr->equip_cnt--;
103 (&player_ptr->inventory_list[item])->wipe();
104 const auto flags_srf = {
105 StatusRedrawingFlag::BONUS,
106 StatusRedrawingFlag::TORCH,
107 StatusRedrawingFlag::MP,
109 rfu.set_flags(flags_srf);
110 const auto flags_swrf = {
111 SubWindowRedrawingFlag::EQUIPMENT,
112 SubWindowRedrawingFlag::SPELL,
114 rfu.set_flags(flags_swrf);
118 player_ptr->inven_cnt--;
120 for (i = item; i < INVEN_PACK; i++) {
121 player_ptr->inventory_list[i] = player_ptr->inventory_list[i + 1];
124 (&player_ptr->inventory_list[i])->wipe();
126 SubWindowRedrawingFlag::INVENTORY,
127 SubWindowRedrawingFlag::SPELL,
129 rfu.set_flags(flags);
133 * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン /
134 * Drop (some of) a non-cursed inventory/equipment item
135 * @param player_ptr プレイヤーへの参照ポインタ
136 * @param item 所持テーブルのID
139 * The object will be dropped "near" the current location
141 void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
145 auto *o_ptr = &player_ptr->inventory_list[item];
150 if (amt > o_ptr->number) {
154 if (item >= INVEN_MAIN_HAND) {
155 item = inven_takeoff(player_ptr, item, amt);
156 o_ptr = &player_ptr->inventory_list[item];
160 q_ptr->copy_from(o_ptr);
161 distribute_charges(o_ptr, q_ptr, amt);
164 const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
165 msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), item_name.data(), index_to_label(item));
166 (void)drop_near(player_ptr, q_ptr, 0, player_ptr->y, player_ptr->x);
167 vary_item(player_ptr, item, -amt);
171 * @brief プレイヤーの所持スロットに存在するオブジェクトをまとめなおす /
172 * Combine items in the pack
174 * Note special handling of the "overflow" slot
176 void combine_pack(PlayerType *player_ptr)
179 bool is_first_combination = true;
180 bool combined = true;
181 while (is_first_combination || combined) {
182 is_first_combination = false;
185 for (int i = INVEN_PACK; i > 0; i--) {
187 o_ptr = &player_ptr->inventory_list[i];
188 if (!o_ptr->is_valid()) {
191 for (int j = 0; j < i; j++) {
193 j_ptr = &player_ptr->inventory_list[j];
194 if (!j_ptr->is_valid()) {
199 * Get maximum number of the stack if these
200 * are similar, get zero otherwise.
202 int max_num = object_similar_part(j_ptr, o_ptr);
204 bool is_max = (max_num != 0) && (j_ptr->number < max_num);
209 if (o_ptr->number + j_ptr->number <= max_num) {
211 object_absorb(j_ptr, o_ptr);
212 player_ptr->inven_cnt--;
214 for (k = i; k < INVEN_PACK; k++) {
215 player_ptr->inventory_list[k] = player_ptr->inventory_list[k + 1];
218 (&player_ptr->inventory_list[k])->wipe();
220 int old_num = o_ptr->number;
221 int remain = j_ptr->number + o_ptr->number - max_num;
222 object_absorb(j_ptr, o_ptr);
223 o_ptr->number = remain;
224 const auto tval = o_ptr->bi_key.tval();
225 if (tval == ItemKindType::ROD) {
226 o_ptr->pval = o_ptr->pval * remain / old_num;
227 o_ptr->timeout = o_ptr->timeout * remain / old_num;
230 if (tval == ItemKindType::WAND) {
231 o_ptr->pval = o_ptr->pval * remain / old_num;
235 RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::INVENTORY);
243 msg_print(_("ザックの中のアイテムをまとめ直した。", "You combine some items in your pack."));
248 * @brief プレイヤーの所持スロットに存在するオブジェクトを並び替える /
249 * Reorder items in the pack
250 * @param player_ptr プレイヤーへの参照ポインタ
252 * Note special handling of the "overflow" slot
254 void reorder_pack(PlayerType *player_ptr)
263 for (i = 0; i < INVEN_PACK; i++) {
264 if ((i == INVEN_PACK) && (player_ptr->inven_cnt == INVEN_PACK)) {
268 o_ptr = &player_ptr->inventory_list[i];
269 if (!o_ptr->is_valid()) {
273 o_value = o_ptr->get_price();
274 for (j = 0; j < INVEN_PACK; j++) {
275 if (object_sort_comp(player_ptr, o_ptr, o_value, &player_ptr->inventory_list[j])) {
286 q_ptr->copy_from(&player_ptr->inventory_list[i]);
287 for (k = i; k > j; k--) {
288 (&player_ptr->inventory_list[k])->copy_from(&player_ptr->inventory_list[k - 1]);
291 (&player_ptr->inventory_list[j])->copy_from(q_ptr);
292 RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::INVENTORY);
296 msg_print(_("ザックの中のアイテムを並べ直した。", "You reorder some items in your pack."));
301 * @brief オブジェクトをプレイヤーが拾って所持スロットに納めるメインルーチン /
302 * Add an item to the players inventory, and return the slot used.
303 * @param o_ptr 拾うオブジェクトの構造体参照ポインタ
304 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
306 * If the new item can combine with an existing item in the inventory,\n
307 * it will do so, using "object_similar()" and "object_absorb()", else,\n
308 * the item will be placed into the "proper" location in the inventory.\n
310 * This function can be used to "over-fill" the player's pack, but only\n
311 * once, and such an action must trigger the "overflow" code immediately.\n
312 * Note that when the pack is being "over-filled", the new item must be\n
313 * placed into the "overflow" slot, and the "overflow" must take place\n
314 * before the pack is reordered, but (optionally) after the pack is\n
315 * combined. This may be tricky. See "dungeon.c" for info.\n
317 * Note that this code must remove any location/stack information\n
318 * from the object once it is placed into the inventory.\n
320 int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr)
322 INVENTORY_IDX i, j, k;
323 INVENTORY_IDX n = -1;
326 auto &rfu = RedrawingFlagsUpdater::get_instance();
327 const auto flags_swrf = {
328 SubWindowRedrawingFlag::INVENTORY,
329 SubWindowRedrawingFlag::PLAYER,
331 for (j = 0; j < INVEN_PACK; j++) {
332 j_ptr = &player_ptr->inventory_list[j];
333 if (!j_ptr->is_valid()) {
338 if (object_similar(j_ptr, o_ptr)) {
339 object_absorb(j_ptr, o_ptr);
340 rfu.set_flag(StatusRedrawingFlag::BONUS);
341 rfu.set_flags(flags_swrf);
346 if (player_ptr->inven_cnt > INVEN_PACK) {
350 for (j = 0; j <= INVEN_PACK; j++) {
351 j_ptr = &player_ptr->inventory_list[j];
352 if (!j_ptr->is_valid()) {
358 if (i < INVEN_PACK) {
359 const auto o_value = o_ptr->get_price();
360 for (j = 0; j < INVEN_PACK; j++) {
361 if (object_sort_comp(player_ptr, o_ptr, o_value, &player_ptr->inventory_list[j])) {
367 for (k = n; k >= i; k--) {
368 (&player_ptr->inventory_list[k + 1])->copy_from(&player_ptr->inventory_list[k]);
371 (&player_ptr->inventory_list[i])->wipe();
374 (&player_ptr->inventory_list[i])->copy_from(o_ptr);
375 j_ptr = &player_ptr->inventory_list[i];
376 j_ptr->held_m_idx = 0;
377 j_ptr->iy = j_ptr->ix = 0;
378 j_ptr->marked.clear().set(OmType::TOUCHED);
380 player_ptr->inven_cnt++;
381 const auto flags_srf = {
382 StatusRedrawingFlag::BONUS,
383 StatusRedrawingFlag::COMBINATION,
384 StatusRedrawingFlag::REORDER,
386 rfu.set_flags(flags_srf);
387 rfu.set_flags(flags_swrf);
392 * @brief アイテムを拾う際にザックから溢れずに済むかを判定する /
393 * Check if we have space for an item in the pack without overflow
394 * @param player_ptr プレイヤーへの参照ポインタ
395 * @param o_ptr 拾いたいオブジェクトの構造体参照ポインタ
396 * @return 溢れずに済むならTRUEを返す
398 bool check_store_item_to_inventory(PlayerType *player_ptr, const ItemEntity *o_ptr)
400 if (player_ptr->inven_cnt < INVEN_PACK) {
404 for (int j = 0; j < INVEN_PACK; j++) {
405 auto *j_ptr = &player_ptr->inventory_list[j];
406 if (!j_ptr->is_valid()) {
410 if (object_similar(j_ptr, o_ptr)) {
419 * @brief 装備スロットからオブジェクトを外すメインルーチン /
420 * Take off (some of) a non-cursed equipment item
421 * @param player_ptr プレイヤーへの参照ポインタ
422 * @param item オブジェクトを外したい所持テーブルのID
424 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
426 * Note that only one item at a time can be wielded per slot.\n
427 * Note that taking off an item when "full" may cause that item\n
428 * to fall to the ground.\n
429 * Return the inventory slot into which the item is placed.\n
431 INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
438 o_ptr = &player_ptr->inventory_list[item];
443 if (amt > o_ptr->number) {
447 q_ptr->copy_from(o_ptr);
449 const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
450 if (((item == INVEN_MAIN_HAND) || (item == INVEN_SUB_HAND)) && o_ptr->is_melee_weapon()) {
451 act = _("を装備からはずした", "You were wielding");
452 } else if (item == INVEN_BOW) {
453 act = _("を装備からはずした", "You were holding");
454 } else if (item == INVEN_LITE) {
455 act = _("を光源からはずした", "You were holding");
457 act = _("を装備からはずした", "You were wearing");
460 inven_item_increase(player_ptr, item, -amt);
461 inven_item_optimize(player_ptr, item);
463 slot = store_item_to_inventory(player_ptr, q_ptr);
465 msg_format("%s(%c)%s。", item_name.data(), index_to_label(slot), act);
467 msg_format("%s %s (%c).", act, item_name.data(), index_to_label(slot));