// rts_ai_scout2 - scout 2.0 #include "rts_header" #include "antistuck_h" /////////////////////////// // PROTOTYPES /////////////////////////// object fnFindGoodTransition(object oLArea,int bLAreaOk=FALSE); object fnRandomTrans(object oArea); string fnFindNearbyInterestingObjects(string sID); object fnMakeMessenger(object oMsg,string sID); void fnSpeak(string sSay); // speak a message if intelligence >8 /////////////////////////////////////////////////////////////////////// MAIN void main() { object oMe=OBJECT_SELF; object oLArea=GetLocalObject(oMe,"oLArea"); string sID=GetLocalString(oMe,"sTeamID"); object oMod=GetModule(); object oOb; object oItem; object oMsg; object oBird; int nC; int nN; int nRun=GetLocalInt(oMe,"nRun"); float fDist; string sMsg; object oDest=GetLocalObject(oMe,"oDestWP"); int nState=GetLocalInt(oMe,"nSState"); object oStart=GetWaypointByTag(sID+"_START"); if (!GetIsObjectValid(oLArea)) { oLArea=GetArea(oMe); SetLocalObject(oMe,"oLArea",oLArea); } //SendMessageToPC(GetFirstPC(),GetName(oMe)+" nS:"+IntToString(nState)+" oD:"+GetTag(oDest)+" in area '"+GetName(GetArea(oDest))+"' fDist:"+FloatToString(GetDistanceBetween(oMe,oDest))); switch(nState) { // main scout switch case 0: { // if in lair leave it - if have stealth activate it if ((GetHasSkill(SKILL_HIDE,oMe)==TRUE||GetHasSkill(SKILL_MOVE_SILENTLY,oMe)==TRUE)&&GetLocalInt(oMe,"nRun")==FALSE) { // enter stealth mode SetActionMode(oMe,ACTION_MODE_STEALTH,TRUE); } // enter stealth mode if (GetArea(oMe)==GetArea(oStart)) { // leave lair if (!GetIsObjectValid(oDest)) fnSpeak("I need to leave the lair."); if (GetArea(oDest)!=GetArea(oMe)&&GetIsObjectValid(oDest)) { // move to destination AssignCommand(oMe,ASActionMoveToObject(oDest,nRun,3.0)); } // move to destination else if (GetIsObjectValid(oDest)) { // find destination oDest=fnFindGoodTransition(oLArea); if (GetIsObjectValid(oDest)) { oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,2); SetLocalObject(oMe,"oDestWP",oDest); AssignCommand(oMe,ASActionMoveToObject(oDest,nRun,3.0)); SetLocalObject(oMe,"oLArea",GetArea(oMe)); } } // find destination else { // arrived AssignCommand(oMe,ClearAllActions()); nState=1; DeleteLocalObject(oMe,"oDestWP"); } // arrived } // leave lair else { // look around nState=1; } // look around break; } // if in lair leave it - if have stealth activate it case 1: { // look around nearby sMsg=fnFindNearbyInterestingObjects(sID); if (GetStringLength(sMsg)<3) { nC=d6(); if (nC<4) nState=2; else { nState=3; } DeleteLocalObject(oMe,"oDestWP"); } else { // found something fnSpeak("I must send a message."); oOb=GetLocalObject(oMod,"oTeamLead"+sID); oMsg=CreateItemOnObject("rtsa_message",oMe); SetLocalString(oMsg,"sMsg",sMsg); SetLocalObject(oMsg,"oDest",GetWaypointByTag(sID+"_START")); 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))); } // found something break; } // look around nearby case 2: { // move around within same area nC=GetLocalInt(oMe,"nMoveAroundStuck"); if (!GetIsObjectValid(oDest)) { nC++; if (nC>3) { nState=3; DeleteLocalInt(oMe,"nMoveAroundStuck"); } else { SetLocalInt(oMe,"nMoveAroundStuck",nC); } } else { DeleteLocalInt(oMe,"nMoveAroundStuck"); } if (!GetIsObjectValid(oDest)) { // pick dest oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20()); if (oDest!=OBJECT_INVALID) { // found place to move to SetLocalObject(oMe,"oDestWP",oDest); nC=fnMoveToDestination(oDest); } // found place to move to } // pick dest else if (GetDistanceBetween(oMe,oDest)>4.0) { // keep moving nC=fnMoveToDestination(oDest); } // keep moving else { // arrived AssignCommand(oMe,ClearAllActions()); DeleteLocalObject(oMe,"oDestWP"); nState=1; } // arrived break; } // move around within same area case 3: { // seek out another area if (!GetIsObjectValid(oDest)) { // find another area oDest=fnFindGoodTransition(oLArea); if (GetIsObjectValid(oDest)) { oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,1); SetLocalObject(oMe,"oDestWP",oDest); nC=fnMoveToDestination(oDest,FALSE); SetLocalObject(oMe,"oLArea",GetArea(oMe)); } else { // try backing up oDest=fnFindGoodTransition(oLArea,TRUE); if (GetIsObjectValid(oDest)) { oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,1); SetLocalObject(oMe,"oDestWP",oDest); nC=fnMoveToDestination(oDest,FALSE); SetLocalObject(oMe,"oLArea",GetArea(oMe)); } } // try backing up } // find another area else if (GetArea(oDest)!=GetArea(oMe)) { // move to destination nC=fnMoveToDestination(oDest); } // move to destination else { // arrived AssignCommand(oMe,ClearAllActions()); DeleteLocalObject(oMe,"oDestWP"); nState=1; } // arrived break; } // seek out another area default: break; } // main scout switch SetLocalInt(oMe,"nSState",nState); } //////////////////////////////////////////////////////////////////////// MAIN //////////////////// // FUNCTIONS //////////////////// string fnFindNearbyInterestingObjects(string sID) { string sRet=""; object oMe=OBJECT_SELF; string sUnits; string sImportant; float fDist; object oOb; int nC=1; int nFC=0; int nEC=0; int nNC=0; int nOT; string sTag; string sRes; oOb=GetNearestObject(OBJECT_TYPE_ALL,oMe,nC); fDist=GetDistanceBetween(oMe,oOb); while(oOb!=OBJECT_INVALID&&fDist<40.0) { // build list of interesting items sTag=GetTag(oOb); nOT=GetObjectType(oOb); sRes=GetResRef(oOb); if (nOT==OBJECT_TYPE_ITEM&&GetLocalInt(oOb,"bNoticed"+sID)!=TRUE) { // an item have not flagged as noticed before if ((GetStringLeft(sTag,4)=="rts_"&&GetPlotFlag(oOb)==TRUE)||(GetStringLeft(sRes,4)=="rts_"&&GetPlotFlag(oOb)==TRUE)||sTag=="MANA_CRYSTAL_5"||sTag=="MANA_CRYSTAL_2"||sTag=="MANA_CRYSTAL_1") { // important item sImportant=sImportant+"an item named "+GetName(oOb)+","; SetLocalInt(oOb,"bNoticed"+sID,TRUE); } // important item } // an item have not flagged as noticed before else if (nOT==OBJECT_TYPE_PLACEABLE&&GetLocalInt(oOb,"bNoticed"+sID)!=TRUE) { // a placeable not flagged as noticed if (sTag=="rts_pl_mag28"||sTag=="VampireCoffin"||sTag=="rts_pl_mag32a"||sTag=="rts_pl_mag32b"||sTag=="ManaPool"||sTag=="MinorManaPool"||sTag=="StrongManaPool"||sTag=="pileogold"||sTag=="RESGOLD"||sTag=="RESADM"||sTag=="RESIRON"||sTag=="RESMITH") { // important placeable sImportant=sImportant+"something called a "+GetName(oOb)+","; SetLocalInt(oOb,"bNoticed"+sID,TRUE); } // important placeable } // a placeable not flagged as noticed else if (nOT==OBJECT_TYPE_CREATURE) { // creatures if (GetIsPC(oOb)==TRUE&&GetIsDM(oOb)==FALSE&&GetLocalString(oOb,"sTeamID")!=sID) sImportant=sImportant+"a player named "+GetName(oOb)+", "; if (GetIsFriend(oOb)==TRUE) { nFC++; } else if (GetIsEnemy(oOb)==TRUE) { nEC++; sUnits=sUnits+GetName(oOb)+", "; } else { nNC++; } if (GetLocalInt(oOb,"bNoticed"+sID)!=TRUE) { // check to see if an important unit if (sTag=="tanner"||sTag=="Apothecary"||sTag=="Healer"||sTag=="Rotund"||sTag=="Fence"||sTag=="NorthernTrader"||sTag=="MERC_LORD1"||sTag=="MERC_LORD2"||sTag=="MERC_LORD3"||sTag=="Smith") { // important NPC sImportant=sImportant+"an important person named "+GetName(oOb)+", "; SetLocalInt(oOb,"bNoticed"+sID,TRUE); } // important NPC } // check to see if an important unit } // creatures nC++; oOb=GetNearestObject(OBJECT_TYPE_ALL,oMe,nC); fDist=GetDistanceBetween(oMe,oOb); } // build list of interesting items if (GetStringLength(sImportant)>3) { // found some important stuff sRet="I was walking in the '"+GetName(GetArea(oMe))+"' area on day "+IntToString(GetCalendarDay())+" of the year "+IntToString(GetCalendarYear())+" and I noticed some important things that lead me to send you this report:"; sRet=sRet+"I noticed "+IntToString(nEC)+" hostile units, "+IntToString(nFC)+" friendly units, and "+IntToString(nNC)+" neutal units. This was not what lead me to report this. I also saw "; sRet=sRet+sImportant+". I made a note of the types of enemy units in the area too and am including that as the end of my report: "; sRet=sRet+sUnits+"."; } // found some important stuff return sRet; } // fnFindNearbyInterestingObjects() object fnFindGoodTransition(object oLArea,int bLAreaOk=FALSE) { // find a good transition object oRet=OBJECT_INVALID; object oMe=OBJECT_SELF; int nC=1; object oOb; object oTO; string sID=GetLocalString(oMe,"sTeamID"); object oStart=GetWaypointByTag(sID+"_START"); oOb=fnRandomTrans(GetArea(oMe)); oTO=GetTransitionTarget(oOb); while((oTO==OBJECT_INVALID||(GetArea(oTO)==oLArea&&bLAreaOk==FALSE)||GetArea(oTO)==GetArea(oMe))&&nC<4) { // find a transition target nC++; oOb=fnRandomTrans(GetArea(oMe)); oTO=GetTransitionTarget(oOb); } // find a transition target if (GetArea(oTO)!=GetArea(oStart)&&GetArea(oMe)!=GetArea(oTO)&&(oTO!=OBJECT_INVALID&&GetArea(oTO)!=oLArea)||(GetArea(oTO)==oLArea&&bLAreaOk==TRUE)) return oTO; return oRet; } // fnFindGoodTransition() void fnBuildTransRand(object oArea) { // build a list of transitions from this area int nC=0; int nL=1; object oFirst=GetFirstObjectInArea(oArea); object oTrans; object oTarget; 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 oTarget=GetTransitionTarget(oTrans); if(GetIsObjectValid(oTarget)) { // transition if (!GetIsObjectValid(GetNearestObjectByTag("NO_SCOUT",oTarget))) { // not forbidden nC++; SetLocalObject(oArea,"oPathingTrans"+IntToString(nC),oTrans); } // not forbidden } // transition nL++; oTrans=GetNearestObject(OBJECT_TYPE_TRIGGER,oFirst,nL); } // triggers nL=1; oTrans=GetNearestObject(OBJECT_TYPE_DOOR,oFirst,nL); while(oTrans!=OBJECT_INVALID) { // doors oTarget=GetTransitionTarget(oTrans); if(GetIsObjectValid(oTarget)) { // transition if (!GetIsObjectValid(GetNearestObjectByTag("NO_SCOUT",oTarget))) { // not forbidden nC++; SetLocalObject(oArea,"oPathingTrans"+IntToString(nC),oTrans); } // not forbidden } // 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() 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 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() void fnSpeak(string sSay) { // speak message if Intelligence>8 int nINT=GetAbilityScore(OBJECT_SELF,ABILITY_INTELLIGENCE); if (nINT>8) SpeakString(sSay); } // fnSpeak()