OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / store / store-util.cpp
1 /*!
2  * @brief 店舗処理関係のユーティリティ
3  * @date 2020/03/20
4  * @author Hourier
5  */
6
7 #include "store/store-util.h"
8 #include "object-enchant/item-feeling.h"
9 #include "object-enchant/special-object-flags.h"
10 #include "object/object-value.h"
11 #include "object/tval-types.h"
12 #include "system/baseitem-info.h"
13 #include "system/item-entity.h"
14
15 store_type *st_ptr = nullptr;
16
17 /*!
18  * @brief 店舗のオブジェクト数を増やす /
19  * Add the item "o_ptr" to a real stores inventory.
20  * @param item 増やしたいアイテムのID
21  * @param num 増やしたい数
22  * @details
23  * <pre>
24  * Increase, by a given amount, the number of a certain item
25  * in a certain store.  This can result in zero items.
26  * </pre>
27  */
28 void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num)
29 {
30     ItemEntity *o_ptr;
31     o_ptr = &st_ptr->stock[item];
32     int cnt = o_ptr->number + num;
33     if (cnt > 255) {
34         cnt = 255;
35     } else if (cnt < 0) {
36         cnt = 0;
37     }
38
39     num = cnt - o_ptr->number;
40     o_ptr->number += num;
41 }
42
43 /*!
44  * @brief 店舗のオブジェクト数を削除する /
45  * Remove a slot if it is empty
46  * @param item 削除したいアイテムのID
47  */
48 void store_item_optimize(INVENTORY_IDX item)
49 {
50     const auto *o_ptr = &st_ptr->stock[item];
51     if (!o_ptr->is_valid() || (o_ptr->number != 0)) {
52         return;
53     }
54
55     st_ptr->stock_num--;
56     for (int j = item; j < st_ptr->stock_num; j++) {
57         st_ptr->stock[j] = st_ptr->stock[j + 1];
58     }
59
60     (&st_ptr->stock[st_ptr->stock_num])->wipe();
61 }
62
63 /*!
64  * @brief 店舗の品揃え変化のためにアイテムを削除する /
65  * Attempt to delete (some of) a random item from the store
66  * @details
67  * <pre>
68  * Hack -- we attempt to "maintain" piles of items when possible.
69  * </pre>
70  */
71 void store_delete(void)
72 {
73     INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num);
74     int num = st_ptr->stock[what].number;
75     if (randint0(100) < 50) {
76         num = (num + 1) / 2;
77     }
78
79     if (randint0(100) < 50) {
80         num = 1;
81     }
82
83     if (st_ptr->stock[what].is_wand_rod()) {
84         st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number;
85     }
86
87     store_item_increase(what, -num);
88     store_item_optimize(what);
89 }
90
91 /*!
92  * @brief 店舗販売中の杖と魔法棒のpvalのリストを返す
93  * @param j_ptr これから売ろうとしているオブジェクト
94  * @return plavリスト(充填数)
95  * @details
96  * 回数の違う杖と魔法棒がスロットを圧迫するのでスロット数制限をかける
97  */
98 std::vector<PARAMETER_VALUE> store_same_magic_device_pvals(ItemEntity *j_ptr)
99 {
100     auto list = std::vector<PARAMETER_VALUE>();
101     for (INVENTORY_IDX i = 0; i < st_ptr->stock_num; i++) {
102         auto *o_ptr = &st_ptr->stock[i];
103         if ((o_ptr == j_ptr) || (o_ptr->bi_id != j_ptr->bi_id) || !o_ptr->is_wand_staff()) {
104             continue;
105         }
106
107         list.push_back(o_ptr->pval);
108     }
109
110     return list;
111 }
112
113 /*!
114  * @brief 店舗に並べた品を同一品であるかどうか判定する /
115  * Determine if a store item can "absorb" another item
116  * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
117  * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
118  * @return 同一扱いできるならTRUEを返す
119  * @details
120  * <pre>
121  * See "object_similar()" for the same function for the "player"
122  * </pre>
123  */
124 bool store_object_similar(ItemEntity *o_ptr, ItemEntity *j_ptr)
125 {
126     if (o_ptr == j_ptr) {
127         return false;
128     }
129
130     if (o_ptr->bi_id != j_ptr->bi_id) {
131         return false;
132     }
133
134     if ((o_ptr->pval != j_ptr->pval) && !o_ptr->is_wand_rod()) {
135         return false;
136     }
137
138     if (o_ptr->to_h != j_ptr->to_h) {
139         return false;
140     }
141
142     if (o_ptr->to_d != j_ptr->to_d) {
143         return false;
144     }
145
146     if (o_ptr->to_a != j_ptr->to_a) {
147         return false;
148     }
149
150     if (o_ptr->ego_idx != j_ptr->ego_idx) {
151         return false;
152     }
153
154     if (o_ptr->is_fixed_or_random_artifact() || j_ptr->is_fixed_or_random_artifact()) {
155         return false;
156     }
157
158     if (o_ptr->art_flags != j_ptr->art_flags) {
159         return false;
160     }
161
162     if (o_ptr->timeout || j_ptr->timeout) {
163         return false;
164     }
165
166     if (o_ptr->ac != j_ptr->ac) {
167         return false;
168     }
169
170     if (o_ptr->dd != j_ptr->dd) {
171         return false;
172     }
173
174     if (o_ptr->ds != j_ptr->ds) {
175         return false;
176     }
177
178     const auto tval = o_ptr->bi_key.tval();
179     if (tval == ItemKindType::CHEST) {
180         return false;
181     }
182
183     if (tval == ItemKindType::STATUE) {
184         return false;
185     }
186
187     if (tval == ItemKindType::CAPTURE) {
188         return false;
189     }
190
191     if ((tval == ItemKindType::LITE) && (o_ptr->fuel != j_ptr->fuel)) {
192         return false;
193     }
194
195     if (o_ptr->discount != j_ptr->discount) {
196         return false;
197     }
198
199     return true;
200 }
201
202 /*!
203  * @brief 店舗に並べた品を重ね合わせできるかどうか判定する /
204  * Allow a store item to absorb another item
205  * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
206  * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
207  * @return 重ね合わせできるならTRUEを返す
208  * @details
209  * <pre>
210  * See "object_similar()" for the same function for the "player"
211  * </pre>
212  */
213 static void store_object_absorb(ItemEntity *o_ptr, ItemEntity *j_ptr)
214 {
215     int max_num = (o_ptr->bi_key.tval() == ItemKindType::ROD) ? std::min(99, MAX_SHORT / o_ptr->get_baseitem().pval) : 99;
216     int total = o_ptr->number + j_ptr->number;
217     int diff = (total > max_num) ? total - max_num : 0;
218     o_ptr->number = (total > max_num) ? max_num : total;
219     if (o_ptr->is_wand_rod()) {
220         o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
221     }
222 }
223
224 /*!
225  * @brief 店舗にオブジェクトを加える /
226  * Add the item "o_ptr" to a real stores inventory.
227  * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ
228  * @return 収めた先のID
229  * @details
230  * <pre>
231  * In all cases, return the slot (or -1) where the object was placed
232  * Note that this is a hacked up version of "store_item_to_inventory()".
233  * Also note that it may not correctly "adapt" to "knowledge" bacoming
234  * known, the player may have to pick stuff up and drop it again.
235  * </pre>
236  */
237 int store_carry(ItemEntity *o_ptr)
238 {
239     const auto value = o_ptr->get_price();
240     if (value <= 0) {
241         return -1;
242     }
243
244     o_ptr->ident |= IDENT_FULL_KNOWN;
245     o_ptr->inscription.reset();
246     o_ptr->feeling = FEEL_NONE;
247     int slot;
248     for (slot = 0; slot < st_ptr->stock_num; slot++) {
249         ItemEntity *j_ptr;
250         j_ptr = &st_ptr->stock[slot];
251         if (store_object_similar(j_ptr, o_ptr)) {
252             store_object_absorb(j_ptr, o_ptr);
253             return slot;
254         }
255     }
256
257     if (st_ptr->stock_num >= st_ptr->stock_size) {
258         return -1;
259     }
260
261     const auto o_tval = o_ptr->bi_key.tval();
262     const auto o_sval = o_ptr->bi_key.sval();
263     for (slot = 0; slot < st_ptr->stock_num; slot++) {
264         const auto *j_ptr = &st_ptr->stock[slot];
265         const auto j_tval = j_ptr->bi_key.tval();
266         const auto j_sval = j_ptr->bi_key.sval();
267         if (o_tval > j_tval) {
268             break;
269         }
270
271         if (o_tval < j_tval) {
272             continue;
273         }
274
275         if (o_sval < j_sval) {
276             break;
277         }
278
279         if (o_sval > j_sval) {
280             continue;
281         }
282
283         if (o_tval == ItemKindType::ROD) {
284             if (o_ptr->pval < j_ptr->pval) {
285                 break;
286             }
287             if (o_ptr->pval > j_ptr->pval) {
288                 continue;
289             }
290         }
291
292         auto j_value = j_ptr->get_price();
293         if (value > j_value) {
294             break;
295         }
296
297         if (value < j_value) {
298             continue;
299         }
300     }
301
302     for (int i = st_ptr->stock_num; i > slot; i--) {
303         st_ptr->stock[i] = st_ptr->stock[i - 1];
304     }
305
306     st_ptr->stock_num++;
307     st_ptr->stock[slot] = *o_ptr;
308     return slot;
309 }