OSDN Git Service

[Refactor] #38844 Continued removing inclusion of monster-race.h in angband.h
[hengband/hengband.git] / src / io / write-diary.c
1 /*!
2  * @brief 日記へのメッセージ追加処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "io/write-diary.h"
8 #include "dungeon/dungeon.h"
9 #include "dungeon/quest.h"
10 #include "floor/floor.h"
11 #include "info-reader/fixed-map-parser.h"
12 #include "io/files-util.h"
13 #include "market/arena-info-table.h"
14 #include "monster-race/monster-race.h"
15 #include "system/system-variables.h"
16 #include "util/angband-files.h"
17 #include "view/display-messages.h"
18 #include "world/world.h"
19
20 // todo *抹殺* したい…
21 bool write_level;
22
23 #ifdef JP
24 #else
25 /*!
26  * @brief Return suffix of ordinal number
27  * @param num number
28  * @return pointer of suffix string.
29  */
30 concptr get_ordinal_number_suffix(int num)
31 {
32         num = ABS(num) % 100;
33         switch (num % 10)
34         {
35         case 1:
36                 return (num == 11) ? "th" : "st";
37         case 2:
38                 return (num == 12) ? "th" : "nd";
39         case 3:
40                 return (num == 13) ? "th" : "rd";
41         default:
42                 return "th";
43         }
44 }
45 #endif
46
47
48 /*!
49  * todo files.c に移すことも検討する?
50  * @brief 日記ファイルを開く
51  * @param fff ファイルへのポインタ
52  * @param disable_diary 日記への追加を無効化する場合TRUE
53  * @return ファイルがあったらTRUE、なかったらFALSE
54  */
55 static bool open_diary_file(FILE **fff, bool *disable_diary)
56 {
57         GAME_TEXT file_name[MAX_NLEN];
58         sprintf(file_name, _("playrecord-%s.txt", "playrec-%s.txt"), savefile_base);
59         char buf[1024];
60         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, file_name);
61         *fff = angband_fopen(buf, "a");
62         if (*fff) return TRUE;
63
64         msg_format(_("%s を開くことができませんでした。プレイ記録を一時停止します。", "Failed to open %s. Play-Record is disabled temporarily."), buf);
65         msg_format(NULL);
66         *disable_diary = TRUE;
67         return FALSE;
68 }
69
70
71 /*!
72  * @brief フロア情報を日記に追加する
73  * @param creature_ptr プレーヤーへの参照ポインタ
74  * @return クエストID
75  */
76 static QUEST_IDX write_floor(player_type *creature_ptr, concptr *note_level, char *note_level_buf)
77 {
78         floor_type *floor_ptr = creature_ptr->current_floor_ptr;
79         QUEST_IDX q_idx = quest_number(creature_ptr, floor_ptr->dun_level);
80         if (!write_level) return q_idx;
81
82         if (floor_ptr->inside_arena)
83                 *note_level = _("アリーナ:", "Arena:");
84         else if (!floor_ptr->dun_level)
85                 *note_level = _("地上:", "Surface:");
86         else if (q_idx && (is_fixed_quest_idx(q_idx) && !((q_idx == QUEST_OBERON) || (q_idx == QUEST_SERPENT))))
87                 *note_level = _("クエスト:", "Quest:");
88         else
89         {
90 #ifdef JP
91                 sprintf(note_level_buf, "%d階(%s):", (int)floor_ptr->dun_level, d_name + d_info[creature_ptr->dungeon_idx].name);
92 #else
93                 sprintf(note_level_buf, "%s L%d:", d_name + d_info[creature_ptr->dungeon_idx].name, (int)floor_ptr->dun_level);
94 #endif
95                 *note_level = note_level_buf;
96         }
97
98         return q_idx;
99 }
100
101
102 /*!
103  * @brief ペットに関する日記を追加する
104  * @param fff 日記ファイル
105  * @param num 日記へ追加する内容番号
106  * @param note 日記内容のIDに応じた文字列参照ポインタ
107  * @return なし
108  */
109 static void write_diary_pet(FILE *fff, int num, concptr note)
110 {
111         switch (num)
112         {
113         case RECORD_NAMED_PET_NAME:
114                 fprintf(fff, _("%sを旅の友にすることに決めた。\n", "decided to travel together with %s.\n"), note);
115                 break;
116         case RECORD_NAMED_PET_UNNAME:
117                 fprintf(fff, _("%sの名前を消した。\n", "unnamed %s.\n"), note);
118                 break;
119         case RECORD_NAMED_PET_DISMISS:
120                 fprintf(fff, _("%sを解放した。\n", "dismissed %s.\n"), note);
121                 break;
122         case RECORD_NAMED_PET_DEATH:
123                 fprintf(fff, _("%sが死んでしまった。\n", "%s died.\n"), note);
124                 break;
125         case RECORD_NAMED_PET_MOVED:
126                 fprintf(fff, _("%sをおいて別のマップへ移動した。\n", "moved to another map leaving %s behind.\n"), note);
127                 break;
128         case RECORD_NAMED_PET_LOST_SIGHT:
129                 fprintf(fff, _("%sとはぐれてしまった。\n", "lost sight of %s.\n"), note);
130                 break;
131         case RECORD_NAMED_PET_DESTROY:
132                 fprintf(fff, _("%sが*破壊*によって消え去った。\n", "%s was killed by *destruction*.\n"), note);
133                 break;
134         case RECORD_NAMED_PET_EARTHQUAKE:
135                 fprintf(fff, _("%sが岩石に押し潰された。\n", "%s was crushed by falling rocks.\n"), note);
136                 break;
137         case RECORD_NAMED_PET_GENOCIDE:
138                 fprintf(fff, _("%sが抹殺によって消え去った。\n", "%s was a victim of genocide.\n"), note);
139                 break;
140         case RECORD_NAMED_PET_WIZ_ZAP:
141                 fprintf(fff, _("%sがデバッグコマンドによって消え去った。\n", "%s was removed by debug command.\n"), note);
142                 break;
143         case RECORD_NAMED_PET_TELE_LEVEL:
144                 fprintf(fff, _("%sがテレポート・レベルによって消え去った。\n", "%s was lost after teleporting a level.\n"), note);
145                 break;
146         case RECORD_NAMED_PET_BLAST:
147                 fprintf(fff, _("%sを爆破した。\n", "blasted %s.\n"), note);
148                 break;
149         case RECORD_NAMED_PET_HEAL_LEPER:
150                 fprintf(fff, _("%sの病気が治り旅から外れた。\n", "%s was healed and left.\n"), note);
151                 break;
152         case RECORD_NAMED_PET_COMPACT:
153                 fprintf(fff, _("%sがモンスター情報圧縮によって消え去った。\n", "%s was lost when the monster list was pruned.\n"), note);
154                 break;
155         case RECORD_NAMED_PET_LOSE_PARENT:
156                 fprintf(fff, _("%sの召喚者が既にいないため消え去った。\n", "%s disappeared because its summoner left.\n"), note);
157                 break;
158         default:
159                 fprintf(fff, "\n");
160                 break;
161         }
162 }
163
164
165 /*!
166  * @brief 日記にメッセージを追加する /
167  * Take note to the diary.
168  * @param type 日記内容のID
169  * @param num 日記内容のIDに応じた数値
170  * @param note 日記内容のIDに応じた文字列参照ポインタ
171  * @return エラーコード
172  */
173 errr exe_write_diary(player_type *creature_ptr, int type, int num, concptr note)
174 {
175         static bool disable_diary = FALSE;
176
177         int day, hour, min;
178         extract_day_hour_min(creature_ptr, &day, &hour, &min);
179
180         if (disable_diary) return -1;
181
182         if (type == DIARY_FIX_QUEST_C ||
183                 type == DIARY_FIX_QUEST_F ||
184                 type == DIARY_RAND_QUEST_C ||
185                 type == DIARY_RAND_QUEST_F ||
186                 type == DIARY_TO_QUEST)
187         {
188                 QUEST_IDX old_quest = creature_ptr->current_floor_ptr->inside_quest;
189                 creature_ptr->current_floor_ptr->inside_quest = (quest[num].type == QUEST_TYPE_RANDOM) ? 0 : num;
190                 init_flags = INIT_NAME_ONLY;
191                 parse_fixed_map(creature_ptr, "q_info.txt", 0, 0, 0, 0);
192                 creature_ptr->current_floor_ptr->inside_quest = old_quest;
193         }
194
195         FILE *fff = NULL;
196         if (!open_diary_file(&fff, &disable_diary)) return -1;
197
198         concptr note_level = "";
199     char note_level_buf[40];
200         QUEST_IDX q_idx = write_floor(creature_ptr, &note_level, note_level_buf);
201
202         bool do_level = TRUE;
203         switch (type)
204         {
205         case DIARY_DIALY:
206         {
207                 if (day < MAX_DAYS)
208                         fprintf(fff, _("%d日目\n", "Day %d\n"), day);
209                 else
210                         fputs(_("*****日目\n", "Day *****\n"), fff);
211
212                 do_level = FALSE;
213                 break;
214         }
215         case DIARY_DESCRIPTION:
216         {
217                 if (num)
218                 {
219                         fprintf(fff, "%s\n", note);
220                         do_level = FALSE;
221                 }
222                 else
223                         fprintf(fff, " %2d:%02d %20s %s\n", hour, min, note_level, note);
224
225                 break;
226         }
227         case DIARY_ART:
228         {
229                 fprintf(fff, _(" %2d:%02d %20s %sを発見した。\n", " %2d:%02d %20s discovered %s.\n"), hour, min, note_level, note);
230                 break;
231         }
232         case DIARY_ART_SCROLL:
233         {
234                 fprintf(fff, _(" %2d:%02d %20s 巻物によって%sを生成した。\n", " %2d:%02d %20s created %s by scroll.\n"), hour, min, note_level, note);
235                 break;
236         }
237         case DIARY_UNIQUE:
238         {
239                 fprintf(fff, _(" %2d:%02d %20s %sを倒した。\n", " %2d:%02d %20s defeated %s.\n"), hour, min, note_level, note);
240                 break;
241         }
242         case DIARY_FIX_QUEST_C:
243         {
244                 if (quest[num].flags & QUEST_FLAG_SILENT) break;
245
246                 fprintf(fff, _(" %2d:%02d %20s クエスト「%s」を達成した。\n",
247                         " %2d:%02d %20s completed quest '%s'.\n"), hour, min, note_level, quest[num].name);
248                 break;
249         }
250         case DIARY_FIX_QUEST_F:
251         {
252                 if (quest[num].flags & QUEST_FLAG_SILENT) break;
253
254                 fprintf(fff, _(" %2d:%02d %20s クエスト「%s」から命からがら逃げ帰った。\n",
255                         " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level, quest[num].name);
256                 break;
257         }
258         case DIARY_RAND_QUEST_C:
259         {
260                 GAME_TEXT name[MAX_NLEN];
261                 strcpy(name, r_name + r_info[quest[num].r_idx].name);
262                 fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)を達成した。\n",
263                         " %2d:%02d %20s completed random quest '%s'\n"), hour, min, note_level, name);
264                 break;
265         }
266         case DIARY_RAND_QUEST_F:
267         {
268                 GAME_TEXT name[MAX_NLEN];
269                 strcpy(name, r_name + r_info[quest[num].r_idx].name);
270                 fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)から逃げ出した。\n",
271                         " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level, name);
272                 break;
273         }
274         case DIARY_MAXDEAPTH:
275         {
276                 fprintf(fff, _(" %2d:%02d %20s %sの最深階%d階に到達した。\n",
277                         " %2d:%02d %20s reached level %d of %s for the first time.\n"), hour, min, note_level,
278                         _(d_name + d_info[creature_ptr->dungeon_idx].name, num),
279                         _(num, d_name + d_info[creature_ptr->dungeon_idx].name));
280                 break;
281         }
282         case DIARY_TRUMP:
283         {
284                 fprintf(fff, _(" %2d:%02d %20s %s%sの最深階を%d階にセットした。\n",
285                         " %2d:%02d %20s reset recall level of %s to %d %s.\n"), hour, min, note_level, note,
286                         _(d_name + d_info[num].name, (int)max_dlv[num]),
287                         _((int)max_dlv[num], d_name + d_info[num].name));
288                 break;
289         }
290         case DIARY_STAIR:
291         {
292                 concptr to = q_idx && (is_fixed_quest_idx(q_idx)
293                         && !((q_idx == QUEST_OBERON) || (q_idx == QUEST_SERPENT)))
294                         ? _("地上", "the surface")
295                         : !(creature_ptr->current_floor_ptr->dun_level + num)
296                         ? _("地上", "the surface")
297                         : format(_("%d階", "level %d"), creature_ptr->current_floor_ptr->dun_level + num);
298                 fprintf(fff, _(" %2d:%02d %20s %sへ%s。\n", " %2d:%02d %20s %s %s.\n"), hour, min, note_level, _(to, note), _(note, to));
299                 break;
300         }
301         case DIARY_RECALL:
302         {
303                 if (!num)
304                         fprintf(fff, _(" %2d:%02d %20s 帰還を使って%sの%d階へ下りた。\n", " %2d:%02d %20s recalled to dungeon level %d of %s.\n"),
305                                 hour, min, note_level, _(d_name + d_info[creature_ptr->dungeon_idx].name, (int)max_dlv[creature_ptr->dungeon_idx]),
306                                 _((int)max_dlv[creature_ptr->dungeon_idx], d_name + d_info[creature_ptr->dungeon_idx].name));
307                 else
308                         fprintf(fff, _(" %2d:%02d %20s 帰還を使って地上へと戻った。\n", " %2d:%02d %20s recalled from dungeon to surface.\n"), hour, min, note_level);
309
310                 break;
311         }
312         case DIARY_TO_QUEST:
313         {
314                 if (quest[num].flags & QUEST_FLAG_SILENT) break;
315
316                 fprintf(fff, _(" %2d:%02d %20s クエスト「%s」へと突入した。\n", " %2d:%02d %20s entered the quest '%s'.\n"),
317                         hour, min, note_level, quest[num].name);
318                 break;
319         }
320         case DIARY_TELEPORT_LEVEL:
321         {
322                 fprintf(fff, _(" %2d:%02d %20s レベル・テレポートで脱出した。\n", " %2d:%02d %20s got out using teleport level.\n"),
323                         hour, min, note_level);
324                 break;
325         }
326         case DIARY_BUY:
327         {
328                 fprintf(fff, _(" %2d:%02d %20s %sを購入した。\n", " %2d:%02d %20s bought %s.\n"), hour, min, note_level, note);
329                 break;
330         }
331         case DIARY_SELL:
332         {
333                 fprintf(fff, _(" %2d:%02d %20s %sを売却した。\n", " %2d:%02d %20s sold %s.\n"), hour, min, note_level, note);
334                 break;
335         }
336         case DIARY_ARENA:
337         {
338                 if (num < 0)
339                 {
340                         int n = -num;
341                         fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦で、%sの前に敗れ去った。\n", " %2d:%02d %20s beaten by %s in the %d%s fight.\n"),
342                                 hour, min, note_level, _(n, note), _("", n), _(note, get_ordinal_number_suffix(n)));
343                         break;
344                 }
345
346                 fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦(%s)に勝利した。\n", " %2d:%02d %20s won the %d%s fight (%s).\n"),
347                         hour, min, note_level, num, _("", get_ordinal_number_suffix(num)), note);
348
349                 if (num == MAX_ARENA_MONS)
350                 {
351                         fprintf(fff, _("                 闘技場のすべての敵に勝利し、チャンピオンとなった。\n",
352                                 "                 won all fights to become a Champion.\n"));
353                         do_level = FALSE;
354                 }
355
356                 break;
357         }
358         case DIARY_FOUND:
359         {
360                 fprintf(fff, _(" %2d:%02d %20s %sを識別した。\n", " %2d:%02d %20s identified %s.\n"), hour, min, note_level, note);
361                 break;
362         }
363         case DIARY_WIZ_TELE:
364         {
365                 concptr to = !creature_ptr->current_floor_ptr->dun_level
366                         ? _("地上", "the surface")
367                         : format(_("%d階(%s)", "level %d of %s"), creature_ptr->current_floor_ptr->dun_level, d_name + d_info[creature_ptr->dungeon_idx].name);
368                 fprintf(fff, _(" %2d:%02d %20s %sへとウィザード・テレポートで移動した。\n",
369                         " %2d:%02d %20s wizard-teleported to %s.\n"), hour, min, note_level, to);
370                 break;
371         }
372         case DIARY_PAT_TELE:
373         {
374                 concptr to = !creature_ptr->current_floor_ptr->dun_level
375                         ? _("地上", "the surface")
376                         : format(_("%d階(%s)", "level %d of %s"), creature_ptr->current_floor_ptr->dun_level, d_name + d_info[creature_ptr->dungeon_idx].name);
377                 fprintf(fff, _(" %2d:%02d %20s %sへとパターンの力で移動した。\n",
378                         " %2d:%02d %20s used Pattern to teleport to %s.\n"), hour, min, note_level, to);
379                 break;
380         }
381         case DIARY_LEVELUP:
382         {
383                 fprintf(fff, _(" %2d:%02d %20s レベルが%dに上がった。\n", " %2d:%02d %20s reached player level %d.\n"), hour, min, note_level, num);
384                 break;
385         }
386         case DIARY_GAMESTART:
387         {
388                 time_t ct = time((time_t*)0);
389                 do_level = FALSE;
390                 if (num)
391                         fprintf(fff, "%s %s", note, ctime(&ct));
392                 else
393                         fprintf(fff, " %2d:%02d %20s %s %s", hour, min, note_level, note, ctime(&ct));
394
395                 break;
396         }
397         case DIARY_NAMED_PET:
398         {
399                 fprintf(fff, " %2d:%02d %20s ", hour, min, note_level);
400                 write_diary_pet(fff, num, note);
401                 break;
402         }
403         case DIARY_WIZARD_LOG:
404                 fprintf(fff, "%s\n", note);
405                 break;
406         default:
407                 break;
408         }
409
410         angband_fclose(fff);
411         if (do_level) write_level = FALSE;
412
413         return 0;
414 }