/* ************************************************************************ * File: events.doc * * * * Usage: An explanation of how to use mud events * * Written by Joseph Arnusch (Vatiken) (Joseph.Arnusch@gmail.com) * * * Usage: An explanation of how to use events * * Written by Eric Green (ejg3@cornell.edu) * ************************************************************************ */ Vatiken's MUD event system -------------------------- Table of Contents ----------------- 1. Purpose 2. Functions Related to MUD Events 3. Steps to Create a New MUD Event 4. Differences between the two systems 1. PURPOSE I scribed a "MUD" event system using the "Death Gate Event" system already in place to allow for increased ease, and maintainability for both rookie and experienced programmers. 2. FUNCTIONS RELATED TO MUD EVENTS a) See EVENTFUNC() in the Death Gate Events documentation below b) void init_events(void) "init_events()" creates the global events list and is the allocated location for placing any global events, these may include things like AI, Weather, and Combat. c) struct mud_event_data * char_has_mud_event(struct char_data * ch, event_id iId) "char_has_mud_event()" returns an event in the characters event list that matches the supplied "event_id", or NULL if none exists. d) NEW_EVENT(event_id, struct, var, time) "NEW_EVENT" creates a new event of the "event_id" type, with the supplied structure (ch, desc, object, etc..), any addtional "var"s, and is set to activate in this amount of "time". e) struct mud_event_list[] The mud_event_list[] is an array of all the events you've designed into your MUD. The reason for this excessive step is primarily for organization and troubleshooting, and it takes a mere couple seconds to add to mud_events.c. 3. STEPS TO CREATE A NEW MUD EVENT a) Add the new event_id to enum list in mud_events.h typedef enum { eNULL, ePROTOCOLS, /* The Protocol Detection Event */ eWHIRLWIND, /* The Whirlwind Attack */ eNEWEVENT /* A NEW EVENT */ } event_id; b) Create the event EVENTFUNC(new_event) { struct char_data *ch, *tch; struct mud_event_data *pMudEvent; struct list_data *room_list; int count; /* This is just a dummy check, but we'll do it anyway */ if (event_obj == NULL) return 0; ... return 0; } c) Add the event_id data to mud_event_list[] struct mud_event_list mud_event_index[] = { { "Null" , NULL , -1 }, /* eNULL */ { "Protocol" , get_protocols , EVENT_DESC }, /* ePROTOCOLS */ { "Whirlwind" , event_whirlwind, EVENT_CHAR } /* eWHIRLWIND */ { "A New Event" , new_event , EVENT_CHAR } /* eNEWEVENT */ }; d) Place a call for the new event if (variableX > variableY) NEW_EVENT(eNEWEVENT, ch, NULL, 60 * PASSES_PER_SEC); e) Sit back and enjoy your event triggering in 60 seconds. 4. DIFFERENCES BETWEEN THE TWO SYSTEMS The biggest differences between the two systems is that the MUD Event System employs certain functions to make it more "dummy proof" without limiting functionality. For example: a) all memory allocated for a MUD event will be freed when the event is no longer in use. b) the mud_event_index[] can/will log when events are called, allowing for an easy way to debug any problems. c) the mud_event structure allows for easy handling of memory that shouldn't be freed with the event like the character him/herself. d) when a character leaves the game, all mud_events will be cleared without manually having to place checks in free_char(). The "MUD Event" system should be adequate for 99% of all events that a developer may be interested in creating, and still allows access the dg_event event system for anything requiring more complicated procedures. ======================================================================== 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.