2026/04/25 Update

Tentatively fixed scrying for NWN:EE.
Added SCRY_AREA_BLOCKED & SCRY_FROM_AREA_BLOCKED area variables to control scrying.
Updated all scrying spells, powers & abilities  to use the above variables.
This commit is contained in:
Jaysyn904
2026-04-25 21:01:33 -04:00
parent 5d111437e0
commit f2fae74d01
16 changed files with 628 additions and 208 deletions

View File

@@ -232,11 +232,13 @@ void ScryMain(object oPC, object oTarget)
// Create the copy
oCopy = CopyObject(oPC, lTarget, OBJECT_INVALID, GetName(oPC) + "_" + COPY_LOCAL_NAME);
CleanCopy(oCopy);
// Attempted Fix to the Copy get's murdered problem.
int nMaxHenchmen = GetMaxHenchmen();
SetMaxHenchmen(99);
AddHenchman(oPC, oCopy);
SetMaxHenchmen(nMaxHenchmen);
// Attempted Fix to the Copy get's murdered problem.
//int nMaxHenchmen = GetMaxHenchmen();
//SetMaxHenchmen(99);
//AddHenchman(oPC, oCopy);
//SetMaxHenchmen(nMaxHenchmen);
SetIsTemporaryFriend(oPC, oCopy, FALSE);
// Set the copy to be undestroyable, so that it won't vanish to the ether
// along with the PC's items.
@@ -357,7 +359,7 @@ void DoScryEnd(object oPC, object oCopy)
PRCRemoveSpellEffects(SPELL_PNP_SCRY_FAMILIAR, oPC, oPC);
PRCRemoveSpellEffects(SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE, oPC, oPC);
PRCRemoveSpellEffects(POWER_CLAIRTANGENT_HAND, oPC, oPC);
// Remove the local signifying that the PC is a projection
DeleteLocalInt(oPC, "Scry_Active");
@@ -400,7 +402,7 @@ void DoScryEnd(object oPC, object oCopy)
// VFX
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eLight, lCopy, 3.0);
DestroyObject(oCopy);
//DestroyObject(oCopy);
//Remove duration marker
DeleteLocalInt(oPC, "SCRY_EXPIRED");
@@ -409,12 +411,94 @@ void DoScryEnd(object oPC, object oCopy)
//Runs tests to see if the projection effect can still continue.
//If the PC has reached 1 HP, end projection normally.
//If the copy is dead, end projection and kill the PC.
void ScryMonitor(object oPC, object oCopy)
void ScryMonitor(object oPC, object oCopy)
{
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor():\n"
+ "oPC = '" + GetName(oPC) + "'\n"
+ "oCopy = '" + GetName(oCopy) + "'"
);
// Abort if the projection is no longer marked as being active
if(!GetLocalInt(oPC, "Scry_Active"))
return;
// Some paranoia in case something interfered and either PC or copy has been destroyed
if(!(GetIsObjectValid(oPC) && GetIsObjectValid(oCopy))){
WriteTimestampedLogEntry("Baelnorn Projection hearbeat aborting due to an invalid object. Object status:" +
"\nPC - " + (GetIsObjectValid(oPC) ? "valid":"invalid") +
"\nCopy - " + (GetIsObjectValid(oCopy) ? "valid":"invalid"));
return;
}
// Start the actual work by checking the copy's status. The death thing should take priority
if(GetIsDead(oCopy))
{
if (DEBUG) DoDebug("prc_inc_scry: Copy is dead, killing PC");
DoScryEnd(oPC, oCopy);
effect eKill = EffectDamage(9999, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);
DelayCommand(3.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eKill, oPC));
}
else
{
// Check if the "projection" has been destroyed or if some other event has caused the projection to end
if(GetLocalInt(oPC, "Scry_Abort"))
{
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor(): The Projection has been terminated, ending projection");
DoScryEnd(oPC, oCopy);
}
else
{
// This makes sure you are invisible.
//AssignCommand(oPC, ClearAllActions(TRUE));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectEthereal()), oPC, SCRY_HB_DELAY + 0.3);
DelayCommand(SCRY_HB_DELAY, ScryMonitor(oPC, oCopy));
}
// Skip destructive cleanup triggers for Clairtangent Hand
if(GetLocalInt(oPC, "ScrySpellId") != POWER_CLAIRTANGENT_HAND)
{
//If duration expired, end effect
if(GetLocalInt(oPC, "SCRY_EXPIRED"))
{
DoScryEnd(oPC, oCopy);
}
// End due to being in combat, except for ephemeral image
if(GetIsInCombat(oPC) && GetLocalInt(oPC, "ScrySpellId") != MYST_EPHEMERAL_IMAGE)
{
DoScryEnd(oPC, oCopy);
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor(): Scryer in combat, ending projection");
AssignCommand(oPC, ClearAllActions(TRUE));
}
// In PnP, once you lose line of effect, the spell ends
float fDistance = FeetToMeters(100.0 + GetLocalInt(oPC, "ScryCasterLevel") * 10.0);
if (GetLocalInt(oPC, "ScrySpellId") == MYST_EPHEMERAL_IMAGE && GetDistanceBetween(oPC, oCopy) > fDistance)
{
DoScryEnd(oPC, oCopy);
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor(): Ephemeral Image distance exceeded, ending projection");
AssignCommand(oPC, ClearAllActions(TRUE));
}
}
}
}
/* void ScryMonitor(object oPC, object oCopy)
{
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor():\n"
if(DEBUG) DoDebug("prc_inc_scry: ScryMonitor():\n"
+ "oPC = '" + GetName(oPC) + "'\n"
+ "oCopy = '" + GetName(oCopy) + "'"
);
// Skip automatic cleanup for Clairtangent Hand
if(GetLocalInt(oPC, "ScrySpellId") == POWER_CLAIRTANGENT_HAND)
{
// Only apply ethereal effect and reschedule
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectEthereal()), oPC, SCRY_HB_DELAY + 0.3);
DelayCommand(SCRY_HB_DELAY, ScryMonitor(oPC, oCopy));
return;
}
// Abort if the projection is no longer marked as being active
if(!GetLocalInt(oPC, "Scry_Active"))
return;
@@ -473,6 +557,7 @@ void ScryMonitor(object oPC, object oCopy)
}
}
}
*/
//Undoes changes made in ApplyScryEffects().
void RemoveScryEffects(object oPC)
@@ -498,6 +583,14 @@ void RemoveScryEffects(object oPC)
IPRemoveMatchingItemProperties(oWeapon, ITEM_PROPERTY_NO_DAMAGE, DURATION_TYPE_PERMANENT);
}
effect eEffect = GetFirstEffect(oPC);
while(GetIsEffectValid(eEffect))
{
if(GetEffectTag(eEffect) == "SCRYING_TAG")
RemoveEffect(oPC, eEffect);
eEffect = GetNextEffect(oPC);
}
array_delete(oPC, "Scry_Nerfed");
}

