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


Reply via email to