/
/*
  SillyMUD Distribution V1.1b             (c) 1993 SillyMUD Developement
 
  See license.doc for distribution terms.   SillyMUD is based on DIKUMUD
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "protos.h"

#define REBOOT_AT    10  /* 0-23, time of optional reboot if -e lib/reboot */


#define TP_MOB    0
#define TP_OBJ	   1
#define TP_ERROR  2


struct room_data *world;              /* dyn alloc'ed array of rooms     */



char *string_fields[] =
{
	"name",
	"short",
	"long",
	"description",
	"title",
	"delete-description",
	"delnoise",
	"delfarnoise",
	"\n"
};

char *room_fields[] =
{
	"name",   /* 1 */
	"desc",
	"fs",
	"exit",
	"exdsc",  /* 5 */
        "extra",  /* 6 */
	"riv",    /* 7 */
	"tele",   /* 8 */
	"tunn",   /* 9 */
	"\n"
};

/* maximum length for text field x+1 */
int length[] =
{
	15,
	60,
	256,
	240,
	60,
	
};


int room_length[] =
{
	80,
	1024,
        50,
	50,
	512,
	512,
        50,
	100,
        50
};

char *skill_fields[] = 
{
	"learned",
	"affected",
	"duration",
	"recognize",
	"\n"
};

int max_value[] =
{
	255,
	255,
	10000,
	1
};

/* ************************************************************************
*  modification of malloc'ed strings                                      *
************************************************************************ */

/* Add user input to the 'current' string (as defined by d->str) */

void string_add(struct descriptor_data *d, char *str)
{
  char *scan;
  int terminator = 0;
  
  /* determine if this is the terminal string, and truncate if so */
  for (scan = str; *scan; scan++)
    if (terminator = (*scan == '@'))  {
      *scan = '\0';
      break;
    }
  
  if (!(*d->str))	{
    if (strlen(str) > d->max_str)  	{
      send_to_char("String too long - Truncated.\n\r",
		   d->character);
      *(str + d->max_str) = '\0';
      terminator = 1;
    }
    CREATE(*d->str, char, strlen(str) + 3);
    strcpy(*d->str, str);
  } else	{
    if (strlen(str) + strlen(*d->str) > d->max_str)	{
      send_to_char("String too long. Last line skipped.\n\r",
		   d->character);
      terminator = 1;
    } else 	{
      if (!(*d->str = (char *) realloc(*d->str, strlen(*d->str) + 
				       strlen(str) + 3)))     	{
	perror("string_add");
	assert(0);
      }
      strcat(*d->str, str);
    }
  }
  
  if (terminator)	{
    d->str = 0;
    if (d->connected == CON_EXDSCR)	{
      SEND_TO_Q(MENU, d);
      d->connected = CON_SLCT;
    }
  } else
    strcat(*d->str, "\n\r");
}


#undef MAX_STR

/* interpret an argument for do_string */
void quad_arg(char *arg, int *type, char *name, int *field, char *string)
{
  char buf[MAX_STRING_LENGTH];

  
  /* determine type */
  arg = one_argument(arg, buf);
  if (is_abbrev(buf, "char"))
    *type = TP_MOB;
  else if (is_abbrev(buf, "obj"))
    *type = TP_OBJ;
  else {
    *type = TP_ERROR;
    return;
  }
  
  /* find name */
  arg = one_argument(arg, name);
  
  /* field name and number */
  arg = one_argument(arg, buf);
  if (!(*field = old_search_block(buf, 0, strlen(buf), string_fields, 0)))
    return;
  
  /* string */
  for (; isspace(*arg); arg++);
  for (; *string = *arg; arg++, string++);
  
  return;
}

	 


