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:
Jaysyn904
2026-05-28 16:27:19 -04:00
parent b27d9d2e5f
commit c437270cd1
40 changed files with 813 additions and 362 deletions

View File

@@ -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(){}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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";

View File

@@ -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

View File

@@ -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