OSDN Git Service

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