/* ************************************************************************ * File: events.doc * * * * Usage: An explanation of how to use events * * * * Written by Eric Green (ejg3@cornell.edu) * ************************************************************************ */ Death Gate Events Table of Contents ----------------- 1. Event Functions and Event Objects 2. Functions for Manipulating Events 3. Steps to Create a New Event Type 4. An Example Event Type 5. Tips for Create Events ----------------------------------------------------------------------------- 1. Event Functions and Event Objects Each event type needs an: Event function: An event function is a function with a prototype of: long (event_function)(void *event_obj) This function is called when the event occurs, and is passed the event object (see below). If the function returns a positive value, the event is reenqueued using the return value as the number of pulses in the future the event will reoccur. If the function returns 0 or a negative number, the event is not reenqueued. If the event is not to be reenqueued, the event function is responsible for freeing the event object. There is a define: #define EVENTFUNC(name) long (name)(void *event_obj) to be used when declaring an event function. Event object: The event object is any structure with the fields to store any data needed by the event function. The event object should not be a game object (such as a struct char_data), since this object is freed when events are canceled (see cancel_event() below). All unique data contained by the object should be freed by a call of free(event_obj). In other words, don't have event_obj include pointers to other structures which aren't pointed to elsewhere. It is also not advisable to have pointers in the event object unless the thing they point to has a pointer to this event and cancels the event when it is freed. Passing NULL as an event object is valid (providing the event function doesn't need any data). ---------------------------------------------------------------------------- 2. Functions for Manipulating Events The prototypes for the interface functions for events are provided in events.h. They are: void event_init(void); This function initializes the event queue for all events. It is only called once, at the initialization of the game. struct event *event_create(EVENTFUNC(*func), void *event_obj, long when); This function creates a new event. At the current time plus 'when', the function call func(event_obj); will be made. A pointer to the created event is returned. Never free() the event returned. Use event_cancel instead if you want to get rid of it prematurely. void event_cancel(struct event *event); This function cancels an event currently in the queue. The event and the event_obj are freed by this call. void event_process(void); This function is called once each pulse to process any pending events. It should not be used outside of the main loop. long event_time(struct event *event); Given event, this function returns the number of pulses until the event occurs. One example of a place it is used is to get the pulses left before an object timer expires, so its current state can be saved and restored later. ----------------------------------------------------------------------------- 3. Steps to Create a New Event Type To add a new event type, you do not need to know anything about what's in events.c, queue.c, or queue.h, the core of the event code. To create an event type: 1. Declare an event object structure. 2. Create your event function. 3. Construct your event object, and call event_create() where needed. 4. Any place that the 'owner' of the event can be destroyed, call event_cancel(). ------------------------------------------------------------------------------ 4. An Example Event Type Example event type: /* the event object for the sniff event */ struct sniff_event_obj { struct char_data *ch; byte type; }; EVENTFUNC(sniff_event) { struct sniff_event_obj *seo = (struct sniff_event_obj *) event_obj; struct char_data *ch, *victim; ch = seo->ch; GET_CHAR_SNIFF(ch) = NULL; if (type == SNIFF_COLD) act("$n sniffs loudly.", FALSE, ch, NULL, NULL, TO_ROOM); else act("$n sniffs some cocaine.", FALSE, ch, NULL, NULL, TO_ROOM); act("You sniff.", FALSE, ch, NULL, NULL, TO_CHAR); if (--seo->severity <= 0) { /* we're done with sniffing */ free(event_obj); } else return PULSE_SNIFF; } ACMD(do_sniff) { struct sniff_event_obj *sniff; CREATE(sniff, struct sniff_event_obj, 1); sniff->ch = ch; sniff->severity = 5; if (GET_CLASS(ch) != CLASS_THIEF) sniff->type = SNIFF_COLD; else sniff->type = SNIFF_COCAINE; GET_CHAR_SNIFF(ch) = event_create(sniff_event, sniff, PULSE_SNIFF); send_to_char(OK, ch); } void extract_char(struct char_data *ch) { ... if (GET_CHAR_SNIFF(ch)) { event_cancel(GET_CHAR_SNIFF(ch)); GET_CHAR_SNIFF(ch) = NULL; } ... } ----------------------------------------------------------------------------- 5. Tips for Create Events Tips for creating events: o event_obj should always be freed (or reused) in the EVENTFUNC() o Any game object pointed to by event_obj should have a pointer to the the event so it can cancel the event if it is extracted. o Any game object with pointers to an event should have the event pointer set to NULL in EVENTFUNC and immediately following event_cancel(). o Any place a game object is extracted from the game, any events it points to should be canceled and its pointer to the events set to NULL.