313 lines
13 KiB
Plaintext
313 lines
13 KiB
Plaintext
|
|
#include "nw_i0_spells"
|
|
//#include "x2_i0_spells"
|
|
#include "prc_inc_spells"
|
|
#include "x2_inc_spellhook"
|
|
#include "x2_inc_toollib"
|
|
#include "util_inc"
|
|
|
|
object GetTargetCreature()
|
|
{
|
|
object oTarget = GetSpellTargetObject();
|
|
if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
|
|
return oTarget;
|
|
else if (GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
|
|
return GetItemPossessor(oTarget);
|
|
else
|
|
return OBJECT_INVALID;
|
|
}
|
|
|
|
object GetTargetWeapon()
|
|
{
|
|
object oTarget = GetSpellTargetObject();
|
|
object oWeapon;
|
|
if (GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
|
|
{
|
|
oWeapon = oTarget;
|
|
}
|
|
else
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
|
|
if (oWeapon == OBJECT_INVALID || !util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
|
|
}
|
|
if (oWeapon == OBJECT_INVALID || !util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_ARMS, oTarget);
|
|
}
|
|
if (oWeapon == OBJECT_INVALID || !util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTarget);
|
|
}
|
|
if (oWeapon == OBJECT_INVALID || !util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTarget);
|
|
}
|
|
if (oWeapon == OBJECT_INVALID || !util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTarget);
|
|
}
|
|
}
|
|
if (!util_IsWeapon(oWeapon))
|
|
{
|
|
oWeapon = OBJECT_INVALID;
|
|
}
|
|
return oWeapon;
|
|
}
|
|
|
|
|
|
float GetSpellDuration()
|
|
{
|
|
int nSpellID = GetSpellId();
|
|
int nCasterLvl = GetCasterLevel(OBJECT_SELF);
|
|
int nMetaMagic = GetMetaMagicFeat();
|
|
float fDuration;
|
|
|
|
switch (nSpellID)
|
|
{
|
|
case SPELL_MAGIC_WEAPON:
|
|
case SPELL_GREATER_MAGIC_WEAPON:
|
|
case SPELL_DARKFIRE:
|
|
case SPELL_FLAME_WEAPON:
|
|
fDuration = TurnsToSeconds(2*nCasterLvl); break;
|
|
case SPELL_BLADE_THIRST:
|
|
fDuration = RoundsToSeconds(2*nCasterLvl); break;
|
|
case SPELL_KEEN_EDGE:
|
|
fDuration = TurnsToSeconds(10*nCasterLvl); break;
|
|
case SPELL_BLESS_WEAPON:
|
|
fDuration = RoundsToSeconds(2*nCasterLvl); break;
|
|
case SPELL_HOLY_SWORD:
|
|
fDuration = RoundsToSeconds(nCasterLvl); break;
|
|
default:
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
if (nMetaMagic == METAMAGIC_EXTEND)
|
|
fDuration *= 2;
|
|
return fDuration;
|
|
}
|
|
|
|
void AddGreaterEnhancementEffectToWeapon(object oMyWeapon, float fDuration, int nBonus)
|
|
{
|
|
IPSafeAddItemProperty(oMyWeapon,ItemPropertyEnhancementBonus(nBonus), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
|
return;
|
|
}
|
|
|
|
void AddKeenEffectToWeapon(object oMyWeapon, float fDuration)
|
|
{
|
|
IPSafeAddItemProperty(oMyWeapon,ItemPropertyKeen(), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
|
|
return;
|
|
}
|
|
|
|
void AddBlessEffectToWeapon(object oTarget, float fDuration)
|
|
{
|
|
// If the spell is cast again, any previous enhancement boni are kept
|
|
IPSafeAddItemProperty(oTarget, ItemPropertyEnhancementBonus(1), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE);
|
|
// Replace existing temporary anti undead boni
|
|
IPSafeAddItemProperty(oTarget, ItemPropertyDamageBonusVsRace(IP_CONST_RACIALTYPE_UNDEAD, IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING );
|
|
IPSafeAddItemProperty(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_HOLY), fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE );
|
|
return;
|
|
}
|
|
|
|
void AddHolyAvengerEffectToWeapon(object oMyWeapon, float fDuration)
|
|
{
|
|
//IPSafeAddItemProperty(oMyWeapon,ItemPropertyEnhancementBonus(2), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING ,FALSE,TRUE);
|
|
IPSafeAddItemProperty(oMyWeapon,ItemPropertyHolyAvenger(), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE);
|
|
return;
|
|
}
|
|
|
|
void AddItemEnhancementEffect(object oItem, float fDuration, int nEnhancementBonus)
|
|
{
|
|
int nBaseItemType = GetBaseItemType(oItem);
|
|
// Ranged weapons and bracers/gauntlets can only gain attac bonuses
|
|
if ( nBaseItemType == BASE_ITEM_LONGBOW
|
|
|| nBaseItemType == BASE_ITEM_HEAVYCROSSBOW
|
|
|| nBaseItemType == BASE_ITEM_GLOVES
|
|
|| nBaseItemType == BASE_ITEM_SHORTBOW
|
|
|| nBaseItemType == BASE_ITEM_SLING
|
|
|| nBaseItemType == BASE_ITEM_LIGHTCROSSBOW)
|
|
IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(nEnhancementBonus), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
|
// Ranged ammunition can only gain damage bonuses
|
|
else if ( nBaseItemType == BASE_ITEM_ARROW
|
|
|| nBaseItemType == BASE_ITEM_BOLT
|
|
|| nBaseItemType == BASE_ITEM_BULLET)
|
|
IPSafeAddItemProperty(oItem, ItemPropertyDamageBonus(nBaseItemType == BASE_ITEM_BULLET ? IP_CONST_DAMAGETYPE_BLUDGEONING : IP_CONST_DAMAGETYPE_PIERCING,nEnhancementBonus),
|
|
fDuration, X2_IP_ADDPROP_POLICY_IGNORE_EXISTING, FALSE, TRUE);
|
|
// All other weapons can gain enhancement bonuses
|
|
else if ( nBaseItemType == BASE_ITEM_ARMOR)
|
|
IPSafeAddItemProperty(oItem, ItemPropertyACBonus(nEnhancementBonus), fDuration, X2_IP_ADDPROP_POLICY_IGNORE_EXISTING, FALSE, TRUE);
|
|
// All other weapons can gain enhancement bonuses
|
|
else if (util_IsWeapon(oItem))
|
|
IPSafeAddItemProperty(oItem, ItemPropertyEnhancementBonus(nEnhancementBonus), fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
|
}
|
|
|
|
void AddItemEnergyEffect(object oItem, float fDuration, int nDamageType, int nDamageBonus)
|
|
{
|
|
// Abort for non-weapons
|
|
int nBaseItemType = GetBaseItemType(oItem);
|
|
if (util_IsWeapon(oItem) || nBaseItemType == BASE_ITEM_GLOVES)
|
|
{
|
|
itemproperty ip = GetFirstItemProperty(oItem);
|
|
while (GetIsItemPropertyValid(ip))
|
|
{
|
|
if (GetItemPropertyTag(ip) == "SPELL_ENERGY_EFFECT")
|
|
{
|
|
FloatingTextStringOnCreature("You override an existing enchantment", OBJECT_SELF, FALSE);
|
|
RemoveItemProperty(oItem, ip);
|
|
}
|
|
ip = GetNextItemProperty(oItem);
|
|
}
|
|
|
|
IPSafeAddItemProperty(oItem, TagItemProperty(ItemPropertyDamageBonus(nDamageType, nDamageBonus), "SPELL_ENERGY_EFFECT"), fDuration,
|
|
X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
|
|
|
|
int nItemVisual = -1;
|
|
switch (nDamageType)
|
|
{
|
|
case IP_CONST_DAMAGETYPE_ACID: nItemVisual = ITEM_VISUAL_ACID; break;
|
|
case IP_CONST_DAMAGETYPE_COLD: nItemVisual = ITEM_VISUAL_COLD; break;
|
|
case IP_CONST_DAMAGETYPE_DIVINE:
|
|
switch (GetAlignmentGoodEvil(OBJECT_SELF))
|
|
{
|
|
case ALIGNMENT_GOOD: nItemVisual = ITEM_VISUAL_HOLY; break;
|
|
case ALIGNMENT_NEUTRAL: nItemVisual = ITEM_VISUAL_SONIC; break;
|
|
case ALIGNMENT_EVIL: nItemVisual = ITEM_VISUAL_EVIL; break;
|
|
}
|
|
break;
|
|
case IP_CONST_DAMAGETYPE_ELECTRICAL: nItemVisual = ITEM_VISUAL_ELECTRICAL; break;
|
|
case IP_CONST_DAMAGETYPE_FIRE: nItemVisual = ITEM_VISUAL_FIRE; break;
|
|
case IP_CONST_DAMAGETYPE_MAGICAL: nItemVisual = ITEM_VISUAL_SONIC; break;
|
|
case IP_CONST_DAMAGETYPE_NEGATIVE: nItemVisual = ITEM_VISUAL_EVIL; break;
|
|
case IP_CONST_DAMAGETYPE_POSITIVE: nItemVisual = ITEM_VISUAL_HOLY; break;
|
|
case IP_CONST_DAMAGETYPE_SONIC: nItemVisual = ITEM_VISUAL_SONIC; break;
|
|
}
|
|
// Add the item visual only if needed
|
|
if (nItemVisual != -1)
|
|
IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(nItemVisual), fDuration,
|
|
X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
void main()
|
|
{
|
|
int nSpellID = GetSpellId();
|
|
object oCaster = OBJECT_SELF;
|
|
object oCreature = GetTargetCreature();
|
|
object oWeapon = GetTargetWeapon();
|
|
object oOffHand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
|
|
float fDuration = GetSpellDuration();
|
|
int nCasterLvl = GetCasterLevel(oCaster);
|
|
int nRemainingSpellUses = GetHasSpell(nSpellID, oCaster);
|
|
|
|
if (fDuration <= 0.0 || oWeapon == OBJECT_INVALID)
|
|
{
|
|
FloatingTextStringOnCreature("Your spell did not take hold", oCaster, FALSE);
|
|
return;
|
|
}
|
|
|
|
int nApplyToOffHand = FALSE;
|
|
if (GetSpellTargetObject() == oCreature &&
|
|
GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature) == oWeapon &&
|
|
util_IsWeapon(oOffHand) &&
|
|
nRemainingSpellUses > 0)
|
|
{
|
|
DecrementRemainingSpellUses(oCaster, nSpellID);
|
|
nApplyToOffHand = TRUE;
|
|
}
|
|
|
|
//Declare major variables
|
|
effect eVis;
|
|
switch (nSpellID)
|
|
{
|
|
case SPELL_HOLY_SWORD: eVis = EffectVisualEffect(VFX_IMP_GOOD_HELP); break;
|
|
default: eVis = EffectVisualEffect(VFX_IMP_SUPER_HEROISM);
|
|
}
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
|
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCreature);
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oCreature, fDuration);
|
|
|
|
switch (nSpellID)
|
|
{
|
|
case SPELL_MAGIC_WEAPON:
|
|
AddItemEnhancementEffect(oWeapon, fDuration, 1);
|
|
if (nApplyToOffHand)
|
|
AddItemEnhancementEffect(oOffHand, fDuration, 1);
|
|
break;
|
|
case SPELL_GREATER_MAGIC_WEAPON:
|
|
AddItemEnhancementEffect(oWeapon, fDuration, min(nCasterLvl/3, 3));
|
|
if (nApplyToOffHand)
|
|
AddItemEnhancementEffect(oOffHand, fDuration, min(nCasterLvl/3, 3));
|
|
break;
|
|
case SPELL_KEEN_EDGE:
|
|
AddKeenEffectToWeapon(oWeapon, fDuration);
|
|
if (nApplyToOffHand)
|
|
AddKeenEffectToWeapon(oOffHand, fDuration);
|
|
break;
|
|
case SPELL_BLESS_WEAPON:
|
|
AddBlessEffectToWeapon(oWeapon, fDuration);
|
|
if (nApplyToOffHand)
|
|
AddBlessEffectToWeapon(oOffHand, fDuration);
|
|
break;
|
|
case SPELL_HOLY_SWORD:
|
|
TLVFXPillar(VFX_IMP_GOOD_HELP, GetLocation(GetSpellTargetObject()), 4, 0.0f, 6.0f);
|
|
AddHolyAvengerEffectToWeapon(oWeapon, fDuration);
|
|
if (nApplyToOffHand)
|
|
AddHolyAvengerEffectToWeapon(oOffHand, fDuration);
|
|
break;
|
|
case SPELL_BLADE_THIRST:
|
|
// If we targeted a creature that's dual wielding, apply +2 to both
|
|
if (GetSpellTargetObject() == oCreature &&
|
|
GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature) == oWeapon &&
|
|
util_IsWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature)))
|
|
{
|
|
AddItemEnhancementEffect(oWeapon, fDuration, 2);
|
|
AddItemEnhancementEffect(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature), fDuration, 2);
|
|
}
|
|
else
|
|
{
|
|
AddItemEnhancementEffect(oWeapon, fDuration, 3);
|
|
}
|
|
break;
|
|
case SPELL_FLAME_WEAPON:
|
|
case SPELL_DARKFIRE:
|
|
{
|
|
int nDamageType = GetLocalInt(oCaster, "SPELL_DAMAGE_TYPE");
|
|
if (nDamageType == 0)
|
|
{
|
|
SendMessageToPC(oCaster, "No damage type selected, defaulting to fire. Type '/dmg [f|c|l|a]' to select");
|
|
nDamageType = IP_CONST_DAMAGETYPE_FIRE;
|
|
}
|
|
AddItemEnergyEffect(oWeapon, fDuration, nDamageType, IP_CONST_DAMAGEBONUS_1d6);
|
|
if (nApplyToOffHand)
|
|
AddItemEnergyEffect(oOffHand, fDuration, nDamageType, IP_CONST_DAMAGEBONUS_1d6);
|
|
}
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
string sItemName = GetName(oWeapon);
|
|
if (nApplyToOffHand)
|
|
{
|
|
string sOffHandName = GetName(oOffHand);
|
|
if (sItemName == sOffHandName)
|
|
sItemName += " (Right Hand) and " + sOffHandName + " (Left Hand)";
|
|
else
|
|
sItemName += " and " + GetName(oOffHand);
|
|
}
|
|
|
|
if (GetIsObjectValid(oCreature) && oCreature != oCaster)
|
|
{
|
|
DelayCommand(1.0, FloatingTextStringOnCreature("You enchanted " + GetName(oCreature) + "'s " + sItemName, oCaster, FALSE));
|
|
DelayCommand(1.0, FloatingTextStringOnCreature(GetName(oCaster) + " enchanted your " + sItemName, oCreature, FALSE));
|
|
}
|
|
else if (oCreature == oCaster)
|
|
DelayCommand(1.0, FloatingTextStringOnCreature("You enchanted your " + sItemName, oCaster, FALSE));
|
|
else
|
|
DelayCommand(1.0, FloatingTextStringOnCreature("You enchanted the targeted " + sItemName, oCaster, FALSE));
|
|
}
|