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.
528 lines
21 KiB
Plaintext
528 lines
21 KiB
Plaintext
/*
|
|
|
|
prc_spellf_inc.nss - Spellfire functions
|
|
|
|
|
|
|
|
By: Flaming_Sword
|
|
Created: February 15, 2006
|
|
Modified: February 15, 2006
|
|
|
|
Naming conventions:
|
|
nExpend <-> GetPersistantLocalInt(oPC, "SpellfireLevelExpend");
|
|
nStored <-> GetPersistantLocalInt(oPC, "SpellfireLevelStored");
|
|
|
|
*/
|
|
|
|
//#include "inc_utility"
|
|
//#include "prc_alterations"
|
|
#include "prc_inc_sp_tch"
|
|
#include "prcsp_engine"
|
|
//int CheckSpellfire(object oCaster, object oTarget, int bFriendly = FALSE);
|
|
|
|
//Spellfire Functions
|
|
|
|
//Verifies levels to expend, returns new levels to expend
|
|
int SpellfireVerifyExpend(object oPC, int nExpend, int nStored)
|
|
{
|
|
int nCON = GetAbilityScore(oPC, ABILITY_CONSTITUTION);
|
|
|
|
//sanity check, at least 1, capped by CON and stored
|
|
if(nExpend < 1)
|
|
{
|
|
nExpend = 1;
|
|
SetPersistantLocalInt(oPC, "SpellfireLevelExpend", nExpend);
|
|
}
|
|
if(nExpend > nCON) nExpend = nCON; //in case CON has changed
|
|
if(nExpend > nStored) nExpend = nStored; //can't spend more than you've got
|
|
|
|
return nExpend;
|
|
}
|
|
|
|
//Adjusts the number of spellfire levels expended
|
|
//in the next use of spellfire
|
|
void AdjustSpellfire(object oPC, int nAdjust)
|
|
{
|
|
int nExpend = GetPersistantLocalInt(oPC, "SpellfireLevelExpend");
|
|
nExpend += nAdjust;
|
|
if(nExpend < 1) nExpend = 1; //at least 1
|
|
SetPersistantLocalInt(oPC, "SpellfireLevelExpend", nExpend);
|
|
SendMessageToPC(oPC, "Spellfire levels to expend: " + IntToString(nExpend));
|
|
}
|
|
|
|
//Sets flag to change quickselects a la psionics
|
|
void SpellfireQuickselectChange(object oPC)
|
|
{
|
|
SetLocalInt(oPC, "Spellfire_Quickselect_Change", 1); //set flag
|
|
SendMessageToPC(oPC, "Select a quickselect to store the current setting");
|
|
DelayCommand(10.0, DeleteLocalInt(oPC, "Spellfire_Quickselect_Change")); //auto-delete
|
|
}
|
|
|
|
//Sets or changes quickselects
|
|
void SpellfireQuickselect(object oPC, int nSpellID)
|
|
{
|
|
int nExpend;
|
|
if(GetLocalInt(oPC, "Spellfire_Quickselect_Change"))
|
|
{
|
|
nExpend = GetPersistantLocalInt(oPC, "SpellfireLevelExpend");
|
|
SetPersistantLocalInt(oPC, "Spellfire_Quickselect_" + IntToString(nSpellID), nExpend);
|
|
SendMessageToPC(oPC, "Quickselect " + IntToString(nSpellID - SPELL_SPELLFIRE_QUICKSELECT_1 + 1) + " set to " + IntToString(nExpend));
|
|
DeleteLocalInt(oPC, "Spellfire_Quickselect_Change");
|
|
}
|
|
else
|
|
{
|
|
nExpend = GetPersistantLocalInt(oPC, "Spellfire_Quickselect_" + IntToString(nSpellID));
|
|
SetPersistantLocalInt(oPC, "SpellfireLevelExpend", nExpend);
|
|
SendMessageToPC(oPC, "Spellfire levels to expend: " + IntToString(nExpend));
|
|
}
|
|
}
|
|
|
|
//Expends spellfire and returns the new value
|
|
int ExpendSpellfire(object oPC)
|
|
{
|
|
int nStored = GetPersistantLocalInt(oPC, "SpellfireLevelStored");
|
|
if(!nStored) return 0;
|
|
int nExpend = GetPersistantLocalInt(oPC, "SpellfireLevelExpend");
|
|
|
|
nExpend = SpellfireVerifyExpend(oPC, nExpend, nStored);
|
|
|
|
nStored -= nExpend;
|
|
SetPersistantLocalInt(oPC, "SpellfireLevelStored", nStored);
|
|
return nExpend;
|
|
}
|
|
|
|
//Applies spellfire damage to target
|
|
void SpellfireDamage(object oCaster, object oTarget, int nRoll, int nDamage, int bMaelstrom = FALSE)
|
|
{
|
|
if(bMaelstrom)
|
|
{
|
|
//nDamage += ApplySpellBetrayalStrikeDamage(oTarget, oCaster);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, nDamage / 2, DAMAGE_TYPE_MAGICAL), oTarget);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage - (nDamage / 2), DAMAGE_TYPE_FIRE), oTarget);
|
|
}
|
|
else
|
|
ApplyTouchAttackDamage(oCaster, oTarget, nRoll, nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_TYPE_FIRE);
|
|
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SPELLF_FLAME), oTarget);
|
|
}
|
|
|
|
//Spellfire attack roll -> damage
|
|
void SpellfireAttackRoll(object oCaster, object oTarget, int nExpend, int iMod = 0, int nDC = 20, int bBeam = FALSE, int bMaelstrom = FALSE)
|
|
{
|
|
int nRoll, nDamage;
|
|
|
|
//Account for Energy Draconic Aura
|
|
if (GetLocalInt(oCaster, "FireEnergyAura") > 0)
|
|
{
|
|
nDC += GetLocalInt(oCaster, "FireEnergyAura");
|
|
}
|
|
|
|
//Weapon Focus (spellfire) applies to spellfire only
|
|
if(GetHasFeat(FEAT_WEAPON_FOCUS_SPELLFIRE, oCaster)) iMod++;
|
|
if(GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_SPELLFIRE, oCaster)) iMod += 2;
|
|
|
|
if(oCaster == oTarget) //yeah, like you could miss with a touch attack on yourself
|
|
{
|
|
nRoll = 1;
|
|
nDamage = d6(nExpend);
|
|
}
|
|
else
|
|
{
|
|
nRoll = bMaelstrom ? 1 : GetAttackRoll(oTarget, oCaster, GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCaster), 0, 0, iMod, TRUE, 0.0, TRUE);
|
|
nDamage = PRCGetReflexAdjustedDamage(d6(nExpend), oTarget, nDC, SAVING_THROW_TYPE_NONE, oCaster);
|
|
}
|
|
if(bBeam)
|
|
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBeam(VFX_BEAM_SPELLFIRE, oCaster, BODY_NODE_HAND, !nRoll), oTarget, 1.2 /*+ (0.5 * IntToFloat(nAttacks))*/);
|
|
if(nRoll && nDamage)
|
|
SpellfireDamage(oCaster, oTarget, nRoll, nDamage, bMaelstrom);
|
|
}
|
|
|
|
//Hits target with spellfire, implements rapid blast
|
|
void SpellfireAttack(object oCaster, object oTarget, int bBeam, int nAttacks = 1)
|
|
{
|
|
if(!GetPersistantLocalInt(oCaster, "SpellfireLevelStored"))
|
|
{
|
|
SendMessageToPC(oCaster, "You have no more stored spellfire levels");
|
|
return;
|
|
}
|
|
int nLevel = GetLevelByClass(CLASS_TYPE_SPELLFIRE, oCaster);
|
|
if(nAttacks > ((nLevel / 4) + 1))
|
|
{
|
|
SendMessageToPC(oCaster, "You do not have enough Spellfire Channeler levels use this feat");
|
|
return;
|
|
}
|
|
int iMod = 0;
|
|
int i;
|
|
//looping attacks
|
|
//SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBeam(VFX_BEAM_SPELLFIRE, oCaster, BODY_NODE_HAND, !nRoll), oTarget, 1.2 + (0.5 * IntToFloat(nAttacks)));
|
|
SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_SPELLFIRE_ATTACK));
|
|
for(i = 0; i < nAttacks; i++)
|
|
DelayCommand(0.5 * IntToFloat(i), SpellfireAttackRoll(oCaster, oTarget, ExpendSpellfire(oCaster), iMod - (2 * i), 20, bBeam));
|
|
//longer effect for more blasts
|
|
DelayCommand(0.1, SendMessageToPC(oCaster, "Spellfire levels stored: " + IntToString(GetPersistantLocalInt(oCaster, "SpellfireLevelStored"))));
|
|
}
|
|
|
|
//Heals target
|
|
void SpellfireHeal(object oCaster, object oTarget)
|
|
{
|
|
if(!GetPersistantLocalInt(oCaster, "SpellfireLevelStored"))
|
|
{
|
|
SendMessageToPC(oCaster, "You have no more stored spellfire levels");
|
|
return;
|
|
}
|
|
int nExpend = ExpendSpellfire(oCaster);
|
|
int nHeal = 2 * nExpend;
|
|
if(GetHasFeat(FEAT_SPELLFIRE_IMPROVED_HEALING, oCaster))
|
|
nHeal = d4(nExpend) + nExpend;
|
|
|
|
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nHeal), oTarget);
|
|
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SPELLF_HEAL), oTarget);
|
|
DelayCommand(0.1, SendMessageToPC(oCaster, "Spellfire levels stored: " + IntToString(GetPersistantLocalInt(oCaster, "SpellfireLevelStored"))));
|
|
}
|
|
|
|
//Maelstrom of fire
|
|
void SpellfireMaelstrom(object oCaster)
|
|
{
|
|
if(!GetPersistantLocalInt(oCaster, "SpellfireLevelStored"))
|
|
{
|
|
SendMessageToPC(oCaster, "You have no more stored spellfire levels");
|
|
return;
|
|
}
|
|
int nLevel = GetLevelByClass(CLASS_TYPE_SPELLFIRE, oCaster);
|
|
int nCHA = GetAbilityModifier(ABILITY_CHARISMA, oCaster);
|
|
int nDC = 10 + nLevel + nCHA;
|
|
|
|
//Account for Energy Draconic Aura
|
|
if (GetLocalInt(oCaster, "FireEnergyAura") > 0)
|
|
{
|
|
nDC += GetLocalInt(oCaster, "FireEnergyAura");
|
|
}
|
|
|
|
//expend once, hit multiple targets
|
|
int nExpend = ExpendSpellfire(oCaster);
|
|
float fDelay;
|
|
location lTarget = GetLocation(oCaster);
|
|
effect eExplode = EffectVisualEffect(VFX_FNF_SPELLF_EXP);
|
|
//KABOOM!
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget);
|
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
|
|
while(GetIsObjectValid(oTarget))
|
|
{
|
|
if(spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster))
|
|
{ //ripped off fireball
|
|
SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_SPELLFIRE_MAELSTROM));
|
|
//Get the distance between the explosion and the target to calculate delay
|
|
fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget)) / 20;
|
|
DelayCommand(fDelay, SpellfireAttackRoll(oCaster, oTarget, nExpend, 0, nDC, FALSE, TRUE));
|
|
}
|
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
|
|
}
|
|
}
|
|
|
|
//Returns the caster level of an item with the cast spell property
|
|
int GetItemCasterLevelFromCastSpell(object oItem, itemproperty ip)
|
|
{
|
|
int nCostTableValue = GetItemPropertyCostTableValue(ip);
|
|
int nSubtype = GetItemPropertySubType(ip);
|
|
int nCasterLevel = StringToInt(Get2DACache("iprp_spells", "CasterLvl", nSubtype));
|
|
|
|
itemproperty ip2 = GetFirstItemProperty(oItem);
|
|
while(GetIsItemPropertyValid(ip2))
|
|
{
|
|
if(GetItemPropertyType(ip2) == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL &&
|
|
//temporary caster level? i think not.
|
|
GetItemPropertyDurationType(ip2) == DURATION_TYPE_PERMANENT &&
|
|
GetItemPropertySubType(ip2) == nSubtype)
|
|
{
|
|
int nNewCasterLevel = GetItemPropertyCostTableValue(ip2); //caster level property
|
|
if(nNewCasterLevel > nCasterLevel) nCasterLevel = nNewCasterLevel;
|
|
break;
|
|
}
|
|
ip2 = GetNextItemProperty(oItem);
|
|
}
|
|
return nCasterLevel;
|
|
}
|
|
|
|
//Returns TRUE if an item is drained
|
|
int SpellfireDrainItem(object oPC, object oItem, int bCharged = TRUE, int bSingleUse = TRUE)
|
|
{
|
|
if(GetIsObjectValid(oItem) && GetIsMagicItem(oItem))
|
|
{ //drain charged item
|
|
if(bCharged) //because big compound if statements are messy
|
|
{
|
|
int nBase = GetBaseItemType(oItem);
|
|
int nExpend = GetPersistantLocalInt(oPC, "SpellfireLevelExpend");
|
|
if(nExpend < 1)
|
|
{
|
|
nExpend = 1;
|
|
SetPersistantLocalInt(oPC, "SpellfireLevelExpend", nExpend);
|
|
}
|
|
int nStored = GetPersistantLocalInt(oPC, "SpellfireLevelStored");
|
|
int nCap = SpellfireMax(oPC) - nStored;
|
|
itemproperty ip;
|
|
int nSubType;
|
|
int nStack = GetItemStackSize(oItem);
|
|
int nCharges = GetItemCharges(oItem);
|
|
if(nCharges) //charged item
|
|
{
|
|
nExpend = min(min(nCharges, nCap), nExpend); //capped by charges and capacity
|
|
SetItemCharges(oItem, nCharges - nExpend); //will destroy item if all charges drained
|
|
AddSpellfireLevels(oPC, nExpend); //adds 1 level/charge
|
|
return TRUE;
|
|
}
|
|
ip = GetFirstItemProperty(oItem);
|
|
while(GetIsItemPropertyValid(ip)) //single use item
|
|
{
|
|
if(GetItemPropertyType(ip) == ITEM_PROPERTY_CAST_SPELL &&
|
|
GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT &&
|
|
GetItemPropertyCostTableValue(ip) == IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE)
|
|
{
|
|
if(DEBUG)
|
|
{
|
|
DoDebug("SpellfireDrainItem(): nBase = " + IntToString(nBase), oPC);
|
|
DoDebug("SpellfireDrainItem(): nStack = " + IntToString(nStack), oPC);
|
|
DoDebug("SpellfireDrainItem(): nCap = " + IntToString(nCap), oPC);
|
|
DoDebug("SpellfireDrainItem(): nExpend = " + IntToString(nExpend), oPC);
|
|
}
|
|
nSubType = GetItemPropertySubType(ip);
|
|
//hardcoded filter
|
|
if(!(
|
|
(nSubType >= 329 && nSubType <= 344) ||
|
|
(nSubType == 359) ||
|
|
(nSubType >= 400 && nSubType <= 409) ||
|
|
(nSubType >= 411 && nSubType <= 446) ||
|
|
(nSubType >= 490 && nSubType <= 500) ||
|
|
(nSubType == 513) ||
|
|
(nSubType >= 521 && nSubType <= 537) ||
|
|
(nSubType >= 750 && nSubType <= 851) ||
|
|
(nSubType >= 1201)
|
|
))
|
|
{
|
|
|
|
if((nBase == BASE_ITEM_POTIONS) ||
|
|
(nBase == BASE_ITEM_SCROLL) ||
|
|
(nBase == BASE_ITEM_SPELLSCROLL) ||
|
|
(nBase == BASE_ITEM_BLANK_POTION) ||
|
|
(nBase == BASE_ITEM_BLANK_SCROLL) ||
|
|
(nBase == BASE_ITEM_ENCHANTED_POTION) ||
|
|
(nBase == BASE_ITEM_ENCHANTED_SCROLL)
|
|
)
|
|
{
|
|
nExpend = min(min(nStack, nCap), nExpend); //capped by charges and capacity
|
|
if(nExpend == nStack)
|
|
DestroyObject(oItem);
|
|
else
|
|
SetItemStackSize(oItem, nStack - nExpend); //modifies stack size as scrolls/potions are used up
|
|
AddSpellfireLevels(oPC, nExpend); //adds 1 level/charge
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
RemoveItemProperty(oItem, ip); //just removes the cast spell property
|
|
AddSpellfireLevels(oPC, 1); //adds 1 level
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
ip = GetNextItemProperty(oItem);
|
|
}
|
|
}
|
|
else //drain permanent item
|
|
{
|
|
itemproperty ip = GetFirstItemProperty(oItem);
|
|
int nCostTableValue = GetItemPropertyCostTableValue(ip);
|
|
while(GetIsItemPropertyValid(ip))
|
|
{
|
|
if(GetItemPropertyType(ip) == ITEM_PROPERTY_CAST_SPELL &&
|
|
GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT &&
|
|
nCostTableValue >= IP_CONST_CASTSPELL_NUMUSES_0_CHARGES_PER_USE)
|
|
{
|
|
nCostTableValue = GetItemPropertyCostTableValue(ip);
|
|
int nSubtype = GetItemPropertySubType(ip);
|
|
int nLevel = GetItemCasterLevelFromCastSpell(oItem, ip) / 2;
|
|
RemoveItemProperty(oItem, ip); //just removes the cast spell property
|
|
AddSpellfireLevels(oPC, nLevel); //adds half the caster level
|
|
|
|
DelayCommand(HoursToSeconds(24), //reapplying property
|
|
IPSafeAddItemProperty(oItem,
|
|
ItemPropertyCastSpell(nSubtype, nCostTableValue),
|
|
0.0,
|
|
X2_IP_ADDPROP_POLICY_KEEP_EXISTING));
|
|
return 1;
|
|
}
|
|
ip = GetNextItemProperty(oItem);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//Returns "'s" if sName has no s at the end, otherwise "'"
|
|
string Name_s(string sName = "")
|
|
{
|
|
return (GetStringRight(sName, 1) == "s") ? "'" : "'s";
|
|
}
|
|
|
|
//Finds an item to drain, favours equipped items
|
|
//WARNING: This will loop through every item property on every item
|
|
// until the right conditions are met
|
|
void SpellfireDrain(object oPC, object oTarget, int bCharged = TRUE, int bExemptCreatureItems = TRUE, int bSingleUse = TRUE)
|
|
{
|
|
object oItem;
|
|
int nObjectType = GetObjectType(oTarget);
|
|
string sMessage_oPC = "";
|
|
string sMessage_oTarget = "";
|
|
string sName_oPC = GetName(oPC);
|
|
string sName_oTarget = GetName(oTarget);
|
|
int bFound = 0;
|
|
|
|
if(nObjectType == OBJECT_TYPE_ITEM)
|
|
{
|
|
oItem = oTarget;
|
|
int nBase = GetBaseItemType(oItem);
|
|
if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_DRAIN_SCROLL_POTION) &&
|
|
((nBase == BASE_ITEM_POTIONS) ||
|
|
(nBase == BASE_ITEM_SCROLL) ||
|
|
(nBase == BASE_ITEM_BLANK_POTION) ||
|
|
(nBase == BASE_ITEM_BLANK_SCROLL)
|
|
)
|
|
)
|
|
{
|
|
sMessage_oPC = "Draining charges from scrolls and potions is not allowed";
|
|
}
|
|
else if(SpellfireDrainItem(oPC, oItem, bCharged))
|
|
{
|
|
bFound = 1;
|
|
sMessage_oPC = "You drained " + sName_oTarget;
|
|
}
|
|
}
|
|
else if(nObjectType == OBJECT_TYPE_CREATURE)
|
|
{
|
|
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, 10, SAVING_THROW_TYPE_NONE, oPC))
|
|
{
|
|
//creature items exempt
|
|
int nSlotMax = bExemptCreatureItems ? INVENTORY_SLOT_CWEAPON_L : NUM_INVENTORY_SLOTS;
|
|
//int nCharges = 0;
|
|
int i;
|
|
for(i = 0; i < nSlotMax; i++)
|
|
{
|
|
oItem = GetItemInSlot(i, oTarget);
|
|
if(SpellfireDrainItem(oPC, oItem, bCharged))
|
|
{
|
|
bFound = 1;
|
|
break;
|
|
}
|
|
}
|
|
oItem = GetFirstItemInInventory(oTarget);
|
|
if(bFound != 1)
|
|
{
|
|
while(GetIsObjectValid(oItem))
|
|
{
|
|
if(SpellfireDrainItem(oPC, oItem, bCharged))
|
|
{
|
|
bFound = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//search function
|
|
if(bFound)
|
|
{
|
|
sMessage_oPC = "You drained " + GetName(oItem) + " from " + sName_oTarget;
|
|
//sMessage_oTarget = sName_oPC + " drained " + GetName(oItem) " from you";
|
|
}
|
|
else
|
|
{
|
|
sMessage_oPC = "You tried to drain one of " + sName_oTarget + Name_s(sName_oTarget) + " items, but failed";
|
|
sMessage_oTarget = sName_oPC + " tried to drain one of your items, but failed";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sMessage_oPC = sName_oTarget + " resisted your attempt to drain one of <his/her> items";
|
|
sMessage_oTarget = "You resisted " + sName_oPC + Name_s(sName_oPC) + " attempt to drain one of your items";
|
|
}
|
|
}
|
|
else if(DEBUG)
|
|
DoDebug("SpellfireDrain(): Invalid target object", oPC);
|
|
|
|
if(bFound && !bCharged)
|
|
{
|
|
string s24 = " for 24 hours";
|
|
sMessage_oPC += s24;
|
|
sMessage_oTarget += s24;
|
|
}
|
|
|
|
if(GetIsPC(oPC) && sMessage_oPC != "") SendMessageToPC(oPC, sMessage_oPC);
|
|
if(GetIsPC(oTarget) && sMessage_oTarget != "") SendMessageToPC(oTarget, sMessage_oTarget);
|
|
}
|
|
|
|
//Toggles a flag
|
|
void SpellfireToggleAbsorbFriendly(object oPC)
|
|
{
|
|
if(GetLocalInt(oPC, "SpellfireAbsorbFriendly"))
|
|
{
|
|
DeleteLocalInt(oPC, "SpellfireAbsorbFriendly");
|
|
FloatingTextStringOnCreature("*Absorb Friendly Spells Off*", oPC);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "SpellfireAbsorbFriendly", 1);
|
|
FloatingTextStringOnCreature("*Absorb Friendly Spells On*", oPC);
|
|
}
|
|
}
|
|
|
|
//Charges items
|
|
void SpellfireChargeItem(object oPC, object oItem)
|
|
{
|
|
int nObjectType = GetObjectType(oItem);
|
|
if(nObjectType == OBJECT_TYPE_ITEM)
|
|
{
|
|
int nExpend = ExpendSpellfire(oPC);
|
|
int nCharges = GetItemCharges(oItem);
|
|
int nNewCharges = nExpend + nCharges;
|
|
if(nNewCharges > 50)
|
|
{
|
|
AddSpellfireLevels(oPC, nNewCharges - 50);
|
|
nNewCharges = 50;
|
|
}
|
|
SetItemCharges(oItem, nCharges + nExpend);
|
|
//Assuming 50 is the maximum
|
|
//refunding excess charges
|
|
}
|
|
else if(DEBUG)
|
|
DoDebug("SpellfireChargeItem(): Invalid target object", oPC);
|
|
}
|
|
|
|
//Applies Crown of Fire effects. Other effects are implemented
|
|
//through heartbeat and onhit scripts
|
|
void SpellfireCrown(object oPC)
|
|
{
|
|
if(GetLocalInt(oPC, "SpellfireCrown"))
|
|
{
|
|
DeleteLocalInt(oPC, "SpellfireCrown");
|
|
PRCRemoveEffectsFromSpell(oPC, SPELL_SPELLFIRE_CROWN);
|
|
FloatingTextStringOnCreature("*Crown of Fire Deactivated*", oPC);
|
|
}
|
|
else
|
|
{
|
|
if(GetPersistantLocalInt(oPC, "SpellfireLevelStored") < 10)
|
|
{
|
|
SendMessageToPC(oPC, "You do not have enough stored spellfire levels");
|
|
return;
|
|
}
|
|
SetLocalInt(oPC, "SpellfireCrown", 1);
|
|
effect eDmgred = EffectDamageReduction(10, DAMAGE_POWER_PLUS_ONE);
|
|
effect eResist = EffectSpellResistanceIncrease(32);
|
|
effect eCrown = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_POSITIVE);
|
|
effect eFlame = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD);
|
|
effect eLight = EffectVisualEffect(VFX_DUR_LIGHT_WHITE_20);
|
|
effect eLink = EffectLinkEffects(eDmgred, eResist);
|
|
eLink = EffectLinkEffects(eLink, eCrown);
|
|
eLink = EffectLinkEffects(eLink, eFlame);
|
|
eLink = EffectLinkEffects(eLink, eLight);
|
|
SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oPC);
|
|
FloatingTextStringOnCreature("*Crown of Fire Activated*", oPC);
|
|
}
|
|
}
|
|
|