PoA_PRC8/_module/nss/diamond_golem_hb.nss
Jaysyn904 ce72b8d120 Updated for NWNEE 37-13
Updated for NWNEE 37-13.  Updated NWNxEE scripts.  CODI Core AI tweaks.  Added Diamond Golem AI.  Full compile.  Updated release archive.
2025-01-10 19:01:12 -05:00

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;
}
}
}