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:
@@ -111,7 +111,7 @@ object CreateLocalNextNPC(object oMaster,int nAssociateType,string sTemplate,loc
|
||||
SetLocalObject(oMaster, IntToString(nAssociateType)+"oHench"+IntToString(nCount), oSummon);
|
||||
SetLocalInt(oSummon, "iAssocNth", nCount);
|
||||
|
||||
SetAssociateState(NW_ASC_HAVE_MASTER,TRUE,oSummon);
|
||||
SetAssociateState(NW_ASC_HAVE_MASTER, TRUE, oSummon);
|
||||
SetAssociateState(NW_ASC_DISTANCE_2_METERS);
|
||||
SetAssociateState(NW_ASC_DISTANCE_4_METERS, FALSE);
|
||||
SetAssociateState(NW_ASC_DISTANCE_6_METERS, FALSE);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
//:://////////////////////////////////////////////
|
||||
#include "nw_inc_gff"
|
||||
#include "inc_debug"
|
||||
#include "prc_inc_racial"
|
||||
#include "prc_inc_nwscript"
|
||||
|
||||
|
||||
//::---------------------------------------------|
|
||||
@@ -30,6 +32,8 @@ int GetMaxPossibleHP(object oCreature)
|
||||
int nMaxHP = 0; // Stores the total maximum hitpoints
|
||||
int i = 1; // Initialize position for class index
|
||||
int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature);
|
||||
int nRacial = MyPRCGetRacialType(oCreature);
|
||||
int nSize = PRCGetCreatureSize(oCreature);
|
||||
|
||||
// Loop through each class position the creature may have, checking each class in turn
|
||||
while (TRUE)
|
||||
@@ -54,8 +58,25 @@ int GetMaxPossibleHP(object oCreature)
|
||||
i++;
|
||||
}
|
||||
|
||||
if(nRacial == RACIAL_TYPE_CONSTRUCT || nRacial == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
nConb = 0;
|
||||
}
|
||||
|
||||
nMaxHP += nConb * GetHitDice(oCreature);
|
||||
|
||||
if(nRacial == RACIAL_TYPE_CONSTRUCT)
|
||||
{
|
||||
if(nSize == CREATURE_SIZE_FINE) nMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_DIMINUTIVE) nMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_TINY) nMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_SMALL) nMaxHP += 10;
|
||||
if(nSize == CREATURE_SIZE_MEDIUM) nMaxHP += 20;
|
||||
if(nSize == CREATURE_SIZE_LARGE) nMaxHP += 30;
|
||||
if(nSize == CREATURE_SIZE_HUGE) nMaxHP += 40;
|
||||
if(nSize == CREATURE_SIZE_GARGANTUAN) nMaxHP += 60;
|
||||
}
|
||||
|
||||
return nMaxHP;
|
||||
}
|
||||
|
||||
@@ -202,13 +223,44 @@ int json_GetCreatureHD(json jCreature)
|
||||
json json_RecalcMaxHP(json jCreature, int iHitDieValue)
|
||||
{
|
||||
int iHD = json_GetCreatureHD(jCreature);
|
||||
int iCON = json_GetCONValue(jCreature);
|
||||
int iMod = GetAbilityModFromValue(iCON);
|
||||
|
||||
//:: Retrieve the RacialType field
|
||||
json jRacialTypeField = JsonObjectGet(jCreature, "Race");
|
||||
int nRacialType = JsonGetInt(jRacialTypeField);
|
||||
|
||||
//:: Retrieve the CreatureSize from the creature appearance field
|
||||
json jAppearanceField = JsonObjectGet(jCreature, "Appearance_Type");
|
||||
int nAppearance = JsonGetInt(jAppearanceField);
|
||||
|
||||
int nSize = StringToInt(Get2DAString("appearance", "SizeCategory", nAppearance));
|
||||
|
||||
//CEP adds other sizes, take them into account too
|
||||
if(nSize == 20)
|
||||
nSize = CREATURE_SIZE_DIMINUTIVE;
|
||||
else if(nSize == 21)
|
||||
nSize = CREATURE_SIZE_FINE;
|
||||
else if(nSize == 22)
|
||||
nSize = CREATURE_SIZE_GARGANTUAN;
|
||||
else if(nSize == 23)
|
||||
nSize = CREATURE_SIZE_COLOSSAL;
|
||||
|
||||
int iNewMaxHP = (iHitDieValue * iHD);
|
||||
|
||||
int nConBonusHP = iMod * iHD;
|
||||
int iNewMaxHP = (iHitDieValue * iHD); /* nConBonusHP */
|
||||
if(nRacialType == RACIAL_TYPE_CONSTRUCT)
|
||||
{
|
||||
if(nSize == CREATURE_SIZE_FINE) iNewMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_DIMINUTIVE) iNewMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_TINY) iNewMaxHP += 0;
|
||||
if(nSize == CREATURE_SIZE_SMALL) iNewMaxHP += 10;
|
||||
if(nSize == CREATURE_SIZE_MEDIUM) iNewMaxHP += 20;
|
||||
if(nSize == CREATURE_SIZE_LARGE) iNewMaxHP += 30;
|
||||
if(nSize == CREATURE_SIZE_HUGE) iNewMaxHP += 40;
|
||||
if(nSize == CREATURE_SIZE_GARGANTUAN) iNewMaxHP += 60;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_RecalcMaxHP | New MaxHP is: "+IntToString(iNewMaxHP)+ ".");
|
||||
|
||||
//jCreature = GffReplaceShort(jCreature, "MaxHitPoints", iNewMaxHP);
|
||||
jCreature = GffReplaceShort(jCreature, "MaxHitPoints", iNewMaxHP);
|
||||
jCreature = GffReplaceShort(jCreature, "CurrentHitPoints", iNewMaxHP);
|
||||
jCreature = GffReplaceShort(jCreature, "HitPoints", iNewMaxHP);
|
||||
|
||||
@@ -425,7 +477,7 @@ json json_AddFeatsFromCreatureVars(json jCreature, int nOriginalHD)
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount));
|
||||
|
||||
int nAdded = 0;
|
||||
int i = 1;
|
||||
int i = 0;
|
||||
int nMaxIterations = 100; // Safety valve
|
||||
int nIterations = 0;
|
||||
|
||||
|
||||
@@ -277,6 +277,32 @@ void ClearNaturalWeapons(object oPC)
|
||||
array_delete(oPC, ARRAY_NAT_PRI_WEAP_ATTACKS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a natural primary weapon to a creature (PC/NPC).
|
||||
*
|
||||
* This function manages a creature's natural primary weapons by storing their
|
||||
* resource references and attack counts in persistent arrays. If the weapon
|
||||
* being added is the first natural weapon, it may automatically become the
|
||||
* creature's active primary natural weapon, unless the creature is a Monk or
|
||||
* Brawler. Optionally, the weapon can be forced to become the active primary
|
||||
* weapon regardless of class.
|
||||
*
|
||||
* @param oPC The creature object to which the natural weapon will be added.
|
||||
* @param sResRef The resource reference string of the natural weapon.
|
||||
* @param nCount (Optional) The number of attacks this natural weapon provides.
|
||||
* Default is 1.
|
||||
* @param nForceUse (Optional) If TRUE, forces this weapon to become the active
|
||||
* primary natural weapon regardless of the creature's class.
|
||||
* Default is FALSE.
|
||||
*
|
||||
* @details
|
||||
* - Creates persistent arrays for weapon references and attack counts if they
|
||||
* do not already exist.
|
||||
* - Checks if the weapon is already present to avoid duplicates.
|
||||
* - Adds the weapon and attack count to the arrays.
|
||||
* - Sets the primary natural weapon index to this weapon if it is the first
|
||||
* natural weapon added, unless the creature is a Monk or Brawler.
|
||||
*/
|
||||
void AddNaturalPrimaryWeapon(object oPC, string sResRef, int nCount = 1, int nForceUse = FALSE)
|
||||
{
|
||||
int nFirstNaturalWeapon = FALSE;
|
||||
|
||||
@@ -363,8 +363,11 @@ int PRCIsFlying(object oCreature)
|
||||
bFlying = TRUE;
|
||||
}
|
||||
if(!bFlying
|
||||
&& ((nWings > 0 && nWings < 79) || nWings == 90))//CEP and Project Q wing models
|
||||
bFlying = TRUE;
|
||||
&& ((nWings > 0 && nWings < 79)
|
||||
|| (nWings > 1959 && nWings < 1962)
|
||||
|| (nWings > 1962 && nWings < 1966)
|
||||
|| nWings == 90))//CEP and Project Q wing models
|
||||
bFlying = TRUE;
|
||||
|
||||
if (GetHasSpellEffect(MOVE_SH_BALANCE_SKY, oCreature))
|
||||
bFlying = TRUE;
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
/* This variable MUST be updated with every new version of the PRC!!! */
|
||||
|
||||
const string PRC_VERSION = "PRC8 4.69";
|
||||
const string PRC_VERSION = "PRC8 4.70";
|
||||
|
||||
/* This variable MUST be updated every time 'assemble_spellbooks.bat' is run!!! */
|
||||
|
||||
|
||||
@@ -672,13 +672,13 @@ void UnarmedFists(object oCreature)
|
||||
|
||||
// Sacred Fists who break their code get no benefits.
|
||||
if (GetHasFeat(FEAT_SF_CODE,oCreature)) iSacFist = 0;
|
||||
|
||||
|
||||
// The monk adds all these classes.
|
||||
int iMonkEq = iMonk + iShou + iSacFist + iHenshin + iZuoken + iShadowSunNinja;
|
||||
|
||||
int iMonkEq = iMonk + iShou + iSacFist + iHenshin + iZuoken + iShadowSunNinja;
|
||||
|
||||
// Ascetic Stalker
|
||||
if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature))
|
||||
iMonkEq += iAscetic;
|
||||
iMonkEq += iAscetic;
|
||||
|
||||
// Determine the type of damage the character should do.
|
||||
string sWeapType;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_lookups"
|
||||
#include "nw_inc_nui"
|
||||
#include "tob_inc_tobfunc"
|
||||
|
||||
//
|
||||
// GetCurrentSpellLevel
|
||||
@@ -153,8 +154,53 @@ json GreyOutButton(json jButton, float w, float h);
|
||||
//
|
||||
json CreateGreyOutRectangle(float w, float h);
|
||||
|
||||
//
|
||||
// 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 CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0);
|
||||
|
||||
void CallSpellUnlevelScript(object oPC, int nClass, int nLevel);
|
||||
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF);
|
||||
void RemoveIPFeat(object oPC, int ipFeatID);
|
||||
|
||||
void CallSpellUnlevelScript(object oPC, int nClass, int nLevel)
|
||||
{
|
||||
SetScriptParam("UnLevel_ClassChoice", IntToString(nClass));
|
||||
SetScriptParam("UnLevel_LevelChoice", IntToString(nLevel));
|
||||
ExecuteScript("prc_unlvl_script", oPC);
|
||||
}
|
||||
|
||||
void RemoveIPFeat(object oPC, int ipFeatID)
|
||||
{
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
itemproperty ipTest = GetFirstItemProperty(oSkin);
|
||||
while(GetIsItemPropertyValid(ipTest))
|
||||
{
|
||||
// Check if the itemproperty is a bonus feat that has been marked for removal
|
||||
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT)
|
||||
{
|
||||
if (GetItemPropertySubType(ipTest) == ipFeatID)
|
||||
{
|
||||
if(DEBUG) DoDebug("_ManeuverRecurseRemoveArray(): Removing bonus feat itemproperty:\n" + DebugIProp2Str(ipTest));
|
||||
// If so, remove it
|
||||
RemoveItemProperty(oSkin, ipTest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ipTest = GetNextItemProperty(oSkin);
|
||||
}
|
||||
}
|
||||
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel)
|
||||
{
|
||||
@@ -528,3 +574,39 @@ void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF)
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -93,9 +93,8 @@ void GainPowerPoints(object oChar, int nGain, int bCanExceedMax = FALSE, int bIn
|
||||
* @param bInform If TRUE, runs TellCharacterPowerPointStatus() on oChar
|
||||
* after making the modification.
|
||||
*/
|
||||
/*
|
||||
void GainTemporaryPowerPoints(object oChar, int nGain, float fDuration, int bInform = TRUE);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decreases the character's current power point count by up to the given
|
||||
* amount, limited to not going below 0.
|
||||
|
||||
Reference in New Issue
Block a user