/*************************************************************************** * 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. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * 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. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * 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. * ***************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "globals.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 #define AREA_VERSION 17 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 ); xprintf( 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 */ xprintf( 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, "Q %i\n", AREA_VERSION ); 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 ); /* * 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 ); fprintf( SaveFile, "| %i %i %i %i %i %i %i\n", pMobIndex->strong_magic, pMobIndex->weak_magic, pMobIndex->race_mods, pMobIndex->power_skills, pMobIndex->power_cast, pMobIndex->resist, pMobIndex->suscept ); 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 ); fprintf( SaveFile, "%0.2f\n", pObject->speed ); /* * 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 %i %i %i %i %i %i\n", val0, val1, val2, val3, pObject->value[4], pObject->value[5], pObject->value[6], pObject->value[7], pObject->value[8], pObject->value[9] ); 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]; xprintf( 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 */ xprintf( filename, "%s.old", CurSaveArea->filename ); rename( CurSaveArea->filename, filename ); /* * And rename .new to area filename */ xprintf( 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; }