[CODE] While loops AND switch in DG scripts

From: Chris Jacobson (fear@ATHENET.NET)
Date: 01/20/98


Heres a REVISED "patch-by-hand" for DG scripts.  Tested and all, works
wonders!  Your filenames will most likely differ.  Plus I use some
patches you might not, like George's buffer patch.

Another note is that GET_TRIG_DEPTH is NO LONGER updated here, it is
useless IMHO, and using BREAK would (excuse the unintended pun) break it
anyways, because if used from nested loops, since it searches for "done"
rather than "end", it doesn't search for "end"s inbetween.

NOTE: this changes the overall design of my original WHILE patch to end
with DONE and not END, so unpatch your previous version (if you have one)
before patching this one.  This allows for CORRECTLY breaking from
WHILE/SWITCH from within nested IFs, the way C works.  I.e, you can do:

while (%x% < 5)
  eval x (%x% + 1)
  if (%x% == 2)
    if (yet something else again)
      break
    end
  end
done


The way these changes work in scripts:

wait <statement>
...
done

switch <statement>
  case <instance>
    ...
    break
  case <instance>
  case <instance>
    ...
    break
  default
    ...
done

"break" can be used to drop out the current "while" or "switch", or end
the script if it isn't in a while/switch.

With while loops, if more than 30 loops occur, it will automatically
cause a WAIT for 1 second.  If more than 100 loops occur since the script
has started executing /from the beginning/ (if it WAITs it will still
remember how many loops), it will mudlog-warn the MUD.

- Chris Jacobson

PS. No credit needed, just dont go telling your builders you wrote this
yerself :-P

-------------------------

*-> in scripts.h:
* add the macro:
#define GET_TRIG_LOOPS(t)               ((t)->loops)

* in trig_data, add:
        int             loops;

* in cmdlist_element, add:
        struct cmdlist_element *original;

*-> scriptengine.c
* add
/*
 * scans for a case/default instance
 * returns the line containg the correct case instance, or the last
 * line of the trigger if not found.
 */
struct cmdlist_element *find_case(TrigData *trig, struct cmdlist_element
*cl,
                void *go, ScriptData *sc, int type, char *cond) {
        struct cmdlist_element *c;
        char *p, *buf;

        if (!(cl->next))                return cl;

        for (c = cl->next; c->next; c = c->next) {
                for (p = c->cmd; *p && isspace(*p); p++);

                if (!strn_cmp("while ", p, 6) || !strn_cmp("switch", p, 6))
                        c = find_done(c);
                else if (!strn_cmp("case ", p, 5)) {
                        buf = get_buffer(MAX_STRING_LENGTH);
                        sprintf(buf, "(%s) == (%s)", cond, p + 5);
                        if (process_if(buf, go, sc, trig, type)) {
                                release_buffer(buf);
                                return c;
                        }
                        release_buffer(buf);
                } else if (!strn_cmp("default", p, 7))  return c;
                else if (!strn_cmp("done", p, 3))               return c;
        }
        return c;
}


/*
 * scans for end of while/switch-blocks.
 * returns the line containg 'end', or the last
 * line of the trigger if not found.
 */
struct cmdlist_element *find_done(struct cmdlist_element *cl) {
        struct cmdlist_element *c;
        char *p;

        if (!(cl->next))        return cl;

        for (c = cl->next; c->next; c = c->next) {
                for (p = c->cmd; *p && isspace(*p); p++);

                if (!strn_cmp("while ", p, 6) || !strn_cmp("switch ", p, 7))
                        c = find_done(c);
                else if (!strn_cmp("done", p, 3))       return c;
        }
        return c;
}


*> script_driver:
* in the beginning, add these variables:
        struct cmdlist_element *temp;
        UInt32  loops = 0;

* replace:
        if (mode == TRIG_NEW)
                GET_TRIG_DEPTH(trig) = 1;
* with:
        if (mode == TRIG_NEW) {
                GET_TRIG_LOOPS(trig) = 0;
                GET_TRIG_DEPTH(trig) = 1;
        }

* replace "} else if (!strn_cmp("end", p, 3)) { ... }" with:
                } else if (!strn_cmp("while ", p, 6)) {
                        temp = find_done(cl);
                        if (process_if(p + 6, go, sc, trig, type)) {
                                temp->original = cl;
                        } else {
                                cl = temp;
                                loops = 0;
                        }
                } else if (!strn_cmp("switch ", p, 7)) {
                        cl = find_case(trig, cl, go, sc, type, p + 7);
                } else if (!strn_cmp("end", p, 3)) {
                        GET_TRIG_DEPTH(trig)--;
                } else if (!strn_cmp("done", p, 4)) {
                        if (cl->original && process_if(cl->original->cmd + 6, go, sc, trig,
type)) {
                                cl = cl->original;
                                loops++;
                                GET_TRIG_LOOPS(trig)++;
                                if (loops == 30) {
                                        process_wait(go, trig, type, "wait 1", cl);
                                        depth--;
                                        release_buffer(cmd);
                                        return ret_val;
                                }
                                if (GET_TRIG_LOOPS(trig) == 100) {
                                        mudlogf(NRM, LVL_BUILDER, TRUE, "SCRIPTERR: Trigger VNum %d has
looped 100 times!!!", GET_TRIG_VNUM(trig));
                                }
                        }
                } else if (!strn_cmp("break", p, 5)) {
                        cl = find_done(cl);
                } else if (!strn_cmp("case", p, 4)) {
                        ;       // Do nothing, this allows multiple cases to a single instance
  }


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     | http://democracy.queensu.ca/~fletcher/Circle/list-faq.html |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/15/00 PST