/* ************************************************************************
*  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.