ack42/
ack42/npcs/a/
ack42/npcs/c/
ack42/npcs/e/
ack42/npcs/f/
ack42/npcs/h/
ack42/npcs/i/
ack42/npcs/l/
ack42/npcs/n/
ack42/npcs/o/
ack42/npcs/p/
ack42/npcs/r/
ack42/npcs/s/
ack42/npcs/w/
ack42/player/c/
ack42/player/s/
ack42/player/z/
/* Mod'ed to save two copies of area... one in Ack! format, and one
 * in 'Standard' Envy format... -S-
 */

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"



/* Way this works:
	Mud reads in area files, stores details in data lists.
	Edit rooms, objects, resets.
	type savearea.
	Sets bool saving_area to true.
	Incrementally saves an area, using data lists.
*/
	

#define SAVEQUEUESIZE 50
#define NOT_SAVING 0
#define START_SAVING 1
#define AM_SAVING 2
#define BUILD_OK -1
#define BUILD_CANTSAVE 1
#define BUILD_TOOMANY  2

#define BUILD_SEC_AREA     1 
#define BUILD_SEC_HELP     2
#define BUILD_SEC_ROOMS    3
#define BUILD_SEC_MOBILES  4
#define BUILD_SEC_MOBPROGS 5
#define BUILD_SEC_OBJECTS  6
#define BUILD_SEC_SHOPS    7
#define BUILD_SEC_RESETS   8
#define BUILD_SEC_SPECIALS 9
#define BUILD_SEC_OBJFUNS  10	/* -S- Mod */
#define BUILD_SEC_END      11


struct save_queue_type
{
   AREA_DATA * area;
   CHAR_DATA * ch;
   int         loops;
} SaveQ[SAVEQUEUESIZE];

/* Semi-local vars. */
int saving_area=0;

/* local */
int 		offset;
int             ToBeSaved=0;
int             CurrentSaving=-1;
AREA_DATA     * CurSaveArea=NULL;
CHAR_DATA     * CurSaveChar=NULL;
int             CurLoops=1;
int             Section;
BUILD_DATA_LIST * Pointer;
RESET_DATA    * ResetPointer;
FILE          * SaveFile;
FILE	      * Envy;
int             AreasModified=0;

/* Local functions */
/* void build_save(); proto in merc.h */
void build_save_area(void);
void build_save_help(void);
void build_save_mobs(void);
void build_save_mobprogs(void);
void build_save_objects(void);
void build_save_rooms(void);
void build_save_shops(void);
void build_save_resets(void);
void build_save_specs(void);
void build_save_objfuns(void);
void build_save_end(void);
char * mprog_type_to_name(int);
void vuild_save_flush(void);
/*  int convert(int lev); */
/* Convert levels from ack -> envy! */

/* int  convert(int lev)	*/
/*  { 		*/
/*   return( lev - ( lev/5 ) ); 	*/
/* }   */   
   
void do_savearea( CHAR_DATA *ch, char *argument )
{
     AREA_DATA * SaveArea;
     int loops;
/*     char first_arg[MAX_INPUT_LENGTH]; unused? */
     

     if (ch==NULL)
     {
       SaveArea=(AREA_DATA *) argument;   
       loops=10;
     }
     else
     {      
      if (ch->in_room==NULL)
       {
        send_to_char("Do not know what room you are in!!, cannot save.\n",ch);
        return;
       }
       
      SaveArea=(ch->in_room)->area;
      if (SaveArea==NULL)
       {
        send_to_char("Do not know what area you are in!!, cannot save.\n",ch);
        return;
       }
      
      if (*argument != '\0')
       {
        loops=atoi(argument);
        if (loops<1)
 	loops=1;
       }
      else
       loops=1;
     }

     if (ToBeSaved==CurrentSaving)
       {
	 send_to_char("Too many areas in queue, please try later.\n",ch);
	 return; 
       }
       
     SaveQ[ToBeSaved].area=SaveArea;
     SaveQ[ToBeSaved].ch=ch;
     SaveQ[ToBeSaved].loops=loops;
     ToBeSaved=(ToBeSaved + 1) % SAVEQUEUESIZE;

     if (saving_area==NOT_SAVING)
      saving_area=START_SAVING;
     else
      send_to_char("Save is queued, please wait. \n",ch);
     
     build_save();
     return;
}

