OSDN Git Service

Merge pull request #1927 from dis-/feature/fix-special-disturb
[hengbandforosx/hengbandosx.git] / src / object / object-stack.cpp
1 /*!
2  * @brief 同種のアイテムをインベントリや床に重ね合わせたり、その判断を行う処理
3  * @date 2020/06/03
4  * @author Hourier
5  */
6
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/object-smith.h"
11 #include "object-enchant/special-object-flags.h"
12 #include "object-enchant/trc-types.h"
13 #include "object/object-kind.h"
14 #include "object/object-value.h"
15 #include "perception/object-perception.h"
16 #include "sv-definition/sv-other-types.h"
17 #include "system/object-type-definition.h"
18
19 /*!
20  * @brief 魔法棒やロッドのスロット分割時に使用回数を分配する /
21  * Distribute charges of rods or wands.
22  * @param o_ptr 分割元オブジェクトの構造体参照ポインタ source item
23  * @param q_ptr 分割先オブジェクトの構造体参照ポインタ target item, must be of the same type as o_ptr
24  * @param amt 分割したい回数量 number of items that are transfered
25  * @details
26  * Hack -- If rods or wands are dropped, the total maximum timeout or\n
27  * charges need to be allocated between the two stacks.  If all the items\n
28  * are being dropped, it makes for a neater message to leave the original\n
29  * stack's pval alone. -LM-\n
30  */
31 void distribute_charges(object_type *o_ptr, object_type *q_ptr, int amt)
32 {
33     if ((o_ptr->tval != ItemKindType::WAND) && (o_ptr->tval != ItemKindType::ROD))
34         return;
35
36     q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
37     if (amt < o_ptr->number)
38         o_ptr->pval -= q_ptr->pval;
39
40     if ((o_ptr->tval != ItemKindType::ROD) || !o_ptr->timeout)
41         return;
42
43     if (q_ptr->pval > o_ptr->timeout)
44         q_ptr->timeout = o_ptr->timeout;
45     else
46         q_ptr->timeout = q_ptr->pval;
47
48     if (amt < o_ptr->number)
49         o_ptr->timeout -= q_ptr->timeout;
50 }
51
52 /*!
53  * @brief 魔法棒やロッドの使用回数を減らす /
54  * @param o_ptr オブジェクトの構造体参照ポインタ source item
55  * @param amt 減らしたい回数量 number of items that are transfered
56  * @details
57  * Hack -- If rods or wand are destroyed, the total maximum timeout or\n
58  * charges of the stack needs to be reduced, unless all the items are\n
59  * being destroyed. -LM-\n
60  */
61 void reduce_charges(object_type *o_ptr, int amt)
62 {
63     if (((o_ptr->tval == ItemKindType::WAND) || (o_ptr->tval == ItemKindType::ROD)) && (amt < o_ptr->number)) {
64         o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
65     }
66 }
67
68 /*!
69  * @brief 両オブジェクトをスロットに重ね合わせ可能な最大数を返す。
70  * Determine if an item can partly absorb a second item. Return maximum number of stack.
71  * @param o_ptr 検証したいオブジェクトの構造体参照ポインタ1
72  * @param j_ptr 検証したいオブジェクトの構造体参照ポインタ2
73  * @return 重ね合わせ可能なアイテム数
74  */
75 int object_similar_part(const object_type *o_ptr, const object_type *j_ptr)
76 {
77     const int max_stack_size = 99;
78     int max_num = max_stack_size;
79     if (o_ptr->k_idx != j_ptr->k_idx)
80         return 0;
81
82     switch (o_ptr->tval) {
83     case ItemKindType::CHEST:
84     case ItemKindType::CARD:
85     case ItemKindType::CAPTURE: {
86         return 0;
87     }
88     case ItemKindType::STATUE: {
89         if ((o_ptr->sval != SV_PHOTO) || (j_ptr->sval != SV_PHOTO))
90             return 0;
91         if (o_ptr->pval != j_ptr->pval)
92             return 0;
93         break;
94     }
95     case ItemKindType::FIGURINE:
96     case ItemKindType::CORPSE: {
97         if (o_ptr->pval != j_ptr->pval)
98             return 0;
99
100         break;
101     }
102     case ItemKindType::FOOD:
103     case ItemKindType::POTION:
104     case ItemKindType::SCROLL: {
105         break;
106     }
107     case ItemKindType::STAFF: {
108         if ((!(o_ptr->ident & (IDENT_EMPTY)) && !o_ptr->is_known()) || (!(j_ptr->ident & (IDENT_EMPTY)) && !j_ptr->is_known()))
109             return 0;
110
111         if (o_ptr->pval != j_ptr->pval)
112             return 0;
113
114         break;
115     }
116     case ItemKindType::WAND: {
117         if ((!(o_ptr->ident & (IDENT_EMPTY)) && !o_ptr->is_known()) || (!(j_ptr->ident & (IDENT_EMPTY)) && !j_ptr->is_known()))
118             return 0;
119
120         break;
121     }
122     case ItemKindType::ROD: {
123         max_num = std::min(max_num, MAX_SHORT / k_info[o_ptr->k_idx].pval);
124         break;
125     }
126     case ItemKindType::BOW:
127     case ItemKindType::DIGGING:
128     case ItemKindType::HAFTED:
129     case ItemKindType::POLEARM:
130     case ItemKindType::SWORD:
131     case ItemKindType::BOOTS:
132     case ItemKindType::GLOVES:
133     case ItemKindType::HELM:
134     case ItemKindType::CROWN:
135     case ItemKindType::SHIELD:
136     case ItemKindType::CLOAK:
137     case ItemKindType::SOFT_ARMOR:
138     case ItemKindType::HARD_ARMOR:
139     case ItemKindType::DRAG_ARMOR:
140     case ItemKindType::RING:
141     case ItemKindType::AMULET:
142     case ItemKindType::LITE:
143     case ItemKindType::WHISTLE: {
144         if (!o_ptr->is_known() || !j_ptr->is_known())
145             return 0;
146     }
147         /* Fall through */
148     case ItemKindType::BOLT:
149     case ItemKindType::ARROW:
150     case ItemKindType::SHOT: {
151         if (o_ptr->is_known() != j_ptr->is_known())
152             return 0;
153         if (o_ptr->feeling != j_ptr->feeling)
154             return 0;
155         if (o_ptr->to_h != j_ptr->to_h)
156             return 0;
157         if (o_ptr->to_d != j_ptr->to_d)
158             return 0;
159         if (o_ptr->to_a != j_ptr->to_a)
160             return 0;
161         if (o_ptr->pval != j_ptr->pval)
162             return 0;
163         if (o_ptr->is_artifact() || j_ptr->is_artifact())
164             return 0;
165         if (o_ptr->name2 != j_ptr->name2)
166             return 0;
167         if (o_ptr->xtra3 != j_ptr->xtra3)
168             return 0;
169         if (o_ptr->xtra4 != j_ptr->xtra4)
170             return 0;
171         if (o_ptr->xtra1 || j_ptr->xtra1)
172             return 0;
173         if (o_ptr->timeout || j_ptr->timeout)
174             return 0;
175         if (o_ptr->ac != j_ptr->ac)
176             return 0;
177         if (o_ptr->dd != j_ptr->dd)
178             return 0;
179         if (o_ptr->ds != j_ptr->ds)
180             return 0;
181         if (Smith::object_effect(o_ptr) != Smith::object_effect(j_ptr))
182             return 0;
183         if (Smith::object_activation(o_ptr) != Smith::object_activation(j_ptr))
184             return 0;
185         break;
186     }
187     default: {
188         if (!o_ptr->is_known() || !j_ptr->is_known())
189             return 0;
190
191         break;
192     }
193     }
194
195     if (o_ptr->art_flags != j_ptr->art_flags)
196         return 0;
197
198     if (o_ptr->curse_flags != j_ptr->curse_flags)
199         return 0;
200     if ((o_ptr->ident & (IDENT_BROKEN)) != (j_ptr->ident & (IDENT_BROKEN)))
201         return 0;
202
203     if (o_ptr->inscription && j_ptr->inscription && (o_ptr->inscription != j_ptr->inscription))
204         return 0;
205
206     if (!stack_force_notes && (o_ptr->inscription != j_ptr->inscription))
207         return 0;
208     if (!stack_force_costs && (o_ptr->discount != j_ptr->discount))
209         return 0;
210
211     return max_num;
212 }
213
214 /*!
215  * @brief 両オブジェクトをスロットに重ねることができるかどうかを返す。
216  * Determine if an item can absorb a second item.
217  * @param o_ptr 検証したいオブジェクトの構造体参照ポインタ1
218  * @param j_ptr 検証したいオブジェクトの構造体参照ポインタ2
219  * @return 重ね合わせ可能ならばTRUEを返す。
220  */
221 bool object_similar(const object_type *o_ptr, const object_type *j_ptr)
222 {
223     int total = o_ptr->number + j_ptr->number;
224     int max_num = object_similar_part(o_ptr, j_ptr);
225     if (!max_num)
226         return false;
227     if (total > max_num)
228         return 0;
229
230     return true;
231 }
232
233 /*!
234  * @brief 両オブジェクトをスロットに重ね合わせる。
235  * Allow one item to "absorb" another, assuming they are similar
236  * @param o_ptr 重ね合わせ先のオブジェクトの構造体参照ポインタ
237  * @param j_ptr 重ね合わせ元のオブジェクトの構造体参照ポインタ
238  */
239 void object_absorb(object_type *o_ptr, object_type *j_ptr)
240 {
241     int max_num = object_similar_part(o_ptr, j_ptr);
242     int total = o_ptr->number + j_ptr->number;
243     int diff = (total > max_num) ? total - max_num : 0;
244
245     o_ptr->number = (total > max_num) ? max_num : total;
246     if (j_ptr->is_known())
247         object_known(o_ptr);
248
249     if (((o_ptr->ident & IDENT_STORE) || (j_ptr->ident & IDENT_STORE)) && (!((o_ptr->ident & IDENT_STORE) && (j_ptr->ident & IDENT_STORE)))) {
250         if (j_ptr->ident & IDENT_STORE)
251             j_ptr->ident &= 0xEF;
252         if (o_ptr->ident & IDENT_STORE)
253             o_ptr->ident &= 0xEF;
254     }
255
256     if (j_ptr->is_fully_known())
257         o_ptr->ident |= (IDENT_FULL_KNOWN);
258     if (j_ptr->inscription)
259         o_ptr->inscription = j_ptr->inscription;
260     if (j_ptr->feeling)
261         o_ptr->feeling = j_ptr->feeling;
262     if (o_ptr->discount < j_ptr->discount)
263         o_ptr->discount = j_ptr->discount;
264     if (o_ptr->tval == ItemKindType::ROD) {
265         o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
266         o_ptr->timeout += j_ptr->timeout * (j_ptr->number - diff) / j_ptr->number;
267     }
268
269     if (o_ptr->tval == ItemKindType::WAND) {
270         o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
271     }
272 }