285 lines
10 KiB
Plaintext
285 lines
10 KiB
Plaintext
/////////////////////////////////////////////////////////////////////////////
|
|
// Real Time Strategy - NWN - Heartbeat kicker
|
|
//===========================================================================
|
|
// By Deva Bryson Winblood. 02/24/2003
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/* This heartbeat just makes sure the DelayCommand() for the NPC fired off
|
|
recently. If it has not then it will start it up again */
|
|
// If no AI has been processed for 12 seconds it will launch the script
|
|
#include "antistuck_h"
|
|
|
|
object fnGetCloseTarget(object oMe,float fRange)
|
|
{ // PURPOSE: Get a close target
|
|
object oRet=OBJECT_INVALID;
|
|
object oOb;
|
|
int nN=1;
|
|
oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,nN,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY);
|
|
if (GetDistanceBetween(oOb,oMe)<=fRange) oRet=oOb;
|
|
return oRet;
|
|
} // fnGetCloseTarget()
|
|
|
|
object fnGetFarTarget(object oMe,float fRange)
|
|
{ // PURPOSE: Get a target perceived by allies
|
|
object oRet=OBJECT_INVALID;
|
|
float fDist=1000.0;
|
|
object oFriend;
|
|
object oOb;
|
|
int nF;
|
|
nF=1;
|
|
oFriend=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,nF,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
|
|
while(oFriend!=OBJECT_INVALID&&GetDistanceBetween(oMe,oFriend)<=fRange)
|
|
{ // check perception of friends
|
|
oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oFriend,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY);
|
|
if (GetDistanceBetween(oOb,oMe)<=fRange)
|
|
{ // enemy in range spotted by ally
|
|
if (GetDistanceBetween(oOb,oMe)<fDist)
|
|
{ // closest so far
|
|
oRet=oOb;
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
} // closest so far
|
|
} // enemy in range spotted by ally
|
|
nF++;
|
|
oFriend=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,nF,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
|
|
} // check perception of friends
|
|
return oRet;
|
|
} // fnGetFarTarget()
|
|
|
|
|
|
float fnFacing(vector vMe,vector vDest)
|
|
{ // PURPOSE: Return what facing should be
|
|
float fRet=0.0;
|
|
int nMX=FloatToInt(vMe.x);
|
|
int nMY=FloatToInt(vMe.y);
|
|
int nDX=FloatToInt(vDest.x);
|
|
int nDY=FloatToInt(vDest.y);
|
|
int nNS;
|
|
int nEW;
|
|
if (nMX>nDX) nEW=-1;
|
|
if (nMY>nDY) nNS=-1;
|
|
if (nMX<nDX) nEW=1;
|
|
if (nMY<nDY) nNS=1;
|
|
if (nEW==0&&nNS==1) fRet=0.0;
|
|
else if (nEW==0&&nNS==-1) fRet=180.0;
|
|
else if (nEW==1&&nNS==0) fRet=90.0;
|
|
else if (nEW==-1&&nNS==0) fRet=270.0;
|
|
else if (nEW==1&&nNS==1) fRet=45.0;
|
|
else if (nEW==-1&&nNS==1) fRet=315.0;
|
|
else if (nEW==1&&nNS==-1) fRet=135.0;
|
|
else if (nEW==-1&&nNS==-1) fRet=225.0;
|
|
return fRet;
|
|
} // fnFacing
|
|
|
|
void fnDamage(object oArtillery,object oTarget,location lLoc,int nType)
|
|
{ // PURPOSE: Do damage
|
|
effect eE;
|
|
object oOb;
|
|
int nN;
|
|
if (nType==1)
|
|
{ // ballista
|
|
eE=EffectDamage(d6(3),DAMAGE_TYPE_PIERCING);
|
|
if (GetCreatureSize(oTarget)==CREATURE_SIZE_LARGE||GetCreatureSize(oTarget)==CREATURE_SIZE_HUGE) eE=EffectDamage(d8(3),DAMAGE_TYPE_PIERCING);
|
|
AssignCommand(oArtillery,ApplyEffectToObject(DURATION_TYPE_INSTANT,eE,oTarget));
|
|
} // ballista
|
|
else
|
|
{ // catapult
|
|
nN=1;
|
|
oOb=GetNearestCreatureToLocation(CREATURE_TYPE_IS_ALIVE,TRUE,lLoc,nN);
|
|
while(oOb!=OBJECT_INVALID&&GetDistanceBetweenLocations(lLoc,GetLocation(oOb))<=8.0)
|
|
{ // in range
|
|
eE=EffectDamage(d6(2),DAMAGE_TYPE_FIRE);
|
|
DelayCommand(0.2,AssignCommand(oArtillery,ApplyEffectToObject(DURATION_TYPE_INSTANT,eE,oOb)));
|
|
eE=EffectDamage(d4(),DAMAGE_TYPE_BLUDGEONING);
|
|
DelayCommand(0.2,AssignCommand(oArtillery,ApplyEffectToObject(DURATION_TYPE_INSTANT,eE,oOb)));
|
|
nN++;
|
|
oOb=GetNearestCreatureToLocation(CREATURE_TYPE_IS_ALIVE,TRUE,lLoc,nN);
|
|
} // in range
|
|
} // catapult
|
|
} // fnDamage()
|
|
|
|
void fnFire(object oArtillery,object oTarget, location lLoc,float fRange)
|
|
{ // PURPOSE: Fire artillery
|
|
float fFacing;
|
|
effect eE;
|
|
int nType=GetLocalInt(oArtillery,"nType");
|
|
int bMiss=FALSE;
|
|
int nHit;
|
|
int nRoll;
|
|
fFacing=fnFacing(GetPosition(oArtillery),GetPosition(oTarget));
|
|
fFacing=fFacing+GetLocalFloat(oArtillery,"fFacingOffset");
|
|
AssignCommand(oArtillery,SetFacing(fFacing));
|
|
if (nType==1)
|
|
{ // ballista
|
|
nHit=GetAC(oTarget);
|
|
if (GetHasSpellEffect(SPELL_SHIELD,oTarget)==TRUE) nHit=nHit+5;
|
|
if (GetHasSpellEffect(SPELL_DISPLACEMENT,oTarget)==TRUE) nHit=nHit+4;
|
|
if (GetHasSpellEffect(SPELL_ENTROPIC_SHIELD,oTarget)==TRUE) nHit=nHit+3;
|
|
nRoll=d20()+5;
|
|
if (nRoll<nHit) bMiss=TRUE;
|
|
eE=EffectBeam(VFX_BEAM_CHAIN,oArtillery,BODY_NODE_HAND,bMiss);
|
|
AssignCommand(oArtillery,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eE,oTarget,1.5));
|
|
if (bMiss!=TRUE) DelayCommand(2.0,fnDamage(oArtillery,oTarget,lLoc,nType));
|
|
} // ballista
|
|
else
|
|
{ // catapult
|
|
eE=EffectVisualEffect(VFX_IMP_MIRV_FLAME);
|
|
AssignCommand(oArtillery,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eE,lLoc,3.0));
|
|
eE=EffectVisualEffect(VFX_FNF_FIREBALL);
|
|
DelayCommand(3.1,ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eE,lLoc));
|
|
DelayCommand(3.2,fnDamage(oArtillery,oTarget,lLoc,nType));
|
|
} // catapult
|
|
DeleteLocalInt(oArtillery,"nLoadCount");
|
|
} // fnFire()
|
|
|
|
void main()
|
|
{
|
|
object oMe=OBJECT_SELF;
|
|
object oDeployed=GetLocalObject(oMe,"oDeployed");
|
|
int bDeployed=GetLocalInt(oMe,"bDeployed");
|
|
object oTarget=GetLocalObject(oMe,"oTarget");
|
|
int nMode=GetLocalInt(oMe,"nMState");
|
|
int nS=GetLocalInt(oMe,"nSState");
|
|
string sRes="dwfballista";
|
|
int nLoadCount=GetLocalInt(oDeployed,"nLoadCount");
|
|
float fDistance=GetDistanceBetween(oMe,oTarget);
|
|
float fRange=40.0;
|
|
int nN;
|
|
object oOb;
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
//SendMessageToPC(GetFirstPC(),"ME:'"+GetName(oMe)+"'");
|
|
//SendMessageToPC(GetFirstPC()," DEPLOYED:"+GetName(oDeployed)+" AREA:"+GetName(GetArea(oDeployed)));
|
|
//SendMessageToPC(GetFirstPC()," TARGET:"+GetName(oTarget));
|
|
//SendMessageToPC(GetFirstPC()," MState:"+IntToString(nMode)+" SState:"+IntToString(nS));
|
|
if (GetResRef(oMe)=="dwfupg2")
|
|
{ // catapult
|
|
fRange=80.0;
|
|
sRes="dwfcatapult";
|
|
} // catapult
|
|
if (oDeployed!=OBJECT_INVALID&&bDeployed==TRUE&&nMode!=3)
|
|
{ // artillery is deployed
|
|
if (nLoadCount<2)
|
|
{ // load
|
|
if (GetDistanceBetween(oMe,oDeployed)>2.0&&oDeployed!=OBJECT_INVALID)
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,ASActionMoveToObject(oDeployed,TRUE,1.0));
|
|
} // move
|
|
else
|
|
{ // animate
|
|
AssignCommand(oMe,SetFacingPoint(GetPosition(oDeployed)));
|
|
ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,5.5);
|
|
nLoadCount++;
|
|
SetLocalInt(oDeployed,"nLoadCount",nLoadCount);
|
|
} // animate
|
|
} // load
|
|
else if (oTarget==OBJECT_INVALID||GetIsEnemy(oTarget)==FALSE||GetArea(oTarget)!=GetArea(oMe)||fDistance<10.0||fDistance>fRange)
|
|
{ // look for target
|
|
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,1.0,5.5));
|
|
if (fRange==40.0)
|
|
{ // close only
|
|
oTarget=fnGetCloseTarget(oMe,fRange);
|
|
} // close only
|
|
else
|
|
{ // close then far
|
|
oTarget=fnGetCloseTarget(oMe,fRange);
|
|
if (oTarget==OBJECT_INVALID) oTarget=fnGetFarTarget(oMe,fRange);
|
|
} // close then far
|
|
if (oTarget!=OBJECT_INVALID)
|
|
{ // found
|
|
AssignCommand(oMe,SpeakString("Target sighted"));
|
|
SetLocalObject(oMe,"oTarget",oTarget);
|
|
} // found
|
|
} // look for target
|
|
else
|
|
{ // fire
|
|
AssignCommand(oMe,SpeakString("Fire!!"));
|
|
if (GetResRef(oMe)=="dwfupg1")
|
|
{ // ballista
|
|
AssignCommand(oMe,PlaySound("cb_sh_ballista"));
|
|
} // ballista
|
|
else
|
|
{ // catapult
|
|
AssignCommand(oMe,PlaySound("cb_sh_catapult"));
|
|
} // catapult
|
|
fnFire(oDeployed,oTarget,GetLocation(oTarget),fRange);
|
|
} // fire
|
|
} // artillery is deployed
|
|
else
|
|
{ // artillery is not deployed
|
|
if (nMode==0)
|
|
{ // stand around - wait
|
|
ExecuteScript("nw_c2_default1",oMe);
|
|
} // stand around - wait
|
|
else if (nMode==1)
|
|
{ // follow
|
|
if (GetArea(oTarget)!=GetArea(oMe))
|
|
{ // teleport
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,JumpToObject(oTarget));
|
|
} // teleport
|
|
else if (GetDistanceBetween(oMe,oTarget)>5.0)
|
|
{ // move
|
|
AssignCommand(oMe,ASActionMoveToObject(oTarget,TRUE,4.0));
|
|
} // move
|
|
else
|
|
{ // standard script
|
|
ExecuteScript("nw_c2_default1",oMe);
|
|
} // standard script
|
|
} // follow
|
|
else if (nMode==2)
|
|
{ // deploy
|
|
if (nS==0)
|
|
{ // animate get low
|
|
ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,5.5);
|
|
SetLocalInt(oMe,"nSState",1);
|
|
} // animate get low
|
|
else if (nS==1)
|
|
{ // create artillery
|
|
oDeployed=CreateObject(OBJECT_TYPE_PLACEABLE,sRes,GetLocation(oMe));
|
|
SetLocalObject(oDeployed,"oOwner",oMe);
|
|
SetLocalObject(oMe,"oDeployed",oDeployed);
|
|
SetLocalInt(oMe,"nSState",2);
|
|
} // create artillery
|
|
else
|
|
{ // completed
|
|
SetLocalInt(oMe,"bDeployed",TRUE);
|
|
DeleteLocalInt(oMe,"nSState");
|
|
DeleteLocalInt(oMe,"nMState");
|
|
AssignCommand(oMe,SpeakString("Deployed"));
|
|
} // completed
|
|
} // deploy
|
|
else if (nMode==3)
|
|
{ // pack up
|
|
if (nS==0)
|
|
{ // move to artillery
|
|
if (GetDistanceBetween(oMe,oDeployed)>1.5)
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,ASActionMoveToObject(oDeployed,TRUE,1.0));
|
|
} // move
|
|
else
|
|
{ SetLocalInt(oMe,"nSState",1); }
|
|
} // move to artillery
|
|
else if (nS==1)
|
|
{ // get mid animation
|
|
AssignCommand(oMe,SetFacingPoint(GetPosition(oDeployed)));
|
|
ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,5.5);
|
|
SetLocalInt(oMe,"nSState",2);
|
|
} // get mid animation
|
|
else if (nS==2)
|
|
{ // destroy artillery
|
|
DestroyObject(oDeployed);
|
|
SetLocalInt(oMe,"nSState",3);
|
|
} // destroy artillery
|
|
else
|
|
{ // completed
|
|
DeleteLocalInt(oMe,"nMState");
|
|
DeleteLocalInt(oMe,"nSState");
|
|
DeleteLocalInt(oMe,"bDeployed");
|
|
DeleteLocalObject(oMe,"oDeployed");
|
|
DeleteLocalObject(oMe,"oTarget");
|
|
AssignCommand(oMe,SpeakString("Packed"));
|
|
} // completed
|
|
} // pack up
|
|
} // artillery is not deployed
|
|
}
|