OSDN Git Service

[Refactor] #40413 Separated display-messages.c/h from util.c/h
[hengband/hengband.git] / src / market / bounty.c
1 #include "market/bounty.h"
2 #include "autopick/autopick.h"
3 #include "core/stuff-handler.h"
4 #include "dungeon/dungeon.h"
5 #include "floor/floor.h"
6 #include "inventory/inventory-object.h"
7 #include "io/input-key-acceptor.h"
8 #include "market/bounty-prize-table.h"
9 #include "market/building-util.h"
10 #include "monster-race/race-flags1.h"
11 #include "monster-race/race-flags2.h"
12 #include "monster-race/race-flags7.h"
13 #include "monster-race/race-flags9.h"
14 #include "monster-race/race-indice-types.h"
15 #include "monster-race/monster-race-hook.h"
16 #include "monster/monster-list.h"
17 #include "monster/monster-util.h"
18 #include "object-enchant/apply-magic.h"
19 #include "object-enchant/item-apply-magic.h"
20 #include "object/object-flavor.h"
21 #include "object/object-generator.h"
22 #include "object/object-kind-hook.h"
23 #include "object/object-info.h"
24 #include "perception/object-perception.h"
25 #include "player/avatar.h"
26 #include "sv-definition/sv-other-types.h"
27 #include "term/term-color-types.h"
28 #include "view/display-messages.h"
29 #include "world/world.h"
30
31 /*!
32  * @brief 賞金首の引き換え処理 / Get prize
33  * @param player_ptr プレーヤーへの参照ポインタ
34  * @return 各種賞金首のいずれかでも換金が行われたか否か。
35  */
36 bool exchange_cash(player_type *player_ptr)
37 {
38     bool change = FALSE;
39     GAME_TEXT o_name[MAX_NLEN];
40     object_type *o_ptr;
41
42     for (INVENTORY_IDX i = 0; i <= INVEN_LARM; i++) {
43         o_ptr = &player_ptr->inventory_list[i];
44         if ((o_ptr->tval == TV_CAPTURE) && (o_ptr->pval == MON_TSUCHINOKO)) {
45             char buf[MAX_NLEN + 20];
46             object_desc(player_ptr, o_name, o_ptr, 0);
47             sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
48             if (get_check(buf)) {
49                 msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(1000000L * o_ptr->number));
50                 player_ptr->au += 1000000L * o_ptr->number;
51                 player_ptr->redraw |= (PR_GOLD);
52                 vary_item(player_ptr, i, -o_ptr->number);
53             }
54
55             change = TRUE;
56         }
57     }
58
59     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
60         o_ptr = &player_ptr->inventory_list[i];
61         if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE) && (o_ptr->pval == MON_TSUCHINOKO)) {
62             char buf[MAX_NLEN + 20];
63             object_desc(player_ptr, o_name, o_ptr, 0);
64             sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
65             if (get_check(buf)) {
66                 msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(200000L * o_ptr->number));
67                 player_ptr->au += 200000L * o_ptr->number;
68                 player_ptr->redraw |= (PR_GOLD);
69                 vary_item(player_ptr, i, -o_ptr->number);
70             }
71
72             change = TRUE;
73         }
74     }
75
76     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
77         o_ptr = &player_ptr->inventory_list[i];
78         if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON) && (o_ptr->pval == MON_TSUCHINOKO)) {
79             char buf[MAX_NLEN + 20];
80             object_desc(player_ptr, o_name, o_ptr, 0);
81             sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
82             if (get_check(buf)) {
83                 msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(100000L * o_ptr->number));
84                 player_ptr->au += 100000L * o_ptr->number;
85                 player_ptr->redraw |= (PR_GOLD);
86                 vary_item(player_ptr, i, -o_ptr->number);
87             }
88
89             change = TRUE;
90         }
91     }
92
93     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
94         o_ptr = &player_ptr->inventory_list[i];
95         if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE) && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[today_mon].name))) {
96             char buf[MAX_NLEN + 20];
97             object_desc(player_ptr, o_name, o_ptr, 0);
98             sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
99             if (get_check(buf)) {
100                 msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[today_mon].level * 50 + 100) * o_ptr->number));
101                 player_ptr->au += (r_info[today_mon].level * 50 + 100) * o_ptr->number;
102                 player_ptr->redraw |= (PR_GOLD);
103                 vary_item(player_ptr, i, -o_ptr->number);
104             }
105
106             change = TRUE;
107         }
108     }
109
110     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
111         o_ptr = &player_ptr->inventory_list[i];
112
113         if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON) && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[today_mon].name))) {
114             char buf[MAX_NLEN + 20];
115             object_desc(player_ptr, o_name, o_ptr, 0);
116             sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
117             if (get_check(buf)) {
118                 msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[today_mon].level * 30 + 60) * o_ptr->number));
119                 player_ptr->au += (r_info[today_mon].level * 30 + 60) * o_ptr->number;
120                 player_ptr->redraw |= (PR_GOLD);
121                 vary_item(player_ptr, i, -o_ptr->number);
122             }
123
124             change = TRUE;
125         }
126     }
127
128     for (int j = 0; j < MAX_BOUNTY; j++) {
129         for (INVENTORY_IDX i = INVEN_PACK - 1; i >= 0; i--) {
130             o_ptr = &player_ptr->inventory_list[i];
131             if ((o_ptr->tval != TV_CORPSE) || (o_ptr->pval != current_world_ptr->bounty_r_idx[j]))
132                 continue;
133
134             char buf[MAX_NLEN + 20];
135             int num, k;
136             INVENTORY_IDX item_new;
137             object_type forge;
138
139             object_desc(player_ptr, o_name, o_ptr, 0);
140             sprintf(buf, _("%sを渡しますか?", "Hand %s over? "), o_name);
141             if (!get_check(buf))
142                 continue;
143
144             vary_item(player_ptr, i, -o_ptr->number);
145             chg_virtue(player_ptr, V_JUSTICE, 5);
146             current_world_ptr->bounty_r_idx[j] += 10000;
147
148             for (num = 0, k = 0; k < MAX_BOUNTY; k++) {
149                 if (current_world_ptr->bounty_r_idx[k] >= 10000)
150                     num++;
151             }
152
153             msg_format(_("これで合計 %d ポイント獲得しました。", "You earned %d point%s total."), num, (num > 1 ? "s" : ""));
154
155             object_prep(&forge, lookup_kind(prize_list[num - 1].tval, prize_list[num - 1].sval));
156             apply_magic(player_ptr, &forge, player_ptr->current_floor_ptr->object_level, AM_NO_FIXED_ART);
157
158             object_aware(player_ptr, &forge);
159             object_known(&forge);
160
161             /*
162              * Hand it --- Assume there is an empty slot.
163              * Since a corpse is handed at first,
164              * there is at least one empty slot.
165              */
166             item_new = store_item_to_inventory(player_ptr, &forge);
167             object_desc(player_ptr, o_name, &forge, 0);
168             msg_format(_("%s(%c)を貰った。", "You get %s (%c). "), o_name, index_to_label(item_new));
169
170             autopick_alter_item(player_ptr, item_new, FALSE);
171             handle_stuff(player_ptr);
172             change = TRUE;
173         }
174     }
175
176     if (change)
177         return TRUE;
178
179     msg_print(_("賞金を得られそうなものは持っていなかった。", "You have nothing."));
180     msg_print(NULL);
181     return FALSE;
182 }
183
184 /*!
185  * @brief 本日の賞金首情報を表示する。
186  * @param player_ptr プレーヤーへの参照ポインタ
187  * @return なし
188  */
189 void today_target(player_type *player_ptr)
190 {
191     char buf[160];
192     monster_race *r_ptr = &r_info[today_mon];
193
194     clear_bldg(4, 18);
195     c_put_str(TERM_YELLOW, _("本日の賞金首", "Wanted monster that changes from day to day"), 5, 10);
196     sprintf(buf, _("ターゲット: %s", "target: %s"), r_name + r_ptr->name);
197     c_put_str(TERM_YELLOW, buf, 6, 10);
198     sprintf(buf, _("死体 ---- $%d", "corpse   ---- $%d"), (int)r_ptr->level * 50 + 100);
199     prt(buf, 8, 10);
200     sprintf(buf, _("骨   ---- $%d", "skeleton ---- $%d"), (int)r_ptr->level * 30 + 60);
201     prt(buf, 9, 10);
202     player_ptr->today_mon = today_mon;
203 }
204
205 /*!
206  * @brief ツチノコの賞金首情報を表示する。
207  * @return なし
208  */
209 void tsuchinoko(void)
210 {
211     clear_bldg(4, 18);
212     c_put_str(TERM_YELLOW, _("一獲千金の大チャンス!!!", "Big chance for quick money!!!"), 5, 10);
213     c_put_str(TERM_YELLOW, _("ターゲット:幻の珍獣「ツチノコ」", "target: the rarest animal 'Tsuchinoko'"), 6, 10);
214     c_put_str(TERM_WHITE, _("生け捕り ---- $1,000,000", "catch alive ---- $1,000,000"), 8, 10);
215     c_put_str(TERM_WHITE, _("死体     ----   $200,000", "corpse      ----   $200,000"), 9, 10);
216     c_put_str(TERM_WHITE, _("骨       ----   $100,000", "bones       ----   $100,000"), 10, 10);
217 }
218
219 /*!
220  * @brief 通常の賞金首情報を表示する。
221  * @return なし
222  */
223 void show_bounty(void)
224 {
225     TERM_LEN y = 0;
226
227     clear_bldg(4, 18);
228     prt(_("死体を持ち帰れば報酬を差し上げます。", "Offer a prize when you bring a wanted monster's corpse"), 4, 10);
229     c_put_str(TERM_YELLOW, _("現在の賞金首", "Wanted monsters"), 6, 10);
230
231     for (int i = 0; i < MAX_BOUNTY; i++) {
232         byte color;
233         concptr done_mark;
234         monster_race *r_ptr
235             = &r_info[(current_world_ptr->bounty_r_idx[i] > 10000 ? current_world_ptr->bounty_r_idx[i] - 10000 : current_world_ptr->bounty_r_idx[i])];
236
237         if (current_world_ptr->bounty_r_idx[i] > 10000) {
238             color = TERM_RED;
239             done_mark = _("(済)", "(done)");
240         } else {
241             color = TERM_WHITE;
242             done_mark = "";
243         }
244
245         c_prt(color, format("%s %s", r_name + r_ptr->name, done_mark), y + 7, 10);
246
247         y = (y + 1) % 10;
248         if (!y && (i < MAX_BOUNTY - 1)) {
249             prt(_("何かキーを押してください", "Hit any key."), 0, 0);
250             (void)inkey();
251             prt("", 0, 0);
252             clear_bldg(7, 18);
253         }
254     }
255 }
256
257 /*!
258  * @brief 今日の賞金首を確定する / Determine today's bounty monster
259  * @param player_type プレーヤーへの参照ポインタ
260  * @return なし
261  * @note conv_old is used if loaded 0.0.3 or older save file
262  */
263 void determine_daily_bounty(player_type *player_ptr, bool conv_old)
264 {
265     int max_dl = 3, i;
266     if (!conv_old) {
267         for (i = 0; i < current_world_ptr->max_d_idx; i++) {
268             if (max_dlv[i] < d_info[i].mindepth)
269                 continue;
270             if (max_dl < max_dlv[i])
271                 max_dl = max_dlv[i];
272         }
273     } else {
274         max_dl = MAX(max_dlv[DUNGEON_ANGBAND], 3);
275     }
276
277     get_mon_num_prep(player_ptr, NULL, NULL);
278
279     while (TRUE) {
280         today_mon = get_mon_num(player_ptr, max_dl, GMN_ARENA);
281         monster_race *r_ptr;
282         r_ptr = &r_info[today_mon];
283
284         if (r_ptr->flags1 & RF1_UNIQUE)
285             continue;
286         if (r_ptr->flags7 & (RF7_NAZGUL | RF7_UNIQUE2))
287             continue;
288         if (r_ptr->flags2 & RF2_MULTIPLY)
289             continue;
290         if ((r_ptr->flags9 & (RF9_DROP_CORPSE | RF9_DROP_SKELETON)) != (RF9_DROP_CORPSE | RF9_DROP_SKELETON))
291             continue;
292         if (r_ptr->level < MIN(max_dl / 2, 40))
293             continue;
294         if (r_ptr->rarity > 10)
295             continue;
296         break;
297     }
298 }
299
300 /*!
301  * @brief 賞金首となるユニークを確定する / Determine bounty uniques
302  * @param player_ptr プレーヤーへの参照ポインタ
303  * @return なし
304  */
305 void determine_bounty_uniques(player_type *player_ptr)
306 {
307     get_mon_num_prep(player_ptr, NULL, NULL);
308     for (int i = 0; i < MAX_BOUNTY; i++) {
309         while (TRUE) {
310             current_world_ptr->bounty_r_idx[i] = get_mon_num(player_ptr, MAX_DEPTH - 1, GMN_ARENA);
311             monster_race *r_ptr;
312             r_ptr = &r_info[current_world_ptr->bounty_r_idx[i]];
313
314             if (!(r_ptr->flags1 & RF1_UNIQUE))
315                 continue;
316
317             if (!(r_ptr->flags9 & (RF9_DROP_CORPSE | RF9_DROP_SKELETON)))
318                 continue;
319
320             if (r_ptr->rarity > 100)
321                 continue;
322
323             if (no_questor_or_bounty_uniques(current_world_ptr->bounty_r_idx[i]))
324                 continue;
325
326             int j;
327             for (j = 0; j < i; j++) {
328                 if (current_world_ptr->bounty_r_idx[i] == current_world_ptr->bounty_r_idx[j])
329                     break;
330             }
331
332             if (j == i)
333                 break;
334         }
335     }
336
337     for (int i = 0; i < MAX_BOUNTY - 1; i++) {
338         for (int j = i; j < MAX_BOUNTY; j++) {
339             MONRACE_IDX tmp;
340             if (r_info[current_world_ptr->bounty_r_idx[i]].level > r_info[current_world_ptr->bounty_r_idx[j]].level) {
341                 tmp = current_world_ptr->bounty_r_idx[i];
342                 current_world_ptr->bounty_r_idx[i] = current_world_ptr->bounty_r_idx[j];
343                 current_world_ptr->bounty_r_idx[j] = tmp;
344             }
345         }
346     }
347 }