2025/11/20 Update

Updated epic swashbucker tlk.
Added notes on Martial Study.
Updated Shadow Servant to scale with Shadow Master level, per PnP.
Made Disciple of Baalzebul's CHA boost intrinsic.
Swarm of Arrows is an Eldritch Knight epic bonus feat.
Epic eldritch theurge is 11th level, not 21st level.
Updated Shadowdancer weapon proficiencies.
WP: Scythe was a usable feat for Warblade.
Gaseous Form added to iprp_spells.
Set Favoured Soul's Regen X Wounds spells to the correct spell level.
Updated Twinfiend to not suck.
Tweaked GetMaxPossibleHP for Undead & Constructs.
Updated PRCIsFlying() for newer CEP2 wings.
More fixes and updated for NUI levelup menu. (@Rakiov)
Added support for de-leveling AMS classes (@Rakiov)
Zakya Rakshasa have a claw & bite attack.
Added check to end grapples after target death.
Removed debug message in GetHighestSpellAvailableByDescriptor()
Monsters won't summon uncontrolled undead.
Added Signal Event to Luminous Armor.
Corrected Signal Event on Shield of Faith.
This commit is contained in:
Jaysyn904
2025-11-20 21:36:52 -05:00
parent 8e82907d07
commit 80070703b4
54 changed files with 26753 additions and 20944 deletions

View File