View File

@@ -130,7 +130,14 @@ void main()
if(myst.bCanMyst)
{
//Declare major variables
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oShadow), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oShadow, FALSE);
return;
}
//Declare major variables
myst.fDur = RoundsToSeconds(myst.nShadowcasterLevel);
if(myst.bExtend) myst.fDur *= 2;

View File

@@ -29,7 +29,14 @@ void main()
if(myst.bCanMyst)
{
myst.fDur = TurnsToSeconds(myst.nShadowcasterLevel);
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oShadow), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oShadow, FALSE);
return;
}
myst.fDur = TurnsToSeconds(myst.nShadowcasterLevel);
if(myst.bExtend) myst.fDur *= 2;
SetLocalInt(oShadow, "ScryCasterLevel", myst.nShadowcasterLevel);
SetLocalInt(oShadow, "ScrySpellId", myst.nMystId);

View File

@@ -141,6 +141,13 @@ void main()
object oShadow = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
struct mystery myst = EvaluateMystery(oShadow, oTarget, METASHADOW_EXTEND);
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oShadow), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oShadow, FALSE);
return;
}
if(myst.bCanMyst)
{

View File

@@ -19,139 +19,200 @@ You can see and hear some creature, which may be at any distance. Only Far Hand
Valid targets are any monster within the same area as the caster, or any PC.
*/
#include "psi_inc_psifunc"
#include "psi_inc_pwresist"
#include "psi_spellhook"
#include "inc_dynconv"
void ApplyScryEffects(object oManifester)
{
if(DEBUG) DoDebug("prc_inc_scry: ApplyScryEffects():\n"
+ "oManifester = '" + GetName(oManifester) + "'"
);
// The Scryer is not supposed to be visible, nor can he move or cast
// He also can't take damage from scrying
effect eLink = EffectSpellImmunity(SPELL_ALL_SPELLS);
// Damage immunities
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, 100));
// Specific immunities
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_BLINDNESS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DEAFNESS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_CRITICAL_HIT));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DEATH));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DISEASE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_ENTANGLE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SLOW));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_KNOCKDOWN));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_NEGATIVE_LEVEL));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_PARALYSIS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SILENCE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SNEAK_ATTACK));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_TRAP));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS));
// Random stuff
eLink = EffectLinkEffects(eLink, EffectCutsceneGhost());
eLink = EffectLinkEffects(eLink, EffectCutsceneImmobilize());
eLink = EffectLinkEffects(eLink, EffectEthereal());
eLink = EffectLinkEffects(eLink, EffectAttackDecrease(50));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY));
// Permanent until Scry ends
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oManifester, GetLocalFloat(oManifester, "ScryDuration") + 6.0);
// Create array for storing a list of the nerfed weapons in
array_create(oManifester, "Scry_Nerfed");
object oWeapon;
itemproperty ipNoDam = ItemPropertyNoDamage();
oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oManifester);
if(IPGetIsMeleeWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}
// Check left hand only if right hand had a weapon
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oManifester);
if(IPGetIsMeleeWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
}else if(IPGetIsRangedWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
#include "psi_inc_psifunc"
#include "psi_inc_pwresist"
#include "psi_spellhook"
#include "inc_dynconv"
#include "prc_inc_scry"
void ApplyScryEffects(object oManifester)
{
if(DEBUG) DoDebug("prc_inc_scry: ApplyScryEffects():\n"
+ "oManifester = '" + GetName(oManifester) + "'"
);
// The Scryer is not supposed to be visible, nor can he move or cast
// He also can't take damage from scrying
effect eLink = EffectSpellImmunity(SPELL_ALL_SPELLS);
// Damage immunities
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, 100));
eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, 100));
// Specific immunities
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_BLINDNESS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DEAFNESS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_CRITICAL_HIT));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DEATH));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_DISEASE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_ENTANGLE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SLOW));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_KNOCKDOWN));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_NEGATIVE_LEVEL));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_PARALYSIS));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SILENCE));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_SNEAK_ATTACK));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_TRAP));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS));
// Random stuff
eLink = EffectLinkEffects(eLink, EffectCutsceneGhost());
eLink = EffectLinkEffects(eLink, EffectCutsceneImmobilize());
eLink = EffectLinkEffects(eLink, EffectEthereal());
eLink = EffectLinkEffects(eLink, EffectAttackDecrease(50));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY));
eLink = TagEffect(eLink, "SCRYING_TAG");
// Permanent until Scry ends
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oManifester, GetLocalFloat(oManifester, "ScryDuration") + 6.0);
// Create array for storing a list of the nerfed weapons in
array_create(oManifester, "Scry_Nerfed");
object oWeapon;
itemproperty ipNoDam = ItemPropertyNoDamage();
oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oManifester);
if(IPGetIsMeleeWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}
// Check left hand only if right hand had a weapon
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oManifester);
if(IPGetIsMeleeWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
}else if(IPGetIsRangedWeapon(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oManifester);
if(GetIsObjectValid(oWeapon)){
if(!GetItemHasItemProperty(oWeapon, ITEM_PROPERTY_NO_DAMAGE)){
//SetLocalInt(oWeapon, "BaelnornProjection_NoDamage", TRUE);
AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
array_set_object(oManifester, "Scry_Nerfed", array_get_size(oManifester, "Scry_Nerfed"), oWeapon);
}}
}
void CheckAndReapplyEffects(object oManifester)
{
// Only apply effects if we're the real body (not the copy)
if(GetStringLeft(GetTag(oManifester), 5) != "Scry_")
{
ApplyScryEffects(oManifester);
}
}
void main()
{
if (!PsiPrePowerCastCode())
void main()
{
if (!PsiPrePowerCastCode())
{
// If code within the PrePowerCastHook (i.e. UMD) reports FALSE, do not run this spell
return;
}
// End of Spell Cast Hook
object oManifester = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
struct manifestation manif =
EvaluateManifestation(oManifester, oTarget,
PowerAugmentationProfile(),
METAPSIONIC_EXTEND
);
if(manif.bCanManifest)
{
// If code within the PrePowerCastHook (i.e. UMD) reports FALSE, do not run this spell
return;
}
// End of Spell Cast Hook
object oManifester = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
struct manifestation manif =
EvaluateManifestation(oManifester, oTarget,
PowerAugmentationProfile(),
METAPSIONIC_EXTEND
);
if(manif.bCanManifest)
{
float fDur = 60.0 * manif.nManifesterLevel;
if(manif.bExtend) fDur *= 2;
SetLocalInt(oManifester, "ScryCasterLevel", manif.nManifesterLevel);
SetLocalInt(oManifester, "ScrySpellId", manif.nSpellID);
SetLocalFloat(oManifester, "ScryDuration", fDur);
SetLocalInt(oManifester, "ScrySpellDC", GetManifesterDC(oManifester));
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oManifester), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oManifester, FALSE);
return;
}
float fDur = 60.0 * manif.nManifesterLevel;
if(manif.bExtend) fDur *= 2;
SetLocalInt(oManifester, "ScryCasterLevel", manif.nManifesterLevel);
SetLocalInt(oManifester, "ScrySpellId", manif.nSpellID);
SetLocalFloat(oManifester, "ScryDuration", fDur);
SetLocalInt(oManifester, "ScrySpellDC", GetManifesterDC(oManifester));
// Clear any existing Clairtangent Hand effects before copy creation
PRCRemoveSpellEffects(POWER_CLAIRTANGENT_HAND, oManifester, oManifester);
// Set flag to reapply effects after scry system completes setup
SetLocalInt(oManifester, "ClrHand_ReapplyEffects", TRUE);
StartDynamicConversation("prc_scry_conv", oManifester, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oManifester);
StartDynamicConversation("prc_scry_conv", oManifester, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oManifester);
// Apply the immunity effects
ApplyScryEffects(oManifester);
}
}
// Reapply effects after scry system setup
DelayCommand(2.0f, CheckAndReapplyEffects(oManifester));
// Apply the immunity effects
//ApplyScryEffects(oManifester);
}
}
/* void main()
{
if (!PsiPrePowerCastCode())
{
// If code within the PrePowerCastHook (i.e. UMD) reports FALSE, do not run this spell
return;
}
// End of Spell Cast Hook
object oManifester = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
struct manifestation manif =
EvaluateManifestation(oManifester, oTarget,
PowerAugmentationProfile(),
METAPSIONIC_EXTEND
);
if(manif.bCanManifest)
{
float fDur = 60.0 * manif.nManifesterLevel;
if(manif.bExtend) fDur *= 2;
SetLocalInt(oManifester, "ScryCasterLevel", manif.nManifesterLevel);
SetLocalInt(oManifester, "ScrySpellId", manif.nSpellID);
SetLocalFloat(oManifester, "ScryDuration", fDur);
SetLocalInt(oManifester, "ScrySpellDC", GetManifesterDC(oManifester));
StartDynamicConversation("prc_scry_conv", oManifester, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oManifester);
// Apply the immunity effects
ApplyScryEffects(oManifester);
}
} */