/* modification of malloc'ed strings in chars/objects */
void do_string(struct char_data *ch, char *arg, int cmd)
{
  
  char name[MAX_STRING_LENGTH], string[MAX_STRING_LENGTH];
  struct extra_descr_data *ed, *tmp;
  int field, type;
  struct char_data *mob;
  struct obj_data *obj;
  if (IS_NPC(ch))
    return;
  
  quad_arg(arg, &type, name, &field, string);
  
  if (type == TP_ERROR)	{
    send_to_char(
		 "Syntax:\n\rstring ('obj'|'char') <name> <field> [<string>].",
		 ch);
    return;
  }
  
  if (!field)	{
    send_to_char("No field by that name. Try 'help string'.\n\r",
		 ch);
    return;
  }
  
  if (type == TP_MOB)	{
    /* locate the beast */
    if (!(mob = get_char_vis(ch, name))) {
      send_to_char("I don't know anyone by that name...\n\r", ch);
      return;
    }
    
    switch(field)	{
    case 1:
      if (!IS_NPC(mob) && GetMaxLevel(ch) < IMPLEMENTOR) {
	send_to_char("You can't change that field for players.", ch);
	return;
      }
      if (!*string) {
	send_to_char("You have to supply a name!\n\r", ch);
	return;
      }
      ch->desc->str = &mob->player.name;
      if (!IS_NPC(mob))
	send_to_char("WARNING: You have changed the name of a player.\n\r", ch);
      break;
    case 2:
      if (!IS_NPC(mob)) {
	send_to_char("That field is for monsters only.\n\r", ch);
	return;
      }
      if (!*string) {
	send_to_char("You have to supply a description!\n\r", ch);
	return;
      }
      ch->desc->str = &mob->player.short_descr;
      break;
    case 3:
      if (!IS_NPC(mob)){
	send_to_char("That field is for monsters only.\n\r", ch);
	return;
      }
      ch->desc->str = &mob->player.long_descr;
      break;
    case 4:ch->desc->str = &mob->player.description; break;
    case 5:
      if (IS_NPC(mob))  {
	send_to_char("Monsters have no titles.\n\r",ch);
	return;
      }
      if ((GetMaxLevel(ch) >= GetMaxLevel(mob)) && (ch != mob)) 
	ch->desc->str = &mob->player.title;
      else {
	send_to_char("Sorry, can't set the title of someone of higher level.\n\r", ch);
	return;
      }
      break;
    case 7:
      if (mob->player.sounds) {
	free(mob->player.sounds);
	mob->player.sounds = 0;
      }
      return;
      break;
    case 8:
      if (mob->player.distant_snds) {
	free(mob->player.distant_snds);
	mob->player.distant_snds = 0;
      }
      return;
      break;
    default:
      send_to_char("That field is undefined for monsters.\n\r", ch);
      return;
      break;
    }
  } else {   /* type == TP_OBJ */
    /* locate the object */
    if (!(obj = get_obj_vis(ch, name)))    	{
      send_to_char("Can't find such a thing here..\n\r", ch);
      return;
    }
    
    switch(field)  	{
      
    case 1: 
      if (!*string) {
	send_to_char("You have to supply a keyword.\n\r", ch);
	return;
      } else {
	ch->desc->str = &obj->name;
	break;
      }
      break;
    case 2: 
      if (!*string) {
	send_to_char("You have to supply a keyword.\n\r", ch);
	return;
      } else {
        ch->desc->str = &obj->short_description; 
	break;
      }
    case 3: ch->desc->str = &obj->description; break;
    case 4:
      if (!*string)  	{
	send_to_char("You have to supply a keyword.\n\r", ch);
	return;
      }
      /* try to locate extra description */
      for (ed = obj->ex_description; ; ed = ed->next)
	if (!ed) {
	  CREATE(ed , struct extra_descr_data, 1);
	  ed->next = obj->ex_description;
	  obj->ex_description = ed;
	  CREATE(ed->keyword, char, strlen(string) + 1);
	  strcpy(ed->keyword, string);
	  ed->description = 0;
	  ch->desc->str = &ed->description;
	  send_to_char("New field.\n\r", ch);
	  break;
	}
	else if (!str_cmp(ed->keyword, string)) /* the field exists */
	  {
	    free(ed->description);
	    ed->description = 0;
	    ch->desc->str = &ed->description;
	    send_to_char(
			 "Modifying description.\n\r", ch);
	    break;
	  }
      ch->desc->max_str = MAX_STRING_LENGTH;
      return; /* the stndrd (see below) procedure does not apply here */
      break;
    case 6: /* deletion */
      if (!*string)  	{
	send_to_char("You must supply a field name.\n\r", ch);
	return;
      }
      /* try to locate field */
      for (ed = obj->ex_description; ; ed = ed->next)
	if (!ed) {
	  send_to_char("No field with that keyword.\n\r", ch);
	  return;
	} else if (!str_cmp(ed->keyword, string)) {
	  free(ed->keyword);
	  if (ed->description)
	    free(ed->description);
	  
	  /* delete the entry in the desr list */						
	  if (ed == obj->ex_description)
	    obj->ex_description = ed->next;
	  else {
	    for(tmp = obj->ex_description; tmp->next != ed; 
		tmp = tmp->next);
	    tmp->next = ed->next;
	  }
	  free(ed);
	  
	  send_to_char("Field deleted.\n\r", ch);
	  return;
	}
      break;				
    default:
      send_to_char(
		   "That field is undefined for objects.\n\r", ch);
      return;
      break;
    }
  }
  
  if (*ch->desc->str)	{
    free(*ch->desc->str);
  }
  
  if (*string) {   /* there was a string in the argument array */ 
    if (strlen(string) > length[field - 1])	{
      send_to_char("String too long - truncated.\n\r", ch);
      *(string + length[field - 1]) = '\0';
    }
    CREATE(*ch->desc->str, char, strlen(string) + 1);
    strcpy(*ch->desc->str, string);
    ch->desc->str = 0;
    send_to_char("Ok.\n\r", ch);
  } else {  /* there was no string. enter string mode */
    send_to_char("Enter string. terminate with '@'.\n\r", ch);
    *ch->desc->str = 0;
    ch->desc->max_str = length[field - 1];
  }
}




