2 * @brief 店舗処理関係のユーティリティ
7 #include "store/store-util.h"
8 #include "object-enchant/apply-magic.h"
9 #include "object-enchant/item-apply-magic.h"
10 #include "object-enchant/item-feeling.h"
11 #include "object-enchant/special-object-flags.h"
12 #include "object-hook/hook-enchant.h"
13 #include "object/object-kind.h"
14 #include "object/object-value.h"
15 #include "perception/object-perception.h"
16 #include "sv-definition/sv-lite-types.h"
17 #include "sv-definition/sv-scroll-types.h"
18 #include "system/object-type-definition.h"
19 #include "world/world-object.h"
21 int cur_store_num = 0;
22 store_type *st_ptr = NULL;
25 * @brief 店舗のオブジェクト数を増やす /
26 * Add the item "o_ptr" to a real stores inventory.
27 * @param item 増やしたいアイテムのID
31 * Increase, by a given amount, the number of a certain item
32 * in a certain store. This can result in zero items.
35 void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num)
38 o_ptr = &st_ptr->stock[item];
39 int cnt = o_ptr->number + num;
45 num = cnt - o_ptr->number;
50 * @brief 店舗のオブジェクト数を削除する /
51 * Remove a slot if it is empty
52 * @param item 削除したいアイテムのID
54 void store_item_optimize(INVENTORY_IDX item)
57 o_ptr = &st_ptr->stock[item];
58 if ((o_ptr->k_idx == 0) || (o_ptr->number != 0))
62 for (int j = item; j < st_ptr->stock_num; j++)
63 st_ptr->stock[j] = st_ptr->stock[j + 1];
65 (&st_ptr->stock[st_ptr->stock_num])->object_wipe();
69 * @brief 店舗の品揃え変化のためにアイテムを削除する /
70 * Attempt to delete (some of) a random item from the store
73 * Hack -- we attempt to "maintain" piles of items when possible.
76 void store_delete(void)
78 INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num);
79 int num = st_ptr->stock[what].number;
80 if (randint0(100) < 50)
83 if (randint0(100) < 50)
86 if ((st_ptr->stock[what].tval == TV_ROD) || (st_ptr->stock[what].tval == TV_WAND))
87 st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number;
89 store_item_increase(what, -num);
90 store_item_optimize(what);
94 * @brief 店舗販売中の杖と魔法棒のpvalのリストを返す
95 * @param j_ptr これから売ろうとしているオブジェクト
96 * @return plavリスト(充填数)
98 * 回数の違う杖と魔法棒がスロットを圧迫するのでスロット数制限をかける
100 static std::vector<PARAMETER_VALUE> store_same_magic_device_pvals(object_type *j_ptr)
102 auto list = std::vector<PARAMETER_VALUE>();
103 for (INVENTORY_IDX i = 0; i < st_ptr->stock_num; i++) {
104 object_type *o_ptr = &st_ptr->stock[i];
107 if (o_ptr->k_idx != j_ptr->k_idx)
109 if (o_ptr->tval != TV_STAFF && o_ptr->tval != TV_WAND)
111 list.push_back(o_ptr->pval);
117 * @brief 店舗の品揃え変化のためにアイテムを追加する /
118 * Creates a random item and gives it to a store
119 * @param player_ptr プレーヤーへの参照ポインタ
122 * This algorithm needs to be rethought. A lot.
123 * Currently, "normal" stores use a pre-built array.
124 * Note -- the "level" given to "obj_get_num()" is a "favored"
125 * level, that is, there is a much higher chance of getting
126 * items with a level approaching that of the given level...
127 * Should we check for "permission" to have the given item?
131 player_type *player_ptr, KIND_OBJECT_IDX fix_k_idx, black_market_crap_pf black_market_crap, store_will_buy_pf store_will_buy, mass_produce_pf mass_produce)
133 if (st_ptr->stock_num >= st_ptr->stock_size)
136 for (int tries = 0; tries < 4; tries++) {
137 KIND_OBJECT_IDX k_idx;
139 if (cur_store_num == STORE_BLACK) {
140 level = 25 + randint0(25);
141 k_idx = get_obj_num(player_ptr, level, 0x00000000);
144 } else if (fix_k_idx > 0) {
146 level = rand_range(1, STORE_OBJ_LEVEL);
148 k_idx = st_ptr->table[randint0(st_ptr->table.size())];
149 level = rand_range(1, STORE_OBJ_LEVEL);
155 q_ptr->object_prep(player_ptr, k_idx);
156 apply_magic_to_object(player_ptr, q_ptr, level, AM_NO_FIXED_ART);
157 if (!(*store_will_buy)(player_ptr, q_ptr))
160 auto pvals = store_same_magic_device_pvals(q_ptr);
161 if (pvals.size() >= 2) {
162 auto pval = pvals.at(randint0(pvals.size()));
166 if (q_ptr->tval == TV_LITE) {
167 if (q_ptr->sval == SV_LITE_TORCH)
168 q_ptr->xtra4 = FUEL_TORCH / 2;
170 if (q_ptr->sval == SV_LITE_LANTERN)
171 q_ptr->xtra4 = FUEL_LAMP / 2;
175 q_ptr->ident |= IDENT_STORE;
176 if (q_ptr->tval == TV_CHEST)
179 if (cur_store_num == STORE_BLACK) {
180 if (black_market_crap(player_ptr, q_ptr) || (object_value(player_ptr, q_ptr) < 10))
183 if (object_value(player_ptr, q_ptr) <= 0)
187 mass_produce(player_ptr, q_ptr);
188 (void)store_carry(player_ptr, q_ptr);
194 * @brief 店舗に並べた品を同一品であるかどうか判定する /
195 * Determine if a store item can "absorb" another item
196 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
197 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
198 * @return 同一扱いできるならTRUEを返す
201 * See "object_similar()" for the same function for the "player"
204 bool store_object_similar(object_type *o_ptr, object_type *j_ptr)
209 if (o_ptr->k_idx != j_ptr->k_idx)
212 if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND) && (o_ptr->tval != TV_ROD))
215 if (o_ptr->to_h != j_ptr->to_h)
218 if (o_ptr->to_d != j_ptr->to_d)
221 if (o_ptr->to_a != j_ptr->to_a)
224 if (o_ptr->name2 != j_ptr->name2)
227 if (object_is_artifact(o_ptr) || object_is_artifact(j_ptr))
230 for (int i = 0; i < TR_FLAG_SIZE; i++)
231 if (o_ptr->art_flags[i] != j_ptr->art_flags[i])
234 if (o_ptr->xtra1 || j_ptr->xtra1)
237 if (o_ptr->timeout || j_ptr->timeout)
240 if (o_ptr->ac != j_ptr->ac)
243 if (o_ptr->dd != j_ptr->dd)
246 if (o_ptr->ds != j_ptr->ds)
249 if (o_ptr->tval == TV_CHEST)
252 if (o_ptr->tval == TV_STATUE)
255 if (o_ptr->tval == TV_CAPTURE)
258 if (o_ptr->discount != j_ptr->discount)
265 * @brief 店舗に並べた品を重ね合わせできるかどうか判定する /
266 * Allow a store item to absorb another item
267 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
268 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
269 * @return 重ね合わせできるならTRUEを返す
272 * See "object_similar()" for the same function for the "player"
275 static void store_object_absorb(object_type *o_ptr, object_type *j_ptr)
277 int max_num = (o_ptr->tval == TV_ROD) ? MIN(99, MAX_SHORT / k_info[o_ptr->k_idx].pval) : 99;
278 int total = o_ptr->number + j_ptr->number;
279 int diff = (total > max_num) ? total - max_num : 0;
280 o_ptr->number = (total > max_num) ? max_num : total;
281 if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND))
282 o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
286 * @brief 店舗にオブジェクトを加える /
287 * Add the item "o_ptr" to a real stores inventory.
288 * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ
292 * In all cases, return the slot (or -1) where the object was placed
293 * Note that this is a hacked up version of "store_item_to_inventory()".
294 * Also note that it may not correctly "adapt" to "knowledge" bacoming
295 * known, the player may have to pick stuff up and drop it again.
298 int store_carry(player_type *player_ptr, object_type *o_ptr)
300 PRICE value = object_value(player_ptr, o_ptr);
304 o_ptr->ident |= IDENT_FULL_KNOWN;
305 o_ptr->inscription = 0;
306 o_ptr->feeling = FEEL_NONE;
308 for (slot = 0; slot < st_ptr->stock_num; slot++) {
310 j_ptr = &st_ptr->stock[slot];
311 if (store_object_similar(j_ptr, o_ptr)) {
312 store_object_absorb(j_ptr, o_ptr);
317 if (st_ptr->stock_num >= st_ptr->stock_size)
320 for (slot = 0; slot < st_ptr->stock_num; slot++) {
322 j_ptr = &st_ptr->stock[slot];
323 if (o_ptr->tval > j_ptr->tval)
325 if (o_ptr->tval < j_ptr->tval)
327 if (o_ptr->sval < j_ptr->sval)
329 if (o_ptr->sval > j_ptr->sval)
331 if (o_ptr->tval == TV_ROD) {
332 if (o_ptr->pval < j_ptr->pval)
334 if (o_ptr->pval > j_ptr->pval)
338 PRICE j_value = object_value(player_ptr, j_ptr);
345 for (int i = st_ptr->stock_num; i > slot; i--)
346 st_ptr->stock[i] = st_ptr->stock[i - 1];
349 st_ptr->stock[slot] = *o_ptr;