// ai_harvester - Challenging AI harvesting unit
#include "ai_header2"
#include "antistuck_h"

/////////////////////////////////////////////////////////////////////// MAIN
void main()
{
    object oMe=OBJECT_SELF;
    int nState=GetLocalInt(oMe,"nSState");
    string sID=GetLocalString(oMe,"sTeamID");
    string sTagMP1="MinorManaPool";
    string sTagMP2="ManaPool";
    string sTagMP5="StrongManaPool";
    string sTagMC1="MANA_CRYSTAL_1";
    string sTagMC2="MANA_CRYSTAL_2";
    string sTagMC5="MANA_CRYSTAL_5";
    object oItem=GetLocalObject(oMe,"oItem");
    object oDest=GetLocalObject(oMe,"oDestWP");
    object oOb;
    object oTarget;
    object oStart=GetWaypointByTag(sID+"_START");
    object oVault=GetObjectByTag(sID+"_VAULT");
    object oMod=GetModule();
    int nErr;
    int nHas=FALSE;
    float fDist;
    int nR;
    //AssignCommand(oMe,SpeakString("*hu "+IntToString(nState)+"*"));
    if (GetItemPossessedBy(OBJECT_SELF,sTagMC1)!=OBJECT_INVALID) nHas=TRUE;
    if (GetItemPossessedBy(OBJECT_SELF,sTagMC2)!=OBJECT_INVALID) nHas=TRUE;
    if (GetItemPossessedBy(OBJECT_SELF,sTagMC5)!=OBJECT_INVALID) nHas=TRUE;
    switch(nState)
    { // sub-state
      case 0: { // leave lair
        if (oDest==OBJECT_INVALID)
        { // pick a destination outside the lair
          if (sID=="SPID") oDest=GetWaypointByTag("AIPATH32");
          else if (sID=="UND") oDest=GetWaypointByTag("AIPATH23");
          else if (sID=="UNC") oDest=GetWaypointByTag("AIPATH21");
          else if (sID=="DWF") oDest=GetWaypointByTag("AIPATH12");
          SetLocalObject(oMe,"oDestWP",oDest);
          AssignCommand(oMe,ClearAllActions());
          AssignCommand(oMe,ActionForceMoveToObject(oDest,TRUE,1.0,90.0));
        } // pick a destination outside the lair
        if (GetArea(oMe)!=GetArea(oStart)) nState=1;
        break;
      } // leave lair
      case 1: { // choose action 0=search in this area, 1 = move on
        oOb=GetNearestObjectByTag(sTagMP5,oMe,1);
        if (oOb==OBJECT_INVALID) oOb=GetNearestObjectByTag(sTagMP2,oMe,1);
        if (oOb==OBJECT_INVALID) oOb=GetNearestObjectByTag(sTagMP1,oMe,1);
        if (oOb==OBJECT_INVALID) oOb=GetNearestObjectByTag(sTagMC5,oMe,1);
        if (oOb==OBJECT_INVALID) oOb=GetNearestObjectByTag(sTagMC2,oMe,1);
        if (oOb==OBJECT_INVALID) oOb=GetNearestObjectByTag(sTagMC1,oMe,1);
        if (oOb==OBJECT_INVALID||fDist>40.0)
        { // pick what to do
          nR=d6();
          if (nR<3) nState=2;
          else { nState=3; }
        } // pick what to do
        else
        { // found something act on it
          SetLocalObject(oMe,"oItem",oOb);
          if (GetObjectType(oOb)==OBJECT_TYPE_PLACEABLE) nState=4;
          else { nState=5; }
        } // found something act on it
        break;
      } // choose action 0 = search in this area, 1 = move on
      case 2: { // search in this area
        if (oDest==OBJECT_INVALID)
        {
          oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d12());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d10());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d8());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d6());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d4());
          if (oOb==OBJECT_INVALID) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,1);
          if (oOb!=OBJECT_INVALID)
          { // waypoint found
            SetLocalObject(oMe,"oDestWP",oOb);
          } // waypoint found
        }
        else
        { // move
          nErr=fnMoveToDestination(oDest,TRUE);
          if (nErr==-1) { AssignCommand(oMe,JumpToObject(oDest)); nState=1; DeleteLocalObject(oMe,"oDestWP"); }
          else if (nErr==1||GetDistanceBetween(oMe,oDest)<1.0) { nState=1; DeleteLocalObject(oMe,"oDestWP");}
        } // move
        break;
      } // search in this area
      case 3: { // move on
        if (oDest==OBJECT_INVALID)
        { // find transition
          oOb=fnFindSafeTransition();
          if (oOb==OBJECT_INVALID) { nState=1; DeleteLocalObject(oMe,"oDestWP"); }
          else
          { SetLocalObject(oMe,"oDestWP",oOb); }
        } // find transition
        else
        { // move to transition
          nErr=fnMoveToDestination(oDest,TRUE);
          if (nErr==-1) { AssignCommand(oMe,JumpToObject(oDest));}
          if (nErr==1||nErr==-1||(GetArea(oDest)==GetArea(oMe)&&GetDistanceBetween(oMe,oDest)<3.0))
          { // arrived
            nState=1; DeleteLocalObject(oMe,"oDestWP");
          } // arrived
        } // move to transition
        break;
      } // move on
      case 4: { // harvest mana pool
        if (GetDistanceBetween(oMe,oItem)>1.9) nErr=fnMoveToDestination(oItem,TRUE);
        if (nErr==-1)
        {
          AssignCommand(oMe,JumpToObject(oItem));
          AssignCommand(oMe,ActionMoveAwayFromObject(oItem,TRUE,3.0));
        }
        else if (oItem!=OBJECT_INVALID&&(nErr==1||GetDistanceBetween(oMe,oItem)<2.0))
        { // harvest
          AssignCommand(oMe,ActionMoveToObject(oItem));
          AssignCommand(oMe,ActionInteractObject(oItem));
          AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nSState",6)));
          nState=7;
        } // harvest
        else if (oItem==OBJECT_INVALID) { DeleteLocalObject(oMe,"oItem"); nState=1; }
        break;
      } // harvest mana pool
      case 5: { // pickup mana crystal
        if (oItem!=OBJECT_INVALID)
        { // item exists
          if (GetItemPossessor(oItem)==oMe) nState=6;
          else if (GetItemPossessor(oItem)!=OBJECT_INVALID)
          { // someone else got it
            DeleteLocalObject(oMe,"oItem"); nState=1;
          } // someone else got it
          else if (GetDistanceBetween(oMe,oItem)<3.0) { // pick it up
            AssignCommand(oMe,ClearAllActions());
            AssignCommand(oMe,ActionMoveToObject(oItem));
            AssignCommand(oMe,ActionPickUpItem(oItem));
          } // pick it up
          else
          {
            nErr=fnMoveToDestination(oItem,TRUE);
          }
        } // item exists
        else { DeleteLocalObject(oMe,"oItem"); nState=1; }
        break;
      } // pickup mana crystal
      case 6: { // return to lair
        nErr=0;
        if (GetArea(oMe)!=GetArea(oVault))
        {
         if (sID=="SPID") nErr=3;
         else if (sID=="DWF") nErr=2;
         else if (sID=="UNC") nErr=1;
         else if (sID=="UND") nErr=3;
         if (GetIsDay()==TRUE&&GetLocalInt(oMod,GetResRef(oMe)+"_light")==2) nErr=4; // light fatal
         SetLocalInt(oMe,"nRun",TRUE);
         oDest=fnPathNextDestination(GetArea(oMe),sID,nErr);
         nErr=fnMoveToDestination(oDest,TRUE);
         if (nErr==-1) { AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,JumpToObject(oStart)); }
       }
       else
       { // deposit mana
         nState=13;
         SetLocalInt(oMe,"nSState",13);
       } // deposit mana
        break;
      } // return to lair
      case 7: { // null state
        break;
      } // null state
      case 13: { // deliver up the crystal
        fDist=GetDistanceBetween(oMe,oVault);
        if ((fDist==0.0&&GetArea(oVault)!=GetArea(OBJECT_SELF))||fDist>1.5)
        { // move
          nErr=fnMoveToDestination(oVault,TRUE);
          if (nHas==FALSE)
          { // delivered
            SetLocalInt(oMe,"nSState",0);
            DeleteLocalObject(oMe,"oDestWP");
            nState=0;
          } // delivered
        } // move
        else if (nHas==TRUE)
        { // move away and try again
          AssignCommand(oMe,ClearAllActions());
          AssignCommand(oMe,ActionMoveAwayFromObject(oVault,TRUE,8.0));
        } // move away and try again
        break;
      } // deliver up the crystal
      default: break;
    } // sub-state
    SetLocalInt(oMe,"nSState",nState);
}
/////////////////////////////////////////////////////////////////////// MAIN