OSDN Git Service

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