OSDN Git Service

[Refactor] #38844 Continued removing inclusion of monster-race.h in angband.h
[hengband/hengband.git] / src / market / arena.c
1 #include "market/arena.h"
2 #include "core/asking-player.h"
3 #include "core/show-file.h"
4 #include "core/stuff-handler.h"
5 #include "dungeon/dungeon.h"
6 #include "floor/floor.h"
7 #include "io/input-key-acceptor.h"
8 #include "main/sound-of-music.h"
9 #include "market/arena-info-table.h"
10 #include "market/building-actions-table.h"
11 #include "market/building-util.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-flags-ability1.h"
14 #include "monster-race/race-flags-ability2.h"
15 #include "monster-race/race-flags-resistance.h"
16 #include "monster-race/race-flags1.h"
17 #include "monster-race/race-flags7.h"
18 #include "monster-race/monster-race-hook.h"
19 #include "monster/monster-list.h"
20 #include "monster/monster-util.h"
21 #include "player/player-effects.h"
22 #include "term/screen-processor.h"
23 #include "util/int-char-converter.h"
24 #include "view/display-messages.h"
25 #include "world/world.h"
26
27 /*!
28  * @brief 優勝時のメッセージを表示し、賞金を与える
29  * @param player_ptr プレーヤーへの参照ポインタ
30  * @return まだ優勝していないか、挑戦者モンスターとの戦いではFALSE
31  */
32 static bool process_ostensible_arena_victory(player_type *player_ptr)
33 {
34     if (player_ptr->arena_number != MAX_ARENA_MONS)
35         return FALSE;
36
37     clear_bldg(5, 19);
38     prt(_("アリーナの優勝者!", "               Arena Victor!"), 5, 0);
39     prt(_("おめでとう!あなたは全ての敵を倒しました。", "Congratulations!  You have defeated all before you."), 7, 0);
40     prt(_("賞金として $1,000,000 が与えられます。", "For that, receive the prize: 1,000,000 gold pieces"), 8, 0);
41
42     prt("", 10, 0);
43     prt("", 11, 0);
44     player_ptr->au += 1000000L;
45     msg_print(_("スペースキーで続行", "Press the space bar to continue"));
46     msg_print(NULL);
47     player_ptr->arena_number++;
48     return TRUE;
49 }
50
51 /*!
52  * @brief はぐれメタルとの対戦
53  * @param player_ptr プレーヤーへの参照ポインタ
54  * @return まだパワー・ワイアーム以下を倒していないならFALSE、倒していたらTRUE
55  */
56 static bool battle_metal_babble(player_type *player_ptr)
57 {
58     if (player_ptr->arena_number <= MAX_ARENA_MONS)
59         return FALSE;
60
61     if (player_ptr->arena_number >= MAX_ARENA_MONS + 2) {
62         msg_print(_("あなたはアリーナに入り、しばらくの間栄光にひたった。", "You enter the arena briefly and bask in your glory."));
63         msg_print(NULL);
64         return TRUE;
65     }
66
67     msg_print(_("君のために最強の挑戦者を用意しておいた。", "The strongest challenger is waiting for you."));
68     msg_print(NULL);
69     if (!get_check(_("挑戦するかね?", "Do you fight? "))) {
70         msg_print(_("残念だ。", "We are disappointed."));
71         return TRUE;
72     }
73
74     msg_print(_("死ぬがよい。", "Die, maggots."));
75     msg_print(NULL);
76
77     player_ptr->exit_bldg = FALSE;
78     reset_tim_flags(player_ptr);
79
80     /* Save the surface floor as saved floor */
81     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS);
82
83     player_ptr->current_floor_ptr->inside_arena = TRUE;
84     player_ptr->leaving = TRUE;
85     player_ptr->leave_bldg = TRUE;
86     return TRUE;
87 }
88
89 static void go_to_arena(player_type *player_ptr)
90 {
91     if (process_ostensible_arena_victory(player_ptr))
92         return;
93
94     if (battle_metal_babble(player_ptr))
95         return;
96
97     if (player_ptr->riding && (player_ptr->pclass != CLASS_BEASTMASTER) && (player_ptr->pclass != CLASS_CAVALRY)) {
98         msg_print(_("ペットに乗ったままではアリーナへ入れさせてもらえなかった。", "You don't have permission to enter with pet."));
99         msg_print(NULL);
100         return;
101     }
102
103     player_ptr->exit_bldg = FALSE;
104     reset_tim_flags(player_ptr);
105     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS);
106
107     player_ptr->current_floor_ptr->inside_arena = TRUE;
108     player_ptr->leaving = TRUE;
109     player_ptr->leave_bldg = TRUE;
110 }
111
112 static void see_arena_poster(player_type *player_ptr)
113 {
114     if (player_ptr->arena_number == MAX_ARENA_MONS) {
115         msg_print(_("あなたは勝利者だ。 アリーナでのセレモニーに参加しなさい。", "You are victorious. Enter the arena for the ceremony."));
116         return;
117     }
118
119     if (player_ptr->arena_number > MAX_ARENA_MONS) {
120         msg_print(_("あなたはすべての敵に勝利した。", "You have won against all foes."));
121         return;
122     }
123
124     monster_race *r_ptr;
125     r_ptr = &r_info[arena_info[player_ptr->arena_number].r_idx];
126     concptr name = (r_name + r_ptr->name);
127     msg_format(_("%s に挑戦するものはいないか?", "Do I hear any challenges against: %s"), name);
128
129     player_ptr->monster_race_idx = arena_info[player_ptr->arena_number].r_idx;
130     player_ptr->window |= (PW_MONSTER);
131     handle_stuff(player_ptr);
132 }
133
134 /*!
135  * @brief 闘技場に入るコマンドの処理 / arena commands
136  * @param player_ptr プレーヤーへの参照ポインタ
137  * @param cmd 闘技場処理のID
138  * @return なし
139  */
140 void arena_comm(player_type *player_ptr, int cmd)
141 {
142     switch (cmd) {
143     case BACT_ARENA:
144         go_to_arena(player_ptr);
145         return;
146     case BACT_POSTER:
147         see_arena_poster(player_ptr);
148         return;
149     case BACT_ARENA_RULES:
150         screen_save();
151
152         /* Peruse the arena help file */
153         (void)show_file(player_ptr, TRUE, _("arena_j.txt", "arena.txt"), NULL, 0, 0);
154         screen_load();
155         break;
156     }
157 }
158
159 /*!
160  * @brief モンスター闘技場に参加するモンスターを更新する。
161  * @param player_ptr プレーヤーへの参照ポインタ
162  * @return なし
163  */
164 void update_gambling_monsters(player_type *player_ptr)
165 {
166     int total, i;
167     int max_dl = 0;
168     int mon_level;
169     int power[4];
170     bool tekitou;
171
172     for (i = 0; i < current_world_ptr->max_d_idx; i++) {
173         if (max_dl < max_dlv[i])
174             max_dl = max_dlv[i];
175     }
176
177     mon_level = randint1(MIN(max_dl, 122)) + 5;
178     if (randint0(100) < 60) {
179         i = randint1(MIN(max_dl, 122)) + 5;
180         mon_level = MAX(i, mon_level);
181     }
182
183     if (randint0(100) < 30) {
184         i = randint1(MIN(max_dl, 122)) + 5;
185         mon_level = MAX(i, mon_level);
186     }
187
188     while (TRUE) {
189         total = 0;
190         tekitou = FALSE;
191         for (i = 0; i < 4; i++) {
192             MONRACE_IDX r_idx;
193             int j;
194             while (TRUE) {
195                 get_mon_num_prep(player_ptr, monster_can_entry_arena, NULL);
196                 r_idx = get_mon_num(player_ptr, mon_level, GMN_ARENA);
197                 if (!r_idx)
198                     continue;
199
200                 if ((r_info[r_idx].flags1 & RF1_UNIQUE) || (r_info[r_idx].flags7 & RF7_UNIQUE2)) {
201                     if ((r_info[r_idx].level + 10) > mon_level)
202                         continue;
203                 }
204
205                 for (j = 0; j < i; j++)
206                     if (r_idx == battle_mon[j])
207                         break;
208                 if (j < i)
209                     continue;
210
211                 break;
212             }
213             battle_mon[i] = r_idx;
214             if (r_info[r_idx].level < 45)
215                 tekitou = TRUE;
216         }
217
218         for (i = 0; i < 4; i++) {
219             monster_race *r_ptr = &r_info[battle_mon[i]];
220             int num_taisei = count_bits(r_ptr->flagsr & (RFR_IM_ACID | RFR_IM_ELEC | RFR_IM_FIRE | RFR_IM_COLD | RFR_IM_POIS));
221
222             if (r_ptr->flags1 & RF1_FORCE_MAXHP)
223                 power[i] = r_ptr->hdice * r_ptr->hside * 2;
224             else
225                 power[i] = r_ptr->hdice * (r_ptr->hside + 1);
226             power[i] = power[i] * (100 + r_ptr->level) / 100;
227             if (r_ptr->speed > 110)
228                 power[i] = power[i] * (r_ptr->speed * 2 - 110) / 100;
229             if (r_ptr->speed < 110)
230                 power[i] = power[i] * (r_ptr->speed - 20) / 100;
231             if (num_taisei > 2)
232                 power[i] = power[i] * (num_taisei * 2 + 5) / 10;
233             else if (r_ptr->a_ability_flags2 & RF6_INVULNER)
234                 power[i] = power[i] * 4 / 3;
235             else if (r_ptr->a_ability_flags2 & RF6_HEAL)
236                 power[i] = power[i] * 4 / 3;
237             else if (r_ptr->a_ability_flags1 & RF5_DRAIN_MANA)
238                 power[i] = power[i] * 11 / 10;
239             if (r_ptr->flags1 & RF1_RAND_25)
240                 power[i] = power[i] * 9 / 10;
241             if (r_ptr->flags1 & RF1_RAND_50)
242                 power[i] = power[i] * 9 / 10;
243             if (r_ptr->flagsr & RFR_RES_ALL)
244                 power[i] *= 100000;
245             if (r_ptr->arena_ratio)
246                 power[i] = power[i] * r_ptr->arena_ratio / 100;
247             total += power[i];
248         }
249
250         for (i = 0; i < 4; i++) {
251             if (power[i] <= 0)
252                 break;
253             power[i] = total * 60 / power[i];
254             if (tekitou && ((power[i] < 160) || power[i] > 1500))
255                 break;
256             if ((power[i] < 160) && randint0(20))
257                 break;
258             if (power[i] < 101)
259                 power[i] = 100 + randint1(5);
260             mon_odds[i] = power[i];
261         }
262
263         if (i == 4)
264             break;
265     }
266 }
267
268 /*!
269  * @brief モンスター闘技場のメインルーチン
270  * @param player_ptr プレーヤーへの参照ポインタ
271  * @return 賭けを開始したか否か
272  */
273 bool monster_arena_comm(player_type *player_ptr)
274 {
275     PRICE maxbet;
276     PRICE wager;
277     char out_val[160], tmp_str[80];
278     concptr p;
279
280     if ((current_world_ptr->game_turn - current_world_ptr->arena_start_turn) > TURNS_PER_TICK * 250) {
281         update_gambling_monsters(player_ptr);
282         current_world_ptr->arena_start_turn = current_world_ptr->game_turn;
283     }
284
285     screen_save();
286
287     /* No money */
288     if (player_ptr->au <= 1) {
289         msg_print(_("おい!おまえ一文なしじゃないか!こっから出ていけ!", "Hey! You don't have gold - get out of here!"));
290         msg_print(NULL);
291         screen_load();
292         return FALSE;
293     }
294
295     clear_bldg(4, 10);
296
297     prt(_("モンスター                                                     倍率", "Monsters                                                       Odds"), 4, 4);
298     for (int i = 0; i < 4; i++) {
299         char buf[80];
300         monster_race *r_ptr = &r_info[battle_mon[i]];
301
302         sprintf(buf, _("%d) %-58s  %4ld.%02ld倍", "%d) %-58s  %4ld.%02ld"), i + 1,
303             _(format("%s%s", r_name + r_ptr->name, (r_ptr->flags1 & RF1_UNIQUE) ? "もどき" : "      "),
304                 format("%s%s", (r_ptr->flags1 & RF1_UNIQUE) ? "Fake " : "", r_name + r_ptr->name)),
305             (long int)mon_odds[i] / 100, (long int)mon_odds[i] % 100);
306         prt(buf, 5 + i, 1);
307     }
308
309     prt(_("どれに賭けますか:", "Which monster: "), 0, 0);
310     while (TRUE) {
311         int i = inkey();
312
313         if (i == ESCAPE) {
314             screen_load();
315             return FALSE;
316         }
317
318         if (i >= '1' && i <= '4') {
319             sel_monster = i - '1';
320             battle_odds = mon_odds[sel_monster];
321             break;
322         }
323
324         else
325             bell();
326     }
327
328     clear_bldg(4, 4);
329     for (int i = 0; i < 4; i++)
330         if (i != sel_monster)
331             clear_bldg(i + 5, i + 5);
332
333     maxbet = player_ptr->lev * 200;
334
335     /* We can't bet more than we have */
336     maxbet = MIN(maxbet, player_ptr->au);
337
338     /* Get the wager */
339     strcpy(out_val, "");
340     sprintf(tmp_str, _("賭け金 (1-%ld)?", "Your wager (1-%ld) ? "), (long int)maxbet);
341
342     /*
343      * Use get_string() because we may need more than
344      * the s16b value returned by get_quantity().
345      */
346     if (!get_string(tmp_str, out_val, 32)) {
347         screen_load();
348         return FALSE;
349     }
350
351     for (p = out_val; *p == ' '; p++)
352         ;
353
354     wager = atol(p);
355     if (wager > player_ptr->au) {
356         msg_print(_("おい!金が足りないじゃないか!出ていけ!", "Hey! You don't have the gold - get out of here!"));
357
358         msg_print(NULL);
359         screen_load();
360         return FALSE;
361     } else if (wager > maxbet) {
362         msg_format(_("%ldゴールドだけ受けよう。残りは取っときな。", "I'll take %ld gold of that. Keep the rest."), (long int)maxbet);
363
364         wager = maxbet;
365     } else if (wager < 1) {
366         msg_print(_("OK、1ゴールドでいこう。", "Ok, we'll start with 1 gold."));
367         wager = 1;
368     }
369
370     msg_print(NULL);
371     battle_odds = MAX(wager + 1, wager * battle_odds / 100);
372     kakekin = wager;
373     player_ptr->au -= wager;
374     reset_tim_flags(player_ptr);
375
376     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS);
377
378     player_ptr->phase_out = TRUE;
379     player_ptr->leaving = TRUE;
380     player_ptr->leave_bldg = TRUE;
381
382     screen_load();
383     return TRUE;
384 }