Thanks for the reply Michael.
I have modified how event_update handles events based on your suggestions. Just
for the sake of following up, the corrected event_update:
void event_update(void)
{
EVENT *ev = NULL, *ev_next = NULL, *ev_last = NULL;
for(ev = events; ev; ev = ev->next)
{
if(ev->delay-- <= 0) //Expired, kill it
{
ev->kill_event = TRUE; //Kill it next loop
ev->fire(ev);
ev->destroy(ev);
}
}
for(ev = events; ev; ev = ev_next)
{
ev_next = ev->next;
if (ev->kill_event)
{
if(ev_last) //We're past the first element of the list.
ev_last->next = ev_next;
else //First element.
events = ev_next;
free_event(ev);
}
else //Not ready yet; start from here.
ev_last = ev;
}
}
I just make a second pass through the events and remove as necessary. Any new
events are created in the first for loop, so the event list will be up-to-date
for the second for loop.
Again, thanks for the advice.
-- Jeremy
----- Original Message -----
From: "Michael Barton" <[EMAIL PROTECTED]>
To: <[email protected]>
Sent: Tuesday, February 03, 2004 10:24 PM
Subject: Re: Linked lists--new elements introduced outside loop creates problems
> Yes, I had the problem of events being created as a result of another event's
> execution.
> What I did was, in the main loop, events are flagged for deletion rather than
> actually being removed.
> All incoming events are put into a temporary list.
> After the main processing loop, a second loop removes events to be deleted.
> Then the temporary list is tacked onto the main queue.
>
> --Palrich.
>
> ----- Original Message -----
> From: "Jeremy Hill" <[EMAIL PROTECTED]>
> To: <[email protected]>
> Sent: Tuesday, February 03, 2004 9:09 PM
> Subject: Linked lists--new elements introduced outside loop creates problems
>
>
> > Greetings,
> >
> > I have implemented a 'wait' mobprogram command that delays execution of a
mob
> > program for a certain amount of time, much like the 'mpsleep' snippet that
is
> > out there. I am doing this with the event system I have created for events
such
> > as these. (Pun intended) Here's what an event looks like.
> > struct event
> > {
> > struct event * next;
> > union
> > {
> > ...
> > struct prog_event_args prog;
> > /* etc.... */
> > } event_args;
> >
> > sh_int delay;
> > char *comments;
> > void (*fire)(struct event *);
> > void (*destroy)(struct event *);
> > bool valid;
> > };
> >
> > However, I'm coming across a small problem that I'm not sure how to resolve,
and
> > wondered if you might have an idea in how to straighten this out.
> >
> > An event is created with an XXX_event function; in this instance, in
> > program_flow: prog_event(ch, (void *)mob, MOB, prog, count+1, timer);
> >
> > ...and is placed into the 'events' list until it is ready to fire. It is
fired,
> > which is a function specific to the event's properties, and then it
> > self-destroys, another function. However, when I create a new event within
the
> > previous event's fire function, the linked list gets out of whack. I'll lay
out
> > some code that'll help explain my problem.
> >
> > Like mobile_update and the other update routines, events are updated as
well:
> > void event_update(void)
> > {
> > EVENT *ev = NULL, *ev_next = NULL, *ev_last = NULL;
> >
> > for(ev = events; ev; ev = ev_next)
> > {
> > ev_next = ev->next;
> >
> > if(--ev->delay <= 0) //Expired, kill it
> > {
> > --> ev->fire(ev); <---
> >
> > if(ev_last) //We're past the first element of the list.
> > ev_last->next = ev_next;
> > else //First element.
> > events = ev_next;
> >
> > --> ev->destroy(ev); <---
> > }
> > else //Not ready yet; start from here.
> > ev_last = ev;
> > }
> > }
> >
> > Pretty straightforward stuff, the items between --> <-- are the focus.
> > Now, firing a program that is done waiting with ev->fire(ev) (function
trimmed
> > for brevity):
> >
> > void fire_prog_event(EVENT * ev)
> > {
> > extern void program_flow( sh_int, char *, CHAR_DATA *, OBJ_DATA *,
> > ROOM_INDEX_DATA *,
> > CHAR_DATA *, const void *, const void *,
int );
> >
> > ...
> > if (ev->event_args.prog.mob && ev->event_args.prog.ch &&
> > ev->event_args.prog.mob->in_room ==
> > ev->event_args.prog.ch->in_room)
> > {
> > program_flow(ev->event_args.prog.prog_code->vnum,
> > ev->event_args.prog.prog_code->code,
> > ev->event_args.prog.mob,
> > NULL,
> > NULL,
> > ev->event_args.prog.ch,
> > NULL, NULL, ev->event_args.prog.line);
> > }
> > }
> > }
> >
> > So if the event's program is still valid--i.e. the mob and ch still exist
and
> > are in the same room yet--then it'll continue execution with a call to
> > program_flow. This means if there is another wait in the mobprog code, this
> > call to program_flow will create a new event to wait again. As you can see,
> > this is all done inside the ev->fire(ev), meaning the linked list is now
> > different for the rest of the code in the event_update()'s for loop.
> >
> > What do you think? I'm thinking I may have to put firing events onto their
own
> > linked list so as not to disrupt the list of the ones still hatching.
However,
> > is there a much more elegant solution?
> >
> >
> >
> >
> > --
> > ROM mailing list
> > [email protected]
> > http://www.rom.org/cgi-bin/mailman/listinfo/rom
>
>
> --
> ROM mailing list
> [email protected]
> http://www.rom.org/cgi-bin/mailman/listinfo/rom