/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: script.cc,v 1.14.2.6 2000/03/24 01:53:50 justin Exp $
// $Revision: 1.14.2.6 $  $Author: justin $ $Date: 2000/03/24 01:53:50 $

//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//

///**********************  script.cc  ******************************///
// This file contains methods pertaining to mob scripting.  This is where
// new conditional statements, and other modifications should go.
//

#include "commands.h"
#include "command2.h"
#include "command3.h"
#include "command4.h"
#include "command5.h"
#include "misc.h"
#include "misc2.h"
#include <stdio.h>
#include "classes.h"
#include "battle.h"
#include "spec_prc.h"
#include "spells.h"
#include "skills.h"
#include <fstream.h>
#include "batl_prc.h"
#include <PtrArray.h>
#include <unistd.h>
#include "load_wld.h"
#include <KVPair.h>


// initialize static variable.
int ScriptCmd::_cnt = 0;


/**  This will not kill, but can set HP to 1 in worst case. */
int affect_crit_stat(StatTypeE ste, String& up_down, int i_th,
                     String* victim, int dice_cnt, int dice_sides,
                     room* rm, critter* caller = NULL) {

   critter* crit_ptr;
   String buf(100);

   if (caller && 
       (caller->isCharmed() || 
        (caller->isPc() && (caller->getImmLevel() < 7)))) {
      caller->show("Huh??\n");
      return -1;
   }

   crit_ptr = rm->haveCritNamed(i_th, victim, ~0);

   if (!crit_ptr) {
      return -1;
   }//if

   if (crit_ptr->isMob()) {
      crit_ptr = mob_to_smob(*crit_ptr,  rm->getIdNum(), TRUE, i_th,
                             victim, ~0);
   }//if

   switch (ste) 
      {
      case STAT_HP: {
         if (strcasecmp(up_down, "up") == 0) {
            crit_ptr->setHP(crit_ptr->getHP() + d(dice_cnt, dice_sides));
         }
         else {
            crit_ptr->setHP(max(crit_ptr->getHP() - d(dice_cnt, dice_sides), 1));
         }
         return crit_ptr->getHP();
      }
      case STAT_MANA: {
         if (strcasecmp(up_down, "up") == 0) {
            crit_ptr->setMana(crit_ptr->getMana() + d(dice_cnt, dice_sides));
         }
         else {
            crit_ptr->setMana(max(crit_ptr->getMana() - d(dice_cnt, dice_sides), 1));
         }
         return crit_ptr->getMana();
      }
      case STAT_MOV: {
         if (strcasecmp(up_down, "up") == 0) {
            crit_ptr->setMov(crit_ptr->getMov() + d(dice_cnt, dice_sides));
         }
         else {
            crit_ptr->setMov(max(crit_ptr->getMov() - d(dice_cnt, dice_sides), 1));
         }
         return crit_ptr->getMov();
      }
      default:
        return -1;
      }//switch
}//affect_crit_stat

/** Exact some damage. */
int exact_damage(int dice_cnt, int dice_sides, String& msg, critter& pc) {
   
   if (pc.isMob()) {
      mudlog << "ERROR:  MOB sent to exact_damage, should be pc or SMOB.\n";
      return -1;
   }

   dice_cnt = bound(0, 20, dice_cnt);
   dice_sides = bound(0, 100, dice_sides);

   pc.emote(msg);

   exact_raw_damage(d(dice_cnt, dice_sides), NORMAL, pc);

   if (pc.HP < 0) { //was a fatality
      agg_kills_vict(&pc, pc);
   }

   return 0;
}//exact_damage

/** Used to provide branching in scripts..  The lengths of the
 * cooked* arrays passed in are directly related to the cooked*
 * arrays found in parse.cc. 
 */
int script_jump_true(String* cooked_strs, int* cooked_ints,
                     critter& script_targ, critter* c_script_owner,
                     room* r_script_owner, int sanity) {
   return script_jump(TRUE, cooked_strs, cooked_ints, script_targ,
                      c_script_owner, r_script_owner, sanity);
}//script_jump_true

int script_jump_false(String* cooked_strs, int* cooked_ints,
                      critter& script_targ, critter* c_script_owner,
                      room* r_script_owner, int sanity) {
   return script_jump(FALSE, cooked_strs, cooked_ints, script_targ,
                      c_script_owner, r_script_owner, sanity);
}


/**  Does a great many comparisons.   Supported fields are:
 *  HP, MANA, MOV, ALIGN
 */
int is_equal_to(int i_th, const String& rhs_critter,
                const String& field, critter& pc) {
   return do_mob_comparison(i_th, rhs_critter, field, pc, CT_EQUALS);
}//is_equal_to
         

/**  Does a great many comparisons.  Supported fields are:
 *  HP, MANA, MOV, ALIGN
 */
int is_greater_than(int i_th, const String& rhs_critter,
                    const String& field, critter& pc) {
   return do_mob_comparison(i_th, rhs_critter, field, pc, CT_GT);
}//isGreaterThan

/**  Does a great many comparisons.  Supported fields are:
 *  HP, MANA, MOV, ALIGN
 */
int is_less_than(int i_th, const String& rhs_critter,
                 const String& field, critter& pc) {
   return do_mob_comparison(i_th, rhs_critter, field, pc, CT_LT);
}//isLessThan

int do_mob_comparison(int i_th, const String& rhs_critter,
                      const String& field, critter& pc, ComparisonTypeE ct) {

   if (mudlog.ofLevel(SCRIPT)) {
      mudlog << "do_mob_comparison, i_th: " << i_th << " rhs_critter: "
             << rhs_critter << " field: " << field
             << " ComparisonTypeE: " << (int)ct << endl;
   }

   critter* crit_ptr = ROOM.haveCritNamed(i_th, &rhs_critter, ~0);

   int rhs_val;
   int pc_val;

   if (!crit_ptr) {
      if (mudlog.ofLevel(ERROR)) {
         mudlog << "ERROR:  Couldn't find crit_ptr, i_th: " << i_th
                << " rhs -:" << rhs_critter << ":-\n";
      }
      return 0;
   }
   
   if (pc.isImmort() || (pc.isSmob() && !pc.isCharmed())) {

      rhs_val = crit_ptr->getFieldValue(field);
      pc_val = pc.getFieldValue(field);

      switch (ct)
         {
         case CT_EQUALS:
            return (rhs_val == pc_val);
         case CT_GT:
            return (pc_val > rhs_val);
         case CT_LT:
            return (pc_val < rhs_val);
         }
   }
   return 0;
}