View File

@@ -151,7 +151,14 @@ void main()
if(manif.bCanManifest)
{
float fDur = 60.0 * manif.nManifesterLevel;
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oManifester), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oManifester, FALSE);
return;
}
float fDur = 60.0 * manif.nManifesterLevel;
if(manif.bExtend) fDur *= 2;
SetLocalInt(oManifester, "ScryCasterLevel", manif.nManifesterLevel);

View File

@@ -150,7 +150,14 @@ void main()
if(manif.bCanManifest)
{
float fDur = 60.0 * manif.nManifesterLevel;
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oManifester), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oManifester, FALSE);
return;
}
float fDur = 60.0 * manif.nManifesterLevel;
if(manif.bExtend) fDur *= 2;
SetLocalInt(oManifester, "ScryCasterLevel", manif.nManifesterLevel);

View File

@@ -5,19 +5,20 @@ void main()
{
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_ILLUSION);
/*
Spellcast Hook Code
Added 2003-06-23 by GeorgZ
If you want to make changes to all spells,
check x2_inc_spellhook.nss to find out more
*/
if (!X2PreSpellCastCode())
{
// If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(OBJECT_SELF), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", OBJECT_SELF, FALSE);
return;
}
int nDuration = GetLevelByTypeArcane();
SetLocalInt(OBJECT_SELF, "ScryCasterLevel", nDuration);

