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-generator.h"
14 #include "object/object-kind.h"
15 #include "object/object-value.h"
16 #include "perception/object-perception.h"
17 #include "sv-definition/sv-lite-types.h"
18 #include "sv-definition/sv-scroll-types.h"
19 #include "system/object-type-definition.h"
20 #include "world/world-object.h"
22 int cur_store_num = 0;
23 store_type *st_ptr = NULL;
26 * @brief 店舗のオブジェクト数を増やす /
27 * Add the item "o_ptr" to a real stores inventory.
28 * @param item 増やしたいアイテムのID
32 * Increase, by a given amount, the number of a certain item
33 * in a certain store. This can result in zero items.
36 void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num)
39 o_ptr = &st_ptr->stock[item];
40 int cnt = o_ptr->number + num;
46 num = cnt - o_ptr->number;
51 * @brief 店舗のオブジェクト数を削除する /
52 * Remove a slot if it is empty
53 * @param item 削除したいアイテムのID
55 void store_item_optimize(INVENTORY_IDX item)
58 o_ptr = &st_ptr->stock[item];
59 if ((o_ptr->k_idx == 0) || (o_ptr->number != 0))
63 for (int j = item; j < st_ptr->stock_num; j++)
64 st_ptr->stock[j] = st_ptr->stock[j + 1];
66 object_wipe(&st_ptr->stock[st_ptr->stock_num]);
70 * @brief 店舗の品揃え変化のためにアイテムを削除する /
71 * Attempt to delete (some of) a random item from the store
74 * Hack -- we attempt to "maintain" piles of items when possible.
77 void store_delete(void)
79 INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num);
80 int num = st_ptr->stock[what].number;
81 if (randint0(100) < 50)
84 if (randint0(100) < 50)
87 if ((st_ptr->stock[what].tval == TV_ROD) || (st_ptr->stock[what].tval == TV_WAND))
88 st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number;
90 store_item_increase(what, -num);
91 store_item_optimize(what);
95 * @brief 店舗販売中の杖と魔法棒のpvalのリストを返す
96 * @param j_ptr これから売ろうとしているオブジェクト
97 * @return plavリスト(充填数)
99 * 回数の違う杖と魔法棒がスロットを圧迫するのでスロット数制限をかける
101 static std::vector<PARAMETER_VALUE> store_same_magic_device_pvals(object_type *j_ptr)
103 auto list = std::vector<PARAMETER_VALUE>();
104 for (INVENTORY_IDX i = 0; i < st_ptr->stock_num; i++) {
105 object_type *o_ptr = &st_ptr->stock[i];
108 if (o_ptr->k_idx != j_ptr->k_idx)
110 if (o_ptr->tval != TV_STAFF && o_ptr->tval != TV_WAND)
112 list.push_back(o_ptr->pval);
118 * @brief 店舗の品揃え変化のためにアイテムを追加する /
119 * Creates a random item and gives it to a store
120 * @param player_ptr プレーヤーへの参照ポインタ
123 * This algorithm needs to be rethought. A lot.
124 * Currently, "normal" stores use a pre-built array.
125 * Note -- the "level" given to "obj_get_num()" is a "favored"
126 * level, that is, there is a much higher chance of getting
127 * items with a level approaching that of the given level...
128 * Should we check for "permission" to have the given item?
132 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)
134 if (st_ptr->stock_num >= st_ptr->stock_size)
137 for (int tries = 0; tries < 4; tries++) {
138 KIND_OBJECT_IDX k_idx;
140 if (cur_store_num == STORE_BLACK) {
141 level = 25 + randint0(25);
142 k_idx = get_obj_num(player_ptr, level, 0x00000000);
145 } else if (fix_k_idx > 0) {
147 level = rand_range(1, STORE_OBJ_LEVEL);
149 k_idx = st_ptr->table[randint0(st_ptr->table.size())];
150 level = rand_range(1, STORE_OBJ_LEVEL);
156 object_prep(player_ptr, q_ptr, k_idx);
157 apply_magic_to_object(player_ptr, q_ptr, level, AM_NO_FIXED_ART);
158 if (!(*store_will_buy)(player_ptr, q_ptr))
161 auto pvals = store_same_magic_device_pvals(q_ptr);
162 if (pvals.size() >= 2) {
163 auto pval = pvals.at(randint0(pvals.size()));
167 if (q_ptr->tval == TV_LITE) {
168 if (q_ptr->sval == SV_LITE_TORCH)
169 q_ptr->xtra4 = FUEL_TORCH / 2;
171 if (q_ptr->sval == SV_LITE_LANTERN)
172 q_ptr->xtra4 = FUEL_LAMP / 2;
176 q_ptr->ident |= IDENT_STORE;
177 if (q_ptr->tval == TV_CHEST)
180 if (cur_store_num == STORE_BLACK) {
181 if (black_market_crap(player_ptr, q_ptr) || (object_value(player_ptr, q_ptr) < 10))
184 if (object_value(player_ptr, q_ptr) <= 0)
188 mass_produce(player_ptr, q_ptr);
189 (void)store_carry(player_ptr, q_ptr);
195 * @brief 店舗に並べた品を同一品であるかどうか判定する /
196 * Determine if a store item can "absorb" another item
197 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
198 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
199 * @return 同一扱いできるならTRUEを返す
202 * See "object_similar()" for the same function for the "player"
205 bool store_object_similar(object_type *o_ptr, object_type *j_ptr)
210 if (o_ptr->k_idx != j_ptr->k_idx)
213 if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND) && (o_ptr->tval != TV_ROD))
216 if (o_ptr->to_h != j_ptr->to_h)
219 if (o_ptr->to_d != j_ptr->to_d)
222 if (o_ptr->to_a != j_ptr->to_a)
225 if (o_ptr->name2 != j_ptr->name2)
228 if (object_is_artifact(o_ptr) || object_is_artifact(j_ptr))
231 for (int i = 0; i < TR_FLAG_SIZE; i++)
232 if (o_ptr->art_flags[i] != j_ptr->art_flags[i])
235 if (o_ptr->xtra1 || j_ptr->xtra1)
238 if (o_ptr->timeout || j_ptr->timeout)
241 if (o_ptr->ac != j_ptr->ac)
244 if (o_ptr->dd != j_ptr->dd)
247 if (o_ptr->ds != j_ptr->ds)
250 if (o_ptr->tval == TV_CHEST)
253 if (o_ptr->tval == TV_STATUE)
256 if (o_ptr->tval == TV_CAPTURE)
259 if (o_ptr->discount != j_ptr->discount)
266 * @brief 店舗に並べた品を重ね合わせできるかどうか判定する /
267 * Allow a store item to absorb another item
268 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
269 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
270 * @return 重ね合わせできるならTRUEを返す
273 * See "object_similar()" for the same function for the "player"
276 static void store_object_absorb(object_type *o_ptr, object_type *j_ptr)
278 int max_num = (o_ptr->tval == TV_ROD) ? MIN(99, MAX_SHORT / k_info[o_ptr->k_idx].pval) : 99;
279 int total = o_ptr->number + j_ptr->number;
280 int diff = (total > max_num) ? total - max_num : 0;
281 o_ptr->number = (total > max_num) ? max_num : total;
282 if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND))
283 o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
287 * @brief 店舗にオブジェクトを加える /
288 * Add the item "o_ptr" to a real stores inventory.
289 * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ
293 * In all cases, return the slot (or -1) where the object was placed
294 * Note that this is a hacked up version of "store_item_to_inventory()".
295 * Also note that it may not correctly "adapt" to "knowledge" bacoming
296 * known, the player may have to pick stuff up and drop it again.
299 int store_carry(player_type *player_ptr, object_type *o_ptr)
301 PRICE value = object_value(player_ptr, o_ptr);
305 o_ptr->ident |= IDENT_FULL_KNOWN;
306 o_ptr->inscription = 0;
307 o_ptr->feeling = FEEL_NONE;
309 for (slot = 0; slot < st_ptr->stock_num; slot++) {
311 j_ptr = &st_ptr->stock[slot];
312 if (store_object_similar(j_ptr, o_ptr)) {
313 store_object_absorb(j_ptr, o_ptr);
318 if (st_ptr->stock_num >= st_ptr->stock_size)
321 for (slot = 0; slot < st_ptr->stock_num; slot++) {
323 j_ptr = &st_ptr->stock[slot];
324 if (o_ptr->tval > j_ptr->tval)
326 if (o_ptr->tval < j_ptr->tval)
328 if (o_ptr->sval < j_ptr->sval)
330 if (o_ptr->sval > j_ptr->sval)
332 if (o_ptr->tval == TV_ROD) {
333 if (o_ptr->pval < j_ptr->pval)
335 if (o_ptr->pval > j_ptr->pval)
339 PRICE j_value = object_value(player_ptr, j_ptr);
346 for (int i = st_ptr->stock_num; i > slot; i--)
347 st_ptr->stock[i] = st_ptr->stock[i - 1];
350 st_ptr->stock[slot] = *o_ptr;