From: Oliver Jowett <oliver@sa-search.massey.ac.nz>
Subject: Re: Events and Ticks


> I did some thinking on this very subject over the weekend. First, I don't
> think that event-based means you get rid of the cascading loops. You still
> have to poll mobs to see if they have events to register.
> 
> So, the aggressive function could work like this:
> 
> [ char_to_room registers a "new person in room" event on the room ]
> [ char_to_room registers another "new person in room" event on the room ]
> 
> [ room_event loop ]
>  we realize that the room has an event pending, so we look at it. Since its
> a "new person in room" event, we check for any room reactions (through room
> programs) and we pass the message to each character and object in the room.
> We also delete any other "new person in room" events, since we've handled
> it.
> 
> [ mob_event loop ]
> the aggressive mob catches the message and decides that it needs to agress
> on a random person. Purge the event.

You can use a single global event queue, which means you don't have to 
run through every room/mob on each pulse.

As an example, here's my current event structure:

/* Event queueing/dequeueing/etc */

typedef void (*ev_callback)(struct _event *ev);

struct _event {
  union {
    CHAR_DATA *ch;
    OBJ_DATA *obj;
    ROOM_INDEX_DATA *room;
  } item;                   /* object/char etc. associated with this       */

  void *param;              /* param for the callback                      */

  ev_callback callback;     /* callback to call                            */
  int when;                 /* when event is going to happen (pulseclock)  */

  struct _event *next;      /* next in priority queue                      */
  struct _event *nextitem;  /* next in item queue                          */
  struct _event **start;    /* pointer to pointer to start of this sublist */
};

The 'next' pointer goes through a global priority queue of events; the
'nextitem' and 'start' pointers are to maintain a list for each
char/room/obj/etc. 

In char_data (and obj_data, room_index_data, etc) I have:

  EVENT *events;

which is a pointer to the first event concerning this character in the
queue; the nextitem pointers then chain through other events concerning
it. ch->events->start == &ch->events, so that the event update function
can remove an event from the itemlist without knowing the details of the
object it's removing it from.

> I'm sure that there are better ways to do it, but the main point is simple:
> the event-based system waits until the movement cycle is complete before it
> starts agressing.

Yes, exactly.

Oliver
--
"The flames are all long gone / But the pain lingers on..."