Dodge update

Added Grey Elf as possible RACE prereq for Arcane Archer, Baelnorn, Bladesinger, Champion of Corellon, Eternal Blade & Nightshade.

Added Expeditious Dodge, Midnight Dodge & Desert Wind Dodge as FEATOR prereqs for Mobility, Spring Attack, Sidestep Charge & Quick Staff.

Added Expeditious Dodge, Midnight Dodge & Desert Wind Dodge as FEATOR prereqs for Combat Medic, Duelist, Dwarven Defender, Drunken Master, Master of Nine, Ninja Spy, Sacred Fist, Shou Disciple, Telflammar Shadowlord, Shadowdancer and Spelldancer.

Fixed PnP Shifter prereqs for Shaman class.

Fixed Invisible Needle reserve feat to work per PnP.

Fixed Song of Fury & other Bladesinger abilities to work with one-handed elven blades.

Updated release archive.
This commit is contained in:
Jaysyn904
2024-09-21 09:47:07 -04:00
parent 5072c1db8d
commit 1b043074dc
27 changed files with 448 additions and 333 deletions

View File

@@ -1,46 +1,101 @@
//Spell script for reserve feat Invisible Needle
//prc_reservinvndl
//by ebonfowl
//Dedicated to Edgar, the real Ebonfowl
#include "x2_inc_spellhook"
#include "prc_sp_func"
#include "prc_inc_sp_tch"
#include "prc_add_spell_dc"
// Function to calculate the ranged attack bonus manually
int CalculateRangedAB(object oCaster)
{
int nBAB = GetBaseAttackBonus(oCaster); // Get the base attack bonus of the caster
int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY, oCaster); // Get Dexterity modifier
int nRangedAttackBonus = nBAB + nDexMod; // Ranged attack bonus is BAB + Dexterity modifier
// Check if the caster has Point Blank Shot feat and is within 30 feet of the target
return nRangedAttackBonus;
}
// Function to handle the ranged attack
void ForceNeedleAttack(object oCaster, object oTarget, int nBonus)
{
// Constants
float fRange = FeetToMeters(5.0 * IntToFloat(nBonus)); // Range is 5 feet per spell level
effect eMissile = EffectVisualEffect(VFX_IMP_MIRV);
effect eVis = EffectVisualEffect(VFX_IMP_MAGBLUE);
// Get the distance to the target and check if it's within range
float fDistance = GetDistanceBetween(oCaster, oTarget);
if (fDistance > fRange)
{
SendMessageToPC(oCaster, "Target is out of range.");
return;
}
// Calculate ranged attack bonus
int nRangedAttackBonus = CalculateRangedAB(oCaster);
// Check for Point Blank Shot (feat)
if (GetHasFeat(FEAT_POINT_BLANK_SHOT, oCaster) && fDistance <= FeetToMeters(30.0)) // Within 30 feet for PBS bonus
{
nRangedAttackBonus += 1;
}
// Perform a standard ranged attack roll (not a ranged touch attack)
int nDieRoll = d20(1);
int nAttackRoll = nDieRoll + nRangedAttackBonus;
int nAC = GetAC(oTarget); // Get the target's AC for a normal ranged attack
// Construct the attack roll message in the format of NWN combat log
string sMessage;
string sCasterName = GetName(oCaster);
string sTargetName = GetName(oTarget);
if (nAttackRoll >= nAC)
{
// If the attack hits, deal damage based on the highest force spell level
int nDamage = d4(nBonus); // Deal 1d4 damage per force spell level
// Handle critical hit on a natural 20
if (nDieRoll == 20)
{
nDamage *= 2;
sMessage = PRC_TEXT_LIGHT_BLUE + sCasterName + PRC_TEXT_ORANGE +" attacks " + sTargetName + ": *critical hit* " + "(" + IntToString(nDieRoll) + " + " + IntToString(nRangedAttackBonus) + " = " + IntToString(nAttackRoll) + ")";
}
else
{
sMessage = PRC_TEXT_LIGHT_BLUE + sCasterName + PRC_TEXT_ORANGE +" attacks " + sTargetName + ": *hit* " + "(" + IntToString(nDieRoll) + " + " + IntToString(nRangedAttackBonus) + " = " + IntToString(nAttackRoll) + ")";
}
// Apply the MIRV and damage effect
effect eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_MAGICAL);
// Delay visual effects to simulate missile travel
float fDelay = fDistance / (3.0 * log(fDistance) + 2.0);
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget, 0.0f, FALSE));
DelayCommand(fDelay + 0.1, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget));
DelayCommand(fDelay + 0.2, SendMessageToPC(oCaster, sMessage));
}
else
{
// If the attack misses
sMessage = PRC_TEXT_LIGHT_BLUE + sCasterName + PRC_TEXT_ORANGE + " attacks " + sTargetName + ": *miss* " + "(" + IntToString(nDieRoll) + " + " + IntToString(nRangedAttackBonus) + " = " + IntToString(nAttackRoll) + ")";
SendMessageToPC(oCaster, sMessage);
}
}
void main()
{
//Declare major variables ( fDist / (3.0f * log( fDist ) + 2.0f) )
// Declare major variables
object oPC = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
int nBonus = GetLocalInt(oPC, "InvisibleNeedleBonus");
int nDamage = d4(nBonus);
int nAttack = GetAttackRoll(oTarget, oPC, OBJECT_INVALID);
effect eMissile = EffectVisualEffect(VFX_IMP_MIRV);
effect eVis = EffectVisualEffect(VFX_IMP_MAGBLUE);
float fDist = GetDistanceBetween(oPC, oTarget);
float fDelay = fDist/(3.0 * log(fDist) + 2.0);
float fDelay2, fTime;
fTime = fDelay;
fDelay2 += 0.1;
fTime += fDelay2;
if (!GetLocalInt(oPC, "InvisibleNeedleBonus"))
{
FloatingTextStringOnCreature("You do not have a spell available of adequate level or type", oPC, FALSE);
return;
}
//Do ranged attack
if (nAttack)
{
//Doube damage on a crit
if (nAttack == 2) nDamage = nDamage*2;
//Apply the MIRV and damage effect
effect eDam = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_MAGICAL);
DelayCommand(fTime, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
DelayCommand(fTime, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget,0.0f,FALSE));
DelayCommand(fDelay2, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eMissile, oTarget));
}
}
ForceNeedleAttack(oPC, oTarget, nBonus);
}