int is_in_posn(String& str, critter& pc) {
   if (isnum(str)) {
      return pc.POS == atoi(str);
   }
   else {
      int posn = bound(0, POS_HIGH_VAL, pc.POS);
      if (strncasecmp(str, PcPositionStrings[posn],
                      strlen(PcPositionStrings[posn])) == 0) {
         return TRUE;
      }//if
      else {
         return FALSE;
      }
   }//else
}//is_in_posn

/* used for random branching in scripts */
int chance(int cnt, int sides, int val) {

   return (val >= d(cnt,sides));

}//chance

/** Used to provide branching in scripts..  The lengths of the
 * cooked* arrays passed in are directly related to the cooked*
 * arrays found in parse.cc. 
 */
int script_jump(int on_test, String* cooked_strs, int* cooked_ints,
                critter& test_targ, critter* c_code_owner,
                room* r_code_owner, int sanity) {
   //Conditional command is second cooked_str
   // offset is the first cooked int.

   if (mudlog.ofLevel(SCRIPT)) {
      mudlog << "script_jump, on_test: " << on_test << " c_owner: "
             << c_code_owner << " r_owner: " << r_code_owner 
             << " sanity: " << sanity << endl;
   }

   int offset = cooked_ints[1];
   String cmd = cooked_strs[1];

   // First make sure we are a mob with a mob script.  May add pc
   // functionality later??
   int test = !on_test;

   if ((c_code_owner && c_code_owner->isInProcNow()) ||
       (r_code_owner && r_code_owner->isInProcNow())) {

      if (mudlog.ofLevel(SCRIPT)) {
         mudlog << "had an owner, and was inProcNow()" << endl;
      }

      if (strcasecmp(cmd, "TRUE") == 0) {
         test = TRUE;
      }
      else if (strcasecmp(cmd, "FALSE") == 0) {
         test = FALSE;
      }
      else {

         //  The + 1 steps past the first command, which was script_jump_***
         test = test_targ.executeCommand(cooked_strs + 1, cooked_ints + 1,
                                         sanity, c_code_owner, r_code_owner,
                                         FALSE,/* do_sub */
                                         FALSE/* was_ordered*/);
         if (mudlog.ofLevel(SCRIPT)) {
            mudlog << "script_jump, test is: " << test << " on test: "
                   << on_test << endl;
         }

         if (test < 0) {
            if (c_code_owner) {
               if (mudlog.ofLevel(WRN)) {
                  mudlog << "WARNING:  Script is funky for test_targ:  "
                         << *(test_targ.getName()) << " code_owner: "
                         << *(c_code_owner->getName()) << " failed conditional: "
                         << cmd << " error: " << test << endl;
               }//if
            }//if
            else if (r_code_owner) {
               if (mudlog.ofLevel(WRN)) {
                  mudlog << "WARNING:  Script is funky for test_targ:  "
                         << *(test_targ.getName()) << " code_owner: "
                         << r_code_owner->getIdNum() << " failed conditional: "
                         << cmd << " error: " << test << endl;
               }
            }//if

            test = FALSE;
         }//if
      }//else

      if ((test && on_test) || (!test && !on_test)) {
         if (c_code_owner)
            c_code_owner->doScriptJump(offset);
         else if (r_code_owner) 
            r_code_owner->doScriptJump(offset);
      }//if

   }//if in proc
   else {
      if (mudlog.ofLevel(WRN)) {
         if (c_code_owner)
            mudlog << "WARNING:  Mob is not scripting in script_jump, code_owner: "
                   << *(c_code_owner->getName()) << endl;
         else if (r_code_owner) 
            mudlog << "WARNING:  Mob is not scripting in script_jump, code_owner: "
                   << r_code_owner->getIdNum() << endl;

      }//if
   }//else
   return 0;
}//script_jump


//used in mob scripts primarily.
 int does_own(critter& pc, int obj1, int obj2, int obj3, int obj4,
             int obj5, int obj6) {

   //figure out if the player owns all the objects in question.
   if (mudlog.ofLevel(SCRIPT)) {
      mudlog << "In does_own, critter:  " << *(pc.getName())
             << " obj1: " << obj1 << " obj2: " << obj2
             << " obj3: " << obj3 << " obj4: " << obj4 << " obj5: "
             << obj5 << " obj6: " << obj6 << endl;
   }//if

   int count1 = 1;
   int count2 = 1;
   int count3 = 1;
   int count4 = 1;
   int count5 = 1;
   int count6 = 1;

   // Get the count for object 1
   if (obj2 == obj1) {
      count1++;
      obj2 = 0;
   }
   if (obj3 == obj1) {
      count1++;
      obj3 = 0;
   }
   if (obj4 == obj1) {
      count1++;
      obj4 = 0;
   }
   if (obj5 == obj1) {
      count1++;
      obj5 = 0;
   }
   if (obj6 == obj1) {
      count1++;
      obj6 = 0;
   }

   // Get the count for object 2
   if (obj3 == obj2) {
      count2++;
      obj3 = 0;
   }
   if (obj4 == obj2) {
      count2++;
      obj4 = 0;
   }
   if (obj5 == obj2) {
      count2++;
      obj5 = 0;
   }
   if (obj6 == obj2) {
      count2++;
      obj6 = 0;
   }
      
   // Get the count for object 3
   if (obj4 == obj3) {
      count3++;
      obj4 = 0;
   }
   if (obj5 == obj3) {
      count3++;
      obj5 = 0;
   }
   if (obj6 == obj3) {
      count3++;
      obj6 = 0;
   }
   // Get the count for object 4
   if (obj5 == obj4) {
      count4++;
      obj5 = 0;
   }
   if (obj6 == obj4) {
      count4++;
      obj6 = 0;
   }
   // Get the count for object 5
   if (obj6 == obj5) {
      count5++;
      obj6 = 0;
   }

   if ((obj1 <= 1) || (pc.haveObjNumbered(count1, obj1))) {
      if ((obj2 <= 1) || (pc.haveObjNumbered(count2, obj2))) {
         if ((obj3 <= 1) || (pc.haveObjNumbered(count3, obj3))) {
            if ((obj4 <= 1) || 
                (pc.haveObjNumbered(count4, obj4))) {
               if ((obj5 <= 1) ||
                   (pc.haveObjNumbered(count5, obj5))) {
                  if ((obj6 <= 1) ||
                      (pc.haveObjNumbered(count6, obj6))) {
                     if (mudlog.ofLevel(SCRIPT)) {
                        mudlog << "Returning TRUE" << endl;
                     }
                     return TRUE;
                  }//if
               }//if
            }//if
         }//if
      }//if
   }//if
   
   if (mudlog.ofLevel(SCRIPT)) {
      mudlog << "Returning FALSE" << endl;
   }

   return FALSE;
}//if_owns


