// RTS - Harvest of Souls (scout routine)
// By Deva Bryson Winblood
// 11/29/2003
/////////////////////////////////////////
#include "rts_header"
/////////////////
// PROTOTYPES
/////////////////
object fnObjectOfInterest();
object fnMakeMessenger(object oMsg,string sID);
object fnRandomTrans(object oArea);
object fnRandomObjects(object oArea);
int fnNotValid(object oArea);

//////////////////////////////////////////////////////////////// MAIN
void main()
{
   object oMe=OBJECT_SELF;
   object oMod=GetModule();
   string sID=GetLocalString(oMe,"sTeamID");
   object oHome=GetWaypointByTag(sID+"_START");
   int nSState=GetLocalInt(oMe,"nSState");
   object oH;
   object oDest=GetLocalObject(oMe,"oDestWP");
   float fDist;
   object oLArea1=GetLocalObject(oMe,"oLArea1");
   object oLArea2=GetLocalObject(oMe,"oLArea2");
   int nN;
   int nR;
   object oMsg;
   string sMsg;
   object oBird;
   object oArea=GetArea(oMe);
   int nRun=GetLocalInt(oMe,"nRun");
   float fFacing=GetFacing(oMe);
   switch(nSState)
   { // the scout main switch
     case 0: { // look for anything interesting
       //SendMessageToPC(GetFirstPC(),GetName(oMe)+" looking for items of interest.");
       fFacing=fFacing+90.0;
       if (fFacing>=360.0) fFacing=fFacing-360.0;
       SetFacing(fFacing);
       ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,1.0,4.0);
       oH=fnObjectOfInterest();
       if (oH!=OBJECT_INVALID)
       { // item of interest
         nN=GetObjectType(oH);
         SetLocalObject(oMe,"oDestWP",oH);
         if (nN==OBJECT_TYPE_CREATURE) SetLocalInt(oMe,"nSState",3);
         else if (nN==OBJECT_TYPE_PLACEABLE) SetLocalInt(oMe,"nSState",4);
         else if (nN==OBJECT_TYPE_ITEM) SetLocalInt(oMe,"nSState",5);
       } // item of interest
       else
       { // move on
         SetLocalInt(oMe,"nSState",1);
       } // move on
       break;
     } // look for anything interesting
     case 1: { // find next destination
       //SendMessageToPC(GetFirstPC(),GetName(oMe)+" looking for destination.");
       if(oArea==oHome||(d6()<4))
       { // seek next area
         //SendMessageToPC(GetFirstPC(),GetName(oMe)+" area transition.");
         oH=fnRandomTrans(oArea);
         oH=GetTransitionTarget(oH);
         oArea=GetArea(oH);
         nN=0;
         while((oH==OBJECT_INVALID||(oArea==oLArea1||oArea==oLArea2||fnNotValid(oH)==TRUE))&&nN<3)
         { // while find
           oH=fnRandomTrans(GetArea(oMe));
           oH=GetTransitionTarget(oH);
           oArea=GetArea(oH);
           nN++;
         } // while find
         if (oArea==oLArea1||oArea==oLArea2||fnNotValid(oH)==TRUE)
         {
           if (GetLocalInt(GetArea(oMe),"nPathingTC")!=1)
           {  oH=OBJECT_INVALID;  }
         }
         if (oH!=OBJECT_INVALID)
         { // pick destination
           nN=d4();
           if (d4()<4) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           else { oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN); }
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           if (oDest!=OBJECT_INVALID)
           { // success
             SetLocalObject(oMe,"oDestWP",oDest);
             SetLocalInt(oMe,"nSState",2);
             SetLocalObject(oMe,"oLArea2",oLArea1);
             SetLocalObject(oMe,"oLArea1",GetArea(oMe));
           } // success
         } // pick destination
         else
         { // couldn't find a way - let's just move through one anyway
           oArea=GetArea(oMe);
           oH=fnRandomTrans(oArea);
           oH=GetTransitionTarget(oH);
           nN=d4();
           if (d4()<4) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           else { oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN); }
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           nN--;
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oH,nN);
           if (oDest==OBJECT_INVALID) oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oH,nN);
           if (oDest!=OBJECT_INVALID)
           { // success
             SetLocalObject(oMe,"oDestWP",oDest);
             SetLocalInt(oMe,"nSState",2);
             SetLocalObject(oMe,"oLArea2",oLArea1);
             SetLocalObject(oMe,"oLArea1",GetArea(oMe));
           } // success
         } // couldn't find a way - let's just move through one anyway
       } // seek next area
       else
       { // seek random object
         oDest=fnRandomObjects(GetArea(oMe));
         if (oDest!=OBJECT_INVALID)
         { // success
           SetLocalObject(oMe,"oDestWP",oDest);
           SetLocalInt(oMe,"nSState",2);
         } // success
       } // seek random object
       break;
     } // find next destination
     case 2: { // move to destination
       nN=fnMoveToDestination(oDest,nRun);
       //SendMessageToPC(GetFirstPC(),GetName(oMe)+" moving to "+GetTag(oDest)+" in area "+GetName(GetArea(oDest))+".");
       if (nN==1||(GetArea(oDest)==GetArea(oMe)&&GetDistanceBetween(oMe,oDest)<3.1))
       { // should have arrived
         SetLocalInt(oMe,"nSState",0);
       } // should have arrived
       else if (nN==-1)
       { // error
         if(GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>9) AssignCommand(oMe,SpeakString("I can't seem to reach "+GetName(oDest)+" in this area."));
         SetLocalInt(oMe,"nSState",0);
       } // error
       break;
     } // move to destination
     case 3: { // message - merchant or plot creature
       oMsg=CreateItemOnObject("rtsa_message",oMe);
       sMsg="I encountered an interesting individual by the name of "+GetName(oDest)+" in area "+GetName(GetArea(oDest))+".";
       SetLocalObject(oDest,"oLastSeen"+sID,GetArea(oDest));
       SetLocalString(oMsg,"sMsg",sMsg);
       SetLocalObject(oMsg,"oDest",GetWaypointByTag(sID+"_START"));
       oDest=GetLocalObject(oMod,"oTeamLead"+sID);
       SetLocalString(oMsg,"sTo",GetName(oDest));
       SetLocalString(oMsg,"sName",GetName(oMe));
       oBird=fnMakeMessenger(oMsg,sID);
       AssignCommand(oBird,ClearAllActions());
       DelayCommand(5.0,AssignCommand(oBird,ExecuteScript("rtsa_ai_birdmsg",oBird)));
       SetLocalInt(oMe,"nSState",0);
       break;
     } // message - merchant or plot creature
     case 4: { // message - mana pool
       sMsg="I saw a "+GetName(oDest)+" in area ";
       sMsg=sMsg+GetName(GetArea(oDest))+".";
       oMsg=CreateItemOnObject("rtsa_message",oMe);
       SetLocalObject(oDest,"oLastSeen"+sID,GetArea(oDest));
       SetLocalString(oMsg,"sMsg",sMsg);
       SetLocalObject(oMsg,"oDest",GetWaypointByTag(sID+"_START"));
       oDest=GetLocalObject(oMod,"oTeamLead"+sID);
       SetLocalString(oMsg,"sTo",GetName(oDest));
       SetLocalString(oMsg,"sName",GetName(oMe));
       oBird=fnMakeMessenger(oMsg,sID);
       AssignCommand(oBird,ClearAllActions());
       DelayCommand(5.0,AssignCommand(oBird,ExecuteScript("rtsa_ai_birdmsg",oBird)));
       SetLocalInt(oMe,"nSState",0);
       break;
     } // message - mana pool
     case 5: { // message - item of value
      sMsg="I saw what looked to be an interesting item lying on the ground in "+GetName(GetArea(oDest))+".";
      sMsg=" I did not attempt to take it because, I thought I should report it first.";
      oH=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oDest,1);
      if (GetDistanceBetween(oH,oDest)<3.0) sMsg=sMsg+"It appears to be guarded by a "+GetName(oH)+".";
      SetLocalObject(oDest,"oLastSeen"+sID,GetArea(oDest));
      SetLocalString(oMsg,"sMsg",sMsg);
      SetLocalObject(oMsg,"oDest",GetWaypointByTag(sID+"_START"));
      oDest=GetLocalObject(oMod,"oTeamLead"+sID);
      SetLocalString(oMsg,"sTo",GetName(oDest));
      SetLocalString(oMsg,"sName",GetName(oMe));
      oBird=fnMakeMessenger(oMsg,sID);
      AssignCommand(oBird,ClearAllActions());
      DelayCommand(5.0,AssignCommand(oBird,ExecuteScript("rtsa_ai_birdmsg",oBird)));
      SetLocalInt(oMe,"nSState",0);
      break;
    } // message - item of value
   } // the scout main switch
}
//////////////////////////////////////////////////////////////// MAIN

