1 #include "inventory/inventory-object.h"
2 #include "core/player-update-types.h"
3 #include "core/window-redrawer.h"
4 #include "flavor/flavor-describer.h"
5 #include "floor/floor-object.h"
6 #include "inventory/inventory-slot-types.h"
7 #include "object-hook/hook-weapon.h"
8 #include "object/object-info.h"
9 #include "object/object-mark-types.h"
10 #include "object/object-stack.h"
11 #include "object/object-value.h"
12 #include "player-info/equipment-info.h"
13 #include "spell-realm/spells-craft.h"
14 #include "system/object-type-definition.h"
15 #include "system/player-type-definition.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 player_ptr->update |= (PU_BONUS);
58 player_ptr->update |= (PU_MANA);
59 player_ptr->update |= (PU_COMBINE);
60 player_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
62 if (o_ptr->number || !player_ptr->ele_attack) {
65 if (!(item == INVEN_MAIN_HAND) && !(item == INVEN_SUB_HAND)) {
68 if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND + INVEN_SUB_HAND - item)) {
72 set_ele_attack(player_ptr, 0, 0);
76 * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する /
77 * Erase an inventory slot if it has no more items
78 * @param player_ptr プレイヤーへの参照ポインタ
79 * @param item 消去したいプレイヤーのアイテム所持スロット
81 void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
83 auto *o_ptr = &player_ptr->inventory_list[item];
91 if (item >= INVEN_MAIN_HAND) {
92 player_ptr->equip_cnt--;
93 (&player_ptr->inventory_list[item])->wipe();
94 player_ptr->update |= PU_BONUS;
95 player_ptr->update |= PU_TORCH;
96 player_ptr->update |= PU_MANA;
98 player_ptr->window_flags |= PW_EQUIP;
99 player_ptr->window_flags |= PW_SPELL;
103 player_ptr->inven_cnt--;
105 for (i = item; i < INVEN_PACK; i++) {
106 player_ptr->inventory_list[i] = player_ptr->inventory_list[i + 1];
109 (&player_ptr->inventory_list[i])->wipe();
110 player_ptr->window_flags |= PW_INVEN;
111 player_ptr->window_flags |= PW_SPELL;
115 * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン /
116 * Drop (some of) a non-cursed inventory/equipment item
117 * @param player_ptr プレイヤーへの参照ポインタ
118 * @param item 所持テーブルのID
121 * The object will be dropped "near" the current location
123 void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
128 GAME_TEXT o_name[MAX_NLEN];
129 o_ptr = &player_ptr->inventory_list[item];
134 if (amt > o_ptr->number) {
138 if (item >= INVEN_MAIN_HAND) {
139 item = inven_takeoff(player_ptr, item, amt);
140 o_ptr = &player_ptr->inventory_list[item];
144 q_ptr->copy_from(o_ptr);
145 distribute_charges(o_ptr, q_ptr, amt);
148 describe_flavor(player_ptr, o_name, q_ptr, 0);
149 msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), o_name, index_to_label(item));
150 (void)drop_near(player_ptr, q_ptr, 0, player_ptr->y, player_ptr->x);
151 vary_item(player_ptr, item, -amt);
155 * @brief プレイヤーの所持スロットに存在するオブジェクトをまとめなおす /
156 * Combine items in the pack
158 * Note special handling of the "overflow" slot
160 void combine_pack(PlayerType *player_ptr)
163 bool is_first_combination = true;
164 bool combined = true;
165 while (is_first_combination || combined) {
166 is_first_combination = false;
169 for (int i = INVEN_PACK; i > 0; i--) {
171 o_ptr = &player_ptr->inventory_list[i];
175 for (int j = 0; j < i; j++) {
177 j_ptr = &player_ptr->inventory_list[j];
183 * Get maximum number of the stack if these
184 * are similar, get zero otherwise.
186 int max_num = object_similar_part(j_ptr, o_ptr);
188 bool is_max = (max_num != 0) && (j_ptr->number < max_num);
193 if (o_ptr->number + j_ptr->number <= max_num) {
195 object_absorb(j_ptr, o_ptr);
196 player_ptr->inven_cnt--;
198 for (k = i; k < INVEN_PACK; k++) {
199 player_ptr->inventory_list[k] = player_ptr->inventory_list[k + 1];
202 (&player_ptr->inventory_list[k])->wipe();
204 int old_num = o_ptr->number;
205 int remain = j_ptr->number + o_ptr->number - max_num;
206 object_absorb(j_ptr, o_ptr);
207 o_ptr->number = remain;
208 if (o_ptr->tval == ItemKindType::ROD) {
209 o_ptr->pval = o_ptr->pval * remain / old_num;
210 o_ptr->timeout = o_ptr->timeout * remain / old_num;
213 if (o_ptr->tval == ItemKindType::WAND) {
214 o_ptr->pval = o_ptr->pval * remain / old_num;
218 player_ptr->window_flags |= (PW_INVEN);
226 msg_print(_("ザックの中のアイテムをまとめ直した。", "You combine some items in your pack."));
231 * @brief プレイヤーの所持スロットに存在するオブジェクトを並び替える /
232 * Reorder items in the pack
233 * @param player_ptr プレイヤーへの参照ポインタ
235 * Note special handling of the "overflow" slot
237 void reorder_pack(PlayerType *player_ptr)
246 for (i = 0; i < INVEN_PACK; i++) {
247 if ((i == INVEN_PACK) && (player_ptr->inven_cnt == INVEN_PACK)) {
251 o_ptr = &player_ptr->inventory_list[i];
256 o_value = object_value(o_ptr);
257 for (j = 0; j < INVEN_PACK; j++) {
258 if (object_sort_comp(player_ptr, o_ptr, o_value, &player_ptr->inventory_list[j])) {
269 q_ptr->copy_from(&player_ptr->inventory_list[i]);
270 for (k = i; k > j; k--) {
271 (&player_ptr->inventory_list[k])->copy_from(&player_ptr->inventory_list[k - 1]);
274 (&player_ptr->inventory_list[j])->copy_from(q_ptr);
275 player_ptr->window_flags |= (PW_INVEN);
279 msg_print(_("ザックの中のアイテムを並べ直した。", "You reorder some items in your pack."));
284 * @brief オブジェクトをプレイヤーが拾って所持スロットに納めるメインルーチン /
285 * Add an item to the players inventory, and return the slot used.
286 * @param o_ptr 拾うオブジェクトの構造体参照ポインタ
287 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
289 * If the new item can combine with an existing item in the inventory,\n
290 * it will do so, using "object_similar()" and "object_absorb()", else,\n
291 * the item will be placed into the "proper" location in the inventory.\n
293 * This function can be used to "over-fill" the player's pack, but only\n
294 * once, and such an action must trigger the "overflow" code immediately.\n
295 * Note that when the pack is being "over-filled", the new item must be\n
296 * placed into the "overflow" slot, and the "overflow" must take place\n
297 * before the pack is reordered, but (optionally) after the pack is\n
298 * combined. This may be tricky. See "dungeon.c" for info.\n
300 * Note that this code must remove any location/stack information\n
301 * from the object once it is placed into the inventory.\n
303 int16_t store_item_to_inventory(PlayerType *player_ptr, ObjectType *o_ptr)
305 INVENTORY_IDX i, j, k;
306 INVENTORY_IDX n = -1;
309 for (j = 0; j < INVEN_PACK; j++) {
310 j_ptr = &player_ptr->inventory_list[j];
316 if (object_similar(j_ptr, o_ptr)) {
317 object_absorb(j_ptr, o_ptr);
319 player_ptr->update |= (PU_BONUS);
320 player_ptr->window_flags |= (PW_INVEN | PW_PLAYER);
325 if (player_ptr->inven_cnt > INVEN_PACK) {
329 for (j = 0; j <= INVEN_PACK; j++) {
330 j_ptr = &player_ptr->inventory_list[j];
337 if (i < INVEN_PACK) {
338 int32_t o_value = object_value(o_ptr);
339 for (j = 0; j < INVEN_PACK; j++) {
340 if (object_sort_comp(player_ptr, o_ptr, o_value, &player_ptr->inventory_list[j])) {
346 for (k = n; k >= i; k--) {
347 (&player_ptr->inventory_list[k + 1])->copy_from(&player_ptr->inventory_list[k]);
350 (&player_ptr->inventory_list[i])->wipe();
353 (&player_ptr->inventory_list[i])->copy_from(o_ptr);
354 j_ptr = &player_ptr->inventory_list[i];
355 j_ptr->held_m_idx = 0;
356 j_ptr->iy = j_ptr->ix = 0;
357 j_ptr->marked = OM_TOUCHED;
359 player_ptr->inven_cnt++;
360 player_ptr->update |= (PU_BONUS | PU_COMBINE | PU_REORDER);
361 player_ptr->window_flags |= (PW_INVEN | PW_PLAYER);
367 * @brief アイテムを拾う際にザックから溢れずに済むかを判定する /
368 * Check if we have space for an item in the pack without overflow
369 * @param player_ptr プレイヤーへの参照ポインタ
370 * @param o_ptr 拾いたいオブジェクトの構造体参照ポインタ
371 * @return 溢れずに済むならTRUEを返す
373 bool check_store_item_to_inventory(PlayerType *player_ptr, const ObjectType *o_ptr)
375 if (player_ptr->inven_cnt < INVEN_PACK) {
379 for (int j = 0; j < INVEN_PACK; j++) {
380 auto *j_ptr = &player_ptr->inventory_list[j];
385 if (object_similar(j_ptr, o_ptr)) {
394 * @brief 装備スロットからオブジェクトを外すメインルーチン /
395 * Take off (some of) a non-cursed equipment item
396 * @param player_ptr プレイヤーへの参照ポインタ
397 * @param item オブジェクトを外したい所持テーブルのID
399 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
401 * Note that only one item at a time can be wielded per slot.\n
402 * Note that taking off an item when "full" may cause that item\n
403 * to fall to the ground.\n
404 * Return the inventory slot into which the item is placed.\n
406 INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
413 GAME_TEXT o_name[MAX_NLEN];
414 o_ptr = &player_ptr->inventory_list[item];
419 if (amt > o_ptr->number) {
423 q_ptr->copy_from(o_ptr);
425 describe_flavor(player_ptr, o_name, q_ptr, 0);
426 if (((item == INVEN_MAIN_HAND) || (item == INVEN_SUB_HAND)) && o_ptr->is_melee_weapon()) {
427 act = _("を装備からはずした", "You were wielding");
428 } else if (item == INVEN_BOW) {
429 act = _("を装備からはずした", "You were holding");
430 } else if (item == INVEN_LITE) {
431 act = _("を光源からはずした", "You were holding");
433 act = _("を装備からはずした", "You were wearing");
436 inven_item_increase(player_ptr, item, -amt);
437 inven_item_optimize(player_ptr, item);
439 slot = store_item_to_inventory(player_ptr, q_ptr);
441 msg_format("%s(%c)%s。", o_name, index_to_label(slot), act);
443 msg_format("%s %s (%c).", act, o_name, index_to_label(slot));