1 #pragma once
2 
3 #include <set>
4 
5 #include "macros.h"
6 
7 // Character info has its own top-level tag, mismatching majors don't break
8 // compatibility there.
9 // DO NOT BUMP THIS UNLESS YOU KNOW WHAT YOU'RE DOING. This would break
10 // the save browser across versions, possibly leading to overwritten games.
11 // It's only there in case there's no way out.
12 #define TAG_CHR_FORMAT 0
13 COMPILE_CHECK(TAG_CHR_FORMAT < 256);
14 
15 // Let CDO updaters know if the syntax changes.
16 // Really, really, REALLY _never_ ever bump this and clean up old #ifdefs
17 // in a single commit, please. Making clean-up and actual code changes,
18 // especially of this size, separated is vital for sanity.
19 #ifndef TAG_MAJOR_VERSION
20 #define TAG_MAJOR_VERSION 34
21 #endif
22 COMPILE_CHECK(TAG_MAJOR_VERSION < 256);
23 
24 // Minor version will be reset to zero when major version changes.
25 enum tag_minor_version
26 {
27     TAG_MINOR_INVALID         = -1,
28     TAG_MINOR_RESET           = 0, // Minor tags were reset
29 #if TAG_MAJOR_VERSION == 34
30     TAG_MINOR_BRANCHES_LEFT,       // Note the first time branches are left
31     TAG_MINOR_VAULT_LIST,          // Don't try to store you.vault_list as prop
32     TAG_MINOR_TRAPS_DETERM,        // Searching for traps is deterministic.
33     TAG_MINOR_ACTION_THROW,        // Store base type of throw objects.
34     TAG_MINOR_TEMP_MUTATIONS,      // Enable transient mutations
35     TAG_MINOR_AUTOINSCRIPTIONS,    // Artefact inscriptions are added on the fly
36     TAG_MINOR_UNCANCELLABLES,      // Restart uncancellable questions upon save load
37     TAG_MINOR_DEEP_ABYSS,          // Multi-level abyss
38     TAG_MINOR_COORD_SERIALIZER,    // Serialize coord_def as int
39     TAG_MINOR_REMOVE_ABYSS_SEED,   // Remove the abyss seed.
40     TAG_MINOR_REIFY_SUBVAULTS,     // Save subvaults with level for attribution
41     TAG_MINOR_VEHUMET_SPELL_GIFT,  // Vehumet gift spells instead of books
42     TAG_MINOR_LUA_DUMMY_0,         // dummy to unbreak util/gen-luatags.pl
43     TAG_MINOR_LUA_DUMMY_1,         // dummy to unbreak util/gen-luatags.pl
44     TAG_MINOR_LUA_DUMMY_2,         // dummy to unbreak util/gen-luatags.pl
45     TAG_MINOR_LUA_DUMMY_3,         // dummy to unbreak util/gen-luatags.pl
46     TAG_MINOR_0_11,                 // 0.11 final saves
47     TAG_MINOR_0_12,                // (no change)
48     TAG_MINOR_BATTLESPHERE_MID,    // Monster battlesphere (mid of creator)
49     TAG_MINOR_MALMUTATE,           // Convert Polymorph to Malmutate on old monsters
50     TAG_MINOR_VEHUMET_MULTI_GIFTS, // Vehumet can offer multiple spells at once
51     TAG_MINOR_ADD_ABYSS_SEED,      // Reinstate abyss seed. Mistakes were made.
52     TAG_MINOR_COMPANION_LIST,      // Added companion list
53     TAG_MINOR_INCREMENTAL_RECALL,  // Made recall incremental
54     TAG_MINOR_GOD_GIFT,            // Remove {god gift} from inscriptions.
55     TAG_MINOR_NOME_NO_MORE,        // Remove unused gnome variable.
56     TAG_MINOR_NO_SPLINT,           // Remove splint mail
57     TAG_MINOR_ORIG_MONNUM,         // orig_monnum is type rather than type+1.
58     TAG_MINOR_SPRINT_SCORES,       // Separate score lists for each sprint map
59     TAG_MINOR_FOOD_AUTOPICKUP,     // Separate meat, fruit, others in \ menu.
60     TAG_MINOR_LORC_TEMPERATURE,    // Save lava orc temperature
61     TAG_MINOR_GARGOYLE_DR,         // Gargoyle damage reduction
62     TAG_MINOR_TRAVEL_ALLY_PACE,    // Pace travel to slowest ally setting
63     TAG_MINOR_AUTOMATIC_MANUALS,   // Manuals are now always studied
64     TAG_MINOR_RM_GARGOYLE_DR,      // Gargoyle DR is redundant.
65     TAG_MINOR_STAT_ZERO,           // Stat zero doesn't cause death.
66     TAG_MINOR_BOX_OF_BEASTS_CHARGES, // Box of Beasts counts its charges.
67     TAG_MINOR_WAR_DOG_REMOVAL,     // War dogs become wolves, then disappear
68     TAG_MINOR_CANARIES,            // Canaries in save files.
69     TAG_MINOR_CHIMERA_GHOST_DEMON, // Use ghost demon
70     TAG_MINOR_MONSTER_PARTS,       // Flag the presence of ghost_demon (and more)
71     TAG_MINOR_OPTIONAL_PARTS,      // Make three big monster structs optional.
72     TAG_MINOR_SHORT_SPELL_TYPE,    // Spell types changed to short instead of byte
73     TAG_MINOR_FORGOTTEN_MAP,       // X^F can be undone.
74     TAG_MINOR_CONTAM_SCALE,        // Scale the magic contamination by a factor of 1000
75     TAG_MINOR_SUMMONER,            // Store summoner data.
76     TAG_MINOR_STAT_MUT,            // Flag for converting stat mutations
77     TAG_MINOR_MAP_ORDER,           // map_def::order added to des cache
78     TAG_MINOR_FIXED_CONSTRICTION,  // Corrected a constricting marshalling bug.
79     TAG_MINOR_SEEDS,               // Per-game seeds for deterministic stuff.
80     TAG_MINOR_ABYSS_BRANCHES,      // Spawn abyss monsters from other branches.
81     TAG_MINOR_BRANCH_ENTRY,        // Store branch entry point (rather than just depth).
82     TAG_MINOR_16_BIT_TABLE,        // Increase the limit for CrawlVector/HashTable to 65535.
83     TAG_MINOR_ABIL_1000,           // Start god ability enums at 1000.
84     TAG_MINOR_CLASS_HP_0,          // Base class maxhp at 0.
85     TAG_MINOR_NOISES,              // Save incompat recovery wrt ATTR_NOISES.
86     TAG_MINOR_ABIL_GOD_FIXUP,      // Movement of some non-god-specific abils.
87     TAG_MINOR_NEMELEX_DUNGEONS,    // Make nemelex not give/track decks of dungeons.
88     TAG_MINOR_DEMONSPAWN,          // Save compat wrt demonspawn enemies.
89     TAG_MINOR_EVENT_TIMERS,        // "Every 20 turn" effects are less determinstic.
90     TAG_MINOR_EVENT_TIMER_FIX,     // Correct event timers in transferred games
91     TAG_MINOR_MONINFO_ENERGY,      // Energy usage in monster_info
92     TAG_MINOR_BOOK_ID,             // Track spellbooks you've identified
93     TAG_MINOR_MISC_SHOP_CHANGE,    // Wand and gadget shops merged
94     TAG_MINOR_HORN_GERYON_CHANGE,  // Horn of geryon changed to an xp-evoker
95     TAG_MINOR_NEMELEX_WEIGHTS,     // Nemelex deck weighting removed
96     TAG_MINOR_UNSEEN_MONSTER,      // Invis indicators for monsters going from seen to unseen
97     TAG_MINOR_MR_ITEM_RESCALE,     // Rescaled MR property on items.
98     TAG_MINOR_MANGROVES,           // Turn all mangroves into trees.
99     TAG_MINOR_FIX_FEAT_SHIFT,      // Fix feature shifts from the last tag.
100     TAG_MINOR_FUNGUS_FORM,         // Removed confusing touch duration from fungus form.
101     TAG_MINOR_STEALTH_RESCALE,     // Item properties: rescaled Stealth, removed Hunger.
102     TAG_MINOR_ATTACK_DESCS,        // Added attacks to monster_info.
103     TAG_MINOR_BRIBE_BRANCH,        // Bribe branch tracking
104     TAG_MINOR_CLOUD_OWNER,         // Track owners of clouds in map knowledge
105     TAG_MINOR_NO_POTION_HEAL,      // Made MUT_NO_POTION_HEAL a normal bad mutation.
106     TAG_MINOR_DIET_MUT,            // Remove carnivore/herbivore muts from random generation.
107     TAG_MINOR_SAGE_REMOVAL,        // Removed the Sage card and status.
108     TAG_MINOR_CALC_UNRAND_REACTS,  // Compute you.unrand_reacts on load
109     TAG_MINOR_SAPROVOROUS,         // Remove Saprovorous from several species
110     TAG_MINOR_CE_HA_DIET,          // Remove intrinsic diet muts from Ce & Ha
111     TAG_MINOR_NO_POT_FOOD,         // Remove Royal Jellies & Ambrosia
112     TAG_MINOR_ROT_IMMUNITY,        // Make rot immunity an intrinsic mutation.
113     TAG_MINOR_FOUL_STENCH,         // Remove Saprovore from the Foul Stench DS Facet
114     TAG_MINOR_FOOD_PURGE,          // Cleaning up old types of food.
115     TAG_MINOR_FOOD_PURGE_AP_FIX,   // Correctly carry over old fruit autopickup.
116     TAG_MINOR_WEIGHTLESS,          // Removal of player burden.
117     TAG_MINOR_DS_CLOUD_MUTATIONS,  // Change Ds conservation muts to cloud immunities.
118     TAG_MINOR_FRIENDLY_PICKUP,     // Remove the friendly_pickup setting.
119     TAG_MINOR_STICKY_FLAME,        // Change the name of you.props "napalmer" & "napalm_aux"
120     TAG_MINOR_SLAYRING_PLUSES,     // Combine Acc/Dam on rings of slaying and artefacts.
121     TAG_MINOR_MERGE_EW,            // Combine enchant weapons scrolls.
122     TAG_MINOR_WEAPON_PLUSES,       // Combine to-hit/to-dam enchantment on weapons.
123     TAG_MINOR_SAVE_TERRAIN_COLOUR, // Save colour in terrain-change markers.
124     TAG_MINOR_REMOVE_BASE_MP,      // Remove base MP bonus.
125     TAG_MINOR_METABOLISM,          // Remove random fast/slow meta mutations
126     TAG_MINOR_RU_SACRIFICES,       // Store Ru sacrifices in an array for coloration
127     TAG_MINOR_IS_UNDEAD,           // Remove the old "is_undead" player field
128     TAG_MINOR_REMOVE_MON_AC_EV,    // Remove the old "ac" & "ev" monster fields
129     TAG_MINOR_DISPLAY_MON_AC_EV,   // Marshall & unmarshall ac/ev in monster_info
130     TAG_MINOR_PLACE_UNPACK,        // Some packed places are level_ids.
131     TAG_MINOR_NO_JUMP,             // Removal of jump-attack.
132     TAG_MINOR_MONSTER_SPELL_SLOTS, // Introduce monster spell slot flags/freqs
133     TAG_MINOR_ARB_SPELL_SLOTS,     // Arbitrary number of monster spell slots.
134     TAG_MINOR_CUT_CUTLASSES,       // Turn crummy cutlasses into real rapiers.
135     TAG_MINOR_NO_GHOST_SPELLCASTER,// Remove an unused field in ghost_demon
136     TAG_MINOR_MID_BEHOLDERS,       // you.beholders and fearmongers store mids
137     TAG_MINOR_REMOVE_ITEM_COLOUR,  // don't store item colour as state
138     TAG_MINOR_CORPSE_CRASH,        // don't crash when loading corpses
139     TAG_MINOR_INIT_RND,            // initialize rnd in more places
140     TAG_MINOR_RING_PLUSSES,        // don't generate +144 rings
141     TAG_MINOR_BLESSED_WPNS,        // Remove blessed long blade base types
142     TAG_MINOR_MON_COLOUR_LOOKUP,   // monster colour lookup when possible
143     TAG_MINOR_CONSUM_APPEARANCE,   // Stop storing item appearance in .plus
144     TAG_MINOR_NEG_IDESC,           // Fix a sign conversion error
145     TAG_MINOR_GHOST_ENERGY,        // ghost_demon has move_energy field
146     TAG_MINOR_TENTACLE_MID,        // Use mids for tentacle code
147     TAG_MINOR_CORPSE_COLOUR,       // Fix corpses with invalid colour.
148     TAG_MINOR_MANGLE_CORPSES,      // Turn NEVER_HIDE corpses into MANGLED_CORPSEs
149     TAG_MINOR_ZOT_OPEN,            // Don't store whether you opened Zot
150     TAG_MINOR_EXPLORE_MODE,        // Store whether you are in explore mode
151     TAG_MINOR_RANDLICHES,          // Liches are now GHOST_DEMONs
152     TAG_MINOR_ISFLAG_HANDLED,      // Game tracks which items player has handled
153     TAG_MINOR_SHOP_HACK,           // The shop hack is dead!
154     TAG_MINOR_STACKABLE_EVOKERS,   // XP evokers stack
155     TAG_MINOR_REALLY_16_BIT_VEC,   // CrawlVector size really saved as 16-bit
156     TAG_MINOR_FIX_8_BIT_VEC_MAX,   // Fix up bad CrawlVector max size
157     TAG_MINOR_TRACK_BANISHER,      // Persist the name of the last thing that banished the player
158     TAG_MINOR_SHOALS_LITE,         // Remove deep water from old Shoals
159     TAG_MINOR_FIX_EXPLORE_MODE,    // Fix char selection screen on old versions
160     TAG_MINOR_UNSTACKABLE_EVOKERS, // XP evokers no longer stack
161     TAG_MINOR_NO_NEGATIVE_VULN,    // Remove negative energy vulnerability
162     TAG_MINOR_MAX_XL,              // Store max XL instead of hardcoding it
163     TAG_MINOR_NO_RPOIS_MINUS,      // Remove rPois- artefacts
164     TAG_MINOR_XP_PENANCE,          // Let gods other than Ash use xp penance
165     TAG_MINOR_SPIT_POISON,         // Give Nagas MUT_SPIT_POISON
166     TAG_MINOR_REAL_MUTS,           // Give some species proper mutations
167     TAG_MINOR_NO_FORLORN,          // Remove Forlorn mutation
168     TAG_MINOR_MP_WANDS,            // Make MP wands a single-level mutation
169     TAG_MINOR_TELEPORTITIS,        // Rescale teleportitis on artefacts
170     TAG_MINOR_ROTTING,             // Remove rot-over-time
171     TAG_MINOR_STAT_ZERO_DURATION,  // Stat zero uses a duration
172     TAG_MINOR_INT_REGEN,           // hp/mp regen are ints
173     TAG_MINOR_NAGA_METABOLISM,     // nagas have slow metabolism
174     TAG_MINOR_BOOL_FLIGHT,         // flight is just a bool
175     TAG_MINOR_STAT_LOSS_XP,        // Stat loss recovers with XP
176     TAG_MINOR_DETERIORATION,       // 2-level deterioration mutation
177     TAG_MINOR_RU_DELAY_STACKING,   // Let Ru delay timers stack again
178     TAG_MINOR_NO_TWISTER,          // Remove ARTP_TWISTER
179     TAG_MINOR_NO_ZOTDEF,           // remove zotdef, along with zot_points and zotdef_wave_name
180     TAG_MINOR_SAVED_PIETY,         // allowed good-god piety to survive through an atheist period
181     TAG_MINOR_GHOST_SINV,          // marshall ghost_demon sinv
182     TAG_MINOR_ID_STATES,           // turn item_type_id_state_type into a bool
183     TAG_MINOR_MON_HD_INFO,         // store player-known monster HD info
184     TAG_MINOR_NO_LEVEL_FLAGS,      // remove a field of env
185     TAG_MINOR_EXORCISE,            // liches, a. liches, & spellforged servitors are no longer ghost_demons
186     TAG_MINOR_BLINK_MUT,           // 1-level blink mutation
187     TAG_MINOR_RUNE_TYPE,           // runes became a base type
188     TAG_MINOR_ZIGFIGS,             // let characters from before ziggurat changes continue zigging
189     TAG_MINOR_RU_PIETY_CONSISTENCY,// make Ru piety constant once determined.
190     TAG_MINOR_SAC_PIETY_LEN,       // marshall length with sacrifice piety
191     TAG_MINOR_MULTI_HOLI,          // Turn monster holiness into a bitfield.
192     TAG_MINOR_SHOPINFO,            // ShopInfo has a real shop
193     TAG_MINOR_UNSHOPINFO,          // Fixup after revert of previous
194     TAG_MINOR_UNUNSHOPINFO,        // Restoration of the tag two before
195     TAG_MINOR_MESSAGE_REPEATS,     // Rewrite the way message repeats work
196     TAG_MINOR_GHOST_NOSINV,        // don't marshall ghost_demon sinv
197     TAG_MINOR_NO_DRACO_TYPE,       // don't marshall mon-info draco_type
198     TAG_MINOR_DEMONIC_SPELLS,      // merge demonic spells into magical spells
199     TAG_MINOR_MUMMY_RESTORATION,   // remove mummy self-restoration ability
200     TAG_MINOR_DECUSTOM_CLOUDS,     // remove support for custom clouds
201     TAG_MINOR_PAKELLAS_WRATH,      // fix Pakellas passive wrath not expiring
202     TAG_MINOR_GLOBAL_BR_INFO,      // move global branch info to a reserved location
203     TAG_MINOR_SPIT_POISON_AGAIN,   // Make Naga poison spit a 2-level mutation.
204     TAG_MINOR_HIDE_TO_SCALE,       // Rename dragon hides to scales.
205     TAG_MINOR_NO_PRIORITY,         // Remove CHANCE priority in map definitions.
206     TAG_MINOR_MOTTLED_REMOVAL,     // Mottled dracos get breathe fire
207     TAG_MINOR_NEMELEX_WRATH,       // Nemelex loses the passive wrath component
208     TAG_MINOR_SLIME_WALL_CLEAR,    // Turn existing Slime:$ walls clear, so they'll be removed on TRJ death.
209     TAG_MINOR_FOOD_PURGE_RELOADED, // The exciting sequel, removing pizza/jerky.
210     TAG_MINOR_ELYVILON_WRATH,      // Make Elyvilon wrath expire with XP gain.
211     TAG_MINOR_DESOLATION_GLOBAL,   // Recover from saves where desolation is incorrectly marked as global
212     TAG_MINOR_NO_MORE_LORC,        // Don't save lava orc temperature (or anything else). LO/Dj removal.
213     TAG_MINOR_NO_ITEM_TRANSIT,     // Remove code to transit items across levels.
214     TAG_MINOR_TOMB_HATCHES,        // Use fixed-destination hatches in Tomb.
215     TAG_MINOR_TRANSPORTERS,        // Transporters and position marker changes.
216     TAG_MINOR_SPIT_POISON_AGAIN_AGAIN, // save compat issues for TAG_MINOR_SPIT_POISON_AGAIN.
217     TAG_MINOR_TRANSPORTER_LANDING, // Transporters landing site features.
218     TAG_MINOR_STATLOCKED_GNOLLS,   // Gnolls have stats locked at 7/7/7.
219     TAG_MINOR_LIGHTNING_ROD_XP_FIX, // Set XP debt for partially used l. rods.
220     TAG_MINOR_LEVEL_XP_INFO,       // Track XP gain by level.
221     TAG_MINOR_LEVEL_XP_INFO_FIX,   // Fix orb spawn XP tracking.
222     TAG_MINOR_FOLLOWER_TRANSIT_TIME, // Handle updating lost_ones after placing.
223     TAG_MINOR_GNOLLS_REDUX,        // Handle Gnolls that always train all skills and no stat lock.
224     TAG_MINOR_TRAINING_TARGETS,    // training targets for skills
225     TAG_MINOR_XP_SCALING,          // scale exp_available and total_experience
226     TAG_MINOR_NO_ACTOR_HELD,       // Remove actor.held.
227     TAG_MINOR_GOLDIFY_BOOKS,       // Spellbooks disintegrate when picked up, like gold/runes/orbs
228     TAG_MINOR_VETO_DISINT,         // Replace veto_disintegrate map markers
229     TAG_MINOR_LEVEL_XP_VAULTS,     // XP tracking now tracks vaults, not spawns.
230     TAG_MINOR_REVEAL_TRAPS,        // All traps generate known
231     TAG_MINOR_GAUNTLET_TRAPPED,    // It was briefly possible to get trapped in a specific gauntlet map.
232     TAG_MINOR_REMOVE_DECKS,        // Decks are no more
233     TAG_MINOR_GAMESEEDS,           // Game seeds + rng state saved
234     TAG_MINOR_YELLOW_DRACONIAN_RACID, // Change yellow draconians' rAcid fake mutation to a true mutation.
235     TAG_MINOR_THROW_CONSOLIDATION, // Throwing brands consolidated
236     TAG_MINOR_VAMPIRE_NO_EAT,      // Decouple Vampires from the food system
237     TAG_MINOR_SINGULAR_THEY,       // Add singular they pronouns
238     TAG_MINOR_ABYSS_UNIQUE_VAULTS, // Separate abyss vault tracking from main dungeon
239     TAG_MINOR_INCREMENTAL_PREGEN,  // save tracks whether the game is an incremental pregen game
240     TAG_MINOR_NO_SUNLIGHT,         // Removal of Fedhas' Sunlight
241     TAG_MINOR_POSITIONAL_MAGIC,    // Positional attack magic overhaul
242     TAG_MINOR_GHOST_MAGIC,         // Ghost update for positional magic
243     TAG_MINOR_MORE_GHOST_MAGIC,    // Update already placed ghosts for positional magic
244     TAG_MINOR_DUMMY_AGILITY,       // Convert garbage "agility" potions into stab
245     TAG_MINOR_TRACK_REGEN_ITEMS,   // Regen items take effect only after maxhp is reached
246     TAG_MINOR_MORGUE_SCREENSHOTS,  // Screenshots morgue section
247     TAG_MINOR_UNSTACK_TREMORSTONES, // Unstack tins of tremorstones
248     TAG_MINOR_MONSTER_TYPE_SIZE,   // Consistently marshall monster_type enums
249     TAG_MINOR_SHAFT_CARD,          // Remove the Shaft card
250     TAG_MINOR_LOAF_BUST,           // Remove rations, eating, and hunger mechanics
251     TAG_MINOR_REVEALED_TRAPS,      // No skill check to spot traps
252     TAG_MINOR_BARDING_MERGE,       // Merge naga and centaur bardings.
253     TAG_MINOR_MERGE_VETOES,        // Merge veto tags in vaults
254     TAG_MINOR_APPENDAGE,           // Change beastly appendage
255     TAG_MINOR_REALLY_UNSTACK_EVOKERS, // Unstack all evokers
256     TAG_MINOR_SETPOLY,             // Despoiler polymorph wands
257     TAG_MINOR_GOLDIFY_MANUALS,     // Move manuals out of the inventory
258     TAG_MINOR_UNCURSE,             // Remove curses from items
259     TAG_MINOR_NEW_ASHENZARI,       // New Ashenzari
260     TAG_MINOR_COMPRESS_BADMUTS,    // Reduce some mutations to 2 levels
261     TAG_MINOR_NEW_TREES,           // New tree types
262     TAG_MINOR_DISEASE,             // Turn disease into a normal duration
263     TAG_MINOR_BOOK_UNID,           // Remove book ID.
264 #endif
265     NUM_TAG_MINORS,
266     TAG_MINOR_VERSION = NUM_TAG_MINORS - 1
267 };
268 
269 // tags that affect loading bones files. If you do save compat that affects
270 // ghosts, these must be updated in addition to the enum above.
271 const set<int> bones_minor_tags =
272         {TAG_MINOR_RESET,
273 #if TAG_MAJOR_VERSION == 34
274          TAG_MINOR_NO_GHOST_SPELLCASTER,
275          TAG_MINOR_MON_COLOUR_LOOKUP,
276          TAG_MINOR_GHOST_ENERGY,
277          TAG_MINOR_BOOL_FLIGHT,
278          TAG_MINOR_POSITIONAL_MAGIC,
279          TAG_MINOR_GHOST_MAGIC,
280 #endif
281         };
282 
283 struct save_version
284 {
save_versionsave_version285     save_version(int _major, int _minor) : major{_major}, minor{_minor}
286     {
287     }
288 
save_versionsave_version289     save_version() : save_version(-1,-1)
290     {
291     }
292 
currentsave_version293     static save_version current()
294     {
295         return save_version(TAG_MAJOR_VERSION, TAG_MINOR_VERSION);
296     }
297 
current_bonessave_version298     static save_version current_bones()
299     {
300         return save_version(TAG_MAJOR_VERSION, *bones_minor_tags.crbegin());
301     }
302 
minimum_supportedsave_version303     static save_version minimum_supported()
304     {
305 #if TAG_MAJOR_VERSION == 34
306         return save_version(33, 17);
307 #else
308         return save_version(TAG_MAJOR_VERSION, 0);
309 #endif
310     }
311 
validsave_version312     bool valid() const
313     {
314         return major > 0 && minor > -1;
315     }
316 
317     inline friend bool operator==(const save_version& lhs,
318                                                     const save_version& rhs)
319     {
320         return lhs.major == rhs.major && lhs.minor == rhs.minor;
321     }
322 
323     inline friend bool operator!=(const save_version& lhs,
324                                                     const save_version& rhs)
325     {
326         return !operator==(lhs, rhs);
327     }
328 
329     inline friend bool operator< (const save_version& lhs,
330                                                     const save_version& rhs)
331     {
332         return lhs.major < rhs.major || lhs.major == rhs.major &&
333                                                     lhs.minor < rhs.minor;
334     }
335     inline friend bool operator> (const save_version& lhs,
336                                                     const save_version& rhs)
337     {
338         return  operator< (rhs, lhs);
339     }
340     inline friend bool operator<=(const save_version& lhs,
341                                                     const save_version& rhs)
342     {
343         return !operator> (lhs, rhs);
344     }
345     inline friend bool operator>=(const save_version& lhs,
346                                                     const save_version& rhs)
347     {
348         return !operator< (lhs,rhs);
349     }
350 
351 
is_futuresave_version352     bool is_future() const
353     {
354         return valid() && *this > save_version::current();
355     }
356 
is_pastsave_version357     bool is_past() const
358     {
359         return valid() && *this < save_version::current();
360     }
361 
is_ancientsave_version362     bool is_ancient() const
363     {
364         return valid() && *this < minimum_supported();
365     }
366 
is_compatiblesave_version367     bool is_compatible() const
368     {
369         return valid() && !is_ancient() && !is_future();
370     }
371 
is_currentsave_version372     bool is_current() const
373     {
374         return valid() && *this == save_version::current();
375     }
376 
is_bones_versionsave_version377     bool is_bones_version() const
378     {
379         return valid() && is_compatible() && bones_minor_tags.count(minor) > 0;
380     }
381 
382     int major;
383     int minor;
384 };
385