void bisect_arg(char *arg, int *field, char *string)
{
  char buf[MAX_INPUT_LENGTH];

  
  /* field name and number */
  arg = one_argument(arg, buf);
  if (!(*field = old_search_block(buf, 0, strlen(buf), room_fields, 0)))
    return;
  
  /* string */
  for (; isspace(*arg); arg++);
  for (; *string = *arg; arg++, string++);
  
  return;
}


void do_edit(struct char_data *ch, char *arg, int cmd)
{
  int field, dflags, dir, exroom, dkey, rspeed, rdir,
  tele_room, tele_time, tele_mask, moblim, tele_cnt;
  unsigned r_flags;
  int s_type;
  char name[MAX_INPUT_LENGTH], string[512], buf[132];
  struct extra_descr_data *ed, *tmp;
  struct room_data	*rp;
  
  rp = real_roomp(ch->in_room);
  
  if ((IS_NPC(ch)) || (GetMaxLevel(ch)<LOW_IMMORTAL))
    return;

  if (!ch->desc) /* someone is forced to do something. can be bad! */
    return;      /* the ch->desc->str field will cause problems... */


#ifndef TEST_SERVER
  if((GetMaxLevel(ch) < 55) && (rp->zone != GET_ZONE(ch))) {
     send_to_char("Sorry, you are not authorized to edit this zone.\n\r", ch);
     return;
  }
#endif
  bisect_arg(arg, &field, string);
  
  if (!field)	{
    send_to_char("No field by that name. Try 'help edit'.\n\r", ch);
    return;
  }
  
  r_flags = -1;
  s_type = -1;
  
  switch(field) {
    
  case 1: ch->desc->str = &rp->name; break;
  case 2: ch->desc->str = &rp->description; break;
  case 3: sscanf(string,"%u %d ",&r_flags,&s_type);
    if ((r_flags < 0)  || (s_type < 0) || (s_type > 11)) {
      send_to_char("didn't quite get those, please try again.\n\r",ch);
      send_to_char("flags must be 0 or positive, and sectors must be from 0 to 11\n\r",ch);
      send_to_char("edit fs <flags> <sector_type>\n\r",ch);
      return;
    }
    rp->room_flags = r_flags;
    rp->sector_type = s_type;
    
    if (rp->sector_type == SECT_WATER_NOSWIM) {
      send_to_char("P.S. you need to do speed and flow\n\r",ch);
      send_to_char("For this river. (set to 0 as default)\n\r",ch);
      rp->river_speed = 0;
      rp->river_dir = 0;
      return;
    }
    return;
    break;
    
  case 4: sscanf(string,"%d %d %d %d ", &dir, &dflags, &dkey, &exroom);
    
    /*
      check if the exit exists
      */
    if ((dir < 0) || (dir > 5)) {
      send_to_char("You need to use numbers for that (0 - 5)",ch);
      return;
    }
    
    if (rp->dir_option[dir]) {
      send_to_char("modifying exit.\n\r",ch);
      switch(dflags) {
      case 1: rp->dir_option[dir]->exit_info = EX_ISDOOR;
              break;
      case 2: rp->dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF;
              break;
      case 3: rp->dir_option[dir]->exit_info = EX_CLIMB;
              break;
      case 4: rp->dir_option[dir]->exit_info = EX_CLIMB | EX_ISDOOR;
              break;
      case 5: rp->dir_option[dir]->exit_info = EX_CLIMB | EX_ISDOOR | EX_PICKPROOF;
	break;
      default: rp->dir_option[dir]->exit_info = 0;
      }

      rp->dir_option[dir]->key = dkey;
      if (real_roomp(exroom) != NULL) {
	rp->dir_option[dir]->to_room = exroom;
      } else {
	send_to_char("Deleting exit.\n\r",ch);
	free(rp->dir_option[dir]);
	rp->dir_option[dir] = 0;
	return;
      }
    } else if (real_roomp(exroom)==NULL) {
      send_to_char("Hey, John Yaya, that's not a valid room.\n\r", ch);
      return;
    } else {
      send_to_char("New exit\n\r",ch);
      CREATE(rp->dir_option[dir], 
	     struct room_direction_data, 1);
      switch(dflags) {
      case 1: rp->dir_option[dir]->exit_info = EX_ISDOOR;
              break;
      case 2: rp->dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF;
              break;
      case 3: rp->dir_option[dir]->exit_info = EX_CLIMB;
              break;
      case 4: rp->dir_option[dir]->exit_info = EX_CLIMB | EX_ISDOOR;
              break;
      case 5: rp->dir_option[dir]->exit_info = EX_CLIMB | EX_ISDOOR | EX_PICKPROOF;
              break;
      default: rp->dir_option[dir]->exit_info = 0;
      }

      rp->dir_option[dir]->key = dkey;
      rp->dir_option[dir]->to_room = exroom;
    }
    
    if (rp->dir_option[dir]->exit_info>0) {
      string[0] = 0;
      send_to_char("enter keywords, 1 line only. \n\r",ch);
      send_to_char("terminate with an @ on the same line.\n\r",ch);
      ch->desc->str = &rp->dir_option[dir]->keyword; 
      break;
    } else {
      return;
    }   
    
  case 5: dir = -1;
    sscanf(string,"%d", &dir); 
    if ((dir >=0) && (dir <= 5)) {
      send_to_char("Enter text, term. with '@' on a blank line",ch);
      string[0] = 0;
      if (rp->dir_option[dir]) {
	ch->desc->str = &rp->dir_option[dir]->general_description;
      } else {
	CREATE(rp->dir_option[dir], 
	       struct room_direction_data, 1);
	ch->desc->str = &rp->dir_option[dir]->general_description;
      }
    } else {
      send_to_char("Illegal direction\n\r",ch);
      send_to_char("Must enter 0-5.I will ask for text.\n\r",ch);
      return;		  
    }
    break;
  case 6: 
    /* 
      extra descriptions 
      */
    if (!*string)  	{
      send_to_char("You have to supply a keyword.\n\r", ch);
      return;
    }
    /* try to locate extra description */
    for (ed = rp->ex_description; ; ed = ed->next)
      if (!ed) {
	CREATE(ed , struct extra_descr_data, 1);
	ed->next = rp->ex_description;
	rp->ex_description = ed;
	CREATE(ed->keyword, char, strlen(string) + 1);
	strcpy(ed->keyword, string);
	ed->description = 0;
	ch->desc->str = &ed->description;
	send_to_char("New field.\n\r", ch);
	break;
      }  else if (!str_cmp(ed->keyword, string)) {
	/* the field exists */
	free(ed->description);
	ed->description = 0;
	ch->desc->str = &ed->description;
	send_to_char( "Modifying description.\n\r", ch);
	break;
      }
    ch->desc->max_str = MAX_STRING_LENGTH;
    return; 
    break;
    
  case 7:
    /*  this is where the river stuff will go */
    rspeed = 0; rdir = 0;
    sscanf(string,"%d %d ",&rspeed,&rdir);
    if ((rdir>= 0) && (rdir <= 5)) {
      rp->river_speed = rspeed;
      rp->river_dir = rdir;
    } else {
      send_to_char("Illegal dir. : edit riv <speed> <dir>\n\r",ch);
    }
    return;

  case 8:
    /*  this is where the teleport stuff will go */
    tele_room = -1; tele_time = -1; tele_mask = -1;
    sscanf(string,"%d %d %d",&tele_time,&tele_room,&tele_mask);
    if (tele_room < 0 || tele_time < 0 || tele_mask < 0) {
      send_to_char(" edit tele <time> <room_nr> <tele-flags>\n\r", ch);
      return;
      break;
    } else {
      if (IS_SET(TELE_COUNT, tele_mask)) {
	sscanf(string,"%d %d %d %d", 
	       &tele_time, &tele_room, &tele_mask, &tele_cnt);
	if (tele_cnt < 0) {
	  send_to_char
	    (" edit tele <time> <room_nr> <tele-flags> [tele-count]\n\r", ch);
	  return;
	} else {
	  real_roomp(ch->in_room)->tele_time = tele_time;
	  real_roomp(ch->in_room)->tele_targ = tele_room;
	  real_roomp(ch->in_room)->tele_mask = tele_mask;
	  real_roomp(ch->in_room)->tele_cnt  = tele_cnt;
	}
      } else {
	real_roomp(ch->in_room)->tele_time = tele_time;
	real_roomp(ch->in_room)->tele_targ = tele_room;
	real_roomp(ch->in_room)->tele_mask = tele_mask;
	real_roomp(ch->in_room)->tele_cnt  = 0;
        return;
      }
    }
    
    return;
  case 9:
    if (sscanf(string, "%d", &moblim) < 1) {
      send_to_char("edit tunn <mob_limit>\n\r", ch);
      return;
      break;
    } else {
      real_roomp(ch->in_room)->moblim = moblim;
      if (!IS_SET(real_roomp(ch->in_room)->room_flags, TUNNEL))
	SET_BIT(real_roomp(ch->in_room)->room_flags, TUNNEL);
        return;
      break;
    }
  case 10: 
    /*
      deletion
      */
      if (!*string)  	{
	send_to_char("You must supply a field name.\n\r", ch);
	return;
      }
      /* try to locate field */
      for (ed = rp->ex_description; ; ed = ed->next)
	if (!ed) {
	  send_to_char("No field with that keyword.\n\r", ch);
	  return;
	} else if (!str_cmp(ed->keyword, string)) {
	  free(ed->keyword);
	  if (ed->description)
	    free(ed->description);
	  
	  /* delete the entry in the desr list */						
	  if (ed == rp->ex_description)
	    rp->ex_description = ed->next;
	  else {
	    for(tmp = rp->ex_description; tmp->next != ed; 
		tmp = tmp->next);
	    tmp->next = ed->next;
	  }
	  free(ed);
	  
	  send_to_char("Field deleted.\n\r", ch);
	  return;
	}
      break;				
    
  default:
    send_to_char("I'm so confused :-)\n\r",ch);
    return;
    break;
  }
  
  if (*ch->desc->str)	{
    free(*ch->desc->str);
  }
  
  if (*string) {   /* there was a string in the argument array */ 
    if (strlen(string) > room_length[field - 1])	{
      send_to_char("String too long - truncated.\n\r", ch);
      *(string + length[field - 1]) = '\0';
    }
    CREATE(*ch->desc->str, char, strlen(string) + 1);
    strcpy(*ch->desc->str, string);
    ch->desc->str = 0;
    send_to_char("Ok.\n\r", ch);
  } else {  /* there was no string. enter string mode */
    send_to_char("Enter string. terminate with '@'.\n\r", ch);
    *ch->desc->str = 0;
    ch->desc->max_str = room_length[field - 1];
  }
  
}


