/
/****************************************************
 * Original Copyover patch by Erwin Andreasen.      *
 * This provides some changes, and easy installation*
 * instructions, and works for 1.4, and 1.4a.       *
 * --Callidyrr                                      *
 ****************************************************/

/* db.c */

change
void boot_db( void )
to this
void boot_db( bool fCopyOver )

search for
        load_morphs( );
        MOBtrigger = TRUE;
add this underneat it
        if (fCopyOver)
        {
          log_string("Running copyover_recover.");
          copyover_recover();
        }

/* mud.h */

search for
#define TOGGLE_BIT(var, bit)    ((var) ^= (bit))
add this underneath it
#define CH(d)                  ((d)->original ? (d)->original : (d)->character)

search for
#define PLANE_FILE      SYSTEM_DIR "planes.dat"   /* For planes          */
add this underneath it
#define COPYOVER_FILE  SYSTEM_DIR "copyover.dat" /* for warm reboots    */
#define EXE_FILE       "../src/smaug"            /* executable path     */

search for
void    act             args( ( sh_int AType, const char *format, CHAR_DATA *ch,
                            const void *arg1, const void *arg2, int type ) );
add this underneath it
void   copyover_recover        args( (void) );

search for
void    boot_db         args( ( void ) );
change to
void    boot_db         args( ( bool fCopyOver ) );

search for
void    ch_printf_color args( ( CHAR_DATA *ch, char *fmt, ... ) );
add this underneath it
void   log_printf      args( (char *fmt, ...) );

search for
CON_READ_IMOTD
add this after it (remember to put a comma after CON_READ_IMOTD (or the last constate..whichever it may be))
CON_COPYOVER_RECOVER

search for
DECLARE_DO_FUN( do_compare      );
underneath it, add this
DECLARE_DO_FUN( do_copyover     );

/* comm.c */

search for
    char hostn[128];
add this underneath it
    bool fCopyOver = !TRUE;

search for
        if ( !is_number( argv[1] ) )
        {
            fprintf( stderr, "Usage: %s [port #]\n", argv[0] );
            exit( 1 );
        }
        else if ( ( port = atoi( argv[1] ) ) <= 1024 )
        {
            fprintf( stderr, "Port number must be above 1024.\n" );
            exit( 1 );
        }
add this underneath it
     if (argv[2] && argv[2][0])
       {
           fCopyOver = TRUE;
           control = atoi(argv[3]);
           control2 = atoi(argv[4]);
       } 
     else
           fCopyOver = FALSE;
 

search for
#endif /* WIN32 */
       
    log_string("Booting Database");
    boot_db( );
change this ( boot_db( ); ) to this:
    boot_db(fCopyOver);

right after that, you'll see this
    control  = init_socket( port   );
    control2 = init_socket( port+1 );
    conclient= init_socket( port+10);
    conjava  = init_socket( port+20);
delete all of that and add this
    if (!fCopyOver) /* We have already the port if copyover'ed */
     {
        control = init_socket (port);
     }

search for this function
void bailout(void)
{
    echo_to_all( AT_IMMORT, "MUD shutting down by system operator NOW!!", ECHOTAR_ALL );
    shutdown_mud( "MUD shutdown by system operator" );
    log_string ("MUD shutdown by system operator");
    Sleep (5000);               /* give "echo_to_all" time to display */
    mud_down = TRUE;            /* This will cause game_loop to exit */
    service_shut_down = TRUE;   /* This will cause characters to be saved */
    fflush(stderr);
    return;
} 
#endif

