347 lines
8.2 KiB
Plaintext
347 lines
8.2 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Custom Mindflayer AI
|
|
//:: x2_ai_mflayer
|
|
//:: Copyright (c) 2003 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This is the Hordes of the Underdark campaign
|
|
Mini AI run on the mindflayer.
|
|
|
|
It does not use any spells assigned to the
|
|
mindflayer, if you want to make a custom mindflayer
|
|
you need to deactivate this AI by removing the
|
|
approriate variable from your beholder creature
|
|
in the toolset
|
|
|
|
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Georg Zoeller
|
|
//:: Created On: 2003-08-21
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "nw_i0_generic"
|
|
#include "x0_i0_spells"
|
|
#include "x2_inc_switches"
|
|
#include "x2_inc_toollib"
|
|
#include "prc_racial_const"
|
|
|
|
#include "hench_i0_generic"
|
|
|
|
|
|
const int X2_MINDFLAYER_TELEPORT_MAXUSES = 10;
|
|
|
|
|
|
int MFGetTargetConditionSucks(object oTarget)
|
|
{
|
|
// if polymorphed we do not suck
|
|
if (GetHasEffect(EFFECT_TYPE_POLYMORPH, oTarget) == TRUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetHasEffect(EFFECT_TYPE_STUNNED, oTarget) || GetHasEffect(EFFECT_TYPE_PARALYZE, oTarget)
|
|
|| GetHasEffect(VFX_DUR_PARALYZE_HOLD, oTarget) || GetHasEffect(VFX_DUR_PARALYZE_HOLD, oTarget) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// if dazed, try to brainsuck only 30% of the time)
|
|
if (GetHasEffect(EFFECT_TYPE_DAZED, oTarget) && (Random(100)<30) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void MFlayerSuck(object oTarget)
|
|
{
|
|
if (GetDistanceBetween( OBJECT_SELF, oTarget ) < 1.5f)
|
|
{
|
|
ActionMoveAwayFromObject(oTarget, FALSE, 1.5f);
|
|
}
|
|
else
|
|
{
|
|
ActionMoveToObject( oTarget, TRUE, 1.5f);
|
|
}
|
|
ActionDoCommand(SetFacingPoint(GetPositionFromLocation(GetLocation(oTarget))));
|
|
ActionWait(0.5f);
|
|
ActionCastSpellAtObject(716, oTarget,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT);
|
|
}
|
|
|
|
|
|
int MFCheckCreature(object oTarget)
|
|
{
|
|
if (GetCreatureUseItems(oTarget) &&
|
|
!GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT, OBJECT_SELF) &&
|
|
!GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS, OBJECT_SELF) &&
|
|
!GetIsImmune(oTarget, IMMUNITY_TYPE_ABILITY_DECREASE, OBJECT_SELF))
|
|
{
|
|
|
|
// if the target is down below 10 hp and AC is below 23, we go into melee as well
|
|
if (GetCurrentHitPoints(oTarget) > 10 || GetAC(oTarget) >= 23)
|
|
{
|
|
if (MFGetTargetConditionSucks(oTarget))
|
|
{
|
|
__TurnCombatRoundOn(TRUE);
|
|
MFlayerSuck(oTarget);
|
|
__TurnCombatRoundOn(FALSE);
|
|
SetCreatureOverrideAIScriptFinished();
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int MFlayerDoPsionics(object oTarget)
|
|
{
|
|
return TalentSpellAttack(oTarget);
|
|
}
|
|
|
|
|
|
void MFlayClearFleeState()
|
|
{
|
|
DeleteLocalInt(OBJECT_SELF,"X2_MFLAYER_AI_FLEEING");
|
|
}
|
|
|
|
void MFlayClearState()
|
|
{
|
|
if (GetCurrentAction(OBJECT_SELF) == ACTION_ATTACKOBJECT || GetCurrentAction(OBJECT_SELF) == ACTION_MOVETOPOINT )
|
|
{
|
|
ClearAllActions();
|
|
}
|
|
}
|
|
|
|
/*
|
|
int TryToTeleport(object oTargetFrom, int bCloseIn = FALSE)
|
|
{
|
|
int nTeleportCounter = GetLocalInt(OBJECT_SELF,"X2_MINDFLAYER_AI_TELECOUNT");
|
|
|
|
if (nTeleportCounter > X2_MINDFLAYER_TELEPORT_MAXUSES)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
nTeleportCounter ++;
|
|
SetLocalInt(OBJECT_SELF,"X2_MINDFLAYER_AI_TELECOUNT",nTeleportCounter);
|
|
}
|
|
|
|
object oExit;
|
|
|
|
if (bCloseIn)
|
|
{
|
|
oExit = GetNearestObjectByTag("X2_WP_MFLAYER_EXIT",oTargetFrom);
|
|
}
|
|
else
|
|
{
|
|
oExit = GetNearestObjectByTag("X2_WP_MFLAYER_EXIT");
|
|
}
|
|
|
|
if (!GetIsObjectValid(oExit))
|
|
{
|
|
return FALSE;
|
|
}
|
|
float fDist = GetDistanceBetween(oExit,oTargetFrom);
|
|
int bJump;
|
|
|
|
if (bCloseIn)
|
|
{
|
|
if ((fDist >= 8.0f) && (fDist <= 20.0f))
|
|
{
|
|
bJump = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((fDist >= 10.0f) && (fDist <= 40.0f))
|
|
{
|
|
bJump = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bJump)
|
|
{
|
|
if (bCloseIn)
|
|
{
|
|
oExit = GetNearestObjectByTag("X2_WP_MFLAYER_EXIT",oTargetFrom,2);
|
|
}
|
|
else
|
|
{
|
|
oExit = GetNearestObjectByTag("X2_WP_MFLAYER_EXIT",OBJECT_SELF,2);
|
|
}
|
|
|
|
if (!GetIsObjectValid(oExit))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
fDist = GetDistanceBetween(oExit,oTargetFrom);
|
|
if (bCloseIn)
|
|
{
|
|
if ((fDist >= 6.0f) && (fDist <= 15.0f))
|
|
{
|
|
bJump = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((fDist >= 8.0f) && (fDist <= 50.0f))
|
|
{
|
|
bJump = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (bJump)
|
|
{
|
|
if (!GetIsDead(OBJECT_SELF))
|
|
{
|
|
|
|
effect eAppear = EffectDisappearAppear(GetLocation(oExit)) ;
|
|
eAppear = ExtraordinaryEffect(eAppear);
|
|
object oSelf = OBJECT_SELF;
|
|
//effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON);
|
|
//ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oSelf);
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eAppear,oSelf,4.0f);
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
// 1 - Melee
|
|
// 2 - Suck
|
|
int GetMindFlayerTactics(object oTarget)
|
|
{
|
|
int nRet = FALSE;
|
|
|
|
// we go melee against petrified targets
|
|
if (GetHasEffect(EFFECT_TYPE_PETRIFY, oTarget) == TRUE)
|
|
{
|
|
nRet = 1;
|
|
}
|
|
else if ((GetIsPlayableRacialType(oTarget) && MFGetTargetConditionSucks(oTarget) || (GetSubRace(oTarget)== "Tiefling")|| GetRacialType(oTarget) == RACIAL_TYPE_TIEFLING))
|
|
{
|
|
nRet = 2;
|
|
}
|
|
// if the target is down below 10 hp and AC is below 23, we go into melee as well
|
|
else if ( GetCurrentHitPoints(oTarget) < 10 && GetAC(oTarget) < 23)
|
|
{
|
|
nRet = 1;
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
|
|
void main()
|
|
{
|
|
//The following two lines should not be touched
|
|
object oIntruder = GetCreatureOverrideAIScriptTarget();
|
|
ClearCreatureOverrideAIScriptTarget();
|
|
|
|
|
|
SetLocalInt(OBJECT_SELF, "HENCH_USE_MIND_BLAST", TRUE);
|
|
|
|
|
|
|
|
// ********************* Start of custom AI script ****************************
|
|
|
|
|
|
// Here you can write your own AI to run in place of DetermineCombatRound.
|
|
// The minimalistic approach would be something like
|
|
//
|
|
// TalentFlee(oTarget); // flee on any combat activity
|
|
|
|
/* if(GetAssociateState(NW_ASC_IS_BUSY))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GetIsObjectValid(oIntruder) == FALSE)
|
|
oIntruder = bkAcquireTarget();
|
|
|
|
if(BashDoorCheck(oIntruder)) {return;}
|
|
// * BK: stop fighting if something bizarre that shouldn't happen, happens
|
|
if (bkEvaluationSanityCheck(oIntruder, GetFollowDistance()) == TRUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GetIsObjectValid(oIntruder) == FALSE || GetIsDead(oIntruder))
|
|
{
|
|
return; // fall back to default AI because SetCreatureOverrideAIScriptFinished(); wasnt called t cal
|
|
} */
|
|
|
|
|
|
if (MFCheckCreature(oIntruder))
|
|
{
|
|
return;
|
|
}
|
|
|
|
object oCurTarget;
|
|
// location testTargetLoc;
|
|
int curLoopCount = 1;
|
|
oCurTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
|
|
OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN,
|
|
CREATURE_TYPE_IS_ALIVE, TRUE);
|
|
|
|
effect curEffect;
|
|
// testTargetLoc = GetLocation(OBJECT_SELF);
|
|
while (GetIsObjectValid(oCurTarget) && curLoopCount <= 10)
|
|
{
|
|
if (GetDistanceToObject(oCurTarget) > 15.0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (MFCheckCreature(oCurTarget))
|
|
{
|
|
return;
|
|
}
|
|
|
|
curLoopCount ++;
|
|
oCurTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
|
|
OBJECT_SELF, curLoopCount, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN,
|
|
CREATURE_TYPE_IS_ALIVE, TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
int nTactics = GetMindFlayerTactics(oIntruder);
|
|
if (nTactics == 2)
|
|
{
|
|
__TurnCombatRoundOn(TRUE);
|
|
MFlayerSuck(oIntruder);
|
|
__TurnCombatRoundOn(FALSE);
|
|
SetCreatureOverrideAIScriptFinished();
|
|
}
|
|
else
|
|
{
|
|
return; // fall back to default AI because SetCreatureOverrideAIScriptFinished(); wasnt called t cal
|
|
}
|
|
*/
|
|
|
|
}
|