muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* cque.c */
/* $Id: cque.c,v 1.9 1993/08/16 01:57:18 nils Exp $ */

#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef XENIX
#include <sys/signal.h>
#else
#include <signal.h>
#endif /* xenix */

#include "db.h"
#include "config.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "nalloc.h"
#ifdef __STDC__
#include <stdlib.h>
#endif


extern char ccom[];
extern dbref cplr;

typedef struct bque BQUE;

struct bque
{
  BQUE *next;
  dbref player; /* player who will do command */
  dbref cause;  /* player causing command (for %n) */
  int left; /* seconds left until execution */
  char *env[10]; /* environment, from wild match */
};

/*static NALLOC *big=NULL;*/
static BQUE *qfirst=NULL,*qlast=NULL,*qwait=NULL;
static BQUE *qlfirst=NULL,*qllast=NULL;

void parse_que(player,command,cause)
     dbref player;
     char *command;
     dbref cause; /* cause is needed to determine priority */
{
  char buff[2000],*s,*r;
  s=buff;
  strcpy(buff,command);
  while((r=(char *)parse_up(&s,';')))
    big_que(player,r,cause);
}


static int add_to(player,am)
     dbref player;             
     int am;
{
  int num;
  char buff[20];
  player=db[player].owner;
  num=atoi(atr_get(player,A_QUEUE));
  num+=am;
  if (num)
    sprintf(buff,"%d",num);
  else
    *buff=0;
  atr_add(player,A_QUEUE,buff);
  return(num);
}

void big_que(player,command,cause)
     dbref player;
     char *command; 
     dbref cause;
{
  int a;
  BQUE *tmp;
/*  if (!big)
    big=nza_open(1);*/
  if (db[player].flags & HAVEN)
    return;
  /* make sure player can afford to do it */
  if (!payfor(player,QUEUE_COST+(((rand() & QUEUE_LOSS)==0) ? 1 : 0)))
    {
      notify(db[player].owner,"Not enough money to queue command.");
      return;
    }                         
  if (add_to(player,1)>QUEUE_QUOTA)
    {                   
      notify(db[player].owner,
	     tprintf("Run away object (%s), commands halted",
		     unparse_object(db[player].owner,player)));
      do_halt(db[player].owner,"");
      /* haven also means no command execution allowed */
      db[player].flags|=HAVEN;
      return;
    }
  tmp=(BQUE *) malloc(sizeof(BQUE)+strlen(command)+1);
  strcpy(Astr(tmp),command);
  tmp->player=player;
  tmp->next=NULL;
  tmp->cause=cause;
  for(a=0;a<10;a++)
    if (!wptr[a])
      tmp->env[a]=NULL;
    else
      strcpy(tmp->env[a]=(char *)malloc(strlen(wptr[a])+1),wptr[a]);
  if (Typeof(cause)==TYPE_PLAYER)
    {
      if (qlast)
	{
	  qlast->next=tmp;
	  qlast=tmp; 
	}         
      else
	qlast=qfirst=tmp;
    }
  else
    {
      if (qllast)
	{
	  qllast->next=tmp;
	  qllast=tmp;    
	}         
      else
	qllast=qlfirst=tmp;
    }
}                

void wait_que(player,wait,command,cause)
     dbref player;
     int wait;
     char *command;
     dbref cause;
{
  BQUE *tmp;                      
  int a;

  /* make sure player can afford to do it */
  if (!payfor(player,QUEUE_COST+(((rand() & QUEUE_LOSS)==0) ? 1 : 0)))
    {
      notify(player,"Not enough money to queue command.");
      return;
    }
  tmp=(BQUE *) malloc(sizeof(BQUE)+strlen(command)+1);
  strcpy(Astr(tmp),command);
  tmp->player=player;
  tmp->next=qwait;
  tmp->left=wait;
  tmp->cause=cause;
  for(a=0;a<10;a++)
    if (!wptr[a])
      tmp->env[a]=NULL;
    else
      strcpy(tmp->env[a]=(char *)malloc(strlen(wptr[a])+1),wptr[a]);
  qwait=tmp;
}

/* call every second to check for wait queue commands */           
void do_second()
{
  BQUE *trail=NULL,*point,*next;
  /* move contents of low priority queue onto end of normal one */
  /* this helps to keep objects from getting out of control since */
  /* its affects on other objects happen only after one seconds */
  /* this should allow @halt to be type before getting blown away */
  /* by scrolling text */
  if (qlfirst)
    {
      if (qlast)
	qlast->next=qlfirst;
      else
	qfirst=qlfirst;
      qlast=qllast;
      qllast=qlfirst=NULL;
    }  
  for(point=qwait;point;point=next)
    /* Note: this would be 0 except the command is being put in the low
       priority queue to be done in one second anyways */
    if (point->left--<=1)
      {                          
	int a;
	giveto(point->player,QUEUE_COST);
	for(a=0;a<10;a++)
	  wptr[a]=point->env[a];
	parse_que(point->player,Astr(point),point->cause);                          
	if (trail)
	  trail->next=next=point->next;
	else 
	  qwait=next=point->next;
	for(a=0;a<10;a++)
	  if (point->env[a])
	    free(point->env[a]);
	free(point);
      }
    else
      next=(trail=point)->next;
}