@@ -0,0 +1,164 @@
//::////////////////////////////////////////////////////////
//:: ;-. ,-. ,-. ,-.
//:: | ) | ) / ( )
//:: |-' |-< | ;-:
//:: | | \ \ ( )
//:: ' ' ' `-' `-'
//::///////////////////////////////////////////////////////
//::
/*
Impactscript for Shadow Servant.
(this is handled in the Familiar script)
Shadow Servant (Su): At 1st level, your shadow familiar permanently
transforms into a Medium shadow elemental. It loses all familiar
traits, but gains new abilities as your shadow servant.
Should your shadow servant die, you can summon a replacement after
24 hours pass. Your shadow servant cannot travel farther from you
than 30 feet + 10 feet for each of your master of shadow levels
(40 feet at 1st level and a maximum of 130 feet at 10th level). If
it is forcibly separated from you by more than this distance, the
servant dissipates instantly, and you must wait 24 hours to summon
a new one.
*/
//::
//:://////////////////////////////////////////////
//:: Script: mshadw_shadserv.nss
//:: Author: Jaysyn
//:: Created: 2025-11-11 19:25:58
//:://////////////////////////////////////////////
#include "prc_inc_json"
#include "prc_inc_spells"
const string SHADOW_SERVANT_RESREF = "prc_shadow_serv";
// Watch function: despawns Shadow Servant if master is dead or out of range
void ShadowServantWatch(object oShadow, object oPC)
{
if(DEBUG) DoDebug("mshadw_shadserv >> ShadowServantWatch: Starting function.");
int nMaster = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
float fRange = 30.0 + (nMaster * 10);
if (!GetIsObjectValid(oShadow) || !GetIsObjectValid(oPC)) return;
if (GetIsDead(oPC) ||
GetDistanceBetween(oShadow, oPC) > FeetToMeters(fRange))
{
DestroyObject(oShadow);
return;
}
DelayCommand(1.0, ShadowServantWatch(oShadow, oPC));
}
void main()
{
object oPC = OBJECT_SELF;
int nMaster = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
int nDexBonus = (nMaster >= 5 && (nMaster % 2)) ? (nMaster - 3) : 0;
float fRange = 30.0 + (nMaster * 10);
// Target location
location lTarget = GetSpellTargetLocation();
// Distance check
if (GetDistanceBetweenLocations(GetLocation(oPC), lTarget) > FeetToMeters(fRange))
{
SendMessageToPC(oPC, "That location is too far away.");
return;
}
// Load template
json jShadow = TemplateToJson(SHADOW_SERVANT_RESREF, RESTYPE_UTC);
if (jShadow == JSON_NULL)
{
SendMessageToPC(oPC, "mshdw_shadserv: TemplateToJson failed <20> bad resref or resource missing.");
return;
}
// Original HD
int nOriginalHD = json_GetCreatureHD(jShadow);
if (nOriginalHD <= 0)
{
SendMessageToPC(oPC, "mshdw_shadserv: json_GetCreatureHD failed <20> template missing HD data.");
return;
}
//:: Add Hit Dice
int nHDToAdd = nMaster -1;
if (nHDToAdd < 0) nHDToAdd = 0;
jShadow = json_AddHitDice(jShadow, nHDToAdd);
if (jShadow == JSON_NULL)
{
SendMessageToPC(oPC, "mshdw_shadserv: json_AddHitDice failed - JSON became invalid.");
return;
}
//:: Update feats
jShadow = json_AddFeatsFromCreatureVars(jShadow, nOriginalHD);
if (jShadow == JSON_NULL)
{
SendMessageToPC(oPC, "mshdw_shadserv: json_AddFeatsFromCreatureVars failed <20> JSON became invalid.");
return;
}
//:: Update stats
jShadow = json_ApplyAbilityBoostFromHD(jShadow, nOriginalHD);
if (jShadow == JSON_NULL)
{
SendMessageToPC(oPC, "mshdw_shadserv: json_ApplyAbilityBoostFromHD failed <20> JSON became invalid.");
return;
}
//:: Bonus DEX from Shadow Servant class ability
jShadow = json_UpdateTemplateStats(jShadow, 0, nDexBonus);
// Size increase
if (nMaster > 2)
{
jShadow = json_AdjustCreatureSize(jShadow, 1, TRUE);
if (jShadow == JSON_NULL)
{
SendMessageToPC(oPC, "mshdw_shadserv: json_AdjustCreatureSize failed - JSON became invalid.");
return;
}
}
object oShadow = JsonToObject(jShadow, lTarget);
effect eSummon = ExtraordinaryEffect(EffectSummonCreature("", VFX_FNF_SUMMON_UNDEAD, 0.0, 0, VFX_IMP_UNSUMMON, oShadow));
ApplyEffectAtLocation(DURATION_TYPE_PERMANENT, eSummon, lTarget);
if (!GetIsObjectValid(oShadow))
{
SendMessageToPC(oPC, "mshdw_shadserv: JsonToObject failed - could not create creature from edited template.");
return;
}
// Set faction to caster<65>s
ChangeFaction(oShadow, oPC);
SetLocalObject(oShadow, "ANIMATOR", oPC);
SetCurrentHitPoints(oShadow, GetMaxPossibleHP(oShadow));
effect eGhost = EffectVisualEffect(VFX_DUR_GHOST_TRANSPARENT);
eGhost = UnyieldingEffect(eGhost);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oShadow);
// Start watch loop
DelayCommand(6.1, ShadowServantWatch(oShadow, oPC));
}

View File

