////////////////////////////////////////////////////////////////////////////// // Real Time Strategy - NWN - Header file for some useful functions //=========================================================================== // By Deva Bryson Winblood. 02/24/2003 ////////////////////////////////////////////////////////////////////////////// // FILE: rts_header int fnMoveToDestination(object oWP,int nAS=FALSE,int nInitStack=FALSE); //// int MAX_AI_SCAN = 4; // used to prevent TMI errors int fnCheckForLight() { // fnCheckForLight object oMe=OBJECT_SELF; object oMod=GetModule(); int nSun=GetLocalInt(oMod,GetTag(oMe)+"_light"); return nSun; } // fnCheckForLight int fnArePCsPresent(object oArea) { int nRet=0; object oOb=GetFirstObjectInArea(oArea); if (GetObjectType(oOb)!=OBJECT_TYPE_WAYPOINT) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oOb,1); if (GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oOb,1)!=OBJECT_INVALID) return 1; return nRet; } // fnCountPCsInArea() object fnRandomObject(object oArea,int nType=OBJECT_TYPE_ALL) { object oRet=OBJECT_INVALID; object oTest=GetFirstObjectInArea(oArea); int nC=GetLocalInt(oArea,"nAllObjects"); if (nType==OBJECT_TYPE_PLACEABLE) nC=GetLocalInt(oArea,"nPlaceables"); else if (nType==OBJECT_TYPE_TRIGGER) nC=GetLocalInt(oArea,"nTriggers"); else if (nType==OBJECT_TYPE_DOOR) nC=GetLocalInt(oArea,"nDoors"); else if (nType==OBJECT_TYPE_WAYPOINT) nC=GetLocalInt(oArea,"nWaypoints"); oRet=GetNearestObject(nType,oTest,Random(nC)+1); return oRet; } // fnRandomObject() object fnExposed(object oD) { // return OBJECT_INVALID if has an RTS_SURFACE object oRet=OBJECT_INVALID; object oW; if (GetTransitionTarget(oD)!=OBJECT_INVALID) { oW=GetNearestObjectByTag("RTS_SURFACE",GetTransitionTarget(oD)); if (oW==OBJECT_INVALID) { // flee here oRet=fnRandomObject(GetArea(GetTransitionTarget(oD)),OBJECT_TYPE_PLACEABLE); } // flee here } return oRet; } // fnExposed void fnInitializeStack(object oNPC) { // init the stack int nTop=GetLocalInt(oNPC,"nPSTop"); int nL=1; //SendMessageToPC(GetFirstPC(),"fnInitializeStack was called"); while (nL<=nTop) { DeleteLocalObject(oNPC,"nPSPath"+IntToString(nL)); nL++; } SetLocalInt(oNPC,"nPSTop",0); } // fnInitalizeStack() void fnPush(object oNPC,object oPath) { // push a path on int nTop=GetLocalInt(oNPC,"nPSTop"); nTop++; //SendMessageToPC(GetFirstPC(),"fnPush("+GetName(oNPC)+","+GetName(GetArea(oPath))+") TOP:"+IntToString(nTop)); SetLocalInt(oNPC,"nPSTop",nTop); SetLocalObject(oNPC,"nPSPath"+IntToString(nTop),oPath); } // fnPush object fnPop(object oNPC) { // pop an item off of the stack int nTop=GetLocalInt(oNPC,"nPSTop"); object oRet=OBJECT_INVALID; if (nTop>0) { oRet=GetLocalObject(oNPC,"nPSPath"+IntToString(nTop)); DeleteLocalObject(oNPC,"nPSPath"+IntToString(nTop)); nTop--; SetLocalInt(oNPC,"nPSTop",nTop); } return oRet; } // fnPop() object fnTransitionBetweenAreas(object oArea1,object oArea2) { // find a transition object oRet=OBJECT_INVALID; object oTest=GetFirstObjectInArea(oArea1); oTest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTest,1); if (oTest==OBJECT_INVALID) SendMessageToPC(GetFirstPC(),"RTS ERROR in area "+GetName(oArea1)+" no placeables available for algorithm to use."); int nDoors=GetLocalInt(oArea1,"nDoors"); int nTriggers=GetLocalInt(oArea1,"nTriggers"); int nC=1; object oWork=GetNearestObject(OBJECT_TYPE_DOOR,oTest,nC); object oTarg=GetTransitionTarget(oWork); //SendMessageToPC(GetFirstPC(),"fnTBA("+GetName(oArea1)+","+GetName(oArea2)+"):Test("+GetName(oTest)+") nDoors:"+IntToString(nDoors)+" nTriggers:"+IntToString(nTriggers)); while(oRet==OBJECT_INVALID&&nC<=nDoors) { // test doors if (GetArea(oTarg)==oArea2) oRet=oTarg; nC++; oWork=GetNearestObject(OBJECT_TYPE_DOOR,oTest,nC); oTarg=GetTransitionTarget(oWork); } // test doors if (oRet==OBJECT_INVALID) { // keep looking nC=1; oWork=GetNearestObject(OBJECT_TYPE_TRIGGER,oTest,nC); oTarg=GetTransitionTarget(oWork); while(oRet==OBJECT_INVALID&&nC<=nTriggers) { // test Triggers if (GetArea(oTarg)==oArea2) oRet=oTarg; nC++; oWork=GetNearestObject(OBJECT_TYPE_TRIGGER,oTest,nC); oTarg=GetTransitionTarget(oWork); } // test Triggers } // keep looking return oRet; } //fnTransitionBetweenAreas() object fnGetNearTransitionTarget(object oTransition) { // Get a closeby object for the transition object oRet=OBJECT_INVALID; float fDist; object oTest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTransition,1); fDist=GetDistanceBetween(oTest,oTransition); if (oTest==OBJECT_INVALID||fDist>10.0) { // keep looking oTest=GetNearestObject(OBJECT_TYPE_ITEM,oTransition,1); fDist=GetDistanceBetween(oTest,oTransition); if (oTest==OBJECT_INVALID||fDist>10.0) { // keep looking oTest=GetNearestObject(OBJECT_TYPE_STORE,oTransition,1); fDist=GetDistanceBetween(oTest,oTransition); if (oTest==OBJECT_INVALID||fDist>10.0) { // keep looking oTest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oTransition,1); fDist=GetDistanceBetween(oTest,oTransition); if (oTest==OBJECT_INVALID||fDist>10.0) { // keep looking oRet=fnRandomObject(GetArea(oTransition),OBJECT_TYPE_WAYPOINT); } // keep looking else oRet=oTest; } // keep looking else oRet=oTest; } // keep looking else oRet=oTest; } // keep looking else oRet=oTest; //SendMessageToPC(GetFirstPC(),"fnGetNearTransitionTarget("+GetTag(oTransition)+":area["+GetName(GetArea(oTransition))+"])="+GetTag(oRet)); return oRet; } // fnGetNearTransitionTarget() int fnNotInStack(object oArea) { int nRet=TRUE; int nC=0; int nTop=GetLocalInt(OBJECT_SELF,"nStackTop"); if (nTop>0) { while(nC0) { // there are PCs - aggressive anti-stuck //SendMessageToPC(GetFirstPC(),"Anti-Stuck PCs"); if (nASC>11) { // that did not work - pick a better destination nRet=-1; } // that did not work - pick a better destination else if (nASC>9) { // very stuck - teleport AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionJumpToObject(oDest)); } // very stuck - teleport else if (nASC>4) { // moderately stuck - look for nearby if (oConfused==OBJECT_INVALID) SetLocalObject(oMe,"oConfused",oDest); else if (oConfused!=oDest) nConfused=0; AssignCommand(oMe,ClearAllActions()); oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d12()); AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0)); DelayCommand(8.0,AssignCommand(oMe,ClearAllActions())); nConfused++; if (nConfused>3) nRet=-1; SetLocalInt(oMe,"nConfused",nConfused); } // moderately stuck - look for nearby else { // normal reminder AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0)); } // normal reminder } // there are PCs - aggressive anti-stuck else { // no PCs-- teleport after 10 //SendMessageToPC(GetFirstPC(),"Anti-Stuck NO PCs"); if (nASC>(15-nMR)) { // that did not work - pick a better destination nRet=-1; } // that did not work - pick a better destination else if (nASC>(13-nMR)) { // teleport AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionJumpToObject(oDest)); SetLocalInt(oMe,"nASC",0); } // teleport } // no PCs-- teleport after 10 } // same distance as last time else { // moved SetLocalInt(oMe,"nASC",0); SetLocalFloat(oMe,"fLastDist",fDist); } // moved } // anti-stuck is engaged else { // no anti-stuck AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0)); } // no anti-stuck return nRet; } // fnMoveTo() int fnMoveToDestination(object oWP,int nAS=FALSE,int nInitStack=FALSE) { // Move to Waypoint with Anti-Stuck on/off // nInitStack = do I need to setup the pathing stack int nRet=0; object oMe=OBJECT_SELF; int nPSTop=GetLocalInt(oMe,"nPSTop"); object oArea=GetArea(oMe); object oDArea=GetArea(oWP); object oDest=GetLocalObject(oMe,"oDestWP"); float fDist; object oBinder=GetObjectByTag("RTS_BINDER"); int nPA=GetLocalInt(oMe,"nPathingActive"); if (oWP==OBJECT_INVALID) return -1; if (nInitStack==FALSE&&nPSTop!=0) { // there is stack info to process still if(oDest==oBinder) { // first call //SendMessageToPC(GetFirstPC(),"First Stack Pathing Call"); oDest=fnPop(oMe); SetLocalObject(oMe,"oDestWP",oDest); } // first call if (fnTransitionBetweenAreas(GetArea(oMe),GetArea(oDest))==OBJECT_INVALID) { // not a valid path oDest=fnPop(oMe); SetLocalObject(oMe,"oDestWP",oDest); } // not a valid path fDist=GetDistanceBetween(oDest,oMe); if ((fDist==0.0&&GetArea(oDest)!=oArea)||fDist>7.0) { // still too far away //SendMessageToPC(GetFirstPC(),"Stack Path Dest:"+GetTag(oDest)+" Area:"+GetName(GetArea(oDest))); nRet=fnMoveTo(oDest,nAS); } // still too far away else { // pop an item off the stack oDest=fnPop(oMe); //SendMessageToPC(GetFirstPC(),"Stack Path: Pop off next destination:"+GetTag(oDest)+" Area:"+GetName(GetArea(oDest))); SetLocalObject(oMe,"oDestWP",oDest); nRet=fnMoveTo(oDest,nAS); } // pop an item off the stack } // there is stack info to process still else if (nInitStack==TRUE) { // initialize the stack fnInitializeStack(oMe); SetLocalInt(oMe,"nPathingActive",TRUE); SetLocalObject(oMe,"oDestWP",oBinder); fnBuildPath(oArea,oWP); // build pathing stack backwards from destination } // initialize the stack else if (nPA==FALSE) { // No stack items & not waiting on complex pathing if (oArea==oDArea) { // same area nRet=fnMoveTo(oWP,nAS); if (nRet==-1) { // abort SetLocalObject(oMe,"oDestWP",OBJECT_INVALID); } // abort } // same area else { // different areas oDest=fnTransitionBetweenAreas(oArea,oDArea); if (oDest!=OBJECT_INVALID) { // adjacent areas nRet=fnMoveTo(oDest,nAS); } // adjacent areas else { // no direct connection nRet=fnMoveToDestination(oWP,nAS,TRUE); // initialize stack } // no direct connection } // different areas } // No stack items & not waiting on complex pathing return nRet; } // fnMoveToDestination()