////////////////////////////////////////////////////////////////////////
// Waypoint Pathing System
// By Deva Bryson Winblood   12/01/2003
////////////////////////////////////////////////////////////////////////
// Pathing works exclusively between lairs with exception of option 4

void fnBuildTransRand(object oArea)
{ // build a list of transitions from this area
  int nC=0;
  int nL=1;
  object oFirst=GetFirstObjectInArea(oArea);
  object oTrans;
  oFirst=GetNearestObject(OBJECT_TYPE_WAYPOINT,oFirst,1);
  //SendMessageToPC(GetFirstPC(),"fnBuildTransRand()");
  if (oFirst!=OBJECT_INVALID)
  {
     oTrans=GetNearestObject(OBJECT_TYPE_TRIGGER,oFirst,nL);
     while(oTrans!=OBJECT_INVALID)
     { // triggers
       if(GetTransitionTarget(oTrans)!=OBJECT_INVALID)
       { // transition
         nC++;
         SetLocalObject(oArea,"oPathingTrans"+IntToString(nC),oTrans);
       } // transition
       nL++;
       oTrans=GetNearestObject(OBJECT_TYPE_TRIGGER,oFirst,nL);
     } // triggers
     nL=1;
     oTrans=GetNearestObject(OBJECT_TYPE_DOOR,oFirst,nL);
     while(oTrans!=OBJECT_INVALID)
     { // doors
       if(GetTransitionTarget(oTrans)!=OBJECT_INVALID)
       { // transition
         nC++;
         SetLocalObject(oArea,"oPathingTrans"+IntToString(nC),oTrans);
       } // transition
       nL++;
       oTrans=GetNearestObject(OBJECT_TYPE_DOOR,oFirst,nL);
     } // doors
     SetLocalInt(oArea,"nPathingTC",nC);
  }
  else
  {
    AssignCommand(OBJECT_SELF,SpeakString("This area is impossible to escape!!!"));
    SendMessageToPC(GetFirstPC(),"RTS SETUP ERROR: Area "+GetName(oArea)+" has no transitions!");
  }
} // fnBuildTransRand()

void fnBuildObjectRand(object oArea)
{ // build a list of objects
  int nC=0;
  int nL=1;
  object oFirst=GetFirstObjectInArea(oArea);
  object oTrans;
  //SendMessageToPC(GetFirstPC(),"fnBuildObjectRand()");
  oFirst=GetNearestObject(OBJECT_TYPE_WAYPOINT,oFirst,1);
  if (oFirst!=OBJECT_INVALID)
  {
     oTrans=GetNearestObject(OBJECT_TYPE_PLACEABLE,oFirst,nL);
     while(oTrans!=OBJECT_INVALID)
     { // placeables
       nC++;
       SetLocalObject(oArea,"oPathingObs"+IntToString(nC),oTrans);
       nL++;
       oTrans=GetNearestObject(OBJECT_TYPE_PLACEABLE,oFirst,nL);
     } // placeables
     nL=1;
     oTrans=GetNearestObject(OBJECT_TYPE_WAYPOINT,oFirst,nL);
     while(oTrans!=OBJECT_INVALID)
     { // waypoints
       nC++;
       SetLocalObject(oArea,"oPathingObs"+IntToString(nC),oTrans);
       nL++;
       oTrans=GetNearestObject(OBJECT_TYPE_WAYPOINT,oFirst,nL);
     } // waypoints
     nC++;
     SetLocalObject(oArea,"oPathingObs"+IntToString(nC),oFirst);
     SetLocalInt(oArea,"nPathingOC",nC);
  }
} // fnBuildObjectRand()

int fnPathValue(object oArea,string sID)
{ // returns path value for area based on team
  int nRet=1000;  // 1000 = avoid it!
  object oFirst=GetFirstObjectInArea(oArea);
  object oWP=GetNearestObjectByTag("PATHINGA",oFirst,1);
  string sName;
  int nPos;
  string sL;
  if (oWP==OBJECT_INVALID) oWP=GetNearestObjectByTag("PATHINGB",oFirst,1);
  if (oWP==OBJECT_INVALID)
  { // check to see if the first object was the waypoint
    if(GetTag(oFirst)=="PATHINGA"||GetTag(oFirst)=="PATHINGB") oWP=oFirst;
  } // check to see if the first object was the waypoint
  if (oWP!=OBJECT_INVALID)
  { //!OI
    sName=GetName(oWP);
    if (sName!="AVOID")
    { // !AVOID
      if (sID=="UND") nPos=0;
      else if (sID=="UNC") nPos=1;
      else if (sID=="SPID") nPos=2;
      else if (sID=="DWF") nPos=3;
      sL=GetSubString(sName,nPos,1);
      if (sL=="A") nRet=10;
      else if (sL=="B") nRet=11;
      else if (sL=="C") nRet=12;
      else
      {
        nRet=StringToInt(sL);
      }
    } // !AVOID
  } //!OI
  return nRet;
} // fnPathValue()


object fnGetTransition(object oArea,int nNum)
{ // returns the specified transition object
  object oTrans=OBJECT_INVALID;
  oTrans=GetLocalObject(oArea,"oPathingTrans"+IntToString(nNum));
  return oTrans;
} // fnGetTransition()

