OSDN Git Service

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