/* **********************************************************************
*  Modification of character skills                                     *
********************************************************************** */


void do_setskill(struct char_data *ch, char *arg, int cmd)
{
	send_to_char("This routine is disabled untill it fitts\n\r", ch);
	send_to_char("The new structures (sorry Quinn) ....Bombman\n\r", ch);
	return;
}








/* db stuff *********************************************** */


/* One_Word is like one_argument, execpt that words in quotes "" are */
/* regarded as ONE word                                              */

char *one_word(char *argument, char *first_arg )
{
  int begin, look_at;
  
  begin = 0;
  
  do
    {
      for ( ;isspace(*(argument + begin)); begin++);
      
      if (*(argument+begin) == '\"') {  /* is it a quote */
	
	begin++;
	
	for (look_at=0; (*(argument+begin+look_at) >= ' ') && 
	     (*(argument+begin+look_at) != '\"') ; look_at++)
				*(first_arg + look_at) = LOWER(*(argument + begin + look_at));
	
	if (*(argument+begin+look_at) == '\"')
	  begin++;
	
      } else {
	
	for (look_at=0; *(argument+begin+look_at) > ' ' ; look_at++)
	  *(first_arg + look_at) = LOWER(*(argument + begin + look_at));
	
      }
      
      *(first_arg + look_at) = '\0';
      begin += look_at;
    }
  while (fill_word(first_arg));
  
  return(argument+begin);
}


