Files
PRC8/nwn/nwnprc/trunk/scripts/prc_swashbuckler.nss
Jaysyn904 cda92e9396 2026/05/23 Update
Archivist wasn't specifically set as a divine class in classes.2da.
Added Create Infusion & Craft Scepter to the Archvist's feat 2da.
The Lich class is now getting the correct level based stat updates.
Fixed Create Infusion and Craft Scepter to use class level instead of caster level in feat.2da.
Added default level up package for Scout.
Added default level up package for Swashbuckler.
Fixed Contingent Resurrection to not permanently remove an epic spell slot.
Fixed the prc cache creature to be cutscene invisible, regardless of which function is creating it.
Added special handling in PRCGetLastSpellCastClass() for Bard/Sublime Chord to fix the DC issue.
Added more CEP2 wings to PRCIsFlying()
Added X2_CI_CRAFTSCEPTER_FEAT_ID to CIGetIsSpellRestrictedFromCraftFeat()
Fixed Small Shield handling in ArcaneSpellFailure()
Fixed Troglodyte's racial Stench ability.
Vow of Poverty dialog no longer shows up when you rest & haven't selected a feat for the previous level.
Swashbuckler Grace now supports 60 levels.
Swashbuckler Dodge now respects Daring Outlaw and supports 60 levels.
Blinding Glory isn't a Glory Domain spell in the PRC8.
Fixed TLK typo in Knight (Cavalier) package description.
2026-05-23 10:36:02 -04:00

260 lines
10 KiB
Plaintext