void build_save()
{
  int a;
  char filename[255];
  char buf[MAX_STRING_LENGTH];
  
  for (a=0;a<CurLoops && saving_area>0;a++)
  { 

   if ( saving_area== START_SAVING)
     {
       CurrentSaving=(CurrentSaving+1) % SAVEQUEUESIZE;
       CurSaveArea=SaveQ[CurrentSaving].area;
       CurSaveChar=SaveQ[CurrentSaving].ch;
       CurLoops=SaveQ[CurrentSaving].loops;
       send_to_char("Starting Save.\n",CurSaveChar);
       
       sprintf(filename,"%s.new",CurSaveArea->filename);
       SaveFile=fopen(filename,"w");
       if (SaveFile==NULL)
	{
	 if (CurrentSaving==ToBeSaved)
	  saving_area=NOT_SAVING;
	 send_to_char("Can not open file for saving.\n",CurSaveChar);
	 return;
	}
	/* Open second file for saving in envy format */
	
       sprintf( buf, "Starting to save %s", CurSaveArea->filename );
       monitor_chan( buf, MONITOR_AREA_SAVING );
	
	
	Section=1;
	offset=CurSaveArea->offset;
	saving_area=AM_SAVING;
	Pointer=NULL;
	ResetPointer=NULL;
      }

    switch (Section)
     {
       case BUILD_SEC_AREA:     build_save_area();     break;
       case BUILD_SEC_HELP:     build_save_help();     break;
       case BUILD_SEC_ROOMS:    build_save_rooms();    break;
       case BUILD_SEC_MOBILES:  build_save_mobs();     break;
       case BUILD_SEC_MOBPROGS: build_save_mobprogs(); break;
       case BUILD_SEC_OBJECTS:  build_save_objects();  break;
       case BUILD_SEC_SHOPS:    build_save_shops();    break;
       case BUILD_SEC_RESETS:   build_save_resets();   break;
       case BUILD_SEC_SPECIALS: build_save_specs();    break;
       case BUILD_SEC_OBJFUNS:  build_save_objfuns();  break;
       case BUILD_SEC_END:      build_save_end();      break;
     }
   }
   return;
}

	    

void build_save_area()
{
     fprintf(SaveFile,"#AREA\n");
     fprintf(SaveFile,"%s~\n",CurSaveArea->name);
     fprintf(SaveFile,"K %s~\n",CurSaveArea->keyword);
     fprintf(SaveFile,"L %s~\n",CurSaveArea->level_label);
     fprintf(SaveFile,"N %i\n",CurSaveArea->area_num);
     fprintf(SaveFile,"I %i %i\n",CurSaveArea->min_level,CurSaveArea->max_level);
     fprintf(SaveFile,"V %i %i\n",CurSaveArea->min_vnum,CurSaveArea->max_vnum);
     fprintf(SaveFile,"X %i\n", CurSaveArea->offset );
     fprintf(SaveFile,"F %i\n", CurSaveArea->reset_rate );
     fprintf(SaveFile,"U %s~\n",CurSaveArea->reset_msg );
     if (CurSaveArea->owner != NULL)
        fprintf(SaveFile,"O %s~\n",CurSaveArea->owner);
     if (CurSaveArea->can_read != NULL)
        fprintf(SaveFile,"R %s~\n",CurSaveArea->can_read);
     if (CurSaveArea->can_write != NULL)
        fprintf(SaveFile,"W %s~\n",CurSaveArea->can_write);
     if (IS_SET(CurSaveArea->flags,AREA_PAYAREA))
        fprintf(SaveFile,"P This is a pay area.\n");
     if (IS_SET(CurSaveArea->flags,AREA_TELEPORT))
        fprintf(SaveFile,"T You can teleport into here\n");
     if (IS_SET(CurSaveArea->flags,AREA_BUILDING))
        fprintf(SaveFile,"B Currently building area.\n");
     if ( IS_SET( CurSaveArea->flags, AREA_NOSHOW ) )
        fprintf( SaveFile, "S Title not shown on area list.\n" ); 
     if ( IS_SET( CurSaveArea->flags, AREA_NO_ROOM_AFF ) )
        fprintf( SaveFile, "M No bad room spells allowed.\n" ); 
 
     
/*     fprintf( Envy, "#AREA\n" );                      remove save bug */
/*     fprintf( Envy, "%s~\n", CurSaveArea->name );                     */
      
     Section++;
}

