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 "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
32 * Increase, by a given amount, the number of a certain item
33 * in a certain store. This can result in zero items.
35 * @todo numは本来ITEM_NUMBER型にしたい。
37 void store_item_increase(INVENTORY_IDX item, int num)
40 o_ptr = &st_ptr->stock[item];
41 int cnt = o_ptr->number + num;
47 num = cnt - o_ptr->number;
48 o_ptr->number += (ITEM_NUMBER)num;
52 * @brief 店舗のオブジェクト数を削除する /
53 * Remove a slot if it is empty
54 * @param item 削除したいアイテムのID
57 void store_item_optimize(INVENTORY_IDX item)
60 o_ptr = &st_ptr->stock[item];
61 if ((o_ptr->k_idx == 0) || (o_ptr->number != 0))
65 for (int j = item; j < st_ptr->stock_num; j++)
66 st_ptr->stock[j] = st_ptr->stock[j + 1];
68 object_wipe(&st_ptr->stock[st_ptr->stock_num]);
72 * @brief 店舗の品揃え変化のためにアイテムを削除する /
73 * Attempt to delete (some of) a random item from the store
77 * Hack -- we attempt to "maintain" piles of items when possible.
80 void store_delete(void)
82 INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num);
83 int num = st_ptr->stock[what].number;
84 if (randint0(100) < 50)
87 if (randint0(100) < 50)
90 if ((st_ptr->stock[what].tval == TV_ROD) || (st_ptr->stock[what].tval == TV_WAND))
91 st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number;
93 store_item_increase(what, -num);
94 store_item_optimize(what);
98 * @brief 店舗の品揃え変化のためにアイテムを追加する /
99 * Creates a random item and gives it to a store
100 * @param player_ptr プレーヤーへの参照ポインタ
104 * This algorithm needs to be rethought. A lot.
105 * Currently, "normal" stores use a pre-built array.
106 * Note -- the "level" given to "obj_get_num()" is a "favored"
107 * level, that is, there is a much higher chance of getting
108 * items with a level approaching that of the given level...
109 * Should we check for "permission" to have the given item?
112 void store_create(player_type *player_ptr, black_market_crap_pf black_market_crap, store_will_buy_pf store_will_buy, mass_produce_pf mass_produce)
114 if (st_ptr->stock_num >= st_ptr->stock_size)
117 for (int tries = 0; tries < 4; tries++) {
120 if (cur_store_num == STORE_BLACK) {
121 level = 25 + randint0(25);
122 i = get_obj_num(player_ptr, level, 0x00000000);
126 i = st_ptr->table[randint0(st_ptr->table_num)];
127 level = rand_range(1, STORE_OBJ_LEVEL);
133 object_prep(player_ptr, q_ptr, i);
134 apply_magic(player_ptr, q_ptr, level, AM_NO_FIXED_ART);
135 if (!(*store_will_buy)(player_ptr, q_ptr))
138 if (q_ptr->tval == TV_LITE) {
139 if (q_ptr->sval == SV_LITE_TORCH)
140 q_ptr->xtra4 = FUEL_TORCH / 2;
142 if (q_ptr->sval == SV_LITE_LANTERN)
143 q_ptr->xtra4 = FUEL_LAMP / 2;
147 q_ptr->ident |= IDENT_STORE;
148 if (q_ptr->tval == TV_CHEST)
151 if (cur_store_num == STORE_BLACK) {
152 if (black_market_crap(player_ptr, q_ptr) || (object_value(player_ptr, q_ptr) < 10))
155 if (object_value(player_ptr, q_ptr) <= 0)
159 mass_produce(player_ptr, q_ptr);
160 (void)store_carry(player_ptr, q_ptr);
166 * @brief 店舗に並べた品を同一品であるかどうか判定する /
167 * Determine if a store item can "absorb" another item
168 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
169 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
170 * @return 同一扱いできるならTRUEを返す
173 * See "object_similar()" for the same function for the "player"
176 bool store_object_similar(object_type *o_ptr, object_type *j_ptr)
181 if (o_ptr->k_idx != j_ptr->k_idx)
184 if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND) && (o_ptr->tval != TV_ROD))
187 if (o_ptr->to_h != j_ptr->to_h)
190 if (o_ptr->to_d != j_ptr->to_d)
193 if (o_ptr->to_a != j_ptr->to_a)
196 if (o_ptr->name2 != j_ptr->name2)
199 if (object_is_artifact(o_ptr) || object_is_artifact(j_ptr))
202 for (int i = 0; i < TR_FLAG_SIZE; i++)
203 if (o_ptr->art_flags[i] != j_ptr->art_flags[i])
206 if (o_ptr->xtra1 || j_ptr->xtra1)
209 if (o_ptr->timeout || j_ptr->timeout)
212 if (o_ptr->ac != j_ptr->ac)
215 if (o_ptr->dd != j_ptr->dd)
218 if (o_ptr->ds != j_ptr->ds)
221 if (o_ptr->tval == TV_CHEST)
224 if (o_ptr->tval == TV_STATUE)
227 if (o_ptr->tval == TV_CAPTURE)
230 if (o_ptr->discount != j_ptr->discount)
237 * @brief 店舗に並べた品を重ね合わせできるかどうか判定する /
238 * Allow a store item to absorb another item
239 * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1
240 * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2
241 * @return 重ね合わせできるならTRUEを返す
244 * See "object_similar()" for the same function for the "player"
247 static void store_object_absorb(object_type *o_ptr, object_type *j_ptr)
249 int max_num = (o_ptr->tval == TV_ROD) ? MIN(99, MAX_SHORT / k_info[o_ptr->k_idx].pval) : 99;
250 int total = o_ptr->number + j_ptr->number;
251 int diff = (total > max_num) ? total - max_num : 0;
252 o_ptr->number = (total > max_num) ? max_num : total;
253 if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND))
254 o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number;
258 * @brief 店舗にオブジェクトを加える /
259 * Add the item "o_ptr" to a real stores inventory.
260 * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ
264 * In all cases, return the slot (or -1) where the object was placed
265 * Note that this is a hacked up version of "store_item_to_inventory()".
266 * Also note that it may not correctly "adapt" to "knowledge" bacoming
267 * known, the player may have to pick stuff up and drop it again.
270 int store_carry(player_type *player_ptr, object_type *o_ptr)
272 PRICE value = object_value(player_ptr, o_ptr);
276 o_ptr->ident |= IDENT_FULL_KNOWN;
277 o_ptr->inscription = 0;
278 o_ptr->feeling = FEEL_NONE;
280 for (slot = 0; slot < st_ptr->stock_num; slot++) {
282 j_ptr = &st_ptr->stock[slot];
283 if (store_object_similar(j_ptr, o_ptr)) {
284 store_object_absorb(j_ptr, o_ptr);
289 if (st_ptr->stock_num >= st_ptr->stock_size)
292 for (slot = 0; slot < st_ptr->stock_num; slot++) {
294 j_ptr = &st_ptr->stock[slot];
295 if (o_ptr->tval > j_ptr->tval)
297 if (o_ptr->tval < j_ptr->tval)
299 if (o_ptr->sval < j_ptr->sval)
301 if (o_ptr->sval > j_ptr->sval)
303 if (o_ptr->tval == TV_ROD) {
304 if (o_ptr->pval < j_ptr->pval)
306 if (o_ptr->pval > j_ptr->pval)
310 PRICE j_value = object_value(player_ptr, j_ptr);
317 for (int i = st_ptr->stock_num; i > slot; i--)
318 st_ptr->stock[i] = st_ptr->stock[i - 1];
321 st_ptr->stock[slot] = *o_ptr;