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:
@@ -98,21 +98,9 @@ void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF);
|
||||
//
|
||||
// CloseNUILevelUpWindow
|
||||
// Closes the NUI Level Up Window if its open
|
||||
// setting reset to 1 will make it clear the entire cache as if the NUI was never opened
|
||||
//
|
||||
void CloseNUILevelUpWindow(object oPC=OBJECT_SELF);
|
||||
|
||||
//
|
||||
// GetTrueClassType
|
||||
// Gets the true class Id for a provided class Id, mostly for RHD and for
|
||||
// ToB prestige classes
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int classId
|
||||
//
|
||||
// Returns:
|
||||
// int the true classId based off nClass
|
||||
//
|
||||
int GetTrueClassType(int nClass, object oPC=OBJECT_SELF);
|
||||
void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0);
|
||||
|
||||
//
|
||||
// GetRemainingSpellChoices
|
||||
@@ -432,7 +420,7 @@ json GetChosenReplaceListObject(object oPC=OBJECT_SELF);
|
||||
// Returns:
|
||||
// int:Boolean TRUE if the spell is a expanded knowledge spell, FALSE otherwise
|
||||
//
|
||||
int IsExpKnowledgePower(int nClass, int spellbookId);
|
||||
int IsExpKnowledgePower(int nClass, int spellbookId, object oPC=OBJECT_SELF);
|
||||
|
||||
//
|
||||
// GetExpKnowledgePowerListRequired
|
||||
@@ -861,7 +849,7 @@ void AddSpellToChosenList(int nClass, int spellbookId, int spellCircle, object o
|
||||
// if the power is a expanded knowledge than we immediatly add it to the
|
||||
// extra list, otherwise check to make sure we have made all choices in our
|
||||
// base list first before adding it to the extra list.
|
||||
if (IsExpKnowledgePower(nClass, spellbookId)
|
||||
if (IsExpKnowledgePower(nClass, spellbookId, oPC)
|
||||
|| GetRemainingPowerChoices(nClass, spellCircle, oPC, FALSE) == 0)
|
||||
{
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
@@ -975,8 +963,7 @@ void RemoveSpellFromChosenList(int nClass, int spellbookId, int spellCircle, obj
|
||||
// for psionics we need to check if the removed spell was a expanded knowledge choice
|
||||
// or not. The id of the list is -1 or -2.
|
||||
int i;
|
||||
//for (i == -1; i >= -2; i--)
|
||||
for (i = -1; i >= -2; i--)
|
||||
for (i == -1; i >= -2; i--)
|
||||
{
|
||||
json expList = (i == -1) ? GetExpandedChoicesList(nClass, oPC) :
|
||||
GetEpicExpandedChoicesList(nClass, oPC);
|
||||
@@ -1062,53 +1049,20 @@ void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF)
|
||||
// figure out what the true base class is (mostly true for RHD)
|
||||
int chosenClass = GetTrueClassType(nClass, oPC);
|
||||
SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass);
|
||||
|
||||
ExecuteScript("prc_nui_lv_view", oPC);
|
||||
}
|
||||
|
||||
int GetTrueClassType(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
if (nClass == CLASS_TYPE_JADE_PHOENIX_MAGE
|
||||
|| nClass == CLASS_TYPE_MASTER_OF_NINE
|
||||
|| nClass == CLASS_TYPE_DEEPSTONE_SENTINEL
|
||||
|| nClass == CLASS_TYPE_BLOODCLAW_MASTER
|
||||
|| nClass == CLASS_TYPE_RUBY_VINDICATOR
|
||||
|| nClass == CLASS_TYPE_ETERNAL_BLADE
|
||||
|| nClass == CLASS_TYPE_SHADOW_SUN_NINJA)
|
||||
{
|
||||
int trueClass = GetPrimaryBladeMagicClass(oPC);
|
||||
return trueClass;
|
||||
}
|
||||
|
||||
if ((nClass == CLASS_TYPE_SHAPECHANGER
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_ARANEA)
|
||||
|| (nClass == CLASS_TYPE_OUTSIDER
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
|
||||
|| (nClass == CLASS_TYPE_ABERRATION
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_DRIDER)
|
||||
|| (nClass == CLASS_TYPE_MONSTROUS
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI)
|
||||
|| (nClass == CLASS_TYPE_MONSTROUS
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL)
|
||||
|| (nClass == CLASS_TYPE_MONSTROUS
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS)
|
||||
|| (nClass == CLASS_TYPE_MONSTROUS
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT))
|
||||
return CLASS_TYPE_SORCERER;
|
||||
if (nClass == CLASS_TYPE_FEY
|
||||
&& GetRacialType(oPC) == RACIAL_TYPE_GLOURA)
|
||||
return CLASS_TYPE_BARD;
|
||||
|
||||
return nClass;
|
||||
}
|
||||
|
||||
void CloseNUILevelUpWindow(object oPC=OBJECT_SELF)
|
||||
void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0)
|
||||
{
|
||||
int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR);
|
||||
// if we are refreshing the NUI but not finished we need to clear some caching done
|
||||
// to save computation time as they will need to be reprocessed.
|
||||
DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass));
|
||||
SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20);
|
||||
if (reset)
|
||||
{
|
||||
ClearLevelUpNUICaches(currentClass, oPC);
|
||||
}
|
||||
int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID);
|
||||
if (nPreviousToken != 0)
|
||||
{
|
||||
@@ -1127,7 +1081,7 @@ int ShouldSpellButtonBeEnabled(int nClass, int circleLevel, int spellbookId, obj
|
||||
|
||||
// if its an expanded knowledge choice and we have already made all our
|
||||
// exp knowledge choices then it needs to be disabled.
|
||||
if (IsExpKnowledgePower(nClass, spellbookId))
|
||||
if (IsExpKnowledgePower(nClass, spellbookId, oPC))
|
||||
{
|
||||
int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)
|
||||
+ GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC);
|
||||
@@ -1540,7 +1494,7 @@ int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF
|
||||
// default logic for spont casters
|
||||
totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC);
|
||||
// Favoured Soul has more 0 choices than there are spells for some reason
|
||||
if (nClass == CLASS_TYPE_FAVOURED_SOUL && circleLevel == 0 && totalSpellsKnown > 7)
|
||||
if (nClass == CLASS_TYPE_FAVOURED_SOUL && circleLevel == 0 && totalSpellsKnown > 6)
|
||||
totalSpellsKnown = 7;
|
||||
|
||||
// logic for spont casters
|
||||
@@ -1555,23 +1509,11 @@ int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF
|
||||
|
||||
if (chosenCircle == circleLevel)
|
||||
SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices);
|
||||
if (DEBUG) DoDebug("Remaining spell choices is " + IntToString(remainingChoices));
|
||||
return remainingChoices;
|
||||
}
|
||||
|
||||
void FinishLevelUp(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
RemoveSpells(nClass, oPC);
|
||||
LearnSpells(nClass, oPC);
|
||||
if (nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel);
|
||||
}
|
||||
CloseNUILevelUpWindow(oPC); // Close while selected-class var is still set
|
||||
ClearLevelUpNUICaches(nClass, oPC);
|
||||
}
|
||||
|
||||
/* void FinishLevelUp(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
RemoveSpells(nClass, oPC);
|
||||
LearnSpells(nClass, oPC);
|
||||
@@ -1581,7 +1523,7 @@ void FinishLevelUp(int nClass, object oPC=OBJECT_SELF)
|
||||
SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel);
|
||||
}
|
||||
ClearLevelUpNUICaches(nClass, oPC);
|
||||
} */
|
||||
}
|
||||
|
||||
void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
@@ -1678,11 +1620,13 @@ void RemoveSpells(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
string sSpellBook = GetSpellsKnown_Array(nClass);
|
||||
string spellsAtLevelList = "SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(GetHitDice(oPC));
|
||||
// remove the spell from the spellbook
|
||||
array_extract_int(oPC, sSpellBook, nSpellbookID);
|
||||
array_extract_int(oPC, spellsAtLevelList, nSpellbookID);
|
||||
// wipe the spell from the player
|
||||
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
WipeSpellFromHide(ipFeatID, oPC);
|
||||
RemoveIPFeat(oPC, ipFeatID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1793,6 +1737,7 @@ void LearnSpells(int nClass, object oPC=OBJECT_SELF)
|
||||
|
||||
// get location of persistant storage on the hide
|
||||
string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel);
|
||||
if (DEBUG) DoDebug("Adding spell " + IntToString(nSpellbookID) + "to " + sSpellbook);
|
||||
//object oToken = GetHideToken(oPC);
|
||||
|
||||
// Create spells known persistant array if it is missing
|
||||
@@ -1803,13 +1748,25 @@ void LearnSpells(int nClass, object oPC=OBJECT_SELF)
|
||||
nSize = 0;
|
||||
}
|
||||
|
||||
string spellsAtLevelList = "SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(GetHitDice(oPC));
|
||||
int spellsAtLevelSize = persistant_array_get_size(oPC, spellsAtLevelList);
|
||||
if (spellsAtLevelSize < 0)
|
||||
{
|
||||
persistant_array_create(oPC, spellsAtLevelList);
|
||||
spellsAtLevelSize = 0;
|
||||
}
|
||||
// set the list of spells learned at this level
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
int spellId = StringToInt(Get2DACache(sFile, "SpellID", nSpellbookID));
|
||||
persistant_array_set_int(oPC, spellsAtLevelList, spellsAtLevelSize, spellId);
|
||||
if (DEBUG) DoDebug("Adding spells to array " + spellsAtLevelList);
|
||||
|
||||
// Mark the spell as known (e.g. add it to the end of oPCs spellbook)
|
||||
persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
|
||||
|
||||
if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
// add spell
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
string sArrayName = "NewSpellbookMem_" + IntToString(nClass);
|
||||
int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
|
||||
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
@@ -1989,7 +1946,7 @@ void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int n
|
||||
//if we could not find the spell here, something went wrong
|
||||
if (persistant_array_extract_int(oPC, sTestArray, spellID) < 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "Could not find spellID " + IntToString(spellID) + " in the class's spellbook!");
|
||||
if (DEBUG) DoDebug("Could not find spellID " + IntToString(spellID) + " in the class's spellbook!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2016,10 +1973,7 @@ void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int n
|
||||
|
||||
// remove spell from player
|
||||
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId));
|
||||
itemproperty ipFeat = PRCItemPropertyBonusFeat(ipFeatID);
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
RemoveItemProperty(oSkin, ipFeat);
|
||||
CheckAndRemoveFeat(oSkin, ipFeat);
|
||||
RemoveIPFeat(oPC, ipFeatID);
|
||||
}
|
||||
|
||||
json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0)
|
||||
@@ -2102,7 +2056,7 @@ string ReasonForDisabledSpell(int nClass, int spellbookId, object oPC=OBJECT_SEL
|
||||
|
||||
// if its an expanded knowledge choice and we have already made all our
|
||||
// exp knowledge choices then it needs to be disabled.
|
||||
if (IsExpKnowledgePower(nClass, spellbookId))
|
||||
if (IsExpKnowledgePower(nClass, spellbookId, oPC))
|
||||
{
|
||||
int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)
|
||||
+ GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC);
|
||||
@@ -2336,11 +2290,15 @@ json GetChosenReplaceListObject(object oPC=OBJECT_SELF)
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int IsExpKnowledgePower(int nClass, int spellbookId)
|
||||
int IsExpKnowledgePower(int nClass, int spellbookId, object oPC=OBJECT_SELF)
|
||||
{
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId));
|
||||
return isExp;
|
||||
if (isExp)
|
||||
return TRUE;
|
||||
int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId));
|
||||
int isOuterDomain = (featId) ? !CheckPowerPrereqs(featId, oPC) : FALSE;
|
||||
return isOuterDomain;
|
||||
}
|
||||
|
||||
json GetCurrentPowerList(object oPC=OBJECT_SELF)
|
||||
@@ -2360,12 +2318,8 @@ int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF)
|
||||
string sFile = GetClassSpellbookFile(nClass);
|
||||
int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId));
|
||||
int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId));
|
||||
// if you don't have the prereqs for a power then don't add it. Specific for
|
||||
// psions
|
||||
if (!CheckPowerPrereqs(featId, oPC))
|
||||
return FALSE;
|
||||
// if the power is a expanded knowledge power
|
||||
if (isExp)
|
||||
if (!CheckPowerPrereqs(featId, oPC) || isExp)
|
||||
{
|
||||
// and we have a expanded knowledge choice left to make then show
|
||||
// the button
|
||||
@@ -2374,10 +2328,12 @@ int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF)
|
||||
int currentCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR);
|
||||
|
||||
int choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC);
|
||||
if (DEBUG) DoDebug("You still have " + IntToString(choicesLeft) + " expanded power choices left!");
|
||||
if (choicesLeft && (currentCircle <= (maxLevel-1)))
|
||||
addPower = TRUE;
|
||||
choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC);
|
||||
if (choicesLeft)
|
||||
if (DEBUG) DoDebug("You still have " + IntToString(choicesLeft) + " epic expanded power choices left!");
|
||||
if (choicesLeft && (currentCircle <= (maxLevel-1)))
|
||||
addPower = TRUE;
|
||||
// otherwise don't show the button.
|
||||
return addPower;
|
||||
@@ -2397,7 +2353,7 @@ void LearnPowers(int nClass, object oPC=OBJECT_SELF)
|
||||
int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i));
|
||||
// get the expanded knowledge list we are adding to if any
|
||||
int expKnow = GetExpKnowledgePowerListRequired(nClass, nSpellbookID, oPC);
|
||||
AddPowerKnown(oPC, nClass, nSpellbookID, TRUE, GetManifesterLevel(oPC, nClass, TRUE), expKnow);
|
||||
AddPowerKnown(oPC, nClass, nSpellbookID, TRUE, GetHitDice(oPC), expKnow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2584,7 +2540,7 @@ int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_S
|
||||
if (chosenDisc != JsonNull())
|
||||
{
|
||||
int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER)))
|
||||
+ JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))));
|
||||
+ JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))));
|
||||
if (nManCount >= prereqs)
|
||||
return TRUE;
|
||||
}
|
||||
@@ -3180,13 +3136,18 @@ json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF)
|
||||
}
|
||||
|
||||
SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass), knownObject);
|
||||
if (DEBUG) DoDebug("Printing json representation of allowed invocations for class " + IntToString(nClass));
|
||||
if (DEBUG) DoDebug(JsonDump(knownObject, 2));
|
||||
return knownObject;
|
||||
}
|
||||
|
||||
int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE)
|
||||
{
|
||||
if (DEBUG) DoDebug ("Getting remaining invocation choices at " + IntToString(chosenCircle) + " circle");
|
||||
int remaining = 0;
|
||||
int nLevel = GetInvokerLevel(oPC, nClass);
|
||||
if (nClass == CLASS_TYPE_DRAGON_SHAMAN) nLevel = GetLevelByClass(nClass, oPC);
|
||||
if (DEBUG) DoDebug("Invoker level is " + IntToString(nLevel));
|
||||
|
||||
json knownObject = GetInvokerKnownListObject(nClass, oPC);
|
||||
json chosenInv = GetChosenSpellListObject(nClass, oPC);
|
||||
@@ -3214,8 +3175,10 @@ int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJEC
|
||||
currentChosen += 1;
|
||||
}
|
||||
}
|
||||
if (DEBUG) DoDebug(IntToString(currentChosen) + " incantations chosen at " + IntToString(chosenCircle) + " circle");
|
||||
|
||||
int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i)));
|
||||
if (DEBUG) DoDebug(IntToString(allowedAtCircle) + " incantations allowed at " + IntToString(chosenCircle) + " circle");
|
||||
|
||||
remaining = (allowedAtCircle - currentChosen + remaining);
|
||||
// if the circle is below the chosen circle and we have a positive remaining,
|
||||
|
||||
Reference in New Issue
Block a user