OSDN Git Service

[Refactor] #40399 Moved drop_from_inventory(), combine_pack() and reorder_pack()...
[hengband/hengband.git] / src / inventory / inventory-object.c
1 #include "inventory/inventory-object.h"
2 #include "object/object-flavor.h"
3 #include "object/object2.h" // 暫定、相互参照している.
4 #include "player/player-effects.h" // 暫定、相互参照している.
5 #include "view/object-describer.h"
6
7 void vary_item(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
8 {
9     if (item >= 0) {
10         inven_item_increase(owner_ptr, item, num);
11         inven_item_describe(owner_ptr, item);
12         inven_item_optimize(owner_ptr, item);
13         return;
14     }
15
16     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
17     floor_item_increase(floor_ptr, 0 - item, num);
18     floor_item_describe(owner_ptr, 0 - item);
19     floor_item_optimize(owner_ptr, 0 - item);
20 }
21
22 /*!
23  * @brief アイテムを増減させ残り所持数メッセージを表示する /
24  * Increase the "number" of an item in the inventory
25  * @param owner_ptr プレーヤーへの参照ポインタ
26  * @param item 所持数を増やしたいプレイヤーのアイテム所持スロット
27  * @param num 増やしたい量
28  * @return なし
29  */
30 void inven_item_increase(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
31 {
32     object_type *o_ptr = &owner_ptr->inventory_list[item];
33     num += o_ptr->number;
34     if (num > 255)
35         num = 255;
36     else if (num < 0)
37         num = 0;
38
39     num -= o_ptr->number;
40     if (num == 0)
41         return;
42
43     o_ptr->number += num;
44     owner_ptr->total_weight += (num * o_ptr->weight);
45     owner_ptr->update |= (PU_BONUS);
46     owner_ptr->update |= (PU_MANA);
47     owner_ptr->update |= (PU_COMBINE);
48     owner_ptr->window |= (PW_INVEN | PW_EQUIP);
49
50     if (o_ptr->number || !owner_ptr->ele_attack)
51         return;
52     if (!(item == INVEN_RARM) && !(item == INVEN_LARM))
53         return;
54     if (has_melee_weapon(owner_ptr, INVEN_RARM + INVEN_LARM - item))
55         return;
56
57     set_ele_attack(owner_ptr, 0, 0);
58 }
59
60 /*!
61  * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する /
62  * Erase an inventory slot if it has no more items
63  * @param owner_ptr プレーヤーへの参照ポインタ
64  * @param item 消去したいプレイヤーのアイテム所持スロット
65  * @return なし
66  */
67 void inven_item_optimize(player_type *owner_ptr, INVENTORY_IDX item)
68 {
69     object_type *o_ptr = &owner_ptr->inventory_list[item];
70     if (!o_ptr->k_idx)
71         return;
72     if (o_ptr->number)
73         return;
74
75     if (item >= INVEN_RARM) {
76         owner_ptr->equip_cnt--;
77         object_wipe(&owner_ptr->inventory_list[item]);
78         owner_ptr->update |= PU_BONUS;
79         owner_ptr->update |= PU_TORCH;
80         owner_ptr->update |= PU_MANA;
81
82         owner_ptr->window |= PW_EQUIP;
83         owner_ptr->window |= PW_SPELL;
84         return;
85     }
86
87     owner_ptr->inven_cnt--;
88     int i;
89     for (i = item; i < INVEN_PACK; i++) {
90         owner_ptr->inventory_list[i] = owner_ptr->inventory_list[i + 1];
91     }
92
93     object_wipe(&owner_ptr->inventory_list[i]);
94     owner_ptr->window |= PW_INVEN;
95     owner_ptr->window |= PW_SPELL;
96 }
97
98 /*!
99  * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン /
100  * Drop (some of) a non-cursed inventory/equipment item
101  * @param owner_ptr プレーヤーへの参照ポインタ
102  * @param item 所持テーブルのID
103  * @param amt 落としたい個数
104  * @return なし
105  * @details
106  * The object will be dropped "near" the current location
107  */
108 void drop_from_inventory(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
109 {
110     object_type forge;
111     object_type *q_ptr;
112     object_type *o_ptr;
113     GAME_TEXT o_name[MAX_NLEN];
114     o_ptr = &owner_ptr->inventory_list[item];
115     if (amt <= 0)
116         return;
117
118     if (amt > o_ptr->number)
119         amt = o_ptr->number;
120
121     if (item >= INVEN_RARM) {
122         item = inven_takeoff(owner_ptr, item, amt);
123         o_ptr = &owner_ptr->inventory_list[item];
124     }
125
126     q_ptr = &forge;
127     object_copy(q_ptr, o_ptr);
128     distribute_charges(o_ptr, q_ptr, amt);
129
130     q_ptr->number = amt;
131     object_desc(owner_ptr, o_name, q_ptr, 0);
132     msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), o_name, index_to_label(item));
133     (void)drop_near(owner_ptr, q_ptr, 0, owner_ptr->y, owner_ptr->x);
134     vary_item(owner_ptr, item, -amt);
135 }
136
137 /*!
138  * @brief プレイヤーの所持スロットに存在するオブジェクトをまとめなおす /
139  * Combine items in the pack
140  * @return なし
141  * @details
142  * Note special handling of the "overflow" slot
143  */
144 void combine_pack(player_type *owner_ptr)
145 {
146     bool flag = FALSE;
147     bool is_first_combination = TRUE;
148     bool combined = TRUE;
149     while (is_first_combination || combined) {
150         is_first_combination = FALSE;
151         combined = FALSE;
152
153         for (int i = INVEN_PACK; i > 0; i--) {
154             object_type *o_ptr;
155             o_ptr = &owner_ptr->inventory_list[i];
156             if (!o_ptr->k_idx)
157                 continue;
158             for (int j = 0; j < i; j++) {
159                 object_type *j_ptr;
160                 j_ptr = &owner_ptr->inventory_list[j];
161                 if (!j_ptr->k_idx)
162                     continue;
163
164                 /*
165                  * Get maximum number of the stack if these
166                  * are similar, get zero otherwise.
167                  */
168                 int max_num = object_similar_part(j_ptr, o_ptr);
169
170                 bool is_max = (max_num != 0) && (j_ptr->number < max_num);
171                 if (!is_max)
172                     continue;
173
174                 if (o_ptr->number + j_ptr->number <= max_num) {
175                     flag = TRUE;
176                     object_absorb(j_ptr, o_ptr);
177                     owner_ptr->inven_cnt--;
178                     int k;
179                     for (k = i; k < INVEN_PACK; k++) {
180                         owner_ptr->inventory_list[k] = owner_ptr->inventory_list[k + 1];
181                     }
182
183                     object_wipe(&owner_ptr->inventory_list[k]);
184                 } else {
185                     int old_num = o_ptr->number;
186                     int remain = j_ptr->number + o_ptr->number - max_num;
187                     object_absorb(j_ptr, o_ptr);
188                     o_ptr->number = remain;
189                     if (o_ptr->tval == TV_ROD) {
190                         o_ptr->pval = o_ptr->pval * remain / old_num;
191                         o_ptr->timeout = o_ptr->timeout * remain / old_num;
192                     }
193
194                     if (o_ptr->tval == TV_WAND) {
195                         o_ptr->pval = o_ptr->pval * remain / old_num;
196                     }
197                 }
198
199                 owner_ptr->window |= (PW_INVEN);
200                 combined = TRUE;
201                 break;
202             }
203         }
204     }
205
206     if (flag)
207         msg_print(_("ザックの中のアイテムをまとめ直した。", "You combine some items in your pack."));
208 }
209
210 /*!
211  * @brief プレイヤーの所持スロットに存在するオブジェクトを並び替える /
212  * Reorder items in the pack
213  * @param owner_ptr プレーヤーへの参照ポインタ
214  * @return なし
215  * @details
216  * Note special handling of the "overflow" slot
217  */
218 void reorder_pack(player_type *owner_ptr)
219 {
220     int i, j, k;
221     s32b o_value;
222     object_type forge;
223     object_type *q_ptr;
224     object_type *o_ptr;
225     bool flag = FALSE;
226
227     for (i = 0; i < INVEN_PACK; i++) {
228         if ((i == INVEN_PACK) && (owner_ptr->inven_cnt == INVEN_PACK))
229             break;
230
231         o_ptr = &owner_ptr->inventory_list[i];
232         if (!o_ptr->k_idx)
233             continue;
234
235         o_value = object_value(o_ptr);
236         for (j = 0; j < INVEN_PACK; j++) {
237             if (object_sort_comp(o_ptr, o_value, &owner_ptr->inventory_list[j]))
238                 break;
239         }
240
241         if (j >= i)
242             continue;
243
244         flag = TRUE;
245         q_ptr = &forge;
246         object_copy(q_ptr, &owner_ptr->inventory_list[i]);
247         for (k = i; k > j; k--) {
248             object_copy(&owner_ptr->inventory_list[k], &owner_ptr->inventory_list[k - 1]);
249         }
250
251         object_copy(&owner_ptr->inventory_list[j], q_ptr);
252         owner_ptr->window |= (PW_INVEN);
253     }
254
255     if (flag)
256         msg_print(_("ザックの中のアイテムを並べ直した。", "You reorder some items in your pack."));
257 }