int test_top()
{
  return(qfirst ? 1 : 0);
}

/* execute one command off the top of the queue */
int do_top()
{                 
  int a;
  BQUE *tmp;

  dbref player;
  if (!qfirst)
    return(0);
  if (qfirst->player!=NOTHING && !(db[qfirst->player].flags & GOING))
    {                  
      giveto(qfirst->player,QUEUE_COST);
      cplr=qfirst->player;
      strcpy(ccom,Astr(qfirst));
      add_to(player=qfirst->player,-1);
      qfirst->player=NOTHING;
      if (!(db[player].flags & HAVEN) && !(db[player].flags&GOING))
	{
	  char buff[1030];
#ifdef LOG_COMMANDS
	  extern FILE *command_log;
#endif
	  int a;
	  for(a=0;a<10;a++)
	    wptr[a]=qfirst->env[a];
#ifdef LOG_COMMANDS
	  if (command_log)
	    fprintf(command_log,">%s<",Astr(qfirst));
#endif
	  pronoun_substitute(buff,qfirst->cause,Astr(qfirst),player);
	  inc_qcmdc();		/* increment command stats */
	  process_command(player,buff+strlen(db[qfirst->cause].name),qfirst->cause);
	}
    }
  tmp=qfirst->next;         
  for(a=0;a<10;a++)
    if (qfirst->env[a])
      free(qfirst->env[a]);
  free(qfirst);
  if (!(qfirst=tmp))
    qlast=NULL;
  return(1);
}

/* tell player what commands they have pending in the queue */
void do_queue(player)
     dbref player;
{
  BQUE *tmp;
  int can_see = power(player, POW_QUEUE);
  
  notify(player,"Immediate commands:");
  for(tmp=qfirst;tmp;tmp=tmp->next)
    if ((db[tmp->player].owner==db[player].owner) || can_see)
      notify(player,tprintf("%s:%s",unparse_object(player,tmp->player),Astr(tmp)));
  for(tmp=qlfirst;tmp;tmp=tmp->next)
    if ((db[tmp->player].owner==db[player].owner) || can_see)
      notify(player,tprintf("%s:%s",unparse_object(player,tmp->player),Astr(tmp)));
  notify(player,"@waited commands:");
  for(tmp=qwait;tmp;tmp=tmp->next)
    if ((db[tmp->player].owner==db[player].owner) || can_see)
      notify(player,tprintf("%s:%d:%s",unparse_object(player,tmp->player),tmp->left,Astr(tmp)));
}

void do_haltall(player)		/* halt everything, period */
     dbref player;
{
  BQUE *i, *next;
  
  if (!power(player,POW_SECURITY)) {
    notify(player,  tprintf("silly %n. you can't halt everything.",db[player].name));
    return;
  }
  if (!qlast)
    qfirst=qlast=malloc(sizeof(BQUE));
  if (!qllast)
    qlfirst=qllast=malloc(sizeof(BQUE));
  qlast->next = qlfirst;
  qllast->next = qwait;
  for (i=qfirst; i; i=next ) {
    next = i->next;
    free(i);
  }
  qlfirst = qllast = qfirst = qlast = qwait = NULL;
  notify(player, "everything halted. every single thing. sigh. sniff. no more stuff to process. sniff sniff.");
}

/* remove all queued commands from a certain player */
void do_halt(player,ncom)
     dbref player;
     char *ncom;
{
  BQUE *tmp,*trail=NULL,*point,*next;
  int num=0; 

  if (!(db[player].flags&QUIET))
    if(player==db[player].owner)
      notify(db[player].owner,"Everything halted.");
    else
      if(!(db[db[player].owner].flags&QUIET))
	notify(db[player].owner,tprintf("%s halted.",
					unparse_object(db[player].owner,player)));
  for(tmp=qfirst;tmp;tmp=tmp->next)
    if ((tmp->player==player) || (db[tmp->player].owner==player))
      {       
	num--;
	giveto(player,QUEUE_COST);
	tmp->player=NOTHING;
      }
  for(tmp=qlfirst;tmp;tmp=tmp->next)
    if ((tmp->player==player) || (db[tmp->player].owner==player))
      {       
	num--;
	giveto(player,QUEUE_COST);
	tmp->player=NOTHING;
      }
  /* remove wait q stuff */
  for(point=qwait;point;point=next)
    if ((point->player==player) || (db[point->player].owner==player))
      {                        
	int a;
	giveto(point->player,QUEUE_COST);
	if (trail)
	  trail->next=next=point->next;
	else 
	  qwait=next=point->next;
	for(a=0;a<10;a++)
	  if (point->env[a])
	    free(point->env[a]);
	free(point);
      }                        
    else
      next=(trail=point)->next;
  if (db[player].owner==player)
    atr_add(player,A_QUEUE,"");
  else
    add_to(player,num); 
  if (*ncom)
    parse_que(player,ncom,player);
}