PRC8/nwn/nwnprc/trunk/spells/x2_s0_enhweap.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

451 lines
19 KiB
Plaintext

/*
x2_s0_enhweap
Consolidation of:
Blackstaff
Blade Thirst
Bless Weapon
Darkfire
Deafening Clang
Flame Weapon
Holy Sword
Keen Edge
Magic Weapon
Greater Magic Weapon
Unholy Sword
Weapon of Impact
Shillelagh
By: Flaming_Sword
Created: Jun 29, 2006
Modified: Jun 30, 2006
Modified; Apr 7, 2007 by motu99
*/
#include "prc_sp_func"
#include "x2_inc_toollib"
/// Used simply to use up a bit less processor time on the delayed command to delete these 6 Ints.
// motu99: seems to be not used any more
void DeleteTheInts(object oTarget)
{
DeleteLocalInt(oTarget, "X2_Wep_Dam_Type");
DeleteLocalInt(oTarget, "X2_Wep_Caster_Lvl");
DeleteLocalInt(oTarget, "X2_Wep_Dam_Type_DF");
DeleteLocalInt(oTarget, "X2_Wep_Caster_Lvl_DF");
DeleteLocalInt(oTarget, "X2_Wep_Caster_Lvl_DC");
DeleteLocalInt(oTarget, "X2_Wep_Penetr_DC");
}
//------------------------------------------------------------------------------
// AN, 2003
// Returns TRUE if oItem is a slashing weapon
//------------------------------------------------------------------------------
int PRCGetSlashingWeapon(object oItem)
{
//Declare major variables
int nItem = GetBaseItemType(oItem);
//exclude creature weapons
if(nItem == BASE_ITEM_CSLASHWEAPON ||
nItem == BASE_ITEM_CSLSHPRCWEAP)
return FALSE;
int nWeapon = (StringToInt(Get2DACache("baseitems", "WeaponType", nItem)));
// 3 = slashing, 4 = piercing-slashing
return (nWeapon == 3 || nWeapon == 4);
/* if((nItem == BASE_ITEM_BASTARDSWORD) ||
(nItem == BASE_ITEM_BATTLEAXE) ||
(nItem == BASE_ITEM_DOUBLEAXE) ||
(nItem == BASE_ITEM_GREATAXE) ||
(nItem == BASE_ITEM_GREATSWORD) ||
(nItem == BASE_ITEM_HALBERD) ||
(nItem == BASE_ITEM_HANDAXE) ||
(nItem == BASE_ITEM_KAMA) ||
(nItem == BASE_ITEM_KATANA) ||
(nItem == BASE_ITEM_KUKRI) ||
(nItem == BASE_ITEM_LONGSWORD)||
(nItem == BASE_ITEM_SCIMITAR)||
(nItem == BASE_ITEM_SCYTHE)||
(nItem == BASE_ITEM_SICKLE)||
(nItem == BASE_ITEM_TWOBLADEDSWORD) ||
(nItem == BASE_ITEM_DWARVENWARAXE) ||
(nItem == BASE_ITEM_THROWINGAXE) ||
(nItem == BASE_ITEM_WHIP)
|| (nItem == 300) //CEP Trident
|| (nItem == 303) //CEP Sai
|| (nItem == 305) //CEP falchion
|| (nItem == 309) //CEP assassin dager
|| (nItem == 310) //CEP katar
|| (nItem == 313) //CEP kukri2
|| (nItem == 316) //CEP falchion
|| (nItem == 319) //CEP sh_x1_mercuryls
|| (nItem == 320) //CEP sh_x1_mercurygs
|| (nItem == 321) //CEP sh_x1_doublesc
|| (nItem == 322) //CEP goad
|| (nItem == 323) //CEP windfirewheel
|| (nItem == 324) //CEP maugdoublesword
)
{
return TRUE;
}
return FALSE;*/
}
//------------------------------------------------------------------------------
// Returns TRUE if oItem is a piercing weapon
//------------------------------------------------------------------------------
int PRCGetPiercingWeapon(object oItem)
{
int nItem = GetBaseItemType(oItem);
//exclude creature weapons
if(nItem == BASE_ITEM_CBLUDGWEAPON)
return FALSE;
int nWeapon = (StringToInt(Get2DACache("baseitems", "WeaponType", nItem)));
// 2 = bludgeoning, 5 = bludgeoning/piercing
return (nWeapon == 1 || nWeapon == 4 || nWeapon == 5);
}
//------------------------------------------------------------------------------
// Returns TRUE if oItem is a bludgeoning weapon
//------------------------------------------------------------------------------
int PRCGetBludgeoningWeapon(object oItem)
{
int nItem = GetBaseItemType(oItem);
//exclude creature weapons
if(nItem == BASE_ITEM_CBLUDGWEAPON)
return FALSE;
int nWeapon = (StringToInt(Get2DACache("baseitems", "WeaponType", nItem)));
// 2 = bludgeoning, 5 = bludgeoning/piercing
return (nWeapon == 2 || nWeapon == 5);
}
void ApplyEffectsToWeapon(object oItem, int nSpellID, float fDuration, object oCaster, int nCasterLevel, int nPenetr)
{
switch(nSpellID)
{
case SPELL_BLADE_THIRST:
{
IPSafeAddItemProperty(oItem, ItemPropertyEnhancementBonus(3), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyLight(IP_CONST_LIGHTBRIGHTNESS_LOW, IP_CONST_LIGHTCOLOR_YELLOW), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
break;
}
case SPELL_BLACKSTAFF:
{
IPSafeAddItemProperty(oItem, ItemPropertyEnhancementBonus(4), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyOnHitProps(IP_CONST_ONHIT_DISPELMAGIC, IP_CONST_ONHIT_SAVEDC_16), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING);
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_EVIL), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
break;
}
case SPELL_SHILLELAGH:
{
IPSafeAddItemProperty(oItem, ItemPropertyEnhancementBonus(1), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_BLUDGEONING, IP_CONST_DAMAGEBONUS_1d6), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_HOLY), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
break;
}
case SPELL_BLESS_WEAPON:
{
// If the spell is cast again, any previous enhancement boni are kept
IPSafeAddItemProperty(oItem, ItemPropertyEnhancementBonus(1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE);
// Replace existing temporary anti undead boni
IPSafeAddItemProperty(oItem, ItemPropertyDamageBonusVsRace(IP_CONST_RACIALTYPE_UNDEAD, IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING );
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_HOLY), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE );
break;
}
case SPELL_DARKFIRE:
case SPELL_FLAME_WEAPON:
{
int nAppearanceType = ITEM_VISUAL_FIRE;
int nDamageType = ChangedElementalDamage(oCaster, DAMAGE_TYPE_FIRE);
int bDarkfire = (nSpellID == SPELL_DARKFIRE);
//SendMessageToPC(OBJECT_SELF, "I am the caster");
switch(nDamageType)
{
case DAMAGE_TYPE_ACID: nAppearanceType = ITEM_VISUAL_ACID; break;
case DAMAGE_TYPE_COLD: nAppearanceType = ITEM_VISUAL_COLD; break;
case DAMAGE_TYPE_ELECTRICAL: nAppearanceType = ITEM_VISUAL_ELECTRICAL; break;
case DAMAGE_TYPE_SONIC: nAppearanceType = ITEM_VISUAL_SONIC; break;
}
// motu99: added differentiation for Darkfire and flame weapon
if (bDarkfire)
{
// DeleteLocalInt(oItem, "X2_Wep_Dam_Type_DF");
SetLocalInt(oItem, "X2_Wep_Dam_Type_DF", nDamageType);
// Sets Caster Level int because it was too confusing trying to figure out caster level
// in the damage script.
// DeleteLocalInt(oItem, "X2_Wep_Caster_Lvl");
SetLocalInt(oItem, "X2_Wep_Caster_Lvl_DF", nCasterLevel);
}
else
{
// DeleteLocalInt(oItem, "X2_Wep_Dam_Type");
SetLocalInt(oItem, "X2_Wep_Dam_Type", nDamageType);
// Sets Caster Level int because it was too confusing trying to figure out caster level
// in the damage script.
// DeleteLocalInt(oItem, "X2_Wep_Caster_Lvl");
SetLocalInt(oItem, "X2_Wep_Caster_Lvl", nCasterLevel);
}
// If the spell is cast again, any previous itemproperties matching are removed.
if(!bDarkfire || (bDarkfire && !(GetBaseItemType(oItem) == BASE_ITEM_SHORTSPEAR && GetHasFeat(FEAT_THUNDER_WEAPON, oCaster))))
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(bDarkfire ? 127 : 124, nCasterLevel), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING);
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(nAppearanceType), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
//DelayCommand(fDuration, DeleteTheInts(oItem));
break;
}
case SPELL_DEAFENING_CLANG:
{
IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_SONIC, IP_CONST_DAMAGEBONUS_3), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING ,FALSE,TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(137, 5),fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, TRUE,FALSE);
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_SONIC), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE );
SetLocalInt(oItem, "X2_Wep_Caster_Lvl_DC", nCasterLevel);
SetLocalInt(oItem, "X2_Wep_Penetr_DC", nPenetr);
break;
}
case SPELL_HOLY_SWORD:
{
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyEnhancementBonus(2), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyEnhancementBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL, 5), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL, IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyAreaOfEffect(IP_CONST_AOE_CIRCLE_VS_EVIL, nCasterLevel), oItem, fDuration);
break;
}
case SPELL_KEEN_EDGE:
{
IPSafeAddItemProperty(oItem,ItemPropertyKeen(), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
break;
}
case SPELL_WEAPON_OF_IMPACT:
{
IPSafeAddItemProperty(oItem,ItemPropertyKeen(), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
break;
}
case SPELL_MAGIC_WEAPON:
{
IPSafeAddItemProperty(oItem,ItemPropertyEnhancementBonus(1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
break;
}
case SPELL_GREATER_MAGIC_WEAPON:
{
int nBonus = nCasterLevel / 3;
if(nBonus > 5) nBonus = 5;
IPSafeAddItemProperty(oItem,ItemPropertyEnhancementBonus(nBonus), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
break;
}
case SPELL_UNHOLYSWORD:
{
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyEnhancementBonus(2), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyEnhancementBonusVsAlign(IP_CONST_ALIGNMENTGROUP_GOOD, 5), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_GOOD, IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), oItem, fDuration);
AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyAreaOfEffect(IP_CONST_AOE_CIRCLE_VS_GOOD, nCasterLevel), oItem, fDuration);
break;
}
}
}
//Implements the spell impact, put code here
// if called in many places, return TRUE if
// stored charges should be decreased
// eg. touch attack hits
//
// Variables passed may be changed if necessary
int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
{
int nSpellID = PRCGetSpellId(oCaster);
int nMetaMagic = PRCGetMetaMagicFeat(oCaster);
int nPenetr = nCasterLevel + SPGetPenetr();
//float fMaxDuration = RoundsToSeconds(nCasterLevel); //modify if necessary
int nDuration = nCasterLevel;
if(CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) nDuration *= 2;
object oMyWeapon = IPGetTargetedOrEquippedMeleeWeapon();
object oPossessor = GetItemPossessor(oMyWeapon);
int bCondition = GetIsObjectValid(oMyWeapon);
if(!bCondition)
{
FloatingTextStrRefOnCreature(83615, oCaster);
return TRUE;
}
int nVis = VFX_IMP_SUPER_HEROISM;
int nDur = VFX_DUR_CESSATE_POSITIVE;
float fDuration = RoundsToSeconds(nDuration);
switch(nSpellID)
{
case SPELL_BLADE_THIRST:
{
bCondition = bCondition && PRCGetSlashingWeapon(oMyWeapon);
break;
}
case SPELL_BLACKSTAFF:
{
nVis = VFX_IMP_EVIL_HELP;
bCondition = bCondition && (GetBaseItemType(oMyWeapon) == BASE_ITEM_QUARTERSTAFF) ||
(GetBaseItemType(oMyWeapon) == BASE_ITEM_MAGICSTAFF) ||
(GetBaseItemType(oMyWeapon) == BASE_ITEM_CRAFTED_STAFF);
break;
}
case SPELL_BLESS_WEAPON:
{
fDuration = TurnsToSeconds(nDuration);
// ---------------- TARGETED ON BOLT -------------------
if(GetIsObjectValid(oTarget) && GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
{
// special handling for blessing crossbow bolts that can slay rakshasa's
if (GetBaseItemType(oTarget) == BASE_ITEM_BOLT)
{
SignalEvent(GetItemPossessor(oTarget), EventSpellCastAt(GetItemPossessor(oTarget), nSpellID, FALSE));
IPSafeAddItemProperty(oTarget, ItemPropertyOnHitCastSpell(123,1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING );
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nVis), GetItemPossessor(oTarget));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(nDur), GetItemPossessor(oTarget), RoundsToSeconds(nDuration));
return TRUE;
}
}
break;
}
case SPELL_DARKFIRE:
{
nVis = VFX_IMP_PULSE_FIRE;
fDuration = HoursToSeconds(nDuration);
break;
}
case SPELL_FLAME_WEAPON:
{
nVis = VFX_IMP_PULSE_FIRE;
fDuration = TurnsToSeconds(nDuration);
break;
}
case SPELL_HOLY_SWORD:
case SPELL_UNHOLYSWORD:
{
nVis = VFX_IMP_GOOD_HELP;
break;
}
case SPELL_KEEN_EDGE:
{
bCondition = bCondition && (PRCGetSlashingWeapon(oMyWeapon) || PRCGetPiercingWeapon(oMyWeapon));
fDuration = TurnsToSeconds(nDuration*10);
break;
}
case SPELL_WEAPON_OF_IMPACT:
{
bCondition = bCondition && PRCGetBludgeoningWeapon(oMyWeapon);
fDuration = TurnsToSeconds(nDuration*10);
break;
}
case SPELL_MAGIC_WEAPON:
{
fDuration = HoursToSeconds(nDuration);
break;
}
case SPELL_GREATER_MAGIC_WEAPON:
{
fDuration = HoursToSeconds(nDuration);
break;
}
case SPELL_SHILLELAGH:
{
int nBaseItemType = GetBaseItemType(oMyWeapon);
if (nBaseItemType == BASE_ITEM_QUARTERSTAFF && !GetIsMagicItem(oMyWeapon))
{
// Execute the code for non-magical quarterstaff here
bCondition = bCondition && TRUE; // Update the condition as needed
fDuration = TurnsToSeconds(nDuration);
}
else if (nBaseItemType == BASE_ITEM_CLUB && !GetIsMagicItem(oMyWeapon))
{
// Execute the code for non-magical club here
bCondition = bCondition && TRUE; // Update the condition as needed
fDuration = TurnsToSeconds(nDuration);
}
else
{
// Invalid weapon type, do nothing or handle the error here
bCondition = bCondition && FALSE; // Update the condition as needed
fDuration = 0.0; // Update the duration as needed
}
break;
}
/* case SPELL_SHILLELAGH:
{
bCondition = bCondition && ((GetBaseItemType(oMyWeapon) == BASE_ITEM_QUARTERSTAFF) ||
(GetBaseItemType(oMyWeapon) == BASE_ITEM_CLUB)) &&
!GetIsMagicItem(oMyWeapon);
fDuration = TurnsToSeconds(nDuration);
break;
} */
}
if(bCondition)
{
SignalEvent(oPossessor, EventSpellCastAt(oPossessor, nSpellID, FALSE));
if (nDuration>0)
{
effect eVis = EffectVisualEffect(nVis);
if(nSpellID == SPELL_DARKFIRE) eVis = EffectLinkEffects(EffectVisualEffect(VFX_IMP_FLAME_M), eVis);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPossessor);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(nDur), oPossessor, fDuration);
ApplyEffectsToWeapon(oMyWeapon, nSpellID, fDuration, oCaster, nCasterLevel, nPenetr);
}
if(nSpellID == SPELL_UNHOLYSWORD)
{
TLVFXPillar(VFX_IMP_GOOD_HELP, GetLocation(PRCGetSpellTargetObject()), 4, 0.0f, 6.0f);
DelayCommand(1.0f, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect( VFX_IMP_SUPER_HEROISM),GetLocation(PRCGetSpellTargetObject())));
}
return TRUE;
}
else
{
if(nSpellID == SPELL_BLACKSTAFF)
FloatingTextStrRefOnCreature(83620, OBJECT_SELF); // not a qstaff
else if((nSpellID == SPELL_BLADE_THIRST) || (nSpellID == SPELL_KEEN_EDGE))
FloatingTextStrRefOnCreature(83621, OBJECT_SELF); // not a slashing weapon
else if(nSpellID == SPELL_WEAPON_OF_IMPACT)
FloatingTextStrRefOnCreature(16789910, OBJECT_SELF); // not a bludgeoning weapon
else if(nSpellID == SPELL_SHILLELAGH)
FloatingTextStrRefOnCreature(16789913, OBJECT_SELF); // not a nonmagical club or quarterstaff
}
return TRUE; //return TRUE if spell charges should be decremented
}
void main()
{
object oCaster = OBJECT_SELF;
int nCasterLevel = PRCGetCasterLevel(oCaster);
if (nCasterLevel > 40) nCasterLevel = 40;
PRCSetSchool(GetSpellSchool(PRCGetSpellId(oCaster)));
if (!X2PreSpellCastCode()) return;
object oTarget = PRCGetSpellTargetObject(oCaster);
int nEvent = GetLocalInt(oCaster, PRC_SPELL_EVENT); //use bitwise & to extract flags
if(!nEvent) //normal cast
{
if(GetLocalInt(oCaster, PRC_SPELL_HOLD) && oCaster == oTarget)
{ //holding the charge, casting spell on self
SetLocalSpellVariables(oCaster, 1); //change 1 to number of charges
return;
}
DoSpell(oCaster, oTarget, nCasterLevel, nEvent);
}
else
{
if(nEvent & PRC_SPELL_EVENT_ATTACK)
{
if(DoSpell(oCaster, oTarget, nCasterLevel, nEvent))
DecrementSpellCharges(oCaster);
}
}
PRCSetSchool();
}