View File

@@ -114,10 +114,10 @@ void ApplyScryEffects(object oPC)
void main()
{
object oPC = OBJECT_SELF;
object oPC = OBJECT_SELF;
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
if (!X2PreSpellCastCode())
{
@@ -125,26 +125,33 @@ SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nSpell = PRCGetSpellId();
float fDur = 60.0 * nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
//Make Metamagic check for extend
if ((nMetaMagic & METAMAGIC_EXTEND))
{
fDur = fDur * 2;
}
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
SetLocalInt(oPC, "ScrySpellId", nSpell);
SetLocalFloat(oPC, "ScryDuration", fDur);
StartDynamicConversation("prc_scry_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
// Apply the immunity effects
ApplyScryEffects(oPC);
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nSpell = PRCGetSpellId();
float fDur = 60.0 * nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
//Make Metamagic check for extend
if ((nMetaMagic & METAMAGIC_EXTEND))
{
fDur = fDur * 2;
}
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
SetLocalInt(oPC, "ScrySpellId", nSpell);
SetLocalFloat(oPC, "ScryDuration", fDur);
StartDynamicConversation("prc_scry_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
// Apply the immunity effects
ApplyScryEffects(oPC);
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
// Getting rid of the integer used to hold the spells spell school

View File

@@ -26,8 +26,6 @@ const int STAGE_CONFIRMATION = 1;
//////////////////////////////////////////////////
/* Aid functions */
//////////////////////////////////////////////////
void StorePCForRecovery(object oPC, object oChoice, int nChoice)
{
SetLocalObject(oPC, "ScryTarget" + IntToString(nChoice), oChoice);
@@ -38,7 +36,188 @@ object RetrievePC(object oPC, int nChoice)
return GetLocalObject(oPC, "ScryTarget" + IntToString(nChoice));
}
void AddLegalTargets(object oPC)
void AddLegalTargets(object oPC)
{
// This reads all of the legal choices
int nSpellId = GetLocalInt(oPC, "ScrySpellId");
int nChoice = 1;
int nDebugCounter = 0; // Add debug counter for frequency limiting
if (nSpellId == SPELL_LOCATE_OBJECT)
{
// First, get all objects in the area you're in
object oObject = GetFirstObjectInArea(GetArea(oPC));
while (GetIsObjectValid(oObject) == TRUE)
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " objects");
// Don't target PCs using this
if (GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE || GetObjectType(oObject) == OBJECT_TYPE_ITEM)
{
// Check if object's area blocks scrying
if(!GetLocalInt(GetArea(oObject), "SCRY_AREA_BLOCKED"))
{
// If its a legal object, target it for locating
AddChoice(GetName(oObject), nChoice, oPC);
StorePCForRecovery(oPC, oObject, nChoice);
}
}
nChoice += 1;
oObject = GetNextObjectInArea(GetArea(oPC));
}
}
else
{
// First, get all creatures in the area you're in
object oCreature = GetFirstObjectInArea(GetArea(oPC));
while (GetIsObjectValid(oCreature) == TRUE)
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " creatures");
// Don't target PCs using this
if (GetObjectType(oCreature) == OBJECT_TYPE_CREATURE)
{
// Check if creature's area blocks scrying
if(!GetLocalInt(GetArea(oCreature), "SCRY_AREA_BLOCKED"))
{
// This can target PCs in the area, but not in other areas
if ((nSpellId == SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE ||
nSpellId == SPELL_LOCATE_CREATURE ||
nSpellId == MYST_TRAIL_OF_HAZE ||
nSpellId == POWER_CLAIRVOYANT_SENSE) &&
oPC != oCreature &&
!GetIsDM(oCreature))
{
AddChoice(GetName(oCreature), nChoice, oPC);
StorePCForRecovery(oPC, oCreature, nChoice);
}
// Normally, the second part takes care of all PCs
else if ((!GetIsPC(oCreature) && !GetIsDM(oCreature)))
{
AddChoice(GetName(oCreature), nChoice, oPC);
StorePCForRecovery(oPC, oCreature, nChoice);
}
}
}
nChoice += 1;
oCreature = GetNextObjectInArea(GetArea(oPC));
}
// These only target in their own areas
if (nSpellId != SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE &&
nSpellId != SPELL_LOCATE_CREATURE &&
nSpellId != MYST_TRAIL_OF_HAZE &&
nSpellId != POWER_CLAIRVOYANT_SENSE)
{
// Now, loop through all of the PCs
object oPCTarget = GetFirstPC();
// Don't target yourself
while (GetIsObjectValid(oPCTarget))
{
if(oPCTarget != oPC && !GetIsDM(oPCTarget))
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " PC targets");
// Check if PC's area blocks scrying
if(!GetLocalInt(GetArea(oPCTarget), "SCRY_AREA_BLOCKED"))
{
AddChoice(GetName(oPCTarget), nChoice, oPC);
StorePCForRecovery(oPC, oPCTarget, nChoice);
}
nChoice += 1;
}
oPCTarget = GetNextPC();
}
}
}
}
/* void AddLegalTargets(object oPC)
{
// This reads all of the legal choices
int nSpellId = GetLocalInt(oPC, "ScrySpellId");
int nChoice = 1;
int nDebugCounter = 0; // Add debug counter for frequency limiting
if (nSpellId == SPELL_LOCATE_OBJECT)
{
// First, get all objects in the area you're in
object oObject = GetFirstObjectInArea(GetArea(oPC));
while (GetIsObjectValid(oObject) == TRUE)
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " objects");
// Don't target PCs using this
if (GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE || GetObjectType(oObject) == OBJECT_TYPE_ITEM)
{
// If its a legal object, target it for locating
AddChoice(GetName(oObject), nChoice, oPC);
StorePCForRecovery(oPC, oObject, nChoice);
}
nChoice += 1;
oObject = GetNextObjectInArea(GetArea(oPC));
}
}
else
{
// First, get all creatures in the area you're in
object oCreature = GetFirstObjectInArea(GetArea(oPC));
while (GetIsObjectValid(oCreature) == TRUE)
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " creatures");
// Don't target PCs using this
if (GetObjectType(oCreature) == OBJECT_TYPE_CREATURE)
{
// This can target PCs in the area, but not in other areas
if ((nSpellId == SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE ||
nSpellId == SPELL_LOCATE_CREATURE ||
nSpellId == MYST_TRAIL_OF_HAZE ||
nSpellId == POWER_CLAIRVOYANT_SENSE) &&
oPC != oCreature &&
!GetIsDM(oCreature))
{
AddChoice(GetName(oCreature), nChoice, oPC);
StorePCForRecovery(oPC, oCreature, nChoice);
}
// Normally, the second part takes care of all PCs
else if ((!GetIsPC(oCreature) && !GetIsDM(oCreature)))
{
AddChoice(GetName(oCreature), nChoice, oPC);
StorePCForRecovery(oPC, oCreature, nChoice);
}
}
nChoice += 1;
oCreature = GetNextObjectInArea(GetArea(oPC));
}
// These only target in their own areas
if (nSpellId != SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE &&
nSpellId != SPELL_LOCATE_CREATURE &&
nSpellId != MYST_TRAIL_OF_HAZE &&
nSpellId != POWER_CLAIRVOYANT_SENSE)
{
// Now, loop through all of the PCs
object oPCTarget = GetFirstPC();
// Don't target yourself
while (GetIsObjectValid(oPCTarget))
{
if(oPCTarget != oPC && !GetIsDM(oPCTarget))
{
if(DEBUG && (++nDebugCounter % 10 == 0))
DoDebug("prc_scry_conv: Processed " + IntToString(nDebugCounter) + " PC targets");
AddChoice(GetName(oPCTarget), nChoice, oPC);
StorePCForRecovery(oPC, oPCTarget, nChoice);
nChoice += 1;
}
oPCTarget = GetNextPC();
}
}
}
}
*/
/* void AddLegalTargets(object oPC)
{
// This reads all of the legal choices
int nSpellId = GetLocalInt(oPC, "ScrySpellId");
@@ -116,7 +295,7 @@ void AddLegalTargets(object oPC)
}
}
}
*/
//////////////////////////////////////////////////
/* Main function */
//////////////////////////////////////////////////
@@ -220,6 +399,7 @@ void main()
if (GetIsSkillSuccessful(oPC, SKILL_TRUESPEAK, nDC))
{ // The function will take it from here
ScryMain(oPC, oChoice);
}
else // Clean up effects
{
@@ -230,6 +410,7 @@ void main()
{
// The function will take it from here
ScryMain(oPC, oChoice);
}
// And we're all done

View File

@@ -129,6 +129,13 @@ SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);

