OSDN Git Service

[Refactor] #40460 Renamed dungeon-file.c/h to fixed-map-parser.c/h
[hengband/hengband.git] / src / dungeon / quest.c
1 #include "dungeon/quest.h"
2 #include "cmd-io/cmd-dump.h"
3 #include "dungeon/dungeon.h"
4 #include "floor/floor-events.h"
5 #include "floor/floor-object.h"
6 #include "floor/floor-save.h"
7 #include "floor/floor.h"
8 #include "grid/feature.h"
9 #include "grid/grid.h"
10 #include "io/write-diary.h"
11 #include "locale/english.h"
12 #include "main/music-definitions-table.h"
13 #include "monster/monster-race-hook.h"
14 #include "monster/monster.h"
15 #include "object-enchant/artifact.h"
16 #include "object-enchant/item-apply-magic.h"
17 #include "object/object-generator.h"
18 #include "player/player-personalities-table.h"
19 #include "player/player-status.h"
20 #include "system/system-variables.h"
21 #include "util/util.h"
22 #include "view/display-main-window.h"
23 #include "world/world.h"
24
25 quest_type *quest; /*!< Quest info */
26 QUEST_IDX max_q_idx; /*!< Maximum number of quests */
27 char quest_text[10][80]; /*!< Quest text */
28 int quest_text_line; /*!< Current line of the quest text */
29 int leaving_quest = 0;
30
31 /*!
32  * @brief クエスト突入時のメッセージテーブル / Array of places to find an inscription
33  */
34 static concptr find_quest[] =
35 {
36         _("床にメッセージが刻まれている:", "You find the following inscription in the floor"),
37         _("壁にメッセージが刻まれている:", "You see a message inscribed in the wall"),
38         _("メッセージを見つけた:", "There is a sign saying"),
39         _("何かが階段の上に書いてある:", "Something is written on the staircase"),
40         _("巻物を見つけた。メッセージが書いてある:", "You find a scroll with the following message"),
41 };
42
43
44 /*!
45  * @brief ランダムクエストの討伐ユニークを決める / Determine the random quest uniques
46  * @param q_ptr クエスト構造体の参照ポインタ
47  * @return なし
48  */
49 void determine_random_questor(player_type *player_ptr, quest_type *q_ptr)
50 {
51         get_mon_num_prep(player_ptr, mon_hook_quest, NULL);
52
53         MONRACE_IDX r_idx;
54         while (TRUE)
55         {
56                 /*
57                  * Random monster 5 - 10 levels out of depth
58                  * (depending on level)
59                  */
60                 r_idx = get_mon_num(player_ptr, q_ptr->level + 5 + randint1(q_ptr->level / 10), GMN_ARENA);
61                 monster_race *r_ptr;
62                 r_ptr = &r_info[r_idx];
63
64                 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
65                 if (r_ptr->flags1 & RF1_QUESTOR) continue;
66                 if (r_ptr->rarity > 100) continue;
67                 if (r_ptr->flags7 & RF7_FRIENDLY) continue;
68                 if (r_ptr->flags7 & RF7_AQUATIC) continue;
69                 if (r_ptr->flags8 & RF8_WILD_ONLY) continue;
70                 if (no_questor_or_bounty_uniques(r_idx)) continue;
71
72                 /*
73                  * Accept monsters that are 2 - 6 levels
74                  * out of depth depending on the quest level
75                  */
76                 if (r_ptr->level > (q_ptr->level + (q_ptr->level / 20))) break;
77         }
78
79         q_ptr->r_idx = r_idx;
80 }
81
82
83 /*!
84  * @brief クエストを達成状態にする /
85  * @param player_ptr プレーヤーへの参照ポインタ
86  * @param quest_num 達成状態にしたいクエストのID
87  * @return なし
88  */
89 void complete_quest(player_type *player_ptr, QUEST_IDX quest_num)
90 {
91         quest_type* const q_ptr = &quest[quest_num];
92
93         switch (q_ptr->type)
94         {
95         case QUEST_TYPE_RANDOM:
96                 if (record_rand_quest) exe_write_diary(player_ptr, DIARY_RAND_QUEST_C, quest_num, NULL);
97                 break;
98         default:
99                 if (record_fix_quest) exe_write_diary(player_ptr, DIARY_FIX_QUEST_C, quest_num, NULL);
100                 break;
101         }
102
103         q_ptr->status = QUEST_STATUS_COMPLETED;
104         q_ptr->complev = player_ptr->lev;
105         update_playtime();
106         q_ptr->comptime = current_world_ptr->play_time;
107
108         if (q_ptr->flags & QUEST_FLAG_SILENT) return;
109
110         play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_QUEST_CLEAR);
111         msg_print(_("クエストを達成した!", "You just completed your quest!"));
112         msg_print(NULL);
113 }
114
115
116 /*!
117  * @brief 特定の敵を倒した際にクエスト達成処理 /
118  * Check for "Quest" completion when a quest monster is killed or charmed.
119  * @param player_ptr プレーヤーへの参照ポインタ
120  * @param m_ptr 撃破したモンスターの構造体参照ポインタ
121  * @return なし
122  */
123 void check_quest_completion(player_type *player_ptr, monster_type *m_ptr)
124 {
125         POSITION y = m_ptr->fy;
126         POSITION x = m_ptr->fx;
127
128         floor_type *floor_ptr = player_ptr->current_floor_ptr;
129         QUEST_IDX quest_num = floor_ptr->inside_quest;
130
131         /* Search for an active quest on this dungeon level */
132         if (!quest_num)
133         {
134                 QUEST_IDX i;
135                 for (i = max_q_idx - 1; i > 0; i--)
136                 {
137                         quest_type* const q_ptr = &quest[i];
138
139                         /* Quest is not active */
140                         if (q_ptr->status != QUEST_STATUS_TAKEN)
141                                 continue;
142
143                         /* Quest is not a dungeon quest */
144                         if (q_ptr->flags & QUEST_FLAG_PRESET)
145                                 continue;
146
147                         /* Quest is not on this level */
148                         if ((q_ptr->level != floor_ptr->dun_level) &&
149                                 (q_ptr->type != QUEST_TYPE_KILL_ANY_LEVEL))
150                                 continue;
151
152                         /* Not a "kill monster" quest */
153                         if ((q_ptr->type == QUEST_TYPE_FIND_ARTIFACT) ||
154                                 (q_ptr->type == QUEST_TYPE_FIND_EXIT))
155                                 continue;
156
157                         /* Interesting quest */
158                         if ((q_ptr->type == QUEST_TYPE_KILL_NUMBER) ||
159                                 (q_ptr->type == QUEST_TYPE_TOWER) ||
160                                 (q_ptr->type == QUEST_TYPE_KILL_ALL))
161                                 break;
162
163                         /* Interesting quest */
164                         if (((q_ptr->type == QUEST_TYPE_KILL_LEVEL) ||
165                                 (q_ptr->type == QUEST_TYPE_KILL_ANY_LEVEL) ||
166                                 (q_ptr->type == QUEST_TYPE_RANDOM)) &&
167                                 (q_ptr->r_idx == m_ptr->r_idx))
168                                 break;
169                 }
170
171                 quest_num = i;
172         }
173
174         /* Handle the current quest */
175         bool create_stairs = FALSE;
176         bool reward = FALSE;
177         if (quest_num && (quest[quest_num].status == QUEST_STATUS_TAKEN))
178         {
179                 /* Current quest */
180                 quest_type* const q_ptr = &quest[quest_num];
181
182                 switch (q_ptr->type)
183                 {
184                 case QUEST_TYPE_KILL_NUMBER:
185                 {
186                         q_ptr->cur_num++;
187
188                         if (q_ptr->cur_num >= q_ptr->num_mon)
189                         {
190                                 complete_quest(player_ptr, quest_num);
191                                 q_ptr->cur_num = 0;
192                         }
193
194                         break;
195                 }
196                 case QUEST_TYPE_KILL_ALL:
197                 {
198                         if (!is_hostile(m_ptr)) break;
199
200                         if (count_all_hostile_monsters(floor_ptr) != 1) break;
201
202                         if (q_ptr->flags & QUEST_FLAG_SILENT)
203                         {
204                                 q_ptr->status = QUEST_STATUS_FINISHED;
205                         }
206                         else
207                         {
208                                 complete_quest(player_ptr, quest_num);
209                         }
210
211                         break;
212                 }
213                 case QUEST_TYPE_KILL_LEVEL:
214                 case QUEST_TYPE_RANDOM:
215                 {
216                         /* Only count valid monsters */
217                         if (q_ptr->r_idx != m_ptr->r_idx)
218                                 break;
219
220                         q_ptr->cur_num++;
221
222                         if (q_ptr->cur_num < q_ptr->max_num) break;
223
224                         complete_quest(player_ptr, quest_num);
225
226                         if (!(q_ptr->flags & QUEST_FLAG_PRESET))
227                         {
228                                 create_stairs = TRUE;
229                                 floor_ptr->inside_quest = 0;
230                         }
231
232                         /* Finish the two main quests without rewarding */
233                         if ((quest_num == QUEST_OBERON) || (quest_num == QUEST_SERPENT))
234                         {
235                                 q_ptr->status = QUEST_STATUS_FINISHED;
236                         }
237
238                         if (q_ptr->type == QUEST_TYPE_RANDOM)
239                         {
240                                 reward = TRUE;
241                                 q_ptr->status = QUEST_STATUS_FINISHED;
242                         }
243
244                         break;
245                 }
246                 case QUEST_TYPE_KILL_ANY_LEVEL:
247                 {
248                         q_ptr->cur_num++;
249                         if (q_ptr->cur_num >= q_ptr->max_num)
250                         {
251                                 complete_quest(player_ptr, quest_num);
252                                 q_ptr->cur_num = 0;
253                         }
254
255                         break;
256                 }
257                 case QUEST_TYPE_TOWER:
258                 {
259                         if (!is_hostile(m_ptr)) break;
260
261                         if (count_all_hostile_monsters(floor_ptr) == 1)
262                         {
263                                 q_ptr->status = QUEST_STATUS_STAGE_COMPLETED;
264
265                                 if ((quest[QUEST_TOWER1].status == QUEST_STATUS_STAGE_COMPLETED) &&
266                                         (quest[QUEST_TOWER2].status == QUEST_STATUS_STAGE_COMPLETED) &&
267                                         (quest[QUEST_TOWER3].status == QUEST_STATUS_STAGE_COMPLETED))
268                                 {
269
270                                         complete_quest(player_ptr, QUEST_TOWER1);
271                                 }
272                         }
273
274                         break;
275                 }
276                 }
277         }
278
279         /* Create a magical staircase */
280         if (create_stairs)
281         {
282                 POSITION ny, nx;
283
284                 /* Stagger around */
285                 while (cave_perma_bold(floor_ptr, y, x) || floor_ptr->grid_array[y][x].o_idx || (floor_ptr->grid_array[y][x].info & CAVE_OBJECT))
286                 {
287                         /* Pick a location */
288                         scatter(player_ptr, &ny, &nx, y, x, 1, 0);
289
290                         /* Stagger */
291                         y = ny; x = nx;
292                 }
293
294                 /* Explain the staircase */
295                 msg_print(_("魔法の階段が現れた...", "A magical staircase appears..."));
296
297                 /* Create stairs down */
298                 cave_set_feat(player_ptr, y, x, feat_down_stair);
299
300                 /* Remember to update everything */
301                 player_ptr->update |= (PU_FLOW);
302         }
303
304         if (!reward) return;
305
306         object_type forge;
307         object_type *o_ptr;
308         for (int i = 0; i < (floor_ptr->dun_level / 15) + 1; i++)
309         {
310                 o_ptr = &forge;
311                 object_wipe(o_ptr);
312
313                 /* Make a great object */
314                 make_object(player_ptr, o_ptr, AM_GOOD | AM_GREAT);
315                 (void)drop_near(player_ptr, o_ptr, -1, y, x);
316         }
317 }
318
319
320 /*!
321  * @brief 特定のアーティファクトを入手した際のクエスト達成処理 /
322  * Check for "Quest" completion when a quest monster is killed or charmed.
323  * @param player_ptr プレーヤーへの参照ポインタ
324  * @param o_ptr 入手したオブジェクトの構造体参照ポインタ
325  * @return なし
326  */
327 void check_find_art_quest_completion(player_type *player_ptr, object_type *o_ptr)
328 {
329         /* Check if completed a quest */
330         for (QUEST_IDX i = 0; i < max_q_idx; i++)
331         {
332                 if ((quest[i].type == QUEST_TYPE_FIND_ARTIFACT) &&
333                         (quest[i].status == QUEST_STATUS_TAKEN) &&
334                         (quest[i].k_idx == o_ptr->name1))
335                 {
336                         complete_quest(player_ptr, i);
337                 }
338         }
339 }
340
341
342 /*!
343  * @brief クエストの導入メッセージを表示する / Discover quest
344  * @param q_idx 開始されたクエストのID
345  */
346 void quest_discovery(QUEST_IDX q_idx)
347 {
348         quest_type *q_ptr = &quest[q_idx];
349         monster_race *r_ptr = &r_info[q_ptr->r_idx];
350         MONSTER_NUMBER q_num = q_ptr->max_num;
351
352         if (!q_idx) return;
353
354         GAME_TEXT name[MAX_NLEN];
355         strcpy(name, (r_name + r_ptr->name));
356
357         msg_print(find_quest[rand_range(0, 4)]);
358         msg_print(NULL);
359
360         if (q_num != 1)
361         {
362 #ifdef JP
363 #else
364                 plural_aux(name);
365 #endif
366                 msg_format(_("注意しろ!この階は%d体の%sによって守られている!", "Be warned, this level is guarded by %d %s!"), q_num, name);
367                 return;
368         }
369
370         bool is_random_quest_skipped = (r_ptr->flags1 & RF1_UNIQUE) != 0;
371         is_random_quest_skipped &= r_ptr->max_num == 0;
372         if (!is_random_quest_skipped)
373         {
374                 msg_format(_("注意せよ!この階は%sによって守られている!", "Beware, this level is protected by %s!"), name);
375                 return;
376         }
377
378         msg_print(_("この階は以前は誰かによって守られていたようだ…。", "It seems that this level was protected by someone before..."));
379         quest[q_idx].status = QUEST_STATUS_FINISHED;
380         q_ptr->complev = 0;
381         update_playtime();
382         q_ptr->comptime = current_world_ptr->play_time;
383 }
384
385
386 /*!
387  * @brief 新しく入ったダンジョンの階層に固定されている一般のクエストを探し出しIDを返す。
388  * / Hack -- Check if a level is a "quest" level
389  * @param player_ptr プレーヤーへの参照ポインタ
390  * @param level 検索対象になる階
391  * @return クエストIDを返す。該当がない場合0を返す。
392  */
393 QUEST_IDX quest_number(player_type *player_ptr, DEPTH level)
394 {
395         floor_type *floor_ptr = player_ptr->current_floor_ptr;
396         if (floor_ptr->inside_quest)
397                 return (floor_ptr->inside_quest);
398
399         for (QUEST_IDX i = 0; i < max_q_idx; i++)
400         {
401                 if (quest[i].status != QUEST_STATUS_TAKEN) continue;
402
403                 if ((quest[i].type == QUEST_TYPE_KILL_LEVEL) &&
404                         !(quest[i].flags & QUEST_FLAG_PRESET) &&
405                         (quest[i].level == level) &&
406                         (quest[i].dungeon == player_ptr->dungeon_idx))
407                         return i;
408         }
409
410         return random_quest_number(player_ptr, level);
411 }
412
413
414 /*!
415  * @brief 新しく入ったダンジョンの階層に固定されているランダムクエストを探し出しIDを返す。
416  * @param player_ptr プレーヤーへの参照ポインタ
417  * @param level 検索対象になる階
418  * @return クエストIDを返す。該当がない場合0を返す。
419  */
420 QUEST_IDX random_quest_number(player_type *player_ptr, DEPTH level)
421 {
422         if (player_ptr->dungeon_idx != DUNGEON_ANGBAND) return 0;
423
424         for (QUEST_IDX i = MIN_RANDOM_QUEST; i < MAX_RANDOM_QUEST + 1; i++)
425         {
426                 if ((quest[i].type == QUEST_TYPE_RANDOM) &&
427                         (quest[i].status == QUEST_STATUS_TAKEN) &&
428                         (quest[i].level == level) &&
429                         (quest[i].dungeon == DUNGEON_ANGBAND))
430                 {
431                         return i;
432                 }
433         }
434
435         return 0;
436 }
437
438
439 /*!
440  * @brief クエスト階層から離脱する際の処理
441  * @param player_ptr プレーヤーへの参照ポインタ
442  * @return なし
443  */
444 void leave_quest_check(player_type *player_ptr)
445 {
446         leaving_quest = player_ptr->current_floor_ptr->inside_quest;
447         if (!leaving_quest) return;
448
449         quest_type* const q_ptr = &quest[leaving_quest];
450         bool is_one_time_quest = ((q_ptr->flags & QUEST_FLAG_ONCE) || (q_ptr->type == QUEST_TYPE_RANDOM)) &&
451                 (q_ptr->status == QUEST_STATUS_TAKEN);
452         if (!is_one_time_quest) return;
453
454         q_ptr->status = QUEST_STATUS_FAILED;
455         q_ptr->complev = player_ptr->lev;
456         update_playtime();
457         q_ptr->comptime = current_world_ptr->play_time;
458
459         /* Additional settings */
460         switch (q_ptr->type)
461         {
462         case QUEST_TYPE_TOWER:
463                 quest[QUEST_TOWER1].status = QUEST_STATUS_FAILED;
464                 quest[QUEST_TOWER1].complev = player_ptr->lev;
465                 break;
466         case QUEST_TYPE_FIND_ARTIFACT:
467                 a_info[q_ptr->k_idx].gen_flags &= ~(TRG_QUESTITEM);
468                 break;
469         case QUEST_TYPE_RANDOM:
470                 r_info[q_ptr->r_idx].flags1 &= ~(RF1_QUESTOR);
471
472                 /* Floor of random quest will be blocked */
473                 prepare_change_floor_mode(player_ptr, CFM_NO_RETURN);
474                 break;
475         }
476
477         /* Record finishing a quest */
478         if (q_ptr->type == QUEST_TYPE_RANDOM)
479         {
480                 if (record_rand_quest)
481                         exe_write_diary(player_ptr, DIARY_RAND_QUEST_F, leaving_quest, NULL);
482                 return;
483         }
484
485         if (record_fix_quest)
486                 exe_write_diary(player_ptr, DIARY_FIX_QUEST_F, leaving_quest, NULL);
487 }
488
489
490 /*!
491  * @brief 「塔」クエストの各階層から離脱する際の処理
492  * @return なし
493  */
494 void leave_tower_check(player_type *player_ptr)
495 {
496         leaving_quest = player_ptr->current_floor_ptr->inside_quest;
497         bool is_leaving_from_tower = leaving_quest != 0;
498         is_leaving_from_tower &= quest[leaving_quest].type == QUEST_TYPE_TOWER;
499         is_leaving_from_tower &= quest[QUEST_TOWER1].status != QUEST_STATUS_COMPLETED;
500         if (!is_leaving_from_tower) return;
501         if (quest[leaving_quest].type != QUEST_TYPE_TOWER) return;
502
503         quest[QUEST_TOWER1].status = QUEST_STATUS_FAILED;
504         quest[QUEST_TOWER1].complev = player_ptr->lev;
505         update_playtime();
506         quest[QUEST_TOWER1].comptime = current_world_ptr->play_time;
507 }
508
509
510 /*!
511  * @brief クエスト入り口にプレイヤーが乗った際の処理 / Do building commands
512  * @param player_ptr プレーヤーへの参照ポインタ
513  * @return なし
514  */
515 void do_cmd_quest(player_type *player_ptr)
516 {
517         if (player_ptr->wild_mode) return;
518
519         take_turn(player_ptr, 100);
520
521         if (!cave_have_flag_bold(player_ptr->current_floor_ptr, player_ptr->y, player_ptr->x, FF_QUEST_ENTER))
522         {
523                 msg_print(_("ここにはクエストの入口はない。", "You see no quest level here."));
524                 return;
525         }
526
527         msg_print(_("ここにはクエストへの入口があります。", "There is an entry of a quest."));
528         if (!get_check(_("クエストに入りますか?", "Do you enter? "))) return;
529         if (IS_ECHIZEN(player_ptr))
530                 msg_print(_("『とにかく入ってみようぜぇ。』", ""));
531         else if (player_ptr->pseikaku == PERSONALITY_CHARGEMAN) msg_print("『全滅してやるぞ!』");
532
533         /* Player enters a new quest */
534         player_ptr->oldpy = 0;
535         player_ptr->oldpx = 0;
536
537         leave_quest_check(player_ptr);
538
539         if (quest[player_ptr->current_floor_ptr->inside_quest].type != QUEST_TYPE_RANDOM) player_ptr->current_floor_ptr->dun_level = 1;
540         player_ptr->current_floor_ptr->inside_quest = player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].special;
541
542         player_ptr->leaving = TRUE;
543 }