Updated for NWNEE 37-13. Updated NWNxEE scripts. CODI Core AI tweaks. Added Diamond Golem AI. Full compile. Updated release archive.
196 lines
7.0 KiB
Plaintext
196 lines
7.0 KiB
Plaintext
#include "x2_inc_spellhook"
|
|
#include "prc_inc_combmove"
|
|
#include "inc_utility"
|
|
|
|
// Constants for tracking steps
|
|
const int STEP_SUNBEAM_MOST_POWERFUL = 1;
|
|
const int STEP_TRUE_STRIKE_AND_ATTACK = 2;
|
|
const int STEP_MOVE_TO_NEAREST = 3;
|
|
const int STEP_TRUE_STRIKE_SELF = 4;
|
|
const int STEP_ATTACK_NEAREST = 5;
|
|
const int STEP_SUNBEAM_OR_TRUE_STRIKE = 6;
|
|
|
|
|
|
void DoAwesomeBlow(object oTarget, object oNPC = OBJECT_SELF)
|
|
{
|
|
int nHP = GetCurrentHitPoints(oTarget);
|
|
int nSizeBonus;
|
|
effect eNone;
|
|
|
|
// Apply the VFX
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE), oTarget);
|
|
|
|
PerformAttack(oTarget, oNPC, eNone, 0.0, -4);
|
|
|
|
if (GetLocalInt(oTarget, "PRCCombat_StruckByAttack"))
|
|
{
|
|
int nDC = nHP - GetCurrentHitPoints(oTarget); // This should be the amount caused by the attack
|
|
|
|
if ((PRCGetCreatureSize(oNPC) + nSizeBonus) > PRCGetCreatureSize(oTarget))
|
|
{
|
|
if (!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
_DoBullRushKnockBack(oTarget, oNPC, 10.0);
|
|
|
|
// Apply knockdown effect after the knockback with a slight delay
|
|
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0));
|
|
|
|
// Trigger dust explosion when the target stops moving
|
|
DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DUST_EXPLOSION), oTarget));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function to get the most powerful opponent
|
|
object GetMostPowerfulOpponent(object oCaster)
|
|
{
|
|
float fRadius = 40.0f; // Limit of perception in NWN
|
|
int nShape = SHAPE_SPHERE; // Shape type
|
|
location lCasterLocation = GetLocation(oCaster); // Correct location type
|
|
|
|
object oTarget = GetFirstObjectInShape(nShape, fRadius, lCasterLocation, TRUE);
|
|
object oStrongest = OBJECT_INVALID;
|
|
float fHighestCR = -1.0f;
|
|
|
|
while (oTarget != OBJECT_INVALID)
|
|
{
|
|
// Check if the target is a creature and hostile to the caster
|
|
if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE && GetIsReactionTypeHostile(oTarget, oCaster))
|
|
{
|
|
float fCR = GetChallengeRating(oTarget);
|
|
if (fCR > fHighestCR)
|
|
{
|
|
fHighestCR = fCR;
|
|
oStrongest = oTarget;
|
|
}
|
|
}
|
|
oTarget = GetNextObjectInShape(nShape, fRadius, lCasterLocation, TRUE);
|
|
}
|
|
return oStrongest;
|
|
}
|
|
|
|
// Function to get the weakest enemy
|
|
object GetWeakestEnemy(object oCaster)
|
|
{
|
|
float fRadius = 40.0f; // Limit of perception in NWN
|
|
int nShape = SHAPE_SPHERE; // Shape type
|
|
location lCasterLocation = GetLocation(oCaster); // Correct location type
|
|
|
|
object oTarget = GetFirstObjectInShape(nShape, fRadius, lCasterLocation, TRUE);
|
|
object oWeakest = OBJECT_INVALID;
|
|
float fLowestCR = 9999.0f;
|
|
|
|
while (oTarget != OBJECT_INVALID)
|
|
{
|
|
// Check if the target is a creature and hostile to the caster
|
|
if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE && GetIsReactionTypeHostile(oTarget, oCaster))
|
|
{
|
|
float fCR = GetChallengeRating(oTarget);
|
|
if (fCR < fLowestCR)
|
|
{
|
|
fLowestCR = fCR;
|
|
oWeakest = oTarget;
|
|
}
|
|
}
|
|
oTarget = GetNextObjectInShape(nShape, fRadius, lCasterLocation, TRUE);
|
|
}
|
|
return oWeakest;
|
|
}
|
|
|
|
|
|
// Function to get the nearest enemy
|
|
object GetNearestEnemy(object oCaster)
|
|
{
|
|
object oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
|
return oTarget;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
object oCaster = OBJECT_SELF;
|
|
object oNearestEnemy = GetNearestEnemy(oCaster);
|
|
|
|
// Retrieve or initialize the current step
|
|
int nStep = GetLocalInt(oCaster, "CURRENT_STEP");
|
|
if (nStep == 0)
|
|
{
|
|
nStep = STEP_SUNBEAM_MOST_POWERFUL;
|
|
}
|
|
|
|
switch (nStep) {
|
|
case STEP_SUNBEAM_MOST_POWERFUL:
|
|
{
|
|
// 100% chance to use Sunbeam, if memorized, on the most powerful opponent
|
|
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
|
|
if (oTarget != OBJECT_INVALID && GetHasSpell(SPELL_SUNBEAM, oCaster))
|
|
{
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_SUNBEAM, oTarget));
|
|
}
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_TRUE_STRIKE_AND_ATTACK);
|
|
break;
|
|
}
|
|
case STEP_TRUE_STRIKE_AND_ATTACK:
|
|
{
|
|
// If nearest enemy is within 10 meters, cast True Strike on self & attack nearest enemy
|
|
if (oNearestEnemy != OBJECT_INVALID && GetDistanceToObject(oNearestEnemy) <= 10.0f)
|
|
{
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_TRUE_STRIKE, oCaster));
|
|
AssignCommand(oCaster, ActionAttack(oNearestEnemy));
|
|
}
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_MOVE_TO_NEAREST);
|
|
break;
|
|
}
|
|
case STEP_MOVE_TO_NEAREST:
|
|
{
|
|
// If nearest enemy is over 10 meters away, move to nearest enemy
|
|
if (oNearestEnemy != OBJECT_INVALID && GetDistanceToObject(oNearestEnemy) > 10.0f)
|
|
{
|
|
AssignCommand(oCaster, ActionMoveToObject(oNearestEnemy));
|
|
}
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_TRUE_STRIKE_SELF);
|
|
break;
|
|
}
|
|
case STEP_TRUE_STRIKE_SELF:
|
|
{
|
|
// 100% to cast True Strike on self
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_TRUE_STRIKE, oCaster));
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_ATTACK_NEAREST);
|
|
break;
|
|
}
|
|
case STEP_ATTACK_NEAREST:
|
|
{
|
|
// Attack nearest enemy
|
|
if (oNearestEnemy != OBJECT_INVALID)
|
|
{
|
|
AssignCommand(oCaster, ActionAttack(oNearestEnemy));
|
|
}
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_SUNBEAM_OR_TRUE_STRIKE);
|
|
break;
|
|
}
|
|
case STEP_SUNBEAM_OR_TRUE_STRIKE:
|
|
{
|
|
// 50% to cast Sunbeam, if memorized, on weakest enemy, else cast True Strike
|
|
object oWeakestEnemy = GetWeakestEnemy(oCaster);
|
|
if (Random(2) == 0 && GetHasSpell(SPELL_SUNBEAM, oCaster) && oWeakestEnemy != OBJECT_INVALID)
|
|
{
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_SUNBEAM, oWeakestEnemy));
|
|
}
|
|
else
|
|
{
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_TRUE_STRIKE, oCaster));
|
|
}
|
|
// If under the effects of True Strike, attack nearest enemy, else cast True Strike
|
|
if (GetHasSpellEffect(SPELL_TRUE_STRIKE, oCaster) && oNearestEnemy != OBJECT_INVALID)
|
|
{
|
|
AssignCommand(oCaster, ActionAttack(oNearestEnemy));
|
|
}
|
|
else
|
|
{
|
|
AssignCommand(oCaster, ActionCastSpellAtObject(SPELL_TRUE_STRIKE, oCaster));
|
|
}
|
|
SetLocalInt(oCaster, "CURRENT_STEP", STEP_SUNBEAM_MOST_POWERFUL);
|
|
break;
|
|
}
|
|
}
|
|
} |