View File

@@ -28,6 +28,13 @@ SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);

View File

@@ -114,41 +114,48 @@ void ApplyScryEffects(object oPC)
void main()
{
object oPC = OBJECT_SELF;
object oPC = OBJECT_SELF;
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
if (!X2PreSpellCastCode())
{
// If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nSpell = PRCGetSpellId();
int nDC = PRCGetSaveDC(oTarget, oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
//Make Metamagic check for extend
if ((nMetaMagic & METAMAGIC_EXTEND))
{
fDur = fDur * 2;
}
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
SetLocalInt(oPC, "ScrySpellId", nSpell);
SetLocalInt(oPC, "ScrySpellDC", nDC);
SetLocalFloat(oPC, "ScryDuration", fDur);
//AssignCommand(oPC, ClearAllActions(TRUE));
StartDynamicConversation("prc_scry_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
// Apply the immunity effects
ApplyScryEffects(oPC);
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nSpell = PRCGetSpellId();
int nDC = PRCGetSaveDC(oTarget, oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
//Make Metamagic check for extend
if ((nMetaMagic & METAMAGIC_EXTEND))
{
fDur = fDur * 2;
}
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
SetLocalInt(oPC, "ScrySpellId", nSpell);
SetLocalInt(oPC, "ScrySpellDC", nDC);
SetLocalFloat(oPC, "ScryDuration", fDur);
//AssignCommand(oPC, ClearAllActions(TRUE));
StartDynamicConversation("prc_scry_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
// Apply the immunity effects
ApplyScryEffects(oPC);
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
// Getting rid of the integer used to hold the spells spell school
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
// Getting rid of the integer used to hold the spells spell school
}

View File

@@ -28,6 +28,13 @@ SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);

View File

@@ -28,6 +28,13 @@ SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_DIVINATION);
return;
}
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
//Declare major variables
object oTarget;
int nCasterLvl = PRCGetCasterLevel(oPC);

View File

@@ -130,7 +130,14 @@ void main()
if(nMetaMagic & METAMAGIC_EXTEND)
fDur *= 2;
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
// Check if current area blocks scrying
if(GetLocalInt(GetArea(oPC), "SCRY_FROM_AREA_BLOCKED"))
{
FloatingTextStringOnCreature("This area prevents scrying.", oPC, FALSE);
return;
}
SetLocalInt(oPC, "ScryCasterLevel", nCasterLvl);
SetLocalInt(oPC, "ScrySpellId", nSpell);
SetLocalInt(oPC, "ScrySpellDC", nDC);
SetLocalFloat(oPC, "ScryDuration", fDur);