struct help_index_element *build_help_index(FILE *fl, int *num)
{
	int nr = -1, issorted, i;
	struct help_index_element *list = 0, mem;
	char buf[81], tmp[81], *scan;
	long pos;

	for (;;)
	{
		pos = ftell(fl);
		fgets(buf, 81, fl);
		*(buf + strlen(buf) - 1) = '\0';
		scan = buf;
		for (;;)
		{
			/* extract the keywords */
			scan = one_word(scan, tmp);

			if (!*tmp)
				break;

			if (!list) {
				CREATE(list, struct help_index_element, 1);
				nr = 0;
			} else  {
			   RECREATE(list, struct help_index_element, ++nr+1);
			}

			list[nr].pos = pos;
			CREATE(list[nr].keyword, char, strlen(tmp) + 1);
			strcpy(list[nr].keyword, tmp);
		}
		/* skip the text */
		do
			fgets(buf, 81, fl);
		while (*buf != '#');
		if (*(buf + 1) == '~')
			break;
	}
	/* we might as well sort the stuff */
	do
	{
		issorted = 1;
		for (i = 0; i < nr; i++)
			if (str_cmp(list[i].keyword, list[i + 1].keyword) > 0)
			{
				mem = list[i];
				list[i] = list[i + 1];
				list[i + 1] = mem;
				issorted = 0;
			}
	}
	while (!issorted);

