diff options
author | peterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573> | 2005-07-21 02:34:44 +0000 |
---|---|---|
committer | peterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573> | 2005-07-21 02:34:44 +0000 |
commit | 673bdae75485d14f759af597c3c62b99601f9a43 (patch) | |
tree | 368103f29fe0ce5dcf98060d9b5faa04590085fb /trunk/source/tags.cc | |
parent | 7e900be770db24b0405fd2162491c405a425873e (diff) | |
download | crawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.tar.gz crawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.zip |
Initial revision
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'trunk/source/tags.cc')
-rw-r--r-- | trunk/source/tags.cc | 1831 |
1 files changed, 1831 insertions, 0 deletions
diff --git a/trunk/source/tags.cc b/trunk/source/tags.cc new file mode 100644 index 0000000000..f4babe75e5 --- /dev/null +++ b/trunk/source/tags.cc @@ -0,0 +1,1831 @@ +/* + * File: tags.cc + * Summary: Auxilary functions to make savefile versioning simpler. + * Written by: Gordon Lipford + * + * Change History (most recent first): + * + * <2> 16 Mar 2001 GDL Added TAG_LEVEL_ATTITUDE + * <1> 27 Jan 2001 GDL Created + */ + +/* ------------------------- how tags work ---------------------------------- + +1. Tag types are enumerated in enum.h, from TAG_VERSION (more a placeholder + than anything else, it is not actually saved as a tag) to TAG_XXX. NUM_TAGS + is equal to the actual number of defined tags. + +2. Tags are created with tag_construct(), which forwards the construction + request appropriately. tag_write() is then used to write the tag to an + output stream. + +3. Tags are parsed with tag_read(), which tries to read a tag header and then + forwards the request appropriately, returning the ID of the tag it found, + or zero if no tag was found. + +4. In order to know which tags are used by a particular file type, a client + calls tag_set_expected( fileType ), which sets up an array of chars. + Within the array, a value of 1 means the tag is expected; -1 means that + the tag is not expected. A client can then set values in this array to + anything other than 1 to indicate a successful tag_read() of that tag. + +5. A case should be provided in tag_missing() for any tag which might be + missing from a tagged save file. For example, if a developer adds + TAG_YOU_NEW_STUFF to the player save file, he would have to provide a + case in tag_missing() for this tag since it might not be there in + earlier savefiles. The tags defined with the original tag system (and + so not needing cases in tag_missing()) are as follows: + + TAG_YOU = 1, // 'you' structure + TAG_YOU_ITEMS, // your items + TAG_YOU_DUNGEON, // dungeon specs (stairs, branches, features) + TAG_LEVEL, // various grids & clouds + TAG_LEVEL_ITEMS, // items/traps + TAG_LEVEL_MONSTERS, // monsters + TAG_GHOST, // ghost + +6. The marshalling and unmarshalling of data is done in network order and + is meant to keep savefiles cross-platform. They are non-ascii - always + FTP in binary mode. Note also that the marshalling sizes are 1,2, and 4 + for byte, short, and long - assuming that 'int' would have been + insufficient on 16 bit systems (and that Crawl otherwise lacks + system-indepedent data types). + +*/ + +#include <stdio.h> +#include <string.h> // for memcpy + +#ifdef LINUX +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#endif + +#ifdef USE_EMX +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#endif + +#ifdef OS9 +#include <stat.h> +#else +#include <sys/stat.h> +#endif + +#include "AppHdr.h" + +#include "abl-show.h" +#include "enum.h" +#include "externs.h" +#include "files.h" +#include "itemname.h" +#include "monstuff.h" +#include "mon-util.h" +#include "randart.h" +#include "skills.h" +#include "skills2.h" +#include "stuff.h" +#include "tags.h" + +// THE BIG IMPORTANT TAG CONSTRUCTION/PARSE BUFFER +static char *tagBuffer = NULL; + +// These three are defined in overmap.cc +extern FixedArray < unsigned char, MAX_LEVELS, MAX_BRANCHES > altars_present; +extern FixedVector < char, MAX_BRANCHES > stair_level; +extern FixedArray < unsigned char, MAX_LEVELS, MAX_BRANCHES > feature; + +extern unsigned char your_sign; /* these two are defined in view.cc */ +extern unsigned char your_colour; + +// temp file pairs used for file level cleanup +FixedArray < bool, MAX_LEVELS, MAX_BRANCHES > tmp_file_pairs; + + +// static helpers +static void tag_construct_you(struct tagHeader &th); +static void tag_construct_you_items(struct tagHeader &th); +static void tag_construct_you_dungeon(struct tagHeader &th); +static void tag_read_you(struct tagHeader &th, char minorVersion); +static void tag_read_you_items(struct tagHeader &th, char minorVersion); +static void tag_read_you_dungeon(struct tagHeader &th); + +static void tag_construct_level(struct tagHeader &th); +static void tag_construct_level_items(struct tagHeader &th); +static void tag_construct_level_monsters(struct tagHeader &th); +static void tag_construct_level_attitude(struct tagHeader &th); +static void tag_read_level(struct tagHeader &th, char minorVersion); +static void tag_read_level_items(struct tagHeader &th, char minorVersion); +static void tag_read_level_monsters(struct tagHeader &th, char minorVersion); +static void tag_read_level_attitude(struct tagHeader &th); +static void tag_missing_level_attitude(); + +static void tag_construct_ghost(struct tagHeader &th); +static void tag_read_ghost(struct tagHeader &th, char minorVersion); + +// provide a wrapper for file writing, just in case. +int write2(FILE * file, char *buffer, unsigned int count) +{ + return fwrite(buffer, 1, count, file); +} + +// provide a wrapper for file reading, just in case. +int read2(FILE * file, char *buffer, unsigned int count) +{ + return fread(buffer, 1, count, file); +} + +void marshallByte(struct tagHeader &th, char data) +{ + tagBuffer[th.offset] = data; + th.offset += 1; +} + +char unmarshallByte(struct tagHeader &th) +{ + char data = tagBuffer[th.offset]; + th.offset += 1; + return data; +} + +// marshall 2 byte short in network order +void marshallShort(struct tagHeader &th, short data) +{ + char b2 = (char)(data & 0x00FF); + char b1 = (char)((data & 0xFF00) >> 8); + + tagBuffer[th.offset] = b1; + tagBuffer[th.offset + 1] = b2; + + th.offset += 2; +} + +// unmarshall 2 byte short in network order +short unmarshallShort(struct tagHeader &th) +{ + short b1 = tagBuffer[th.offset]; + short b2 = tagBuffer[th.offset + 1]; + + short data = (b1 << 8) | (b2 & 0x00FF); + + th.offset += 2; + return data; +} + +// marshall 4 byte int in network order +void marshallLong(struct tagHeader &th, long data) +{ + char b4 = (char) (data & 0x000000FF); + char b3 = (char)((data & 0x0000FF00) >> 8); + char b2 = (char)((data & 0x00FF0000) >> 16); + char b1 = (char)((data & 0xFF000000) >> 24); + + tagBuffer[th.offset] = b1; + tagBuffer[th.offset + 1] = b2; + tagBuffer[th.offset + 2] = b3; + tagBuffer[th.offset + 3] = b4; + + th.offset += 4; +} + +// unmarshall 4 byte int in network order +long unmarshallLong(struct tagHeader &th) +{ + long b1 = tagBuffer[th.offset]; + long b2 = tagBuffer[th.offset + 1]; + long b3 = tagBuffer[th.offset + 2]; + long b4 = tagBuffer[th.offset + 3]; + + long data = (b1 << 24) | ((b2 & 0x000000FF) << 16); + data |= ((b3 & 0x000000FF) << 8) | (b4 & 0x000000FF); + + th.offset += 4; + return data; +} + +// single precision float -- marshall in network order. +void marshallFloat(struct tagHeader &th, float data) +{ + long intBits = *((long *)(&data)); + marshallLong(th, intBits); +} + +// single precision float -- unmarshall in network order. +float unmarshallFloat(struct tagHeader &th) +{ + long intBits = unmarshallLong(th); + + return *((float *)(&intBits)); +} + +// string -- marshall length & string data +void marshallString(struct tagHeader &th, char *data, int maxSize) +{ + // allow for very long strings. + short len = strlen(data); + if (maxSize > 0 && len > maxSize) + len = maxSize; + marshallShort(th, len); + + // put in the actual string -- we'll null terminate on + // unmarshall. + memcpy(&tagBuffer[th.offset], data, len); + + th.offset += len; +} + +// string -- unmarshall length & string data +void unmarshallString(struct tagHeader &th, char *data, int maxSize) +{ + // get length + short len = unmarshallShort(th); + int copylen = len; + if (len > maxSize && maxSize > 0) + copylen = maxSize; + + // read the actual string and null terminate + memcpy(data, &tagBuffer[th.offset], copylen); + data[copylen] = '\0'; + + th.offset += len; +} + +// boolean (to avoid system-dependant bool implementations) +void marshallBoolean(struct tagHeader &th, bool data) +{ + char charRep = 0; // for false + if (data) + charRep = 1; + + tagBuffer[th.offset] = charRep; + th.offset += 1; +} + +// boolean (to avoid system-dependant bool implementations) +bool unmarshallBoolean(struct tagHeader &th) +{ + bool data; + + if (tagBuffer[th.offset] == 1) + data = true; + else + data = false; + + th.offset += 1; + return data; +} + +// Saving the date as a string so we're not reliant on a particular epoch. +void make_date_string( time_t in_date, char buff[20] ) +{ + if (in_date <= 0) + { + buff[0] = '\0'; + return; + } + + + struct tm *date = localtime( &in_date ); + + snprintf( buff, 20, + "%4d%02d%02d%02d%02d%02d%s", + date->tm_year + 1900, date->tm_mon, date->tm_mday, + date->tm_hour, date->tm_min, date->tm_sec, + ((date->tm_isdst > 0) ? "D" : "S") ); +} + +static int get_val_from_string( const char *ptr, int len ) +{ + int ret = 0; + int pow = 1; + + for (const char *chr = ptr + len - 1; chr >= ptr; chr--) + { + ret += (*chr - '0') * pow; + pow *= 10; + } + + return (ret); +} + +time_t parse_date_string( char buff[20] ) +{ + struct tm date; + + date.tm_year = get_val_from_string( &buff[0], 4 ) - 1900; + date.tm_mon = get_val_from_string( &buff[4], 2 ); + date.tm_mday = get_val_from_string( &buff[6], 2 ); + date.tm_hour = get_val_from_string( &buff[8], 2 ); + date.tm_min = get_val_from_string( &buff[10], 2 ); + date.tm_sec = get_val_from_string( &buff[12], 2 ); + + date.tm_isdst = (buff[14] == 'D'); + + return (mktime( &date )); +} + +// PUBLIC TAG FUNCTIONS +void tag_init(long largest_tag) +{ + if (tagBuffer != NULL) + return; + + tagBuffer = (char *)malloc(largest_tag); +} + +void tag_construct(struct tagHeader &th, int tagID) +{ + th.offset = 0; + th.tagID = tagID; + + switch(tagID) + { + case TAG_YOU: + tag_construct_you(th); + break; + case TAG_YOU_ITEMS: + tag_construct_you_items(th); + break; + case TAG_YOU_DUNGEON: + tag_construct_you_dungeon(th); + break; + case TAG_LEVEL: + tag_construct_level(th); + break; + case TAG_LEVEL_ITEMS: + tag_construct_level_items(th); + break; + case TAG_LEVEL_MONSTERS: + tag_construct_level_monsters(th); + break; + case TAG_LEVEL_ATTITUDE: + tag_construct_level_attitude(th); + break; + case TAG_GHOST: + tag_construct_ghost(th); + break; + default: + // I don't know how to make that! + break; + } +} + +void tag_write(struct tagHeader &th, FILE *saveFile) +{ + const int tagHdrSize = 6; + int tagSize=0; + + char swap[tagHdrSize]; + + // make sure there is some data to write! + if (th.offset == 0) + return; + + // special case: TAG_VERSION. Skip tag header. + if (th.tagID != TAG_VERSION) + { + // swap out first few bytes + memcpy(swap, tagBuffer, tagHdrSize); + + // save tag size + tagSize = th.offset; + + // swap in the header + th.offset = 0; + marshallShort(th, th.tagID); + marshallLong(th, tagSize); + + // write header + write2(saveFile, tagBuffer, th.offset); + + // swap real data back in + memcpy(tagBuffer, swap, tagHdrSize); + + // reset tag size + th.offset = tagSize; + } + + // write tag data + write2(saveFile, tagBuffer, th.offset); + return; +} + +// minorVersion is available for any sub-readers that need it +// (like TAG_LEVEL_MONSTERS) +int tag_read(FILE *fp, char minorVersion) +{ + const int tagHdrSize = 6; + struct tagHeader hdr, th; + th.offset = 0; + + // read tag header + if (read2(fp, tagBuffer, tagHdrSize) != tagHdrSize) + return 0; + + // unmarshall tag type and length (not including header) + hdr.tagID = unmarshallShort(th); + hdr.offset = unmarshallLong(th); + + // sanity check + if (hdr.tagID <= 0 || hdr.offset <= 0) + return 0; + + // now reset th and read actual data + th.offset = 0; + if (read2(fp, tagBuffer, hdr.offset) != hdr.offset) + return 0; + + // ok, we have data now. + switch(hdr.tagID) + { + case TAG_YOU: + tag_read_you(th, minorVersion); + break; + case TAG_YOU_ITEMS: + tag_read_you_items(th, minorVersion); + break; + case TAG_YOU_DUNGEON: + tag_read_you_dungeon(th); + break; + case TAG_LEVEL: + tag_read_level(th, minorVersion); + break; + case TAG_LEVEL_ITEMS: + tag_read_level_items(th, minorVersion); + break; + case TAG_LEVEL_MONSTERS: + tag_read_level_monsters(th, minorVersion); + break; + case TAG_LEVEL_ATTITUDE: + tag_read_level_attitude(th); + break; + case TAG_GHOST: + tag_read_ghost(th, minorVersion); + break; + default: + // I don't know how to read that! + return 0; + } + + return hdr.tagID; +} + + +// older savefiles might want to call this to get a tag +// properly initialized if it wasn't part of the savefile. +// For now, none are supported. + +// This function will be called AFTER all other tags for +// the savefile are read, so everything that can be +// initialized should have been by now. + +// minorVersion is available for any child functions that need +// it (currently none) +void tag_missing(int tag, char minorVersion) +{ + UNUSED( minorVersion ); + + switch(tag) + { + case TAG_LEVEL_ATTITUDE: + tag_missing_level_attitude(); + break; + default: + perror("Tag %d is missing; file is likely corrupt."); + end(-1); + } +} + +// utility +void tag_set_expected(char tags[], int fileType) +{ + int i; + + for(i=0; i<NUM_TAGS; i++) + { + tags[i] = -1; + switch(fileType) + { + case TAGTYPE_PLAYER: + if (i >= TAG_YOU && i <=TAG_YOU_DUNGEON) + tags[i] = 1; + break; + case TAGTYPE_LEVEL: + if (i >= TAG_LEVEL && i <= TAG_LEVEL_ATTITUDE) + tags[i] = 1; + break; + case TAGTYPE_GHOST: + if (i == TAG_GHOST) + tags[i] = 1; + default: + // I don't know what kind of file that is! + break; + } + } +} + +// NEVER _MODIFY_ THE CONSTRUCT/READ FUNCTIONS, EVER. THAT IS THE WHOLE POINT +// OF USING TAGS. Apologies for the screaming. + +// Note anyway that the formats are somewhat flexible; you could change map +// size, the # of slots in player inventory, etc. Constants like GXM, +// NUM_EQUIP, and NUM_DURATIONS are saved, so the appropriate amount will +// be restored even if a later version increases these constants. + +// --------------------------- player tags (foo.sav) -------------------- // +static void tag_construct_you(struct tagHeader &th) +{ + char buff[20]; // used for date string + int i,j; + + marshallString(th, you.your_name, 30); + + marshallByte(th,you.religion); + marshallByte(th,you.piety); + marshallByte(th,you.invis); + marshallByte(th,you.conf); + marshallByte(th,you.paralysis); + marshallByte(th,you.slow); + marshallByte(th,you.fire_shield); + marshallByte(th,you.rotting); + marshallByte(th,you.exhausted); + marshallByte(th,you.deaths_door); + marshallByte(th,your_sign); + marshallByte(th,your_colour); + marshallByte(th,you.pet_target); + + marshallByte(th,you.max_level); + marshallByte(th,you.where_are_you); + marshallByte(th,you.char_direction); + marshallByte(th,you.your_level); + marshallByte(th,you.is_undead); + marshallByte(th,you.special_wield); + marshallByte(th,you.berserker); + marshallByte(th,you.berserk_penalty); + marshallByte(th,you.level_type); + marshallByte(th,you.synch_time); + marshallByte(th,you.disease); + marshallByte(th,you.species); + + marshallShort(th, you.hp); + + if (you.haste > 215) + you.haste = 215; + + marshallByte(th,you.haste); + + if (you.might > 215) + you.might = 215; + + marshallByte(th,you.might); + + if (you.levitation > 215) + you.levitation = 215; + + marshallByte(th,you.levitation); + + if (you.poison > 215) + you.poison = 215; + + marshallByte(th,you.poison); + + marshallShort(th, you.hunger); + + // how many you.equip? + marshallByte(th, NUM_EQUIP); + for (i = 0; i < NUM_EQUIP; ++i) + marshallByte(th,you.equip[i]); + + marshallByte(th,you.magic_points); + marshallByte(th,you.max_magic_points); + marshallByte(th,you.strength); + marshallByte(th,you.intel); + marshallByte(th,you.dex); + marshallByte(th,you.confusing_touch); + marshallByte(th,you.sure_blade); + marshallByte(th,you.hit_points_regeneration); + marshallByte(th,you.magic_points_regeneration); + + marshallShort(th, you.hit_points_regeneration * 100); + marshallLong(th, you.experience); + marshallLong(th, you.gold); + + marshallByte(th,you.char_class); + marshallByte(th,you.experience_level); + marshallLong(th, you.exp_available); + + /* max values */ + marshallByte(th,you.max_strength); + marshallByte(th,you.max_intel); + marshallByte(th,you.max_dex); + + marshallShort(th, you.base_hp); + marshallShort(th, you.base_hp2); + marshallShort(th, you.base_magic_points); + marshallShort(th, you.base_magic_points2); + + marshallShort(th, you.x_pos); + marshallShort(th, you.y_pos); + + marshallString(th, you.class_name, 30); + + marshallShort(th, you.burden); + + // how many spells? + marshallByte(th, 25); + for (i = 0; i < 25; ++i) + marshallByte(th, you.spells[i]); + + marshallByte(th, 52); + for (i = 0; i < 52; i++) + marshallByte( th, you.spell_letter_table[i] ); + + marshallByte(th, 52); + for (i = 0; i < 52; i++) + marshallShort( th, you.ability_letter_table[i] ); + + // how many skills? + marshallByte(th, 50); + for (j = 0; j < 50; ++j) + { + marshallByte(th,you.skills[j]); /* skills! */ + marshallByte(th,you.practise_skill[j]); /* skills! */ + marshallLong(th,you.skill_points[j]); + marshallByte(th,you.skill_order[j]); /* skills ordering */ + } + + // how many durations? + marshallByte(th, NUM_DURATIONS); + for (j = 0; j < NUM_DURATIONS; ++j) + marshallByte(th,you.duration[j]); + + // how many attributes? + marshallByte(th, 30); + for (j = 0; j < 30; ++j) + marshallByte(th,you.attribute[j]); + + // how many mutations/demon powers? + marshallShort(th, 100); + for (j = 0; j < 100; ++j) + { + marshallByte(th,you.mutation[j]); + marshallByte(th,you.demon_pow[j]); + } + + // how many penances? + marshallByte(th, MAX_NUM_GODS); + for (i = 0; i < MAX_NUM_GODS; i++) + marshallByte(th, you.penance[i]); + + // which gods have been worshipped by this character? + marshallByte(th, MAX_NUM_GODS); + for (i = 0; i < MAX_NUM_GODS; i++) + marshallByte(th, you.worshipped[i]); + + marshallByte(th, you.gift_timeout); + marshallByte(th, you.normal_vision); + marshallByte(th, you.current_vision); + marshallByte(th, you.hell_exit); + + // elapsed time + marshallFloat(th, (float)you.elapsed_time); + + // wizard mode used + marshallByte(th, you.wizard); + + // time of game start + make_date_string( you.birth_time, buff ); + marshallString(th, buff, 20); + + // real_time == -1 means game was started before this feature + if (you.real_time != -1) + { + const time_t now = time(NULL); + you.real_time += (now - you.start_time); + + // Reset start_time now that real_time is being saved out... + // this may just be a level save. + you.start_time = now; + } + + marshallLong( th, you.real_time ); + marshallLong( th, you.num_turns ); +} + +static void tag_construct_you_items(struct tagHeader &th) +{ + int i,j; + + // how many inventory slots? + marshallByte(th, ENDOFPACK); + for (i = 0; i < ENDOFPACK; ++i) + { + marshallByte(th,you.inv[i].base_type); + marshallByte(th,you.inv[i].sub_type); + marshallShort(th,you.inv[i].plus); + marshallLong(th,you.inv[i].special); + marshallByte(th,you.inv[i].colour); + marshallLong(th,you.inv[i].flags); + marshallShort(th,you.inv[i].quantity); + marshallShort(th,you.inv[i].plus2); + } + + // item descrip for each type & subtype + // how many types? + marshallByte(th, 5); + // how many subtypes? + marshallByte(th, 50); + for (i = 0; i < 5; ++i) + { + for (j = 0; j < 50; ++j) + marshallByte(th, you.item_description[i][j]); + } + + // identification status + // how many types? + marshallByte(th, 4); + // how many subtypes? + marshallByte(th, 50); + + // this is really dumb. We copy the id[] array from itemname + // to the stack, for no good reason that I can see. + char identy[4][50]; + + save_id(identy); + + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 50; ++j) + marshallByte(th, identy[i][j]); + } + + // how many unique items? + marshallByte(th, 50); + for (j = 0; j < 50; ++j) + { + marshallByte(th,you.unique_items[j]); /* unique items */ + marshallByte(th,you.had_book[j]); + } + + // how many unrandarts? + marshallShort(th, NO_UNRANDARTS); + + for (j = 0; j < NO_UNRANDARTS; ++j) + marshallBoolean(th, does_unrandart_exist(j)); +} + +static void tag_construct_you_dungeon(struct tagHeader &th) +{ + int i,j; + + // how many unique creatures? + marshallByte(th, 50); + for (j = 0; j < 50; ++j) + marshallByte(th,you.unique_creatures[j]); /* unique beasties */ + + // how many branches? + marshallByte(th, MAX_BRANCHES); + for (j = 0; j < 30; ++j) + { + marshallByte(th,you.branch_stairs[j]); + marshallByte(th,stair_level[j]); + } + + // how many levels? + marshallShort(th, MAX_LEVELS); + for (i = 0; i < MAX_LEVELS; ++i) + { + for (j = 0; j < MAX_BRANCHES; ++j) + { + marshallByte(th,altars_present[i][j]); + marshallByte(th,feature[i][j]); + marshallBoolean(th,tmp_file_pairs[i][j]); + } + } +} + +static void tag_read_you(struct tagHeader &th, char minorVersion) +{ + char buff[20]; // For birth date + int i,j; + char count_c; + short count_s; + + unmarshallString(th, you.your_name, 30); + + you.religion = unmarshallByte(th); + you.piety = unmarshallByte(th); + you.invis = unmarshallByte(th); + you.conf = unmarshallByte(th); + you.paralysis = unmarshallByte(th); + you.slow = unmarshallByte(th); + you.fire_shield = unmarshallByte(th); + you.rotting = unmarshallByte(th); + you.exhausted = unmarshallByte(th); + you.deaths_door = unmarshallByte(th); + your_sign = unmarshallByte(th); + your_colour = unmarshallByte(th); + you.pet_target = unmarshallByte(th); + + you.max_level = unmarshallByte(th); + you.where_are_you = unmarshallByte(th); + you.char_direction = unmarshallByte(th); + you.your_level = unmarshallByte(th); + you.is_undead = unmarshallByte(th); + you.special_wield = unmarshallByte(th); + you.berserker = unmarshallByte(th); + you.berserk_penalty = unmarshallByte(th); + you.level_type = unmarshallByte(th); + you.synch_time = unmarshallByte(th); + you.disease = unmarshallByte(th); + you.species = unmarshallByte(th); + you.hp = unmarshallShort(th); + you.haste = unmarshallByte(th); + you.might = unmarshallByte(th); + you.levitation = unmarshallByte(th); + you.poison = unmarshallByte(th); + you.hunger = unmarshallShort(th); + + // how many you.equip? + count_c = unmarshallByte(th); + for (i = 0; i < count_c; ++i) + you.equip[i] = unmarshallByte(th); + + you.magic_points = unmarshallByte(th); + you.max_magic_points = unmarshallByte(th); + you.strength = unmarshallByte(th); + you.intel = unmarshallByte(th); + you.dex = unmarshallByte(th); + you.confusing_touch = unmarshallByte(th); + you.sure_blade = unmarshallByte(th); + you.hit_points_regeneration = unmarshallByte(th); + you.magic_points_regeneration = unmarshallByte(th); + + you.hit_points_regeneration = unmarshallShort(th) / 100; + you.experience = unmarshallLong(th); + you.gold = unmarshallLong(th); + + you.char_class = unmarshallByte(th); + you.experience_level = unmarshallByte(th); + you.exp_available = unmarshallLong(th); + + /* max values */ + you.max_strength = unmarshallByte(th); + you.max_intel = unmarshallByte(th); + you.max_dex = unmarshallByte(th); + + you.base_hp = unmarshallShort(th); + you.base_hp2 = unmarshallShort(th); + you.base_magic_points = unmarshallShort(th); + you.base_magic_points2 = unmarshallShort(th); + + you.x_pos = unmarshallShort(th); + you.y_pos = unmarshallShort(th); + + unmarshallString(th, you.class_name, 30); + + you.burden = unmarshallShort(th); + + // how many spells? + you.spell_no = 0; + count_c = unmarshallByte(th); + for (i = 0; i < count_c; ++i) + { + you.spells[i] = unmarshallByte(th); + if (you.spells[i] != SPELL_NO_SPELL) + you.spell_no++; + } + + if (minorVersion >= 2) + { + count_c = unmarshallByte(th); + for (i = 0; i < count_c; i++) + you.spell_letter_table[i] = unmarshallByte(th); + + count_c = unmarshallByte(th); + for (i = 0; i < count_c; i++) + you.ability_letter_table[i] = unmarshallShort(th); + } + else + { + for (i = 0; i < 52; i++) + { + you.spell_letter_table[i] = -1; + you.ability_letter_table[i] = ABIL_NON_ABILITY; + } + + for (i = 0; i < 25; i++) + { + if (you.spells[i] != SPELL_NO_SPELL) + you.spell_letter_table[i] = i; + } + + if (you.religion != GOD_NO_GOD) + set_god_ability_slots(); + } + + // how many skills? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + { + you.skills[j] = unmarshallByte(th); + you.practise_skill[j] = unmarshallByte(th); + you.skill_points[j] = unmarshallLong(th); + + if (minorVersion >= 2) + you.skill_order[j] = unmarshallByte(th); + } + + // initialize ordering when we don't read it in: + if (minorVersion < 2) + init_skill_order(); + + // set up you.total_skill_points and you.skill_cost_level + calc_total_skill_points(); + + // how many durations? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + you.duration[j] = unmarshallByte(th); + + // how many attributes? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + you.attribute[j] = unmarshallByte(th); + + // how many mutations/demon powers? + count_s = unmarshallShort(th); + for (j = 0; j < count_s; ++j) + { + you.mutation[j] = unmarshallByte(th); + you.demon_pow[j] = unmarshallByte(th); + } + + // how many penances? + count_c = unmarshallByte(th); + for (i = 0; i < count_c; i++) + you.penance[i] = unmarshallByte(th); + + if (minorVersion >= 2) + { + count_c = unmarshallByte(th); + for (i = 0; i < count_c; i++) + you.worshipped[i] = unmarshallByte(th); + } + else + { + for (i = 0; i < count_c; i++) + you.worshipped[i] = false; + + if (you.religion != GOD_NO_GOD) + you.worshipped[you.religion] = true; + } + + you.gift_timeout = unmarshallByte(th); + you.normal_vision = unmarshallByte(th); + you.current_vision = unmarshallByte(th); + you.hell_exit = unmarshallByte(th); + + // elapsed time + you.elapsed_time = (double)unmarshallFloat(th); + + if (minorVersion >= 1) + { + // wizard mode + you.wizard = (bool) unmarshallByte(th); + + // time of character creation + unmarshallString( th, buff, 20 ); + you.birth_time = parse_date_string( buff ); + } + + if (minorVersion >= 2) + { + you.real_time = unmarshallLong(th); + you.num_turns = unmarshallLong(th); + } + else + { + you.real_time = -1; + you.num_turns = -1; + } +} + +static void tag_convert_to_4_3_item( item_def &item ) +{ + const unsigned char plus = item.plus; + const unsigned char plus2 = item.plus2; + const unsigned char ident = item.flags; + const unsigned char special = item.special; + + if (item.quantity <= 0) + return; + + // First, convert ident into flags: + item.flags = (ident == 3) ? ISFLAG_IDENT_MASK : + (ident > 0) ? ISFLAG_KNOW_CURSE + : 0; + + switch (item.base_type) + { + case OBJ_ARMOUR: + if ((ident == 1 && special % 30 >= 25) || ident == 2) + item.flags |= ISFLAG_KNOW_TYPE; + + // Convert special values + item.special %= 30; + if (item.special < 25) + { + if (item.sub_type == ARM_HELMET) + { + item.plus2 = plus2 % 30; + set_helmet_desc( item, (special / 30) << 8 ); + } + else + { + switch (special / 30) + { + case DARM_EMBROIDERED_SHINY: + set_equip_desc( item, ISFLAG_EMBROIDERED_SHINY ); + break; + case DARM_RUNED: + set_equip_desc( item, ISFLAG_RUNED ); + break; + case DARM_GLOWING: + set_equip_desc( item, ISFLAG_GLOWING ); + break; + case DARM_ELVEN: + set_equip_race( item, ISFLAG_ELVEN ); + break; + case DARM_DWARVEN: + set_equip_race( item, ISFLAG_DWARVEN ); + break; + case DARM_ORCISH: + set_equip_race( item, ISFLAG_ORCISH ); + break; + default: + break; + } + } + } + else if (item.special == 25) + { + item.flags |= ISFLAG_UNRANDART; + item.special = 0; + } + else + { + item.flags |= ISFLAG_RANDART; + + // calc old seed + item.special = item.base_type * special + + item.sub_type * (plus % 100) + + plus2 * 100; + } + break; + + case OBJ_WEAPONS: + if ((ident == 1 && (special < 180 && special % 30 >= 25)) || ident == 2) + item.flags |= ISFLAG_KNOW_TYPE; + + // Convert special values + if (special < 181) // don't mangle fixed artefacts + { + item.special %= 30; + if (item.special < 25) + { + switch (special / 30) + { + case DWPN_RUNED: + set_equip_desc( item, ISFLAG_RUNED ); + break; + case DWPN_GLOWING: + set_equip_desc( item, ISFLAG_GLOWING ); + break; + case DWPN_ORCISH: + set_equip_race( item, ISFLAG_ORCISH ); + break; + case DWPN_ELVEN: + set_equip_race( item, ISFLAG_ELVEN ); + break; + case DWPN_DWARVEN: + set_equip_race( item, ISFLAG_DWARVEN ); + break; + default: + break; + } + } + else if (item.special == 25) + { + item.flags |= ISFLAG_UNRANDART; + item.special = 0; + } + else + { + item.flags |= ISFLAG_RANDART; + + // calc old seed + item.special = item.base_type * special + + item.sub_type * (plus % 100) + + plus2 * 100; + } + } + break; + + case OBJ_MISSILES: + // Needles were moved into the bonus eggplant spot. -- bwr + if (item.sub_type == 6) + item.sub_type = MI_NEEDLE; + + if (ident == 2) + item.flags |= ISFLAG_KNOW_TYPE; + + // Convert special values + item.special %= 30; + switch (special / 30) + { + case DAMMO_ORCISH: + set_equip_race( item, ISFLAG_ORCISH ); + break; + case DAMMO_ELVEN: + set_equip_race( item, ISFLAG_ELVEN ); + break; + case DAMMO_DWARVEN: + set_equip_race( item, ISFLAG_DWARVEN ); + break; + default: + break; + } + break; + + case OBJ_WANDS: + if (ident == 2) + item.flags |= ISFLAG_KNOW_PLUSES; + break; + + case OBJ_JEWELLERY: + if (ident == 1 && (special == 200 || special == 201)) + item.flags |= ISFLAG_KNOW_TYPE; + else if (ident == 2) + item.flags |= (ISFLAG_KNOW_TYPE | ISFLAG_KNOW_PLUSES); + + if (special == 201) + { + item.flags |= ISFLAG_UNRANDART; + item.special = 0; + } + else if (special == 200) + { + item.flags |= ISFLAG_RANDART; + + // calc old seed + item.special = item.base_type * special + + item.sub_type * (plus % 100) + + plus2 * 100; + } + break; + + default: + if (ident > 0) + item.flags |= ISFLAG_KNOW_TYPE; + break; + } + + + // Second, convert plus and plus2 + if (item.base_type == OBJ_WEAPONS + || item.base_type == OBJ_MISSILES + || item.base_type == OBJ_ARMOUR + || item.base_type == OBJ_JEWELLERY) + { + item.plus = plus; + + // item is cursed: + if (plus > 100) + { + item.plus -= 100; + item.flags |= ISFLAG_CURSED; + } + + // Weapons use both as pluses. + // Non-artefact jewellery uses both as pluses. + // Artefact jewellery has literal values for both pluses. + // Armour and Missiles only use plus for their plus value. + // Armour has literal usage of plus2 for sub-subtypes. + if (item.base_type != OBJ_JEWELLERY) + { + item.plus -= 50; + + if (item.base_type == OBJ_WEAPONS) + item.plus2 -= 50; + } + else if (special != 200) + { + // regular jewellery & unrandarts -- unused pluses were 0s + if (item.plus) + item.plus -= 50; + + if (item.plus2) + item.plus2 -= 50; + } + else if (special == 200) + { + // Randart jewellery used pluses only as seeds, right now + // they're always zero (since random artefact rings avoid + // base types with pluses). + item.plus = 0; + item.plus2 = 0; + } + } +} + +static void tag_read_you_items(struct tagHeader &th, char minorVersion) +{ + int i,j; + char count_c, count_c2; + short count_s; + + // how many inventory slots? + count_c = unmarshallByte(th); + for (i = 0; i < count_c; ++i) + { + if (minorVersion < 1) + { + you.inv[i].base_type = (unsigned char) unmarshallByte(th); + you.inv[i].sub_type = (unsigned char) unmarshallByte(th); + you.inv[i].plus = (unsigned char) unmarshallByte(th); + you.inv[i].special = (unsigned char) unmarshallByte(th); + you.inv[i].colour = (unsigned char) unmarshallByte(th); + you.inv[i].flags = (unsigned char) unmarshallByte(th); + you.inv[i].quantity = unmarshallShort(th); + you.inv[i].plus2 = (unsigned char) unmarshallByte(th); + + tag_convert_to_4_3_item( you.inv[i] ); + } + else + { + you.inv[i].base_type = (unsigned char) unmarshallByte(th); + you.inv[i].sub_type = (unsigned char) unmarshallByte(th); + you.inv[i].plus = unmarshallShort(th); + you.inv[i].special = unmarshallLong(th); + you.inv[i].colour = (unsigned char) unmarshallByte(th); + you.inv[i].flags = (unsigned long) unmarshallLong(th); + you.inv[i].quantity = unmarshallShort(th); + you.inv[i].plus2 = unmarshallShort(th); + } + + // these never need to be saved for items in the inventory -- bwr + you.inv[i].x = -1; + you.inv[i].y = -1; + you.inv[i].link = i; + } + + // item descrip for each type & subtype + // how many types? + count_c = unmarshallByte(th); + // how many subtypes? + count_c2 = unmarshallByte(th); + for (i = 0; i < count_c; ++i) + { + for (j = 0; j < count_c2; ++j) + you.item_description[i][j] = unmarshallByte(th); + } + + // identification status + // how many types? + count_c = unmarshallByte(th); + // how many subtypes? + count_c2 = unmarshallByte(th); + + // argh.. this is awful. + for (i = 0; i < count_c; ++i) + { + for (j = 0; j < count_c2; ++j) + { + char ch; + ch = unmarshallByte(th); + + switch (i) + { + case IDTYPE_WANDS: + set_ident_type(OBJ_WANDS, j, ch); + break; + case IDTYPE_SCROLLS: + set_ident_type(OBJ_SCROLLS, j, ch); + break; + case IDTYPE_JEWELLERY: + set_ident_type(OBJ_JEWELLERY, j, ch); + break; + case IDTYPE_POTIONS: + set_ident_type(OBJ_POTIONS, j, ch); + break; + } + } + } + + // how many unique items? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + { + you.unique_items[j] = unmarshallByte(th); + you.had_book[j] = unmarshallByte(th); + } + + // how many unrandarts? + count_s = unmarshallShort(th); + for (j = 0; j < count_s; ++j) + set_unrandart_exist(j, unmarshallBoolean(th)); + + // # of unrandarts could certainly change. If it does, + // the new ones won't exist yet - zero them out. + for (; j < NO_UNRANDARTS; j++) + set_unrandart_exist(j, 0); +} + +static void tag_read_you_dungeon(struct tagHeader &th) +{ + int i,j; + char count_c; + short count_s; + + // how many unique creatures? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + you.unique_creatures[j] = unmarshallByte(th); + + // how many branches? + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + { + you.branch_stairs[j] = unmarshallByte(th); + stair_level[j] = unmarshallByte(th); + } + + // how many levels? + count_s = unmarshallShort(th); + for (i = 0; i < count_s; ++i) + { + for (j = 0; j < count_c; ++j) + { + altars_present[i][j] = unmarshallByte(th); + feature[i][j] = unmarshallByte(th); + tmp_file_pairs[i][j] = unmarshallBoolean(th); + } + } +} + +// ------------------------------- level tags ---------------------------- // + +static void tag_construct_level(struct tagHeader &th) +{ + int i; + int count_x, count_y; + + marshallFloat(th, (float)you.elapsed_time); + + // map grids + // how many X? + marshallShort(th, GXM); + // how many Y? + marshallShort(th, GYM); + for (count_x = 0; count_x < GXM; count_x++) + { + for (count_y = 0; count_y < GYM; count_y++) + { + marshallByte(th, grd[count_x][count_y]); + marshallByte(th, env.map[count_x][count_y]); + marshallByte(th, env.cgrid[count_x][count_y]); + } + } + + marshallShort(th, env.cloud_no); + + // how many clouds? + marshallShort(th, MAX_CLOUDS); + for (i = 0; i < MAX_CLOUDS; i++) + { + marshallByte(th, env.cloud[i].x); + marshallByte(th, env.cloud[i].y); + marshallByte(th, env.cloud[i].type); + marshallShort(th, env.cloud[i].decay); + } + + // how many shops? + marshallByte(th, 5); + for (i = 0; i < 5; i++) + { + marshallByte(th, env.shop[i].keeper_name[0]); + marshallByte(th, env.shop[i].keeper_name[1]); + marshallByte(th, env.shop[i].keeper_name[2]); + marshallByte(th, env.shop[i].x); + marshallByte(th, env.shop[i].y); + marshallByte(th, env.shop[i].greed); + marshallByte(th, env.shop[i].type); + marshallByte(th, env.shop[i].level); + } +} + +static void tag_construct_level_items(struct tagHeader &th) +{ + int i; + + // how many traps? + marshallShort(th, MAX_TRAPS); + for (i = 0; i < MAX_TRAPS; ++i) + { + marshallByte(th, env.trap[i].type); + marshallByte(th, env.trap[i].x); + marshallByte(th, env.trap[i].y); + } + + // how many items? + marshallShort(th, MAX_ITEMS); + for (i = 0; i < MAX_ITEMS; ++i) + { + marshallByte(th, mitm[i].base_type); + marshallByte(th, mitm[i].sub_type); + marshallShort(th, mitm[i].plus); + marshallShort(th, mitm[i].plus2); + marshallLong(th, mitm[i].special); + marshallShort(th, mitm[i].quantity); + + marshallByte(th, mitm[i].colour); + marshallShort(th, mitm[i].x); + marshallShort(th, mitm[i].y); + marshallLong(th, mitm[i].flags); + + marshallShort(th, mitm[i].link); // unused + marshallShort(th, igrd[mitm[i].x][mitm[i].y]); // unused + } +} + +static void tag_construct_level_monsters(struct tagHeader &th) +{ + int i,j; + + // how many mons_alloc? + marshallByte(th, 20); + for (i = 0; i < 20; ++i) + marshallShort(th, env.mons_alloc[i]); + + // how many monsters? + marshallShort(th, MAX_MONSTERS); + // how many monster enchantments? + marshallByte(th, NUM_MON_ENCHANTS); + // how many monster inventory slots? + marshallByte(th, NUM_MONSTER_SLOTS); + + for (i = 0; i < MAX_MONSTERS; i++) + { + marshallByte(th, menv[i].armour_class); + marshallByte(th, menv[i].evasion); + marshallByte(th, menv[i].hit_dice); + marshallByte(th, menv[i].speed); + marshallByte(th, menv[i].speed_increment); + marshallByte(th, menv[i].behaviour); + marshallByte(th, menv[i].x); + marshallByte(th, menv[i].y); + marshallByte(th, menv[i].target_x); + marshallByte(th, menv[i].target_y); + marshallByte(th, menv[i].flags); + + for (j = 0; j < NUM_MON_ENCHANTS; j++) + marshallByte(th, menv[i].enchantment[j]); + + marshallShort(th, menv[i].type); + marshallShort(th, menv[i].hit_points); + marshallShort(th, menv[i].max_hit_points); + marshallShort(th, menv[i].number); + + for (j = 0; j < NUM_MONSTER_SLOTS; j++) + marshallShort(th, menv[i].inv[j]); + } +} + +void tag_construct_level_attitude(struct tagHeader &th) +{ + int i; + + // how many monsters? + marshallShort(th, MAX_MONSTERS); + + for (i = 0; i < MAX_MONSTERS; i++) + { + marshallByte(th, menv[i].attitude); + marshallShort(th, menv[i].foe); + } +} + + +static void tag_read_level( struct tagHeader &th, char minorVersion ) +{ + int i,j; + int gx, gy; + + env.elapsed_time = (double)unmarshallFloat(th); + + // map grids + // how many X? + gx = unmarshallShort(th); + // how many Y? + gy = unmarshallShort(th); + for (i = 0; i < gx; i++) + { + for (j = 0; j < gy; j++) + { + grd[i][j] = unmarshallByte(th); + env.map[i][j] = unmarshallByte(th); + if (env.map[i][j] == 201) // what is this?? + env.map[i][j] = 239; + + mgrd[i][j] = NON_MONSTER; + env.cgrid[i][j] = unmarshallByte(th); + + if (minorVersion < 3) + { + // increased number of clouds to 100 in 4.3 + if (env.cgrid[i][j] > 30) + env.cgrid[i][j] = 101; + } + } + } + + env.cloud_no = unmarshallShort(th); + + // how many clouds? + gx = unmarshallShort(th); + for (i = 0; i < gx; i++) + { + env.cloud[i].x = unmarshallByte(th); + env.cloud[i].y = unmarshallByte(th); + env.cloud[i].type = unmarshallByte(th); + env.cloud[i].decay = unmarshallShort(th); + } + + // how many shops? + gx = unmarshallByte(th); + for (i = 0; i < gx; i++) + { + env.shop[i].keeper_name[0] = unmarshallByte(th); + env.shop[i].keeper_name[1] = unmarshallByte(th); + env.shop[i].keeper_name[2] = unmarshallByte(th); + env.shop[i].x = unmarshallByte(th); + env.shop[i].y = unmarshallByte(th); + env.shop[i].greed = unmarshallByte(th); + env.shop[i].type = unmarshallByte(th); + env.shop[i].level = unmarshallByte(th); + } +} + +static void tag_read_level_items(struct tagHeader &th, char minorVersion) +{ + int i; + int count; + + // how many traps? + count = unmarshallShort(th); + for (i = 0; i < count; ++i) + { + env.trap[i].type = unmarshallByte(th); + env.trap[i].x = unmarshallByte(th); + env.trap[i].y = unmarshallByte(th); + } + + // how many items? + count = unmarshallShort(th); + for (i = 0; i < count; ++i) + { + if (minorVersion < 3) + { + mitm[i].base_type = (unsigned char) unmarshallByte(th); + mitm[i].sub_type = (unsigned char) unmarshallByte(th); + mitm[i].plus = (unsigned char) unmarshallByte(th); + mitm[i].plus2 = (unsigned char) unmarshallByte(th); + mitm[i].special = (unsigned char) unmarshallByte(th); + mitm[i].quantity = unmarshallLong(th); + mitm[i].colour = (unsigned char) unmarshallByte(th); + mitm[i].x = (unsigned char) unmarshallByte(th); + mitm[i].y = (unsigned char) unmarshallByte(th); + mitm[i].flags = (unsigned char) unmarshallByte(th); + + tag_convert_to_4_3_item( mitm[i] ); + } + else + { + mitm[i].base_type = (unsigned char) unmarshallByte(th); + mitm[i].sub_type = (unsigned char) unmarshallByte(th); + mitm[i].plus = unmarshallShort(th); + mitm[i].plus2 = unmarshallShort(th); + mitm[i].special = unmarshallLong(th); + mitm[i].quantity = unmarshallShort(th); + mitm[i].colour = (unsigned char) unmarshallByte(th); + mitm[i].x = unmarshallShort(th); + mitm[i].y = unmarshallShort(th); + mitm[i].flags = (unsigned long) unmarshallLong(th); + } + + // pre 4.2 files had monster items stacked at (2,2) -- moved to (0,0) + if (minorVersion < 2 && mitm[i].x == 2 && mitm[i].y == 2) + { + mitm[i].x = 0; + mitm[i].y = 0; + } + + unmarshallShort(th); // mitm[].link -- unused + unmarshallShort(th); // igrd[mitm[i].x][mitm[i].y] -- unused + } +} + +static void tag_read_level_monsters(struct tagHeader &th, char minorVersion) +{ + int i,j; + int count, ecount, icount; + + // how many mons_alloc? + count = unmarshallByte(th); + for (i = 0; i < count; ++i) + env.mons_alloc[i] = unmarshallShort(th); + + // how many monsters? + count = unmarshallShort(th); + // how many monster enchantments? + ecount = unmarshallByte(th); + // how many monster inventory slots? + icount = unmarshallByte(th); + + for (i = 0; i < count; i++) + { + menv[i].armour_class = unmarshallByte(th); + menv[i].evasion = unmarshallByte(th); + menv[i].hit_dice = unmarshallByte(th); + menv[i].speed = unmarshallByte(th); + menv[i].speed_increment = unmarshallByte(th); + menv[i].behaviour = unmarshallByte(th); + menv[i].x = unmarshallByte(th); + menv[i].y = unmarshallByte(th); + menv[i].target_x = unmarshallByte(th); + menv[i].target_y = unmarshallByte(th); + menv[i].flags = unmarshallByte(th); + + // VERSION NOTICE: for pre 4.2 files, flags was either 0 + // or 1. Now, we can transfer ENCH_CREATED_FRIENDLY over + // from the enchantments array to flags. + // Also need to take care of ENCH_FRIEND_ABJ_xx flags + + for (j = 0; j < ecount; j++) + menv[i].enchantment[j] = unmarshallByte(th); + + if (minorVersion < 2) + { + menv[i].flags = 0; + for(j=0; j<NUM_MON_ENCHANTS; j++) + { + if (j>=ecount) + menv[i].enchantment[j] = ENCH_NONE; + else + { + if (menv[i].enchantment[j] == 71) // old ENCH_CREATED_FRIENDLY + { + menv[i].enchantment[j] = ENCH_NONE; + menv[i].flags |= MF_CREATED_FRIENDLY; + } + if (menv[i].enchantment[j] >= 65 // old ENCH_FRIEND_ABJ_I + && menv[i].enchantment[j] <= 70) // old ENCH_FRIEND_ABJ_VI + { + menv[i].enchantment[j] -= (65 - ENCH_ABJ_I); + menv[i].flags |= MF_CREATED_FRIENDLY; + } + } + } + } // end minorversion < 2 + + menv[i].type = unmarshallShort(th); + menv[i].hit_points = unmarshallShort(th); + menv[i].max_hit_points = unmarshallShort(th); + menv[i].number = unmarshallShort(th); + + for (j = 0; j < icount; j++) + menv[i].inv[j] = unmarshallShort(th); + + // place monster + if (menv[i].type != -1) + mgrd[menv[i].x][menv[i].y] = i; + } +} + +void tag_read_level_attitude(struct tagHeader &th) +{ + int i, count; + + // how many monsters? + count = unmarshallShort(th); + + for (i = 0; i < count; i++) + { + menv[i].attitude = unmarshallByte(th); + menv[i].foe = unmarshallShort(th); + } +} + +void tag_missing_level_attitude() +{ + // we don't really have to do a lot here. + // just set foe to MHITNOT; they'll pick up + // a foe first time through handle_monster() if + // there's one around. + + // as for attitude, a couple simple checks + // can be used to determine friendly/neutral/ + // hostile. + int i; + bool isFriendly; + unsigned int new_beh = BEH_WANDER; + + for(i=0; i<MAX_MONSTERS; i++) + { + // only do actual monsters + if (menv[i].type < 0) + continue; + + isFriendly = testbits(menv[i].flags, MF_CREATED_FRIENDLY); + + menv[i].foe = MHITNOT; + + switch(menv[i].behaviour) + { + case 0: // old BEH_SLEEP + new_beh = BEH_SLEEP; // don't wake sleepers + break; + case 3: // old BEH_FLEE + case 10: // old BEH_FLEE_FRIEND + new_beh = BEH_FLEE; + break; + case 1: // old BEH_CHASING_I + case 6: // old BEH_FIGHT + new_beh = BEH_SEEK; + break; + case 7: // old BEH_ENSLAVED + if (!mons_has_ench(&menv[i], ENCH_CHARM)) + isFriendly = true; + break; + default: + break; + } + + menv[i].attitude = (isFriendly)?ATT_FRIENDLY : ATT_HOSTILE; + menv[i].behaviour = new_beh; + menv[i].foe_memory = 0; + } +} + + +// ------------------------------- ghost tags ---------------------------- // + +static void tag_construct_ghost(struct tagHeader &th) +{ + int i; + + marshallString(th, ghost.name, 20); + + // how many ghost values? + marshallByte(th, 20); + + for (i = 0; i < 20; i++) + marshallShort( th, ghost.values[i] ); +} + +static void tag_read_ghost(struct tagHeader &th, char minorVersion) +{ + int i, count_c; + + snprintf( info, INFO_SIZE, "minor version = %d", minorVersion ); + + unmarshallString(th, ghost.name, 20); + + // how many ghost values? + count_c = unmarshallByte(th); + + for (i = 0; i < count_c; i++) + { + // for version 4.4 we moved from unsigned char to shorts -- bwr + if (minorVersion < 4) + ghost.values[i] = unmarshallByte(th); + else + ghost.values[i] = unmarshallShort(th); + } + + if (minorVersion < 4) + { + // Getting rid 9of hopefulling the last) of this silliness -- bwr + if (ghost.values[ GVAL_RES_FIRE ] >= 97) + ghost.values[ GVAL_RES_FIRE ] -= 100; + + if (ghost.values[ GVAL_RES_COLD ] >= 97) + ghost.values[ GVAL_RES_COLD ] -= 100; + } +} + +// ----------------------------------------------------------------------- // |