/////////////////////////
// FUNCTIONS
/////////////////////////

//// Randoms
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()


object fnRandomTrans(object oArea)
{ // return a random transition door or trigger
  object oRet=OBJECT_INVALID;
  int nC=GetLocalInt(oArea,"nPathingTC");
  if (nC<1)
  {
    fnBuildTransRand(oArea);
    return OBJECT_INVALID;
  }
  else
  {
    nC=Random(nC)+1;
    oRet=GetLocalObject(oArea,"oPathingTrans"+IntToString(nC));
  }
  return oRet;
} // fnRandomTrans()

object fnRandomObjects(object oArea)
{ // return an object in this area
  object oRet=OBJECT_INVALID;
  int nC=GetLocalInt(oArea,"nPathingOC");
  if (nC<1)
  {
    fnBuildObjectRand(oArea);
    return OBJECT_INVALID;
  }
  else
  {
    nC=Random(nC)+1;
    oRet=GetLocalObject(oArea,"oPathingObs"+IntToString(nC));
  }
  return oRet;
} // fnRandomObjects()


//////////// messenger
object fnMakeMessenger(object oMsg,string sID)
{ // return messenger bird
  object oBird=OBJECT_INVALID;
  string sResRef=sID+"_bird";
  object oSource=GetItemPossessor(oMsg);
  //fnDebug("    [SCOUT]fnMakeMessenger("+GetName(oMsg)+")");
  if (oMsg!=OBJECT_INVALID)
  { // valid message
    oBird=CreateObject(OBJECT_TYPE_CREATURE,sResRef,GetLocation(oSource),FALSE);
    ChangeFaction(oBird,oSource);
    SetLocalString(oBird,"sTeamID",GetLocalString(oSource,"sTeamID"));
    SetLocalObject(oBird,"oDest",GetLocalObject(oMsg,"oDest"));
    SetLocalFloat(oBird,"fDelay",10.0);
    AssignCommand(oSource,ClearAllActions());
    AssignCommand(oSource,ActionGiveItem(oMsg,oBird));
    //fnDebug("          Bird:"+GetName(oBird));
    SetAILevel(oBird,AI_LEVEL_NORMAL);
    SetDroppableFlag(oMsg,TRUE);
  } // valid message
  return oBird;
} // fnMakeMessenger()


