/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMud ROM Derivative (c) 2001-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#include "merc.h"
#include "recycle.h"
#include "tables.h"
#include "interp.h"
#include "vnums.h"
static ObjData *rgObjNest[MAX_NEST];
Proto (void write_char, (CharData *, FileData *));
Proto (void write_pet, (CharData *, FileData *));
Proto (void read_pet, (CharData *, FileData *));
Proto (void read_descriptor, (Descriptor *, FileData *));
Proto (void write_descriptor, (Descriptor *, FileData *));
#define TAB_SIZE 8
char *
format_tabs (int len)
{
if (len < TAB_SIZE)
return "\t\t\t";
else if (len < TAB_SIZE * 2)
return "\t\t";
else if (len < TAB_SIZE * 3)
return "\t";
else
return FORMATF ("%*s", Max (1, len - (TAB_SIZE)), " ");
}
const char *
pfile_filename (const char *name)
{
static int i;
static char rbuf[5][MSL];
char buf[MSL], first_name[MSL];
++i, i %= 5;
strcpy (buf, name);
one_argument (buf, first_name);
sprintf (rbuf[i], "%s.plr", first_name);
return (rbuf[i]);
}
char *
pfilename (const char *name, pfile_t type)
{
static int i;
static char rbuf[5][MSL];
char filename[MSL];
++i, i %= 5;
strcpy (filename, pfile_filename (name));
switch (type)
{
case PFILE_NORMAL:
#if defined(NO_INITIAL_ALPHA_PFILEDIRS)
sprintf (rbuf[i], PLAYER_DIR "%s", filename);
#else
sprintf (rbuf[i], PLAYER_DIR "%c" DIR_SYM "%s", filename[0], filename);
#endif
break;
case PFILE_BACKUP:
#if defined(NO_INITIAL_ALPHA_PFILEDIRS)
sprintf (rbuf[i], PLAYER_BACKUP "%s", filename);
#else
sprintf (rbuf[i], PLAYER_BACKUP "%c" DIR_SYM "%s", filename[0],
filename);
#endif
break;
case PFILE_DELETED:
sprintf (rbuf[i], DELETE_DIR "%s", filename);
break;
default:
sprintf (rbuf[i], "ERROR_PFILENAME_%s_INCORRECT_TYPE_%d",
filename, (int) type);
bugf ("ERROR_PFILENAME_INCORRECT_TYPE %d - %s", (int) type, filename);
break;
}
return (rbuf[i]);
}
bool
save_char_obj_to_filename (CharData * ch, const char *filename)
{
FileData *fp;
if ((fp = f_open (filename, "w")) == NULL)
{
bugf ("Save_char_obj: file open on %s", ch->name);
log_error (filename);
return false;
}
else
{
write_char (ch, fp);
if (ch->carrying_first != NULL)
write_obj (ch, ch->carrying_last, fp, 0, 0, SAVE_CHAR);
if (ch->pet != NULL && ch->pet->in_room == ch->in_room)
{
write_pet (ch->pet, fp);
write_obj (ch->pet, ch->pet->carrying_last, fp, 0, 0, SAVE_PET);
}
if (ch->desc && (crs_info.status == CRS_COPYOVER || crash_info.crashed))
write_descriptor (ch->desc, fp);
f_printf (fp, "#%s" LF, END_MARK);
f_close (fp);
return true;
}
}
void
save_char_obj (CharData * ch)
{
if (IsNPC (ch))
return;
if (ch->desc != NULL && ch->desc->original != NULL)
ch = ch->desc->original;
if (get_trust (ch) < mud_info.min_save_lvl)
return;
save_char_obj_to_filename (ch, pfilename (ch->name, PFILE_NORMAL));
return;
}
void
backup_char_obj (CharData * ch)
{
char buf[MIL];
if (IsNPC (ch))
return;
if (ch->desc != NULL && ch->desc->original != NULL)
ch = ch->desc->original;
if (get_trust (ch) < mud_info.min_save_lvl * 3)
return;
strcpy (buf, pfilename (ch->name, PFILE_BACKUP));
if (save_char_obj_to_filename (ch, buf))
{
ch->pcdata->backup = ch->pcdata->played;
#ifdef unix
system (FORMATF ("gzip -fq %s", buf));
#endif
}
return;
}
void
write_char (CharData * ch, FileData * fp)
{
AffectData *paf;
int sn, gn, pos;
int i, j;
f_printf (fp, "#%s" LF,
get_char_save_header (IsNPC (ch) ? SAVE_MOB : SAVE_CHAR));
write_string (fp, "Name", ch->name, NULL);
write_int (fp, "Id", "%ld", ch->id, 0);
write_time (fp, "LogO", current_time, false);
write_int (fp, "Vers", "%d", PFILE_VERSION, 0);
write_string (fp, "ShD", ch->short_descr, NULL);
write_string (fp, "LnD", ch->long_descr, NULL);
write_string (fp, "Desc", ch->description, NULL);
write_string (fp, "Prom", ch->prompt, NULL);
write_string (fp, "GProm", ch->gprompt, NULL);
write_string (fp, "Race", ch->race->name, NULL);
if (CharClan (ch) != NULL)
{
write_string (fp, "Clan", CharClan (ch)->name, NULL);
write_int (fp, "Rank", "%d", ch->rank, -1);
}
write_int (fp, "Sex", "%d", ch->sex, -1);
write_array (fp, "Cla", "%d", ch->Class, MAX_MCLASS);
write_int (fp, "PrClass", "%d", ch->pcdata->prime_class, 0);
if (ch->pcdata->stay_race)
f_printf (fp, "StayRace" LF);
write_int (fp, "Levl", "%d", ch->level, 0);
write_int (fp, "Tru", "%d", ch->trust, 0);
write_int (fp, "Sec", "%d", ch->pcdata->security, 0);
write_int (fp, "Plyd", "%d",
ch->pcdata->played + (int) (current_time - ch->logon), 0);
write_int (fp, "Scro", "%d", ch->lines, -1);
write_int (fp, "Cols", "%d", ch->columns, -1);
write_int (fp, "Room", "%ld",
(ch->in_room == get_room_index (ROOM_VNUM_LIMBO) &&
ch->was_in_room !=
NULL) ? ch->was_in_room->vnum : ch->in_room ==
NULL ? 3001 : ch->in_room->vnum, 0);
f_writef (fp, "HMV", "%ld %ld %ld %ld %ld %ld" LF, ch->hit,
ch->max_hit, ch->mana, ch->max_mana, ch->move, ch->max_move);
write_int (fp, "Gold", "%ld", ch->gold, 0);
write_int (fp, "Silv", "%ld", ch->silver, 0);
write_int (fp, "Exp", "%d", ch->exp, 0);
write_bit (fp, "Act", ch->act, 0);
write_bit (fp, "AfBy", ch->affected_by, 0);
write_bit (fp, "Comm", ch->comm, 0);
write_bit (fp, "Wizn", ch->wiznet, 0);
write_int (fp, "Invi", "%d", ch->invis_level, 0);
write_int (fp, "Inco", "%d", ch->incog_level, 0);
write_int (fp, "Pos", "%d",
ch->position == POS_FIGHTING ? POS_STANDING : ch->position, -1);
write_int (fp, "Prac", "%d", ch->practice, 0);
write_int (fp, "Trai", "%d", ch->train, 0);
write_int (fp, "Save", "%d", ch->saving_throw, 0);
write_int (fp, "Alig", "%d", ch->alignment, 0);
write_int (fp, "Hit", "%d", ch->hitroll, 0);
write_int (fp, "Dam", "%d", ch->damroll, 0);
write_array (fp, "ACs", "%d", ch->armor, MAX_AC);
write_array (fp, "Stance", "%d", ch->stance, MAX_STANCE);
write_int (fp, "Wimp", "%d", ch->wimpy, 0);
write_array (fp, "Attr", "%d", ch->perm_stat, STAT_MAX);
write_array (fp, "AMod", "%d", ch->mod_stat, STAT_MAX);
if (IsNPC (ch))
{
write_int (fp, "Vnum", "%ld", ch->pIndexData->vnum, 0);
}
else
{
write_string (fp, "Pass", ch->pcdata->pwd, NULL);
write_string (fp, "Bin", ch->pcdata->bamfin, NULL);
write_string (fp, "Bout", ch->pcdata->bamfout, NULL);
write_string (fp, "Titl", ch->pcdata->title, NULL);
write_int (fp, "Pnts", "%d", ch->pcdata->points, 0);
write_int (fp, "TSex", "%d", ch->pcdata->true_sex, -1);
write_int (fp, "LLev", "%d", ch->pcdata->last_level, 0);
f_writef (fp, "HMVP", "%ld %ld %ld" LF, ch->pcdata->perm_hit,
ch->pcdata->perm_mana, ch->pcdata->perm_move);
write_array (fp, "Cnd", "%d", ch->pcdata->condition, 4);
write_int (fp, "QuestPnts", "%d", ch->pcdata->quest.points, 0);
write_int (fp, "QuestTime", "%d", ch->pcdata->quest.time, 0);
if (ch->pcdata->quest.giver)
write_int (fp, "QuestGiver", "%ld",
ch->pcdata->quest.giver->pIndexData->vnum, 0);
if (ch->pcdata->quest.room)
write_int (fp, "QuestLoc", "%ld", ch->pcdata->quest.room->vnum, 0);
if (ch->pcdata->quest.obj)
write_int (fp, "QuestObj", "%ld",
ch->pcdata->quest.obj->pIndexData->vnum, 0);
if (ch->pcdata->quest.mob)
write_int (fp, "QuestMob", "%ld",
ch->pcdata->quest.mob->pIndexData->vnum, 0);
write_int (fp, "Trivia", "%d", ch->pcdata->trivia, 0);
if (ch->pcdata->str_ed_key != '.' && ch->pcdata->str_ed_key != ' ')
f_writef (fp, "StrEdKey", "%c" LF, ch->pcdata->str_ed_key);
write_int (fp, "TimeZone", "%d", ch->pcdata->timezone, -1);
write_int (fp, "AWins", "%d", ch->pcdata->awins, 0);
write_int (fp, "ALosses", "%d", ch->pcdata->alosses, 0);
write_int (fp, "BankG", "%ld", ch->pcdata->gold_bank, 0);
write_int (fp, "Shares", "%d", ch->pcdata->shares, 0);
if (ch->deity != NULL)
write_string (fp, "Deity", ch->deity->name, NULL);
if (Gquester (ch))
{
write_array (fp, "GQmobs", "%ld", ch->gquest->gq_mobs,
gquest_info.mob_count);
}
if (war_info.status != WAR_OFF && ch->war != NULL)
{
f_writef (fp, "WarInfo", "%ld %ld %ld %s" LF, ch->war->hit,
ch->war->mana, ch->war->move,
write_flags (ch->war->flags));
}
if (HAS_HOME (ch))
{
write_array (fp, "Homes", "%ld", ch->pcdata->home, MAX_HOME_VNUMS);
}
f_writef (fp, "Colo", "%d", MAX_CUSTOM_COLOR);
for (i = 0; i < MAX_CUSTOM_COLOR; i++)
for (j = 0; j < CT_MAX; j++)
f_printf (fp, " %d", ch->pcdata->color[i].at[j]);
f_printf (fp, LF);
write_string (fp, "WhoD", ch->pcdata->who_descr, NULL);
write_array (fp, "GStats", "%ld", ch->pcdata->gamestat, MAX_GAMESTAT);
write_bit (fp, "Vt100", ch->pcdata->vt100, 0);
for (pos = 0; pos < MAX_ALIAS; pos++)
{
if (NullStr (ch->pcdata->alias[pos]) ||
NullStr (ch->pcdata->alias_sub[pos]))
break;
f_writef (fp, "Alias", "%s %s~" LF, ch->pcdata->alias[pos],
ch->pcdata->alias_sub[pos]);
}
for (pos = 0; pos < MAX_BUDDY; pos++)
{
if (NullStr (ch->pcdata->buddies[pos]))
break;
write_string (fp, "Buddy", ch->pcdata->buddies[pos], NULL);
}
for (pos = 0; pos < MAX_IGNORE; pos++)
{
if (NullStr (ch->pcdata->ignore[pos]))
break;
f_writef (fp, "Ignore", "%s~ %s" LF, ch->pcdata->ignore[pos],
write_flags (ch->pcdata->ignore_flags[pos]));
}
f_writef (fp, "Boards", "%d", MAX_BOARD);
for (i = 0; i < MAX_BOARD; i++)
f_printf (fp, " %s " TIME_T_FMT, boards[i].short_name,
ch->pcdata->last_note[i]);
f_printf (fp, LF);
f_writef (fp, "Subscribe", "%d", MAX_BOARD);
for (i = 0; i < MAX_BOARD; i++)
f_printf (fp, " %s %d", boards[i].short_name,
ch->pcdata->unsubscribed[i]);
f_printf (fp, LF);
for (sn = 0; sn < top_skill; sn++)
{
if (skill_table[sn].name != NULL && ch->pcdata->learned[sn] > 0)
{
f_writef (fp, "Sk", "%d '%s'" LF, ch->pcdata->learned[sn],
skill_table[sn].name);
}
}
for (gn = 0; gn < top_group; gn++)
{
if (group_table[gn].name != NULL && ch->pcdata->group_known[gn])
{
f_writef (fp, "Gr", "'%s'" LF, group_table[gn].name);
}
}
}
for (paf = ch->affect_first; paf != NULL; paf = paf->next)
{
if (paf->type < 0 || paf->type >= top_skill)
continue;
f_writef (fp, "Affc", "'%s' %3d %3d %3d %3d %3d %s" LF,
skill_table[paf->type].name, paf->where, paf->level,
paf->duration, paf->modifier, paf->location,
write_flags (paf->bitvector));
}
write_rle (ch->pcdata->explored, fp);
#ifndef DISABLE_I3
i3save_char (ch, fp);
#endif
f_printf (fp, END_MARK LF);
return;
}
void
write_pet (CharData * pet, FileData * fp)
{
AffectData *paf;
f_printf (fp, "#%s" LF, get_char_save_header (SAVE_PET));
write_int (fp, "Vnum", "%ld", pet->pIndexData->vnum, 0);
write_string (fp, "Name", pet->name, NULL);
write_time (fp, "LogO", current_time, false);
write_string (fp, "ShD", pet->short_descr, pet->pIndexData->short_descr);
write_string (fp, "LnD", pet->long_descr, pet->pIndexData->long_descr);
write_string (fp, "Desc", pet->description, pet->pIndexData->description);
if (pet->race != pet->pIndexData->race)
write_string (fp, "Race", pet->race->name, NULL);
write_int (fp, "Sex", "%d", pet->sex, -1);
write_int (fp, "Levl", "%d", pet->level, pet->pIndexData->level);
f_writef (fp, "HMV", "%ld %ld %ld %ld %ld %ld" LF, pet->hit,
pet->max_hit, pet->mana, pet->max_mana, pet->move, pet->max_move);
write_int (fp, "Gold", "%ld", pet->gold, 0);
write_int (fp, "Silv", "%ld", pet->silver, 0);
write_int (fp, "Exp", "%d", pet->exp, 0);
write_bit (fp, "Act", pet->act, pet->pIndexData->act);
write_bit (fp, "AfBy", pet->affected_by, pet->pIndexData->affected_by);
write_bit (fp, "Comm", pet->comm, 0);
write_int (fp, "Pos", "%d", pet->position =
POS_FIGHTING ? POS_STANDING : pet->position, -1);
write_int (fp, "Save", "%d", pet->saving_throw, 0);
write_int (fp, "Alig", "%d", pet->alignment, pet->pIndexData->alignment);
write_int (fp, "Hit", "%d", pet->hitroll, pet->pIndexData->hitroll);
write_int (fp, "Dam", "%d", pet->damroll,
pet->pIndexData->damage[DICE_BONUS]);
write_array (fp, "ACs", "%d", pet->armor, MAX_AC);
write_array (fp, "Attr", "%d", pet->perm_stat, STAT_MAX);
write_array (fp, "AMod", "%d", pet->mod_stat, STAT_MAX);
for (paf = pet->affect_first; paf != NULL; paf = paf->next)
{
if (paf->type < 0 || paf->type >= top_skill)
continue;
f_writef (fp, "Affc", "'%s' %3d %3d %3d %3d %3d %s" LF,
skill_table[paf->type].name, paf->where, paf->level,
paf->duration, paf->modifier, paf->location,
write_flags (paf->bitvector));
}
f_printf (fp, END_MARK LF);
return;
}
char *
get_obj_save_header (save_t type)
{
switch (type)
{
case SAVE_CHAR:
return "OBJECT";
case SAVE_CORPSE:
return "CORPSE";
case SAVE_ROOM:
return "ROOMOBJ";
case SAVE_PET:
return "PETOBJ";
default:
bugf ("Bad save type (%d)", type);
return "OBJECT";
}
}
char *
get_char_save_header (save_t type)
{
switch (type)
{
case SAVE_CHAR:
return "PLAYER";
case SAVE_MOB:
return "MOB";
case SAVE_PET:
return "PET";
default:
return "CHAR";
}
}
#define get_desc_save_header "DESC"
void
write_obj (CharData * ch, ObjData * obj, FileData * fp, int iNest,
int iNext, save_t type)
{
ExDescrData *ed;
AffectData *paf;
vnum_t where = ROOM_VNUM_MORGUE;
if (!obj)
return;
if (obj->prev_content != NULL)
{
if (obj->prev_content->in_room == NULL
|| (type == SAVE_ROOM && iNext < 35))
write_obj (ch, obj->prev_content, fp, iNest, iNext + 1, type);
}
if (type == SAVE_CORPSE || type == SAVE_ROOM)
{
if (obj->in_obj != NULL)
where = 1;
if (obj->in_room != NULL)
where = obj->in_room->vnum;
}
if (ch && !IsObjStat (obj, ITEM_QUEST) &&
(type == SAVE_CHAR || type == SAVE_PET) && obj->prev_content == NULL)
{
if ((ch->level < obj->level - lvl_bonus (ch)))
return;
if ((obj->item_type == ITEM_KEY && (IsNPC (ch)
|| obj->pIndexData->vnum !=
ch->pcdata->home_key))
|| (obj->item_type == ITEM_MAP && !obj->value[0]))
return;
}
f_printf (fp, "#%s" LF, get_obj_save_header (type));
write_int (fp, "Vnum", "%ld", obj->pIndexData->vnum, 0);
if (type == SAVE_CORPSE || type == SAVE_ROOM)
write_int (fp, "Where", "%ld", where, ROOM_VNUM_MORGUE);
write_string (fp, "Owner", obj->owner, NULL);
if (!obj->pIndexData->new_format)
f_printf (fp, "Oldstyle" LF);
if (obj->enchanted)
f_printf (fp, "Enchanted" LF);
write_int (fp, "Nest", "%d", iNest, -1);
write_string (fp, "Name", obj->name, obj->pIndexData->name);
write_string (fp, "ShD", obj->short_descr, obj->pIndexData->short_descr);
write_string (fp, "Desc", obj->description, obj->pIndexData->description);
write_bit (fp, "ExtF", obj->extra_flags, obj->pIndexData->extra_flags);
write_bit (fp, "WeaF", obj->wear_flags, obj->pIndexData->wear_flags);
write_int (fp, "Ityp", "%d", obj->item_type, obj->pIndexData->item_type);
write_int (fp, "Wt", "%d", obj->weight, obj->pIndexData->weight);
write_int (fp, "Cond", "%d", obj->condition, obj->pIndexData->condition);
write_int (fp, "Wear", "%d", obj->wear_loc, WEAR_NONE);
write_int (fp, "Lev", "%d", obj->level, obj->pIndexData->level);
write_int (fp, "Time", "%d", obj->timer, 0);
write_int (fp, "Cost", "%ld", obj->cost, 0);
if (obj->enchanted
|| memcmp (obj->value, obj->pIndexData->value, sizeof (obj->value)))
write_array (fp, "Valu", "%ld", obj->value, 5);
switch (obj->item_type)
{
case ITEM_POTION:
case ITEM_SCROLL:
case ITEM_PILL:
if (obj->value[1] > 0)
{
f_writef (fp, "Spell 1", "'%s'" LF,
skill_table[obj->value[1]].name);
}
if (obj->value[2] > 0)
{
f_writef (fp, "Spell 2", "'%s'" LF,
skill_table[obj->value[2]].name);
}
if (obj->value[3] > 0)
{
f_writef (fp, "Spell 3", "'%s'" LF,
skill_table[obj->value[3]].name);
}
break;
case ITEM_STAFF:
case ITEM_WAND:
if (obj->value[3] > 0)
{
f_writef (fp, "Spell 3", "'%s'" LF,
skill_table[obj->value[3]].name);
}
break;
default:
break;
}
for (paf = obj->affect_first; paf != NULL; paf = paf->next)
{
if (paf->type < 0 || paf->type >= top_skill)
continue;
f_writef (fp, "Affc", "'%s' %3d %3d %3d %3d %3d %s" LF,
skill_table[paf->type].name, paf->where, paf->level,
paf->duration, paf->modifier, paf->location,
write_flags (paf->bitvector));
}
for (ed = obj->ed_first; ed != NULL; ed = ed->next)
{
f_writef (fp, "ExDe", "%s~ %s~" LF, ed->keyword, ed->description);
}
f_printf (fp, END_MARK LF);
if (obj->content_last != NULL)
write_obj (ch, obj->content_last, fp, iNest + 1, iNext, type);
return;
}
void
write_descriptor (Descriptor * d, FileData * fp)
{
f_printf (fp, "#%s" LF, get_desc_save_header);
write_string (fp, "Host", d->host, NULL);
write_int (fp, "Descr", "%d", d->descriptor, 0);
write_int (fp, "Connected", "%d", d->connected, 0);
write_int (fp, "IP", "%ld", d->ip, 0);
write_int (fp, "Port", "%d", d->port, 0);
write_bit (fp, "Flags", d->desc_flags, 0);
write_int (fp, "ScrW", "%u", d->scr_width, 80);
write_int (fp, "ScrH", "%u", d->scr_height, 24);
write_int (fp, "ByteN", "%d", d->bytes_normal, 0);
#ifndef DISABLE_MCCP
write_int (fp, "ByteC", "%d", d->bytes_compressed, 0);
write_int (fp, "CVersion", "%d", d->mccp_version, 0);
#endif
write_string (fp, "TType", d->ttype, NULL);
if (IsMXP (d))
{
write_string (fp, "MXPSup", d->mxp.supports, NULL);
write_int (fp, "MXPVer", "%.2f", d->mxp.mxp_ver, 0);
write_int (fp, "MXPClVer", "%.2f", d->mxp.client_ver, 0);
write_int (fp, "MXPStyl", "%.2f", d->mxp.style_ver, 0);
write_string (fp, "MXPClien", d->mxp.client, NULL);
write_int (fp, "MXPReg", "%d", d->mxp.registered, 0);
write_bit (fp, "MXPFlag1", d->mxp.flags, 0);
write_bit (fp, "MXPFlag2", d->mxp.flags2, 0);
}
if (IsPortal (d))
{
write_int (fp, "Keycode", "%u", d->portal.keycode, 0);
write_string (fp, "PortVer", d->portal.version, NULL);
}
if (IsFireCl (d))
write_int (fp, "IMPver", "%.2f", d->imp_vers, 0);
if (IsPueblo (d))
write_int (fp, "Pueblo", "%.2f", d->pueblo_vers, 0);
f_printf (fp, END_MARK LF);
return;
}
void
set_player_level (CharData * ch, int Old, int New, int version)
{
int diff = MAX_LEVEL - LEVEL_IMMORTAL;
int imm_level = Old - diff;
int mod = New - Old;
if (ch->version >= version)
return;
if (ch->level >= imm_level)
ch->level += mod;
if (ch->trust >= imm_level)
ch->trust += mod;
save_char_obj (ch);
}
void
pload_default (CharData * ch)
{
int stat;
ch->race = default_race;
ch->act =
PLR_NOSUMMON | PLR_AUTOMAP | PLR_AUTOEXIT | PLR_AUTODAMAGE |
PLR_AUTOASSIST | PLR_AUTOGOLD | PLR_AUTOLOOT | PLR_AUTOSAC |
PLR_AUTOSPLIT | PLR_AUTOPROMPT;
ch->comm = COMM_COMBINE | COMM_PROMPT;
ch->prompt = str_dup (DEFAULT_PROMPT);
for (stat = 0; stat < STAT_MAX; stat++)
ch->perm_stat[stat] = 13;
ch->pcdata->security = 0;
default_color (ch, -1);
ch->pcdata->trivia = 0;
end_quest (ch, 0);
#ifndef DISABLE_I3
i3init_char (ch);
#endif
}
void
pload_found (CharData * ch)
{
int i;
if (ch->race == NULL)
ch->race = default_race;
ch->size = ch->race->size;
ch->dam_type = 17;
for (i = 0; i < MAX_RACE_SKILL; i++)
{
if (ch->race->skills[i] == NULL)
break;
group_add (ch, ch->race->skills[i], false);
}
ch->affected_by = ch->affected_by | ch->race->aff;
ch->imm_flags = ch->imm_flags | ch->race->imm;
ch->res_flags = ch->res_flags | ch->race->res;
ch->vuln_flags = ch->vuln_flags | ch->race->vuln;
ch->form = ch->race->form;
ch->parts = ch->race->parts;
set_player_level (ch, 0, 0, 0);
ch->Class[CLASS_COUNT] = 0;
while (ch->Class[ch->Class[CLASS_COUNT]] != -1)
ch->Class[CLASS_COUNT] += 1;
if (ch->version < 11)
{
ch->pcdata->home[PC_HOME_COUNT] = 0;
while (get_room_index (ch->pcdata->home[PC_HOME_COUNT]) != NULL)
ch->pcdata->home[PC_HOME_COUNT] += 1;
}
if (ch->version < 12)
default_color (ch, -1);
}
bool
load_char_obj (Descriptor * d, const char *name)
{
CharData *ch;
static FileData *fp;
static bool found;
char buf[MIL];
ch = new_char ();
ch->pcdata = new_pcdata ();
d->character = ch;
ch->desc = d;
ch->name = str_dup (capitalize (name));
ch->id = get_pc_id ();
pload_default (ch);
found = false;
sprintf (buf, "%s.gz", pfilename (name, PFILE_NORMAL));
#ifdef GZFILEIO
if ((fp = f_open (buf, "rb")) == NULL)
#else
if ((fp = f_open (buf, "r")) != NULL)
{
f_close (fp);
#ifdef unix
system (FORMATF ("gzip -dfq %s", buf));
#else
bugf ("File '%s' is compressed!", buf);
AttemptJump = false;
return found;
#endif
}
#endif
sprintf (buf, pfilename (name, PFILE_NORMAL));
if ((fp = f_open (buf, "r")) != NULL)
{
int iNest;
AttemptJump = true;
if (setjmp (jump_env) == 1)
{
size_t iLine, iChar;
char c;
iChar = f_tell (fp);
f_seek (fp, 0, SEEK_SET);
for (iLine = 0; (size_t) f_tell (fp) < iChar; iLine++)
{
while ((c = f_getc (fp)) != '\n' && c != EOF)
;
}
f_seek (fp, iChar, SEEK_SET);
bugf ("[*LCO*] Error in file '%s' line %d", capitalize (name),
iLine);
f_close (fp);
return found;
}
for (iNest = 0; iNest < MAX_NEST; iNest++)
rgObjNest[iNest] = NULL;
found = true;
for (;;)
{
char letter;
char *word;
letter = read_letter (fp);
if (letter == '*')
{
read_to_eol (fp);
continue;
}
if (letter != '#')
{
bugf ("# not found. (%c)", letter);
break;
}
word = read_word (fp);
if (!str_cmp (word, get_char_save_header (SAVE_CHAR)))
read_char (ch, fp);
else if (!str_cmp (word, get_obj_save_header (SAVE_CHAR)))
read_obj (ch, fp, SAVE_CHAR);
else if (!str_cmp (word, get_char_save_header (SAVE_PET)))
read_pet (ch, fp);
else if (!str_cmp (word, get_obj_save_header (SAVE_PET)))
read_obj (ch, fp, SAVE_PET);
else if (!str_cmp (word, get_desc_save_header))
read_descriptor (d, fp);
else if (!str_cmp (word, END_MARK))
break;
else
{
bug ("Load_char_obj: bad section.");
break;
}
}
f_close (fp);
}
AttemptJump = false;
if (found)
{
pload_found (ch);
}
return found;
}
void
read_char (CharData * ch, FileData * fp)
{
char buf[MAX_STRING_LENGTH];
const char *word;
bool fMatch;
int count = 0;
int count2 = 0;
int lastlogoff = current_time;
int percent;
int ignore = 0;
logf ("Loading %s.", ch->name);
for (;;)
{
word = f_eof (fp) ? END_MARK : read_word (fp);
fMatch = false;
switch (toupper (word[0]))
{
case '*':
fMatch = true;
read_to_eol (fp);
break;
case 'A':
Key ("Act", ch->act, read_flag (fp));
Key ("AffectedBy", ch->affected_by, read_flag (fp));
Key ("AfBy", ch->affected_by, read_flag (fp));
Key ("Alignment", ch->alignment, read_number (fp));
Key ("Alig", ch->alignment, read_number (fp));
Key ("AWins", ch->pcdata->awins, read_number (fp));
Key ("ALosses", ch->pcdata->alosses, read_number (fp));
if (!str_cmp (word, "Alia"))
{
if (count >= MAX_ALIAS)
{
read_to_eol (fp);
fMatch = true;
break;
}
ch->pcdata->alias[count] = str_dup (read_word (fp));
ch->pcdata->alias_sub[count] = str_dup (read_word (fp));
count++;
fMatch = true;
break;
}
if (!str_cmp (word, "Alias"))
{
if (count >= MAX_ALIAS)
{
read_to_eol (fp);
fMatch = true;
break;
}
ch->pcdata->alias[count] = str_dup (read_word (fp));
ch->pcdata->alias_sub[count] = read_string (fp);
count++;
fMatch = true;
break;
}
Key_Ignore ("AC");
Key_Ignore ("Armor");
if (!str_cmp (word, "ACs"))
{
if (ch->version < 9)
{
int i;
for (i = 0; i < 4; i++)
ch->armor[i] = read_number (fp);
}
else
read_array (fp, ch->armor, MAX_AC, 100);
fMatch = true;
break;
}
if (!str_cmp (word, "AffD"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("read_char: unknown skill.");
else
paf->type = sn;
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_number (fp);
Link (paf, ch->affect, next, prev);
fMatch = true;
break;
}
if (!str_cmp (word, "Affc"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("read_char: unknown skill.");
else
paf->type = sn;
paf->where = read_enum (where_t, fp);
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_flag (fp);
Link (paf, ch->affect, next, prev);
fMatch = true;
break;
}
if (!str_cmp (word, "AttrMod") || !str_cmp (word, "AMod"))
{
if (ch->version < 9)
{
int stat;
for (stat = 0; stat < STAT_MAX; stat++)
ch->mod_stat[stat] = read_number (fp);
}
else
read_array (fp, ch->mod_stat, STAT_MAX, 3);
fMatch = true;
break;
}
if (!str_cmp (word, "AttrPerm") || !str_cmp (word, "Attr"))
{
if (ch->version < 9)
{
int stat;
for (stat = 0; stat < STAT_MAX; stat++)
ch->perm_stat[stat] = read_number (fp);
}
else
read_array (fp, ch->perm_stat, STAT_MAX, 3);
fMatch = true;
break;
}
break;
case 'B':
Key_Str ("Bamfin", ch->pcdata->bamfin);
Key_Str ("Bamfout", ch->pcdata->bamfout);
Key_Str ("Bin", ch->pcdata->bamfin);
Key_Str ("Bout", ch->pcdata->bamfout);
Key ("BankG", ch->pcdata->gold_bank, read_number (fp));
if (!str_cmp (word, "Buddy"))
{
if (count2 >= MAX_BUDDY)
{
read_to_eol (fp);
fMatch = true;
break;
}
ch->pcdata->buddies[count2] = read_string (fp);
count2++;
fMatch = true;
break;
}
if (!str_cmp (word, "Boards"))
{
int i, num = read_number (fp);
char *boardname;
for (; num; num--)
{
boardname = read_word (fp);
i = board_lookup (boardname);
if (i == BOARD_NOTFOUND)
{
sprintf (buf,
"read_char: %s had unknown board name: %s. Skipped.",
ch->name, boardname);
log_string (buf);
read_number (fp);
}
else
ch->pcdata->last_note[i] = read_number (fp);
}
fMatch = true;
break;
}
break;
case 'C':
if (!str_cmp (word, "Cla") || !str_cmp (word, "Class"))
{
if (ch->version < 10)
{
int i, j;
for (i = 0; i < MAX_MCLASS; i++)
{
ch->Class[i] = read_number (fp);
if (ch->Class[i] == -1)
break;
}
for (i = j = 0; i < MAX_MCLASS; i++)
{
if (ch->Class[i] < 0 || ch->Class[i] >= top_class)
{
ch->Class[i] = -1;
j++;
continue;
}
ch->Class[i - j] = ch->Class[i];
ch->Class[i - j + 1] = -1;
}
}
else
{
read_array (fp, ch->Class, MAX_MCLASS, -1);
}
fMatch = true;
break;
}
Key_SFun ("Clan", ch->pcdata->clan, clan_lookup);
if (!str_cmp (word, "Condition") || !str_cmp (word, "Cond"))
{
ch->pcdata->condition[0] = read_number (fp);
ch->pcdata->condition[1] = read_number (fp);
ch->pcdata->condition[2] = read_number (fp);
fMatch = true;
break;
}
if (!str_cmp (word, "Cnd"))
{
if (ch->version < 9)
{
ch->pcdata->condition[0] = read_number (fp);
ch->pcdata->condition[1] = read_number (fp);
ch->pcdata->condition[2] = read_number (fp);
ch->pcdata->condition[3] = read_number (fp);
}
else
read_array (fp, ch->pcdata->condition, 4, 0);
fMatch = true;
break;
}
Key ("Comm", ch->comm, read_flag (fp));
Key ("Cols", ch->columns, read_number (fp));
if (!str_cmp (word, "Colo"))
{
if (ch->version >= 8)
{
int i, j, num = read_number (fp);
for (i = 0; i < Min (num, MAX_CUSTOM_COLOR); i++)
{
if (i >= MAX_CUSTOM_COLOR)
break;
for (j = 0; j < CT_MAX; j++)
ch->pcdata->color[i].at[j] = read_number (fp);
}
}
read_to_eol (fp);
fMatch = true;
break;
}
break;
case 'D':
Key ("Damroll", ch->damroll, read_number (fp));
Key ("Dam", ch->damroll, read_number (fp));
Key_Str ("Description", ch->description);
Key_Str ("Desc", ch->description);
Key_SFun ("Deity", ch->deity, deity_lookup);
break;
case 'E':
if (!str_cmp (word, END_MARK))
{
if (ch->in_room == NULL)
ch->in_room = get_room_index (ROOM_VNUM_LIMBO);
percent = (current_time - lastlogoff) * 25 / (2 * 60 * 60);
percent = Min (percent, 100);
if (percent > 0 && !IsAffected (ch, AFF_POISON)
&& !IsAffected (ch, AFF_PLAGUE))
{
ch->hit += (ch->max_hit - ch->hit) * percent / 100;
ch->mana += (ch->max_mana - ch->mana) * percent / 100;
ch->move += (ch->max_move - ch->move) * percent / 100;
}
return;
}
Key ("Exp", ch->exp, read_number (fp));
break;
case 'G':
Key ("Gold", ch->gold, read_number (fp));
if (!str_cmp (word, "GQmobs"))
{
if (gquest_info.running != GQUEST_OFF)
{
ch->gquest = new_gqlist ();
alloc_mem (ch->gquest->gq_mobs, vnum_t,
gquest_info.mob_count);
read_array (fp, ch->gquest->gq_mobs,
gquest_info.mob_count, -1);
ch->gquest->ch = ch;
Link (ch->gquest, gqlist, next, prev);
}
fMatch = true;
break;
}
if (!str_cmp (word, "Group") || !str_cmp (word, "Gr"))
{
int gn;
char *temp;
temp = read_word (fp);
gn = group_lookup (temp);
if (gn < 0)
{
bugf ("read_char: unknown group (%s). ", temp);
}
else
gn_add (ch, gn);
fMatch = true;
break;
}
Key_Array ("Gstats", ch->pcdata->gamestat, MAX_GAMESTAT, 0);
Key_Str ("GProm", ch->gprompt);
break;
case 'H':
Key ("Hitroll", ch->hitroll, read_number (fp));
Key ("Hit", ch->hitroll, read_number (fp));
Key ("HKey", ch->pcdata->home_key, read_number (fp));
Key ("HRoom", ch->pcdata->home_room, read_number (fp));
Key_Array ("Homes", ch->pcdata->home, MAX_HOME_VNUMS, 0);
if (!str_cmp (word, "HpManaMove") || !str_cmp (word, "HMV"))
{
ch->hit = read_number (fp);
ch->max_hit = read_number (fp);
ch->mana = read_number (fp);
ch->max_mana = read_number (fp);
ch->move = read_number (fp);
ch->max_move = read_number (fp);
fMatch = true;
break;
}
if (!str_cmp (word, "HpManaMovePerm") || !str_cmp (word, "HMVP"))
{
ch->pcdata->perm_hit = read_number (fp);
ch->pcdata->perm_mana = read_number (fp);
ch->pcdata->perm_move = read_number (fp);
fMatch = true;
break;
}
break;
case 'I':
Key ("Id", ch->id, read_number (fp));
Key ("InvisLevel", ch->invis_level, read_number (fp));
Key ("Inco", ch->incog_level, read_number (fp));
Key ("Invi", ch->invis_level, read_number (fp));
if (!str_cmp (word, "Ignore"))
{
if (ignore >= MAX_IGNORE)
{
read_to_eol (fp);
fMatch = true;
break;
}
ch->pcdata->ignore[ignore] = read_string (fp);
ch->pcdata->ignore_flags[ignore] = read_flag (fp);
ignore++;
fMatch = true;
break;
}
#ifndef DISABLE_I3
if ((fMatch = i3load_char (ch, fp, word)))
break;
#endif
break;
case 'L':
Key ("LastLevel", ch->pcdata->last_level, read_number (fp));
Key ("LLev", ch->pcdata->last_level, read_number (fp));
Key ("Level", ch->level, read_number (fp));
Key ("Lev", ch->level, read_number (fp));
Key ("Levl", ch->level, read_number (fp));
Key ("LogO", lastlogoff, read_number (fp));
Key_Str ("LongDescr", ch->long_descr);
Key_Str ("LnD", ch->long_descr);
break;
case 'N':
Key_Str ("Name", ch->name);
Key_Ignore ("Not");
break;
case 'P':
Key_Str ("Password", ch->pcdata->pwd);
Key_Str ("Pass", ch->pcdata->pwd);
Key ("Played", ch->pcdata->played, read_number (fp));
Key ("Plyd", ch->pcdata->played, read_number (fp));
Key ("Points", ch->pcdata->points, read_number (fp));
Key ("Pnts", ch->pcdata->points, read_number (fp));
Key ("Position", ch->position, read_enum (position_t, fp));
Key ("Pos", ch->position, read_enum (position_t, fp));
Key ("Practice", ch->practice, read_number (fp));
Key ("Prac", ch->practice, read_number (fp));
Key ("PrClass", ch->pcdata->prime_class, read_number (fp));
Key_Str ("Prompt", ch->prompt);
Key_Str ("Prom", ch->prompt);
break;
case 'Q':
Key ("QuestPnts", ch->pcdata->quest.points, read_number (fp));
Key ("QuestTime", ch->pcdata->quest.time, read_number (fp));
Key ("QuestStatus", ch->pcdata->quest.status,
read_enum (quest_t, fp));
Key_Do ("QuestLoc",
(ch->pcdata->quest.room =
get_room_index (read_number (fp))));
Key_Do ("QuestMob",
(ch->pcdata->quest.mob =
find_quest_char (ch, read_number (fp))));
Key_Do ("QuestObj",
(ch->pcdata->quest.obj =
create_quest_obj (ch, read_number (fp))));
Key_Do ("QuestGiver",
(ch->pcdata->quest.giver =
find_quest_char (ch, read_number (fp))));
break;
case 'R':
Key ("Rank", ch->rank, read_number (fp));
Key_SFun ("Race", ch->race, race_lookup);
Key_Do ("RoomRLE", read_rle (ch->pcdata->explored, fp));
Key_Do ("Room", (ch->in_room = get_room_index (read_number (fp))));
break;
case 'S':
Key ("SavingThrow", ch->saving_throw, read_number (fp));
Key ("Save", ch->saving_throw, read_number (fp));
Key ("Scro", ch->lines, read_number (fp));
Key ("Sex", ch->sex, read_enum (sex_t, fp));
Key_Str ("ShortDescr", ch->short_descr);
Key_Str ("ShD", ch->short_descr);
Key ("Sec", ch->pcdata->security, read_number (fp));
Key ("Silv", ch->silver, read_number (fp));
Key ("Shares", ch->pcdata->shares, read_number (fp));
Key ("StrEdKey", ch->pcdata->str_ed_key, read_letter (fp));
Key_Do ("StayRace", (ch->pcdata->stay_race = true));
Key_Array ("Stance", ch->stance, MAX_STANCE, 0);
if (!str_cmp (word, "Skill") || !str_cmp (word, "Sk"))
{
int sn;
int value;
char *temp;
value = read_number (fp);
temp = read_word (fp);
sn = skill_lookup (temp);
if (sn < 0)
{
bugf ("read_char: unknown skill. (%s)", temp);
}
else
ch->pcdata->learned[sn] = value;
fMatch = true;
break;
}
if (!str_cmp (word, "Subscribe"))
{
int i, num = read_number (fp);
char *boardname;
for (; num; num--)
{
boardname = read_word (fp);
i = board_lookup (boardname);
if (i == BOARD_NOTFOUND)
{
sprintf (buf,
"read_char: %s had unknown board name: %s. Skipped.",
ch->name, boardname);
log_string (buf);
read_number (fp);
}
else
ch->pcdata->unsubscribed[i] = read_number (fp);
}
fMatch = true;
break;
}
break;
case 'T':
Key ("TrueSex", ch->pcdata->true_sex, read_enum (sex_t, fp));
Key ("TSex", ch->pcdata->true_sex, read_enum (sex_t, fp));
Key ("Trai", ch->train, read_number (fp));
Key ("Trust", ch->trust, read_number (fp));
Key ("Tru", ch->trust, read_number (fp));
Key ("Trivia", ch->pcdata->trivia, read_number (fp));
Key ("TimeZone", ch->pcdata->timezone, read_number (fp));
if (!str_cmp (word, "Title") || !str_cmp (word, "Titl"))
{
ch->pcdata->title = read_string (fp);
if (ch->pcdata->title[0] != '.' &&
ch->pcdata->title[0] != ',' &&
ch->pcdata->title[0] != '!' && ch->pcdata->title[0] != '?')
{
sprintf (buf, " %s", ch->pcdata->title);
replace_str (&ch->pcdata->title, buf);
}
fMatch = true;
break;
}
break;
case 'V':
Key ("Version", ch->version, read_number (fp));
Key ("Vers", ch->version, read_number (fp));
Key ("Vt100", ch->pcdata->vt100, read_flag (fp));
Key_Do ("Vnum",
(ch->pIndexData = get_char_index (read_number (fp))));
break;
case 'W':
if (!str_cmp (word, "WarInfo"))
{
if (war_info.status != WAR_OFF)
{
ch->war = new_warlist ();
ch->war->hit = read_number (fp);
ch->war->mana = read_number (fp);
ch->war->move = read_number (fp);
ch->war->flags = read_flag (fp);
ch->war->ch = ch;
Link (ch->war, warlist, next, prev);
}
fMatch = true;
break;
}
Key ("Wimpy", ch->wimpy, read_number (fp));
Key ("Wimp", ch->wimpy, read_number (fp));
Key ("Wizn", ch->wiznet, read_flag (fp));
Key_Str ("WhoD", ch->pcdata->who_descr);
break;
}
if (!fMatch)
{
bugf ("read_char: no match for %s->%s.", ch->name, word);
read_to_eol (fp);
}
}
}
void
read_pet (CharData * ch, FileData * fp)
{
const char *word;
CharData *pet;
bool fMatch;
int lastlogoff = current_time;
int percent;
word = f_eof (fp) ? END_MARK : read_word (fp);
if (!str_cmp (word, "Vnum"))
{
vnum_t vnum;
vnum = read_number (fp);
if (get_char_index (vnum) == NULL)
{
bugf ("Fread_pet: bad vnum %ld.", vnum);
pet = create_mobile (get_char_index (MOB_VNUM_FIDO));
}
else
pet = create_mobile (get_char_index (vnum));
}
else
{
bug ("Fread_pet: no vnum in file.");
pet = create_mobile (get_char_index (MOB_VNUM_FIDO));
}
for (;;)
{
word = f_eof (fp) ? END_MARK : read_word (fp);
fMatch = false;
switch (toupper (word[0]))
{
case '*':
fMatch = true;
read_to_eol (fp);
break;
case 'A':
Key ("Act", pet->act, read_flag (fp));
Key ("AfBy", pet->affected_by, read_flag (fp));
Key ("Alig", pet->alignment, read_number (fp));
if (!str_cmp (word, "ACs"))
{
if (pet->version < 9)
{
int i;
for (i = 0; i < 4; i++)
pet->armor[i] = read_number (fp);
}
else
read_array (fp, pet->armor, MAX_AC, 100);
fMatch = true;
break;
}
if (!str_cmp (word, "AffD"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("read_char: unknown skill.");
else
paf->type = sn;
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_number (fp);
Link (paf, pet->affect, next, prev);
fMatch = true;
break;
}
if (!str_cmp (word, "Affc"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("read_char: unknown skill.");
else
paf->type = sn;
paf->where = read_enum (where_t, fp);
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_flag (fp);
Link (paf, pet->affect, next, prev);
fMatch = true;
break;
}
if (!str_cmp (word, "AMod"))
{
if (pet->version < 9)
{
int stat;
for (stat = 0; stat < STAT_MAX; stat++)
pet->mod_stat[stat] = read_number (fp);
}
else
read_array (fp, pet->mod_stat, STAT_MAX, 0);
fMatch = true;
break;
}
if (!str_cmp (word, "Attr"))
{
if (ch->version < 9)
{
int stat;
for (stat = 0; stat < STAT_MAX; stat++)
pet->perm_stat[stat] = read_number (fp);
}
else
read_array (fp, pet->perm_stat, STAT_MAX, 3);
fMatch = true;
break;
}
break;
case 'C':
Key ("Comm", pet->comm, read_flag (fp));
break;
case 'D':
Key ("Dam", pet->damroll, read_number (fp));
Key_Str ("Desc", pet->description);
break;
case 'E':
if (!str_cmp (word, END_MARK))
{
pet->leader = ch;
pet->master = ch;
ch->pet = pet;
percent = (current_time - lastlogoff) * 25 / (2 * 60 * 60);
if (percent > 0 && !IsAffected (ch, AFF_POISON)
&& !IsAffected (ch, AFF_PLAGUE))
{
percent = Min (percent, 100);
pet->hit += (pet->max_hit - pet->hit) * percent / 100;
pet->mana += (pet->max_mana - pet->mana) * percent / 100;
pet->move += (pet->max_move - pet->move) * percent / 100;
}
return;
}
Key ("Exp", pet->exp, read_number (fp));
break;
case 'G':
Key ("Gold", pet->gold, read_number (fp));
break;
case 'H':
Key ("Hit", pet->hitroll, read_number (fp));
if (!str_cmp (word, "HMV"))
{
pet->hit = read_number (fp);
pet->max_hit = read_number (fp);
pet->mana = read_number (fp);
pet->max_mana = read_number (fp);
pet->move = read_number (fp);
pet->max_move = read_number (fp);
fMatch = true;
break;
}
break;
case 'L':
Key ("Levl", pet->level, read_number (fp));
Key_Str ("LnD", pet->long_descr);
Key ("LogO", lastlogoff, read_number (fp));
break;
case 'N':
Key_Str ("Name", pet->name);
break;
case 'P':
Key ("Pos", pet->position, read_enum (position_t, fp));
break;
case 'R':
Key_SFun ("Race", pet->race, race_lookup);
break;
case 'S':
Key ("Save", pet->saving_throw, read_number (fp));
Key ("Sex", pet->sex, read_enum (sex_t, fp));
Key_Str ("ShD", pet->short_descr);
Key ("Silv", pet->silver, read_number (fp));
break;
if (!fMatch)
{
bug ("Fread_pet: no match.");
read_to_eol (fp);
}
}
}
}
void
read_obj (CharData * ch, FileData * fp, save_t type)
{
ObjData *obj;
const char *word;
int iNest;
bool fMatch;
bool fNest;
bool fVnum;
bool first;
bool new_format;
bool make_new;
vnum_t where;
fVnum = false;
obj = NULL;
first = true;
new_format = false;
make_new = false;
word = f_eof (fp) ? END_MARK : read_word (fp);
if (!str_cmp (word, "Vnum"))
{
vnum_t vnum;
ObjIndex *pObj;
first = false;
vnum = read_number (fp);
if ((pObj = get_obj_index (vnum)) == NULL)
{
bugf ("Fread_obj: bad vnum %ld.", vnum);
}
else
{
obj = create_object (pObj, -1);
new_format = true;
fVnum = true;
}
}
if (obj == NULL)
{
obj = new_obj ();
obj->name = str_dup ("");
obj->short_descr = str_dup ("");
obj->description = str_dup ("");
}
fNest = false;
fVnum = true;
iNest = 0;
where = type == SAVE_CORPSE ? ROOM_VNUM_MORGUE : 0;
for (;;)
{
if (first)
first = false;
else
word = f_eof (fp) ? END_MARK : read_word (fp);
fMatch = false;
switch (toupper (word[0]))
{
case '*':
fMatch = true;
read_to_eol (fp);
break;
case 'A':
if (!str_cmp (word, "AffD"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("Fread_obj: unknown skill.");
else
paf->type = sn;
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_number (fp);
Link (paf, obj->affect, next, prev);
fMatch = true;
break;
}
if (!str_cmp (word, "Affc"))
{
AffectData *paf;
int sn;
paf = new_affect ();
sn = skill_lookup (read_word (fp));
if (sn < 0)
bug ("Fread_obj: unknown skill.");
else
paf->type = sn;
paf->where = read_enum (where_t, fp);
paf->level = read_number (fp);
paf->duration = read_number (fp);
paf->modifier = read_number (fp);
paf->location = read_enum (apply_t, fp);
paf->bitvector = read_flag (fp);
Link (paf, obj->affect, next, prev);
fMatch = true;
break;
}
break;
case 'C':
Key ("Cond", obj->condition, read_number (fp));
Key ("Cost", obj->cost, read_number (fp));
break;
case 'D':
Key_Str ("Description", obj->description);
Key_Str ("Desc", obj->description);
break;
case 'E':
Key_Do ("Enchanted", (obj->enchanted = true));
Key ("ExtraFlags", obj->extra_flags, read_number (fp));
Key ("ExtF", obj->extra_flags, read_flag (fp));
if (!str_cmp (word, "ExtraDescr") || !str_cmp (word, "ExDe"))
{
ExDescrData *ed;
ed = new_ed ();
ed->keyword = read_string (fp);
ed->description = read_string (fp);
Link (ed, obj->ed, next, prev);
fMatch = true;
}
if (!str_cmp (word, END_MARK))
{
if (!fNest || (fVnum && obj->pIndexData == NULL))
{
bug ("Fread_obj: incomplete object.");
free_obj (obj);
return;
}
else
{
if (!fVnum)
{
free_obj (obj);
obj = create_object (get_obj_index (OBJ_VNUM_DUMMY), 0);
}
if (!new_format)
{
Link (obj, obj, next, prev);
obj->pIndexData->count++;
}
if (!obj->pIndexData->new_format &&
obj->item_type == ITEM_ARMOR && obj->value[1] == 0)
{
obj->value[1] = obj->value[0];
obj->value[2] = obj->value[0];
}
if (make_new)
{
wloc_t wear;
wear = obj->wear_loc;
extract_obj (obj);
obj = create_object (obj->pIndexData, 0);
obj->wear_loc = wear;
}
if (iNest == 0 || rgObjNest[iNest] == NULL)
{
switch (type)
{
case SAVE_CORPSE:
{
RoomIndex *Room;
CorpseData *c;
c = new_corpse ();
c->corpse = obj;
Link (c, corpse, next, prev);
if ((Room = get_room_index (where)) == NULL)
Room = get_room_index (ROOM_VNUM_MORGUE);
obj_to_room (obj, Room);
}
break;
case SAVE_ROOM:
{
RoomIndex *Room;
if ((Room = get_room_index (where)) == NULL)
extract_obj (obj);
else
obj_to_room (obj, Room);
}
break;
case SAVE_CHAR:
obj_to_char (obj, ch);
break;
case SAVE_PET:
obj_to_char (obj, ch->pet ? ch->pet : ch);
break;
default:
bugf ("Bad save type (%d)", type);
break;
}
}
else
obj_to_obj (obj, rgObjNest[iNest - 1]);
return;
}
}
break;
case 'I':
Key ("ItemType", obj->item_type, read_enum (item_t, fp));
Key ("Ityp", obj->item_type, read_enum (item_t, fp));
break;
case 'L':
Key ("Level", obj->level, read_number (fp));
Key ("Lev", obj->level, read_number (fp));
break;
case 'N':
Key_Str ("Name", obj->name);
if (!str_cmp (word, "Nest"))
{
iNest = read_number (fp);
if (iNest < 0 || iNest >= MAX_NEST)
{
bugf ("Fread_obj: bad nest %d.", iNest);
}
else
{
rgObjNest[iNest] = obj;
fNest = true;
}
fMatch = true;
}
break;
case 'O':
if (!str_cmp (word, "Oldstyle"))
{
if (obj->pIndexData != NULL && obj->pIndexData->new_format)
make_new = true;
fMatch = true;
break;
}
Key_Str ("Owner", obj->owner);
break;
case 'S':
Key_Str ("ShortDescr", obj->short_descr);
Key_Str ("ShD", obj->short_descr);
if (!str_cmp (word, "Spell"))
{
int iValue;
int sn;
iValue = read_number (fp);
sn = skill_lookup (read_word (fp));
if (iValue < 0 || iValue > 3)
{
bugf ("Fread_obj: bad iValue %d.", iValue);
}
else if (sn < 0)
{
bug ("Fread_obj: unknown skill.");
}
else
{
obj->value[iValue] = sn;
}
fMatch = true;
break;
}
break;
case 'T':
Key ("Timer", obj->timer, read_number (fp));
Key ("Time", obj->timer, read_number (fp));
break;
case 'V':
if (!str_cmp (word, "Values") || !str_cmp (word, "Vals"))
{
obj->value[0] = read_number (fp);
obj->value[1] = read_number (fp);
obj->value[2] = read_number (fp);
obj->value[3] = read_number (fp);
if (obj->item_type == ITEM_WEAPON && obj->value[0] == 0)
obj->value[0] = obj->pIndexData->value[0];
fMatch = true;
break;
}
if (!str_cmp (word, "Val"))
{
obj->value[0] = read_number (fp);
obj->value[1] = read_number (fp);
obj->value[2] = read_number (fp);
obj->value[3] = read_number (fp);
obj->value[4] = read_number (fp);
fMatch = true;
break;
}
Key_Array ("Valu", obj->value, 5, 0);
if (!str_cmp (word, "Vnum"))
{
vnum_t vnum;
ObjIndex *pObj;
vnum = read_number (fp);
if ((pObj = get_obj_index (vnum)) == NULL)
bugf ("Fread_obj: bad vnum %ld.", vnum);
else
{
obj->pIndexData = pObj;
fVnum = true;
}
fMatch = true;
break;
}
break;
case 'W':
Key ("WearFlags", obj->wear_flags, read_number (fp));
Key ("WeaF", obj->wear_flags, read_flag (fp));
Key ("WearLoc", obj->wear_loc, read_enum (wloc_t, fp));
Key ("Wear", obj->wear_loc, read_enum (wloc_t, fp));
Key ("Weight", obj->weight, read_number (fp));
Key ("Wt", obj->weight, read_number (fp));
Key ("Where", where, read_number (fp));
break;
}
if (!fMatch)
{
bug ("Fread_obj: no match.");
read_to_eol (fp);
}
}
}
void
read_descriptor (Descriptor * d, FileData * fp)
{
const char *word;
bool fMatch;
for (;;)
{
word = f_eof (fp) ? END_MARK : read_word (fp);
fMatch = false;
if (crs_info.status != CRS_COPYOVER_RECOVER)
{
if (!str_cmp (word, END_MARK))
return;
else
{
read_to_eol (fp);
continue;
}
}
switch (toupper (word[0]))
{
case '*':
fMatch = true;
read_to_eol (fp);
break;
case 'B':
Key ("ByteN", d->bytes_normal, read_number (fp));
#ifndef DISABLE_MCCP
Key ("ByteC", d->bytes_compressed, read_number (fp));
#endif
break;
case 'C':
Key ("Connected", d->connected, read_enum (connect_t, fp));
#ifndef DISABLE_MCCP
Key ("CVersion", d->mccp_version, read_number (fp));
#endif
break;
case 'D':
Key ("Descr", d->descriptor, read_number (fp));
break;
case 'E':
if (!str_cmp (word, END_MARK))
return;
break;
case 'F':
Key ("Flags", d->desc_flags, read_flag (fp));
break;
case 'H':
Key_Str ("Host", d->host);
break;
case 'I':
Key_Do ("IMPver", d->imp_vers = atof (read_word (fp)));
Key ("IP", d->ip, read_number (fp));
break;
case 'K':
Key ("Keycode", d->portal.keycode, read_number (fp));
break;
case 'M':
Key_Str ("MXPSup", d->mxp.supports);
Key_Do ("MXPVer", d->mxp.mxp_ver = atof (read_word (fp)));
Key_Do ("MXPClVer", d->mxp.client_ver = atof (read_word (fp)));
Key_Do ("MXPStyl", d->mxp.style_ver = atof (read_word (fp)));
Key_Str ("MXPClien", d->mxp.client);
Key ("MXPReg", d->mxp.registered, read_number (fp));
Key ("MXPFlag1", d->mxp.flags, read_flag (fp));
Key ("MXPFlag2", d->mxp.flags2, read_flag (fp));
break;
case 'P':
Key_StrCpy ("PortVer", d->portal.version);
Key_Do ("Pueblo", d->pueblo_vers = atof (read_word (fp)));
Key ("Port", d->port, read_number (fp));
break;
case 'S':
Key ("ScrW", d->scr_width, read_number (fp));
Key ("ScrH", d->scr_height, read_number (fp));
break;
case 'T':
Key_StrCpy ("TType", d->ttype);
break;
}
if (!fMatch)
{
bugf ("no match for %s.", word);
read_to_eol (fp);
}
}
}
void
save_corpses (void)
{
FileData *fp;
CorpseData *c;
if ((fp = f_open (CORPSE_FILE, "w")) == NULL)
{
bug ("save_corpses: " CORPSE_FILE " not found.");
}
else
{
for (c = corpse_first; c != NULL; c = c->next)
{
if (c->corpse->item_type == ITEM_CORPSE_PC)
write_obj (NULL, c->corpse, fp, 0, 0, SAVE_CORPSE);
else
update_corpses (c->corpse, true);
}
f_printf (fp, "#" END_MARK LF);
f_close (fp);
}
return;
}
void
load_corpses (void)
{
FileData *fp;
log_string ("Loading corpses...");
if ((fp = f_open (CORPSE_FILE, "r")) == NULL)
{
bug ("load_corpses: " CORPSE_FILE " not found");
}
else
{
for (;;)
{
char letter;
char *word;
letter = read_letter (fp);
if (letter == '*')
{
read_to_eol (fp);
continue;
}
if (letter != '#')
{
bugf ("# not found. (%c)", letter);
break;
}
word = read_word (fp);
if (!str_cmp (word, get_obj_save_header (SAVE_CORPSE)))
read_obj (NULL, fp, SAVE_CORPSE);
else if (!str_cmp (word, END_MARK))
break;
else
{
bug ("load_corpses: bad section.");
break;
}
}
f_close (fp);
}
return;
}
void
update_corpses (ObjData * obj, bool pdelete)
{
if (obj && obj->item_type == ITEM_CORPSE_PC)
{
CorpseData *c;
for (c = corpse_first; c != NULL; c = c->next)
if (c->corpse == obj)
break;
if (c != NULL)
{
if (pdelete)
{
UnLink (c, corpse, next, prev);
free_corpse (c);
save_corpses ();
}
}
else if (obj->content_first != NULL && obj->in_room != NULL)
{
c = new_corpse ();
c->corpse = obj;
Link (c, corpse, next, prev);
save_corpses ();
}
}
return;
}
void
checkcorpse (CharData * ch)
{
CorpseData *c;
bool found = false;
int count = 0;
if (!ch || IsNPC (ch))
return;
for (c = corpse_first; c != NULL; c = c->next)
{
if (c->corpse && is_name (ch->name, c->corpse->owner))
{
found = true;
count++;
}
}
if (found)
{
chprintlnf
(ch, NEWLINE "{f{RWARNING:{x {WYou have %s in the game.{x",
intstr (count, "corpse"));
new_wiznet (ch, intstr (count, "corpse"), 0, 0, 0,
"$N has $t in the game.");
}
}