Files
PRC8/nwn/nwnprc/trunk/psionics/psi_pow_clrhand.nss
Jaysyn904 f2fae74d01 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.
2026-04-25 21:01:33 -04:00

218 lines
11 KiB
Plaintext

/** @file psi_pow_clrhand
Clairtangent Hand
Clairsentience (Scrying)
Level: Seer 5
Display: Auditory, mental, and visual
Manifesting Time: 1 standard action
Range: See text
Area: See text
Duration: Up to 1 min./level; see text (D)
Saving Throw: None
Power Resistance: No
Power Points: 9
Metapsionics: Extend
You can see and hear some creature, which may be at any distance. Only Far Hand may be manifested while using this power.
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"
#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())
{
// 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)
{
// 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);
// 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);
}
} */