/* --- This is Kyndig's timed event code. He released it I think about three or four years ago, but it got lost. I happened to have a copy of it, and have tried to put everything back together. Some basic examples of how to use the various handlers are included at the bottom of this file. If you decide to use this code, please give thanks to Kyndig and Kyndig.com for releasing it. If you improve this code, please share your improvements. Without the concept of sharing, likely none of this would be here for you to enjoy. Sincerely, Dalsor, aka Eric --- */ /* --- This is the second release of this code. The first was missing some functionality, such as actually updating the events. oops. Yes, I know this is not in order... I worked from the bottom of a grep up in most places, so if you're feeling a little backwards when adding this, that's why. ;) --- */ /* --- Update.c --- */ void free_event args( (EVENT_DATA *ev) ); EVENT_DATA *events; #define kill_event \ if(!ev_next) { free_event(ev); return; } \ if(ev_last!=NULL) ev_last->next=ev_next; \ else events=ev_next; \ free_event(ev); \ continue; /* * Handle events. */ void event_update(void) { EVENT_DATA *ev = NULL, *ev_next, *ev_last = ev; if(!events) return; for( ev = events; ev; ev = ev_next) { ev_next = ev->next; if(ev->delay-- <= 0) { switch(ev->action) { case ACTION_PRINT: if( ( !ev->args[0]) || (! ev->argv[0] ) ) { kill_event } stc( ev->args[0], ev->argv[0] ); break; case ACTION_FUNCTION: if( !ev->args[0] ) { kill_event } do_function(ev->argv[0], ev->do_fun, ev->args[0]); break; case ACTION_WAIT: if(!ev->argv[0]) { kill_event } WAIT_STATE(ev->to,PULSE_PER_SECOND*ev->argi[0]); break; case ACTION_ACT: if(!ev->args[0] || !ev->argv[0]) { kill_event } act(ev->args[0], ev->argv[0], ev->argv[1],ev->argv[2],ev->argi[0]); break; } if(!ev_next) { if( (ev != events) && (ev_last != NULL) ) { if( ev_last->next == ev ) ev_last->next=NULL; } else { if( ev == events) events = NULL; } free_event( ev ); return; } if( ev_last != NULL) ev_last->next = ev_next; else events = ev_next; free_event( ev ); continue; } /* end delay */ ev_last = ev; } /* end loop */ return; } /* --- Update.c update_handler --- */ static int pulse_event; if ( --pulse_event <= 0 ) { pulse_event = PULSE_EVENT; event_update(); } /* --- Recycle.c --- */ /* stuff for recycling timed events */ EVENT_DATA *ev_free; EVENT_DATA *new_event(void) { static EVENT_DATA ev_zero; EVENT_DATA *ev; if ( ev_free == NULL ) ev = alloc_perm(sizeof(*ev)); else { ev = ev_free; ev_free = ev_free->next; } *ev = ev_zero; VALIDATE(ev); ev->to = NULL; return ev; } void free_event(EVENT_DATA *ev) { if (!IS_VALID(ev)) return; INVALIDATE(ev); ev->next = ev_free; ev_free = ev; } /* --- Recycle.h --- */ /* timed event recycling */ #define ED EVENT_DATA ED *new_event args( (void) ); void free_event args( (ED *ev) ); #undef ED /* --- BigHeader.h aww.h, merc.h, mud.h or wherever the primary header is. --- */ typedef struct event_data EVENT_DATA; /* timed events */ /* timed events from kyndig.com */ struct event_data { int delay; CHAR_DATA *to; int action; DO_FUN *do_fun; char *args[5]; void *argv[5]; int argi[5]; EVENT_DATA *next; bool valid; }; extern EVENT_DATA *events; /* timer.c */ char * nsprintf args( (char *, char *, ...) ); void wait_wait args( (CHAR_DATA *, int, int) ); void wait_printf args( (CHAR_DATA *, int, char *, ...) ); void wait_act args( (int, char *, void *, void *, void *, int) ); void wait_function args( (CHAR_DATA *ch,int delay, DO_FUN *do_fun, char *argument) ); EVENT_DATA *create_event(int, char *); /* --- Define.h Or primary header, such as mud.h, merc.h, or whatever. --- */ #define PULSE_EVENT ( 2 * PULSE_PER_SECOND) /* timed event action */ #define ACTION_PRINT 1 #define ACTION_FUNCTION 2 #define ACTION_WAIT 3 #define ACTION_ACT 4 /* --- Begin timer.c Add this .o to Makefile Start copying and pasting after the comment line directly below. --- */ /******************************************************************************* * ROM Version 2.4 beta * * Original DikuMUD by Hans Staerfeldt, Katja Nyboe, * * Tom Madsen, Michael Seifert, and Sebastian Hammer * * Based on MERC 2.1 code by Hatchet, Furey, and Kahn * * ROM 2.4 copyright (c) 1993-1996 Russ Taylor * * * * ___ _ _ _ _ ____ ____ ____ _ _ ____ _ _ _ _ _ _ ____ ____ ____ * * | \ | | |\ | | __ |___ | | |\ | |__/ | | |\ | |\ | |___ |__/ [__ * * |__/ |__| | \| |__] |___ |__| | \| | \ |__| | \| | \| |___ | \ ___] * * kyncode version: 3b.99 (not yet released) * *******************************************************************************/ #if defined(macintosh) #include #else #include #include #endif #include #include #include #include #include #include #include #include /* you'll probably want to change this aww.h to mud.h or merc.h or whatever */ #include "aww.h" #include "recycle.h" char *nsprintf(char *fr, char *fmt, ...) { char buf[2*MSL]; va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); free_string(fr); return str_dup(buf); } EVENT_DATA *create_event(int delay, char *act) { EVENT_DATA *ev; if(!str_cmp(act, "print")) { ev=new_event(); ev->action=ACTION_PRINT; } else if(!str_cmp(act, "wait")) { ev=new_event(); ev->action=ACTION_WAIT; } else if(!str_cmp(act, "act")) { ev=new_event(); ev->action=ACTION_ACT; } else if(!str_cmp(act, "function")) { ev=new_event(); ev->action=ACTION_FUNCTION; } else { /* Bad Action */ return NULL; } ev->delay= delay; ev->next = events; events = ev; return ev; } /* send an 'act' sequence to target after delay has been met */ void wait_act(int delay, char *msg, void *a1, void *a2, void *a3, int type) { EVENT_DATA *ev=create_event(delay, "act"); ev->args[0]=str_dup(msg); ev->argv[0]=a1; ev->argv[1]=a2; ev->argv[2]=a3; ev->argi[0]=type; return; } /* send a delayed FORMATED string to target ( Uses printf_ function ) */ void wait_printf(CHAR_DATA *ch, int delay, char * fmt, ...) { char buf[2*MSL]; va_list args; EVENT_DATA *ev = create_event(delay, "print"); va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); ev->args[0] = str_dup(buf); ev->argv[0] = ch; return; } /* after the delay has been met..it will freeze * the targeted victim for the set amount of 'dur'ation * ex: wait_wait(ch,2,5); would: * cause player who triggered this call to be frozen * for 5 seconds after 2 seconds of function call * good for mprogs */ void wait_wait(CHAR_DATA *ch, int delay, int dur) { EVENT_DATA *ev = create_event( delay, "wait"); ev->argv[0] = ch; ev->argi[0] = dur; } /* call the specified function after delay has been met */ void wait_function (CHAR_DATA *ch, int delay, DO_FUN *do_fun, char *argument) { EVENT_DATA *ev = create_event( delay, "function" ); ev->argv[0] = ch; ev->do_fun = do_fun; ev->args[0] = str_dup( argument ); return; } /* --- End timer.c Stop copying and pasting at the comment line two lines up. Following are some examples of using the events code. --- */ /* --- Excerpt from a stitching skill... What this does is delay the character for 15 EVENT pulses. During those 15 pulses it sends messages telling the character et al what's going on. This uses wait_printf and wait_act function. It could also use wait_wait ( see notation in timer.c ). --- */ WAIT_STATE( ch, PULSE_EVENT * 15 ); wait_printf(ch,5,"You begin to stitch %s.\n\r",objBuf); wait_act(5,"$n begins to stitch $t.",ch,objBuf,0,TO_ROOM); wait_act(8,"You lean over $t, taking great care on your work.",ch,objBuf,0,TO_CHAR); wait_act(8,"$n leans over $t, taking great care on $s work.",ch,objBuf,0,TO_ROOM); wait_act(11,"You pull the stitches on $t tight, finishing the work.",ch,objBuf,0,TO_CHAR); wait_act(11,"$n pulls the stitches on $t tight, finishing the work.",ch,objBuf,0,TO_ROOM); wait_act(15,"{c$n admires the finished work on $t.", ch, objBuf, NULL, TO_ROOM ); wait_act(15,"{cYou admire the finished work on $t.", ch, objBuf, NULL, TO_CHAR ); /* --- Excerpt from a spec program... What this does is make the mob go into a room, wait a couple seconds, say something, wait a couple more seconds, leave the room, wait a few more seconds, then walk away. This uses the wait_function and wait_act functions. --- */ do_enter( ch, "door" ); act( "$n, Captain of the Guard, glances casually about the room.", ch, NULL, NULL, TO_ROOM ); if ( ch->in_room->people != NULL ) wait_function( ch, 2, do_say, "Peace be on the people of Caemlyn." ); wait_function( ch, 2, do_enter, "door" ); wait_act( 4, "{g$n barks, {G'{gParade, turn! Face... West!{G'{x", ch, NULL, NULL, TO_ROOM ); wait_act( 4, "The guards following $n turn with a click of their boot heels.", ch, NULL, NULL, TO_ROOM ); wait_act( 4, "{g$n barks, {G'{gMarch!{G'{x", ch, NULL, NULL, TO_ROOM ); wait_function( ch, 4, do_west, "" ); /* --- So that demonstrates very basically the primary functions. By looking over these examples, though, I hope it's evident that this code can be very useful in complex event handling. Expanding the code for other functions is also very simple. Not that wait_wait is not used in either of these examples. --- */