2026/05/28 Afternoon update
Updated damagtypes.2da for CEP3 reserved rows. Added and setup Darkvision icon. Added and setup Ultravision icon. Added spell icon for Thicket of Blades. Fixed Blacklight, Cloud of the Archeai, Darkness, Deeper Darkness, Damning Darkness, Utterdark, Grasping Shadows, Dawn and Dusk and Child of Shadow and Light for Telflammar Shadowlord's Shadow Blur and Shadow Sight abilities. Updated Blacklight's TLK entry. Created a constant for Shadow Discorporation. Fixed Shadow Time never ending on the targets. Updated prc_inc_combat to use monk iterative progression if warranted. Updated PRCGetIsRealSpellKnownByClass() to handle Sublime Chord better. (@Lightbeard) Added class heartbeat script for Shadowlord to handle Shadow Blur and Shadow Sight. Added ShadowlordEffects() to prc_inc_spells. Added constants for new damagetypes. Completely rewrote Verminlord's Vermin Domination. Fixed duration for Empathic Feedback. Fixed Morality Undone to not break characters over a server reset.
This commit is contained in:
@@ -73,6 +73,7 @@ void RemoveTSFromObject(object oTarget)
|
||||
|| nSpellId == 14205 // POWER_TEMPORALACCELERATION
|
||||
|| nSpellId == 17366 // MOVE_DM_MOMENT_ALACRITY
|
||||
|| nSpellId == 17511 // MOVE_WR_WHITE_RAVEN_TACTICS
|
||||
|| nSpellId == 18428 // MYST_SHADOW_TIME
|
||||
)
|
||||
RemoveEffect(oTarget, eTest);
|
||||
eTest = GetNextEffect(oTarget);
|
||||
@@ -81,3 +82,5 @@ void RemoveTSFromObject(object oTarget)
|
||||
StopFade(oTarget);
|
||||
SetCommandable(TRUE, oTarget);
|
||||
}
|
||||
|
||||
//void main(){}
|
||||
@@ -2235,6 +2235,7 @@ const int FEAT_INSECT_PLAGUE = 2312; //CONSTANT
|
||||
const int FEAT_SUMMON_CORNUGON = 2313; //CONSTANT
|
||||
const int FEAT_BEGUILEING_NATURE = 2314; //CONSTANT
|
||||
|
||||
//:: Fist of Hextor Feats
|
||||
const int FEAT_DEVICE_LORE = 2333;
|
||||
const int FEAT_IRON_HEWS = 2334;
|
||||
const int FEAT_RUSTING_GRASP = 2335;
|
||||
@@ -2245,6 +2246,9 @@ const int FEAT_GREATER_IRON_HEWS = 2339;
|
||||
const int FEAT_IRON_SKIN = 2340;
|
||||
const int FEAT_IRON_BODY = 2341;
|
||||
|
||||
//:: Telflammar Shadowlord Feats
|
||||
const int FEAT_SHADOWDISCORPO = 3305;
|
||||
|
||||
const int FEAT_COFFIN_SANCTUARY = 2343;
|
||||
const int FEAT_GASEOUS_FORM = 2344;
|
||||
|
||||
|
||||
@@ -8803,7 +8803,9 @@ void AttackLoopMain(object oDefender, object oAttacker,
|
||||
if(DEBUG) DoDebug("Entered AttackLoopMain: bonus attacks = " + IntToString(iBonusAttacks)+", main attacks = "+IntToString(iMainAttacks)+", offhand attacks = "+IntToString(iOffHandAttacks));
|
||||
|
||||
// ugly workaround to make this global available for other functions after a call to DelayCommand or AssignCommand
|
||||
bUseMonkAttackMod = sAttackVars.bUseMonkAttackMod;
|
||||
//bUseMonkAttackMod = sAttackVars.bUseMonkAttackMod;
|
||||
|
||||
sAttackVars.bUseMonkAttackMod = GetHasMonkWeaponEquipped(oAttacker);
|
||||
|
||||
// turn off touch attack if var says it only applies to first attack
|
||||
if (sAttackVars.iAttackNumber && !sAttackVars.bApplyTouchToAll) sAttackVars.iTouchAttackType == FALSE;
|
||||
|
||||
@@ -657,6 +657,53 @@ int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF)
|
||||
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
||||
// this will only check the spellbook of the class specified
|
||||
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF)
|
||||
{
|
||||
// check for whether bard and sorc are using the prc spellbooks
|
||||
if (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
if (!UseNewSpellBook(oPC))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get the cls_spell_***.2da index for the real spell
|
||||
int nSpellbookSpell = RealSpellToSpellbookID(nClass, nRealSpellID);
|
||||
if (nSpellbookSpell == -1)
|
||||
return FALSE;
|
||||
|
||||
string sFile = GetFileForClass(nClass);
|
||||
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookSpell);
|
||||
if (sSpellLevel == "")
|
||||
return FALSE;
|
||||
|
||||
int nSpellLevel = StringToInt(sSpellLevel);
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
|
||||
// Check whether the class can actually cast spells of this circle.
|
||||
int nCasterLevel = GetSpellslotLevel(nClass, oPC);
|
||||
int nAbility = GetAbilityScoreForClass(nClass, oPC);
|
||||
if (GetSlotCount(nCasterLevel, nSpellLevel, nAbility, nClass, oPC) <= 0)
|
||||
return FALSE;
|
||||
|
||||
// Prepared casters know their full list, except Archivist.
|
||||
if (nSpellbookType == SPELLBOOK_TYPE_PREPARED && nClass != CLASS_TYPE_ARCHIVIST)
|
||||
return TRUE;
|
||||
|
||||
// Spontaneous casters only know spells they've actually learned.
|
||||
if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookSpell));
|
||||
if (GetHasFeat(nFeatID, oPC))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// checks if oPC knows the specified spell
|
||||
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
||||
// this will only check the spellbook of the class specified
|
||||
/* int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF)
|
||||
{
|
||||
// check for whether bard and sorc are using the prc spellbooks
|
||||
if (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
|
||||
@@ -692,7 +739,7 @@ int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJ
|
||||
// at this stage, prepared casters know the spell and only spontaneous classes need checking
|
||||
// there are exceptions and these need hardcoding:
|
||||
|
||||
if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST)
|
||||
/* if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST)
|
||||
return TRUE;
|
||||
|
||||
// spontaneous casters have all their known spells as hide feats
|
||||
@@ -703,7 +750,8 @@ int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJ
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
//routes to action cast spell, but puts a wrapper around to tell other functions its a
|
||||
//SLA, so dont craft etc
|
||||
//also defaults th totalDC to 10+spellevel+chamod
|
||||
|
||||
@@ -214,6 +214,7 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_SHADOWSMITH: iData |= 0x01; break;
|
||||
case CLASS_TYPE_SHADOW_SUN_NINJA: sScript = "tob_shadowsun"; break;
|
||||
case CLASS_TYPE_SHADOWBLADE: sScript = "prc_sb_shdstlth"; break;
|
||||
case CLASS_TYPE_SHADOWLORD: sScript = "prc_shadowlord"; break;
|
||||
case CLASS_TYPE_SHADOWMIND: sScript = "psi_shadowmind"; break;
|
||||
case CLASS_TYPE_SHADOWBANE_STALKER: sScript = "prc_shadstalker"; break;
|
||||
case CLASS_TYPE_SHADOW_THIEF_AMN: sScript = "prc_amn"; break;
|
||||
@@ -237,7 +238,7 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_SWIFT_WING: sScript = "prc_swiftwing"; break;
|
||||
case CLASS_TYPE_SWORDSAGE: sScript = "tob_swordsage"; iData |= 0x01; break;
|
||||
case CLASS_TYPE_TALON_OF_TIAMAT: sScript = "prc_talontiamat"; break;
|
||||
case CLASS_TYPE_TEMPEST: sScript = "prc_tempest"; break;
|
||||
case CLASS_TYPE_TEMPEST: sScript = "prc_tempest"; break;
|
||||
case CLASS_TYPE_TEMPUS: sScript = "prc_battletempus"; break;
|
||||
case CLASS_TYPE_TENEBROUS_APOSTATE: sScript = "bnd_tenebrous"; break;
|
||||
case CLASS_TYPE_THAYAN_KNIGHT: sScript = "prc_thayknight"; break;
|
||||
|
||||
@@ -20,6 +20,26 @@
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns a linked effect bundle containing Shadowlord ultravision,
|
||||
* visual feedback effects, and concealment for higher Shadowlord levels.
|
||||
*
|
||||
* @param iShadow
|
||||
* Shadowlord level of the target creature.
|
||||
*
|
||||
* @param eBaseEffect
|
||||
* Existing linked effect bundle to append effects to.
|
||||
* Typically ePnP, eLink, or eLink2.
|
||||
*
|
||||
* @return
|
||||
* Updated linked effect bundle containing:
|
||||
* - Ultravision
|
||||
* - Ultravision icon
|
||||
* - Magical sight visuals
|
||||
* - Positive effect visuals
|
||||
* - 20% concealment at Shadowlord level 2+
|
||||
*/
|
||||
effect ShadowlordEffects(int iShadow, effect eBaseEffect);
|
||||
|
||||
|
||||
//:: Calculates total Shield AC bonuses from all sources
|
||||
@@ -381,6 +401,30 @@ const int TYPE_DIVINE = -2;
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
effect ShadowlordEffects(int iShadow, effect eBaseEffect)
|
||||
{
|
||||
|
||||
//:: Create visual feedback effect link
|
||||
effect eVis = EffectVisualEffect(VFX_DUR_ULTRAVISION);
|
||||
eVis = EffectLinkEffects(eVis, EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE));
|
||||
eVis = EffectLinkEffects(eVis, EffectVisualEffect(VFX_DUR_MAGICAL_SIGHT));
|
||||
eVis = EffectLinkEffects(eVis, EffectIcon(EFFECT_ICON_ULTRAVISION));
|
||||
|
||||
//:: Link Ultravision and visual feedback into base effect
|
||||
eBaseEffect = EffectLinkEffects(eBaseEffect, EffectUltravision());
|
||||
eBaseEffect = EffectLinkEffects(eBaseEffect, eVis);
|
||||
if(DEBUG) DoDebug("ShadowlordEffects() >> Setting up Ultravision");
|
||||
|
||||
if (iShadow > 1)
|
||||
{
|
||||
//;: Add concealment for level 2+ Shadowlords
|
||||
eBaseEffect = EffectLinkEffects(eBaseEffect, EffectConcealment(20));
|
||||
if(DEBUG) DoDebug("ShadowlordEffects() >> Setting up Concealment");
|
||||
}
|
||||
|
||||
return eBaseEffect;
|
||||
}
|
||||
|
||||
|
||||
// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise
|
||||
int GetIsSubradialSpell(int nSpellID)
|
||||
|
||||
@@ -205,7 +205,7 @@ const string PRC_PNP_FIND_TRAPS = "PRC_PNP_FIND_TRAPS";
|
||||
|
||||
/**
|
||||
* PnP Darkness
|
||||
* Is a mobile AOE based off an item
|
||||
* Is a mobile AOE based off an item when cast on a creature.
|
||||
*/
|
||||
const string PRC_PNP_DARKNESS = "PRC_PNP_DARKNESS";
|
||||
|
||||
|
||||
@@ -3,9 +3,26 @@
|
||||
* Include file for various constants that don't really belong in any of the other files,
|
||||
* but aren't numerous enough to warrant their own.
|
||||
*/
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: New base item types
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: New effect icons (effecticons.2da)
|
||||
//:://////////////////////////////////////////////
|
||||
const int EFFECT_ICON_DARKVISION = 130;
|
||||
const int EFFECT_ICON_ULTRAVISION = 131;
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: New damage types (damagetypes.2da)
|
||||
//:://////////////////////////////////////////////
|
||||
const int DAMAGE_TYPE_POISON = 16384; // CUSTOM2
|
||||
const int DAMAGE_TYPE_PSYCHIC = 32768; // CUSTOM4
|
||||
const int DAMAGE_TYPE_RADIANT = 65536; // CUSTOM6
|
||||
const int DAMAGE_TYPE_FORCE = 524288; // CUSTOM7
|
||||
const int DAMAGE_TYPE_UNTYPED = 1048576; // CUSTOM8
|
||||
const int DAMAGE_TYPE_VILE = 2097152; // CUSTOM9
|
||||
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: New base item types
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
const int BASE_ITEM_GOLEM = 23; //:: not actually used for anything else
|
||||
|
||||
@@ -2725,7 +2725,41 @@ int X2GetSpellCastOnSequencerItem(object oItem, object oCaster, int nSpellID, in
|
||||
// * This is our little concentration system for black blade of disaster
|
||||
// * if the mage tries to cast any kind of spell, the blade is signaled an event to die
|
||||
//------------------------------------------------------------------------------
|
||||
void X2BreakConcentrationSpells()
|
||||
void X2BreakConcentrationSpells()
|
||||
{
|
||||
//end Dragonsong Lyrist songs
|
||||
DeleteLocalInt(OBJECT_SELF, "SpellConc");
|
||||
|
||||
if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER))
|
||||
{
|
||||
//this is also in summon HB
|
||||
//but needed here to handle quickend spells
|
||||
//Disintegrate is cast from the blade so doesn't end the summon
|
||||
|
||||
// Determine the correct tag based on PRC switch
|
||||
string sTargetTag = GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER) ? "prc_bbod001" : "x2_s_bblade";
|
||||
|
||||
// Loop through all summoned associates
|
||||
int i = 1;
|
||||
object oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
|
||||
while(GetIsObjectValid(oAssoc))
|
||||
{
|
||||
string sTag = GetTag(oAssoc);
|
||||
// Use case-insensitive comparison
|
||||
if(GetStringLowerCase(sTag) == GetStringLowerCase(sTargetTag))
|
||||
{
|
||||
if(GetLocalInt(oAssoc, "X2_L_CREATURE_NEEDS_CONCENTRATION"))
|
||||
{
|
||||
SignalEvent(oAssoc, EventUserDefined(X2_EVENT_CONCENTRATION_BROKEN));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* void X2BreakConcentrationSpells()
|
||||
{
|
||||
//end Dragonsong Lyrist songs
|
||||
DeleteLocalInt(OBJECT_SELF, "SpellConc");
|
||||
@@ -2747,7 +2781,7 @@ void X2BreakConcentrationSpells()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// being hit by any kind of negative effect affecting the caster's ability to concentrate
|
||||
|
||||
Reference in New Issue
Block a user