319 lines
7.9 KiB
Plaintext
319 lines
7.9 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Beholder AI and Attack Include
|
|
//:: x2_inc_beholder
|
|
//:: Copyright (c) 2003 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
|
|
Include file for several beholder functions
|
|
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Georg Zoeller
|
|
//:: Created On: August, 2003
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "x0_i0_spells"
|
|
//#include "prc_inc_spells"
|
|
|
|
const int BEHOLDER_RAY_DEATH = 1;
|
|
const int BEHOLDER_RAY_TK = 2;
|
|
const int BEHOLDER_RAY_PETRI= 3;
|
|
const int BEHOLDER_RAY_CHARM = 4;
|
|
const int BEHOLDER_RAY_SLOW = 5;
|
|
const int BEHOLDER_RAY_WOUND = 6;
|
|
const int BEHOLDER_RAY_FEAR = 7;
|
|
|
|
const int BEHOLDER_RAY_DIS = 8;
|
|
const int BEHOLDER_RAY_CHARMP = 9;
|
|
const int BEHOLDER_RAY_SLEEP = 10;
|
|
|
|
struct beholder_target_struct
|
|
{
|
|
object oTarget1;
|
|
int nRating1;
|
|
object oTarget2;
|
|
int nRating2;
|
|
object oTarget3;
|
|
int nRating3;
|
|
int nCount;
|
|
};
|
|
|
|
|
|
|
|
int GetAntiMagicRayMakesSense ( object oTarget );
|
|
void OpenAntiMagicEye ( object oTarget );
|
|
void CloseAntiMagicEye ( object oTarget );
|
|
int BehGetTargetThreatRating ( object oTarget );
|
|
int BehDetermineHasEffect ( int nRay, object oCreature );
|
|
void BehDoFireBeam ( int nRay, object oTarget );
|
|
|
|
struct beholder_target_struct GetRayTargets ( object oTarget );
|
|
|
|
int GetAntiMagicRayMakesSense(object oTarget)
|
|
{
|
|
int bRet = TRUE;
|
|
int nType;
|
|
|
|
effect eTest = GetFirstEffect(oTarget);
|
|
|
|
if (!GetIsEffectValid(eTest))
|
|
{
|
|
int nMag = GetLevelByClass(CLASS_TYPE_WIZARD,oTarget) + GetLevelByClass(CLASS_TYPE_SORCERER,oTarget) + GetLevelByClass(CLASS_TYPE_BARD,oTarget) + GetLevelByClass(CLASS_TYPE_RANGER,oTarget) + GetLevelByClass(CLASS_TYPE_PALADIN,oTarget);
|
|
// at least 3 levels of magic user classes... we better use anti magic anyway
|
|
if (nMag < 4)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (GetIsEffectValid(eTest) && bRet == TRUE )
|
|
{
|
|
nType = GetEffectType(eTest);
|
|
if (nType == EFFECT_TYPE_STUNNED || nType == EFFECT_TYPE_PARALYZE ||
|
|
nType == EFFECT_TYPE_SLEEP || nType == EFFECT_TYPE_PETRIFY ||
|
|
nType == EFFECT_TYPE_CHARMED || nType == EFFECT_TYPE_CONFUSED ||
|
|
nType == EFFECT_TYPE_FRIGHTENED || nType == EFFECT_TYPE_SLOW )
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
eTest = GetNextEffect(oTarget);
|
|
}
|
|
}
|
|
|
|
if (GetHasSpellEffect(727,oTarget)) // already antimagic
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
void OpenAntiMagicEye (object oTarget)
|
|
{
|
|
if (GetAntiMagicRayMakesSense(oTarget))
|
|
{
|
|
ActionCastSpellAtObject(727 , GetSpellTargetObject(),METAMAGIC_ANY,TRUE,0, PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
|
|
}
|
|
}
|
|
|
|
// being a badass beholder, we close our antimagic eye only to attack with our eye rays
|
|
// and then reopen it...
|
|
void CloseAntiMagicEye(object oTarget)
|
|
{
|
|
RemoveSpellEffects (727,OBJECT_SELF,oTarget);
|
|
}
|
|
|
|
|
|
// stacking protection
|
|
int BehDetermineHasEffect(int nRay, object oCreature)
|
|
{
|
|
switch (nRay)
|
|
{
|
|
case BEHOLDER_RAY_FEAR : if (GetHasEffect(EFFECT_TYPE_FRIGHTENED,oCreature))
|
|
return TRUE;
|
|
|
|
case BEHOLDER_RAY_DEATH : if (GetIsDead(oCreature))
|
|
return TRUE;
|
|
|
|
case BEHOLDER_RAY_CHARM: if (GetHasEffect(EFFECT_TYPE_CHARMED,oCreature))
|
|
return TRUE;
|
|
|
|
case BEHOLDER_RAY_SLOW: if (GetHasEffect(EFFECT_TYPE_SLOW,oCreature))
|
|
return TRUE;
|
|
|
|
case BEHOLDER_RAY_SLEEP: if (GetHasEffect(EFFECT_TYPE_SLEEP,oCreature))
|
|
return TRUE;
|
|
|
|
case BEHOLDER_RAY_PETRI: if (GetHasEffect(EFFECT_TYPE_PETRIFY,oCreature))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int BehGetTargetThreatRating(object oTarget)
|
|
{
|
|
if (oTarget == OBJECT_INVALID)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int nRet = 20;
|
|
|
|
if (GetDistanceBetween(oTarget,OBJECT_SELF) <5.0f)
|
|
{
|
|
nRet += 3;
|
|
}
|
|
|
|
nRet += (GetHitDice(oTarget)-GetHitDice(OBJECT_SELF) /2);
|
|
|
|
if (GetPlotFlag(oTarget)) //
|
|
{
|
|
nRet -= 6 ;
|
|
}
|
|
|
|
if (GetMaster(oTarget)!= OBJECT_INVALID)
|
|
{
|
|
nRet -= 4;
|
|
}
|
|
|
|
if (GetHasEffect(EFFECT_TYPE_PETRIFY,oTarget))
|
|
{
|
|
nRet -=10;
|
|
}
|
|
|
|
if (GetIsDead(oTarget))
|
|
{
|
|
nRet = 0;
|
|
}
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
struct beholder_target_struct GetRayTargets(object oTarget)
|
|
{
|
|
|
|
struct beholder_target_struct stRet;
|
|
object oMaster = oTarget;
|
|
object oSumm;
|
|
object oHench1;
|
|
int nMaster;
|
|
int nSumm;
|
|
int nHench1;
|
|
int nCount = 0;
|
|
if (!GetIsPC(oTarget))
|
|
{
|
|
if (GetMaster(oTarget) != OBJECT_INVALID)
|
|
{
|
|
oMaster = GetMaster(oTarget);
|
|
}
|
|
}
|
|
|
|
if (oMaster != OBJECT_INVALID)
|
|
{
|
|
nCount ++;
|
|
nMaster = BehGetTargetThreatRating(oMaster);
|
|
|
|
oSumm = GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMaster);
|
|
if (oSumm != OBJECT_INVALID)
|
|
{
|
|
nSumm = BehGetTargetThreatRating(oSumm);
|
|
nCount ++;
|
|
}
|
|
|
|
object oHench1 = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oMaster,1);
|
|
if (oHench1 != OBJECT_INVALID)
|
|
{
|
|
nHench1 = BehGetTargetThreatRating(oHench1);
|
|
nCount ++;
|
|
}
|
|
}
|
|
|
|
|
|
stRet.oTarget1 = oMaster;
|
|
stRet.nRating1 = nMaster;
|
|
if (oSumm != OBJECT_INVALID)
|
|
{
|
|
stRet.oTarget2 = oSumm;
|
|
stRet.nRating2 = nSumm;
|
|
}
|
|
else
|
|
{
|
|
stRet.oTarget2 = oMaster;
|
|
stRet.nRating2 = nMaster;
|
|
nCount =2;
|
|
}
|
|
|
|
if (nCount ==3)
|
|
{
|
|
stRet.oTarget3 = oHench1;
|
|
stRet.nRating3 = nHench1;
|
|
}
|
|
stRet.nCount = nCount;
|
|
|
|
|
|
return stRet;
|
|
|
|
}
|
|
|
|
|
|
void BehDoFireBeam(int nRay, object oTarget)
|
|
{
|
|
|
|
// don't use a ray if the target already has that effect
|
|
if (BehDetermineHasEffect(nRay,oTarget))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int bHit = TouchAttackRanged(oTarget,FALSE)>0;
|
|
int nProj;
|
|
switch (nRay)
|
|
{
|
|
case BEHOLDER_RAY_DEATH: nProj = 776;
|
|
break;
|
|
case BEHOLDER_RAY_TK: nProj = 777;
|
|
break;
|
|
case BEHOLDER_RAY_PETRI: nProj = 778;
|
|
break;
|
|
case BEHOLDER_RAY_CHARM: nProj = 779;
|
|
break;
|
|
case BEHOLDER_RAY_SLOW: nProj = 780;
|
|
break;
|
|
case BEHOLDER_RAY_WOUND: nProj = 783;
|
|
break;
|
|
case BEHOLDER_RAY_FEAR: nProj = 783;
|
|
break;
|
|
|
|
case BEHOLDER_RAY_DIS: nProj = 785;
|
|
break;
|
|
case BEHOLDER_RAY_CHARMP: nProj = 786;
|
|
break;
|
|
case BEHOLDER_RAY_SLEEP: nProj = 787;
|
|
break;
|
|
|
|
}
|
|
|
|
if (bHit)
|
|
{
|
|
ActionCastSpellAtObject(nProj,oTarget,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE);
|
|
}
|
|
else
|
|
{
|
|
location lFail = GetLocation(oTarget);
|
|
vector vFail = GetPositionFromLocation(lFail);
|
|
|
|
if (GetDistanceBetween(OBJECT_SELF,oTarget) > 6.0f)
|
|
{
|
|
|
|
vFail.x += IntToFloat(Random(3)) - 1.5;
|
|
vFail.y += IntToFloat(Random(3)) - 1.5;
|
|
vFail.z += IntToFloat(Random(2));
|
|
lFail = Location(GetArea(oTarget),vFail,0.0f);
|
|
|
|
}
|
|
//----------------------------------------------------------------------
|
|
// if we are fairly near, calculating a location could cause us to
|
|
// spin, so we use the same location all the time
|
|
//----------------------------------------------------------------------
|
|
else
|
|
{
|
|
vFail.z += 0.8;
|
|
vFail.y += 0.2;
|
|
vFail.x -= 0.2;
|
|
}
|
|
|
|
ActionCastFakeSpellAtLocation(nProj,lFail);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//void main(){} |