add this function underneath it
void do_copyover (CHAR_DATA *ch, char * argument)
{
  FILE *fp;
  DESCRIPTOR_DATA *d, *d_next;
  char buf [100], buf2[100], buf3[100], buf4[100], buf5[100];
  fp = fopen (COPYOVER_FILE, "w");

  if (!fp)
   {
      send_to_char ("Copyover file not writeable, aborted.\n\r",ch);
      log_printf ("Could not write to copyover file: %s", COPYOVER_FILE);
      perror ("do_copyover:fopen");
      return; 
   }
        
    /* Consider changing all saved areas here, if you use OLC */

    /* do_asave (NULL, ""); - autosave changed areas */
  
    /* Shutdown IMC network or port will already be bound! */
  
    imc_shutdown_network();
    sprintf (buf, "\n\r *** COPYOVER initated by %s - please remain seated!\n\r", ch->name);
     /* For each playing descriptor, save its state */
    for (d = first_descriptor; d ; d = d_next)
     {
       CHAR_DATA * och = CH(d);
       d_next = d->next; /* We delete from the list , so need to save this */
       if (!d->character || d->connected != CON_PLAYING ) /* drop those logging on */
         {
            write_to_descriptor (d->descriptor, "\n\rSorry, we are rebooting."
               " Come back in a few minutes.\n\r", 0);
            close_socket (d, FALSE); /* throw'em out */
          }
        else
          {
             fprintf (fp, "%d %s %s\n", d->descriptor, och->name, d->host);
             if (och->level == 1)
               {
                  write_to_descriptor (d->descriptor, "Since you are level one,"
                     "and level one characters do not save, you gain a free level!\n\r",
                      0);
                  advance_level (och);
                  och->level++; /* Advance_level doesn't do that */
               }
                  save_char_obj (och);
                  write_to_descriptor (d->descriptor, buf, 0);
           }
      }
        fprintf (fp, "-1\n");
        fclose (fp);
           
        /* Close reserve and other always-open files and release other resources */
        fclose (fpReserve);
        fclose (fpLOG);
                  
        /* exec - descriptors are inherited */
                         
        sprintf (buf, "%d", port);
        sprintf (buf2, "%d", control);
                
        execl (EXE_FILE, "smaug", buf, "copyover", buf2, buf3,
          buf4, buf5, (char *) NULL);
            
        /* Failed - sucessful exec will not return */
        
        perror ("do_copyover: execl");
        send_to_char ("Reboot FAILED!\n\r",ch);
        
        /* Here you might want to reopen fpReserve */
        /* Since I'm a neophyte type guy, I'll assume this is
           a good idea and cut and past from main()  */
        
        if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
         {
           perror( NULL_FILE );
           exit( 1 );
         }
        if ( ( fpLOG = fopen( NULL_FILE, "r" ) ) == NULL )
         {  
           perror( NULL_FILE );
           exit( 1 );
         }
        
}
/* Recover from a copyover - load players */
void copyover_recover ()
{
  DESCRIPTOR_DATA *d;
  FILE *fp;
  char name [100];   
  char host[MAX_STRING_LENGTH];
  int desc;
  bool fOld;
           
  log_string ("Warmboot recovery initiated");
  fp = fopen (COPYOVER_FILE, "r");
 
  if (!fp) /* there are some descriptors open which will hang forever then ? */
        {
          perror ("copyover_recover:fopen");
          log_string("Warmboot file not found. Exitting.\n\r");
           exit (1); 
        }  
  
  unlink (COPYOVER_FILE); /* In case something crashes
                              - doesn't prevent reading */
  for (;;)  
   {       
     fscanf (fp, "%d %s %s\n", &desc, name, host);
     if (desc == -1)
       break;
 
        /* Write something, and check if it goes error-free */
     if (!write_to_descriptor (desc, "\n\rRestoring from copyover...\n\r", 0))
       {
         close (desc); /* nope */
         continue;   
        }  
  
      CREATE(d, DESCRIPTOR_DATA, 1);
      init_descriptor (d, desc); /* set up various stuff */
  
      d->host = STRALLOC( host );
     
      LINK( d, first_descriptor, last_descriptor, next, prev );
      d->connected = CON_COPYOVER_RECOVER; /* negative so close_socket
                                              will cut them off */
        
        /* Now, find the pfile */
        
      fOld = load_char_obj (d, name, FALSE);
         
      if (!fOld) /* Player file not found?! */
       {
          write_to_descriptor (desc, "\n\rSomehow, your character was lost in the warmboot. Please contact an Immortal.\n\r", 0
);
          close_socket (d, FALSE);
       }
      else /* ok! */
       {
          write_to_descriptor (desc, "\n\rWarmboot recovery complete.\n\r",0);
      
           /* This isn't necassary, but _why_
              do we want to dump someone in limbo? */
           if (!d->character->in_room)
                d->character->in_room = get_room_index (ROOM_VNUM_TEMPLE);
           /* Insert in the char_list */
           LINK( d->character, first_char, last_char, next, prev );
        
           /*
            * So that it doesn't reset as default of 0 when 20 players are on
            *                                                -- Callidyrr
            */
           num_descriptors++;
           sysdata.maxplayers++;
      
           char_to_room (d->character, d->character->in_room);
           do_look (d->character, "auto noprog");
           act (AT_ACTION, "$n materializes!", d->character, NULL, NULL, TO_ROOM);
           d->connected = CON_PLAYING;
       }
   }
}