	*num = nr;
	return(list);
}



void page_string(struct descriptor_data *d, char *str, int keep_internal)
{
  if (!d)
    return;
  
  if (keep_internal)	{
    CREATE(d->showstr_head, char, strlen(str) + 1);
    strcpy(d->showstr_head, str);
    d->showstr_point = d->showstr_head;
  }
  else
    d->showstr_point = str;
  
  show_string(d, "");
}



void show_string(struct descriptor_data *d, char *input)
{
  char buffer[MAX_STRING_LENGTH], buf[MAX_INPUT_LENGTH];
  register char *scan, *chk;
  int lines = 0, toggle = 1;
  int i;  
  one_argument(input, buf);
  
  if (*buf)    {
    if (d->showstr_head){
      free(d->showstr_head);
      d->showstr_head = 0;
    }
    d->showstr_point = 0;
    return;
  }
  
  if(d->character->term == 0)
     i = 22;
  else
     i = d->character->size - 7;
  /* show a chunk */
  for (scan = buffer;; scan++, d->showstr_point++) {
    if((((*scan = *d->showstr_point) == '\n') || (*scan == '\r')) &&
       ((toggle = -toggle) < 0))
      lines++;
    else if (!*scan || (lines >= i))      {
      *scan = '\0';
      SEND_TO_Q(buffer, d);
      
      /* see if this is the end (or near the end) of the string */
      for (chk = d->showstr_point; isspace(*chk); chk++);
      if (!*chk)	  {
	if (d->showstr_head)	      {
	  free(d->showstr_head);
	  d->showstr_head = 0;
	}
	d->showstr_point = 0;
      }
      return;
    }
  }
}






