OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[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-savefile50.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-base/player-class.h"
38 #include "player-info/class-info.h"
39 #include "player-info/race-info.h"
40 #include "player/player-personality.h"
41 #include "player/player-sex.h"
42 #include "player/race-info-table.h"
43 #include "system/angband-exceptions.h"
44 #include "system/angband-version.h"
45 #include "system/player-type-definition.h"
46 #include "system/system-variables.h"
47 #include "util/angband-files.h"
48 #include "util/enum-converter.h"
49 #include "view/display-messages.h"
50 #include "world/world.h"
51 #include <sstream>
52 #include <string>
53 #include <vector>
54
55 /*!
56  * @brief 変愚蛮怒 v2.1.3で追加された街とクエストについて読み込む
57  * @param player_ptr プレイヤーへの参照ポインタ
58  * @return エラーコード
59  * @details 旧海底都市クエスト (クエストNo.18)は廃止済
60  */
61 static errr load_town_quest(PlayerType *player_ptr)
62 {
63     if (h_older_than(2, 1, 3)) {
64         return 0;
65     }
66
67     auto load_town_result = load_town();
68     if (load_town_result != 0) {
69         return load_town_result;
70     }
71
72     auto [max_quests_load, max_rquests_load] = load_quest_info();
73     analyze_quests(player_ptr, max_quests_load, max_rquests_load);
74     if (h_older_than(1, 7, 0, 6)) {
75         auto &quest_list = QuestList::get_instance();
76         quest_list[i2enum<QuestId>(OLD_QUEST_WATER_CAVE)] = {};
77         quest_list[i2enum<QuestId>(OLD_QUEST_WATER_CAVE)].status = QuestStatusType::UNTAKEN;
78     }
79
80     load_wilderness_info(player_ptr);
81     return analyze_wilderness();
82 }
83
84 /*!
85  * @brief 合計のプレイ時間をロードする
86  */
87 static void rd_total_play_time()
88 {
89     if (loading_savefile_version_is_older_than(4)) {
90         return;
91     }
92
93     w_ptr->sf_play_time = rd_u32b();
94 }
95
96 /*!
97  * @brief 勝利した職業フラグをロードする
98  */
99 static void rd_winner_class()
100 {
101     if (loading_savefile_version_is_older_than(4)) {
102         return;
103     }
104
105     rd_FlagGroup(w_ptr->sf_winner, rd_byte);
106     rd_FlagGroup(w_ptr->sf_retired, rd_byte);
107 }
108
109 static void load_player_world(PlayerType *player_ptr)
110 {
111     rd_total_play_time();
112     rd_winner_class();
113     rd_base_info(player_ptr);
114     rd_player_info(player_ptr);
115     preserve_mode = rd_bool();
116     player_ptr->wait_report_score = rd_bool();
117     rd_dummy2();
118     rd_global_configurations(player_ptr);
119     rd_extra(player_ptr);
120
121     if (player_ptr->energy_need < -999) {
122         player_ptr->timewalk = true;
123     }
124
125     load_note(_("特別情報をロードしました", "Loaded extra information"));
126 }
127
128 static errr load_hp(PlayerType *player_ptr)
129 {
130     auto tmp16u = rd_u16b();
131     if (tmp16u > PY_MAX_LEVEL) {
132         load_note(format(_("ヒットポイント配列が大きすぎる(%u)!", "Too many (%u) hitpoint entries!"), tmp16u));
133         return 25;
134     }
135
136     for (auto i = 0; i < tmp16u; i++) {
137         player_ptr->player_hp[i] = rd_s16b();
138     }
139
140     return 0;
141 }
142
143 static void load_spells(PlayerType *player_ptr)
144 {
145     player_ptr->spell_learned1 = rd_u32b();
146     player_ptr->spell_learned2 = rd_u32b();
147     player_ptr->spell_worked1 = rd_u32b();
148     player_ptr->spell_worked2 = rd_u32b();
149     player_ptr->spell_forgotten1 = rd_u32b();
150     player_ptr->spell_forgotten2 = rd_u32b();
151     if (h_older_than(0, 0, 5)) {
152         set_zangband_learnt_spells(player_ptr);
153     } else {
154         player_ptr->learned_spells = rd_s16b();
155     }
156
157     if (h_older_than(0, 0, 6)) {
158         player_ptr->add_spells = 0;
159     } else {
160         player_ptr->add_spells = rd_s16b();
161     }
162 }
163
164 static errr verify_checksum()
165 {
166     auto n_v_check = v_check;
167     if (rd_u32b() == n_v_check) {
168         return 0;
169     }
170
171     load_note(_("チェックサムがおかしい", "Invalid checksum"));
172     return 11;
173 }
174
175 static errr verify_encoded_checksum()
176 {
177     auto n_x_check = x_check;
178     if (rd_u32b() == n_x_check) {
179         return 0;
180     }
181
182     load_note(_("エンコードされたチェックサムがおかしい", "Invalid encoded checksum"));
183     return 11;
184 }
185
186 /*!
187  * @brief セーブファイル読み込み処理の実体 / Actually read the savefile
188  * @return エラーコード
189  */
190 static errr exe_reading_savefile(PlayerType *player_ptr)
191 {
192     rd_version_info();
193     rd_dummy3();
194     rd_system_info();
195     load_lore();
196     auto item_loader = ItemLoaderFactory::create_loader();
197     item_loader->load_item();
198     auto load_town_quest_result = load_town_quest(player_ptr);
199     if (load_town_quest_result != 0) {
200         return load_town_quest_result;
201     }
202
203     load_note(_("クエスト情報をロードしました", "Loaded Quests"));
204     item_loader->load_artifact();
205     load_player_world(player_ptr);
206     auto load_hp_result = load_hp(player_ptr);
207     if (load_hp_result != 0) {
208         return load_hp_result;
209     }
210
211     auto short_pclass = enum2i(player_ptr->pclass);
212     sp_ptr = &sex_info[player_ptr->psex];
213     rp_ptr = &race_info[enum2i(player_ptr->prace)];
214     cp_ptr = &class_info[short_pclass];
215     ap_ptr = &personality_info[player_ptr->ppersonality];
216
217     set_zangband_class(player_ptr);
218     mp_ptr = &class_magics_info[short_pclass];
219
220     load_spells(player_ptr);
221     if (PlayerClass(player_ptr).equals(PlayerClassType::MINDCRAFTER)) {
222         player_ptr->add_spells = 0;
223     }
224
225     auto load_inventory_result = load_inventory(player_ptr);
226     if (load_inventory_result != 0) {
227         return load_inventory_result;
228     }
229
230     load_store(player_ptr);
231     player_ptr->pet_follow_distance = rd_s16b();
232     if (h_older_than(0, 4, 10)) {
233         set_zangband_pet(player_ptr);
234     } else {
235         player_ptr->pet_extra_flags = rd_u16b();
236     }
237
238     if (!h_older_than(1, 0, 9)) {
239         std::vector<char> buf(SCREEN_BUF_MAX_SIZE);
240         rd_string(buf.data(), SCREEN_BUF_MAX_SIZE);
241         if (buf[0]) {
242             screen_dump = string_make(buf.data());
243         }
244     }
245
246     auto restore_dungeon_result = restore_dungeon(player_ptr);
247     if (restore_dungeon_result != 0) {
248         return restore_dungeon_result;
249     }
250
251     if (h_older_than(1, 7, 0, 6)) {
252         remove_water_cave(player_ptr);
253     }
254
255     auto checksum_result = verify_checksum();
256     if (checksum_result != 0) {
257         return checksum_result;
258     }
259
260     return verify_encoded_checksum();
261 }
262
263 /*!
264  * @brief セーブファイル読み込み処理 (UIDチェック等含む) / Reading the savefile (including UID check)
265  * @param player_ptr プレイヤーへの参照ポインタ
266  * @return エラーコード
267  */
268 static errr rd_savefile(PlayerType *player_ptr)
269 {
270     safe_setuid_grab();
271     loading_savefile = angband_fopen(savefile, FileOpenMode::READ, true);
272     safe_setuid_drop();
273     if (!loading_savefile) {
274         return -1;
275     }
276
277     try {
278         auto err = exe_reading_savefile(player_ptr);
279         if (ferror(loading_savefile)) {
280             err = -1;
281         }
282
283         angband_fclose(loading_savefile);
284         return err;
285     } catch (SaveDataNotSupportedException const &e) {
286         msg_print(e.what());
287         angband_fclose(loading_savefile);
288         return 1;
289     }
290 }
291
292 /*!
293  * @brief 死亡した、または互換性のないセーブデータを読み込んだ時にやりなおさせる
294  * @param plyaer_ptr プレイヤーへの参照ポインタ
295  * @param new_game 新しくゲームを始めさせるフラグ
296  * @return 常にtrue (前後の処理上都合が良いため)
297  */
298 static bool reset_save_data(PlayerType *player_ptr, bool *new_game)
299 {
300     *new_game = true;
301     player_ptr->is_dead = false;
302     w_ptr->sf_lives++;
303     return true;
304 }
305
306 static bool on_read_save_data_not_supported(PlayerType *player_ptr, bool *new_game)
307 {
308     auto mes_not_play = _("このセーブデータの続きをプレイすることはできません。", "You can't play the rest of the game from this save data.");
309     auto mes_check_restart = _("最初からプレイを始めますか?(モンスターの思い出は引き継がれます)", "Play from the beginning? (Monster recalls will be inherited.) ");
310     msg_print(mes_not_play);
311     msg_print(nullptr);
312     if (!input_check(mes_check_restart)) {
313         msg_print(_("ゲームを終了します。", "Exit the game."));
314         msg_print(nullptr);
315         return false;
316     }
317
318     player_ptr->wait_report_score = false;
319     return reset_save_data(player_ptr, new_game);
320 }
321
322 /**
323  * @brief セーブデータから引き継いでプレイできるかどうか調べる
324  *
325  * @param player_ptr プレイヤーへの参照ポインタ
326  * @return 引き継ぎ可能ならtrue、そうでなければfalseを返す
327  */
328 static bool can_takeover_savefile(PlayerType *player_ptr)
329 {
330     if (loading_savefile_version_is_older_than(8) && PlayerClass(player_ptr).equals(PlayerClassType::SMITH)) {
331         return false;
332     }
333
334     return true;
335 }
336
337 /*!
338  * @brief セーブデータ読み込みのメインルーチン /
339  * Attempt to Load a "savefile"
340  * @param player_ptr プレイヤーへの参照ポインタ
341  * @param new_game セーブデータの新規作成が必要か否か
342  * @return セーブデータが読み込めればtrue
343  */
344 bool load_savedata(PlayerType *player_ptr, bool *new_game)
345 {
346     auto what = "generic";
347     w_ptr->game_turn = 0;
348     player_ptr->is_dead = false;
349     if (savefile.empty()) {
350         return true;
351     }
352
353     const auto &savefile_str = savefile.string();
354 #ifndef WINDOWS
355     if (access(savefile_str.data(), 0) < 0) {
356         msg_print(_("セーブファイルがありません。", "Savefile does not exist."));
357         msg_print(nullptr);
358         *new_game = true;
359         return true;
360     }
361 #endif
362
363     auto err = false;
364     auto fd = -1;
365
366     // バリアント名長1バイト+バージョン番号4バイト+セーブファイルエンコードキー1バイト == 6バイト.
367     constexpr auto variant_length = static_cast<char>(VARIANT_NAME.length());
368     constexpr auto version_length = variant_length + 6;
369     char tmp_ver[version_length]{};
370     if (!err) {
371         fd = fd_open(savefile, O_RDONLY);
372         if (fd < 0) {
373             err = true;
374         }
375
376         if (err) {
377             what = _("セーブファイルを開けません", "Cannot open savefile");
378         }
379     }
380
381     if (!err) {
382         if (fd_read(fd, tmp_ver, version_length)) {
383             err = true;
384         }
385
386         if (err) {
387             what = _("セーブファイルを読めません", "Cannot read savefile");
388         }
389     }
390
391     if (!err) {
392         // v0.0.X~v3.0.0 Alpha51までは、セーブデータの第1バイトがFAKE_MAJOR_VERというZangbandと互換性を取ったバージョン番号フィールドだった.
393         // v3.0.0 Alpha52以降は、バリアント名の長さフィールドとして再定義した.
394         // 10~13はその名残。変愚蛮怒から更にバリアントを切ったらこの評価は不要.
395         auto tmp_major = tmp_ver[0];
396         auto is_old_ver = (10 <= tmp_major) && (tmp_major <= 13);
397         if (tmp_major == variant_length) {
398             if (std::string_view(&tmp_ver[1], variant_length) != VARIANT_NAME) {
399                 throw(_("セーブデータのバリアントは変愚蛮怒以外です", "The variant of save data is other than Hengband!"));
400             }
401
402             w_ptr->sf_extra = tmp_ver[version_length - 1];
403             (void)fd_close(fd);
404         } else if (is_old_ver) {
405             w_ptr->sf_extra = tmp_ver[3];
406             (void)fd_close(fd);
407         } else {
408             (void)fd_close(fd);
409             throw("Invalid version is detected!");
410         }
411     }
412
413     if (err) {
414         msg_format("%s: %s", what, savefile_str.data());
415         msg_print(nullptr);
416         return false;
417     }
418
419     if (!err) {
420         term_clear();
421         auto ret_rd_savefile = rd_savefile(player_ptr);
422         if (ret_rd_savefile != 0) {
423             err = true;
424         }
425
426         if (ret_rd_savefile < 0) {
427             what = _("セーブファイルを解析出来ません。", "Cannot parse savefile");
428         } else if (ret_rd_savefile > 0) {
429             return on_read_save_data_not_supported(player_ptr, new_game);
430         }
431     }
432
433     if (!err) {
434         if (!w_ptr->game_turn) {
435             err = true;
436         }
437
438         if (err) {
439             what = _("セーブファイルが壊れています", "Broken savefile");
440         }
441     }
442
443     if (err) {
444         msg_format(_("エラー(%s)がバージョン %d.%d.%d.%d 用セーブファイル読み込み中に発生。", "Error (%s) reading %d.%d.%d.%d savefile."), what,
445             w_ptr->h_ver_major, w_ptr->h_ver_minor, w_ptr->h_ver_patch, w_ptr->h_ver_extra);
446         msg_print(nullptr);
447         return false;
448     }
449
450     if (!can_takeover_savefile(player_ptr)) {
451         return on_read_save_data_not_supported(player_ptr, new_game);
452     }
453
454     if (player_ptr->is_dead) {
455         return reset_save_data(player_ptr, new_game);
456     }
457
458     w_ptr->character_loaded = true;
459     auto tmp = counts_read(player_ptr, 2);
460     if (tmp > player_ptr->count) {
461         player_ptr->count = tmp;
462     }
463
464     if (counts_read(player_ptr, 0) > w_ptr->play_time || counts_read(player_ptr, 1) == w_ptr->play_time) {
465         counts_write(player_ptr, 2, ++player_ptr->count);
466     }
467
468     counts_write(player_ptr, 1, w_ptr->play_time);
469     return true;
470 }