PRC8/nwn/nwnprc/trunk/scripts/ft_poweratk.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
Updated AMS marker feats.  Removed arcane & divine marker feats.  Updated Dread Necromancer for epic progression. Updated weapon baseitem models.  Updated new weapons for crafting & npc equip.
 Updated prefix.  Updated release archive.
2024-02-11 14:01:05 -05:00

230 lines
8.8 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Power Attack script
//:: ft_poweratk
//::///////////////////////////////////////////////
/*
This script handles the PRC power attack feats.
<Ornedan> For PA, I was thinking 3 radials
<Ornedan> One for the presets
<Ornedan> One for +0, +1, +2, +3, +4
<Ornedan> One for +0, +5, +10, +15, +20
<Ornedan> And a bunch of switches to control it:
<Ornedan> PRC_POWER_ATTACK - 3 values:
<Ornedan> -1 -- Disabled. Never apply the PRC PA feats to hide
<Ornedan> 0 -- Default. As it is now, you can't go higher than the equivalent BW feat you have
<Ornedan> 1 -- Full PnP. Ignores the BW IPA
<Ornedan> PRC_POWER_ATTACK_STACK_WITH_BW
<Ornedan> 0 - Default. Allow people to use both at the same time
<Ornedan> 1 - Add the BW effects in when limiting to BAB
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "prc_inc_combat"
#include "inc_addragebonus"
//#include "prc_inc_sneak" //for Dragonfire damage type resolving
/*
const int SINGLE_START = 2171;
const int SINGLE_LAST = 2175;
const int FIVES_START = 2177;
const int FIVES_LAST = 2181;
*/
// Converts the given amount of bonus damage to equivalent DAMAGE_BONUS constant
// Due to the bonus cap, bonuses are cropped to +20
int BonusAtk(int nDmg)
{
switch (nDmg)
{
case 1: return DAMAGE_BONUS_1;
case 2: return DAMAGE_BONUS_2;
case 3: return DAMAGE_BONUS_3;
case 4: return DAMAGE_BONUS_4;
case 5: return DAMAGE_BONUS_5;
case 6: return DAMAGE_BONUS_6;
case 7: return DAMAGE_BONUS_7;
case 8: return DAMAGE_BONUS_8;
case 9: return DAMAGE_BONUS_9;
case 10: return DAMAGE_BONUS_10;
case 11: return DAMAGE_BONUS_11;
case 12: return DAMAGE_BONUS_12;
case 13: return DAMAGE_BONUS_13;
case 14: return DAMAGE_BONUS_14;
case 15: return DAMAGE_BONUS_15;
case 16: return DAMAGE_BONUS_16;
case 17: return DAMAGE_BONUS_17;
case 18: return DAMAGE_BONUS_18;
case 19: return DAMAGE_BONUS_19;
case 20: return DAMAGE_BONUS_20;
}
if(nDmg > 20) return DAMAGE_BONUS_20;
return -1; // Invalid value received
}
/*
int CalculatePower(object oUser)
{
int nPower = GetLocalInt(oUser, "PRC_PowerAttack_Level");
int nSID = GetSpellID();
// Changing the value of +0,+1,+2,+3,+4 radial
if(nSID >= SINGLE_START && <= SINGLE_LAST)
{
// Extract the old fives value
nPower = (nPower / 5) * 5;
// Add in the new single value
nPower += nSID - SINGLE_START;
}
// Changing the value of +0,+5,+10,+15,+20 radial
else if(nSID >= FIVES_START && <= FIVES_LAST)
{
// Extract the old single value
nPower = nPower % 5;
// Add in the new fives value
nPower += (nSID - FIVES_START) * 5;
}
// Unknown SpellId
else
{
WriteTimestampedLogEntry("ft_poweratk called with unknown SpellID: " + IntToString(nSID));
nPower = 0;
}
// Cache the new PA level
SetLocalInt(oUser, "PRC_PowerAttack_Level", nPower);
return nPower;
}
*/
void main()
{
object oUser = OBJECT_SELF;
int nPower = GetLocalInt(oUser, "PRC_PowerAttack_Level");
// The PRC Power Attack must be active for this to do anything
if(GetPRCSwitch(PRC_POWER_ATTACK) == PRC_POWER_ATTACK_DISABLED)
return;
// Get the old Power Attack, if any
int nOld = GetLocalInt(oUser, "PRC_PowerAttackSpellID");
// Remove effects from it
if(nOld)
{
PRCRemoveSpellEffects(nOld, oUser, oUser);
DeleteLocalInt(oUser, "PRC_PowerAttackSpellID");
DeleteLocalInt(oUser, "PRC_PowerAttack_DamageBonus");
}
// Activate Power Attack if the new value is non-zero
if(nPower)
{
// Requires the appropriate BW PA feat.
if(!GetHasFeat(FEAT_POWER_ATTACK))
{
FloatingTextStrRefOnCreature(16823148, oUser, FALSE); //Prereq: Power Attack feat
return;
}
if(nPower > 5 && // If the power attack is in BW IPA range
!GetHasFeat(FEAT_IMPROVED_POWER_ATTACK) && // And they don't have IPA
GetPRCSwitch(PRC_POWER_ATTACK) != PRC_POWER_ATTACK_FULL_PNP) // And full PnP PA, which ignores BW IPA isn't active
{
FloatingTextStrRefOnCreature(16823149, oUser, FALSE); // Prereq: Improved Power Attack feat
return;
}
// This script is for the melee weapon PA. If Power Shot is implemented using the same script
// at some future date, change this.
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oUser);
int nBase = GetBaseItemType(oWeapon);
int nThrow = FALSE;
if (GetIsThrowingWeaponType(nBase) && GetHasFeat(FEAT_POWER_THROW, oUser)) nThrow = TRUE; // Power throw allows power attacking with throwing weapons
if(GetWeaponRanged(oWeapon) && !nThrow)
{
FloatingTextStrRefOnCreature(16823150, oUser, FALSE); // You may not use this feat with a ranged weapon.
return;
}
// All checks are done, initialize variables for calculating the effect.
int nDamageBonusType = GetDamageTypeOfWeapon(INVENTORY_SLOT_RIGHTHAND, oUser);
if(GetLocalInt(oUser, "DragonFireAssOn")) nDamageBonusType = GetDragonfireDamageType(oUser);
int nDmg, nHit, nDex, nTemp;
effect eDamage;
effect eToHit;
// Initialize the calculation with the power attack value given by the user.
nHit = nPower;
// Check if we are set to care about BW power attack being active
if(GetPRCSwitch(PRC_POWER_ATTACK_STACK_WITH_BW))
{
nTemp += GetActionMode(oUser, ACTION_MODE_POWER_ATTACK) ? 5 : 0;
nTemp += GetActionMode(oUser, ACTION_MODE_IMPROVED_POWER_ATTACK) ? 10 : 0;
}
// The attack bonus paid to PA is limited to one's BAB
if(GetBaseAttackBonus(oUser) < (nHit + nTemp))
{
nHit = GetBaseAttackBonus(oUser) - ((GetActionMode(oUser, ACTION_MODE_POWER_ATTACK) ? 5 : 0) +
(GetActionMode(oUser, ACTION_MODE_IMPROVED_POWER_ATTACK ? 10 : 0)));
if(nHit < 0) nHit = 0;
FloatingTextStrRefOnCreature(16823151, oUser, FALSE); // Your base attack bonus isn't high enough to pay for chosen Power Attack level.
}
// Focused Strike adds Dex mod to damage, limited to number of AB paid.
if(GetHasFeat(FEAT_FOCUSED_STRIKE))
{
// Negative Dex mod won't reduce damage
nDex = GetAbilityModifier(ABILITY_DEXTERITY) > 0 ? GetAbilityModifier(ABILITY_DEXTERITY) : 0;
if(nDex > nHit) nDex = nHit;
}
// Calculate in Frenzied Berserker PA feats
nTemp = GetHasFeat(FEAT_SUPREME_POWER_ATTACK, oUser) ? nHit * 2 :
GetHasFeat(FEAT_FREBZK_IMPROVED_POWER_ATTACK, oUser) ? FloatToInt(1.5 * nHit) :
nHit;
// Calculate the damage. Supreme Power Attack doubles the damage
nDmg = BonusAtk(nTemp + nDex + GetEssentiaInvestedFeat(oUser, FEAT_COBALT_POWER));
eDamage = EffectDamageIncrease(nDmg, nDamageBonusType);
eToHit = EffectAttackDecrease(nHit);
effect eLink = ExtraordinaryEffect(EffectLinkEffects(eDamage, eToHit));
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oUser);
// Cache the spellid of the power attack used. Also acts as a marker
SetLocalInt(oUser, "PRC_PowerAttackSpellID", PRCGetSpellId());
// Cache the amount of damage granted. This is used by the PRC combat engine
SetLocalInt(oUser, "PRC_PowerAttack_DamageBonus", nDmg);
// Add an eventscript that makes sure the PC does not use a ranged weapon with Power Attack
AddEventScript(oUser, EVENT_ONPLAYEREQUIPITEM, "prc_powatk_equ", TRUE, FALSE);
// Power Attack Activated
string sMes = "*" + GetStringByStrRef(417) + " " + IntToString(nHit) + " " + GetStringByStrRef(63798) + "*";
FloatingTextStringOnCreature(sMes, oUser, FALSE);
if (GetHasFeat(FEAT_FAVORED_POWER_ATTACK, oUser))
{
ActionCastSpellAtObject(SPELL_UR_FAVORITE_ENEMY, oUser, METAMAGIC_ANY, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
}
}
// Turn Power Attack off
else
{
RemoveEventScript(oUser, EVENT_ONPLAYEREQUIPITEM, "prc_powatk_equ", TRUE);
// Power Attack Mode Deactivated
string sMes = "* " + GetStringByStrRef(58282) + " *";
FloatingTextStringOnCreature(sMes, oUser, FALSE);
if(GetHasFeat(FEAT_FAVORED_POWER_ATTACK, oUser))
{
ActionCastSpellAtObject(SPELL_UR_FAVORITE_ENEMY, oUser, METAMAGIC_ANY, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
}
}
}