void night_watchman()
{
  long tc;
  struct tm *t_info;
  
  extern int mudshutdown;
  
  void send_to_all(char *messg);
  
  tc = time(0);
  t_info = localtime(&tc);
  
  if ((t_info->tm_hour == 8) && (t_info->tm_wday > 0) &&
      (t_info->tm_wday < 6))
    if (t_info->tm_min > 50)
      {
	log("Leaving the scene for the serious folks.");
	send_to_all("Closing down. Thank you for flying DikuMUD.\n\r");
	mudshutdown = 1;
      }
    else if (t_info->tm_min > 40)
      send_to_all("ATTENTION: DikuMUD will shut down in 10 minutes.\n\r");
    else if (t_info->tm_min > 30)
      send_to_all("Warning: The game will close in 20 minutes.\n\r");
}


void check_reboot()
{
  long tc;
  struct tm *t_info;
  char dummy;
  FILE *boot;
  
  extern int mudshutdown, reboot;
  
  tc = time(0);
  t_info = localtime(&tc);
  
  if ((t_info->tm_hour + 1) == REBOOT_AT && t_info->tm_min > 30)
    if (boot = fopen("./reboot", "r"))
      {
	if (t_info->tm_min > 50)
	  {
	    log("Reboot exists.");
	    fread(&dummy, sizeof(dummy), 1, boot);
	    if (!feof(boot))   /* the file is nonepty */
	      {
		log("Reboot is nonempty.");
		if (system("./reboot"))
		  {
		    log("Reboot script terminated abnormally");
		    send_to_all("The reboot was cancelled.\n\r");
		    system("mv ./reboot reboot.FAILED");
		    fclose(boot);
		    return;
		  }
		else
		  system("mv ./reboot reboot.SUCCEEDED");
	      }
	    
	    send_to_all("Automatic reboot. Come back in a little while.\n\r");
	    mudshutdown = reboot = 1;
	  }
	else if (t_info->tm_min > 40)
	  send_to_all("ATTENTION: DikuMUD will reboot in 10 minutes.\n\r");
	else if (t_info->tm_min > 30)
	  send_to_all(
	      "Warning: The game will close and reboot in 20 minutes.\n\r");
	
	fclose(boot);
      }
}