int fnIsAboveGroundDestination(object oTrans)
{ // does this transition lead to an above ground location
  int nRet=FALSE;
  object oDest=GetTransitionTarget(oTrans);
  object oFirst=GetFirstObjectInArea(GetArea(oTrans));
  if (GetTag(oFirst)=="PATHINGA") nRet=TRUE;
  else
  { // test
    oDest=GetNearestObjectByTag("PATHINGA",oFirst,1);
    if (oDest!=OBJECT_INVALID) nRet=TRUE;
  } // test
  return nRet;
} // fnIsAboveGroundDestination()

object fnPathNextDestination(object oCurrentArea,string sDestID,int nOpt=0)
{ /*  Find an object in next destination and return it
      OPTIONS: 0 = Path choosing preferably the same area type as current
               1 = Path choosing preferably underground ways
               2 = Path choosing preferably aboveground ways
               3 = Path choosing below ground during day, above ground at night
               4 = Below ground a MUST! Also seek below ground shelter
      NOTE: the above ground areas are generally less cluttered and thus offer
      faster travel.  So, option 3 is best for creatures with low light sensitivity.
      Option 4 is suggested for light fatal creatures DURING THE day
      */
  object oRet=OBJECT_INVALID;
  int nCurrentPos=fnPathValue(oCurrentArea,sDestID);
  object oBest=OBJECT_INVALID;
  int nBest=100;
  object oNonPref=OBJECT_INVALID;
  int nNonPref=101;
  int nL;
  int nCur;
  object oTrans;
  object oDest;
  int nC=GetLocalInt(oCurrentArea,"nPathingTC");
  if (nC==0)
  { // need to build pathing info
    fnBuildTransRand(oCurrentArea);
    nC=GetLocalInt(oCurrentArea,"nPathingTC");
  } // need to builg pathing info
  nL=1;
  while(nL<=nC)
  { // test transitions
    oTrans=fnGetTransition(oCurrentArea,nL);
    oDest=GetTransitionTarget(oTrans);
    nCur=fnPathValue(GetArea(oDest),sDestID);
    if (nCur<nBest||(nCur==nBest&&d4()<3))
    { // might be a good destination
      if (nOpt==0)
      { // whatever works
        nBest=nCur;
        oBest=oDest;
      } // whatever works
      else if (nOpt==1)
      { // prefer underground
        if (fnIsAboveGroundDestination(oTrans)==TRUE)
        { // above ground
          if (nCur<=nNonPref)
          { // set nonpref
            nNonPref=nCur;
            oNonPref=oDest;
          } // set nonpref
        } // above ground
        else
        { // below ground
          nBest=nCur;
          oBest=oDest;
        } // below ground
      } // prefer underground
      else if (nOpt==2)
      { // prefer aboveground
        if (fnIsAboveGroundDestination(oTrans)==TRUE)
        { // above ground
          nBest=nCur;
          oBest=oDest;
        } // above ground
        else
        { // below ground
          if (nCur<nNonPref||(nCur==nNonPref&&d4()<3))
          { // set nonpref
            nNonPref=nCur;
            oNonPref=oDest;
          } // set nonpref
        } // below ground
      } // prefer aboveground
      else if (nOpt==3)
      { // day/night preference
        if (GetIsDay()==TRUE||GetIsDawn()==TRUE)
        { // day time
          if (fnIsAboveGroundDestination(oTrans)==TRUE)
          { // above ground
            if (nCur<nNonPref||(nCur==nNonPref&&d4()<3))
            { // set nonpref
              nNonPref=nCur;
              oNonPref=oDest;
            } // set nonpref
          } // above ground
          else
          { // below ground
            nBest=nCur;
            oBest=oDest;
          } // below ground
        } // day time
        else
        { // night time
          if (fnIsAboveGroundDestination(oTrans)==TRUE)
          { // above ground
            nBest=nCur;
            oBest=oDest;
          } // above ground
          else
          { // below ground
            if (nCur<nNonPref||(nCur==nNonPref&&d4()<3))
            { // set nonpref
              nNonPref=nCur;
              oNonPref=oDest;
            } // set nonpref
          } // below ground
        } // night time
      } // day/night preference
      else if (nOpt==4)
      { // if day MUST use below ground
        if (GetIsDay()==TRUE||GetIsDawn()==TRUE)
        {
          if (fnIsAboveGroundDestination(oTrans)==FALSE)
          { // good destination
            oBest=oDest;
            nBest=nCur;
          } // good destination
        }
        else
        { // any will do
          oBest=oDest;
          nBest=nCur;
        } // any will do
      } // if day MUST use below ground
    } // might be a good destination
    nL++;
  } // test transitions
  if (nNonPref<nBest)
  { // use non-prefered
    oDest=oNonPref;
  } // use non-prefered
  else
  { // use the best
    oDest=oBest;
  } // use the best
  if (oDest!=OBJECT_INVALID)
  { // choose nearby dest
    oTrans=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,d4());
    if (oTrans==OBJECT_INVALID) oTrans=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,1);
    if (oTrans==OBJECT_INVALID) oTrans=GetNearestObject(OBJECT_TYPE_PLACEABLE,oDest,1);
    oRet=oTrans;
  } // choose nearby dest
  return oRet;
} // fnPathNextDestination()