/* Cque.c */
#include "os.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#ifdef MEM_CHECK
#include "mem_check.h"
#endif
static void big_que (dbref player, char *command, dbref cause);
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 */
char *comm; /* command to be executed */
};
static BQUE *qfirst = NULL, *qlast = NULL, *qwait = NULL;
static BQUE *qlfirst = NULL, *qllast = NULL;
void parse_que (dbref player, char *command, dbref cause /* cause is needed to determine priority */
)
{
char buff[BUFFER_LEN], *s, *r;
s = buff;
strcpy (buff, command);
while (r = parse_up (&s, ';')) {
big_que (player, r, cause);
}
}
static int add_to (dbref player, int am)
{
int num = 0;
ATTR *a;
char buff[MAX_COMMAND_LEN];
player = db[player].owner;
a = atr_get (player, "QUEUE");
if (a)
num = atoi (a->value);
num += am;
if (num > 0)
sprintf (buff, "%d", num);
else
*buff = 0;
(void) atr_add (player, "QUEUE", buff, GOD, NOTHING);
return (num);
}
static void big_que (dbref player, char *command, dbref cause)
{
int a;
BQUE *tmp;
if ((Typeof (player) != TYPE_PLAYER) && (db[player].flags & HALT))
return;
/* make sure player can afford to do it */
if (!payfor (player,
QUEUE_COST + (((OS_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, "Run away objects, commands halted");
do_halt (db[player].owner, "");
/* halt means no command execution allowed */
db[player].flags |= HALT;
return;
}
tmp = (BQUE *) malloc (sizeof (BQUE));
strcpy ((tmp->comm = (char *) malloc (strlen (command) + 1)), command);
#ifdef MEM_CHECK
add_check ("bqueue");
add_check ("bqueue_comm");
#endif
tmp->player = player;
tmp->next = NULL;
tmp->left = 0;
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]);
#ifdef MEM_CHECK
add_check ("bqueue_env");
#endif
}
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 (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 + (((OS_RAND () & QUEUE_LOSS) == 0) ? 1 : 0))) {
notify (player, "Not enough money to queue command.");
return;
}
tmp = (BQUE *) malloc (sizeof (BQUE));
strcpy ((tmp->comm = (char *) malloc (strlen (command) + 1)), command);
#ifdef MEM_CHECK
add_check ("bqueue");
add_check ("bqueue_comm");
#endif
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]);
#ifdef MEM_CHECK
add_check ("bqueue_env");
#endif
}
qwait = tmp;
}
/* call every second to check for wait queue commands */
void do_second (void)
{
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, point->comm, 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 ((char *) point->env[a]);
#ifdef MEM_CHECK
del_check ("bqueue_env");
#endif
}
if (point->comm)
free ((char *) point->comm);
free ((char *) point);
#ifdef MEM_CHECK
del_check ("bqueue_comm");
del_check ("bqueue");
#endif
} else
next = (trail = point)->next;
}
int test_top (void)
{
return (qfirst ? 1 : 0);
}
/* execute one command off the top of the queue */
int do_top (void)
{
int a;
int i = 0;
BQUE *tmp;
dbref player;
char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN];
char tbuf3[BUFFER_LEN], *s;
if (!qfirst)
return (0);
if (qfirst->player && !(db[qfirst->player].flags & GOING)) {
giveto (qfirst->player, QUEUE_COST);
cplr = qfirst->player;
strcpy (ccom, qfirst->comm);
add_to (player = qfirst->player, -1);
qfirst->player = 0;
if ((Typeof (player) == TYPE_PLAYER) || !(db[player].flags & HALT)) {
for (a = 0; a < 10; a++) {
wptr[a] = qfirst->env[a];
}
strcpy (tbuf2, uncompress (qfirst->comm));
tbuf3[0] = '\0';
for (s = tbuf2; *s; tbuf3[i++] = toupper ((int)*s++));
tbuf3[i++] = '\0';
if ((strstr (tbuf3, "@DOL")) == NULL)
strcpy (tbuf1, pronoun_substitute (qfirst->cause, tbuf2, player));
else
strcpy (tbuf1, tbuf2);
if (IS (player, TYPE_THING, THING_VERBOSE))
notify (db[player].owner, tprintf ("#%d] %s", player, tbuf1));
process_command (player, tbuf1, qfirst->cause);
}
}
tmp = qfirst->next;
for (a = 0; a < 10; a++)
if (qfirst->env[a]) {
free ((char *) qfirst->env[a]);
#ifdef MEM_CHECK
del_check ("bqueue_env");
#endif
}
if (qfirst->comm)
free ((char *) qfirst->comm);
free ((char *) qfirst);
#ifdef MEM_CHECK
del_check ("bqueue_comm");
del_check ("bqueue");
#endif
if (!(qfirst = tmp))
qlast = NULL;
return (1);
}
/* tell player what commands they have pending in the queue */
void do_queue (dbref player, const char *what)
{
BQUE *tmp;
dbref victim = NOTHING;
int everything = 0;
int quick = 0;
int pq = 0, oq = 0, wq = 0;
int tpq = 0, toq = 0, twq = 0;
if (!string_compare (what, "count")) {
victim = player;
everything = 1;
quick = 1;
} else if (Wizard (player)) {
if (!what || !*what)
victim = player;
else if (!string_compare (what, "all")) { /* do the whole thing */
victim = player;
everything = 1;
} else {
init_match (player, what, TYPE_PLAYER);
match_player ();
match_absolute ();
match_me ();
victim = match_result ();
}
} else {
victim = player;
}
switch (victim) {
case NOTHING:
notify (player, "I couldn't find that player.");
break;
case AMBIGUOUS:
notify (player, "I don't know who you mean!");
break;
default:
if (everything == 1)
notify (player, "Queue for : all");
else
notify (player, tprintf ("Queue for : %s", db[victim].name));
if (!quick)
notify (player, "Player Queue:");
for (tmp = qfirst; tmp; tmp = tmp->next) {
tpq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
pq++;
if (!quick)
notify (player, tprintf ("%s:%s", unparse_object (player,
tmp->player), tmp->comm));
}
}
if (!quick)
notify (player, "Object Queue:");
for (tmp = qlfirst; tmp; tmp = tmp->next) {
toq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
oq++;
if (!quick)
notify (player, tprintf ("%s:%s", unparse_object (player,
tmp->player), tmp->comm));
}
}
if (!quick)
notify (player, "Wait Queue:");
for (tmp = qwait; tmp; tmp = tmp->next) {
twq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
wq++;
if (!quick)
notify (player, tprintf ("[%d]%s:%s", tmp->left,
unparse_object (player, tmp->player), tmp->comm));
}
}
notify (player, "------------ Queue Done ------------");
notify (player,
tprintf ("Totals: Player...%d/%d Object...%d/%d Wait...%d/%d",
pq, tpq, oq, toq, wq, twq));
}
}
/* remove all queued commands from a certain player */
/* it cannot be called on specific objects */
void do_halt (dbref player, char *ncom)
{
BQUE *tmp, *trail = NULL, *point, *next;
int num = 0;
notify (db[player].owner, "Halted.");
for (tmp = qfirst; tmp; tmp = tmp->next)
if ((tmp->player == player) || (db[tmp->player].owner == player)) {
num--;
giveto (player, QUEUE_COST);
tmp->player = 0;
}
for (tmp = qlfirst; tmp; tmp = tmp->next)
if ((tmp->player == player) || (db[tmp->player].owner == player)) {
num--;
giveto (player, QUEUE_COST);
tmp->player = 0;
}
/* remove wait q stuff */
for (point = qwait; point; point = next)
if ((point->player == player) || (db[point->player].owner == player)) {
int a;
giveto (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 ((char *) point->env[a]);
#ifdef MEM_CHECK
del_check ("bqueue_env");
#endif
}
if (point->comm)
free ((char *) point->comm);
free ((char *) point);
#ifdef MEM_CHECK
del_check ("bqueue_comm");
del_check ("bqueue");
#endif
} else
next = (trail = point)->next;
if (db[player].owner == player)
(void) atr_add (player, "QUEUE", "", GOD, NOTHING);
else
add_to (player, num);
if (*ncom)
parse_que (player, ncom, player);
}
void do_halt1 (dbref player, const char *arg1, const char *arg2)
{
dbref victim;
char temp[BUFFER_LEN];
if (*arg1 == '\0')
do_halt (player, "");
else {
init_match (player, arg1, NOTYPE);
match_neighbor ();
match_possession ();
match_me ();
match_absolute ();
match_player ();
if ((victim = noisy_match_result ()) == NOTHING)
return;
if ((db[victim].owner != player) && (!Wizard (player))) {
notify (player, "Permission denied.");
return;
}
if (Typeof (victim) != TYPE_PLAYER) {
sprintf (temp, "#%d", victim);
do_set (player, temp, "HALT");
} else {
if (victim != player)
notify (player, "Halted.");
do_halt (victim, (char*)arg2);
}
}
}
void do_allhalt (dbref player)
{
dbref victim;
if (!Wizard (player)) {
notify (player, "Sorry, you can only halt your own items.");
return;
}
for (victim = 0; victim < db_top; victim++) {
if (Typeof (victim) == TYPE_PLAYER) {
notify (victim, tprintf ("Your objects have been globally halted by %s",
db[player].name));
do_halt (victim, "");
}
}
}