#if 0
int workhours()
{
  long tc;
  struct tm *t_info;
  
  tc = time(0);
  t_info = localtime(&tc);
  
  return((t_info->tm_wday > 0) && (t_info->tm_wday < 6) && 
	 (t_info->tm_hour >= 9) && (t_info->tm_hour < 17));
}






/*
* This procedure is *heavily* system dependent. If your system is not set up
* properly for this particular way of reading the system load (It's weird all
* right - but I couldn't think of anything better), change it, or don't use -l.
* It shouldn't be necessary to use -l anyhow. It's oppressive and unchristian
* to harness man's desire to play. Who needs a friggin' degree, anyhow?
*/

int load()
{
  struct syslinfo {
    char	sl_date[12];	/* "Tue Sep 16\0" */
    char	sl_time[8];	/* "11:10\0" */
    char	sl_load1[6];	/* "12.0\0" */
    char	sl_load2[10];	/* "+2.3 14u\0" */
  } info;
  FILE *fl;
  int i, sum;
  static int previous[5];
  static int p_point = -1;
  extern int slow_death;
  
  if (!(fl = fopen("/tmp/.sysline", "r")))    {
    perror("sysline. (dying)");
    slow_death = 1;
    return(-1);
  }
  if (!fread(&info, sizeof(info), 1, fl))    {
    perror("fread sysline (dying)");
    slow_death = 1;
    return(-1);
  }
  fclose(fl);
  
  if (p_point < 0)    {
    previous[0] = atoi(info.sl_load1);
    for (i = 1; i< 5; i++)
      previous[i] = previous[0];
    p_point = 1;
    return(previous[0]);
  }  else    {
    /* put new figure in table */
    previous[p_point] = atoi(info.sl_load1);
    if (++p_point > 4)
      p_point = 0;
    
    for (i = 0, sum = 0; i < 5; i++)
      sum += previous[i];
    return((int) sum / 5);
  }
}

char *nogames()
{
  static char text[200];
  FILE *fl;
  
  if (fl = fopen("lib/nogames", "r"))
    {
      log("/usr/games/nogames exists");
      fgets(text, fl);
      return(text);
      fclose(fl);
    }
  else
    return(0);
}


/* emulate the game regulator */
void gr(int s)
{
  char *txt = 0, buf[1024];
  int ld = 0;
  static char *warnings[3] =
    {
      "If things don't look better within 3 minutes, the game will pause.\n\r",
      "The game will close temporarily 2 minutes from now.\n\r",
      "WARNING: The game will close in 1 minute.\n\r"
      };
  static int wnr = 0;
  
  extern int slow_death, mudshutdown;
  
  void send_to_all(char *messg);
  
  void coma(int s);
  
  if (((ld = load()) >= 6) || (txt = nogames()) || slow_death)
    {
      if (ld >= 6)	{
	  sprintf(buf, "The system load is greater than 6.0 (%d)\n\r", ld);
	  send_to_all(buf);
	}
      else if (slow_death)
	send_to_all("The game is dying.\n\r");
      else
	{
	  strcpy(buf,
		 "Game playing is no longer permitted on this machine:\n\r");
	  strcat(buf, txt);
	  strcat(buf, "\n\r"); 
	  send_to_all(buf);
	}
      
      if (wnr < 3)
	send_to_all(warnings[wnr++]);
      else
	if (ld >= 6)
	  {
	    coma(s);
	    wnr = 0;
	  }
	else
	  mudshutdown = 1;
    }
  else if (workhours())
    mudshutdown = 1;				/* this shouldn't happen */
  else if (wnr)
    {
      send_to_all("Things look brighter now - you can continue playing.\n\r");
      wnr = 0;
    }
}

#endif