HoS_PRC8/_mod/_module/nss/rts_ai_raid.nss

556 lines
21 KiB
Plaintext
Raw Normal View History

2024-11-25 19:36:07 -05:00
//////////////////////////////////////////////////////////////////
// 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)<GetMaxHitPoints(oAlly))
{ // heal?
if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS)>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()