///*********************************************************************///
////*********************** GenScript  ****************************///
///*********************************************************************///

int GenScript::_cnt = 0;

GenScript::GenScript() {
   _cnt++;
   stack_ptr = -1;
   target = -1;
   actor = -1;
   precedence = 0;
   needs_compiling = TRUE;
   next_lbl_num = 0;
}

GenScript::GenScript(String& trig, int targ, int act, String& discriminator,
                     int prec) {
   _cnt++;
   trigger_cmd = trig;
   target = targ;
   actor = act;
   stack_ptr = -1;
   needs_compiling = TRUE;
   next_lbl_num = 0;

   trig_discriminator = discriminator;
   if (trig_discriminator.Strlen() > 0) {
      trig_discriminator.Strip();
      trig_discriminator.Prepend(" ");
      trig_discriminator.Append(" ");
   }

   precedence = prec;
}//Full constructor

GenScript::GenScript(const GenScript& src) {
   _cnt++;
   *this = src;
}

void GenScript::doScriptJump(int abs_offset) {
   if ((abs_offset < compiled_cmds.getCurLen()) &&
       (abs_offset >= 0)) {
      stack_ptr = abs_offset;
   }//if
   else {
      stack_ptr = -1; //all done
      mudlog << "ERROR:  Script jump out of range." << endl;
   }
}//doScriptJump


const ScriptCmd* GenScript::getNextCommand() {
   if (mudlog.ofLevel(SCRIPT)) {
      mudlog << "GenScript::getNextCommand, stack_ptr: " << stack_ptr
             << endl << getRunningScript() << endl;
   }

   if (stack_ptr >= 0) {
      int tmp = stack_ptr;
      stack_ptr++;
      if (mudlog.ofLevel(SCRIPT)) {
         mudlog << "GenScript::getNextCommand, tmp: " << tmp << endl;
         if (running_cmds[tmp])
            mudlog << " returning: " << running_cmds[tmp]->getCommand() << endl;
      }
      return running_cmds[tmp];
   }//if
   else {
      if (mudlog.ofLevel(SCRIPT)) {
         mudlog << "GenScript::getNextCommand, stack_ptr: " << stack_ptr
                << " returning NULL" << endl;
      }
      return NULL;
   }
}//getNextCommand


/**  This txt_ is really a long glob of commands, seperated by
 * semi-colons.
 */
void GenScript::setScript(const String& txt_) {
   mudlog.log(DBG, "In setScript.");

   String txt(txt_);
   String* tmp_str;

   //mudlog.log(DBG, txt);
   //mudlog.log(DBG, "About to clear ptr list.");
   script_cmds.clearAndDestroy();

   //mudlog.log(DBG, "Going into while loop.");
   while ((tmp_str = txt.getUntil(';'))) {
      appendCmd(*tmp_str);
      delete tmp_str;
   }//while

   stack_ptr = -1;
   needs_compiling = TRUE;

   compile(); //Compile into script assembly code

   //mudlog.log(DBG, "Done w/addScript.");
}//addScript


GenScript& GenScript::operator=(const GenScript& src) {

   if (this == &src)
      return *this;

   //mudlog.log("In GenScript::operator=");
   trigger_cmd = src.trigger_cmd;
   trig_discriminator = src.trig_discriminator;
   stack_ptr = src.stack_ptr;
   needs_compiling = src.needs_compiling;

   script_cmds.becomeDeepCopyOf(src.script_cmds);
   compiled_cmds.becomeDeepCopyOf(src.compiled_cmds);
   running_cmds.becomeDeepCopyOf(src.running_cmds);

   target = src.target;
   actor = src.actor;
   precedence = src.precedence;

   return *this;
}//operator=


GenScript::~GenScript() {
   _cnt--;
   clear();
}

// Static Class Data
char* GenScript::triggers[] = {
   "break", "close", "discuss", "donate",
   "drop", "eat", "enter", "examine", "exit", "fill", "flip", "follow",
   "get", "give", "grab", "group",
   "hit", "insert", "junk", "list", "lock", "look", "meditate", "nod",
   "open", "order", "pay", "pick", "prone", "pull", "push", "put", 
   "remove", "rest", "say", "shake", "shoot", "sit", "slap", "sleep", "stand",
   "tell", "throw", "turn", "twist", "ungroup", "unlock", "wake", "wear",
   "wield", "yell", NULL };


// Static function, maybe should really check it in the future!
int GenScript::checkScript(const String& str) {
   return str.Strlen();
}


// Static function
int GenScript::validTrigger(const char* trig) {
   int cmp;
   for (int i = 0; triggers[i]; i++) {
      cmp = strcasecmp(triggers[i], trig);
      if (cmp == 0) {
         return TRUE;
      }
      else if (cmp > 0) { //already past it
         return FALSE;
      }
   }//for

   return FALSE;
}//validTrigger


String GenScript::toStringBrief(int client_format, int mob_num,
                                entity_type entity, int idx) {
   String buf(100);
   if (client_format) {
      String tmp_d;
      if (trig_discriminator.Strlen() == 0)
         tmp_d = "NA";
      else
         tmp_d = trig_discriminator;

      String tmp(100);

      if (entity == ENTITY_CRITTER) {
         Sprintf(buf, "<MOB_SCRIPT %S %i %i %i %i %i>", &trigger_cmd,
                 mob_num, actor, target, precedence, idx);
      }
      else if (entity == ENTITY_ROOM) {
         Sprintf(buf, "<ROOM_SCRIPT %S %i %i %i %i %i>", &trigger_cmd,
                 mob_num, actor, target, precedence, idx);
      }
      else if (entity == ENTITY_OBJECT) {
         Sprintf(buf, "<OBJ_SCRIPT %S %i %i %i %i %i>", &trigger_cmd,
                 mob_num, actor, target, precedence, idx);
      }

      Sprintf(tmp, "<DISCRIM %S>", &tmp_d);
      buf.Append(tmp);

      return buf;
   }
   else {
      Sprintf(buf, "Trigger:  %S  Actor Mob:  %i  Target #:  %i  Precedence: %i\n\tDiscriminator:  %S.\n", 
              &trigger_cmd, actor, target, precedence, &trig_discriminator);
   }
   return buf;
}//toStringBrief


