OSDN Git Service

[Refactor] #1743 Reshaped load.cpp
[hengbandforosx/hengbandosx.git] / src / load / load.cpp
1 /*!
2  * @brief セーブファイル読み込み処理 / Purpose: support for loading savefiles -BEN-
3  * @date 2014/07/07
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.  Other copyrights may also apply.
10  */
11
12 #include "load/load.h"
13 #include "core/asking-player.h"
14 #include "dungeon/quest.h"
15 #include "game-option/birth-options.h"
16 #include "io/files-util.h"
17 #include "io/report.h"
18 #include "io/uid-checker.h"
19 #include "load/angband-version-comparer.h"
20 #include "load/dummy-loader.h"
21 #include "load/dungeon-loader.h"
22 #include "load/extra-loader.h"
23 #include "load/info-loader.h"
24 #include "load/inventory-loader.h"
25 #include "load/item/item-loader-factory.h"
26 #include "load/load-util.h"
27 #include "load/load-zangband.h"
28 #include "load/lore-loader.h"
29 #include "load/old/item-loader-savefile10.h"
30 #include "load/old/load-v1-5-0.h"
31 #include "load/old/load-v1-7-0.h"
32 #include "load/option-loader.h"
33 #include "load/player-info-loader.h"
34 #include "load/quest-loader.h"
35 #include "load/store-loader.h"
36 #include "load/world-loader.h"
37 #include "player-info/class-info.h"
38 #include "player-info/race-info.h"
39 #include "player/player-personality.h"
40 #include "player/player-sex.h"
41 #include "player/race-info-table.h"
42 #include "system/angband-version.h"
43 #include "system/player-type-definition.h"
44 #include "system/system-variables.h"
45 #include "util/angband-files.h"
46 #include "util/enum-converter.h"
47 #include "view/display-messages.h"
48 #include "world/world.h"
49 #include <sstream>
50 #include <string>
51
52 /*!
53  * @brief 変愚蛮怒 v2.1.3で追加された街とクエストについて読み込む
54  * @param player_ptr プレイヤーへの参照ポインタ
55  * @return エラーコード
56  */
57 static errr load_town_quest(PlayerType *player_ptr)
58 {
59     if (h_older_than(2, 1, 3)) {
60         return 0;
61     }
62
63     auto load_town_result = load_town();
64     if (load_town_result != 0) {
65         return load_town_result;
66     }
67     
68     uint16_t max_quests_load;
69     byte max_rquests_load;
70     auto load_quest_result = load_quest_info(&max_quests_load, &max_rquests_load);
71     if (load_quest_result != 0) {
72         return load_quest_result;
73     }
74
75     analyze_quests(player_ptr, max_quests_load, max_rquests_load);
76
77     /* Quest 18 was removed */
78     if (h_older_than(1, 7, 0, 6)) {
79         quest[OLD_QUEST_WATER_CAVE] = {};
80         quest[OLD_QUEST_WATER_CAVE].status = QuestStatusType::UNTAKEN;
81     }
82
83     load_wilderness_info(player_ptr);
84     return analyze_wilderness();
85 }
86
87 /*!
88  * @brief 合計のプレイ時間をロードする
89  */
90 static void rd_total_play_time()
91 {
92     if (loading_savefile_version_is_older_than(4)) {
93         return;
94     }
95     
96     w_ptr->sf_play_time = rd_u32b();
97 }
98
99 /*!
100  * @brief 勝利した職業フラグをロードする
101  */
102 static void rd_winner_class()
103 {
104     if (loading_savefile_version_is_older_than(4)) {
105         return;
106     }
107
108     rd_FlagGroup(w_ptr->sf_winner, rd_byte);
109     rd_FlagGroup(w_ptr->sf_retired, rd_byte);
110 }
111
112 static void load_player_world(PlayerType *player_ptr)
113 {
114     rd_total_play_time();
115     rd_winner_class();
116     rd_base_info(player_ptr);
117     rd_player_info(player_ptr);
118     preserve_mode = rd_byte() != 0;
119     player_ptr->wait_report_score = rd_byte() != 0;
120     rd_dummy2();
121     rd_global_configurations(player_ptr);
122     rd_extra(player_ptr);
123
124     if (player_ptr->energy_need < -999) {
125         player_ptr->timewalk = true;
126     }
127
128     load_note(_("特別情報をロードしました", "Loaded extra information"));
129 }
130
131 static errr load_hp(PlayerType *player_ptr)
132 {
133     auto tmp16u = rd_u16b();
134     if (tmp16u > PY_MAX_LEVEL) {
135         load_note(format(_("ヒットポイント配列が大きすぎる(%u)!", "Too many (%u) hitpoint entries!"), tmp16u));
136         return 25;
137     }
138
139     for (auto i = 0; i < tmp16u; i++) {
140         player_ptr->player_hp[i] = rd_s16b();
141     }
142
143     return 0;
144 }
145
146 static void load_spells(PlayerType *player_ptr)
147 {
148     player_ptr->spell_learned1 = rd_u32b();
149     player_ptr->spell_learned2 = rd_u32b();
150     player_ptr->spell_worked1 = rd_u32b();
151     player_ptr->spell_worked2 = rd_u32b();
152     player_ptr->spell_forgotten1 = rd_u32b();
153     player_ptr->spell_forgotten2 = rd_u32b();
154     if (h_older_than(0, 0, 5)) {
155         set_zangband_learnt_spells(player_ptr);
156     } else {
157         player_ptr->learned_spells = rd_s16b();
158     }
159
160     if (h_older_than(0, 0, 6)) {
161         player_ptr->add_spells = 0;
162     } else {
163         player_ptr->add_spells = rd_s16b();
164     }
165 }
166
167 static errr verify_checksum()
168 {
169     auto n_v_check = v_check;
170     if (rd_u32b() == n_v_check) {
171         return 0;
172     }
173
174     load_note(_("チェックサムがおかしい", "Invalid checksum"));
175     return 11;
176 }
177
178 static errr verify_encoded_checksum()
179 {
180     auto n_x_check = x_check;
181     if (rd_u32b() == n_x_check) {
182         return 0;
183     }
184
185     load_note(_("エンコードされたチェックサムがおかしい", "Invalid encoded checksum"));
186     return 11;
187 }
188
189 /*!
190  * @brief セーブファイル読み込み処理の実体 / Actually read the savefile
191  * @return エラーコード
192  */
193 static errr exe_reading_savefile(PlayerType *player_ptr)
194 {
195     rd_version_info();
196     rd_dummy3();
197     rd_system_info();
198     load_lore();
199     auto item_loader = ItemLoaderFactory::create_loader();
200     item_loader->load_item();
201     auto load_town_quest_result = load_town_quest(player_ptr);
202     if (load_town_quest_result != 0) {
203         return load_town_quest_result;
204     }
205
206     load_note(_("クエスト情報をロードしました", "Loaded Quests"));
207     item_loader->load_artifact();
208     load_player_world(player_ptr);
209     auto load_hp_result = load_hp(player_ptr);
210     if (load_hp_result != 0) {
211         return load_hp_result;
212     }
213
214     auto short_pclass = enum2i(player_ptr->pclass);
215     sp_ptr = &sex_info[player_ptr->psex];
216     rp_ptr = &race_info[enum2i(player_ptr->prace)];
217     cp_ptr = &class_info[short_pclass];
218     ap_ptr = &personality_info[player_ptr->ppersonality];
219
220     set_zangband_class(player_ptr);
221     mp_ptr = &m_info[short_pclass];
222
223     load_spells(player_ptr);
224     if (player_ptr->pclass == PlayerClassType::MINDCRAFTER) {
225         player_ptr->add_spells = 0;
226     }
227
228     auto load_inventory_result = load_inventory(player_ptr);
229     if (load_inventory_result != 0) {
230         return load_inventory_result;
231     }
232
233     load_store(player_ptr);
234     player_ptr->pet_follow_distance = rd_s16b();
235     if (h_older_than(0, 4, 10)) {
236         set_zangband_pet(player_ptr);
237     } else {
238         player_ptr->pet_extra_flags = rd_u16b();
239     }
240
241     if (!h_older_than(1, 0, 9)) {
242         std::vector<char> buf(SCREEN_BUF_MAX_SIZE);
243         rd_string(buf.data(), SCREEN_BUF_MAX_SIZE);
244         if (buf[0]) {
245             screen_dump = string_make(buf.data());
246         }
247     }
248
249     auto restore_dungeon_result = restore_dungeon(player_ptr);
250     if (restore_dungeon_result != 0) {
251         return restore_dungeon_result;
252     }
253
254     if (h_older_than(1, 7, 0, 6)) {
255         remove_water_cave(player_ptr);
256     }
257
258     auto checksum_result = verify_checksum();
259     if (checksum_result != 0) {
260         return checksum_result;
261     }
262
263     return verify_encoded_checksum();
264 }
265
266 /*!
267  * @brief セーブファイル読み込み処理 (UIDチェック等含む) / Reading the savefile (including UID check)
268  * @param player_ptr プレイヤーへの参照ポインタ
269  * @return エラーコード
270  */
271 static errr rd_savefile(PlayerType *player_ptr)
272 {
273     safe_setuid_grab(player_ptr);
274     loading_savefile = angband_fopen(savefile, "rb");
275     safe_setuid_drop();
276     if (!loading_savefile) {
277         return -1;
278     }
279
280     errr err = exe_reading_savefile(player_ptr);
281     if (ferror(loading_savefile)) {
282         err = -1;
283     }
284
285     angband_fclose(loading_savefile);
286     return err;
287 }
288
289 /**
290  * @brief セーブデータから引き継いでプレイできるかどうか調べる
291  *
292  * @param player_ptr プレイヤーへの参照ポインタ
293  * @return 引き継ぎ可能ならtrue、そうでなければfalseを返す
294  */
295 static bool can_takeover_savefile(const PlayerType *player_ptr)
296 {
297     if (loading_savefile_version_is_older_than(8) && player_ptr->pclass == PlayerClassType::SMITH) {
298         return false;
299     }
300
301     return true;
302 }
303
304 /*!
305  * @brief セーブデータ読み込みのメインルーチン /
306  * Attempt to Load a "savefile"
307  * @param player_ptr プレイヤーへの参照ポインタ
308  * @param new_game セーブデータの新規作成が必要か否か
309  * @return セーブデータが読み込めればtrue
310  */
311 bool load_savedata(PlayerType *player_ptr, bool *new_game)
312 {
313     auto what = "generic";
314     w_ptr->game_turn = 0;
315     player_ptr->is_dead = false;
316     if (!savefile[0]) {
317         return true;
318     }
319
320 #ifndef WINDOWS
321     if (access(savefile, 0) < 0) {
322         msg_print(_("セーブファイルがありません。", "Savefile does not exist."));
323         msg_print(nullptr);
324         *new_game = true;
325         return true;
326     }
327 #endif
328
329     auto err = false;
330     auto fd = -1;
331     char tmp_ver[14]{};
332     if (!err) {
333         fd = fd_open(savefile, O_RDONLY);
334         if (fd < 0) {
335             err = true;
336         }
337
338         if (err) {
339             what = _("セーブファイルを開けません", "Cannot open savefile");
340         }
341     }
342
343     if (!err) {
344         if (fd_read(fd, (char *)(tmp_ver), 14)) {
345             err = true;
346         }
347
348         if (err) {
349             what = _("セーブファイルを読めません", "Cannot read savefile");
350         }
351     }
352
353     if (!err) {
354         auto tmp_major = tmp_ver[0];
355         auto is_old_ver = (10 <= tmp_major) && (tmp_major <= 13);
356         if (tmp_major == 8) {
357             std::string variant_name(VERSION_NAME);
358             std::stringstream current_variant;
359             for (auto i = 1; i < 9; i++) {
360                 current_variant << tmp_ver[i];
361             }
362
363             if (current_variant.str() != variant_name) {
364                 throw(_("セーブデータのバリアントは変愚蛮怒以外です", "The variant of save data is other than Hengband!"));
365             }
366
367             w_ptr->sf_extra = tmp_ver[13];
368             (void)fd_close(fd);
369         } else if (is_old_ver) {
370             w_ptr->sf_extra = tmp_ver[3];
371             (void)fd_close(fd);
372         } else {
373             (void)fd_close(fd);
374             throw("Invalid version is detected!");
375         }
376     }
377
378     if (err) {
379         msg_format("%s: %s", what, savefile);
380         msg_print(nullptr);
381         return false;
382     }
383
384     if (!err) {
385         term_clear();
386         if (rd_savefile(player_ptr)) {
387             err = true;
388         }
389
390         if (err) {
391             what = _("セーブファイルを解析出来ません。", "Cannot parse savefile");
392         }
393     }
394
395     if (!err) {
396         if (!w_ptr->game_turn) {
397             err = true;
398         }
399
400         if (err) {
401             what = _("セーブファイルが壊れています", "Broken savefile");
402         }
403     }
404
405     if (err) {
406         msg_format(_("エラー(%s)がバージョン%d.%d.%d.%d 用セーブファイル読み込み中に発生。", "Error (%s) reading %d.%d.%d.% savefile."), what,
407             w_ptr->h_ver_major, w_ptr->h_ver_minor, w_ptr->h_ver_patch, w_ptr->h_ver_extra);
408         msg_print(nullptr);
409         return false;
410     }
411
412     if (!can_takeover_savefile(player_ptr)) {
413         msg_format(_("このセーブデータの続きをプレイすることはできません。", "You can't play the rest of the game from this save data."));
414         msg_print(nullptr);
415         if (!get_check(_("最初からプレイを始めますか?(モンスターの思い出は引き継がれます)",
416                 "Play from the beginning? (Monster recalls will be inherited.) "))) {
417             msg_format(_("ゲームを終了します。", "Exit the game."));
418             msg_print(nullptr);
419             return false;
420         }
421
422         player_ptr->is_dead = true;
423         player_ptr->wait_report_score = false;
424     }
425
426     if (player_ptr->is_dead) {
427         *new_game = true;
428         player_ptr->is_dead = false;
429         w_ptr->sf_lives++;
430         return true;
431     }
432
433     w_ptr->character_loaded = true;
434     auto tmp = counts_read(player_ptr, 2);
435     if (tmp > player_ptr->count)
436         player_ptr->count = tmp;
437
438     if (counts_read(player_ptr, 0) > w_ptr->play_time || counts_read(player_ptr, 1) == w_ptr->play_time) {
439         counts_write(player_ptr, 2, ++player_ptr->count);
440     }
441
442     counts_write(player_ptr, 1, w_ptr->play_time);
443     return true;
444 }