OSDN Git Service

Merge pull request #3232 from sikabane-works/release/3.0.0Alpha79
[hengbandforosx/hengbandosx.git] / src / main / angband-initializer.cpp
1 /*!
2  * @file angband-initializer.cpp
3  * @brief 変愚蛮怒のシステム初期化
4  * @date 2014/01/28
5  * @author
6  * <pre>
7  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8  * This software may be copied and distributed for educational, research,
9  * and not for profit purposes provided that this copyright and statement
10  * are included in all such copies.  Other copyrights may also apply.
11  * 2014 Deskull rearranged comment for Doxygen.\n
12  * </pre>
13  */
14
15 #include "main/angband-initializer.h"
16 #include "dungeon/quest.h"
17 #include "floor/wild.h"
18 #include "info-reader/feature-reader.h"
19 #include "io/files-util.h"
20 #include "io/read-pref-file.h"
21 #include "io/uid-checker.h"
22 #include "main/game-data-initializer.h"
23 #include "main/info-initializer.h"
24 #include "market/building-initializer.h"
25 #include "monster-race/monster-race.h"
26 #include "monster-race/race-flags7.h"
27 #include "system/angband-version.h"
28 #include "system/dungeon-info.h"
29 #include "system/monster-race-info.h"
30 #include "system/system-variables.h"
31 #include "term/gameterm.h"
32 #include "term/screen-processor.h"
33 #include "term/term-color-types.h"
34 #include "time.h"
35 #include "util/angband-files.h"
36 #include "world/world.h"
37 #ifndef WINDOWS
38 #include "util/string-processor.h"
39 #include <dirent.h>
40 #endif
41 #ifdef PRIVATE_USER_PATH
42 #include <string>
43 #endif
44
45 /*!
46  * @brief 各データファイルを読み取るためのパスを取得する.
47  * @param libpath 各PCのインストール環境における"lib/" を表す絶対パス
48  */
49 void init_file_paths(const std::filesystem::path &libpath)
50 {
51     ANGBAND_DIR = std::filesystem::path(libpath);
52     ANGBAND_DIR_APEX = std::filesystem::path(libpath).append("apex");
53     ANGBAND_DIR_BONE = std::filesystem::path(libpath).append("bone");
54     ANGBAND_DIR_DATA = std::filesystem::path(libpath).append("data");
55     ANGBAND_DIR_EDIT = std::filesystem::path(libpath).append("edit");
56     ANGBAND_DIR_SCRIPT = std::filesystem::path(libpath).append("script");
57     ANGBAND_DIR_FILE = std::filesystem::path(libpath).append("file");
58     ANGBAND_DIR_HELP = std::filesystem::path(libpath).append("help");
59     ANGBAND_DIR_INFO = std::filesystem::path(libpath).append("info");
60     ANGBAND_DIR_PREF = std::filesystem::path(libpath).append("pref");
61     ANGBAND_DIR_SAVE = std::filesystem::path(libpath).append("save");
62     ANGBAND_DIR_DEBUG_SAVE = std::filesystem::path(ANGBAND_DIR_SAVE).append("log");
63 #ifdef PRIVATE_USER_PATH
64     ANGBAND_DIR_USER = std::filesystem::path(PRIVATE_USER_PATH).append(VARIANT_NAME);
65 #else
66     ANGBAND_DIR_USER = std::filesystem::path(libpath).append("user");
67 #endif
68     ANGBAND_DIR_XTRA = std::filesystem::path(libpath).append("xtra");
69
70     time_t now = time(nullptr);
71     struct tm *t = localtime(&now);
72     char tmp[128];
73     strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H-%M-%S", t);
74     path_build(debug_savefile, sizeof(debug_savefile), ANGBAND_DIR_DEBUG_SAVE, tmp);
75
76 #ifdef WINDOWS
77     struct _finddata_t c_file;
78     intptr_t hFile;
79     char log_file_expr[1024];
80     path_build(log_file_expr, sizeof(log_file_expr), ANGBAND_DIR_DEBUG_SAVE, "*-*");
81
82     if ((hFile = _findfirst(log_file_expr, &c_file)) != -1L) {
83         do {
84             if (((t->tm_yday + 365 - localtime(&c_file.time_write)->tm_yday) % 365) > 7) {
85                 char c_file_fullpath[1024];
86                 path_build(c_file_fullpath, sizeof(c_file_fullpath), ANGBAND_DIR_DEBUG_SAVE, c_file.name);
87                 remove(c_file_fullpath);
88             }
89         } while (_findnext(hFile, &c_file) == 0);
90         _findclose(hFile);
91     }
92 #else
93     const auto &debug_save_str = ANGBAND_DIR_DEBUG_SAVE.string();
94     DIR *saves_dir = opendir(debug_save_str.data());
95     if (saves_dir == nullptr) {
96         return;
97     }
98
99     struct dirent *next_entry;
100     while ((next_entry = readdir(saves_dir))) {
101         if (!angband_strchr(next_entry->d_name, '-')) {
102             continue;
103         }
104
105         char path[1024];
106         struct stat next_stat;
107         path_build(path, sizeof(path), ANGBAND_DIR_DEBUG_SAVE, next_entry->d_name);
108         constexpr auto one_week = 7 * 24 * 60 * 60;
109         if ((stat(path, &next_stat) == 0) && (difftime(now, next_stat.st_mtime) > one_week)) {
110             remove(path);
111         }
112     }
113
114     closedir(saves_dir);
115 #endif
116 }
117
118 /*!
119  * @brief 画面左下にシステムメッセージを表示する / Take notes on line 23
120  * @param str 初期化中のコンテンツ文字列
121  */
122 static void init_note_term(concptr str)
123 {
124     term_erase(0, 23, 255);
125     term_putstr(20, 23, -1, TERM_WHITE, str);
126     term_fresh();
127 }
128
129 /*!
130  * @brief ゲーム画面無しの時の初期化メッセージ出力
131  * @param str 初期化中のコンテンツ文字列
132  */
133 static void init_note_no_term(concptr str)
134 {
135     /* Don't show initialization message when there is no game terminal. */
136     (void)str;
137 }
138
139 /*!
140  * @brief 全ゲームデータ読み込みのサブルーチン / Explain a broken "lib" folder and quit (see below).
141  * @param なし
142  * @note
143  * <pre>
144  * This function is "messy" because various things
145  * may or may not be initialized, but the "plog()" and "quit()"
146  * functions are "supposed" to work under any conditions.
147  * </pre>
148  */
149 static void init_angband_aux(const std::string &why)
150 {
151     plog(why.data());
152     plog(_("'lib'ディレクトリが存在しないか壊れているようです。", "The 'lib' directory is probably missing or broken."));
153     plog(_("ひょっとするとアーカイブが正しく解凍されていないのかもしれません。", "The 'lib' directory is probably missing or broken."));
154     plog(_("該当する'README'ファイルを読んで確認してみて下さい。", "See the 'README' file for more information."));
155     quit(_("致命的なエラー。", "Fatal Error."));
156 }
157
158 /*!
159  * @brief タイトル記述
160  * @param なし
161  */
162 static void put_title()
163 {
164     const auto title = get_version();
165
166     auto col = (title.length() <= MAIN_TERM_MIN_COLS) ? (MAIN_TERM_MIN_COLS - title.length()) / 2 : 0;
167     constexpr auto VER_INFO_ROW = 3; //!< タイトル表記(行)
168     prt(title, VER_INFO_ROW, col);
169 }
170
171 /*!
172  * @brief 全ゲームデータ読み込みのメインルーチン /
173  * @param player_ptr プレイヤーへの参照ポインタ
174  * @param no_term TRUEならゲーム画面無しの状態で初期化を行う。
175  *                コマンドラインからスポイラーの出力のみを行う時の使用を想定する。
176  */
177 void init_angband(PlayerType *player_ptr, bool no_term)
178 {
179     char buf[1024];
180     path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
181     auto fd = fd_open(buf, O_RDONLY);
182     if (fd < 0) {
183         std::string why = _("'", "Cannot access the '");
184         why.append(buf);
185         why.append(_("'ファイルにアクセスできません!", "' file!"));
186         init_angband_aux(why);
187     }
188
189     (void)fd_close(fd);
190     if (!no_term) {
191         term_clear();
192         path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
193         auto *fp = angband_fopen(buf, FileOpenMode::READ);
194         if (fp) {
195             int i = 0;
196             while (0 == angband_fgets(fp, buf, sizeof(buf))) {
197                 term_putstr(0, i++, -1, TERM_WHITE, buf);
198             }
199
200             angband_fclose(fp);
201         }
202
203         term_flush();
204     }
205
206     path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
207     fd = fd_open(buf, O_RDONLY);
208     if (fd < 0) {
209         safe_setuid_grab(player_ptr);
210         fd = fd_make(buf, true);
211         safe_setuid_drop();
212         if (fd < 0) {
213             std::string why = _("'", "Cannot create the '");
214             why.append(buf);
215             why.append(_("'ファイルを作成できません!", "' file!"));
216             init_angband_aux(why);
217         }
218     }
219
220     (void)fd_close(fd);
221     if (!no_term) {
222         put_title();
223     }
224
225     void (*init_note)(concptr) = (no_term ? init_note_no_term : init_note_term);
226
227     init_note(_("[変数を初期化しています...(その他)", "[Initializing values... (misc)]"));
228     if (init_misc(player_ptr)) {
229         quit(_("その他の変数を初期化できません", "Cannot initialize misc. values"));
230     }
231
232     init_note(_("[データの初期化中... (地形)]", "[Initializing arrays... (features)]"));
233     if (init_terrains_info()) {
234         quit(_("地形初期化不能", "Cannot initialize features"));
235     }
236
237     if (init_feat_variables()) {
238         quit(_("地形初期化不能", "Cannot initialize features"));
239     }
240
241     init_note(_("[データの初期化中... (アイテム)]", "[Initializing arrays... (objects)]"));
242     if (init_baseitems_info()) {
243         quit(_("アイテム初期化不能", "Cannot initialize objects"));
244     }
245
246     init_note(_("[データの初期化中... (伝説のアイテム)]", "[Initializing arrays... (artifacts)]"));
247     if (init_artifacts_info()) {
248         quit(_("伝説のアイテム初期化不能", "Cannot initialize artifacts"));
249     }
250
251     init_note(_("[データの初期化中... (名のあるアイテム)]", "[Initializing arrays... (ego-items)]"));
252     if (init_egos_info()) {
253         quit(_("名のあるアイテム初期化不能", "Cannot initialize ego-items"));
254     }
255
256     init_note(_("[データの初期化中... (モンスター)]", "[Initializing arrays... (monsters)]"));
257     if (init_monster_race_definitions()) {
258         quit(_("モンスター初期化不能", "Cannot initialize monsters"));
259     }
260
261     init_note(_("[データの初期化中... (ダンジョン)]", "[Initializing arrays... (dungeon)]"));
262     if (init_dungeons_info()) {
263         quit(_("ダンジョン初期化不能", "Cannot initialize dungeon"));
264     }
265
266     for (const auto &d_ref : dungeons_info) {
267         if (d_ref.idx > 0 && MonsterRace(d_ref.final_guardian).is_valid()) {
268             monraces_info[d_ref.final_guardian].flags7 |= RF7_GUARDIAN;
269         }
270     }
271
272     init_note(_("[データの初期化中... (魔法)]", "[Initializing arrays... (magic)]"));
273     if (init_class_magics_info()) {
274         quit(_("魔法初期化不能", "Cannot initialize magic"));
275     }
276
277     init_note(_("[データの初期化中... (熟練度)]", "[Initializing arrays... (skill)]"));
278     if (init_class_skills_info()) {
279         quit(_("熟練度初期化不能", "Cannot initialize skill"));
280     }
281
282     init_note(_("[配列を初期化しています... (荒野)]", "[Initializing arrays... (wilderness)]"));
283     if (init_wilderness()) {
284         quit(_("荒野を初期化できません", "Cannot initialize wilderness"));
285     }
286
287     init_note(_("[配列を初期化しています... (街)]", "[Initializing arrays... (towns)]"));
288     init_towns();
289
290     init_note(_("[配列を初期化しています... (建物)]", "[Initializing arrays... (buildings)]"));
291     init_buildings();
292
293     init_note(_("[配列を初期化しています... (クエスト)]", "[Initializing arrays... (quests)]"));
294     QuestList::get_instance().initialize();
295     if (init_vaults_info()) {
296         quit(_("vault 初期化不能", "Cannot initialize vaults"));
297     }
298
299     init_note(_("[データの初期化中... (その他)]", "[Initializing arrays... (other)]"));
300     init_other(player_ptr);
301     init_note(_("[データの初期化中... (アロケーション)]", "[Initializing arrays... (alloc)]"));
302     init_alloc();
303     init_note(_("[ユーザー設定ファイルを初期化しています...]", "[Initializing user pref files...]"));
304     process_pref_file(player_ptr, "pref.prf");
305     process_pref_file(player_ptr, std::string("pref-").append(ANGBAND_SYS).append(".prf").data());
306     init_note(_("[初期化終了]", "[Initialization complete]"));
307 }