Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
280 lines
11 KiB
Plaintext
280 lines
11 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Shadowcasting Mystery Hook File.
|
|
//:: shd_mysthook.nss
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
|
|
This file acts as a hub for all code that
|
|
is hooked into the mystery scripts for Shadowcasting
|
|
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Stratovarius
|
|
//:: Created On: 7-2-2019
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "x2_inc_spellhook"
|
|
#include "prc_inc_spells"
|
|
#include "inc_utility"
|
|
#include "prc_inc_itmrstr"
|
|
|
|
// This function holds all functions that are supposed to run before the actual
|
|
// spellscript gets run. If this functions returns FALSE, the spell is aborted
|
|
// and the spellscript will not run
|
|
int ShadPreMystCastCode();
|
|
|
|
// Does the counterspelling for Warp Spell,
|
|
// and the storing of the spell for later use
|
|
int WarpMyst(object oCaster, int nMyst)
|
|
{
|
|
int nWarp = GetLocalInt(oCaster, "WarpSpell");
|
|
// If Warp Spell isn't set, just keep going
|
|
if (!nWarp) return TRUE;
|
|
|
|
object oShadow = GetLocalObject(oCaster, "WarpSpell"); // The one who cast Warp Spell
|
|
|
|
DeleteLocalInt(oCaster, "WarpSpell");
|
|
DeleteLocalObject(oCaster, "WarpSpell");
|
|
|
|
int nLevel = GetShadowcasterLevel(oCaster);
|
|
if (d20() + nWarp > d20() + nLevel) // Won the caster level check
|
|
{
|
|
// Set a marker on the Shadowcaster
|
|
SetLocalInt(oShadow, "WarpSpellSuccess", TRUE);
|
|
FloatingTextStringOnCreature("You have successfully warped your opponent's "+GetMysteryName(nMyst), oShadow, FALSE);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SOUL_TRAP), oCaster);
|
|
return FALSE;
|
|
}
|
|
|
|
FloatingTextStringOnCreature("Your warp spell has failed", oShadow, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
// Stores the spell for use with Echo Spell
|
|
void EchoMyst(object oCaster, int nMyst)
|
|
{
|
|
int nEcho = GetLocalInt(oCaster, "EchoSpell");
|
|
// If Echo Spell isn't set, just skip
|
|
if (nEcho)
|
|
{
|
|
object oShadow = GetLocalObject(oCaster, "EchoSpell"); // The one who cast Echo Spell
|
|
SetLocalInt(oShadow, "EchoedSpell", nMyst);
|
|
FloatingTextStringOnCreature("You have echoed " + GetMysteryName(nMyst) + " and have one round to cast it", oShadow, FALSE);
|
|
DelayCommand(9.0, DeleteLocalInt(oShadow, "EchoedSpell"));
|
|
DeleteLocalInt(oCaster, "EchoSpell");
|
|
DeleteLocalObject(oCaster, "EchoSpell");
|
|
}
|
|
}
|
|
|
|
int MysterySpellFailure(object oShadow, int nMystId, int nMystLevel, int nClass)
|
|
{
|
|
// Mysteries of both types ignore arcane spell failure
|
|
if (GetIsMysterySupernatural(oShadow, nMystId, nClass) || GetIsMysterySLA(oShadow, nMystId, nClass))
|
|
return TRUE;
|
|
|
|
int nASF = GetArcaneSpellFailure(oShadow);
|
|
|
|
if(Random(100) < nASF)
|
|
{
|
|
int nFail = TRUE;
|
|
// Still spell helps
|
|
if((GetHasFeat(FEAT_EPIC_AUTOMATIC_STILL_SPELL_1, oShadow) && nMystLevel <= 3)
|
|
|| (GetHasFeat(FEAT_EPIC_AUTOMATIC_STILL_SPELL_2, oShadow) && nMystLevel <= 6)
|
|
|| (GetHasFeat(FEAT_EPIC_AUTOMATIC_STILL_SPELL_3, oShadow) && nMystLevel <= 9))
|
|
{
|
|
nFail = FALSE;
|
|
}
|
|
if(nFail)
|
|
{
|
|
//52946 = Spell failed due to arcane spell failure!
|
|
FloatingTextStrRefOnCreature(52946, oShadow, FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int ShadowTime(object oCaster, object oTarget, int bSpellIsHostile)
|
|
{
|
|
// PnP Timestop
|
|
if(GetPRCSwitch(PRC_TIMESTOP_NO_HOSTILE))
|
|
{
|
|
if(GetHasSpellEffect(SPELL_TIME_STOP, oCaster)
|
|
|| GetHasSpellEffect(4032, oCaster) //epic spell: Greater Timestop
|
|
|| GetHasSpellEffect(14236, oCaster) //psionic power: Temporal Acceleration
|
|
|| GetHasSpellEffect(18428, oCaster)) //Mystery MYST_SHADOW_TIME
|
|
{
|
|
if(!GetIsObjectValid(oTarget)
|
|
|| oTarget != oCaster
|
|
|| bSpellIsHostile)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// if FALSE is returned by this function, the spell will not be cast
|
|
// the order in which the functions are called here DOES MATTER, changing it
|
|
// WILL break the crafting subsystems
|
|
//------------------------------------------------------------------------------
|
|
int ShadPreMystCastCode()
|
|
{
|
|
object oShadow = OBJECT_SELF;
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
int nMystID = PRCGetSpellId();
|
|
int nMystLevel = GetMysteryLevel(oShadow);
|
|
int nShadowcastingClass = GetShadowcastingClass(oShadow);
|
|
int bMystIsHostile = Get2DACache("spells", "HostileSetting", nMystID) == "1";
|
|
|
|
int nContinue = !ExecuteScriptAndReturnInt("prespellcode",oShadow);
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Break any spell require maintaining concentration
|
|
//---------------------------------------------------------------------------
|
|
X2BreakConcentrationSpells();
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Check for PRC spell effects
|
|
//---------------------------------------------------------------------------
|
|
if(nContinue)
|
|
nContinue = PRCSpellEffects(oShadow, oTarget, nMystID, nMystLevel, nShadowcastingClass, bMystIsHostile, -1);
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #1: " + IntToString(nContinue));
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Run Arcane Spell Failure
|
|
//---------------------------------------------------------------------------
|
|
if (nContinue)
|
|
nContinue = MysterySpellFailure(oShadow, nMystID, nMystLevel, nShadowcastingClass);
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #2: " + IntToString(nContinue));
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Run Shadow Time
|
|
//---------------------------------------------------------------------------
|
|
if (nContinue)
|
|
nContinue = ShadowTime(oShadow, oTarget, bMystIsHostile);
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #3: " + IntToString(nContinue));
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Run Grappling Concentration Check
|
|
//---------------------------------------------------------------------------
|
|
if (nContinue)
|
|
nContinue = GrappleConc(oShadow, nMystLevel);
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #4: " + IntToString(nContinue));
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This stuff is only interesting for player characters we assume that use
|
|
// magic device always works and NPCs don't use the crafting feats or
|
|
// sequencers anyway. Thus, any NON PC spellcaster always exits this script
|
|
// with TRUE (unless they are DM possessed or in the Wild Magic Area in
|
|
// Chapter 2 of Hordes of the Underdark.
|
|
//---------------------------------------------------------------------------
|
|
if(!GetIsPC(oShadow)
|
|
&& !GetPRCSwitch(PRC_NPC_HAS_PC_SPELLCASTING))
|
|
{
|
|
if(!GetIsDMPossessed(oShadow) && !GetLocalInt(GetArea(oShadow), "X2_L_WILD_MAGIC"))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Run use magic device skill check
|
|
//---------------------------------------------------------------------------
|
|
if (nContinue)
|
|
{
|
|
nContinue = X2UseMagicDeviceCheck(oShadow);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// run any user defined spellscript here
|
|
//-----------------------------------------------------------------------
|
|
if (nContinue)
|
|
{
|
|
nContinue = X2RunUserDefinedSpellScript();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Check for the new restricted itemproperties
|
|
//---------------------------------------------------------------------------
|
|
if(nContinue
|
|
&& GetIsObjectValid(GetSpellCastItem())
|
|
&& !CheckPRCLimitations(GetSpellCastItem(), oShadow))
|
|
{
|
|
SendMessageToPC(oShadow, "You cannot use "+GetName(GetSpellCastItem()));
|
|
nContinue = FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Warp Spell
|
|
//---------------------------------------------------------------------------
|
|
if (nContinue)
|
|
{
|
|
nContinue = WarpMyst(oShadow, nMystID);
|
|
}
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #5: " + IntToString(nContinue));
|
|
|
|
EchoMyst(oShadow, nMystID);
|
|
|
|
//---------------------------------------------------------------------------
|
|
// The following code is only of interest if an item was targeted
|
|
//---------------------------------------------------------------------------
|
|
if (GetIsObjectValid(oTarget) && GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
|
|
{
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Check if spell was used to trigger item creation feat
|
|
//-----------------------------------------------------------------------
|
|
if (nContinue) {
|
|
nContinue = !ExecuteScriptAndReturnInt("x2_pc_craft", oShadow);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// * Execute item OnSpellCast At routing script if activated
|
|
//-----------------------------------------------------------------------
|
|
if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS) == TRUE)
|
|
{
|
|
SetUserDefinedItemEventNumber(X2_ITEM_EVENT_SPELLCAST_AT);
|
|
int nRet = ExecuteScriptAndReturnInt(GetUserDefinedItemEventScriptName(oTarget), oShadow);
|
|
if (nRet == X2_EXECUTE_SCRIPT_END)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Prevent any spell that has no special coding to handle targetting of items
|
|
// from being cast on items. We do this because we can not predict how
|
|
// all the hundreds spells in NWN will react when cast on items
|
|
//-----------------------------------------------------------------------
|
|
if (nContinue) {
|
|
nContinue = X2CastOnItemWasAllowed(oTarget);
|
|
}
|
|
}
|
|
|
|
//Cleaning spell variables used for holding the charge
|
|
if(!GetLocalInt(oShadow, "PRC_SPELL_EVENT"))
|
|
{
|
|
DeleteLocalInt(oShadow, "PRC_SPELL_CHARGE_COUNT");
|
|
DeleteLocalInt(oShadow, "PRC_SPELL_CHARGE_SPELLID");
|
|
DeleteLocalObject(oShadow, "PRC_SPELL_CONC_TARGET");
|
|
DeleteLocalInt(oShadow, "PRC_SPELL_METAMAGIC");
|
|
DeleteLocalManifestation(oShadow, "PRC_POWER_HOLD_MANIFESTATION");
|
|
DeleteLocalMystery(oShadow, "MYST_HOLD_MYST");
|
|
}
|
|
else if(GetLocalInt(oShadow, "PRC_SPELL_CHARGE_SPELLID") != PRCGetSpellId())
|
|
{ //Sanity check, in case something goes wrong with the action queue
|
|
DeleteLocalInt(oShadow, "PRC_SPELL_EVENT");
|
|
}
|
|
|
|
if(DEBUG) DoDebug("ShadPreMystCastCode nContinue #6: " + IntToString(nContinue));
|
|
return nContinue;
|
|
} |