/////////// find
float fnGetVisionRange(object oMe)
{ // return distance can notice
  float fRet=25.0;
  return fRet;
} // fnGetVisionRange()


object fnObjectOfInterest()
{ // return objects of interest
  object oRet=OBJECT_INVALID;
  object oMe=OBJECT_SELF;
  string sID=GetLocalString(oMe,"sTeamID");
  object oH;
  int nC;
  int nType;
  string sT;
  float fRange=fnGetVisionRange(oMe);
  object oMerch=GetObjectByTag("Wizard");
  if (GetNearestObjectByTag(sID+"_START")!=OBJECT_INVALID) return OBJECT_INVALID; // in your own lair
  if (oMerch==OBJECT_INVALID)
      oMerch=GetObjectByTag("Rotund");
  if (oMerch==OBJECT_INVALID)
      oMerch=GetObjectByTag("Fence");
  if (oMerch==OBJECT_INVALID)
      oMerch=GetObjectByTag("Smith");
  if (oMerch==OBJECT_INVALID)
      oMerch=GetObjectByTag("Apothecary");
  nC=1;
  oH=GetNearestObject(OBJECT_TYPE_ALL,oMe,nC);
  while(oH!=OBJECT_INVALID&&GetDistanceBetween(oH,oMe)<=fRange)
  { // poll nearby items
    if(GetLocalInt(oH,"nScouted"+sID)!=TRUE)
    { // possible target
      SetLocalInt(oH,"nScouted"+sID,TRUE);
      nType=GetObjectType(oH);
      sT=GetTag(oH);
      if (nType==OBJECT_TYPE_CREATURE&&(GetPlotFlag(oH)==TRUE||GetFactionEqual(oMerch,oH)==TRUE))
        return oH;
      if (nType==OBJECT_TYPE_PLACEABLE&&(sT=="MinorManaPool"||sT=="ManaPool"||sT=="StrongManaPool"))
        return oH;
      if (nType==OBJECT_TYPE_ITEM&&(GetPlotFlag(oH)==TRUE||GetGoldPieceValue(oH)>2000||sT==""))
        return oH;
    } // possible target
    // next item
    nC++;
    oH=GetNearestObject(OBJECT_TYPE_ALL,oMe,nC);
  } // poll nearby items
  return oRet;
} // fnObjectOfInterest()

int fnNotValid(object oArea)
{ // if not a valid area return TRUE
  object oFirst=GetFirstObjectInArea(oArea);
  object oPath=GetNearestObjectByTag("PATHINGA",oFirst,1);
  if (oPath==OBJECT_INVALID) oPath=GetNearestObjectByTag("PATHINGB",oFirst,1);
  if (oPath==OBJECT_INVALID)
  { //
    if (GetTag(oFirst)=="PATHINGA"||GetTag(oFirst)=="PATHINGB") oPath=oFirst;
  } //
  if (oPath==OBJECT_INVALID) return TRUE;
  if (GetName(oPath)=="AVOID") return TRUE;
  return FALSE;
} // fnNotValid()