search for this
void new_descriptor( int new_desc )
above that function, add this one.

void init_descriptor( DESCRIPTOR_DATA *dnew, int desc)
{
    dnew->next         = NULL;
    dnew->descriptor   = desc;
    dnew->connected    = CON_GET_NAME;
    dnew->outsize      = 2000;
    dnew->idle         = 0;
    dnew->lines        = 0;
    dnew->scrlen       = 24;
    dnew->user         = STRALLOC("unknown");
    dnew->newstate     = 0;
    dnew->prevcolor    = 0x07;

    CREATE( dnew->outbuf, char, dnew->outsize );
}

THEN just delete the whole void new_descriptor code..and put this one in
(I didn't feel like goin to the whole void new_descriptor function and see all of the little
changes..because..it's quite big..)
After deleting it, put this in it's place
void new_descriptor( int new_desc )
{               
    char buf[MAX_STRING_LENGTH];
    DESCRIPTOR_DATA *dnew;
    struct sockaddr_in sock;  
    struct hostent *from;
    int desc;
    int size;
/*    char bugbuf[MAX_STRING_LENGTH];*/
#ifdef WIN32
    unsigned long arg = 1;
#endif
    
    size = sizeof(sock);
    if ( check_bad_desc( new_desc ) )
    {
      set_alarm( 0 );
      return;   
    }
    set_alarm( 20 );
    alarm_section = "new_descriptor::accept";
    if ( ( desc = accept( new_desc, (struct sockaddr *) &sock, &size) ) < 0 )
    {
        set_alarm( 0 );
        return;
    }
    if ( check_bad_desc( new_desc ) )
    { 
      set_alarm( 0 );
      return;
    }
#if !defined(FNDELAY)
#define FNDELAY O_NDELAY
#endif
     
    set_alarm( 20 );
    alarm_section = "new_descriptor: after accept";
    
#ifdef WIN32
    if ( ioctlsocket(desc, FIONBIO, &arg) == -1 )
#else
    if ( fcntl( desc, F_SETFL, FNDELAY ) == -1 )
#endif
    { 
        perror( "New_descriptor: fcntl: FNDELAY" );
        set_alarm( 0 );
        return;
    }
    if ( check_bad_desc( new_desc ) )
      return;
     
    CREATE( dnew, DESCRIPTOR_DATA, 1 );
    init_descriptor(dnew, desc );
    dnew->port = ntohs(sock.sin_port);
    strcpy( buf, inet_ntoa( sock.sin_addr ) );
    sprintf( log_buf, "Sock.sinaddr:  %s, port %hd.",
                buf, dnew->port );
    log_string_plus( log_buf, LOG_COMM, sysdata.log_level );
    dnew->host = STRALLOC( buf );
    from = gethostbyaddr( (char *) &sock.sin_addr,
        sizeof(sock.sin_addr), AF_INET );
   CREATE( dnew->outbuf, char, dnew->outsize );
    
    strcpy( buf, inet_ntoa( sock.sin_addr ) );
    sprintf( log_buf, "Sock.sinaddr:  %s, port %hd.",
                buf, dnew->port );
    log_string_plus( log_buf, LOG_COMM, sysdata.log_level );
    if ( sysdata.NO_NAME_RESOLVING )   
      dnew->host = STRALLOC( buf );
    else
    {
       from = gethostbyaddr( (char *) &sock.sin_addr,
                sizeof(sock.sin_addr), AF_INET );
       dnew->host = STRALLOC( (char *)( from ? from->h_name : buf) );
    }
    if ( check_total_bans( dnew ) )
    {
          write_to_descriptor (desc,
                         "Your site has been banned from this Mud.\n\r", 0);
          free_desc (dnew);
          set_alarm (0);
          return;
     }
     /*
     * Init descriptor data.
     */ 
     
    if ( !last_descriptor && first_descriptor )
    {
        DESCRIPTOR_DATA *d;
     
        bug( "New_descriptor: last_desc is NULL, but first_desc is not! ...fixing" );
        for ( d = first_descriptor; d; d = d->next )
           if ( !d->next )
                last_descriptor = d;
    }
          
    LINK( dnew, first_descriptor, last_descriptor, next, prev );
     /*
     * Send the greeting.   
     */ 
    {
        extern char * help_greeting;
        if ( help_greeting[0] == '.' )
            write_to_buffer( dnew, help_greeting+1, 0 );
        else
            write_to_buffer( dnew, help_greeting  , 0 );
    }
           
    alarm_section = "new_descriptor: set_auth";
    set_auth(dnew);
    alarm_section = "new_descriptor: after set_auth";
    
    if ( ++num_descriptors > sysdata.maxplayers )
       sysdata.maxplayers = num_descriptors;
    if ( sysdata.maxplayers > sysdata.alltimemax )
    {   
        if ( sysdata.time_of_max )
          DISPOSE(sysdata.time_of_max);
        sprintf(buf, "%24.24s", ctime(&current_time));
        sysdata.time_of_max = str_dup(buf);
        sysdata.alltimemax = sysdata.maxplayers;
        sprintf( log_buf, "Broke all-time maximum player record: %d", sysdata.alltimemax );
        log_string_plus( log_buf, LOG_COMM, sysdata.log_level );
        to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL );
        save_sysdata( sysdata );
    }
    set_alarm(0);
    return;
}


