/*
CircleMUD Server-Side Macro/Alias Timer support v.1.0
by Keats (plamzi) @ bedlam.gotdns.com:9000
bedlam@eyecandid.com
*/
/* ADD to structs.h */
struct txt_q {
struct txt_block *head;
struct txt_block *tail;
/* begin addition */
struct txt_q *next;
int delay;
/* end addition */
};
struct descriptor_data {
...
/* begin addition */
struct txt_q *timer_input;
/* end addition */
}
/* ADD to comm.c */
if (!(pulse % PULSE_VIOLENCE)) perform_violence();
...
/* begin addition */
if (!(pulse % PASSES_PER_SEC)) process_timer_queues();
/* end addition */
/* ADD to handler.c */
void extract_char(struct char_data * ch)
{
...
/* begin addition */
// flush any delay timer queues when char is extracted
if (ch->desc && ch->desc->timer_input) {
struct txt_q *q, *temp;
while (ch->desc->timer_input) {
q = ch->desc->timer_input;
REMOVE_FROM_LIST(q, ch->desc->timer_input, next);
free(q);
}
}
/* end addition */
if (ch->desc) {
STATE(ch->desc) = CON_MENU;
SEND_TO_Q(MENU, ch->desc);
}
} /* end of extract_char */
/* ADD to interpreter.c */
/* begin addition */
#define Q_ADD 0
#define Q_RESUME 1
ACMD(do_wait);
/* end addition */
...
/* begin addition */
{ "wait" , POS_DEAD, do_wait , 0, 0, 0, 0},
/* end addition */
...
/* push our temp_queue on to the _front_ of the input queue */
void perform_complex_alias(struct descriptor_data *d, struct txt_q *input_q, char *orig, struct alias *a)
{
...
/* comment out the block at the end of func */
/* push our temp_queue on to the _front_ of the input queue */
/*
if (input_q->head == NULL)
*input_q = temp_queue;
else {
temp_queue.tail->next = input_q->head;
input_q->head = temp_queue.head;
}
*/
/* begin addition */
run_timer_queue(d, &d->input, &temp_queue, Q_ADD);
/* end addition */
}
/* Bedlam server-side timers for aliases (can be used for server-side triggers as well) */
/* called once per sec from comm.c - currently processes timers even on linkless chars but you can change that behavior */
void process_timer_queues() {
struct descriptor_data *d;
for (d = descriptor_list; d; d = d->next) {
if (d->connected != CON_PLAYING || !d->character || IS_NPC(d->character) || !d->timer_input) continue;
process_timer_queue(d);
}
}
void process_timer_queue(struct descriptor_data *d) {
struct txt_q *q, *next;
int count;
//this odd loop allows for queues to be removed during iteration
for (q = d->timer_input; q; q = next) {
if (!q) continue;
next = q->next;
q->delay--;
if (q->delay == 0) run_timer_queue(d, &d->input, q, Q_RESUME);
}
}
void run_timer_queue(struct descriptor_data *d, struct txt_q *input_q, struct txt_q *q, int mode) {
/* mode 0 is Q_ADD (called by perform_complex_alias), 1 is Q_RESUME (called by process_timer_queue)*/
struct txt_block *this, *next;
struct txt_q temp_queue;
struct txt_q *temp;
int dummy;
temp_queue.head = temp_queue.tail = NULL;
//if (mode)
//log("DEBUG: entering run timer queue in mode: RESUME");
//else
//log("DEBUG: entering run timer queue in mode: ADD");
//log("DEBUG: queue has timer");
for (this = next = q->head;this;this = next) {
if (!next) continue;
next = this->next;
get_from_q(q, arg, &dummy);
half_chop(arg, buf, buf2);
if (str_cmp(buf, "wait")) {
//log("DEBUG: Non-wait cmd written to queue");
write_to_q(arg, &temp_queue, 1);
if (!next) {
if (mode == Q_RESUME) {
REMOVE_FROM_LIST(q, d->timer_input, next);
free(q);
//log("DEBUG: remove from timer queues (last cmd reached)");
}
add_to_q(temp_queue, d);
return;
} else
continue;
}
if (!*buf2) {
//no wait number, ignore
//log("DEBUG: no wait seconds");
continue;
}
if (!is_number(buf2)) {
//wait arg is not number, ignore
//log("DEBUG: wait argument is not a number");
continue;
}
int delay = atoi(buf2);
if (delay > 0 && delay < 3601) {
//log("DEBUG: valid delay timer detected");
if (!next) {
if (mode == Q_RESUME) {
REMOVE_FROM_LIST(q, d->timer_input, next);
free(q);
//log("DEBUG: remove from timer queues (last cmd is wait)");
}
}
else {
//more commands
q->delay = delay;
if (mode == Q_ADD) {
//log("DEBUG: adding new timer queue");
if (!d->timer_input) {
//log("DEBUG: first timer queue");
CREATE(d->timer_input, struct txt_q, 1);
d->timer_input->delay = q->delay;
d->timer_input->head = q->head;
d->timer_input->tail = q->tail;
d->timer_input->next = NULL;
}
else {
//log("DEBUG: append timer queue");
CREATE(temp, struct txt_q, 1);
temp->delay = q->delay;
temp->head = q->head;
temp->tail = q->tail;
temp->next = d->timer_input;
d->timer_input = temp;
}
}
//else log("DEBUG: reset timer for a delay queue");
} //end command loop
add_to_q(temp_queue, d);
//print_q(&d->input);
//print_q(&d->delayed_input);
return;
} // timer out of range error
} // end queue loop
}
void add_to_q (struct txt_q temp_queue, struct descriptor_data *d) {
if (temp_queue.head) {
//log("DEBUG: adding pre-timer commands to input queue");
if ((&d->input)->head == NULL)
*(&d->input) = temp_queue;
else {
temp_queue.tail->next = (&d->input)->head;
(&d->input)->head = temp_queue.head;
}
}
else {
// the dummy command 'wait' is set up to print nothing back
// we 'need' it for macros that begin with 'wait #'
// just so we won't have to modify the way comm.c handles input
// this is a quick workaround - there's probably a better way
sprintf(arg, "wait");
write_to_q(arg, &d->input, 1);
}
}
ACMD(do_wait) { return; }
/* debug helper func - print queue */
void print_q (struct txt_q *q) {
//log("DEBUG: print queue");
struct txt_block *this;
int qnum = 1;
for (this = q->head; this; this = this->next) {
sprintf(buf, "(Q) %d. %s", qnum, this->text);
log(buf);
qnum++;
}
}