1 /**
2 * @file
3 * @brief Functions used to save and load levels/games.
4 **/
5
6 // old compiler compatibility for CAO/CBRO stdint.h. cstdint doesn't work
7 // on these gcc versions to provide UINT8_MAX.
8 #ifndef __STDC_LIMIT_MACROS
9 #define __STDC_LIMIT_MACROS 1
10 #endif
11 #include <stdint.h>
12
13 #include "AppHdr.h"
14
15 #include "files.h"
16
17 #include "json.h"
18 #include "json-wrapper.h"
19
20 #include <algorithm>
21 #include <cctype>
22 #include <cerrno>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <functional>
27 #include <string>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #ifdef HAVE_UTIMES
31 #include <sys/time.h>
32 #endif
33 #include <sys/types.h>
34 #ifdef UNIX
35 #include <unistd.h>
36 #endif
37
38 #include "abyss.h"
39 #include "act-iter.h"
40 #include "areas.h"
41 #include "branch.h"
42 #include "chardump.h"
43 #include "cloud.h"
44 #include "coordit.h"
45 #include "dactions.h"
46 #include "dbg-util.h"
47 #include "dgn-overview.h"
48 #include "directn.h"
49 #include "dungeon.h"
50 #include "end.h"
51 #include "tile-env.h"
52 #include "errors.h"
53 #include "player-save-info.h"
54 #include "fineff.h"
55 #include "ghost.h"
56 #include "god-abil.h"
57 #include "god-companions.h"
58 #include "god-passive.h"
59 #include "hints.h"
60 #include "initfile.h"
61 #include "item-name.h"
62 #include "items.h"
63 #include "jobs.h"
64 #include "kills.h"
65 #include "level-state-type.h"
66 #include "libutil.h"
67 #include "macro.h"
68 #include "mapmark.h"
69 #include "message.h"
70 #include "mon-behv.h"
71 #include "mon-death.h"
72 #include "mon-place.h"
73 #include "notes.h"
74 #include "place.h"
75 #include "prompt.h"
76 #include "skills.h"
77 #include "species.h"
78 #include "spl-summoning.h"
79 #include "stairs.h"
80 #include "state.h"
81 #include "stringutil.h"
82 #include "syscalls.h"
83 #include "tag-version.h"
84 #include "teleport.h"
85 #include "terrain.h"
86 #ifdef USE_TILE
87 // TODO -- dolls
88 #include "rltiles/tiledef-player.h"
89 #include "tilepick-p.h"
90 #endif
91 #include "tileview.h"
92 #include "tiles-build-specific.h"
93 #include "timed-effects.h"
94 #include "ui.h"
95 #include "unwind.h"
96 #include "version.h"
97 #include "view.h"
98 #include "xom.h"
99
100 #ifdef __ANDROID__
101 #include <android/log.h>
102 #endif
103
104 #ifndef F_OK // MSVC for example
105 #define F_OK 0
106 #endif
107
108 #define BONES_DIAGNOSTICS (defined(WIZARD) || defined(DEBUG_BONES) || defined(DEBUG_DIAGNOSTICS))
109
110 #ifdef BONES_DIAGNOSTICS
111 /// show diagnostics following a wizard command, even if not a debug build
_ghost_dprf(const char * format,...)112 static void _ghost_dprf(const char *format, ...)
113 {
114 va_list argp;
115 va_start(argp, format);
116
117 #ifndef DEBUG_DIAGNOSTICS
118 const bool wiz_cmd = (crawl_state.prev_cmd == CMD_WIZARD);
119 if (wiz_cmd)
120 #endif
121 do_message_print(MSGCH_DIAGNOSTICS, 0, false, false, format, argp);
122
123 va_end(argp);
124 }
125 #else
126 # define _ghost_dprf(...) ((void)0)
127 #endif
128
129 static bool _ghost_version_compatible(const save_version &version);
130
131 static bool _restore_tagged_chunk(package *save, const string &name,
132 tag_type tag, const char* complaint);
133 static bool _read_char_chunk(package *save);
134
135 static bool _convert_obsolete_species();
136
137 const short GHOST_SIGNATURE = short(0xDC55);
138
139 const int GHOST_LIMIT = 27; // max number of ghost files per level
140
_redraw_all()141 static void _redraw_all()
142 {
143 you.redraw_hit_points = true;
144 you.redraw_magic_points = true;
145 you.redraw_stats.init(true);
146 you.redraw_armour_class = true;
147 you.redraw_evasion = true;
148 you.redraw_experience = true;
149 you.redraw_status_lights = true;
150 }
151
is_save_file_name(const string & name)152 static bool is_save_file_name(const string &name)
153 {
154 int off = name.length() - strlen(SAVE_SUFFIX);
155 if (off <= 0)
156 return false;
157 return !strcasecmp(name.c_str() + off, SAVE_SUFFIX);
158 }
159
160 // Returns the save_info from the save.
_read_character_info(package * save)161 static player_save_info _read_character_info(package *save)
162 {
163 player_save_info fromfile;
164
165 // Backup before we clobber "you".
166 const player backup(you);
167 unwind_var<game_type> gtype(crawl_state.type);
168
169 try // need a redundant try block just so we can restore the backup
170 { // (or risk an = operator on you getting misused)
171 fromfile.save_loadable = _read_char_chunk(save);
172 fromfile = you;
173 }
174 catch (ext_fail_exception &E) {}
175
176 you = backup;
177
178 return fromfile;
179 }
180
get_dir_files_sorted(const string & dirname)181 vector<string> get_dir_files_sorted(const string &dirname)
182 {
183 auto result = get_dir_files(dirname);
184 sort(result.begin(), result.end());
185 return result;
186 }
187
188 // Returns a vector of files (including directories if requested) in
189 // the given directory, recursively. All filenames returned are
190 // relative to the start directory. If an extension is supplied, all
191 // filenames (and directory names if include_directories is set)
192 // returned must be suffixed with the extension (the extension is not
193 // modified in any way, so if you want, say, ".des", you must include
194 // the "." as well).
195 //
196 // If recursion_depth is -1, the recursion is infinite, as far as the
197 // directory structure and filesystem allows. If recursion_depth is 0,
198 // only files in the start directory are returned.
get_dir_files_recursive(const string & dirname,const string & ext,int recursion_depth,bool include_directories)199 vector<string> get_dir_files_recursive(const string &dirname, const string &ext,
200 int recursion_depth,
201 bool include_directories)
202 {
203 vector<string> files;
204
205 const int next_recur_depth =
206 recursion_depth == -1? -1 : recursion_depth - 1;
207 const bool recur = recursion_depth == -1 || recursion_depth > 0;
208
209 for (const string &filename : get_dir_files_sorted(dirname))
210 {
211 if (dir_exists(catpath(dirname, filename)))
212 {
213 if (include_directories
214 && (ext.empty() || ends_with(filename, ext)))
215 {
216 files.push_back(filename);
217 }
218
219 if (recur)
220 {
221 // Each filename in a subdirectory has to be prefixed
222 // with the subdirectory name.
223 for (const string &subdirfile
224 : get_dir_files_recursive(catpath(dirname, filename),
225 ext, next_recur_depth))
226 {
227 files.push_back(catpath(filename, subdirfile));
228 }
229 }
230 }
231 else
232 {
233 if (ext.empty() || ends_with(filename, ext))
234 files.push_back(filename);
235 }
236 }
237 return files;
238 }
239
get_dir_files_ext(const string & dir,const string & ext)240 vector<string> get_dir_files_ext(const string &dir, const string &ext)
241 {
242 return get_dir_files_recursive(dir, ext, 0);
243 }
244
get_parent_directory(const string & filename)245 string get_parent_directory(const string &filename)
246 {
247 string::size_type pos = filename.rfind(FILE_SEPARATOR);
248 if (pos != string::npos)
249 return filename.substr(0, pos + 1);
250 #ifdef ALT_FILE_SEPARATOR
251 pos = filename.rfind(ALT_FILE_SEPARATOR);
252 if (pos != string::npos)
253 return filename.substr(0, pos + 1);
254 #endif
255 return "";
256 }
257
get_base_filename(const string & filename)258 string get_base_filename(const string &filename)
259 {
260 string::size_type pos = filename.rfind(FILE_SEPARATOR);
261 if (pos != string::npos)
262 return filename.substr(pos + 1);
263 #ifdef ALT_FILE_SEPARATOR
264 pos = filename.rfind(ALT_FILE_SEPARATOR);
265 if (pos != string::npos)
266 return filename.substr(pos + 1);
267 #endif
268 return filename;
269 }
270
get_cache_name(const string & filename)271 string get_cache_name(const string &filename)
272 {
273 string::size_type pos = filename.rfind(FILE_SEPARATOR);
274 while (pos != string::npos && filename.find("/des", pos) != pos)
275 pos = filename.rfind(FILE_SEPARATOR, pos - 1);
276 if (pos != string::npos)
277 return replace_all_of(filename.substr(pos + 5), " /\\:", "_");
278 #ifdef ALT_FILE_SEPARATOR
279 pos = filename.rfind(ALT_FILE_SEPARATOR);
280 while (pos != string::npos && filename.find("/des", pos) != pos)
281 pos = filename.rfind(ALT_FILE_SEPARATOR, pos - 1);
282 if (pos != string::npos)
283 return replace_all_of(filename.substr(pos + 5), " /\\:", "_");
284 #endif
285 return filename;
286 }
287
is_absolute_path(const string & path)288 bool is_absolute_path(const string &path)
289 {
290 return !path.empty()
291 && (path[0] == FILE_SEPARATOR
292 #ifdef TARGET_OS_WINDOWS
293 || path.find(':') != string::npos
294 #endif
295 );
296 }
297
298 // Concatenates two paths, separating them with FILE_SEPARATOR if necessary.
299 // Assumes that the second path is not absolute.
300 //
301 // If the first path is empty, returns the second unchanged. The second path
302 // may be absolute in this case.
catpath(const string & first,const string & second)303 string catpath(const string &first, const string &second)
304 {
305 if (first.empty())
306 return second;
307
308 string directory = first;
309 if (directory[directory.length() - 1] != FILE_SEPARATOR
310 && (second.empty() || second[0] != FILE_SEPARATOR))
311 {
312 directory += FILE_SEPARATOR;
313 }
314 directory += second;
315
316 return directory;
317 }
318
319 // Given a relative path and a reference file name, returns the relative path
320 // suffixed to the directory containing the reference file name. Assumes that
321 // the second path is not absolute.
get_path_relative_to(const string & referencefile,const string & relativepath)322 string get_path_relative_to(const string &referencefile,
323 const string &relativepath)
324 {
325 return catpath(get_parent_directory(referencefile),
326 relativepath);
327 }
328
change_file_extension(const string & filename,const string & ext)329 string change_file_extension(const string &filename, const string &ext)
330 {
331 const string::size_type pos = filename.rfind('.');
332 return (pos == string::npos? filename : filename.substr(0, pos)) + ext;
333 }
334
file_modtime(const string & file)335 time_t file_modtime(const string &file)
336 {
337 struct stat filestat;
338 if (stat(file.c_str(), &filestat))
339 return 0;
340
341 return filestat.st_mtime;
342 }
343
file_modtime(FILE * f)344 time_t file_modtime(FILE *f)
345 {
346 struct stat filestat;
347 if (fstat(fileno(f), &filestat))
348 return 0;
349
350 return filestat.st_mtime;
351 }
352
_create_directory(const char * dir)353 static bool _create_directory(const char *dir)
354 {
355 if (!mkdir_u(dir, 0755))
356 return true;
357 if (errno == EEXIST) // might be not a directory
358 return dir_exists(dir);
359 return false;
360 }
361
_create_dirs(const string & dir)362 static bool _create_dirs(const string &dir)
363 {
364 string sep = " ";
365 sep[0] = FILE_SEPARATOR;
366 vector<string> segments = split_string(sep, dir, false, false);
367
368 string path;
369 for (int i = 0, size = segments.size(); i < size; ++i)
370 {
371 path += segments[i];
372
373 // Handle absolute paths correctly.
374 if (i == 0 && dir.size() && dir[0] == FILE_SEPARATOR)
375 path = FILE_SEPARATOR + path;
376
377 if (!_create_directory(path.c_str()))
378 return false;
379
380 path += FILE_SEPARATOR;
381 }
382 return true;
383 }
384
385 // Checks whether the given path is safe to read from. A path is safe if:
386 // 1. If Unix: It contains no shell metacharacters.
387 // 2. If DATA_DIR_PATH is set: the path is not an absolute path.
388 // 3. If DATA_DIR_PATH is set: the path contains no ".." sequence.
assert_read_safe_path(const string & path)389 void assert_read_safe_path(const string &path)
390 {
391 // Check for rank tomfoolery first:
392 if (path.empty())
393 throw unsafe_path("Empty file name.");
394
395 #ifdef UNIX
396 if (!shell_safe(path.c_str()))
397 throw unsafe_path_f("\"%s\" contains bad characters.", path.c_str());
398 #endif
399
400 #ifdef DATA_DIR_PATH
401 if (is_absolute_path(path))
402 throw unsafe_path_f("\"%s\" is an absolute path.", path.c_str());
403
404 if (path.find("..") != string::npos)
405 throw unsafe_path_f("\"%s\" contains \"..\" sequences.", path.c_str());
406 #endif
407
408 // Path is okay.
409 }
410
canonicalise_file_separator(const string & path)411 string canonicalise_file_separator(const string &path)
412 {
413 const string sep(1, FILE_SEPARATOR);
414 return replace_all_of(replace_all_of(path, "/", sep),
415 "\\", sep);
416 }
417
_get_base_dirs()418 static vector<string> _get_base_dirs()
419 {
420 const string rawbases[] =
421 {
422 #ifdef DATA_DIR_PATH
423 DATA_DIR_PATH,
424 #else
425 !SysEnv.crawl_dir.empty()? SysEnv.crawl_dir : "",
426 !SysEnv.crawl_base.empty()? SysEnv.crawl_base : "",
427 #endif
428 #ifdef TARGET_OS_MACOSX
429 SysEnv.crawl_base + "../Resources/",
430 #endif
431 #ifdef __ANDROID__
432 ANDROID_ASSETS,
433 "/sdcard/Android/data/org.develz.crawl/files/",
434 #endif
435 };
436
437 const string prefixes[] =
438 {
439 string("dat") + FILE_SEPARATOR,
440 #ifdef USE_TILE_LOCAL
441 string("dat/tiles") + FILE_SEPARATOR,
442 #endif
443 string("docs") + FILE_SEPARATOR,
444 string("settings") + FILE_SEPARATOR,
445 #ifndef DATA_DIR_PATH
446 string("..") + FILE_SEPARATOR + "docs" + FILE_SEPARATOR,
447 string("..") + FILE_SEPARATOR + "dat" + FILE_SEPARATOR,
448 #ifdef USE_TILE_LOCAL
449 string("..") + FILE_SEPARATOR + "dat/tiles" + FILE_SEPARATOR,
450 #endif
451 string("..") + FILE_SEPARATOR + "settings" + FILE_SEPARATOR,
452 string("..") + FILE_SEPARATOR,
453 #endif
454 "",
455 };
456
457 vector<string> bases;
458 for (string base : rawbases)
459 {
460 if (base.empty())
461 continue;
462
463 base = canonicalise_file_separator(base);
464
465 if (base[base.length() - 1] != FILE_SEPARATOR)
466 base += FILE_SEPARATOR;
467
468 for (unsigned p = 0; p < ARRAYSZ(prefixes); ++p)
469 bases.push_back(base + prefixes[p]);
470 }
471
472 return bases;
473 }
474
validate_basedirs()475 void validate_basedirs()
476 {
477 // TODO: could use this to pick a single data directory?
478 vector<string> bases(_get_base_dirs());
479 bool found = false;
480
481 // there are a few others, but this should be enough to minimally run something
482 const vector<string> data_subfolders =
483 {
484 "clua",
485 "database",
486 "defaults",
487 "des",
488 "descript",
489 "dlua"
490 #ifdef USE_TILE_LOCAL
491 , "tiles"
492 #endif
493 };
494
495 for (const string &d : bases)
496 {
497 if (dir_exists(d))
498 {
499 bool everything = true;
500 bool something = false;
501 for (auto subdir : data_subfolders)
502 {
503 if (dir_exists(d + subdir))
504 something = true;
505 else
506 everything = false;
507 }
508 if (everything)
509 {
510 mprf(MSGCH_PLAIN, "Data directory '%s' found.", d.c_str());
511 found = true;
512 }
513 else if (something)
514 {
515 // give an error for this case because this incomplete data
516 // directory will be checked before others, possibly leading
517 // to a weird mix of data files.
518 if (!found)
519 {
520 mprf(MSGCH_ERROR,
521 "Incomplete or corrupted data directory '%s'",
522 d.c_str());
523 }
524 }
525 }
526 }
527
528 // can't proceed if nothing complete was found.
529 if (!found)
530 {
531 string err = "Missing DCSS data directory; tried: \n";
532 err += comma_separated_line(bases.begin(), bases.end());
533
534 end(1, false, "%s", err.c_str());
535 }
536 }
537
datafile_path(string basename,bool croak_on_fail,bool test_base_path,bool (* thing_exists)(const string &))538 string datafile_path(string basename, bool croak_on_fail, bool test_base_path,
539 bool (*thing_exists)(const string&))
540 {
541 basename = canonicalise_file_separator(basename);
542
543 if (test_base_path && thing_exists(basename))
544 return basename;
545
546 for (const string &basedir : _get_base_dirs())
547 {
548 string name = basedir + basename;
549 #ifdef __ANDROID__
550 __android_log_print(ANDROID_LOG_INFO,"Crawl","Looking for %s as '%s'",basename.c_str(),name.c_str());
551 #endif
552 if (thing_exists(name))
553 return name;
554 }
555
556 // Die horribly.
557 if (croak_on_fail)
558 {
559 end(1, false, "Cannot find data file '%s' anywhere, aborting\n",
560 basename.c_str());
561 }
562
563 return "";
564 }
565
566 // Checks if directory 'dir' exists and tries to create it if it
567 // doesn't exist, modifying 'dir' to its canonical form.
568 //
569 // If given an empty 'dir', returns true without modifying 'dir' or
570 // performing any other checks.
571 //
572 // Otherwise, returns true if the directory already exists or was just
573 // created. 'dir' will be modified to a canonical representation,
574 // guaranteed to have the file separator appended to it, and with any
575 // / and \ separators replaced with the one true FILE_SEPARATOR.
576 //
check_mkdir(const string & whatdir,string * dir,bool silent)577 bool check_mkdir(const string &whatdir, string *dir, bool silent)
578 {
579 if (dir->empty())
580 return true;
581
582 *dir = canonicalise_file_separator(*dir);
583
584 // Suffix the separator if necessary
585 if ((*dir)[dir->length() - 1] != FILE_SEPARATOR)
586 *dir += FILE_SEPARATOR;
587
588 if (!dir_exists(*dir) && !_create_dirs(*dir))
589 {
590 if (!silent)
591 {
592 #ifdef __ANDROID__
593 __android_log_print(ANDROID_LOG_INFO, "Crawl",
594 "%s \"%s\" does not exist and I can't create it.",
595 whatdir.c_str(), dir->c_str());
596 #endif
597 fprintf(stderr, "%s \"%s\" does not exist "
598 "and I can't create it.\n",
599 whatdir.c_str(), dir->c_str());
600 }
601 return false;
602 }
603
604 return true;
605 }
606
607 // Get the directory that contains save files for the current game
608 // type. This will not be the same as get_base_savedir() for game
609 // types such as Sprint.
_get_savefile_directory()610 static string _get_savefile_directory()
611 {
612 string dir = catpath(Options.save_dir, crawl_state.game_savedir_path());
613 check_mkdir("Save directory", &dir, false);
614 if (dir.empty())
615 dir = ".";
616 return dir;
617 }
618
619
620 /**
621 * Location of legacy ghost files. (The save directory.)
622 *
623 * @return The path to the directory for old ghost files.
624 */
_get_old_bonefile_directory()625 static string _get_old_bonefile_directory()
626 {
627 string dir = catpath(Options.shared_dir, crawl_state.game_savedir_path());
628 check_mkdir("Bones directory", &dir, false);
629 if (dir.empty())
630 dir = ".";
631 return dir;
632 }
633
634 /**
635 * Location of ghost files.
636 *
637 * @return The path to the directory for ghost files.
638 */
_get_bonefile_directory()639 static string _get_bonefile_directory()
640 {
641 string dir = catpath(Options.shared_dir, crawl_state.game_savedir_path());
642 dir = catpath(dir, "bones");
643 check_mkdir("Bones directory", &dir, false);
644 if (dir.empty())
645 dir = ".";
646 return dir;
647 }
648
649 // Returns a subdirectory of the current savefile directory as returned by
650 // _get_savefile_directory.
_get_savedir_path(const string & shortpath)651 static string _get_savedir_path(const string &shortpath)
652 {
653 return canonicalise_file_separator(
654 catpath(_get_savefile_directory(), shortpath));
655 }
656
657 // Returns a subdirectory of the base save directory that contains all saves
658 // and cache directories. Save files for game type != GAME_TYPE_NORMAL may
659 // be found in a subdirectory of this dir. Use _get_savefile_directory() if
660 // you want the directory that contains save games for the current game
661 // type.
_get_base_savedir_path(const string & subpath="")662 static string _get_base_savedir_path(const string &subpath = "")
663 {
664 return canonicalise_file_separator(catpath(Options.save_dir, subpath));
665 }
666
667 // Given a simple (relative) path, returns the path relative to the
668 // base save directory and a subdirectory named with the game version.
669 // This is useful when writing cache files and similar output that
670 // should not be shared between different game versions.
savedir_versioned_path(const string & shortpath)671 string savedir_versioned_path(const string &shortpath)
672 {
673 #ifdef VERSIONED_CACHE_DIR
674 const string versioned_dir =
675 _get_base_savedir_path(string("cache.") + Version::Long);
676 #else
677 const string versioned_dir = _get_base_savedir_path();
678 #endif
679 return catpath(versioned_dir, shortpath);
680 }
681
682 #ifdef USE_TILE
683 #define LINEMAX 1024
_readln(chunk_reader & rd,char * buf)684 static bool _readln(chunk_reader &rd, char *buf)
685 {
686 for (int space = LINEMAX - 1; space; space--)
687 {
688 if (!rd.read(buf, 1))
689 return false;
690 if (*buf == '\n')
691 break;
692 buf++;
693 }
694 *buf = 0;
695 return true;
696 }
697
_fill_player_doll(player_save_info & p,package * save)698 static void _fill_player_doll(player_save_info &p, package *save)
699 {
700 dolls_data equip_doll;
701 for (unsigned int j = 0; j < TILEP_PART_MAX; ++j)
702 equip_doll.parts[j] = TILEP_SHOW_EQUIP;
703
704 equip_doll.parts[TILEP_PART_BASE]
705 = tilep_species_to_base_tile(p.species, p.experience_level);
706
707 bool success = false;
708
709 chunk_reader fdoll(save, "tdl");
710 {
711 char fbuf[LINEMAX];
712 if (_readln(fdoll,fbuf))
713 {
714 tilep_scan_parts(fbuf, equip_doll, p.species, p.experience_level);
715 tilep_race_default(p.species, p.experience_level, &equip_doll);
716 success = true;
717 }
718 }
719
720 if (!success) // Use default doll instead.
721 {
722 job_type job = get_job_by_name(p.class_name.c_str());
723 if (job == JOB_UNKNOWN)
724 job = JOB_FIGHTER;
725
726 tilep_job_default(job, &equip_doll);
727 }
728 p.doll = equip_doll;
729 }
730 #endif
731
732 /*
733 * Returns a list of the names of characters that are already saved for the
734 * current user.
735 */
736
_find_saved_characters()737 static vector<player_save_info> _find_saved_characters()
738 {
739 vector<player_save_info> chars;
740
741 if (Options.no_save)
742 return chars;
743
744 #ifndef DISABLE_SAVEGAME_LISTS
745 string searchpath = _get_savefile_directory();
746
747 if (searchpath.empty())
748 searchpath = ".";
749
750 for (const string &filename : get_dir_files_sorted(searchpath))
751 {
752 if (is_save_file_name(filename))
753 {
754 try
755 {
756 package save(_get_savedir_path(filename).c_str(), false);
757 player_save_info p = _read_character_info(&save);
758 if (!p.name.empty())
759 {
760 p.filename = filename;
761 #ifdef USE_TILE
762 if (Options.tile_menu_icons && save.has_chunk("tdl"))
763 _fill_player_doll(p, &save);
764 #endif
765 chars.push_back(p);
766 }
767 }
768 catch (ext_fail_exception &E)
769 {
770 dprf("%s: %s", filename.c_str(), E.what());
771 }
772 catch (game_ended_condition &E) // another process is using the save
773 {
774 if (E.exit_reason != game_exit::abort)
775 throw;
776 }
777 }
778 }
779
780 sort(chars.begin(), chars.end());
781 #endif // !DISABLE_SAVEGAME_LISTS
782 return chars;
783 }
784
find_all_saved_characters()785 vector<player_save_info> find_all_saved_characters()
786 {
787 set<string> dirs;
788 vector<player_save_info> saved_characters;
789 for (int i = 0; i < NUM_GAME_TYPE; ++i)
790 {
791 unwind_var<game_type> gt(
792 crawl_state.type,
793 static_cast<game_type>(i));
794
795 const string savedir = _get_savefile_directory();
796 if (dirs.count(savedir))
797 continue;
798
799 dirs.insert(savedir);
800
801 vector<player_save_info> chars_in_dir = _find_saved_characters();
802 saved_characters.insert(saved_characters.end(),
803 chars_in_dir.begin(),
804 chars_in_dir.end());
805 }
806 return saved_characters;
807 }
808
save_exists(const string & filename)809 bool save_exists(const string& filename)
810 {
811 return file_exists(_get_savefile_directory() + filename);
812 }
813
get_savedir_filename(const string & name)814 string get_savedir_filename(const string &name)
815 {
816 return _get_savefile_directory() + get_save_filename(name);
817 }
818
819 #define MAX_FILENAME_LENGTH 250
get_save_filename(const string & name)820 string get_save_filename(const string &name)
821 {
822 return chop_string(strip_filename_unsafe_chars(name), MAX_FILENAME_LENGTH,
823 false) + SAVE_SUFFIX;
824 }
825
_game_type_has_saves(const game_type g)826 static bool _game_type_has_saves(const game_type g)
827 {
828 // TODO: this may be useful elsewhere too?
829 switch (g)
830 {
831 case GAME_TYPE_ARENA:
832 case GAME_TYPE_HIGH_SCORES:
833 case GAME_TYPE_INSTRUCTIONS:
834 case GAME_TYPE_UNSPECIFIED:
835 return false;
836 default:
837 return true;
838 }
839 }
840
_game_type_removed(const game_type g)841 static bool _game_type_removed(const game_type g)
842 {
843 return g == GAME_TYPE_ZOTDEF;
844 }
845
_append_save_info(JsonWrapper & json,const char * filename,game_type intended_gt=NUM_GAME_TYPE)846 static bool _append_save_info(JsonWrapper &json, const char *filename,
847 game_type intended_gt=NUM_GAME_TYPE)
848 {
849 if (!file_exists(filename))
850 return false;
851 try
852 {
853 package save(filename, false);
854 player_save_info p = _read_character_info(&save);
855
856 // TODO: some json for the non-loadable case? I think this comes up
857 // for save compat mismatches so shouldn't be relevant for webtiles
858 // except in case of bugs...
859 if (p.name.empty() || !p.save_loadable)
860 return false;
861
862 auto *game_json = json_mkobject();
863
864 // TODO: version info might be useful?
865 json_append_member(game_json, "loadable", json_mkbool(true));
866 json_append_member(game_json, "name", json_mkstring(p.name));
867 json_append_member(game_json, "game_type",
868 json_mkstring(gametype_to_str(p.saved_game_type)));
869 json_append_member(game_json, "short_desc",
870 json_mkstring(p.short_desc(false)));
871 json_append_member(game_json, "really_short_desc",
872 json_mkstring(p.really_short_desc()));
873
874 // for the case where we are querying just one file, we don't have
875 // info on what the save slot is (if any -- could be an arbitrary
876 // file) so just use the file's value. This is really only here so
877 // that there is a consistent format to the json.
878 json_append_member(json.node, intended_gt == NUM_GAME_TYPE
879 ? gametype_to_str(p.saved_game_type).c_str()
880 : gametype_to_str(intended_gt).c_str(),
881 game_json);
882 return true;
883 }
884 catch (game_ended_condition &E) // another process is using the save
885 {
886 if (E.exit_reason != game_exit::abort)
887 end(1); // something has gone fairly wrong in this case
888
889 auto *game_json = json_mkobject();
890
891 json_append_member(game_json, "loadable", json_mkbool(false));
892 json_append_member(game_json, "name", json_mkstring(""));
893 json_append_member(game_json, "game_type", json_mkstring(""));
894 json_append_member(game_json, "short_desc",
895 json_mkstring("Save in use"));
896 json_append_member(game_json, "really_short_desc",
897 json_mkstring(""));
898
899 // May give "none" in the case of querying a save file by name
900 // that is currently in use.
901 json_append_member(json.node, gametype_to_str(intended_gt).c_str(),
902 game_json);
903 return true;
904 }
905 }
906
_append_player_save_info(JsonWrapper & json,const char * name,game_type gt)907 static bool _append_player_save_info(JsonWrapper &json, const char *name, game_type gt)
908 {
909 // requires init file to have been read, otherwise the correct savedir
910 // paths may not have been initialized
911 unwind_var<game_type> temp_gt(crawl_state.type, gt);
912 return _append_save_info(json, get_savedir_filename(name).c_str(), gt);
913 }
914
915 /**
916 * Print information about save files associated with `name` in JSON format.
917 * The JSON format is a map (JSON Object) from (saveable) game types to save
918 * information.
919 *
920 * If `name` is a filename, the map will have one element in it for just that
921 * file; if it is a player name, the map will have one entry for every
922 * game type that has a save. (Keep in mind that most game types share a single
923 * save slot.)
924 *
925 * If a save file is currently in use by some other process, it will get
926 * `loadable': false, as well as most other info missing. If a save is queried
927 * by filename and is in use, it will additionally be mapped from game type
928 * `none`.
929 */
print_save_json(const char * name)930 NORETURN void print_save_json(const char *name)
931 {
932 // TODO: The overall call is quite heavy. Can the overhead to get to this
933 // point be simplified at all? On my local machine it's about 80-100ms per
934 // call if things go well.
935 try
936 {
937 JsonWrapper json(json_mkobject());
938 // Check for the exact filename first, then go by char name.
939 // TODO: based on other CLOs, but maybe these shouldn't be collapsed
940 // into a single option?
941 if (file_exists(name))
942 {
943 if (!_append_save_info(json, name))
944 {
945 fprintf(stderr, "Could not load '%s'\n", name);
946 end(1);
947 }
948 }
949 else
950 {
951 // ugh. This is a heavy-handed way to ensure that the savedir
952 // option is set correctly on the first parse_args pass.
953 // TODO: test on dgl...
954 Options.reset_options();
955
956 // treat `name` as a character name. Prints an empty json dict
957 // if this is wrong (or if the character has no saves).
958 // TODO: this code (and much other code) could be a lot smarter
959 // about shared save slots. (Everything but sprint shares just
960 // one slot...)
961 for (int i = 0; i < NUM_GAME_TYPE; ++i)
962 {
963 auto gt = static_cast<game_type>(i);
964 if (_game_type_has_saves(gt) && !_game_type_removed(gt))
965 _append_player_save_info(json, name, gt);
966 }
967 }
968
969 fprintf(stdout, "%s", json.to_string().c_str());
970 end(0);
971 }
972 catch (ext_fail_exception &fe)
973 {
974 fprintf(stderr, "Error: %s\n", fe.what());
975 end(1);
976 }
977 }
978
get_prefs_filename()979 string get_prefs_filename()
980 {
981 #ifdef DGL_STARTUP_PREFS_BY_NAME
982 return _get_savefile_directory() + "start-"
983 + strip_filename_unsafe_chars(Options.game.name) + "-ns.prf";
984 #else
985 return _get_savefile_directory() + "start-ns.prf";
986 #endif
987 }
988
write_ghost_version(writer & outf)989 void write_ghost_version(writer &outf)
990 {
991 // this may be distinct from the current save version
992 write_save_version(outf, save_version::current_bones());
993
994 // extended_version just pads the version out to four 32-bit words.
995 // This makes the bones file compatible with Hearse with no extra
996 // munging needed.
997
998 // Use a single signature 16-bit word to indicate that this is
999 // Stone Soup and to disambiguate this (unmunged) bones file
1000 // from the munged bones files offered by the old Crawl-aware
1001 // hearse.pl. Crawl-aware hearse.pl will prefix the bones file
1002 // with the first 16-bits of the Crawl version, and the following
1003 // 7 16-bit words set to 0.
1004 marshallShort(outf, GHOST_SIGNATURE);
1005
1006 // Write the three remaining 32-bit words of padding.
1007 for (int i = 0; i < 3; ++i)
1008 marshallInt(outf, 0);
1009 }
1010
_write_tagged_chunk(const string & chunkname,tag_type tag)1011 static void _write_tagged_chunk(const string &chunkname, tag_type tag)
1012 {
1013 writer outf(you.save, chunkname);
1014
1015 write_save_version(outf, save_version::current());
1016 tag_write(tag, outf);
1017 }
1018
_get_dest_stair_type(dungeon_feature_type stair_taken,bool & find_first)1019 static int _get_dest_stair_type(dungeon_feature_type stair_taken,
1020 bool &find_first)
1021 {
1022 // Order is important here.
1023 if (stair_taken == DNGN_EXIT_ABYSS)
1024 {
1025 find_first = false;
1026 return DNGN_EXIT_DUNGEON;
1027 }
1028
1029 if (stair_taken == DNGN_EXIT_HELL)
1030 return DNGN_ENTER_HELL;
1031
1032 if (stair_taken == DNGN_ENTER_HELL)
1033 return DNGN_EXIT_HELL;
1034
1035 if (player_in_hell() && feat_is_stone_stair_down(stair_taken))
1036 {
1037 find_first = false;
1038 return DNGN_ENTER_HELL;
1039 }
1040
1041 if (feat_is_stone_stair(stair_taken))
1042 {
1043 switch (stair_taken)
1044 {
1045 case DNGN_STONE_STAIRS_UP_I: return DNGN_STONE_STAIRS_DOWN_I;
1046 case DNGN_STONE_STAIRS_UP_II: return DNGN_STONE_STAIRS_DOWN_II;
1047 case DNGN_STONE_STAIRS_UP_III: return DNGN_STONE_STAIRS_DOWN_III;
1048
1049 case DNGN_STONE_STAIRS_DOWN_I: return DNGN_STONE_STAIRS_UP_I;
1050 case DNGN_STONE_STAIRS_DOWN_II: return DNGN_STONE_STAIRS_UP_II;
1051 case DNGN_STONE_STAIRS_DOWN_III: return DNGN_STONE_STAIRS_UP_III;
1052
1053 default: die("unknown stone stair %d", stair_taken);
1054 }
1055 }
1056
1057 if (feat_is_escape_hatch(stair_taken) || stair_taken == DNGN_TRAP_SHAFT)
1058 return stair_taken;
1059
1060 if (stair_taken == DNGN_ENTER_DIS
1061 || stair_taken == DNGN_ENTER_GEHENNA
1062 || stair_taken == DNGN_ENTER_COCYTUS
1063 || stair_taken == DNGN_ENTER_TARTARUS)
1064 {
1065 return player_in_hell() ? DNGN_ENTER_HELL : stair_taken;
1066 }
1067
1068 if (feat_is_branch_exit(stair_taken))
1069 {
1070 for (branch_iterator it; it; ++it)
1071 if (it->exit_stairs == stair_taken)
1072 return it->entry_stairs;
1073 die("entrance corresponding to exit %d not found", stair_taken);
1074 }
1075
1076 if (feat_is_branch_entrance(stair_taken))
1077 {
1078 for (branch_iterator it; it; ++it)
1079 if (it->entry_stairs == stair_taken)
1080 return it->exit_stairs;
1081 die("return corresponding to entry %d not found", stair_taken);
1082 }
1083 #if TAG_MAJOR_VERSION == 34
1084 if (stair_taken == DNGN_ENTER_LABYRINTH)
1085 {
1086 // dgn_find_nearby_stair uses special logic for labyrinths.
1087 return DNGN_ENTER_LABYRINTH;
1088 }
1089 #endif
1090
1091 if (feat_is_portal_entrance(stair_taken))
1092 return DNGN_STONE_ARCH;
1093
1094 // Note: stair_taken can equal things like DNGN_FLOOR
1095 // Just find a nice empty square.
1096 find_first = false;
1097 return DNGN_FLOOR;
1098 }
1099
_place_player_on_stair(int stair_taken,const coord_def & dest_pos,const string & hatch_name)1100 static void _place_player_on_stair(int stair_taken, const coord_def& dest_pos,
1101 const string &hatch_name)
1102
1103 {
1104 bool find_first = true;
1105 dungeon_feature_type stair_type = static_cast<dungeon_feature_type>(
1106 _get_dest_stair_type(static_cast<dungeon_feature_type>(stair_taken),
1107 find_first));
1108
1109 you.moveto(dgn_find_nearby_stair(stair_type, dest_pos, find_first,
1110 hatch_name));
1111 }
1112
_clear_env_map()1113 static void _clear_env_map()
1114 {
1115 env.map_knowledge.init(map_cell());
1116 env.map_forgotten.reset();
1117 }
1118
_grab_follower_at(const coord_def & pos,bool can_follow)1119 static bool _grab_follower_at(const coord_def &pos, bool can_follow)
1120 {
1121 if (pos == you.pos())
1122 return false;
1123
1124 monster* fol = monster_at(pos);
1125 if (!fol || !fol->alive() || fol->incapacitated())
1126 return false;
1127
1128 // only H's ancestors can follow into portals & similar.
1129 if (!can_follow && !mons_is_hepliaklqana_ancestor(fol->type))
1130 return false;
1131
1132 // The monster has to already be tagged in order to follow.
1133 if (!testbits(fol->flags, MF_TAKING_STAIRS))
1134 return false;
1135
1136 // If a monster that can't use stairs was marked as a follower,
1137 // it's because it's an ally and there might be another ally
1138 // behind it that might want to push through.
1139 // This means we don't actually send it on transit, but we do
1140 // return true, so adjacent real followers are handled correctly. (jpeg)
1141 if (!mons_can_use_stairs(*fol))
1142 return true;
1143
1144 level_id dest = level_id::current();
1145
1146 dprf("%s is following to %s.", fol->name(DESC_THE, true).c_str(),
1147 dest.describe().c_str());
1148 bool could_see = you.can_see(*fol);
1149 fol->set_transit(dest);
1150 fol->destroy_inventory();
1151 monster_cleanup(fol);
1152 if (could_see)
1153 view_update_at(pos);
1154 return true;
1155 }
1156
_grab_followers()1157 static void _grab_followers()
1158 {
1159 const bool can_follow = branch_allows_followers(you.where_are_you);
1160
1161 int non_stair_using_allies = 0;
1162 int non_stair_using_summons = 0;
1163
1164 monster* dowan = nullptr;
1165 monster* duvessa = nullptr;
1166
1167 // Handle some hacky cases
1168 for (adjacent_iterator ai(you.pos()); ai; ++ai)
1169 {
1170 monster* fol = monster_at(*ai);
1171 if (fol == nullptr)
1172 continue;
1173
1174 if (mons_is_mons_class(fol, MONS_DUVESSA) && fol->alive())
1175 duvessa = fol;
1176
1177 if (mons_is_mons_class(fol, MONS_DOWAN) && fol->alive())
1178 dowan = fol;
1179
1180 if (fol->wont_attack() && !mons_can_use_stairs(*fol))
1181 {
1182 non_stair_using_allies++;
1183 // If the class can normally use stairs it
1184 // must have been a summon
1185 if (mons_class_can_use_stairs(fol->type))
1186 non_stair_using_summons++;
1187 }
1188 }
1189
1190 // Deal with Dowan and Duvessa here.
1191 if (dowan && duvessa)
1192 {
1193 if (!testbits(dowan->flags, MF_TAKING_STAIRS)
1194 || !testbits(duvessa->flags, MF_TAKING_STAIRS))
1195 {
1196 dowan->flags &= ~MF_TAKING_STAIRS;
1197 duvessa->flags &= ~MF_TAKING_STAIRS;
1198 }
1199 }
1200 else if (dowan && !duvessa)
1201 {
1202 if (!dowan->props.exists("can_climb"))
1203 dowan->flags &= ~MF_TAKING_STAIRS;
1204 }
1205 else if (!dowan && duvessa)
1206 {
1207 if (!duvessa->props.exists("can_climb"))
1208 duvessa->flags &= ~MF_TAKING_STAIRS;
1209 }
1210
1211 if (can_follow && non_stair_using_allies > 0)
1212 {
1213 // Summons won't follow and will time out.
1214 if (non_stair_using_summons > 0)
1215 {
1216 mprf("Your summoned %s left behind.",
1217 non_stair_using_allies > 1 ? "allies are" : "ally is");
1218 }
1219 else
1220 {
1221 // Permanent undead are left behind but stay.
1222 mprf("Your mindless thrall%s behind.",
1223 non_stair_using_allies > 1 ? "s stay" : " stays");
1224 }
1225 }
1226
1227 bool visited[GXM][GYM];
1228 memset(&visited, 0, sizeof(visited));
1229
1230 vector<coord_def> places[2] = { { you.pos() }, {} };
1231 int place_set = 0;
1232 while (!places[place_set].empty())
1233 {
1234 for (const coord_def &p : places[place_set])
1235 {
1236 for (adjacent_iterator ai(p); ai; ++ai)
1237 {
1238 if (visited[ai->x][ai->y])
1239 continue;
1240
1241 visited[ai->x][ai->y] = true;
1242 if (_grab_follower_at(*ai, can_follow))
1243 places[!place_set].push_back(*ai);
1244 }
1245 }
1246 places[place_set].clear();
1247 place_set = !place_set;
1248 }
1249
1250 // Clear flags of monsters that didn't follow.
1251 for (auto &mons : menv_real)
1252 {
1253 if (!mons.alive())
1254 continue;
1255 if (mons.type == MONS_BATTLESPHERE)
1256 end_battlesphere(&mons, false);
1257 if (mons.type == MONS_SPECTRAL_WEAPON)
1258 end_spectral_weapon(&mons, false);
1259 mons.flags &= ~MF_TAKING_STAIRS;
1260 }
1261 }
1262
_do_lost_monsters()1263 static void _do_lost_monsters()
1264 {
1265 // Uniques can be considered wandering Pan just like you, so they're not
1266 // gone forever. The likes of Cerebov won't be generated elsewhere, but
1267 // there's no need to special-case that.
1268 if (player_in_branch(BRANCH_PANDEMONIUM))
1269 for (monster_iterator mi; mi; ++mi)
1270 if (mons_is_unique(mi->type) && !(mi->flags & MF_TAKING_STAIRS))
1271 you.unique_creatures.set(mi->type, false);
1272 }
1273
1274 // Should be called after _grab_followers(), so that items carried by
1275 // followers won't be considered lost.
_do_lost_items()1276 static void _do_lost_items()
1277 {
1278 for (const auto &item : env.item)
1279 if (item.defined() && item.pos != ITEM_IN_INVENTORY)
1280 item_was_lost(item);
1281 }
1282
1283 /**
1284 * Perform cleanup when leaving a level.
1285 *
1286 * If returning to the previous level on the level stack (e.g. when leaving the
1287 * abyss), pop it off the stack. Delete non-permanent levels. Also check to be
1288 * sure no loops have formed in the level stack, and, for Fedhasites, rots any
1289 * corpses left behind.
1290 *
1291 * @param stair_taken The means used to leave the last level.
1292 * @param old_level The ID of the previous level.
1293 * @param return_pos Set to the level entrance, if popping a stack level.
1294 * @return Whether the level was popped onto the stack.
1295 */
_leave_level(dungeon_feature_type stair_taken,const level_id & old_level,coord_def * return_pos)1296 static bool _leave_level(dungeon_feature_type stair_taken,
1297 const level_id& old_level, coord_def *return_pos)
1298 {
1299 bool popped = false;
1300
1301 if (!you.level_stack.empty()
1302 && you.level_stack.back().id == level_id::current())
1303 {
1304 *return_pos = you.level_stack.back().pos;
1305 you.level_stack.pop_back();
1306 env.level_state |= LSTATE_DELETED;
1307 popped = true;
1308 }
1309 else if (stair_taken == DNGN_TRANSIT_PANDEMONIUM
1310 || stair_taken == DNGN_EXIT_THROUGH_ABYSS
1311 || stair_taken == DNGN_STONE_STAIRS_DOWN_I
1312 && old_level.branch == BRANCH_ZIGGURAT
1313 || old_level.branch == BRANCH_ABYSS)
1314 {
1315 env.level_state |= LSTATE_DELETED;
1316 }
1317
1318 if (is_level_on_stack(level_id::current())
1319 && !player_in_branch(BRANCH_ABYSS))
1320 {
1321 vector<string> stack;
1322 for (level_pos lvl : you.level_stack)
1323 stack.push_back(lvl.id.describe());
1324 if (you.wizard)
1325 {
1326 // warn about breakage so testers know it's an abnormal situation.
1327 mprf(MSGCH_ERROR, "Error: you smelly wizard, how dare you enter "
1328 "the same level (%s) twice! It will be trampled upon return.\n"
1329 "The stack has: %s.",
1330 level_id::current().describe().c_str(),
1331 comma_separated_line(stack.begin(), stack.end(),
1332 ", ", ", ").c_str());
1333 }
1334 else
1335 {
1336 die("Attempt to enter a portal (%s) twice; stack: %s",
1337 level_id::current().describe().c_str(),
1338 comma_separated_line(stack.begin(), stack.end(),
1339 ", ", ", ").c_str());
1340 }
1341 }
1342
1343 return popped;
1344 }
1345
1346 /**
1347 * Move the player to the appropriate entrance location in a level.
1348 *
1349 * @param stair_taken The means used to leave the last level.
1350 * @param return_pos The location of the entrance portal, if applicable.
1351 * @param dest_pos The player's location on the last level.
1352 */
_place_player(dungeon_feature_type stair_taken,const coord_def & return_pos,const coord_def & dest_pos,const string & hatch_name)1353 static void _place_player(dungeon_feature_type stair_taken,
1354 const coord_def &return_pos,
1355 const coord_def &dest_pos, const string &hatch_name)
1356 {
1357 if (player_in_branch(BRANCH_ABYSS))
1358 you.moveto(ABYSS_CENTRE);
1359 else if (!return_pos.origin())
1360 you.moveto(return_pos);
1361 else
1362 _place_player_on_stair(stair_taken, dest_pos, hatch_name);
1363
1364 // Don't return the player into walls, deep water, or a trap.
1365 for (distance_iterator di(you.pos(), true, false); di; ++di)
1366 if (you.is_habitable_feat(env.grid(*di))
1367 && !is_feat_dangerous(env.grid(*di), true)
1368 && !feat_is_trap(env.grid(*di)))
1369 {
1370 if (you.pos() != *di)
1371 you.moveto(*di);
1372 break;
1373 }
1374
1375 // This should fix the "monster occurring under the player" bug.
1376 monster *mon = monster_at(you.pos());
1377 if (mon && !fedhas_passthrough(mon))
1378 {
1379 for (distance_iterator di(you.pos()); di; ++di)
1380 {
1381 if (!monster_at(*di) && mon->is_habitable(*di))
1382 {
1383 mon->move_to_pos(*di);
1384 return;
1385 }
1386 }
1387
1388 dprf("%s under player and can't be moved anywhere; killing",
1389 mon->name(DESC_PLAIN).c_str());
1390 monster_die(*mon, KILL_DISMISSED, NON_MONSTER);
1391 // XXX: do we need special handling for uniques...?
1392 }
1393 }
1394
1395 // Update the trackers after the player changed level.
trackers_init_new_level()1396 void trackers_init_new_level()
1397 {
1398 travel_init_new_level();
1399 }
1400
_get_hatch_name()1401 static string _get_hatch_name()
1402 {
1403 vector <map_marker *> markers;
1404 markers = find_markers_by_prop(HATCH_NAME_PROP);
1405 for (auto m : markers)
1406 {
1407 if (m->pos == you.pos())
1408 {
1409 string name = m->property(HATCH_NAME_PROP);
1410 ASSERT(!name.empty());
1411 return name;
1412 }
1413 }
1414 return "";
1415 }
1416
1417 static const string VISITED_LEVELS_KEY = "visited_levels";
1418
1419 #if TAG_MAJOR_VERSION == 34
1420 // n.b. these functions are in files.cc largely because this is where the fixup
1421 // needs to happen.
1422 // before pregeneration, whether the level had been visited was synonymous with
1423 // whether it had been visited, but after, we need to track this information
1424 // more directly. It is also inferrable from turns_on_level, but you can't get
1425 // at that very easily without fully loading the level.
1426 // no need for a minor version here, though there will be a brief window of
1427 // offline pregen games that this doesn't handle right -- they will get things
1428 // like broken runelock. (In principle this fixup could be done by loading
1429 // each level and checking turns, but it's not worth the trouble for these few
1430 // games.)
_fixup_visited_from_package()1431 static void _fixup_visited_from_package()
1432 {
1433 // for games started later than this fixup, this prop is initialized in
1434 // player::player
1435 CrawlHashTable &visited = you.props[VISITED_LEVELS_KEY].get_table();
1436 if (visited.size()) // only 0 for upgrades, or before entering D:1
1437 return;
1438 vector<level_id> levels = all_dungeon_ids();
1439 for (const level_id &lid : levels)
1440 if (is_existing_level(lid))
1441 visited[lid.describe()] = true;
1442 }
1443 #endif
1444
set_level_visited(const level_id & level)1445 void player::set_level_visited(const level_id &level)
1446 {
1447 auto &visited = props[VISITED_LEVELS_KEY].get_table();
1448 visited[level.describe()] = true;
1449 }
1450
1451 /**
1452 * Has the player visited the level currently stored in the save under the id
1453 * `level`, if there is one? Returns false if there isn't one. This stores
1454 * *token level* visited state, not type-level -- it does not answer questions
1455 * like, e.g. has the player ever visited a trove? For that, see place_info.
1456 * This distinction matters mainly for portal branches, especially ones that can
1457 * be revisited, e.g. Pan levels and zigs.
1458 */
level_visited(const level_id & level)1459 bool player::level_visited(const level_id &level)
1460 {
1461 // `is_existing_level` is not reliable after the game end, because the
1462 // save no longer exists, so we ignore it for printing morgues
1463 if (!is_existing_level(level) && you.save)
1464 return false;
1465 const auto &visited = props[VISITED_LEVELS_KEY].get_table();
1466 return visited.exists(level.describe());
1467 }
1468
_generic_level_reset()1469 static void _generic_level_reset()
1470 {
1471 // TODO: can more be pulled into here?
1472
1473 you.prev_targ = MHITNOT;
1474 you.prev_grd_targ.reset();
1475
1476 // Lose all listeners.
1477 dungeon_events.clear();
1478 clear_travel_trail();
1479 }
1480
1481
1482 // used to resolve generation order for cases where a single level has multiple
1483 // portals. This currently should only include portals that can appear at most
1484 // once.
1485 static const vector<branch_type> portal_generation_order =
1486 {
1487 BRANCH_SEWER,
1488 BRANCH_OSSUARY,
1489 BRANCH_ICE_CAVE,
1490 BRANCH_VOLCANO,
1491 BRANCH_BAILEY,
1492 BRANCH_GAUNTLET,
1493 #if TAG_MAJOR_VERSION == 34
1494 BRANCH_LABYRINTH,
1495 #endif
1496 // do not pregenerate bazaar (TODO: this is non-ideal)
1497 // do not pregenerate trove
1498 BRANCH_WIZLAB,
1499 BRANCH_DESOLATION,
1500 };
1501
update_portal_entrances()1502 void update_portal_entrances()
1503 {
1504 unordered_set<branch_type, std::hash<int>> seen_portals;
1505 auto const cur_level = level_id::current();
1506 // add any portals not currently registered
1507 for (rectangle_iterator ri(0); ri; ++ri)
1508 {
1509 dungeon_feature_type feat = env.grid(*ri);
1510 // excludes pan, hell, abyss.
1511 if (feat_is_portal_entrance(feat) && !feature_mimic_at(*ri))
1512 {
1513 level_id whither = stair_destination(feat, "", false);
1514 if (whither.branch == BRANCH_ZIGGURAT // not (quite) pregenerated
1515 || whither.branch == BRANCH_TROVE // not pregenerated
1516 || whither.branch == BRANCH_BAZAAR) // multiple bazaars possible
1517 {
1518 continue; // handle these differently
1519 }
1520 dprf("Setting up entry for %s.", whither.describe().c_str());
1521 ASSERT(count(portal_generation_order.begin(),
1522 portal_generation_order.end(),
1523 whither.branch) == 1);
1524 if (brentry[whither.branch] != level_id())
1525 {
1526 mprf(MSGCH_ERROR, "Second portal entrance for %s!",
1527 whither.describe().c_str());
1528 }
1529 brentry[whither.branch] = cur_level;
1530 seen_portals.insert(whither.branch);
1531 }
1532 }
1533 // clean up any portals that aren't actually here -- comes up for wizmode
1534 // and test mode cases.
1535 for (auto b : portal_generation_order)
1536 if (!seen_portals.count(b) && brentry[b] == cur_level)
1537 brentry[b] = level_id();
1538 }
1539
reset_portal_entrances()1540 void reset_portal_entrances()
1541 {
1542 for (auto b : portal_generation_order)
1543 if (brentry[b].is_valid())
1544 brentry[b] = level_id();
1545 }
1546
1547 /**
1548 * Generate portals relative to the current level. This function does not clean
1549 * up builder state.
1550 *
1551 * @return the number of levels that generated, or -1 if the builder failed.
1552 */
_generate_portal_levels()1553 static int _generate_portal_levels()
1554 {
1555 // find any portals that branch off of the current level.
1556 level_id here = level_id::current();
1557 vector<level_id> to_build;
1558 for (auto b : portal_generation_order)
1559 if (brentry[b] == here)
1560 for (int i = 1; i <= brdepth[b]; i++)
1561 to_build.push_back(level_id(b, i));
1562
1563 int count = 0;
1564 for (auto lid : to_build)
1565 {
1566 if (!generate_level(lid))
1567 {
1568 // Should this crash? Reaching this case means that multiple
1569 // entrances to a non-reusable portal generated.
1570 if (you.save->has_chunk(lid.describe()))
1571 mprf(MSGCH_ERROR, "Portal %s already exists!", lid.describe().c_str());
1572 else
1573 return -1;
1574 }
1575 count++;
1576 }
1577 return count;
1578 }
1579
1580 /**
1581 * Ensure that the level given by `l` is generated. This does not do much in
1582 * the way of cleanup, and the caller must ensure the player ends up somewhere
1583 * sensible afterwards (this will not place the player, and will wipe out their
1584 * current location state if a level is built). Does not do anything if the
1585 * save already contains the relevant level.
1586 *
1587 * This function may generate multiple levels: any necessary portal levels
1588 * needed for `l` are built also.
1589 *
1590 * @param l the level to try to build.
1591 * @return whether the required builder steps succeeded, if there are any;
1592 * false means that either there was a builder error, or the level already
1593 * exists. This can be checked by looking at whether the save chunk exists.
1594 */
generate_level(const level_id & l)1595 bool generate_level(const level_id &l)
1596 {
1597 const string level_name = l.describe();
1598 if (you.save->has_chunk(level_name))
1599 return false;
1600
1601 unwind_var<int> you_depth(you.depth, l.depth);
1602 unwind_var<branch_type> you_branch(you.where_are_you, l.branch);
1603 unwind_var<coord_def> you_saved_position(you.position);
1604 you.position.reset();
1605
1606 // simulate a reasonable stair to enter the level with
1607 const dungeon_feature_type stair_taken =
1608 you.depth == 1
1609 ? (you.where_are_you == BRANCH_DUNGEON
1610 ? DNGN_UNSEEN
1611 : branches[you.where_are_you].entry_stairs)
1612 : DNGN_STONE_STAIRS_DOWN_I;
1613
1614 unwind_var<dungeon_feature_type> stair(you.transit_stair, stair_taken);
1615 // TODO how necessary is this?
1616 unwind_bool ylev(you.entering_level, true);
1617 // n.b. crawl_state.generating_level is handled in builder
1618
1619 _generic_level_reset();
1620 delete_all_clouds();
1621 los_changed(); // invalidate the los cache, which impacts monster placement
1622
1623 // initialize env for builder
1624 env.turns_on_level = -1;
1625 tile_init_default_flavour();
1626 tile_clear_flavour();
1627 tile_env.names.clear();
1628 _clear_env_map();
1629
1630 // finally -- everything is set up, call the builder.
1631 dprf("Generating new level for '%s'.", level_name.c_str());
1632 if (!builder(true))
1633 return false;
1634
1635 auto &vault_list = you.vault_list[level_id::current()];
1636 #ifdef DEBUG
1637 // places where a level can generate multiple times.
1638 // could add portals to this list for debugging purposes?
1639 if ( you.where_are_you == BRANCH_ABYSS
1640 || you.where_are_you == BRANCH_PANDEMONIUM
1641 || you.where_are_you == BRANCH_BAZAAR
1642 || you.where_are_you == BRANCH_ZIGGURAT)
1643 {
1644 vault_list.push_back("[gen]");
1645 }
1646 #endif
1647 const auto &level_vaults = level_vault_names();
1648 vault_list.insert(vault_list.end(),
1649 level_vaults.begin(), level_vaults.end());
1650
1651 // initialize env for a new level
1652 env.turns_on_level = 0;
1653 env.sanctuary_pos = coord_def(-1, -1);
1654 env.sanctuary_time = 0;
1655 env.markers.init_all(); // init first, activation happens when entering
1656 show_update_emphasis(); // Clear map knowledge stair emphasis in env.
1657 update_portal_entrances();
1658
1659 // save the level and associated env state
1660 save_level(level_id::current());
1661
1662 const string save_name = level_id::current().describe(); // should be same as level_name...
1663
1664 // generate levels for all portals that branch off from here
1665 int portal_level_count = _generate_portal_levels();
1666 if (portal_level_count == -1)
1667 return false; // something failed, bail immediately
1668 else if (portal_level_count > 0)
1669 {
1670 // if portals were generated, we're currently elsewhere. Switch back to
1671 // the level generated before the portals.
1672 ASSERT(you.save->has_chunk(save_name));
1673 dprf("Reloading new level '%s'.", save_name.c_str());
1674 _restore_tagged_chunk(you.save, save_name, TAG_LEVEL,
1675 "Level file is invalid.");
1676 }
1677 // Did the generation process actually manage to place the player? This is
1678 // a useful sanity check, and also is necessary for the initial loading
1679 // process.
1680 you.on_current_level = (you_depth.original_value() == l.depth
1681 && you_branch.original_value() == l.branch);
1682 return true;
1683 }
1684
1685 // bel's original proposal generated D to lair depth, then lair, then D
1686 // to orc depth, then orc, then the rest of D. I have simplified this to
1687 // just generate whole branches at a time -- I am not sure how much real
1688 // impact this has, though it does mean a pregen popup when the player enters
1689 // lair, typically.
1690 //
1691 // Portals are handled via `portal_generation_order`, and generated as-needed
1692 // with the level they appear on.
1693 //
1694 // We generate temple first so as to save the player a popup when they find it
1695 // in mid-dungeon; it's fully decided in game setup and shouldn't interact with
1696 // rng for other branches anyways.
1697 //
1698 // How should this relate to logical_branch_order etc?
1699 static const vector<branch_type> branch_generation_order =
1700 {
1701 BRANCH_TEMPLE,
1702 BRANCH_DUNGEON,
1703 BRANCH_LAIR,
1704 BRANCH_ORC,
1705 BRANCH_SPIDER,
1706 BRANCH_SNAKE,
1707 BRANCH_SHOALS,
1708 BRANCH_SWAMP,
1709 BRANCH_VAULTS,
1710 BRANCH_CRYPT,
1711 BRANCH_DEPTHS,
1712 BRANCH_VESTIBULE,
1713 BRANCH_ELF,
1714 BRANCH_ZOT,
1715 BRANCH_SLIME,
1716 BRANCH_TOMB,
1717 BRANCH_TARTARUS,
1718 BRANCH_COCYTUS,
1719 BRANCH_DIS,
1720 BRANCH_GEHENNA,
1721 BRANCH_PANDEMONIUM,
1722 BRANCH_ZIGGURAT,
1723 NUM_BRANCHES,
1724 };
1725
_branch_pregenerates(branch_type b)1726 static bool _branch_pregenerates(branch_type b)
1727 {
1728 if (!you.deterministic_levelgen)
1729 return false;
1730 if (b == NUM_BRANCHES || !brentry[b].is_valid() && is_random_subbranch(b))
1731 return false;
1732 return count(branch_generation_order.begin(),
1733 branch_generation_order.end(), b) > 0;
1734 }
1735
1736 /**
1737 * Generate dungeon branches in a stable order until the level `stopping_point`
1738 * is found; `stopping_point` will be generated if it doesn't already exist. If
1739 * it does exist, the function is a noop.
1740 *
1741 * If `stopping_point` is not in the generation order, it will be generated on
1742 * its own.
1743 *
1744 * To generate all generatable levels, pass a level_id with NUM_BRANCHES as the
1745 * branch.
1746 *
1747 * @return whether stopping_point generated; if stopping_point is NUM_BRANCHES,
1748 * whether the full pregen list completed. This will return false if all needed
1749 * levels are already generated, so the caller should check whether false is an
1750 * error case or trivial success (using the save chunk).
1751 */
pregen_dungeon(const level_id & stopping_point)1752 bool pregen_dungeon(const level_id &stopping_point)
1753 {
1754 // TODO: the is_valid() check here doesn't look quite right to me, but so
1755 // far I can't get it to break anything...
1756 if (stopping_point.is_valid()
1757 || stopping_point.branch != NUM_BRANCHES &&
1758 is_random_subbranch(stopping_point.branch) && you.wizard)
1759 {
1760 if (you.save->has_chunk(stopping_point.describe()))
1761 return false;
1762
1763 if (!_branch_pregenerates(stopping_point.branch))
1764 return generate_level(stopping_point);
1765 }
1766
1767 vector<level_id> to_generate;
1768 bool at_end = false;
1769 for (auto br : branch_generation_order)
1770 {
1771 if (br == BRANCH_ZIGGURAT &&
1772 stopping_point.branch == BRANCH_ZIGGURAT)
1773 {
1774 // zigs delete levels as they go, so don't catchup when we're
1775 // already in one. Zigs are only handled this way so that everything
1776 // else generates first.
1777 to_generate.push_back(stopping_point);
1778 continue;
1779 }
1780 // TODO: why is dungeon invalid? it's not set up properly in
1781 // `initialise_branch_depths` for some reason. The vestibule is invalid
1782 // because its depth isn't set until the player actually enters a
1783 // portal, similarly for other portal branches.
1784 if (br < NUM_BRANCHES &&
1785 (brentry[br].is_valid()
1786 || br == BRANCH_DUNGEON || br == BRANCH_VESTIBULE
1787 || !is_connected_branch(br)))
1788 {
1789 for (int i = 1; i <= brdepth[br]; i++)
1790 {
1791 level_id new_level = level_id(br, i);
1792 // skip any levels that have already generated.
1793 if (you.save->has_chunk(new_level.describe()))
1794 continue;
1795 to_generate.push_back(new_level);
1796
1797 if (br == stopping_point.branch
1798 && (i == stopping_point.depth || i == brdepth[br]))
1799 {
1800 at_end = true;
1801 break;
1802 }
1803 }
1804 }
1805 if (at_end)
1806 break;
1807 }
1808
1809 if (to_generate.size() == 0)
1810 {
1811 dprf("levelgen: No valid levels to generate.");
1812 return false;
1813 }
1814 // TODO: some levels are very slow (typically in depths), and a popup might
1815 // be helpful to the player. But is there a good way to tell?
1816 else if (to_generate.size() == 1)
1817 return generate_level(to_generate[0]); // no popup for this case
1818 else
1819 {
1820 // be sure that AK start doesn't interfere with the builder
1821 unwind_var<game_chapter> chapter(you.chapter, CHAPTER_ORB_HUNTING);
1822
1823 ui::progress_popup progress("Generating dungeon...\n\n", 35);
1824 progress.advance_progress();
1825
1826 for (const level_id &new_level : to_generate)
1827 {
1828 string status = "\nbuilding ";
1829
1830 switch (new_level.branch)
1831 {
1832 case BRANCH_SPIDER:
1833 case BRANCH_SNAKE:
1834 status += "a lair branch";
1835 break;
1836 case BRANCH_SHOALS:
1837 case BRANCH_SWAMP:
1838 status += "another lair branch";
1839 break;
1840 default:
1841 status += branches[new_level.branch].longname;
1842 break;
1843 }
1844 progress.set_status_text(status);
1845 dprf("Pregenerating %s:%d",
1846 branches[new_level.branch].abbrevname, new_level.depth);
1847 progress.advance_progress();
1848
1849 // (save chunk existence is checked above, so isn't relevant here)
1850 if (!generate_level(new_level))
1851 return false; // level failed to generate -- bail immediately
1852 }
1853
1854 return true;
1855 }
1856 }
1857
_rescue_player_from_wall()1858 static void _rescue_player_from_wall()
1859 {
1860 // n.b. you.wizmode_teleported_into_rock would be better, but it is not
1861 // actually saved.
1862 if (cell_is_solid(you.pos()) && !you.wizard)
1863 {
1864 // if the player has somehow gotten into a wall, there may have been
1865 // a fairly non-trivial crash, putting the player at some arbitrary
1866 // position relative to where they were. Rescue them by trying to find
1867 // a seen staircase, with a clear space near the wall as just a
1868 // a fallback.
1869 mprf(MSGCH_ERROR, "Emergency fixup: removing player from wall "
1870 "at %d,%d. Please report this as a bug!",
1871 you.pos().x, you.pos().y);
1872 vector<coord_def> upstairs;
1873 vector<coord_def> downstairs;
1874 coord_def backup_clear_pos(-1,-1);
1875 for (distance_iterator di(you.pos()); di; ++di)
1876 {
1877 // just find any clear square as a backup for really weird cases.
1878 if (!in_bounds(backup_clear_pos) && !cell_is_solid(*di))
1879 backup_clear_pos = *di;
1880 // TODO: in principle this should use env.map_forgotten if it
1881 // exists, but I'm not sure that is worth the trouble.
1882 if (feat_is_stair(env.grid(*di)) && env.map_seen(*di))
1883 {
1884 const command_type dir = feat_stair_direction(env.grid(*di));
1885 if (dir == CMD_GO_UPSTAIRS)
1886 upstairs.push_back(*di);
1887 else if (dir == CMD_GO_DOWNSTAIRS)
1888 downstairs.push_back(*di);
1889 }
1890 }
1891 coord_def target = backup_clear_pos;
1892 if (upstairs.size())
1893 target = upstairs[0];
1894 else if (downstairs.size())
1895 target = downstairs[0];
1896 if (!in_bounds(target) && player_in_branch(BRANCH_ABYSS))
1897 {
1898 // something is *seriously* messed up. This can happen if the game
1899 // crashed on an AK start where the initial map wasn't saved.
1900 // Because it is abyss, it is relatively safe to just move a player
1901 // to an arbitrary point and let abyss shift take over. (AK starts,
1902 // the main case, can also escape from the abyss at this point.)
1903 const coord_def emergency(1,1);
1904 env.grid(emergency) = DNGN_FLOOR;
1905 target = emergency;
1906 }
1907 // if things get this messed up, don't make them worse
1908 ASSERT(in_bounds(target));
1909 you.moveto(target);
1910 }
1911 }
1912
1913 /**
1914 * Load the current level.
1915 *
1916 * @param stair_taken The means used to enter the level.
1917 * @param load_mode Whether the level is being entered, examined, etc.
1918 * @return Whether a new level was created.
1919 */
load_level(dungeon_feature_type stair_taken,load_mode_type load_mode,const level_id & old_level)1920 bool load_level(dungeon_feature_type stair_taken, load_mode_type load_mode,
1921 const level_id& old_level)
1922 {
1923 const string level_name = level_id::current().describe();
1924 if (!you.save->has_chunk(level_name) && load_mode == LOAD_VISITOR)
1925 return false;
1926
1927 const bool make_changes =
1928 (load_mode == LOAD_START_GAME || load_mode == LOAD_ENTER_LEVEL);
1929
1930 #if TAG_MAJOR_VERSION == 34
1931 // fixup saves that don't have this prop initialized.
1932 if (load_mode == LOAD_RESTART_GAME)
1933 _fixup_visited_from_package();
1934 #endif
1935
1936 // Did we get here by popping the level stack?
1937 bool popped = false;
1938
1939 coord_def return_pos; //TODO: initialize to null
1940
1941 string hatch_name = "";
1942 if (feat_is_escape_hatch(stair_taken))
1943 hatch_name = _get_hatch_name();
1944
1945 if (load_mode != LOAD_VISITOR)
1946 popped = _leave_level(stair_taken, old_level, &return_pos);
1947
1948 unwind_var<dungeon_feature_type> stair(
1949 you.transit_stair, stair_taken, DNGN_UNSEEN);
1950 unwind_bool ylev(you.entering_level, load_mode != LOAD_VISITOR, false);
1951
1952 #ifdef DEBUG_LEVEL_LOAD
1953 mprf(MSGCH_DIAGNOSTICS, "Loading... branch: %d, level: %d",
1954 you.where_are_you, you.depth);
1955 #endif
1956
1957 // Save position for hatches to place a marker on the destination level.
1958 coord_def dest_pos = you.pos();
1959
1960 _generic_level_reset();
1961
1962 // We clear twice - on save and on load.
1963 // Once would be enough...
1964 if (make_changes)
1965 delete_all_clouds();
1966
1967 // This block is to grab followers and save the old level to disk.
1968 if (load_mode == LOAD_ENTER_LEVEL)
1969 {
1970 dprf("stair_taken = %s", dungeon_feature_name(stair_taken));
1971 // Not the case normally, but can happen during recovery of damaged
1972 // games.
1973 if (old_level.depth != -1)
1974 {
1975 _grab_followers();
1976
1977 if (env.level_state & LSTATE_DELETED)
1978 delete_level(old_level), dprf("<lightmagenta>Deleting level.</lightmagenta>");
1979 else
1980 save_level(old_level);
1981 }
1982
1983 // The player is now between levels.
1984 you.position.reset();
1985
1986 update_companions();
1987 }
1988
1989 #ifdef USE_TILE
1990 if (load_mode != LOAD_VISITOR)
1991 {
1992 tiles.clear_minimap();
1993 crawl_view_buffer empty_vbuf;
1994 tiles.load_dungeon(empty_vbuf, crawl_view.vgrdc);
1995 }
1996 #endif
1997
1998 if (load_mode != LOAD_VISITOR
1999 && you.chapter == CHAPTER_POCKET_ABYSS
2000 && player_in_branch(BRANCH_DUNGEON))
2001 {
2002 // If we're leaving the Abyss for the first time as a Chaos
2003 // Knight of Lugonu (who start out there), enable normal monster
2004 // generation.
2005 you.chapter = CHAPTER_ORB_HUNTING;
2006 }
2007
2008 // GENERATE new level(s) when the file can't be opened:
2009 if (pregen_dungeon(level_id::current()))
2010 {
2011 // sanity check: did the pregenerator leave us on the requested level? If
2012 // this fails via a bug, and this ASSERT isn't here, something incorrect
2013 // will get saved under the chunk for the current level (typically the
2014 // last level in the pregen sequence, which is zig 27).
2015 ASSERT(you.on_current_level);
2016 }
2017 else
2018 {
2019 if (!you.save->has_chunk(level_name))
2020 {
2021 // The builder has failed somewhere along the way, and couldn't get
2022 // to the stopping point. The most likely (only?) cause is that
2023 // there were too many vetoes, which can occasionally happen in
2024 // Depths. To deal with this we force save and crash.
2025 //
2026 // Basically this will ensure that the rng state after the
2027 // attempt is saved, making resuming likely to be possible. Setting
2028 // `you.on_current_level` means that the save has the player on a
2029 // non-generated level. Reloading a save in this state triggers
2030 // the levelgen sequence needed to put them there.
2031
2032 // ensure these props can't be saved, otherwise the save is likely
2033 // to become unloadable
2034 if (you.props.exists("force_map")
2035 || you.props.exists("force_minivault"))
2036 {
2037 // TODO: is there a good way of doing this without the crash?
2038 mprf(MSGCH_ERROR, "&P with '%s' failed; clearing force props and trying with random generation next.",
2039 you.props.exists("force_map")
2040 ? you.props["force_map"].get_string().c_str()
2041 : you.props["force_minivault"].get_string().c_str());
2042 // without a flush this mprf doesn't get saved
2043 flush_prev_message();
2044 you.props.erase("force_minivault");
2045 you.props.erase("force_map");
2046 }
2047
2048 if (crawl_state.need_save)
2049 {
2050 you.on_current_level = true;
2051 save_game(false);
2052 }
2053
2054 die("Builder failure while generating '%s'!\nLast builder error: '%s'",
2055 level_id::current().describe().c_str(),
2056 crawl_state.last_builder_error.c_str());
2057 }
2058
2059 dprf("Loading old level '%s'.", level_name.c_str());
2060 _restore_tagged_chunk(you.save, level_name, TAG_LEVEL, "Level file is invalid.");
2061 if (load_mode != LOAD_VISITOR)
2062 you.on_current_level = true;
2063 _redraw_all(); // TODO why is there a redraw call here?
2064 }
2065
2066 const bool just_created_level = !you.level_visited(level_id::current());
2067
2068 // Clear map knowledge stair emphasis.
2069 show_update_emphasis();
2070
2071 // Shouldn't happen, but this is too unimportant to assert.
2072 deleteAll(env.final_effects);
2073
2074 los_changed();
2075
2076 if (load_mode != LOAD_VISITOR)
2077 you.set_level_visited(level_id::current());
2078
2079 // Markers must be activated early, since they may rely on
2080 // events issued later, e.g. DET_ENTERING_LEVEL or
2081 // the DET_TURN_ELAPSED from update_level.
2082 if (make_changes || load_mode == LOAD_RESTART_GAME)
2083 env.markers.activate_all();
2084
2085 if (make_changes && env.elapsed_time && !just_created_level)
2086 update_level(you.elapsed_time - env.elapsed_time);
2087
2088 // Apply all delayed actions, if any. TODO: logic for marshalling this is
2089 // kind of odd.
2090 // TODO: does this need make_changes?
2091 if (just_created_level)
2092 env.dactions_done = 0;
2093
2094 // Here's the second cloud clearing, on load (see above).
2095 if (make_changes)
2096 {
2097 // this includes various things that are irrelevant for new levels, but
2098 // also some things that aren't, such as bribe branch.
2099 catchup_dactions();
2100
2101 delete_all_clouds();
2102
2103 _place_player(stair_taken, return_pos, dest_pos, hatch_name);
2104 }
2105
2106 crawl_view.set_player_at(you.pos(), load_mode != LOAD_VISITOR);
2107
2108 // Actually "move" the followers if applicable.
2109 if (load_mode == LOAD_ENTER_LEVEL)
2110 place_followers();
2111
2112 // Load monsters in transit.
2113 if (load_mode == LOAD_ENTER_LEVEL)
2114 place_transiting_monsters();
2115
2116 if (just_created_level && make_changes)
2117 replace_boris();
2118
2119 if (make_changes)
2120 {
2121 // Tell stash-tracker and travel that we've changed levels.
2122 trackers_init_new_level();
2123 tile_new_level(just_created_level);
2124 }
2125 else if (load_mode == LOAD_RESTART_GAME)
2126 {
2127 _rescue_player_from_wall();
2128 // Travel needs initialize some things on reload, too.
2129 travel_init_load_level();
2130 }
2131
2132 _redraw_all();
2133
2134 if (load_mode != LOAD_VISITOR)
2135 dungeon_events.fire_event(DET_ENTERING_LEVEL);
2136
2137 // Things to update for player entering level
2138 if (load_mode == LOAD_ENTER_LEVEL)
2139 {
2140 // new levels have less wary monsters, and we don't
2141 // want them to attack players quite as soon:
2142 you.time_taken *= (just_created_level ? 1 : 2);
2143
2144 you.time_taken = div_rand_round(you.time_taken * 3, 4);
2145
2146 dprf("arrival time: %d", you.time_taken);
2147
2148 if (just_created_level)
2149 run_map_epilogues();
2150 }
2151
2152 // Save the created/updated level out to disk:
2153 if (make_changes)
2154 save_level(level_id::current());
2155
2156 setup_environment_effects();
2157
2158 setup_vault_mon_list();
2159
2160 // Inform user of level's annotation.
2161 if (load_mode != LOAD_VISITOR
2162 && !get_level_annotation().empty()
2163 && !crawl_state.level_annotation_shown)
2164 {
2165 mprf(MSGCH_PLAIN, YELLOW, "Level annotation: %s",
2166 get_level_annotation().c_str());
2167 }
2168
2169 if (load_mode != LOAD_VISITOR)
2170 crawl_state.level_annotation_shown = false;
2171
2172 if (make_changes)
2173 {
2174 // Update PlaceInfo entries
2175 PlaceInfo& curr_PlaceInfo = you.get_place_info();
2176 PlaceInfo delta;
2177
2178 if (load_mode == LOAD_START_GAME
2179 || (load_mode == LOAD_ENTER_LEVEL
2180 && old_level.branch != you.where_are_you
2181 && !popped))
2182 {
2183 delta.num_visits++;
2184 }
2185
2186 if (just_created_level)
2187 delta.levels_seen++;
2188
2189 you.global_info += delta;
2190 #ifdef DEBUG_LEVEL_LOAD
2191 mprf(MSGCH_DIAGNOSTICS,
2192 "global_info:: num_visits: %d, levels_seen: %d",
2193 you.global_info.num_visits, you.global_info.levels_seen);
2194 #endif
2195 you.global_info.assert_validity();
2196
2197 curr_PlaceInfo += delta;
2198 #ifdef DEBUG_LEVEL_LOAD
2199 mprf(MSGCH_DIAGNOSTICS,
2200 "curr_PlaceInfo:: num_visits: %d, levels_seen: %d",
2201 curr_PlaceInfo.num_visits, curr_PlaceInfo.levels_seen);
2202 #endif
2203 #if TAG_MAJOR_VERSION == 34
2204 // this fixup is for a bug where turns_on_level==0 was used to set
2205 // just_created_level, and there were some obscure ways to have 0
2206 // turns on a level that you had entered previously. It only applies
2207 // to a narrow version range (basically 0.23.0) but there's no way to
2208 // do a sensible minor version check here and the fixup can't happen
2209 // on load.
2210 if (is_connected_branch(curr_PlaceInfo.branch)
2211 && brdepth[curr_PlaceInfo.branch] > 0
2212 && static_cast<int>(curr_PlaceInfo.levels_seen)
2213 > brdepth[curr_PlaceInfo.branch])
2214 {
2215 mprf(MSGCH_ERROR,
2216 "Fixing up corrupted PlaceInfo for %s (levels_seen is %d)",
2217 branches[curr_PlaceInfo.branch].shortname,
2218 curr_PlaceInfo.levels_seen);
2219 curr_PlaceInfo.levels_seen = brdepth[curr_PlaceInfo.branch];
2220 }
2221 #endif
2222 curr_PlaceInfo.assert_validity();
2223 }
2224
2225 if (just_created_level && make_changes)
2226 {
2227 you.attribute[ATTR_ABYSS_ENTOURAGE] = 0;
2228 gozag_detect_level_gold(true);
2229 }
2230
2231
2232 if (load_mode != LOAD_VISITOR)
2233 {
2234 dungeon_events.fire_event(
2235 dgn_event(DET_ENTERED_LEVEL, coord_def(), you.time_taken,
2236 load_mode == LOAD_RESTART_GAME));
2237 }
2238
2239 if (load_mode == LOAD_ENTER_LEVEL)
2240 {
2241 // 50% chance of repelling the stair you just came through.
2242 if (you.duration[DUR_REPEL_STAIRS_MOVE]
2243 || you.duration[DUR_REPEL_STAIRS_CLIMB])
2244 {
2245 dungeon_feature_type feat = env.grid(you.pos());
2246 if (feat != DNGN_ENTER_SHOP
2247 && feat_stair_direction(feat) != CMD_NO_CMD
2248 && feat_stair_direction(stair_taken) != CMD_NO_CMD)
2249 {
2250 string stair_str = feature_description_at(you.pos(), false,
2251 DESC_THE);
2252 string verb = stair_climb_verb(feat);
2253
2254 if (coinflip()
2255 && slide_feature_over(you.pos()))
2256 {
2257 mprf("%s slides away from you right after you %s it!",
2258 stair_str.c_str(), verb.c_str());
2259 }
2260
2261 if (coinflip())
2262 {
2263 // Stairs stop fleeing from you now you actually caught one.
2264 mprf("%s settles down.", stair_str.c_str());
2265 you.duration[DUR_REPEL_STAIRS_MOVE] = 0;
2266 you.duration[DUR_REPEL_STAIRS_CLIMB] = 0;
2267 }
2268 }
2269 }
2270
2271 ash_detect_portals(is_map_persistent());
2272
2273 if (just_created_level)
2274 xom_new_level_noise_or_stealth();
2275 }
2276
2277 if (just_created_level && (load_mode == LOAD_ENTER_LEVEL
2278 || load_mode == LOAD_START_GAME))
2279 {
2280 decr_zot_clock();
2281 }
2282
2283 // Initialize halos, etc.
2284 invalidate_agrid(true);
2285
2286 // Maybe make a note if we reached a new level.
2287 // Don't do so if we are just moving around inside Pan, though.
2288 if (just_created_level && make_changes
2289 && stair_taken != DNGN_TRANSIT_PANDEMONIUM)
2290 {
2291 take_note(Note(NOTE_DUNGEON_LEVEL_CHANGE));
2292 }
2293
2294 // If the player entered the level from a different location than they last
2295 // exited it, have monsters lose track of where they are
2296 if (make_changes && you.position != env.old_player_pos)
2297 shake_off_monsters(you.as_player());
2298
2299 #if TAG_MAJOR_VERSION == 34
2300 if (make_changes && you.props.exists("zig-fixup")
2301 && you.where_are_you == BRANCH_TOMB
2302 && you.depth == brdepth[BRANCH_TOMB])
2303 {
2304 if (!just_created_level)
2305 {
2306 int obj = items(false, OBJ_MISCELLANY, MISC_ZIGGURAT, 0);
2307 ASSERT(obj != NON_ITEM);
2308 bool success = move_item_to_grid(&obj, you.pos(), true);
2309 ASSERT(success);
2310 }
2311 you.props.erase("zig-fixup");
2312 }
2313 #endif
2314
2315 return just_created_level;
2316 }
2317
save_level(const level_id & lid)2318 void save_level(const level_id& lid)
2319 {
2320 if (you.level_visited(lid))
2321 travel_cache.get_level_info(lid).update();
2322
2323 // Nail all items to the ground.
2324 fix_item_coordinates();
2325
2326 _write_tagged_chunk(lid.describe(), TAG_LEVEL);
2327 }
2328
2329 #if TAG_MAJOR_VERSION == 34
2330 # define CHUNK(short, long) short
2331 #else
2332 # define CHUNK(short, long) long
2333 #endif
2334
2335 #define SAVEFILE(short, long, savefn) \
2336 do \
2337 { \
2338 writer w(you.save, CHUNK(short, long)); \
2339 savefn(w); \
2340 } while (false)
2341
2342 // Stack allocated string's go in separate function, so Valgrind doesn't
2343 // complain.
_save_game_base()2344 static void _save_game_base()
2345 {
2346 /* Stashes */
2347 SAVEFILE("st", "stashes", StashTrack.save);
2348
2349 /* lua */
2350 SAVEFILE("lua", "lua", clua.save); // what goes in here?
2351
2352 /* kills */
2353 SAVEFILE("kil", "kills", you.kills.save);
2354
2355 /* travel cache */
2356 SAVEFILE("tc", "travel_cache", travel_cache.save);
2357
2358 /* notes */
2359 SAVEFILE("nts", "notes", save_notes);
2360
2361 /* tutorial/hints mode */
2362 if (crawl_state.game_is_hints_tutorial())
2363 SAVEFILE("tut", "tutorial", save_hints);
2364
2365 /* messages */
2366 SAVEFILE("msg", "messages", save_messages);
2367
2368 /* tile dolls (empty for ASCII)*/
2369 #ifdef USE_TILE
2370 // Save the current equipment into a file.
2371 SAVEFILE("tdl", "tiles_doll", save_doll_file);
2372 #endif
2373
2374 _write_tagged_chunk("you", TAG_YOU);
2375 _write_tagged_chunk("chr", TAG_CHR);
2376 }
2377
2378 // Stack allocated string's go in separate function, so Valgrind doesn't
2379 // complain.
_save_game_exit()2380 static void _save_game_exit()
2381 {
2382 clua.save_persist();
2383
2384 // Prompt for saving macros.
2385 if (crawl_state.unsaved_macros)
2386 macro_save();
2387
2388 // Must be exiting -- save level & goodbye!
2389 if (!you.entering_level)
2390 save_level(level_id::current());
2391
2392 clrscr();
2393
2394 #ifdef DGL_WHEREIS
2395 whereis_record("saved");
2396 #endif
2397 #ifdef USE_TILE_WEB
2398 tiles.send_exit_reason("saved");
2399 #endif
2400
2401 delete you.save;
2402 you.save = 0;
2403 }
2404
save_game(bool leave_game,const char * farewellmsg)2405 void save_game(bool leave_game, const char *farewellmsg)
2406 {
2407 unwind_bool saving_game(crawl_state.saving_game, true);
2408 // Should you.no_save disable more here? Currently it entails an empty
2409 // package, and persists won't save, but there's a bunch of other stuff
2410 // that can.
2411 ASSERT(you.on_current_level || Options.no_save);
2412
2413
2414 if (leave_game && Options.dump_on_save)
2415 {
2416 if (!dump_char(you.your_name, true))
2417 {
2418 mpr("Char dump unsuccessful! Sorry about that.");
2419 if (!crawl_state.seen_hups)
2420 more();
2421 }
2422 #ifdef USE_TILE_WEB
2423 else
2424 tiles.send_dump_info("save", you.your_name);
2425 #endif
2426 }
2427
2428 // Stack allocated string's go in separate function,
2429 // so Valgrind doesn't complain.
2430 _save_game_base();
2431
2432 // If just save, early out.
2433 if (!leave_game)
2434 {
2435 if (!crawl_state.disables[DIS_SAVE_CHECKPOINTS])
2436 you.save->commit();
2437 return;
2438 }
2439
2440 // Stack allocated string's go in separate function,
2441 // so Valgrind doesn't complain.
2442 _save_game_exit();
2443
2444 game_ended(game_exit::save, farewellmsg ? farewellmsg
2445 : "See you soon, " + you.your_name + "!");
2446 }
2447
2448 // Saves the game without exiting.
save_game_state()2449 void save_game_state()
2450 {
2451 save_game(false);
2452 if (crawl_state.seen_hups)
2453 save_game(true);
2454 }
2455
_bones_save_individual_levels(bool store)2456 static bool _bones_save_individual_levels(bool store)
2457 {
2458 // Only use level-numbered bones files for places where players die a lot.
2459 // For the permastore, go even coarser (just D and Lair use level numbers).
2460 // n.b. some branches here may not currently generate ghosts.
2461 // TODO: further adjustments? Make Zot coarser?
2462 return store ? player_in_branch(BRANCH_DUNGEON) ||
2463 player_in_branch(BRANCH_LAIR)
2464 : !(player_in_branch(BRANCH_ZIGGURAT) ||
2465 player_in_branch(BRANCH_CRYPT) ||
2466 player_in_branch(BRANCH_TOMB) ||
2467 player_in_branch(BRANCH_ABYSS) ||
2468 player_in_branch(BRANCH_SLIME));
2469 }
2470
_make_ghost_filename(bool store=false)2471 static string _make_ghost_filename(bool store=false)
2472 {
2473 const bool with_number = _bones_save_individual_levels(store);
2474 // Players die so rarely in hell in practice that it doesn't even make
2475 // sense to have per-hell bones. (Maybe vestibule should be separate?)
2476 const string level_desc = player_in_hell(true) ? "Hells" :
2477 replace_all(level_id::current().describe(false, with_number), ":", "-");
2478 return string("bones.") + (store ? "store." : "") + level_desc;
2479 }
2480
_bones_permastore_file()2481 static string _bones_permastore_file()
2482 {
2483 string filename = _make_ghost_filename(true);
2484 string full_path = _get_bonefile_directory() + filename;
2485 if (file_exists(full_path))
2486 return full_path;
2487
2488 string dist_full_path = datafile_path(
2489 string("dist_bones") + FILE_SEPARATOR + filename, false, false);
2490 if (dist_full_path.empty())
2491 return dist_full_path;
2492
2493 // no matching permastore is in the player's bones file, but one exists in
2494 // the crawl distribution. Install it.
2495
2496 FILE *src = fopen(dist_full_path.c_str(), "rb");
2497 if (!src)
2498 {
2499 mprf(MSGCH_ERROR, "Bones file exists but can't be opened: %s",
2500 dist_full_path.c_str());
2501 return "";
2502 }
2503 FILE *target = lk_open("wb", full_path);
2504 if (!target)
2505 {
2506 mprf(MSGCH_ERROR, "Unable to open bones file %s for writing",
2507 full_path.c_str());
2508 fclose(src);
2509 return "";
2510 }
2511
2512 _ghost_dprf("Copying %s to %s", dist_full_path.c_str(), full_path.c_str());
2513
2514 char buf[BUFSIZ];
2515
2516 size_t size;
2517 while ((size = fread(buf, sizeof(char), BUFSIZ, src)) > 0)
2518 fwrite(buf, sizeof(char), size, target);
2519
2520 lk_close(target);
2521
2522 if (!feof(src))
2523 {
2524 mprf(MSGCH_ERROR, "Error installing bones file to %s",
2525 full_path.c_str());
2526 if (unlink(full_path.c_str()) != 0)
2527 {
2528 mprf(MSGCH_ERROR,
2529 "Failed to unlink probably corrupt bones file: %s",
2530 full_path.c_str());
2531 }
2532 fclose(src);
2533 return "";
2534 }
2535 fclose(src);
2536 return full_path;
2537 }
2538
2539 // Bones files
2540 //
2541 // There are two kinds of bones files: temporary bones files and the
2542 // permastore. Temporary bones files are ephemeral: ghosts will be reused only
2543 // if they are on the floor where the player dies. The permastore is a more
2544 // permanent stock of ghosts (per level) to use as a backup in case the
2545 // temporary bones files are depleted.
2546
2547 /**
2548 * Lists all bonefiles for the current level.
2549 *
2550 * @return A vector containing absolute paths to 0+ bonefiles.
2551 */
_list_bones()2552 static vector<string> _list_bones()
2553 {
2554 string bonefile_dir = _get_bonefile_directory();
2555 string base_filename = _make_ghost_filename();
2556 string underscored_filename = base_filename + "_";
2557
2558 vector<string> filenames = get_dir_files_sorted(bonefile_dir);
2559 vector<string> bonefiles;
2560 for (const auto &filename : filenames)
2561 if (starts_with(filename, underscored_filename)
2562 && !ends_with(filename, ".backup"))
2563 {
2564 bonefiles.push_back(bonefile_dir + filename);
2565 _ghost_dprf("bonesfile %s", (bonefile_dir + filename).c_str());
2566 }
2567
2568 string old_bonefile = _get_old_bonefile_directory() + base_filename;
2569 if (access(old_bonefile.c_str(), F_OK) == 0)
2570 {
2571 _ghost_dprf("Found old bonefile %s", old_bonefile.c_str());
2572 bonefiles.push_back(old_bonefile);
2573 }
2574
2575 return bonefiles;
2576 }
2577
2578 /**
2579 * Attempts to find a file containing ghost(s) appropriate for the player.
2580 *
2581 * @return The filename of an appropriate bones file; may be "".
2582 */
_find_ghost_file()2583 static string _find_ghost_file()
2584 {
2585 vector<string> bonefiles = _list_bones();
2586 if (bonefiles.empty())
2587 return "";
2588 return bonefiles[random2(bonefiles.size())];
2589 }
2590
_old_bones_filename(string ghost_filename,const save_version & v)2591 static string _old_bones_filename(string ghost_filename, const save_version &v)
2592 {
2593 // TODO: a way of looking for any backup with a version earlier than v
2594 if (ends_with(ghost_filename, ".backup"))
2595 return ghost_filename; // already an old bones file
2596
2597 string new_filename = make_stringf("%s-v%d.%d.backup", ghost_filename.c_str(),
2598 v.major, v.minor);
2599 return new_filename;
2600 }
2601
_backup_bones_for_upgrade(string ghost_filename,save_version & v)2602 static bool _backup_bones_for_upgrade(string ghost_filename, save_version &v)
2603 {
2604 // Copy the bones file to a versioned name, so that non-upgraded saves can
2605 // load it. Copying would be cleaner with c++ ios stuff, but we need to
2606 // interact with the lock system.
2607
2608 if (ghost_filename.empty())
2609 return false;
2610 if (ends_with(ghost_filename, ".backup"))
2611 return false; // already an old bones file
2612
2613 string upgrade_filename = _old_bones_filename(ghost_filename, v);
2614 if (file_exists(upgrade_filename))
2615 return false;
2616 _ghost_dprf("Backing up bones file %s to %s before upgrade to %d.%d",
2617 ghost_filename.c_str(), upgrade_filename.c_str(),
2618 save_version::current_bones().major,
2619 save_version::current_bones().minor);
2620
2621 FILE *backup_src = lk_open("rb", ghost_filename);
2622 if (!backup_src)
2623 {
2624 mprf(MSGCH_ERROR, "Bones file to back up doesn't exist: %s",
2625 ghost_filename.c_str());
2626 return false;
2627 }
2628 FILE *backup_target = lk_open("wb", upgrade_filename);
2629 if (!backup_target)
2630 {
2631 mprf(MSGCH_ERROR, "Unable to open bones backup file %s for writing",
2632 upgrade_filename.c_str());
2633 lk_close(backup_src);
2634 return false;
2635 }
2636
2637 char buf[BUFSIZ];
2638
2639 size_t size;
2640 while ((size = fread(buf, sizeof(char), BUFSIZ, backup_src)) > 0)
2641 fwrite(buf, sizeof(char), size, backup_target);
2642
2643 lk_close(backup_target);
2644
2645 if (!feof(backup_src))
2646 {
2647 mprf(MSGCH_ERROR, "Error backing up bones file to %s",
2648 upgrade_filename.c_str());
2649 if (unlink(upgrade_filename.c_str()) != 0)
2650 {
2651 mprf(MSGCH_ERROR,
2652 "Failed to unlink probably corrupt bones file: %s",
2653 upgrade_filename.c_str());
2654 }
2655 lk_close(backup_src);
2656 return false;
2657 }
2658 lk_close(backup_src);
2659 return true;
2660 }
2661
read_ghost_header(reader & inf)2662 save_version read_ghost_header(reader &inf)
2663 {
2664 auto version = get_save_version(inf);
2665 if (!version.valid())
2666 return version;
2667
2668 #if TAG_MAJOR_VERSION == 34
2669 // downgrade bones files saved before the bones sub-versioning system
2670 if (version > save_version::current_bones() && version.is_compatible())
2671 {
2672 _ghost_dprf("Setting bones file version from %d.%d to %d.%d on load",
2673 version.major, version.minor,
2674 save_version::current_bones().major,
2675 save_version::current_bones().minor);
2676 version = save_version::current_bones();
2677 }
2678 #endif
2679
2680 try
2681 {
2682 // Check for the DCSS ghost signature.
2683 if (unmarshallShort(inf) != GHOST_SIGNATURE)
2684 return save_version(); // version was valid, but this isn't a bones file
2685
2686 // Discard three more 32-bit words of padding.
2687 inf.read(nullptr, 3*4);
2688 }
2689 catch (short_read_exception &E)
2690 {
2691 mprf(MSGCH_ERROR,
2692 "Ghost file \"%s\" seems to be invalid (short read); deleting it.",
2693 inf.filename().c_str());
2694 return save_version();
2695 }
2696
2697 return version;
2698 }
2699
load_bones_file(string ghost_filename,bool backup)2700 vector<ghost_demon> load_bones_file(string ghost_filename, bool backup)
2701 {
2702 vector<ghost_demon> result;
2703
2704 if (ghost_filename.empty())
2705 return result; // no such ghost.
2706
2707 reader inf(ghost_filename);
2708 if (!inf.valid())
2709 {
2710 // file doesn't exist
2711 _ghost_dprf("Ghost file '%s' invalid before read.", ghost_filename.c_str());
2712 return result;
2713 }
2714
2715 inf.set_safe_read(true); // don't die on 0-byte bones
2716 save_version version = read_ghost_header(inf);
2717 if (!_ghost_version_compatible(version))
2718 {
2719 string error = "Incompatible bones file: " + ghost_filename;
2720 throw corrupted_save(error, version);
2721 }
2722 inf.setMinorVersion(version.minor);
2723 if (backup && version < save_version::current_bones())
2724 _backup_bones_for_upgrade(ghost_filename, version);
2725
2726 try
2727 {
2728 result = tag_read_ghosts(inf);
2729 inf.fail_if_not_eof(ghost_filename);
2730 }
2731 catch (short_read_exception &short_read)
2732 {
2733 string error = "Broken bones file: " + ghost_filename;
2734 throw corrupted_save(error, version);
2735 }
2736 inf.close();
2737
2738 if (!debug_check_ghosts(result))
2739 {
2740 string error = "Bones file is buggy: " + ghost_filename;
2741 throw corrupted_save(error, version);
2742 }
2743
2744 return result;
2745 }
2746
2747
_load_ghosts_core(string filename,bool backup_on_upgrade)2748 static vector<ghost_demon> _load_ghosts_core(string filename,
2749 bool backup_on_upgrade)
2750 {
2751 vector<ghost_demon> results;
2752 try
2753 {
2754 results = load_bones_file(filename, backup_on_upgrade);
2755 }
2756 catch (corrupted_save &err)
2757 {
2758 // not a corrupted save per se, just from the future. Try to load the
2759 // versioned bones file if it exists.
2760 if (err.version.valid() && err.version.is_future())
2761 {
2762 string old_bones =
2763 _old_bones_filename(filename, save_version::current());
2764 if (old_bones != filename)
2765 {
2766 _ghost_dprf("Loading ghost from backup bones file %s",
2767 old_bones.c_str());
2768 return load_bones_file(old_bones, false);
2769 }
2770 else
2771 mprf(MSGCH_ERROR, "Mismatch between bones backup "
2772 "filename '%s' and version %d.%d!", filename.c_str(),
2773 err.version.major, err.version.minor);
2774 // intentional fallthrough -- unlink the misnamed file
2775 }
2776 else
2777 mprf(MSGCH_ERROR, "%s", err.what());
2778 string report;
2779 // if we get to this point the bones file is unreadable and needs to
2780 // be scrapped
2781 if (unlink(filename.c_str()) != 0)
2782 report = "Failed to unlink bad bones file";
2783 else
2784 report = "Clearing bad bones file";
2785 mprf(MSGCH_ERROR, "%s: %s", report.c_str(), filename.c_str());
2786 }
2787 return results;
2788
2789 }
2790
_load_ephemeral_ghosts()2791 static vector<ghost_demon> _load_ephemeral_ghosts()
2792 {
2793 vector<ghost_demon> results;
2794
2795 string ghost_filename = _find_ghost_file();
2796 if (ghost_filename.empty())
2797 {
2798 _ghost_dprf("%s", "No ephemeral ghost files for this level.");
2799 return results; // no such ghost.
2800 }
2801
2802 results = _load_ghosts_core(ghost_filename, true);
2803
2804 if (unlink(ghost_filename.c_str()) != 0)
2805 {
2806 mprf(MSGCH_ERROR, "Failed to unlink bones file: %s",
2807 ghost_filename.c_str());
2808 }
2809 return results;
2810 }
2811
_load_permastore_ghosts(bool backup_on_upgrade=false)2812 static vector<ghost_demon> _load_permastore_ghosts(bool backup_on_upgrade=false)
2813 {
2814 return _load_ghosts_core(_bones_permastore_file(), backup_on_upgrade);
2815 }
2816
2817 /**
2818 * Attempt to fill in a monster based on bones files.
2819 *
2820 * @param mons the monster to fill in
2821 *
2822 * @return whether there was a saved ghost that could be used.
2823 */
define_ghost_from_bones(monster & mons)2824 bool define_ghost_from_bones(monster& mons)
2825 {
2826 rng::generator rng(rng::SYSTEM_SPECIFIC);
2827
2828 bool used_permastore = false;
2829
2830 vector<ghost_demon> loaded_ghosts = _load_ephemeral_ghosts();
2831 if (loaded_ghosts.empty())
2832 {
2833 loaded_ghosts = _load_permastore_ghosts();
2834 if (loaded_ghosts.empty())
2835 return false;
2836 used_permastore = true;
2837 }
2838
2839 int place_i = random2(loaded_ghosts.size());
2840 _ghost_dprf("Loaded ghost file with %u ghost(s), placing %s",
2841 (unsigned int)loaded_ghosts.size(), loaded_ghosts[place_i].name.c_str());
2842
2843 mons.set_ghost(loaded_ghosts[place_i]);
2844 mons.type = MONS_PLAYER_GHOST;
2845 mons.ghost_init(false);
2846
2847 if (!mons.alive())
2848 mprf(MSGCH_ERROR, "Placed ghost is not alive.");
2849 else if (mons.type != MONS_PLAYER_GHOST)
2850 {
2851 mprf(MSGCH_ERROR, "Placed ghost is not MONS_PLAYER_GHOST, but %s",
2852 mons.name(DESC_PLAIN, true).c_str());
2853 }
2854
2855 if (!used_permastore)
2856 {
2857 loaded_ghosts.erase(loaded_ghosts.begin() + place_i);
2858
2859 if (!loaded_ghosts.empty())
2860 save_ghosts(loaded_ghosts);
2861 }
2862 return true;
2863 }
2864
2865 /**
2866 * Attempt to load one or more ghosts into the level.
2867 *
2868 * @param max_ghosts A maximum number of ghosts to creat.
2869 * Set to <= 0 to load as many as possible.
2870 * @param creating_level Whether a level is currently being generated.
2871 * @return Whether ghosts were actually generated.
2872 */
load_ghosts(int max_ghosts,bool creating_level)2873 bool load_ghosts(int max_ghosts, bool creating_level)
2874 {
2875 ASSERT(you.transit_stair == DNGN_UNSEEN || creating_level);
2876 ASSERT(!you.entering_level || creating_level);
2877 ASSERT(!creating_level
2878 || (you.entering_level && you.transit_stair != DNGN_UNSEEN));
2879 // Only way to load a ghost without creating a level is via a wizard
2880 // command.
2881 ASSERT(creating_level || (crawl_state.prev_cmd == CMD_WIZARD));
2882
2883 #ifdef BONES_DIAGNOSTICS
2884 // this is pretty hacky, but arguably cleaner than what it is replacing.
2885 // The effect is to show bones diagnostic messages on wizmode builds during
2886 // level building
2887 unwind_var<command_type> last_cmd(crawl_state.prev_cmd, creating_level ?
2888 CMD_WIZARD : crawl_state.prev_cmd);
2889 #endif
2890
2891 vector<ghost_demon> loaded_ghosts = _load_ephemeral_ghosts();
2892
2893 _ghost_dprf("Loaded ghost file with %u ghost(s), will attempt to place %d of them",
2894 (unsigned int)loaded_ghosts.size(), max_ghosts);
2895
2896 bool ghost_errors = false;
2897
2898 max_ghosts = max_ghosts <= 0 ? loaded_ghosts.size()
2899 : min(max_ghosts, (int) loaded_ghosts.size());
2900 int placed_ghosts = 0;
2901
2902 // Translate ghost to monster and place.
2903 while (!loaded_ghosts.empty() && placed_ghosts < max_ghosts)
2904 {
2905 monster * const mons = get_free_monster();
2906 if (!mons)
2907 break;
2908
2909 mons->set_new_monster_id();
2910 mons->set_ghost(loaded_ghosts[0]);
2911 mons->type = MONS_PLAYER_GHOST;
2912 mons->ghost_init();
2913
2914 loaded_ghosts.erase(loaded_ghosts.begin());
2915 placed_ghosts++;
2916
2917 if (!mons->alive())
2918 {
2919 _ghost_dprf("Placed ghost is not alive.");
2920 ghost_errors = true;
2921 }
2922 else if (mons->type != MONS_PLAYER_GHOST)
2923 {
2924 _ghost_dprf("Placed ghost is not MONS_PLAYER_GHOST, but %s",
2925 mons->name(DESC_PLAIN, true).c_str());
2926 ghost_errors = true;
2927 }
2928 }
2929
2930 if (placed_ghosts < max_ghosts)
2931 {
2932 _ghost_dprf("Unable to place %u ghost(s)", max_ghosts - placed_ghosts);
2933 ghost_errors = true;
2934 }
2935 #ifdef BONES_DIAGNOSTICS
2936 if (ghost_errors)
2937 more();
2938 #endif
2939
2940 // resave any unused ghosts
2941 if (!loaded_ghosts.empty())
2942 save_ghosts(loaded_ghosts);
2943
2944 return true;
2945 }
2946
_type_name_processed(game_type t)2947 static string _type_name_processed(game_type t)
2948 {
2949 string name = game_state::game_type_name_for(t);
2950 return name.size() ? name : "regular";
2951 }
2952
2953 // returns false if a new game should start instead
_restore_game(const string & filename)2954 static bool _restore_game(const string& filename)
2955 {
2956 if (Options.no_save)
2957 return false;
2958
2959 // In webtiles, a more before the player is loaded will crash when it tries
2960 // to send enough information to the webtiles client to render the display.
2961 // This is just cosmetic for other build targets.
2962 unwind_bool save_more(crawl_state.show_more_prompt, false);
2963 game_type menu_game_type = crawl_state.type;
2964
2965 clear_message_store();
2966
2967 you.save = new package((_get_savefile_directory() + filename).c_str(), true);
2968
2969 if (!_read_char_chunk(you.save))
2970 {
2971 // Note: if we are here, the save info was properly read, it would
2972 // raise an exception otherwise.
2973 if (yesno(("There is an existing game for name '" + you.your_name +
2974 "' from an incompatible version of Crawl ("
2975 + you.prev_save_version + ").\n"
2976 "Unless you reinstall that version, you can't load it.\n"
2977 "Do you want to DELETE that game and start a new one?"
2978 ).c_str(),
2979 true, 'n'))
2980 {
2981 you.save->unlink();
2982 you.save = 0;
2983 return false;
2984 }
2985 if (Options.remember_name)
2986 crawl_state.default_startup_name = you.your_name; // for main menu
2987 you.save->abort();
2988 delete you.save;
2989 you.save = 0;
2990 game_ended(game_exit::abort,
2991 you.your_name + " is from an incompatible version and can't be loaded.");
2992 }
2993
2994 if (!crawl_state.bypassed_startup_menu
2995 && menu_game_type != crawl_state.type)
2996 {
2997 if (!yesno(("You already have a "
2998 + _type_name_processed(crawl_state.type) +
2999 " game saved under the name '" + you.your_name + "';\n"
3000 "do you want to load that instead?").c_str(),
3001 true, 'n'))
3002 {
3003 you.save->abort(); // don't even rewrite the header
3004 delete you.save;
3005 you.save = 0;
3006 game_ended(game_exit::abort,
3007 "Please use a different name to start a new " +
3008 _type_name_processed(menu_game_type) + " game, then.");
3009 }
3010 }
3011
3012 if (Options.remember_name)
3013 crawl_state.default_startup_name = you.your_name; // for main menu
3014
3015 if (numcmp(you.prev_save_version.c_str(), Version::Long, 2) == -1
3016 && version_is_stable(you.prev_save_version.c_str()))
3017 {
3018 if (!yesno(("This game comes from a previous release of Crawl (" +
3019 you.prev_save_version + ").\n\nIf you load it now,"
3020 " you won't be able to go back. Continue?").c_str(),
3021 true, 'n'))
3022 {
3023 you.save->abort(); // don't even rewrite the header
3024 delete you.save;
3025 you.save = 0;
3026 game_ended(game_exit::abort, "Please use version " +
3027 you.prev_save_version + " to load " + you.your_name + " then.");
3028 }
3029 }
3030
3031 you.on_current_level = false; // we aren't on the current level until
3032 // everything is fully loaded
3033 _restore_tagged_chunk(you.save, "you", TAG_YOU, "Save data is invalid.");
3034
3035 _convert_obsolete_species();
3036
3037 const int minorVersion = crawl_state.minor_version;
3038
3039 if (you.save->has_chunk(CHUNK("st", "stashes")))
3040 {
3041 reader inf(you.save, CHUNK("st", "stashes"), minorVersion);
3042 StashTrack.load(inf);
3043 }
3044
3045 #ifdef CLUA_BINDINGS
3046 if (you.save->has_chunk("lua"))
3047 {
3048 vector<char> buf;
3049 chunk_reader inf(you.save, "lua");
3050 inf.read_all(buf);
3051 buf.push_back(0);
3052 clua.execstring(&buf[0]);
3053 }
3054 #endif
3055
3056 if (you.save->has_chunk(CHUNK("kil", "kills")))
3057 {
3058 reader inf(you.save, CHUNK("kil", "kills"),minorVersion);
3059 you.kills.load(inf);
3060 }
3061
3062 if (you.save->has_chunk(CHUNK("tc", "travel_cache")))
3063 {
3064 reader inf(you.save, CHUNK("tc", "travel_cache"), minorVersion);
3065 travel_cache.load(inf, minorVersion);
3066 }
3067
3068 if (you.save->has_chunk(CHUNK("nts", "notes")))
3069 {
3070 reader inf(you.save, CHUNK("nts", "notes"), minorVersion);
3071 load_notes(inf);
3072 }
3073
3074 /* hints mode */
3075 if (you.save->has_chunk(CHUNK("tut", "tutorial")))
3076 {
3077 reader inf(you.save, CHUNK("tut", "tutorial"), minorVersion);
3078 load_hints(inf);
3079 }
3080
3081 /* messages */
3082 if (you.save->has_chunk(CHUNK("msg", "messages")))
3083 {
3084 reader inf(you.save, CHUNK("msg", "messages"), minorVersion);
3085 load_messages(inf);
3086 }
3087
3088 // Handle somebody SIGHUP'ing out of the skill menu with every skill
3089 // disabled. Doing this here rather in tags code because it can trigger
3090 // UI, which may not be safe if everything isn't fully loaded.
3091 check_selected_skills();
3092
3093 return true;
3094 }
3095
3096 // returns false if a new game should start instead
restore_game(const string & filename)3097 bool restore_game(const string& filename)
3098 {
3099 try
3100 {
3101 return _restore_game(filename);
3102 }
3103 catch (corrupted_save &err)
3104 {
3105 if (yesno(make_stringf(
3106 "There exists a save by that name but it appears to be invalid.\n"
3107 "Do you want to delete it?\n"
3108 "Error: %s", err.what()).c_str(), // TODO linebreak error
3109 true, 'n'))
3110 {
3111 if (you.save)
3112 you.save->unlink();
3113 you.save = 0;
3114 return false;
3115 }
3116 // Shouldn't crash probably...
3117 fail("Aborting; you may try to recover it somehow.");
3118 }
3119 }
3120
_load_level(const level_id & level)3121 static void _load_level(const level_id &level)
3122 {
3123 // Load the given level.
3124 you.where_are_you = level.branch;
3125 you.depth = level.depth;
3126
3127 load_level(DNGN_STONE_STAIRS_DOWN_I, LOAD_VISITOR, level_id());
3128 }
3129
3130 // Given a level returns true if the level has been created already
3131 // in this game. Warning: after a game has ended, there is a phase where the
3132 // save has been deleted and this check isn't usable, and this is when a moruge
3133 // is generated.
is_existing_level(const level_id & level)3134 bool is_existing_level(const level_id &level)
3135 {
3136 return you.save && you.save->has_chunk(level.describe());
3137 }
3138
delete_level(const level_id & level)3139 void delete_level(const level_id &level)
3140 {
3141 travel_cache.erase_level_info(level);
3142 StashTrack.remove_level(level);
3143 shopping_list.del_things_from(level);
3144
3145 clear_level_exclusion_annotation(level);
3146 clear_level_annotations(level);
3147
3148 if (you.save)
3149 you.save->delete_chunk(level.describe());
3150
3151 auto &visited = you.props[VISITED_LEVELS_KEY].get_table();
3152 visited.erase(level.describe());
3153
3154 if (level.branch == BRANCH_ABYSS)
3155 {
3156 save_abyss_uniques();
3157 destroy_abyss();
3158 }
3159 _do_lost_monsters();
3160 _do_lost_items();
3161 }
3162
3163 // This class provides a way to walk the dungeon with a bit more flexibility
3164 // than you used to get with apply_to_all_dungeons.
level_excursion()3165 level_excursion::level_excursion()
3166 : original(level_id::current()), ever_changed_levels(false)
3167 {
3168 }
3169
go_to(const level_id & next)3170 void level_excursion::go_to(const level_id& next)
3171 {
3172 // This ASSERT is here because level excursions are often triggered as
3173 // side effects, e.g. in shopping list code, and we really don't want this
3174 // happening during normal levelgen (weird interactions with seeding,
3175 // potential crashes if items or monsters are incomplete, etc). However,
3176 // the abyss purposefully does level excursions in order to pick up
3177 // features from other levels and place them in the abyss: this is
3178 // basically safe to do, and seeding isn't a concern.
3179 ASSERT(!crawl_state.generating_level || original.branch == BRANCH_ABYSS);
3180
3181 if (level_id::current() != next)
3182 {
3183 if (!you.level_visited(level_id::current()))
3184 travel_cache.erase_level_info(level_id::current());
3185
3186 ever_changed_levels = true;
3187
3188 save_level(level_id::current());
3189 _load_level(next);
3190
3191 if (you.level_visited(next))
3192 {
3193 LevelInfo &li = travel_cache.get_level_info(next);
3194 li.set_level_excludes();
3195 }
3196 // TODO: this won't clear excludes on an excursion to an unvisited
3197 // level. Does this matter? Not right now, this case is only used for
3198 // abyss procgen.
3199 }
3200
3201 you.on_current_level = (level_id::current() == original);
3202 }
3203
~level_excursion()3204 level_excursion::~level_excursion()
3205 {
3206 // Go back to original level and reactivate markers if we ever
3207 // left the level.
3208 if (ever_changed_levels)
3209 {
3210 // This may be a no-op if the level-excursion subsequently
3211 // returned to the original level. However, at this point
3212 // markers will still not be activated.
3213 go_to(original);
3214
3215 // Quietly reactivate markers.
3216 env.markers.activate_all(false);
3217 }
3218 }
3219
get_save_version(reader & file)3220 save_version get_save_version(reader &file)
3221 {
3222 int major, minor;
3223 try
3224 {
3225 major = unmarshallUByte(file);
3226 minor = unmarshallUByte(file);
3227 if (minor == UINT8_MAX)
3228 minor = unmarshallInt(file);
3229 }
3230 catch (short_read_exception& E)
3231 {
3232 // Empty file?
3233 return save_version(-1, -1);
3234 }
3235 return save_version(major, minor);
3236 }
3237
write_save_version(writer & outf,save_version version)3238 void write_save_version(writer &outf, save_version version)
3239 {
3240 marshallUByte(outf, version.major);
3241 if (version.minor < UINT8_MAX)
3242 marshallUByte(outf, version.minor);
3243 else
3244 {
3245 marshallUByte(outf, UINT8_MAX);
3246 marshallInt(outf, version.minor);
3247 }
3248 }
3249
_convert_obsolete_species()3250 static bool _convert_obsolete_species()
3251 {
3252 // At this point the character has been loaded but not resaved, but the grid, lua, stashes, etc have not been.
3253 #if TAG_MAJOR_VERSION == 34
3254 if (you.species == SP_LAVA_ORC)
3255 {
3256 if (!yesno(
3257 "This Lava Orc save game cannot be loaded as-is. If you load it now,\n"
3258 "your character will be converted to a Hill Orc. Continue?",
3259 false, 'N'))
3260 {
3261 you.save->abort(); // don't even rewrite the header
3262 delete you.save;
3263 you.save = 0;
3264 game_ended(game_exit::abort,
3265 "Please load the save in an earlier version "
3266 "if you want to keep it as a Lava Orc.");
3267 }
3268 change_species_to(SP_HILL_ORC);
3269 // No need for conservation
3270 you.innate_mutation[MUT_CONSERVE_SCROLLS]
3271 = you.mutation[MUT_CONSERVE_SCROLLS] = 0;
3272 // This is not an elegant way to deal with lava, but at this point the
3273 // level isn't loaded so we can't check the grid features. In
3274 // addition, even if the player isn't over lava, they might still get
3275 // trapped.
3276 fly_player(100);
3277 return true;
3278 }
3279 #endif
3280 return false;
3281 }
3282
_read_char_chunk(package * save)3283 static bool _read_char_chunk(package *save)
3284 {
3285 reader inf(save, "chr");
3286
3287 try
3288 {
3289 const auto version = get_save_version(inf);
3290 const auto major = version.major, minor = version.minor;
3291 uint8_t format;
3292
3293 unsigned int len = unmarshallInt(inf);
3294 if (len > 1024) // something is fishy
3295 fail("Save file corrupted (info > 1KB)");
3296 vector<unsigned char> buf;
3297 buf.resize(len);
3298 inf.read(&buf[0], len);
3299 inf.fail_if_not_eof("chr");
3300 reader th(buf);
3301
3302 // 0.8 trunks (30.0 .. 32.12) were format 0 but without the marker.
3303 if (major > 32 || major == 32 && minor >= 13)
3304 th.read(&format, 1);
3305 else
3306 format = 0;
3307
3308 if (format > TAG_CHR_FORMAT)
3309 fail("Incompatible character data");
3310
3311 tag_read_char(th, format, major, minor);
3312
3313 // Check if we read everything only on the exact same version,
3314 // but that's the common case.
3315 if (major == TAG_MAJOR_VERSION && minor == TAG_MINOR_VERSION)
3316 inf.fail_if_not_eof("chr");
3317
3318 #if TAG_MAJOR_VERSION == 34
3319 if (major == 33 && minor == TAG_MINOR_0_11)
3320 return true;
3321 #endif
3322 return major == TAG_MAJOR_VERSION && minor <= TAG_MINOR_VERSION;
3323 }
3324 catch (short_read_exception &E)
3325 {
3326 fail("Save file corrupted");
3327 };
3328 }
3329
_tagged_chunk_version_compatible(reader & inf,string * reason)3330 static bool _tagged_chunk_version_compatible(reader &inf, string* reason)
3331 {
3332 ASSERT(reason);
3333
3334 const save_version version = get_save_version(inf);
3335
3336 if (!version.valid())
3337 {
3338 *reason = make_stringf("File is corrupt (found version %d,%d).",
3339 version.major, version.minor);
3340 return false;
3341 }
3342
3343 if (!version.is_compatible())
3344 {
3345 if (version.is_ancient())
3346 {
3347 const auto min_supported = save_version::minimum_supported();
3348 *reason = make_stringf("This save is from an older version.\n"
3349 "\n"
3350 CRAWL " %s is not compatible with save files this old. You can:\n"
3351 " • continue your game with an older version of " CRAWL "\n"
3352 " • delete it and start a new game\n"
3353 "\n"
3354 "This save's version: (%d.%d) (must be >= %d.%d)",
3355 Version::Short,
3356 version.major, version.minor,
3357 min_supported.major, min_supported.minor);
3358 }
3359 else if (version.is_future())
3360 {
3361 const auto current = save_version::current();
3362 *reason = make_stringf("This save is from a newer version.\n"
3363 "\n"
3364 CRAWL " cannot load saves from newer versions. You can:\n"
3365 " • continue your game with a newer version of " CRAWL "\n"
3366 " • delete it and start a new game\n"
3367 "\n"
3368 "This save's version: (%d.%d) (must be <= %d.%d)",
3369 version.major, version.minor,
3370 current.major, current.minor);
3371 }
3372 return false;
3373 }
3374
3375 inf.setMinorVersion(version.minor);
3376 return true;
3377 }
3378
_restore_tagged_chunk(package * save,const string & name,tag_type tag,const char * complaint)3379 static bool _restore_tagged_chunk(package *save, const string &name,
3380 tag_type tag, const char* complaint)
3381 {
3382 reader inf(save, name);
3383 string reason;
3384 if (!_tagged_chunk_version_compatible(inf, &reason))
3385 {
3386 if (!complaint)
3387 {
3388 dprf("chunk %s: %s", name.c_str(), reason.c_str());
3389 return false;
3390 }
3391 else
3392 end(-1, false, "\n%s %s\n", complaint, reason.c_str());
3393 }
3394
3395 crawl_state.minor_version = inf.getMinorVersion();
3396 try
3397 {
3398 tag_read(inf, tag);
3399 }
3400 catch (short_read_exception &E)
3401 {
3402 fail("truncated save chunk (%s)", name.c_str());
3403 };
3404
3405 inf.fail_if_not_eof(name);
3406 return true;
3407 }
3408
_ghost_version_compatible(const save_version & version)3409 static bool _ghost_version_compatible(const save_version &version)
3410 {
3411 if (!version.valid())
3412 return false;
3413 if (!version.is_compatible())
3414 {
3415 _ghost_dprf("Ghost version mismatch: ghost was %d.%d; current is %d.%d",
3416 version.major, version.minor,
3417 save_version::current().major, save_version::current().minor);
3418 return false;
3419 }
3420 return true;
3421 }
3422
3423 /**
3424 * Attempt to open a new bones file for saving ghosts.
3425 *
3426 * @param[out] return_gfilename The name of the file created, if any.
3427 * @return A FILE object, or nullptr.
3428 **/
_make_bones_file(string * return_gfilename)3429 static FILE* _make_bones_file(string * return_gfilename)
3430 {
3431 const string bone_dir = _get_bonefile_directory();
3432 const string base_filename = _make_ghost_filename(false);
3433
3434 for (int i = 0; i < GHOST_LIMIT; i++)
3435 {
3436 const string g_file_name = make_stringf("%s%s_%d", bone_dir.c_str(),
3437 base_filename.c_str(), i);
3438 FILE *ghost_file = lk_open_exclusive(g_file_name);
3439 // need to check file size, so can't open 'wb' - would truncate!
3440
3441 if (!ghost_file)
3442 {
3443 dprf("Could not open %s", g_file_name.c_str());
3444 continue;
3445 }
3446
3447 dprf("found %s", g_file_name.c_str());
3448
3449 *return_gfilename = g_file_name;
3450 return ghost_file;
3451 }
3452
3453 return nullptr;
3454 }
3455
3456 #define GHOST_PERMASTORE_SIZE 10
3457 #define GHOST_PERMASTORE_REPLACE_CHANCE 5
3458
_ghost_permastore_size()3459 static size_t _ghost_permastore_size()
3460 {
3461 if (_bones_save_individual_levels(true))
3462 return GHOST_PERMASTORE_SIZE;
3463 else
3464 return GHOST_PERMASTORE_SIZE * 2;
3465 }
3466
_update_permastore(const vector<ghost_demon> & ghosts)3467 static vector<ghost_demon> _update_permastore(const vector<ghost_demon> &ghosts)
3468 {
3469 rng::generator rng(rng::SYSTEM_SPECIFIC);
3470 if (ghosts.empty())
3471 return ghosts;
3472
3473 // this read is not locked...
3474 vector<ghost_demon> permastore = _load_permastore_ghosts();
3475 vector<ghost_demon> leftovers;
3476
3477 bool rewrite = false;
3478 unsigned int i = 0;
3479 const size_t max_ghosts = _ghost_permastore_size();
3480 while (permastore.size() < max_ghosts && i < ghosts.size())
3481 {
3482 // TODO: heuristics to make this as distinct as possible; maybe
3483 // create a new name?
3484 permastore.push_back(ghosts[i]);
3485 #ifdef DGAMELAUNCH
3486 // randomize name for online play
3487 permastore.back().name = make_name();
3488 #endif
3489 i++;
3490 rewrite = true;
3491 }
3492 if (i > 0)
3493 _ghost_dprf("Permastoring %d ghosts", i);
3494 if (!rewrite && x_chance_in_y(GHOST_PERMASTORE_REPLACE_CHANCE, 100)
3495 && i < ghosts.size())
3496 {
3497 int rewrite_i = random2(permastore.size());
3498 permastore[rewrite_i] = ghosts[i];
3499 #ifdef DGAMELAUNCH
3500 permastore[rewrite_i].name = make_name();
3501 #endif
3502 rewrite = true;
3503 }
3504 while (i < ghosts.size())
3505 {
3506 leftovers.push_back(ghosts[i]);
3507 i++;
3508 }
3509
3510 if (rewrite)
3511 {
3512 string permastore_file = _bones_permastore_file();
3513
3514 // the following is to ensure that an old game doesn't overwrite a
3515 // permastore that has a version in the future relative to that game.
3516 {
3517 reader inf(permastore_file);
3518 if (inf.valid())
3519 {
3520 inf.set_safe_read(true); // don't die on 0-byte bones
3521 save_version version = read_ghost_header(inf);
3522 if (version.valid() && version.is_future())
3523 {
3524 permastore_file = _old_bones_filename(permastore_file,
3525 save_version::current());
3526 }
3527 inf.close();
3528 }
3529 }
3530
3531 FILE *ghost_file = lk_open("wb", permastore_file);
3532
3533 if (!ghost_file)
3534 {
3535 // this will fail silently if the lock fails, seems safest
3536 // TODO: better lock system for servers?
3537 _ghost_dprf("Could not open ghost permastore: %s",
3538 permastore_file.c_str());
3539 return ghosts;
3540 }
3541
3542 _ghost_dprf("Rewriting ghost permastore %s with %u ghosts",
3543 permastore_file.c_str(), (unsigned int) permastore.size());
3544 writer outw(permastore_file, ghost_file);
3545 write_ghost_version(outw);
3546 tag_write_ghosts(outw, permastore);
3547
3548 lk_close(ghost_file);
3549 }
3550 return leftovers;
3551 }
3552
3553 /**
3554 * Attempt to save all ghosts from the current level.
3555 *
3556 * Including the player, if they're not undead. Doesn't save ghosts from D:1-2
3557 * or Temple.
3558 *
3559 * @param force Forces ghost generation even in otherwise-disallowed levels.
3560 **/
save_ghosts(const vector<ghost_demon> & ghosts,bool force,bool use_store)3561 void save_ghosts(const vector<ghost_demon> &ghosts, bool force, bool use_store)
3562 {
3563 // n.b. this is not called in the normal course of events for wizmode
3564 // chars, so for debugging anything to do with deaths in wizmode, you will
3565 // need to edit a conditional at the end of ouch.cc:ouch.
3566 _ghost_dprf("Trying to save ghosts.");
3567 if (ghosts.empty())
3568 {
3569 _ghost_dprf("Could not find any ghosts for this level to save.");
3570 return;
3571 }
3572
3573 if (!force && !ghost_demon::ghost_eligible())
3574 {
3575 _ghost_dprf("No eligible ghosts.");
3576 return;
3577 }
3578
3579 vector<ghost_demon> leftovers;
3580 if (use_store)
3581 leftovers = _update_permastore(ghosts);
3582 else
3583 leftovers = ghosts;
3584 if (leftovers.size() == 0)
3585 return;
3586
3587 if (_list_bones().size() >= static_cast<size_t>(GHOST_LIMIT))
3588 {
3589 _ghost_dprf("Too many ghosts for this level already!");
3590 return;
3591 }
3592
3593 string g_file_name = "";
3594 FILE* ghost_file = _make_bones_file(&g_file_name);
3595
3596 if (!ghost_file)
3597 {
3598 _ghost_dprf("Could not open file to save ghosts.");
3599 return;
3600 }
3601
3602 writer outw(g_file_name, ghost_file);
3603
3604 write_ghost_version(outw);
3605 tag_write_ghosts(outw, leftovers);
3606
3607 lk_close(ghost_file);
3608
3609 _ghost_dprf("Saved ghosts (%s).", g_file_name.c_str());
3610 }
3611
3612 ////////////////////////////////////////////////////////////////////////////
3613 // Locking
3614
lock_file_handle(FILE * handle,bool write)3615 bool lock_file_handle(FILE *handle, bool write)
3616 {
3617 return lock_file(fileno(handle), write, true);
3618 }
3619
unlock_file_handle(FILE * handle)3620 bool unlock_file_handle(FILE *handle)
3621 {
3622 return unlock_file(fileno(handle));
3623 }
3624
3625 /**
3626 * Attempts to open & lock a file.
3627 *
3628 * @param mode The file access mode. ('r', 'ab+', etc)
3629 * @param file The path to the file to be opened.
3630 * @return A handle for the specified file, if successful; else nullptr.
3631 */
lk_open(const char * mode,const string & file)3632 FILE *lk_open(const char *mode, const string &file)
3633 {
3634 ASSERT(mode);
3635
3636 FILE *handle = fopen_u(file.c_str(), mode);
3637 if (!handle)
3638 return nullptr;
3639
3640 const bool write_lock = mode[0] != 'r' || strchr(mode, '+');
3641 if (!lock_file_handle(handle, write_lock))
3642 {
3643 mprf(MSGCH_ERROR, "ERROR: Could not lock file %s", file.c_str());
3644 fclose(handle);
3645 handle = nullptr;
3646 }
3647
3648 return handle;
3649 }
3650
3651 /**
3652 * Attempts to open and lock a file for exclusive write access; fails if
3653 * the file already exists.
3654 *
3655 * @param file The path to the file to be opened.
3656 * @return A locked file handle for the specified file, if
3657 * successful; else nullptr.
3658 */
lk_open_exclusive(const string & file)3659 FILE *lk_open_exclusive(const string &file)
3660 {
3661 int fd = open_u(file.c_str(), O_WRONLY|O_BINARY|O_EXCL|O_CREAT, 0666);
3662 if (fd < 0)
3663 return nullptr;
3664
3665 if (!lock_file(fd, true))
3666 {
3667 mprf(MSGCH_ERROR, "ERROR: Could not lock file %s", file.c_str());
3668 close(fd);
3669 return nullptr;
3670 }
3671
3672 return fdopen(fd, "wb");
3673 }
3674
lk_close(FILE * handle)3675 void lk_close(FILE *handle)
3676 {
3677 if (handle == nullptr || handle == stdin)
3678 return;
3679
3680 unlock_file_handle(handle);
3681
3682 // actually close
3683 fclose(handle);
3684 }
3685
3686 /////////////////////////////////////////////////////////////////////////////
3687 // file_lock
3688 //
3689 // Locks a named file (usually an empty lock file), creating it if necessary.
3690
file_lock(const string & s,const char * _mode,bool die_on_fail)3691 file_lock::file_lock(const string &s, const char *_mode, bool die_on_fail)
3692 : handle(nullptr), mode(_mode), filename(s)
3693 {
3694 if (!(handle = lk_open(mode, filename)) && die_on_fail)
3695 end(1, true, "Unable to open lock file \"%s\"", filename.c_str());
3696 }
3697
~file_lock()3698 file_lock::~file_lock()
3699 {
3700 if (handle)
3701 lk_close(handle);
3702 }
3703
3704 /////////////////////////////////////////////////////////////////////////////
3705
fopen_replace(const char * name)3706 FILE *fopen_replace(const char *name)
3707 {
3708 int fd;
3709
3710 // Stave off symlink attacks. Races will be handled with O_EXCL.
3711 unlink_u(name);
3712 fd = open_u(name, O_CREAT|O_EXCL|O_WRONLY, 0666);
3713 if (fd == -1)
3714 return 0;
3715 return fdopen(fd, "w");
3716 }
3717
3718 // Returns the size of the opened file with the give FILE* handle.
file_size(FILE * handle)3719 off_t file_size(FILE *handle)
3720 {
3721 #ifdef __ANDROID__
3722 off_t pos = ftello(handle);
3723 if (fseeko(handle, 0, SEEK_END) < 0)
3724 return 0;
3725 off_t ret = ftello(handle);
3726 fseeko(handle, pos, SEEK_SET);
3727 return ret;
3728 #else
3729 struct stat fs;
3730 const int err = fstat(fileno(handle), &fs);
3731 return err? 0 : fs.st_size;
3732 #endif
3733 }
3734
get_title_files()3735 vector<string> get_title_files()
3736 {
3737 vector<string> titles;
3738 for (const string &dir : _get_base_dirs())
3739 for (const string &file : get_dir_files_sorted(dir))
3740 if (file.substr(0, 6) == "title_")
3741 titles.push_back(file);
3742 return titles;
3743 }
3744