Re: Events & Casting

From: Mysidia (jmhess@i-55.com)
Date: 01/22/02


> the casting: *** would just be random, a number(whatever, whatever); maybe..
> Anyways the question is, has anyone done anything like this? If so how did
> you go about doing it? Any advice or comments would be greatly appreciated
> on this, its something that I need to do, but just haven't gotten around to
> it. Figured it would be good to ask before doing, maybe I can find a
> shortcut or something to that effect.

You want to make certain user input schedule a procedure to be executed
by the system later under certain conditions circle doesn't have such
a facility presently, so that means a new subsystem probably needs to
be implemented to best accomplish this it seems this could be
generalized usefully as a "timer system" of sorts, these are timed
activities, they could be thought of more generally as events, but
"event" implies things other than delay values would trigger it.

It's more complicated than it seems it should be in some respects..
'ch' and 'victim' pointers are unreliable unless extract_char is
appropriately hooked, for example, yet there's no other way to
refer to a specific target, so the only reliable way to do it
is to use those kind of hooks [ugh] additionally, there's the
matter of reconstructing how the spell was cast (target chars,
objects, areas?, etc).

Here's my thought of what an implementation might resemble for
do_cast, for other entry points to casting spells (ie, for NPCs)
the troubles get larger:
typedef struct { const struct timer_data* timer; void *data; } ec_ctx;
typedef struct { int total_rounds; int spell; struct char_data *v;
                 struct obj_data *o; } CAST_INFO;
typedef struct timer_data {
  void *owner, *data;
  void (* free_data)(void *);
  int (* flush_data)(aTimer*, void *),
      (* handler)(void* owner, ec_ctx info);
  struct tx { struct timer_data **prev, struct timer_data *next; } tl;
  int time_left; } aTimer;

and then a set of procedures like...

static struct { aTimer* list; } timerList;
static aTimer *NewTimer() {aTimer*t = (aTimer*)calloc(sizeof(aTimer),1);
  if(t==0){log(__FILE__":%d: malloc bad.",__LINE__);abort();};
  t->handler = (int (*)(void*, ec_ctx))0;
  t->free_data = (void (*)(void *))0; t->flush_data = 0;
  return t;}
static aTimer *AddTimer(aTimer*x) {x->tl.prev = &(timerList.list);
  if ((x->tl.next = timerList.list) != 0)
      timerList.list.prev = &(x->tl.next);
  timerList.list = x;
}
static aTimer *DelTimer(aTimer*x) {
  if (x->next != 0) x->next->prev = x->prev;
  (*(x->lt.prev)) = x->next;
}
static void FreeTimer(aTimer*x) {
 if (x->free_data) { x->free_data(data); } free(x); }
static void UpdateTimer(aTimer *x, void *asdf) {
   if (x->handler) { ec_ctx c={x,asdf}; x->handler(x->owner, c); }

   if (--x->time_left < 0) {
       DelTimer(x); Freetimer(x);
   }
}
static void FlushTimer(aTimer *x, void*cd) {
        if (x->owner == cd || ((x->flush_data) && (* x->flush_data)(x,cd)))
        {
                DelTimer(x);
                FreeTimer(x);
        }
}
static void for_each_timer(void *y, void (* proc)(aTimer*, void*))
{
        aTimer *x = timerList.list, *x_next;
        while(x) { x_next = x->next; proc(x, y); x = x_next; }
}
static void free_cast(void *d) {
        CAST_INFO* x = (CAST_INFO *)d;
        free(d);
}
static void cast_round(void *owner, ec_ctx x) {
        struct char_data* ch = (struct char_data *)owner;
        CAST_INFO* ci = (CAST_INFO *)(x.timer->data);

        if (x.timer->time_left == 0) {
                // or call_magic, depending // actual cast
                cast_spell(ch, ci->v, ci->o, ci->spell);
        }
        // ch gets message about continuing to cast
        // (ci->total_rounds - x.timer->time_left) being the number
        // of stars to print in cast: **** ...
}
static int vict_died(aTimer* x, void *d) {
        if (d && ( ((CAST_INFO *)x->data)->v == d ||
            ((CAST_INFO *)x->data)->o == d)) {
             if (d != x->owner)
                send_to_char("Aborted\r\n",
                             (struct char_data*)(x->owner));
             return 1;
        }
        return 0;
}
static CAST_INFO* MakeCastData(struct char_data* ch,
                  struct char_data* victim, struct obj_data* obj,
                  int sp, int tot)
{
  CAST_INFO *ci = calloc(sizeof(CAT_INFO),1);

  ci->total_rounds = tot;    ci->spell = sp;      ci->v = victim;
  return ci;
}

/* Update timers, call from heartbeat() at fixed intervals*/
extern void UpdateTimers() { for_each_timer(UpdateTimer, 0); }

/* FlushTimers called from extract_char and extract_obj when anything
   is extracted, also in char_from_room and obj_from_room.. unless
   ofcourse casting should continue if a target gets taken out
   of the area(?) */
extern void FlushTimers(void* objCh) { for_each_timer(FlushTimer, objCh); }

/* Call from do_cast to start the whole mess */
extern void StartCasting(struct char_data* ch, struct char_data* vict,
                         struct obj_data* obj, int spellnum)
{
        aTimer *t = NewTimer();
        AddTimer(t);
        t->time_left = number(XXX, YYY);
        t->handler = cast_round;
        t->free_data = free_cast;
        t->flush_data = vict_died;
        t->data = MakeCastData(ch, vict, obj, spellnum, t->time_left);
}

-Mysid

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   | Newbie List:  http://groups.yahoo.com/group/circle-newbies/   |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 06/25/03 PDT