#include "prc_inc_spells"
#include "prc_inc_wpnrest"
//DAMAGE_TYPE_BASE_WEAPON
//GetAbilityModifier(ABILITY_INTELLIGENCE, oPC)
//Add INT bonus to damage inflicted, when they are in light armor or less.
//Still need to remove bonus when they are encumbered.
//Need to add an onhit to see if the target is Crit or Sneak immune, and heal the INT bonus back.
//Need to add in Weakening and Wounding criticals (on crit, deal 2 STR and 2 Con, respectively).
//Applies Reflex Save bonus is the character is in light armor or less.
//Still need to remove bonus when they are encumbered.
void Grace(object oPC, object oSkin)
{
object oArmor=GetItemInSlot(INVENTORY_SLOT_CHEST,oPC);
int iBase = GetBaseAC(oArmor);
int iMax = 3;
int nGrace;
// Calculate based on feats first (for levels 2-38)
nGrace = GetHasFeat(FEAT_SWASH_GRACE1, oPC) ? 1 : 0;
nGrace = GetHasFeat(FEAT_SWASH_GRACE2, oPC) ? 2 : nGrace;
nGrace = GetHasFeat(FEAT_SWASH_GRACE3, oPC) ? 3 : nGrace;
nGrace = GetHasFeat(FEAT_SWASH_GRACE4, oPC) ? 4 : nGrace;
nGrace = GetHasFeat(FEAT_SWASH_GRACE5, oPC) ? 5 : nGrace;
// For levels beyond 38 (where feats don't exist), calculate based on class level
int nClass = GetLevelByClass(CLASS_TYPE_SWASHBUCKLER, oPC);
if (nClass >= 56) nGrace = 7;
else if (nClass >= 47) nGrace = 6;
// If Daring Outlaw is present, recalculate based on combined levels
if (GetHasFeat(FEAT_DARING_OUTLAW, oPC))
{
nClass = GetLevelByClass(CLASS_TYPE_SWASHBUCKLER, oPC) + GetLevelByClass(CLASS_TYPE_ROGUE, oPC);
if (nClass >= 56) nGrace = 7;
else if (nClass >= 47) nGrace = 6;
else if (nClass >= 38) nGrace = 5;
else if (nClass >= 29) nGrace = 4;
else if (nClass >= 20) nGrace = 3;
else if (nClass >= 11) nGrace = 2;
else if (nClass >= 2) nGrace = 1;
else nGrace = 0;
}
if (GetBaseAC(oArmor)>iMax )
SetCompositeBonus(oSkin,"SwashGrace",0,ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC,IP_CONST_SAVEBASETYPE_REFLEX);
else
SetCompositeBonus(oSkin,"SwashGrace",nGrace,ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC,IP_CONST_SAVEBASETYPE_REFLEX);
}
//Applies a Dodge AC boost when they are wearing light armor or less.
//Still need to remove bonus when they are encumbered.
void Dodge(object oPC, object oSkin, int sDodge)
{
object oArmor=GetItemInSlot(INVENTORY_SLOT_CHEST,oPC);
int iBase = GetBaseAC(oArmor);
int iMax = 3;
if (GetBaseAC(oArmor)>iMax )
SetCompositeBonus(oSkin,"SwashAC",0,ITEM_PROPERTY_AC_BONUS);
else
SetCompositeBonus(oSkin,"SwashAC",sDodge,ITEM_PROPERTY_AC_BONUS);
}
//Adds Int bonus to damage.
//Make a special on-hit that heals your INT bonus if the target is immune to Sneak or Crits
//Make this only apply to weapons useable with weapon finesse
//make this not apply if you are wearing medium or heavy armor, or are encumbered.
void SmartWound(object oPC, object oSkin, int iStrike, int iEquip)
{
object oArmor=GetItemInSlot(INVENTORY_SLOT_CHEST,oPC);
int iBase = GetBaseAC(oArmor);
int iMax = 3;
int iLight = GetHasSwashbucklerWeapon(oPC);
if (iBase > iMax ) PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
else if (iLight < 1) PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
else
{
if (GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)))
{
ActionCastSpellOnSelf(SPELL_SWASH_DAMAGE);
}
else
{
PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
}
}
}
/* void SmartWound(object oPC, object oSkin, int iStrike, int iEquip)
{
object oArmor=GetItemInSlot(INVENTORY_SLOT_CHEST,oPC);
int iBase = GetBaseAC(oArmor);
int iMax = 3;
int iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_DAGGER ? 1 : 0;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_KATAR ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_HANDAXE ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_KAMA ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_KUKRI ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_LIGHTHAMMER ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_LIGHTMACE ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_LIGHT_PICK ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_RAPIER ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_SHORTSWORD ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_SICKLE ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_WHIP ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_SAI ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_SAP ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_NUNCHAKU ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_GOAD ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_ELVEN_LIGHTBLADE ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_ELVEN_THINBLADE ? 1 : iLight;
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_EAGLE_CLAW ? 1 : iLight;
if (GetLevelByClass(CLASS_TYPE_IAIJUTSU_MASTER) > 0)
{
iLight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC))==BASE_ITEM_KATANA ? 1 : iLight;
}
if (iBase > iMax ) PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
else if (iLight < 1) PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
else
{
if (GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)))
{
ActionCastSpellOnSelf(SPELL_SWASH_DAMAGE);
}
else
{
PRCRemoveEffectsFromSpell(oPC, SPELL_SWASH_DAMAGE);
}
}
}
*/
//This makes a unique on hit which calls on the "prc_swashweak" scripts
//to simulate a critical hit roll percentage. On success, it deals
//2 STR damage (and 2 CON damage at level 19)
void CritSTR(object oPC, object oSkin,int iStrike, int iEquip)
{
object oItem ;
object oItemb ;
if (iEquip==2)
{
oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
if ( GetLocalInt(oItem,"CritHarm")) return;
AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,1),oItem,9999.0);
SetLocalInt(oItem,"CritHarm",1);
}
else if (iEquip==1)
{
oItem=GetItemLastUnequipped();
RemoveSpecificProperty(oItem,ITEM_PROPERTY_ONHITCASTSPELL,IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,0,1,"",-1,DURATION_TYPE_TEMPORARY);
DeleteLocalInt(oItem,"CritHarm");
}
else
{
oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
if (!GetLocalInt(oItem,"CritHarm"))
{
AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,1),oItem,9999.0);
SetLocalInt(oItem,"CritHarm",1);
}
}
if (iEquip==2)
{
oItemb=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
if ( GetLocalInt(oItemb,"CritHarm")) return;
AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,1),oItemb,9999.0);
SetLocalInt(oItemb,"CritHarm",1);
}
else if (iEquip==1)
{
oItemb=GetItemLastUnequipped();
RemoveSpecificProperty(oItemb,ITEM_PROPERTY_ONHITCASTSPELL,IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,0,1,"",-1,DURATION_TYPE_TEMPORARY);
DeleteLocalInt(oItemb,"CritHarm");
}
else
{
oItemb=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
if (!GetLocalInt(oItemb,"CritHarm"))
{
AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER,1),oItemb,9999.0);
SetLocalInt(oItemb,"CritHarm",1);
}
}
}
void main()
{
//Declare main variables.
object oPC = OBJECT_SELF;
object oSkin = GetPCSkin(oPC);
int nClass = GetLevelByClass(CLASS_TYPE_SWASHBUCKLER,oPC);
int sDodge = GetHasFeat(SWASH_DODGE_1, oPC) ? 1 : 0;
sDodge = GetHasFeat(SWASH_DODGE_2, oPC) ? 2 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_3, oPC) ? 3 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_4, oPC) ? 4 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_5, oPC) ? 5 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_6, oPC) ? 6 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_7, oPC) ? 7 : sDodge;
sDodge = GetHasFeat(SWASH_DODGE_8, oPC) ? 8 : sDodge;
// For levels beyond 40 (where feats don't exist), calculate based on class level
if (nClass >= 45) sDodge = 9;
else if (nClass >= 50) sDodge = 10;
else if (nClass >= 55) sDodge = 11;
else if (nClass >= 60) sDodge = 12;
// If Daring Outlaw is present, recalculate based on combined levels
if (GetHasFeat(FEAT_DARING_OUTLAW, oPC))
{
nClass = GetLevelByClass(CLASS_TYPE_SWASHBUCKLER, oPC) + GetLevelByClass(CLASS_TYPE_ROGUE, oPC);
if (nClass >= 60) sDodge = 12;
else if (nClass >= 55) sDodge = 11;
else if (nClass >= 50) sDodge = 10;
else if (nClass >= 45) sDodge = 9;
else if (nClass >= 40) sDodge = 8;
else if (nClass >= 35) sDodge = 7;
else if (nClass >= 30) sDodge = 6;
else if (nClass >= 25) sDodge = 5;
else if (nClass >= 20) sDodge = 4;
else if (nClass >= 15) sDodge = 3;
else if (nClass >= 10) sDodge = 2;
else if (nClass >= 5) sDodge = 1;
else sDodge = 0;
}
int iStrike = GetHasFeat(INSIGHTFUL_STRIKE, oPC);
int iEquip= GetLocalInt(oPC,"ONEQUIP");
int WeakCrit = GetHasFeat(WEAKENING_CRITICAL, oPC);
int WoundCrit = GetHasFeat(WOUNDING_CRITICAL, oPC);
if (nClass>1) Grace(oPC, oSkin);
if (sDodge>0) Dodge(oPC, oSkin, sDodge);
if (iStrike>0) SmartWound(oPC, oSkin, iStrike, iEquip);
if (iStrike>0) CritSTR(oPC, oSkin, iStrike, iEquip);
}