@@ -3,8 +3,19 @@
void main()
{
ExecuteScript("nw_ch_summon_9", OBJECT_SELF);
ExecuteScript("prc_npc_spawn", OBJECT_SELF);
object oNPC = OBJECT_SELF;
ExecuteScript("nw_ch_summon_9", oNPC);
ExecuteScript("prc_npc_spawn", oNPC);
//:: Used for the Twinfiend Pit Fiend summon
int nUltravision = GetLocalInt(oNPC,"INNATE_ULTRAVISION");
if(nUltravision)
{
effect eUltra = EffectUltravision();
eUltra = UnyieldingEffect(eUltra);
DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eUltra, oNPC));
}
//use companion appearances
/*if(GetPRCSwitch(MARKER_PRC_COMPANION))

View File

@@ -31,7 +31,7 @@ void main()
int bKing = GetHasFeat(FEAT_KING_LIES, oPC) ? 4 : 0;
int bDevil = GetHasFeat(FEAT_TONGUE_DEVIL, oPC) ? iInt : 0;
if (bKing>0) KingofLies(oPC, oSkin,bKing);
//if (bKing>0) KingofLies(oPC, oSkin,bKing); Handled in stat 2DA now
if (bDevil>0) DevilTongue(oPC, oSkin,bDevil);
}

View File

@@ -10,6 +10,7 @@
#include "psi_inc_psifunc"
#include "inc_ecl"
#include "prc_inc_assoc"
#include "prc_inc_combmove"
void PreyOnTheWeak(object oDead)
{
@@ -48,6 +49,9 @@ void main()
{
object oDead = GetLastBeingDied();
object oKiller = MyGetLastKiller();
DelayCommand(0.1f, EndGrapple(oDead, oKiller));
DelayCommand(0.2f, EndGrapple(oKiller, oDead));
// We are not actually dead until -10
// Unless it's a spell death

View File

@@ -34,6 +34,28 @@ const string CHAT_COMMAND_INDICATOR_1 = "~~";
const string CHAT_COMMAND_INDICATOR_2 = "..";
const int CHAT_COMMAND_INDICATOR_LENGHT = 2;
void ForceRemoveAllSpells(object oPC)
{
int classId;
for(classId = 1; classId < CLASS_TYPE_INVALID; classId++)
{
int j;
for (j = 0; j <= 40; j++)
{
DelayCommand(0.0f, CallSpellUnlevelScript(oPC, classId, j));
}
}
SendMessageToPC(oPC, "Finished removing spells.");
}
void ResetCharacterXPAndRemoveSpells(object oPC)
{
int xp = GetXP(oPC);
ForceRemoveAllSpells(oPC);
SetXP(oPC, 1);
SetXP(oPC, xp);
}
int GetIsChatCommand(string sString)
{
string sTest = GetStringLeft(sString, CHAT_COMMAND_INDICATOR_LENGHT);
@@ -111,6 +133,50 @@ void main()
string firstWord = JsonGetString(JsonArrayGet(sCommandSplit, 0));
// if first word is /pa we are using the power attack interface
if (firstWord == "/relevel")
{
int confirmed = GetLocalInt(oPC, "RelevelConfirm");
if(confirmed)
{
SendMessageToPC(oPC, "Please wait as we relevel you, this may take some time...");
DelayCommand(1.0f, ResetCharacterXPAndRemoveSpells(oPC));
DeleteLocalInt(oPC, "RelevelConfirm");
}
else
{
SendMessageToPC(oPC, "This will relevel you back to level 1 while preserving XP, type /relevel again to confirm.");
SetLocalInt(oPC, "RelevelConfirm", 1);
CloseNUILevelUpWindow(oPC, TRUE);
}
SetPCChatMessage();
}
else
{
DeleteLocalInt(oPC, "RelevelConfirm");
SetPCChatMessage();
}
if (firstWord == "/resetSpells")
{
int confirmed = GetLocalInt(oPC, "ResetSpellsConfirm");
if (confirmed)
{
SendMessageToPC(oPC, "Please wait as we remove your spells, this may take some time...");
DelayCommand(1.0f, ForceRemoveAllSpells(oPC));
DeleteLocalInt(oPC, "ResetSpellsConfirm");
CloseNUILevelUpWindow(oPC, TRUE);
}
else
{
SendMessageToPC(oPC, "This will reset all spell choices among all PRC classes. Type /resetSpells again to confirm.");
SetLocalInt(oPC, "ResetSpellsConfirm", 1);
}
SetPCChatMessage();
}
else
{
DeleteLocalInt(oPC, "ResetSpellsConfirm");
SetPCChatMessage();
}
if(firstWord == "/pa")
{
if(JsonGetLength(sCommandSplit) >= 2)
@@ -147,17 +213,6 @@ void main()
SetPCChatMessage();
return;
}
if (firstWord == "/lvl")
{
if (JsonGetLength(sCommandSplit) >= 2)
{
int classPos = StringToInt(JsonGetString(JsonArrayGet(sCommandSplit, 1)));
int nClass = GetClassByPosition(classPos, oPC);
OpenNUILevelUpWindow(nClass, oPC);
SetPCChatMessage();
return;
}
}
}
// Execute scripts hooked to this event for the player triggering it

View File

@@ -142,8 +142,8 @@ int GetHighestSpellAvailableByDescriptor(object oPC, string sDescriptor)
sSpellLabel = Get2DACache(sFile, "Label", i);
if(sSpellLabel != "") // Non-blank row
{
SendMessageToPC(oPC, "GetHighestSpellAvailableByDescriptor >> Entered function.");
SendMessageToPC(oPC, "Row " + IntToString(i) +
if (DEBUG) DoDebug("GetHighestSpellAvailableByDescriptor >> Entered function.");
if (DEBUG) DoDebug("Row " + IntToString(i) +
" Label = " + sSpellLabel +
" SpellID = " + IntToString(nSpellID) +
" HasSpell " + IntToString(PRCGetHasSpell(nSpellID, oPC)));

View File

@@ -0,0 +1,474 @@
//::///////////////////////////////////////////////
//:: PRC Unlevel Logic
//:: prc_unlvl_script
//:://////////////////////////////////////////////
/*
This is the logic for removing spells from a PRC class in case of
unleveling or for fixing issues
*/
//:://////////////////////////////////////////////
//:: Created By: Rakiov
//:: Created On: 22.09.2025
//:://////////////////////////////////////////////
#include "tob_inc_tobfunc"
#include "tob_inc_moveknwn"
#include "inv_inc_invfunc"
#include "shd_inc_mystknwn"
#include "shd_inc_shdfunc"
#include "true_inc_truknwn"
#include "true_inc_trufunc"
#include "prc_nui_com_inc"
////////////////////////////////////////////////////////////////////////////
/// ///
/// Implementations ///
/// ///
////////////////////////////////////////////////////////////////////////////
int FindSpellbookId(int nClass, int spellId)
{
string sFile = GetClassSpellbookFile(nClass);
int totalSpells = Get2DARowCount(sFile);
int i;
for (i = 0; i < totalSpells; i++)
{
int currentSpellId = StringToInt(Get2DACache(sFile, "SpellID", i));
if (currentSpellId == spellId)
return i;
}
return 0;
}
void RemoveSpellsFromPlayer(object oPC, int nClass, string spellArray, string totalSpellsId, int nType=0)
{
// if we found the spell, then we remove it.
int totalRemoved = persistant_array_get_size(oPC, spellArray);
if (DEBUG) DoDebug("Found " + IntToString(totalRemoved) + " spells in " + spellArray + ", removing them.");
string sFile = GetClassSpellbookFile(nClass);
int i;
for (i = 0; i < totalRemoved; i++)
{
int spellId = persistant_array_get_int(oPC, spellArray, i);
int spellbookId = FindSpellbookId(nClass, spellId);
if (spellbookId != 0)
{
// remove spell from player
string spellName = Get2DACache(sFile, "Label", spellbookId);
if (DEBUG) DoDebug( "Removing spell " + spellName);
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId));
object oSkin = GetPCSkin(oPC);
RemoveIPFeat(oPC, ipFeatID);
if (GetIsBladeMagicClass(nClass))
{
string sDisciplineArray = _MANEUVER_LIST_DISCIPLINE + IntToString(nType) + "_" + Get2DACache(sFile, "Discipline", spellbookId);
int totalDiscSpells = GetPersistantLocalInt(oPC, sDisciplineArray);
SetPersistantLocalInt(oPC, sDisciplineArray, totalDiscSpells - 1);
if (DEBUG) DoDebug(sDisciplineArray + " total maneuvers is now " + IntToString(totalDiscSpells-1));
}
}
}
persistant_array_delete(oPC, spellArray);
int totalSpellCount = GetPersistantLocalInt(oPC, totalSpellsId);
// decrement the amount of spells known.
SetPersistantLocalInt(oPC, totalSpellsId,
totalSpellCount - totalRemoved
);
if (DEBUG) DoDebug(totalSpellsId + " total spells is now " + IntToString(totalSpellCount - totalRemoved));
}
string GetMaxSpellsKnownName(int nClass)
{
if (GetIsShadowMagicClass(nClass))
{
return _MYSTERY_LIST_TOTAL_KNOWN;
}
if (GetIsInvocationClass(nClass))
{
return _INVOCATION_LIST_TOTAL_KNOWN;
}
if (GetIsBladeMagicClass(nClass))
{
return _MANEUVER_LIST_TOTAL_KNOWN;
}
if (GetIsTruenamingClass(nClass))
{
return _UTTERANCE_LIST_TOTAL_KNOWN;
}
if (GetIsPsionicClass(nClass))
{
return _POWER_LIST_TOTAL_KNOWN;
}
return "";
}
string GetGeneralArrayId(int nClass)
{
if (GetIsShadowMagicClass(nClass))
{
return _MYSTERY_LIST_GENERAL_ARRAY;
}
if (GetIsInvocationClass(nClass))
{
return _INVOCATION_LIST_GENERAL_ARRAY;
}
if (GetIsBladeMagicClass(nClass))
{
return _MANEUVER_LIST_GENERAL_ARRAY;
}
if (GetIsTruenamingClass(nClass))
{
return _UTTERANCE_LIST_GENERAL_ARRAY;
}
if (GetIsPsionicClass(nClass))
{
return _POWER_LIST_GENERAL_ARRAY;
}
return "";
}
string GetBaseListName(int nClass)
{
if (GetIsShadowMagicClass(nClass))
{
return _MYSTERY_LIST_NAME_BASE;
}
if (GetIsInvocationClass(nClass))
{
return _INVOCATION_LIST_NAME_BASE;
}
if (GetIsBladeMagicClass(nClass))
{
return _MANEUVER_LIST_NAME_BASE;
}
if (GetIsTruenamingClass(nClass))
{
return _UTTERANCE_LIST_NAME_BASE;
}
if (GetIsPsionicClass(nClass))
{
return _POWER_LIST_NAME_BASE;
}
return "";
}
string GetLevelArrayListName(int nClass)
{
if (GetIsShadowMagicClass(nClass))
{
return _MYSTERY_LIST_LEVEL_ARRAY;
}
if (GetIsInvocationClass(nClass))
{
return _INVOCATION_LIST_LEVEL_ARRAY;
}
if (GetIsBladeMagicClass(nClass))
{
return _MANEUVER_LIST_LEVEL_ARRAY;
}
if (GetIsTruenamingClass(nClass))
{
return _UTTERANCE_LIST_LEVEL_ARRAY;
}
if (GetIsPsionicClass(nClass))
{
return _POWER_LIST_LEVEL_ARRAY;
}
return "";
}
void RemoveSpellsAtLevel(object oPC, int nClass, int level, int nList = 0)
{
if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
{
string sFile = GetClassSpellbookFile(nClass);
string spellsAtLevelList = ("SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(level));
string spellLevelBook = GetSpellsKnown_Array(nClass);
if (level == 0)
{
spellsAtLevelList = spellLevelBook;
int totalSpells = Get2DARowCount(sFile);
int i;
for (i = 0; i < totalSpells; i++)
{
int featID = StringToInt(Get2DACache(sFile, "FeatID", i));
if (featID && GetHasFeat(featID, oPC, TRUE))
{
string spellName = Get2DACache(sFile, "Label", i);
if (DEBUG) DoDebug( "Removing spellID " + IntToString(i) + ", spell name: " + spellName);
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", i));
WipeSpellFromHide(ipFeatID, oPC);
}
}
persistant_array_delete(oPC, spellsAtLevelList);
}
else if (persistant_array_exists(oPC, spellsAtLevelList))
{
if (DEBUG) DoDebug( "Removing spells in " + spellsAtLevelList);
int knownSpellsCount = persistant_array_get_size(oPC, spellsAtLevelList);
int i;
for (i = 0; i < knownSpellsCount; i++)
{
int spellId = persistant_array_get_int(oPC, spellsAtLevelList, i);
int spellbookId = FindSpellbookId(nClass, spellId);
if (spellbookId)
{
array_extract_int(oPC, spellLevelBook, spellbookId);
// wipe the spell from the player
string spellName = Get2DACache(sFile, "Label", spellbookId);
if (DEBUG) DoDebug( "Removing spellID " + IntToString(spellbookId) + ", spell name: " + spellName);
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId));
WipeSpellFromHide(ipFeatID, oPC);
}
}
persistant_array_delete(oPC, spellsAtLevelList);
if (nClass == CLASS_TYPE_BEGUILER
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|| nClass == CLASS_TYPE_WARMAGE)
{
int nAdvLearn = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass)) - knownSpellsCount;
SetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass), nAdvLearn);
}
}
}
else
{
int chosenList = (nList != 0) ? nList : nClass;
string baseList = GetBaseListName(nClass);
string totalCountId = GetMaxSpellsKnownName(nClass);
if (GetIsBladeMagicClass(nClass))
{
// remove maneuvers
int maneuver;
for (maneuver = 1; maneuver <= MANEUVER_TYPE_MANEUVER; maneuver++)
{
string spellArray = baseList + IntToString(chosenList) + IntToString(maneuver);
if (level == 0)
{
spellArray += GetGeneralArrayId(nClass);
}
else
{
spellArray += GetLevelArrayListName(nClass) + IntToString(level);
}
if (persistant_array_exists(oPC, spellArray))
{
string totalSpellsId = baseList + IntToString(chosenList) + IntToString(maneuver) + totalCountId;
RemoveSpellsFromPlayer(oPC, nClass, spellArray, totalSpellsId, maneuver);
}
}
return;
}
else if (GetIsTruenamingClass(nClass))
{
// Lexicon 1
string spellArray = baseList + IntToString(chosenList) + "1";
if (level == 0)
{
spellArray += GetGeneralArrayId(nClass);
}
else
{
spellArray += GetLevelArrayListName(nClass) + IntToString(level);
}
if (persistant_array_exists(oPC, spellArray))
{
string totalSpellsId = baseList + IntToString(chosenList) + totalCountId;
RemoveSpellsFromPlayer(oPC, nClass, spellArray, totalSpellsId);
}
// Lexicon 2
spellArray = baseList + IntToString(chosenList) + "2";
if (level == 0)
{
spellArray += GetGeneralArrayId(nClass);
}
else
{
spellArray += GetLevelArrayListName(nClass) + IntToString(level);
}
if (persistant_array_exists(oPC, spellArray))
{
string totalSpellsId = baseList + IntToString(chosenList) + totalCountId;
RemoveSpellsFromPlayer(oPC, nClass, spellArray, totalSpellsId);
}
// Lexicon 3
spellArray = baseList + IntToString(chosenList) + "3";
if (level == 0)
{
spellArray += GetGeneralArrayId(nClass);
}
else
{
spellArray += GetLevelArrayListName(nClass) + IntToString(level);
}
if (persistant_array_exists(oPC, spellArray))
{
string totalSpellsId = baseList + IntToString(chosenList) + totalCountId;
RemoveSpellsFromPlayer(oPC, nClass, spellArray, totalSpellsId);
}
return;
}
string spellArray = (baseList + IntToString(chosenList));
if (level == 0)
{
spellArray += GetGeneralArrayId(nClass);
}
else
{
spellArray += GetLevelArrayListName(nClass) + IntToString(level);
}
if (persistant_array_exists(oPC, spellArray))
{
if (DEBUG) DoDebug( "Removing spells from " + spellArray);
string totalSpellsId = baseList + IntToString(chosenList) + totalCountId;
RemoveSpellsFromPlayer(oPC, nClass, spellArray, totalSpellsId);
}
}
}
int IsClassPRCSpellCaster(int nClass, object oPlayer)
{
// This controls who can use the Spellbook NUI, if for some reason you don't
// want a class to be allowed to use this you can comment out their line here
// Bard and Sorc are allowed if they took a PRC that makes them use the spellbook
if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|| GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED)
return TRUE;
// Arcane Spont
if (nClass == CLASS_TYPE_ASSASSIN
|| nClass == CLASS_TYPE_BEGUILER
|| nClass == CLASS_TYPE_CELEBRANT_SHARESS
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|| nClass == CLASS_TYPE_DUSKBLADE
|| nClass == CLASS_TYPE_HARPER
|| nClass == CLASS_TYPE_HEXBLADE
|| nClass == CLASS_TYPE_KNIGHT_WEAVE
|| nClass == CLASS_TYPE_SHADOWLORD
|| nClass == CLASS_TYPE_SUBLIME_CHORD
|| nClass == CLASS_TYPE_SUEL_ARCHANAMACH
|| nClass == CLASS_TYPE_WARMAGE)
return TRUE;
// Psionics
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|| nClass == CLASS_TYPE_PSION
|| nClass == CLASS_TYPE_PSYWAR
|| nClass == CLASS_TYPE_WILDER
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|| nClass == CLASS_TYPE_WARMIND)
return TRUE;
// Invokers
if (nClass == CLASS_TYPE_WARLOCK
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
return TRUE;
// Divine Spont
if (nClass == CLASS_TYPE_ARCHIVIST //while technically prepared, they use the spont system of casting
|| nClass == CLASS_TYPE_FAVOURED_SOUL
|| nClass == CLASS_TYPE_JUSTICEWW)
return TRUE;
// ToB Classes
if (nClass == CLASS_TYPE_WARBLADE
|| nClass == CLASS_TYPE_SWORDSAGE
|| nClass == CLASS_TYPE_CRUSADER)
return TRUE;
// Mystery Classes
if (nClass == CLASS_TYPE_SHADOWCASTER
|| nClass == CLASS_TYPE_SHADOWSMITH)
return TRUE;
// Truenamers
if (nClass == CLASS_TYPE_TRUENAMER)
return TRUE;
// RHD Casters
if ((nClass == CLASS_TYPE_SHAPECHANGER
&& GetRacialType(oPlayer) == RACIAL_TYPE_ARANEA
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_OUTSIDER
&& GetRacialType(oPlayer) == RACIAL_TYPE_RAKSHASA
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_ABERRATION
&& GetRacialType(oPlayer) == RACIAL_TYPE_DRIDER
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_MONSTROUS
&& GetRacialType(oPlayer) == RACIAL_TYPE_ARKAMOI
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_MONSTROUS
&& GetRacialType(oPlayer) == RACIAL_TYPE_HOBGOBLIN_WARSOUL
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_MONSTROUS
&& GetRacialType(oPlayer) == RACIAL_TYPE_REDSPAWN_ARCANISS
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_MONSTROUS
&& GetRacialType(oPlayer) == RACIAL_TYPE_MARRUTACT
&& !GetLevelByClass(CLASS_TYPE_SORCERER))
|| (nClass == CLASS_TYPE_FEY
&& GetRacialType(oPlayer) == RACIAL_TYPE_GLOURA
&& !GetLevelByClass(CLASS_TYPE_BARD)))
return TRUE;
// Binders
if (nClass == CLASS_TYPE_BINDER)
return TRUE;
return FALSE;
}
void CheckAndRemoveSpellsForClassAtLevel(object oPC, int nClass, int level)
{
if (IsClassPRCSpellCaster(nClass, oPC))
{
if (GetIsInvocationClass(nClass))
{
RemoveSpellsAtLevel(oPC, nClass, level, INVOCATION_LIST_EXTRA);
RemoveSpellsAtLevel(oPC, nClass, level, INVOCATION_LIST_EXTRA_EPIC);
}
if (GetIsPsionicClass(nClass))
{
RemoveSpellsAtLevel(oPC, nClass, level, POWER_LIST_EXP_KNOWLEDGE);
RemoveSpellsAtLevel(oPC, nClass, level, POWER_LIST_EPIC_EXP_KNOWLEDGE);
}
RemoveSpellsAtLevel(oPC, nClass, level);
}
}
void main()
{
int nClass = StringToInt(GetScriptParam("UnLevel_ClassChoice"));
int nLevel = StringToInt(GetScriptParam("UnLevel_LevelChoice"));
if (nClass)
{
CheckAndRemoveSpellsForClassAtLevel(OBJECT_SELF, nClass, nLevel);
}
}