search for this chunk of code
char *myobj( OBJ_DATA *obj )
{
    if ( !str_prefix("a ", obj->short_descr) )
        return obj->short_descr + 2;
    if ( !str_prefix("an ", obj->short_descr) )
        return obj->short_descr + 3;
    if ( !str_prefix("the ", obj->short_descr) )
        return obj->short_descr + 4;
    if ( !str_prefix("some ", obj->short_descr) )
        return obj->short_descr + 5;
    return obj->short_descr;
}
right after it, add this
void log_printf(char *fmt, ...)
{
  char buf[MAX_STRING_LENGTH*2];
  va_list args;
      
  va_start(args, fmt);
  vsprintf(buf, fmt, args);
  va_end(args);
    
  log_string(buf);
}



/* tables.c */

in case 'c':
add this
        if ( !str_cmp( name, "do_copyover" ))           return do_copyover;

go down.. a little bit..if you're new to coding..search for..
    if ( skill == do_compare )          return "do_compare";
underneath it, add this
    if ( skill == do_copyover )         return "do_copyover";



/**************************************************************************
 *                        End of Code Additions                           *
 **************************************************************************/

Ok, now..after all that work is done (finally huh?)
do a clean make

If you already have a mud running, shut it down, and restart it.
once the mud is up, type this: cedit copyover create
then you can set it to whatever level you wish by typing this cedit copyover level ##
after that, enter this: cedit save cmdtable

If you don't have your mud running, start it up, then type this inside the mud:
cedit copyover create, and you can also set it to whatever level you with by entering
cedit copyover level ##, and then..cedit save cmdtable to save it.
THAT'S IT! YOU'RE ALL DONE. Now, just type copyover..and voila

--Callidyrr