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-generator.h"
9 #include "object/object-info.h"
10 #include "object/object-mark-types.h"
11 #include "object/object-stack.h"
12 #include "object/object-value.h"
13 #include "spell-realm/spells-craft.h"
14 #include "util/object-sort.h"
15 #include "view/display-messages.h"
16 #include "view/object-describer.h"
18 void vary_item(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
21 inven_item_increase(owner_ptr, item, num);
22 inven_item_describe(owner_ptr, item);
23 inven_item_optimize(owner_ptr, item);
27 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
28 floor_item_increase(floor_ptr, 0 - item, num);
29 floor_item_describe(owner_ptr, 0 - item);
30 floor_item_optimize(owner_ptr, 0 - item);
34 * @brief アイテムを増減させ残り所持数メッセージを表示する /
35 * Increase the "number" of an item in the inventory
36 * @param owner_ptr プレーヤーへの参照ポインタ
37 * @param item 所持数を増やしたいプレイヤーのアイテム所持スロット
41 void inven_item_increase(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
43 object_type *o_ptr = &owner_ptr->inventory_list[item];
55 owner_ptr->total_weight += (num * o_ptr->weight);
56 owner_ptr->update |= (PU_BONUS);
57 owner_ptr->update |= (PU_MANA);
58 owner_ptr->update |= (PU_COMBINE);
59 owner_ptr->window |= (PW_INVEN | PW_EQUIP);
61 if (o_ptr->number || !owner_ptr->ele_attack)
63 if (!(item == INVEN_RARM) && !(item == INVEN_LARM))
65 if (has_melee_weapon(owner_ptr, INVEN_RARM + INVEN_LARM - item))
68 set_ele_attack(owner_ptr, 0, 0);
72 * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する /
73 * Erase an inventory slot if it has no more items
74 * @param owner_ptr プレーヤーへの参照ポインタ
75 * @param item 消去したいプレイヤーのアイテム所持スロット
78 void inven_item_optimize(player_type *owner_ptr, INVENTORY_IDX item)
80 object_type *o_ptr = &owner_ptr->inventory_list[item];
86 if (item >= INVEN_RARM) {
87 owner_ptr->equip_cnt--;
88 object_wipe(&owner_ptr->inventory_list[item]);
89 owner_ptr->update |= PU_BONUS;
90 owner_ptr->update |= PU_TORCH;
91 owner_ptr->update |= PU_MANA;
93 owner_ptr->window |= PW_EQUIP;
94 owner_ptr->window |= PW_SPELL;
98 owner_ptr->inven_cnt--;
100 for (i = item; i < INVEN_PACK; i++) {
101 owner_ptr->inventory_list[i] = owner_ptr->inventory_list[i + 1];
104 object_wipe(&owner_ptr->inventory_list[i]);
105 owner_ptr->window |= PW_INVEN;
106 owner_ptr->window |= PW_SPELL;
110 * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン /
111 * Drop (some of) a non-cursed inventory/equipment item
112 * @param owner_ptr プレーヤーへの参照ポインタ
113 * @param item 所持テーブルのID
117 * The object will be dropped "near" the current location
119 void drop_from_inventory(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
124 GAME_TEXT o_name[MAX_NLEN];
125 o_ptr = &owner_ptr->inventory_list[item];
129 if (amt > o_ptr->number)
132 if (item >= INVEN_RARM) {
133 item = inven_takeoff(owner_ptr, item, amt);
134 o_ptr = &owner_ptr->inventory_list[item];
138 object_copy(q_ptr, o_ptr);
139 distribute_charges(o_ptr, q_ptr, amt);
142 describe_flavor(owner_ptr, o_name, q_ptr, 0);
143 msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), o_name, index_to_label(item));
144 (void)drop_near(owner_ptr, q_ptr, 0, owner_ptr->y, owner_ptr->x);
145 vary_item(owner_ptr, item, -amt);
149 * @brief プレイヤーの所持スロットに存在するオブジェクトをまとめなおす /
150 * Combine items in the pack
153 * Note special handling of the "overflow" slot
155 void combine_pack(player_type *owner_ptr)
158 bool is_first_combination = TRUE;
159 bool combined = TRUE;
160 while (is_first_combination || combined) {
161 is_first_combination = FALSE;
164 for (int i = INVEN_PACK; i > 0; i--) {
166 o_ptr = &owner_ptr->inventory_list[i];
169 for (int j = 0; j < i; j++) {
171 j_ptr = &owner_ptr->inventory_list[j];
176 * Get maximum number of the stack if these
177 * are similar, get zero otherwise.
179 int max_num = object_similar_part(j_ptr, o_ptr);
181 bool is_max = (max_num != 0) && (j_ptr->number < max_num);
185 if (o_ptr->number + j_ptr->number <= max_num) {
187 object_absorb(j_ptr, o_ptr);
188 owner_ptr->inven_cnt--;
190 for (k = i; k < INVEN_PACK; k++) {
191 owner_ptr->inventory_list[k] = owner_ptr->inventory_list[k + 1];
194 object_wipe(&owner_ptr->inventory_list[k]);
196 int old_num = o_ptr->number;
197 int remain = j_ptr->number + o_ptr->number - max_num;
198 object_absorb(j_ptr, o_ptr);
199 o_ptr->number = remain;
200 if (o_ptr->tval == TV_ROD) {
201 o_ptr->pval = o_ptr->pval * remain / old_num;
202 o_ptr->timeout = o_ptr->timeout * remain / old_num;
205 if (o_ptr->tval == TV_WAND) {
206 o_ptr->pval = o_ptr->pval * remain / old_num;
210 owner_ptr->window |= (PW_INVEN);
218 msg_print(_("ザックの中のアイテムをまとめ直した。", "You combine some items in your pack."));
222 * @brief プレイヤーの所持スロットに存在するオブジェクトを並び替える /
223 * Reorder items in the pack
224 * @param owner_ptr プレーヤーへの参照ポインタ
227 * Note special handling of the "overflow" slot
229 void reorder_pack(player_type *owner_ptr)
238 for (i = 0; i < INVEN_PACK; i++) {
239 if ((i == INVEN_PACK) && (owner_ptr->inven_cnt == INVEN_PACK))
242 o_ptr = &owner_ptr->inventory_list[i];
246 o_value = object_value(owner_ptr, o_ptr);
247 for (j = 0; j < INVEN_PACK; j++) {
248 if (object_sort_comp(owner_ptr, o_ptr, o_value, &owner_ptr->inventory_list[j]))
257 object_copy(q_ptr, &owner_ptr->inventory_list[i]);
258 for (k = i; k > j; k--) {
259 object_copy(&owner_ptr->inventory_list[k], &owner_ptr->inventory_list[k - 1]);
262 object_copy(&owner_ptr->inventory_list[j], q_ptr);
263 owner_ptr->window |= (PW_INVEN);
267 msg_print(_("ザックの中のアイテムを並べ直した。", "You reorder some items in your pack."));
271 * @brief オブジェクトをプレイヤーが拾って所持スロットに納めるメインルーチン /
272 * Add an item to the players inventory, and return the slot used.
273 * @param o_ptr 拾うオブジェクトの構造体参照ポインタ
274 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
276 * If the new item can combine with an existing item in the inventory,\n
277 * it will do so, using "object_similar()" and "object_absorb()", else,\n
278 * the item will be placed into the "proper" location in the inventory.\n
280 * This function can be used to "over-fill" the player's pack, but only\n
281 * once, and such an action must trigger the "overflow" code immediately.\n
282 * Note that when the pack is being "over-filled", the new item must be\n
283 * placed into the "overflow" slot, and the "overflow" must take place\n
284 * before the pack is reordered, but (optionally) after the pack is\n
285 * combined. This may be tricky. See "dungeon.c" for info.\n
287 * Note that this code must remove any location/stack information\n
288 * from the object once it is placed into the inventory.\n
290 s16b store_item_to_inventory(player_type *owner_ptr, object_type *o_ptr)
292 INVENTORY_IDX i, j, k;
293 INVENTORY_IDX n = -1;
296 for (j = 0; j < INVEN_PACK; j++) {
297 j_ptr = &owner_ptr->inventory_list[j];
302 if (object_similar(j_ptr, o_ptr)) {
303 object_absorb(j_ptr, o_ptr);
305 owner_ptr->total_weight += (o_ptr->number * o_ptr->weight);
306 owner_ptr->update |= (PU_BONUS);
307 owner_ptr->window |= (PW_INVEN);
312 if (owner_ptr->inven_cnt > INVEN_PACK)
315 for (j = 0; j <= INVEN_PACK; j++) {
316 j_ptr = &owner_ptr->inventory_list[j];
322 if (i < INVEN_PACK) {
323 s32b o_value = object_value(owner_ptr, o_ptr);
324 for (j = 0; j < INVEN_PACK; j++) {
325 if (object_sort_comp(owner_ptr, o_ptr, o_value, &owner_ptr->inventory_list[j]))
330 for (k = n; k >= i; k--) {
331 object_copy(&owner_ptr->inventory_list[k + 1], &owner_ptr->inventory_list[k]);
334 object_wipe(&owner_ptr->inventory_list[i]);
337 object_copy(&owner_ptr->inventory_list[i], o_ptr);
338 j_ptr = &owner_ptr->inventory_list[i];
339 j_ptr->next_o_idx = 0;
340 j_ptr->held_m_idx = 0;
341 j_ptr->iy = j_ptr->ix = 0;
342 j_ptr->marked = OM_TOUCHED;
344 owner_ptr->total_weight += (j_ptr->number * j_ptr->weight);
345 owner_ptr->inven_cnt++;
346 owner_ptr->update |= (PU_BONUS | PU_COMBINE | PU_REORDER);
347 owner_ptr->window |= (PW_INVEN);
353 * @brief アイテムを拾う際にザックから溢れずに済むかを判定する /
354 * Check if we have space for an item in the pack without overflow
355 * @param owner_ptr プレーヤーへの参照ポインタ
356 * @param o_ptr 拾いたいオブジェクトの構造体参照ポインタ
357 * @return 溢れずに済むならTRUEを返す
359 bool check_store_item_to_inventory(player_type *player_ptr, object_type *o_ptr)
364 if (player_ptr->inven_cnt < INVEN_PACK)
367 for (int j = 0; j < INVEN_PACK; j++) {
368 object_type *j_ptr = &player_ptr->inventory_list[j];
372 if (object_similar(j_ptr, o_ptr))
380 * @brief 装備スロットからオブジェクトを外すメインルーチン /
381 * Take off (some of) a non-cursed equipment item
382 * @param owner_ptr プレーヤーへの参照ポインタ
383 * @param item オブジェクトを外したい所持テーブルのID
385 * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
387 * Note that only one item at a time can be wielded per slot.\n
388 * Note that taking off an item when "full" may cause that item\n
389 * to fall to the ground.\n
390 * Return the inventory slot into which the item is placed.\n
392 INVENTORY_IDX inven_takeoff(player_type *owner_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
399 GAME_TEXT o_name[MAX_NLEN];
400 o_ptr = &owner_ptr->inventory_list[item];
404 if (amt > o_ptr->number)
407 object_copy(q_ptr, o_ptr);
409 describe_flavor(owner_ptr, o_name, q_ptr, 0);
410 if (((item == INVEN_RARM) || (item == INVEN_LARM)) && object_is_melee_weapon(o_ptr)) {
411 act = _("を装備からはずした", "You were wielding");
412 } else if (item == INVEN_BOW) {
413 act = _("を装備からはずした", "You were holding");
414 } else if (item == INVEN_LITE) {
415 act = _("を光源からはずした", "You were holding");
417 act = _("を装備からはずした", "You were wearing");
420 inven_item_increase(owner_ptr, item, -amt);
421 inven_item_optimize(owner_ptr, item);
423 slot = store_item_to_inventory(owner_ptr, q_ptr);
425 msg_format("%s(%c)%s。", o_name, index_to_label(slot), act);
427 msg_format("%s %s (%c).", act, o_name, index_to_label(slot));