OSDN Git Service

[Refactor] #40532 Separated monster-writer.c/h from save.c
[hengband/hengband.git] / src / save / save.c
1 /*!
2  * @file save.c
3  * @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
4  * @date 2014/07/12
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  * </pre>
12  */
13
14 #include "save/save.h"
15 #include "birth/quick-start.h"
16 #include "cmd-building/cmd-building.h"
17 #include "core/player-update-types.h"
18 #include "dungeon/dungeon.h"
19 #include "dungeon/quest.h"
20 #include "floor/floor-events.h"
21 #include "floor/floor-town.h"
22 #include "floor/floor.h"
23 #include "floor/wild.h"
24 #include "game-option/birth-options.h"
25 #include "game-option/cheat-options.h"
26 #include "game-option/option-flags.h"
27 #include "game-option/option-types-table.h"
28 #include "game-option/runtime-arguments.h"
29 #include "game-option/special-options.h"
30 #include "game-option/text-display-options.h"
31 #include "grid/grid.h"
32 #include "inventory/inventory-slot-types.h"
33 #include "io/report.h"
34 #include "io/uid-checker.h"
35 #include "load/floor-loader.h"
36 #include "load/load.h"
37 #include "load/savedata-flag-types.h"
38 #include "monster-race/monster-race.h"
39 #include "monster/monster-compaction.h"
40 #include "monster/monster-info.h"
41 #include "monster/monster-status.h"
42 #include "object/object-kind.h"
43 #include "save/item-writer.h"
44 #include "save/monster-writer.h"
45 #include "save/save-util.h"
46 #include "store/store-util.h"
47 #include "store/store.h"
48 #include "system/angband-version.h"
49 #include "system/artifact-type-definition.h"
50 #include "system/floor-type-definition.h"
51 #include "util/angband-files.h"
52 #include "util/quarks.h"
53 #include "util/sort.h"
54 #include "view/display-messages.h"
55 #include "world/world.h"
56
57 /*!
58  * @brief その他のゲーム情報を書き込む(実質はアイテムの鑑定情報のみ) / Write an "xtra" record
59  * @param k_idx ベースアイテムのID
60  * @return なし
61  */
62 static void wr_xtra(KIND_OBJECT_IDX k_idx)
63 {
64     byte tmp8u = 0;
65
66     object_kind *k_ptr = &k_info[k_idx];
67
68     if (k_ptr->aware)
69         tmp8u |= 0x01;
70     if (k_ptr->tried)
71         tmp8u |= 0x02;
72
73     wr_byte(tmp8u);
74 }
75
76 /*!
77  * @brief セーブデータに店舗情報を書き込む / Write a "store" record
78  * @param store_ptr 店舗情報の参照ポインタ
79  * @return なし
80  */
81 static void wr_store(store_type *store_ptr)
82 {
83     /* Save the "open" counter */
84     wr_u32b(store_ptr->store_open);
85
86     /* Save the "insults" */
87     wr_s16b(store_ptr->insult_cur);
88
89     /* Save the current owner */
90     wr_byte(store_ptr->owner);
91
92     /* Save the stock size */
93     wr_s16b(store_ptr->stock_num);
94
95     /* Save the "haggle" info */
96     wr_s16b(store_ptr->good_buy);
97     wr_s16b(store_ptr->bad_buy);
98
99     wr_s32b(store_ptr->last_visit);
100
101     /* Save the stock */
102     for (int j = 0; j < store_ptr->stock_num; j++) {
103         /* Save each item in stock */
104         wr_item(&store_ptr->stock[j]);
105     }
106 }
107
108 /*!
109  * @brief セーブデータに乱数情報を書き込む / Write RNG state
110  * @return 常に0(成功を返す)
111  */
112 static errr wr_randomizer(void)
113 {
114     wr_u16b(0);
115     wr_u16b(Rand_place);
116
117     for (int i = 0; i < RAND_DEG; i++) {
118         wr_u32b(Rand_state[i]);
119     }
120
121     return 0;
122 }
123
124 /*!
125  * @brief ゲームオプション情報を書き込む / Write the "options"
126  * @return なし
127  */
128 static void wr_options(void)
129 {
130     for (int i = 0; i < 4; i++)
131         wr_u32b(0L);
132
133     /*** Special options ***/
134     /* Write "delay_factor" */
135     wr_byte(delay_factor);
136
137     /* Write "hitpoint_warn" */
138     wr_byte(hitpoint_warn);
139
140     /* Write "mana_warn" */
141     wr_byte(mana_warn);
142
143     /*** Cheating options ***/
144
145     u16b c = 0;
146     if (current_world_ptr->wizard)
147         c |= 0x0002;
148
149     if (cheat_sight)
150         c |= 0x0040;
151     if (cheat_turn)
152         c |= 0x0080;
153
154     if (cheat_peek)
155         c |= 0x0100;
156     if (cheat_hear)
157         c |= 0x0200;
158     if (cheat_room)
159         c |= 0x0400;
160     if (cheat_xtra)
161         c |= 0x0800;
162     if (cheat_know)
163         c |= 0x1000;
164     if (cheat_live)
165         c |= 0x2000;
166     if (cheat_save)
167         c |= 0x4000;
168     if (cheat_diary_output)
169         c |= 0x8000;
170
171     wr_u16b(c);
172
173     /* Autosave info */
174     wr_byte(autosave_l);
175     wr_byte(autosave_t);
176     wr_s16b(autosave_freq);
177
178     /*** Extract options ***/
179     /* Analyze the options */
180     for (int i = 0; option_info[i].o_desc; i++) {
181         int os = option_info[i].o_set;
182         int ob = option_info[i].o_bit;
183
184         /* Process real entries */
185         if (!option_info[i].o_var)
186             continue;
187
188         if (*option_info[i].o_var) {
189             option_flag[os] |= (1L << ob);
190         } else {
191             option_flag[os] &= ~(1L << ob);
192         }
193     }
194
195     /*** Normal options ***/
196     /* Dump the flags */
197     for (int i = 0; i < 8; i++)
198         wr_u32b(option_flag[i]);
199
200     /* Dump the masks */
201     for (int i = 0; i < 8; i++)
202         wr_u32b(option_mask[i]);
203
204     /*** Window options ***/
205     /* Dump the flags */
206     for (int i = 0; i < 8; i++)
207         wr_u32b(window_flag[i]);
208
209     /* Dump the masks */
210     for (int i = 0; i < 8; i++)
211         wr_u32b(window_mask[i]);
212 }
213
214 /*!
215  * @brief ダミー情報スキップを書き込む / Hack -- Write the "ghost" info
216  * @return なし
217  */
218 static void wr_ghost(void)
219 {
220     wr_string(_("不正なゴースト", "Broken Ghost"));
221
222     /* Hack -- stupid data */
223     for (int i = 0; i < 60; i++)
224         wr_byte(0);
225 }
226
227 /*!
228  * @brief クイック・スタート情報を書き込む / Save quick start data
229  * @return なし
230  */
231 static void save_quick_start(void)
232 {
233     wr_byte(previous_char.psex);
234     wr_byte((byte)previous_char.prace);
235     wr_byte((byte)previous_char.pclass);
236     wr_byte((byte)previous_char.pseikaku);
237     wr_byte((byte)previous_char.realm1);
238     wr_byte((byte)previous_char.realm2);
239
240     wr_s16b(previous_char.age);
241     wr_s16b(previous_char.ht);
242     wr_s16b(previous_char.wt);
243     wr_s16b(previous_char.sc);
244     wr_s32b(previous_char.au);
245
246     for (int i = 0; i < A_MAX; i++)
247         wr_s16b(previous_char.stat_max[i]);
248     for (int i = 0; i < A_MAX; i++)
249         wr_s16b(previous_char.stat_max_max[i]);
250
251     for (int i = 0; i < PY_MAX_LEVEL; i++)
252         wr_s16b((s16b)previous_char.player_hp[i]);
253
254     wr_s16b(previous_char.chaos_patron);
255
256     for (int i = 0; i < 8; i++)
257         wr_s16b(previous_char.vir_types[i]);
258
259     for (int i = 0; i < 4; i++)
260         wr_string(previous_char.history[i]);
261
262     /* UNUSED : Was number of random quests */
263     wr_byte(0);
264
265     /* No quick start after using debug mode or cheat options */
266     if (current_world_ptr->noscore)
267         previous_char.quick_ok = FALSE;
268
269     wr_byte((byte)previous_char.quick_ok);
270 }
271
272 /*!
273  * @brief その他の情報を書き込む / Write some "extra" info
274  * @return なし
275  */
276 static void wr_extra(player_type *creature_ptr)
277 {
278     wr_string(creature_ptr->name);
279     wr_string(creature_ptr->died_from);
280     wr_string(creature_ptr->last_message ? creature_ptr->last_message : "");
281
282     save_quick_start();
283
284     for (int i = 0; i < 4; i++) {
285         wr_string(creature_ptr->history[i]);
286     }
287
288     /* Race/Class/Gender/Spells */
289     wr_byte((byte)creature_ptr->prace);
290     wr_byte((byte)creature_ptr->pclass);
291     wr_byte((byte)creature_ptr->pseikaku);
292     wr_byte((byte)creature_ptr->psex);
293     wr_byte((byte)creature_ptr->realm1);
294     wr_byte((byte)creature_ptr->realm2);
295     wr_byte(0);
296
297     wr_byte((byte)creature_ptr->hitdie);
298     wr_u16b(creature_ptr->expfact);
299
300     wr_s16b(creature_ptr->age);
301     wr_s16b(creature_ptr->ht);
302     wr_s16b(creature_ptr->wt);
303
304     /* Dump the stats (maximum and current) */
305     for (int i = 0; i < A_MAX; ++i)
306         wr_s16b(creature_ptr->stat_max[i]);
307     for (int i = 0; i < A_MAX; ++i)
308         wr_s16b(creature_ptr->stat_max_max[i]);
309     for (int i = 0; i < A_MAX; ++i)
310         wr_s16b(creature_ptr->stat_cur[i]);
311
312     /* Ignore the transient stats */
313     for (int i = 0; i < 12; ++i)
314         wr_s16b(0);
315
316     wr_u32b(creature_ptr->au);
317
318     wr_u32b(creature_ptr->max_exp);
319     wr_u32b(creature_ptr->max_max_exp);
320     wr_u32b(creature_ptr->exp);
321     wr_u32b(creature_ptr->exp_frac);
322     wr_s16b(creature_ptr->lev);
323
324     for (int i = 0; i < 64; i++)
325         wr_s16b(creature_ptr->spell_exp[i]);
326     for (int i = 0; i < 5; i++)
327         for (int j = 0; j < 64; j++)
328             wr_s16b(creature_ptr->weapon_exp[i][j]);
329
330     for (int i = 0; i < GINOU_MAX; i++)
331         wr_s16b(creature_ptr->skill_exp[i]);
332     for (int i = 0; i < MAX_SPELLS; i++)
333         wr_s32b(creature_ptr->magic_num1[i]);
334     for (int i = 0; i < MAX_SPELLS; i++)
335         wr_byte(creature_ptr->magic_num2[i]);
336
337     wr_byte((byte)creature_ptr->start_race);
338     wr_s32b(creature_ptr->old_race1);
339     wr_s32b(creature_ptr->old_race2);
340     wr_s16b(creature_ptr->old_realm);
341
342     for (int i = 0; i < MAX_MANE; i++) {
343         wr_s16b((s16b)creature_ptr->mane_spell[i]);
344         wr_s16b((s16b)creature_ptr->mane_dam[i]);
345     }
346
347     wr_s16b(creature_ptr->mane_num);
348
349     for (int i = 0; i < MAX_BOUNTY; i++) {
350         wr_s16b(current_world_ptr->bounty_r_idx[i]);
351     }
352
353     for (int i = 0; i < 4; i++) {
354         wr_s16b(battle_mon[i]);
355         wr_u32b(mon_odds[i]);
356     }
357
358     wr_s16b(creature_ptr->town_num); /* -KMW- */
359
360     /* Write arena and rewards information -KMW- */
361     wr_s16b(creature_ptr->arena_number);
362     wr_s16b(creature_ptr->current_floor_ptr->inside_arena);
363     wr_s16b(creature_ptr->current_floor_ptr->inside_quest);
364     wr_s16b(creature_ptr->phase_out);
365     wr_byte(creature_ptr->exit_bldg);
366     wr_byte(0); /* Unused */
367
368     wr_s16b((s16b)creature_ptr->oldpx);
369     wr_s16b((s16b)creature_ptr->oldpy);
370
371     /* Was number of creature_ptr->rewards[] */
372     wr_s16b(0);
373
374     wr_s32b(creature_ptr->mhp);
375     wr_s32b(creature_ptr->chp);
376     wr_u32b(creature_ptr->chp_frac);
377
378     wr_s32b(creature_ptr->msp);
379     wr_s32b(creature_ptr->csp);
380     wr_u32b(creature_ptr->csp_frac);
381
382     /* Max Player and Dungeon Levels */
383     wr_s16b(creature_ptr->max_plv);
384     byte tmp8u = (byte)current_world_ptr->max_d_idx;
385     wr_byte(tmp8u);
386     for (int i = 0; i < tmp8u; i++)
387         wr_s16b((s16b)max_dlv[i]);
388
389     /* More info */
390     wr_s16b(0);
391     wr_s16b(0);
392     wr_s16b(0);
393     wr_s16b(0);
394     wr_s16b(creature_ptr->sc);
395     wr_s16b(creature_ptr->concent);
396
397     wr_s16b(0); /* old "rest" */
398     wr_s16b(creature_ptr->blind);
399     wr_s16b(creature_ptr->paralyzed);
400     wr_s16b(creature_ptr->confused);
401     wr_s16b(creature_ptr->food);
402     wr_s16b(0); /* old "food_digested" */
403     wr_s16b(0); /* old "protection" */
404     wr_s16b(creature_ptr->energy_need);
405     wr_s16b(creature_ptr->enchant_energy_need);
406     wr_s16b(creature_ptr->fast);
407     wr_s16b(creature_ptr->slow);
408     wr_s16b(creature_ptr->afraid);
409     wr_s16b(creature_ptr->cut);
410     wr_s16b(creature_ptr->stun);
411     wr_s16b(creature_ptr->poisoned);
412     wr_s16b(creature_ptr->image);
413     wr_s16b(creature_ptr->protevil);
414     wr_s16b(creature_ptr->invuln);
415     wr_s16b(creature_ptr->ult_res);
416     wr_s16b(creature_ptr->hero);
417     wr_s16b(creature_ptr->shero);
418     wr_s16b(creature_ptr->shield);
419     wr_s16b(creature_ptr->blessed);
420     wr_s16b(creature_ptr->tim_invis);
421     wr_s16b(creature_ptr->word_recall);
422     wr_s16b(creature_ptr->recall_dungeon);
423     wr_s16b(creature_ptr->alter_reality);
424     wr_s16b(creature_ptr->see_infra);
425     wr_s16b(creature_ptr->tim_infra);
426     wr_s16b(creature_ptr->oppose_fire);
427     wr_s16b(creature_ptr->oppose_cold);
428     wr_s16b(creature_ptr->oppose_acid);
429     wr_s16b(creature_ptr->oppose_elec);
430     wr_s16b(creature_ptr->oppose_pois);
431     wr_s16b(creature_ptr->tsuyoshi);
432     wr_s16b(creature_ptr->tim_esp);
433     wr_s16b(creature_ptr->wraith_form);
434     wr_s16b(creature_ptr->resist_magic);
435     wr_s16b(creature_ptr->tim_regen);
436     wr_s16b(creature_ptr->tim_pass_wall);
437     wr_s16b(creature_ptr->tim_stealth);
438     wr_s16b(creature_ptr->tim_levitation);
439     wr_s16b(creature_ptr->tim_sh_touki);
440     wr_s16b(creature_ptr->lightspeed);
441     wr_s16b(creature_ptr->tsubureru);
442     wr_s16b(creature_ptr->magicdef);
443     wr_s16b(creature_ptr->tim_res_nether);
444     wr_s16b(creature_ptr->tim_res_time);
445     wr_byte((byte)creature_ptr->mimic_form);
446     wr_s16b(creature_ptr->tim_mimic);
447     wr_s16b(creature_ptr->tim_sh_fire);
448     wr_s16b(creature_ptr->tim_sh_holy);
449     wr_s16b(creature_ptr->tim_eyeeye);
450
451     /* by henkma */
452     wr_s16b(creature_ptr->tim_reflect);
453     wr_s16b(creature_ptr->multishadow);
454     wr_s16b(creature_ptr->dustrobe);
455
456     wr_s16b(creature_ptr->chaos_patron);
457     wr_u32b(creature_ptr->muta1);
458     wr_u32b(creature_ptr->muta2);
459     wr_u32b(creature_ptr->muta3);
460
461     for (int i = 0; i < 8; i++)
462         wr_s16b(creature_ptr->virtues[i]);
463     for (int i = 0; i < 8; i++)
464         wr_s16b(creature_ptr->vir_types[i]);
465
466     wr_s16b(creature_ptr->ele_attack);
467     wr_u32b(creature_ptr->special_attack);
468     wr_s16b(creature_ptr->ele_immune);
469     wr_u32b(creature_ptr->special_defense);
470     wr_byte(creature_ptr->knowledge);
471     wr_byte(creature_ptr->autopick_autoregister);
472     wr_byte(0);
473     wr_byte((byte)creature_ptr->action);
474     wr_byte(0);
475     wr_byte(preserve_mode);
476     wr_byte(creature_ptr->wait_report_score);
477
478     /* Future use */
479     for (int i = 0; i < 12; i++)
480         wr_u32b(0L);
481
482     /* Ignore some flags */
483     wr_u32b(0L);
484     wr_u32b(0L);
485     wr_u32b(0L);
486
487     /* Write the "object seeds" */
488     wr_u32b(current_world_ptr->seed_flavor);
489     wr_u32b(current_world_ptr->seed_town);
490
491     /* Special stuff */
492     wr_u16b(creature_ptr->panic_save);
493     wr_u16b(current_world_ptr->total_winner);
494     wr_u16b(current_world_ptr->noscore);
495
496     /* Write death */
497     wr_byte(creature_ptr->is_dead);
498
499     /* Write feeling */
500     wr_byte(creature_ptr->feeling);
501
502     /* Turn when level began */
503     wr_s32b(creature_ptr->current_floor_ptr->generated_turn);
504
505     /* Turn of last "feeling" */
506     wr_s32b(creature_ptr->feeling_turn);
507
508     /* Current turn */
509     wr_s32b(current_world_ptr->game_turn);
510
511     wr_s32b(current_world_ptr->dungeon_turn);
512
513     wr_s32b(current_world_ptr->arena_start_turn);
514
515     wr_s16b(today_mon);
516     wr_s16b(creature_ptr->today_mon);
517     wr_s16b(creature_ptr->riding);
518
519     /* Current floor_id */
520     wr_s16b(creature_ptr->floor_id);
521
522     /* Save temporary preserved pets (obsolated) */
523     wr_s16b(0);
524
525     wr_u32b(current_world_ptr->play_time);
526     wr_s32b(creature_ptr->visit);
527     wr_u32b(creature_ptr->count);
528 }
529
530 /*!
531  * @brief 保存フロアの書き込み / Actually write a saved floor data using effectively compressed format.
532  * @param sf_ptr 保存したいフロアの参照ポインタ
533  * @return なし
534  */
535 static void wr_saved_floor(player_type *player_ptr, saved_floor_type *sf_ptr)
536 {
537     /*** Basic info ***/
538     /* Dungeon floor specific info follows */
539     floor_type *floor_ptr = player_ptr->current_floor_ptr;
540     if (!sf_ptr) {
541         /*** Not a saved floor ***/
542
543         wr_s16b((s16b)floor_ptr->dun_level);
544     } else {
545         /*** The saved floor ***/
546
547         wr_s16b(sf_ptr->floor_id);
548         wr_byte((byte)sf_ptr->savefile_id);
549         wr_s16b((s16b)sf_ptr->dun_level);
550         wr_s32b(sf_ptr->last_visit);
551         wr_u32b(sf_ptr->visit_mark);
552         wr_s16b(sf_ptr->upper_floor_id);
553         wr_s16b(sf_ptr->lower_floor_id);
554     }
555
556     wr_u16b((u16b)floor_ptr->base_level);
557     wr_u16b((s16b)player_ptr->current_floor_ptr->num_repro);
558     wr_u16b((u16b)player_ptr->y);
559     wr_u16b((u16b)player_ptr->x);
560     wr_u16b((u16b)floor_ptr->height);
561     wr_u16b((u16b)floor_ptr->width);
562     wr_byte(player_ptr->feeling);
563
564     /*********** Make template for grid_type **********/
565
566     /*
567      * Usually number of templates are fewer than 255.  Even if
568      * more than 254 are exist, the occurrence of each template
569      * with larger ID is very small when we sort templates by
570      * occurrence.  So we will use two (or more) bytes for
571      * templete ID larger than 254.
572      *
573      * Ex: 256 will be "0xff" "0x01".
574      *     515 will be "0xff" "0xff" "0x03"
575      */
576
577     /* Fake max number */
578     u16b max_num_temp = 255;
579
580     /* Allocate the "template" array */
581     grid_template_type *templates;
582     C_MAKE(templates, max_num_temp, grid_template_type);
583
584     /* Extract template array */
585     u16b num_temp = 0;
586     for (int y = 0; y < floor_ptr->height; y++) {
587         for (int x = 0; x < floor_ptr->width; x++) {
588             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
589
590             int i;
591             for (i = 0; i < num_temp; i++) {
592                 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
593                     && templates[i].special == g_ptr->special) {
594                     /* Same terrain is exist */
595                     templates[i].occurrence++;
596                     break;
597                 }
598             }
599
600             /* Are there same one? */
601             if (i < num_temp)
602                 continue;
603
604             /* If the max_num_temp is too small, increase it. */
605             if (num_temp >= max_num_temp) {
606                 grid_template_type *old_template = templates;
607
608                 /* Re-allocate the "template" array */
609                 C_MAKE(templates, max_num_temp + 255, grid_template_type);
610                 (void)C_COPY(templates, old_template, max_num_temp, grid_template_type);
611                 C_KILL(old_template, max_num_temp, grid_template_type);
612                 max_num_temp += 255;
613             }
614
615             /* Add new template */
616             templates[num_temp].info = g_ptr->info;
617             templates[num_temp].feat = g_ptr->feat;
618             templates[num_temp].mimic = g_ptr->mimic;
619             templates[num_temp].special = g_ptr->special;
620             templates[num_temp].occurrence = 1;
621
622             /* Increase number of template */
623             num_temp++;
624         }
625     }
626
627     /* Sort by occurrence */
628     int dummy_why;
629     ang_sort(player_ptr, templates, &dummy_why, num_temp, ang_sort_comp_cave_temp, ang_sort_swap_cave_temp);
630
631     /*** Dump templates ***/
632
633     /* Total templates */
634     wr_u16b(num_temp);
635
636     /* Dump the templates */
637     for (int i = 0; i < num_temp; i++) {
638         grid_template_type *ct_ptr = &templates[i];
639         wr_u16b((u16b)ct_ptr->info);
640         wr_s16b(ct_ptr->feat);
641         wr_s16b(ct_ptr->mimic);
642         wr_s16b(ct_ptr->special);
643     }
644
645     /*** "Run-Length-Encoding" of floor ***/
646     /* Note that this will induce two wasted bytes */
647     byte count = 0;
648     u16b prev_u16b = 0;
649
650     for (int y = 0; y < floor_ptr->height; y++) {
651         for (int x = 0; x < floor_ptr->width; x++) {
652             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
653             int i;
654             for (i = 0; i < num_temp; i++) {
655                 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
656                     && templates[i].special == g_ptr->special)
657                     break;
658             }
659
660             /* Extract an ID */
661             u16b tmp16u = (u16b)i;
662
663             /* If the run is broken, or too full, flush it */
664             if ((tmp16u == prev_u16b) && (count != MAX_UCHAR)) {
665                 count++;
666                 continue;
667             }
668
669             wr_byte((byte)count);
670
671             while (prev_u16b >= MAX_UCHAR) {
672                 /* Mark as actual data is larger than 254 */
673                 wr_byte(MAX_UCHAR);
674                 prev_u16b -= MAX_UCHAR;
675             }
676
677             wr_byte((byte)prev_u16b);
678             prev_u16b = tmp16u;
679             count = 1;
680         }
681     }
682
683     /* Flush the data (if any) */
684     if (count > 0) {
685         wr_byte((byte)count);
686
687         while (prev_u16b >= MAX_UCHAR) {
688             /* Mark as actual data is larger than 254 */
689             wr_byte(MAX_UCHAR);
690             prev_u16b -= MAX_UCHAR;
691         }
692
693         wr_byte((byte)prev_u16b);
694     }
695
696     /* Free the "template" array */
697     C_KILL(templates, max_num_temp, grid_template_type);
698
699     /*** Dump objects ***/
700
701     /* Total objects */
702     wr_u16b(floor_ptr->o_max);
703
704     /* Dump the objects */
705     for (int i = 1; i < floor_ptr->o_max; i++) {
706         object_type *o_ptr = &floor_ptr->o_list[i];
707         wr_item(o_ptr);
708     }
709
710     /*** Dump the monsters ***/
711
712     /* Total monsters */
713     wr_u16b(floor_ptr->m_max);
714
715     /* Dump the monsters */
716     for (int i = 1; i < floor_ptr->m_max; i++) {
717         monster_type *m_ptr = &floor_ptr->m_list[i];
718         wr_monster(m_ptr);
719     }
720 }
721
722 /*!
723  * @brief 現在フロアの書き込み /
724  * Write the current dungeon (new method)
725  * @player_ptr プレーヤーへの参照ポインタ
726  * @return 保存に成功したらTRUE
727  */
728 static bool wr_dungeon(player_type *player_ptr)
729 {
730     forget_lite(player_ptr->current_floor_ptr);
731     forget_view(player_ptr->current_floor_ptr);
732     clear_mon_lite(player_ptr->current_floor_ptr);
733
734     /* Update lite/view */
735     player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
736     player_ptr->update |= (PU_MONSTERS | PU_DISTANCE | PU_FLOW);
737
738     /*** Meta info ***/
739
740     /* Number of floor_id used from birth */
741     wr_s16b(max_floor_id);
742
743     /* Current dungeon type */
744     wr_byte((byte)player_ptr->dungeon_idx);
745
746     /*** No saved floor (On the surface etc.) ***/
747     if (!player_ptr->floor_id) {
748         /* No array elements */
749         wr_byte(0);
750
751         /* Write the current floor data */
752         wr_saved_floor(player_ptr, NULL);
753
754         /* Success */
755         return TRUE;
756     }
757
758     /*** In the dungeon ***/
759
760     /* Number of array elements */
761     wr_byte(MAX_SAVED_FLOORS);
762
763     /* Write the saved_floors array */
764     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
765         saved_floor_type *sf_ptr = &saved_floors[i];
766
767         wr_s16b(sf_ptr->floor_id);
768         wr_byte((byte)sf_ptr->savefile_id);
769         wr_s16b((s16b)sf_ptr->dun_level);
770         wr_s32b(sf_ptr->last_visit);
771         wr_u32b(sf_ptr->visit_mark);
772         wr_s16b(sf_ptr->upper_floor_id);
773         wr_s16b(sf_ptr->lower_floor_id);
774     }
775
776     /* Extract pointer to current floor */
777     saved_floor_type *cur_sf_ptr;
778     cur_sf_ptr = get_sf_ptr(player_ptr->floor_id);
779
780     /* Save current floor to temporary file */
781     if (!save_floor(player_ptr, cur_sf_ptr, (SLF_SECOND)))
782         return FALSE;
783
784     /* Move data in temporary files to the savefile */
785     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
786         saved_floor_type *sf_ptr = &saved_floors[i];
787         if (!sf_ptr->floor_id)
788             continue;
789         if (!load_floor(player_ptr, sf_ptr, (SLF_SECOND | SLF_NO_KILL))) {
790             wr_byte(1);
791             continue;
792         }
793
794         wr_byte(0);
795         wr_saved_floor(player_ptr, sf_ptr);
796     }
797
798     if (!load_floor(player_ptr, cur_sf_ptr, (SLF_SECOND)))
799         return FALSE;
800     return TRUE;
801 }
802
803 /*!
804  * @brief セーブデータの書き込み /
805  * Actually write a save-file
806  * @param player_ptr プレーヤーへの参照ポインタ
807  * @return 成功すればtrue
808  */
809 static bool wr_savefile_new(player_type *player_ptr)
810 {
811     /* Compact the objects */
812     compact_objects(player_ptr, 0);
813
814     /* Compact the monsters */
815     compact_monsters(player_ptr, 0);
816
817     /* Guess at the current time */
818     u32b now = (u32b)time((time_t *)0);
819
820     /* Note the operating system */
821     current_world_ptr->sf_system = 0L;
822
823     /* Note when the file was saved */
824     current_world_ptr->sf_when = now;
825
826     /* Note the number of saves */
827     current_world_ptr->sf_saves++;
828
829     /*** Actually write the file ***/
830     /* Dump the file header */
831     save_xor_byte = 0;
832     wr_byte(FAKE_VER_MAJOR);
833     save_xor_byte = 0;
834     wr_byte(FAKE_VER_MINOR);
835     save_xor_byte = 0;
836     wr_byte(FAKE_VER_PATCH);
837     save_xor_byte = 0;
838
839     /* Initial value of xor_byte */
840     byte tmp8u = (byte)Rand_external(256);
841     wr_byte(tmp8u);
842
843     /* Reset the checksum */
844     v_stamp = 0L;
845     x_stamp = 0L;
846
847     /* Write the savefile version for Hengband 1.1.1 and later */
848     wr_byte(H_VER_EXTRA);
849     wr_byte(H_VER_PATCH);
850     wr_byte(H_VER_MINOR);
851     wr_byte(H_VER_MAJOR);
852
853     /* Operating system */
854     wr_u32b(current_world_ptr->sf_system);
855
856     /* Time file last saved */
857     wr_u32b(current_world_ptr->sf_when);
858
859     /* Number of past lives */
860     wr_u16b(current_world_ptr->sf_lives);
861
862     /* Number of times saved */
863     wr_u16b(current_world_ptr->sf_saves);
864
865     wr_u32b(0L);
866     wr_u16b(0);
867     wr_byte(0);
868
869 #ifdef JP
870 #ifdef EUC
871     /* EUC kanji code */
872     wr_byte(2);
873 #endif
874 #ifdef SJIS
875     /* SJIS kanji code */
876     wr_byte(3);
877 #endif
878 #else
879     /* ASCII */
880     wr_byte(1);
881 #endif
882
883     /* Write the RNG state */
884     wr_randomizer();
885
886     /* Write the boolean "options" */
887     wr_options();
888
889     /* Dump the number of "messages" */
890     u32b tmp32u = message_num();
891     if (compress_savefile && (tmp32u > 40))
892         tmp32u = 40;
893     wr_u32b(tmp32u);
894
895     /* Dump the messages (oldest first!) */
896     for (int i = tmp32u - 1; i >= 0; i--) {
897         wr_string(message_str((s16b)i));
898     }
899
900     /* Dump the monster lore */
901     u16b tmp16u = max_r_idx;
902     wr_u16b(tmp16u);
903     for (MONRACE_IDX r_idx = 0; r_idx < tmp16u; r_idx++) {
904         wr_lore(r_idx);
905     }
906
907     /* Dump the object memory */
908     tmp16u = max_k_idx;
909     wr_u16b(tmp16u);
910     for (KIND_OBJECT_IDX k_idx = 0; k_idx < tmp16u; k_idx++) {
911         wr_xtra(k_idx);
912     }
913
914     /* Dump the towns */
915     tmp16u = max_towns;
916     wr_u16b(tmp16u);
917
918     /* Dump the quests */
919     tmp16u = max_q_idx;
920     wr_u16b(tmp16u);
921
922     /* Dump the quests */
923     tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
924     wr_byte(tmp8u);
925
926     for (int i = 0; i < max_q_idx; i++) {
927         quest_type *const q_ptr = &quest[i];
928
929         /* Save status for every quest */
930         wr_s16b(q_ptr->status);
931
932         /* And the dungeon level too */
933         /* (prevents problems with multi-level quests) */
934         wr_s16b((s16b)q_ptr->level);
935
936         wr_byte((byte)q_ptr->complev);
937         wr_u32b(q_ptr->comptime);
938
939         bool is_quest_running = q_ptr->status == QUEST_STATUS_TAKEN;
940         is_quest_running |= q_ptr->status == QUEST_STATUS_COMPLETED;
941         is_quest_running |= !is_fixed_quest_idx(i);
942         if (!is_quest_running)
943             continue;
944
945         wr_s16b((s16b)q_ptr->cur_num);
946         wr_s16b((s16b)q_ptr->max_num);
947         wr_s16b(q_ptr->type);
948         wr_s16b(q_ptr->r_idx);
949         wr_s16b(q_ptr->k_idx);
950         wr_byte((byte)q_ptr->flags);
951         wr_byte((byte)q_ptr->dungeon);
952     }
953
954     /* Dump the position in the wilderness */
955     wr_s32b(player_ptr->wilderness_x);
956     wr_s32b(player_ptr->wilderness_y);
957
958     wr_byte(player_ptr->wild_mode);
959     wr_byte(player_ptr->ambush_flag);
960
961     wr_s32b(current_world_ptr->max_wild_x);
962     wr_s32b(current_world_ptr->max_wild_y);
963
964     /* Dump the wilderness seeds */
965     for (int i = 0; i < current_world_ptr->max_wild_x; i++) {
966         for (int j = 0; j < current_world_ptr->max_wild_y; j++) {
967             wr_u32b(wilderness[j][i].seed);
968         }
969     }
970
971     /* Hack -- Dump the artifacts */
972     tmp16u = max_a_idx;
973     wr_u16b(tmp16u);
974     for (int i = 0; i < tmp16u; i++) {
975         artifact_type *a_ptr = &a_info[i];
976         wr_byte(a_ptr->cur_num);
977         wr_s16b(a_ptr->floor_id);
978     }
979
980     /* Write the "extra" information */
981     wr_extra(player_ptr);
982
983     /* Dump the "player hp" entries */
984     tmp16u = PY_MAX_LEVEL;
985     wr_u16b(tmp16u);
986     for (int i = 0; i < tmp16u; i++) {
987         wr_s16b((s16b)player_ptr->player_hp[i]);
988     }
989
990     /* Write spell data */
991     wr_u32b(player_ptr->spell_learned1);
992     wr_u32b(player_ptr->spell_learned2);
993     wr_u32b(player_ptr->spell_worked1);
994     wr_u32b(player_ptr->spell_worked2);
995     wr_u32b(player_ptr->spell_forgotten1);
996     wr_u32b(player_ptr->spell_forgotten2);
997
998     wr_s16b(player_ptr->learned_spells);
999     wr_s16b(player_ptr->add_spells);
1000
1001     /* Dump the ordered spells */
1002     for (int i = 0; i < 64; i++) {
1003         wr_byte((byte)player_ptr->spell_order[i]);
1004     }
1005
1006     for (int i = 0; i < INVEN_TOTAL; i++) {
1007         object_type *o_ptr = &player_ptr->inventory_list[i];
1008         if (!o_ptr->k_idx)
1009             continue;
1010
1011         /* Dump index */
1012         wr_u16b((u16b)i);
1013
1014         /* Dump object */
1015         wr_item(o_ptr);
1016     }
1017
1018     /* Add a sentinel */
1019     wr_u16b(0xFFFF);
1020
1021     /* Note the towns */
1022     tmp16u = max_towns;
1023     wr_u16b(tmp16u);
1024
1025     /* Note the stores */
1026     tmp16u = MAX_STORES;
1027     wr_u16b(tmp16u);
1028
1029     /* Dump the stores of all towns */
1030     for (int i = 1; i < max_towns; i++) {
1031         for (int j = 0; j < MAX_STORES; j++) {
1032             wr_store(&town_info[i].store[j]);
1033         }
1034     }
1035
1036     /* Write the pet command settings */
1037     wr_s16b(player_ptr->pet_follow_distance);
1038     wr_s16b(player_ptr->pet_extra_flags);
1039
1040     /* Write screen dump for sending score */
1041     if (screen_dump && (player_ptr->wait_report_score || !player_ptr->is_dead)) {
1042         wr_string(screen_dump);
1043     } else {
1044         wr_string("");
1045     }
1046
1047     /* Player is not dead, write the dungeon */
1048     if (!player_ptr->is_dead) {
1049         /* Dump the dungeon */
1050         if (!wr_dungeon(player_ptr))
1051             return FALSE;
1052
1053         /* Dump the ghost */
1054         wr_ghost();
1055
1056         /* No scripts */
1057         wr_s32b(0);
1058     }
1059
1060     /* Write the "value check-sum" */
1061     wr_u32b(v_stamp);
1062
1063     /* Write the "encoded checksum" */
1064     wr_u32b(x_stamp);
1065
1066     if (ferror(saving_savefile) || (fflush(saving_savefile) == EOF))
1067         return FALSE;
1068     return TRUE;
1069 }
1070
1071 /*!
1072  * @brief セーブデータ書き込みのサブルーチン /
1073  * Medium level player saver
1074  * @param player_ptr プレーヤーへの参照ポインタ
1075  * @return 成功すればtrue
1076  * @details
1077  * Angband 2.8.0 will use "fd" instead of "fff" if possible
1078  */
1079 static bool save_player_aux(player_type *player_ptr, char *name)
1080 {
1081     /* Grab permissions */
1082     safe_setuid_grab(player_ptr);
1083
1084     /* Create the savefile */
1085     int file_permission = 0644;
1086     int fd = fd_make(name, file_permission);
1087
1088     /* Drop permissions */
1089     safe_setuid_drop();
1090
1091     bool is_save_successful = FALSE;
1092     saving_savefile = NULL;
1093     if (fd >= 0) {
1094         /* Close the "fd" */
1095         (void)fd_close(fd);
1096
1097         /* Grab permissions */
1098         safe_setuid_grab(player_ptr);
1099
1100         /* Open the savefile */
1101         saving_savefile = angband_fopen(name, "wb");
1102
1103         /* Drop permissions */
1104         safe_setuid_drop();
1105
1106         /* Successful open */
1107         if (saving_savefile) {
1108             /* Write the savefile */
1109             if (wr_savefile_new(player_ptr))
1110                 is_save_successful = TRUE;
1111
1112             /* Attempt to close it */
1113             if (angband_fclose(saving_savefile))
1114                 is_save_successful = FALSE;
1115         }
1116
1117         /* Grab permissions */
1118         safe_setuid_grab(player_ptr);
1119
1120         /* Remove "broken" files */
1121         if (!is_save_successful)
1122             (void)fd_kill(name);
1123
1124         /* Drop permissions */
1125         safe_setuid_drop();
1126     }
1127
1128     if (!is_save_successful)
1129         return FALSE;
1130
1131     counts_write(player_ptr, 0, current_world_ptr->play_time);
1132     current_world_ptr->character_saved = TRUE;
1133     return TRUE;
1134 }
1135
1136 /*!
1137  * @brief セーブデータ書き込みのメインルーチン /
1138  * Attempt to save the player in a savefile
1139  * @param player_ptr プレーヤーへの参照ポインタ
1140  * @return 成功すればtrue
1141  */
1142 bool save_player(player_type *player_ptr)
1143 {
1144     char safe[1024];
1145     strcpy(safe, savefile);
1146     strcat(safe, ".new");
1147
1148     /* Grab permissions */
1149     safe_setuid_grab(player_ptr);
1150
1151     fd_kill(safe);
1152
1153     /* Drop permissions */
1154     safe_setuid_drop();
1155     update_playtime();
1156
1157     /* Attempt to save the player */
1158     bool result = FALSE;
1159     if (save_player_aux(player_ptr, safe)) {
1160         char temp[1024];
1161
1162         /* Old savefile */
1163         strcpy(temp, savefile);
1164         strcat(temp, ".old");
1165
1166         /* Grab permissions */
1167         safe_setuid_grab(player_ptr);
1168
1169         /* Remove it */
1170         fd_kill(temp);
1171
1172         /* Preserve old savefile */
1173         fd_move(savefile, temp);
1174
1175         /* Activate new savefile */
1176         fd_move(safe, savefile);
1177
1178         /* Remove preserved savefile */
1179         fd_kill(temp);
1180
1181         /* Drop permissions */
1182         safe_setuid_drop();
1183
1184         /* Hack -- Pretend the character was loaded */
1185         current_world_ptr->character_loaded = TRUE;
1186
1187         result = TRUE;
1188     }
1189
1190     /* Return the result */
1191     return result;
1192 }
1193
1194 /*!
1195  * @brief セーブデータ読み込みのメインルーチン /
1196  * Attempt to Load a "savefile"
1197  * @param creature_ptr プレーヤーへの参照ポインタ
1198  * @return 成功すればtrue
1199  * @details
1200  * <pre>
1201  * Version 2.7.0 introduced a slightly different "savefile" format from
1202  * older versions, requiring a completely different parsing method.
1203  *
1204  * Note that savefiles from 2.7.0 - 2.7.2 are completely obsolete.
1205  *
1206  * Pre-2.8.0 savefiles lose some data, see "load2.c" for info.
1207  *
1208  * Pre-2.7.0 savefiles lose a lot of things, see "load1.c" for info.
1209  *
1210  * On multi-user systems, you may only "read" a savefile if you will be
1211  * allowed to "write" it later, this prevents painful situations in which
1212  * the player loads a savefile belonging to someone else, and then is not
1213  * allowed to save his game when he quits.
1214  *
1215  * We return "TRUE" if the savefile was usable, and we set the global
1216  * flag "current_world_ptr->character_loaded" if a real, living, character was loaded.
1217  *
1218  * Note that we always try to load the "current" savefile, even if
1219  * there is no such file, so we must check for "empty" savefile names.
1220  * </pre>
1221  */
1222 bool load_player(player_type *player_ptr)
1223 {
1224     concptr what = "generic";
1225
1226     current_world_ptr->game_turn = 0;
1227     player_ptr->is_dead = FALSE;
1228
1229     /* Allow empty savefile name */
1230     if (!savefile[0])
1231         return TRUE;
1232
1233 #if !defined(WINDOWS)
1234
1235     /* Fix this */
1236
1237     /* Verify the existance of the savefile */
1238     if (access(savefile, 0) < 0) {
1239         /* Give a message */
1240         msg_print(_("セーブファイルがありません。", "Savefile does not exist."));
1241
1242         msg_print(NULL);
1243
1244         /* Allow this */
1245         return TRUE;
1246     }
1247
1248 #endif
1249
1250     errr err = 0;
1251     int fd = -1;
1252     byte vvv[4];
1253     if (!err) {
1254         /* Open the savefile */
1255         fd = fd_open(savefile, O_RDONLY);
1256
1257         /* No file */
1258         if (fd < 0)
1259             err = -1;
1260
1261         /* Message (below) */
1262         if (err)
1263             what = _("セーブファイルを開けません。", "Cannot open savefile");
1264     }
1265
1266     /* Process file */
1267     if (!err) {
1268         /* Read the first four bytes */
1269         if (fd_read(fd, (char *)(vvv), 4))
1270             err = -1;
1271
1272         /* What */
1273         if (err)
1274             what = _("セーブファイルを読めません。", "Cannot read savefile");
1275         (void)fd_close(fd);
1276     }
1277
1278     /* Process file */
1279     if (!err) {
1280         /* Extract version */
1281         current_world_ptr->z_major = vvv[0];
1282         current_world_ptr->z_minor = vvv[1];
1283         current_world_ptr->z_patch = vvv[2];
1284         current_world_ptr->sf_extra = vvv[3];
1285
1286         term_clear();
1287
1288         /* Attempt to load */
1289         err = rd_savefile(player_ptr);
1290
1291         /* Message (below) */
1292         if (err)
1293             what = _("セーブファイルを解析出来ません。", "Cannot parse savefile");
1294     }
1295
1296     if (!err) {
1297         /* Invalid turn */
1298         if (!current_world_ptr->game_turn)
1299             err = -1;
1300
1301         /* Message (below) */
1302         if (err)
1303             what = _("セーブファイルが壊れています", "Broken savefile");
1304     }
1305
1306     if (!err) {
1307         /* Give a conversion warning */
1308         if ((FAKE_VER_MAJOR != current_world_ptr->z_major) || (FAKE_VER_MINOR != current_world_ptr->z_minor)
1309             || (FAKE_VER_PATCH != current_world_ptr->z_patch)) {
1310             if (current_world_ptr->z_major == 2 && current_world_ptr->z_minor == 0 && current_world_ptr->z_patch == 6) {
1311                 msg_print(_("バージョン 2.0.* 用のセーブファイルを変換しました。", "Converted a 2.0.* savefile."));
1312             } else {
1313                 msg_format(_("バージョン %d.%d.%d 用のセーブ・ファイルを変換しました。", "Converted a %d.%d.%d savefile."),
1314                     (current_world_ptr->z_major > 9) ? current_world_ptr->z_major - 10 : current_world_ptr->z_major, current_world_ptr->z_minor,
1315                     current_world_ptr->z_patch);
1316             }
1317             msg_print(NULL);
1318         }
1319
1320         /* Player is dead */
1321         if (player_ptr->is_dead) {
1322             /* Cheat death */
1323             if (arg_wizard) {
1324                 /* A character was loaded */
1325                 current_world_ptr->character_loaded = TRUE;
1326                 return TRUE;
1327             }
1328
1329             /* Player is no longer "dead" */
1330             player_ptr->is_dead = FALSE;
1331
1332             /* Count lives */
1333             current_world_ptr->sf_lives++;
1334
1335             return TRUE;
1336         }
1337
1338         /* A character was loaded */
1339         current_world_ptr->character_loaded = TRUE;
1340
1341         {
1342             u32b tmp = counts_read(player_ptr, 2);
1343             if (tmp > player_ptr->count)
1344                 player_ptr->count = tmp;
1345             if (counts_read(player_ptr, 0) > current_world_ptr->play_time || counts_read(player_ptr, 1) == current_world_ptr->play_time)
1346                 counts_write(player_ptr, 2, ++player_ptr->count);
1347             counts_write(player_ptr, 1, current_world_ptr->play_time);
1348         }
1349
1350         /* Success */
1351         return TRUE;
1352     }
1353
1354     msg_format(_("エラー(%s)がバージョン%d.%d.%d 用セーブファイル読み込み中に発生。", "Error (%s) reading %d.%d.%d savefile."), what,
1355         (current_world_ptr->z_major > 9) ? current_world_ptr->z_major - 10 : current_world_ptr->z_major, current_world_ptr->z_minor,
1356         current_world_ptr->z_patch);
1357     msg_print(NULL);
1358     return FALSE;
1359 }
1360
1361 /*!
1362  * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporary saved floor file
1363  * @param player_ptr プレーヤーへの参照ポインタ
1364  * @param sf_ptr 保存フロア参照ポインタ
1365  * @return なし
1366  */
1367 static bool save_floor_aux(player_type *player_ptr, saved_floor_type *sf_ptr)
1368 {
1369     /* Compact the objects */
1370     compact_objects(player_ptr, 0);
1371     /* Compact the monsters */
1372     compact_monsters(player_ptr, 0);
1373
1374     /*** Actually write the file ***/
1375     /* Initial value of xor_byte */
1376     byte tmp8u = (byte)randint0(256);
1377     save_xor_byte = 0;
1378     wr_byte(tmp8u);
1379
1380     /* Reset the checksum */
1381     v_stamp = 0L;
1382     x_stamp = 0L;
1383
1384     /* Write the sign of this process */
1385     wr_u32b(saved_floor_file_sign);
1386
1387     /* Dump the dungeon floor */
1388     wr_saved_floor(player_ptr, sf_ptr);
1389
1390     /* Write the "value check-sum" */
1391     wr_u32b(v_stamp);
1392
1393     /* Write the "encoded checksum" */
1394     wr_u32b(x_stamp);
1395
1396     if (ferror(saving_savefile) || (fflush(saving_savefile) == EOF))
1397         return FALSE;
1398     return TRUE;
1399 }
1400
1401 /*!
1402  * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporarily saved-floor data
1403  * @param player_ptr プレーヤーへの参照ポインタ
1404  * @param sf_ptr 保存フロア参照ポインタ
1405  * @param mode 保存オプション
1406  * @return なし
1407  */
1408 bool save_floor(player_type *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode)
1409 {
1410     FILE *old_fff = NULL;
1411     byte old_xor_byte = 0;
1412     u32b old_v_stamp = 0;
1413     u32b old_x_stamp = 0;
1414
1415     char floor_savefile[1024];
1416     if (!(mode & SLF_SECOND)) {
1417     }
1418
1419     /* We have one file already opened */
1420     else {
1421         /* Backup original values */
1422         old_fff = saving_savefile;
1423         old_xor_byte = save_xor_byte;
1424         old_v_stamp = v_stamp;
1425         old_x_stamp = x_stamp;
1426     }
1427
1428     /* New savefile */
1429     sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
1430
1431     /* Grab permissions */
1432     safe_setuid_grab(player_ptr);
1433
1434     /* Remove it */
1435     fd_kill(floor_savefile);
1436
1437     /* Drop permissions */
1438     safe_setuid_drop();
1439
1440     /* Attempt to save the player */
1441
1442     /* No file yet */
1443     saving_savefile = NULL;
1444
1445     /* Grab permissions */
1446     safe_setuid_grab(player_ptr);
1447
1448     /* Create the savefile */
1449     int fd = fd_make(floor_savefile, 0644);
1450
1451     /* Drop permissions */
1452     safe_setuid_drop();
1453
1454     bool is_save_successful = FALSE;
1455     if (fd >= 0) {
1456         /* Close the "fd" */
1457         (void)fd_close(fd);
1458
1459         /* Grab permissions */
1460         safe_setuid_grab(player_ptr);
1461
1462         /* Open the savefile */
1463         saving_savefile = angband_fopen(floor_savefile, "wb");
1464
1465         /* Drop permissions */
1466         safe_setuid_drop();
1467
1468         /* Successful open */
1469         if (saving_savefile) {
1470             /* Write the savefile */
1471             if (save_floor_aux(player_ptr, sf_ptr))
1472                 is_save_successful = TRUE;
1473
1474             /* Attempt to close it */
1475             if (angband_fclose(saving_savefile))
1476                 is_save_successful = FALSE;
1477         }
1478
1479         /* Remove "broken" files */
1480         if (!is_save_successful) {
1481             /* Grab permissions */
1482             safe_setuid_grab(player_ptr);
1483
1484             (void)fd_kill(floor_savefile);
1485
1486             /* Drop permissions */
1487             safe_setuid_drop();
1488         }
1489     }
1490
1491     if (!(mode & SLF_SECOND)) {
1492     }
1493
1494     /* We have one file already opened */
1495     else {
1496         /* Restore original values */
1497         saving_savefile = old_fff;
1498         save_xor_byte = old_xor_byte;
1499         v_stamp = old_v_stamp;
1500         x_stamp = old_x_stamp;
1501     }
1502
1503     return is_save_successful;
1504 }