OSDN Git Service

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