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