HoS_PRC8/_mod/_module/nss/rts_unit_ai.nss
Jaysyn904 04165202c0 Initial upload
Initial upload
2024-11-25 19:36:07 -05:00

1195 lines
40 KiB
Plaintext

////////////////////////////////////////////////////////////////////////////
// Real Time Strategy - NWN - UNIT AI
//==========================================================================
// By Deva Bryson Winblood. 02/24/2003
////////////////////////////////////////////////////////////////////////////
#include "rts_header"
#include "rts_h_moving"
#include "rtsh_multiplay"
#include "antistuck_h"
#include "uc_h"
#include "prc_inc_util"
///////////////// PROTOTYPES ///////////////////////////////////////////////
void fnMainAIRoutine(); // Called if all interruption options are false
void fnRoam(int nS); // Roam about
void fnHarvest(int nS); // Harvest
void fnGuard(int nS); // Guard
void fnAttack(int nS); // Attack
void fnSeek(int nS); // Seek
void fnHeal(int nS); // Heal
void fnUpgrade(); // Upgrade
void fnFollow(object oD);// Follow command
void fnGuardBase(); // Guard The Base
void fnLightSensitive(); // apply sensitivity;
void fnBurning(); // apply burning damage
void fnScout(int nS); // Scout for items of interest
void fnFleeSunlight(); // run for cover at dawn
void fnRecon(); // reconnoiter command
void fnHealSelfNPC(); // healing routine for non-team NPCs
//======================================================[ M A I N ]=========
void main()
{
object oMod=GetModule();
int nDelay=GetLocalInt(oMod,"nAIDelay"); // delay before firing again
object oAttacker=GetLastAttacker(); // who attacked me last
float fDist=0.0;
int nDisableNonEssential=GetLocalInt(oMod,"nDisableNonEssential");
// string sNamer;
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=GetDistanceBetween(oAttacker,OBJECT_SELF);
if (nDisableNonEssential==TRUE) nDelay=nDelay+2; // add 2 seconds to AI processing time to reduce CPU usage
SetLocalInt(OBJECT_SELF,"nLastDelaySec",GetTimeSecond()); // set monitor for HBKICK
//sNamer="["+GetTag(OBJECT_SELF)+"]"+GetName(OBJECT_SELF);
// sNamer=sNamer+" MS:"+IntToString(nMState)+" TIME:"+IntToString(GetTimeSecond());
//SendMessageToPC(GetFirstPC(),sNamer);
if (!IsInConversation(OBJECT_SELF))
{ // !talking
if (fDist==0.0||fDist>20.0)
{ // attacker is not nearby
if ((oEnemy!=OBJECT_INVALID&&nMState!=1)||oEnemy==OBJECT_INVALID)
{ // There is either no enemy near or I am in HARVEST mode
if (GetLocalInt(OBJECT_SELF,"nAIBusy")!=TRUE)
fnMainAIRoutine();
} // There is either no enemy near or I am in HARVEST mode
} // attacker is not nearby
} // !talking
if (fnCheckForLight()>0&&GetNearestObjectByTag("RTS_SURFACE",OBJECT_SELF)!=OBJECT_INVALID)
{ // possible sun problems
if (GetIsDay())
{
if (fnCheckForLight()==1) fnLightSensitive();
else
{
fnBurning();
if (nMState!=13)
{ // flee dumbass
SetLocalInt(OBJECT_SELF,"nMState",13);
SetLocalInt(OBJECT_SELF,"nSState",0);
} // flee dumbass
}
}
else if ((GetIsDawn()||GetIsDay())&&nMState!=5)
{ // flee sunlight
if (nMState!=13)
{ // flee dumbass
SetLocalInt(OBJECT_SELF,"nMState",13);
SetLocalInt(OBJECT_SELF,"nSState",0);
} // flee dumbass
} // flee sunlight
} // possible sun problems
fDist=IntToFloat(nDelay)+(IntToFloat(Random(10))/10.0);
DelayCommand(fDist,ExecuteScript("rts_unit_ai",OBJECT_SELF));
}
//======================================================[ M A I N ]=========
//----------------------------------------- MAIN ROUTINE -------------------
void fnMainAIRoutine()
{ // Process the state machine
int nMState=GetLocalInt(OBJECT_SELF,"nMState"); // main state
int nSState=GetLocalInt(OBJECT_SELF,"nSState"); // sub state
object oDestWP=GetLocalObject(OBJECT_SELF,"oDestWP"); // Destination Waypoint
object oMe=OBJECT_SELF;
object oPer=oPer=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE);
int nCHP=GetCurrentHitPoints(oMe);
string sID=GetLocalString(oMe,"sTeamID");
int nMHP=GetMaxHitPoints(oMe);
float fDist;
if (oPer==OBJECT_INVALID)
{ // I don't see an enemy
// check to see if viable to switch to heal
if (nCHP<(nMHP/2))
{ // 50+% damaged
if (nMState==2||nMState==11||nMState==0)
{ // okay to interrupt
nMState=9; // switch to HEAL
nSState=0;
SetLocalInt(oMe,"nMState",9);
SetLocalInt(oMe,"nSState",0);
} // okay to interrupt
} // 50+% damaged
} // I don't see an enemy
//SendMessageToPC(GetFirstPC(),GetTag(OBJECT_SELF)+"(M:"+IntToString(nMState)+",S:"+IntToString(nSState)+")");
switch(nMState)
{ // main state switch
case 1: { // HARVEST
//SetAILevel(oMe,AI_LEVEL_NORMAL);
//fnHarvest(nSState);
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rts_ai_harvest",OBJECT_SELF);
break;
} // HARVEST
case 2: { // GUARD
//SetAILevel(oMe,AI_LEVEL_LOW);
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
//fnGuard(nSState);
ExecuteScript("rts_ai_guard",oMe);
break;
} // GUARD
case 3: { // ATTACK
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnAttack(nSState);
break;
} // ATTACK
case 4: { // PROTECT
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFollow(oDestWP);
break;
} // PROTECT
case 5: { // FOLLOW
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFollow(oDestWP);
break;
} // FOLLOW
case 6: { // SEEK
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
fnSeek(nSState);
break;
} // SEEK
case 7: { // STAND
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
AssignCommand(oMe,ClearAllActions());
break;
} // STAND
case 8: { // ROAM
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
fnRoam(nSState);
break;
} // ROAM
case 9: { // HEAL
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
if (GetStringLength(sID)>2) fnHeal(nSState);
else
{ // non-team NPC heal
fnHealSelfNPC();
} // non-team NPC heal
break;
} // HEAL
case 10: { // UPGRADE
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnUpgrade();
break;
} // UPGRADE
case 11: { // Guard Base
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
fnGuardBase();
break;
} // Guard Base
case 12: { // Scout
SetAILevel(oMe,AI_LEVEL_NORMAL);
//fnScout(nSState);
ExecuteScript("rts_ai_scout2",OBJECT_SELF);
break;
} // Scout
case 13: { // flee sunlight
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFleeSunlight();
} // flee sunlight
case 14: { // recon
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnRecon();
break;
} // recon
case 16: { // bait
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
break;
} // bait
case 17: { // raid
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_raid_v2",OBJECT_SELF);
break;
} // raid
case 18: { // control point capture - AI
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_cpc",OBJECT_SELF);
break;
} // control point capture - AI
case 19: { // harvester - AI
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_harvester",OBJECT_SELF);
break;
} // harvester - AI
case 20: { // item collector - ai
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_itemcollect",OBJECT_SELF);
break;
} // item collector - ai
case 21: { // guard area
SetAILevel(oMe,AI_LEVEL_DEFAULT);
ExecuteScript("ai_guard",OBJECT_SELF);
break;
} // guard area
case 22: { // scavenger bird
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_sbird",oMe);
break;
} // scavenger bird
case 23: { // Power reservoir Recover
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_powerres",oMe);
break;
} // Power Reservoir Recover
case 24: { // Mine
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("ai_mine",oMe);
break;
} // Mine
case 25: { // Merchant
ExecuteScript("ai_merchant",oMe);
break;
} // Merchant
case 26: { // Merchant Helper
ExecuteScript("ai_merchanth",oMe);
break;
} // Merchant Helper
default: {
if (oPer==OBJECT_INVALID) SetAILevel(oMe,AI_LEVEL_DEFAULT);
else { SetAILevel(oMe,AI_LEVEL_NORMAL); }
break;
}
} // main state switch
} // fnMainAIRoutine()
void fnHealSelfNPC()
{ // try to heal self
object oMe=OBJECT_SELF;
object oItem;
int nMHP=GetMaxHitPoints(oMe);
int nCHP=GetCurrentHitPoints(oMe);
if (nCHP<nMHP)
{ // need some healing
if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS)==TRUE)
ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oMe);
else if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS)==TRUE)
ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oMe);
else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS)==TRUE)
ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oMe);
else if (GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS)==TRUE)
ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oMe);
else if (GetHasSpell(SPELL_HEAL)==TRUE)
ActionCastSpellAtObject(SPELL_HEAL,oMe);
else if (GetHasSpell(SPELL_HEALING_CIRCLE)==TRUE)
ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,oMe);
else if (GetHasSpell(SPELL_MASS_HEAL)==TRUE)
ActionCastSpellAtObject(SPELL_MASS_HEAL,oMe);
else if (GetHasSpell(SPELL_REGENERATE)==TRUE)
ActionCastSpellAtObject(SPELL_REGENERATE,oMe);
else if (GetHasSpell(SPELL_RESTORATION)==TRUE)
ActionCastSpellAtObject(SPELL_RESTORATION,oMe);
else if (GetHasSpell(SPELL_LESSER_RESTORATION)==TRUE)
ActionCastSpellAtObject(SPELL_LESSER_RESTORATION,oMe);
else if (GetItemPossessedBy(oMe,"NW_IT_MEDKIT001")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MEDKIT001");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_HEALINGKIT,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MEDKIT002")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MEDKIT002");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_HEALINGKIT,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MEDKIT003")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MEDKIT003");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_HEALINGKIT,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MEDKIT004")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MEDKIT004");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_HEALINGKIT,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MPOTION001")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MPOTION001");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MPOTION020")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MPOTION020");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MPOTION002")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MPOTION002");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MPOTION003")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MPOTION003");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_CURE_CRITICAL_WOUNDS,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
else if (GetItemPossessedBy(oMe,"NW_IT_MPOTION012")!=OBJECT_INVALID)
{
oItem=GetItemPossessedBy(oMe,"NW_IT_MPOTION012");
DestroyObject(oItem);
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK,1.0,1.0);
ActionCastSpellAtObject(SPELL_HEAL,oMe,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
}
} // need some healing
else
{
SetLocalInt(oMe,"nMState",0);
}
} // fnHealSelfNPC()
void fnRoam(int nS)
{ // Do roaming based on Substate passed
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDestWP");
int nR;
object oWork;
string sID=GetLocalString(oMe,"sTeamID");
object oPC=GetLocalObject(GetModule(),"oTeamLead"+sID);
object oArea=GetArea(oMe);
object oLastAt=GetLocalObject(oMe,"oLastAt");
float fDist;
int nTMI=0;
switch (nS)
{ // states
case 0: { // choose destination
nR=d8();
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Roam) Current Area:"+GetName(oArea)+" [choose destination]");
if (nR==1)
{ // leave area
nR=0;
oWork=fnRandomObject(oArea,OBJECT_TYPE_DOOR);
while((GetTransitionTarget(oWork)==OBJECT_INVALID||GetArea(GetTransitionTarget(oWork))==oLastAt)&&nTMI<MAX_AI_SCAN)
{ // find door to another area
nR++;
if (nR>1) nR=0;
nTMI++;
if (nR==0) oWork=fnRandomObject(oArea,OBJECT_TYPE_DOOR);
else oWork=fnRandomObject(oArea,OBJECT_TYPE_TRIGGER);
} // find door to another area
if (oWork==OBJECT_INVALID) SetLocalObject(oMe,"oLastAt",OBJECT_INVALID);
oWork=GetTransitionTarget(oWork);
if (oWork!=OBJECT_INVALID)
{ //
oWork=fnGetNearTransitionTarget(oWork);
} //
SetLocalObject(oMe,"oLastAt",GetArea(oMe));
if(d10()<2)
{ // make a comment
nR=GetAbilityScore(oMe,ABILITY_INTELLIGENCE);
if (nR>6&&nR<10) ActionSpeakString("Me leave here.");
else if (nR>9&&nR<13) ActionSpeakString("I need to go somewhere else.");
else if (nR>12) ActionSpeakString("I must be away from this region.");
} // make a comment
} // leave area
else
{ // roam in same area
nR=d4();
if (nR<3) oWork=fnRandomObject(oArea,OBJECT_TYPE_WAYPOINT);
else oWork=fnRandomObject(oArea,OBJECT_TYPE_PLACEABLE);
} // roam in same area
oDest=oWork;
//SendMessageToPC(oPC,"["+GetName(oMe)+"] Destination Chosen:"+GetTag(oDest)+" in Area("+GetName(GetArea(oDest))+")");
SetLocalObject(oMe,"oDestWP",oDest);
SetLocalInt(oMe,"nSState",1);
} // choose destination
case 1: { // move to destination
fDist=GetDistanceBetween(oDest,oMe);
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Roam)Moving to:"+GetTag(oDest)+" in area:"+GetName(GetArea(oDest))+" distance:"+FloatToString(fDist));
if ((fDist==0.0&&GetArea(oDest)!=GetArea(oMe))||fDist>4.0)
{ // still a ways to go
nR=fnMoveToDestination(oDest,TRUE);
if (nR==-1)
{ // error
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
SetLocalInt(oMe,"nSState",0); // error choose another destination
} // error
} // still a ways to go
else
{ // should be there
SetLocalInt(oMe,"nSState",0); // choose another destination
} // should be there
break;
} // move to destination
} // states
} // fnRoam()
//---------------------------------------------- GUARD -----------------------
void fnGuard(int nS)
{ // Guard
int nRun=GetLocalInt(OBJECT_SELF,"nRun");
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDestWP");
int nC=0;
int nR;
float fDist;
string sID=GetLocalString(oMe,"sTeamID");
object oMod=GetModule();
object oPC=GetLocalObject(oMod,"oTeamLead"+sID);
//SendMessageToPC(oPC," == fnGuard() ==");
while(oDest==OBJECT_INVALID&&nC<10)
{ // pick random guard point
nC++;
nR=Random(5)+1;
oDest=GetLocalObject(oMod,"oGUARD"+IntToString(nR)+sID);
} // pick random harvest point
if (oDest==OBJECT_INVALID)
oDest=GetLocalObject(oMod,"oGUARD4"+sID);
if (oDest==OBJECT_INVALID)
oDest=GetWaypointByTag(sID+"_VAULT");
if (oDest==OBJECT_INVALID)
SendMessageToPC(GetFirstPC(),"RTS ERROR: Missing Guard point #4 for Team ["+sID+"]");
switch(nS)
{ // main switch
case 0: { // move to guard post
fDist=GetDistanceToObject(oDest);
if (fDist!=-1.0&&fDist<3.5)
{ // already there
SetLocalInt(oMe,"nSState",1);
} // already there
else if (oDest!=OBJECT_INVALID)
fnMoveToDestination(oDest,TRUE);
else if (oDest==OBJECT_INVALID&&GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>9)
{
AssignCommand(oMe,ActionSpeakString("I don't see the guard position anywhere."));
SetLocalInt(oMe,"nMState",11); // Guard the base
}
else if (oDest==OBJECT_INVALID) SetLocalInt(oMe,"nMState",11); // Guard the base
break;
} // Move to guard post
case 1: { // Pick nearby object and move
if (GetCurrentAction(oMe)==ACTION_INVALID)
{ // AI
if (d4()<3)
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_WAYPOINT);
else
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_PLACEABLE);
//SendMessageToPC(GetFirstPC(),"Pick random move:"+GetTag(oDest));
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ASActionMoveToObject(oDest,nRun,1.0));
DelayCommand(8.0,AssignCommand(oMe,ClearAllActions()));
DelayCommand(5.0,SetLocalInt(oMe,"nSState",0));
} // AI
break;
} // Pick nearby object and move
} // main switch
} // fnGuard()
//----------------------------------------------- ATTACK --------------------
void fnAttack(int nS)
{ // Attack
int nRun=GetLocalInt(OBJECT_SELF,"nRun");
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDestWP");
int nC=0;
int nR;
float fDist;
string sID=GetLocalString(oMe,"sTeamID");
object oMod=GetModule();
while(oDest==OBJECT_INVALID&&nC<10)
{ // pick random harvest point
nC++;
nR=Random(5)+1;
oDest=GetLocalObject(oMod,"oATTACK"+IntToString(nR)+sID);
} // pick random harvest point
switch(nS)
{ // main switch
case 0: { // move to guard post
fDist=GetDistanceBetween(oDest,OBJECT_SELF);
if (fDist!=0.0&&fDist<4.0)
{ // already there
SetLocalInt(oMe,"nSState",1);
} // already there
else if (oDest!=OBJECT_INVALID)
fnMoveToDestination(oDest,TRUE);
if (oDest==OBJECT_INVALID&&GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>9)
{
AssignCommand(oMe,ActionSpeakString("I don't see the attack position anywhere."));
}
if (oDest==OBJECT_INVALID) SetLocalInt(oMe,"nMState",11); // Guard the base
break;
} // Move to guard post
case 1: { // Pick nearby object and move
if (GetCurrentAction(oMe)==ACTION_INVALID)
{ // AI
if (d4()<3)
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_WAYPOINT);
else
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_PLACEABLE);
//SendMessageToPC(GetFirstPC(),"Pick random move:"+GetTag(oDest));
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ASActionMoveToObject(oDest,nRun,1.0));
DelayCommand(8.0,AssignCommand(oMe,ClearAllActions()));
DelayCommand(5.0,SetLocalInt(oMe,"nSState",0));
} // AI
break;
} // Pick nearby object and move
} // main switch
} // fnAttack()
void fnSeek(int nS)
{ // Seek
int nState=nS;
object oMe=OBJECT_SELF;
int nRun=GetLocalInt(oMe,"nRun");
object oDest=GetLocalObject(oMe,"oDestWP");
object oArea=GetArea(oMe);
object oWork;
string sID=GetLocalString(oMe,"sTeamID");
object oPC=GetLocalObject(GetModule(),"oTeamLead"+sID);
int nAlt=0;
int nTMI=0;
object oLastAt=GetLocalObject(oMe,"oLastAt");
float fDist;
int nErr;
object oPer;
int nR; // random numbers
int nSeekMethod;
switch(nState)
{ // main state
case 0: { // listen for enemies
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Seek)Area:"+GetName(oArea)+" [listen for enemies]");
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,1.0,2.0));
oPer=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_HEARD_AND_NOT_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE);
if (oPer==OBJECT_INVALID)
{ // OI
SetLocalInt(oMe,"nSState",1);
} // OI
else
{
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>9&&d6()==1) AssignCommand(oMe,ActionSpeakString("I heard something.",TALKVOLUME_WHISPER));
SetLocalObject(oMe,"oDestWP",oPer);
SetLocalInt(oMe,"nSState",3);
}
break;
} // listen for enemies
case 1: { // no enemy - so pick a destination and do some walking
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Seek)Area:"+GetName(oArea)+"[Choose destination]");
nR=d20();
if (nR<19)
{ // leave area
nR=0;
oWork=fnRandomObject(oArea,OBJECT_TYPE_DOOR);
while((GetTransitionTarget(oWork)==OBJECT_INVALID||GetArea(GetTransitionTarget(oWork))==oLastAt)&&nTMI<MAX_AI_SCAN)
{ // find door to another area
nR++;
if (nR>1) nR=0;
nTMI++;
if (nR==0) oWork=fnRandomObject(oArea,OBJECT_TYPE_DOOR);
else oWork=fnRandomObject(oArea,OBJECT_TYPE_TRIGGER);
} // find door to another area
if (oWork==OBJECT_INVALID) SetLocalObject(oMe,"oLastAt",OBJECT_INVALID);
oWork=GetTransitionTarget(oWork);
if (oWork!=OBJECT_INVALID)
{ //
oWork=fnGetNearTransitionTarget(oWork);
SetLocalObject(oMe,"oDestWP",oWork);
} //
SetLocalObject(oMe,"oLastAt",GetArea(oMe));
if(d10()<2)
{ // make a comment
nR=GetAbilityScore(oMe,ABILITY_INTELLIGENCE);
if (nR>6&&nR<10) ActionSpeakString("Me leave here.");
else if (nR>9&&nR<13) ActionSpeakString("I need to go somewhere else.");
else if (nR>12) ActionSpeakString("I must be away from this region.");
} // make a comment
} // leave area
else
{ // roam in same area
nR=d4();
if (nR<3) oWork=fnRandomObject(oArea,OBJECT_TYPE_WAYPOINT);
else oWork=fnRandomObject(oArea,OBJECT_TYPE_PLACEABLE);
} // roam in same area
oDest=oWork;
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Seek)Area:"+GetName(oArea)+"Destination:"+GetTag(oDest)+" in area:"+GetName(GetArea(oDest)));
SetLocalObject(oMe,"oDestWP",oDest);
SetLocalInt(oMe,"nSState",2);
} // no enemy - so pick a destination and do some walking
case 2: { // Move to destination
fDist=GetDistanceBetween(oDest,oMe);
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Seek)Area:"+GetName(oArea)+"Moving to Dest:"+GetTag(oDest)+"/area:"+GetName(GetArea(oDest))+" Dist:"+FloatToString(fDist)+" GD2O:"+FloatToString(GetDistanceToObject(oDest)));
if ((fDist!=0.0&&fDist<=3.0)||(fDist==0.0&&GetArea(oDest)==GetArea(oMe)))
{ // you made it
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
SetLocalInt(oMe,"nSState",0);
} // you made it
else
{ // still moving
nErr=fnMoveToDestination(oDest,TRUE);
if (nErr==-1)
{
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
SetLocalInt(oMe,"nSState",0);
}
} // still moving
break;
} // move to destination
case 3: { // enemy heard/seen
//SendMessageToPC(oPC,"["+GetName(oMe)+"](Seek) An enemy was heard moving towards.");
fDist=GetDistanceBetween(oDest,oMe);
if ((GetArea(oDest)!=GetArea(oMe))||fDist>39.9||GetIsDead(oDest))
{ // they are gone
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
} // they are gone
else
{ // moving
nErr=fnMoveToDestination(oDest,TRUE);
if (nErr==-1)
{
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
SetLocalInt(oMe,"nSState",0);
}
} // moving
break;
} // enemy heard/seen
} // main state
} // Seek
void fnHealThem(object oHeal)
{
int nAM=GetAbilityModifier(ABILITY_CONSTITUTION,oHeal);
if (nAM<1) nAM=0;
effect eHeal=EffectHeal(1+nAM);
SetLocalInt(oHeal,"nHealing",TRUE);
ApplyEffectToObject(DURATION_TYPE_INSTANT,eHeal,oHeal,1.0);
int nCHP=GetCurrentHitPoints(oHeal);
int nMHP=GetMaxHitPoints(oHeal);
if (nMHP>nCHP&&GetLocalInt(oHeal,"nMState")==9)
DelayCommand(30.0,fnHealThem(oHeal));
else
SetLocalInt(oHeal,"nHealing",FALSE);
} // fnHeal
//----------------------------------------------- HEAL ----------------------
void fnHeal(int nS)
{ // Heal
object oMod=GetModule();
int nState=nS;
object oMe=OBJECT_SELF;
string sID=GetLocalString(oMe,"sTeamID");
object oWP=GetWaypointByTag(sID+"_HEAL");
int nCHP=GetCurrentHitPoints(oMe);
int nMHP=GetMaxHitPoints(oMe);
int nErr;
float fDist;
if (oWP==OBJECT_INVALID) ActionSpeakString("There is no waypoint labeled "+sID+"_HEAL!");
if (nMHP==nCHP)
{
nState=0;
SetLocalInt(oMe,"nSState",0);
}
switch(nState)
{ // state
case 0: { // if wounded seek out healing point
if (nCHP<nMHP)
SetLocalInt(oMe,"nSState",1);
else
{ // what to do when healed
PRCForceRest(oMe);
SetLocalInt(oMe,"nMState",2); // Guard
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
} // what to do when healed
break;
} // if wounded seek out healing point
case 1: { // seek out healing area
fDist=GetDistanceBetween(oMe,oWP);
if ((fDist!=0.0&&fDist<8.0)||(fDist==0.0&&GetArea(oMe)==GetArea(oWP)))
{ // close enough
SetLocalInt(oMe,"nSState",2);
} // close enough
else
{
nErr=fnMoveToDestination(oWP,TRUE);
}
break;
} // seek out healing area
case 2: { // heal
if (nCHP==nMHP)
{ // healed
SetLocalInt(oMe,"nSState",0);
SetLocalInt(oMe,"nHealing",FALSE);
} // healed
else
{ // do healing
if(GetLocalInt(oMe,"nHealing")!=TRUE)
fnHealThem(oMe);
ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,4.0);
} // do healing
break;
} // heal
} // state
} // fnHeal()
//----------------------------------------------- UPGRADE -------------------
void fnUpgrade()
{ // Upgrade
object oMe=OBJECT_SELF;
ExecuteScript("rts_up_setup",oMe);
object oMod=GetModule();
string sID=GetLocalString(oMe,"sTeamID");
object oPC=GetLocalObject(oMe,"oUpgradePC");
object oSpeaker=GetLocalObject(oMe,"oSpeaker");
int nS=GetLocalInt(oMe,"nSState");
int nUpTo=GetLocalInt(oMe,"nUpTo");
int nGold;
int nMana;
int nSoul;
object oNew;
string sNID;
int nWork;
location lLoc=GetLocation(oMe);
effect eVFX=EffectVisualEffect(VFX_IMP_HEAD_NATURE);
int nMHP=GetMaxHitPoints(oMe);
int nCHP=GetCurrentHitPoints(oMe);
int nDmg=nMHP-nCHP;
int nN;
int nMe=GetLocalInt(oMe,"nUnitNum");
object oDestWP=GetLocalObject(oMe,"oDestWP");
int nTotalTime=GetLocalInt(oMe,"nBornTime");
int nKills=GetLocalInt(oMe,"nKills");
object oAttacker=GetLastAttacker();
float fDist=GetDistanceBetween(oAttacker,oMe);
effect eDmg=EffectDamage(nDmg);
int nRun=GetLocalInt(oMe,"nRun");
if (oSpeaker!=oPC&&GetIsObjectValid(oSpeaker)) oPC=oSpeaker;
DeleteLocalObject(oMe,"oSpeaker");
DeleteLocalObject(oMe,"oUpgradePC");
switch (nS)
{ // state
case 0: { // initiate upgrade conversation
ActionStartConversation(oPC,"rts_upgrade",TRUE);
break;
} // initiate upgrade conversation
case 2: { // upgrade
if (GetIsDead(oAttacker)||fDist==0.0||fDist>20.0) oAttacker=OBJECT_INVALID;
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVFX,oMe,1.0);
eVFX=EffectCutsceneGhost();
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVFX,oMe,2.0);
eVFX=EffectCutsceneImmobilize();
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVFX,oMe,2.0);
DelayCommand(1.5,DestroyObject(oMe));
nN=GetUnitUpgradeNumber(sID,nMe,nUpTo);
sNID=GetUnitResRef(sID,nN);
oNew=CreateObject(OBJECT_TYPE_CREATURE,sNID,lLoc);
SetLocalInt(oNew,"nUnitNum",nN);
SetLocalInt(oNew,"nRun",nRun);
if (oAttacker!=OBJECT_INVALID)
{ // set last attacker
AssignCommand(oAttacker,ClearAllActions());
AssignCommand(oAttacker,ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oNew,1.0));
}// set last attacker
else
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oNew,1.0);
TakeResourceCost(oPC,nN,1,nMe);
DelayCommand(5.0,SetLocalInt(oNew,"nBornTime",nTotalTime)); // set original time on the upgrade
SetLocalInt(oNew,"nKills",nKills); // Set kills accurate on upgrade
SetLocalObject(oNew,"oDestWP",oDestWP) ; // preserve following, or destination
break;
} // upgrade
} // state
} // fnUpgrade()
//----------------------------------------------- FOLLOW --------------------
void fnFollow(object oD)
{ // follow
object oMe=OBJECT_SELF;
int nFD=GetLocalInt(oMe,"nFollowDist");
float fD=3.0;
float fDist=GetDistanceBetween(oD,oMe);
string sID=GetLocalString(oMe,"sTeamID");
int nRun=GetLocalInt(oMe,"nRun");
int nStray=GetLocalInt(oMe,"nParm");
int bHeld=FALSE;
object oMod=GetModule();
effect eCSP=EffectCutsceneParalyze();
effect eP=EffectParalyze();
effect eT=GetFirstEffect(oMe);
while(!bHeld&&GetIsEffectValid(eT))
{ // check each effect
if (eT==eCSP||eT==eP) bHeld=TRUE;
eT=GetNextEffect(oMe);
} // check each effect
if (nFD==1) fD=7.0;
if (nFD==2) fD=5.0;
if (GetIsDead(oD)||oD==OBJECT_INVALID)
{ // no longer someone to follow
AssignCommand(oMe,ClearAllActions());
SetLocalInt(oMe,"nMState",2); // switch to GUARD mode
SetLocalInt(oMe,"nSState",0);
SetLocalObject(OBJECT_SELF,"oDestWP",GetLocalObject(oMod,"oGUARD5"+sID));
} // no longer someone to follow
else if (GetArea(oD)!=GetArea(oMe))
{ // target is in another area
if (GetTag(GetModule())=="HarvestofSouls")
{ // Harvest of Souls
if (GetTag(GetArea(oD))=="ThePlaneofInBetween")
{ // they are in the place of death
AssignCommand(oMe,ClearAllActions());
SetLocalInt(oMe,"nMState",2); // switch to GUARD mode
SetLocalInt(oMe,"nSState",0);
SetLocalObject(OBJECT_SELF,"oDestWP",GetLocalObject(oMod,"oGUARD5"+sID));
} // they are in the place of death
else if (!bHeld)
{ // jump to them
nStray++;
SetLocalInt(oMe,"nParm",nStray);
if (nStray>2)
{ // jump
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oD));
} // jump
else
{ // run
if (GetDistanceBetween(oMe,oD)>fD||GetArea(oMe)!=GetArea(oD))
{ // move
AssignCommand(oMe,ASActionMoveToObject(oD,TRUE,fD));
} // move
} // run
} // jump to them
} // Harvest of Souls
else if (!bHeld)
{ // teleport to whom you are supposed to follow
nStray++;
SetLocalInt(oMe,"nParm",nStray);
if (nStray>2)
{ // jump
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oD));
} // jump
else
{ // run
if (GetDistanceBetween(oMe,oD)>fD||GetArea(oMe)!=GetArea(oD))
{ // move
AssignCommand(oMe,ASActionMoveToObject(oD,TRUE,fD));
} // move
} // run
} // teleport to whom you are supposed to follow
} // target is in another area
else if (!bHeld)
{ // business as usual
SetLocalInt(oMe,"nParm",0);
if (fDist!=0.0&&fDist>=fD)
{
if (fDist>(fD*2.0)) nRun=TRUE; // RUN
if (GetDistanceBetween(oMe,oD)>fD||GetArea(oMe)!=GetArea(oD))
{ // move
AssignCommand(oMe,ASActionMoveToObject(oD,nRun,fD));
} // move
}
else if (fDist<(fD*0.75))
{ // too close
AssignCommand(oMe,ClearAllActions());
} // too close
} // business as usual
} // fnFollow
int fnNotTransition(object oD)
{ // check for transition
if (GetTransitionTarget(oD)!=OBJECT_INVALID) return TRUE;
return FALSE;
} // fnNotTransition
void fnGuardBase()
{ // Guard Base
object oMe=OBJECT_SELF;
int nS=GetLocalInt(oMe,"nSState");
object oDest=GetLocalObject(oMe,"oDestWP");
string sID=GetLocalString(oMe,"sTeamID");
int nErr;
int nC=0;
float fDist;
object oBase=GetWaypointByTag(sID+"_START");
switch(nS)
{ // main switch
case 0: { // are we in our own base
if (GetDistanceToObject(oBase)!=-1.0)
{ // we're home
nS=1;
SetLocalInt(oMe,"nSState",1);
} // we're home
else
{
nErr=fnMoveToDestination(oBase,TRUE);
}
break;
} // are we in our own base
case 1: { // choose a destination
nC=d12();
if (nC==1)
{ // seek vault
oDest=GetWaypointByTag(sID+"_VAULT");
} // seek vault
else if (nC==2)
{ // seek throne
oDest=GetWaypointByTag(sID+"_START");
} // seek throne
else if (nC==3)
{ // seek heal
oDest=GetWaypointByTag(sID+"_HEAL");
} // seek heal
else if (nC==4)
{ // LD1
oDest=GetWaypointByTag(sID+"_LD1");
} // LD1
else if (nC==5)
{ // LD2
oDest=GetWaypointByTag(sID+"_LD2");
} // LD2
else if (nC==6)
{ // seek random
if (d4()>2)
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20());
else
oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,d20());
} // seek random
else
{ // animate
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,1.0,3.0));
} // animate
//SendMessageToPC(GetFirstPC(),"["+GetName(oMe)+"]Selected Destination:"+GetTag(oDest));
SetLocalObject(oMe,"oDestWP",oDest);
SetLocalInt(oMe,"nSState",2);
} // choose a destination
case 2: { // move to destination
fDist=GetDistanceToObject(oDest);
//SendMessageToPC(GetFirstPC(),"["+GetName(oMe)+"]Moving to Object:"+GetTag(oDest)+" Dist:"+FloatToString(fDist));
if (fDist!=-1.0&&fDist>3.0)
{ // keep moving
nErr=fnMoveToDestination(oDest,TRUE);
/*if (nErr=-1)
{ // error
SendMessageToPC(GetFirstPC(),"nErr==-1 for ["+GetName(oMe)+"]");
SetLocalInt(oMe,"nSState",1);
} */ // error
} // keep moving
else
{ // pick new destination
SetLocalInt(oMe,"nSState",1);
} // pick new destination
break;
} // move to destination
} // main switch
} // fnGuardBase();
void fnLightSensitive()
{ // light sensitivity
float fDur=IntToFloat(GetLocalInt(GetModule(),"nAIDelay"));
effect eAttackD=EffectAttackDecrease(2);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eAttackD,OBJECT_SELF,fDur);
object oMe=OBJECT_SELF;
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>9&&d20()==1)
AssignCommand(oMe,ActionSpeakString("This sunlight is horrible!"));
} // fnLightSensitive()
void fnBurning()
{ // burning in the sun
effect eDmg=EffectDamage(d20(),DAMAGE_TYPE_FIRE,DAMAGE_POWER_PLUS_FIVE);
effect eBurn=EffectVisualEffect(VFX_IMP_FLAME_M);
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,OBJECT_SELF,1.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eBurn,OBJECT_SELF,4.0);
} // fnBurning()
void fnFleeSunlight()
{ // flee the sun
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDestWP");
int nS=GetLocalInt(oMe,"nSState");
float fDist;
int nErr;
switch(nS)
{ // Main switch
case 0: { // speak and set destination
ClearAllActions();
if (d6()<4) ActionSpeakString("The sun is rising and I must seek cover.");
else ActionSpeakString("I can feel the coming of the day and must flee.");
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_DOOR);
if (GetTransitionTarget(oDest)!=OBJECT_INVALID)
{ // test it
oDest=fnExposed(oDest);
} // test it
else
{
oDest=OBJECT_INVALID;
}
if (oDest==OBJECT_INVALID)
{ // check a trigger
oDest=fnRandomObject(GetArea(oMe),OBJECT_TYPE_TRIGGER);
if (GetTransitionTarget(oDest)!=OBJECT_INVALID)
{ // test it
oDest=fnExposed(oDest);
} // test it
else
{
oDest=OBJECT_INVALID;
}
} // check a trigger
SetLocalObject(oMe,"oDestWP",oDest);
if (oDest!=OBJECT_INVALID)
SetLocalInt(oMe,"nSState",1); // move
break;
} // speak and set destination
case 1: { // move
fDist=GetDistanceToObject(oDest);
if (fDist==-1.0||fDist>4.0)
{ // move
SetLocalInt(oMe,"nRun",TRUE);
nErr=fnMoveToDestination(oDest,TRUE);
} // move
else
{ // should be there
SetLocalInt(oMe,"nSState",2);
} // should be there
break;
} // move
case 2: { // wait for dusk - Go to GUARD LAIR at Dusk
if (GetIsDusk()||GetIsNight())
{ // switch to Guard Lair
ClearAllActions();
SetLocalInt(oMe,"nMState",11);
SetLocalInt(oMe,"nSState",0);
} // switch to Guard Lair
else
ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,8.0);
break;
} // wait for dusk - go to GUARD LAIR at Dusk
} // main switch
} // flee the sun
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,"oDestWP"); // 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=GetDistanceBetween(oLead,oMe);
int nReconV=GetLocalInt(oMe,"nRecon");
if (GetIsInCombat(oMe)!=TRUE&&IsInConversation(oMe)!=TRUE)
{ // not talking or fighting
//SendMessageToPC(GetFirstPC(),GetName(oMe)+" called fnRecon()");
if ((fDist!=0.0&&GetArea(oLead)==GetArea(oMe))&&(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;
//SendMessageToPC(GetFirstPC(),"["+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",2); // Go into guard mode
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDestWP",GetLocalObject(oMod,"oGUARD4"+sID));
} // cannot recon on that unit - prevent cheating
} // not fighting or talking
else
{ // fighting or talking
} // fighting or talking
} // fnRecon()