OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / store / sell-order.cpp
1 #include "store/sell-order.h"
2 #include "action/weapon-shield.h"
3 #include "autopick/autopick.h"
4 #include "core/asking-player.h"
5 #include "core/player-update-types.h"
6 #include "core/stuff-handler.h"
7 #include "core/window-redrawer.h"
8 #include "flavor/flavor-describer.h"
9 #include "flavor/object-flavor-types.h"
10 #include "floor/floor-object.h"
11 #include "game-option/birth-options.h"
12 #include "game-option/play-record-options.h"
13 #include "inventory/inventory-object.h"
14 #include "inventory/inventory-slot-types.h"
15 #include "io/write-diary.h"
16 #include "main/sound-definitions-table.h"
17 #include "main/sound-of-music.h"
18 #include "object-enchant/item-feeling.h"
19 #include "object-enchant/special-object-flags.h"
20 #include "object-hook/hook-checker.h"
21 #include "object/item-tester-hooker.h"
22 #include "object/item-use-flags.h"
23 #include "object/object-generator.h"
24 #include "object/object-info.h"
25 #include "object/object-stack.h"
26 #include "object/object-value.h"
27 #include "player-info/avatar.h"
28 #include "racial/racial-android.h"
29 #include "spell-kind/spells-perception.h"
30 #include "store/home.h"
31 #include "store/owner-insults.h"
32 #include "store/pricing.h"
33 #include "store/say-comments.h"
34 #include "store/service-checker.h"
35 #include "store/store-util.h"
36 #include "store/store.h"
37 #include "system/object-type-definition.h"
38 #include "term/screen-processor.h"
39 #include "view/display-messages.h"
40 #include "view/display-store.h"
41 #include "view/object-describer.h"
42 #include "util/bit-flags-calculator.h"
43 #include "world/world.h"
44
45 /*!
46  * @brief プレイヤーが売却する時の値切り処理メインルーチン /
47  * Haggling routine                             -RAK-
48  * @param player_ptr プレーヤーへの参照ポインタ
49  * @param o_ptr オブジェクトの構造体参照ポインタ
50  * @param price 最終価格を返す参照ポインタ
51  * @return プレイヤーの価格に対して店主が不服ならばTRUEを返す /
52  * Return TRUE if purchase is NOT successful
53  */
54 static bool sell_haggle(player_type *player_ptr, object_type *o_ptr, s32b *price)
55 {
56     s32b cur_ask = price_item(player_ptr, o_ptr, ot_ptr->max_inflate, TRUE);
57     s32b final_ask = price_item(player_ptr, o_ptr, ot_ptr->min_inflate, TRUE);
58     int noneed = noneedtobargain(final_ask);
59     s32b purse = (s32b)(ot_ptr->max_cost);
60     bool final = FALSE;
61     concptr pmt = _("提示金額", "Offer");
62     if (noneed || !manual_haggle || (final_ask >= purse)) {
63         if (!manual_haggle && !noneed) {
64             final_ask -= final_ask / 10;
65         }
66
67         if (final_ask >= purse) {
68             msg_print(_("即座にこの金額にまとまった。", "You instantly agree upon the price."));
69             msg_print(NULL);
70             final_ask = purse;
71         } else if (noneed) {
72             msg_print(_("結局この金額にまとまった。", "You eventually agree upon the price."));
73             msg_print(NULL);
74         } else {
75             msg_print(_("すんなりとこの金額にまとまった。", "You quickly agree upon the price."));
76             msg_print(NULL);
77         }
78
79         cur_ask = final_ask;
80         final = TRUE;
81         pmt = _("最終提示金額", "Final Offer");
82     }
83
84     cur_ask *= o_ptr->number;
85     final_ask *= o_ptr->number;
86
87     s32b min_per = ot_ptr->haggle_per;
88     s32b max_per = min_per * 3;
89     s32b last_offer = object_value(player_ptr, o_ptr) * o_ptr->number;
90     last_offer = last_offer * ot_ptr->max_inflate / 100L;
91     s32b offer = 0;
92     allow_inc = FALSE;
93     bool flag = FALSE;
94     bool loop_flag;
95     int annoyed = 0;
96     bool cancel = FALSE;
97     *price = 0;
98     while (!flag) {
99         while (TRUE) {
100             loop_flag = TRUE;
101
102             char out_val[160];
103             (void)sprintf(out_val, "%s :  %ld", pmt, (long)cur_ask);
104             put_str(out_val, 1, 0);
105             cancel = receive_offer(_("提示する価格? ", "What price do you ask? "), &offer, last_offer, -1, cur_ask, final);
106
107             if (cancel) {
108                 flag = TRUE;
109             } else if (offer < cur_ask) {
110                 say_comment_6();
111                 offer = last_offer;
112             } else if (offer == cur_ask) {
113                 flag = TRUE;
114                 *price = offer;
115             } else {
116                 loop_flag = FALSE;
117             }
118
119             if (flag || !loop_flag)
120                 break;
121         }
122
123         if (flag)
124             continue;
125
126         s32b x1 = 100 * (last_offer - offer) / (last_offer - cur_ask);
127         if (x1 < min_per) {
128             if (haggle_insults()) {
129                 flag = TRUE;
130                 cancel = TRUE;
131             }
132         } else if (x1 > max_per) {
133             x1 = x1 * 3 / 4;
134             if (x1 < max_per)
135                 x1 = max_per;
136         }
137
138         s32b x2 = rand_range(x1 - 2, x1 + 2);
139         s32b x3 = ((offer - cur_ask) * x2 / 100L) + 1;
140         if (x3 < 0)
141             x3 = 0;
142         cur_ask += x3;
143
144         if (cur_ask > final_ask) {
145             cur_ask = final_ask;
146             final = TRUE;
147             pmt = _("最終提示金額", "Final Offer");
148
149             annoyed++;
150             if (annoyed > 3) {
151                 flag = TRUE;
152 #ifdef JP
153                 /* 追加 $0 で買い取られてしまうのを防止 By FIRST*/
154                 cancel = TRUE;
155 #endif
156                 (void)(increase_insults());
157             }
158         } else if (offer <= cur_ask) {
159             flag = TRUE;
160             *price = offer;
161         }
162
163         last_offer = offer;
164         allow_inc = TRUE;
165         prt("", 1, 0);
166         char out_val[160];
167         (void)sprintf(out_val, _("前回の提示価格 $%ld", "Your last bid %ld"), (long)last_offer);
168         put_str(out_val, 1, 39);
169         say_comment_3(cur_ask, annoyed);
170     }
171
172     if (cancel)
173         return TRUE;
174
175     updatebargain(*price, final_ask, o_ptr->number);
176     return FALSE;
177 }
178
179 /*!
180  * @brief 店からの売却処理のメインルーチン /
181  * Sell an item to the store (or home)
182  * @param owner_ptr プレーヤーへの参照ポインタ
183  * @return なし
184  */
185 void store_sell(player_type *owner_ptr)
186 {
187     concptr q;
188     if (cur_store_num == STORE_HOME)
189         q = _("どのアイテムを置きますか? ", "Drop which item? ");
190     else if (cur_store_num == STORE_MUSEUM)
191         q = _("どのアイテムを寄贈しますか? ", "Give which item? ");
192     else
193         q = _("どのアイテムを売りますか? ", "Sell which item? ");
194
195     item_tester_hook = store_will_buy;
196
197     /* 我が家でおかしなメッセージが出るオリジナルのバグを修正 */
198     concptr s;
199     if (cur_store_num == STORE_HOME) {
200         s = _("置けるアイテムを持っていません。", "You don't have any items to drop.");
201     } else if (cur_store_num == STORE_MUSEUM) {
202         s = _("寄贈できるアイテムを持っていません。", "You don't have any items to give.");
203     } else {
204         s = _("欲しい物がないですねえ。", "You have nothing that I want.");
205     }
206
207     OBJECT_IDX item;
208     object_type *o_ptr;
209     o_ptr = choose_object(owner_ptr, &item, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT, TV_NONE);
210     if (!o_ptr)
211         return;
212
213     if ((item >= INVEN_MAIN_HAND) && object_is_cursed(o_ptr)) {
214         msg_print(_("ふーむ、どうやらそれは呪われているようだね。", "Hmmm, it seems to be cursed."));
215         return;
216     }
217
218     int amt = 1;
219     if (o_ptr->number > 1) {
220         amt = get_quantity(NULL, o_ptr->number);
221         if (amt <= 0)
222             return;
223     }
224
225     object_type forge;
226     object_type *q_ptr;
227     q_ptr = &forge;
228     object_copy(q_ptr, o_ptr);
229     q_ptr->number = amt;
230     if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND))
231         q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
232
233     GAME_TEXT o_name[MAX_NLEN];
234     describe_flavor(owner_ptr, o_name, q_ptr, 0);
235     if ((cur_store_num != STORE_HOME) && (cur_store_num != STORE_MUSEUM)) {
236         q_ptr->inscription = 0;
237         q_ptr->feeling = FEEL_NONE;
238     }
239
240     if (!store_check_num(q_ptr)) {
241         if (cur_store_num == STORE_HOME)
242             msg_print(_("我が家にはもう置く場所がない。", "Your home is full."));
243
244         else if (cur_store_num == STORE_MUSEUM)
245             msg_print(_("博物館はもう満杯だ。", "The Museum is full."));
246
247         else
248             msg_print(_("すいませんが、店にはもう置く場所がありません。", "I have not the room in my store to keep it."));
249
250         return;
251     }
252
253     int choice;
254     PRICE price, value, dummy;
255     if ((cur_store_num != STORE_HOME) && (cur_store_num != STORE_MUSEUM)) {
256         msg_format(_("%s(%c)を売却する。", "Selling %s (%c)."), o_name, index_to_label(item));
257         msg_print(NULL);
258
259         choice = sell_haggle(owner_ptr, q_ptr, &price);
260         if (st_ptr->store_open >= current_world_ptr->game_turn)
261             return;
262
263         if (choice == 0) {
264             say_comment_1(owner_ptr);
265             sound(SOUND_SELL);
266             if (cur_store_num == STORE_BLACK)
267                 chg_virtue(owner_ptr, V_JUSTICE, -1);
268
269             if ((o_ptr->tval == TV_BOTTLE) && (cur_store_num != STORE_HOME))
270                 chg_virtue(owner_ptr, V_NATURE, 1);
271             decrease_insults();
272
273             owner_ptr->au += price;
274             store_prt_gold(owner_ptr);
275             dummy = object_value(owner_ptr, q_ptr) * q_ptr->number;
276
277             identify_item(owner_ptr, o_ptr);
278             q_ptr = &forge;
279             object_copy(q_ptr, o_ptr);
280             q_ptr->number = amt;
281             q_ptr->ident |= IDENT_STORE;
282             if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND))
283                 q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
284
285             value = object_value(owner_ptr, q_ptr) * q_ptr->number;
286             describe_flavor(owner_ptr, o_name, q_ptr, 0);
287             msg_format(_("%sを $%ldで売却しました。", "You sold %s for %ld gold."), o_name, (long)price);
288
289             if (record_sell)
290                 exe_write_diary(owner_ptr, DIARY_SELL, 0, o_name);
291
292             if (!((o_ptr->tval == TV_FIGURINE) && (value > 0)))
293                 purchase_analyze(owner_ptr, price, value, dummy);
294
295             distribute_charges(o_ptr, q_ptr, amt);
296             q_ptr->timeout = 0;
297             inven_item_increase(owner_ptr, item, -amt);
298             inven_item_describe(owner_ptr, item);
299             if (o_ptr->number > 0)
300                 autopick_alter_item(owner_ptr, item, FALSE);
301
302             inven_item_optimize(owner_ptr, item);
303             int item_pos = store_carry(owner_ptr, q_ptr);
304             if (item_pos >= 0) {
305                 store_top = (item_pos / store_bottom) * store_bottom;
306                 display_store_inventory(owner_ptr);
307             }
308         }
309     } else if (cur_store_num == STORE_MUSEUM) {
310         char o2_name[MAX_NLEN];
311         describe_flavor(owner_ptr, o2_name, q_ptr, OD_NAME_ONLY);
312
313         if (-1 == store_check_num(q_ptr))
314             msg_print(_("それと同じ品物は既に博物館にあるようです。", "The Museum already has one of those items."));
315         else
316             msg_print(_("博物館に寄贈したものは取り出すことができません!!", "You cannot take back items which have been donated to the Museum!!"));
317         
318         if (!get_check(format(_("本当に%sを寄贈しますか?", "Really give %s to the Museum? "), o2_name)))
319             return;
320
321         identify_item(owner_ptr, q_ptr);
322         q_ptr->ident |= IDENT_FULL_KNOWN;
323
324         distribute_charges(o_ptr, q_ptr, amt);
325         msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), o_name, index_to_label(item));
326         choice = 0;
327
328         vary_item(owner_ptr, item, -amt);
329
330         int item_pos = home_carry(owner_ptr, q_ptr);
331         if (item_pos >= 0) {
332             store_top = (item_pos / store_bottom) * store_bottom;
333             display_store_inventory(owner_ptr);
334         }
335     } else {
336         distribute_charges(o_ptr, q_ptr, amt);
337         msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), o_name, index_to_label(item));
338         choice = 0;
339         vary_item(owner_ptr, item, -amt);
340         int item_pos = home_carry(owner_ptr, q_ptr);
341         if (item_pos >= 0) {
342             store_top = (item_pos / store_bottom) * store_bottom;
343             display_store_inventory(owner_ptr);
344         }
345     }
346
347     set_bits(owner_ptr->update, PU_BONUS);
348     set_bits(owner_ptr->window_flags, PW_PLAYER);
349     handle_stuff(owner_ptr);
350
351     if ((choice == 0) && (item >= INVEN_MAIN_HAND)) {
352         calc_android_exp(owner_ptr);
353         verify_equip_slot(owner_ptr, item);
354     }
355 }