/**  This gives the non-compiled, non-running version.  Think of it
 * as source code!
 */
String GenScript::getScript() {
   String buf(1024);

   for (int i = 0; i<script_cmds.getCurLen(); i++) {
      if (script_cmds.constElementAt(i)) {
         buf.Append(script_cmds.constElementAt(i)->getTarget());
         buf.Append(" ");
         buf.Append(script_cmds.constElementAt(i)->getCommand());
         buf.Append(";;\n");
      }//if
   }//while

   return buf;
}//getScript


/**  This gives the compiled, non-running version.  Think of it
 * as assembly code!
 */
String GenScript::getCompiledScript() {
   String buf(1024);
   String tmp(100);

   String targ(50);
   String cmd(100);
   for (int i = 0; i < compiled_cmds.getCurLen(); i++) {
      if (compiled_cmds.constElementAt(i)) {
         targ = compiled_cmds.constElementAt(i)->getTarget();
         cmd = compiled_cmds.constElementAt(i)->getCommand();
         Sprintf(tmp, "[%i] %S %S\n", i, &targ, &cmd);
         buf.Append(tmp);
      }//if
   }//while

   return buf;
}//getCompiledScript

/**  This gives the compiled, running version.  Think of it
 * as machine code!
 */
String GenScript::getRunningScript() {
   String buf(1024);
   String tmp(100);

   //mudlog << "getRunningScript, cur_len:  " << running_cmds.getCurLen()
   //       << endl;

   String targ(50);
   String cmd(100);

   for (int i = 0; i<running_cmds.getCurLen(); i++) {
      if (running_cmds.constElementAt(i)) {
         targ = running_cmds.constElementAt(i)->getTarget();
         cmd = running_cmds.constElementAt(i)->getCommand();
         Sprintf(tmp, "[%i] %S %S\n", i, &targ, &cmd);
         buf.Append(tmp);
      }//if
   }//while

   return buf;
}//getRunningScript


