2 * @brief 同種のアイテムをインベントリや床に重ね合わせたり、その判断を行う処理
7 #include "object/object-stack.h"
8 #include "game-option/game-play-options.h"
9 #include "object-enchant/object-ego.h"
10 #include "object-enchant/special-object-flags.h"
11 #include "object-enchant/trc-types.h"
12 #include "object/object-value.h"
13 #include "object/tval-types.h"
14 #include "perception/object-perception.h"
15 #include "smith/object-smith.h"
16 #include "sv-definition/sv-other-types.h"
17 #include "system/baseitem-info.h"
18 #include "system/item-entity.h"
19 #include "util/bit-flags-calculator.h"
22 * @brief 魔法棒やロッドのスロット分割時に使用回数を分配する /
23 * Distribute charges of rods or wands.
24 * @param o_ptr 分割元オブジェクトの構造体参照ポインタ source item
25 * @param q_ptr 分割先オブジェクトの構造体参照ポインタ target item, must be of the same type as o_ptr
26 * @param amt 分割したい回数量 number of items that are transfered
28 * Hack -- If rods or wands are dropped, the total maximum timeout or\n
29 * charges need to be allocated between the two stacks. If all the items\n
30 * are being dropped, it makes for a neater message to leave the original\n
31 * stack's pval alone. -LM-\n
33 void distribute_charges(ItemEntity *o_ptr, ItemEntity *q_ptr, int amt)
35 if (!o_ptr->is_wand_rod()) {
39 q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
40 if (amt < o_ptr->number) {
41 o_ptr->pval -= q_ptr->pval;
44 if ((o_ptr->bi_key.tval() != ItemKindType::ROD) || !o_ptr->timeout) {
48 if (q_ptr->pval > o_ptr->timeout) {
49 q_ptr->timeout = o_ptr->timeout;
51 q_ptr->timeout = q_ptr->pval;
54 if (amt < o_ptr->number) {
55 o_ptr->timeout -= q_ptr->timeout;
60 * @brief 魔法棒やロッドの使用回数を減らす /
61 * @param o_ptr オブジェクトの構造体参照ポインタ source item
62 * @param amt 減らしたい回数量 number of items that are transfered
64 * Hack -- If rods or wand are destroyed, the total maximum timeout or\n
65 * charges of the stack needs to be reduced, unless all the items are\n
66 * being destroyed. -LM-\n
68 void reduce_charges(ItemEntity *o_ptr, int amt)
70 if (o_ptr->is_wand_rod() && (amt < o_ptr->number)) {
71 o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
76 * @brief 両オブジェクトをスロットに重ね合わせ可能な最大数を返す。
77 * Determine if an item can partly absorb a second item. Return maximum number of stack.
78 * @param o_ptr 検証したいオブジェクトの構造体参照ポインタ1
79 * @param j_ptr 検証したいオブジェクトの構造体参照ポインタ2
80 * @return 重ね合わせ可能なアイテム数
82 int object_similar_part(const ItemEntity *o_ptr, const ItemEntity *j_ptr)
84 if (o_ptr->bi_id != j_ptr->bi_id) {
88 constexpr auto max_stack_size = 99;
89 auto max_num = max_stack_size;
90 switch (o_ptr->bi_key.tval()) {
91 case ItemKindType::CHEST:
92 case ItemKindType::CARD:
93 case ItemKindType::CAPTURE:
95 case ItemKindType::STATUE: {
96 const auto o_sval = o_ptr->bi_key.sval();
97 const auto j_sval = j_ptr->bi_key.sval();
98 if ((o_sval != SV_PHOTO) || (j_sval != SV_PHOTO) || (o_ptr->pval != j_ptr->pval)) {
104 case ItemKindType::FIGURINE:
105 case ItemKindType::CORPSE:
106 if (o_ptr->pval != j_ptr->pval) {
111 case ItemKindType::FOOD:
112 case ItemKindType::POTION:
113 case ItemKindType::SCROLL:
115 case ItemKindType::STAFF:
116 if ((none_bits(o_ptr->ident, IDENT_EMPTY) && !o_ptr->is_known()) || (none_bits(j_ptr->ident, IDENT_EMPTY) && !j_ptr->is_known())) {
120 if (o_ptr->pval != j_ptr->pval) {
125 case ItemKindType::WAND:
126 if ((!(o_ptr->ident & (IDENT_EMPTY)) && !o_ptr->is_known()) || (!(j_ptr->ident & (IDENT_EMPTY)) && !j_ptr->is_known())) {
131 case ItemKindType::ROD:
132 max_num = std::min(max_num, MAX_SHORT / baseitems_info[o_ptr->bi_id].pval);
134 case ItemKindType::GLOVES:
135 if (o_ptr->is_glove_same_temper(j_ptr)) {
139 if (!o_ptr->is_known() || !j_ptr->is_known()) {
143 if (!o_ptr->can_pile(j_ptr)) {
148 case ItemKindType::LITE:
149 if (o_ptr->fuel != j_ptr->fuel) {
153 if (!o_ptr->can_pile(j_ptr)) {
158 case ItemKindType::BOW:
159 case ItemKindType::DIGGING:
160 case ItemKindType::HAFTED:
161 case ItemKindType::POLEARM:
162 case ItemKindType::SWORD:
163 case ItemKindType::BOOTS:
164 case ItemKindType::HELM:
165 case ItemKindType::CROWN:
166 case ItemKindType::SHIELD:
167 case ItemKindType::CLOAK:
168 case ItemKindType::SOFT_ARMOR:
169 case ItemKindType::HARD_ARMOR:
170 case ItemKindType::DRAG_ARMOR:
171 case ItemKindType::RING:
172 case ItemKindType::AMULET:
173 case ItemKindType::WHISTLE:
174 if (!o_ptr->is_known() || !j_ptr->is_known()) {
178 if (!o_ptr->can_pile(j_ptr)) {
183 case ItemKindType::BOLT:
184 case ItemKindType::ARROW:
185 case ItemKindType::SHOT:
186 if (!o_ptr->can_pile(j_ptr)) {
192 if (!o_ptr->is_known() || !j_ptr->is_known()) {
199 if (o_ptr->art_flags != j_ptr->art_flags) {
203 if (o_ptr->curse_flags != j_ptr->curse_flags) {
207 if (any_bits(o_ptr->ident, IDENT_BROKEN) != any_bits(j_ptr->ident, IDENT_BROKEN)) {
211 if (o_ptr->is_inscribed() && j_ptr->is_inscribed() && (o_ptr->inscription != j_ptr->inscription)) {
215 if (!stack_force_notes && (o_ptr->inscription != j_ptr->inscription)) {
219 if (!stack_force_costs && (o_ptr->discount != j_ptr->discount)) {
227 * @brief 両オブジェクトをスロットに重ねることができるかどうかを返す。
228 * Determine if an item can absorb a second item.
229 * @param o_ptr 検証したいオブジェクトの構造体参照ポインタ1
230 * @param j_ptr 検証したいオブジェクトの構造体参照ポインタ2
231 * @return 重ね合わせ可能ならばTRUEを返す。
233 bool object_similar(const ItemEntity *o_ptr, const ItemEntity *j_ptr)
235 int total = o_ptr->number + j_ptr->number;
236 int max_num = object_similar_part(o_ptr, j_ptr);
240 if (total > max_num) {
248 * @brief 両オブジェクトをスロットに重ね合わせる。
249 * Allow one item to "absorb" another, assuming they are similar
250 * @param o_ptr 重ね合わせ先のオブジェクトの構造体参照ポインタ
251 * @param j_ptr 重ね合わせ元のオブジェクトの構造体参照ポインタ
253 void object_absorb(ItemEntity *o_ptr, ItemEntity *j_ptr)
255 int max_num = object_similar_part(o_ptr, j_ptr);
256 int total = o_ptr->number + j_ptr->number;
257 int diff = (total > max_num) ? total - max_num : 0;
259 o_ptr->number = (total > max_num) ? max_num : total;
260 if (j_ptr->is_known()) {
264 if (((o_ptr->ident & IDENT_STORE) || (j_ptr->ident & IDENT_STORE)) && (!((o_ptr->ident & IDENT_STORE) && (j_ptr->ident & IDENT_STORE)))) {
265 if (j_ptr->ident & IDENT_STORE) {
266 j_ptr->ident &= 0xEF;
268 if (o_ptr->ident & IDENT_STORE) {
269 o_ptr->ident &= 0xEF;
273 if (j_ptr->is_fully_known()) {
274 o_ptr->ident |= (IDENT_FULL_KNOWN);
276 if (j_ptr->is_inscribed()) {
277 o_ptr->inscription = j_ptr->inscription;
279 if (j_ptr->feeling) {
280 o_ptr->feeling = j_ptr->feeling;
282 if (o_ptr->discount < j_ptr->discount) {
283 o_ptr->discount = j_ptr->discount;
286 const auto tval = o_ptr->bi_key.tval();
287 if (tval == ItemKindType::ROD) {
288 o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
289 o_ptr->timeout += j_ptr->timeout * (j_ptr->number - diff) / j_ptr->number;
292 if (tval == ItemKindType::WAND) {
293 o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;