void build_save_help()
{
     HELP_DATA *pHelp;

     if (Pointer==NULL) /* Start */
     {
      if (CurSaveArea->first_area_help_text==NULL)
       {
	Section++;
	return;
       }
      send_to_char("Saving help section.\n",CurSaveChar);
      fprintf(SaveFile,"#HELPS\n");
      Pointer=CurSaveArea->first_area_help_text;
     }

     pHelp=Pointer->data;
     fprintf(SaveFile,"%i %s~\n",pHelp->level,pHelp->keyword);
     if (isspace(pHelp->text[0]))
      fprintf(SaveFile,".%s~\n",pHelp->text);
     else
      fprintf(SaveFile,"%s~\n",pHelp->text);

     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"0 $~\n");
       Section++;
      }
     /* No saving helps for envy format */
     
     return;
}

void build_save_mobs()
{
     MOB_INDEX_DATA *pMobIndex;
     MPROG_DATA* mprg;
     int finish_progs;
     
     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_mobile==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving mobs.\n",CurSaveChar);
       fprintf(SaveFile,"#MOBILES\n");
       Pointer=CurSaveArea->first_area_mobile;
      }

     pMobIndex=Pointer->data;
     fprintf(SaveFile,"#%i\n",pMobIndex->vnum);
     fprintf(SaveFile,"%s~\n",pMobIndex->player_name);
     fprintf(SaveFile,"%s~\n",pMobIndex->short_descr);
     fprintf(SaveFile,"%s~\n",pMobIndex->long_descr);
     fprintf(SaveFile,"%s~\n",pMobIndex->description);
     fprintf(SaveFile,"%i %i %i S\n",pMobIndex->act,
			 pMobIndex->affected_by,pMobIndex->alignment);
     fprintf(SaveFile,"%i %i\n",pMobIndex->level,pMobIndex->sex);
     fprintf(SaveFile,"%i %i %i\n",pMobIndex->ac_mod, pMobIndex->hr_mod,
			 pMobIndex->dr_mod);

     /* Save in Envy format.... */
/*     fprintf(Envy,"#%i\n",((pMobIndex->vnum)+offset) );      */
/*     fprintf(Envy,"%s~\n",pMobIndex->player_name);           */
/*     fprintf(Envy,"%s~\n",pMobIndex->short_descr);           */
/*     fprintf(Envy,"%s~\n",pMobIndex->long_descr);   	       */
/*     fprintf(Envy,"%s~\n",pMobIndex->description);           */
/*     fprintf(Envy,"%i %i %i S\n",pMobIndex->act,             */
/*			 pMobIndex->affected_by,pMobIndex->alignment); */
/*     fprintf(Envy,"%i 0 0 0d0+0 0d0+0\n0 0\n0 0       */
/*     		%i\n",convert(pMobIndex->level),pMobIndex->sex);   */
     

   /* Write out new details - clan, class, race and skills
    * The '!' signifies new section to load_mobiles() in db.c
    */
    

   fprintf( SaveFile, "! %i %i %i %i %i %i %i\n",
      pMobIndex->class, 
      pMobIndex->clan, 
      pMobIndex->race,
      pMobIndex->position,
      pMobIndex->skills,
      pMobIndex->cast,
      pMobIndex->def );
     
     
     mprg=pMobIndex->first_mprog;
     finish_progs=0;
     while (mprg)
      {
       if (mprg->filename == NULL)
	{
	 fprintf(SaveFile,">%s ",mprog_type_to_name(mprg->type));
	 fprintf(SaveFile,"%s~\n",mprg->arglist);
	 fprintf(SaveFile,"%s~\n",mprg->comlist);
	 finish_progs=1;
	}
       mprg=mprg->next;
      }
     if (finish_progs)
     {
       fprintf(SaveFile,"|\n");
     }


     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"#0\n");
       Section++;
      }
      return;
}

void build_save_mobprogs()
{
     MOB_INDEX_DATA * pMobIndex;
     MOBPROG_ITEM   * pItem;

     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_mobprog==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving mobprogs.\n",CurSaveChar);
       fprintf(SaveFile,"#MOBPROGS\n");
       
       Pointer=CurSaveArea->first_area_mobprog;
      }

     pItem=Pointer->data;
     pMobIndex=pItem->mob;
     
     fprintf(SaveFile,"M %i %s\n",pMobIndex->vnum,pItem->filename);

     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"S\n");
       Section++;
      }
      return;
}