/**  Should these arguments trigger this command? */
int GenScript::matches(const String& cmd, String& arg1, critter& act,
                       int targ, int obj_actor_num = -1) {

   if (mudlog.ofLevel(DBG)) {
      mudlog << "GenScript::Matches(args....)" << endl;
      mudlog << "Cmd:  " << cmd << "  arg1 -:" << arg1 << ":- act:  "
             <<  *(name_of_crit(act, ~0))
             << "  targ:  " << targ << " obj_actor_num: "
             << obj_actor_num << endl;
      mudlog << "this:  " << toStringBrief(0, 0, ENTITY_ROOM, 0) << endl;
   }

   if (strcasecmp(cmd, trigger_cmd) == 0) {
      mudlog.log("commands are equal...");
      // now check to see if arg1 is found ANYWHERE in the
      // discriminator (if it exists)
      if (trig_discriminator.Strlen() > 0) {
         arg1.Tolower();

         // Do special checks (but not for say, discuss, yell, or tell)
         if (strcasecmp(cmd, "say") && strcasecmp(cmd, "yell")
             && strcasecmp(cmd, "tell") && strcasecmp(cmd, "discuss")) {
            //if we're not communications..
            if (strcasecmp(cmd, "give") == 0) { //if we are give cmd
               int obj_num = atoi(arg1);
               if ((obj_num > 0) && (obj_num < NUMBER_OF_ITEMS)) {
                  if (!strstr(trig_discriminator, arg1)) {
                     if (mudlog.ofLevel(DBG)) {
                        mudlog << "Returning false, give, target not right."
                               << endl;
                     }
                     return FALSE;
                  }//if
               }//if
            }//if
            else if (strcasecmp(cmd, "enter") == 0) {
               if (!strstr(trig_discriminator, arg1)) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, enter, descrim wrong."
                            << endl;
                  }
                  return FALSE;
               }
            }//else
            else if (strcasecmp(cmd, "put") == 0) {
               int obj_num = atoi(arg1); //bag
               if ((obj_num > 1) && (obj_num < NUMBER_OF_ITEMS)) {
                  if (!strstr(trig_discriminator, arg1)) {
                     if (mudlog.ofLevel(DBG)) {
                        mudlog << "Returning false, put, descrim wrong."
                               << endl;
                     }
                     return FALSE;
                  }//if
               }//if
            }
            else if ((strcasecmp(cmd, "pull") == 0) || 
                     (strcasecmp(cmd, "push") == 0)) {
               if (!strstr(trig_discriminator, arg1)) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, put, descrim wrong."
                            << endl;
                  }
                  return FALSE;
               }//if
            }

            // Checks for normal discriminators.
            if (strstr(trig_discriminator, "FEM")) {
               if (!act.isFemale()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not FEMALE" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "MALE")) {
               if (!act.isMale()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not MALE" << endl;
                  }
                  return FALSE;
               }//if
            }//if

            if (strstr(trig_discriminator, "NEUTER")) {
               if (!act.isNeuter()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not MALE" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "BARD")) {
               if (!act.isBard()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not BARD" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "WARRIOR")) {
               if (!act.isWarrior()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not Warrior" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "SAGE")) {
               if (!act.isSage()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not SAGE" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "WIZARD")) {
               if (!act.isWizard()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not wizard" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "THIEF")) {
               if (!act.isThief()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not THIEF" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "ALCHEMIST")) {
               if (!act.isAlchemist()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not ALCHEMIST" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "CLERIC")) {
               if (!act.isCleric()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not CLERIC" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "HUMAN")) {
               if (!act.isHuman()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not Human" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "ANITRE")) {
               if (!act.isAnitre()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not ANITRE" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "DARKLING")) {
               if (!act.isDarkling()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not DARKLING" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "DRAGON")) {
               if (!act.isDragon()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not DRAGON" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "DWARF")) {
               if (!act.isDwarf()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not DWARF" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "OGRUE")) {
               if (!act.isOgrue()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not OGRUE" << endl;
                  }
                  return FALSE;
               }//if
            }//if

            if (strstr(trig_discriminator, "ELF")) {
               if (!act.isElf()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not ELF" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "UNDEAD")) {
               if (!act.isUndead()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not UNDEAD" << endl;
                  }
                  return FALSE;
               }//if
            }//if
            
            if (strstr(trig_discriminator, "ANIMAL")) {
               if (!act.isAnimal()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not ANIMAL" << endl;
                  }
                  return FALSE;
               }//if
            }//if

            if (strstr(trig_discriminator, "MONSTER")) {
               if (!act.isMonster()) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, not MONSTER" << endl;
                  }
                  return FALSE;
               }//if
            }//if
         }//if we're not say, discuss, yell, or tell
         else {
            // Don't just let them guess letters...
            if (trig_discriminator.Strlen() >= 5) {
               if (arg1.Strlen() < 3) {
                  if (mudlog.ofLevel(DBG)) {
                     mudlog << "Returning false, arg1.strlen < 3" << endl;
                  }
                  return FALSE;
               }
            }
            
            // Look for substring (trig_discriminator) in arg1
            //          haystack, needle
            //mudlog << "Discrim -:" << trig_discriminator << ":-  arg1 -:"
            //       << arg1 << ":-" << endl;
            if (!strstr(arg1, trig_discriminator)) {
               String tmp_arg1(arg1.Strlen() + 5);
               tmp_arg1.Append(" ");
               tmp_arg1.Append(arg1);
               tmp_arg1.Append(" ");
               //mudlog << "Discrim -:" << trig_discriminator << ":-  arg1 -:"
               //       << tmp_arg1 << ":-" << endl;
               if (!strstr(tmp_arg1, trig_discriminator)) {
                  //now try turning all punctuation to spaces...
                  for (int i = 0; i<tmp_arg1.Strlen(); i++) {
                     if (ispunct(tmp_arg1.charAt(i))) {
                        tmp_arg1.setCharAt(i, ' ');
                     }//if
                  }//for

                  if (!strstr(tmp_arg1, trig_discriminator)) {
                     if (mudlog.ofLevel(DBG)) {
                        mudlog << "Returning false, discrim, strstr failed."
                               << endl;
                     }
                     return FALSE;
                  }//if
               }//if
            }//if
         }//else
      }//if, check the discriminator

      // Now, other special checks

      //  Should we check targets??
      if (target > 1) {
         if (targ != target) {
            if (mudlog.ofLevel(DBG)) {
               mudlog << "Returning false, target != targ" << endl;
            }
            return FALSE;
         }//if
      }

      if (actor > 1) {
         // Objects can be the 'actor' for object scripts (only)
         if (obj_actor_num > 0) {
            if (obj_actor_num != actor) {
               if (mudlog.ofLevel(DBG)) {
                  mudlog << "Returning false, OBJ_NUM != actor" << endl;
               }
               return FALSE;
            }
         }
         else {
            if (act.MOB_NUM != actor) {
               if (mudlog.ofLevel(DBG)) {
                  mudlog << "Returning false, MOB_NUM != actor" << endl;
               }
               return FALSE;
            }
         }//else
      }//if

      if (mudlog.ofLevel(DBG)) {
         mudlog << "Returning TRUE" << endl;
      }
      return TRUE;
   }//if

   if (mudlog.ofLevel(DBG)) {
      mudlog << "Returning FALSE, commands not equal." << endl;
   }
   return FALSE;
}//matches


// Consider this a weaker == operator (don't compare actuall script)
int GenScript::matches(const GenScript& src) {
   if (strcasecmp(trig_discriminator, src.trig_discriminator) != 0)
      return FALSE;
   if (strcasecmp(trigger_cmd, src.trigger_cmd) != 0)
      return FALSE;
   if (actor != src.actor)
      return FALSE;
   if (target != src.target)
      return FALSE;

   return TRUE;
}//Matches (GenScript)


void GenScript::clean() {
   running_cmds.clearAndDestroy();
   resetStackPtr();
}


void GenScript::clear() {
   trigger_cmd.Clear();
   trig_discriminator.Clear();

   script_cmds.clearAndDestroy();
   compiled_cmds.clearAndDestroy();
   running_cmds.clearAndDestroy();

   target = actor = -1;
   precedence = 0;
   stack_ptr = -1;
   needs_compiling = TRUE;
   next_lbl_num = 0;
}//clear

int MobScript::_cnt = 0;
int MobScript::parseScriptCommand(ScriptCmd& cmd, critter& owner, int& obj_was_deleted) {
   // Look at first command and see if it has non-standard actors.
   obj_was_deleted = FALSE;
   critter* script_actor = NULL;
   object* obj_script_actor = NULL;

   //Sprintf(tmp_buf, "**M@%ul_%i ", (unsigned int)(&act), rm.getIdNum());
   String targ(100);
   targ = cmd.getTarget();
   if (targ.Strlen() && strncmp("**M@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int mob_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (mob_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         script_actor = room_list[rm_num].haveCritter((critter*)(mob_ptr));
      }
   }//if
   else if (targ.Strlen() && strncmp("**O@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int obj_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (obj_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         obj_script_actor = room_list[rm_num].haveObject((object*)(obj_ptr));
      }
   }//if

   if (obj_script_actor) {
      mudlog.log("Had an obj_script_actor.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return obj_script_actor->processInput(targ, room_list[obj_script_actor->getCurRoomNum()],
                                            obj_was_deleted);
   }
   else if (!script_actor) {
      script_actor = &owner;
   }//if

   targ = cmd.getCommand(); //reuse targ, it should contain the command now.
   return script_actor->processInput(targ, FALSE, TRUE, &owner, NULL);
}//parseScriptCommand



/** compile() must be called after all appends have been
 * completed.  It is most definately DOES MODIFY it's argument str.
 */
void GenScript::appendCmd(String& str) {
   str.Strip();

   if (str.Strlen() > 0) {
      String targ(30);
      short a,b;

      if (strncmp("**%", str, 3) == 0) {
         targ = str.Get_Command(a,b); //pop it off the front of the string
      }//if
      else {
         targ = "";
      }
      script_cmds.appendShallowCopy(new ScriptCmd(targ, str));
   }//if

   needs_compiling = TRUE;
}//AppendCmd


/**  Do all the substitution needed...  Be sure to reset the
 * stack_ptr after doing this...  TODO:  Do it here??
 * Also
 */
void GenScript::generateScript(String& cmd, String& arg1, critter& act,
                               int targ, room& rm, critter* script_owner,
                               object* object_owner = NULL) {

   //mudlog << "GenScript::generateScript, compiled_cmds.cur_len: "
   //       << compiled_cmds.getCurLen() << endl;

   if (needs_compiling)
      compile();

   critter* targ_crit = NULL;
   object* targ_obj = NULL;

   if (targ > 0) {
      // first, generate a critter if possible 
      if (check_l_range(targ, 0, NUMBER_OF_MOBS, act, FALSE)) {
         if (mob_list[targ].CRIT_FLAGS.get(18))
            targ_crit = &(mob_list[targ]);
      }

      if (check_l_range(targ, 0, NUMBER_OF_ITEMS, act, FALSE)) {
         if (obj_list[targ].OBJ_FLAGS.get(10))
            targ_obj = &(obj_list[targ]);
      }
   }

   int len;
   ScriptCmd tmp_cmd;
   String cmd_str(50);
   String targ_str(50);
   String buf(500);
   char tmp_buf[100];
   char ch;

   running_cmds.clearAndDestroy(); //null out entire array.

   for (int idx = 0; idx < compiled_cmds.getCurLen(); idx++) {
      
      if (compiled_cmds[idx]) {
         tmp_cmd = *(compiled_cmds[idx]);
      }
      else {
         mudlog << "ERROR:  idx[" << idx 
                << "] Got a null cmd when generating script." << endl;
         continue;
      }

      // First, take care of special case where we are specifying the
      // actor with the first command of:  **%M

      targ_str = tmp_cmd.getTarget();
      

      if (strncmp("**%M", targ_str, 4) == 0) { //actor
         sprintf(tmp_buf, "**M@%8X_%i ", (unsigned int)(&act), rm.getIdNum());
         targ_str = tmp_buf;
      }//if
      else if (strncmp("**%m", targ_str, 4) == 0) { //target
         sprintf(tmp_buf, "**M@%8X_%i ", (unsigned int)(targ_crit),
                 rm.getIdNum());
         targ_str = tmp_buf;
      }//if
      else if (strncmp("**%S", targ_str, 4) == 0) { //script owner, default
         if (object_owner) {
            // For Object Scripts
            sprintf(tmp_buf, "**O@%8X_%i ", (unsigned int)(object_owner),
                    rm.getIdNum());
         }
         else {
            sprintf(tmp_buf, "**M@%8X_%i ", (unsigned int)(script_owner),
                    rm.getIdNum());
         }
         targ_str = tmp_buf;
      }//if
      else if (strncmp("**%o", targ_str, 4) == 0) { //target
         sprintf(tmp_buf, "**O@%8X_%i ", (unsigned int)(targ_obj),
                 rm.getIdNum());
         targ_str = tmp_buf;
      }//if
      else {
         targ_str = "";
      }

      cmd_str = tmp_cmd.getCommand();

      // ok, got a command, now lets do substitutions.
      // buf accumulates the new command string.
      buf.Clear();
      len = cmd_str.Strlen();
      for (int i = 0; i<len; i++) {
         ch = cmd_str[i];
         //mudlog << "i: " << i << " ch: " << ch << endl;

         if (ch == '%') {
            i++;

            if (i >= len)
               break;

            // If here, then check the next char to determine action.
            ch = cmd_str[i];
            //mudlog << "Before switch: i: " << i << " ch: " << ch << endl;
            switch (ch) {
            case '%':
               buf.Append("%");
               break;
            case 'M': //ACTOR
               buf.Append(*(act.getShortName(~0)));
               break;
            case 'm': //target
               if (targ_crit) {
                  buf.Append(*(targ_crit->getShortName(~0)));
               }
               break;
            case 'o': //target
               if (targ_obj) { //this is the short name, btw
                  buf.Append(*(targ_obj->getName(~0)));
               }
               break;
            case 'S': // one running script, if mob
               if (script_owner) {
                  buf.Append(*(script_owner->getName(~0)));
               }//if
               else if (object_owner) {
                  buf.Append(*(object_owner->getName(~0)));
               }
               break;
            default:
               buf.Append("__PARSE ERROR__");
            }//switch
         }//if we found a % sign
         else if (ch == '\n') {
            buf.Append(' ');
         }
         else {
            buf.Append(ch);
         }
      }//for


      // When here, we have a command, ready to be put onto the queue.
      //mudlog << "Setting running_cmds[" << idx << "] " << buf << endl;

      // No need to set and destroy because we cleared earlier.
      running_cmds.set(new ScriptCmd(targ_str, buf), idx);
      //mudlog << "Running_cmds.curlen: " << running_cmds.getCurLen()
      //       << endl;
      //mudlog << getRunningScript() << endl;
   }//for

}//GenerateScript


void GenScript::compile() { //compile into script assembly...
   // The trick will be to turn the normal script into something
   // more easily understood and dealt with by the computer.  For
   // now, we will parse if-then-else statements, and compute labels.

   // First, walk the entire set of commands, translating high level
   // constructs into label jumps.  Later, will translate label jumps
   // into index jumps.

   //mudlog << "In GenScript::compile" << endl;

   compiled_cmds.clearAndDestroy();

   PtrArray<ScriptCmd> first_pass(100); //will hold first pass compile results

   int i = 0;

   //mudlog << "About to parse Block" << endl;

   parseBlockFP(i, script_cmds, first_pass);

   //mudlog << "About to optimize labels." << endl;

   optimizeLabels(first_pass, compiled_cmds);

   if (mudlog.ofLevel(DBG)) {
      //mudlog << "All done compiling, compiled_cmds:" << endl;
      //for (int z = 0; z<compiled_cmds.getCurLen(); z++) {
      //   mudlog << *(compiled_cmds.constElementAt(z)) << endl;
      //}//for
   }//if

   first_pass.clearAndDestroy();
   
   needs_compiling = FALSE;
}//compile


int GenScript::findOffset(List<KVPair<String, int>*>& lst,
                          const String& str) {
   Cell<KVPair<String, int>*> cll(lst);
   KVPair<String, int>* ptr;

   // Key is label, val is the index.

   while ((ptr = cll.next())) {
      if (strcmp(ptr->key, str) == 0) {
         return ptr->val;
      }//if
   }//while
   return -1;
}

void GenScript::optimizeLabels(const PtrArray<ScriptCmd>& incomming,
                               PtrArray<ScriptCmd>& rslts) {
   short eos, tbp; //not really using these...

   //mudlog << "In optimize Labels" << endl;

   List<KVPair<String, int>*> labels;

   rslts.clearAndDestroy();

   //find all labels and compute their offsets.
   String first_cmd;
   String cmd_str(100);
   String new_cmd(200);
   String buf(200);
   
   int offset;

   for (int i = 0; i<incomming.getCurLen(); i++) {
      cmd_str = incomming.constElementAt(i)->getCommand();
      first_cmd = cmd_str.Look_Command();

      if (strcasecmp(first_cmd, "label:") == 0) {
         //mudlog << "Found a label on line: " << i << " -:"
         //       << *(incomming.constElementAt(i)) << endl;

         //we don't care what this responds..it's a label cmd, just want to
         // strip it off of the string.
         cmd_str.Get_Command(eos, tbp);

         cmd_str.Strip();

         // Makes a copy of incomming data, btw.
         labels.append(new KVPair<String, int>(cmd_str, i));
      }//if
   }//for

   // So now, we have all the labels... Now lets translate the script_goto's
   // into script_jumps.

   //mudlog << "Optimize Labels:  translating script_goto's into script_jumps"
   //       << endl;

   String tmp_cmd(50);

   for (int i = 0; i<incomming.getCurLen(); i++) {
      cmd_str = incomming.constElementAt(i)->getCommand();
      first_cmd = cmd_str.Look_Command();
      //mudlog << "Line[" << i << "] " << *(incomming.constElementAt(i))
      //       << endl;
      if (strncasecmp(first_cmd, "script_goto", strlen("script_goto")) == 0) {
         //mudlog << "Found script_goto on line: " << i << endl;
         tmp_cmd = cmd_str.Get_Command(eos, tbp); //grab first one again
         tmp_cmd = cmd_str.Get_Command(eos, tbp); //grab second one (label)
         tmp_cmd.Strip();

         offset = findOffset(labels, tmp_cmd);

         if (offset < 0) {
            mudlog << "ERROR:  got a -1 for findOffset for label -:"
                   << tmp_cmd << ":-" << endl;
         }

         cmd_str.Strip();

         if (strncasecmp(first_cmd, "script_goto_false",
                        strlen("script_goto_false")) == 0) {
            Sprintf(buf, "script_jump_false %i %S", offset, &cmd_str);
         }
         else {
            Sprintf(buf, "script_jump_true %i %S", offset, &cmd_str);
         }

         rslts.appendShallowCopy(new ScriptCmd(incomming.constElementAt(i)->getTarget(), buf));
      }//if
      else {
         rslts.appendShallowCopy(new ScriptCmd(*(incomming.constElementAt(i))));
      }//for
   }//for
}//optimizeLabels


String GenScript::getNextLabel() {
   String retval(30);
   Sprintf(retval, "LaBeL__%i", next_lbl_num);
   next_lbl_num++;
   return retval;
}


void GenScript::parseBlockFP(int& start_idx,
                             const PtrArray<ScriptCmd>& incomming,
                             PtrArray<ScriptCmd>& rslts) {
   short eos, tbp; //not really using these...

   String first_cmd;
   String cmd_str(100);
   String new_cmd(200);
   String tmp2(100);
   int i;

   //mudlog << "In parseBlockFP:  idx:  " << start_idx << endl;

   for (i = start_idx; i<incomming.getCurLen(); i++) {
      cmd_str = incomming.constElementAt(i)->getCommand();
      // lets look at the command, and deal with it.
      first_cmd = cmd_str.Look_Command();

      //mudlog << "Incomming[" << i << "] " << *(incomming.constElementAt(i))
      //       << "  FirstCommand:  " << first_cmd << endl;

      if (strcasecmp(first_cmd, "if") == 0) {
         //mudlog << "Was an 'if'" << endl;

         //insert a label jump in rslts.
         cmd_str.Get_Command(eos, tbp); //strip first "if" cmd off of it

         // Now get next two labels.
         String lbl_false = getNextLabel();
         Sprintf(new_cmd, "script_goto_false %S %S", &lbl_false, &cmd_str);

         rslts.appendShallowCopy(new ScriptCmd(incomming.constElementAt(i)->getTarget(), new_cmd));

         //if it's true, then just fall through...

         // Now, get all stuff up to the else (or end)

         PtrArray<ScriptCmd> internal_block;

         // recurse
         i++;
         parseBlockFP(i, incomming, internal_block);

         // we grab pointers, shallow copy, so there is no need to
         // delete the new data allocated for internal_block
         rslts.appendShallowCopy(internal_block);

         // Now do the second block, the else.
         internal_block.clear(); //don't delete ptrs

         // We want to jump over the 'else' part if we ran the first
         // part, so make a jump to the end of the entire "if".
         String lbl_eo_if = getNextLabel();
         Sprintf(new_cmd, "script_goto_true %S TRUE", &lbl_eo_if);
         rslts.appendShallowCopy(new ScriptCmd(NULL_STRING, new_cmd));

         // Now append the false label from above.
         Sprintf(tmp2, "label: %S", &lbl_false);
         rslts.appendShallowCopy(new ScriptCmd(NULL_STRING, tmp2));

         parseBlockFP(i, incomming, internal_block);
         i--; //parseBlock sets to next one, and for loop increments as well.
         // So, decrement it by one to negate for-loop increment in this case.

         rslts.appendShallowCopy(internal_block);
         internal_block.clear(); //just null out ptrs, don't delete data

         Sprintf(tmp2, "label: %S", &lbl_eo_if);
         rslts.appendShallowCopy(new ScriptCmd(NULL_STRING, tmp2));

         // Now, increment i (automatically, and continue!
      }//if it was an if statement
      else if (strcasecmp(first_cmd, "else") == 0) {
         //then done with a block.
         start_idx = i + 1;
         return;
      }
      else if (strcasecmp(first_cmd, "end") == 0) {
         //then done with a block.
         start_idx = i + 1;
         return;
      }
      else {
         rslts.appendShallowCopy(new ScriptCmd(*(incomming.constElementAt(i))));
      }//else
   }//for
   start_idx = i + 1;
}//parseBlockFP


void GenScript::read(ifstream& da_file) {
   char buf[100];
   clear();
   mudlog.log(DB, "in GenScript::Read()");

   if (!da_file) {
      if (mudlog.ofLevel(ERROR)) {
         mudlog << "ERROR:  da_file FALSE in GenScript read." << endl;
      }
      return;
   }

   da_file >> buf;

   trigger_cmd = buf;

   if (mudlog.ofLevel(DB))
      mudlog << "Trigger: -:" << trigger_cmd << ":-" << endl << flush;

   da_file >> target >> actor >> precedence;


   if (mudlog.ofLevel(DB))
      mudlog << "Target: " << target << " actor: " << actor << " takes_prec: "
             << precedence << endl;

   da_file.getline(buf, 80);

   if (mudlog.ofLevel(DB))
      mudlog << "Rest of line -:" << buf << ":-" << endl;

   trig_discriminator.Getline(da_file, 80);

   if (mudlog.ofLevel(DB))
      mudlog << "Trig_discriminator -:" << trig_discriminator << ":-" << endl;

   if (trig_discriminator.Strlen() > 0) {
      trig_discriminator.Strip();
      trig_discriminator.Prepend(" ");
      trig_discriminator.Append(" ");
   }

   // now, read in the command script
   // It will be one large chuck of text, which will be parsed
   // and put into the queue.
   String sbuf(1024);
   sbuf.Termed_Read(da_file);

   if (mudlog.ofLevel(DB)) {
      mudlog << "Script read:  Termed Read:  -:" << sbuf << ":-\n" << endl;
   }

   String* tmp_str;
   while ((tmp_str = sbuf.getUntil(';'))) {
      if (mudlog.ofLevel(DB)) {
         mudlog << "Script read:  Get Until:  -:" << *tmp_str << ":-" << endl;
      }
      appendCmd(*tmp_str);
      delete tmp_str;
   }

   compile(); //Compile into script assembly code
   
}//Read


void GenScript::write(ofstream& da_file) const {
   da_file << trigger_cmd << " " << target 
           << " " << actor << " " << precedence 
           << "\t Trigger Command, targ, actor \n";
   da_file << trig_discriminator << endl;

   String output(1024);
   for (int i = 0; i<script_cmds.getCurLen(); i++) {
      if (script_cmds.constElementAt(i)) {
         output.Append(script_cmds.constElementAt(i)->getTarget());
         output.Append(" ");
         output.Append(script_cmds.constElementAt(i)->getCommand());
         output.Append(";\n");
      }//if
   }//for

   da_file << output << "\n~\n";
}//Write


int RoomScript::_cnt = 0;
int RoomScript::parseScriptCommand(ScriptCmd& cmd, room& owner, int& obj_was_deleted) {
   obj_was_deleted = FALSE;
   if (mudlog.ofLevel(DBG)) {
      mudlog << "RoomScript::parseScriptCommand, target -:"
             << cmd.getTarget() << ":-  cmd -:"
             << cmd.getCommand() << ":-  owner id: "
             << owner.getIdNum() << endl;
   }

   String command(cmd.getCommand());
   // Look at first command and see if it has non-standard actors.
   critter* script_actor = NULL;
   object* obj_script_actor = NULL;

   // This is how the target is created, btw.
   //Sprintf(tmp_buf, "**M@%ul_%i ", (unsigned int)(&act), rm.getIdNum());

   String targ(50);
   targ = cmd.getTarget();
   if (targ.Strlen() && strncmp("**M@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int mob_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (mob_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         script_actor = room_list[rm_num].haveCritter((critter*)(mob_ptr));
      }
   }//if
   else if (targ.Strlen() && strncmp("**O@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int obj_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (obj_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         obj_script_actor = room_list[rm_num].haveObject((object*)(obj_ptr));
      }
   }//if

   if (obj_script_actor) {
      mudlog.log("Had an obj_script_actor.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return obj_script_actor->processInput(targ, room_list[obj_script_actor->getCurRoomNum()],
                                            obj_was_deleted);
   }
   else if (script_actor) {
      mudlog.log("Had a script_actor.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return script_actor->processInput(targ, FALSE, TRUE, NULL, &owner);
   }
   else {
      mudlog.log("Room was the owner.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return owner.processInput(targ);
   }
}//parseScriptCommand

int ObjectScript::_cnt = 0;
int ObjectScript::parseScriptCommand(ScriptCmd& cmd, object& owner, int& obj_was_deleted) {
   obj_was_deleted = FALSE;
   if (mudlog.ofLevel(DBG)) {
      mudlog << "ObjectScript::parseScriptCommand, target -:"
             << cmd.getTarget() << ":-  cmd -:"
             << cmd.getCommand() << ":-  owner id: "
             << owner.getIdNum() << " obj_cur_room# " << owner.getCurRoomNum()
             << endl;
   }

   String command(cmd.getCommand());
   // Look at first command and see if it has non-standard actors.
   critter* script_actor = NULL;
   object* obj_script_actor = NULL;

   // This is how the target is created, btw.
   //Sprintf(tmp_buf, "**M@%ul_%i ", (unsigned int)(&act), rm.getIdNum());

   String targ(50);
   targ = cmd.getTarget();
   if (targ.Strlen() && strncmp("**M@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int mob_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (mob_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         script_actor = room_list[rm_num].haveCritter((critter*)(mob_ptr));
      }
   }//if
   else if (targ.Strlen() && strncmp("**O@", targ, 4) == 0) {
      //we will assume it's right, make the compiler fix it otherwise.
      char* foo = (char*)((const char*)targ); //do type conversion.
      foo[12] = 0;
      unsigned int obj_ptr = strtoul(foo + 4, NULL, 16);
      foo[12] = '_'; //put it back like it was, for now
      int rm_num = strtol(foo + 13, NULL, 10);

      if (obj_ptr != 0) {
         rm_num = bound(0, NUMBER_OF_ROOMS, rm_num);
         obj_script_actor = room_list[rm_num].haveObject((object*)(obj_ptr));
      }
   }//if

   if (obj_script_actor) {
      mudlog.log("Had an obj_script_actor.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return obj_script_actor->processInput(targ, room_list[obj_script_actor->getCurRoomNum()],
                                            obj_was_deleted);
   }
   else if (script_actor) {
      mudlog.log("Had a script_actor.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return script_actor->processInput(targ, FALSE, TRUE, NULL,
                                        &(room_list[owner.getCurRoomNum()]));
   }
   else {
      mudlog.log("Room was the owner.\n");
      targ = cmd.getCommand(); //reuse targ, it should contain the command now.
      return owner.processInput(targ, room_list[owner.getCurRoomNum()],
                                obj_was_deleted);
   }
}//parseScriptCommand