OSDN Git Service

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