OSDN Git Service

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