diff -r -N -c socketmud/src/Makefile socketmud-event/src/Makefile *** socketmud/src/Makefile Sat Mar 22 14:41:50 2003 --- socketmud-event/src/Makefile Wed Apr 2 10:06:26 2003 *************** *** 2,9 **** C_FLAGS = -Wall -O -pedantic L_FLAGS = -lz -lpthread -lcrypt ! O_FILES = socket.o io.o strings.o update.o utils.o interpret.o help.o \ ! action_safe.o mccp.o save.o all: $(O_FILES) rm -f SocketMud --- 2,9 ---- C_FLAGS = -Wall -O -pedantic L_FLAGS = -lz -lpthread -lcrypt ! O_FILES = socket.o io.o strings.o utils.o interpret.o help.o \ ! action_safe.o mccp.o save.o event.o event-handler.o all: $(O_FILES) rm -f SocketMud diff -r -N -c socketmud/src/event-handler.c socketmud-event/src/event-handler.c *** socketmud/src/event-handler.c Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event-handler.c Wed Apr 2 10:06:26 2003 *************** *** 0 **** --- 1,439 ---- + #include + #include + #include + #include + #include + + /* include main header file */ + #include "mud.h" + + EVENT_DATA *eventqueue[MAX_EVENT_HASH]; + EVENT_DATA *eventlast[MAX_EVENT_HASH]; + EVENT_DATA *pEventNext = NULL, *event_free = NULL, *event_free_last = NULL; + EVENT_DATA *global_event_list = NULL; + EVENT_DATA *global_event_last = NULL; + int current_bucket = 0; + + /* function :: enqueue_event() + * arguments :: the event to enqueue and the delay time. + * ====================================================== + * This function takes an event which has _already_ been + * linked locally to it's owner, and places it in the + * event queue, thus making it execute in the given time. + */ + bool enqueue_event(EVENT_DATA *event, int game_pulses) + { + int bucket, passes; + + /* check to see if the event has been attached to an owner */ + if (event->ownertype == EVENT_UNOWNED) + { + bug("enqueue_event: event type %d with no owner.", event->type); + return FALSE; + } + + /* An event must be enqueued into the future */ + if (game_pulses < 1) + game_pulses = 1; + + /* calculate which bucket to put the event in, + * and how many passes the event must stay in the queue. + */ + bucket = (game_pulses + current_bucket) % MAX_EVENT_HASH; + passes = game_pulses / MAX_EVENT_HASH; + + /* let the event store this information */ + event->passes = passes; + event->bucket = bucket; + + /* attach the event in the queue */ + LINK_GLOBAL(event, eventqueue[bucket], eventlast[bucket]); + + /* success */ + return TRUE; + } + + /* function :: free_event() + * arguments :: the event to be free'ed. + * ====================================================== + * This function recycles events. Can be safely called + * on any dequeued event. + */ + void free_event(EVENT_DATA *event) + { + /* free memory */ + free(event->argument); + + /* attach data to the free list */ + LINK_GLOBAL(event, event_free, event_free_last); + } + + /* function :: dequeue_event() + * arguments :: the event to dequeue. + * ====================================================== + * This function takes an event which has _already_ been + * enqueued, and removes it both from the event queue, and + * from the owners local list. This function is usually + * called when the owner is destroyed or after the event + * is executed. + */ + void dequeue_event(EVENT_DATA *event) + { + /* dequeue from the bucket */ + UNLINK_GLOBAL(event, eventqueue[event->bucket], eventlast[event->bucket], + "dequeue_event: event type %d not found in global queue.", event->type); + + /* update global next pointer if we have to */ + if (event == pEventNext) + pEventNext = pEventNext->next_global; + + /* dequeue from owners local list */ + switch(event->ownertype) + { + default: + bug("dequeue_event: event type %d has no owner.", event->type); + break; + case EVENT_OWNER_GAME: + UNLINK_LOCAL(event, global_event_list, global_event_last, + "dequeue_event (game): event type %d not found in local list.", event->type); + break; + case EVENT_OWNER_DMOB: + UNLINK_LOCAL(event, event->owner.dMob->event_first, event->owner.dMob->event_last, + "dequeue_event (mobile): event type %d not found in local list.", event->type); + break; + case EVENT_OWNER_DSOCKET: + UNLINK_LOCAL(event, event->owner.dSock->event_first, event->owner.dSock->event_last, + "dequeue_event (socket): event type %d not found in local list.", event->type); + break; + } + + /* free the data */ + free_event(event); + } + + /* function :: alloc_event() + * arguments :: none + * ====================================================== + * This function allocates memory for an event, and + * makes sure it's values are set to default. + */ + EVENT_DATA *alloc_event() + { + EVENT_DATA *event; + + if (event_free) + { + event = event_free; + + UNLINK_GLOBAL(event, event_free, event_free_last, + "alloc_event: %s", "event not found in local list."); + } + else + { + event = calloc(1, sizeof(*event)); + } + + /* clear the event */ + event->fun = NULL; + event->argument = NULL; + event->owner.dMob = NULL; /* only need to NULL one of the union members */ + event->passes = 0; + event->bucket = 0; + event->ownertype = EVENT_UNOWNED; + event->type = EVENT_NONE; + + /* return the allocated and cleared event */ + return event; + } + + /* function :: init_event_queue() + * arguments :: what section to initialize. + * ====================================================== + * This function is used to initialize the event queue, + * and the first section should be initialized at boot, + * the second section should be called after all areas, + * players, monsters, etc has been loaded into memory, + * and it should contain all maintanence events. + */ + void init_event_queue(int section) + { + EVENT_DATA *event; + int i; + + if (section == 1) + { + for (i = 0; i < MAX_EVENT_HASH; i++) + { + eventqueue[i] = NULL; + eventlast[i] = NULL; + } + } + else if (section == 2) + { + event = alloc_event(); + event->fun = &event_game_tick; + event->type = EVENT_GAME_TICK; + add_event_game(event, 10 * 60 * PULSES_PER_SECOND); + } + } + + /* function :: heartbeat() + * arguments :: none + * ====================================================== + * This function is called once per game pulse, and it will + * check the queue, and execute any pending events, which + * has been enqueued to execute at this specific time. + */ + void heartbeat() + { + EVENT_DATA *event; + + /* current_bucket should be global, it is also used in enqueue_event + * to figure out what bucket to place the new event in. + */ + current_bucket = (current_bucket + 1) % MAX_EVENT_HASH; + + for (event = eventqueue[current_bucket]; event; event = pEventNext) + { + /* pEventNext is also global, should an event cause other + * events to be dequeued, it is vital that we known which + * event is actually next. Remember to update this pointer in + * dequeue_event(). + */ + pEventNext = event->next_global; + + /* Here we use the event->passes integer, to keep track of + * how many times we have ignored this event. + */ + if (event->passes-- > 0) continue; + + /* execute event and extract if needed. We assume that all + * event functions are of the following prototype + * + * bool event_function ( EVENT_DATA *event ); + * + * Any event returning TRUE is not dequeued, it is assumed + * that the event has dequeued itself. + */ + if (!((*event->fun)(event))) + dequeue_event(event); + } + } + + /* function :: add_event_mobile() + * arguments :: the event, the owner and the delay + * ====================================================== + * This function attaches an event to a mobile, and sets + * all the correct values, and makes sure it is enqueued + * into the event queue. + */ + void add_event_mobile(EVENT_DATA *event, D_MOBILE *dMob, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_mobile: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_mobile: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_DMOB; + event->owner.dMob = dMob; + + /* attach the event to the mobiles local list */ + LINK_LOCAL(event, dMob->event_first, dMob->event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_mobile: event type %d failed to be enqueued.", event->type); + } + + /* function :: add_event_socket() + * arguments :: the event, the owner and the delay + * ====================================================== + * This function attaches an event to a socket, and sets + * all the correct values, and makes sure it is enqueued + * into the event queue. + */ + void add_event_socket(EVENT_DATA *event, D_SOCKET *dSock, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_socket: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_socket: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_DSOCKET; + event->owner.dSock = dSock; + + /* attach the event to the sockets local list */ + LINK_LOCAL(event, dSock->event_first, dSock->event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_socket: event type %d failed to be enqueued.", event->type); + } + + /* function :: add_event_game() + * arguments :: the event and the delay + * ====================================================== + * This funtion attaches an event to the list og game + * events, and makes sure it's enqueued with the correct + * delay time. + */ + void add_event_game(EVENT_DATA *event, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_game: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_game: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_GAME; + + /* attach the event to the gamelist */ + LINK_LOCAL(event, global_event_list, global_event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_game: event type %d failed to be enqueued.", event->type); + } + + /* function :: event_isset_socket() + * arguments :: the socket and the type of event + * ====================================================== + * This function checks to see if a given type of event + * is enqueued/attached to a given socket, and if it is, + * it will return a pointer to this event. + */ + EVENT_DATA *event_isset_socket(D_SOCKET *dSock, int type) + { + EVENT_DATA *event; + + for (event = dSock->event_first; event; event = event->next_local) + { + if (event->type == type) + return event; + } + + /* no event found, return NULL */ + return NULL; + } + + /* function :: event_isset_mobile() + * arguments :: the mobile and the type of event + * ====================================================== + * This function checks to see if a given type of event + * is enqueued/attached to a given mobile, and if it is, + * it will return a pointer to this event. + */ + EVENT_DATA *event_isset_mobile(D_MOBILE *dMob, int type) + { + EVENT_DATA *event; + + for (event = dMob->event_first; event; event = event->next_local) + { + if (event->type == type) + return event; + } + + /* no event found, return NULL */ + return NULL; + } + + /* function :: strip_event_socket() + * arguments :: the socket and the type of event + * ====================================================== + * This function will dequeue all events of a given type + * from the given socket. + */ + void strip_event_socket(D_SOCKET *dSock, int type) + { + EVENT_DATA *event, *event_next; + + for (event = dSock->event_first; event; event = event_next) + { + event_next = event->next_local; + + if (event->type == type) + dequeue_event(event); + } + } + + /* function :: strip_event_mobile() + * arguments :: the mobile and the type of event + * ====================================================== + * This function will dequeue all events of a given type + * from the given mobile. + */ + void strip_event_mobile(D_MOBILE *dMob, int type) + { + EVENT_DATA *event, *event_next; + + for (event = dMob->event_first; event; event = event_next) + { + event_next = event->next_local; + + if (event->type == type) + dequeue_event(event); + } + } + + /* function :: init_events_mobile() + * arguments :: the mobile + * ====================================================== + * this function should be called when a player is loaded, + * it will initialize all updating events for that player. + */ + void init_events_player(D_MOBILE *dMob) + { + EVENT_DATA *event; + + /* save the player every 2 minutes */ + event = alloc_event(); + event->fun = &event_mobile_save; + event->type = EVENT_MOBILE_SAVE; + add_event_mobile(event, dMob, 2 * 60 * PULSES_PER_SECOND); + } + + /* function :: init_events_socket() + * arguments :: the mobile + * ====================================================== + * this function should be called when a socket connects, + * it will initialize all updating events for that socket. + */ + void init_events_socket(D_SOCKET *dSock) + { + EVENT_DATA *event; + + /* disconnect/idle */ + event = alloc_event(); + event->fun = &event_socket_idle; + event->type = EVENT_SOCKET_IDLE; + add_event_socket(event, dSock, 5 * 60 * PULSES_PER_SECOND); + } diff -r -N -c socketmud/src/event.c socketmud-event/src/event.c *** socketmud/src/event.c Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event.c Wed Apr 2 10:06:26 2003 *************** *** 0 **** --- 1,80 ---- + #include + #include + #include + #include + + /* include main header file */ + #include "mud.h" + + /* event_game_tick is just to show how to make global events + * which can be used to update the game. + */ + bool event_game_tick(EVENT_DATA *event) + { + D_MOBILE *dMob; + + /* send a tick message to everyone */ + for (dMob = dmobile_list; dMob; dMob = dMob->next) + { + text_to_mobile(dMob, "Tick!\n\r"); + } + + /* enqueue another game tick in 10 minutes */ + event = alloc_event(); + event->fun = &event_game_tick; + event->type = EVENT_GAME_TICK; + add_event_game(event, 10 * 60 * PULSES_PER_SECOND); + + return FALSE; + } + + bool event_mobile_save(EVENT_DATA *event) + { + D_MOBILE *dMob; + + /* Check to see if there is an owner of this event. + * If there is no owner, we return TRUE, because + * it's the safest - and post a bug message. + */ + if ((dMob = event->owner.dMob) == NULL) + { + bug("event_mobile_save: no owner."); + return TRUE; + } + + /* save the actual player file */ + save_player(dMob); + + /* enqueue a new event to save the pfile in 2 minutes */ + event = alloc_event(); + event->fun = &event_mobile_save; + event->type = EVENT_MOBILE_SAVE; + add_event_mobile(event, dMob, 2 * 60 * PULSES_PER_SECOND); + + return FALSE; + } + + bool event_socket_idle(EVENT_DATA *event) + { + D_SOCKET *dSock; + + /* Check to see if there is an owner of this event. + * If there is no owner, we return TRUE, because + * it's the safest - and post a bug message. + */ + if ((dSock = event->owner.dSock) == NULL) + { + bug("event_socket_idle: no owner."); + return TRUE; + } + + /* tell the socket that it has idled out, and close it */ + text_to_socket(dSock, "You have idled out...\n\n\r"); + close_socket(dSock, FALSE); + + /* since we closed the socket, all events owned + * by that socket has been dequeued, and we need + * to return TRUE, so the caller knows this. + */ + return TRUE; + } diff -r -N -c socketmud/src/event.h socketmud-event/src/event.h *** socketmud/src/event.h Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event.h Wed Apr 2 10:06:26 2003 *************** *** 0 **** --- 1,170 ---- + /* event.h + * + * This file contains the event data struture, global variables + * and specially defined values like MAX_EVENT_HASH. + */ + + /* the size of the event queue */ + #define MAX_EVENT_HASH 128 + + /* the different types of owners */ + #define EVENT_UNOWNED 0 + #define EVENT_OWNER_NONE 1 + #define EVENT_OWNER_DSOCKET 2 + #define EVENT_OWNER_DMOB 3 + #define EVENT_OWNER_GAME 4 + + /* the NULL event type */ + #define EVENT_NONE 0 + + /* Mobile events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions. + */ + #define EVENT_MOBILE_SAVE 1 + + /* Socket events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions. + */ + #define EVENT_SOCKET_IDLE 1 + + /* Game events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions + */ + #define EVENT_GAME_TICK 1 + + /* the event prototype */ + typedef bool EVENT_FUN ( EVENT_DATA *event ); + + /* a couple of linked list macro's */ + #define LINK_GLOBAL(item, list, last) \ + { \ + if (last == NULL) \ + { \ + last = item; \ + list = item; \ + item->next_global = NULL; \ + item->prev_global = NULL; \ + } \ + else \ + { \ + item->next_global = list; \ + item->prev_global = NULL; \ + list->prev_global = item; \ + list = item; \ + } \ + } + #define LINK_LOCAL(item, list, last) \ + { \ + if (last == NULL) \ + { \ + last = item; \ + list = item; \ + item->next_local = NULL; \ + item->prev_local = NULL; \ + } \ + else \ + { \ + item->next_local = list; \ + item->prev_local = NULL; \ + list->prev_local = item; \ + list = item; \ + } \ + } + #define UNLINK_GLOBAL(item, list, last, bugmess, bugarg) \ + { \ + if (last == list) \ + { \ + last = NULL; \ + list = NULL; \ + } \ + else if (item == list) \ + { \ + list = item->next_global; \ + item->next_global->prev_global = NULL; \ + } \ + else if (item == last) \ + { \ + last = item->prev_global; \ + item->prev_global->next_global = NULL; \ + } \ + else if (!item->prev_global || !item->next_global) \ + { \ + bug(bugmess, bugarg); \ + } \ + else \ + { \ + item->prev_global->next_global = item->next_global; \ + item->next_global->prev_global = item->prev_global; \ + } \ + } + #define UNLINK_LOCAL(item, list, last, bugmess, bugarg) \ + { \ + if (last == list) \ + { \ + last = NULL; \ + list = NULL; \ + } \ + else if (item == list) \ + { \ + list = item->next_local; \ + item->next_local->prev_local = NULL; \ + } \ + else if (item == last) \ + { \ + last = item->prev_local; \ + item->prev_local->next_local = NULL; \ + } \ + else if (!item->prev_local || !item->next_local) \ + { \ + bug(bugmess, bugarg); \ + } \ + else \ + { \ + item->prev_local->next_local = item->next_local; \ + item->next_local->prev_local = item->prev_local; \ + } \ + } + + /* the event structure */ + struct event_data + { + EVENT_DATA * next_global; /* next event in this hash bucket */ + EVENT_DATA * prev_global; /* prev event in this hash bucket */ + EVENT_DATA * next_local; /* next event for owner */ + EVENT_DATA * prev_local; /* prev event for owner */ + EVENT_FUN * fun; /* the function being called */ + char * argument; /* the text argument given (if any) */ + sh_int passes; /* how long before this event executes */ + sh_int type; /* event type EVENT_XXX_YYY */ + sh_int ownertype; /* type of owner (unlinking req) */ + sh_int bucket; /* which bucket is this event in */ + + union + { /* this is the owner of the event, we */ + D_MOBILE * dMob; /* use a union to make sure any of the */ + D_SOCKET * dSock; /* types can be used for an event. */ + } owner; + }; + + /* functions which can be accessed outside event-handler.c */ + EVENT_DATA *alloc_event ( void ); + EVENT_DATA *event_isset_socket ( D_SOCKET *dSock, int type ); + EVENT_DATA *event_isset_mobile ( D_MOBILE *dMob, int type ); + void dequeue_event ( EVENT_DATA *event ); + void init_event_queue ( int section ); + void init_events_player ( D_MOBILE *dMob ); + void init_events_socket ( D_SOCKET *dSock ); + void heartbeat ( void ); + void add_event_mobile ( EVENT_DATA *event, D_MOBILE *dMob, int delay ); + void add_event_socket ( EVENT_DATA *event, D_SOCKET *dSock, int delay ); + void add_event_game ( EVENT_DATA *event, int delay ); + void strip_event_socket ( D_SOCKET *dSock, int type ); + void strip_event_mobile ( D_MOBILE *dMob, int type ); + + /* all events should be defined here */ + bool event_mobile_save ( EVENT_DATA *event ); + bool event_socket_idle ( EVENT_DATA *event ); + bool event_game_tick ( EVENT_DATA *event ); diff -r -N -c socketmud/src/mud.h socketmud-event/src/mud.h *** socketmud/src/mud.h Sat Mar 22 14:59:16 2003 --- socketmud-event/src/mud.h Wed Apr 2 10:06:26 2003 *************** *** 107,118 **** --- 107,121 ---- typedef struct dMobile D_MOBILE; typedef struct help_data HELP_DATA; typedef struct lookup_data LOOKUP_DATA; + typedef struct event_data EVENT_DATA; /* the actual structures */ struct dSocket { D_SOCKET * next; D_MOBILE * player; + EVENT_DATA * event_first; + EVENT_DATA * event_last; char * hostname; char inbuf[MAX_BUFFER]; char outbuf[MAX_OUTPUT]; *************** *** 131,136 **** --- 134,141 ---- { D_MOBILE * next; D_SOCKET * socket; + EVENT_DATA * event_first; + EVENT_DATA * event_last; char * name; char * password; sh_int level; *************** *** 164,169 **** --- 169,177 ---- int size; /* The allocated size of data */ } BUFFER; + /* here we include external structure headers */ + #include "event.h" + /****************************** * End of new structures * ******************************/ *************** *** 264,274 **** int bprintf ( BUFFER *buffer, char *fmt, ... ); /* - * update.c - */ - void update_handler ( void ); - - /* * help.c */ bool check_help ( D_M *dMob, char *helpfile ); --- 272,277 ---- diff -r -N -c socketmud/src/socket.c socketmud-event/src/socket.c *** socketmud/src/socket.c Wed Apr 2 10:11:59 2003 --- socketmud-event/src/socket.c Wed Apr 2 10:12:27 2003 *************** *** 54,59 **** --- 54,62 ---- /* note that we are booting up */ log("Program starting."); + /* initialize the event queue - part 1*/ + init_event_queue(1); + if (argv[1] && argv[1][0]) { fCopyOver = TRUE; *************** *** 68,73 **** --- 71,79 ---- /* load all external data */ load_muddata(fCopyOver); + /* initialize the event queue - part 2*/ + init_event_queue(2); + /* main game loop */ game_loop(control); *************** *** 181,188 **** close_socket(dsock, FALSE); } ! /* call the top-level update handler */ ! update_handler(); /* * Here we sleep out the rest of the pulse, thus forcing --- 187,194 ---- close_socket(dsock, FALSE); } ! /* call the event queue */ ! heartbeat(); /* * Here we sleep out the rest of the pulse, thus forcing *************** *** 354,359 **** --- 360,368 ---- text_to_buffer(sock_new, greeting); text_to_buffer(sock_new, "What is your name? "); + /* initialize socket events */ + init_events_socket(sock_new); + /* everything went as it was supposed to */ return TRUE; } *************** *** 386,391 **** --- 395,404 ---- else if (dsock->player) free_mobile(dsock->player); + /* dequeue all events for this socket */ + while (dsock->event_first) + dequeue_event(dsock->event_first); + /* set the closed state */ dsock->state = STATE_CLOSED; } *************** *** 945,950 **** --- 958,969 ---- /* and into the game */ dsock->state = STATE_PLAYING; text_to_buffer(dsock, motd); + + /* initialize events on the player */ + init_events_player(dsock->player); + + /* strip the idle event from this socket */ + strip_event_socket(dsock, EVENT_SOCKET_IDLE); } else { *************** *** 994,999 **** --- 1013,1024 ---- /* and let him enter the game */ dsock->state = STATE_PLAYING; text_to_buffer(dsock, motd); + + /* initialize events on the player */ + init_events_player(dsock->player); + + /* strip the idle event from this socket */ + strip_event_socket(dsock, EVENT_SOCKET_IDLE); } } else *************** *** 1017,1022 **** --- 1042,1049 ---- sock_new->lookup_status = TSTATE_LOOKUP; sock_new->player = NULL; sock_new->top_output = 0; + sock_new->event_first = NULL; + sock_new->event_last = NULL; } /* does the lookup, changes the hostname, and dies */ diff -r -N -c socketmud/src/update.c socketmud-event/src/update.c *** socketmud/src/update.c Sat Mar 22 14:52:30 2003 --- socketmud-event/src/update.c Thu Jan 1 01:00:00 1970 *************** *** 1,25 **** - /* - * This file contains all the update functions. - */ - #include - #include - - /* include main header file */ - #include "mud.h" - - /* - * Update_handler() - * - * This is the toplevel update function, - * which is called once every second. - */ - void update_handler() - { - D_SOCKET *dsock; - - for (dsock = dsock_list; dsock; dsock = dsock->next) - { - /* do nothing */ - } - return; - } --- 0 ---- diff -r -N -c socketmud/src/utils.c socketmud-event/src/utils.c *** socketmud/src/utils.c Mon Mar 24 21:58:42 2003 --- socketmud-event/src/utils.c Wed Apr 2 10:06:26 2003 *************** *** 38,43 **** --- 38,45 ---- dMob->name = NULL; dMob->password = NULL; dMob->level = LEVEL_PLAYER; + dMob->event_first = NULL; + dMob->event_last = NULL; } void free_mobile(D_MOBILE *dMob) *************** *** 75,80 **** --- 77,86 ---- free(dMob->name); free(dMob->password); + /* dequeue all events for this mobile */ + while (dMob->event_first) + dequeue_event(dMob->event_first); + /* put it back in the free list */ dMob->next = dmobile_free; dmobile_free = dMob; *************** *** 185,190 **** --- 191,199 ---- /* attach to mobile list */ dMob->next = dmobile_list; dmobile_list = dMob; + + /* initialize events on the player */ + init_events_player(dMob); } else /* ah bugger */ {