/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* Ground ZERO improvements copyright pending 1994, 1995 by James Hilke *
* *
* 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 *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "ground0.h"
#if !defined(macintosh)
extern int _filbuf args( (FILE *) );
#endif
/*
* Array of containers read for proper re-nesting of objects.
*/
#define MAX_NEST 100
static OBJ_DATA * rgObjNest [MAX_NEST];
/*
* Local functions.
*/
void fwrite_char args( ( CHAR_DATA *ch, FILE *fp ) );
void fwrite_obj args( ( CHAR_DATA *ch, OBJ_DATA *obj,
FILE *fp, int iNest ) );
void fread_char args( ( CHAR_DATA *ch, FILE *fp ) );
void fread_obj args( ( CHAR_DATA *ch, FILE *fp ) );
void set_default_pcdata args ((CHAR_DATA *ch));
void set_default_colors args ((CHAR_DATA *ch));
void set_char_defaults args ((CHAR_DATA *ch));
PC_DATA *alloc_pcdata args(());
CHAR_DATA *alloc_char args(());
void do_save_all (CHAR_DATA *ch, char *argument)
{
FILE *fp;
CHAR_DATA *chars_to_save;
OBJ_DATA *objs_to_save;
char buf[MAX_STRING_LENGTH];
int count_objs = 0, count_chars = 0;
int count;
/* form =
random number seed
max on
tick counter
expansions
!name1 kills killed rep x y level hp
vnum1 hpc1 hps1 vnum2 hpc2 hps2 . . . vnumN hpcN hpsN 0
!name2 kills killed rep x y level hp
vnum1 hpc1 hps1 vnum2 hpc2 hps2 . . . vnumN hpcN hpsN 0
.
.
!nameN kills killed rep x y level hp
vnum1 hpc1 hps1 vnum2 hpc2 hps2 . . . vnumN hpcN hpsN 0
~
vnum1 x y level hpc hps special#
vnum2 x y level hpc hps special#
.
.
vnum3 x y level hpc hps special#
0
special# is zero in general case, but can be assigned an arbitrary value to
be checked when loaded in for cases such as a mine burried under the ground,
etc that requires special action by the game
*/
if (ch)
send_to_char ("Saving EVERYTHING . . .\n\r", ch);
if ((fp = fopen ("../boot/fullsave.txt", "w")) == NULL)
{
if (ch)
send_to_char ("Error openning file fullsave.c.", ch);
return;
}
fprintf (fp, "%d\n%d\n%d\n%d\n", game_seed, max_on, tick_counter,
expansions);
for (chars_to_save = char_list; chars_to_save;
chars_to_save = chars_to_save->next)
{
/* don't save the imms cuz they come back untrusted which puts them
in a random room when they are kicked out of their god room for
being ld and untrusted */
if (IS_NPC (chars_to_save) || IS_IMMORTAL (chars_to_save))
continue;
count_chars++;
fprintf (fp, "!%s\n%d %d %d %d %d %d\n", chars_to_save->names,
chars_to_save->kills, chars_to_save->deaths,
chars_to_save->in_room->x,
chars_to_save->in_room->y,
chars_to_save->in_room->level,
chars_to_save->hit);
for (objs_to_save = chars_to_save->carrying; objs_to_save;
objs_to_save = objs_to_save->next_content)
{
count_objs++;
if (!objs_to_save->pIndexData->number_to_put_in)
continue;
fprintf (fp, "%d %d %d ", objs_to_save->pIndexData->vnum,
objs_to_save->hp_char, objs_to_save->hp_struct);
if (objs_to_save->contains)
{
count_objs++;
fprintf (fp, "%d %d %d ",
objs_to_save->contains->pIndexData->vnum,
objs_to_save->contains->hp_char,
objs_to_save->contains->hp_struct);
}
}
fprintf (fp, "0\n");
}
fprintf (fp, "~\n");
for (objs_to_save = object_list; objs_to_save;
objs_to_save = objs_to_save->next)
{
if (objs_to_save->carried_by)
continue;
if (!objs_to_save->pIndexData->number_to_put_in)
continue;
if (objs_to_save->in_room)
{
fprintf (fp, "%d %d %d %d %d %d", objs_to_save->pIndexData->vnum,
objs_to_save->in_room->x, objs_to_save->in_room->y,
objs_to_save->in_room->level, objs_to_save->hp_char,
objs_to_save->hp_struct);
count_objs++;
}
else
if (objs_to_save->destination)
{
fprintf (fp, "%d %d %d %d %d %d", objs_to_save->pIndexData->vnum,
objs_to_save->destination->x,
objs_to_save->destination->y,
objs_to_save->destination->level, objs_to_save->hp_char,
objs_to_save->hp_struct);
count_objs++;
}
else
{
/* otherwise it is ammo in a weapon and should have been gotten
when characters were saved */
continue;
}
if (IS_SET (objs_to_save->general_flags, GEN_CAN_BURY) &&
(objs_to_save->destination) &&
(objs_to_save->destination->mine == objs_to_save))
fprintf (fp, " 1\n");
else
fprintf (fp, " 0\n");
}
fprintf (fp, "0\n");
fclose (fp);
sprintf (buf, "%%%d objects and %d characters were saved.\n\r", count_objs,
count_chars);
do_immtalk (NULL, buf);
log_string (&(buf[1]));
if (ch)
send_to_char ("Done.\n\r", ch);
}
/*
* Save a character and inventory.
* Would be cool to save NPC's too for quest purposes,
* some of the infrastructure is provided.
*/
void save_char_obj( CHAR_DATA *ch )
{
char strsave[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
FILE *fp;
if ( IS_NPC(ch) )
return;
if ( ch->desc != NULL && ch->desc->original != NULL )
ch = ch->desc->original;
/* create god log */
if (ch->trust)
{
fclose(fpReserve);
sprintf(strsave, "%sPS%s",GOD_DIR, capitalize(ch->names));
if ((fp = fopen(strsave,"w")) == NULL)
{
bug("Save_char_obj: fopen",0);
perror(strsave);
}
fprintf(fp,"Trust %2d %s%s\n",
get_trust(ch), ch->names, ch->pcdata->title_line);
fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
}
fclose( fpReserve );
sprintf( strsave, "%sPS%s", PLAYER_DIR, capitalize( ch->names ) );
if ( ( fp = fopen( PLAYER_TEMP, "w" ) ) == NULL )
{
bug( "Save_char_obj: fopen", 0 );
perror( strsave );
}
else
{
fwrite_char( ch, fp );
fprintf (fp, "#END\n");
}
fclose( fp );
/* move the file */
sprintf(buf,"mv %s %s",PLAYER_TEMP,strsave);
system(buf);
fpReserve = fopen( NULL_FILE, "r" );
return;
}
/*
* Write the char.
*/
void fwrite_char( CHAR_DATA *ch, FILE *fp )
{
AFFECT_DATA *paf;
int sn, gn;
fprintf( fp, "#PLAYER\n");
fprintf( fp, "Name %s~\n", ch->names );
if (ch->short_descript && ch->short_descript[0])
fprintf( fp, "ShD %s~\n", ch->short_descript);
fprintf( fp, "Sex %d\n", ch->sex );
fprintf (fp, "nhp_solo %d\n", ch->pcdata->solo_hit);
if (ch->kills)
fprintf (fp, "Kills2 %d\n", ch->kills);
if (ch->deaths)
fprintf (fp, "Killed2 %d\n", ch->deaths);
fprintf( fp, "Plyd %d\n",
ch->played + (int) (current_time - ch->logon) );
fprintf( fp, "Note %d\n", ch->last_note );
fprintf( fp, "Scro %d\n", ch->lines );
if (ch->act != 0)
fprintf( fp, "Act %d\n", ch->act );
if (ch->invis_level != 0)
fprintf( fp, "Invi %d\n", ch->invis_level );
fprintf( fp, "Pass %s~\n", ch->pcdata->password);
if (ch->kill_msg)
fprintf( fp, "KillMsg %s~\n", ch->kill_msg);
if (ch->pcdata->account)
fprintf (fp, "Account %s~\n", ch->pcdata->account);
if (ch->pcdata->poofin_msg && ch->pcdata->poofin_msg[0])
fprintf( fp, "Bin %s~\n", ch->pcdata->poofin_msg);
if (ch->pcdata->poofout_msg && ch->pcdata->poofout_msg[0])
fprintf( fp, "Bout %s~\n", ch->pcdata->poofout_msg);
fprintf( fp, "Titl %s~\n", ch->pcdata->title_line );
fprintf( fp, "Color %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
ch->color,
ch->pcdata->color_hp,
ch->pcdata->color_desc,
ch->pcdata->color_obj,
ch->pcdata->color_action,
ch->pcdata->color_combat_o,
ch->pcdata->color_combat_condition_s,
ch->pcdata->color_combat_condition_o,
ch->pcdata->color_xy,
ch->pcdata->color_wizi,
ch->pcdata->color_level,
ch->pcdata->color_exits,
ch->pcdata->color_say,
ch->pcdata->color_tell,
ch->pcdata->color_reply);
fprintf (fp, "End\n\n");
}
CHAR_DATA *alloc_char ()
{
CHAR_DATA *temp;
if ( char_free == NULL )
return alloc_perm( sizeof(CHAR_DATA) );
else
{
temp = char_free;
char_free = char_free->next;
return temp;
}
}
PC_DATA *alloc_pcdata ()
{
PC_DATA *temp;
if ( pcdata_free == NULL )
return alloc_perm( sizeof(PC_DATA) );
else
{
temp = pcdata_free;
pcdata_free = pcdata_free->next;
return temp;
}
}
void set_char_defaults (CHAR_DATA *ch)
{
ch->move_delay = 0;
ch->where_start = NULL;
ch->valid = VALID_VALUE;
ch->ld_behavior = 0;
ch->affected_by = 0;
ch->temp_flags = 0;
ch->act = 0;
ch->comm = COMM_COMBINE | COMM_PROMPT;
ch->invis_level = 0;
ch->trust = 0;
ch->armor = 0;
ch->last_fight = 0;
}
void set_default_colors (CHAR_DATA *ch)
{
ch->pcdata->color_combat_condition_s= 0x1;
ch->pcdata->color_action = 0x9;
ch->pcdata->color_xy = 0xe;
ch->pcdata->color_wizi = 0x4;
ch->pcdata->color_hp = 0x5;
ch->pcdata->color_combat_condition_o = 0x8;
ch->pcdata->color_combat_o = 0xd;
ch->pcdata->color_level = 0x8;
ch->pcdata->color_exits = 0x9;
ch->pcdata->color_desc = 0xa;
ch->pcdata->color_obj = 0xb;
ch->pcdata->color_say = 0xc;
ch->pcdata->color_tell = 0x0;
ch->pcdata->color_reply = 0x1;
}
void set_default_pcdata (CHAR_DATA *ch)
{
ch->pcdata->confirm_delete = FALSE;
ch->pcdata->password = NULL;
ch->pcdata->poofin_msg = NULL;
ch->pcdata->poofin_msg = NULL;
ch->pcdata->title_line = NULL;
ch->pcdata->account = NULL;
ch->pcdata->solo_hit = HIT_POINTS_MORTAL;
}
/*
* Load a char and inventory into a new ch structure.
*/
CHAR_DATA *load_char_obj( DESCRIPTOR_DATA *d, char *name )
{
static PC_DATA pcdata_zero;
char strsave[MAX_INPUT_LENGTH];
char buf[100];
CHAR_DATA *ch;
FILE *fp;
bool found;
int stat;
ch = alloc_char ();
clear_char(ch);
ch->pcdata = alloc_pcdata ();
*ch->pcdata = pcdata_zero;
if (d)
{
d->character = ch;
ch->desc = d;
}
else
ch->desc = NULL;
ch->names = str_dup (name);
set_char_defaults (ch);
ch->color = 1;
set_default_colors (ch);
set_default_pcdata (ch);
found = FALSE;
fclose( fpReserve );
#if defined(unix)
/* decompress if .gz file exists */
sprintf( strsave, "%sPS%s%s", PLAYER_DIR, capitalize(name),".gz");
if ( ( fp = fopen( strsave, "r" ) ) != NULL )
{
fclose(fp);
sprintf(buf,"gzip -dfq %s",strsave);
system(buf);
}
#endif
sprintf( strsave, "%sPS%s", PLAYER_DIR, capitalize( name ) );
if ( ( fp = fopen( strsave, "r" ) ) != NULL )
{
int iNest;
for ( iNest = 0; iNest < MAX_NEST; iNest++ )
rgObjNest[iNest] = NULL;
found = TRUE;
/* freed from above, will be found in pfile */
free_string (ch->names);
ch->names = NULL;
for ( ; ; )
{
char letter;
char *word;
letter = fread_letter( fp );
if ( letter == '*' )
{
fread_to_eol( fp );
continue;
}
if ( letter != '#' )
{
bug( "Load_char_obj: # not found.", 0 );
break;
}
word = fread_word( fp );
if ( !str_cmp( word, "PLAYER" ) ) fread_char ( ch, fp );
else if ( !str_cmp( word, "END" ) ) break;
else
{
bug( "Load_char_obj: bad section.", 0 );
break;
}
}
fclose( fp );
}
fpReserve = fopen( NULL_FILE, "r" );
if (found)
return ch;
else
return 0;
}
/*
* Read in a char.
*/
#if defined(KEY)
#undef KEY
#endif
#define KEY( literal, field, value ) \
if ( !str_cmp( word, literal ) ) \
{ \
field = value; \
fMatch = TRUE; \
break; \
}
#define IGNORE(literal) \
if ( !str_cmp( word, literal ) ) \
{ \
fMatch = TRUE; \
fread_to_eol (fp); \
break; \
}
void fread_char( CHAR_DATA *ch, FILE *fp )
{
char buf[MAX_STRING_LENGTH];
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( "Act", ch->act, fread_number( fp ) );
KEY( "Account", ch->pcdata->account, fread_string(fp));
case 'B':
KEY( "Bamfin", ch->pcdata->poofin_msg, fread_string( fp ) );
KEY( "Bamfout", ch->pcdata->poofout_msg,fread_string( fp ) );
KEY( "Bin", ch->pcdata->poofin_msg, fread_string( fp ) );
KEY( "Bout", ch->pcdata->poofout_msg,fread_string( fp ) );
break;
case 'C':
if ( !str_cmp( word, "Color"))
{
log_string("Reading colors");
ch->color = fread_number( fp );
ch->pcdata->color_hp = fread_number( fp );
ch->pcdata->color_desc = fread_number( fp );
ch->pcdata->color_obj = fread_number( fp );
ch->pcdata->color_action = fread_number( fp );
ch->pcdata->color_combat_o = fread_number( fp );
ch->pcdata->color_combat_condition_s = fread_number( fp );
ch->pcdata->color_combat_condition_o = fread_number( fp );
ch->pcdata->color_xy = fread_number( fp );
ch->pcdata->color_wizi = fread_number( fp );
ch->pcdata->color_level = fread_number( fp );
ch->pcdata->color_exits = fread_number( fp );
ch->pcdata->color_say = fread_number( fp );
ch->pcdata->color_tell = fread_number( fp );
ch->pcdata->color_reply = fread_number( fp );
fMatch=TRUE;
break;
}
break;
case 'E':
if ( !str_cmp( word, "End" ) )
return;
break;
case 'H':
IGNORE ("hp_solo");
/* KEY ("hp_solo", ch->pcdata->solo_hit, fread_number (fp));*/
break;
case 'I':
KEY( "InvisLevel", ch->invis_level, fread_number( fp ) );
KEY( "Invi", ch->invis_level, fread_number( fp ) );
break;
case 'K':
IGNORE ("Killed");
IGNORE ("Kills");
KEY ("Kills2", ch->kills, fread_number(fp));
KEY ("Killed2", ch->deaths, fread_number(fp));
KEY( "KillMsg", ch->kill_msg, fread_string( fp ) );
break;
case 'N':
KEY( "Name", ch->names, fread_string( fp ) );
KEY ("nhp_solo", ch->pcdata->solo_hit, fread_number (fp));
KEY( "Note", ch->last_note, fread_number( fp ) );
break;
case 'P':
KEY( "Password", ch->pcdata->password, fread_string( fp ) );
KEY( "Pass", ch->pcdata->password, fread_string( fp ) );
KEY( "Played", ch->played, fread_number( fp ) );
KEY( "Plyd", ch->played, fread_number( fp ) );
break;
case 'S':
KEY( "Scro", ch->lines, fread_number( fp ) );
KEY( "Sex", ch->sex, fread_number( fp ) );
KEY( "ShortDescr", ch->short_descript, fread_string( fp ) );
KEY( "ShD", ch->short_descript, fread_string( fp ) );
break;
case 'T':
KEY( "Trust", ch->trust, fread_number( fp ) );
KEY( "Tru", ch->trust, fread_number( fp ) );
if ( !str_cmp( word, "Title" ) || !str_cmp( word, "Titl"))
{
ch->pcdata->title_line = fread_string(fp);
if (ch->pcdata->title_line[0] != '.' &&
ch->pcdata->title_line[0] != ',' &&
ch->pcdata->title_line[0] != '!' &&
ch->pcdata->title_line[0] != '?')
{
sprintf( buf, " %s", ch->pcdata->title_line );
free_string (ch->pcdata->title_line);
ch->pcdata->title_line = str_dup (buf);
}
fMatch = TRUE;
break;
}
break;
}
if ( !fMatch )
{
bug( "Fread_char: no match.", 0 );
fread_to_eol( fp );
}
}
}
void save_account_list ()
{
FILE *fp;
ACCOUNT_DATA *tracker;
if ((fp = fopen (ACCOUNTS_FILE, "w")) == NULL)
return;
fprintf (fp, "#ACCOUNTS\n");
for (tracker = accounts_list; tracker; tracker = tracker->next)
fprintf (fp, "%s %s\n", tracker->login, tracker->password);
fprintf (fp, "$\n\n#$\n\n");
fclose (fp);
}