/************************************************************************** * # # # ## # # ### ## ## ### http://www.lyonesse.it * * # # # # # ## # # # # # * * # # # # # ## ## # # ## ## ## # # ## * * # # # # # ## # # # # # # # # # # # * * ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 * * * * -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir * * * * ********************************************************************** * * * * File: save.c * * * * Players load & save routines * * * **************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "comm.h" #include "handler.h" #include "db.h" #include "interpreter.h" #include "utils.h" #include "spells.h" extern SPELL_INFO_DATA spell_info[TOP_SPELL_DEFINE + 1]; extern VEHICLE_DATA *first_vehicle; extern VEHICLE_DATA *last_vehicle; extern int max_obj_save; /* change in config.c */ /* external functions */ SPELLBOOK *new_spellbook(OBJ_DATA *obj, int type, bool rand); BOOK_PAGE *new_book_page(void); VEHICLE_DATA *fread_rent_vehicle( FILE *fp, ROOM_DATA *sRoom ); CHAR_DATA *fread_rent_mount( FILE *fp, ROOM_DATA *sRoom ); bitvector_t asciiflag_conv(char *flag); long get_ptable_by_name(const char *name); void fwrite_rent_vehicle(VEHICLE_DATA *vehicle, FILE *fp); void extract_vehicle(VEHICLE_DATA *vehicle, int mode); int learn_course(CHAR_DATA *ch, int cnum); /* locals */ OBJ_DATA *fread_one_obj( FILE *fp, int *location ); int fwrite_one_obj( OBJ_DATA *obj, FILE *fp, int mode, int location ); #define LOC_INVENTORY 0 #define MAX_BAG_ROWS 5 #if defined(KEY) #undef KEY #endif #define KEY( literal, field, value ) \ if ( !strcmp( word, literal ) ) \ { \ field = value; \ fMatch = TRUE; \ break; \ } bool LoadingCharObj; /* ======================================================================= */ void fread_one_char(CHAR_DATA *ch, FILE *fp) { AFFECTED_DATA af; char *word; bool fMatch; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'A': KEY( "Ab_Cha", ch->real_abils.cha, fread_number(fp) ); KEY( "Ab_Con", ch->real_abils.con, fread_number(fp) ); KEY( "Ab_Dex", ch->real_abils.dex, fread_number(fp) ); KEY( "Ab_Int", ch->real_abils.intel, fread_number(fp) ); KEY( "Ab_Str", ch->real_abils.str, fread_number(fp) ); KEY( "Ab_Wis", ch->real_abils.wis, fread_number(fp) ); KEY( "Act", PLR_FLAGS(ch), asciiflag_conv(fread_word(fp)) ); KEY( "AffFlags", AFF_FLAGS(ch), asciiflag_conv(fread_word(fp)) ); if ( !strcmp( word, "Affection" ) ) { af.type = fread_number(fp); af.duration = fread_number(fp); af.modifier = fread_number(fp); af.location = fread_number(fp); af.bitvector = asciiflag_conv(fread_word(fp)); affect_to_char(ch, &af); fMatch = TRUE; break; } KEY( "Alignment", GET_ALIGNMENT(ch), fread_number(fp) ); KEY( "Armor", GET_AC(ch), fread_number(fp) ); break; case 'B': KEY( "Badpws", GET_BAD_PWS(ch), fread_number(fp) ); KEY( "Bank", GET_BANK_GOLD(ch), fread_number(fp) ); KEY( "Birth", ch->player.time.birth, fread_number(fp) ); break; case 'C': KEY( "Clan", GET_CLAN(ch), fread_number(fp) ); KEY( "ClanRank", GET_CLAN_RANK(ch), fread_number(fp) ); KEY( "Class", GET_CLASS(ch), fread_number(fp) ); KEY( "CondDrunk", GET_COND(ch, DRUNK), fread_number(fp) ); KEY( "CondHunger", GET_COND(ch, FULL), fread_number(fp) ); KEY( "CondThirst", GET_COND(ch, THIRST), fread_number(fp) ); if (!strcmp(word, "Course")) { learn_course(ch, fread_number(fp)); fMatch = TRUE; break; } break; case 'D': KEY( "Damroll", GET_DAMROLL(ch), fread_number(fp) ); KEY( "DeathsMob", GET_MOB_DEATHS(ch), fread_number(fp) ); KEY( "DeathsPc", GET_PLR_DEATHS(ch), fread_number(fp) ); KEY( "Descr", GET_DDESC(ch), fread_string_nospace(fp) ); break; case 'E': KEY( "Exp", GET_EXP(ch), fread_number(fp) ); if ( !strcmp( word, "End" ) ) return; break; case 'F': KEY( "FreezeLev", GET_FREEZE_LEV(ch), fread_number(fp) ); break; case 'H': KEY( "Height", GET_HEIGHT(ch), fread_number(fp) ); KEY( "Home", GET_HOME(ch), fread_number(fp) ); KEY( "Host", ch->player_specials->host, fread_string_nospace(fp) ); KEY( "Hitroll", GET_HITROLL(ch), fread_number(fp) ); break; case 'I': KEY( "Id", GET_IDNUM(ch), fread_number(fp) ); KEY( "InvisLev", GET_INVIS_LEV(ch), fread_number(fp) ); break; case 'K': KEY( "KillsMob", GET_MOB_KILLS(ch), fread_number(fp) ); KEY( "KillsPc", GET_PLR_KILLS(ch), fread_number(fp) ); KEY("KillsCurrPos", GET_KILLS_CURPOS(ch), fread_number(fp)); if (!str_cmp(word, "Kills")) { int i = fread_number(fp); GET_KILLS_VNUM(ch, i) = fread_number(fp); GET_KILLS_AMOUNT(ch, i) = fread_number(fp); fMatch = TRUE; break; } if (!str_cmp(word, "Knowings")) { long idnum; char chname[256]; idnum = fread_number(fp); strcpy(chname, fread_word(fp)); know_add_load(ch, idnum, chname); fMatch = TRUE; break; } break; case 'L': KEY( "LastLogon", ch->player.time.logon, fread_number(fp) ); KEY( "Level", GET_LEVEL(ch), fread_number(fp) ); KEY( "LevelTot", GET_TOT_LEVEL(ch), fread_number(fp) ); if ( !strcmp( word, "LoadCoord" ) ) { if ( !ch->player_specials->load_coord ) CREATE( ch->player_specials->load_coord, COORD_DATA, 1 ); GET_LOAD_Y(ch) = fread_number(fp); GET_LOAD_X(ch) = fread_number(fp); fMatch = TRUE; break; } KEY( "LoadRoom", GET_LOADROOM(ch), fread_number(fp) ); if (!strcmp(word, "LoadBuilding")) { GET_LOADBUILDING(ch) = fread_number(fp); GET_LOADROOM(ch) = fread_number(fp); fMatch = TRUE; break; } if (!strcmp(word, "LoadShip")) { GET_LOADSHIP(ch) = fread_number(fp); GET_LOADROOM(ch) = fread_number(fp); fMatch = TRUE; break; } break; case 'M': KEY( "Multiclass", MULTICLASS(ch), asciiflag_conv(fread_word(fp)) ); if ( !strcmp( word, "Memorized" ) ) { int sn = fread_number(fp); fMatch = TRUE; if ( sn < 1 || sn >= MAX_SPELLS ) break; MEMORIZED(ch, sn) = fread_number(fp); break; } break; case 'N': KEY( "Name", GET_PC_NAME(ch), str_dup(fread_word(fp)) ); break; case 'P': if ( !strcmp( word, "Points_Hit" ) ) { GET_HIT(ch) = fread_number(fp); GET_MAX_HIT(ch) = fread_number(fp); fMatch = TRUE; break; } if ( !strcmp( word, "Points_Mana" ) ) { GET_MANA(ch) = fread_number(fp); GET_MAX_MANA(ch) = fread_number(fp); fMatch = TRUE; break; } if ( !strcmp( word, "Points_Move" ) ) { GET_MOVE(ch) = fread_number(fp); GET_MAX_MOVE(ch) = fread_number(fp); fMatch = TRUE; break; } if ( !strcmp( word, "Password" ) ) { char *pw = fread_word(fp); strcpy( GET_PASSWD(ch), pw ); fMatch = TRUE; break; } KEY( "Practices", GET_PRACTICES(ch), fread_number(fp) ); KEY( "Played", ch->player.time.played, fread_number(fp) ); KEY( "PoofIn", POOFIN(ch), fread_string_nospace(fp) ); KEY( "PoofOut", POOFOUT(ch), fread_string_nospace(fp) ); KEY( "PrfFlags", PRF_FLAGS(ch), asciiflag_conv(fread_word(fp)) ); break; case 'R': KEY( "Race", GET_RACE(ch), fread_number(fp) ); break; case 'S': if ( !strcmp( word, "SavingThrow" ) ) { GET_SAVE(ch, 0) = fread_number(fp); GET_SAVE(ch, 1) = fread_number(fp); GET_SAVE(ch, 2) = fread_number(fp); GET_SAVE(ch, 3) = fread_number(fp); GET_SAVE(ch, 4) = fread_number(fp); fMatch = TRUE; break; } KEY( "Sex", GET_SEX(ch), fread_number(fp) ); if ( !strcmp( word, "Skill" ) ) { int sn = fread_number(fp); fMatch = TRUE; if ( sn < 0 || sn >= MAX_SKILLS ) break; GET_SKILL(ch, sn) = fread_number(fp); break; } break; case 'T': KEY( "Title", GET_TITLE(ch), fread_string_nospace(fp) ); break; case 'W': KEY( "Weight", GET_WEIGHT(ch), fread_number(fp) ); KEY( "Wimp", GET_WIMP_LEV(ch), fread_number(fp) ); break; default: log("SYSERR: Unknown word %s in pfile.", word); break; } } } /* * Load a char, TRUE if loaded, FALSE if not */ int load_char(char *name, CHAR_DATA *ch) { FILE *fp; char filename[40]; int id, i; if ( ( id = get_ptable_by_name( name ) ) < 0 ) return ( -1 ); if (!get_filename(name, filename, PLR_FILE)) return ( -1 ); if ( !( fp = fopen( filename, "r" ) ) ) { log( "SYSERR: Couldn't open player file %s", filename ); return ( -1 ); } /* character initializations */ // initializations necessary to keep some things straight ch->affected = NULL; GET_LOADROOM(ch) = NOWHERE; GET_LOADBUILDING(ch) = NOWHERE; GET_LOADSHIP(ch) = NOTHING; GET_LOADCOORD(ch) = NULL; for (i = 1; i <= MAX_SKILLS; i++) GET_SKILL(ch, i) = 0; for (i = 0; i < 5; i++) GET_SAVE(ch, i) = 0; for (i = 1; i < 101; i++) { GET_KILLS_VNUM(ch, i) = 0; GET_KILLS_AMOUNT(ch, i) = 0; } GET_SEX(ch) = 0; GET_CLASS(ch) = 0; GET_RACE(ch) = 0; GET_LEVEL(ch) = 0; GET_TOT_LEVEL(ch) = 0; GET_HOME(ch) = 0; GET_HEIGHT(ch) = 0; GET_WEIGHT(ch) = 0; GET_ALIGNMENT(ch) = 0; PLR_FLAGS(ch) = 0; AFF_FLAGS(ch) = 0; MULTICLASS(ch) = 0; GET_INVIS_LEV(ch) = 0; GET_FREEZE_LEV(ch) = 0; GET_WIMP_LEV(ch) = 0; GET_COND(ch, FULL) = 0; GET_COND(ch, THIRST) = 0; GET_COND(ch, DRUNK) = 0; GET_BAD_PWS(ch) = 0; PRF_FLAGS(ch) = 0; GET_PRACTICES(ch) = 0; GET_BANK_GOLD(ch) = 0; GET_EXP(ch) = 0; GET_HITROLL(ch) = 0; GET_DAMROLL(ch) = 0; GET_AC(ch) = 0; GET_HIT(ch) = 0; GET_MAX_HIT(ch) = 0; GET_MANA(ch) = 0; GET_MAX_MANA(ch) = 0; GET_MOVE(ch) = 0; GET_MAX_MOVE(ch) = 0; ch->real_abils.str = 0; ch->real_abils.dex = 0; ch->real_abils.intel = 0; ch->real_abils.wis = 0; ch->real_abils.con = 0; ch->real_abils.cha = 0; GET_KILLS_CURPOS(ch) = 1; GET_MOB_KILLS(ch) = 0; GET_MOB_DEATHS(ch) = 0; GET_PLR_KILLS(ch) = 0; GET_PLR_DEATHS(ch) = 0; GET_CLAN(ch) = -1; GET_CLAN_RANK(ch) = -1; /* end of character initializations */ // Now read from file.. for ( ; ; ) { char letter; char *word; letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( feof( fp ) ) break; if ( letter != '#' ) { log( "load_char: # not found." ); break; } word = fread_word( fp ); if (!str_cmp(word, "PLAYER")) fread_one_char(ch, fp); else if (!str_cmp(word, "END")) // Done break; else log("SYSERR: unknown word %s.", word); } ch->aff_abils = ch->real_abils; affect_total(ch); // initialization for imms if (IS_IMMORTAL(ch)) { for (i = 1; i <= MAX_SKILLS; i++) GET_SKILL(ch, i) = 100; GET_COND(ch, FULL) = -1; GET_COND(ch, THIRST) = -1; GET_COND(ch, DRUNK) = -1; } fclose(fp); return (id); } /* ======================================================================= */ /* * write the vital data of a player to the player file */ void save_char(CHAR_DATA *ch, ROOM_DATA *load_room) { FILE *fl; AFFECTED_DATA *aff, tmp_aff[MAX_AFFECT]; OBJ_DATA *char_eq[NUM_WEARS]; char outname[MAX_NAME_LENGTH+3], buf[MAX_STRING_LENGTH]; char filename[50]; char dflags[128], dpref[128], bits[127]; int i; if (IS_NPC(ch) || GET_PFILEPOS(ch) < 0) return; /* * This version of save_char allows ch->desc to be null (to allow * "set file" to use it). This causes the player's last host * and probably last login to null out. */ if (!PLR_FLAGGED(ch, PLR_LOADROOM)) { if (load_room == NULL) { GET_LOADCOORD(ch) = NULL; GET_LOADROOM(ch) = NOWHERE; GET_LOADBUILDING(ch) = NOWHERE; GET_LOADSHIP(ch) = NOWHERE; } else if ( IS_WILD( load_room ) ) { if ( !GET_LOADCOORD(ch) ) CREATE( ch->player_specials->load_coord, COORD_DATA, 1 ); GET_LOAD_Y(ch) = load_room->coord->y; GET_LOAD_X(ch) = load_room->coord->x; GET_LOADROOM(ch) = NOWHERE; GET_LOADSHIP(ch) = NOTHING; } else if (IS_BUILDING(load_room)) { GET_LOADROOM(ch) = load_room->number; GET_LOADBUILDING(ch) = ch->in_building->vnum; GET_LOADSHIP(ch) = NOTHING; } else if ( IS_SHIP( load_room ) ) { GET_LOADCOORD(ch) = NULL; GET_LOADROOM(ch) = load_room->number; GET_LOADSHIP(ch) = ch->in_ship->vnum; GET_LOADBUILDING(ch) = NOTHING; } else { GET_LOADCOORD(ch) = NULL; GET_LOADROOM(ch) = load_room->number; GET_LOADBUILDING(ch) = NOWHERE; GET_LOADSHIP(ch) = NOTHING; } } strcpy( outname, GET_PC_NAME(ch) ); if (!get_filename(outname, filename, PLR_FILE)) return; if ( !( fl = fopen( filename, "w" ) ) ) { log("SYSERR: Couldn't open player file %s for write", filename); return; } /* Unaffect everything a character can be affected by */ for (i = 0; i < NUM_WEARS; i++) { if ( GET_EQ(ch, i) ) char_eq[i] = unequip_char(ch, i); else char_eq[i] = NULL; } for ( aff = ch->affected, i = 0; i < MAX_AFFECT; i++ ) { if (aff) { tmp_aff[i] = *aff; tmp_aff[i].next = NULL; aff = aff->next; } else { tmp_aff[i].type = 0; tmp_aff[i].duration = 0; tmp_aff[i].modifier = 0; tmp_aff[i].location = 0; tmp_aff[i].bitvector = 0; tmp_aff[i].next = NULL; } } /* * remove the affections so that the raw values are stored; otherwise the * effects are doubled when the char logs back in. */ while (ch->affected) affect_remove(ch, ch->affected); //ch->aff_abils = ch->real_abils; if (PLR_FLAGGED(ch, PLR_NOTDEADYET)) REMOVE_BIT(PLR_FLAGS(ch), PLR_NOTDEADYET); ch->player.time.played += (long) (time(0) - ch->player.time.logon); ch->player.time.logon = time(0); fprintf(fl, "#PLAYER\n"); fprintf(fl, "Id %d\n", GET_IDNUM(ch)); if (GET_PC_NAME(ch)) fprintf(fl, "Name %s\n", GET_PC_NAME(ch)); if (GET_PASSWD(ch)) fprintf(fl, "Password %s\n", GET_PASSWD(ch)); if (GET_TITLE(ch)) fprintf(fl, "Title %s~\n", GET_TITLE(ch)); if (GET_DDESC(ch) && *GET_DDESC(ch)) { strcpy(buf, GET_DDESC(ch)); strip_cr(buf); fprintf(fl, "Descr %s~\n", buf); } fprintf(fl, "Sex %d\n", GET_SEX(ch)); fprintf(fl, "Class %d\n", GET_CLASS(ch)); fprintf(fl, "Race %d\n", GET_RACE(ch)); if (MULTICLASS(ch)) { sprintascii(dpref, MULTICLASS(ch)); fprintf(fl, "Multiclass %s\n", dpref); } fprintf(fl, "Level %d\n", GET_LEVEL(ch)); fprintf(fl, "LevelTot %d\n", GET_TOT_LEVEL(ch)); fprintf(fl, "Clan %d\n", GET_CLAN(ch)); fprintf(fl, "ClanRank %d\n", GET_CLAN_RANK(ch)); fprintf(fl, "Ab_Str %hd\n", ch->real_abils.str); fprintf(fl, "Ab_Int %hd\n", ch->real_abils.intel); fprintf(fl, "Ab_Wis %hd\n", ch->real_abils.wis); fprintf(fl, "Ab_Dex %hd\n", ch->real_abils.dex); fprintf(fl, "Ab_Con %hd\n", ch->real_abils.con); fprintf(fl, "Ab_Cha %hd\n", ch->real_abils.cha); fprintf(fl, "Points_Hit %hd %hd\n", GET_HIT(ch), GET_MAX_HIT(ch)); fprintf(fl, "Points_Mana %hd %hd\n", GET_MANA(ch), GET_MAX_MANA(ch)); fprintf(fl, "Points_Move %hd %hd\n", GET_MOVE(ch), GET_MAX_MOVE(ch)); fprintf(fl, "Armor %hd\n", GET_AC(ch)); fprintf(fl, "Exp %d\n", GET_EXP(ch)); fprintf(fl, "Hitroll %hd\n", GET_HITROLL(ch)); fprintf(fl, "Damroll %hd\n", GET_DAMROLL(ch)); fprintf(fl, "KillsMob %d\n", GET_MOB_KILLS(ch) ); fprintf(fl, "KillsPc %d\n", GET_PLR_KILLS(ch) ); fprintf(fl, "DeathsMob %d\n", GET_MOB_DEATHS(ch) ); fprintf(fl, "DeathsPc %d\n", GET_PLR_DEATHS(ch) ); fprintf(fl, "Home %d\n", GET_HOME(ch)); fprintf(fl, "Birth %d\n", ch->player.time.birth); fprintf(fl, "Played %d\n", ch->player.time.played); fprintf(fl, "LastLogon %d\n", ch->player.time.logon); fprintf(fl, "Height %d\n", GET_HEIGHT(ch)); fprintf(fl, "Weight %d\n", GET_WEIGHT(ch)); fprintf(fl, "Alignment %d\n", GET_ALIGNMENT(ch)); if (PLR_FLAGS(ch)) { sprintascii(dpref, PLR_FLAGS(ch)); fprintf(fl, "Act %s\n", dpref); } if (GET_PRACTICES(ch)) fprintf(fl, "Practices %d\n", GET_PRACTICES(ch)); if (GET_BANK_GOLD(ch)) fprintf(fl, "Bank %d\n", GET_BANK_GOLD(ch)); if ( ch->player_specials->host ) fprintf(fl, "Host %s\n", ch->player_specials->host); if ( AFF_FLAGS(ch) ) { sprintascii(bits, AFF_FLAGS(ch)); fprintf(fl, "AffFlags %s\n", bits); } fprintf(fl, "SavingThrow %d %d %d %d %d\n", GET_SAVE(ch, 0), GET_SAVE(ch, 1), GET_SAVE(ch, 2), GET_SAVE(ch, 3), GET_SAVE(ch, 4)); if (GET_WIMP_LEV(ch)) fprintf(fl, "Wimp %d\n", GET_WIMP_LEV(ch)); if (GET_FREEZE_LEV(ch)) fprintf(fl, "FreezeLev %d\n", GET_FREEZE_LEV(ch)); if (GET_INVIS_LEV(ch)) fprintf(fl, "InvisLev %d\n", GET_INVIS_LEV(ch)); if (GET_LOADBUILDING(ch) != NOWHERE) fprintf(fl, "LoadBuilding %d\n", GET_LOADBUILDING(ch)); if (GET_LOADROOM(ch) != NOWHERE) fprintf(fl, "LoadRoom %d\n", GET_LOADROOM(ch)); if ( GET_LOADCOORD(ch) ) fprintf(fl, "LoadCoord %d %d\n", GET_LOAD_Y(ch), GET_LOAD_X(ch) ); if ( GET_LOADSHIP(ch) != NOTHING ) fprintf(fl, "LoadShip %d %d\n", GET_LOADSHIP(ch), GET_LOADROOM(ch)); if ( GET_LOADBUILDING(ch) != NOTHING ) fprintf(fl, "LoadBuilding %d %d\n", GET_LOADBUILDING(ch), GET_LOADROOM(ch)); if (PRF_FLAGS(ch)) { sprintascii(bits, PRF_FLAGS(ch)); fprintf(fl, "PrfFlags %s\n", bits); } if (GET_BAD_PWS(ch)) fprintf(fl, "Badpws %d\n", GET_BAD_PWS(ch)); /* affected_type */ for (i = 0; i < MAX_AFFECT; i++) { if (tmp_aff[i].type) { sprintascii( dflags, tmp_aff[i].bitvector ); fprintf(fl, "Affection %d %d %d %d %s\n", tmp_aff[i].type, tmp_aff[i].duration, tmp_aff[i].modifier, tmp_aff[i].location, dflags); } } if (IS_IMMORTAL(ch)) { if ( POOFIN(ch) ) fprintf(fl, "PoofIn %s~\n", POOFIN(ch)); if ( POOFOUT(ch) ) fprintf(fl, "PoofOut %s~\n", POOFOUT(ch)); } /* Mortal only stuffs */ if (IS_MORTAL(ch)) { if (GET_COND(ch, FULL)) fprintf(fl, "CondHunger %d\n", GET_COND(ch, FULL)); if (GET_COND(ch, THIRST)) fprintf(fl, "CondThirst %d\n", GET_COND(ch, THIRST)); if (GET_COND(ch, DRUNK)) fprintf(fl, "CondDrunk %d\n", GET_COND(ch, DRUNK)); /* Skills */ for (i = 1; i <= MAX_SKILLS; i++) { if ( GET_SKILL(ch, i) > 0 ) fprintf(fl, "Skill %d %d\n", i, GET_SKILL(ch, i) ); } /* introduction system */ if ( ch->player_specials->first_known ) { KNOWN_DATA *pKnow; for ( pKnow = ch->player_specials->first_known; pKnow; pKnow = pKnow->next ) fprintf( fl, "Knowings %d %s\n", pKnow->idnum, pKnow->name ); } if ( ch->player_specials->courses ) { KNOWN_COURSE *kCourse; for (kCourse = ch->player_specials->courses; kCourse; kCourse = kCourse->next) fprintf(fl, "Course %d\n", kCourse->coursenum); } } for ( i = 1; i <= MAX_SPELLS; i++ ) { if ( MEMORIZED(ch, i) ) fprintf(fl, "Memorized %d %d\n", i, MEMORIZED(ch, i)); } fprintf(fl, "KillsCurrPos %d\n", GET_KILLS_CURPOS(ch)); for (i = 1; i < 101; i++) { if (GET_KILLS_VNUM(ch, i) == 0) continue; fprintf(fl, "Kills %d %d %hd\n", i, GET_KILLS_VNUM(ch, i), GET_KILLS_AMOUNT(ch, i)); } fprintf(fl, "End\n" ); fprintf(fl, "#END\n" ); fclose(fl); /* more char_to_store code to restore affects */ /* add spell and eq affections back in now */ for (i = 0; i < MAX_AFFECT; i++) { if (tmp_aff[i].type) affect_to_char(ch, &tmp_aff[i]); } for (i = 0; i < NUM_WEARS; i++) { if (char_eq[i]) equip_char(ch, char_eq[i], i); } } /* ************************************************************************* */ /* Related Functions */ /* ************************************************************************* */ /* ******************************************************************* */ /* Object Save Routine */ /* ******************************************************************* */ int DeleteCharFile(char *name) { FILE *fl; char filename[50]; if (!get_filename(name, filename, OBJS_FILE)) return (0); if (!(fl = fopen(filename, "r"))) { if (errno != ENOENT) /* if it fails but NOT because of no file */ log("SYSERR: deleting crash file %s (1): %s", filename, strerror(errno)); return (0); } fclose(fl); /* if it fails, NOT because of no file */ if (remove(filename) < 0 && errno != ENOENT) log("SYSERR: deleting crash file %s (2): %s", filename, strerror(errno)); return (1); } /* returns TRUE if item can NOT be saved, FALSE otherwise */ bool ItemNoSave(OBJ_DATA *obj) { if (!obj) return (FALSE); if ( GET_OBJ_TYPE(obj) == ITEM_KEY ) return (TRUE); if ( OBJ_FLAGGED(obj, ITEM_NOSAVE) ) return (TRUE); if ( GET_OBJ_RNUM(obj) <= NOTHING && !OBJ_FLAGGED(obj, ITEM_UNIQUE) ) return (TRUE); return (FALSE); } /* look for items no-save in inventory and containers */ void ExtractItemNoSave(OBJ_DATA *obj) { if (obj) { ExtractItemNoSave(obj->first_content); ExtractItemNoSave(obj->next_content); if (ItemNoSave(obj)) extract_obj(obj); } } /* look for equipped items no-save */ void ExtractItemNoSaveEq(CHAR_DATA *ch) { int j; for (j = 0; j < NUM_WEARS; j++) { if (GET_EQ(ch, j) == NULL) continue; if (ItemNoSave(GET_EQ(ch, j))) // item cannot be saved, will take care later ExtractItemNoSave() obj_to_char(unequip_char(ch, j), ch); else // look for items in equipped containers.. ExtractItemNoSave(GET_EQ(ch, j)); } } void RestoreWeight(OBJ_DATA *obj) { if (obj) { RestoreWeight(obj->first_content); RestoreWeight(obj->next_content); if (obj->in_obj) GET_OBJ_WEIGHT(obj->in_obj) += get_real_obj_weight(obj); } } void ExtractSavedItems(OBJ_DATA * obj) { if (obj) { ExtractSavedItems(obj->first_content); ExtractSavedItems(obj->next_content); extract_obj(obj); } } int save_objs(OBJ_DATA *obj, FILE *fp, int mode, int location) { OBJ_DATA *tmp; int result; if (obj) { save_objs(obj->prev_content, fp, mode, location); save_objs(obj->last_content, fp, mode, MIN(0, location) - 1); result = fwrite_one_obj(obj, fp, mode, location); for (tmp = obj->in_obj; tmp; tmp = tmp->in_obj) GET_OBJ_WEIGHT(tmp) -= get_real_obj_weight(obj); if (!result) return (0); } return (TRUE); } void SaveCharObj(CHAR_DATA *ch, bool quitting) { FILE *fp; char fname[MAX_STRING_LENGTH]; int j; if ( IS_NPC(ch) ) return; if (!get_filename(GET_NAME(ch), fname, OBJS_FILE)) return; if (!(fp = fopen(fname, "w"))) return; ExtractItemNoSaveEq(ch); ExtractItemNoSave(ch->first_carrying); for (j = 0; j < NUM_WEARS; j++) { if ( GET_EQ(ch, j) ) { if (!save_objs(GET_EQ(ch,j), fp, 0, j + 1)) { fclose(fp); return; } if (quitting) { RestoreWeight(GET_EQ(ch, j)); ExtractSavedItems(GET_EQ(ch, j)); } } } if (!save_objs(ch->last_carrying, fp, 0, 0)) { fclose(fp); return; } if (PLR_FLAGGED(ch, PLR_CAMPED)) { CHAR_DATA *mount; VEHICLE_DATA *pVeh, *veh_next = NULL; // scan the room for mounts and/or vehicles... for (mount = ch->in_room->people; mount; mount = mount->next_in_room) { if (!IS_NPC(mount) || GET_MOB_VNUM(mount) == NOTHING || MOB_OWNER(mount) != GET_IDNUM(ch)) continue; fprintf(fp, "#MOUNT\n"); fprintf(fp, "Mob_vnum %d\n", GET_MOB_VNUM(mount)); fprintf(fp, "End\n"); extract_char(mount); } for (pVeh = ch->in_room->vehicles; pVeh; pVeh = veh_next) { veh_next = pVeh->next_in_room; if (pVeh->owner_id != GET_IDNUM(ch)) continue; fwrite_rent_vehicle(pVeh, fp); extract_vehicle(pVeh, 1); } } fprintf(fp, "#END\n"); fclose(fp); if (quitting) ExtractSavedItems(ch->first_carrying); } void CharLoseAllItems(CHAR_DATA *ch) { int j; for (j = 0; j < NUM_WEARS; j++) { if (GET_EQ(ch, j)) { RestoreWeight(GET_EQ(ch, j)); ExtractSavedItems(GET_EQ(ch, j)); } } ExtractSavedItems(ch->first_carrying); ch->first_carrying = NULL; ch->last_carrying = NULL; } /* * AutoEQ by Burkhard Knopf <burkhard.knopf@informatik.tu-clausthal.de> */ void AutoEquip(CHAR_DATA *ch, OBJ_DATA *obj, int location) { int j; /* Lots of checks... */ if (location > 0) /* Was wearing it. */ { switch (j = (location - 1)) { case WEAR_LIGHT: break; case WEAR_FINGER_R: case WEAR_FINGER_L: if (!CAN_WEAR(obj, ITEM_WEAR_FINGER)) /* not fitting :( */ location = LOC_INVENTORY; break; case WEAR_NECK_1: case WEAR_NECK_2: if (!CAN_WEAR(obj, ITEM_WEAR_NECK)) location = LOC_INVENTORY; break; case WEAR_BODY: if (!CAN_WEAR(obj, ITEM_WEAR_BODY)) location = LOC_INVENTORY; break; case WEAR_HEAD: if (!CAN_WEAR(obj, ITEM_WEAR_HEAD)) location = LOC_INVENTORY; break; case WEAR_LEGS: if (!CAN_WEAR(obj, ITEM_WEAR_LEGS)) location = LOC_INVENTORY; break; case WEAR_FEET: if (!CAN_WEAR(obj, ITEM_WEAR_FEET)) location = LOC_INVENTORY; break; case WEAR_HANDS: if (!CAN_WEAR(obj, ITEM_WEAR_HANDS)) location = LOC_INVENTORY; break; case WEAR_ARMS: if (!CAN_WEAR(obj, ITEM_WEAR_ARMS)) location = LOC_INVENTORY; break; case WEAR_SHIELD: if (!CAN_WEAR(obj, ITEM_WEAR_SHIELD)) location = LOC_INVENTORY; break; case WEAR_ABOUT: if (!CAN_WEAR(obj, ITEM_WEAR_ABOUT)) location = LOC_INVENTORY; break; case WEAR_WAIST: if (!CAN_WEAR(obj, ITEM_WEAR_WAIST)) location = LOC_INVENTORY; break; case WEAR_WRIST_R: case WEAR_WRIST_L: if (!CAN_WEAR(obj, ITEM_WEAR_WRIST)) location = LOC_INVENTORY; break; case WEAR_WIELD: if (!CAN_WEAR(obj, ITEM_WEAR_WIELD)) location = LOC_INVENTORY; break; case WEAR_HOLD: if (CAN_WEAR(obj, ITEM_WEAR_HOLD)) break; if (IS_WARRIOR(ch) && CAN_WEAR(obj, ITEM_WEAR_WIELD) && GET_OBJ_TYPE(obj) == ITEM_WEAPON) break; location = LOC_INVENTORY; break; case WEAR_SHOULDERS: if ( !CAN_WEAR(obj, ITEM_WEAR_SHOULDER) ) location = LOC_INVENTORY; break; default: location = LOC_INVENTORY; } if (location > 0) /* Wearable. */ { if (!GET_EQ(ch,j)) { /* * Check the characters's alignment to prevent them from being * zapped through the auto-equipping. */ if (invalid_align(ch, obj) || invalid_class(ch, obj)) location = LOC_INVENTORY; else equip_char(ch, obj, j); } else /* Oops, saved a player with double equipment? */ { char aeq[128]; sprintf(aeq, "SYSERR: autoeq: '%s' already equipped in position %d.", GET_NAME(ch), location); mudlog(aeq, BRF, LVL_IMMORT, TRUE); location = LOC_INVENTORY; } } } if (location <= 0) /* Inventory */ obj = obj_to_char(obj, ch); } int LoadCharObj(CHAR_DATA *ch) { FILE *fp; VEHICLE_DATA *vehicle = NULL; char fname[MAX_STRING_LENGTH]; int num_objs = 0, j; /* AutoEQ addition. */ OBJ_DATA *obj, *obj2, *cont_row[MAX_BAG_ROWS], *veh_cont_row[MAX_BAG_ROWS]; int location; for (j = 0; j < MAX_BAG_ROWS; j++) { cont_row[j] = NULL; veh_cont_row[j] = NULL; } if (!get_filename(GET_NAME(ch), fname, OBJS_FILE)) return (1); if (!(fp = fopen(fname, "r"))) { if (errno != ENOENT) /* if it fails, NOT because of no file */ { log("SYSERR: READING OBJECT FILE %s (5): %s", fname, strerror(errno)); send_to_char( "\r\n********************* NOTICE *********************\r\n" "There was a problem loading your objects from disk.\r\n" "Contact a God for assistance.\r\n", ch); } sprintf(buf, "%s entering game with no equipment.", GET_NAME(ch)); mudlog(buf, NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); return (1); } if (feof(fp)) { log("SYSERR: LoadCharObj(): %s's rent file was empty!", GET_NAME(ch)); return (1); } LoadingCharObj = TRUE; for ( ; ; ) { char letter; char *word; letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( feof( fp ) ) break; if ( letter != '#' ) { log( "LoadCharObj(): # not found." ); break; } word = fread_word( fp ); if ( !strcmp( word, "OBJECT" ) ) // Objects { if ( ( obj = fread_one_obj( fp, &location ) ) == NULL ) continue; num_objs += obj->count; AutoEquip(ch, obj, location); /* * What to do with a new loaded item: * * If there's a list with location less than 1 below this, then its * container has disappeared from the file so we put the list back into * the character's inventory. (Equipped items are 0 here.) * * If there's a list of contents with location of 1 below this, then we * check if it is a container: * - Yes: Get it from the character, fill it, and give it back so we * have the correct weight. * - No: The container is missing so we put everything back into the * character's inventory. * * For items with negative location, we check if there is already a list * of contents with the same location. If so, we put it there and if not, * we start a new list. * * Since location for contents is < 0, the list indices are switched to * non-negative. * * This looks ugly, but it works. */ if (location > 0) /* Equipped */ { for (j = MAX_BAG_ROWS - 1; j > 0; j--) { if (cont_row[j]) /* No container, back to inventory. */ { for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_char(cont_row[j], ch); } cont_row[j] = NULL; } } if (cont_row[0]) /* Content list existing. */ { if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER || GET_OBJ_TYPE(obj) == ITEM_MISSILE_CONT) { /* Remove object, fill it, equip again. */ obj = unequip_char(ch, location - 1); for (; cont_row[0]; cont_row[0] = obj2) { obj2 = cont_row[0]->next_content; obj_to_obj(cont_row[0], obj); } equip_char(ch, obj, location - 1); } else /* Object isn't container, empty the list. */ { for (; cont_row[0]; cont_row[0] = obj2) { obj2 = cont_row[0]->next_content; obj_to_char(cont_row[0], ch); } cont_row[0] = NULL; } } } else /* location <= 0 */ { for (j = MAX_BAG_ROWS - 1; j > -location; j--) { if (cont_row[j]) /* No container, back to inventory. */ { for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; cont_row[j] = obj_to_char(cont_row[j], ch); } cont_row[j] = NULL; } } if (j == -location && cont_row[j]) /* Content list exists. */ { if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER || GET_OBJ_TYPE(obj) == ITEM_MISSILE_CONT) { /* Take the item, fill it, and give it back. */ obj_from_char(obj); obj->first_content = NULL; obj->last_content = NULL; for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_obj(cont_row[j], obj); } obj = obj_to_char(obj, ch); /* Add to inventory first. */ } else /* Object isn't container, empty content list. */ { for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_char(cont_row[j], ch); } cont_row[j] = NULL; } } if (location < 0 && location >= -MAX_BAG_ROWS) { /* * Let the object be part of the content list but put it at the * list's end. Thus having the items in the same order as before * the character rented. */ obj_from_char(obj); if ((obj2 = cont_row[-location - 1]) != NULL) { while (obj2->next_content) obj2 = obj2->next_content; obj2->next_content = obj; } else cont_row[-location - 1] = obj; } } } else if (!strcmp(word, "MOUNT")) { fread_rent_mount(fp, ch->in_room); } else if (!strcmp(word, "VEHICLE")) { if ( !( vehicle = fread_rent_vehicle(fp, ch->in_room) ) ) { log( "SYSERR: LoadCharObj() cannot load vehicle data." ); send_to_char("There is a problem with your vehcile. Tell an Immortal.\r\n", ch); fclose( fp ); LoadingCharObj = FALSE; return (1); } LINK(vehicle, first_vehicle, last_vehicle, next, prev); } else if (!strcmp(word, "OBJVEH")) { if ( !vehicle ) { log("SYSERR: LoadCharObj() - trying to load an object without a vehicle."); fclose(fp); LoadingCharObj = FALSE; return (1); } if ( ( obj = fread_one_obj( fp, &location ) ) == NULL ) continue; obj = obj_to_vehicle(obj, vehicle); for (j = MAX_BAG_ROWS - 1; j > -location; j--) { if (veh_cont_row[j]) { for (; veh_cont_row[j]; veh_cont_row[j] = obj2) { obj2 = veh_cont_row[j]->next_content; veh_cont_row[j] = obj_to_vehicle( veh_cont_row[j], vehicle ); } veh_cont_row[j] = NULL; } } if (j == -location && veh_cont_row[j]) { if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER || GET_OBJ_TYPE(obj) == ITEM_MISSILE_CONT) { obj_from_vehicle(obj); obj->first_content = NULL; obj->last_content = NULL; for (; veh_cont_row[j]; veh_cont_row[j] = obj2) { obj2 = veh_cont_row[j]->next_content; obj_to_obj(veh_cont_row[j], obj); } obj = obj_to_vehicle( obj, vehicle ); } else { for (; veh_cont_row[j]; veh_cont_row[j] = obj2) { obj2 = veh_cont_row[j]->next_content; veh_cont_row[j] = obj_to_vehicle( veh_cont_row[j], vehicle ); } veh_cont_row[j] = NULL; } } if (location < 0 && location >= -MAX_BAG_ROWS) { obj_from_vehicle(obj); if ((obj2 = veh_cont_row[-location - 1]) != NULL) { while (obj2->next_content) obj2 = obj2->next_content; obj2->next_content = obj; } else veh_cont_row[-location - 1] = obj; } } else if (!strcmp(word, "END")) // Done break; } fclose(fp); LoadingCharObj = FALSE; /* Little hoarding check. -gg 3/1/98 */ sprintf(fname, "%s (level %d) has %d object%s (max %d).", GET_NAME(ch), GET_LEVEL(ch), num_objs, num_objs != 1 ? "s" : "", max_obj_save); mudlog(fname, NRM, MAX(GET_INVIS_LEV(ch), LVL_GOD), TRUE); return (1); } /* * Write an object */ #define IS_VALID_SN(sn) ( (sn) >=0 && (sn) < MAX_SKILLS ) int fwrite_one_obj( OBJ_DATA *obj, FILE *fp, int mode, int location ) { EXTRA_DESCR *ed; sh_int aff; char dflags[128], dwear[128]; obj_vnum vobj; switch (mode) { default: fprintf( fp, "#OBJECT\n" ); break; case 1: fprintf( fp, "#OBJVEH\n" ); break; } /* explicit or implicit unique item.. */ if ( OBJ_FLAGGED(obj, ITEM_UNIQUE) || obj->item_number == NOTHING ) { /* better safe than sorry */ SET_BIT( GET_OBJ_EXTRA(obj), ITEM_UNIQUE ); vobj = obj->item_number = NOTHING; fprintf( fp, "Vnum %d\n", obj->item_number ); if ( obj->name ) fprintf( fp, "Name %s~\n", obj->name ); if ( obj->short_description ) fprintf( fp, "ShortDescr %s~\n", obj->short_description ); if ( obj->description ) fprintf( fp, "Description %s~\n", obj->description ); if ( obj->action_description ) fprintf( fp, "ActionDesc %s~\n", obj->action_description ); } /* "normal" item */ else { vobj = obj->item_number; fprintf( fp, "Vnum %d\n", obj_index[vobj].vnum ); if ( obj->name ) { if ( QUICKMATCH( obj->name, obj_proto[vobj].name ) == 0 ) fprintf( fp, "Name %s~\n", obj->name ); } if ( obj->short_description ) { if ( QUICKMATCH( obj->short_description, obj_proto[vobj].short_description ) == 0 ) fprintf( fp, "ShortDescr %s~\n", obj->short_description ); } if ( obj->description ) { if ( QUICKMATCH( obj->description, obj_proto[vobj].description ) == 0 ) fprintf( fp, "Description %s~\n", obj->description ); } if ( obj->action_description ) { if ( QUICKMATCH( obj->action_description, obj_proto[vobj].action_description ) == 0 ) fprintf( fp, "ActionDesc %s~\n", obj->action_description ); } } fprintf( fp, "Location %d\n", location ); sprintascii( dflags, GET_OBJ_EXTRA(obj) ); fprintf( fp, "ExtraFlags %s\n", dflags ); sprintascii( dwear, GET_OBJ_WEAR(obj) ); fprintf( fp, "WearFlags %s\n", dwear ); if ( OBJ_FLAGGED(obj, ITEM_UNIQUE) ) { fprintf( fp, "ItemType %d\n", GET_OBJ_TYPE(obj) ); fprintf( fp, "Weight %d\n", GET_OBJ_WEIGHT(obj) ); fprintf( fp, "Level %d\n", GET_OBJ_LEVEL(obj) ); fprintf( fp, "Cost %d\n", GET_OBJ_COST(obj) ); } else { if ( GET_OBJ_TYPE(obj) != obj_proto[obj->item_number].obj_flags.type_flag ) fprintf( fp, "ItemType %d\n", GET_OBJ_TYPE(obj) ); if ( GET_OBJ_WEIGHT(obj) != obj_proto[obj->item_number].obj_flags.weight ) fprintf( fp, "Weight %d\n", GET_OBJ_WEIGHT(obj) ); if ( GET_OBJ_LEVEL(obj) != obj_proto[obj->item_number].obj_flags.level ) fprintf( fp, "Level %d\n", GET_OBJ_LEVEL(obj) ); if ( obj->obj_flags.timer ) fprintf( fp, "Timer %d\n", GET_OBJ_TIMER(obj) ); if ( GET_OBJ_COST(obj) != obj_proto[obj->item_number].obj_flags.cost ) fprintf( fp, "Cost %d\n", GET_OBJ_COST(obj) ); } fprintf( fp, "Count %d\n", obj->count ); fprintf( fp, "Cond_curr %d\n", GET_OBJ_COND(obj)); fprintf( fp, "Cond_max %d\n", GET_OBJ_MAXCOND(obj)); fprintf( fp, "Quality %d\n", GET_OBJ_QUALITY(obj) ); fprintf( fp, "Values %d %d %d %d\n", GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2), GET_OBJ_VAL(obj, 3)); if (GET_OBJ_OWNER(obj) != NOBODY) fprintf( fp, "Owner %d\n", GET_OBJ_OWNER(obj) ); // save spells switch ( GET_OBJ_TYPE(obj) ) { case ITEM_POTION: case ITEM_SCROLL: if ( IS_VALID_SN( GET_OBJ_VAL(obj, 1) ) ) fprintf( fp, "Spell 1 '%s'\n", spell_info[GET_OBJ_VAL(obj, 1)].name ); if ( IS_VALID_SN( GET_OBJ_VAL(obj, 2) ) ) fprintf( fp, "Spell 2 '%s'\n", spell_info[GET_OBJ_VAL(obj, 2)].name ); if ( IS_VALID_SN( GET_OBJ_VAL(obj, 3) ) ) fprintf( fp, "Spell 3 '%s'\n", spell_info[GET_OBJ_VAL(obj, 3)].name ); break; case ITEM_STAFF: case ITEM_WAND: if ( IS_VALID_SN( GET_OBJ_VAL(obj, 3) ) ) fprintf( fp, "Spell 3 '%s'\n", spell_info[GET_OBJ_VAL(obj, 3)].name ); break; } // Save affections for ( aff = 0; aff < MAX_OBJ_AFF; aff++ ) { if ( obj->affected[aff].location == APPLY_NONE ) continue; fprintf( fp, "Affect %d %d\n", obj->affected[aff].location, obj->affected[aff].modifier ); } if ( OBJ_FLAGGED(obj, ITEM_UNIQUE) ) { // Save extra descriptions for ( ed = obj->ex_description; ed; ed = ed->next ) { fprintf( fp, "ExtraDescr %s~ %s~\n", ed->keyword, ed->description ); } } else { /* TODO - check obj<->proto extra descr */ } // Save special data attached if ( obj->special ) { if ( OBJ_FLAGGED(obj, ITEM_HAS_SPELLS) ) { OBJ_SPELLS_DATA *ospell; for (ospell = (OBJ_SPELLS_DATA *) obj->special; ospell; ospell = ospell->next) { if ( ospell->spellnum == 0 ) continue; fprintf( fp, "ObjSpell '%s' %hd %hd\n", skill_name(ospell->spellnum), ospell->level, ospell->percent ); } } else if ( OBJ_FLAGGED(obj, ITEM_HAS_TRAPS) ) { OBJ_TRAP_DATA *trap; for (trap = (OBJ_TRAP_DATA *) obj->special; trap; trap = trap->next) fprintf(fp, "ObjTrap %d %d %d %hd\n", trap->action, trap->charges, trap->dam_type, trap->whole_room); } else if ( OBJ_FLAGGED(obj, ITEM_IS_SPELLBOOK) ) { SPELLBOOK *book = (SPELLBOOK *) obj->special; BOOK_PAGE *page; fprintf(fp, "Book %hd\n", book->type); for (page = book->first_page; page; page = page->next) fprintf(fp, "Page %hd %hd %hd '%s'\n", page->status, page->flags, page->spellnum, (page->spellname ? page->spellname : "a blank page") ); } } fprintf( fp, "End\n\n" ); return (1); } OBJ_DATA *fread_one_obj( FILE *fp, int *location ) { OBJ_DATA *obj; char *word; bool fMatch; int fVnum = 0; int j = 0; CREATE(obj, OBJ_DATA, 1); clear_object(obj); for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'A': KEY( "ActionDesc", obj->action_description, fread_string_nospace( fp ) ); if ( !strcmp( word, "Affect" ) ) { if (j >= MAX_OBJ_AFF) { fMatch = TRUE; break; } obj->affected[j].location = fread_number( fp ); obj->affected[j].modifier = fread_number( fp ); j++; fMatch = TRUE; break; } break; case 'B': if ( !strcmp(word, "Book") ) { int type = fread_number(fp); if ( obj->special ) log("SYSERR: special already assigned to obj."); else if ( !OBJ_FLAGGED(obj, ITEM_IS_SPELLBOOK) ) log("SYSERR: book special assigned to a non-book obj."); else { SPELLBOOK *book = new_spellbook(obj, type, FALSE); book->type = type; obj->special = book; } fMatch = TRUE; break; } break; case 'C': KEY( "Cost", GET_OBJ_COST(obj), fread_number( fp ) ); KEY( "Count", obj->count, fread_number( fp ) ); KEY( "Cond_curr", GET_OBJ_COND(obj), fread_number( fp ) ); KEY( "Cond_max", GET_OBJ_MAXCOND(obj), fread_number( fp ) ); break; case 'D': KEY( "Description", obj->description, fread_string_nospace( fp ) ); break; case 'E': KEY( "ExtraFlags", GET_OBJ_EXTRA(obj), asciiflag_conv(fread_word(fp)) ); if ( !strcmp( word, "ExtraDescr" ) ) { EXTRA_DESCR *new_descr; CREATE(new_descr, EXTRA_DESCR, 1); new_descr->keyword = fread_string_nospace(fp); new_descr->description = fread_string_nospace(fp); /* add to the obj extradescr list */ new_descr->next = obj->ex_description; obj->ex_description = new_descr; fMatch = TRUE; break; } if ( !strcmp( word, "End" ) ) { if ( !fVnum ) { if ( obj->name ) sprintf ( buf, "Fread_one_obj: %s incomplete object.", obj->name ); else sprintf ( buf, "Fread_one_obj: incomplete object." ); log( buf ); if ( obj->name ) STRFREE( obj->name ); if ( obj->description ) STRFREE( obj->description ); if ( obj->short_description ) STRFREE( obj->short_description ); if ( obj->action_description ) STRFREE( obj->action_description ); DISPOSE( obj ); return (NULL); } else if ( fVnum == 2 ) // unique item { // make checks for unique items } return (obj); } break; case 'I': KEY( "ItemType", GET_OBJ_TYPE(obj), fread_number( fp ) ); break; case 'L': KEY( "Level", GET_OBJ_LEVEL(obj), fread_number( fp ) ); KEY( "Location", *location, fread_number( fp ) ); break; case 'O': if ( !strcmp( word, "ObjSpell" ) ) { OBJ_SPELLS_DATA *ospell, *spells_list = NULL; int sn; fMatch = TRUE; if ( obj->special ) { if ( !OBJ_FLAGGED(obj, ITEM_HAS_SPELLS) ) { log("SYSERR: non-spell special already assigned to obj."); break; } spells_list = (OBJ_SPELLS_DATA *) obj->special; } sn = find_skill_num( fread_word( fp ) ); if ( sn < 0 || sn > MAX_SPELLS ) { log( "Fread_one_obj: unknown skill.", 0 ); break; } CREATE(ospell, OBJ_SPELLS_DATA, 1); ospell->spellnum = sn; ospell->level = fread_number(fp); ospell->percent = fread_number(fp); ospell->next = spells_list; spells_list = ospell; obj->special = spells_list; SET_BIT(GET_OBJ_EXTRA(obj), ITEM_HAS_SPELLS); break; } if ( !strcmp( word, "ObjTrap" ) ) { OBJ_TRAP_DATA *trap, *traps_list = NULL; fMatch = TRUE; if ( obj->special ) { if ( !OBJ_FLAGGED(obj, ITEM_HAS_TRAPS) ) { log("SYSERR: non-trap special already assigned to obj."); break; } traps_list = (OBJ_TRAP_DATA *) obj->special; } CREATE(trap, OBJ_TRAP_DATA, 1); trap->action = fread_number(fp); trap->charges = fread_number(fp); trap->dam_type = fread_number(fp); trap->whole_room = fread_number(fp); trap->next = traps_list; traps_list = trap; obj->special = traps_list; SET_BIT(GET_OBJ_EXTRA(obj), ITEM_HAS_TRAPS); break; } KEY( "Owner", GET_OBJ_OWNER(obj), fread_number( fp ) ); break; case 'P': if ( !strcmp(word, "Page") ) { if ( !obj->special || !OBJ_FLAGGED(obj, ITEM_IS_SPELLBOOK) ) log("SYSERR: book page without special spellbook."); else { SPELLBOOK *book = (SPELLBOOK *) obj->special; BOOK_PAGE *page; CREATE(page, BOOK_PAGE, 1); page->status = fread_number(fp); page->flags = fread_number(fp); page->spellnum = fread_number(fp); page->spellname = str_dup(fread_word(fp)); LINK(page, book->first_page, book->last_page, next, prev); book->num_of_pages++; if ( page->spellnum != NOTHING ) book->num_of_spells++; else DISPOSE(page->spellname); } fMatch = TRUE; break; } break; case 'Q': KEY( "Quality", GET_OBJ_QUALITY(obj), fread_number( fp ) ); case 'N': KEY( "Name", obj->name, fread_string_nospace( fp ) ); break; case 'S': KEY( "ShortDescr", obj->short_description, fread_string_nospace( fp ) ); if ( !strcmp( word, "Spell" ) ) { int iValue; int sn; iValue = fread_number( fp ); sn = find_skill_num( fread_word(fp) ); if ( iValue < 0 || iValue > 5 ) log( "Fread_one__obj: bad iValue %d.", iValue ); else if ( sn < 0 ) log( "Fread_one_obj: unknown skill.", 0 ); else GET_OBJ_VAL(obj, iValue) = sn; fMatch = TRUE; break; } break; case 'T': KEY( "Timer", GET_OBJ_TIMER(obj), fread_number(fp) ); break; case 'V': if ( !strcmp( word, "Values" ) ) { GET_OBJ_VAL(obj, 0) = fread_number(fp); GET_OBJ_VAL(obj, 1) = fread_number(fp); GET_OBJ_VAL(obj, 2) = fread_number(fp); GET_OBJ_VAL(obj, 3) = fread_number(fp); fMatch = TRUE; break; } if ( !strcmp( word, "Vnum" ) ) { int vnum; vnum = fread_number( fp ); if ( vnum == NOTHING ) // unique item { obj->item_number = NOTHING; LINK(obj, first_object, last_object, next, prev); fVnum = 2; } else if ( ( obj = read_object(vnum, VIRTUAL) ) == NULL ) fVnum = 0; else fVnum = 1; fMatch = TRUE; break; } break; case 'W': KEY( "WearFlags", GET_OBJ_WEAR(obj), asciiflag_conv(fread_word(fp)) ); KEY( "Weight", GET_OBJ_WEIGHT(obj), fread_number( fp ) ); break; } if ( !fMatch ) { EXTRA_DESCR *ed, *temp; log( "Fread_one_obj: no match." ); log( word, 0 ); fread_to_eol( fp ); if ( obj->name ) STRFREE( obj->name ); if ( obj->description ) STRFREE( obj->description ); if ( obj->short_description ) STRFREE( obj->short_description ); while ( (ed = obj->ex_description) != NULL ) { if ( ed->keyword ) STRFREE( ed->keyword ); if ( ed->description ) STRFREE( ed->description ); REMOVE_FROM_LIST(ed, obj->ex_description, next ); DISPOSE( ed ); } DISPOSE( obj ); return (NULL); } } } void SaveAll(bool bQuit) { DESCRIPTOR_DATA *d; for (d = descriptor_list; d; d = d->next) { if ((STATE(d) == CON_PLAYING) && !IS_NPC(d->character)) { if (PLR_FLAGGED(d->character, PLR_CRASH)) { SaveCharObj(d->character, bQuit); save_char(d->character, NULL); REMOVE_BIT(PLR_FLAGS(d->character), PLR_CRASH); } } } }