void build_save_objects()
{
     OBJ_INDEX_DATA *pObject;
     AFFECT_DATA * pAf;
     EXTRA_DESCR_DATA *pEd;
     int val0,val1,val2,val3;

     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_object==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving objects.\n",CurSaveChar);
       fprintf(SaveFile,"#OBJECTS\n");
       Pointer=CurSaveArea->first_area_object;
      }

     pObject=Pointer->data;
     
     fprintf(SaveFile,"#%i\n",pObject->vnum);
     fprintf(SaveFile,"%s~\n",pObject->name);
     fprintf(SaveFile,"%s~\n",pObject->short_descr);
     fprintf(SaveFile,"%s~\n",pObject->description);
     fprintf(SaveFile,"%i %i %i %i\n",pObject->item_type,pObject->extra_flags,
					pObject->wear_flags,pObject->item_apply);

     /* Check for pills, potions, scrolls, staffs and wands.  */
     val0=pObject->value[0];
     val1=pObject->value[1];
     val2=pObject->value[2];
     val3=pObject->value[3];
	switch ( pObject->item_type )
	{
	case ITEM_PILL:
	case ITEM_POTION:
	case ITEM_SCROLL:
	 val1=val1<0 ? -1 : skill_table[val1].slot;
	 val2=val2<0 ? -1 : skill_table[val2].slot;
	 val3=val3<0 ? -1 : skill_table[val3].slot;
	    break;

	case ITEM_STAFF:
	case ITEM_WAND:
	 val3=val3<0 ? -1 : skill_table[val3].slot;
	    break;
	}
     fprintf(SaveFile,"%i %i %i %i\n",val0,val1,val2,val3);
     fprintf(SaveFile,"%i\n",pObject->weight);
     
     
     pAf=pObject->first_apply;
     while (pAf)
      {
       fprintf(SaveFile,"A\n");
       fprintf(SaveFile,"%i %i\n",pAf->location,pAf->modifier);
       pAf=pAf->next;
      }

     pEd=pObject->first_exdesc;
     while (pEd)
      {
       fprintf(SaveFile,"E\n");
       fprintf(SaveFile,"%s~\n",pEd->keyword);
       fprintf(SaveFile,"%s~\n",pEd->description);
       pEd=pEd->next;
      }

       if ( ( pObject->level > 1 ) && (pObject->level < 130 ) )
       {
         fprintf(SaveFile, "L\n");
         fprintf(SaveFile,"%d\n",pObject->level);
       }
       else
       {
         fprintf(SaveFile, "L\n");
         fprintf(SaveFile,"%d\n", 1);
       }

      /* Now for Envy... taken from my OLC :P */

     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"#0\n");
       Section++;
      }
     
     return;
}
     
void build_save_rooms()
{
     ROOM_INDEX_DATA *pRoomIndex;
     EXTRA_DESCR_DATA *pEd;
     int d;
     EXIT_DATA *pexit;
     int locks=0;

     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_room==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving rooms.\n",CurSaveChar);
       fprintf(SaveFile,"#ROOMS\n");
       Pointer=CurSaveArea->first_area_room;
      }

     pRoomIndex=Pointer->data;
     
     fprintf(SaveFile,"#%i\n",pRoomIndex->vnum);
     fprintf(SaveFile,"%s~\n",pRoomIndex->name);
     fprintf(SaveFile,"%s~\n",pRoomIndex->description);
     fprintf(SaveFile,"%i %i\n",pRoomIndex->room_flags,pRoomIndex->sector_type);

     /* Now do doors. */
     for (d=0;d<6;d++)
      {
       if (pRoomIndex->exit[d] )
       {
	 
	 fprintf(SaveFile,"D%i\n",d);
	 pexit=pRoomIndex->exit[d];
	 fprintf(SaveFile,"%s~\n",pexit->description);
	 fprintf(SaveFile,"%s~\n",pexit->keyword);
	 /* Deal with locks */
	 /* -S- Mod: Filter out EX_LOCKED and EX_CLOSED and save exit_info */
	 locks=pexit->exit_info;
	 if ( IS_SET( locks, EX_CLOSED ) )
	    REMOVE_BIT( locks, EX_CLOSED );
	 if ( IS_SET( locks, EX_LOCKED ) )
	    REMOVE_BIT( locks, EX_LOCKED );
	 
	 #if 0 
	 /* BUG: before, an isdoor OR pickproof flag alone would give locks=1 */
	 if (pexit->exit_info & EX_ISDOOR)
	  locks++;
	 if (pexit->exit_info & EX_PICKPROOF)
	  locks++;
         #endif
     
     	 fprintf(SaveFile,"%i %i %i\n",locks,pexit->key,pexit->vnum);
	}
       }

     /* Now do extra descripts.. */
	 
     pEd=pRoomIndex->first_exdesc;
     while (pEd)
      {
       fprintf(SaveFile,"E\n");
       fprintf(SaveFile,"%s~\n",pEd->keyword);
       fprintf(SaveFile,"%s~\n",pEd->description);
       pEd=pEd->next;
      }

     /* End of one room */
     fprintf(SaveFile,"S\n");

     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"#0\n");
       Section++;
      }
      return;
}

