/* 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++; } }