////////////////////////////////////////////////////////////////// // rts_ai_raid - This is the raid AI command set //---------------------------------------------------------------- // By Deva Bryson Winblood. 12/01/2003 ////////////////////////////////////////////////////////////////// #include "rts_wp_header" #include "rts_header" void fnBuffUp(); // cast any buffing spells void fnStealth(); // cast invis or other spells void fnAntiStuck(); // Why am I standing here up on this roof top? void fnConsolidate(object oMe,string sID,int nMS,string sTTR); void fnDeconsolidate(object oMe); void main() { object oMe=OBJECT_SELF; object oMod=GetModule(); int nState=GetLocalInt(oMe,"nSState"); int nParm=GetLocalInt(oMe,"nParm"); object oH; object oDest=GetLocalObject(oMe,"oDestWP"); float fDist; int nHas=GetLocalInt(oMe,"nHasRaidGoods"); string sDID=GetLocalString(oMe,"sTeamToRaid"); string sID=GetLocalString(oMe,"sTeamID"); int nRun=GetLocalInt(oMe,"nRun"); object oLeader=GetLocalObject(oMod,"oTeamLead"+sID); int nC; int nMethod=0; string sMsg; object oItem; object oDestA=GetWaypointByTag(sDID+"_START"); object oAlly=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); object oEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); object oFEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY); object oFPC=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC); int bConsolidationLeader=GetLocalInt(oMe,"bConsolidationLeader"); if ((oFPC==OBJECT_INVALID||GetDistanceBetween(oFPC,oMe)>45.0)&&(oFEnemy==OBJECT_INVALID||GetDistanceBetween(oMe,oFEnemy)>50.0)&&GetArea(oMe)!=GetArea(oDestA)) { // possibly consolidate forces fnConsolidate(oMe,sID,GetLocalInt(oMe,"nMState"),sDID); } // possibly consolidate forces else if (bConsolidationLeader==TRUE) { // deconsolidate forces fnDeconsolidate(oMe); } // deconsolidate forces if (sID=="SPID") nMethod=3; else if (sID=="DWF") nMethod=2; else if (sID=="UNC") nMethod=1; else if (sID=="UND") nMethod=3; if (GetLocalInt(oMod,GetResRef(oMe)+"_light")==2) nMethod=4; // light fatal switch(nState) { // main switch case 0: { // initialize raid SetAILevel(oMe,AI_LEVEL_NORMAL); SetLocalInt(oMe,"nSState",1); break; } // initialize raid case 1: { // travel to enemy lair oH=GetObjectByTag(sDID+"_START"); if (GetArea(oH)!=GetArea(oMe)) { // path oH=fnPathNextDestination(GetArea(oMe),sDID,nMethod); if(fDist>0.5||GetArea(oH)!=GetArea(oMe)&&GetCurrentAction(oMe)!=ACTION_MOVETOPOINT) { AssignCommand(oMe,ActionMoveToObject(oH,nRun,1.0)); } } // path else { // arrived SetLocalInt(oMe,"nSState",2); } // arrived fnAntiStuck(); break; } // travel to enemy lair case 2: { // at enemy lair if (nParm==3) fnBuffUp(); else { fnStealth(); } if(nParm==0) SetLocalInt(oMe,"nSState",3); else if (nParm==1) SetLocalInt(oMe,"nSState",4); else if (nParm==2) SetLocalInt(oMe,"nSState",5); else if (nParm==3) SetLocalInt(oMe,"nSState",6); else { SetLocalInt(oMe,"nSState",4); } fnAntiStuck(); break; } // at enemy lair case 3: { // information raid AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,2.0,6.0)); sMsg="I made it to the "+GetName(GetArea(oMe))+" and looked at their units. This is what I noticed"; nC=1; oH=GetNearestObject(OBJECT_TYPE_CREATURE,oMe,nC); while (oH!=OBJECT_INVALID) { //!OI sMsg=sMsg+", "+GetName(oH); nC++; oH=GetNearestObject(OBJECT_TYPE_CREATURE,oMe,nC); } //!OI sMsg=sMsg+". I then left to try to make it back to our lair to report."; oItem=CreateItemOnObject("rtsa_message",oMe); oDest=GetLocalObject(oMod,"oTeamLead"+sID); SetLocalString(oItem,"sMsg",sMsg); SetLocalObject(oItem,"oDest",GetWaypointByTag(sID+"_START")); SetLocalString(oItem,"sTo",GetName(oDest)); SetLocalString(oItem,"sName",GetName(oMe)); SetLocalObject(oMe,"oMsg",oItem); SetLocalInt(oMe,"nSState",10); fnAntiStuck(); break; } // information raid case 4: { // attack raid if (oEnemy==OBJECT_INVALID) { // check for ally to help if (oAlly!=OBJECT_INVALID) { // ally present if (GetMaxHitPoints(oAlly)>GetCurrentHitPoints(oAlly)) { // heal if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oAlly)); } // cast else if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oAlly)); } // cast else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oAlly)); } // cast else if (GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oAlly)); } // cast else if (GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_CRITICAL_WOUNDS,oAlly)); } // cast else if (GetHasSpell(SPELL_HEAL)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEAL,oAlly)); } // cast else if (GetHasSpell(SPELL_HEALING_CIRCLE)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,oAlly)); } // cast else { // seek enemies oH=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20()); if (oH!=OBJECT_INVALID) AssignCommand(oMe,ActionMoveToObject(oH,nRun,4.0)); } // seek enemies } // heal else if (GetMaxHitPoints(oMe)>GetCurrentHitPoints(oMe)) { // I am wounded if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oMe)); } // cast else if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oMe)); } // cast else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oMe)); } // cast else if (GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oMe)); } // cast else if (GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_CRITICAL_WOUNDS,oMe)); } // cast else if (GetHasSpell(SPELL_HEAL)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEAL,oMe)); } // cast else if (GetHasSpell(SPELL_HEALING_CIRCLE)>0) { // cast AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,oMe)); } // cast else { // seek enemies oH=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20()); if (oH!=OBJECT_INVALID) AssignCommand(oMe,ActionMoveToObject(oH,nRun,4.0)); } // seek enemies } // I am wounded else { // seek enemies oH=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20()); if (oH!=OBJECT_INVALID) AssignCommand(oMe,ActionMoveToObject(oH,nRun,4.0)); } // seek enemies } // ally present } // check for ally to help else { // enemy present if (GetRacialType(oEnemy)==RACIAL_TYPE_UNDEAD) { // Turn undead if(GetHasFeat(FEAT_TURN_UNDEAD)==TRUE) { // try to turn undead AssignCommand(oMe,ActionUseFeat(FEAT_TURN_UNDEAD,oMe)); } // try to turn undead } // Turn Undead } // enemy present fnAntiStuck(); break; } // attack raid case 5: { // steal mana raid oH=GetObjectByTag(sDID+"_VAULT"); fDist=GetDistanceBetween(oH,oMe); if (fDist>5.0&&GetCurrentAction()!=ACTION_MOVETOPOINT) { // move AssignCommand(oMe,ActionMoveToObject(oH,nRun,2.0)); } // move else { // near vault if (GetObjectType(oDest)==OBJECT_TYPE_ITEM) { // have targeted an item if (GetItemPossessor(oDest)==oMe) { // I have the object SetLocalInt(oMe,"nHasRaidGoods",TRUE); SetLocalInt(oMe,"nSState",10); } // I have the object else if (GetObjectType(GetItemPossessor(oDest))==OBJECT_TYPE_CREATURE) { // someone else picked it up SetLocalObject(oMe,"oDestWP",OBJECT_INVALID); // look for more } // someone else picked it up else if (GetDistanceBetween(oDest,oMe)>1.2) { if (GetCurrentAction(oMe)!=ACTION_MOVETOPOINT) AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0)); } else { // pick it up AssignCommand(oMe,ActionPickUpItem(oDest)); } // pick it up } // have targeted an item else { // find target oH=GetNearestObjectByTag("MANA_CRYSTAL_5",oMe,1); if (oH==OBJECT_INVALID) oH=GetNearestObjectByTag("MANA_CRYSTAL_2",oMe,1); if (oH==OBJECT_INVALID) oH=GetNearestObjectByTag("MANA_CRYSTAL_1",oMe,1); if (oH==OBJECT_INVALID) SetLocalInt(oMe,"nSState",10); // no mana to steal if (oH!=OBJECT_INVALID) SetLocalObject(oMe,"oDestWP",oH); } // find target } // near vault fnAntiStuck(); break; } // steal mana raid case 6: { // steal gold raid oH=GetObjectByTag(sDID+"_CHEST"); if (oH==OBJECT_INVALID) oH=GetObjectByTag(sDID+"_TAXES"); fDist=GetDistanceBetween(oH,oMe); if (fDist>2.0&&GetCurrentAction()!=ACTION_MOVETOPOINT) { // move AssignCommand(oMe,ActionMoveToObject(oH,nRun,1.0)); } // move else if (fDist<2.0&&GetArea(oH)==GetArea(oMe)) { // steal from chest if (GetIsTrapped(oH)==TRUE) { // trapped if (GetHasSkill(SKILL_DISABLE_TRAP,oMe)==TRUE) { // disarm AssignCommand(oMe,ActionUseSkill(SKILL_DISABLE_TRAP,oH)); } // disarm else { // cannot disarm AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,3.0)); AssignCommand(oMe,ActionInteractObject(oH)); } // cannot disarm } // trapped else { // not trapped AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,3.0)); AssignCommand(oMe,ActionInteractObject(oH)); oItem=GetFirstItemInInventory(oH); while(oItem!=OBJECT_INVALID) { if (GetResRef(oItem)=="nw_it_gold001") { // take gold SetLocalInt(oMe,"nHasRaidGoods",TRUE); nC=GetItemStackSize(oItem); DestroyObject(oItem); oItem=CreateItemOnObject("nw_it_gold001",oMe,nC); SetLocalInt(oMe,"nSState",10); } // take gold oItem=GetNextItemInInventory(oH); } } // not trapped SetLocalInt(oMe,"nSState",10); } // steal from chest fnAntiStuck(); break; } // steal gold raid case 10: { // return home oH=GetObjectByTag(sID+"_START"); if (GetArea(oH)!=GetArea(oMe)) { // path oH=fnPathNextDestination(GetArea(oMe),sID,nMethod); if (GetCurrentAction(oMe)!=ACTION_MOVETOPOINT) AssignCommand(oMe,ActionMoveToObject(oH,nRun,8.0)); } // path else { // arrived SetLocalInt(oMe,"nSState",11); } // arrived fnAntiStuck(); break; } // return home case 11: { // deliveries if (nParm==0) { // message oItem=GetLocalObject(oMe,"oMsg"); if (GetItemPossessor(oItem)==oMe) { // drop it AssignCommand(oMe,ActionPutDownItem(oItem)); } // drop it else { SetLocalInt(oMe,"nSState",12); DeleteLocalObject(oMe,"oMsg"); } } // message else if (nParm==2) { // mana oH=GetObjectByTag(sID+"_VAULT"); oItem=GetLocalObject(oMe,"oDestWP"); fDist=GetDistanceBetween(oH,oMe); if (fDist>2.0) { // move to vault if (GetCurrentAction()!=ACTION_MOVETOPOINT) AssignCommand(oMe,ActionMoveToObject(oH,nRun,1.0)); } // move to vault else { // deposit mana if (GetItemPossessor(oItem)==oMe) { // move away and try again AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionMoveAwayFromObject(oH,TRUE,8.0)); } // move away and try again else { SendMessageToPC(oLeader,GetName(oMe)+" deposited stolen mana into your mana vault."); SetLocalInt(oMe,"nSState",12); } } // deposit mana } // mana else if (nParm==3) { // gold oH=GetObjectByTag(sID+"_CHEST"); nC=GetGold(oMe); TakeGoldFromCreature(nC,oMe,TRUE); oItem=CreateItemOnObject("nw_it_gold001",oH,nC); SendMessageToPC(oLeader,GetName(oMe)+" deposited "+IntToString(nC)+" stolen gold into your tax chest."); SetLocalInt(oMe,"nSState",12); } // gold else { // SetLocalInt(oMe,"nSState",12); } // fnAntiStuck(); break; } // deliveries case 12: { // done SetAILevel(oMe,AI_LEVEL_DEFAULT); SetLocalInt(oMe,"nMState",0); SetLocalInt(oMe,"nSState",0); DeleteLocalObject(oMe,"oDestWP"); break; } // done default: break; } // main switch } /////////////// // Functions /////////////// void fnBuffUp() { // cast buff spells if have any object oMe=OBJECT_SELF; object oAlly=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); object oEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); if (GetHasSpell(SPELL_STONESKIN)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_STONESKIN,oMe)); } // else if (GetHasSpell(SPELL_BARKSKIN)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_BARKSKIN,oMe)); } // else if (GetHasSpell(SPELL_GLOBE_OF_INVULNERABILITY)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_GLOBE_OF_INVULNERABILITY,oMe)); } // else if (GetHasSpell(SPELL_ETHEREAL_VISAGE)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_ETHEREAL_VISAGE,oMe)); } // else if (GetHasSpell(SPELL_GHOSTLY_VISAGE)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_GHOSTLY_VISAGE,oMe)); } // else if (GetHasSpell(SPELL_MAGE_ARMOR)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_MAGE_ARMOR,oMe)); } // if (GetHasSpell(SPELL_SHIELD)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_SHIELD,oMe)); } // if (GetHasSpell(SPELL_BLESS)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_BLESS,oMe)); } // // Nearby friends if (oAlly!=OBJECT_INVALID&&(oEnemy==OBJECT_INVALID||GetDistanceBetween(oEnemy,oMe)>25.0)) { // buff up ally if (GetHasSpell(SPELL_BULLS_STRENGTH)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_BULLS_STRENGTH,oAlly)); } // if (GetCurrentHitPoints(oAlly)0) { // heal AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oAlly)); } // heal else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS)>0) { // heal AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oAlly)); } // heal else if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS)>0) { // heal AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oAlly)); } // heal } // heal? } // buff up ally } // cast buff spells if have any void fnStealth() { // cast stealth spells object oMe=OBJECT_SELF; object oAlly=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); object oEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); if (GetHasSpell(SPELL_INVISIBILITY_SPHERE)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_INVISIBILITY_SPHERE,oMe)); } // else if (GetHasSpell(SPELL_IMPROVED_INVISIBILITY)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_IMPROVED_INVISIBILITY,oMe)); } // else if (GetHasSpell(SPELL_INVISIBILITY)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_INVISIBILITY,oMe)); } // if (GetHasSpell(SPELL_HASTE)>0) { // AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HASTE,oMe)); } // } // fnStealth() void fnAntiStuck() { // this function makes sure to get the NPC moving if they have not moved in // quite awhile object oMe=OBJECT_SELF; float fStoredX=GetLocalFloat(oMe,"fStoredX"); float fStoredY=GetLocalFloat(oMe,"fStoredY"); object oWP; int nSC=GetLocalInt(oMe,"nStuckCount"); vector vPos=GetPosition(oMe); if (vPos.x!=fStoredX||vPos.y!=fStoredY) { // not stuck SetLocalFloat(oMe,"fStoredX",vPos.x); SetLocalFloat(oMe,"fStoredY",vPos.y); DeleteLocalInt(oMe,"nStuckCount"); } // not stuck else if (vPos.x==fStoredX&&vPos.y==fStoredY) { // might be stuck nSC++; if (nSC>5) { // get unstuck oWP=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d6()); if (oWP==OBJECT_INVALID) oWP=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d4()); if (oWP==OBJECT_INVALID) oWP=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,d4()); if (oWP==OBJECT_INVALID) oWP=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d4()); if (oWP==OBJECT_INVALID) { // go home oWP=GetWaypointByTag(GetLocalString(oMe,"sTeamID")+"_START"); } // go home if (oWP!=OBJECT_INVALID&&GetIsInCombat(oMe)==FALSE&&IsInConversation(oMe)==FALSE) { AssignCommand(oMe,ClearAllActions(TRUE)); AssignCommand(oMe,JumpToObject(oWP)); } } // get unstuck else if (GetIsInCombat(oMe)==FALSE) { SetLocalInt(oMe,"nStuckCount",nSC); } else { // not stuck because, in combat DeleteLocalInt(oMe,"nStuckCount"); } // not stuck because, in combat } // might be stuck } // fnAntiStuck() void fnConsolidate(object oMe,string sID,int nMS,string sTTR) { // consolidate object oCL=GetWaypointByTag(sID+"_HOLDING"); int nC=1; int nCD=0; object oF=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,nC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND); float fDist=GetDistanceBetween(oMe,oF); int nSS; int nMS; string sDID; while(oF!=OBJECT_INVALID&&fDist<70.0) { // look at friends within 40 meters nSS=GetLocalInt(oF,"nSState"); nMS=GetLocalInt(oF,"nMState"); sDID=GetLocalString(oF,"sTeamToRaid"); if (GetLocalInt(oF,"bConsolidationLeader")==FALSE) { // not a consolidation leader if (nMS==17&&nSS<3&&sDID==sTTR&&GetStringLength(sDID)>0) { // consolidate this unit AssignCommand(oF,ClearAllActions(TRUE)); SetLocalInt(oF,"nSState",0); AssignCommand(oF,JumpToObject(oCL)); DelayCommand(2.0,SetAILevel(oF,AI_LEVEL_VERY_LOW)); DelayCommand(2.5,SetCommandable(FALSE,oF)); SetLocalObject(oF,"oConsolidationLeader",oMe); nCD++; SetLocalObject(oMe,"oConsolidated"+IntToString(nCD),oF); } // consolidate this unit } // not a consolidation leader nC++; oF=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,nC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND); fDist=GetDistanceBetween(oMe,oF); } // look at friends within 40 meters if (nCD>0) SetLocalInt(oMe,"bConsolidationLeader",TRUE); } // fnConsolidate() void fnDeconsolidate(object oMe) { // deconsolidate int nC=1; object oF=GetLocalObject(oMe,"oConsolidated"+IntToString(nC)); while(oF!=OBJECT_INVALID) { // bring consolidated forces back out SetCommandable(TRUE,oF); SetAILevel(oF,AI_LEVEL_NORMAL); DelayCommand(0.1,AssignCommand(oF,ClearAllActions())); DelayCommand(0.2,AssignCommand(oF,JumpToObject(oMe))); SetLocalInt(oF,"nSState",0); DeleteLocalObject(oMe,"oConsolidated"+IntToString(nC)); nC++; oF=GetLocalObject(oMe,"oConsolidated"+IntToString(nC)); } // bring consolidated forces back out DeleteLocalInt(oMe,"bConsolidationLeader"); } // fnDeconsolidate()