void build_save_shops()
{
     SHOP_DATA *pShop;
     int iTrade;
     
     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_shop==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving shops.\n",CurSaveChar);
       fprintf(SaveFile,"#SHOPS\n");
       Pointer=CurSaveArea->first_area_shop;
      }
    
     pShop=Pointer->data;
     fprintf(SaveFile,"%i ",pShop->keeper);
     for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
      fprintf(SaveFile,"%i ",pShop->buy_type[iTrade]);
     fprintf(SaveFile,"%i %i %i %i\n",pShop->profit_buy,pShop->profit_sell,
			       pShop->open_hour,pShop->close_hour);
     
     
     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"0\n");
       Section++;
      }
      return;
}

void build_save_specs()
{
     MOB_INDEX_DATA *pMob;
     
     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_specfunc==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving specials.\n",CurSaveChar);
       fprintf(SaveFile,"#SPECIALS\n");
       Pointer=CurSaveArea->first_area_specfunc;
      }
    
     pMob=Pointer->data;

     fprintf(SaveFile,"M %i ",pMob->vnum);
     fprintf(SaveFile,"%s\n",rev_spec_lookup(pMob->spec_fun));


     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
          fprintf(SaveFile,"S\n");
          Section++;
      }
      return;
}

void build_save_objfuns()
{
     OBJ_INDEX_DATA *pObj;
     
     if (Pointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_area_objfunc==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving objfuns.\n",CurSaveChar);
       fprintf( SaveFile, "#OBJFUNS\n" );
       Pointer=CurSaveArea->first_area_objfunc;
      }
    
     pObj=Pointer->data;

     fprintf(SaveFile,"O %i ",pObj->vnum);
     fprintf(SaveFile,"%s\n",rev_obj_fun_lookup(pObj->obj_fun));

     Pointer=Pointer->next;
     if (Pointer==NULL) /* End */
      {
       fprintf(SaveFile,"S\n");
       Section++;
      }
      return;
}

void build_save_resets()
{
     if (ResetPointer==NULL)  /* Start */
      {
       if (CurSaveArea->first_reset==NULL)
	{
	 Section++;
	 return;
	}
       send_to_char("Saving resets.\n",CurSaveChar);
       fprintf(SaveFile,"#RESETS\n");
       ResetPointer=CurSaveArea->first_reset;
      }

     fprintf(SaveFile,"%c %i %i %i ",ResetPointer->command,ResetPointer->ifflag,
	       			         ResetPointer->arg1,   ResetPointer->arg2);
     if (ResetPointer->command=='G' || ResetPointer->command=='R')
	fprintf(SaveFile,"%s\n",ResetPointer->notes);
     else
	fprintf(SaveFile,"%i %s\n",ResetPointer->arg3,ResetPointer->notes);

     ResetPointer=ResetPointer->next;
     if (ResetPointer==NULL)  /* End */
      {
       fprintf(SaveFile,"S\n");
       Section++;
      }
     return;
}
     
void build_save_end()
{
     char filename[255];
     char buf[MAX_STRING_LENGTH];

     sprintf( buf, "Finished saving %s", CurSaveArea->filename );
     monitor_chan( buf, MONITOR_AREA_SAVING );
     
     fprintf(SaveFile,"#$\n");
     send_to_char("Finished saving.\n",CurSaveChar);
     fclose(SaveFile);
     /* Save backup */
     sprintf(filename,"%s.old",CurSaveArea->filename);
     rename(CurSaveArea->filename,filename);
     /* And rename .new to area filename */
     sprintf(filename,"%s.new",CurSaveArea->filename);
     rename(filename,CurSaveArea->filename);
     
     Section=0;
     if (ToBeSaved==(CurrentSaving+1) % SAVEQUEUESIZE)
       saving_area=NOT_SAVING;
     else
       saving_area=START_SAVING;
}

     
void build_save_flush()
{
    AREA_DATA * pArea;
    
    if (AreasModified == 0)
     return;
    
    for (pArea=first_area; pArea != NULL; pArea=pArea->next)
    {
     if (pArea->modified)
      {
       pArea->modified=0;
       do_savearea(NULL,(char *) pArea);
      }
    }
    
    AreasModified=0;
}

void area_modified(AREA_DATA * pArea)
{
   pArea->modified=1;
   AreasModified=1;
}