/////////////////////////////////////////////////////////////////////////////////// // REAL TIME STRATEGY ADVENTURE - Kit // FILE: rtsa_unit_ai // NAME: This is the main script that controls Unit Artificial Intelligence // SCRIPTED BY: Deva Bryson Winblood // DATE: 4/13/2003 /////////////////////////////////////////////////////////////////////////////////// #include "rtsa_headera" // ai #include "rtsa_headere" // errors #include "rtsa_headerp" // parser #include "antistuck_h" ///////////////////////////////////////// // PROTOTYPES ///////////////////////////////////////// void fnMainAIRoutine(); // The main switch void fnFollowPC(int nType=0); // FOLLOW command void fnRoam(); // ROAM command void fnSeek(); // SEEK AND DESTROY command void fnGuardLair(); // GUARD LAIR command void fnGuardLocation(); // GUARD SPECIFIC LOCATION command void fnAttackLocation(); // ATTACK SPECIFIC LOCATION command void fnHeal(); // return to heal location in lair and heal void fnHide(); // Use HIDE and MOVE SILENTLY skills void fnSearch(); // Search for and disarm traps void fnRecon(); // reconnoiter command void fnBurrow(); // Burrow command void fnDestroyObject(); // Destroy Object void fnOpenObject(); // Open Object void fnDie(); // Die void fnRetreat(); // flee to base void fnSleep(); // sleep and recover spells void fnPatrol(); // Walk up to a 4 point patrol path void fnBreed(); // breed creatures void fnFlee(string sWhere="NA"); // Flee to base, sunlight, insanity ////////////////////////////////////////////////////////// MAIN ///////////////// void main() { object oMod=GetModule(); object oMe=OBJECT_SELF; int nDelay=GetLocalInt(oMod,"nRTSAIDelay"); object oAttacker=GetLastAttacker(); float fDist=-1.0; int nSpeed=GetLocalInt(oMe,"nSpeed"); object oEnemy=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,OBJECT_SELF,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE); int nMState=GetLocalInt(OBJECT_SELF,"nMState"); if (!GetIsDead(oAttacker)) fDist=GetDistanceToObject(oAttacker); SetLocalInt(OBJECT_SELF,"nLastDelaySec",GetTimeSecond()); // set monitor for HBKICK if (!IsInConversation(oMe)) { // is not talking if (fDist==-1.0||fDist>20.0) { // Last attacker is not near if ((oEnemy!=OBJECT_INVALID&&(nMState>27&&nMState<51))||oEnemy==OBJECT_INVALID||GetLocalInt(oMe,"nAggression")==1) { // No enemies perceived nearby if (GetLocalInt(oMe,"nAIBusy")!=TRUE) { // Not in busy mode fnMainAIRoutine(); } // Not in busy mode } // No enemies perceived nearby } // Last attacker is not near } // is not talking // DelayCommand(IntToFloat(nDelay+nSpeed),ExecuteScript("rtsa_unit_ai",oMe)); ExecuteScript("rtsa_ai_smonitor",oMe); } // main() /////////////////////////////////////////////////////////// MAIN ///////////////// /////////////////////////////////////// // FUNCTIONS /////////////////////////////////////// //--------------------------------------------------[ fnMainAIRoutine ]------ void fnMainAIRoutine() { // main switch statement for AI object oMe=OBJECT_SELF; int nMState=GetLocalInt(oMe,"nMState"); // main state int nSState=GetLocalInt(oMe,"nSState"); // sub state object oDest=GetLocalObject(oMe,"oDest"); // Destination Waypoint object oPer=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE); int nCHP=GetCurrentHitPoints(oMe); int nMHP=GetMaxHitPoints(oMe); float fDist; string sID=GetLocalString(oMe,"sTeamID"); fnDebug("["+GetName(oMe)+"] MainState:"+IntToString(nMState)+" SubState:"+IntToString(nSState)); switch(nMState) { // Main Switch -----------------------------------<<<<< case 1: { // Follow Leader SetAILevel(oMe,AI_LEVEL_DEFAULT); if(GetLocalString(oDest,"sTeamID")!="FREE") fnFollowPC(); else fnFollowPC(1); break; } // Follow Leader case 2: { // Protect SetAILevel(oMe,AI_LEVEL_NORMAL); fnFollowPC(1); break; } // Protect case 3: {// Guard Location SetAILevel(oMe,AI_LEVEL_DEFAULT); fnGuardLocation(); break; } // Guard Location case 4: {// Attack Location SetAILevel(oMe,AI_LEVEL_NORMAL); fnAttackLocation(); break; } // Attack Location case 5: {// Roam SetAILevel(oMe,AI_LEVEL_DEFAULT); fnRoam(); break; } // Roam case 6: {// Seek and Destroy SetAILevel(oMe,AI_LEVEL_NORMAL); fnSeek(); break; } // Seek and Destroy case 7: {// Scout SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_scout",oMe); break; } // Scout case 8: {// Heal SetAILevel(oMe,AI_LEVEL_NORMAL); fnHeal(); break; } // Heal case 9: {// Hide SetAILevel(oMe,AI_LEVEL_DEFAULT); fnHide(); break; } // Hide case 10: {// Search SetAILevel(oMe,AI_LEVEL_DEFAULT); fnSearch(); break; } // Search case 11: {// Recon SetAILevel(oMe,AI_LEVEL_DEFAULT); fnRecon(); break; } // Recon case 12: {// Burrow SetAILevel(oMe,AI_LEVEL_NORMAL); fnBurrow(); break; } // Burrow case 13: {// Destroy Object SetAILevel(oMe,AI_LEVEL_DEFAULT); fnDestroyObject(); break; } // Destroy Object case 14: {// Trade SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_trade",oMe); break; } // Trade case 15: {// Deliver Message SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_message",oMe); break; } // Deliver Message case 16: {// Build SetAILevel(oMe,AI_LEVEL_DEFAULT); SetLocalInt(oMe,"nParm",1); if(nSState==0) ExecuteScript("rtsa_su_cb",oMe); else ExecuteScript("rtsa_ai_cb",oMe); break; } // Build case 17: {// Craft SetAILevel(oMe,AI_LEVEL_DEFAULT); SetLocalInt(oMe,"nParm",2); if(nSState==0) ExecuteScript("rtsa_su_cb",oMe); else ExecuteScript("rtsa_ai_cb",oMe); break; } // Craft case 18: {// Upgrade SetAILevel(oMe,AI_LEVEL_DEFAULT); ExecuteScript("rtsa_upgrade",oMe); break; } // Upgrade case 19: {// Breed SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_breed",oMe); break; } // Breed case 20: {// Open Object SetAILevel(oMe,AI_LEVEL_DEFAULT); fnOpenObject(); break; } // Open Object case 21: {// Guard the Lair SetAILevel(oMe,AI_LEVEL_DEFAULT); fnGuardLair(); break; } // Guard the Lair case 22: {// Stand SetAILevel(oMe,AI_LEVEL_DEFAULT); break; } // Stand case 23: {// Sleep SetAILevel(oMe,AI_LEVEL_NORMAL); fnSleep(); break; } // Sleep case 24: {// Patrol SetAILevel(oMe,AI_LEVEL_NORMAL); fnPatrol(); break; } // Patrol case 25: {// Die SetAILevel(oMe,AI_LEVEL_DEFAULT); fnDie(); break; } // Die case 26: {// Manage Inventory SetAILevel(oMe,AI_LEVEL_DEFAULT); break; } // Manage Inventory case 27: {// Heal Nearby SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_healn",oMe); break; } // Heal Nearby case 28: {// retreat SetAILevel(oMe,AI_LEVEL_DEFAULT); fnRetreat(); break; } // retreat case 30: {// harvest SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_harv",oMe); break; } // harvest case 40: {// Flee to base SetAILevel(oMe,AI_LEVEL_NORMAL); fnFlee(sID+"_START"); break; } // Flee to base case 41: {// Flee sunlight SetAILevel(oMe,AI_LEVEL_NORMAL); fnFlee("SUN"); break; } // Flee sunlight case 42: {// Insanity SetAILevel(oMe,AI_LEVEL_DEFAULT); fnFlee("NA"); break; } // Insanity case 51: { // Custom command 1 SetAILevel(oMe,AI_LEVEL_DEFAULT); ExecuteScript("rtsa_ai_cust1",oMe); break; } // Custom command 1 case 52: { // Custom command 2 SetAILevel(oMe,AI_LEVEL_DEFAULT); ExecuteScript("rtsa_ai_cust2",oMe); break; } // Custom command 2 case 53: { // Custom command 3 SetAILevel(oMe,AI_LEVEL_NORMAL); ExecuteScript("rtsa_ai_cust3",oMe); break; } // Custom Command 3 default: { // default SetAILevel(oMe,AI_LEVEL_DEFAULT); SetLocalInt(oMe,"nSpeed",0); break; } // default } // Main Switch -----------------------------------<<<<< } // fnMainAIRoutine() //----------------------------------------------------[ fnFollowPC ]---------- void fnFollowPC(int nType=0) { // follow a PC object oMe=OBJECT_SELF; object oMod=GetModule(); string sID=GetLocalString(oMe,"sTeamID"); object oLeader=GetLocalObject(oMod,"oTeamLead"+sID); float fClose=3.0; int nParm=GetLocalInt(oMe,"nParm"); float fDist; if (nType==1) oLeader=GetLocalObject(oMe,"oDest"); fDist=GetDistanceToObject(oLeader); if (nParm==2) fClose=7.0; if (fDist==-1.0||fDist>40.0) { // too far away - teleport AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,JumpToObject(oLeader)); AssignCommand(oMe,ActionForceFollowObject(oLeader,fClose)); } // too far away - teleport else { // keep following AssignCommand(oMe,ActionForceFollowObject(oLeader,fClose)); } // keep following } // fnFollowPC() //-----------------------------------------------------[ Roam ]--------------- void fnRoam() { // Roam about - only seeking to leave an area 1 on 8 object oMe=OBJECT_SELF; object oArea=GetArea(oMe); int nR=d8(); int nResults; object oDest=GetLocalObject(oMe,"oDest"); int nSState=GetLocalInt(oMe,"nSState"); fnDebug(" fnRoam() was called by "+GetName(oMe)+" State:"+IntToString(nSState)+" Destination:"+GetTag(oDest)); switch(nSState) { // state case 0: { // find destination fnFlushS("Pathing"); if (nR==1) { // leave area oDest=fnRandomTrans(oArea); oDest=GetTransitionTarget(oDest); fnDebug(" Random Trans:"+GetTag(oDest)); if (oDest!=OBJECT_INVALID) { SetLocalInt(oMe,"nSState",1); nSState=1; } SetLocalObject(oMe,"oDest",oDest); } // leave area else { // random object here oDest=fnRandomObject(oArea); if (oDest!=OBJECT_INVALID) SetLocalInt(oMe,"nSState",1); fnDebug(" Random Object:"+GetTag(oDest)); SetLocalObject(oMe,"oDest",oDest); } // random object here } // find destination case 1: { // move to destination if (nSState==1) { // if proper state fnDebug(" Calling fnMovePath"); nResults=fnMovePath(oDest,TRUE); if (nResults==1||nResults==-1) { // arrived or error SetLocalInt(oMe,"nSState",0); } // arrived or error } // if proper state break; } // move to destination default: { SetLocalInt(oMe,"nSState",0); break; } } // state } // fnRoam() //------------------------------------------------[ SEEK AND DESTROY ]-------- void fnSeek() { // seek out enemies and destroy // oLArea1 & oLArea2 - remembers the previous 2 areas visited object oMe=OBJECT_SELF; int nSState=GetLocalInt(oMe,"nSState"); object oDest=GetLocalObject(oMe,"oDest"); int nErr; // error trapping object oH; // object handle float fDist; // used to measure distances int nN; // number object oArea=GetArea(oMe); object oLArea1=GetLocalObject(oMe,"oLArea1"); object oLArea2=GetLocalObject(oMe,"oLArea2"); if (nSState==0) { // find enemy or next destination fnFlushS("Pathing"); fnDebug(" Seek - State: 0"); oH=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE); if (oH!=OBJECT_INVALID) { oDest=oH; SetLocalObject(oMe,"oDest",oH); } if (oH==OBJECT_INVALID) { // no enemies nearby if (d8()>4) { // seek area transition oH=fnRandomTrans(oArea); oH=GetTransitionTarget(oH); nN=0; while((GetArea(oH)==oLArea1||GetArea(oH)==oLArea2)&&nN<3) { // find good transition oH=fnRandomTrans(oArea); oH=GetTransitionTarget(oH); nN++; } // find good transition if (GetArea(oH)!=oLArea1&&GetArea(oH)!=oLArea2) { // found a good target SetLocalObject(oMe,"oDest",oH); oDest=oH; SetLocalInt(oMe,"nSState",2); nSState=2; SetLocalObject(oMe,"oLArea2",oLArea1); SetLocalObject(oMe,"oLArea1",oArea); } // found a good target } // seek area transition else { // seek object oH=fnRandomObject(oArea); if (oH!=OBJECT_INVALID) { // good object oDest=oH; SetLocalInt(oMe,"nSState",2); SetLocalObject(oMe,"oDest",oH); nSState=2; } // good object } // seek object } // no enemies nearby else { // see enemy - engage SetLocalObject(oMe,"oDest",oH); SetLocalInt(oMe,"nSState",1); nSState=1; } // see enemy - engage } // find enemy or next destination if (nSState==1) { // engage enemy AssignCommand(oMe,ASActionMoveToObject(oDest,TRUE,2.0)); fDist=GetDistanceToObject(oDest); if (fDist==-1.0||fDist>60.0) { // no longer in sight SetLocalInt(oMe,"nSState",0); AssignCommand(oMe,ClearAllActions()); } // no longer in sight } // engage enemy if (nSState==2) { // move to destination fnDebug(" Seek - State: 2"); nErr=fnMoveToDestination(oDest,TRUE); if (nErr==1) { // should be there fDist=GetDistanceToObject(oDest); if (fDist!=-1.0&&fDist<3.0) { // we are indeed there SetLocalInt(oMe,"nSState",0); AssignCommand(oMe,ClearAllActions()); } // we are indeed there } // should be there else if (nErr==-1) { // can't reach there if(GetArea(oDest)!=oArea) { // failed to reach another area SetLocalObject(oMe,"oLArea1",oLArea2); DeleteLocalObject(oMe,"oLArea2"); } // failed to reach another area SetLocalInt(oMe,"nSState",0); AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionSpeakString("I cannot get there.")); AssignCommand(oMe,PlayVoiceChat(VOICE_CHAT_CANTDO)); SetLocalInt(oMe,"nASC",0); SetLocalObject(oMe,"oDest",OBJECT_INVALID); } // can't reach there } // move to destination } // fnSeek() //--------------------------------------------[ GUARD LAIR ]------------------ void fnGuardLair() { // Guard the lair command object oMe=OBJECT_SELF; object oArea=GetArea(oMe); object oH; float fDist; int nErr; string sTeamID=GetLocalString(oMe,"sTeamID"); object oDest=GetLocalObject(oMe,"oDest"); int nSState=GetLocalInt(oMe,"nSState"); switch(nSState) { // Guard lair switch case 0: { // find out if in lair oH=GetWaypointByTag(sTeamID+"_START"); if (GetDistanceToObject(oH)==-1.0) { // different area nSState=1; oDest=oH; SetLocalObject(oMe,"oDest",oDest); } // different area else { // same area nSState=2; } // same area } // find out if in lair case 1: { // Move to lair if (nSState==1) { // do it fDist=GetDistanceToObject(oDest); if (fDist==-1.0||fDist>4.0) { // not close enough nErr=fnMovePath(oDest,TRUE); if (nErr==-1) fnError("RTSA ERROR: '"+GetName(oMe)+"' cannot reach "+sTeamID+"_START."); } // not close enough else { // arrived nSState=2; } // arrived } // do it break; } // Move to lair case 2: { // Pick new target oH=fnRandomObject(oArea); if (oH!=OBJECT_INVALID) { // good object oDest=oH; SetLocalInt(oMe,"nSState",3); SetLocalObject(oMe,"oDest",oH); nSState=3; } // good object } // Pick new target case 3: { // Move to target if (nSState==3) { // do it fDist=GetDistanceToObject(oDest); if (fDist==-1.0||fDist>4.0) { // not close enough nErr=fnMovePath(oDest,TRUE); if (nErr==-1) { // cannot reach nSState=0; } // cannot reach } // not close enough else { // arrived nSState=2; } // arrived } // do it break; } // Move to target default: { nSState=0; break; } } // Guard lair switch SetLocalInt(oMe,"nSState",nSState); } // fnGuardLair() //--------------------------------------------------[ fnGuardLocation ]------- void fnGuardLocation() { // if not at location move to it - if chase enemy return to this location // when done chasing. object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oDest"); float fDist=GetDistanceToObject(oDest); int nErr; if (fDist==-1.0||fDist>6.9||oDest==OBJECT_INVALID) { // move to area to guard if (oDest!=OBJECT_INVALID) { // !OI nErr=fnMovePath(oDest,TRUE); if (nErr==-1) { // error reaching location - switch to guard the lair SetLocalInt(oMe,"nMState",21); SetLocalInt(oMe,"nSState",0); } // error reaching location - switch to guard the lair } // !OI else { // target missing switch to Guard The Lair SetLocalInt(oMe,"nMState",21); SetLocalInt(oMe,"nSState",0); } // target missing switch to Guard The Lair } // move to area to guard else { // in area make sure pathing stack is empty nErr=fnSizeS("Pathing"); if (nErr!=0) fnFlushS("Pathing"); } // in area make sure pathing stack is empty } // fnGuardLocation() //------------------------------------------------[ fnAttackLocation ]-------- void fnAttackLocation() { // go to location - wander short distances from there looking for targets object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oDest"); float fDist=GetDistanceToObject(oDest); int nErr; if (fDist==-1.0||fDist>6.9||oDest==OBJECT_INVALID) { // move to location if (oDest!=OBJECT_INVALID) { // !OI nErr=fnMovePath(oDest,TRUE); if (nErr==-1) { // error reaching location - switch to guard the lair SetLocalInt(oMe,"nMState",21); SetLocalInt(oMe,"nSState",0); } // error reaching location - switch to guard the lair } // !OI else { // target missing switch to Guard The Lair SetLocalInt(oMe,"nMState",21); SetLocalInt(oMe,"nSState",0); } // target missing switch to Guard The Lair } // move to location else { // pick nearby location oDest=fnRandomObject(GetArea(oMe),0); AssignCommand(oMe,ASActionMoveToObject(oDest)); DelayCommand(10.0,AssignCommand(oMe,ClearAllActions())); } // pick nearby location } // fnAttackLocation() void fnHeal() { // return to healing location in lair and heal object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oDest"); float fDist=GetDistanceToObject(oDest); int nSState=GetLocalInt(oMe,"nSState"); int nMHP=GetMaxHitPoints(oMe); int nCHP=GetCurrentHitPoints(oMe); int nPrev=GetLocalInt(oMe,"nPrev"); object oPrev=GetLocalObject(oMe,"oPrev"); string sID=GetLocalString(oMe,"sTeamID"); int nHealAmt=1+GetAbilityModifier(ABILITY_CONSTITUTION,oMe); effect eHeal; int nErr; if (nHealAmt<1) nHealAmt=1; eHeal=EffectHeal(nHealAmt); if (nMHP==nCHP) { // healed AssignCommand(oMe,ClearAllActions()); SetLocalInt(oMe,"nMState",nPrev); SetLocalInt(oMe,"nSState",0); SetLocalObject(oMe,"oDest",oPrev); } // healed else { // needs healing switch(nSState) { // heal sub-state case 0: { // find destination heal location oDest=GetWaypointByTag(sID+"_HEAL"); if (oDest!=OBJECT_INVALID) { // valid location SetLocalInt(oMe,"nSState",1); SetLocalObject(oMe,"oDest",oDest); nErr=fnMovePath(oDest,TRUE); // start moving } // valid location else { // not valid AssignCommand(oMe,ClearAllActions()); if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I don't know where the healing location is.")); SetLocalInt(oMe,"nMState",nPrev); SetLocalInt(oMe,"nSState",0); SetLocalObject(oMe,"oDest",oPrev); } // not valid break; } // find destination heal location case 1: { // await arrival at heal location nErr=fnMovePath(oDest,TRUE); if (nErr==1) { // arrived SetLocalInt(oMe,"nSState",2); } // arrived else if (nErr==-1) { // cannot reach AssignCommand(oMe,ClearAllActions()); if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I cannot reach the healing location.")); SetLocalInt(oMe,"nMState",nPrev); SetLocalInt(oMe,"nSState",0); SetLocalObject(oMe,"oDest",oPrev); } // cannot reach break; } // await arrival at heal location case 2: { // start heal process AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_BACK,1.0,31.0)); DelayCommand(30.0,ApplyEffectToObject(DURATION_TYPE_INSTANT,eHeal,oMe,1.0)); break; } // start heal process } // heal sub-state } // needs healing } // fnHeal() void fnHide() { // use the HIDE skill object oMe=OBJECT_SELF; AssignCommand(oMe,ActionUseSkill(SKILL_HIDE,oMe)); AssignCommand(oMe,ActionUseSkill(SKILL_MOVE_SILENTLY,oMe)); } // use the HIDE skill void fnSearch() { // search for and disarm traps object oMe=OBJECT_SELF; int nPrev=GetLocalInt(oMe,"nPrev"); int nSState=GetLocalInt(oMe,"nSState"); object oPrev=GetLocalObject(oMe,"oPrev"); object oDest=GetLocalObject(oMe,"oDest"); int nC; int nD; float fDist; switch(nSState) { // search and disarm state case 0: { // look for nearby traps nC=1; oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nC); fDist=GetDistanceToObject(oDest); while(oDest!=OBJECT_INVALID&&nSState==0&&fDist<15.1) { // check for traps if (GetTrapDetectable(oDest)==TRUE&&GetTrapDisarmable(oDest)==TRUE) { // check to see if detected nD=d20()+GetSkillRank(SKILL_SEARCH,oMe)-GetTrapDetectDC(oDest); if (nD>-1) { // detected SetLocalObject(oMe,"oDest",oDest); SetLocalInt(oMe,"nSState",1); nSState=1; } // detected } // check to see if detected if (nSState==0) { // next trap nC++; oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nC); fDist=GetDistanceToObject(oDest); } // next trap } // check for traps if (nSState==0) { // no traps detected if(GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I don't think there are any traps here.")); SetLocalInt(oMe,"nSState",2); } // no traps detected break; } // look for nearby traps case 1: { // disarm trap AssignCommand(oMe,ActionUseSkill(SKILL_DISABLE_TRAP,oDest)); if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I see a trap. I'll try to disarm it.")); SetLocalInt(oMe,"nSState",0); SetLocalObject(oMe,"oDest",OBJECT_INVALID); break; } // disarm trap case 2: { // no more traps AssignCommand(oMe,ClearAllActions()); SetLocalInt(oMe,"nMState",nPrev); SetLocalInt(oMe,"nSState",0); SetLocalObject(oMe,"oDest",oPrev); break; } // no more traps } // search and disarm state } // search for and disarm traps void fnRecon() { // reconnoiter object oMe=OBJECT_SELF; int nParm=GetLocalInt(oMe,"nParm"); float fAheadDist=3.0; float fDX; float fDY; float fDZ; float fMX=0.0; float fMY=0.0; string sID=GetLocalString(oMe,"sTeamID"); object oMod=GetModule(); object oLead=GetLocalObject(oMe,"oDest"); // who to follow location lRecon; float fFacing=GetFacing(oLead); vector vVecPC=GetPosition(oLead); float fLX=vVecPC.x; float fLY=vVecPC.y; float fLZ=vVecPC.z; vector vNewVec; int nRun=GetLocalInt(oMe,"nRun"); float fDist=GetDistanceToObject(oLead); int nReconV=GetLocalInt(oMe,"nRecon"); if ((fDist!=-1.0)&&(nReconV!=TRUE)) SetLocalInt(oMe,"nRecon",TRUE); if (GetLocalInt(oMe,"nRecon")==TRUE) { // was near object when recon initiated if (oLead!=OBJECT_INVALID) { // valid leader if (nParm==2) fAheadDist=7.0; else if (nParm==3) fAheadDist=10.0; else if (nParm==4) fAheadDist=15.0; else if (nParm==5) fAheadDist=20.0; else if (nParm==6) fAheadDist=30.0; fnDebug("["+GetName(oMe)+"]Recon:("+FloatToString(fLX)+","+FloatToString(fLY)+","+FloatToString(fLZ)+") Ahead Dist:"+FloatToString(fAheadDist)); if (fFacing>335.0||fFacing<25.0) { // east fMX=1.0; } // east else if (fFacing>291.0&&fFacing<335.1) { // south east fMX=0.75; fMY=-0.75; } // south east else if (fFacing>250.0&&fFacing<291.1) { // south fMY=-1.0; } // south else if (fFacing>200.0&&fFacing<250.1) { // south west fMX=-0.75; fMY=-0.75; } // south west else if (fFacing>160.0&&fFacing<200.1) { // west fMX=-1.0; } // west else if (fFacing>110.0&&fFacing<160.1) { // north west fMX=-0.75; fMY=0.75; } // north west else if (fFacing>70.0&&fFacing<110.1) { // north fMY=1.0; } // north else { // north east fMY=0.75; fMX=0.75; } // north east fDX=fLX+(fMX*fAheadDist); fDY=fLY+(fMY*fAheadDist); fDZ=fLZ; if (fDX<0.0) fDX=0.0; if (fDY<0.0) fDY=0.0; fnDebug(" MULTIPLIERS: X:"+FloatToString(fMX)+" Y:"+FloatToString(fMY)); fnDebug(" Facing:"+FloatToString(fFacing)+" Recon to:"+FloatToString(fDX)+","+FloatToString(fDY)+","+FloatToString(fDZ)); vNewVec=Vector(fDX,fDY,fDZ); //vNewVec=VectorNormalize(vNewVec); if (GetArea(oLead)!=GetArea(oMe)) { // jump to leader AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,JumpToObject(oLead)); } // jump to leader else { // same area lRecon=Location(GetArea(oMe),vNewVec,fFacing); AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionMoveToLocation(lRecon,nRun)); } // same area } // valid leader } // was near object when recon initiated else { // cannot recon on that unit - prevent cheating if(GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I do not see that recon leader here. I therefor can no longer recon.")); SetLocalInt(oMe,"nMState",0); SetLocalInt(oMe,"nSState",0); } // cannot recon on that unit - prevent cheating } // fnRecon() void fnBurrow() { // dig into the ground and wait object oMe=OBJECT_SELF; object oBurrow=GetLocalObject(oMe,"oDest"); int nSState=GetLocalInt(oMe,"nSState"); string sID=GetLocalString(oMe,"sTeamID"); object oWP=GetWaypointByTag(sID+"_LIMBO"); float fDist; int nC; int nEnemy=FALSE; switch (nSState) { // burrow switch case 0: { // play animation - digging AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,9.0)); SetLocalInt(oMe,"nSState",1); break; } // play animation - digging case 1: { // place scorch mark + dig AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,9.0)); oBurrow=CreateObject(OBJECT_TYPE_PLACEABLE,"rtsa_burrow",GetLocation(oMe),FALSE); SetLocalObject(oMe,"oDest",oBurrow); SetLocalInt(oMe,"nSState",2); break; } // place scorch mark + dig case 2: { // teleport to limbo AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,JumpToObject(oWP)); SetLocalInt(oMe,"nSState",3); break; } // teleport to limbo case 3: { // wait for enemies nC=1; oWP=GetNearestObject(OBJECT_TYPE_CREATURE,oBurrow,nC); fDist=GetDistanceBetween(oWP,oBurrow); while(fDist<10.1&&oWP!=OBJECT_INVALID&&nEnemy==FALSE) { // look for enemies if (GetIsEnemy(oWP)==TRUE) nEnemy=TRUE; else { // continue looking nC++; oWP=GetNearestObject(OBJECT_TYPE_CREATURE,oBurrow,nC); fDist=GetDistanceBetween(oWP,oBurrow); } // continue looking } // look for enemies if (nEnemy==TRUE) { // enemy time AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,JumpToObject(oBurrow)); DestroyObject(oBurrow,2.0); SetLocalInt(oMe,"nSState",0); } // enemy time break; } // wait for enemies } // burrow switch } // fnBurrow() void fnDestroyObject() { // Destroy object object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oDest"); float fDist=GetDistanceToObject(oDest); int nErr; if (GetArea(oDest)!=GetArea(oMe)) { // different area nErr=fnMovePath(oDest,TRUE); if (nErr==-1) { // cannot reach AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy.")); SetLocalInt(oMe,"nMState",0); } // cannot reach } // different area else { // same area if (fDist>3.0) { // too far away nErr=fnMoveToDestination(oDest,TRUE); if (nErr==-1) { // cannot reach AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy.")); SetLocalInt(oMe,"nMState",0); } // cannot reach } // too far away else { // close enough if (GetPlotFlag(oDest)==TRUE) { // plot item AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,SpeakString("I cannot possibly destroy that object.")); SetLocalInt(oMe,"nMState",0); } // plot item else { // attack it AssignCommand(oMe,ActionAttack(oDest)); } // attack it } // close enough } // same area } // fnDestroyObject() void fnOpenObject() { // Destroy object object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oDest"); float fDist=GetDistanceToObject(oDest); int nErr; if (GetArea(oDest)!=GetArea(oMe)) { // different area nErr=fnMovePath(oDest,TRUE); if (nErr==-1) { // cannot reach AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy.")); SetLocalInt(oMe,"nMState",0); } // cannot reach } // different area else { // same area if (fDist>3.0) { // too far away nErr=fnMoveToDestination(oDest,TRUE); if (nErr==-1) { // cannot reach AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy.")); SetLocalInt(oMe,"nMState",0); } // cannot reach } // too far away else { // close enough if (GetLocked(oDest)==TRUE) { // attempt to unlock nErr=d20()+GetSkillRank(SKILL_OPEN_LOCK,oMe); if (nErr>=GetLockUnlockDC(oDest)) { // open the lock AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,3.0)); AssignCommand(oMe,ActionDoCommand(SetLocked(oDest,FALSE))); AssignCommand(oMe,ActionDoCommand(AssignCommand(oDest,SpeakString("*click*")))); } // open the lock } // attempt to unlock else { // open the object AssignCommand(oMe,ActionOpenDoor(oDest)); AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nMState",0))); } // open the object } // close enough } // same area } // fnOpenObject() void fnDie() { // self terminate object oMe=OBJECT_SELF; int nMHP=GetMaxHitPoints(oMe); effect eDie; nMHP=nMHP*2; eDie=EffectDamage(nMHP); ApplyEffectToObject(DURATION_TYPE_INSTANT,eDie,oMe,1.0); } // fnDie() void fnRetreat() { // flee to oRETREAT location or sID_START object oMe=OBJECT_SELF; int nParm=GetLocalInt(oMe,"nParm"); // previous run state int nParm2=GetLocalInt(oMe,"nParm2"); // previous aggression state int nSState=GetLocalInt(oMe,"nSState"); object oDest=GetLocalObject(oMe,"oDest"); object oMod=GetModule(); string sID=GetLocalString(oMe,"sTeamID"); switch (nSState) { // retreat switch case 0: { // determine retreat location oDest=GetLocalObject(oMod,"o"+sID+"Retreat"); if (oDest==OBJECT_INVALID) oDest=GetWaypointByTag(sID+"_START"); SetLocalObject(oMe,"oDest",oDest); nParm=GetLocalInt(oMe,"nRun"); SetLocalInt(oMe,"nParm",nParm); nParm2=GetLocalInt(oMe,"nAggression"); SetLocalInt(oMe,"nParm2",nParm2); SetLocalInt(oMe,"nSState",1); SetLocalInt(oMe,"nRun",TRUE); SetLocalInt(oMe,"nAggression",1); break; } // determine retreat location case 1: { // retreat nParm=fnMovePath(oDest,TRUE); if (nParm==1||nParm==-1) { // arrived SetLocalInt(oMe,"nSState",2); } // arrived break; } // retreat case 2: { // set back to original behavior SetLocalInt(oMe,"nRun",nParm); SetLocalInt(oMe,"nAggression",nParm2); SetLocalInt(oMe,"nMState",0); break; } // set back to original behavior } // retreat switch } // fnRetreat() void fnSleep() { // sleep object oMe=OBJECT_SELF; int nPrev=GetLocalInt(oMe,"nPrev"); int nCHP=GetCurrentHitPoints(oMe); int nMHP=GetMaxHitPoints(oMe); int nDif=nMHP-nCHP; effect eDmg; nDif=nDif-1; if (GetAbilityModifier(ABILITY_CONSTITUTION,oMe)>0) nDif=nDif-GetAbilityModifier(ABILITY_CONSTITUTION,oMe); if (nDif<1) nDif=0; if (GetLocalInt(oMe,"nSState")==0) { SetLocalInt(oMe,"nRestTime",GetTimeHour()); SetLocalInt(oMe,"nSState",1); } eDmg=EffectDamage(nDif); ActionRest(); if (nDif>0) ActionDoCommand(ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oMe,1.0)); ActionDoCommand(SetLocalInt(oMe,"nMState",nPrev)); } // fnSleep() void fnPatrol() { // 4 point patrol system object oMe=OBJECT_SELF; int nParm=GetLocalInt(oMe,"nParm"); // current patrol point object oDest=GetLocalObject(oMe,"oDest"); int nSState=GetLocalInt(oMe,"nSState"); int nErr; string sVar; switch (nSState) { // Patrol switch case 0: { // initialize patrol AssignCommand(oMe,ClearAllActions()); if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7) AssignCommand(oMe,SpeakString("I am beginning my patrol.")); SetLocalInt(oMe,"nParm",0); SetLocalInt(oMe,"nSState",1); break; } // initialize patrol case 1: { // choose destination if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7&&d4()<3) AssignCommand(oMe,SpeakString("I'm off to my next patrol location.")); nParm++; if (nParm>4) nParm=1; sVar="oPatrol0"+IntToString(nParm); oDest=GetLocalObject(oMe,sVar); if (oDest!=OBJECT_INVALID) { // valid object SetLocalObject(oMe,"oDest",oDest); SetLocalInt(oMe,"nSState",2); } // valid object SetLocalInt(oMe,"nParm",nParm); break; } // choose destination case 2: { // moving nErr=fnMovePath(oDest,TRUE); if (nErr==1||nErr==-1) SetLocalInt(oMe,"nSState",1); break; } // moving } // Patrol switch } // fnPatrol() object fnNoSunPlace() { // find an object to run to that is out of the sun object oRet=OBJECT_INVALID; object oMe=OBJECT_SELF; object oArea=GetArea(oMe); int nC=GetLocalInt(oArea,"nNumTrans"); int nL=1; object oDest; object oWarn; while(nL<=nC&&oRet==OBJECT_INVALID) { // find destination oDest=GetLocalObject(oArea,"oTrans"+IntToString(nL)); oDest=GetTransitionTarget(oDest); if (oDest!=OBJECT_INVALID) { // valid transition oWarn=GetNearestObjectByTag("RTSA_SUN",oMe); if (oWarn==OBJECT_INVALID) return oDest; } // valid transition nL++; } // find destination return oRet; } // fnNoSunPlace() void fnFlee(string sWhere="NA") { // Flee to base, sunlight, and insanity object oMe=OBJECT_SELF; string sID=GetLocalString(oMe,"sTeamID"); int nS=GetLocalInt(oMe,"nSState"); object oDest=GetLocalObject(oMe,"oDest"); int nN; SetLocalInt(oMe,"nRun",TRUE); switch(nS) { // Flee switch case 0: { // find destination if (sWhere=="SUN") { // find place away from the sun oDest=fnNoSunPlace(); if (oDest!=OBJECT_INVALID) { // get moving SetLocalObject(oMe,"oDest",oDest); SetLocalInt(oMe,"nSState",1); } // get moving else { // Move to random door oDest=fnRandomTrans(GetArea(oMe)); oDest=GetTransitionTarget(oDest); SetLocalObject(oMe,"oDest",oDest); SetLocalInt(oMe,"nSState",1); } // Move to random door } // find place away from the sun else { // insane oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,d20()); if (oDest!=OBJECT_INVALID) { // found one oDest=GetTransitionTarget(oDest); if (oDest!=OBJECT_INVALID) { // works oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oDest,d4()); if (oDest!=OBJECT_INVALID) { // found a target SetLocalObject(oMe,"oDest",oDest); SetLocalInt(oMe,"nSState",1); } // found a target } // works } // found one } // insane break; } // find destination case 1: { // move to destination nN=fnMovePath(oDest,TRUE); if (nN==-1) { // error SetLocalInt(oMe,"nSState",0); } // error else if (nN==1) { // arrived if (sWhere=="SUN") { // out of the sunlight if (GetNearestObjectByTag("RTSA_SUN",oMe)!=OBJECT_INVALID) SetLocalInt(oMe,"nMState",0); else { SetLocalInt(oMe,"nMState",0); SetLocalInt(oMe,"nSState",0); } } // out of the sunlight else { SetLocalInt(oMe,"nSState",1); } } // arrived break; } // move to destination } // Flee switch } // fnFlee()