mirror of
https://github.com/tbamud/tbamud.git
synced 2026-01-13 12:58:50 +01:00
249 lines
5.4 KiB
C
249 lines
5.4 KiB
C
/**************************************************************************
|
|
* File: dg_event.c Part of tbaMUD *
|
|
* Usage: This file contains a simplified event system to allow trigedit *
|
|
* to use the "wait" command, causing a delay in the middle of a script. *
|
|
* *
|
|
* $Author: Mark A. Heilpern/egreen/Welcor $ *
|
|
* $Date: 2004/10/11 12:07:00$ *
|
|
* $Revision: 1.0.14 $ *
|
|
**************************************************************************/
|
|
|
|
#include "conf.h"
|
|
#include "sysdep.h"
|
|
#include "structs.h"
|
|
#include "db.h"
|
|
#include "utils.h"
|
|
#include "dg_event.h"
|
|
#include "constants.h"
|
|
|
|
struct queue *event_q; /* the event queue */
|
|
|
|
extern long pulse;
|
|
|
|
/* initializes the event queue */
|
|
void event_init(void)
|
|
{
|
|
event_q = queue_init();
|
|
}
|
|
|
|
|
|
/* Add an event to the current list. Creates an event and returns it. */
|
|
struct event *event_create(EVENTFUNC(*func), void *event_obj, long when)
|
|
{
|
|
struct event *new_event;
|
|
|
|
if (when < 1) /* make sure its in the future */
|
|
when = 1;
|
|
|
|
CREATE(new_event, struct event, 1);
|
|
new_event->func = func;
|
|
new_event->event_obj = event_obj;
|
|
new_event->q_el = queue_enq(event_q, new_event, when + pulse);
|
|
|
|
return new_event;
|
|
}
|
|
|
|
/* removes the event from the system */
|
|
void event_cancel(struct event *event)
|
|
{
|
|
if (!event) {
|
|
log("SYSERR: Attempted to cancel a NULL event");
|
|
return;
|
|
}
|
|
|
|
if (!event->q_el) {
|
|
log("SYSERR: Attempted to cancel a non-NULL unqueued event, freeing anyway");
|
|
} else
|
|
queue_deq(event_q, event->q_el);
|
|
|
|
if (event->event_obj)
|
|
free(event->event_obj);
|
|
free(event);
|
|
}
|
|
|
|
/* Process any events whose time has come. */
|
|
void event_process(void)
|
|
{
|
|
struct event *the_event;
|
|
long new_time;
|
|
|
|
while ((long) pulse >= queue_key(event_q)) {
|
|
if (!(the_event = (struct event *) queue_head(event_q))) {
|
|
log("SYSERR: Attempt to get a NULL event");
|
|
return;
|
|
}
|
|
|
|
/* Set the_event->q_el to NULL so that any functions called beneath
|
|
* event_process can tell if they're being called beneath the actual
|
|
* event function. */
|
|
the_event->q_el = NULL;
|
|
|
|
/* call event func, reenqueue event if retval > 0 */
|
|
if ((new_time = (the_event->func)(the_event->event_obj)) > 0)
|
|
the_event->q_el = queue_enq(event_q, the_event, new_time + pulse);
|
|
else
|
|
free(the_event);
|
|
}
|
|
}
|
|
|
|
/* returns the time remaining before the event */
|
|
long event_time(struct event *event)
|
|
{
|
|
long when;
|
|
|
|
when = queue_elmt_key(event->q_el);
|
|
|
|
return (when - pulse);
|
|
}
|
|
|
|
/* frees all events in the queue */
|
|
void event_free_all(void)
|
|
{
|
|
struct event *the_event;
|
|
|
|
while ((the_event = (struct event *) queue_head(event_q))) {
|
|
if (the_event->event_obj)
|
|
free(the_event->event_obj);
|
|
free(the_event);
|
|
}
|
|
|
|
queue_free(event_q);
|
|
}
|
|
|
|
/* boolean function to tell whether an event is queued or not */
|
|
int event_is_queued(struct event *event)
|
|
{
|
|
if (event->q_el)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Generic queue functions for building and using a priority queue. */
|
|
/* returns a new, initialized queue */
|
|
struct queue *queue_init(void)
|
|
{
|
|
struct queue *q;
|
|
|
|
CREATE(q, struct queue, 1);
|
|
|
|
return q;
|
|
}
|
|
|
|
/* add data into the priority queue q with key */
|
|
struct q_element *queue_enq(struct queue *q, void *data, long key)
|
|
{
|
|
struct q_element *qe, *i;
|
|
int bucket;
|
|
|
|
CREATE(qe, struct q_element, 1);
|
|
qe->data = data;
|
|
qe->key = key;
|
|
|
|
bucket = key % NUM_EVENT_QUEUES; /* which queue does this go in */
|
|
|
|
if (!q->head[bucket]) { /* queue is empty */
|
|
q->head[bucket] = qe;
|
|
q->tail[bucket] = qe;
|
|
}
|
|
|
|
else {
|
|
for (i = q->tail[bucket]; i; i = i->prev) {
|
|
|
|
if (i->key < key) { /* found insertion point */
|
|
if (i == q->tail[bucket])
|
|
q->tail[bucket] = qe;
|
|
else {
|
|
qe->next = i->next;
|
|
i->next->prev = qe;
|
|
}
|
|
|
|
qe->prev = i;
|
|
i->next = qe;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == NULL) { /* insertion point is front of list */
|
|
qe->next = q->head[bucket];
|
|
q->head[bucket] = qe;
|
|
qe->next->prev = qe;
|
|
}
|
|
}
|
|
|
|
return qe;
|
|
}
|
|
|
|
/* remove queue element qe from the priority queue q */
|
|
void queue_deq(struct queue *q, struct q_element *qe)
|
|
{
|
|
int i;
|
|
|
|
assert(qe);
|
|
|
|
i = qe->key % NUM_EVENT_QUEUES;
|
|
|
|
if (qe->prev == NULL)
|
|
q->head[i] = qe->next;
|
|
else
|
|
qe->prev->next = qe->next;
|
|
|
|
if (qe->next == NULL)
|
|
q->tail[i] = qe->prev;
|
|
else
|
|
qe->next->prev = qe->prev;
|
|
|
|
free(qe);
|
|
}
|
|
|
|
/* Removes and returns the data of the first element of the priority queue q. */
|
|
void *queue_head(struct queue *q)
|
|
{
|
|
void *dg_data;
|
|
int i;
|
|
|
|
i = pulse % NUM_EVENT_QUEUES;
|
|
|
|
if (!q->head[i])
|
|
return NULL;
|
|
|
|
dg_data = q->head[i]->data;
|
|
queue_deq(q, q->head[i]);
|
|
return dg_data;
|
|
}
|
|
|
|
/* Returns the key of the head element of the priority queue if q is NULL, then
|
|
* return the largest unsigned number. */
|
|
long queue_key(struct queue *q)
|
|
{
|
|
int i;
|
|
|
|
i = pulse % NUM_EVENT_QUEUES;
|
|
|
|
if (q->head[i])
|
|
return q->head[i]->key;
|
|
else
|
|
return LONG_MAX;
|
|
}
|
|
|
|
/* returns the key of queue element qe */
|
|
long queue_elmt_key(struct q_element *qe)
|
|
{
|
|
return qe->key;
|
|
}
|
|
|
|
/* free q and contents */
|
|
void queue_free(struct queue *q)
|
|
{
|
|
int i;
|
|
struct q_element *qe, *next_qe;
|
|
|
|
for (i = 0; i < NUM_EVENT_QUEUES; i++)
|
|
for (qe = q->head[i]; qe; qe = next_qe) {
|
|
next_qe = qe->next;
|
|
free(qe);
|
|
}
|
|
|
|
free(q);
|
|
}
|
|
|