1 /**
2 * @file
3 * @brief Auxiliary functions to make savefile versioning simpler.
4 **/
5
6 /*
7 The marshalling and unmarshalling of data is done in big endian and
8 is meant to keep savefiles cross-platform. Note also that the marshalling
9 sizes are 1, 2, and 4 for byte, short, and int. If a strange platform
10 with different sizes of these basic types pops up, please sed it to fixed-
11 width ones. For now, that wasn't done in order to keep things convenient.
12 */
13
14 #include "AppHdr.h"
15
16 #include "feature.h"
17 #include "mpr.h"
18 #include "tags.h"
19
20 #include <algorithm>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <iterator>
25 #include <vector>
26 #ifdef UNIX
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #endif
32
33 #include "abyss.h"
34 #include "act-iter.h"
35 #include "artefact.h"
36 #include "art-enum.h"
37 #include "branch.h"
38 #include "chardump.h"
39 #include "colour.h"
40 #include "coordit.h"
41 #if TAG_MAJOR_VERSION == 34
42 #include "decks.h"
43 #endif
44 #include "dbg-scan.h"
45 #include "dbg-util.h"
46 #include "describe.h"
47 #include "dgn-overview.h"
48 #include "dungeon.h"
49 #include "end.h"
50 #include "tile-env.h"
51 #include "errors.h"
52 #include "ghost.h"
53 #include "god-abil.h" // just for the Ru sac penalty key
54 #include "god-passive.h"
55 #include "god-companions.h"
56 #include "item-name.h"
57 #include "item-prop.h"
58 #include "item-status-flag-type.h"
59 #include "item-type-id-state-type.h"
60 #include "items.h"
61 #include "jobs.h"
62 #include "mapmark.h"
63 #include "misc.h"
64 #include "mon-death.h"
65 #if TAG_MAJOR_VERSION == 34
66 #include "mon-place.h"
67 #include "mon-poly.h"
68 #include "mon-tentacle.h"
69 #include "mon-util.h"
70 #endif
71 #include "mutation.h"
72 #include "place.h"
73 #include "player-stats.h"
74 #include "prompt.h" // index_to_letter
75 #include "religion.h"
76 #include "skills.h"
77 #include "species.h"
78 #include "spl-wpnench.h"
79 #include "state.h"
80 #include "stringutil.h"
81 #include "syscalls.h"
82 #include "tag-version.h"
83 #include "terrain.h"
84 #include "rltiles/tiledef-dngn.h"
85 #include "rltiles/tiledef-player.h"
86 #include "tilepick.h"
87 #include "tileview.h"
88 #ifdef USE_TILE
89 #include "tilemcache.h"
90 #endif
91 #include "transform.h"
92 #include "unwind.h"
93 #include "version.h"
94
95 vector<ghost_demon> global_ghosts; // only for reading/writing
96
97 // defined in dgn-overview.cc
98 extern map<branch_type, set<level_id> > stair_level;
99 extern map<level_pos, shop_type> shops_present;
100 extern map<level_pos, god_type> altars_present;
101 extern map<level_pos, branch_type> portals_present;
102 extern map<level_pos, string> portal_notes;
103 extern map<level_id, string> level_annotations;
104 extern map<level_id, string> level_exclusions;
105 extern map<level_id, string> level_uniques;
106 extern set<pair<string, level_id> > auto_unique_annotations;
107
108 // defined in abyss.cc
109 extern abyss_state abyssal_state;
110
reader(const string & _read_filename,int minorVersion)111 reader::reader(const string &_read_filename, int minorVersion)
112 : _filename(_read_filename), _chunk(0), _pbuf(nullptr), _read_offset(0),
113 _minorVersion(minorVersion), _safe_read(false)
114 {
115 _file = fopen_u(_filename.c_str(), "rb");
116 opened_file = !!_file;
117 }
118
reader(package * save,const string & chunkname,int minorVersion)119 reader::reader(package *save, const string &chunkname, int minorVersion)
120 : _file(0), _chunk(0), opened_file(false), _pbuf(0), _read_offset(0),
121 _minorVersion(minorVersion), _safe_read(false)
122 {
123 ASSERT(save);
124 _chunk = new chunk_reader(save, chunkname);
125 }
126
~reader()127 reader::~reader()
128 {
129 if (_chunk)
130 delete _chunk;
131 close();
132 }
133
close()134 void reader::close()
135 {
136 if (opened_file && _file)
137 fclose(_file);
138 _file = nullptr;
139 }
140
advance(size_t offset)141 void reader::advance(size_t offset)
142 {
143 char junk[128];
144
145 while (offset)
146 {
147 const size_t junklen = min(sizeof(junk), offset);
148 offset -= junklen;
149 read(junk, junklen);
150 }
151 }
152
valid() const153 bool reader::valid() const
154 {
155 return (_file && !feof(_file)) ||
156 (_pbuf && _read_offset < _pbuf->size());
157 }
158
_short_read(bool safe_read)159 static NORETURN void _short_read(bool safe_read)
160 {
161 if (!crawl_state.need_save || safe_read)
162 throw short_read_exception();
163 // Would be nice to name the save chunk here, but in interesting cases
164 // we're reading a copy from memory (why?).
165 die_noline("short read while reading save");
166 }
167
168 // Reads input in network byte order, from a file or buffer.
readByte()169 unsigned char reader::readByte()
170 {
171 if (_file)
172 {
173 int b = fgetc(_file);
174 if (b == EOF)
175 _short_read(_safe_read);
176 return b;
177 }
178 else if (_chunk)
179 {
180 unsigned char buf;
181 if (_chunk->read(&buf, 1) != 1)
182 _short_read(_safe_read);
183 return buf;
184 }
185 else
186 {
187 if (_read_offset >= _pbuf->size())
188 _short_read(_safe_read);
189 return (*_pbuf)[_read_offset++];
190 }
191 }
192
read(void * data,size_t size)193 void reader::read(void *data, size_t size)
194 {
195 if (_file)
196 {
197 if (data)
198 {
199 if (fread(data, 1, size, _file) != size)
200 _short_read(_safe_read);
201 }
202 else
203 fseek(_file, (long)size, SEEK_CUR);
204 }
205 else if (_chunk)
206 {
207 if (_chunk->read(data, size) != size)
208 _short_read(_safe_read);
209 }
210 else
211 {
212 if (_read_offset+size > _pbuf->size())
213 _short_read(_safe_read);
214 if (data && size)
215 memcpy(data, &(*_pbuf)[_read_offset], size);
216
217 _read_offset += size;
218 }
219 }
220
getMinorVersion() const221 int reader::getMinorVersion() const
222 {
223 ASSERT(_minorVersion != TAG_MINOR_INVALID);
224 return _minorVersion;
225 }
226
setMinorVersion(int minorVersion)227 void reader::setMinorVersion(int minorVersion)
228 {
229 _minorVersion = minorVersion;
230 }
231
fail_if_not_eof(const string & name)232 void reader::fail_if_not_eof(const string &name)
233 {
234 char dummy;
235 if (_chunk ? _chunk->read(&dummy, 1) :
236 _file ? (fgetc(_file) != EOF) :
237 _read_offset >= _pbuf->size())
238 {
239 fail("Incomplete read of \"%s\" - aborting.", name.c_str());
240 }
241 }
242
check_ok(bool ok)243 void writer::check_ok(bool ok)
244 {
245 if (!ok && !failed)
246 {
247 failed = true;
248 if (!_ignore_errors)
249 end(1, true, "Error writing to %s", _filename.c_str());
250 }
251 }
252
writeByte(unsigned char ch)253 void writer::writeByte(unsigned char ch)
254 {
255 if (failed)
256 return;
257
258 if (_chunk)
259 _chunk->write(&ch, 1);
260 else if (_file)
261 check_ok(fputc(ch, _file) != EOF);
262 else
263 _pbuf->push_back(ch);
264 }
265
write(const void * data,size_t size)266 void writer::write(const void *data, size_t size)
267 {
268 if (failed)
269 return;
270
271 if (_chunk)
272 _chunk->write(data, size);
273 else if (_file)
274 check_ok(fwrite(data, 1, size, _file) == size);
275 else
276 {
277 const unsigned char* cdata = static_cast<const unsigned char*>(data);
278 _pbuf->insert(_pbuf->end(), cdata, cdata+size);
279 }
280 }
281
tell()282 long writer::tell()
283 {
284 ASSERT(!_chunk);
285 return _file? ftell(_file) : _pbuf->size();
286 }
287
288 #ifdef DEBUG_GLOBALS
289 // Force a conditional jump valgrind may pick up, no matter the optimizations.
290 static volatile uint32_t hashroll;
CHECK_INITIALIZED(uint32_t x)291 static void CHECK_INITIALIZED(uint32_t x)
292 {
293 hashroll = 0;
294 if ((hashroll += x) & 1)
295 hashroll += 2;
296 }
297 #else
298 #define CHECK_INITIALIZED(x)
299 #endif
300
301 // static helper declarations
302 static void _tag_construct_char(writer &th);
303 static void _tag_construct_you(writer &th);
304 static void _tag_construct_you_items(writer &th);
305 static void _tag_construct_you_dungeon(writer &th);
306 static void _tag_construct_lost_monsters(writer &th);
307 static void _tag_construct_companions(writer &th);
308 static void _tag_read_you(reader &th);
309 static void _tag_read_you_items(reader &th);
310 static void _tag_read_you_dungeon(reader &th);
311 static void _tag_read_lost_monsters(reader &th);
312 #if TAG_MAJOR_VERSION == 34
313 static void _tag_read_lost_items(reader &th);
314 #endif
315 static void _tag_read_companions(reader &th);
316
317 static void _tag_construct_level(writer &th);
318 static void _tag_construct_level_items(writer &th);
319 static void _tag_construct_level_monsters(writer &th);
320 static void _tag_construct_level_tiles(writer &th);
321 static void _tag_read_level(reader &th);
322 static void _tag_read_level_items(reader &th);
323 static void _tag_read_level_monsters(reader &th);
324 static void _tag_read_level_tiles(reader &th);
325 static void _regenerate_tile_flavour();
326 static void _draw_tiles();
327
328 static void _tag_construct_ghost(writer &th, vector<ghost_demon> &);
329 static vector<ghost_demon> _tag_read_ghost(reader &th);
330
331 static void _marshallGhost(writer &th, const ghost_demon &ghost);
332 static ghost_demon _unmarshallGhost(reader &th);
333
334 static void _marshallSpells(writer &, const monster_spells &);
335
336 static void _marshallMonsterInfo (writer &, const monster_info &);
337 static void _unmarshallMonsterInfo (reader &, monster_info &mi);
338
339 template<typename T, typename T_iter, typename T_marshal>
340 static void _marshall_iterator(writer &th, T_iter beg, T_iter end,
341 T_marshal marshal);
342 template<typename T, typename U>
343 static void _unmarshall_vector(reader& th, vector<T>& vec, U T_unmarshall);
344
345 template<int SIZE>
346 static void _marshallFixedBitVector(writer& th, const FixedBitVector<SIZE>& arr);
347 template<int SIZE>
348 static void _unmarshallFixedBitVector(reader& th, FixedBitVector<SIZE>& arr);
349
marshallByte(writer & th,int8_t data)350 void marshallByte(writer &th, int8_t data)
351 {
352 CHECK_INITIALIZED(data);
353 th.writeByte(data);
354 }
355
unmarshallByte(reader & th)356 int8_t unmarshallByte(reader &th)
357 {
358 return th.readByte();
359 }
360
marshallUByte(writer & th,uint8_t data)361 void marshallUByte(writer &th, uint8_t data)
362 {
363 CHECK_INITIALIZED(data);
364 th.writeByte(data);
365 }
366
unmarshallUByte(reader & th)367 uint8_t unmarshallUByte(reader &th)
368 {
369 return th.readByte();
370 }
371
372 // Marshall 2 byte short in network order.
marshallShort(writer & th,short data)373 void marshallShort(writer &th, short data)
374 {
375 // TODO: why does this use `short` and `char` when unmarshall uses int16_t??
376 CHECK_INITIALIZED(data);
377 const char b2 = (char)(data & 0x00FF);
378 const char b1 = (char)((data & 0xFF00) >> 8);
379 th.writeByte(b1);
380 th.writeByte(b2);
381 }
382
383 // Unmarshall 2 byte short in network order.
unmarshallShort(reader & th)384 int16_t unmarshallShort(reader &th)
385 {
386 int16_t b1 = th.readByte();
387 int16_t b2 = th.readByte();
388 int16_t data = (b1 << 8) | (b2 & 0x00FF);
389 return data;
390 }
391
392 // Marshall 4 byte int in network order.
marshallInt(writer & th,int32_t data)393 void marshallInt(writer &th, int32_t data)
394 {
395 CHECK_INITIALIZED(data);
396 char b4 = (char) (data & 0x000000FF);
397 char b3 = (char)((data & 0x0000FF00) >> 8);
398 char b2 = (char)((data & 0x00FF0000) >> 16);
399 char b1 = (char)((data & 0xFF000000) >> 24);
400
401 th.writeByte(b1);
402 th.writeByte(b2);
403 th.writeByte(b3);
404 th.writeByte(b4);
405 }
406
407 // Unmarshall 4 byte signed int in network order.
unmarshallInt(reader & th)408 int32_t unmarshallInt(reader &th)
409 {
410 int32_t b1 = th.readByte();
411 int32_t b2 = th.readByte();
412 int32_t b3 = th.readByte();
413 int32_t b4 = th.readByte();
414
415 int32_t data = (b1 << 24) | ((b2 & 0x000000FF) << 16);
416 data |= ((b3 & 0x000000FF) << 8) | (b4 & 0x000000FF);
417 return data;
418 }
419
marshallUnsigned(writer & th,uint64_t v)420 void marshallUnsigned(writer& th, uint64_t v)
421 {
422 do
423 {
424 unsigned char b = (unsigned char)(v & 0x7f);
425 v >>= 7;
426 if (v)
427 b |= 0x80;
428 th.writeByte(b);
429 }
430 while (v);
431 }
432
unmarshallUnsigned(reader & th)433 uint64_t unmarshallUnsigned(reader& th)
434 {
435 unsigned i = 0;
436 uint64_t v = 0;
437 for (;;)
438 {
439 unsigned char b = th.readByte();
440 v |= (uint64_t)(b & 0x7f) << i;
441 i += 7;
442 if (!(b & 0x80))
443 break;
444 }
445 return v;
446 }
447
marshallSigned(writer & th,int64_t v)448 void marshallSigned(writer& th, int64_t v)
449 {
450 if (v < 0)
451 marshallUnsigned(th, (uint64_t)((-v - 1) << 1) | 1);
452 else
453 marshallUnsigned(th, (uint64_t)(v << 1));
454 }
455
unmarshallSigned(reader & th)456 int64_t unmarshallSigned(reader& th)
457 {
458 uint64_t u;
459 unmarshallUnsigned(th, u);
460 if (u & 1)
461 return (int64_t)(-(u >> 1) - 1);
462 else
463 return (int64_t)(u >> 1);
464 }
465
466 // Optimized for short vectors that have only the first few bits set, and
467 // can have invalid length. For long ones you might want to do this
468 // differently to not lose 1/8 bits and speed.
469 template<int SIZE>
_marshallFixedBitVector(writer & th,const FixedBitVector<SIZE> & arr)470 void _marshallFixedBitVector(writer& th, const FixedBitVector<SIZE>& arr)
471 {
472 int last_bit;
473 for (last_bit = SIZE - 1; last_bit > 0; last_bit--)
474 if (arr[last_bit])
475 break;
476
477 int i = 0;
478 while (1)
479 {
480 uint8_t byte = 0;
481 for (int j = 0; j < 7; j++)
482 if (i < SIZE && arr[i++])
483 byte |= 1 << j;
484 if (i <= last_bit)
485 marshallUByte(th, byte);
486 else
487 {
488 marshallUByte(th, byte | 0x80);
489 break;
490 }
491 }
492 }
493
494 template<int SIZE>
_unmarshallFixedBitVector(reader & th,FixedBitVector<SIZE> & arr)495 void _unmarshallFixedBitVector(reader& th, FixedBitVector<SIZE>& arr)
496 {
497 arr.reset();
498
499 int i = 0;
500 while (1)
501 {
502 uint8_t byte = unmarshallUByte(th);
503 for (int j = 0; j < 7; j++)
504 if (i < SIZE)
505 arr.set(i++, !!(byte & (1 << j)));
506 if (byte & 0x80)
507 break;
508 }
509 }
510
511 // FIXME: Kill this abomination - it will break!
512 template<typename T>
_marshall_as_int(writer & th,const T & t)513 static void _marshall_as_int(writer& th, const T& t)
514 {
515 marshallInt(th, static_cast<int>(t));
516 }
517
518 template <typename data>
marshallSet(writer & th,const set<data> & s,void (* marshall)(writer &,const data &))519 void marshallSet(writer &th, const set<data> &s,
520 void (*marshall)(writer &, const data &))
521 {
522 marshallInt(th, s.size());
523 for (const data &elt : s)
524 marshall(th, elt);
525 }
526
527 template<typename key, typename value>
marshallMap(writer & th,const map<key,value> & data,void (* key_marshall)(writer &,const key &),void (* value_marshall)(writer &,const value &))528 void marshallMap(writer &th, const map<key,value>& data,
529 void (*key_marshall)(writer&, const key&),
530 void (*value_marshall)(writer&, const value&))
531 {
532 marshallInt(th, data.size());
533 for (const auto &entry : data)
534 {
535 key_marshall(th, entry.first);
536 value_marshall(th, entry.second);
537 }
538 }
539
540 template<typename T_iter, typename T_marshall_t>
_marshall_iterator(writer & th,T_iter beg,T_iter end,T_marshall_t T_marshall)541 static void _marshall_iterator(writer &th, T_iter beg, T_iter end,
542 T_marshall_t T_marshall)
543 {
544 marshallInt(th, distance(beg, end));
545 while (beg != end)
546 {
547 T_marshall(th, *beg);
548 ++beg;
549 }
550 }
551
552 template<typename T, typename U>
_unmarshall_vector(reader & th,vector<T> & vec,U T_unmarshall)553 static void _unmarshall_vector(reader& th, vector<T>& vec, U T_unmarshall)
554 {
555 vec.clear();
556 const int num_to_read = unmarshallInt(th);
557 for (int i = 0; i < num_to_read; ++i)
558 vec.push_back(T_unmarshall(th));
559 }
560
561 template <typename T_container, typename T_inserter, typename T_unmarshall>
unmarshall_container(reader & th,T_container & container,T_inserter inserter,T_unmarshall unmarshal)562 static void unmarshall_container(reader &th, T_container &container,
563 T_inserter inserter, T_unmarshall unmarshal)
564 {
565 container.clear();
566 const int num_to_read = unmarshallInt(th);
567 for (int i = 0; i < num_to_read; ++i)
568 (container.*inserter)(unmarshal(th));
569 }
570
_pack(const level_id & id)571 static unsigned short _pack(const level_id& id)
572 {
573 return (static_cast<int>(id.branch) << 8) | (id.depth & 0xFF);
574 }
575
marshall_level_id(writer & th,const level_id & id)576 void marshall_level_id(writer& th, const level_id& id)
577 {
578 marshallShort(th, _pack(id));
579 }
580
_marshall_level_id_set(writer & th,const set<level_id> & id)581 static void _marshall_level_id_set(writer& th, const set<level_id>& id)
582 {
583 marshallSet(th, id, marshall_level_id);
584 }
585
586 // XXX: Redundant with level_pos.save()/load().
_marshall_level_pos(writer & th,const level_pos & lpos)587 static void _marshall_level_pos(writer& th, const level_pos& lpos)
588 {
589 marshallInt(th, lpos.pos.x);
590 marshallInt(th, lpos.pos.y);
591 marshall_level_id(th, lpos.id);
592 }
593
594 template <typename data, typename set>
unmarshallSet(reader & th,set & dset,data (* data_unmarshall)(reader &))595 void unmarshallSet(reader &th, set &dset,
596 data (*data_unmarshall)(reader &))
597 {
598 dset.clear();
599 int len = unmarshallInt(th);
600 for (int i = 0; i < len; ++i)
601 dset.insert(data_unmarshall(th));
602 }
603
604 template<typename key, typename value, typename map>
unmarshallMap(reader & th,map & data,key (* key_unmarshall)(reader &),value (* value_unmarshall)(reader &))605 void unmarshallMap(reader& th, map& data,
606 key (*key_unmarshall) (reader&),
607 value (*value_unmarshall)(reader&))
608 {
609 const int len = unmarshallInt(th);
610 key k;
611 for (int i = 0; i < len; ++i)
612 {
613 k = key_unmarshall(th);
614 pair<key, value> p(k, value_unmarshall(th));
615 data.insert(p);
616 }
617 }
618
619 template<typename T>
unmarshall_int_as(reader & th)620 static T unmarshall_int_as(reader& th)
621 {
622 return static_cast<T>(unmarshallInt(th));
623 }
624
625 #if TAG_MAJOR_VERSION == 34
from_packed_place(unsigned short place)626 level_id level_id::from_packed_place(unsigned short place)
627 #else
628 static level_id _unpack(unsigned short place)
629 #endif
630 {
631 level_id id;
632
633 id.branch = static_cast<branch_type>((place >> 8) & 0xFF);
634 id.depth = (int8_t)(place & 0xFF);
635
636 return id;
637 }
638
unmarshall_level_id(reader & th)639 level_id unmarshall_level_id(reader& th)
640 {
641 #if TAG_MAJOR_VERSION == 34
642 return level_id::from_packed_place(unmarshallShort(th));
643 #else
644 return _unpack(unmarshallShort(th));
645 #endif
646 }
647
_unmarshall_level_id_set(reader & th)648 static set<level_id> _unmarshall_level_id_set(reader& th)
649 {
650 set<level_id> id;
651 unmarshallSet(th, id, unmarshall_level_id);
652 return id;
653 }
654
_unmarshall_level_pos(reader & th)655 static level_pos _unmarshall_level_pos(reader& th)
656 {
657 level_pos lpos;
658 lpos.pos.x = unmarshallInt(th);
659 lpos.pos.y = unmarshallInt(th);
660 lpos.id = unmarshall_level_id(th);
661 return lpos;
662 }
663
marshallCoord(writer & th,const coord_def & c)664 void marshallCoord(writer &th, const coord_def &c)
665 {
666 marshallInt(th, c.x);
667 marshallInt(th, c.y);
668 }
669
unmarshallCoord(reader & th)670 coord_def unmarshallCoord(reader &th)
671 {
672 coord_def c;
673 #if TAG_MAJOR_VERSION == 34
674 if (th.getMinorVersion() >= TAG_MINOR_COORD_SERIALIZER
675 && th.getMinorVersion() != TAG_MINOR_0_11)
676 {
677 #endif
678 c.x = unmarshallInt(th);
679 c.y = unmarshallInt(th);
680 #if TAG_MAJOR_VERSION == 34
681 }
682 else
683 {
684 c.x = unmarshallShort(th);
685 c.y = unmarshallShort(th);
686 }
687 #endif
688 return c;
689 }
690
691 #if TAG_MAJOR_VERSION == 34
692 // Between TAG_MINOR_OPTIONAL_PARTS and TAG_MINOR_FIXED_CONSTRICTION
693 // we neglected to marshall the constricting[] map of monsters. Fix
694 // those up.
_fix_missing_constrictions()695 static void _fix_missing_constrictions()
696 {
697 for (int i = -1; i < MAX_MONSTERS; ++i)
698 {
699 const actor* m = i < 0 ? (actor*)&you : (actor*)&env.mons[i];
700 if (!m->alive())
701 continue;
702 if (!m->constricted_by)
703 continue;
704 actor *h = actor_by_mid(m->constricted_by);
705 // Not a known bug, so don't fix this up.
706 if (!h)
707 continue;
708
709 if (!h->constricting)
710 h->constricting = new actor::constricting_t;
711 if (h->constricting->find(m->mid) == h->constricting->end())
712 {
713 dprf("Fixing missing constriction for %s (mindex=%d mid=%d)"
714 " of %s (mindex=%d mid=%d)",
715 h->name(DESC_PLAIN, true).c_str(), h->mindex(), h->mid,
716 m->name(DESC_PLAIN, true).c_str(), m->mindex(), m->mid);
717
718 (*h->constricting)[m->mid] = 0;
719 }
720 }
721 }
722 #endif
723
_marshall_constriction(writer & th,const actor * who)724 static void _marshall_constriction(writer &th, const actor *who)
725 {
726 marshallInt(th, who->constricted_by);
727 marshallInt(th, who->escape_attempts);
728
729 // Assumes an empty map is marshalled as just the int 0.
730 const actor::constricting_t * const cmap = who->constricting;
731 if (cmap)
732 marshallMap(th, *cmap, _marshall_as_int<mid_t>, _marshall_as_int<int>);
733 else
734 marshallInt(th, 0);
735 }
736
_unmarshall_constriction(reader & th,actor * who)737 static void _unmarshall_constriction(reader &th, actor *who)
738 {
739 #if TAG_MAJOR_VERSION == 34
740 if (th.getMinorVersion() < TAG_MINOR_NO_ACTOR_HELD)
741 unmarshallInt(th);
742 #endif
743 who->constricted_by = unmarshallInt(th);
744 who->escape_attempts = unmarshallInt(th);
745
746 actor::constricting_t cmap;
747 unmarshallMap(th, cmap, unmarshall_int_as<mid_t>, unmarshallInt);
748
749 if (cmap.size() == 0)
750 who->constricting = 0;
751 else
752 who->constricting = new actor::constricting_t(cmap);
753 }
754
755 template <typename marshall, typename grid>
_run_length_encode(writer & th,marshall m,const grid & g,int width,int height)756 static void _run_length_encode(writer &th, marshall m, const grid &g,
757 int width, int height)
758 {
759 int last = 0, nlast = 0;
760 for (int y = 0; y < height; ++y)
761 for (int x = 0; x < width; ++x)
762 {
763 if (!nlast)
764 last = g[x][y];
765 if (last == g[x][y] && nlast < 255)
766 {
767 nlast++;
768 continue;
769 }
770
771 marshallByte(th, nlast);
772 m(th, last);
773
774 last = g[x][y];
775 nlast = 1;
776 }
777
778 marshallByte(th, nlast);
779 m(th, last);
780 }
781
782 template <typename unmarshall, typename grid>
_run_length_decode(reader & th,unmarshall um,grid & g,int width,int height)783 static void _run_length_decode(reader &th, unmarshall um, grid &g,
784 int width, int height)
785 {
786 const int end = width * height;
787 int offset = 0;
788 while (offset < end)
789 {
790 const int run = unmarshallUByte(th);
791 const int value = um(th);
792
793 for (int i = 0; i < run; ++i)
794 {
795 const int y = offset / width;
796 const int x = offset % width;
797 g[x][y] = value;
798 ++offset;
799 }
800 }
801 }
802
803 union float_marshall_kludge
804 {
805 float f_num;
806 int32_t l_num;
807 };
808 COMPILE_CHECK(sizeof(float) == sizeof(int32_t));
809
810 // single precision float -- marshall in network order.
marshallFloat(writer & th,float data)811 void marshallFloat(writer &th, float data)
812 {
813 float_marshall_kludge k;
814 k.f_num = data;
815 marshallInt(th, k.l_num);
816 }
817
818 // single precision float -- unmarshall in network order.
unmarshallFloat(reader & th)819 float unmarshallFloat(reader &th)
820 {
821 float_marshall_kludge k;
822 k.l_num = unmarshallInt(th);
823 return k.f_num;
824 }
825
826 // string -- 2 byte length, string data
marshallString(writer & th,const string & data)827 void marshallString(writer &th, const string &data)
828 {
829 size_t len = data.length();
830 // A limit of 32K. TODO: why doesn't this use int16_t?
831 if (len > SHRT_MAX)
832 die("trying to marshall too long a string (len=%ld)", (long int)len);
833 marshallShort(th, len);
834
835 th.write(data.c_str(), len);
836 }
837
unmarshallString(reader & th)838 string unmarshallString(reader &th)
839 {
840 char buffer[SHRT_MAX]; // TODO: why doesn't this use int16_t?
841
842 short len = unmarshallShort(th);
843 ASSERT(len >= 0);
844 ASSERT(len <= (ssize_t)sizeof(buffer));
845
846 th.read(buffer, len);
847
848 return string(buffer, len);
849 }
850
851 // This one must stay with a 16 bit signed big-endian length tag, to allow
852 // older versions to browse and list newer saves.
marshallString2(writer & th,const string & data)853 static void marshallString2(writer &th, const string &data)
854 {
855 marshallString(th, data);
856 }
857
unmarshallString2(reader & th)858 static string unmarshallString2(reader &th)
859 {
860 return unmarshallString(th);
861 }
862
863 // string -- 4 byte length, non-terminated string data.
marshallString4(writer & th,const string & data)864 void marshallString4(writer &th, const string &data)
865 {
866 const size_t len = data.length();
867 if (len > static_cast<size_t>(numeric_limits<int32_t>::max()))
868 die("trying to marshall too long a string (len=%ld)", (long int) len);
869 marshallInt(th, len);
870 th.write(data.c_str(), len);
871 }
872
unmarshallString4(reader & th,string & s)873 void unmarshallString4(reader &th, string& s)
874 {
875 const int len = unmarshallInt(th);
876 ASSERT(len >= 0);
877 s.resize(len);
878 if (len)
879 th.read(&s.at(0), len);
880 }
881
882 // boolean (to avoid system-dependent bool implementations)
marshallBoolean(writer & th,bool data)883 void marshallBoolean(writer &th, bool data)
884 {
885 th.writeByte(data ? 1 : 0);
886 }
887
888 // boolean (to avoid system-dependent bool implementations)
unmarshallBoolean(reader & th)889 bool unmarshallBoolean(reader &th)
890 {
891 return th.readByte() != 0;
892 }
893
894 // Saving the date as a string so we're not reliant on a particular epoch.
make_date_string(time_t in_date)895 string make_date_string(time_t in_date)
896 {
897 if (in_date <= 0)
898 return "";
899
900 struct tm *date = TIME_FN(&in_date);
901
902 return make_stringf(
903 "%4d%02d%02d%02d%02d%02d%s",
904 date->tm_year + 1900, date->tm_mon, date->tm_mday,
905 date->tm_hour, date->tm_min, date->tm_sec,
906 ((date->tm_isdst > 0) ? "D" : "S"));
907 }
908
marshallStringVector(writer & th,const vector<string> & vec)909 static void marshallStringVector(writer &th, const vector<string> &vec)
910 {
911 _marshall_iterator(th, vec.begin(), vec.end(), marshallString);
912 }
913
unmarshallStringVector(reader & th)914 static vector<string> unmarshallStringVector(reader &th)
915 {
916 vector<string> vec;
917 _unmarshall_vector(th, vec, unmarshallString);
918 return vec;
919 }
920
921 // This code looks totally busted but I don't really want to look further...
_fixup_monster_type(reader & th,monster_type x)922 static monster_type _fixup_monster_type(reader &th, monster_type x)
923 {
924 #if TAG_MAJOR_VERSION == 34
925 if (x >= MONS_NO_MONSTER)
926 return x;
927
928 # define AXED(a) if (x > a) --x
929 if (th.getMinorVersion() == TAG_MINOR_0_11)
930 {
931 AXED(MONS_KILLER_BEE); // killer bee larva
932 AXED(MONS_SHADOW_IMP); // midge
933 AXED(MONS_AGNES); // Jozef
934 }
935 #endif
936
937 return x;
938 }
939
unmarshallMonType(reader & th)940 static monster_type unmarshallMonType(reader &th)
941 {
942 monster_type x;
943 #if TAG_MAJOR_VERSION == 34
944 if (th.getMinorVersion() < TAG_MINOR_MONSTER_TYPE_SIZE)
945 x = static_cast<monster_type>(unmarshallShort(th));
946 else
947 #endif
948 x = static_cast<monster_type>(unmarshallUnsigned(th));
949
950 return _fixup_monster_type(th, x);
951 }
952
953 // yay marshalling inconsistencies
unmarshallMonType_Info(reader & th)954 static monster_type unmarshallMonType_Info(reader &th)
955 {
956 monster_type x = static_cast<monster_type>(unmarshallUnsigned(th));
957 return _fixup_monster_type(th, x);
958 }
959
marshallMonType(writer & th,monster_type mt)960 static void marshallMonType(writer &th, monster_type mt)
961 {
962 marshallUnsigned(th, mt);
963 }
964
unmarshallSpellType(reader & th,bool mons=false)965 static spell_type unmarshallSpellType(reader &th
966 #if TAG_MAJOR_VERSION == 34
967 , bool mons = false
968 #endif
969 )
970 {
971 spell_type x = SPELL_NO_SPELL;
972 #if TAG_MAJOR_VERSION == 34
973 if (!mons && th.getMinorVersion() < TAG_MINOR_SHORT_SPELL_TYPE)
974 x = static_cast<spell_type>(unmarshallUByte(th));
975 else
976 #endif
977 x = static_cast<spell_type>(unmarshallShort(th));
978
979 #if TAG_MAJOR_VERSION == 34
980 if (th.getMinorVersion() == TAG_MINOR_0_11)
981 {
982 AXED(SPELL_DEBUGGING_RAY); // projected noise
983 AXED(SPELL_HEAL_OTHER); // summon greater holy
984 }
985 #endif
986
987 return x;
988 }
989
rewrite_feature(dungeon_feature_type x,int minor_version)990 static dungeon_feature_type rewrite_feature(dungeon_feature_type x,
991 int minor_version)
992 {
993 #if TAG_MAJOR_VERSION == 34
994 if (minor_version == TAG_MINOR_0_11)
995 {
996 // turn old trees into...trees
997 if (x == DNGN_OPEN_SEA)
998 x = DNGN_TREE;
999 else if (x >= DNGN_LAVA_SEA && x < 30)
1000 x = (dungeon_feature_type)(x - 1);
1001 }
1002 // turn mangroves into trees
1003 else if (minor_version < TAG_MINOR_MANGROVES && x == DNGN_OPEN_SEA)
1004 x = DNGN_TREE;
1005 else if (minor_version < TAG_MINOR_FIX_FEAT_SHIFT
1006 && x > DNGN_OPEN_SEA && x < DNGN_LAVA)
1007 {
1008 x = static_cast<dungeon_feature_type>(x - 1);
1009 }
1010
1011 if (x >= DNGN_DRY_FOUNTAIN_BLUE && x <= DNGN_DRY_FOUNTAIN_BLOOD)
1012 x = DNGN_DRY_FOUNTAIN;
1013
1014 if (x == DNGN_SEALED_DOOR && minor_version < TAG_MINOR_0_12)
1015 x = DNGN_CLOSED_DOOR;
1016 if (x == DNGN_BADLY_SEALED_DOOR)
1017 x = DNGN_SEALED_DOOR;
1018 if (x == DNGN_ESCAPE_HATCH_UP && player_in_branch(BRANCH_LABYRINTH))
1019 x = DNGN_EXIT_LABYRINTH;
1020 if (x == DNGN_DEEP_WATER && player_in_branch(BRANCH_SHOALS)
1021 && minor_version < TAG_MINOR_SHOALS_LITE)
1022 {
1023 x = DNGN_SHALLOW_WATER;
1024 }
1025
1026 // ensure that killing TRJ opens the slime:$ vaults
1027 if (you.where_are_you == BRANCH_SLIME && you.depth == brdepth[BRANCH_SLIME]
1028 && minor_version < TAG_MINOR_SLIME_WALL_CLEAR
1029 && x == DNGN_STONE_WALL)
1030 {
1031 x = DNGN_CLEAR_STONE_WALL;
1032 }
1033
1034 if (x == DNGN_ENTER_LABYRINTH)
1035 x = DNGN_ENTER_GAUNTLET;
1036
1037 if (minor_version < TAG_MINOR_NEW_TREES && x == DNGN_TREE)
1038 {
1039 if (you.where_are_you == BRANCH_SWAMP)
1040 x = DNGN_MANGROVE;
1041 else if (you.where_are_you == BRANCH_ABYSS
1042 || you.where_are_you == BRANCH_PANDEMONIUM)
1043 {
1044 x = DNGN_DEMONIC_TREE;
1045 }
1046 }
1047 #else
1048 UNUSED(minor_version);
1049 #endif
1050
1051 return x;
1052 }
1053
unmarshallFeatureType(reader & th)1054 dungeon_feature_type unmarshallFeatureType(reader &th)
1055 {
1056 dungeon_feature_type x = static_cast<dungeon_feature_type>(unmarshallUByte(th));
1057 return rewrite_feature(x, th.getMinorVersion());
1058 }
1059
1060 #if TAG_MAJOR_VERSION == 34
1061 // yay marshalling inconsistencies
unmarshallFeatureType_Info(reader & th)1062 static dungeon_feature_type unmarshallFeatureType_Info(reader &th)
1063 {
1064 dungeon_feature_type x = static_cast<dungeon_feature_type>(unmarshallUnsigned(th));
1065 x = rewrite_feature(x, th.getMinorVersion());
1066
1067 // There was a period of time when this function (only this one, not
1068 // unmarshallFeatureType) lacked some of the conversions now done by
1069 // rewrite_feature. In case any saves were transferred through those
1070 // versions, replace bad features with DNGN_UNSEEN. Questionable, but
1071 // this is just map_knowledge so the impact should be low.
1072 return is_valid_feature_type(x) ? x : DNGN_UNSEEN;
1073 }
1074 #endif
1075
1076 #define CANARY marshallUByte(th, 171)
1077 #if TAG_MAJOR_VERSION == 34
1078 #define EAT_CANARY do if (th.getMinorVersion() >= TAG_MINOR_CANARIES \
1079 && unmarshallUByte(th) != 171) \
1080 { \
1081 die("save corrupted: canary gone"); \
1082 } while (0)
1083 #else
1084 #define EAT_CANARY do if ( unmarshallUByte(th) != 171) \
1085 { \
1086 die("save corrupted: canary gone"); \
1087 } while (0)
1088 #endif
1089
1090 #if TAG_MAJOR_VERSION == 34
_ensure_entry(branch_type br)1091 static void _ensure_entry(branch_type br)
1092 {
1093 dungeon_feature_type entry = branches[br].entry_stairs;
1094 for (rectangle_iterator ri(1); ri; ++ri)
1095 if (orig_terrain(*ri) == entry)
1096 return;
1097
1098 // Find primary upstairs.
1099 for (rectangle_iterator ri(1); ri; ++ri)
1100 if (orig_terrain(*ri) == DNGN_STONE_STAIRS_UP_I)
1101 {
1102 for (distance_iterator di(*ri); di; ++di)
1103 if (in_bounds(*di) && env.grid(*di) == DNGN_FLOOR)
1104 {
1105 env.grid(*di) = entry; // No need to update LOS, etc.
1106 // Announce the repair even in non-debug builds.
1107 mprf(MSGCH_ERROR, "Placing missing branch entry: %s.",
1108 dungeon_feature_name(entry));
1109 return;
1110 }
1111 die("no floor to place a branch entrance");
1112 }
1113 die("no upstairs on %s???", level_id::current().describe().c_str());
1114 }
1115
_ensure_exit(branch_type br)1116 static void _ensure_exit(branch_type br)
1117 {
1118 dungeon_feature_type exit = branches[br].exit_stairs;
1119
1120 for (rectangle_iterator ri(1); ri; ++ri)
1121 if (orig_terrain(*ri) == exit)
1122 return;
1123
1124 // Find primary downstairs.
1125 for (rectangle_iterator ri(1); ri; ++ri)
1126 if (orig_terrain(*ri) == DNGN_STONE_STAIRS_DOWN_I)
1127 {
1128 for (distance_iterator di(*ri); di; ++di)
1129 if (in_bounds(*di)
1130 && (env.grid(*di) == DNGN_FLOOR
1131 || env.grid(*di) == DNGN_SHALLOW_WATER))
1132 {
1133 env.grid(*di) = exit; // No need to update LOS, etc.
1134 // Announce the repair even in non-debug builds.
1135 mprf(MSGCH_ERROR, "Placing missing branch exit: %s.",
1136 dungeon_feature_name(exit));
1137 return;
1138 }
1139 die("no floor to place a branch exit");
1140 }
1141 die("no downstairs on %s???", level_id::current().describe().c_str());
1142 }
1143
_add_missing_branches()1144 static void _add_missing_branches()
1145 {
1146 const level_id lc = level_id::current();
1147
1148 // Could do all just in case, but this seems safer:
1149 if (brentry[BRANCH_VAULTS] == lc)
1150 _ensure_entry(BRANCH_VAULTS);
1151 if (brentry[BRANCH_ZOT] == lc)
1152 _ensure_entry(BRANCH_ZOT);
1153 if (lc == level_id(BRANCH_DEPTHS, 2) || lc == level_id(BRANCH_DUNGEON, 21))
1154 _ensure_entry(BRANCH_VESTIBULE);
1155 if (lc == level_id(BRANCH_DEPTHS, 3) || lc == level_id(BRANCH_DUNGEON, 24))
1156 _ensure_entry(BRANCH_PANDEMONIUM);
1157 if (lc == level_id(BRANCH_DEPTHS, 4) || lc == level_id(BRANCH_DUNGEON, 25))
1158 _ensure_entry(BRANCH_ABYSS);
1159 if (player_in_branch(BRANCH_VESTIBULE))
1160 {
1161 for (rectangle_iterator ri(0); ri; ++ri)
1162 {
1163 if (env.grid(*ri) == DNGN_STONE_ARCH)
1164 {
1165 map_marker *marker = env.markers.find(*ri, MAT_FEATURE);
1166 if (marker)
1167 {
1168 map_feature_marker *featm =
1169 dynamic_cast<map_feature_marker*>(marker);
1170 // [ds] Ensure we're activating the correct feature
1171 // markers. Feature markers are also used for other things,
1172 // notably to indicate the return point from a portal
1173 // vault.
1174 switch (featm->feat)
1175 {
1176 case DNGN_ENTER_COCYTUS:
1177 case DNGN_ENTER_DIS:
1178 case DNGN_ENTER_GEHENNA:
1179 case DNGN_ENTER_TARTARUS:
1180 env.grid(*ri) = featm->feat;
1181 dprf("opened %s", dungeon_feature_name(featm->feat));
1182 env.markers.remove(marker);
1183 break;
1184 default:
1185 break;
1186 }
1187 }
1188 }
1189 }
1190 }
1191 }
1192 #endif
1193
1194
1195 // Write a tagged chunk of data to the FILE*.
1196 // tagId specifies what to write.
tag_write(tag_type tagID,writer & outf)1197 void tag_write(tag_type tagID, writer &outf)
1198 {
1199 vector<unsigned char> buf;
1200 writer th(&buf);
1201 switch (tagID)
1202 {
1203 case TAG_CHR:
1204 _tag_construct_char(th);
1205 break;
1206 case TAG_YOU:
1207 _tag_construct_you(th);
1208 CANARY;
1209 _tag_construct_you_items(th);
1210 CANARY;
1211 _tag_construct_you_dungeon(th);
1212 CANARY;
1213 _tag_construct_lost_monsters(th);
1214 CANARY;
1215 _tag_construct_companions(th);
1216 break;
1217 case TAG_LEVEL:
1218 _tag_construct_level(th);
1219 CANARY;
1220 _tag_construct_level_items(th);
1221 CANARY;
1222 _tag_construct_level_monsters(th);
1223 CANARY;
1224 _tag_construct_level_tiles(th);
1225 break;
1226 case TAG_GHOST:
1227 _tag_construct_ghost(th, global_ghosts);
1228 break;
1229 default:
1230 // I don't know how to make that!
1231 break;
1232 }
1233
1234 // make sure there is some data to write!
1235 if (buf.empty())
1236 return;
1237
1238 // Write tag header.
1239 marshallInt(outf, buf.size());
1240
1241 // Write tag data.
1242 outf.write(&buf[0], buf.size());
1243 }
1244
_shunt_monsters_out_of_walls()1245 static void _shunt_monsters_out_of_walls()
1246 {
1247 for (int i = 0; i < MAX_MONSTERS; ++i)
1248 {
1249 monster &m(env.mons[i]);
1250 if (m.alive() && in_bounds(m.pos()) && cell_is_solid(m.pos())
1251 && (env.grid(m.pos()) != DNGN_MALIGN_GATEWAY
1252 || mons_genus(m.type) != MONS_ELDRITCH_TENTACLE))
1253 {
1254 for (distance_iterator di(m.pos()); di; ++di)
1255 if (!actor_at(*di) && !cell_is_solid(*di))
1256 {
1257 #if TAG_MAJOR_VERSION == 34
1258 // Could have been a rock worm or a dryad.
1259 if (m.type != MONS_GHOST)
1260 #endif
1261 mprf(MSGCH_ERROR, "Error: monster %s in %s at (%d,%d)",
1262 m.name(DESC_PLAIN, true).c_str(),
1263 dungeon_feature_name(env.grid(m.pos())),
1264 m.pos().x, m.pos().y);
1265 env.mgrid(m.pos()) = NON_MONSTER;
1266 m.position = *di;
1267 env.mgrid(*di) = i;
1268 break;
1269 }
1270 }
1271 }
1272 }
1273
1274 // Read a piece of data from inf into memory, then run the appropriate reader.
1275 //
1276 // minorVersion is available for any sub-readers that need it
tag_read(reader & inf,tag_type tag_id)1277 void tag_read(reader &inf, tag_type tag_id)
1278 {
1279 // Read header info and data
1280 vector<unsigned char> buf;
1281 const int data_size = unmarshallInt(inf);
1282 ASSERT(data_size >= 0);
1283
1284 // Fetch data in one go
1285 buf.resize(data_size);
1286 inf.read(&buf[0], buf.size());
1287
1288 // Ok, we have data now.
1289 reader th(buf, inf.getMinorVersion());
1290 switch (tag_id)
1291 {
1292 case TAG_YOU:
1293 _tag_read_you(th);
1294 EAT_CANARY;
1295 _tag_read_you_items(th);
1296 EAT_CANARY;
1297 _tag_read_you_dungeon(th);
1298 EAT_CANARY;
1299 _tag_read_lost_monsters(th);
1300 EAT_CANARY;
1301 #if TAG_MAJOR_VERSION == 34
1302 if (th.getMinorVersion() < TAG_MINOR_NO_ITEM_TRANSIT)
1303 {
1304 _tag_read_lost_items(th);
1305 EAT_CANARY;
1306 }
1307 if (th.getMinorVersion() >= TAG_MINOR_COMPANION_LIST)
1308 #endif
1309 _tag_read_companions(th);
1310
1311 // If somebody SIGHUP'ed out of the skill menu with every skill
1312 // disabled. Doing this here rather in _tag_read_you() because
1313 // you.can_currently_train() requires the player's equipment be loaded.
1314 init_can_currently_train();
1315 break;
1316 case TAG_LEVEL:
1317 _tag_read_level(th);
1318 EAT_CANARY;
1319 _tag_read_level_items(th);
1320 // We have to do this here because _tag_read_level_monsters()
1321 // might kill an elsewhere Ilsuiw follower, which ends up calling
1322 // terrain.cc:_dgn_check_terrain_items, which checks env.item.
1323 link_items();
1324 EAT_CANARY;
1325 _tag_read_level_monsters(th);
1326 EAT_CANARY;
1327 #if TAG_MAJOR_VERSION == 34
1328 _add_missing_branches();
1329
1330 // If an eleionoma destroyed the Swamp exit due to the bug fixed in
1331 // 0d5cf04, put the branch exit on the closest floor or shallow water
1332 // square we can find near the first down stairs.
1333 if (you.where_are_you == BRANCH_SWAMP
1334 && you.depth == 1)
1335 {
1336 _ensure_exit(BRANCH_SWAMP);
1337 }
1338 #endif
1339 _shunt_monsters_out_of_walls();
1340 // The Abyss needs to visit other levels during level gen, before
1341 // all cells have been filled. We mustn't crash when it returns
1342 // from those excursions, and generate_abyss will check_map_validity
1343 // itself after the grid is fully populated.
1344 if (!player_in_branch(BRANCH_ABYSS))
1345 {
1346 unwind_var<coord_def> you_pos(you.position, coord_def());
1347 check_map_validity();
1348 }
1349 _tag_read_level_tiles(th);
1350 #if TAG_MAJOR_VERSION == 34
1351 if (you.where_are_you == BRANCH_GAUNTLET
1352 && th.getMinorVersion() < TAG_MINOR_GAUNTLET_TRAPPED)
1353 {
1354 vault_placement *place = dgn_vault_at(you.pos());
1355 if (place && place->map.desc_or_name()
1356 == "gammafunk_gauntlet_branching")
1357 {
1358 auto exit = DNGN_EXIT_GAUNTLET;
1359 env.grid(you.pos()) = exit;
1360 // Announce the repair even in non-debug builds.
1361 mprf(MSGCH_ERROR, "Placing emergency exit: %s.",
1362 dungeon_feature_name(exit));
1363 }
1364 }
1365
1366 // We can't do this when we unmarshall shops, since we haven't
1367 // unmarshalled items yet...
1368 if (th.getMinorVersion() < TAG_MINOR_SHOP_HACK)
1369 for (auto& entry : env.shop)
1370 {
1371 // Shop items were heaped up at this cell.
1372 for (stack_iterator si(coord_def(0, entry.second.num+5)); si; ++si)
1373 {
1374 entry.second.stock.push_back(*si);
1375 dec_mitm_item_quantity(si.index(), si->quantity);
1376 }
1377 }
1378 #endif
1379 break;
1380 case TAG_GHOST:
1381 global_ghosts = _tag_read_ghost(th);
1382 break;
1383 default:
1384 // I don't know how to read that!
1385 die("unknown tag type");
1386 }
1387 }
1388
_tag_construct_char(writer & th)1389 static void _tag_construct_char(writer &th)
1390 {
1391 marshallByte(th, TAG_CHR_FORMAT);
1392 // Important: you may never remove or alter a field without bumping
1393 // CHR_FORMAT. Bumping it makes all saves invisible when browsed in an
1394 // older version.
1395 // Please keep this compatible even over major version breaks!
1396
1397 // Appending fields is fine, but inserting new fields anywhere other than
1398 // the end of this function is not!
1399
1400 marshallString2(th, you.your_name);
1401 marshallString2(th, Version::Long);
1402
1403 marshallByte(th, you.species);
1404 marshallByte(th, you.char_class);
1405 marshallByte(th, you.experience_level);
1406 marshallString2(th, string(get_job_name(you.char_class)));
1407 marshallByte(th, you.religion);
1408 marshallString2(th, you.jiyva_second_name);
1409
1410 // don't save wizmode suppression
1411 marshallByte(th, you.wizard || you.suppress_wizard);
1412
1413 marshallByte(th, crawl_state.type);
1414 if (crawl_state.game_is_tutorial())
1415 marshallString2(th, crawl_state.map);
1416
1417 marshallString2(th, species::name(you.species));
1418 marshallString2(th, you.religion ? god_name(you.religion) : "");
1419
1420 // separate from the tutorial so we don't have to bump TAG_CHR_FORMAT
1421 marshallString2(th, crawl_state.map);
1422
1423 marshallByte(th, you.explore);
1424 }
1425
1426 /// is a custom scoring mechanism being stored?
_calc_score_exists()1427 static bool _calc_score_exists()
1428 {
1429 lua_stack_cleaner clean(dlua);
1430 dlua.pushglobal("dgn.persist.calc_score");
1431 return !lua_isnil(dlua, -1);
1432 }
1433
_tag_construct_you(writer & th)1434 static void _tag_construct_you(writer &th)
1435 {
1436 marshallInt(th, you.last_mid);
1437 marshallByte(th, you.piety);
1438 marshallShort(th, you.pet_target);
1439
1440 marshallByte(th, you.max_level);
1441 marshallByte(th, you.where_are_you);
1442 marshallByte(th, you.depth);
1443 marshallByte(th, you.chapter);
1444 marshallByte(th, you.royal_jelly_dead);
1445 marshallByte(th, you.transform_uncancellable);
1446 marshallByte(th, you.berserk_penalty);
1447 marshallInt(th, you.abyss_speed);
1448
1449 ASSERT(you.hp > 0 || you.pending_revival);
1450 marshallShort(th, you.pending_revival ? 0 : you.hp);
1451
1452 marshallBoolean(th, you.fishtail);
1453 marshallBoolean(th, you.vampire_alive);
1454 _marshall_as_int(th, you.form);
1455 CANARY;
1456
1457 // how many you.equip?
1458 marshallByte(th, NUM_EQUIP - EQ_FIRST_EQUIP);
1459 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
1460 marshallByte(th, you.equip[i]);
1461 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
1462 marshallBoolean(th, you.melded[i]);
1463 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
1464 marshallBoolean(th, you.activated[i]);
1465
1466 ASSERT_RANGE(you.magic_points, 0, you.max_magic_points + 1);
1467 marshallUByte(th, you.magic_points);
1468 marshallByte(th, you.max_magic_points);
1469
1470 COMPILE_CHECK(NUM_STATS == 3);
1471 for (int i = 0; i < NUM_STATS; ++i)
1472 marshallByte(th, you.base_stats[i]);
1473 for (int i = 0; i < NUM_STATS; ++i)
1474 marshallByte(th, you.stat_loss[i]);
1475
1476 CANARY;
1477
1478 marshallInt(th, you.hit_points_regeneration);
1479 marshallInt(th, you.magic_points_regeneration);
1480
1481 marshallInt(th, you.experience);
1482 marshallInt(th, you.total_experience);
1483 marshallInt(th, you.gold);
1484
1485 marshallInt(th, you.exp_available);
1486
1487 marshallInt(th, you.zigs_completed);
1488 marshallByte(th, you.zig_max);
1489
1490 marshallString(th, you.banished_by);
1491
1492 marshallShort(th, you.hp_max_adj_temp);
1493 marshallShort(th, you.hp_max_adj_perm);
1494 marshallShort(th, you.mp_max_adj);
1495
1496 marshallShort(th, you.pos().x);
1497 marshallShort(th, you.pos().y);
1498
1499 _marshallFixedBitVector<NUM_SPELLS>(th, you.spell_library);
1500 _marshallFixedBitVector<NUM_SPELLS>(th, you.hidden_spells);
1501
1502 // how many spells?
1503 marshallUByte(th, MAX_KNOWN_SPELLS);
1504 for (int i = 0; i < MAX_KNOWN_SPELLS; ++i)
1505 marshallShort(th, you.spells[i]);
1506
1507 marshallByte(th, 52);
1508 for (int i = 0; i < 52; i++)
1509 marshallByte(th, you.spell_letter_table[i]);
1510
1511 marshallByte(th, 52);
1512 for (int i = 0; i < 52; i++)
1513 marshallShort(th, you.ability_letter_table[i]);
1514
1515 marshallUByte(th, you.old_vehumet_gifts.size());
1516 for (auto spell : you.old_vehumet_gifts)
1517 marshallShort(th, spell);
1518
1519 marshallUByte(th, you.vehumet_gifts.size());
1520 for (auto spell : you.vehumet_gifts)
1521 marshallShort(th, spell);
1522
1523 CANARY;
1524
1525 // how many skills?
1526 marshallByte(th, NUM_SKILLS);
1527 for (int j = 0; j < NUM_SKILLS; ++j)
1528 {
1529 marshallUByte(th, you.skills[j]);
1530 marshallByte(th, you.train[j]);
1531 marshallByte(th, you.train_alt[j]);
1532 marshallInt(th, you.training[j]);
1533 marshallInt(th, you.skill_points[j]);
1534 marshallInt(th, you.ct_skill_points[j]);
1535 marshallByte(th, you.skill_order[j]); // skills ordering
1536 marshallInt(th, you.training_targets[j]);
1537 marshallInt(th, you.skill_manual_points[j]);
1538 }
1539
1540 marshallBoolean(th, you.auto_training);
1541 marshallByte(th, you.exercises.size());
1542 for (auto sk : you.exercises)
1543 marshallInt(th, sk);
1544
1545 marshallByte(th, you.exercises_all.size());
1546 for (auto sk : you.exercises_all)
1547 marshallInt(th, sk);
1548
1549 marshallByte(th, you.skill_menu_do);
1550 marshallByte(th, you.skill_menu_view);
1551
1552 CANARY;
1553
1554 // how many durations?
1555 marshallUByte(th, NUM_DURATIONS);
1556 for (int j = 0; j < NUM_DURATIONS; ++j)
1557 marshallInt(th, you.duration[j]);
1558
1559 // how many attributes?
1560 marshallByte(th, NUM_ATTRIBUTES);
1561 for (int j = 0; j < NUM_ATTRIBUTES; ++j)
1562 marshallInt(th, you.attribute[j]);
1563
1564 // Event timers.
1565 marshallByte(th, NUM_TIMERS);
1566 for (int j = 0; j < NUM_TIMERS; ++j)
1567 {
1568 marshallInt(th, you.last_timer_effect[j]);
1569 marshallInt(th, you.next_timer_effect[j]);
1570 }
1571
1572 // how many mutations/demon powers?
1573 marshallShort(th, NUM_MUTATIONS);
1574 for (int j = 0; j < NUM_MUTATIONS; ++j)
1575 {
1576 marshallByte(th, you.mutation[j]);
1577 marshallByte(th, you.innate_mutation[j]);
1578 marshallByte(th, you.temp_mutation[j]);
1579 marshallByte(th, you.sacrifices[j]);
1580 }
1581
1582 marshallByte(th, you.demonic_traits.size());
1583 for (int j = 0; j < int(you.demonic_traits.size()); ++j)
1584 {
1585 marshallByte(th, you.demonic_traits[j].level_gained);
1586 marshallShort(th, you.demonic_traits[j].mutation);
1587 }
1588
1589 // set up sacrifice piety by ability
1590 marshallShort(th, 1 + ABIL_FINAL_SACRIFICE - ABIL_FIRST_SACRIFICE);
1591 for (int j = ABIL_FIRST_SACRIFICE; j <= ABIL_FINAL_SACRIFICE; ++j)
1592 marshallByte(th, you.sacrifice_piety[j]);
1593
1594 CANARY;
1595
1596 // how many penances?
1597 marshallByte(th, NUM_GODS);
1598 for (god_iterator it; it; ++it)
1599 marshallByte(th, you.penance[*it]);
1600
1601 // which gods have been worshipped by this character?
1602 for (god_iterator it; it; ++it)
1603 marshallByte(th, you.worshipped[*it]);
1604
1605 // what is the extent of divine generosity?
1606 for (god_iterator it; it; ++it)
1607 marshallShort(th, you.num_current_gifts[*it]);
1608 for (god_iterator it; it; ++it)
1609 marshallShort(th, you.num_total_gifts[*it]);
1610 for (god_iterator it; it; ++it)
1611 marshallBoolean(th, you.one_time_ability_used[*it]);
1612
1613 // how much piety have you achieved at highest with each god?
1614 for (god_iterator it; it; ++it)
1615 marshallByte(th, you.piety_max[*it]);
1616
1617 marshallByte(th, you.gift_timeout);
1618 marshallUByte(th, you.saved_good_god_piety);
1619 marshallByte(th, you.previous_good_god);
1620
1621 for (god_iterator it; it; ++it)
1622 marshallInt(th, you.exp_docked[*it]);
1623 for (god_iterator it; it; ++it)
1624 marshallInt(th, you.exp_docked_total[*it]);
1625
1626 // elapsed time
1627 marshallInt(th, you.elapsed_time);
1628
1629 // time of game start
1630 marshallInt(th, you.birth_time);
1631
1632 handle_real_time();
1633
1634 // TODO: maybe switch to marshalling real_time_ms.
1635 marshallInt(th, you.real_time());
1636 marshallInt(th, you.num_turns);
1637 marshallInt(th, you.exploration);
1638
1639 marshallInt(th, you.magic_contamination);
1640
1641 #if TAG_MAJOR_VERSION == 34
1642 marshallUByte(th, 0);
1643 #endif
1644 marshallUByte(th, you.transit_stair);
1645 marshallByte(th, you.entering_level);
1646 marshallBoolean(th, you.travel_ally_pace);
1647
1648 marshallByte(th, you.deaths);
1649 marshallByte(th, you.lives);
1650
1651 CANARY;
1652
1653 marshallInt(th, you.dactions.size());
1654 for (daction_type da : you.dactions)
1655 marshallByte(th, da);
1656
1657 marshallInt(th, you.level_stack.size());
1658 for (const level_pos &lvl : you.level_stack)
1659 lvl.save(th);
1660
1661 // List of currently beholding monsters (usually empty).
1662 marshallShort(th, you.beholders.size());
1663 for (mid_t beh : you.beholders)
1664 _marshall_as_int(th, beh);
1665
1666 marshallShort(th, you.fearmongers.size());
1667 for (mid_t monger : you.fearmongers)
1668 _marshall_as_int(th, monger);
1669
1670 marshallByte(th, you.piety_hysteresis);
1671
1672 you.m_quiver_history.save(th);
1673 you.quiver_action.save(QUIVER_MAIN_SAVE_KEY);
1674 you.launcher_action.save(QUIVER_LAUNCHER_SAVE_KEY);
1675
1676 CANARY;
1677
1678 // Action counts.
1679 marshallShort(th, you.action_count.size());
1680 for (const auto &ac : you.action_count)
1681 {
1682 marshallShort(th, ac.first.first);
1683 marshallInt(th, ac.first.second);
1684 for (int k = 0; k < 27; k++)
1685 marshallInt(th, ac.second[k]);
1686 }
1687
1688 marshallByte(th, NUM_BRANCHES);
1689 for (int i = 0; i < NUM_BRANCHES; i++)
1690 marshallBoolean(th, you.branches_left[i]);
1691
1692 marshallCoord(th, abyssal_state.major_coord);
1693 marshallInt(th, abyssal_state.seed);
1694 marshallInt(th, abyssal_state.depth);
1695 marshallFloat(th, abyssal_state.phase);
1696 marshall_level_id(th, abyssal_state.level);
1697
1698 #if TAG_MAJOR_VERSION == 34
1699 if (abyssal_state.level.branch == BRANCH_DWARF || !abyssal_state.level.is_valid())
1700 abyssal_state.level = level_id(static_cast<branch_type>(BRANCH_DUNGEON), 19);
1701 #endif
1702
1703 _marshall_constriction(th, &you);
1704
1705 marshallUByte(th, you.octopus_king_rings);
1706
1707 marshallUnsigned(th, you.uncancel.size());
1708 for (const pair<uncancellable_type, int>& unc : you.uncancel)
1709 {
1710 marshallUByte(th, unc.first);
1711 marshallInt(th, unc.second);
1712 }
1713
1714 marshallUnsigned(th, you.recall_list.size());
1715 for (mid_t recallee : you.recall_list)
1716 _marshall_as_int(th, recallee);
1717
1718 marshallUByte(th, 1); // number of seeds, for historical reasons: always 1
1719 marshallUnsigned(th, you.game_seed);
1720 marshallBoolean(th, you.fully_seeded); // TODO: remove on major version inc?
1721 marshallBoolean(th, you.deterministic_levelgen);
1722 CrawlVector rng_states = rng::generators_to_vector();
1723 rng_states.write(th);
1724
1725 CANARY;
1726
1727 // don't let vault caching errors leave a normal game with sprint scoring
1728 if (!crawl_state.game_is_sprint())
1729 ASSERT(!_calc_score_exists());
1730
1731 if (!dlua.callfn("dgn_save_data", "u", &th))
1732 mprf(MSGCH_ERROR, "Failed to save Lua data: %s", dlua.error.c_str());
1733
1734 CANARY;
1735
1736 // Write a human-readable string out on the off chance that
1737 // we fail to be able to read this file back in using some later version.
1738 string revision = "Git:";
1739 revision += Version::Long;
1740 marshallString(th, revision);
1741
1742 you.props.write(th);
1743 }
1744
_tag_construct_you_items(writer & th)1745 static void _tag_construct_you_items(writer &th)
1746 {
1747 // how many inventory slots?
1748 marshallByte(th, ENDOFPACK);
1749 for (const auto &item : you.inv)
1750 marshallItem(th, item);
1751
1752 _marshallFixedBitVector<NUM_RUNE_TYPES>(th, you.runes);
1753 marshallByte(th, you.obtainable_runes);
1754
1755 // Item descrip for each type & subtype.
1756 // how many types?
1757 marshallUByte(th, NUM_IDESC);
1758 // how many subtypes?
1759 marshallUByte(th, MAX_SUBTYPES);
1760 for (int i = 0; i < NUM_IDESC; ++i)
1761 for (int j = 0; j < MAX_SUBTYPES; ++j)
1762 marshallInt(th, you.item_description[i][j]);
1763
1764 marshallUByte(th, NUM_OBJECT_CLASSES);
1765 for (int i = 0; i < NUM_OBJECT_CLASSES; ++i)
1766 {
1767 if (!item_type_has_ids((object_class_type)i))
1768 continue;
1769 for (int j = 0; j < MAX_SUBTYPES; ++j)
1770 marshallBoolean(th, you.type_ids[i][j]);
1771 }
1772
1773 CANARY;
1774
1775 // how many unique items?
1776 marshallUByte(th, MAX_UNRANDARTS);
1777 for (int j = 0; j < MAX_UNRANDARTS; ++j)
1778 marshallByte(th,you.unique_items[j]);
1779
1780 marshallShort(th, NUM_WEAPONS);
1781 for (int j = 0; j < NUM_WEAPONS; ++j)
1782 marshallInt(th,you.seen_weapon[j]);
1783
1784 marshallShort(th, NUM_ARMOURS);
1785 for (int j = 0; j < NUM_ARMOURS; ++j)
1786 marshallInt(th,you.seen_armour[j]);
1787
1788 _marshallFixedBitVector<NUM_MISCELLANY>(th, you.seen_misc);
1789
1790 for (int i = 0; i < NUM_OBJECT_CLASSES; i++)
1791 for (int j = 0; j < MAX_SUBTYPES; j++)
1792 marshallInt(th, you.force_autopickup[i][j]);
1793 }
1794
marshallPlaceInfo(writer & th,PlaceInfo place_info)1795 static void marshallPlaceInfo(writer &th, PlaceInfo place_info)
1796 {
1797 marshallInt(th, place_info.branch);
1798
1799 marshallInt(th, place_info.num_visits);
1800 marshallInt(th, place_info.levels_seen);
1801
1802 marshallInt(th, place_info.mon_kill_exp);
1803
1804 for (int i = 0; i < KC_NCATEGORIES; i++)
1805 marshallInt(th, place_info.mon_kill_num[i]);
1806
1807 marshallInt(th, place_info.turns_total);
1808 marshallInt(th, place_info.turns_explore);
1809 marshallInt(th, place_info.turns_travel);
1810 marshallInt(th, place_info.turns_interlevel);
1811 marshallInt(th, place_info.turns_resting);
1812 marshallInt(th, place_info.turns_other);
1813
1814 marshallInt(th, place_info.elapsed_total);
1815 marshallInt(th, place_info.elapsed_explore);
1816 marshallInt(th, place_info.elapsed_travel);
1817 marshallInt(th, place_info.elapsed_interlevel);
1818 marshallInt(th, place_info.elapsed_resting);
1819 marshallInt(th, place_info.elapsed_other);
1820 }
1821
marshallLevelXPInfo(writer & th,LevelXPInfo xp_info)1822 static void marshallLevelXPInfo(writer &th, LevelXPInfo xp_info)
1823 {
1824 marshall_level_id(th, xp_info.level);
1825
1826 marshallInt(th, xp_info.non_vault_xp);
1827 marshallInt(th, xp_info.non_vault_count);
1828 marshallInt(th, xp_info.vault_xp);
1829 marshallInt(th, xp_info.vault_count);
1830 }
1831
_tag_construct_you_dungeon(writer & th)1832 static void _tag_construct_you_dungeon(writer &th)
1833 {
1834 // how many unique creatures?
1835 marshallShort(th, NUM_MONSTERS);
1836 for (int j = 0; j < NUM_MONSTERS; ++j)
1837 marshallByte(th,you.unique_creatures[j]); // unique beasties
1838
1839 // how many branches?
1840 marshallByte(th, NUM_BRANCHES);
1841 for (int j = 0; j < NUM_BRANCHES; ++j)
1842 {
1843 marshallInt(th, brdepth[j]);
1844 marshall_level_id(th, brentry[j]);
1845 marshallInt(th, branch_bribe[j]);
1846 }
1847
1848 // Root of the dungeon; usually BRANCH_DUNGEON.
1849 marshallInt(th, root_branch);
1850
1851 marshallMap(th, stair_level,
1852 _marshall_as_int<branch_type>, _marshall_level_id_set);
1853 marshallMap(th, shops_present,
1854 _marshall_level_pos, _marshall_as_int<shop_type>);
1855 marshallMap(th, altars_present,
1856 _marshall_level_pos, _marshall_as_int<god_type>);
1857 marshallMap(th, portals_present,
1858 _marshall_level_pos, _marshall_as_int<branch_type>);
1859 marshallMap(th, portal_notes,
1860 _marshall_level_pos, marshallString);
1861 marshallMap(th, level_annotations,
1862 marshall_level_id, marshallString);
1863 marshallMap(th, level_exclusions,
1864 marshall_level_id, marshallString);
1865 marshallMap(th, level_uniques,
1866 marshall_level_id, marshallString);
1867 marshallUniqueAnnotations(th);
1868
1869 marshallPlaceInfo(th, you.global_info);
1870 vector<PlaceInfo> list = you.get_all_place_info();
1871 // How many different places we have info on?
1872 marshallShort(th, list.size());
1873
1874 for (const PlaceInfo &place : list)
1875 marshallPlaceInfo(th, place);
1876
1877 marshallLevelXPInfo(th, you.global_xp_info);
1878
1879 vector<LevelXPInfo> xp_info_list = you.get_all_xp_info();
1880 // How many different levels do we have info on?
1881 marshallShort(th, xp_info_list.size());
1882 for (const LevelXPInfo &info : xp_info_list)
1883 marshallLevelXPInfo(th, info);
1884
1885 _marshall_iterator(th, you.uniq_map_tags.begin(), you.uniq_map_tags.end(),
1886 marshallString);
1887 _marshall_iterator(th, you.uniq_map_names.begin(), you.uniq_map_names.end(),
1888 marshallString);
1889 _marshall_iterator(th, you.uniq_map_tags_abyss.begin(),
1890 you.uniq_map_tags_abyss.end(), marshallString);
1891 _marshall_iterator(th, you.uniq_map_names_abyss.begin(),
1892 you.uniq_map_names_abyss.end(), marshallString);
1893 marshallMap(th, you.vault_list, marshall_level_id, marshallStringVector);
1894
1895 write_level_connectivity(th);
1896 }
1897
marshall_follower(writer & th,const follower & f)1898 static void marshall_follower(writer &th, const follower &f)
1899 {
1900 ASSERT(!invalid_monster_type(f.mons.type));
1901 ASSERT(f.mons.alive());
1902 marshallMonster(th, f.mons);
1903 marshallInt(th, f.transit_start_time);
1904 for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
1905 marshallItem(th, f.items[i]);
1906 }
1907
unmarshall_follower(reader & th)1908 static follower unmarshall_follower(reader &th)
1909 {
1910 follower f;
1911 unmarshallMonster(th, f.mons);
1912 #if TAG_MAJOR_VERSION == 34
1913 if (th.getMinorVersion() >= TAG_MINOR_FOLLOWER_TRANSIT_TIME)
1914 #endif
1915 f.transit_start_time = unmarshallInt(th);
1916 #if TAG_MAJOR_VERSION == 34
1917 else
1918 {
1919 //Set transit_start_time to 0 and let follower heal completely
1920 f.transit_start_time = 0;
1921 }
1922 #endif
1923 for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
1924 unmarshallItem(th, f.items[i]);
1925 return f;
1926 }
1927
marshall_companion(writer & th,const companion & c)1928 static void marshall_companion(writer &th, const companion &c)
1929 {
1930 marshall_follower(th, c.mons);
1931 marshall_level_id(th, c.level);
1932 marshallInt(th, c.timestamp);
1933 }
1934
unmarshall_companion(reader & th)1935 static companion unmarshall_companion(reader &th)
1936 {
1937 companion c;
1938 c.mons = unmarshall_follower(th);
1939 c.level = unmarshall_level_id(th);
1940 c.timestamp = unmarshallInt(th);
1941 return c;
1942 }
1943
marshall_follower_list(writer & th,const m_transit_list & mlist)1944 static void marshall_follower_list(writer &th, const m_transit_list &mlist)
1945 {
1946 marshallShort(th, mlist.size());
1947
1948 for (const auto &follower : mlist)
1949 marshall_follower(th, follower);
1950 }
1951
unmarshall_follower_list(reader & th)1952 static m_transit_list unmarshall_follower_list(reader &th)
1953 {
1954 m_transit_list mlist;
1955
1956 const int size = unmarshallShort(th);
1957
1958 for (int i = 0; i < size; ++i)
1959 {
1960 follower f = unmarshall_follower(th);
1961 if (!f.mons.alive())
1962 {
1963 mprf(MSGCH_ERROR,
1964 "Dead monster %s in transit list in saved game, ignoring.",
1965 f.mons.name(DESC_PLAIN, true).c_str());
1966 }
1967 else
1968 mlist.push_back(f);
1969 }
1970
1971 return mlist;
1972 }
1973
1974 #if TAG_MAJOR_VERSION == 34
unmarshall_item_list(reader & th)1975 static i_transit_list unmarshall_item_list(reader &th)
1976 {
1977 i_transit_list ilist;
1978
1979 const int size = unmarshallShort(th);
1980
1981 for (int i = 0; i < size; ++i)
1982 {
1983 item_def item;
1984 unmarshallItem(th, item);
1985 ilist.push_back(item);
1986 }
1987
1988 return ilist;
1989 }
1990 #endif
1991
marshall_level_map_masks(writer & th)1992 static void marshall_level_map_masks(writer &th)
1993 {
1994 for (rectangle_iterator ri(0); ri; ++ri)
1995 {
1996 marshallInt(th, env.level_map_mask(*ri));
1997 marshallInt(th, env.level_map_ids(*ri));
1998 }
1999 }
2000
unmarshall_level_map_masks(reader & th)2001 static void unmarshall_level_map_masks(reader &th)
2002 {
2003 for (rectangle_iterator ri(0); ri; ++ri)
2004 {
2005 env.level_map_mask(*ri) = unmarshallInt(th);
2006 env.level_map_ids(*ri) = unmarshallInt(th);
2007 }
2008 }
2009
marshall_level_map_unique_ids(writer & th)2010 static void marshall_level_map_unique_ids(writer &th)
2011 {
2012 marshallSet(th, env.level_uniq_maps, marshallString);
2013 marshallSet(th, env.level_uniq_map_tags, marshallString);
2014 }
2015
unmarshall_level_map_unique_ids(reader & th)2016 static void unmarshall_level_map_unique_ids(reader &th)
2017 {
2018 unmarshallSet(th, env.level_uniq_maps, unmarshallString);
2019 unmarshallSet(th, env.level_uniq_map_tags, unmarshallString);
2020 }
2021
2022 static void marshall_subvault_place(writer &th,
2023 const subvault_place &subvault_place);
2024
marshall_mapdef(writer & th,const map_def & map)2025 static void marshall_mapdef(writer &th, const map_def &map)
2026 {
2027 marshallString(th, map.name);
2028 map.write_index(th);
2029 map.write_maplines(th);
2030 marshallString(th, map.description);
2031 marshallMap(th, map.feat_renames,
2032 _marshall_as_int<dungeon_feature_type>, marshallString);
2033 _marshall_iterator(th,
2034 map.subvault_places.begin(),
2035 map.subvault_places.end(),
2036 marshall_subvault_place);
2037 }
2038
marshall_subvault_place(writer & th,const subvault_place & subvault_place)2039 static void marshall_subvault_place(writer &th,
2040 const subvault_place &subvault_place)
2041 {
2042 marshallCoord(th, subvault_place.tl);
2043 marshallCoord(th, subvault_place.br);
2044 marshall_mapdef(th, *subvault_place.subvault);
2045 }
2046
2047 static subvault_place unmarshall_subvault_place(reader &th);
unmarshall_mapdef(reader & th)2048 static map_def unmarshall_mapdef(reader &th)
2049 {
2050 map_def map;
2051 map.name = unmarshallString(th);
2052 map.read_index(th);
2053 map.read_maplines(th);
2054 map.description = unmarshallString(th);
2055 unmarshallMap(th, map.feat_renames,
2056 unmarshall_int_as<dungeon_feature_type>,
2057 unmarshallString);
2058 #if TAG_MAJOR_VERSION == 34
2059 if (th.getMinorVersion() >= TAG_MINOR_REIFY_SUBVAULTS
2060 && th.getMinorVersion() != TAG_MINOR_0_11)
2061 #endif
2062 _unmarshall_vector(th, map.subvault_places, unmarshall_subvault_place);
2063
2064 // reload the map epilogue from the current cache in case it hasn't yet
2065 // been run.
2066 // it would probably be better game-design-wise to marshall the epilogue,
2067 // but currently I don't think we marshall any lua code and I'm not sure
2068 // this is the best practice to get into.
2069 map.reload_epilogue();
2070 return map;
2071 }
2072
unmarshall_subvault_place(reader & th)2073 static subvault_place unmarshall_subvault_place(reader &th)
2074 {
2075 subvault_place subvault;
2076 subvault.tl = unmarshallCoord(th);
2077 subvault.br = unmarshallCoord(th);
2078 subvault.set_subvault(unmarshall_mapdef(th));
2079 return subvault;
2080 }
2081
marshall_vault_placement(writer & th,const vault_placement & vp)2082 static void marshall_vault_placement(writer &th, const vault_placement &vp)
2083 {
2084 marshallCoord(th, vp.pos);
2085 marshallCoord(th, vp.size);
2086 marshallShort(th, vp.orient);
2087 marshall_mapdef(th, vp.map);
2088 _marshall_iterator(th, vp.exits.begin(), vp.exits.end(), marshallCoord);
2089 #if TAG_MAJOR_VERSION == 34
2090 marshallShort(th, -1);
2091 #endif
2092 marshallByte(th, vp.seen);
2093 }
2094
unmarshall_vault_placement(reader & th)2095 static vault_placement unmarshall_vault_placement(reader &th)
2096 {
2097 vault_placement vp;
2098 vp.pos = unmarshallCoord(th);
2099 vp.size = unmarshallCoord(th);
2100 vp.orient = static_cast<map_section_type>(unmarshallShort(th));
2101 vp.map = unmarshall_mapdef(th);
2102 _unmarshall_vector(th, vp.exits, unmarshallCoord);
2103 #if TAG_MAJOR_VERSION == 34
2104 unmarshallShort(th);
2105 #endif
2106 vp.seen = !!unmarshallByte(th);
2107
2108 return vp;
2109 }
2110
marshall_level_vault_placements(writer & th)2111 static void marshall_level_vault_placements(writer &th)
2112 {
2113 marshallShort(th, env.level_vaults.size());
2114 for (unique_ptr<vault_placement> &vp : env.level_vaults)
2115 marshall_vault_placement(th, *vp);
2116 }
2117
unmarshall_level_vault_placements(reader & th)2118 static void unmarshall_level_vault_placements(reader &th)
2119 {
2120 const int nvaults = unmarshallShort(th);
2121 ASSERT(nvaults >= 0);
2122 dgn_clear_vault_placements();
2123 for (int i = 0; i < nvaults; ++i)
2124 {
2125 env.level_vaults.emplace_back(
2126 new vault_placement(unmarshall_vault_placement(th)));
2127 }
2128 }
2129
marshall_level_vault_data(writer & th)2130 static void marshall_level_vault_data(writer &th)
2131 {
2132 marshallString(th, env.level_build_method);
2133 marshallSet(th, env.level_layout_types, marshallString);
2134
2135 marshall_level_map_masks(th);
2136 marshall_level_map_unique_ids(th);
2137 #if TAG_MAJOR_VERSION == 34
2138 marshallInt(th, 0);
2139 #endif
2140 marshall_level_vault_placements(th);
2141 }
2142
unmarshall_level_vault_data(reader & th)2143 static void unmarshall_level_vault_data(reader &th)
2144 {
2145 env.level_build_method = unmarshallString(th);
2146 unmarshallSet(th, env.level_layout_types, unmarshallString);
2147
2148 unmarshall_level_map_masks(th);
2149 unmarshall_level_map_unique_ids(th);
2150 #if TAG_MAJOR_VERSION == 34
2151 if (th.getMinorVersion() >= TAG_MINOR_VAULT_LIST) // 33:17 has it
2152 unmarshallStringVector(th);
2153 #endif
2154 unmarshall_level_vault_placements(th);
2155 }
2156
marshall_shop(writer & th,const shop_struct & shop)2157 static void marshall_shop(writer &th, const shop_struct& shop)
2158 {
2159 marshallByte(th, shop.type);
2160 marshallByte(th, shop.keeper_name[0]);
2161 marshallByte(th, shop.keeper_name[1]);
2162 marshallByte(th, shop.keeper_name[2]);
2163 marshallByte(th, shop.pos.x);
2164 marshallByte(th, shop.pos.y);
2165 marshallByte(th, shop.greed);
2166 marshallByte(th, shop.level);
2167 marshallString(th, shop.shop_name);
2168 marshallString(th, shop.shop_type_name);
2169 marshallString(th, shop.shop_suffix_name);
2170 _marshall_iterator(th, shop.stock.begin(), shop.stock.end(),
2171 bind(marshallItem, placeholders::_1, placeholders::_2,
2172 false));
2173 }
2174
unmarshall_shop(reader & th,shop_struct & shop)2175 static void unmarshall_shop(reader &th, shop_struct& shop)
2176 {
2177 shop.type = static_cast<shop_type>(unmarshallByte(th));
2178 #if TAG_MAJOR_VERSION == 34
2179 if (shop.type == SHOP_UNASSIGNED)
2180 return;
2181 if (th.getMinorVersion() < TAG_MINOR_MISC_SHOP_CHANGE
2182 && shop.type == NUM_SHOPS)
2183 {
2184 // This was SHOP_MISCELLANY, which is now part of SHOP_EVOKABLES.
2185 shop.type = SHOP_EVOKABLES;
2186 }
2187 #else
2188 ASSERT(shop.type != SHOP_UNASSIGNED);
2189 #endif
2190 shop.keeper_name[0] = unmarshallUByte(th);
2191 shop.keeper_name[1] = unmarshallUByte(th);
2192 shop.keeper_name[2] = unmarshallUByte(th);
2193 shop.pos.x = unmarshallByte(th);
2194 shop.pos.y = unmarshallByte(th);
2195 shop.greed = unmarshallByte(th);
2196 shop.level = unmarshallByte(th);
2197 shop.shop_name = unmarshallString(th);
2198 shop.shop_type_name = unmarshallString(th);
2199 shop.shop_suffix_name = unmarshallString(th);
2200 #if TAG_MAJOR_VERSION == 34
2201 if (th.getMinorVersion() < TAG_MINOR_SHOP_HACK)
2202 shop.stock.clear();
2203 else
2204 #endif
2205 _unmarshall_vector(th, shop.stock, [] (reader& r) -> item_def
2206 {
2207 item_def ret;
2208 unmarshallItem(r, ret);
2209 return ret;
2210 });
2211 }
2212
save(writer & outf) const2213 void ShopInfo::save(writer& outf) const
2214 {
2215 marshall_shop(outf, shop);
2216 }
2217
load(reader & inf)2218 void ShopInfo::load(reader& inf)
2219 {
2220 #if TAG_MAJOR_VERSION == 34
2221 if (inf.getMinorVersion() < TAG_MINOR_SHOPINFO
2222 || inf.getMinorVersion() == TAG_MINOR_UNSHOPINFO)
2223 {
2224 shop.type = static_cast<shop_type>(unmarshallShort(inf));
2225
2226 shop.pos.x = unmarshallShort(inf);
2227 shop.pos.x &= 0xFF;
2228
2229 shop.pos.y = unmarshallShort(inf);
2230
2231 int itemcount = unmarshallShort(inf);
2232
2233 // xref hack in shopping.cc:shop_name()
2234 shop.shop_name = " ";
2235 unmarshallString4(inf, shop.shop_type_name);
2236 for (int i = 0; i < itemcount; ++i)
2237 {
2238 shop.stock.emplace_back();
2239 unmarshallItem(inf, shop.stock.back());
2240 int cost = unmarshallShort(inf);
2241 shop.greed = cost * 10 / item_value(shop.stock.back(),
2242 shoptype_identifies_stock(shop.type));
2243 }
2244 }
2245 else
2246 #endif
2247 unmarshall_shop(inf, shop);
2248 }
2249
_tag_construct_lost_monsters(writer & th)2250 static void _tag_construct_lost_monsters(writer &th)
2251 {
2252 marshallMap(th, the_lost_ones, marshall_level_id,
2253 marshall_follower_list);
2254 }
2255
_tag_construct_companions(writer & th)2256 static void _tag_construct_companions(writer &th)
2257 {
2258 #if TAG_MAJOR_VERSION == 34
2259 fixup_bad_companions();
2260 #endif
2261 marshallMap(th, companion_list, _marshall_as_int<mid_t>,
2262 marshall_companion);
2263 }
2264
2265 // Save versions 30-32.26 are readable but don't store the names.
2266 static const char* old_species[]=
2267 {
2268 "Human", "High Elf", "Deep Elf", "Sludge Elf", "Mountain Dwarf", "Halfling",
2269 "Hill Orc", "Kobold", "Mummy", "Naga", "Ogre", "Troll",
2270 "Red Draconian", "White Draconian", "Green Draconian", "Yellow Draconian",
2271 "Grey Draconian", "Black Draconian", "Purple Draconian", "Mottled Draconian",
2272 "Pale Draconian", "Draconian", "Centaur", "Demigod", "Spriggan", "Minotaur",
2273 "Demonspawn", "Ghoul", "Tengu", "Merfolk", "Vampire", "Deep Dwarf", "Felid",
2274 "Octopode",
2275 };
2276
2277 static const char* old_gods[]=
2278 {
2279 "", "Zin", "The Shining One", "Kikubaaqudgha", "Yredelemnul", "Xom",
2280 "Vehumet", "Okawaru", "Makhleb", "Sif Muna", "Trog", "Nemelex Xobeh",
2281 "Elyvilon", "Lugonu", "Beogh", "Jiyva", "Fedhas", "Cheibriados",
2282 "Ashenzari",
2283 };
2284
tag_read_char(reader & th,uint8_t,uint8_t major,uint8_t minor)2285 void tag_read_char(reader &th, uint8_t /*format*/, uint8_t major, uint8_t minor)
2286 {
2287 // Important: values out of bounds are good here, the save browser needs to
2288 // be forward-compatible. We validate them only on an actual restore.
2289 you.your_name = unmarshallString2(th);
2290 you.prev_save_version = unmarshallString2(th);
2291 dprf("Saved character %s, version: %s", you.your_name.c_str(),
2292 you.prev_save_version.c_str());
2293
2294 you.species = static_cast<species_type>(unmarshallUByte(th));
2295 you.char_class = static_cast<job_type>(unmarshallUByte(th));
2296 you.experience_level = unmarshallByte(th);
2297 you.chr_class_name = unmarshallString2(th);
2298 you.religion = static_cast<god_type>(unmarshallUByte(th));
2299 you.jiyva_second_name = unmarshallString2(th);
2300
2301 you.wizard = unmarshallBoolean(th);
2302
2303 // this was mistakenly inserted in the middle for a few tag versions - this
2304 // just makes sure that games generated in that time period are still
2305 // readable, but should not be used for new games
2306 #if TAG_CHR_FORMAT == 0
2307 // TAG_MINOR_EXPLORE_MODE and TAG_MINOR_FIX_EXPLORE_MODE
2308 if (major == 34 && (minor >= 121 && minor < 130))
2309 you.explore = unmarshallBoolean(th);
2310 #endif
2311
2312 crawl_state.type = (game_type) unmarshallUByte(th);
2313 // normalize invalid game types so they can be treated uniformly elsewhere
2314 if (crawl_state.type > NUM_GAME_TYPE)
2315 crawl_state.type = NUM_GAME_TYPE;
2316
2317 // prevent an ASSERT in game_is_tutorial on game types from the future
2318 if (crawl_state.game_is_valid_type() && crawl_state.game_is_tutorial())
2319 crawl_state.map = unmarshallString2(th);
2320 else
2321 crawl_state.map = "";
2322
2323 if (major > 32 || major == 32 && minor > 26)
2324 {
2325 you.chr_species_name = unmarshallString2(th);
2326 you.chr_god_name = unmarshallString2(th);
2327 }
2328 else
2329 {
2330 if (you.species >= 0 && you.species < (int)ARRAYSZ(old_species))
2331 you.chr_species_name = old_species[you.species];
2332 else
2333 you.chr_species_name = "Yak";
2334 if (you.religion >= 0 && you.religion < (int)ARRAYSZ(old_gods))
2335 you.chr_god_name = old_gods[you.religion];
2336 else
2337 you.chr_god_name = "Marduk";
2338 }
2339
2340 if (major > 34 || major == 34 && minor >= 29)
2341 crawl_state.map = unmarshallString2(th);
2342
2343 if (major > 34 || major == 34 && minor >= 130)
2344 you.explore = unmarshallBoolean(th);
2345 }
2346
2347 #if TAG_MAJOR_VERSION == 34
_cap_mutation_at(mutation_type mut,int cap)2348 static void _cap_mutation_at(mutation_type mut, int cap)
2349 {
2350 if (you.mutation[mut] > cap)
2351 {
2352 // Don't convert real mutation levels to temporary.
2353 int real_levels = you.get_base_mutation_level(mut, true, false, true);
2354 you.temp_mutation[mut] = max(cap - real_levels, 0);
2355
2356 you.mutation[mut] = cap;
2357 }
2358 if (you.innate_mutation[mut] > cap)
2359 you.innate_mutation[mut] = cap;
2360 }
2361
_clear_mutation(mutation_type mut)2362 static void _clear_mutation(mutation_type mut)
2363 {
2364 _cap_mutation_at(mut, 0);
2365 }
2366
_fixup_removed_spells(spell_type s)2367 static spell_type _fixup_removed_spells(spell_type s)
2368 {
2369 switch (s)
2370 {
2371 case SPELL_FORCE_LANCE:
2372 case SPELL_VENOM_BOLT:
2373 case SPELL_POISON_ARROW:
2374 case SPELL_BOLT_OF_COLD:
2375 case SPELL_BOLT_OF_DRAINING:
2376 case SPELL_THROW_FLAME:
2377 case SPELL_THROW_FROST:
2378 case SPELL_STICKS_TO_SNAKES:
2379 case SPELL_INFUSION:
2380 case SPELL_SHROUD_OF_GOLUBRIA:
2381 case SPELL_SPECTRAL_WEAPON:
2382 case SPELL_RING_OF_FLAMES:
2383 case SPELL_DARKNESS:
2384 return SPELL_NO_SPELL;
2385
2386 case SPELL_FLAME_TONGUE:
2387 return SPELL_FOXFIRE;
2388
2389 case SPELL_THROW_ICICLE:
2390 return SPELL_HAILSTORM;
2391
2392 case SPELL_BOLT_OF_FIRE:
2393 return SPELL_STARBURST;
2394
2395 case SPELL_CONFUSE:
2396 return SPELL_CONFUSING_TOUCH;
2397
2398 default:
2399 return s;
2400 }
2401 }
2402
_fixup_positional_monster_spell(spell_type s)2403 static spell_type _fixup_positional_monster_spell(spell_type s)
2404 {
2405 switch (s)
2406 {
2407 case SPELL_DAZZLING_FLASH:
2408 case SPELL_INNER_FLAME:
2409 case SPELL_CONJURE_FLAME:
2410 return SPELL_NO_SPELL;
2411
2412 case SPELL_ISKENDERUNS_MYSTIC_BLAST:
2413 return SPELL_FORCE_LANCE;
2414
2415 case SPELL_AGONY:
2416 return SPELL_AGONY_RANGE;
2417
2418 case SPELL_DISPEL_UNDEAD:
2419 return SPELL_DISPEL_UNDEAD_RANGE;
2420
2421 default:
2422 return s;
2423 }
2424 }
2425
_fixup_library_spells(FixedBitVector<NUM_SPELLS> & lib)2426 static void _fixup_library_spells(FixedBitVector<NUM_SPELLS>& lib)
2427 {
2428 for (int i = 0; i < NUM_SPELLS; ++i)
2429 {
2430 spell_type newspell = _fixup_removed_spells((spell_type) i);
2431
2432 if (newspell == SPELL_NO_SPELL)
2433 lib.set(i, false);
2434 else if (newspell != (spell_type) i)
2435 {
2436 // Only give the fixup if they had the spell, don't remove
2437 // replacements
2438 if (lib[i])
2439 lib.set(newspell, lib[i]);
2440 lib.set(i, false);
2441 }
2442 }
2443 }
2444 #endif
2445
unmarshall_vehumet_spells(reader & th,set<spell_type> & old_gifts,set<spell_type> & gifts)2446 void unmarshall_vehumet_spells(reader &th, set<spell_type>& old_gifts,
2447 set<spell_type>& gifts)
2448 {
2449 #if TAG_MAJOR_VERSION == 34
2450 if (th.getMinorVersion() >= TAG_MINOR_VEHUMET_SPELL_GIFT
2451 && th.getMinorVersion() != TAG_MINOR_0_11)
2452 {
2453 #endif
2454 const auto num_old_gifts = unmarshallUByte(th);
2455 for (int i = 0; i < num_old_gifts; ++i)
2456 {
2457 const auto spell = unmarshallSpellType(th);
2458 if (!spell_removed(spell))
2459 old_gifts.insert(spell);
2460 }
2461
2462 #if TAG_MAJOR_VERSION == 34
2463 if (th.getMinorVersion() < TAG_MINOR_VEHUMET_MULTI_GIFTS)
2464 {
2465 const auto spell = unmarshallSpellType(th);
2466 if (!spell_removed(spell))
2467 gifts.insert(spell);
2468 }
2469 else
2470 {
2471 #endif
2472 const auto num_gifts = unmarshallUByte(th);
2473 for (int i = 0; i < num_gifts; ++i)
2474 {
2475 const auto spell = unmarshallSpellType(th);
2476 if (!spell_removed(spell))
2477 gifts.insert(spell);
2478 }
2479 #if TAG_MAJOR_VERSION == 34
2480 }
2481 }
2482 #endif
2483 }
2484
unmarshall_player_spells(reader & th)2485 FixedVector<spell_type, MAX_KNOWN_SPELLS> unmarshall_player_spells(reader &th)
2486 {
2487 FixedVector<spell_type, MAX_KNOWN_SPELLS> spells(SPELL_NO_SPELL);
2488
2489 const auto count = unmarshallUByte(th);
2490 ASSERT(count >= 0);
2491
2492 for (int i = 0; i < count && i < MAX_KNOWN_SPELLS; ++i)
2493 {
2494 spells[i] = unmarshallSpellType(th);
2495 #if TAG_MAJOR_VERSION == 34
2496 spells[i] = _fixup_removed_spells(spells[i]);
2497 #endif
2498 if (spell_removed(spells[i]))
2499 spells[i] = SPELL_NO_SPELL;
2500 }
2501
2502 for (int i = MAX_KNOWN_SPELLS; i < count; ++i)
2503 unmarshallSpellType(th);
2504
2505 return spells;
2506 }
2507
unmarshall_player_spell_letter_table(reader & th)2508 FixedVector<int, 52> unmarshall_player_spell_letter_table(reader &th)
2509 {
2510 FixedVector<int, 52> spell_letter_table;
2511
2512 const auto count = unmarshallByte(th);
2513 ASSERT(count == (int)spell_letter_table.size());
2514
2515 for (int i = 0; i < count; i++)
2516 {
2517 int s = unmarshallByte(th);
2518 ASSERT_RANGE(s, -1, MAX_KNOWN_SPELLS);
2519 spell_letter_table[i] = s;
2520 }
2521
2522 return spell_letter_table;
2523 }
2524
2525
remove_removed_library_spells(FixedBitVector<NUM_SPELLS> & lib)2526 void remove_removed_library_spells(FixedBitVector<NUM_SPELLS>& lib)
2527 {
2528 for (int i = 0; i < NUM_SPELLS; ++i)
2529 lib.set(i, lib[i] && !spell_removed(static_cast<spell_type>(i)));
2530 }
2531
2532
_fixup_species_mutations(mutation_type mut)2533 static void _fixup_species_mutations(mutation_type mut)
2534 {
2535 // this is *not safe* to use with any mutations where there could be a
2536 // physiology conflict, or with mutations where there could be random
2537 // upgrades on top of the innate levels (e.g. MUT_ROLL).
2538 int total = 0;
2539 // Don't perma_mutate since that gives messages.
2540 for (const auto& lum : get_species_def(you.species).level_up_mutations)
2541 if (lum.xp_level <= you.experience_level && lum.mut == mut)
2542 total += lum.mut_level;
2543
2544 you.innate_mutation[mut] = you.mutation[mut] = total;
2545 }
2546
_tag_read_you(reader & th)2547 static void _tag_read_you(reader &th)
2548 {
2549 int count;
2550
2551 ASSERT(species::is_valid(you.species));
2552 ASSERT(job_type_valid(you.char_class));
2553 ASSERT_RANGE(you.experience_level, 1, 28);
2554 ASSERT(you.religion < NUM_GODS);
2555 ASSERT_RANGE(crawl_state.type, GAME_TYPE_UNSPECIFIED + 1, NUM_GAME_TYPE);
2556 you.last_mid = unmarshallInt(th);
2557 you.piety = unmarshallUByte(th);
2558 ASSERT(you.piety <= MAX_PIETY);
2559 #if TAG_MAJOR_VERSION == 34
2560 if (th.getMinorVersion() < TAG_MINOR_ROTTING)
2561 unmarshallUByte(th);
2562 #endif
2563 you.pet_target = unmarshallShort(th);
2564
2565 you.max_level = unmarshallByte(th);
2566 you.where_are_you = static_cast<branch_type>(unmarshallUByte(th));
2567 ASSERT(you.where_are_you < NUM_BRANCHES);
2568 you.depth = unmarshallByte(th);
2569 ASSERT(you.depth > 0);
2570 you.chapter = static_cast<game_chapter>(unmarshallUByte(th));
2571 ASSERT(you.chapter < NUM_CHAPTERS);
2572
2573 #if TAG_MAJOR_VERSION == 34
2574 if (th.getMinorVersion() < TAG_MINOR_ZOT_OPEN)
2575 unmarshallBoolean(th);
2576 #endif
2577 you.royal_jelly_dead = unmarshallBoolean(th);
2578 you.transform_uncancellable = unmarshallBoolean(th);
2579
2580 #if TAG_MAJOR_VERSION == 34
2581 if (th.getMinorVersion() < TAG_MINOR_IS_UNDEAD)
2582 unmarshallUByte(th);
2583 if (th.getMinorVersion() < TAG_MINOR_CALC_UNRAND_REACTS)
2584 unmarshallShort(th);
2585 #endif
2586 you.berserk_penalty = unmarshallByte(th);
2587 #if TAG_MAJOR_VERSION == 34
2588 if (th.getMinorVersion() >= TAG_MINOR_GARGOYLE_DR
2589 && th.getMinorVersion() < TAG_MINOR_RM_GARGOYLE_DR)
2590 {
2591 unmarshallInt(th); // Slough an integer.
2592 }
2593
2594 if (th.getMinorVersion() < TAG_MINOR_AUTOMATIC_MANUALS)
2595 {
2596 unmarshallShort(th);
2597 unmarshallInt(th);
2598 }
2599 #endif
2600
2601 you.abyss_speed = unmarshallInt(th);
2602
2603 #if TAG_MAJOR_VERSION == 34
2604 // was you.disease
2605 if (th.getMinorVersion() < TAG_MINOR_DISEASE)
2606 unmarshallInt(th);
2607 #endif
2608 you.hp = unmarshallShort(th);
2609 #if TAG_MAJOR_VERSION == 34
2610 // was you.hunger
2611 if (th.getMinorVersion() < TAG_MINOR_LOAF_BUST)
2612 unmarshallShort(th);
2613 #endif
2614 you.fishtail = unmarshallBoolean(th);
2615 #if TAG_MAJOR_VERSION == 34
2616 if (th.getMinorVersion() >= TAG_MINOR_VAMPIRE_NO_EAT)
2617 you.vampire_alive = unmarshallBoolean(th);
2618 else
2619 you.vampire_alive = true;
2620 #else
2621 you.vampire_alive = unmarshallBoolean(th);
2622 #endif
2623 #if TAG_MAJOR_VERSION == 34
2624 if (th.getMinorVersion() < TAG_MINOR_NOME_NO_MORE)
2625 unmarshallInt(th);
2626 #endif
2627 you.form = unmarshall_int_as<transformation>(th);
2628 ASSERT_RANGE(static_cast<int>(you.form), 0, NUM_TRANSFORMS);
2629 #if TAG_MAJOR_VERSION == 34
2630 // Fix the effects of #7668 (Vampire lose undead trait once coming back
2631 // from lich form).
2632 if (you.form == transformation::none)
2633 you.transform_uncancellable = false;
2634 #else
2635 ASSERT(you.form != transformation::none || !you.transform_uncancellable);
2636 #endif
2637 EAT_CANARY;
2638
2639 #if TAG_MAJOR_VERSION == 34
2640 if (th.getMinorVersion() < TAG_MINOR_SAGE_REMOVAL)
2641 {
2642 count = unmarshallShort(th);
2643 ASSERT_RANGE(count, 0, 32768);
2644 for (int i = 0; i < count; ++i)
2645 {
2646 unmarshallByte(th);
2647 unmarshallInt(th);
2648 unmarshallInt(th);
2649 }
2650 }
2651 #endif
2652
2653 // How many you.equip?
2654 count = unmarshallByte(th);
2655 ASSERT(count <= NUM_EQUIP);
2656 for (int i = EQ_FIRST_EQUIP; i < count; ++i)
2657 {
2658 you.equip[i] = unmarshallByte(th);
2659 ASSERT_RANGE(you.equip[i], -1, ENDOFPACK);
2660 }
2661 for (int i = count; i < NUM_EQUIP; ++i)
2662 you.equip[i] = -1;
2663 for (int i = 0; i < count; ++i)
2664 you.melded.set(i, unmarshallBoolean(th));
2665 for (int i = count; i < NUM_EQUIP; ++i)
2666 you.melded.set(i, false);
2667 #if TAG_MAJOR_VERSION == 34
2668 if (th.getMinorVersion() >= TAG_MINOR_TRACK_REGEN_ITEMS)
2669 {
2670 #endif
2671 for (int i = 0; i < count; ++i)
2672 you.activated.set(i, unmarshallBoolean(th));
2673
2674 for (int i = count; i < NUM_EQUIP; ++i)
2675 you.activated.set(i, false);
2676 #if TAG_MAJOR_VERSION == 34
2677 }
2678 #endif
2679
2680 you.magic_points = unmarshallUByte(th);
2681 you.max_magic_points = unmarshallByte(th);
2682
2683 for (int i = 0; i < NUM_STATS; ++i)
2684 you.base_stats[i] = unmarshallByte(th);
2685 #if TAG_MAJOR_VERSION == 34
2686 // Gnolls previously had stats fixed at 7/7/7, so randomly award them stats
2687 // based on the points they'd have gotten from XL/3 selection and XL/4
2688 // random SID.
2689 if (th.getMinorVersion() >= TAG_MINOR_STATLOCKED_GNOLLS
2690 && th.getMinorVersion() < TAG_MINOR_GNOLLS_REDUX
2691 && you.species == SP_GNOLL)
2692 {
2693 const species_def& sd = get_species_def(you.species);
2694
2695 // Give base stat points.
2696 species_stat_init(you.species);
2697
2698 const set<stat_type> all_stats = {STAT_STR, STAT_INT, STAT_DEX};
2699 int num_points = you.experience_level / 3;
2700 for (int i = 0; i < num_points; ++i)
2701 modify_stat(*random_iterator(all_stats), 1, false);
2702
2703 num_points = you.experience_level / sd.how_often;
2704 for (int i = 0; i < num_points; ++i)
2705 modify_stat(*random_iterator(sd.level_stats), 1, false);
2706 }
2707 #endif
2708
2709 for (int i = 0; i < NUM_STATS; ++i)
2710 you.stat_loss[i] = unmarshallByte(th);
2711
2712 #if TAG_MAJOR_VERSION == 34
2713 if (th.getMinorVersion() < TAG_MINOR_STAT_ZERO_DURATION)
2714 {
2715 for (int i = 0; i < NUM_STATS; ++i)
2716 unmarshallUByte(th);
2717 }
2718 if (th.getMinorVersion() < TAG_MINOR_STAT_ZERO)
2719 {
2720 for (int i = 0; i < NUM_STATS; ++i)
2721 unmarshallString(th);
2722 }
2723 #endif
2724 EAT_CANARY;
2725
2726 #if TAG_MAJOR_VERSION == 34
2727 if (th.getMinorVersion() < TAG_MINOR_INT_REGEN)
2728 {
2729 you.hit_points_regeneration = unmarshallByte(th);
2730 you.magic_points_regeneration = unmarshallByte(th);
2731 unmarshallShort(th);
2732 }
2733 else
2734 {
2735 #endif
2736 you.hit_points_regeneration = unmarshallInt(th);
2737 you.magic_points_regeneration = unmarshallInt(th);
2738 #if TAG_MAJOR_VERSION == 34
2739 }
2740 #endif
2741
2742 you.experience = unmarshallInt(th);
2743 you.total_experience = unmarshallInt(th);
2744 you.gold = unmarshallInt(th);
2745 you.exp_available = unmarshallInt(th);
2746 #if TAG_MAJOR_VERSION == 34
2747 if (th.getMinorVersion() < TAG_MINOR_XP_SCALING)
2748 {
2749 you.total_experience *= 10;
2750 you.exp_available *= 10;
2751 }
2752 if (th.getMinorVersion() < TAG_MINOR_NO_ZOTDEF)
2753 unmarshallInt(th);
2754 #endif
2755 you.zigs_completed = unmarshallInt(th);
2756 you.zig_max = unmarshallByte(th);
2757 #if TAG_MAJOR_VERSION == 34
2758 if (th.getMinorVersion() < TAG_MINOR_TRACK_BANISHER)
2759 you.banished_by = "";
2760 else
2761 #endif
2762 you.banished_by = unmarshallString(th);
2763
2764 you.hp_max_adj_temp = unmarshallShort(th);
2765 you.hp_max_adj_perm = unmarshallShort(th);
2766 you.mp_max_adj = unmarshallShort(th);
2767 #if TAG_MAJOR_VERSION == 34
2768 if (th.getMinorVersion() < TAG_MINOR_REMOVE_BASE_MP)
2769 {
2770 int baseadj = unmarshallShort(th);
2771 you.mp_max_adj += baseadj;
2772 }
2773 if (th.getMinorVersion() < TAG_MINOR_CLASS_HP_0)
2774 you.hp_max_adj_perm -= 8;
2775 #endif
2776
2777 const int x = unmarshallShort(th);
2778 const int y = unmarshallShort(th);
2779 // SIGHUP during Step from Time/etc is ok.
2780 ASSERT(!x && !y || in_bounds(x, y));
2781 you.moveto(coord_def(x, y));
2782
2783 #if TAG_MAJOR_VERSION == 34
2784 if (th.getMinorVersion() < TAG_MINOR_WEIGHTLESS)
2785 unmarshallShort(th);
2786 #endif
2787
2788 #if TAG_MAJOR_VERSION == 34
2789 if (th.getMinorVersion() >= TAG_MINOR_GOLDIFY_BOOKS)
2790 {
2791 #endif
2792 _unmarshallFixedBitVector<NUM_SPELLS>(th, you.spell_library);
2793 _unmarshallFixedBitVector<NUM_SPELLS>(th, you.hidden_spells);
2794 #if TAG_MAJOR_VERSION == 34
2795 _fixup_library_spells(you.spell_library);
2796 _fixup_library_spells(you.hidden_spells);
2797 }
2798 #endif
2799
2800 remove_removed_library_spells(you.spell_library);
2801 remove_removed_library_spells(you.hidden_spells);
2802
2803 you.spells = unmarshall_player_spells(th);
2804 you.spell_letter_table = unmarshall_player_spell_letter_table(th);
2805 you.spell_no = count_if(begin(you.spells), end(you.spells),
2806 [](const spell_type spell) { return spell != SPELL_NO_SPELL; });
2807
2808 count = unmarshallByte(th);
2809 ASSERT(count == (int)you.ability_letter_table.size());
2810 for (int i = 0; i < count; i++)
2811 {
2812 int a = unmarshallShort(th);
2813 #if TAG_MAJOR_VERSION == 34
2814 if (th.getMinorVersion() < TAG_MINOR_ABIL_1000)
2815 {
2816 if (a >= 230)
2817 a += 2000 - 230;
2818 else if (a >= 50)
2819 a += 1000 - 50;
2820 }
2821 if (th.getMinorVersion() < TAG_MINOR_ABIL_GOD_FIXUP)
2822 {
2823 if (a >= ABIL_ASHENZARI_END_TRANSFER + 1
2824 && a <= ABIL_ASHENZARI_END_TRANSFER + 3)
2825 {
2826 a += ABIL_STOP_RECALL - ABIL_ASHENZARI_END_TRANSFER - 1;
2827 }
2828 }
2829 if (a == ABIL_FLY
2830 || a == ABIL_WISP_BLINK // was ABIL_FLY_II
2831 && th.getMinorVersion() < TAG_MINOR_0_12)
2832 {
2833 a = ABIL_NON_ABILITY;
2834 }
2835 if (a == ABIL_EVOKE_STOP_LEVITATING
2836 || a == ABIL_STOP_FLYING)
2837 {
2838 a = ABIL_NON_ABILITY;
2839 }
2840
2841 if (th.getMinorVersion() < TAG_MINOR_NO_JUMP)
2842 {
2843 // ABIL_JUMP deleted (ABIL_DIG has its old spot), map it
2844 // away and shift following intrinsic abilities down.
2845 // ABIL_EVOKE_JUMP was also deleted, but was the last
2846 // evocable ability, so just map it away.
2847 if (a == ABIL_DIG || a == ABIL_EVOKE_TELEPORT_CONTROL + 1)
2848 a = ABIL_NON_ABILITY;
2849 else if (a > ABIL_DIG && a < ABIL_MIN_EVOKE)
2850 a -= 1;
2851 }
2852
2853 if (th.getMinorVersion() < TAG_MINOR_MOTTLED_REMOVAL)
2854 {
2855 if (a == ABIL_BREATHE_STICKY_FLAME)
2856 a = ABIL_BREATHE_FIRE;
2857 }
2858
2859 // Bad offset from games transferred prior to 0.17-a0-2121-g4af814f.
2860 if (a == NUM_ABILITIES)
2861 a = ABIL_NON_ABILITY;
2862 #endif
2863 ASSERT_RANGE(a, ABIL_NON_ABILITY, NUM_ABILITIES);
2864 ASSERT(a != 0);
2865 you.ability_letter_table[i] = static_cast<ability_type>(a);
2866 }
2867
2868 unmarshall_vehumet_spells(th, you.old_vehumet_gifts, you.vehumet_gifts);
2869 EAT_CANARY;
2870
2871 // how many skills?
2872 count = unmarshallUByte(th);
2873 ASSERT(count <= NUM_SKILLS);
2874 for (int j = 0; j < count; ++j)
2875 {
2876 you.skills[j] = unmarshallUByte(th);
2877 ASSERT(you.skills[j] <= 27 || you.wizard);
2878
2879 you.train[j] = (training_status)unmarshallByte(th);
2880 you.train_alt[j] = (training_status)unmarshallByte(th);
2881 #if TAG_MAJOR_VERSION == 34
2882 // Gnolls always train all skills.
2883 if (th.getMinorVersion() < TAG_MINOR_GNOLLS_REDUX
2884 && you.species == SP_GNOLL)
2885 {
2886 you.train[j] = you.train_alt[j] = TRAINING_ENABLED;
2887 }
2888 #endif
2889 you.training[j] = unmarshallInt(th);
2890 you.skill_points[j] = unmarshallInt(th);
2891 you.ct_skill_points[j] = unmarshallInt(th);
2892 you.skill_order[j] = unmarshallByte(th);
2893 #if TAG_MAJOR_VERSION == 34
2894 if (th.getMinorVersion() >= TAG_MINOR_TRAINING_TARGETS)
2895 {
2896 #endif
2897 you.training_targets[j] = unmarshallInt(th);
2898 #if TAG_MAJOR_VERSION == 34
2899 }
2900 else
2901 you.training_targets[j] = 0;
2902
2903 if (th.getMinorVersion() >= TAG_MINOR_GOLDIFY_MANUALS)
2904 {
2905 #endif
2906 you.skill_manual_points[j] = unmarshallInt(th);
2907 #if TAG_MAJOR_VERSION == 34
2908 }
2909 else
2910 you.skill_manual_points[j] = 0;
2911 #endif
2912 }
2913
2914 you.auto_training = unmarshallBoolean(th);
2915
2916 count = unmarshallByte(th);
2917 for (int i = 0; i < count; i++)
2918 you.exercises.push_back((skill_type)unmarshallInt(th));
2919
2920 count = unmarshallByte(th);
2921 for (int i = 0; i < count; i++)
2922 you.exercises_all.push_back((skill_type)unmarshallInt(th));
2923
2924 you.skill_menu_do = static_cast<skill_menu_state>(unmarshallByte(th));
2925 you.skill_menu_view = static_cast<skill_menu_state>(unmarshallByte(th));
2926 #if TAG_MAJOR_VERSION == 34
2927 if (you.skill_menu_view == SKM_VIEW_TRANSFER)
2928 you.skill_menu_view = SKM_NONE;
2929 // Was Ashenzari skill transfer information
2930 // Four ints to discard
2931 if (th.getMinorVersion() < TAG_MINOR_NEW_ASHENZARI)
2932 for (int j = 0; j < 4; ++j)
2933 unmarshallInt(th);
2934 #endif
2935
2936 // Set up you.skill_cost_level.
2937 you.skill_cost_level = 0;
2938 check_skill_cost_change();
2939
2940 EAT_CANARY;
2941
2942 // how many durations?
2943 count = unmarshallUByte(th);
2944 COMPILE_CHECK(NUM_DURATIONS < 256);
2945 for (int j = 0; j < count && j < NUM_DURATIONS; ++j)
2946 you.duration[j] = unmarshallInt(th);
2947 for (int j = NUM_DURATIONS; j < count; ++j)
2948 unmarshallInt(th);
2949 #if TAG_MAJOR_VERSION == 34
2950 if (you.species == SP_LAVA_ORC)
2951 you.duration[DUR_MAGIC_ARMOUR] = 0;
2952
2953 if (th.getMinorVersion() < TAG_MINOR_FUNGUS_FORM
2954 && you.form == transformation::fungus)
2955 {
2956 you.duration[DUR_CONFUSING_TOUCH] = 0;
2957 }
2958
2959 you.duration[DUR_JELLY_PRAYER] = 0;
2960 #endif
2961
2962 // how many attributes?
2963 count = unmarshallUByte(th);
2964 COMPILE_CHECK(NUM_ATTRIBUTES < 256);
2965 for (int j = 0; j < count && j < NUM_ATTRIBUTES; ++j)
2966 {
2967 #if TAG_MAJOR_VERSION == 34
2968 if (j == ATTR_BANISHMENT_IMMUNITY && th.getMinorVersion() == TAG_MINOR_0_11)
2969 {
2970 unmarshallInt(th); // ATTR_UNUSED_1
2971 count--;
2972 }
2973 if (j == ATTR_NOISES && th.getMinorVersion() == TAG_MINOR_CLASS_HP_0
2974 && count == 40)
2975 {
2976 dprf("recovering ATTR_NOISES");
2977 j++, count++;
2978 }
2979 #endif
2980 you.attribute[j] = unmarshallInt(th);
2981 }
2982 #if TAG_MAJOR_VERSION == 34
2983 if (count == ATTR_PAKELLAS_EXTRA_MP && you_worship(GOD_PAKELLAS))
2984 you.attribute[ATTR_PAKELLAS_EXTRA_MP] = POT_MAGIC_MP;
2985 #endif
2986 for (int j = count; j < NUM_ATTRIBUTES; ++j)
2987 you.attribute[j] = 0;
2988 for (int j = NUM_ATTRIBUTES; j < count; ++j)
2989 unmarshallInt(th);
2990
2991 #if TAG_MAJOR_VERSION == 34
2992 if (you.attribute[ATTR_DIVINE_REGENERATION])
2993 {
2994 you.attribute[ATTR_DIVINE_REGENERATION] = 0;
2995 you.duration[DUR_TROGS_HAND] = max(you.duration[DUR_TROGS_HAND],
2996 you.duration[DUR_REGENERATION]);
2997 you.duration[DUR_REGENERATION] = 0;
2998 }
2999 if (you.attribute[ATTR_SEARING_RAY] > 3)
3000 you.attribute[ATTR_SEARING_RAY] = 0;
3001
3002 if (you.attribute[ATTR_DELAYED_FIREBALL])
3003 you.attribute[ATTR_DELAYED_FIREBALL] = 0;
3004
3005 if (th.getMinorVersion() < TAG_MINOR_STAT_LOSS_XP)
3006 {
3007 for (int i = 0; i < NUM_STATS; ++i)
3008 {
3009 if (you.stat_loss[i] > 0)
3010 {
3011 you.attribute[ATTR_STAT_LOSS_XP] = stat_loss_roll();
3012 break;
3013 }
3014 }
3015 }
3016
3017 #endif
3018
3019 #if TAG_MAJOR_VERSION == 34
3020 // Nemelex item type sacrifice toggles.
3021 if (th.getMinorVersion() < TAG_MINOR_NEMELEX_WEIGHTS)
3022 {
3023 count = unmarshallByte(th);
3024 ASSERT(count <= NUM_OBJECT_CLASSES);
3025 for (int j = 0; j < count; ++j)
3026 unmarshallInt(th);
3027 }
3028 #endif
3029
3030 int timer_count = 0;
3031 #if TAG_MAJOR_VERSION == 34
3032 if (th.getMinorVersion() >= TAG_MINOR_EVENT_TIMERS)
3033 {
3034 #endif
3035 timer_count = unmarshallByte(th);
3036 ASSERT(timer_count <= NUM_TIMERS);
3037 for (int j = 0; j < timer_count; ++j)
3038 {
3039 you.last_timer_effect[j] = unmarshallInt(th);
3040 you.next_timer_effect[j] = unmarshallInt(th);
3041 }
3042 #if TAG_MAJOR_VERSION == 34
3043 }
3044 else
3045 timer_count = 0;
3046 #endif
3047 // We'll have to fix up missing/broken timer entries after
3048 // we unmarshall you.elapsed_time.
3049
3050 // how many mutations/demon powers?
3051 count = unmarshallShort(th);
3052 ASSERT_RANGE(count, 0, NUM_MUTATIONS + 1);
3053 for (int j = 0; j < count; ++j)
3054 {
3055 you.mutation[j] = unmarshallUByte(th);
3056 you.innate_mutation[j] = unmarshallUByte(th);
3057 #if TAG_MAJOR_VERSION == 34
3058 if (th.getMinorVersion() >= TAG_MINOR_TEMP_MUTATIONS
3059 && th.getMinorVersion() != TAG_MINOR_0_11)
3060 {
3061 #endif
3062 you.temp_mutation[j] = unmarshallUByte(th);
3063 #if TAG_MAJOR_VERSION == 34
3064 }
3065 if (th.getMinorVersion() < TAG_MINOR_RU_SACRIFICES)
3066 you.sacrifices[j] = 0;
3067 else
3068 {
3069 #endif
3070 you.sacrifices[j] = unmarshallUByte(th);
3071 #if TAG_MAJOR_VERSION == 34
3072 }
3073
3074 if (you.innate_mutation[j] + you.temp_mutation[j] > you.mutation[j])
3075 {
3076 if (th.getMinorVersion() >= TAG_MINOR_SPIT_POISON_AGAIN
3077 && th.getMinorVersion() < TAG_MINOR_SPIT_POISON_AGAIN_AGAIN
3078 && j == MUT_SPIT_POISON)
3079 {
3080 // this special case needs to be handled diferently or
3081 // the level will be set too high; innate is what's corrupted.
3082 you.mutation[j] = you.innate_mutation[j] = 1;
3083 you.temp_mutation[j] = 0;
3084 }
3085 else
3086 {
3087 mprf(MSGCH_ERROR, "Mutation #%d out of sync, fixing up.", j);
3088 you.mutation[j] = you.innate_mutation[j] + you.temp_mutation[j];
3089 }
3090 }
3091 #endif
3092 }
3093
3094
3095 // mutation fixups happen below here.
3096 // *REMINDER*: if you fix up an innate mutation, remember to adjust both
3097 // `you.mutation` and `you.innate_mutation`.
3098
3099 #if TAG_MAJOR_VERSION == 34
3100 if (th.getMinorVersion() < TAG_MINOR_STAT_MUT)
3101 {
3102 // Convert excess mutational stats into base stats.
3103 mutation_type stat_mutations[] = { MUT_STRONG, MUT_CLEVER, MUT_AGILE };
3104 stat_type stat_types[] = { STAT_STR, STAT_INT, STAT_DEX };
3105 for (int j = 0; j < 3; ++j)
3106 {
3107 mutation_type mut = stat_mutations[j];
3108 stat_type stat = stat_types[j];
3109 int total_mutation_level = you.temp_mutation[mut] + you.mutation[mut];
3110 if (total_mutation_level > 2)
3111 {
3112 int new_level = max(0, min(you.temp_mutation[mut] - you.mutation[mut], 2));
3113 you.temp_mutation[mut] = new_level;
3114 }
3115 if (you.mutation[mut] > 2)
3116 {
3117 int excess = you.mutation[mut] - 4;
3118 if (excess > 0)
3119 you.base_stats[stat] += excess;
3120 you.mutation[mut] = 2;
3121 }
3122 }
3123 mutation_type bad_stat_mutations[] = { MUT_WEAK, MUT_DOPEY, MUT_CLUMSY };
3124 for (int j = 0; j < 3; ++j)
3125 {
3126 mutation_type mut = bad_stat_mutations[j];
3127 int level = you.mutation[mut];
3128 switch (level)
3129 {
3130 case 0:
3131 case 1:
3132 you.mutation[mut] = 0;
3133 break;
3134 case 2:
3135 case 3:
3136 you.mutation[mut] = 1;
3137 break;
3138 default:
3139 you.mutation[mut] = 2;
3140 break;
3141 };
3142 if (you.temp_mutation[mut] > 2 && you.mutation[mut] < 2)
3143 you.temp_mutation[mut] = 1;
3144 else
3145 you.temp_mutation[mut] = 0;
3146 }
3147 }
3148 you.mutation[MUT_FAST] = you.innate_mutation[MUT_FAST];
3149 you.mutation[MUT_SLOW] = you.innate_mutation[MUT_SLOW];
3150 if (you.species != SP_NAGA)
3151 _clear_mutation(MUT_SPIT_POISON);
3152 #endif
3153
3154 // TODO: this code looks really out of context, it should at least have
3155 // an ASSERT identifying count, but I'm not 100% sure what that would be
3156 for (int j = count; j < NUM_MUTATIONS; ++j)
3157 you.mutation[j] = you.innate_mutation[j] = you.sacrifices[j];
3158
3159 #if TAG_MAJOR_VERSION == 34
3160 if (th.getMinorVersion() < TAG_MINOR_NO_POTION_HEAL)
3161 { // These use to apply no matter what the minor tag
3162 // was, so when TAG_MINOR_NO_POTION_HEAL was added
3163 // these were all moved to only apply to previous
3164 // tags.
3165
3166 // some mutations from this tag are handled by generic cleanup code
3167 // below.
3168
3169 if (you.species == SP_GARGOYLE)
3170 _clear_mutation(MUT_POISON_RESISTANCE);
3171
3172 if (you.species == SP_FORMICID)
3173 you.mutation[MUT_ANTENNAE] = you.innate_mutation[MUT_ANTENNAE] = 3;
3174 }
3175
3176 if (th.getMinorVersion() < TAG_MINOR_SAPROVOROUS
3177 && you.species == SP_OGRE)
3178 {
3179 // Remove the innate level of fast metabolism
3180 you.mutation[MUT_FAST_METABOLISM] -= 1;
3181 you.innate_mutation[MUT_FAST_METABOLISM] -= 1;
3182 }
3183
3184 if (th.getMinorVersion() < TAG_MINOR_ROT_IMMUNITY
3185 && you.species == SP_VINE_STALKER)
3186 {
3187 you.mutation[MUT_NO_POTION_HEAL] =
3188 you.innate_mutation[MUT_NO_POTION_HEAL] = 2;
3189 }
3190
3191 if (th.getMinorVersion() < TAG_MINOR_DS_CLOUD_MUTATIONS
3192 && you.species == SP_DEMONSPAWN)
3193 {
3194 if (you.innate_mutation[MUT_CONSERVE_POTIONS])
3195 {
3196 // cleanup handled below
3197 you.mutation[MUT_FREEZING_CLOUD_IMMUNITY] =
3198 you.innate_mutation[MUT_FREEZING_CLOUD_IMMUNITY] = 1;
3199 }
3200 if (you.innate_mutation[MUT_CONSERVE_SCROLLS])
3201 {
3202 // cleanup handled below
3203 you.mutation[MUT_FLAME_CLOUD_IMMUNITY] =
3204 you.innate_mutation[MUT_FLAME_CLOUD_IMMUNITY] = 1;
3205 }
3206 }
3207
3208 // fixup trick for species-specific mutations. Not safe for mutations that
3209 // can also appear randomly, or have other uses. This ensures that
3210 // if `s` should have `m`, then it does, and also if the player has `m`
3211 // and is the wrong species, that they don't.
3212 // TODO: can we automate this from the species def?
3213 // (There's a lot of weird interactions and special cases to worry about..)
3214 #define SP_MUT_FIX(m, s) if (you.has_innate_mutation(m) || you.species == (s)) _fixup_species_mutations(m)
3215
3216 SP_MUT_FIX(MUT_QUADRUMANOUS, SP_FORMICID);
3217 SP_MUT_FIX(MUT_NO_DRINK, SP_MUMMY);
3218 SP_MUT_FIX(MUT_REFLEXIVE_HEADBUTT, SP_MINOTAUR);
3219 SP_MUT_FIX(MUT_STEAM_RESISTANCE, SP_PALE_DRACONIAN);
3220 SP_MUT_FIX(MUT_PAWS, SP_FELID);
3221 SP_MUT_FIX(MUT_NO_GRASPING, SP_FELID);
3222 SP_MUT_FIX(MUT_NO_ARMOUR, SP_FELID);
3223 SP_MUT_FIX(MUT_MULTILIVED, SP_FELID);
3224 SP_MUT_FIX(MUT_CONSTRICTING_TAIL, SP_NAGA);
3225 SP_MUT_FIX(MUT_DISTRIBUTED_TRAINING, SP_GNOLL);
3226 SP_MUT_FIX(MUT_MERTAIL, SP_MERFOLK);
3227 SP_MUT_FIX(MUT_TENTACLE_ARMS, SP_OCTOPODE);
3228 SP_MUT_FIX(MUT_VAMPIRISM, SP_VAMPIRE);
3229 SP_MUT_FIX(MUT_FLOAT, SP_DJINNI);
3230 SP_MUT_FIX(MUT_INNATE_CASTER, SP_DJINNI);
3231 SP_MUT_FIX(MUT_HP_CASTING, SP_DJINNI);
3232 SP_MUT_FIX(MUT_FLAT_HP, SP_DJINNI);
3233 SP_MUT_FIX(MUT_FORLORN, SP_DEMIGOD);
3234 SP_MUT_FIX(MUT_DAYSTALKER, SP_BARACHI);
3235
3236 if (you.has_innate_mutation(MUT_NIMBLE_SWIMMER)
3237 || you.species == SP_MERFOLK || you.species == SP_OCTOPODE)
3238 {
3239 _fixup_species_mutations(MUT_NIMBLE_SWIMMER);
3240 }
3241 if (you.species == SP_GARGOYLE || you.species == SP_MUMMY
3242 || you.species == SP_GHOUL)
3243 {
3244 // not safe for SP_MUT_FIX because demonspawn use this and it doesn't
3245 // handle ds muts
3246 _fixup_species_mutations(MUT_TORMENT_RESISTANCE);
3247 }
3248 if (you.species == SP_MUMMY)
3249 {
3250 // not safe for SP_MUT_FIX
3251 _fixup_species_mutations(MUT_HEAT_VULNERABILITY);
3252 }
3253 // not sure this is safe for SP_MUT_FIX, leaving it out for now
3254 if (you.species == SP_GREY_DRACONIAN || you.species == SP_GARGOYLE
3255 || you.species == SP_GHOUL || you.species == SP_MUMMY
3256 || you.species == SP_VAMPIRE)
3257 {
3258 _fixup_species_mutations(MUT_UNBREATHING);
3259 }
3260
3261 #undef SP_MUT_FIX
3262
3263 if (th.getMinorVersion() < TAG_MINOR_SPIT_POISON
3264 && you.species == SP_NAGA)
3265 {
3266 if (you.innate_mutation[MUT_SPIT_POISON] < 2)
3267 {
3268 you.mutation[MUT_SPIT_POISON] =
3269 you.innate_mutation[MUT_SPIT_POISON] = 2;
3270 }
3271 // cleanup handled below
3272 if (you.mutation[MUT_BREATHE_POISON])
3273 you.mutation[MUT_SPIT_POISON] = 3;
3274 }
3275
3276 // Give nagas constrict, tengu flight, and mummies restoration/enhancers.
3277 if (th.getMinorVersion() < TAG_MINOR_REAL_MUTS
3278 && (you.species == SP_NAGA
3279 || you.species == SP_TENGU
3280 || you.species == SP_MUMMY))
3281 {
3282 for (int xl = 2; xl <= you.experience_level; ++xl)
3283 give_level_mutations(you.species, xl);
3284 }
3285
3286 if (th.getMinorVersion() < TAG_MINOR_MP_WANDS)
3287 {
3288 if (you.mutation[MUT_MP_WANDS] > 1)
3289 you.mutation[MUT_MP_WANDS] = 1;
3290 }
3291
3292 if (th.getMinorVersion() < TAG_MINOR_DETERIORATION)
3293 {
3294 if (you.mutation[MUT_DETERIORATION] > 2)
3295 you.mutation[MUT_DETERIORATION] = 2;
3296 }
3297
3298 if (th.getMinorVersion() < TAG_MINOR_BLINK_MUT)
3299 {
3300 if (you.mutation[MUT_BLINK] > 1)
3301 you.mutation[MUT_BLINK] = 1;
3302 }
3303
3304 if (th.getMinorVersion() < TAG_MINOR_SPIT_POISON_AGAIN)
3305 {
3306 if (you.mutation[MUT_SPIT_POISON] > 1)
3307 you.mutation[MUT_SPIT_POISON] -= 1;
3308 // Before TAG_MINOR_SPIT_POISON_AGAIN_AGAIN this second if was missing.
3309 if (you.innate_mutation[MUT_SPIT_POISON] > 1)
3310 you.innate_mutation[MUT_SPIT_POISON] -= 1;
3311 }
3312 else if (th.getMinorVersion() < TAG_MINOR_SPIT_POISON_AGAIN_AGAIN)
3313 {
3314 // Between these two tags the value for you.innate_mutation could get
3315 // corrupted. No valid save after TAG_MINOR_SPIT_POISON_AGAIN should
3316 // have innate set to 2 for this for this mutation.
3317
3318 // this doesn't correct you.mutation, because the 2,2 configuration
3319 // can result from two cases: (i) a save was upgraded across
3320 // TAG_MINOR_SPIT_POISON_AGAIN, had its mutations corrupted, and
3321 // then was fixed up to 2,2 on load, or (ii) a save-pre-
3322 // TAG_MINOR_SPIT_POISON_AGAIN had exhale poison, had 1 subtracted
3323 // from mutation, and ends up as 2,2. So, some lucky upgrades will get
3324 // exhale poison.
3325
3326 if (you.innate_mutation[MUT_SPIT_POISON] == 2)
3327 you.innate_mutation[MUT_SPIT_POISON] = 1;
3328 }
3329
3330 // Slow regeneration split into two single-level muts:
3331 // * Inhibited regeneration (no regen in los of monsters, what Gh get)
3332 // * No regeneration (what DDs get)
3333 {
3334 if (you.species == SP_DEEP_DWARF
3335 && (you.mutation[MUT_INHIBITED_REGENERATION] > 0
3336 || you.mutation[MUT_NO_REGENERATION] != 1))
3337 {
3338 you.innate_mutation[MUT_INHIBITED_REGENERATION] = 0;
3339 you.mutation[MUT_INHIBITED_REGENERATION] = 0;
3340 you.innate_mutation[MUT_NO_REGENERATION] = 1;
3341 you.mutation[MUT_NO_REGENERATION] = 1;
3342 }
3343 else if (you.species == SP_GHOUL
3344 && you.mutation[MUT_INHIBITED_REGENERATION] > 1)
3345 {
3346 you.innate_mutation[MUT_INHIBITED_REGENERATION] = 1;
3347 you.mutation[MUT_INHIBITED_REGENERATION] = 1;
3348 }
3349 else if (you.mutation[MUT_INHIBITED_REGENERATION] > 1)
3350 you.mutation[MUT_INHIBITED_REGENERATION] = 1;
3351 }
3352
3353 if (th.getMinorVersion() < TAG_MINOR_YELLOW_DRACONIAN_RACID
3354 && you.species == SP_YELLOW_DRACONIAN)
3355 {
3356 you.mutation[MUT_ACID_RESISTANCE] = 1;
3357 you.innate_mutation[MUT_ACID_RESISTANCE] = 1;
3358 }
3359
3360 if (th.getMinorVersion() < TAG_MINOR_COMPRESS_BADMUTS)
3361 {
3362 if (you.mutation[MUT_SCREAM] > 2)
3363 you.mutation[MUT_SCREAM] = 2;
3364
3365 if (you.species == SP_VINE_STALKER)
3366 _fixup_species_mutations(MUT_NO_POTION_HEAL);
3367 else if (you.mutation[MUT_NO_POTION_HEAL] > 2)
3368 you.mutation[MUT_NO_POTION_HEAL] = 2;
3369 }
3370
3371 // fully clean up any removed mutations
3372 for (auto m : get_removed_mutations())
3373 _clear_mutation(m);
3374
3375 // Fixup for Sacrifice XP from XL 27 (#9895). No minor tag, but this
3376 // should still be removed on a major bump.
3377 const int xl_remaining = you.get_max_xl() - you.experience_level;
3378 if (xl_remaining < 0)
3379 adjust_level(xl_remaining);
3380 #endif
3381
3382 count = unmarshallUByte(th);
3383 you.demonic_traits.clear();
3384 for (int j = 0; j < count; ++j)
3385 {
3386 player::demon_trait dt;
3387 dt.level_gained = unmarshallByte(th);
3388 ASSERT_RANGE(dt.level_gained, 1, 28);
3389 dt.mutation = static_cast<mutation_type>(unmarshallShort(th));
3390 #if TAG_MAJOR_VERSION == 34
3391 if (dt.mutation == MUT_CONSERVE_POTIONS)
3392 dt.mutation = MUT_FREEZING_CLOUD_IMMUNITY;
3393 else if (dt.mutation == MUT_CONSERVE_SCROLLS)
3394 dt.mutation = MUT_FLAME_CLOUD_IMMUNITY;
3395 #endif
3396 ASSERT_RANGE(dt.mutation, 0, NUM_MUTATIONS);
3397 you.demonic_traits.push_back(dt);
3398 }
3399
3400 #if TAG_MAJOR_VERSION == 34
3401 if (th.getMinorVersion() < TAG_MINOR_SAC_PIETY_LEN)
3402 {
3403 const int OLD_NUM_ABILITIES = 1503;
3404
3405 // set up sacrifice piety by abilities
3406 for (int j = 0; j < NUM_ABILITIES; ++j)
3407 {
3408 if (th.getMinorVersion() < TAG_MINOR_RU_PIETY_CONSISTENCY
3409 || j >= OLD_NUM_ABILITIES) // NUM_ABILITIES may have increased
3410 {
3411 you.sacrifice_piety[j] = 0;
3412 }
3413 else
3414 you.sacrifice_piety[j] = unmarshallUByte(th);
3415 }
3416
3417 // If NUM_ABILITIES decreased, discard the extras.
3418 if (th.getMinorVersion() >= TAG_MINOR_RU_PIETY_CONSISTENCY)
3419 {
3420 for (int j = NUM_ABILITIES; j < OLD_NUM_ABILITIES; ++j)
3421 (void) unmarshallUByte(th);
3422 }
3423 }
3424 else
3425 #endif
3426 {
3427 const int num_saved = unmarshallShort(th);
3428
3429 you.sacrifice_piety.init(0);
3430 for (int j = 0; j < num_saved; ++j)
3431 {
3432 const int idx = ABIL_FIRST_SACRIFICE + j;
3433 const uint8_t val = unmarshallUByte(th);
3434 if (idx <= ABIL_FINAL_SACRIFICE)
3435 you.sacrifice_piety[idx] = val;
3436 }
3437 }
3438
3439 EAT_CANARY;
3440
3441 // how many penances?
3442 count = unmarshallUByte(th);
3443 ASSERT(count <= NUM_GODS);
3444 for (int i = 0; i < count; i++)
3445 {
3446 #if TAG_MAJOR_VERSION == 34
3447 if (th.getMinorVersion() < TAG_MINOR_XP_PENANCE && i == GOD_GOZAG)
3448 {
3449 unmarshallUByte(th);
3450 you.penance[i] = 0;
3451 continue;
3452 }
3453 #endif
3454 you.penance[i] = unmarshallUByte(th);
3455 #if TAG_MAJOR_VERSION == 34
3456 if (th.getMinorVersion() < TAG_MINOR_NEMELEX_WRATH
3457 && player_under_penance(GOD_NEMELEX_XOBEH)
3458 && i == GOD_NEMELEX_XOBEH)
3459 {
3460 you.penance[i] = max(you.penance[i] - 100, 0);
3461 }
3462 #endif
3463 ASSERT(you.penance[i] <= MAX_PENANCE);
3464 }
3465
3466 #if TAG_MAJOR_VERSION == 34
3467 // Fix invalid ATTR_GOD_WRATH_XP if no god is giving penance.
3468 // cf. 0.14-a0-2640-g5c5a558
3469 if (you.attribute[ATTR_GOD_WRATH_XP] != 0
3470 || you.attribute[ATTR_GOD_WRATH_COUNT] != 0)
3471 {
3472 god_iterator it;
3473 for (; it; ++it)
3474 {
3475 if (player_under_penance(*it))
3476 break;
3477 }
3478 if (!it)
3479 {
3480 you.attribute[ATTR_GOD_WRATH_XP] = 0;
3481 you.attribute[ATTR_GOD_WRATH_COUNT] = 0;
3482 }
3483 }
3484 #endif
3485
3486 for (int i = 0; i < count; i++)
3487 you.worshipped[i] = unmarshallByte(th);
3488
3489 for (int i = 0; i < count; i++)
3490 you.num_current_gifts[i] = unmarshallShort(th);
3491 for (int i = 0; i < count; i++)
3492 you.num_total_gifts[i] = unmarshallShort(th);
3493 for (int i = 0; i < count; i++)
3494 you.one_time_ability_used.set(i, unmarshallBoolean(th));
3495 for (int i = 0; i < count; i++)
3496 you.piety_max[i] = unmarshallByte(th);
3497 #if TAG_MAJOR_VERSION == 34
3498 if (th.getMinorVersion() < TAG_MINOR_NEMELEX_DUNGEONS)
3499 {
3500 unmarshallByte(th);
3501 for (int i = 0; i < NEM_GIFT_SUMMONING; i++)
3502 unmarshallBoolean(th);
3503 unmarshallBoolean(th); // dungeons weight
3504 for (int i = NEM_GIFT_SUMMONING; i < NUM_NEMELEX_GIFT_TYPES; i++)
3505 unmarshallBoolean(th);
3506 }
3507 else if (th.getMinorVersion() < TAG_MINOR_NEMELEX_WEIGHTS)
3508 {
3509 count = unmarshallByte(th);
3510 ASSERT(count == NUM_NEMELEX_GIFT_TYPES);
3511 for (int i = 0; i < count; i++)
3512 unmarshallBoolean(th);
3513 }
3514 #endif
3515
3516 you.gift_timeout = unmarshallByte(th);
3517 #if TAG_MAJOR_VERSION == 34
3518 if (th.getMinorVersion() < TAG_MINOR_SAVED_PIETY)
3519 {
3520 you.saved_good_god_piety = 0;
3521 you.previous_good_god = GOD_NO_GOD;
3522 }
3523 else
3524 {
3525 #endif
3526 you.saved_good_god_piety = unmarshallUByte(th);
3527 you.previous_good_god = static_cast<god_type>(unmarshallByte(th));
3528 #if TAG_MAJOR_VERSION == 34
3529 }
3530 #endif
3531
3532 #if TAG_MAJOR_VERSION == 34
3533 if (th.getMinorVersion() < TAG_MINOR_BRANCH_ENTRY)
3534 {
3535 int depth = unmarshallByte(th);
3536 branch_type br = static_cast<branch_type>(unmarshallByte(th));
3537 ASSERT(br < NUM_BRANCHES);
3538 brentry[BRANCH_VESTIBULE] = level_id(br, depth);
3539 }
3540 #endif
3541
3542 #if TAG_MAJOR_VERSION == 34
3543 if (th.getMinorVersion() < TAG_MINOR_XP_PENANCE)
3544 {
3545 for (god_iterator it; it; ++it)
3546 {
3547 if (*it == GOD_ASHENZARI)
3548 you.exp_docked[*it] = unmarshallInt(th);
3549 else
3550 you.exp_docked[*it] = 0;
3551 }
3552 for (god_iterator it; it; ++it)
3553 {
3554 if (*it == GOD_ASHENZARI)
3555 you.exp_docked_total[*it] = unmarshallInt(th);
3556 else
3557 you.exp_docked_total[*it] = 0;
3558 }
3559 }
3560 else
3561 {
3562 #endif
3563 for (int i = 0; i < count; i++)
3564 you.exp_docked[i] = unmarshallInt(th);
3565 for (int i = 0; i < count; i++)
3566 you.exp_docked_total[i] = unmarshallInt(th);
3567 #if TAG_MAJOR_VERSION == 34
3568 }
3569 if (th.getMinorVersion() < TAG_MINOR_PAKELLAS_WRATH
3570 && player_under_penance(GOD_PAKELLAS))
3571 {
3572 you.exp_docked[GOD_PAKELLAS] = excom_xp_docked();
3573 you.exp_docked_total[GOD_PAKELLAS] = you.exp_docked[GOD_PAKELLAS];
3574 }
3575 if (th.getMinorVersion() < TAG_MINOR_ELYVILON_WRATH
3576 && player_under_penance(GOD_ELYVILON))
3577 {
3578 you.exp_docked[GOD_ELYVILON] = excom_xp_docked();
3579 you.exp_docked_total[GOD_ELYVILON] = you.exp_docked[GOD_ELYVILON];
3580 }
3581
3582 #endif
3583
3584 // elapsed time
3585 you.elapsed_time = unmarshallInt(th);
3586 you.elapsed_time_at_last_input = you.elapsed_time;
3587
3588 // Initialize new timers now that we know the time.
3589 const int last_20_turns = you.elapsed_time - (you.elapsed_time % 200);
3590 for (int j = timer_count; j < NUM_TIMERS; ++j)
3591 {
3592 you.last_timer_effect[j] = last_20_turns;
3593 you.next_timer_effect[j] = last_20_turns + 200;
3594 }
3595
3596 // Verify that timers aren't scheduled for the past.
3597 for (int j = 0; j < NUM_TIMERS; ++j)
3598 {
3599 if (you.next_timer_effect[j] < you.elapsed_time)
3600 {
3601 #if TAG_MAJOR_VERSION == 34
3602 if (th.getMinorVersion() >= TAG_MINOR_EVENT_TIMERS
3603 && th.getMinorVersion() < TAG_MINOR_EVENT_TIMER_FIX)
3604 {
3605 dprf("Fixing up timer %d from %d to %d",
3606 j, you.next_timer_effect[j], last_20_turns + 200);
3607 you.last_timer_effect[j] = last_20_turns;
3608 you.next_timer_effect[j] = last_20_turns + 200;
3609 }
3610 else
3611 #endif
3612 die("Timer %d next trigger in the past [%d < %d]",
3613 j, you.next_timer_effect[j], you.elapsed_time);
3614 }
3615 }
3616
3617 // time of character creation
3618 you.birth_time = unmarshallInt(th);
3619
3620 const int real_time = unmarshallInt(th);
3621 you.real_time_ms = chrono::milliseconds(real_time * 1000);
3622 you.num_turns = unmarshallInt(th);
3623 you.exploration = unmarshallInt(th);
3624
3625 #if TAG_MAJOR_VERSION == 34
3626 if (th.getMinorVersion() < TAG_MINOR_CONTAM_SCALE)
3627 you.magic_contamination = unmarshallShort(th) * 1000;
3628 else
3629 #endif
3630 you.magic_contamination = unmarshallInt(th);
3631
3632 #if TAG_MAJOR_VERSION == 34
3633 unmarshallUByte(th);
3634 #endif
3635 you.transit_stair = unmarshallFeatureType(th);
3636 you.entering_level = unmarshallByte(th);
3637 #if TAG_MAJOR_VERSION == 34
3638 if (th.getMinorVersion() >= TAG_MINOR_TRAVEL_ALLY_PACE)
3639 {
3640 #endif
3641 you.travel_ally_pace = unmarshallBoolean(th);
3642 #if TAG_MAJOR_VERSION == 34
3643 }
3644 #endif
3645
3646 you.deaths = unmarshallByte(th);
3647 you.lives = unmarshallByte(th);
3648
3649 #if TAG_MAJOR_VERSION == 34
3650 if (th.getMinorVersion() >= TAG_MINOR_LORC_TEMPERATURE &&
3651 th.getMinorVersion() < TAG_MINOR_NO_MORE_LORC)
3652 {
3653 // These were once the temperature fields on player for lava orcs.
3654 // Still need to unmarshall them from older saves.
3655 unmarshallFloat(th); // was you.temperature
3656 unmarshallFloat(th); // was you.temperature_last
3657 }
3658 #endif
3659
3660 you.pending_revival = !you.hp;
3661
3662 EAT_CANARY;
3663
3664 int n_dact = unmarshallInt(th);
3665 ASSERT_RANGE(n_dact, 0, 100000); // arbitrary, sanity check
3666 you.dactions.resize(n_dact, NUM_DACTIONS);
3667 for (int i = 0; i < n_dact; i++)
3668 {
3669 int a = unmarshallUByte(th);
3670 ASSERT(a < NUM_DACTIONS);
3671 you.dactions[i] = static_cast<daction_type>(a);
3672 }
3673
3674 you.level_stack.clear();
3675 int n_levs = unmarshallInt(th);
3676 for (int k = 0; k < n_levs; k++)
3677 {
3678 level_pos pos;
3679 pos.load(th);
3680 you.level_stack.push_back(pos);
3681 }
3682
3683 // List of currently beholding monsters (usually empty).
3684 count = unmarshallShort(th);
3685 ASSERT(count >= 0);
3686 for (int i = 0; i < count; i++)
3687 {
3688 #if TAG_MAJOR_VERSION == 34
3689 if (th.getMinorVersion() < TAG_MINOR_MID_BEHOLDERS)
3690 {
3691 unmarshallShort(th);
3692 you.duration[DUR_MESMERISED] = 0;
3693 }
3694 else
3695 #endif
3696 you.beholders.push_back(unmarshall_int_as<mid_t>(th));
3697 }
3698
3699 // Also usually empty.
3700 count = unmarshallShort(th);
3701 ASSERT(count >= 0);
3702 for (int i = 0; i < count; i++)
3703 {
3704 #if TAG_MAJOR_VERSION == 34
3705 if (th.getMinorVersion() < TAG_MINOR_MID_BEHOLDERS)
3706 {
3707 unmarshallShort(th);
3708 you.duration[DUR_AFRAID] = 0;
3709 }
3710 else
3711 #endif
3712 you.fearmongers.push_back(unmarshall_int_as<mid_t>(th));
3713 }
3714
3715 you.piety_hysteresis = unmarshallByte(th);
3716
3717 you.m_quiver_history.load(th);
3718
3719 #if TAG_MAJOR_VERSION == 34
3720 if (th.getMinorVersion() < TAG_MINOR_FRIENDLY_PICKUP)
3721 unmarshallByte(th);
3722 if (th.getMinorVersion() < TAG_MINOR_NO_ZOTDEF)
3723 unmarshallString(th);
3724 #endif
3725
3726 EAT_CANARY;
3727
3728 #if TAG_MAJOR_VERSION == 34
3729 if (th.getMinorVersion() == TAG_MINOR_0_11)
3730 {
3731 for (unsigned int k = 0; k < 5; k++)
3732 unmarshallInt(th);
3733 }
3734 #endif
3735
3736 // Counts of actions made, by type.
3737 count = unmarshallShort(th);
3738 for (int i = 0; i < count; i++)
3739 {
3740 caction_type caction = (caction_type)unmarshallShort(th);
3741 int subtype = unmarshallInt(th);
3742 #if TAG_MAJOR_VERSION == 34
3743 if ((th.getMinorVersion() < TAG_MINOR_ACTION_THROW
3744 || th.getMinorVersion() == TAG_MINOR_0_11) && caction == CACT_THROW)
3745 {
3746 subtype = subtype | (OBJ_MISSILES << 16);
3747 }
3748 #endif
3749 for (int j = 0; j < 27; j++)
3750 you.action_count[make_pair(caction, subtype)][j] = unmarshallInt(th);
3751 }
3752
3753 #if TAG_MAJOR_VERSION == 34
3754 if (th.getMinorVersion() >= TAG_MINOR_BRANCHES_LEFT) // 33:17 has it
3755 {
3756 #endif
3757 count = unmarshallByte(th);
3758 for (int i = 0; i < count; i++)
3759 you.branches_left.set(i, unmarshallBoolean(th));
3760 #if TAG_MAJOR_VERSION == 34
3761 }
3762 else
3763 {
3764 // Assume all branches already exited in transferred games.
3765 you.branches_left.init(true);
3766 }
3767 #endif
3768
3769 abyssal_state.major_coord = unmarshallCoord(th);
3770 #if TAG_MAJOR_VERSION == 34
3771 if (th.getMinorVersion() >= TAG_MINOR_DEEP_ABYSS
3772 && th.getMinorVersion() != TAG_MINOR_0_11)
3773 {
3774 if (th.getMinorVersion() >= TAG_MINOR_REMOVE_ABYSS_SEED
3775 && th.getMinorVersion() < TAG_MINOR_ADD_ABYSS_SEED)
3776 {
3777 abyssal_state.seed = rng::get_uint32();
3778 }
3779 else
3780 #endif
3781 abyssal_state.seed = unmarshallInt(th);
3782 abyssal_state.depth = unmarshallInt(th);
3783 abyssal_state.destroy_all_terrain = false;
3784 #if TAG_MAJOR_VERSION == 34
3785 }
3786 else
3787 {
3788 unmarshallFloat(th); // converted abyssal_state.depth to int.
3789 abyssal_state.depth = 0;
3790 abyssal_state.destroy_all_terrain = true;
3791 abyssal_state.seed = rng::get_uint32();
3792 }
3793 #endif
3794 abyssal_state.phase = unmarshallFloat(th);
3795
3796 #if TAG_MAJOR_VERSION == 34
3797 if (th.getMinorVersion() >= TAG_MINOR_ABYSS_BRANCHES)
3798 abyssal_state.level = unmarshall_level_id(th);
3799 if (!abyssal_state.level.is_valid())
3800 {
3801 abyssal_state.level.branch = BRANCH_DEPTHS;
3802 abyssal_state.level.depth = 1;
3803 }
3804 #else
3805 abyssal_state.level = unmarshall_level_id(th);
3806 #endif
3807
3808 _unmarshall_constriction(th, &you);
3809
3810 you.octopus_king_rings = unmarshallUByte(th);
3811
3812 #if TAG_MAJOR_VERSION == 34
3813 if (th.getMinorVersion() >= TAG_MINOR_UNCANCELLABLES
3814 && th.getMinorVersion() != TAG_MINOR_0_11)
3815 {
3816 #endif
3817 count = unmarshallUnsigned(th);
3818 ASSERT_RANGE(count, 0, 16); // sanity check
3819 you.uncancel.resize(count);
3820 for (int i = 0; i < count; i++)
3821 {
3822 you.uncancel[i].first = (uncancellable_type)unmarshallUByte(th);
3823 you.uncancel[i].second = unmarshallInt(th);
3824 }
3825 #if TAG_MAJOR_VERSION == 34
3826 // Cancel any item-based deck manipulations
3827 if (th.getMinorVersion() < TAG_MINOR_REMOVE_DECKS)
3828 {
3829 erase_if(you.uncancel,
3830 [](const pair<uncancellable_type, int> uc) {
3831 return uc.first == UNC_DRAW_THREE
3832 || uc.first == UNC_STACK_FIVE;
3833 });
3834 }
3835 }
3836
3837 if (th.getMinorVersion() >= TAG_MINOR_INCREMENTAL_RECALL)
3838 {
3839 #endif
3840 count = unmarshallUnsigned(th);
3841 you.recall_list.resize(count);
3842 for (int i = 0; i < count; i++)
3843 you.recall_list[i] = unmarshall_int_as<mid_t>(th);
3844 #if TAG_MAJOR_VERSION == 34
3845 }
3846
3847 if (th.getMinorVersion() >= TAG_MINOR_SEEDS)
3848 {
3849 #endif
3850 count = unmarshallUByte(th);
3851
3852 #if TAG_MAJOR_VERSION == 34
3853 ASSERT(th.getMinorVersion() < TAG_MINOR_GAMESEEDS || count == 1);
3854 if (th.getMinorVersion() < TAG_MINOR_GAMESEEDS)
3855 {
3856 you.game_seed = count > 0 ? unmarshallInt(th) : rng::get_uint64();
3857 dprf("Upgrading from unseeded game.");
3858 crawl_state.seed = you.game_seed;
3859 you.fully_seeded = false;
3860 for (int i = 1; i < count; i++)
3861 unmarshallInt(th);
3862 }
3863 else
3864 {
3865 #endif
3866 // RNG block: game seed (uint64), whether the game is properly seeded,
3867 // and then internal RNG states stored as a vector.
3868 ASSERT(count == 1);
3869 you.game_seed = unmarshallUnsigned(th);
3870 dprf("Unmarshalling seed %" PRIu64, you.game_seed);
3871 crawl_state.seed = you.game_seed;
3872 you.fully_seeded = unmarshallBoolean(th);
3873 #if TAG_MAJOR_VERSION == 34
3874 // there is no way to tell the levelgen method for games before this
3875 // tag, unfortunately. Though if there are unvisited generated levels,
3876 // that guarantees some form of deterministic pregen.
3877 if (th.getMinorVersion() < TAG_MINOR_INCREMENTAL_PREGEN)
3878 you.deterministic_levelgen = false;
3879 else
3880 #endif
3881 you.deterministic_levelgen = unmarshallBoolean(th);
3882 CrawlVector rng_states;
3883 rng_states.read(th);
3884 rng::load_generators(rng_states);
3885 #if TAG_MAJOR_VERSION == 34
3886 }
3887 #endif
3888
3889 #if TAG_MAJOR_VERSION == 34
3890 }
3891 #endif
3892
3893 EAT_CANARY;
3894
3895 if (!dlua.callfn("dgn_load_data", "u", &th))
3896 {
3897 mprf(MSGCH_ERROR, "Failed to load Lua persist table: %s",
3898 dlua.error.c_str());
3899 }
3900
3901 EAT_CANARY;
3902
3903 crawl_state.save_rcs_version = unmarshallString(th);
3904
3905 you.props.clear();
3906 you.props.read(th);
3907 #if TAG_MAJOR_VERSION == 34
3908 if (!you.props.exists(TIME_PER_LEVEL_KEY) && you.elapsed_time > 0)
3909 {
3910 CrawlHashTable &time_tracking = you.props[TIME_PER_LEVEL_KEY].get_table();
3911 time_tracking["upgrade"] = -1;
3912 }
3913
3914 if (th.getMinorVersion() < TAG_MINOR_STICKY_FLAME)
3915 {
3916 if (you.props.exists("napalmer"))
3917 you.props["sticky_flame_source"] = you.props["napalmer"];
3918 if (you.props.exists("napalm_aux"))
3919 you.props["sticky_flame_aux"] = you.props["napalm_aux"];
3920 }
3921
3922 if (you.duration[DUR_EXCRUCIATING_WOUNDS] && !you.props.exists(ORIGINAL_BRAND_KEY))
3923 you.props[ORIGINAL_BRAND_KEY] = SPWPN_NORMAL;
3924
3925 // Both saves prior to TAG_MINOR_RU_DELAY_STACKING, and saves transferred
3926 // from before that tag to a version where this minor tag was backwards.
3927 if (!you.props.exists(RU_SACRIFICE_PENALTY_KEY))
3928 you.props[RU_SACRIFICE_PENALTY_KEY] = 0;
3929 if (th.getMinorVersion() < TAG_MINOR_ZIGFIGS)
3930 you.props["zig-fixup"] = true;
3931
3932 // For partially used lightning rods, set the XP debt based on charges.
3933 if (th.getMinorVersion() < TAG_MINOR_LIGHTNING_ROD_XP_FIX
3934 && you.props.exists(THUNDERBOLT_CHARGES_KEY)
3935 && evoker_debt(MISC_LIGHTNING_ROD) == 0)
3936 {
3937 for (int i = 0; i < you.props[THUNDERBOLT_CHARGES_KEY].get_int(); i++)
3938 expend_xp_evoker(MISC_LIGHTNING_ROD);
3939 }
3940 if (th.getMinorVersion() < TAG_MINOR_SINGULAR_THEY
3941 && you.props.exists(HEPLIAKLQANA_ALLY_GENDER_KEY))
3942 {
3943 if (you.props[HEPLIAKLQANA_ALLY_GENDER_KEY].get_int() == GENDER_NEUTER)
3944 you.props[HEPLIAKLQANA_ALLY_GENDER_KEY] = GENDER_NEUTRAL;
3945 }
3946
3947 if (th.getMinorVersion() < TAG_MINOR_SHAFT_CARD
3948 && you.props.exists(NEMELEX_STACK_KEY))
3949 {
3950 auto oldstack = you.props[NEMELEX_STACK_KEY].get_vector();
3951 you.props[NEMELEX_STACK_KEY].get_vector().clear();
3952 for (auto c : oldstack)
3953 {
3954 card_type card = static_cast<card_type>(c.get_int());
3955 if (card != CARD_SHAFT_REMOVED)
3956 you.props[NEMELEX_STACK_KEY].get_vector().push_back(card);
3957 }
3958 }
3959
3960 // Appendage changed to meld, so let's untransform players who were using
3961 // the old one
3962 if (th.getMinorVersion() < TAG_MINOR_APPENDAGE
3963 && you.form == transformation::appendage)
3964 {
3965 you.form = transformation::none;
3966 you.duration[DUR_TRANSFORMATION] = 0;
3967 const mutation_type app = static_cast<mutation_type>(you.attribute[ATTR_UNUSED3]);
3968 const int levels = you.get_base_mutation_level(app);
3969 const int beast_levels = app == MUT_HORNS ? 2 : 3;
3970 // Preserve extra mutation levels acquired after transforming.
3971 const int extra = max(0, levels - you.get_innate_mutation_level(app)
3972 - beast_levels);
3973 you.mutation[app] = you.get_innate_mutation_level(app) + extra;
3974 you.attribute[ATTR_UNUSED3] = 0;
3975 }
3976
3977 if (you.props.exists(WU_JIAN_HEAVENLY_STORM_KEY) && !you.duration[DUR_HEAVENLY_STORM])
3978 {
3979 mprf(MSGCH_ERROR, "Fixing up incorrect heavenly storm key");
3980 wu_jian_end_heavenly_storm();
3981 }
3982
3983 if (you.props.exists("tornado_since"))
3984 {
3985 you.props["polar_vortex_since"] = you.props["tornado_since"].get_int();
3986 you.props.erase("tornado_since");
3987 }
3988
3989 #endif
3990 }
3991
3992 #if TAG_MAJOR_VERSION == 34
3993 /// _cleanup_book_ids handles unmarshalling of old ID data for books.
_cleanup_book_ids(reader & th,int n_subtypes)3994 static void _cleanup_book_ids(reader &th, int n_subtypes)
3995 {
3996 if (th.getMinorVersion() >= TAG_MINOR_BOOK_UNID
3997 || th.getMinorVersion() < TAG_MINOR_BOOK_ID)
3998 {
3999 return;
4000 }
4001
4002 const bool ubyte = th.getMinorVersion() < TAG_MINOR_ID_STATES;
4003 for (int j = 0; j < n_subtypes; ++j)
4004 {
4005 if (ubyte)
4006 unmarshallUByte(th);
4007 else
4008 unmarshallBoolean(th);
4009 }
4010 }
4011 #endif
4012
_tag_read_you_items(reader & th)4013 static void _tag_read_you_items(reader &th)
4014 {
4015 int count, count2;
4016
4017 // how many inventory slots?
4018 count = unmarshallByte(th);
4019 ASSERT(count == ENDOFPACK); // not supposed to change
4020 #if TAG_MAJOR_VERSION == 34
4021 string bad_slots;
4022 #endif
4023 for (int i = 0; i < count; ++i)
4024 {
4025 item_def &it = you.inv[i];
4026 unmarshallItem(th, it);
4027 #if TAG_MAJOR_VERSION == 34
4028 // Fixups for actual items.
4029 if (it.defined())
4030 {
4031 // From 0.18-a0-273-gf174401 to 0.18-a0-290-gf199c8b, stash
4032 // search would change the position of items in inventory.
4033 if (it.pos != ITEM_IN_INVENTORY)
4034 {
4035 bad_slots += index_to_letter(i);
4036 it.pos = ITEM_IN_INVENTORY;
4037 }
4038
4039 // Items in inventory have already been handled.
4040 if (th.getMinorVersion() < TAG_MINOR_ISFLAG_HANDLED)
4041 it.flags |= ISFLAG_HANDLED;
4042 }
4043 #endif
4044 }
4045 #if TAG_MAJOR_VERSION == 34
4046 if (!bad_slots.empty())
4047 {
4048 mprf(MSGCH_ERROR, "Fixed bad positions for inventory slots %s",
4049 bad_slots.c_str());
4050 }
4051 #endif
4052
4053 // Initialize cache of equipped unrand functions
4054 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
4055 {
4056 const item_def *item = you.slot_item(static_cast<equipment_type>(i));
4057
4058 if (item && is_unrandom_artefact(*item))
4059 {
4060 #if TAG_MAJOR_VERSION == 34
4061 // save-compat: if the player was wearing the Ring of Vitality before
4062 // it turned into an amulet, take it off safely
4063 if (is_unrandom_artefact(*item, UNRAND_VITALITY) && i != EQ_AMULET)
4064 {
4065 you.equip[i] = -1;
4066 you.melded.set(i, false);
4067 continue;
4068 }
4069 // likewise the boots of the Assassin before it became a hat
4070 if (is_unrandom_artefact(*item, UNRAND_HOOD_ASSASSIN)
4071 && i != EQ_HELMET)
4072 {
4073 you.equip[i] = -1;
4074 you.melded.set(i, false);
4075 continue;
4076 }
4077 #endif
4078
4079 const unrandart_entry *entry = get_unrand_entry(item->unrand_idx);
4080
4081 if (entry->world_reacts_func)
4082 you.unrand_reacts.set(i);
4083 }
4084 }
4085
4086 _unmarshallFixedBitVector<NUM_RUNE_TYPES>(th, you.runes);
4087 you.obtainable_runes = unmarshallByte(th);
4088
4089 // Item descrip for each type & subtype.
4090 // how many types?
4091 count = unmarshallUByte(th);
4092 ASSERT(count <= NUM_IDESC);
4093 // how many subtypes?
4094 count2 = unmarshallUByte(th);
4095 ASSERT(count2 <= MAX_SUBTYPES);
4096 for (int i = 0; i < count; ++i)
4097 for (int j = 0; j < count2; ++j)
4098 #if TAG_MAJOR_VERSION == 34
4099 {
4100 if (th.getMinorVersion() < TAG_MINOR_CONSUM_APPEARANCE)
4101 you.item_description[i][j] = unmarshallUByte(th);
4102 else
4103 #endif
4104 you.item_description[i][j] = unmarshallInt(th);
4105 #if TAG_MAJOR_VERSION == 34
4106 // We briefly had a problem where we sign-extended the old
4107 // 8-bit item_descriptions on conversion. Fix those up.
4108 if (th.getMinorVersion() < TAG_MINOR_NEG_IDESC
4109 && (int)you.item_description[i][j] < 0)
4110 {
4111 you.item_description[i][j] &= 0xff;
4112 }
4113 }
4114 #endif
4115 for (int i = 0; i < count; ++i)
4116 for (int j = count2; j < MAX_SUBTYPES; ++j)
4117 you.item_description[i][j] = 0;
4118 int iclasses = unmarshallUByte(th);
4119 ASSERT(iclasses <= NUM_OBJECT_CLASSES);
4120
4121 // Identification status.
4122 for (int i = 0; i < iclasses; ++i)
4123 {
4124 if (!item_type_has_ids((object_class_type)i))
4125 {
4126 #if TAG_MAJOR_VERSION == 34
4127 if (i == OBJ_BOOKS)
4128 _cleanup_book_ids(th, count2);
4129 #endif
4130 continue;
4131 }
4132 for (int j = 0; j < count2; ++j)
4133 {
4134 #if TAG_MAJOR_VERSION == 34
4135 if (th.getMinorVersion() < TAG_MINOR_ID_STATES)
4136 {
4137 const uint8_t x = unmarshallUByte(th);
4138 ASSERT(x < NUM_ID_STATE_TYPES);
4139 if (x > ID_UNKNOWN_TYPE)
4140 you.type_ids[i][j] = true;
4141 else
4142 you.type_ids[i][j] = false;
4143 }
4144 else
4145 #endif
4146 you.type_ids[i][j] = unmarshallBoolean(th);
4147 }
4148 for (int j = count2; j < MAX_SUBTYPES; ++j)
4149 you.type_ids[i][j] = false;
4150 }
4151
4152 #if TAG_MAJOR_VERSION == 34
4153 if (th.getMinorVersion() < TAG_MINOR_ID_STATES)
4154 {
4155 CrawlHashTable old_type_id_props;
4156 old_type_id_props.read(th);
4157 }
4158 #endif
4159
4160 EAT_CANARY;
4161
4162 // how many unique items?
4163 count = unmarshallUByte(th);
4164 COMPILE_CHECK(NUM_UNRANDARTS <= 256);
4165 for (int j = 0; j < count && j < NUM_UNRANDARTS; ++j)
4166 {
4167 you.unique_items[j] =
4168 static_cast<unique_item_status_type>(unmarshallByte(th));
4169 }
4170 // # of unrandarts could certainly change.
4171 // If it does, the new ones won't exist yet - zero them out.
4172 for (int j = count; j < NUM_UNRANDARTS; j++)
4173 you.unique_items[j] = UNIQ_NOT_EXISTS;
4174 for (int j = NUM_UNRANDARTS; j < count; j++)
4175 unmarshallByte(th);
4176
4177 #if TAG_MAJOR_VERSION == 34
4178 if (th.getMinorVersion() < TAG_MINOR_GOLDIFY_BOOKS)
4179 {
4180 // how many books?
4181 count = unmarshallUByte(th);
4182 COMPILE_CHECK(NUM_FIXED_BOOKS <= 256);
4183 for (int j = 0; j < count && j < NUM_FIXED_BOOKS; ++j)
4184 unmarshallByte(th);
4185 for (int j = NUM_FIXED_BOOKS; j < count; ++j)
4186 unmarshallByte(th);
4187
4188 // how many spells?
4189 count = unmarshallShort(th);
4190 ASSERT(count >= 0);
4191 for (int j = 0; j < count && j < NUM_SPELLS; ++j)
4192 unmarshallByte(th);
4193 for (int j = NUM_SPELLS; j < count; ++j)
4194 unmarshallByte(th);
4195 }
4196 #endif
4197
4198 count = unmarshallShort(th);
4199 ASSERT(count >= 0);
4200 for (int j = 0; j < count && j < NUM_WEAPONS; ++j)
4201 you.seen_weapon[j] = unmarshallInt(th);
4202 for (int j = count; j < NUM_WEAPONS; ++j)
4203 you.seen_weapon[j] = 0;
4204 for (int j = NUM_WEAPONS; j < count; ++j)
4205 unmarshallInt(th);
4206
4207 count = unmarshallShort(th);
4208 ASSERT(count >= 0);
4209 for (int j = 0; j < count && j < NUM_ARMOURS; ++j)
4210 you.seen_armour[j] = unmarshallInt(th);
4211 for (int j = count; j < NUM_ARMOURS; ++j)
4212 you.seen_armour[j] = 0;
4213 for (int j = NUM_ARMOURS; j < count; ++j)
4214 unmarshallInt(th);
4215 _unmarshallFixedBitVector<NUM_MISCELLANY>(th, you.seen_misc);
4216
4217 for (int i = 0; i < iclasses; i++)
4218 for (int j = 0; j < count2; j++)
4219 you.force_autopickup[i][j] = unmarshallInt(th);
4220
4221 // preconditions: need to have read items, and you (incl props).
4222 you.quiver_action.load(QUIVER_MAIN_SAVE_KEY);
4223 you.launcher_action.load(QUIVER_LAUNCHER_SAVE_KEY);
4224
4225 #if TAG_MAJOR_VERSION == 34
4226 if (th.getMinorVersion() < TAG_MINOR_FOOD_AUTOPICKUP)
4227 {
4228 const int oldstate = you.force_autopickup[OBJ_FOOD][NUM_FOODS];
4229 you.force_autopickup[OBJ_FOOD][FOOD_RATION] = oldstate;
4230
4231 you.force_autopickup[OBJ_BOOKS][BOOK_MANUAL] =
4232 you.force_autopickup[OBJ_BOOKS][NUM_BOOKS];
4233 }
4234 if (th.getMinorVersion() < TAG_MINOR_FOOD_PURGE_AP_FIX)
4235 {
4236 FixedVector<int, MAX_SUBTYPES> &food_pickups =
4237 you.force_autopickup[OBJ_FOOD];
4238
4239 // If fruit pickup was not set explicitly during the time between
4240 // FOOD_PURGE and FOOD_PURGE_AP_FIX, copy the old exemplar FOOD_PEAR.
4241 if (food_pickups[FOOD_FRUIT] == AP_FORCE_NONE)
4242 food_pickups[FOOD_FRUIT] = food_pickups[FOOD_PEAR];
4243 }
4244 if (you.species == SP_FORMICID)
4245 remove_one_equip(EQ_HELMET, false, true);
4246
4247 if (th.getMinorVersion() < TAG_MINOR_CONSUM_APPEARANCE)
4248 {
4249 // merge scroll seeds
4250 for (int subtype = 0; subtype < MAX_SUBTYPES; subtype++)
4251 {
4252 const int seed1 = you.item_description[IDESC_SCROLLS][subtype]
4253 & 0xff;
4254 const int seed2 = you.item_description[IDESC_SCROLLS_II][subtype]
4255 & 0xff;
4256 const int seed3 = OBJ_SCROLLS & 0xff;
4257 you.item_description[IDESC_SCROLLS][subtype] = seed1
4258 | (seed2 << 8)
4259 | (seed3 << 16);
4260 }
4261 }
4262
4263 // Remove any decks now that items have been loaded.
4264 if (th.getMinorVersion() < TAG_MINOR_REMOVE_DECKS)
4265 reclaim_decks();
4266
4267 // Reset training arrays for transfered gnolls that didn't train all skills.
4268 if (th.getMinorVersion() < TAG_MINOR_GNOLLS_REDUX)
4269 reset_training();
4270
4271 // Move any books from inventory into the player's library.
4272 // (Likewise for manuals.)
4273 if (th.getMinorVersion() < TAG_MINOR_GOLDIFY_MANUALS)
4274 add_held_books_to_library();
4275
4276 for (int i = 0; i < ENDOFPACK; ++i)
4277 if (you.inv[i].defined())
4278 god_id_item(you.inv[i], true);
4279 #endif
4280 }
4281
unmarshallPlaceInfo(reader & th)4282 static PlaceInfo unmarshallPlaceInfo(reader &th)
4283 {
4284 PlaceInfo place_info;
4285
4286 #if TAG_MAJOR_VERSION == 34
4287 int br = unmarshallInt(th);
4288 // This is for extremely old saves that predate NUM_BRANCHES, probably only
4289 // a very small window of time in the 34 major version.
4290 if (br == -1)
4291 br = GLOBAL_BRANCH_INFO;
4292 ASSERT(br >= 0);
4293 // at the time NUM_BRANCHES was one above BRANCH_DEPTHS, so we check that
4294 if (th.getMinorVersion() < TAG_MINOR_GLOBAL_BR_INFO && br == BRANCH_DEPTHS+1)
4295 br = GLOBAL_BRANCH_INFO;
4296 place_info.branch = static_cast<branch_type>(br);
4297 #else
4298 place_info.branch = static_cast<branch_type>(unmarshallInt(th));
4299 #endif
4300
4301 place_info.num_visits = unmarshallInt(th);
4302 place_info.levels_seen = unmarshallInt(th);
4303
4304 place_info.mon_kill_exp = unmarshallInt(th);
4305
4306 for (int i = 0; i < KC_NCATEGORIES; i++)
4307 place_info.mon_kill_num[i] = unmarshallInt(th);
4308
4309 place_info.turns_total = unmarshallInt(th);
4310 place_info.turns_explore = unmarshallInt(th);
4311 place_info.turns_travel = unmarshallInt(th);
4312 place_info.turns_interlevel = unmarshallInt(th);
4313 place_info.turns_resting = unmarshallInt(th);
4314 place_info.turns_other = unmarshallInt(th);
4315
4316 place_info.elapsed_total = unmarshallInt(th);
4317 place_info.elapsed_explore = unmarshallInt(th);
4318 place_info.elapsed_travel = unmarshallInt(th);
4319 place_info.elapsed_interlevel = unmarshallInt(th);
4320 place_info.elapsed_resting = unmarshallInt(th);
4321 place_info.elapsed_other = unmarshallInt(th);
4322
4323 return place_info;
4324 }
4325
unmarshallLevelXPInfo(reader & th)4326 static LevelXPInfo unmarshallLevelXPInfo(reader &th)
4327 {
4328 LevelXPInfo xp_info;
4329
4330 xp_info.level = unmarshall_level_id(th);
4331
4332 #if TAG_MAJOR_VERSION == 34
4333 // Track monster placement from vaults instead of tracking spawns.
4334 if (th.getMinorVersion() < TAG_MINOR_LEVEL_XP_VAULTS)
4335 {
4336 // Spawned/generated xp and counts have to be combined as non-vault
4337 // info. We have no vault info on dead monsters, so this is the best we
4338 // can do.
4339 xp_info.non_vault_xp = unmarshallInt(th);
4340 xp_info.non_vault_xp += unmarshallInt(th);
4341 xp_info.non_vault_count = unmarshallInt(th);
4342 xp_info.non_vault_count += unmarshallInt(th);
4343 // turns spent on level, which we don't need.
4344 unmarshallInt(th);
4345 }
4346 else
4347 {
4348 #endif
4349 xp_info.non_vault_xp = unmarshallInt(th);
4350 xp_info.non_vault_count = unmarshallInt(th);
4351 xp_info.vault_xp = unmarshallInt(th);
4352 xp_info.vault_count = unmarshallInt(th);
4353 #if TAG_MAJOR_VERSION == 34
4354 }
4355 #endif
4356
4357 return xp_info;
4358 }
4359
4360 #if TAG_MAJOR_VERSION == 34
4361 static branch_type old_entries[] =
4362 {
4363 /* D */ NUM_BRANCHES,
4364 /* Temple */ BRANCH_DUNGEON,
4365 /* Orc */ BRANCH_DUNGEON,
4366 /* Elf */ BRANCH_ORC,
4367 /* Dwarf */ BRANCH_ELF,
4368 /* Lair */ BRANCH_DUNGEON,
4369 /* Swamp */ BRANCH_LAIR,
4370 /* Shoals */ BRANCH_LAIR,
4371 /* Snake */ BRANCH_LAIR,
4372 /* Spider */ BRANCH_LAIR,
4373 /* Slime */ BRANCH_LAIR,
4374 /* Vaults */ BRANCH_DUNGEON,
4375 /* Blade */ BRANCH_VAULTS,
4376 /* Crypt */ BRANCH_VAULTS,
4377 /* Tomb */ BRANCH_CRYPT, // or Forest
4378 /* Hell */ NUM_BRANCHES,
4379 /* Dis */ BRANCH_VESTIBULE,
4380 /* Geh */ BRANCH_VESTIBULE,
4381 /* Coc */ BRANCH_VESTIBULE,
4382 /* Tar */ BRANCH_VESTIBULE,
4383 /* Zot */ BRANCH_DUNGEON,
4384 /* Forest */ BRANCH_VAULTS,
4385 /* Abyss */ NUM_BRANCHES,
4386 /* Pan */ NUM_BRANCHES,
4387 /* various portal branches */ NUM_BRANCHES,
4388 NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES,
4389 NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES, NUM_BRANCHES,
4390 NUM_BRANCHES,
4391 };
4392 #endif
4393
_tag_read_you_dungeon(reader & th)4394 static void _tag_read_you_dungeon(reader &th)
4395 {
4396 // how many unique creatures?
4397 int count = unmarshallShort(th);
4398 you.unique_creatures.reset();
4399 for (int j = 0; j < count; ++j)
4400 {
4401 const bool created = unmarshallBoolean(th);
4402
4403 if (j < NUM_MONSTERS && created)
4404 you.unique_creatures.set(j, created);
4405 }
4406
4407 // how many branches?
4408 count = unmarshallUByte(th);
4409 ASSERT(count <= NUM_BRANCHES);
4410 for (int j = 0; j < count; ++j)
4411 {
4412 brdepth[j] = unmarshallInt(th);
4413 ASSERT_RANGE(brdepth[j], -1, MAX_BRANCH_DEPTH + 1);
4414 #if TAG_MAJOR_VERSION == 34
4415 if (th.getMinorVersion() < TAG_MINOR_BRANCH_ENTRY)
4416 {
4417 int depth = unmarshallInt(th);
4418 if (j != BRANCH_VESTIBULE)
4419 brentry[j] = level_id(old_entries[j], depth);
4420 }
4421 else
4422 #endif
4423 brentry[j] = unmarshall_level_id(th);
4424 #if TAG_MAJOR_VERSION == 34
4425 if (th.getMinorVersion() < TAG_MINOR_BRIBE_BRANCH)
4426 branch_bribe[j] = 0;
4427 else
4428 #endif
4429 branch_bribe[j] = unmarshallInt(th);
4430 }
4431 // Initialize data for any branches added after this save version.
4432 for (int j = count; j < NUM_BRANCHES; ++j)
4433 {
4434 brdepth[j] = branches[j].numlevels;
4435 brentry[j] = level_id(branches[j].parent_branch, branches[j].mindepth);
4436 branch_bribe[j] = 0;
4437 }
4438
4439 #if TAG_MAJOR_VERSION == 34
4440 // Deepen the Abyss; this is okay since new abyssal stairs will be
4441 // generated as the place shifts.
4442 if (crawl_state.game_is_normal() && th.getMinorVersion() <= TAG_MINOR_ORIG_MONNUM)
4443 brdepth[BRANCH_ABYSS] = 5;
4444 #endif
4445
4446 ASSERT(you.depth <= brdepth[you.where_are_you]);
4447
4448 // Root of the dungeon; usually BRANCH_DUNGEON.
4449 root_branch = static_cast<branch_type>(unmarshallInt(th));
4450 #if TAG_MAJOR_VERSION == 34
4451 if (th.getMinorVersion() < TAG_MINOR_BRANCH_ENTRY)
4452 {
4453 brentry[root_branch].clear();
4454 if (brentry[BRANCH_FOREST].is_valid())
4455 brentry[BRANCH_TOMB].branch = BRANCH_FOREST;
4456 }
4457 #endif
4458
4459 unmarshallMap(th, stair_level,
4460 unmarshall_int_as<branch_type>,
4461 _unmarshall_level_id_set);
4462 unmarshallMap(th, shops_present,
4463 _unmarshall_level_pos, unmarshall_int_as<shop_type>);
4464 unmarshallMap(th, altars_present,
4465 _unmarshall_level_pos, unmarshall_int_as<god_type>);
4466 unmarshallMap(th, portals_present,
4467 _unmarshall_level_pos, unmarshall_int_as<branch_type>);
4468 unmarshallMap(th, portal_notes,
4469 _unmarshall_level_pos, unmarshallString);
4470 unmarshallMap(th, level_annotations,
4471 unmarshall_level_id, unmarshallString);
4472 unmarshallMap(th, level_exclusions,
4473 unmarshall_level_id, unmarshallString);
4474 unmarshallMap(th, level_uniques,
4475 unmarshall_level_id, unmarshallString);
4476 unmarshallUniqueAnnotations(th);
4477
4478 PlaceInfo place_info = unmarshallPlaceInfo(th);
4479 ASSERT(place_info.is_global());
4480 you.set_place_info(place_info);
4481
4482 unsigned short count_p = (unsigned short) unmarshallShort(th);
4483
4484 auto places = you.get_all_place_info();
4485 // Use "<=" so that adding more branches or non-dungeon places
4486 // won't break save-file compatibility.
4487 ASSERT(count_p <= places.size());
4488
4489 for (int i = 0; i < count_p; i++)
4490 {
4491 place_info = unmarshallPlaceInfo(th);
4492 #if TAG_MAJOR_VERSION == 34
4493 if (place_info.is_global())
4494 {
4495 // This is to fix some crashing saves that didn't import
4496 // correctly, where under certain circumstances upgrading
4497 // a game to a version with an added branch could fail to
4498 // initialize the branch number. This has happened at least three
4499 // times now for slightly different reasons, for depths,
4500 // desolation, and gauntlet. The depths fixup is old enough that
4501 // it is handled differently.
4502 //
4503 // The basic assumption is that if a place is marked as global, it's
4504 // not properly initialized. The fixup assumes that logical branch
4505 // order (used by get_all_place_info) has not changed since the
4506 // save except at the end.
4507
4508 const branch_type branch_to_fix = places[i].branch;
4509 mprf(MSGCH_ERROR,
4510 "Save file has uninitialized PlaceInfo for branch %s",
4511 branches[places[i].branch].shortname);
4512 // these are the known cases where this fix applies. It would
4513 // probably be possible to drop this ASSERT...
4514 ASSERT(branch_to_fix == BRANCH_DESOLATION ||
4515 branch_to_fix == BRANCH_GAUNTLET);
4516 place_info.branch = branch_to_fix;
4517 }
4518 #endif
4519 ASSERT(!place_info.is_global());
4520 you.set_place_info(place_info);
4521 }
4522
4523 #if TAG_MAJOR_VERSION == 34
4524 if (th.getMinorVersion() < TAG_MINOR_TOMB_HATCHES)
4525 {
4526 PlaceInfo pinfo = you.get_place_info(BRANCH_TOMB);
4527 if (pinfo.levels_seen > 0)
4528 you.props[TOMB_STONE_STAIRS_KEY] = true;
4529 }
4530 #endif
4531
4532 #if TAG_MAJOR_VERSION == 34
4533 if (th.getMinorVersion() >= TAG_MINOR_LEVEL_XP_INFO)
4534 {
4535 #endif
4536 auto xp_info = unmarshallLevelXPInfo(th);
4537 ASSERT(xp_info.is_global());
4538 you.set_level_xp_info(xp_info);
4539
4540 count_p = (unsigned short) unmarshallShort(th);
4541 for (int i = 0; i < count_p; i++)
4542 {
4543 xp_info = unmarshallLevelXPInfo(th);
4544 ASSERT(!xp_info.is_global());
4545 you.set_level_xp_info(xp_info);
4546 }
4547 #if TAG_MAJOR_VERSION == 34
4548 }
4549 #endif
4550
4551 typedef pair<string_set::iterator, bool> ssipair;
4552 unmarshall_container(th, you.uniq_map_tags,
4553 (ssipair (string_set::*)(const string &))
4554 &string_set::insert,
4555 unmarshallString);
4556 unmarshall_container(th, you.uniq_map_names,
4557 (ssipair (string_set::*)(const string &))
4558 &string_set::insert,
4559 unmarshallString);
4560 #if TAG_MAJOR_VERSION == 34
4561 if (th.getMinorVersion() >= TAG_MINOR_ABYSS_UNIQUE_VAULTS)
4562 {
4563 #endif
4564 unmarshall_container(th, you.uniq_map_tags_abyss,
4565 (ssipair (string_set::*)(const string &))
4566 &string_set::insert,
4567 unmarshallString);
4568 unmarshall_container(th, you.uniq_map_names_abyss,
4569 (ssipair (string_set::*)(const string &))
4570 &string_set::insert,
4571 unmarshallString);
4572 #if TAG_MAJOR_VERSION == 34
4573 }
4574 if (th.getMinorVersion() >= TAG_MINOR_VAULT_LIST) // 33:17 has it
4575 #endif
4576 unmarshallMap(th, you.vault_list, unmarshall_level_id,
4577 unmarshallStringVector);
4578
4579 read_level_connectivity(th);
4580 }
4581
_tag_read_lost_monsters(reader & th)4582 static void _tag_read_lost_monsters(reader &th)
4583 {
4584 the_lost_ones.clear();
4585 unmarshallMap(th, the_lost_ones,
4586 unmarshall_level_id, unmarshall_follower_list);
4587 }
4588
4589 #if TAG_MAJOR_VERSION == 34
_tag_read_lost_items(reader & th)4590 static void _tag_read_lost_items(reader &th)
4591 {
4592 items_in_transit transiting_items;
4593
4594 unmarshallMap(th, transiting_items,
4595 unmarshall_level_id, unmarshall_item_list);
4596 }
4597 #endif
4598
_tag_read_companions(reader & th)4599 static void _tag_read_companions(reader &th)
4600 {
4601 companion_list.clear();
4602
4603 unmarshallMap(th, companion_list, unmarshall_int_as<mid_t>,
4604 unmarshall_companion);
4605 }
4606
4607 template <typename Z>
_last_used_index(const Z & thinglist,int max_things)4608 static int _last_used_index(const Z &thinglist, int max_things)
4609 {
4610 for (int i = max_things - 1; i >= 0; --i)
4611 if (thinglist[i].defined())
4612 return i + 1;
4613 return 0;
4614 }
4615
4616 // ------------------------------- level tags ---------------------------- //
4617
_tag_construct_level(writer & th)4618 static void _tag_construct_level(writer &th)
4619 {
4620 marshallByte(th, env.floor_colour);
4621 marshallByte(th, env.rock_colour);
4622
4623 marshallInt(th, you.on_current_level ? you.elapsed_time : env.elapsed_time);
4624 marshallCoord(th, you.on_current_level ? you.pos() : env.old_player_pos);
4625
4626 // Map grids.
4627 // how many X?
4628 marshallShort(th, GXM);
4629 // how many Y?
4630 marshallShort(th, GYM);
4631
4632 marshallInt(th, env.turns_on_level);
4633
4634 CANARY;
4635
4636 for (int count_x = 0; count_x < GXM; count_x++)
4637 for (int count_y = 0; count_y < GYM; count_y++)
4638 {
4639 marshallByte(th, env.grid[count_x][count_y]);
4640 marshallMapCell(th, env.map_knowledge[count_x][count_y]);
4641 marshallInt(th, env.pgrid[count_x][count_y].flags);
4642 }
4643
4644 marshallBoolean(th, !!env.map_forgotten);
4645 if (env.map_forgotten)
4646 for (int x = 0; x < GXM; x++)
4647 for (int y = 0; y < GYM; y++)
4648 marshallMapCell(th, (*env.map_forgotten)[x][y]);
4649
4650 _run_length_encode(th, marshallByte, env.grid_colours, GXM, GYM);
4651
4652 CANARY;
4653
4654 // how many clouds?
4655 marshallShort(th, env.cloud.size());
4656 for (const auto& entry : env.cloud)
4657 {
4658 const cloud_struct& cloud = entry.second;
4659 marshallByte(th, cloud.type);
4660 ASSERT(cloud.type != CLOUD_NONE);
4661 ASSERT_IN_BOUNDS(cloud.pos);
4662 marshallByte(th, cloud.pos.x);
4663 marshallByte(th, cloud.pos.y);
4664 marshallShort(th, cloud.decay);
4665 marshallByte(th, cloud.spread_rate);
4666 marshallByte(th, cloud.whose);
4667 marshallByte(th, cloud.killer);
4668 marshallInt(th, cloud.source);
4669 marshallInt(th, cloud.excl_rad);
4670 }
4671
4672 CANARY;
4673
4674 // how many shops?
4675 marshallShort(th, env.shop.size());
4676 for (const auto& entry : env.shop)
4677 marshall_shop(th, entry.second);
4678
4679 CANARY;
4680
4681 marshallCoord(th, env.sanctuary_pos);
4682 marshallByte(th, env.sanctuary_time);
4683
4684 marshallInt(th, env.spawn_random_rate);
4685
4686 env.markers.write(th);
4687 env.properties.write(th);
4688
4689 // number of completed dactions. Assume, apparently, that a level can only
4690 // be saved if they're complete? TODO: logic is kind of weird.
4691 marshallInt(th, you.dactions.size());
4692
4693 // Save heightmap, if present.
4694 marshallByte(th, !!env.heightmap);
4695 if (env.heightmap)
4696 {
4697 grid_heightmap &heightmap(*env.heightmap);
4698 for (rectangle_iterator ri(0); ri; ++ri)
4699 marshallShort(th, heightmap(*ri));
4700 }
4701
4702 CANARY;
4703
4704 marshallInt(th, env.forest_awoken_until);
4705 marshall_level_vault_data(th);
4706 marshallInt(th, env.density);
4707 }
4708
marshallItem(writer & th,const item_def & item,bool iinfo)4709 void marshallItem(writer &th, const item_def &item, bool iinfo)
4710 {
4711 marshallByte(th, item.base_type);
4712 if (item.base_type == OBJ_UNASSIGNED)
4713 return;
4714
4715 #if TAG_MAJOR_VERSION == 34
4716 if (!item.is_valid(iinfo))
4717 {
4718 string name;
4719 item_def dummy = item;
4720 if (!item.quantity)
4721 name = "(quantity: 0) ", dummy.quantity = 1;
4722 name += dummy.name(DESC_PLAIN, true);
4723 die("Invalid item: %s", name.c_str());
4724 }
4725 #endif
4726 ASSERT(item.is_valid(iinfo));
4727
4728 marshallByte(th, item.sub_type);
4729 marshallShort(th, item.plus);
4730 marshallShort(th, item.plus2);
4731 marshallInt(th, item.special);
4732 marshallShort(th, item.quantity);
4733
4734 marshallByte(th, item.rnd);
4735 marshallShort(th, item.pos.x);
4736 marshallShort(th, item.pos.y);
4737 marshallInt(th, item.flags);
4738
4739 marshallShort(th, item.link);
4740 if (item.pos.x >= 0 && item.pos.y >= 0)
4741 marshallShort(th, env.igrid(item.pos)); // unused
4742 else
4743 marshallShort(th, -1); // unused
4744
4745 marshallByte(th, item.slot);
4746
4747 item.orig_place.save(th);
4748 marshallShort(th, item.orig_monnum);
4749 marshallString(th, item.inscription);
4750
4751 item.props.write(th);
4752 }
4753
4754 #if TAG_MAJOR_VERSION == 34
_trim_god_gift_inscrip(item_def & item)4755 static void _trim_god_gift_inscrip(item_def& item)
4756 {
4757 item.inscription = replace_all(item.inscription, "god gift, ", "");
4758 item.inscription = replace_all(item.inscription, "god gift", "");
4759 item.inscription = replace_all(item.inscription, "Psyche", "");
4760 item.inscription = replace_all(item.inscription, "Sonja", "");
4761 item.inscription = replace_all(item.inscription, "Donald", "");
4762 }
4763
4764 /// Replace "dragon armour" with "dragon scales" in an artefact's name.
_fixup_dragon_artefact_name(item_def & item,string name_key)4765 static void _fixup_dragon_artefact_name(item_def &item, string name_key)
4766 {
4767 if (!item.props.exists(name_key))
4768 return;
4769
4770 string &name = item.props[name_key].get_string();
4771 static const string to_repl = "dragon armour";
4772 string::size_type found = name.find(to_repl, 0);
4773 if (found != string::npos)
4774 name.replace(found, to_repl.length(), "dragon scales");
4775 }
4776 #endif
4777
unmarshallItem(reader & th,item_def & item)4778 void unmarshallItem(reader &th, item_def &item)
4779 {
4780 item.base_type = static_cast<object_class_type>(unmarshallByte(th));
4781 if (item.base_type == OBJ_UNASSIGNED)
4782 return;
4783 item.sub_type = unmarshallUByte(th);
4784 item.plus = unmarshallShort(th);
4785 #if TAG_MAJOR_VERSION == 34
4786 if (th.getMinorVersion() < TAG_MINOR_RUNE_TYPE
4787 && item.is_type(OBJ_MISCELLANY, MISC_RUNE_OF_ZOT))
4788 {
4789 item.base_type = OBJ_RUNES;
4790 item.sub_type = item.plus;
4791 item.plus = 0;
4792 }
4793 if (th.getMinorVersion() < TAG_MINOR_ZIGFIGS
4794 // enum was accidentally inserted in the middle
4795 && item.is_type(OBJ_MISCELLANY, MISC_ZIGGURAT))
4796 {
4797 item.sub_type = MISC_PHANTOM_MIRROR;
4798 }
4799 #endif
4800 item.plus2 = unmarshallShort(th);
4801 item.special = unmarshallInt(th);
4802 item.quantity = unmarshallShort(th);
4803 #if TAG_MAJOR_VERSION == 34
4804 // These used to come in stacks in monster inventory as throwing weapons.
4805 // Replace said stacks (but not single items) with boomerangs.
4806 if (item.quantity > 1 && item.base_type == OBJ_WEAPONS
4807 && (item.sub_type == WPN_CLUB || item.sub_type == WPN_HAND_AXE
4808 || item.sub_type == WPN_DAGGER || item.sub_type == WPN_SPEAR))
4809 {
4810 item.base_type = OBJ_MISSILES;
4811 item.sub_type = MI_BOOMERANG;
4812 item.plus = item.plus2 = 0;
4813 item.brand = SPMSL_NORMAL;
4814 }
4815
4816 // Strip vestiges of distracting gold.
4817 if (item.base_type == OBJ_GOLD)
4818 item.special = 0;
4819
4820 if (th.getMinorVersion() < TAG_MINOR_REMOVE_ITEM_COLOUR)
4821 /* item.colour = */ unmarshallUByte(th);
4822 #endif
4823
4824 item.rnd = unmarshallUByte(th);
4825
4826 item.pos.x = unmarshallShort(th);
4827 item.pos.y = unmarshallShort(th);
4828 item.flags = unmarshallInt(th);
4829 item.link = unmarshallShort(th);
4830 #if TAG_MAJOR_VERSION == 34
4831 // ITEM_IN_SHOP was briefly NON_ITEM + NON_ITEM (1e85cf0), but that
4832 // doesn't fit in a short.
4833 if (item.link == static_cast<signed short>(54000))
4834 item.link = ITEM_IN_SHOP;
4835 #endif
4836
4837 unmarshallShort(th); // env.igrid[item.x][item.y] -- unused
4838
4839 item.slot = unmarshallByte(th);
4840
4841 #if TAG_MAJOR_VERSION == 34
4842 if (th.getMinorVersion() < TAG_MINOR_PLACE_UNPACK)
4843 {
4844 unsigned short packed = unmarshallShort(th);
4845 if (packed == 0)
4846 item.orig_place.clear();
4847 else if (packed == 0xFFFF)
4848 item.orig_place = level_id(BRANCH_DUNGEON, 0);
4849 else
4850 item.orig_place = level_id::from_packed_place(packed);
4851 }
4852 else
4853 #endif
4854 item.orig_place.load(th);
4855
4856 item.orig_monnum = unmarshallShort(th);
4857 #if TAG_MAJOR_VERSION == 34
4858 if (th.getMinorVersion() < TAG_MINOR_ORIG_MONNUM && item.orig_monnum > 0)
4859 item.orig_monnum--;
4860 #endif
4861 item.inscription = unmarshallString(th);
4862
4863 item.props.clear();
4864 item.props.read(th);
4865 #if TAG_MAJOR_VERSION == 34
4866 if (th.getMinorVersion() < TAG_MINOR_CORPSE_COLOUR
4867 && item.base_type == OBJ_CORPSES
4868 && item.props.exists(FORCED_ITEM_COLOUR_KEY)
4869 && !item.props[FORCED_ITEM_COLOUR_KEY].get_int())
4870 {
4871 item.props[FORCED_ITEM_COLOUR_KEY] = LIGHTRED;
4872 }
4873
4874 // If we lost the monster held in an orc corpse because we marshalled
4875 // it as a dead monster, clear out the prop.
4876 if (item.props.exists(ORC_CORPSE_KEY)
4877 && item.props[ORC_CORPSE_KEY].get_monster().type == MONS_NO_MONSTER)
4878 {
4879 item.props.erase(ORC_CORPSE_KEY);
4880 }
4881 #endif
4882 // Fixup artefact props to handle reloading items when the new version
4883 // of Crawl has more artefact props.
4884 if (is_artefact(item))
4885 artefact_fixup_props(item);
4886
4887 #if TAG_MAJOR_VERSION == 34
4888 // Remove artefact autoinscriptions from the saved inscription.
4889 if ((th.getMinorVersion() < TAG_MINOR_AUTOINSCRIPTIONS
4890 || th.getMinorVersion() == TAG_MINOR_0_11) && is_artefact(item))
4891 {
4892 string art_ins = artefact_inscription(item);
4893 if (!art_ins.empty())
4894 {
4895 item.inscription = replace_all(item.inscription, art_ins + ",", "");
4896 item.inscription = replace_all(item.inscription, art_ins, "");
4897
4898 // Avoid q - the ring "Foo" {+Fly rF+, +Lev rF+}
4899 art_ins = replace_all(art_ins, "+Fly", "+Lev");
4900 item.inscription = replace_all(item.inscription, art_ins + ",", "");
4901 item.inscription = replace_all(item.inscription, art_ins, "");
4902
4903 trim_string(item.inscription);
4904 }
4905 }
4906
4907 // Upgrade item knowledge to cope with the fix for #1083
4908 if (item.base_type == OBJ_JEWELLERY)
4909 {
4910 if (item.flags & ISFLAG_KNOW_PROPERTIES)
4911 item.flags |= ISFLAG_KNOW_TYPE;
4912 }
4913
4914 if (item.base_type == OBJ_POTIONS)
4915 {
4916 switch (item.sub_type)
4917 {
4918 case POT_GAIN_STRENGTH:
4919 case POT_GAIN_DEXTERITY:
4920 case POT_GAIN_INTELLIGENCE:
4921 case POT_POISON:
4922 case POT_SLOWING:
4923 case POT_PORRIDGE:
4924 case POT_DECAY:
4925 case POT_WATER:
4926 case POT_RESTORE_ABILITIES:
4927 case POT_STRONG_POISON:
4928 case POT_BLOOD:
4929 case POT_BLOOD_COAGULATED:
4930 item.sub_type = POT_DEGENERATION;
4931 break;
4932 case POT_CURE_MUTATION:
4933 case POT_BENEFICIAL_MUTATION:
4934 item.sub_type = POT_MUTATION;
4935 break;
4936 case POT_DUMMY_AGILITY:
4937 item.sub_type = POT_ATTRACTION;
4938 break;
4939 default:
4940 break;
4941 }
4942
4943 // Check on save load that the above switch has
4944 // converted all removed potion types.
4945 switch (item.sub_type)
4946 {
4947 default:
4948 break;
4949 CASE_REMOVED_POTIONS(item.sub_type)
4950 }
4951 }
4952
4953 if (item.is_type(OBJ_STAVES, STAFF_CHANNELING))
4954 item.sub_type = STAFF_ENERGY;
4955
4956 if (th.getMinorVersion() < TAG_MINOR_GOD_GIFT)
4957 {
4958 _trim_god_gift_inscrip(item);
4959 if (is_stackable_item(item))
4960 origin_reset(item);
4961 }
4962
4963 if (th.getMinorVersion() < TAG_MINOR_NO_SPLINT
4964 && item.base_type == OBJ_ARMOUR && item.sub_type > ARM_CHAIN_MAIL)
4965 {
4966 --item.sub_type;
4967 }
4968
4969 if (th.getMinorVersion() < TAG_MINOR_BOX_OF_BEASTS_CHARGES
4970 && item.is_type(OBJ_MISCELLANY, MISC_BOX_OF_BEASTS))
4971 {
4972 // Give charges to box of beasts. If the player used it
4973 // already then, well, they got some freebies.
4974 item.plus = random_range(5, 15, 2);
4975 }
4976
4977 if (item.is_type(OBJ_MISCELLANY, MISC_BUGGY_EBONY_CASKET))
4978 {
4979 item.sub_type = MISC_BOX_OF_BEASTS;
4980 item.plus = 1;
4981 }
4982
4983 // was spiked flail
4984 if (item.is_type(OBJ_WEAPONS, WPN_SPIKED_FLAIL)
4985 && th.getMinorVersion() <= TAG_MINOR_FORGOTTEN_MAP)
4986 {
4987 item.sub_type = WPN_FLAIL;
4988 }
4989
4990 if (item.base_type == OBJ_WEAPONS
4991 && (item.brand == SPWPN_RETURNING
4992 || item.brand == SPWPN_REACHING
4993 || item.brand == SPWPN_ORC_SLAYING
4994 || item.brand == SPWPN_DRAGON_SLAYING
4995 || item.brand == SPWPN_EVASION))
4996 {
4997 item.brand = SPWPN_NORMAL;
4998 }
4999
5000 // Not putting these in a minor tag since it's possible for an old
5001 // random monster spawn list to place flame/frost weapons.
5002 if (item.base_type == OBJ_WEAPONS && get_weapon_brand(item) == SPWPN_FROST)
5003 {
5004 if (is_artefact(item))
5005 artefact_set_property(item, ARTP_BRAND, SPWPN_FREEZING);
5006 else
5007 item.brand = SPWPN_FREEZING;
5008 }
5009 if (item.base_type == OBJ_WEAPONS && get_weapon_brand(item) == SPWPN_FLAME)
5010 {
5011 if (is_artefact(item))
5012 artefact_set_property(item, ARTP_BRAND, SPWPN_FLAMING);
5013 else
5014 item.brand = SPWPN_FLAMING;
5015 }
5016
5017 // Rescale old MR (range 35-99) to new discrete steps (40/80/120)
5018 // Negative MR was only supposed to exist for Folly, but paranoia.
5019 if (th.getMinorVersion() < TAG_MINOR_MR_ITEM_RESCALE
5020 && is_artefact(item)
5021 && item.base_type != OBJ_BOOKS
5022 && artefact_property(item, ARTP_WILLPOWER))
5023 {
5024 int prop_mr = artefact_property(item, ARTP_WILLPOWER);
5025 if (prop_mr > 99)
5026 artefact_set_property(item, ARTP_WILLPOWER, 3);
5027 else if (prop_mr > 79)
5028 artefact_set_property(item, ARTP_WILLPOWER, 2);
5029 else if (prop_mr < -40)
5030 artefact_set_property(item, ARTP_WILLPOWER, -2);
5031 else if (prop_mr < 0)
5032 artefact_set_property(item, ARTP_WILLPOWER, -1);
5033 else
5034 artefact_set_property(item, ARTP_WILLPOWER, 1);
5035 }
5036
5037 // Rescale stealth (range 10..79 and -10..-98) to discrete steps (+-50/100)
5038 if (th.getMinorVersion() < TAG_MINOR_STEALTH_RESCALE
5039 && is_artefact(item)
5040 && item.base_type != OBJ_BOOKS)
5041 {
5042 if (artefact_property(item, ARTP_STEALTH))
5043 {
5044 int prop_st = artefact_property(item, ARTP_STEALTH);
5045 if (prop_st > 60)
5046 artefact_set_property(item, ARTP_STEALTH, 2);
5047 else if (prop_st < -70)
5048 artefact_set_property(item, ARTP_STEALTH, -2);
5049 else if (prop_st < 0)
5050 artefact_set_property(item, ARTP_STEALTH, -1);
5051 else
5052 artefact_set_property(item, ARTP_STEALTH, 1);
5053 }
5054
5055 // Remove fast metabolism property
5056 if (artefact_property(item, ARTP_METABOLISM))
5057 {
5058 artefact_set_property(item, ARTP_METABOLISM, 0);
5059 artefact_set_property(item, ARTP_STEALTH, -1);
5060 }
5061
5062 // Make sure no weird fake-rap combinations are produced by the upgrade
5063 // from rings of sustenance with {Stlth} to stealth
5064 if (item.base_type == OBJ_JEWELLERY && item.sub_type == RING_STEALTH)
5065 artefact_set_property(item, ARTP_STEALTH, 0);
5066 }
5067
5068 if (th.getMinorVersion() < TAG_MINOR_NO_POT_FOOD)
5069 {
5070 // Replace War Chants with Battle to avoid empty-book errors.
5071
5072 // Moved under TAG_MINOR_NO_POT_FOOD because it was formerly
5073 // not restricted to a particular range of minor tags.
5074 if (item.is_type(OBJ_BOOKS, BOOK_WAR_CHANTS))
5075 item.sub_type = BOOK_BATTLE;
5076
5077 if (item.base_type == OBJ_FOOD && (item.sub_type == FOOD_UNUSED
5078 || item.sub_type == FOOD_AMBROSIA))
5079 {
5080 item.sub_type = FOOD_ROYAL_JELLY; // will be fixed up later
5081 }
5082 }
5083
5084 if (th.getMinorVersion() < TAG_MINOR_FOOD_PURGE)
5085 {
5086 if (item.base_type == OBJ_FOOD)
5087 {
5088 if (item.sub_type == FOOD_SAUSAGE)
5089 item.sub_type = FOOD_BEEF_JERKY;
5090 if (item.sub_type == FOOD_CHEESE)
5091 item.sub_type = FOOD_PIZZA;
5092 if (item.sub_type == FOOD_PEAR
5093 || item.sub_type == FOOD_APPLE
5094 || item.sub_type == FOOD_CHOKO
5095 || item.sub_type == FOOD_APRICOT
5096 || item.sub_type == FOOD_ORANGE
5097 || item.sub_type == FOOD_BANANA
5098 || item.sub_type == FOOD_STRAWBERRY
5099 || item.sub_type == FOOD_RAMBUTAN
5100 || item.sub_type == FOOD_GRAPE
5101 || item.sub_type == FOOD_SULTANA
5102 || item.sub_type == FOOD_LYCHEE
5103 || item.sub_type == FOOD_LEMON)
5104 {
5105 item.sub_type = FOOD_FRUIT; // will be fixed up later
5106 }
5107 }
5108 }
5109 if (th.getMinorVersion() < TAG_MINOR_FOOD_PURGE_RELOADED)
5110 {
5111 if (item.base_type == OBJ_FOOD)
5112 {
5113 if (item.sub_type == FOOD_BEEF_JERKY
5114 || item.sub_type == FOOD_PIZZA)
5115 {
5116 item.sub_type = FOOD_ROYAL_JELLY; // will be fixed up later
5117 }
5118 }
5119 }
5120
5121 // Combine old rings of slaying (Acc/Dam) to new (Dam).
5122 // Also handle the changes to the respective ARTP_.
5123 if (th.getMinorVersion() < TAG_MINOR_SLAYRING_PLUSES)
5124 {
5125 int acc, dam, slay = 0;
5126
5127 if (item.props.exists(ARTEFACT_PROPS_KEY))
5128 {
5129 acc = artefact_property(item, ARTP_ACCURACY);
5130 dam = artefact_property(item, ARTP_SLAYING);
5131 slay = dam < 0 ? dam : max(acc, dam);
5132
5133 artefact_set_property(item, ARTP_SLAYING, slay);
5134 }
5135
5136 if (item.is_type(OBJ_JEWELLERY, RING_SLAYING))
5137 {
5138 acc = item.plus;
5139 dam = item.plus2;
5140 slay = dam < 0 ? dam : max(acc, dam);
5141
5142 item.plus = slay;
5143 item.plus2 = 0; // probably harmless but might as well
5144 }
5145 }
5146
5147 if (th.getMinorVersion() < TAG_MINOR_MERGE_EW)
5148 {
5149 // Combine EW1/EW2/EW3 scrolls into single enchant weapon scroll.
5150 if (item.base_type == OBJ_SCROLLS
5151 && (item.sub_type == SCR_ENCHANT_WEAPON_II
5152 || item.sub_type == SCR_ENCHANT_WEAPON_III))
5153 {
5154 item.sub_type = SCR_ENCHANT_WEAPON;
5155 }
5156 }
5157
5158 if (th.getMinorVersion() < TAG_MINOR_WEAPON_PLUSES)
5159 {
5160 int acc, dam, slay = 0;
5161
5162 if (item.base_type == OBJ_WEAPONS)
5163 {
5164 acc = item.plus;
5165 dam = item.plus2;
5166 slay = dam < 0 ? dam : max(acc,dam);
5167
5168 item.plus = slay;
5169 item.plus2 = 0; // probably harmless but might as well
5170 }
5171 }
5172
5173 if (th.getMinorVersion() < TAG_MINOR_CUT_CUTLASSES)
5174 {
5175 if (item.is_type(OBJ_WEAPONS, WPN_CUTLASS))
5176 item.sub_type = WPN_RAPIER;
5177 }
5178
5179 if (th.getMinorVersion() < TAG_MINOR_INIT_RND)
5180 {
5181 // 0 is now reserved to indicate that rnd is uninitialized
5182 if (item.rnd == 0)
5183 item.rnd = 1 + random2(255);
5184 }
5185
5186 if (th.getMinorVersion() < TAG_MINOR_RING_PLUSSES)
5187 if (item.base_type == OBJ_JEWELLERY && item.plus > 6)
5188 item.plus = 6;
5189
5190 if (th.getMinorVersion() < TAG_MINOR_BLESSED_WPNS
5191 && item.base_type == OBJ_WEAPONS)
5192 {
5193 const int initial_type = item.sub_type;
5194 switch (item.sub_type)
5195 {
5196 case WPN_BLESSED_FALCHION: item.sub_type = WPN_FALCHION; break;
5197 case WPN_BLESSED_LONG_SWORD: item.sub_type = WPN_LONG_SWORD; break;
5198 case WPN_BLESSED_SCIMITAR: item.sub_type = WPN_SCIMITAR; break;
5199 case WPN_BLESSED_DOUBLE_SWORD: item.sub_type = WPN_DOUBLE_SWORD; break;
5200 case WPN_BLESSED_GREAT_SWORD: item.sub_type = WPN_GREAT_SWORD; break;
5201 case WPN_BLESSED_TRIPLE_SWORD: item.sub_type = WPN_TRIPLE_SWORD; break;
5202 default: break;
5203 }
5204 if (initial_type != item.sub_type)
5205 set_item_ego_type(item, OBJ_WEAPONS, SPWPN_HOLY_WRATH);
5206 }
5207
5208 if (th.getMinorVersion() < TAG_MINOR_CONSUM_APPEARANCE)
5209 {
5210 if (item.base_type == OBJ_POTIONS)
5211 item.subtype_rnd = item.plus; // was consum_desc
5212 else if (item.base_type == OBJ_SCROLLS)
5213 {
5214 // faithfully preserve weirdness
5215 item.subtype_rnd = item.subtype_rnd
5216 | (item.plus << 8) // was consum_desc
5217 | (OBJ_SCROLLS << 16);
5218 }
5219 }
5220
5221 if (th.getMinorVersion() < TAG_MINOR_MANGLE_CORPSES)
5222 if (item.props.exists("never_hide"))
5223 item.props.erase("never_hide");
5224
5225 if (th.getMinorVersion() < TAG_MINOR_ISFLAG_HANDLED
5226 && item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN))
5227 {
5228 // Items we've dropped or thrown have been handled already.
5229 item.flags |= ISFLAG_HANDLED;
5230 }
5231
5232 if (th.getMinorVersion() < TAG_MINOR_UNSTACKABLE_EVOKERS
5233 && is_xp_evoker(item))
5234 {
5235 item.quantity = 1;
5236 }
5237
5238 if (th.getMinorVersion() < TAG_MINOR_UNSTACK_TREMORSTONES
5239 && item.base_type == OBJ_MISCELLANY
5240 && item.sub_type == MISC_TIN_OF_TREMORSTONES)
5241 {
5242 item.quantity = 1;
5243 }
5244
5245 if (th.getMinorVersion() < TAG_MINOR_REALLY_UNSTACK_EVOKERS
5246 && item.base_type == OBJ_MISCELLANY
5247 && (item.sub_type == MISC_PHANTOM_MIRROR
5248 || item.sub_type == MISC_BOX_OF_BEASTS) )
5249 {
5250 item.quantity = 1;
5251 }
5252
5253 if (th.getMinorVersion() < TAG_MINOR_NO_NEGATIVE_VULN
5254 && is_artefact(item)
5255 && item.base_type != OBJ_BOOKS
5256 && artefact_property(item, ARTP_NEGATIVE_ENERGY))
5257 {
5258 if (artefact_property(item, ARTP_NEGATIVE_ENERGY) < 0)
5259 artefact_set_property(item, ARTP_NEGATIVE_ENERGY, 0);
5260 }
5261
5262 if (th.getMinorVersion() < TAG_MINOR_NO_RPOIS_MINUS
5263 && is_artefact(item)
5264 && item.base_type != OBJ_BOOKS
5265 && artefact_property(item, ARTP_POISON))
5266 {
5267 if (artefact_property(item, ARTP_POISON) < 0)
5268 artefact_set_property(item, ARTP_POISON, 0);
5269 }
5270
5271 if (th.getMinorVersion() < TAG_MINOR_TELEPORTITIS
5272 && is_artefact(item)
5273 && item.base_type != OBJ_BOOKS
5274 && artefact_property(item, ARTP_CAUSE_TELEPORTATION) > 1)
5275 {
5276 artefact_set_property(item, ARTP_CAUSE_TELEPORTATION, 1);
5277 }
5278
5279 if (th.getMinorVersion() < TAG_MINOR_NO_TWISTER
5280 && is_artefact(item)
5281 && item.base_type != OBJ_BOOKS
5282 && artefact_property(item, ARTP_TWISTER))
5283 {
5284 artefact_set_property(item, ARTP_TWISTER, 0);
5285 }
5286
5287 // Monsters could zap wands below zero from
5288 // 0.17-a0-739-g965e8eb to 0.17-a0-912-g3e33c8f.
5289 if (item.base_type == OBJ_WANDS && item.charges < 0)
5290 item.charges = 0;
5291
5292 // Prevent weird states for saves between UNCURSE and NEW_ASHENZARI
5293 if (th.getMinorVersion() < TAG_MINOR_NEW_ASHENZARI && item.cursed())
5294 item.flags &= (~ISFLAG_CURSED);
5295
5296 // turn old hides into the corresponding armour
5297 static const map<int, armour_type> hide_to_armour = {
5298 { ARM_TROLL_HIDE, ARM_TROLL_LEATHER_ARMOUR },
5299 { ARM_FIRE_DRAGON_HIDE, ARM_FIRE_DRAGON_ARMOUR },
5300 { ARM_ICE_DRAGON_HIDE, ARM_ICE_DRAGON_ARMOUR },
5301 { ARM_STEAM_DRAGON_HIDE, ARM_STEAM_DRAGON_ARMOUR },
5302 { ARM_STORM_DRAGON_HIDE, ARM_STORM_DRAGON_ARMOUR },
5303 { ARM_GOLD_DRAGON_HIDE, ARM_GOLD_DRAGON_ARMOUR },
5304 { ARM_SWAMP_DRAGON_HIDE, ARM_SWAMP_DRAGON_ARMOUR },
5305 { ARM_PEARL_DRAGON_HIDE, ARM_PEARL_DRAGON_ARMOUR },
5306 { ARM_SHADOW_DRAGON_HIDE, ARM_SHADOW_DRAGON_ARMOUR },
5307 { ARM_QUICKSILVER_DRAGON_HIDE, ARM_QUICKSILVER_DRAGON_ARMOUR },
5308 };
5309 // ASSUMPTION: there was no such thing as an artefact hide
5310 if (item.base_type == OBJ_ARMOUR && hide_to_armour.count(item.sub_type))
5311 {
5312 auto subtype_ptr = map_find(hide_to_armour, item.sub_type);
5313 ASSERT(subtype_ptr);
5314 item.sub_type = *subtype_ptr;
5315 }
5316
5317 if (th.getMinorVersion() < TAG_MINOR_HIDE_TO_SCALE && armour_is_hide(item))
5318 {
5319 _fixup_dragon_artefact_name(item, ARTEFACT_NAME_KEY);
5320 _fixup_dragon_artefact_name(item, ARTEFACT_APPEAR_KEY);
5321 }
5322
5323 if (item.is_type(OBJ_FOOD, FOOD_BREAD_RATION))
5324 item.sub_type = FOOD_RATION;
5325 else if (item.is_type(OBJ_FOOD, FOOD_ROYAL_JELLY))
5326 {
5327 item.sub_type = FOOD_RATION;
5328 item.quantity = max(1, div_rand_round(item.quantity, 3));
5329 }
5330 else if (item.is_type(OBJ_FOOD, FOOD_FRUIT))
5331 {
5332 item.sub_type = FOOD_RATION;
5333 item.quantity = max(1, div_rand_round(item.quantity, 5));
5334 }
5335 if (item.is_type(OBJ_FOOD, FOOD_RATION) && item.pos == ITEM_IN_INVENTORY)
5336 {
5337 item.props["item_tile_name"] = "food_ration_inventory";
5338 bind_item_tile(item);
5339 }
5340
5341 if (th.getMinorVersion() < TAG_MINOR_THROW_CONSOLIDATION
5342 && item.base_type == OBJ_MISSILES)
5343 {
5344 if (item.sub_type == MI_NEEDLE)
5345 {
5346 item.sub_type = MI_DART;
5347
5348 switch (item.brand)
5349 {
5350 case SPMSL_PARALYSIS:
5351 case SPMSL_SLOW:
5352 case SPMSL_SLEEP:
5353 case SPMSL_CONFUSION:
5354 case SPMSL_SICKNESS:
5355 item.brand = SPMSL_BLINDING;
5356 break;
5357 default: break;
5358 }
5359 }
5360 else if (item.sub_type == MI_BOOMERANG || item.sub_type == MI_JAVELIN)
5361 {
5362 switch (item.brand)
5363 {
5364 case SPMSL_RETURNING:
5365 case SPMSL_EXPLODING:
5366 case SPMSL_POISONED:
5367 case SPMSL_PENETRATION:
5368 item.brand = SPMSL_NORMAL;
5369 break;
5370 case SPMSL_STEEL:
5371 item.brand = SPMSL_SILVER;
5372 break;
5373 }
5374 }
5375 }
5376
5377 if (th.getMinorVersion() < TAG_MINOR_BARDING_MERGE)
5378 {
5379 if (item.is_type(OBJ_ARMOUR, ARM_CENTAUR_BARDING))
5380 item.sub_type = ARM_BARDING;
5381 }
5382
5383 #endif
5384
5385 if (is_unrandom_artefact(item))
5386 setup_unrandart(item, false);
5387
5388 bind_item_tile(item);
5389 }
5390
5391 #define MAP_SERIALIZE_FLAGS_MASK 3
5392 #define MAP_SERIALIZE_FLAGS_8 1
5393 #define MAP_SERIALIZE_FLAGS_16 2
5394 #define MAP_SERIALIZE_FLAGS_32 3
5395
5396 #define MAP_SERIALIZE_FEATURE 4
5397 #define MAP_SERIALIZE_FEATURE_COLOUR 8
5398 #define MAP_SERIALIZE_ITEM 0x10
5399 #define MAP_SERIALIZE_CLOUD 0x20
5400 #define MAP_SERIALIZE_MONSTER 0x40
5401
marshallMapCell(writer & th,const map_cell & cell)5402 void marshallMapCell(writer &th, const map_cell &cell)
5403 {
5404 unsigned flags = 0;
5405
5406 if (cell.flags > 0xffff)
5407 flags |= MAP_SERIALIZE_FLAGS_32;
5408 else if (cell.flags > 0xff)
5409 flags |= MAP_SERIALIZE_FLAGS_16;
5410 else if (cell.flags)
5411 flags |= MAP_SERIALIZE_FLAGS_8;
5412
5413 if (cell.feat() != DNGN_UNSEEN)
5414 flags |= MAP_SERIALIZE_FEATURE;
5415
5416 if (cell.feat_colour())
5417 flags |= MAP_SERIALIZE_FEATURE_COLOUR;
5418
5419 if (cell.cloud() != CLOUD_NONE)
5420 flags |= MAP_SERIALIZE_CLOUD;
5421
5422 if (cell.item())
5423 flags |= MAP_SERIALIZE_ITEM;
5424
5425 if (cell.monster() != MONS_NO_MONSTER)
5426 flags |= MAP_SERIALIZE_MONSTER;
5427
5428 marshallUnsigned(th, flags);
5429
5430 switch (flags & MAP_SERIALIZE_FLAGS_MASK)
5431 {
5432 case MAP_SERIALIZE_FLAGS_8:
5433 marshallByte(th, static_cast<int8_t>(cell.flags));
5434 break;
5435 case MAP_SERIALIZE_FLAGS_16:
5436 marshallShort(th, static_cast<int16_t>(cell.flags));
5437 break;
5438 case MAP_SERIALIZE_FLAGS_32:
5439 marshallInt(th, static_cast<int32_t>(cell.flags));
5440 break;
5441 }
5442
5443 if (flags & MAP_SERIALIZE_FEATURE)
5444 #if TAG_MAJOR_VERSION == 34
5445 marshallUnsigned(th, cell.feat());
5446 #else
5447 marshallUByte(th, cell.feat());
5448 #endif
5449
5450 if (flags & MAP_SERIALIZE_FEATURE_COLOUR)
5451 marshallUnsigned(th, cell.feat_colour());
5452
5453 if (feat_is_trap(cell.feat()))
5454 marshallByte(th, cell.trap());
5455
5456 if (flags & MAP_SERIALIZE_CLOUD)
5457 {
5458 cloud_info* ci = cell.cloudinfo();
5459 marshallUnsigned(th, ci->type);
5460 marshallUnsigned(th, ci->colour);
5461 marshallUnsigned(th, ci->duration);
5462 marshallShort(th, ci->tile);
5463 marshallUByte(th, ci->killer);
5464 }
5465
5466 if (flags & MAP_SERIALIZE_ITEM)
5467 marshallItem(th, *cell.item(), true);
5468
5469 if (flags & MAP_SERIALIZE_MONSTER)
5470 _marshallMonsterInfo(th, *cell.monsterinfo());
5471 }
5472
unmarshallMapCell(reader & th,map_cell & cell)5473 void unmarshallMapCell(reader &th, map_cell& cell)
5474 {
5475 unsigned flags = unmarshallUnsigned(th);
5476 unsigned cell_flags = 0;
5477 trap_type trap = TRAP_UNASSIGNED;
5478
5479 cell.clear();
5480
5481 switch (flags & MAP_SERIALIZE_FLAGS_MASK)
5482 {
5483 case MAP_SERIALIZE_FLAGS_8:
5484 cell_flags = static_cast<uint8_t>(unmarshallByte(th));
5485 break;
5486 case MAP_SERIALIZE_FLAGS_16:
5487 cell_flags = static_cast<uint16_t>(unmarshallShort(th));
5488 break;
5489 case MAP_SERIALIZE_FLAGS_32:
5490 cell_flags = static_cast<uint32_t>(unmarshallInt(th));
5491 break;
5492 }
5493
5494 dungeon_feature_type feature = DNGN_UNSEEN;
5495 unsigned feat_colour = 0;
5496
5497 if (flags & MAP_SERIALIZE_FEATURE)
5498 #if TAG_MAJOR_VERSION == 34
5499 feature = unmarshallFeatureType_Info(th);
5500 #else
5501 feature = unmarshallFeatureType(th);
5502 #endif
5503
5504 if (flags & MAP_SERIALIZE_FEATURE_COLOUR)
5505 feat_colour = unmarshallUnsigned(th);
5506
5507 if (feat_is_trap(feature))
5508 {
5509 trap = (trap_type)unmarshallByte(th);
5510 #if TAG_MAJOR_VERSION == 34
5511 if (th.getMinorVersion() == TAG_MINOR_0_11 && trap >= TRAP_TELEPORT)
5512 trap = (trap_type)(trap - 1);
5513 if (trap == TRAP_ALARM)
5514 feature = DNGN_TRAP_ALARM;
5515 else if (trap == TRAP_ZOT)
5516 feature = DNGN_TRAP_ZOT;
5517 else if (trap == TRAP_GOLUBRIA)
5518 feature = DNGN_PASSAGE_OF_GOLUBRIA;
5519 #endif
5520 }
5521
5522 cell.set_feature(feature, feat_colour, trap);
5523
5524 if (flags & MAP_SERIALIZE_CLOUD)
5525 {
5526 cloud_info ci;
5527 ci.type = (cloud_type)unmarshallUnsigned(th);
5528 unmarshallUnsigned(th, ci.colour);
5529 unmarshallUnsigned(th, ci.duration);
5530 ci.tile = unmarshallShort(th);
5531 #if TAG_MAJOR_VERSION == 34
5532 if (th.getMinorVersion() >= TAG_MINOR_CLOUD_OWNER)
5533 #endif
5534 ci.killer = static_cast<killer_type>(unmarshallUByte(th));
5535 cell.set_cloud(ci);
5536 }
5537
5538 if (flags & MAP_SERIALIZE_ITEM)
5539 {
5540 item_def item;
5541 unmarshallItem(th, item);
5542 cell.set_item(item, false);
5543 }
5544
5545 if (flags & MAP_SERIALIZE_MONSTER)
5546 {
5547 monster_info mi;
5548 _unmarshallMonsterInfo(th, mi);
5549 cell.set_monster(mi);
5550 }
5551
5552 // set this last so the other sets don't override this
5553 cell.flags = cell_flags;
5554 }
5555
_tag_construct_level_items(writer & th)5556 static void _tag_construct_level_items(writer &th)
5557 {
5558 // how many traps?
5559 marshallShort(th, env.trap.size());
5560 for (const auto& entry : env.trap)
5561 {
5562 const trap_def& trap = entry.second;
5563 marshallByte(th, trap.type);
5564 marshallCoord(th, trap.pos);
5565 marshallShort(th, trap.ammo_qty);
5566 }
5567
5568 // how many items?
5569 const int ni = _last_used_index(env.item, MAX_ITEMS);
5570 marshallShort(th, ni);
5571 for (int i = 0; i < ni; ++i)
5572 marshallItem(th, env.item[i]);
5573 }
5574
marshall_mon_enchant(writer & th,const mon_enchant & me)5575 static void marshall_mon_enchant(writer &th, const mon_enchant &me)
5576 {
5577 marshallShort(th, me.ench);
5578 marshallShort(th, me.degree);
5579 marshallShort(th, me.who);
5580 marshallInt(th, me.source);
5581 marshallShort(th, min(me.duration, INFINITE_DURATION));
5582 marshallShort(th, min(me.maxduration, INFINITE_DURATION));
5583 }
5584
unmarshall_mon_enchant(reader & th)5585 static mon_enchant unmarshall_mon_enchant(reader &th)
5586 {
5587 mon_enchant me;
5588 me.ench = static_cast<enchant_type>(unmarshallShort(th));
5589 me.degree = unmarshallShort(th);
5590 me.who = static_cast<kill_category>(unmarshallShort(th));
5591 me.source = unmarshallInt(th);
5592 me.duration = unmarshallShort(th);
5593 me.maxduration = unmarshallShort(th);
5594 return me;
5595 }
5596
5597 enum mon_part_t
5598 {
5599 MP_GHOST_DEMON = BIT(0),
5600 MP_CONSTRICTION = BIT(1),
5601 MP_ITEMS = BIT(2),
5602 MP_SPELLS = BIT(3),
5603 };
5604
marshallMonster(writer & th,const monster & m)5605 void marshallMonster(writer &th, const monster& m)
5606 {
5607 if (!m.alive())
5608 {
5609 marshallMonType(th, MONS_NO_MONSTER);
5610 return;
5611 }
5612
5613 uint32_t parts = 0;
5614 if (mons_is_ghost_demon(m.type))
5615 parts |= MP_GHOST_DEMON;
5616 if (m.is_constricted() || m.is_constricting())
5617 parts |= MP_CONSTRICTION;
5618 for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
5619 if (m.inv[i] != NON_ITEM)
5620 parts |= MP_ITEMS;
5621 if (m.spells.size() > 0)
5622 parts |= MP_SPELLS;
5623
5624 marshallMonType(th, m.type);
5625 marshallUnsigned(th, parts);
5626 ASSERT(m.mid > 0);
5627 marshallInt(th, m.mid);
5628 marshallString(th, m.mname);
5629 marshallByte(th, m.xp_tracking);
5630 marshallByte(th, m.get_experience_level());
5631 marshallByte(th, m.speed);
5632 marshallByte(th, m.speed_increment);
5633 marshallByte(th, m.behaviour);
5634 marshallByte(th, m.pos().x);
5635 marshallByte(th, m.pos().y);
5636 marshallByte(th, m.target.x);
5637 marshallByte(th, m.target.y);
5638 marshallCoord(th, m.firing_pos);
5639 marshallCoord(th, m.patrol_point);
5640 int help = m.travel_target;
5641 marshallByte(th, help);
5642
5643 marshallShort(th, m.travel_path.size());
5644 for (coord_def pos : m.travel_path)
5645 marshallCoord(th, pos);
5646
5647 marshallUnsigned(th, m.flags.flags);
5648 marshallInt(th, m.experience);
5649
5650 marshallShort(th, m.enchantments.size());
5651 for (const auto &entry : m.enchantments)
5652 marshall_mon_enchant(th, entry.second);
5653 marshallByte(th, m.ench_countdown);
5654
5655 marshallShort(th, min(m.hit_points, MAX_MONSTER_HP));
5656 marshallShort(th, min(m.max_hit_points, MAX_MONSTER_HP));
5657 marshallInt(th, m.number);
5658 marshallMonType(th, m.base_monster);
5659 marshallShort(th, m.colour);
5660 marshallInt(th, m.summoner);
5661
5662 if (parts & MP_ITEMS)
5663 for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
5664 marshallShort(th, m.inv[j]);
5665 if (parts & MP_SPELLS)
5666 _marshallSpells(th, m.spells);
5667 marshallByte(th, m.god);
5668 marshallByte(th, m.attitude);
5669 marshallShort(th, m.foe);
5670 marshallInt(th, m.foe_memory);
5671 marshallShort(th, m.damage_friendly);
5672 marshallShort(th, m.damage_total);
5673 marshallByte(th, m.went_unseen_this_turn);
5674 marshallCoord(th, m.unseen_pos);
5675
5676 if (parts & MP_GHOST_DEMON)
5677 {
5678 // *Must* have ghost field set.
5679 ASSERT(m.ghost);
5680 _marshallGhost(th, *m.ghost);
5681 }
5682
5683 if (parts & MP_CONSTRICTION)
5684 _marshall_constriction(th, &m);
5685
5686 m.props.write(th);
5687 }
5688
_marshall_mi_attack(writer & th,const mon_attack_def & attk)5689 static void _marshall_mi_attack(writer &th, const mon_attack_def &attk)
5690 {
5691 marshallInt(th, attk.type);
5692 marshallInt(th, attk.flavour);
5693 marshallInt(th, attk.damage);
5694 }
5695
_unmarshall_mi_attack(reader & th)5696 static mon_attack_def _unmarshall_mi_attack(reader &th)
5697 {
5698 mon_attack_def attk;
5699 attk.type = static_cast<attack_type>(unmarshallInt(th));
5700 attk.flavour = static_cast<attack_flavour>(unmarshallInt(th));
5701 attk.damage = unmarshallInt(th);
5702
5703 return attk;
5704 }
5705
_marshallMonsterInfo(writer & th,const monster_info & mi)5706 void _marshallMonsterInfo(writer &th, const monster_info& mi)
5707 {
5708 _marshallFixedBitVector<NUM_MB_FLAGS>(th, mi.mb);
5709 marshallString(th, mi.mname);
5710 marshallUnsigned(th, mi.type);
5711 marshallUnsigned(th, mi.base_type);
5712 marshallUnsigned(th, mi.number);
5713 marshallInt(th, mi._colour);
5714 marshallUnsigned(th, mi.attitude);
5715 marshallUnsigned(th, mi.threat);
5716 marshallUnsigned(th, mi.dam);
5717 marshallUnsigned(th, mi.fire_blocker);
5718 marshallString(th, mi.description);
5719 marshallString(th, mi.quote);
5720 marshallUnsigned(th, mi.holi.flags);
5721 marshallUnsigned(th, mi.mintel);
5722 marshallUnsigned(th, mi.hd);
5723 marshallUnsigned(th, mi.ac);
5724 marshallUnsigned(th, mi.ev);
5725 marshallUnsigned(th, mi.base_ev);
5726 marshallInt(th, mi.mresists);
5727 marshallUnsigned(th, mi.mitemuse);
5728 marshallByte(th, mi.mbase_speed);
5729 marshallByte(th, mi.menergy.move);
5730 marshallByte(th, mi.menergy.swim);
5731 marshallByte(th, mi.menergy.attack);
5732 marshallByte(th, mi.menergy.missile);
5733 marshallByte(th, mi.menergy.spell);
5734 marshallByte(th, mi.menergy.special);
5735 marshallByte(th, mi.menergy.item);
5736 marshallByte(th, mi.menergy.pickup_percent);
5737 for (int i = 0; i < MAX_NUM_ATTACKS; ++i)
5738 _marshall_mi_attack(th, mi.attack[i]);
5739 for (unsigned int i = 0; i <= MSLOT_LAST_VISIBLE_SLOT; ++i)
5740 {
5741 if (mi.inv[i])
5742 {
5743 marshallBoolean(th, true);
5744 marshallItem(th, *mi.inv[i], true);
5745 }
5746 else
5747 marshallBoolean(th, false);
5748 }
5749 if (mons_is_pghost(mi.type))
5750 {
5751 marshallUnsigned(th, mi.i_ghost.species);
5752 marshallUnsigned(th, mi.i_ghost.job);
5753 marshallUnsigned(th, mi.i_ghost.religion);
5754 marshallUnsigned(th, mi.i_ghost.best_skill);
5755 marshallShort(th, mi.i_ghost.best_skill_rank);
5756 marshallShort(th, mi.i_ghost.xl_rank);
5757 marshallShort(th, mi.i_ghost.damage);
5758 marshallShort(th, mi.i_ghost.ac);
5759 }
5760
5761 mi.props.write(th);
5762 }
5763
_unmarshallMonsterInfo(reader & th,monster_info & mi)5764 void _unmarshallMonsterInfo(reader &th, monster_info& mi)
5765 {
5766 _unmarshallFixedBitVector<NUM_MB_FLAGS>(th, mi.mb);
5767 mi.mname = unmarshallString(th);
5768
5769 mi.type = unmarshallMonType_Info(th);
5770 ASSERT(!invalid_monster_type(mi.type));
5771 mi.base_type = unmarshallMonType_Info(th);
5772
5773 #if TAG_MAJOR_VERSION == 34
5774 if ((mons_genus(mi.type) == MONS_DRACONIAN
5775 || (mons_genus(mi.type) == MONS_DEMONSPAWN
5776 && th.getMinorVersion() >= TAG_MINOR_DEMONSPAWN))
5777 && th.getMinorVersion() < TAG_MINOR_NO_DRACO_TYPE)
5778 {
5779 unmarshallMonType_Info(th); // was draco_type
5780 }
5781 #endif
5782
5783 unmarshallUnsigned(th, mi.number);
5784 #if TAG_MAJOR_VERSION == 34
5785 if (th.getMinorVersion() < TAG_MINOR_MON_COLOUR_LOOKUP)
5786 mi._colour = int(unmarshallUnsigned(th));
5787 else
5788 #endif
5789 mi._colour = unmarshallInt(th);
5790 unmarshallUnsigned(th, mi.attitude);
5791 unmarshallUnsigned(th, mi.threat);
5792 unmarshallUnsigned(th, mi.dam);
5793 unmarshallUnsigned(th, mi.fire_blocker);
5794 mi.description = unmarshallString(th);
5795 mi.quote = unmarshallString(th);
5796
5797 uint64_t holi_flags = unmarshallUnsigned(th);
5798 #if TAG_MAJOR_VERSION == 34
5799 if (th.getMinorVersion() >= TAG_MINOR_MULTI_HOLI)
5800 {
5801 #endif
5802 mi.holi.flags = holi_flags;
5803 #if TAG_MAJOR_VERSION == 34
5804 }
5805 else
5806 mi.holi.flags = 1<<holi_flags;
5807 #endif
5808
5809 #if TAG_MAJOR_VERSION == 34
5810 // XXX: special case MH_UNDEAD becoming MH_UNDEAD | MH_NATURAL
5811 // to save MF_FAKE_UNDEAD. Beware if you add a NATURAL bit
5812 // to an undead monster.
5813 if (mons_class_holiness(mi.type) & ~mi.holi
5814 && !(mi.holi & MH_UNDEAD) && !(mons_class_holiness(mi.type) & MH_NATURAL))
5815 {
5816 mi.holi |= mons_class_holiness(mi.type);
5817 }
5818 #endif
5819
5820 unmarshallUnsigned(th, mi.mintel);
5821
5822 #if TAG_MAJOR_VERSION == 34
5823 if (th.getMinorVersion() >= TAG_MINOR_MON_HD_INFO)
5824 {
5825 #endif
5826 unmarshallUnsigned(th, mi.hd);
5827 #if TAG_MAJOR_VERSION == 34
5828 }
5829 else
5830 mi.hd = mons_class_hit_dice(mi.type);
5831
5832 if (th.getMinorVersion() >= TAG_MINOR_DISPLAY_MON_AC_EV)
5833 {
5834 #endif
5835 unmarshallUnsigned(th, mi.ac);
5836 unmarshallUnsigned(th, mi.ev);
5837 unmarshallUnsigned(th, mi.base_ev);
5838 #if TAG_MAJOR_VERSION == 34
5839 }
5840 else
5841 {
5842 mi.ac = get_mons_class_ac(mi.type);
5843 mi.ev = mi.base_ev = get_mons_class_ev(mi.type);
5844 }
5845 #endif
5846
5847 mi.mr = mons_class_willpower(mi.type, mi.base_type);
5848 mi.can_see_invis = mons_class_sees_invis(mi.type, mi.base_type);
5849
5850 mi.mresists = unmarshallInt(th);
5851 #if TAG_MAJOR_VERSION == 34
5852 if (mi.mresists & MR_OLD_RES_ACID)
5853 set_resist(mi.mresists, MR_RES_ACID, 3);
5854 #endif
5855 unmarshallUnsigned(th, mi.mitemuse);
5856 mi.mbase_speed = unmarshallByte(th);
5857
5858 #if TAG_MAJOR_VERSION == 34
5859 // See comment in unmarshallMonster(): this could be an elemental
5860 // wellspring masquerading as a spectral weapon, or a polymoth masquerading
5861 // as a wellspring.
5862 if (th.getMinorVersion() < TAG_MINOR_CANARIES
5863 && th.getMinorVersion() >= TAG_MINOR_WAR_DOG_REMOVAL
5864 && mi.type >= MONS_SPECTRAL_WEAPON
5865 && mi.type <= MONS_POLYMOTH)
5866 {
5867 switch (mi.base_speed())
5868 {
5869 case 10:
5870 mi.type = MONS_ELEMENTAL_WELLSPRING;
5871 break;
5872 case 12:
5873 mi.type = MONS_POLYMOTH;
5874 break;
5875 case 25:
5876 case 30:
5877 mi.type = MONS_SPECTRAL_WEAPON;
5878 break;
5879 default:
5880 die("Unexpected monster_info with type %d and speed %d",
5881 mi.type, mi.base_speed());
5882 }
5883 }
5884
5885 // As above; this could be one of several monsters.
5886 if (th.getMinorVersion() < TAG_MINOR_DEMONSPAWN
5887 && mi.type >= MONS_MONSTROUS_DEMONSPAWN
5888 && mi.type <= MONS_SALAMANDER_MYSTIC)
5889 {
5890 switch (mi.colour(true))
5891 {
5892 case BROWN: // monstrous demonspawn, naga ritualist
5893 if (mi.spells[0].spell == SPELL_FORCE_LANCE)
5894 mi.type = MONS_NAGA_RITUALIST;
5895 else
5896 mi.type = MONS_MONSTROUS_DEMONSPAWN;
5897 break;
5898 case BLUE: // gelid demonspawn
5899 mi.type = MONS_GELID_DEMONSPAWN;
5900 break;
5901 case RED: // infernal demonspawn
5902 mi.type = MONS_INFERNAL_DEMONSPAWN;
5903 break;
5904 case LIGHTGRAY: // torturous demonspawn, naga sharpshooter
5905 if (mi.spells[0].spell == SPELL_PORTAL_PROJECTILE)
5906 mi.type = MONS_NAGA_SHARPSHOOTER;
5907 else
5908 mi.type = MONS_TORTUROUS_DEMONSPAWN;
5909 break;
5910 case LIGHTBLUE: // blood saint, shock serpent
5911 if (mi.base_type != MONS_NO_MONSTER)
5912 mi.type = MONS_BLOOD_SAINT;
5913 else
5914 mi.type = MONS_SHOCK_SERPENT;
5915 break;
5916 case LIGHTCYAN: // warmonger, drowned soul
5917 if (mi.base_type != MONS_NO_MONSTER)
5918 mi.type = MONS_WARMONGER;
5919 else
5920 mi.type = MONS_DROWNED_SOUL;
5921 break;
5922 case LIGHTGREEN: // corrupter
5923 mi.type = MONS_CORRUPTER;
5924 break;
5925 case LIGHTMAGENTA: // black sun
5926 mi.type = MONS_BLACK_SUN;
5927 break;
5928 case CYAN: // worldbinder
5929 mi.type = MONS_WORLDBINDER;
5930 break;
5931 case MAGENTA: // vine stalker, mana viper, grand avatar
5932 if (mi.base_speed() == 30)
5933 mi.type = MONS_GRAND_AVATAR;
5934 else
5935 mi.type = MONS_MANA_VIPER;
5936 break;
5937 case WHITE: // salamander firebrand
5938 mi.type = MONS_SALAMANDER_FIREBRAND;
5939 break;
5940 case YELLOW: // salamander mystic
5941 mi.type = MONS_SALAMANDER_MYSTIC;
5942 break;
5943 default:
5944 die("Unexpected monster with type %d and colour %d",
5945 mi.type, mi.colour(true));
5946 }
5947 if (mons_is_demonspawn(mi.type)
5948 && mons_species(mi.type) == MONS_DEMONSPAWN
5949 && mi.type != MONS_DEMONSPAWN)
5950 {
5951 ASSERT(mi.base_type != MONS_NO_MONSTER);
5952 }
5953 }
5954
5955 if (th.getMinorVersion() < TAG_MINOR_MONINFO_ENERGY)
5956 mi.menergy = mons_class_energy(mi.type);
5957 else
5958 {
5959 #endif
5960 mi.menergy.move = unmarshallByte(th);
5961 mi.menergy.swim = unmarshallByte(th);
5962 mi.menergy.attack = unmarshallByte(th);
5963 mi.menergy.missile = unmarshallByte(th);
5964 mi.menergy.spell = unmarshallByte(th);
5965 mi.menergy.special = unmarshallByte(th);
5966 mi.menergy.item = unmarshallByte(th);
5967 mi.menergy.pickup_percent = unmarshallByte(th);
5968 #if TAG_MAJOR_VERSION == 34
5969 }
5970 #endif
5971
5972 // Some TAG_MAJOR_VERSION == 34 saves suffered data loss here, beware.
5973 // Should be harmless, hopefully.
5974 #if TAG_MAJOR_VERSION == 34
5975 if (th.getMinorVersion() < TAG_MINOR_BOOL_FLIGHT)
5976 unmarshallUnsigned(th);
5977 #endif
5978 #if TAG_MAJOR_VERSION == 34
5979 if (th.getMinorVersion() < TAG_MINOR_ATTACK_DESCS)
5980 {
5981 for (int i = 0; i < MAX_NUM_ATTACKS; ++i)
5982 {
5983 mi.attack[i] = get_monster_data(mi.type)->attack[i];
5984 mi.attack[i].damage = 0;
5985 }
5986 }
5987 else
5988 #endif
5989 for (int i = 0; i < MAX_NUM_ATTACKS; ++i)
5990 mi.attack[i] = _unmarshall_mi_attack(th);
5991
5992 for (unsigned int i = 0; i <= MSLOT_LAST_VISIBLE_SLOT; ++i)
5993 {
5994 if (unmarshallBoolean(th))
5995 {
5996 mi.inv[i].reset(new item_def());
5997 unmarshallItem(th, *mi.inv[i]);
5998 }
5999 }
6000
6001 if (mons_is_pghost(mi.type))
6002 {
6003 unmarshallUnsigned(th, mi.i_ghost.species);
6004 unmarshallUnsigned(th, mi.i_ghost.job);
6005 unmarshallUnsigned(th, mi.i_ghost.religion);
6006 unmarshallUnsigned(th, mi.i_ghost.best_skill);
6007 mi.i_ghost.best_skill_rank = unmarshallShort(th);
6008 mi.i_ghost.xl_rank = unmarshallShort(th);
6009 mi.i_ghost.damage = unmarshallShort(th);
6010 mi.i_ghost.ac = unmarshallShort(th);
6011 }
6012 #if TAG_MAJOR_VERSION == 34
6013 if ((mons_is_ghost_demon(mi.type)
6014 || (mi.type == MONS_LICH || mi.type == MONS_ANCIENT_LICH
6015 || mi.type == MONS_SPELLFORGED_SERVITOR)
6016 && th.getMinorVersion() < TAG_MINOR_EXORCISE)
6017 && th.getMinorVersion() >= TAG_MINOR_GHOST_SINV
6018 && th.getMinorVersion() < TAG_MINOR_GHOST_NOSINV)
6019 {
6020 unmarshallBoolean(th); // was can_sinv
6021 }
6022 #endif
6023
6024 mi.props.clear();
6025 mi.props.read(th);
6026
6027 #if TAG_MAJOR_VERSION == 34
6028 if (mi.type == MONS_ZOMBIE_SMALL || mi.type == MONS_ZOMBIE_LARGE)
6029 mi.type = MONS_ZOMBIE;
6030 if (mi.type == MONS_SKELETON_SMALL || mi.type == MONS_SKELETON_LARGE)
6031 mi.type = MONS_SKELETON;
6032 if (mi.type == MONS_SIMULACRUM_SMALL || mi.type == MONS_SIMULACRUM_LARGE)
6033 mi.type = MONS_SIMULACRUM;
6034 if (th.getMinorVersion() < TAG_MINOR_WAR_DOG_REMOVAL)
6035 {
6036 if (mi.type == MONS_WAR_DOG)
6037 mi.type = MONS_WOLF;
6038 }
6039 #endif
6040
6041 if (mons_is_removed(mi.type))
6042 {
6043 mi.type = MONS_GHOST;
6044 mi.props.clear();
6045 }
6046 }
6047
_tag_construct_level_monsters(writer & th)6048 static void _tag_construct_level_monsters(writer &th)
6049 {
6050 int nm = 0;
6051 for (int i = 0; i < MAX_MONS_ALLOC; ++i)
6052 if (env.mons_alloc[i] != MONS_NO_MONSTER)
6053 nm = i + 1;
6054
6055 // how many mons_alloc?
6056 marshallByte(th, nm);
6057 for (int i = 0; i < nm; ++i)
6058 marshallMonType(th, env.mons_alloc[i]);
6059
6060 // how many monsters?
6061 nm = _last_used_index(env.mons, MAX_MONSTERS);
6062 marshallShort(th, nm);
6063
6064 for (int i = 0; i < nm; i++)
6065 {
6066 monster& m(env.mons[i]);
6067
6068 #if defined(DEBUG) || defined(DEBUG_MONS_SCAN)
6069 if (m.type != MONS_NO_MONSTER)
6070 {
6071 if (invalid_monster_type(m.type))
6072 {
6073 mprf(MSGCH_ERROR, "Marshalled monster #%d %s",
6074 i, m.name(DESC_PLAIN, true).c_str());
6075 }
6076 if (!in_bounds(m.pos()))
6077 {
6078 mprf(MSGCH_ERROR,
6079 "Marshalled monster #%d %s out of bounds at (%d, %d)",
6080 i, m.name(DESC_PLAIN, true).c_str(),
6081 m.pos().x, m.pos().y);
6082 }
6083 }
6084 #endif
6085 marshallMonster(th, m);
6086 }
6087 }
6088
_tag_construct_level_tiles(writer & th)6089 void _tag_construct_level_tiles(writer &th)
6090 {
6091 // Map grids.
6092 // how many X?
6093 marshallShort(th, GXM);
6094 // how many Y?
6095 marshallShort(th, GYM);
6096
6097 marshallShort(th, tile_env.names.size());
6098 for (const string &name : tile_env.names)
6099 {
6100 marshallString(th, name);
6101 #ifdef DEBUG_TILE_NAMES
6102 mprf("Writing '%s' into save.", name.c_str());
6103 #endif
6104 }
6105
6106 // flavour
6107 marshallShort(th, tile_env.default_flavour.wall_idx);
6108 marshallShort(th, tile_env.default_flavour.floor_idx);
6109
6110 marshallShort(th, tile_env.default_flavour.wall);
6111 marshallShort(th, tile_env.default_flavour.floor);
6112 marshallShort(th, tile_env.default_flavour.special);
6113
6114 for (int count_x = 0; count_x < GXM; count_x++)
6115 for (int count_y = 0; count_y < GYM; count_y++)
6116 {
6117 marshallShort(th, tile_env.flv[count_x][count_y].wall_idx);
6118 marshallShort(th, tile_env.flv[count_x][count_y].floor_idx);
6119 marshallShort(th, tile_env.flv[count_x][count_y].feat_idx);
6120
6121 marshallShort(th, tile_env.flv[count_x][count_y].wall);
6122 marshallShort(th, tile_env.flv[count_x][count_y].floor);
6123 marshallShort(th, tile_env.flv[count_x][count_y].feat);
6124 marshallShort(th, tile_env.flv[count_x][count_y].special);
6125 }
6126
6127 marshallInt(th, TILE_WALL_MAX);
6128 }
6129
_tag_read_level(reader & th)6130 static void _tag_read_level(reader &th)
6131 {
6132 env.floor_colour = unmarshallUByte(th);
6133 env.rock_colour = unmarshallUByte(th);
6134
6135 #if TAG_MAJOR_VERSION == 34
6136 if (th.getMinorVersion() < TAG_MINOR_NO_LEVEL_FLAGS)
6137 unmarshallInt(th);
6138 #endif
6139
6140 env.elapsed_time = unmarshallInt(th);
6141 env.old_player_pos = unmarshallCoord(th);
6142 env.absdepth0 = absdungeon_depth(you.where_are_you, you.depth);
6143
6144 // Map grids.
6145 // how many X?
6146 const int gx = unmarshallShort(th);
6147 // how many Y?
6148 const int gy = unmarshallShort(th);
6149 ASSERT(gx == GXM);
6150 ASSERT(gy == GYM);
6151
6152 env.turns_on_level = unmarshallInt(th);
6153
6154 EAT_CANARY;
6155
6156 env.map_seen.reset();
6157 #if TAG_MAJOR_VERSION == 34
6158 vector<coord_def> transporters;
6159 #endif
6160 for (int i = 0; i < gx; i++)
6161 for (int j = 0; j < gy; j++)
6162 {
6163 dungeon_feature_type feat = unmarshallFeatureType(th);
6164 env.grid[i][j] = feat;
6165 ASSERT(feat < NUM_FEATURES);
6166
6167 #if TAG_MAJOR_VERSION == 34
6168 // Save these for potential destination clean up.
6169 if (env.grid[i][j] == DNGN_TRANSPORTER)
6170 transporters.push_back(coord_def(i, j));
6171 #endif
6172 unmarshallMapCell(th, env.map_knowledge[i][j]);
6173 // Fixup positions
6174 if (env.map_knowledge[i][j].monsterinfo())
6175 env.map_knowledge[i][j].monsterinfo()->pos = coord_def(i, j);
6176 if (env.map_knowledge[i][j].cloudinfo())
6177 env.map_knowledge[i][j].cloudinfo()->pos = coord_def(i, j);
6178
6179 env.map_knowledge[i][j].flags &= ~MAP_VISIBLE_FLAG;
6180 if (env.map_knowledge[i][j].seen())
6181 env.map_seen.set(i, j);
6182 env.pgrid[i][j].flags = unmarshallInt(th);
6183
6184 env.mgrid[i][j] = NON_MONSTER;
6185 }
6186
6187 #if TAG_MAJOR_VERSION == 34
6188 if (th.getMinorVersion() < TAG_MINOR_FORGOTTEN_MAP)
6189 env.map_forgotten.reset();
6190 else
6191 #endif
6192 if (unmarshallBoolean(th))
6193 {
6194 MapKnowledge *f = new MapKnowledge();
6195 for (int x = 0; x < GXM; x++)
6196 for (int y = 0; y < GYM; y++)
6197 unmarshallMapCell(th, (*f)[x][y]);
6198 env.map_forgotten.reset(f);
6199 }
6200 else
6201 env.map_forgotten.reset();
6202
6203 env.grid_colours.init(BLACK);
6204 _run_length_decode(th, unmarshallByte, env.grid_colours, GXM, GYM);
6205
6206 EAT_CANARY;
6207
6208 env.cloud.clear();
6209 // how many clouds?
6210 const int num_clouds = unmarshallShort(th);
6211 cloud_struct cloud;
6212 for (int i = 0; i < num_clouds; i++)
6213 {
6214 cloud.type = static_cast<cloud_type>(unmarshallByte(th));
6215 #if TAG_MAJOR_VERSION == 34
6216 // old system marshalled empty clouds this way
6217 if (cloud.type == CLOUD_NONE)
6218 continue;
6219 #else
6220 ASSERT(cloud.type != CLOUD_NONE);
6221 #endif
6222 cloud.pos.x = unmarshallByte(th);
6223 cloud.pos.y = unmarshallByte(th);
6224 ASSERT_IN_BOUNDS(cloud.pos);
6225 cloud.decay = unmarshallShort(th);
6226 cloud.spread_rate = unmarshallUByte(th);
6227 cloud.whose = static_cast<kill_category>(unmarshallUByte(th));
6228 cloud.killer = static_cast<killer_type>(unmarshallUByte(th));
6229 cloud.source = unmarshallInt(th);
6230 #if TAG_MAJOR_VERSION == 34
6231 if (th.getMinorVersion() < TAG_MINOR_DECUSTOM_CLOUDS)
6232 {
6233 unmarshallShort(th); // was cloud.colour
6234 unmarshallString(th); // was cloud.name
6235 unmarshallString(th); // was cloud.tile
6236 }
6237 #endif
6238 cloud.excl_rad = unmarshallInt(th);
6239
6240 #if TAG_MAJOR_VERSION == 34
6241 // Remove clouds stuck in walls, from 0.18-a0-603-g332275c to
6242 // 0.18-a0-629-g16988c9.
6243 if (!cell_is_solid(cloud.pos))
6244 #endif
6245 env.cloud[cloud.pos] = cloud;
6246 }
6247
6248 EAT_CANARY;
6249
6250 // how many shops?
6251 const int num_shops = unmarshallShort(th);
6252 shop_struct shop;
6253 for (int i = 0; i < num_shops; i++)
6254 {
6255 unmarshall_shop(th, shop);
6256 if (shop.type == SHOP_UNASSIGNED)
6257 continue;
6258 #if TAG_MAJOR_VERSION == 34
6259 shop.num = i;
6260 #endif
6261 env.shop[shop.pos] = shop;
6262 }
6263
6264 EAT_CANARY;
6265
6266 env.sanctuary_pos = unmarshallCoord(th);
6267 env.sanctuary_time = unmarshallByte(th);
6268
6269 env.spawn_random_rate = unmarshallInt(th);
6270
6271 env.markers.read(th);
6272 #if TAG_MAJOR_VERSION == 34
6273 if (th.getMinorVersion() < TAG_MINOR_TRANSPORTER_LANDING)
6274 {
6275 for (auto& tr : transporters)
6276 {
6277 if (env.grid(tr) != DNGN_TRANSPORTER)
6278 continue;
6279
6280 const coord_def dest = get_transporter_dest(tr);
6281 if (dest != INVALID_COORD)
6282 env.grid(dest) = DNGN_TRANSPORTER_LANDING;
6283 }
6284 }
6285 if (th.getMinorVersion() < TAG_MINOR_VETO_DISINT)
6286 {
6287 for (map_marker *mark : env.markers.get_all(MAT_ANY))
6288 {
6289 if (mark->property("veto_disintegrate") == "veto")
6290 {
6291 map_wiz_props_marker *marker =
6292 new map_wiz_props_marker(mark->pos);
6293 marker->set_property("veto_dig", "veto");
6294 env.markers.add(marker);
6295 }
6296 }
6297 }
6298 if (th.getMinorVersion() < TAG_MINOR_MERGE_VETOES)
6299 {
6300 for (map_marker *mark : env.markers.get_all(MAT_ANY))
6301 {
6302 if (mark->property("veto_dig") == "veto"
6303 || mark->property("veto_fire") == "veto"
6304 || mark->property("veto_shatter") == "veto"
6305 || mark->property("veto_tornado") == "veto")
6306 {
6307 map_wiz_props_marker *marker =
6308 new map_wiz_props_marker(mark->pos);
6309 marker->set_property("veto_destroy", "veto");
6310 env.markers.add(marker);
6311 }
6312 }
6313 }
6314 #endif
6315
6316 env.properties.clear();
6317 env.properties.read(th);
6318 #if TAG_MAJOR_VERSION == 34
6319 if (th.getMinorVersion() < TAG_MINOR_PLACE_UNPACK)
6320 {
6321 CrawlHashTable &props = env.properties;
6322 if (props.exists(VAULT_MON_BASES_KEY))
6323 {
6324 ASSERT(!props.exists(VAULT_MON_PLACES_KEY));
6325 CrawlVector &type_vec = props[VAULT_MON_TYPES_KEY].get_vector();
6326 CrawlVector &base_vec = props[VAULT_MON_BASES_KEY].get_vector();
6327 size_t size = type_vec.size();
6328 props[VAULT_MON_PLACES_KEY].new_vector(SV_LEV_ID).resize(size);
6329 CrawlVector &place_vec = props[VAULT_MON_PLACES_KEY].get_vector();
6330 for (size_t i = 0; i < size; i++)
6331 {
6332 if (type_vec[i].get_int() == -1)
6333 place_vec[i] = level_id::from_packed_place(base_vec[i].get_int());
6334 else
6335 place_vec[i] = level_id();
6336 }
6337 }
6338 }
6339 #endif
6340
6341 env.dactions_done = unmarshallInt(th);
6342
6343 // Restore heightmap
6344 env.heightmap.reset(nullptr);
6345 const bool have_heightmap = unmarshallBoolean(th);
6346 if (have_heightmap)
6347 {
6348 env.heightmap.reset(new grid_heightmap);
6349 grid_heightmap &heightmap(*env.heightmap);
6350 for (rectangle_iterator ri(0); ri; ++ri)
6351 heightmap(*ri) = unmarshallShort(th);
6352 }
6353
6354 EAT_CANARY;
6355
6356 env.forest_awoken_until = unmarshallInt(th);
6357 unmarshall_level_vault_data(th);
6358 env.density = unmarshallInt(th);
6359 #if TAG_MAJOR_VERSION == 34
6360
6361 if (th.getMinorVersion() < TAG_MINOR_NO_SUNLIGHT)
6362 {
6363 int num_lights = unmarshallShort(th);
6364 ASSERT(num_lights >= 0);
6365 while (num_lights-- > 0)
6366 {
6367 unmarshallCoord(th);
6368 unmarshallInt(th);
6369 }
6370 }
6371 #endif
6372 }
6373
6374 #if TAG_MAJOR_VERSION == 34
_fixup_soh_breath(monster_type mtyp)6375 static spell_type _fixup_soh_breath(monster_type mtyp)
6376 {
6377 switch (mtyp)
6378 {
6379 case MONS_SERPENT_OF_HELL:
6380 default:
6381 return SPELL_SERPENT_OF_HELL_GEH_BREATH;
6382 case MONS_SERPENT_OF_HELL_COCYTUS:
6383 return SPELL_SERPENT_OF_HELL_COC_BREATH;
6384 case MONS_SERPENT_OF_HELL_DIS:
6385 return SPELL_SERPENT_OF_HELL_DIS_BREATH;
6386 case MONS_SERPENT_OF_HELL_TARTARUS:
6387 return SPELL_SERPENT_OF_HELL_TAR_BREATH;
6388 }
6389 }
6390
_need_poly_refresh(const monster & mon)6391 static bool _need_poly_refresh(const monster &mon)
6392 {
6393 if (!mon.props.exists(POLY_SET_KEY))
6394 return true;
6395 const CrawlVector &set = mon.props[POLY_SET_KEY].get_vector();
6396 for (int poly_mon : set)
6397 {
6398 const monster_type mc = (monster_type)poly_mon;
6399 // removed monster
6400 if (mc == MONS_PROGRAM_BUG || mons_species(mc) == MONS_PROGRAM_BUG)
6401 return true;
6402 }
6403 return false;
6404 }
6405 #endif
6406
_tag_read_level_items(reader & th)6407 static void _tag_read_level_items(reader &th)
6408 {
6409 unwind_bool dont_scan(crawl_state.crash_debug_scans_safe, false);
6410 env.trap.clear();
6411 // how many traps?
6412 const int trap_count = unmarshallShort(th);
6413 trap_def trap;
6414 for (int i = 0; i < trap_count; ++i)
6415 {
6416 trap.type = static_cast<trap_type>(unmarshallUByte(th));
6417 #if TAG_MAJOR_VERSION == 34
6418 if (trap.type == TRAP_UNASSIGNED)
6419 continue;
6420 #else
6421 ASSERT(trap.type != TRAP_UNASSIGNED);
6422 #endif
6423 trap.pos = unmarshallCoord(th);
6424 trap.ammo_qty = unmarshallShort(th);
6425 #if TAG_MAJOR_VERSION == 34
6426 if (th.getMinorVersion() == TAG_MINOR_0_11 && trap.type >= TRAP_TELEPORT)
6427 trap.type = (trap_type)(trap.type - 1);
6428 if (th.getMinorVersion() < TAG_MINOR_REVEAL_TRAPS)
6429 env.grid(trap.pos) = trap.feature();
6430 if (th.getMinorVersion() >= TAG_MINOR_TRAPS_DETERM
6431 && th.getMinorVersion() != TAG_MINOR_0_11
6432 && th.getMinorVersion() < TAG_MINOR_REVEALED_TRAPS)
6433 {
6434 unmarshallUByte(th);
6435 }
6436 #endif
6437 env.trap[trap.pos] = trap;
6438 }
6439
6440 #if TAG_MAJOR_VERSION == 34
6441 // Fix up floor that trap_def::destroy left as a trap (from
6442 // 0.18-a0-605-g5e852a4 to 0.18-a0-614-gc92b81f).
6443 for (int i = 0; i < GXM; i++)
6444 for (int j = 0; j < GYM; j++)
6445 {
6446 coord_def pos(i, j);
6447 if (feat_is_trap(env.grid(pos)) && !map_find(env.trap, pos))
6448 env.grid(pos) = DNGN_FLOOR;
6449 }
6450
6451 #endif
6452
6453 // how many items?
6454 const int item_count = unmarshallShort(th);
6455 ASSERT_RANGE(item_count, 0, MAX_ITEMS + 1);
6456 for (int i = 0; i < item_count; ++i)
6457 unmarshallItem(th, env.item[i]);
6458 for (int i = item_count; i < MAX_ITEMS; ++i)
6459 env.item[i].clear();
6460
6461 #ifdef DEBUG_ITEM_SCAN
6462 // There's no way to fix this, even with wizard commands, so get
6463 // rid of it when restoring the game.
6464 for (int i = 0; i < item_count; ++i)
6465 {
6466 if (env.item[i].defined() && env.item[i].pos.origin())
6467 {
6468 debug_dump_item(env.item[i].name(DESC_PLAIN).c_str(), i, env.item[i],
6469 "Fixing up unlinked temporary item:");
6470 env.item[i].clear();
6471 }
6472 }
6473 #endif
6474 }
6475
unmarshallMonster(reader & th,monster & m)6476 void unmarshallMonster(reader &th, monster& m)
6477 {
6478 m.reset();
6479
6480 m.type = unmarshallMonType(th);
6481 if (m.type == MONS_NO_MONSTER)
6482 return;
6483
6484 ASSERT(!invalid_monster_type(m.type));
6485
6486 #if TAG_MAJOR_VERSION == 34
6487 uint32_t parts = 0;
6488 if (th.getMinorVersion() < TAG_MINOR_MONSTER_PARTS)
6489 {
6490 if (mons_is_ghost_demon(m.type))
6491 parts |= MP_GHOST_DEMON;
6492 }
6493 else
6494 parts = unmarshallUnsigned(th);
6495 if (th.getMinorVersion() < TAG_MINOR_OPTIONAL_PARTS)
6496 parts |= MP_CONSTRICTION | MP_ITEMS | MP_SPELLS;
6497 #else
6498 uint32_t parts = unmarshallUnsigned(th);
6499 #endif
6500 m.mid = unmarshallInt(th);
6501 ASSERT(m.mid > 0);
6502 m.mname = unmarshallString(th);
6503 #if TAG_MAJOR_VERSION == 34
6504 if (th.getMinorVersion() >= TAG_MINOR_LEVEL_XP_INFO)
6505 {
6506 // This was monster::is_spawn before the level XP info fix.
6507 if (th.getMinorVersion() < TAG_MINOR_LEVEL_XP_INFO_FIX)
6508 {
6509 // We no longer track spawns but instead whether the monster comes
6510 // from a vault. This gets determined from props below for
6511 // transferred games.
6512 unmarshallByte(th);
6513 m.xp_tracking = XP_NON_VAULT;
6514 }
6515 else
6516 #endif
6517 m.xp_tracking = static_cast<xp_tracking_type>(unmarshallUByte(th));
6518 #if TAG_MAJOR_VERSION == 34
6519 }
6520 // Don't track monsters generated before TAG_MINOR_LEVEL_XP_INFO.
6521 else
6522 m.xp_tracking = XP_UNTRACKED;
6523
6524
6525 if (th.getMinorVersion() < TAG_MINOR_REMOVE_MON_AC_EV)
6526 {
6527 unmarshallByte(th);
6528 unmarshallByte(th);
6529 }
6530 #endif
6531 m.set_hit_dice( unmarshallByte(th));
6532 #if TAG_MAJOR_VERSION == 34
6533 // Draining used to be able to take a monster to 0 HD, but that
6534 // caused crashes if they tried to cast spells.
6535 m.set_hit_dice(max(m.get_experience_level(), 1));
6536 #else
6537 ASSERT(m.get_experience_level() > 0);
6538 #endif
6539 m.speed = unmarshallByte(th);
6540 // Avoid sign extension when loading files (Elethiomel's hang)
6541 m.speed_increment = unmarshallUByte(th);
6542 m.behaviour = static_cast<beh_type>(unmarshallUByte(th));
6543 int x = unmarshallByte(th);
6544 int y = unmarshallByte(th);
6545 m.set_position(coord_def(x,y));
6546 m.target.x = unmarshallByte(th);
6547 m.target.y = unmarshallByte(th);
6548
6549 m.firing_pos = unmarshallCoord(th);
6550 m.patrol_point = unmarshallCoord(th);
6551
6552 int help = unmarshallByte(th);
6553 m.travel_target = static_cast<montravel_target_type>(help);
6554
6555 const int len = unmarshallShort(th);
6556 for (int i = 0; i < len; ++i)
6557 m.travel_path.push_back(unmarshallCoord(th));
6558
6559 m.flags.flags = unmarshallUnsigned(th);
6560 m.experience = unmarshallInt(th);
6561
6562 m.enchantments.clear();
6563 const int nenchs = unmarshallShort(th);
6564 for (int i = 0; i < nenchs; ++i)
6565 {
6566 mon_enchant me = unmarshall_mon_enchant(th);
6567 m.enchantments[me.ench] = me;
6568 m.ench_cache.set(me.ench, true);
6569 }
6570 m.ench_countdown = unmarshallByte(th);
6571
6572 m.hit_points = unmarshallShort(th);
6573 m.max_hit_points = unmarshallShort(th);
6574 m.number = unmarshallInt(th);
6575 m.base_monster = unmarshallMonType(th);
6576 m.colour = unmarshallShort(th);
6577 #if TAG_MAJOR_VERSION == 34
6578 if (th.getMinorVersion() < TAG_MINOR_SUMMONER)
6579 m.summoner = 0;
6580 else
6581 #endif
6582 m.summoner = unmarshallInt(th);
6583
6584 if (parts & MP_ITEMS)
6585 for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
6586 m.inv[j] = unmarshallShort(th);
6587
6588 if (parts & MP_SPELLS)
6589 {
6590 unmarshallSpells(th, m.spells
6591 #if TAG_MAJOR_VERSION == 34
6592 , m.get_experience_level()
6593 #endif
6594 );
6595 #if TAG_MAJOR_VERSION == 34
6596 monster_spells oldspells = m.spells;
6597 m.spells.clear();
6598 for (mon_spell_slot &slot : oldspells)
6599 {
6600 if (th.getMinorVersion() < TAG_MINOR_MORE_GHOST_MAGIC)
6601 slot.spell = _fixup_positional_monster_spell(slot.spell);
6602
6603 if (mons_is_zombified(m) && !mons_enslaved_soul(m)
6604 && slot.spell != SPELL_CREATE_TENTACLES)
6605 {
6606 // zombies shouldn't have (most) spells
6607 }
6608 else if (slot.spell == SPELL_DRACONIAN_BREATH)
6609 {
6610 // Replace Draconian Breath with the colour-specific spell,
6611 // and remove Azrael's bad breath while we're at it.
6612 if (mons_genus(m.type) == MONS_DRACONIAN)
6613 m.spells.push_back(drac_breath(draco_or_demonspawn_subspecies(m)));
6614 }
6615 // Give Mnoleg back malign gateway in place of tentacles.
6616 else if (slot.spell == SPELL_CREATE_TENTACLES
6617 && m.type == MONS_MNOLEG)
6618 {
6619 slot.spell = SPELL_MALIGN_GATEWAY;
6620 slot.freq = 27;
6621 m.spells.push_back(slot);
6622 }
6623 else if (slot.spell == SPELL_CHANT_FIRE_STORM)
6624 {
6625 slot.spell = SPELL_FIRE_STORM;
6626 m.spells.push_back(slot);
6627 }
6628 else if (slot.spell == SPELL_SERPENT_OF_HELL_BREATH_REMOVED)
6629 {
6630 slot.spell = _fixup_soh_breath(m.type);
6631 m.spells.push_back(slot);
6632 }
6633 #if TAG_MAJOR_VERSION == 34
6634 else if (slot.spell != SPELL_DELAYED_FIREBALL
6635 && slot.spell != SPELL_MELEE
6636 && slot.spell != SPELL_NO_SPELL)
6637 {
6638 m.spells.push_back(slot);
6639 }
6640 #endif
6641 else if (slot.spell == SPELL_CORRUPT_BODY)
6642 {
6643 slot.spell = SPELL_CORRUPTING_PULSE;
6644 m.spells.push_back(slot);
6645 }
6646 }
6647 #endif
6648 }
6649
6650 m.god = static_cast<god_type>(unmarshallByte(th));
6651 m.attitude = static_cast<mon_attitude_type>(unmarshallByte(th));
6652 m.foe = unmarshallShort(th);
6653 #if TAG_MAJOR_VERSION == 34
6654 // In 0.16 alpha we briefly allowed YOU_FAULTLESS as a monster's foe.
6655 if (m.foe == YOU_FAULTLESS)
6656 m.foe = MHITYOU;
6657 #endif
6658 m.foe_memory = unmarshallInt(th);
6659
6660 m.damage_friendly = unmarshallShort(th);
6661 m.damage_total = unmarshallShort(th);
6662
6663 #if TAG_MAJOR_VERSION == 34
6664 if (th.getMinorVersion() < TAG_MINOR_UNSEEN_MONSTER)
6665 {
6666 m.went_unseen_this_turn = false;
6667 m.unseen_pos = coord_def(0, 0);
6668 }
6669 else
6670 {
6671 #endif
6672 m.went_unseen_this_turn = unmarshallByte(th);
6673 m.unseen_pos = unmarshallCoord(th);
6674 #if TAG_MAJOR_VERSION == 34
6675 }
6676 #endif
6677
6678 #if TAG_MAJOR_VERSION == 34
6679 if (m.type == MONS_LABORATORY_RAT)
6680 _unmarshallGhost(th), m.type = MONS_RAT;
6681
6682 // MONS_SPECTRAL_WEAPON was inserted into the wrong place
6683 // (0.13-a0-1964-g2fab1c1, merged into trunk in 0.13-a0-1981-g9e80fb2),
6684 // and then had a ghost_demon structure added (0.13-a0-2055-g6cfaa00).
6685 // Neither event had an associated tag, but both were between the
6686 // same two adjacent tags.
6687 if (th.getMinorVersion() < TAG_MINOR_CANARIES
6688 && th.getMinorVersion() >= TAG_MINOR_WAR_DOG_REMOVAL
6689 && m.type >= MONS_SPECTRAL_WEAPON
6690 && m.type <= MONS_POLYMOTH)
6691 {
6692 // But fortunately the three monsters it could be all have different
6693 // speeds, and none of those speeds are 3/2 or 2/3 any others. We will
6694 // assume that none of these had the wretched enchantment. Ugh.
6695 switch (m.speed)
6696 {
6697 case 6: case 7: // slowed
6698 case 10:
6699 case 15: // hasted/berserked
6700 m.type = MONS_GHOST; // wellspring
6701 break;
6702 case 8: // slowed
6703 case 12:
6704 case 18: // hasted/berserked
6705 m.type = MONS_POLYMOTH;
6706 break;
6707 case 16: case 17: case 20: // slowed
6708 case 25:
6709 case 30:
6710 case 37: case 38: case 45: // hasted/berserked
6711 m.type = MONS_SPECTRAL_WEAPON;
6712 break;
6713 default:
6714 die("Unexpected monster with type %d and speed %d",
6715 m.type, m.speed);
6716 }
6717 }
6718
6719 // Spectral weapons became speed 30 in the commit immediately preceding
6720 // the one that added the ghost_demon. Since the commits were in the
6721 // same batch, no one should have saves where the speed is 30 and the
6722 // spectral weapon didn't have a ghost_demon, or where the speed is
6723 // 25 and it did.
6724 if (th.getMinorVersion() < TAG_MINOR_CANARIES
6725 && m.type == MONS_SPECTRAL_WEAPON
6726 // normal, slowed, and hasted, respectively.
6727 && m.speed != 30 && m.speed != 20 && m.speed != 45)
6728 {
6729 // Don't bother trying to fix it up.
6730 m.type = MONS_WOOD_GOLEM; // anything removed
6731 m.mid = ++you.last_mid; // sabotage the bond
6732 ASSERT(m.mid < MID_FIRST_NON_MONSTER);
6733 parts &= MP_GHOST_DEMON;
6734 }
6735 else if (m.type == MONS_CHIMERA
6736 && th.getMinorVersion() < TAG_MINOR_CHIMERA_GHOST_DEMON)
6737 {
6738 // Don't unmarshall the ghost demon if this is an invalid chimera
6739 }
6740 else if (th.getMinorVersion() < TAG_MINOR_DEMONSPAWN
6741 && m.type >= MONS_MONSTROUS_DEMONSPAWN
6742 && m.type <= MONS_SALAMANDER_MYSTIC)
6743 {
6744 // The demonspawn-enemies branch was merged in such a fashion
6745 // that it bumped several monster enums (see merge commit:
6746 // 0.14-a0-2321-gdab6825).
6747 // Try to figure out what it is.
6748 switch (m.colour)
6749 {
6750 case BROWN: // monstrous demonspawn, naga ritualist
6751 if (m.spells[0].spell == SPELL_FORCE_LANCE)
6752 m.type = MONS_NAGA_RITUALIST;
6753 else
6754 m.type = MONS_MONSTROUS_DEMONSPAWN;
6755 break;
6756 case BLUE: // gelid demonspawn
6757 m.type = MONS_GELID_DEMONSPAWN;
6758 break;
6759 case RED: // infernal demonspawn
6760 m.type = MONS_INFERNAL_DEMONSPAWN;
6761 break;
6762 case LIGHTGRAY: // torturous demonspawn, naga sharpshooter
6763 if (m.spells[0].spell == SPELL_PORTAL_PROJECTILE)
6764 m.type = MONS_NAGA_SHARPSHOOTER;
6765 else
6766 m.type = MONS_TORTUROUS_DEMONSPAWN;
6767 break;
6768 case LIGHTBLUE: // blood saint, shock serpent
6769 if (m.base_monster != MONS_NO_MONSTER)
6770 m.type = MONS_BLOOD_SAINT;
6771 else
6772 m.type = MONS_SHOCK_SERPENT;
6773 break;
6774 case LIGHTCYAN: // warmonger, drowned soul
6775 if (m.base_monster != MONS_NO_MONSTER)
6776 m.type = MONS_WARMONGER;
6777 else
6778 m.type = MONS_DROWNED_SOUL;
6779 break;
6780 case LIGHTGREEN: // corrupter
6781 m.type = MONS_CORRUPTER;
6782 break;
6783 case LIGHTMAGENTA: // black sun
6784 m.type = MONS_BLACK_SUN;
6785 break;
6786 case CYAN: // worldbinder
6787 m.type = MONS_WORLDBINDER;
6788 break;
6789 case MAGENTA: // vine stalker, mana viper, grand avatar
6790 switch (m.speed)
6791 {
6792 case 20:
6793 case 30:
6794 case 45:
6795 m.type = MONS_GRAND_AVATAR;
6796 break;
6797 case 9:
6798 case 10:
6799 case 14:
6800 case 21:
6801 m.type = MONS_MANA_VIPER;
6802 break;
6803 default:
6804 die("Unexpected monster with type %d and speed %d",
6805 m.type, m.speed);
6806 }
6807 break;
6808 case WHITE: // salamander firebrand
6809 m.type = MONS_SALAMANDER_FIREBRAND;
6810 break;
6811 case YELLOW: // salamander mystic
6812 m.type = MONS_SALAMANDER_MYSTIC;
6813 break;
6814 default:
6815 die("Unexpected monster with type %d and colour %d",
6816 m.type, m.colour);
6817 }
6818 if (mons_is_demonspawn(m.type)
6819 && mons_species(m.type) == MONS_DEMONSPAWN
6820 && m.type != MONS_DEMONSPAWN)
6821 {
6822 ASSERT(m.base_monster != MONS_NO_MONSTER);
6823 }
6824 }
6825 else if (th.getMinorVersion() < TAG_MINOR_EXORCISE
6826 && th.getMinorVersion() >= TAG_MINOR_RANDLICHES
6827 && (m.type == MONS_LICH || m.type == MONS_ANCIENT_LICH
6828 || m.type == MONS_SPELLFORGED_SERVITOR))
6829 {
6830 m.spells = _unmarshallGhost(th).spells;
6831 }
6832 else
6833 #endif
6834 if (parts & MP_GHOST_DEMON)
6835 m.set_ghost(_unmarshallGhost(th));
6836
6837 #if TAG_MAJOR_VERSION == 34
6838 // Turn elephant slugs into ghosts because they are dummies now.
6839 if (m.type == MONS_ELEPHANT_SLUG)
6840 m.type = MONS_GHOST;
6841 #endif
6842
6843 if (parts & MP_CONSTRICTION)
6844 _unmarshall_constriction(th, &m);
6845
6846 m.props.clear();
6847 m.props.read(th);
6848
6849 if (m.props.exists("monster_tile_name"))
6850 {
6851 string tile = m.props["monster_tile_name"].get_string();
6852 tileidx_t index;
6853 if (!tile_player_index(tile.c_str(), &index))
6854 {
6855 // If invalid tile name, complain and discard the props.
6856 dprf("bad tile name: \"%s\".", tile.c_str());
6857 m.props.erase("monster_tile_name");
6858 if (m.props.exists("monster_tile"))
6859 m.props.erase("monster_tile");
6860 }
6861 else // Update monster tile.
6862 m.props["monster_tile"] = short(index);
6863 }
6864
6865 #if TAG_MAJOR_VERSION == 34
6866 // Forget seen spells if the monster doesn't have any, most likely because
6867 // of a polymorph that happened before polymorph began removing this key.
6868 if (m.spells.empty())
6869 m.props.erase(SEEN_SPELLS_KEY);
6870
6871 // Battlespheres that don't know their creator's mid must have belonged
6872 // to the player pre-monster-battlesphere.
6873 if (th.getMinorVersion() < TAG_MINOR_BATTLESPHERE_MID
6874 && m.type == MONS_BATTLESPHERE && !m.props.exists("bs_mid"))
6875 {
6876 // It must have belonged to the player.
6877 m.summoner = MID_PLAYER;
6878 }
6879 else if (m.props.exists("bs_mid"))
6880 {
6881 m.summoner = m.props["bs_mid"].get_int();
6882 m.props.erase("bs_mid");
6883 }
6884
6885 if (m.props.exists(IOOD_MID))
6886 m.summoner = m.props[IOOD_MID].get_int(), m.props.erase(IOOD_MID);
6887
6888 if (m.props.exists("siren_call"))
6889 {
6890 m.props["merfolk_avatar_call"] = m.props["siren_call"].get_bool();
6891 m.props.erase("siren_call");
6892 }
6893
6894 if (m.type == MONS_ZOMBIE_SMALL || m.type == MONS_ZOMBIE_LARGE)
6895 m.type = MONS_ZOMBIE;
6896 if (m.type == MONS_SKELETON_SMALL || m.type == MONS_SKELETON_LARGE)
6897 m.type = MONS_SKELETON;
6898 if (m.type == MONS_SIMULACRUM_SMALL || m.type == MONS_SIMULACRUM_LARGE)
6899 m.type = MONS_SIMULACRUM;
6900
6901 if (th.getMinorVersion() < TAG_MINOR_WAR_DOG_REMOVAL)
6902 {
6903 if (m.type == MONS_WAR_DOG)
6904 m.type = MONS_WOLF;
6905 }
6906
6907 if (m.props.exists("no_hide"))
6908 m.props.erase("no_hide");
6909
6910 if (m.props.exists("original_name"))
6911 {
6912 m.props[ORIGINAL_TYPE_KEY].get_int() =
6913 get_monster_by_name(m.props["original_name"].get_string());
6914 }
6915
6916 if (m.props.exists("given beogh shield"))
6917 {
6918 m.props.erase("given beogh shield");
6919 m.props[BEOGH_SH_GIFT_KEY] = true;
6920 }
6921
6922 if (m.props.exists("given beogh armour"))
6923 {
6924 m.props.erase("given beogh armour");
6925 m.props[BEOGH_ARM_GIFT_KEY] = true;
6926 }
6927
6928 if (m.props.exists("given beogh weapon"))
6929 {
6930 m.props.erase("given beogh weapon");
6931 m.props[BEOGH_MELEE_WPN_GIFT_KEY] = true;
6932 }
6933
6934 if (m.props.exists("given beogh range weapon"))
6935 {
6936 m.props.erase("given beogh range weapon");
6937 m.props[BEOGH_RANGE_WPN_GIFT_KEY] = true;
6938 }
6939
6940 // fixup for versions of frenzy that involved a permanent attitude change,
6941 // with the original attitude stored in a prop.
6942 if (m.props.exists("old_attitude"))
6943 {
6944 m.attitude = static_cast<mon_attitude_type>(
6945 m.props["old_attitude"].get_short());
6946 m.props.erase("old_attitude");
6947 }
6948
6949 if (th.getMinorVersion() < TAG_MINOR_LEVEL_XP_VAULTS
6950 && m.props.exists("map"))
6951 {
6952 m.xp_tracking = XP_VAULT;
6953 }
6954
6955 if (th.getMinorVersion() < TAG_MINOR_SETPOLY || _need_poly_refresh(m))
6956 init_poly_set(&m);
6957 #endif
6958
6959 if (m.type != MONS_PROGRAM_BUG && mons_species(m.type) == MONS_PROGRAM_BUG)
6960 {
6961 m.type = MONS_GHOST;
6962 m.props.clear();
6963 }
6964
6965 // If an upgrade synthesizes ghost_demon, please mark it in "parts" above.
6966 ASSERT(parts & MP_GHOST_DEMON || !mons_is_ghost_demon(m.type));
6967
6968 m.check_speed();
6969 }
6970
_tag_read_level_monsters(reader & th)6971 static void _tag_read_level_monsters(reader &th)
6972 {
6973 unwind_bool dont_scan(crawl_state.crash_debug_scans_safe, false);
6974 int count;
6975
6976 reset_all_monsters();
6977
6978 // how many mons_alloc?
6979 count = unmarshallByte(th);
6980 ASSERT(count >= 0);
6981 for (int i = 0; i < count && i < MAX_MONS_ALLOC; ++i)
6982 env.mons_alloc[i] = unmarshallMonType(th);
6983 for (int i = MAX_MONS_ALLOC; i < count; ++i)
6984 unmarshallShort(th);
6985 for (int i = count; i < MAX_MONS_ALLOC; ++i)
6986 env.mons_alloc[i] = MONS_NO_MONSTER;
6987
6988 // how many monsters?
6989 count = unmarshallShort(th);
6990 ASSERT_RANGE(count, 0, MAX_MONSTERS + 1);
6991
6992 for (int i = 0; i < count; i++)
6993 {
6994 monster& m = env.mons[i];
6995 unmarshallMonster(th, m);
6996
6997 // place monster
6998 if (!m.alive())
6999 continue;
7000
7001 monster *dup_m = monster_by_mid(m.mid);
7002
7003 #if TAG_MAJOR_VERSION == 34
7004 // clear duplicates of followers who got their god cleared as the result
7005 // of a bad polymorph prior to e6d7efa92cb0. This only fires on level
7006 // load *when there are duplicate mids*, because otherwise the clones
7007 // aren't uniquely identifiable. This fix may still result in duplicate
7008 // mid errors from time to time, but should never crash; saving and
7009 // loading will fix up the duplicate errors. A similar check also
7010 // happens in follower::place (since that runs after the level is
7011 // loaded).
7012 if (dup_m)
7013 {
7014 if (maybe_bad_priest_monster(*dup_m))
7015 fixup_bad_priest_monster(*dup_m);
7016 else if (maybe_bad_priest_monster(m))
7017 {
7018 fixup_bad_priest_monster(m);
7019 env.mid_cache[dup_m->mid] = dup_m->mindex();
7020 // dup_m should already be placed, so nothing else is needed.
7021 continue;
7022 }
7023 // we could print an error on the else case, but this is already
7024 // going to be handled by debug_mons_scan.
7025 }
7026 #endif
7027
7028 // companion_is_elsewhere checks the mid cache
7029 env.mid_cache[m.mid] = i;
7030 if (m.is_divine_companion() && companion_is_elsewhere(m.mid))
7031 {
7032 dprf("Killed elsewhere companion %s(%d) on %s",
7033 m.name(DESC_PLAIN, true).c_str(), m.mid,
7034 level_id::current().describe(false, true).c_str());
7035 monster_die(m, KILL_RESET, -1, true, false);
7036 // avoid "mid cache bogosity" if there's an unhandled clone bug
7037 if (dup_m && dup_m->alive())
7038 {
7039 mprf(MSGCH_ERROR, "elsewhere companion has duplicate mid %d: %s",
7040 dup_m->mid, dup_m->full_name(DESC_PLAIN).c_str());
7041 env.mid_cache[dup_m->mid] = dup_m->mindex();
7042 }
7043 continue;
7044 }
7045
7046 #if defined(DEBUG) || defined(DEBUG_MONS_SCAN)
7047 if (invalid_monster_type(m.type))
7048 {
7049 mprf(MSGCH_ERROR, "Unmarshalled monster #%d %s",
7050 i, m.name(DESC_PLAIN, true).c_str());
7051 }
7052 if (!in_bounds(m.pos()))
7053 {
7054 mprf(MSGCH_ERROR,
7055 "Unmarshalled monster #%d %s out of bounds at (%d, %d)",
7056 i, m.name(DESC_PLAIN, true).c_str(),
7057 m.pos().x, m.pos().y);
7058 }
7059 int midx = env.mgrid(m.pos());
7060 if (midx != NON_MONSTER)
7061 {
7062 mprf(MSGCH_ERROR, "(%d, %d) for %s already occupied by %s",
7063 m.pos().x, m.pos().y,
7064 m.name(DESC_PLAIN, true).c_str(),
7065 env.mons[midx].name(DESC_PLAIN, true).c_str());
7066 }
7067 #endif
7068 env.mgrid(m.pos()) = i;
7069 }
7070 #if TAG_MAJOR_VERSION == 34
7071 // This relies on TAG_YOU (including lost monsters) being unmarshalled
7072 // on game load before the initial level.
7073 if (th.getMinorVersion() < TAG_MINOR_FIXED_CONSTRICTION
7074 && th.getMinorVersion() >= TAG_MINOR_OPTIONAL_PARTS)
7075 {
7076 _fix_missing_constrictions();
7077 }
7078 if (th.getMinorVersion() < TAG_MINOR_TENTACLE_MID)
7079 {
7080 for (monster_iterator mi; mi; ++mi)
7081 {
7082 if (mi->props.exists("inwards"))
7083 {
7084 const int old_midx = mi->props["inwards"].get_int();
7085 if (invalid_monster_index(old_midx))
7086 mi->props["inwards"].get_int() = MID_NOBODY;
7087 else
7088 mi->props["inwards"].get_int() = env.mons[old_midx].mid;
7089 }
7090 if (mi->props.exists("outwards"))
7091 {
7092 const int old_midx = mi->props["outwards"].get_int();
7093 if (invalid_monster_index(old_midx))
7094 mi->props["outwards"].get_int() = MID_NOBODY;
7095 else
7096 mi->props["outwards"].get_int() = env.mons[old_midx].mid;
7097 }
7098 if (mons_is_tentacle_or_tentacle_segment(mi->type))
7099 mi->tentacle_connect = env.mons[mi->tentacle_connect].mid;
7100 }
7101 }
7102 #endif
7103 }
7104
_debug_count_tiles()7105 static void _debug_count_tiles()
7106 {
7107 #ifdef DEBUG_DIAGNOSTICS
7108 # ifdef USE_TILE
7109 map<int,bool> found;
7110 int t, cnt = 0;
7111 for (int i = 0; i < GXM; i++)
7112 for (int j = 0; j < GYM; j++)
7113 {
7114 t = tile_env.bk_bg[i][j];
7115 if (!found.count(t))
7116 cnt++, found[t] = true;
7117 t = tile_env.bk_fg[i][j];
7118 if (!found.count(t))
7119 cnt++, found[t] = true;
7120 t = tile_env.bk_cloud[i][j];
7121 if (!found.count(t))
7122 cnt++, found[t] = true;
7123 }
7124 dprf("Unique tiles found: %d", cnt);
7125 # endif
7126 #endif
7127 }
7128
_tag_read_level_tiles(reader & th)7129 void _tag_read_level_tiles(reader &th)
7130 {
7131 // Map grids.
7132 // how many X?
7133 const int gx = unmarshallShort(th);
7134 // how many Y?
7135 const int gy = unmarshallShort(th);
7136
7137 tile_env.names.clear();
7138 unsigned int num_tilenames = unmarshallShort(th);
7139 for (unsigned int i = 0; i < num_tilenames; ++i)
7140 {
7141 #ifdef DEBUG_TILE_NAMES
7142 string temp = unmarshallString(th);
7143 mprf("Reading tile_names[%d] = %s", i, temp.c_str());
7144 tile_env.names.push_back(temp);
7145 #else
7146 tile_env.names.push_back(unmarshallString(th));
7147 #endif
7148 }
7149
7150 // flavour
7151 tile_env.default_flavour.wall_idx = unmarshallShort(th);
7152 tile_env.default_flavour.floor_idx = unmarshallShort(th);
7153 tile_env.default_flavour.wall = unmarshallShort(th);
7154 tile_env.default_flavour.floor = unmarshallShort(th);
7155 tile_env.default_flavour.special = unmarshallShort(th);
7156
7157 for (int x = 0; x < gx; x++)
7158 for (int y = 0; y < gy; y++)
7159 {
7160 tile_env.flv[x][y].wall_idx = unmarshallShort(th);
7161 tile_env.flv[x][y].floor_idx = unmarshallShort(th);
7162 tile_env.flv[x][y].feat_idx = unmarshallShort(th);
7163
7164 // These get overwritten by _regenerate_tile_flavour
7165 tile_env.flv[x][y].wall = unmarshallShort(th);
7166 tile_env.flv[x][y].floor = unmarshallShort(th);
7167 tile_env.flv[x][y].feat = unmarshallShort(th);
7168 tile_env.flv[x][y].special = unmarshallShort(th);
7169 }
7170
7171 _debug_count_tiles();
7172
7173 _regenerate_tile_flavour();
7174
7175 // Draw remembered map
7176 _draw_tiles();
7177 }
7178
_get_tile_from_vector(const unsigned int idx)7179 static tileidx_t _get_tile_from_vector(const unsigned int idx)
7180 {
7181 if (idx <= 0 || idx > tile_env.names.size())
7182 {
7183 #ifdef DEBUG_TILE_NAMES
7184 mprf("Index out of bounds: idx = %d - 1, size(tile_names) = %d",
7185 idx, tile_env.names.size());
7186 #endif
7187 return 0;
7188 }
7189 string tilename = tile_env.names[idx - 1];
7190
7191 tileidx_t tile;
7192 if (!tile_dngn_index(tilename.c_str(), &tile))
7193 {
7194 #ifdef DEBUG_TILE_NAMES
7195 mprf("tilename %s (index %d) not found",
7196 tilename.c_str(), idx - 1);
7197 #endif
7198 return 0;
7199 }
7200 #ifdef DEBUG_TILE_NAMES
7201 mprf("tilename %s (index %d) resolves to tile %d",
7202 tilename.c_str(), idx - 1, (int) tile);
7203 #endif
7204
7205 return tile;
7206 }
7207
_regenerate_tile_flavour()7208 static void _regenerate_tile_flavour()
7209 {
7210 /* Remember the wall_idx and floor_idx; tile_init_default_flavour
7211 sets them to 0 */
7212 tileidx_t default_wall_idx = tile_env.default_flavour.wall_idx;
7213 tileidx_t default_floor_idx = tile_env.default_flavour.floor_idx;
7214 tile_init_default_flavour();
7215 if (default_wall_idx)
7216 {
7217 tileidx_t new_wall = _get_tile_from_vector(default_wall_idx);
7218 if (new_wall)
7219 {
7220 tile_env.default_flavour.wall_idx = default_wall_idx;
7221 tile_env.default_flavour.wall = new_wall;
7222 }
7223 }
7224 if (default_floor_idx)
7225 {
7226 tileidx_t new_floor = _get_tile_from_vector(default_floor_idx);
7227 if (new_floor)
7228 {
7229 tile_env.default_flavour.floor_idx = default_floor_idx;
7230 tile_env.default_flavour.floor = new_floor;
7231 }
7232 }
7233
7234 for (rectangle_iterator ri(coord_def(0, 0), coord_def(GXM-1, GYM-1));
7235 ri; ++ri)
7236 {
7237 tile_flavour &flv = tile_env.flv(*ri);
7238 flv.wall = 0;
7239 flv.floor = 0;
7240 flv.feat = 0;
7241 flv.special = 0;
7242
7243 if (flv.wall_idx)
7244 {
7245 tileidx_t new_wall = _get_tile_from_vector(flv.wall_idx);
7246 if (!new_wall)
7247 flv.wall_idx = 0;
7248 else
7249 flv.wall = new_wall;
7250 }
7251 if (flv.floor_idx)
7252 {
7253 tileidx_t new_floor = _get_tile_from_vector(flv.floor_idx);
7254 if (!new_floor)
7255 flv.floor_idx = 0;
7256 else
7257 flv.floor = new_floor;
7258 }
7259 if (flv.feat_idx)
7260 {
7261 tileidx_t new_feat = _get_tile_from_vector(flv.feat_idx);
7262 if (!new_feat)
7263 flv.feat_idx = 0;
7264 else
7265 flv.feat = new_feat;
7266 }
7267 }
7268
7269 tile_new_level(true, false);
7270 }
7271
_draw_tiles()7272 static void _draw_tiles()
7273 {
7274 #ifdef USE_TILE
7275 for (rectangle_iterator ri(coord_def(0, 0), coord_def(GXM-1, GYM-1));
7276 ri; ++ri)
7277 {
7278 tile_draw_map_cell(*ri);
7279 }
7280 #endif
7281 }
7282 // ------------------------------- ghost tags ---------------------------- //
7283
_marshallSpells(writer & th,const monster_spells & spells)7284 static void _marshallSpells(writer &th, const monster_spells &spells)
7285 {
7286 const uint8_t spellsize = spells.size();
7287 marshallByte(th, spellsize);
7288 for (int j = 0; j < spellsize; ++j)
7289 {
7290 marshallShort(th, spells[j].spell);
7291 marshallByte(th, spells[j].freq);
7292 marshallShort(th, spells[j].flags.flags);
7293 }
7294 }
7295
7296 #if TAG_MAJOR_VERSION == 34
7297 static const uint8_t NUM_MONSTER_SPELL_SLOTS = 6;
7298
_fixup_spells(monster_spells & spells,int hd)7299 static void _fixup_spells(monster_spells &spells, int hd)
7300 {
7301 for (auto& slot : spells)
7302 slot.flags |= MON_SPELL_WIZARD;
7303
7304 if (spells.size() >= NUM_MONSTER_SPELL_SLOTS)
7305 spells[NUM_MONSTER_SPELL_SLOTS-1].flags |= MON_SPELL_EMERGENCY;
7306
7307 for (auto& slot : spells)
7308 slot.freq = (hd + 50) / spells.size();
7309 }
7310 #endif
7311
unmarshallSpells(reader & th,monster_spells & spells,unsigned hd)7312 void unmarshallSpells(reader &th, monster_spells &spells
7313 #if TAG_MAJOR_VERSION == 34
7314 , unsigned hd
7315 #endif
7316 )
7317 {
7318 const uint8_t spellsize =
7319 #if TAG_MAJOR_VERSION == 34
7320
7321 (th.getMinorVersion() < TAG_MINOR_ARB_SPELL_SLOTS)
7322 ? NUM_MONSTER_SPELL_SLOTS :
7323 #endif
7324 unmarshallByte(th);
7325 spells.clear();
7326 spells.resize(spellsize);
7327 for (int j = 0; j < spellsize; ++j)
7328 {
7329 spells[j].spell = unmarshallSpellType(th
7330
7331 #if TAG_MAJOR_VERSION == 34
7332 , true
7333 #endif
7334 );
7335 #if TAG_MAJOR_VERSION == 34
7336 if (th.getMinorVersion() < TAG_MINOR_MALMUTATE
7337 && spells[j].spell == SPELL_POLYMORPH)
7338 {
7339 spells[j].spell = SPELL_MALMUTATE;
7340 }
7341
7342 if (spells[j].spell == SPELL_FAKE_RAKSHASA_SUMMON)
7343 spells[j].spell = SPELL_PHANTOM_MIRROR;
7344
7345 if (spells[j].spell == SPELL_SUNRAY)
7346 spells[j].spell = SPELL_STONE_ARROW;
7347
7348 if (th.getMinorVersion() >= TAG_MINOR_MONSTER_SPELL_SLOTS)
7349 {
7350 #endif
7351 spells[j].freq = unmarshallByte(th);
7352 spells[j].flags.flags = unmarshallShort(th);
7353 #if TAG_MAJOR_VERSION == 34
7354 if (th.getMinorVersion() < TAG_MINOR_DEMONIC_SPELLS)
7355 {
7356 if (spells[j].flags & MON_SPELL_VOCAL)
7357 {
7358 spells[j].flags &= ~MON_SPELL_VOCAL;
7359 spells[j].flags |= MON_SPELL_MAGICAL;
7360 }
7361 }
7362 }
7363 #endif
7364
7365 if (spell_removed(spells[j].spell))
7366 spells[j].spell = SPELL_NO_SPELL;
7367 }
7368
7369 int total_given_freq = 0;
7370 for (const auto &slot : spells)
7371 total_given_freq += slot.freq;
7372
7373 erase_if(spells, [](const mon_spell_slot &t) {
7374 return t.spell == SPELL_NO_SPELL;
7375 });
7376
7377 #if TAG_MAJOR_VERSION == 34
7378 // This will turn all old spells into wizard spells, which
7379 // isn't right but is the simplest way to do this.
7380 if (th.getMinorVersion() < TAG_MINOR_MONSTER_SPELL_SLOTS)
7381 {
7382 _fixup_spells(spells, hd);
7383 total_given_freq = spell_freq_for_hd(hd); // would be zero otherwise
7384 }
7385 #endif
7386
7387 normalize_spell_freq(spells, total_given_freq);
7388 }
7389
_marshallGhost(writer & th,const ghost_demon & ghost)7390 static void _marshallGhost(writer &th, const ghost_demon &ghost)
7391 {
7392 // save compat changes with minor tags here must be added to bones_minor_tags
7393 marshallString(th, ghost.name);
7394
7395 marshallShort(th, ghost.species);
7396 marshallShort(th, ghost.job);
7397 marshallByte(th, ghost.religion);
7398 marshallShort(th, ghost.best_skill);
7399 marshallShort(th, ghost.best_skill_level);
7400 marshallShort(th, ghost.xl);
7401 marshallShort(th, ghost.max_hp);
7402 marshallShort(th, ghost.ev);
7403 marshallShort(th, ghost.ac);
7404 marshallShort(th, ghost.damage);
7405 marshallShort(th, ghost.speed);
7406 marshallShort(th, ghost.move_energy);
7407 marshallByte(th, ghost.see_invis);
7408 marshallShort(th, ghost.brand);
7409 marshallShort(th, ghost.att_type);
7410 marshallShort(th, ghost.att_flav);
7411 marshallInt(th, ghost.resists);
7412 marshallByte(th, ghost.colour);
7413 marshallBoolean(th, ghost.flies);
7414
7415 _marshallSpells(th, ghost.spells);
7416 }
7417
_unmarshallGhost(reader & th)7418 static ghost_demon _unmarshallGhost(reader &th)
7419 {
7420 // save compat changes with minor tags here must be added to bones_minor_tags
7421 ghost_demon ghost;
7422
7423 ghost.name = unmarshallString(th);
7424 ghost.species = static_cast<species_type>(unmarshallShort(th));
7425 ghost.job = static_cast<job_type>(unmarshallShort(th));
7426 ghost.religion = static_cast<god_type>(unmarshallByte(th));
7427 ghost.best_skill = static_cast<skill_type>(unmarshallShort(th));
7428 ghost.best_skill_level = unmarshallShort(th);
7429 ghost.xl = unmarshallShort(th);
7430 ghost.max_hp = unmarshallShort(th);
7431 ghost.ev = unmarshallShort(th);
7432 ghost.ac = unmarshallShort(th);
7433 ghost.damage = unmarshallShort(th);
7434 ghost.speed = unmarshallShort(th);
7435 #if TAG_MAJOR_VERSION == 34
7436 if (th.getMinorVersion() < TAG_MINOR_GHOST_ENERGY)
7437 ghost.move_energy = 10;
7438 else
7439 #endif
7440 ghost.move_energy = unmarshallShort(th);
7441 // fix up ghost_demons that forgot to have move_energy initialized
7442 if (ghost.move_energy < FASTEST_PLAYER_MOVE_SPEED
7443 || ghost.move_energy > 15) // Ponderous naga
7444 {
7445 ghost.move_energy = 10;
7446 }
7447 ghost.see_invis = unmarshallByte(th);
7448 ghost.brand = static_cast<brand_type>(unmarshallShort(th));
7449 ghost.att_type = static_cast<attack_type>(unmarshallShort(th));
7450 ghost.att_flav = static_cast<attack_flavour>(unmarshallShort(th));
7451 ghost.resists = unmarshallInt(th);
7452 #if TAG_MAJOR_VERSION == 34
7453 if (ghost.resists & MR_OLD_RES_ACID)
7454 set_resist(ghost.resists, MR_RES_ACID, 3);
7455 if (th.getMinorVersion() < TAG_MINOR_NO_GHOST_SPELLCASTER)
7456 unmarshallByte(th);
7457 if (th.getMinorVersion() < TAG_MINOR_MON_COLOUR_LOOKUP)
7458 unmarshallByte(th);
7459 #endif
7460 ghost.colour = unmarshallByte(th);
7461
7462 #if TAG_MAJOR_VERSION == 34
7463 if (th.getMinorVersion() < TAG_MINOR_BOOL_FLIGHT)
7464 ghost.flies = unmarshallShort(th);
7465 else
7466 #endif
7467 ghost.flies = unmarshallBoolean(th);
7468
7469 unmarshallSpells(th, ghost.spells
7470 #if TAG_MAJOR_VERSION == 34
7471 , ghost.xl
7472 #endif
7473 );
7474
7475 #if TAG_MAJOR_VERSION == 34
7476 monster_spells oldspells = ghost.spells;
7477 ghost.spells.clear();
7478 for (mon_spell_slot &slot : oldspells)
7479 {
7480 if (th.getMinorVersion() < TAG_MINOR_GHOST_MAGIC)
7481 slot.spell = _fixup_positional_monster_spell(slot.spell);
7482 if (!spell_removed(slot.spell))
7483 ghost.spells.push_back(slot);
7484 }
7485 #endif
7486
7487 return ghost;
7488 }
7489
_tag_construct_ghost(writer & th,vector<ghost_demon> & ghosts)7490 static void _tag_construct_ghost(writer &th, vector<ghost_demon> &ghosts)
7491 {
7492 // How many ghosts?
7493 marshallShort(th, ghosts.size());
7494
7495 for (const ghost_demon &ghost : ghosts)
7496 _marshallGhost(th, ghost);
7497 }
7498
_tag_read_ghost(reader & th)7499 static vector<ghost_demon> _tag_read_ghost(reader &th)
7500 {
7501 vector<ghost_demon> result;
7502 int nghosts = unmarshallShort(th);
7503
7504 if (nghosts < 1 || nghosts > MAX_GHOSTS)
7505 {
7506 string error = "Bones file has an invalid ghost count (" +
7507 to_string(nghosts) + ")";
7508 throw corrupted_save(error);
7509 }
7510
7511 for (int i = 0; i < nghosts; ++i)
7512 result.push_back(_unmarshallGhost(th));
7513 return result;
7514 }
7515
tag_read_ghosts(reader & th)7516 vector<ghost_demon> tag_read_ghosts(reader &th)
7517 {
7518 global_ghosts.clear();
7519 tag_read(th, TAG_GHOST);
7520 return global_ghosts; // should use copy semantics?
7521 }
7522
tag_write_ghosts(writer & th,const vector<ghost_demon> & ghosts)7523 void tag_write_ghosts(writer &th, const vector<ghost_demon> &ghosts)
7524 {
7525 global_ghosts = ghosts;
7526 tag_write(TAG_GHOST, th);
7527 }
7528