Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80070703b4 |
12
Notes/Class Expansion/Epic Swashbuckler.txt
Normal file
12
Notes/Class Expansion/Epic Swashbuckler.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
You have become the embodiment of panache and daring. You are an epic Swashbuckler.
|
||||
|
||||
Hit Die: d10
|
||||
Skill Points at Each Additional Level: 4+ Int Modifier
|
||||
Bonus Feats: The epic swashbuckler gains a bonus feat every three levels.
|
||||
|
||||
Special:
|
||||
Swashbuckler Dodge: This bonus continues to increase by +1 at every five levels after 20th.
|
||||
Grace: An epic swashbuckler gains another +1 bonus on Reflex saves at 29th and 39th level. A swashbuckler loses this bonus when wearing medium or heavy armor or when encumbered.
|
||||
|
||||
Epic Swashbuckler Bonus Feat List:
|
||||
Armor Skin, Blinding Speed, Devastating Critical, Epic Damage Reduction, Epic Prowess, Epic Toughness, Epic Weapon Focus, Improved Stunning Fist, Improved Whirlwind Attack, Overwhelming Critical, Superior Initiative
|
||||
BIN
Notes/MartialStudyNotes.pdf
Normal file
BIN
Notes/MartialStudyNotes.pdf
Normal file
Binary file not shown.
682
Notes/prc_amagsys_gain.nss.bak
Normal file
682
Notes/prc_amagsys_gain.nss.bak
Normal file
@@ -0,0 +1,682 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Alternate magic system gain evaluation script
|
||||
//:: prc_amagsys_gain
|
||||
//:://////////////////////////////////////////////
|
||||
/** @file
|
||||
This file determines if the given character
|
||||
has gained new spells / powers / utterances /
|
||||
whathaveyou since the last time it was run.
|
||||
If so, it starts the relevant selection
|
||||
conversations.
|
||||
|
||||
Add new classes to their respective magic
|
||||
user type block, or if such doesn't exist
|
||||
yet for the system the class belongs to,
|
||||
make a new block for them at the end of main().
|
||||
|
||||
|
||||
@author Ornedan
|
||||
@date Created - 2006.12.14
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
//:: Updated for .35 by Jaysyn 2023/03/11
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "inc_dynconv"
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_newspellbook"
|
||||
#include "true_inc_trufunc"
|
||||
#include "tob_inc_tobfunc"
|
||||
#include "shd_inc_shdfunc"
|
||||
#include "inv_inc_invfunc"
|
||||
#include "prc_nui_lv_inc"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void CheckSpellbooks(object oPC);
|
||||
void CheckPsionics(object oPC);
|
||||
void CheckInvocations(object oPC);
|
||||
void CheckToB(object oPC);
|
||||
void CheckShadow(object oPC);
|
||||
void CheckTruenaming(object oPC);
|
||||
int CheckMissingPowers(object oPC, int nClass);
|
||||
int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel);
|
||||
int CheckMissingUtterances(object oPC, int nClass, int nLexicon);
|
||||
int CheckMissingManeuvers(object oPC, int nClass);
|
||||
int CheckMissingMysteries(object oPC, int nClass);
|
||||
int CheckMissingInvocations(object oPC, int nClass);
|
||||
void AMSCompatibilityCheck(object oPC);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
// Sanity checks - Shifted or polymorphed characters may have their hide fucked up, and might be missing access to their hide-feats
|
||||
// @todo Shifting probably doesn't do this anymore, could be ditchable - Ornedan, 20061214
|
||||
if(GetLocalInt(oPC, "nPCShifted"))
|
||||
return;
|
||||
effect eTest = GetFirstEffect(oPC);
|
||||
while(GetIsEffectValid(eTest))
|
||||
{
|
||||
if(GetEffectType(eTest) == EFFECT_TYPE_POLYMORPH)
|
||||
return;
|
||||
eTest = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
DelayCommand(0.0f, CheckSpellbooks(oPC));
|
||||
}
|
||||
|
||||
// Handle new spellbooks
|
||||
|
||||
void CheckSpellbooks(object oPC)
|
||||
{
|
||||
|
||||
if(GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) > 0)
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_SUBLIME_CHORD, 4, 9);
|
||||
|
||||
if(GetHasFeat(FEAT_SUBLIME_CHORD_SPELLCASTING_BARD, oPC))
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 3);
|
||||
}
|
||||
if(GetHasFeat(FEAT_SUBLIME_CHORD_SPELLCASTING_SORCERER))
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 3);
|
||||
}
|
||||
if(GetHasFeat(FEAT_SUBLIME_CHORD_SPELLCASTING_WARMAGE, oPC))
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_WARMAGE, 0, 3);
|
||||
}
|
||||
if(GetHasFeat(FEAT_SUBLIME_CHORD_SPELLCASTING_DUSKBLADE, oPC))
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_DUSKBLADE, 0, 3);
|
||||
}
|
||||
if(GetHasFeat(FEAT_SUBLIME_CHORD_SPELLCASTING_BEGUILER, oPC))
|
||||
{
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_BEGUILER, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Check all classes that might need a spellbook update
|
||||
if(GetIsRHDSorcerer(oPC)) CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9);
|
||||
if(GetIsRHDBard(oPC)) CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6);
|
||||
|
||||
if(!GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK))
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6);
|
||||
if(!GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK))
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9);
|
||||
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_SUEL_ARCHANAMACH, 1, 5);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_FAVOURED_SOUL, 0, 9);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_WARMAGE, 0, 9);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_DREAD_NECROMANCER, 1, 9);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_HEXBLADE, 1, 4);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_DUSKBLADE, 0, 5);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_JUSTICEWW, 1, 4);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_KNIGHT_WEAVE, 1, 6);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_ARCHIVIST, 0, 9);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_BEGUILER, 0, 9);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_HARPER, 1, 3);
|
||||
CheckMissingSpells(oPC, CLASS_TYPE_CELEBRANT_SHARESS, 1, 4);
|
||||
//CheckMissingSpells(oPC, CLASS_TYPE_ASSASSIN, 1, 4);
|
||||
|
||||
// Check psionics
|
||||
DelayCommand(0.0f, CheckPsionics(oPC));
|
||||
}
|
||||
|
||||
|
||||
/* void CheckSpellbooks(object oPC)
|
||||
{
|
||||
if(GetIsRHDSorcerer(oPC) && CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9))
|
||||
return;
|
||||
if(GetIsRHDBard(oPC) && CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6))
|
||||
return;
|
||||
if(!GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6))
|
||||
return;
|
||||
if(!GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_SUEL_ARCHANAMACH, 1, 5))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_FAVOURED_SOUL, 0, 9))
|
||||
return;
|
||||
// if(CheckMissingSpells(oPC, CLASS_TYPE_MYSTIC, 0, 9))
|
||||
// return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_WARMAGE, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_DREAD_NECROMANCER, 1, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_HEXBLADE, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_DUSKBLADE, 0, 5))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_JUSTICEWW, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_KNIGHT_WEAVE, 1, 6))
|
||||
return;
|
||||
// if(CheckMissingSpells(oPC, CLASS_TYPE_WITCH, 0, 9))
|
||||
// return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_SUBLIME_CHORD, 4, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_ARCHIVIST, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_BEGUILER, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_HARPER, 1, 3))
|
||||
return;
|
||||
// if(CheckMissingSpells(oPC, CLASS_TYPE_TEMPLAR, 0, 9))
|
||||
// return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_ASSASSIN, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_CELEBRANT_SHARESS, 1, 4))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckPsionics(oPC));
|
||||
}
|
||||
*/
|
||||
|
||||
// Handle psionics
|
||||
void CheckPsionics(object oPC)
|
||||
{
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSION))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_WILDER))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSYWAR))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSYCHIC_ROGUE))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_FIST_OF_ZUOKEN))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_WARMIND))
|
||||
return;
|
||||
//expanded knowledge
|
||||
if(CheckMissingPowers(oPC, -1))
|
||||
return;
|
||||
//epic expanded knowledge
|
||||
if(CheckMissingPowers(oPC, -2))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckInvocations(oPC));
|
||||
}
|
||||
|
||||
// Handle Invocations
|
||||
void CheckInvocations(object oPC)
|
||||
{
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGONFIRE_ADEPT))
|
||||
return;
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_WARLOCK))
|
||||
return;
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGON_SHAMAN))
|
||||
return;
|
||||
//extra invocations
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_INVALID))
|
||||
return;
|
||||
//epic extra invocations
|
||||
if(CheckMissingInvocations(oPC, -2))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckToB(oPC));
|
||||
}
|
||||
|
||||
// Handle Tome of Battle
|
||||
void CheckToB(object oPC)
|
||||
{
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_CRUSADER))
|
||||
return;
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_SWORDSAGE))
|
||||
return;
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_WARBLADE))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckShadow(oPC));
|
||||
}
|
||||
|
||||
// Handle Shadowcasting
|
||||
void CheckShadow(object oPC)
|
||||
{
|
||||
if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWCASTER))
|
||||
return;
|
||||
if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWSMITH))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckTruenaming(oPC));
|
||||
}
|
||||
|
||||
// Handle Truenaming - Three different Lexicons to check
|
||||
void CheckTruenaming(object oPC)
|
||||
{
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_EVOLVING_MIND))
|
||||
return;
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_CRAFTED_TOOL))
|
||||
return;
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_PERFECTED_MAP))
|
||||
return;
|
||||
|
||||
if(!GetIsDM(oPC))
|
||||
DelayCommand(0.0f, AMSCompatibilityCheck(oPC));
|
||||
}
|
||||
|
||||
int CheckMissingPowers(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel && nClass != -1 && nClass != -2)
|
||||
return FALSE;
|
||||
else if(nClass == -1 && !GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1))
|
||||
return FALSE;
|
||||
else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1))
|
||||
return FALSE;
|
||||
|
||||
int nCurrentPowers = GetPowerCount(oPC, nClass);
|
||||
int nMaxPowers = GetMaxPowerCount(oPC, nClass);
|
||||
|
||||
if(nCurrentPowers < nMaxPowers)
|
||||
{
|
||||
if (nClass <= 0)
|
||||
nClass = GetPrimaryPsionicClass(oPC);
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("psi_powconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingInvocations(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel && (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN))
|
||||
return FALSE;
|
||||
else if(nClass == CLASS_TYPE_INVALID && !GetHasFeat(FEAT_EXTRA_INVOCATION_I))
|
||||
return FALSE;
|
||||
else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I))
|
||||
return FALSE;
|
||||
|
||||
int nCurrentInvocations = GetInvocationCount(oPC, nClass);
|
||||
if(DEBUG) DoDebug("Current Invocations: " + IntToString(nCurrentInvocations));
|
||||
int nMaxInvocations = GetMaxInvocationCount(oPC, nClass);
|
||||
if(DEBUG) DoDebug("Max Invocations: " + IntToString(nMaxInvocations));
|
||||
|
||||
if(nCurrentInvocations < nMaxInvocations)
|
||||
{
|
||||
if (nClass == CLASS_TYPE_INVALID || nClass == -2)
|
||||
nClass = GetPrimaryInvocationClass(oPC);
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain invocations and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("inv_invokeconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void AddSpellsForLevel(int nClass, int nLevel)
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
//object oToken = GetHideToken(oPC);
|
||||
string sFile = GetFileForClass(nClass);
|
||||
string sSpellbook;
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
sSpellbook = "Spellbook"+IntToString(nClass);
|
||||
else
|
||||
sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(nLevel);
|
||||
|
||||
// Create spells known persistant array if it is missing
|
||||
int nSize = persistant_array_get_size(oPC, sSpellbook);
|
||||
if (nSize < 0)
|
||||
{
|
||||
persistant_array_create(oPC, sSpellbook);
|
||||
nSize = 0;
|
||||
}
|
||||
|
||||
//check for learnable spells
|
||||
object oToken_Class = GetObjectByTag("SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nLevel));
|
||||
int nSpells_Total = persistant_array_get_size(oToken_Class, "Lkup");
|
||||
int i;
|
||||
for(i = 0; i < nSpells_Total; i++)
|
||||
{
|
||||
int nSpellbookID = persistant_array_get_int(oToken_Class, "Lkup", i);
|
||||
if(Get2DAString(sFile, "AL", nSpellbookID) != "1")
|
||||
{
|
||||
persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
|
||||
nSize++;
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
|
||||
AddSpellUse(oPC, nSpellbookID, nClass, sFile, "NewSpellbookMem_" + IntToString(nClass), nSpellbookType, oSkin, nFeatID, nIPFeatID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel)
|
||||
{
|
||||
int nLevel;
|
||||
|
||||
//:: Rakshasa cast as sorcerers
|
||||
if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC);
|
||||
|
||||
//:: Aranea cast as sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_ARANEA)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_SHAPECHANGER, oPC);
|
||||
|
||||
//::Arkamoi cast as sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
|
||||
//::Hobgoblin Warsouls cast as sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
|
||||
//:: Driders cast as sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_DRIDER)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_ABERRATION, oPC);
|
||||
|
||||
//:: Marrutact cast as 6/7 sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
|
||||
//:: Redspawn Arcaniss cast as 3/4 sorcerers
|
||||
else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
|
||||
//:: Gloura cast as bards
|
||||
else if(nClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oPC) && GetRacialType(oPC) == RACIAL_TYPE_GLOURA)
|
||||
nLevel = GetSpellslotLevel(nClass, oPC); //GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
|
||||
else
|
||||
nLevel = nClass == CLASS_TYPE_SUBLIME_CHORD ? GetLevelByClass(nClass, oPC) : GetSpellslotLevel(nClass, oPC);
|
||||
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 1 Class: " + IntToString(nClass));
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 1 Level: " + IntToString(nLevel));
|
||||
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
if(nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
if((GetLevelByClass(nClass, oPC) == nLevel) //no PrC
|
||||
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || GetHasFeat(FEAT_DRACONIC_BREATH, oPC))) //no Draconic feats that apply
|
||||
return FALSE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
int nLastGainLevel = GetPersistantLocalInt(oPC, "LastSpellGainLevel");
|
||||
nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
|
||||
|
||||
|
||||
//add cleric spells known for level 0
|
||||
if(persistant_array_get_size(oPC, "Spellbook_Known_"+IntToString(CLASS_TYPE_ARCHIVIST)+"_0") < 5) // TODO: replace with GetSpellKnownCurrentCount
|
||||
{
|
||||
ActionDoCommand(AddSpellsForLevel(CLASS_TYPE_ARCHIVIST, 0));
|
||||
}
|
||||
if(nLastGainLevel < nLevel)
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_ARCHIVIST);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, TRUE, FALSE, oPC);
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 2 Class: " + IntToString(nClass));
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 2 Level: " + IntToString(nLevel));
|
||||
|
||||
int i;
|
||||
for(i = nMinLevel; i <= nMaxLevel; i++)
|
||||
{
|
||||
int nMaxSpells = GetSpellKnownMaxCount(nLevel, i, nClass, oPC);
|
||||
if(nMaxSpells > 0)
|
||||
{
|
||||
int nCurrentSpells = GetSpellKnownCurrentCount(oPC, i, nClass);
|
||||
int nSpellsAvailable = GetSpellUnknownCurrentCount(oPC, i, nClass);
|
||||
|
||||
if(nCurrentSpells < nMaxSpells && nSpellsAvailable > 0)
|
||||
{
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS && bKnowsAllClassSpells(nClass))
|
||||
{
|
||||
ActionDoCommand(AddSpellsForLevel(nClass, i));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", nClass);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "SpellbookMaxSpelllevel", nMaxLevel);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Advanced Learning check
|
||||
nLevel = GetLevelByClass(nClass, oPC);
|
||||
int nALSpells = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass));
|
||||
if(nClass == CLASS_TYPE_BEGUILER && nALSpells < (nLevel+1)/4)//one every 4 levels starting at 3.
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_BEGUILER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_DREAD_NECROMANCER && nALSpells < nLevel/4)//one every 4 levels
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_DREAD_NECROMANCER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_WARMAGE)
|
||||
{
|
||||
if((nLevel >= 40 && nALSpells < 9) ||// :/
|
||||
(nLevel >= 36 && nLevel < 40 && nALSpells < 8) ||
|
||||
(nLevel >= 32 && nLevel < 36 && nALSpells < 7) ||
|
||||
(nLevel >= 28 && nLevel < 32 && nALSpells < 6) ||
|
||||
(nLevel >= 24 && nLevel < 28 && nALSpells < 5) ||
|
||||
(nLevel >= 16 && nLevel < 24 && nALSpells < 4) ||
|
||||
(nLevel >= 11 && nLevel < 16 && nALSpells < 3) ||
|
||||
(nLevel >= 6 && nLevel < 11 && nALSpells < 2) ||
|
||||
(nLevel >= 3 && nLevel < 6 && nALSpells < 1))
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_WARMAGE);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_NIGHTSTALKER && nALSpells < (nLevel+1)/6)//one every 6 levels starting at 5th
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_NIGHTSTALKER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingUtterances(object oPC, int nClass, int nLexicon)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentUtterances = GetUtteranceCount(oPC, nClass, nLexicon);
|
||||
int nMaxUtterances = GetMaxUtteranceCount(oPC, nClass, nLexicon);
|
||||
if(DEBUG) DoDebug("CheckMissingUtterances(" + IntToString(nClass) + ", " + IntToString(nLexicon) + ", " + GetName(oPC) + ") = " + IntToString(nCurrentUtterances) + ", " + IntToString(nMaxUtterances));
|
||||
|
||||
if(nCurrentUtterances < nMaxUtterances)
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain Utterances and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("true_utterconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingManeuvers(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentManeuvers = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
|
||||
int nMaxManeuvers = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
|
||||
int nCurrentStances = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
|
||||
int nMaxStances = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
|
||||
|
||||
if(nCurrentManeuvers < nMaxManeuvers || nCurrentStances < nMaxStances)
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("tob_moveconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingMysteries(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentMysteries = GetMysteryCount(oPC, nClass);
|
||||
int nMaxMysteries = GetMaxMysteryCount(oPC, nClass);
|
||||
|
||||
if(nCurrentMysteries < nMaxMysteries)
|
||||
{
|
||||
if (!IsLevelUpNUIOpen(oPC))
|
||||
OpenNUILevelUpWindow(nClass, oPC);
|
||||
/*
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("shd_mystconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//AMS Compatibility functions - xwarren:
|
||||
void CopyAMSArray(object oPC, object oAMSToken, int nClass, string sArray, int nMin, int nMax, int nLoopSize = 100)
|
||||
{
|
||||
string sFile = GetFileForClass(nClass);
|
||||
int i = nMin;
|
||||
while(i < nMin + nLoopSize && i < nMax)
|
||||
{
|
||||
int nSpellbookID = persistant_array_get_int(oPC, sArray, i);
|
||||
int nSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
|
||||
if(DEBUG) DoDebug("Copying spell "+IntToString(nSpell));
|
||||
array_set_int(oAMSToken, sArray, i, nSpell);
|
||||
i++;
|
||||
}
|
||||
if(i < nMax)
|
||||
DelayCommand(0.0, CopyAMSArray(oPC, oAMSToken, nClass, sArray, i, nMax));
|
||||
}
|
||||
|
||||
void DoBuckUpAMS(object oPC, int nClass, string sSpellbook, object oHideToken, object oAMSToken)
|
||||
{
|
||||
if(DEBUG) DoDebug("Creating buck-up copy of "+sSpellbook);
|
||||
if(array_exists(oAMSToken, sSpellbook))
|
||||
array_delete(oAMSToken, sSpellbook);
|
||||
array_create(oAMSToken, sSpellbook);
|
||||
int nSize = persistant_array_get_size(oPC, sSpellbook);
|
||||
DelayCommand(0.0, CopyAMSArray(oPC, oAMSToken, nClass, sSpellbook, 0, nSize));
|
||||
}
|
||||
|
||||
void AMSCompatibilityCheck(object oPC)
|
||||
{
|
||||
//Get an extra hide token with amagsys info
|
||||
object oAMSToken = GetHideToken(oPC, TRUE);
|
||||
object oHideToken = GetHideToken(oPC); //ebonfowl: no longer used but I'm leaving it to not have to edit other functions
|
||||
|
||||
int i;
|
||||
for(i = 1; i <= 8; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
string sSpellbook;
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
sSpellbook = "Spellbook"+IntToString(nClass);
|
||||
int nSize1 = persistant_array_get_size(oPC, sSpellbook);
|
||||
int nSize2 = array_get_size(oAMSToken, sSpellbook);
|
||||
if(nSize1 > nSize2)
|
||||
DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
|
||||
}
|
||||
else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
|
||||
{
|
||||
int j;
|
||||
for(j = 0; j <= 9; j++)
|
||||
{
|
||||
sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(j);
|
||||
int nSize1 = persistant_array_get_size(oPC, sSpellbook);
|
||||
int nSize2 = array_get_size(oAMSToken, sSpellbook);
|
||||
if(nSize1 > nSize2)
|
||||
DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
530
Notes/prc_nui_com_inc.nss.bak
Normal file
530
Notes/prc_nui_com_inc.nss.bak
Normal file
@@ -0,0 +1,530 @@
|
||||
#include "prc_nui_consts"
|
||||
#include "inc_newspellbook"
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_lookups"
|
||||
#include "nw_inc_nui"
|
||||
|
||||
//
|
||||
// GetCurrentSpellLevel
|
||||
// Gets the current spell level the class can achieve at the current
|
||||
// caster level (ranging from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
// nLevel:int the caster level
|
||||
//
|
||||
// Returns:
|
||||
// int the circle the class can achieve currently
|
||||
//
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel);
|
||||
|
||||
//
|
||||
// GetMaxSpellLevel
|
||||
// Gets the highest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest circle that can be achieved
|
||||
//
|
||||
int GetMaxSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetMinSpellLevel
|
||||
// Gets the lowest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the lowest circle that can be achieved
|
||||
//
|
||||
int GetMinSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetHighestLevelPossibleInClass
|
||||
// Given a class Id this will determine what the max level of a class can be
|
||||
// achieved
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest possible level the class can achieve
|
||||
//
|
||||
int GetHighestLevelPossibleInClass(int nClass);
|
||||
|
||||
//
|
||||
// GetClassSpellbookFile
|
||||
// Gets the class 2da spellbook/ability for the given class Id
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the classID
|
||||
//
|
||||
// Returns:
|
||||
// string the 2da file name for the spell/abilities of the ClassID
|
||||
//
|
||||
string GetClassSpellbookFile(int nClass);
|
||||
|
||||
//
|
||||
// GetBinderSpellToFeatDictionary
|
||||
// Sets up the Binder Spell Dictionary that is used to match a binder's vestige
|
||||
// to their feat. This is constructed based off the binder's known location of
|
||||
// their feat and spell ranges in the base 2das respectivly. After constructing
|
||||
// this it will be saved to the player locally as a cached result since we do
|
||||
// not need to call this again.
|
||||
//
|
||||
// Argument:
|
||||
// oPlayer:object the player
|
||||
//
|
||||
// Returns:
|
||||
// json:Dictionary<String,Int> a dictionary of mapping between the SpellID
|
||||
// and the FeatID of a vestige ability
|
||||
//
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF);
|
||||
|
||||
//
|
||||
// GetSpellLevelIcon
|
||||
// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns
|
||||
// into "ir_cantrips"
|
||||
//
|
||||
// Arguments:
|
||||
// spellLevel:int the spell level we want the icon for
|
||||
//
|
||||
// Returns:
|
||||
// string the spell level icon
|
||||
//
|
||||
string GetSpellLevelIcon(int spellLevel);
|
||||
|
||||
//
|
||||
// GetSpellLevelToolTip
|
||||
// Gets the spell level tool tip text based on the int spell level provided (i.e.
|
||||
// 0 turns into "Cantrips")
|
||||
//
|
||||
// Arguments:
|
||||
// spellLevel:int the spell level we want the tooltip for
|
||||
//
|
||||
// Returns:
|
||||
// string the spell level toop tip
|
||||
//
|
||||
string GetSpellLevelToolTip(int spellLevel);
|
||||
|
||||
//
|
||||
// GetSpellIcon
|
||||
// Gets the spell icon based off the spellId, or featId supplied
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the class Id
|
||||
// featId:int the featId we can use the icon for
|
||||
// spellId:int the spell Id we want the icon for
|
||||
//
|
||||
// Returns:
|
||||
// json:String the string of the icon we want.
|
||||
//
|
||||
json GetSpellIcon(int spellId, int featId=0, int nClass=0);
|
||||
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0);
|
||||
|
||||
//
|
||||
// GreyOutButton
|
||||
// Takes NUI Button along with it's width and height and greys it out it with a drawn
|
||||
// colored rectangle to represent it's not been selected or not valid.
|
||||
//
|
||||
// Arguments:
|
||||
// jButton:json the NUI Button
|
||||
// w:float the width of the button
|
||||
// h:float the height of the button
|
||||
//
|
||||
// Returns:
|
||||
// json the NUI button greyed out
|
||||
//
|
||||
json GreyOutButton(json jButton, float w, float h);
|
||||
|
||||
//
|
||||
// CreateGreyOutRectangle
|
||||
// Creates a grey out rectangle for buttons
|
||||
//
|
||||
// Arguments:
|
||||
// w:float the width of the button
|
||||
// h:float the height of the button
|
||||
//
|
||||
// Returns:
|
||||
// json the transparant black rectangle
|
||||
//
|
||||
json CreateGreyOutRectangle(float w, float h);
|
||||
|
||||
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0);
|
||||
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF);
|
||||
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel)
|
||||
{
|
||||
int currentLevel = nLevel;
|
||||
|
||||
// ToB doesn't have a concept of spell levels, but still match up to it
|
||||
if(nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER)
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
|
||||
// Binders don't really have a concept of spell level
|
||||
if (nClass == CLASS_TYPE_BINDER
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle
|
||||
return 1;
|
||||
|
||||
//Shadowsmith has no concept of spell levels
|
||||
if (nClass == CLASS_TYPE_SHADOWSMITH)
|
||||
return 2;
|
||||
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
return 4;
|
||||
|
||||
// Spont casters have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
|
||||
int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel);
|
||||
return maxLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
string spellLevel2da = GetAMSKnownFileName(nClass);
|
||||
|
||||
currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da
|
||||
|
||||
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)
|
||||
currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1;
|
||||
|
||||
int totalLevel = Get2DARowCount(spellLevel2da);
|
||||
|
||||
// in case we somehow go over bounds just don't :)
|
||||
if (currentLevel >= totalLevel)
|
||||
currentLevel = totalLevel - 1;
|
||||
|
||||
//Psionics have MaxPowerLevel as their column name
|
||||
string columnName = "MaxPowerLevel";
|
||||
|
||||
//Invokers have MaxInvocationLevel
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
columnName = "MaxInvocationLevel";
|
||||
|
||||
// Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
columnName = "EvolvingMind";
|
||||
spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
columnName = "VestigeLvl";
|
||||
spellLevel2da = "cls_bind_binder";
|
||||
}
|
||||
|
||||
// ToB doesn't have a concept of this, but we don't care.
|
||||
|
||||
int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel));
|
||||
return maxLevel;
|
||||
}
|
||||
}
|
||||
|
||||
int GetMinSpellLevel(int nClass)
|
||||
{
|
||||
// again sponts have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
|| nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER
|
||||
|| nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_BINDER)
|
||||
return 1;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int GetMaxSpellLevel(int nClass)
|
||||
{
|
||||
if (nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSION)
|
||||
return 9;
|
||||
if (nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_WARMIND)
|
||||
return 5;
|
||||
if (nClass == CLASS_TYPE_PSYWAR)
|
||||
return 6;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
|
||||
int GetHighestLevelPossibleInClass(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
|
||||
//sponts have their spells in the classes.2da
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
sFile = GetAMSKnownFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
sFile = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "cls_bind_binder";
|
||||
}
|
||||
}
|
||||
|
||||
return Get2DARowCount(sFile);
|
||||
}
|
||||
|
||||
string GetClassSpellbookFile(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
// Spontaneous casters use a specific file name structure
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = GetFileForClass(nClass);
|
||||
}
|
||||
// everyone else uses this structure
|
||||
else
|
||||
{
|
||||
sFile = GetAMSDefinitionFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "vestiges";
|
||||
}
|
||||
}
|
||||
|
||||
return sFile;
|
||||
}
|
||||
|
||||
string GetSpellLevelIcon(int spellLevel)
|
||||
{
|
||||
switch (spellLevel)
|
||||
{
|
||||
case 0: return "ir_cantrips";
|
||||
case 1: return "ir_level1";
|
||||
case 2: return "ir_level2";
|
||||
case 3: return "ir_level3";
|
||||
case 4: return "ir_level4";
|
||||
case 5: return "ir_level5";
|
||||
case 6: return "ir_level6";
|
||||
case 7: return "ir_level789";
|
||||
case 8: return "ir_level789";
|
||||
case 9: return "ir_level789";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetSpellLevelToolTip(int spellLevel)
|
||||
{
|
||||
switch (spellLevel)
|
||||
{
|
||||
case 0: return "Cantrips";
|
||||
case 1: return "Level 1";
|
||||
case 2: return "Level 2";
|
||||
case 3: return "Level 3";
|
||||
case 4: return "Level 4";
|
||||
case 5: return "Level 5";
|
||||
case 6: return "Level 6";
|
||||
case 7: return "Level 7";
|
||||
case 8: return "Level 8";
|
||||
case 9: return "Level 9";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
json GetSpellIcon(int spellId,int featId=0,int nClass=0)
|
||||
{
|
||||
// Binder's spells don't have the FeatID on the spells.2da, so we have to use
|
||||
// the mapping we constructed to get it.
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
json binderDict = GetBinderSpellToFeatDictionary();
|
||||
int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId)));
|
||||
return JsonString(Get2DACache("feat", "Icon", featId));
|
||||
}
|
||||
|
||||
if (featId)
|
||||
return JsonString(Get2DACache("feat", "Icon", featId));
|
||||
|
||||
int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId));
|
||||
|
||||
// if this is a sub radial spell, then we use spell's icon instead
|
||||
if (masterSpellID)
|
||||
return JsonString(Get2DACache("spells", "IconResRef", spellId));
|
||||
|
||||
// the FeatID holds the accurate spell icon, not the SpellID
|
||||
int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId));
|
||||
|
||||
return JsonString(Get2DACache("feat", "Icon", nFeatID));
|
||||
}
|
||||
|
||||
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0)
|
||||
{
|
||||
if ((nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER) && spellId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
if (nClass == CLASS_TYPE_TRUENAMER && featId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
||||
if (realSpellID)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID)));
|
||||
if (spellId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
if (featId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
||||
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
}
|
||||
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF)
|
||||
{
|
||||
// a dictionary of <SpellID, FeatID>
|
||||
json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR);
|
||||
// if this hasn't been created, create it now.
|
||||
if (binderDict == JsonNull())
|
||||
binderDict = JsonObject();
|
||||
else
|
||||
return binderDict;
|
||||
|
||||
// the starting row for binder spells
|
||||
int spellIndex = 19070;
|
||||
// the starting row for binder feats
|
||||
int featIndex = 9030;
|
||||
//the end of the binder spells/feats
|
||||
while (spellIndex <= 19156 && featIndex <= 9104)
|
||||
{
|
||||
// get the SpellID tied to the feat
|
||||
int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex));
|
||||
// if the spellID matches the current index, then this is the spell
|
||||
// attached to the feat
|
||||
if (spellID == spellIndex)
|
||||
{
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex));
|
||||
|
||||
// move to next spell/feat
|
||||
featIndex++;
|
||||
spellIndex++;
|
||||
}
|
||||
// else we have reached a subdial spell
|
||||
else
|
||||
{
|
||||
// loop through until we reach back at spellID
|
||||
while (spellIndex < spellID)
|
||||
{
|
||||
int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex));
|
||||
|
||||
// add the sub radial to the dict, tied to the master's FeatID
|
||||
int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell)));
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId));
|
||||
|
||||
spellIndex++;
|
||||
}
|
||||
|
||||
|
||||
// some feats overlap the same FeatID, can cause this to get stuck.
|
||||
// if it happens then move on
|
||||
if (spellIndex > spellID)
|
||||
featIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// cache the result
|
||||
SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict);
|
||||
return binderDict;
|
||||
}
|
||||
|
||||
json GreyOutButton(json jButton, float w, float h)
|
||||
{
|
||||
json retValue = jButton;
|
||||
|
||||
json jBorders = JsonArray();
|
||||
jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h));
|
||||
|
||||
return NuiDrawList(jButton, JsonBool(FALSE), jBorders);
|
||||
}
|
||||
|
||||
json CreateGreyOutRectangle(float w, float h)
|
||||
{
|
||||
// set the points of the button shape
|
||||
json jPoints = JsonArray();
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints);
|
||||
}
|
||||
|
||||
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0)
|
||||
{
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass);
|
||||
ExecuteScript("prc_nui_dsc_view", oPlayer);
|
||||
}
|
||||
|
||||
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF)
|
||||
{
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR);
|
||||
}
|
||||
|
||||
3353
Notes/prc_nui_lv_inc.nss.bak
Normal file
3353
Notes/prc_nui_lv_inc.nss.bak
Normal file
File diff suppressed because it is too large
Load Diff
165
Notes/prc_onplayerchat.nss.bak
Normal file
165
Notes/prc_onplayerchat.nss.bak
Normal file
@@ -0,0 +1,165 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: OnPlayerChat eventscript
|
||||
//:: prc_onplayerchat
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
A OnChat script that parses what is said and
|
||||
uses any commands or NUI associated with
|
||||
commands.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Updated By: Rakiov
|
||||
//:: Created On: 22.05.2005
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
PRC Chat Command Format:
|
||||
~~command arg1 arg2 arg3 arg4 arg5
|
||||
OR:
|
||||
..command arg1 arg2 arg3 arg4 arg5
|
||||
*/
|
||||
|
||||
#include "prc_alterations"
|
||||
#include "prc_inc_chat"
|
||||
#include "prc_inc_chat_dm"
|
||||
#include "prc_inc_chat_pow"
|
||||
#include "prc_inc_chat_shf"
|
||||
#include "nw_inc_nui"
|
||||
#include "prc_string_inc"
|
||||
#include "prc_nui_sb_inc"
|
||||
#include "prc_nui_consts"
|
||||
#include "prc_nui_lv_inc"
|
||||
|
||||
const string CHAT_COMMAND_INDICATOR_1 = "~~";
|
||||
const string CHAT_COMMAND_INDICATOR_2 = "..";
|
||||
const int CHAT_COMMAND_INDICATOR_LENGHT = 2;
|
||||
|
||||
int GetIsChatCommand(string sString)
|
||||
{
|
||||
string sTest = GetStringLeft(sString, CHAT_COMMAND_INDICATOR_LENGHT);
|
||||
if(sTest == CHAT_COMMAND_INDICATOR_1
|
||||
|| sTest == CHAT_COMMAND_INDICATOR_2)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
string RemoveChatCommandIndicator(string sString)
|
||||
{
|
||||
return GetStringRight(sString, GetStringLength(sString) - CHAT_COMMAND_INDICATOR_LENGHT);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCChatSpeaker();
|
||||
string sChat = GetPCChatMessage();
|
||||
|
||||
if(GetIsChatCommand(sChat))
|
||||
{
|
||||
sChat = RemoveChatCommandIndicator(sChat);
|
||||
SetPCChatVolume(TALKVOLUME_TELL); //Set volume for all chat commands
|
||||
|
||||
if(GetStringWord(sChat, 1) == "help")
|
||||
{
|
||||
if(GetStringWord(sChat, 2) == "")
|
||||
{
|
||||
HelpText(oPC, "=== HELP SUMMARY");
|
||||
HelpText(oPC, "");
|
||||
HelpText(oPC, "Chat commands start with ~~ or .. followed by the command name and then any parameters.");
|
||||
HelpText(oPC, " For example '~~execute test_script' will run the script named 'test_script'.");
|
||||
HelpText(oPC, "");
|
||||
HelpText(oPC, "A hyphen in a command name indicates that the word may be abbreviated as short as the point where the hyphen is.");
|
||||
HelpText(oPC, " For example, 'exec-ute' may be entered as 'execute', 'execu', or 'exec', but not as 'exe'.");
|
||||
HelpText(oPC, "");
|
||||
HelpText(oPC, "Typing '~~help' displays a summary of the available commands (what you're reading now).");
|
||||
HelpText(oPC, "Typing '~~help <command-name>' displays more detailed information about the specified command.");
|
||||
HelpText(oPC, "");
|
||||
}
|
||||
|
||||
if (Debug_ProcessChatCommand_Help(oPC, sChat))
|
||||
{}
|
||||
else if (PowerAttack_ProcessChatCommand_Help(oPC, sChat))
|
||||
{}
|
||||
else if (PnPShifter_ProcessChatCommand_Help(oPC, sChat))
|
||||
{}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Debug_ProcessChatCommand(oPC, sChat))
|
||||
{}
|
||||
else if (PowerAttack_ProcessChatCommand(oPC, sChat))
|
||||
{}
|
||||
else if (PnPShifter_ProcessChatCommand(oPC, sChat))
|
||||
{}
|
||||
else
|
||||
SendMessageToPC(oPC, "Unrecognized chat command: " + sChat);
|
||||
}
|
||||
}
|
||||
else if(GetLocalInt(oPC, PRC_CHAT_HOOK_ACTIVE))
|
||||
{
|
||||
SetPCChatVolume(TALKVOLUME_TELL);
|
||||
SetLocalString(oPC, PRC_PLAYER_RESPONSE, sChat);
|
||||
ExecuteScript(GetLocalString(oPC, PRC_CHAT_HOOK_SCRIPT), oPC);
|
||||
_clear_chat_vars(oPC);
|
||||
}
|
||||
|
||||
// get current player message and split it up into a list
|
||||
string sCommand = GetPCChatMessage();
|
||||
json sCommandSplit = StringSplit(sChat);
|
||||
|
||||
if(JsonGetLength(sCommandSplit) > 0)
|
||||
{
|
||||
string firstWord = JsonGetString(JsonArrayGet(sCommandSplit, 0));
|
||||
|
||||
// if first word is /pa we are using the power attack interface
|
||||
if(firstWord == "/pa")
|
||||
{
|
||||
if(JsonGetLength(sCommandSplit) >= 2)
|
||||
{
|
||||
//if a parameter is given then run the power attack command directly.
|
||||
string param1 = JsonGetString(JsonArrayGet(sCommandSplit, 1));
|
||||
int paAmount = StringToInt(param1);
|
||||
SetLocalInt(oPC, "PRC_PowerAttack_Level", paAmount);
|
||||
ExecuteScript("prc_nui_pa_trggr", oPC);
|
||||
|
||||
// update the NUI so it is in sync
|
||||
int nToken = NuiFindWindow(oPC, NUI_PRC_POWER_ATTACK_WINDOW);
|
||||
if (nToken != 0)
|
||||
{
|
||||
NuiSetBind(oPC, nToken, NUI_PRC_PA_TEXT_BIND, JsonString(IntToString(paAmount)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no param is given then open the NUI
|
||||
ExecuteScript("prc_nui_pa_view", oPC);
|
||||
}
|
||||
|
||||
// clear message from chat
|
||||
SetPCChatMessage();
|
||||
return;
|
||||
}
|
||||
// If the first word is /sb then we open the Spellbook NUI
|
||||
if(firstWord == "/sb")
|
||||
{
|
||||
ExecuteScript("prc_nui_sb_view", oPC);
|
||||
|
||||
// clear message from chat
|
||||
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
|
||||
ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERCHAT);
|
||||
}
|
||||
@@ -129,7 +129,7 @@
|
||||
125 Soulcaster 16790611 16837012 16837013 16837014 16837015 IR_MYSTIC 4 CLS_ATK_3 CLS_FEAT_SOULC CLS_SAVTHR_WIZ CLS_SKILL_SOULC CLS_BFEAT_SOULC 2 **** **** 1 0 10 11 11 16 16 10 INT 0X00 0X0 0 CLASS_TYPE_SOULCASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SOULC 40 0 1 0 10 10 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
126 Sacred_Fist 16790612 16825367 16825368 16825369 16825370 IR_SACREDFIST 8 CLS_ATK_1 CLS_FEAT_SACFIS CLS_SAVTHR_WILD CLS_SKILL_SACFIS CLS_BFEAT_SACFIS 4 **** **** 1 0 14 14 12 16 10 10 WIS 0X00 0X0 0 CLASS_TYPE_SACREDFIST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SACFIS 40 0 0 1 10 5 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
127 Legendary_Dreadnought 16790613 16826086 16826087 16826088 16826089 IC_LEGDREAD 12 CLS_ATK_1 CLS_FEAT_LGDR CLS_SAVTHR_FIGHT CLS_SKILL_LGDR CLS_BFEAT_LGDR 2 **** **** 1 0 16 13 16 10 10 9 STR 0X00 0X0 0 CLASS_TYPE_LEGENDARY_DREADNOUGHT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_LGDR 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
128 Disciple_of_Baalzebul 16790614 16826094 16826095 16826096 16826097 IC_BAALZEBUL 6 CLS_ATK_2 CLS_FEAT_BAAL CLS_SAVTHR_BARD CLS_SKILL_BAAL CLS_BFEAT_BAAL 6 **** **** 1 0 12 14 14 10 12 15 CHA 0X09 0X2 0 CLASS_TYPE_DISC_BAALZEBUL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_BAAL 40 0 0 0 10 4 0 cls_stat_baal **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
129 Mighty_Contender_of_Kord 16790615 16824935 16824936 16824937 16824938 IC_LEGDREAD 10 CLS_ATK_2 CLS_FEAT_KORD CLS_SAVTHR_CLER CLS_SKILL_KORD CLS_BFEAT_KORD 2 **** **** 1 0 14 8 14 16 10 14 WIS 0X00 0X0 0 CLASS_TYPE_MIGHTY_CONTENDER_KORD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_KORD 40 0 0 1 10 4 0 cls_stat_kord **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
130 Iaijutsu_Master 16790616 16826114 16826115 16826116 16826117 IC_IAIJUTSU 10 CLS_ATK_1 CLS_FEAT_IAIJ CLS_SAVTHR_ROG CLS_SKILL_IAIJ CLS_BFEAT_IAIJ 4 **** **** 1 0 16 13 16 10 10 9 CHA 0X05 0X1 0 CLASS_TYPE_IAIJUTSU_MASTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_IAIJ 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
131 Disciple_of_Dispater 16790617 16826136 16826137 16826138 16826139 IR_BLKGRD 10 CLS_ATK_1 CLS_FEAT_DISP CLS_SAVTHR_MONK CLS_SKILL_DISP CLS_BFEAT_DISP 4 **** **** 1 0 16 13 16 10 10 9 CON 0X09 0X2 0 CLASS_TYPE_DISPATER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DISP 40 0 0 0 10 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
18 FEAT_EKNIGHT_SPELLCASTING_SUEL_ARCHANAMACH 18960 2 1 0
|
||||
19 FEAT_EKNIGHT_SPELLCASTING_WARMAGE 19002 2 1 0
|
||||
20 FEAT_EKNIGHT_SPELLCASTING_WIZARD 19047 2 1 0
|
||||
21 FEAT_EPIC_SWARM_OF_ARROWS 25995 1 -1 0
|
||||
21 Ambidex 1 1 -1 0
|
||||
22 CShot 5 1 -1 0
|
||||
23 Cleave 6 1 -1 0
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
74 Bane_Magic_Undead 23578 0 -1 0
|
||||
75 Bane_Magic_Vermin 23579 0 -1 0
|
||||
76 **Epic_Feats** **** **** **** ****
|
||||
77 FEAT_EPIC_ELDRITCH_THEURGE 23516 3 21 0
|
||||
77 FEAT_EPIC_ELDRITCH_THEURGE 23516 3 11 0
|
||||
78 FEAT_CRAFT_EPIC_WONDROUS_ITEM 3488 0 -1 0
|
||||
79 FEAT_CRAFT_EPIC_MAGIC_ARMS_AND_ARMOR 3489 0 -1 0
|
||||
80 FEAT_CRAFT_EPIC_ROD 3490 0 -1 0
|
||||
|
||||
@@ -20,54 +20,51 @@
|
||||
16 WeapProfSim_Dart 7914 3 1 0
|
||||
17 WeapProfSim_Light_Mace 7908 3 1 0
|
||||
18 WeapProfSim_Morningstar 7923 3 1 0
|
||||
19 WeapProfSim_Sickle 7929 3 1 0
|
||||
20 WeapProfSim_Sling 7930 3 1 0
|
||||
21 WP_Katar 7945 3 1 0
|
||||
22 WP_Sap 7944 3 1 0
|
||||
23 WP_LightCrossbow 7951 3 1 0
|
||||
24 WP_HeavyCrossbow 7952 3 1 0
|
||||
25 WP_Quarterstaff 7953 3 1 0
|
||||
26 WP_Dagger 7954 3 1 0
|
||||
27 WP_Club 7955 3 1 0
|
||||
28 WP_Shortsword 7901 3 1 0
|
||||
29 WP_Shortbow 7910 3 1 0
|
||||
30 WP_Rapier 7924 3 1 0
|
||||
31 ArmProfLgt 3 3 1 0
|
||||
32 FEAT_EPIC_BLINDING_SPEED 491 1 -1 1
|
||||
33 FEAT_EPIC_SKILL_FOCUS_APPRAISE 588 1 -1 0
|
||||
34 FEAT_EPIC_SKILL_FOCUS_CONCENTRATION 589 1 -1 0
|
||||
35 FEAT_EPIC_SKILL_FOCUS_CRAFT_TRAP 590 1 -1 0
|
||||
36 FEAT_EPIC_SKILL_FOCUS_DISABLETRAP 591 1 -1 0
|
||||
37 FEAT_EPIC_SKILL_FOCUS_DISCIPLINE 592 1 -1 0
|
||||
38 FEAT_EPIC_SKILL_FOCUS_HEAL 593 1 -1 0
|
||||
39 FEAT_EPIC_SKILL_FOCUS_HIDE 594 1 -1 0
|
||||
40 FEAT_EPIC_SKILL_FOCUS_LISTEN 595 1 -1 0
|
||||
41 FEAT_EPIC_SKILL_FOCUS_LORE 596 1 -1 0
|
||||
42 FEAT_EPIC_SKILL_FOCUS_MOVESILENTLY 597 1 -1 0
|
||||
43 FEAT_EPIC_SKILL_FOCUS_OPENLOCK 598 1 -1 0
|
||||
44 FEAT_EPIC_SKILL_FOCUS_PARRY 599 1 -1 0
|
||||
45 FEAT_EPIC_SKILL_FOCUS_PERSUADE 601 1 -1 0
|
||||
46 FEAT_EPIC_SKILL_FOCUS_PICKPOCKET 602 1 -1 0
|
||||
47 FEAT_EPIC_SKILL_FOCUS_SEARCH 603 1 -1 0
|
||||
48 FEAT_EPIC_SKILL_FOCUS_SETTRAP 604 1 -1 0
|
||||
49 FEAT_EPIC_SKILL_FOCUS_SPELLCRAFT 605 1 -1 0
|
||||
50 FEAT_EPIC_SKILL_FOCUS_SPOT 606 1 -1 0
|
||||
51 FEAT_EPIC_SKILL_FOCUS_TAUNT 607 1 -1 0
|
||||
52 FEAT_EPIC_SKILL_FOCUS_TUMBLE 608 1 -1 0
|
||||
53 FEAT_EPIC_SKILL_FOCUS_USEMAGICDEVICE 609 1 -1 0
|
||||
54 FEAT_EPIC_SELF_CONCEALMENT_10 748 1 -1 0
|
||||
55 FEAT_EPIC_SELF_CONCEALMENT_20 749 1 -1 0
|
||||
56 FEAT_EPIC_SELF_CONCEALMENT_30 750 1 -1 0
|
||||
57 FEAT_EPIC_SELF_CONCEALMENT_40 751 1 -1 0
|
||||
58 FEAT_EPIC_SELF_CONCEALMENT_50 752 1 -1 0
|
||||
59 FEAT_EPIC_SUPERIOR_INITIATIVE 753 1 -1 0
|
||||
60 FEAT_EPIC_DODGE 856 1 -1 0
|
||||
61 FEAT_IMPROVED_WHIRLWIND 868 1 -1 0
|
||||
62 FEAT_EPIC_SKILL_FOCUS_CRAFT_ARMOR 913 1 -1 0
|
||||
63 FEAT_EPIC_SKILL_FOCUS_CRAFT_WEAPON 914 1 -1 0
|
||||
64 FEAT_EPIC_SKILL_FOCUS_BLUFF 917 1 -1 0
|
||||
65 FEAT_EPIC_SKILL_FOCUS_INTIMIDATE 918 1 -1 0
|
||||
66 FEAT_EPIC_SHADOWDANCER 980 3 11 0
|
||||
67 FEAT_EPIC_EPIC_SHADOWLORD 1002 2 -1 0
|
||||
68 FEAT_EPIC_REFLEXES 585 1 -1 0
|
||||
69 FEAT_LINGERING_DAMAGE 3099 0 -1 0
|
||||
19 WP_Sap 7944 3 1 0
|
||||
20 WP_LightCrossbow 7951 3 1 0
|
||||
21 WP_HeavyCrossbow 7952 3 1 0
|
||||
22 WP_Quarterstaff 7953 3 1 0
|
||||
23 WP_Dagger 7954 3 1 0
|
||||
24 WP_Club 7955 3 1 0
|
||||
25 WP_Shortsword 7901 3 1 0
|
||||
26 WP_Shortbow 7910 3 1 0
|
||||
27 WP_Rapier 7924 3 1 0
|
||||
28 ArmProfLgt 3 3 1 0
|
||||
29 FEAT_EPIC_BLINDING_SPEED 491 1 -1 1
|
||||
30 FEAT_EPIC_SKILL_FOCUS_APPRAISE 588 1 -1 0
|
||||
31 FEAT_EPIC_SKILL_FOCUS_CONCENTRATION 589 1 -1 0
|
||||
32 FEAT_EPIC_SKILL_FOCUS_CRAFT_TRAP 590 1 -1 0
|
||||
33 FEAT_EPIC_SKILL_FOCUS_DISABLETRAP 591 1 -1 0
|
||||
34 FEAT_EPIC_SKILL_FOCUS_DISCIPLINE 592 1 -1 0
|
||||
35 FEAT_EPIC_SKILL_FOCUS_HEAL 593 1 -1 0
|
||||
36 FEAT_EPIC_SKILL_FOCUS_HIDE 594 1 -1 0
|
||||
37 FEAT_EPIC_SKILL_FOCUS_LISTEN 595 1 -1 0
|
||||
38 FEAT_EPIC_SKILL_FOCUS_LORE 596 1 -1 0
|
||||
39 FEAT_EPIC_SKILL_FOCUS_MOVESILENTLY 597 1 -1 0
|
||||
40 FEAT_EPIC_SKILL_FOCUS_OPENLOCK 598 1 -1 0
|
||||
41 FEAT_EPIC_SKILL_FOCUS_PARRY 599 1 -1 0
|
||||
42 FEAT_EPIC_SKILL_FOCUS_PERSUADE 601 1 -1 0
|
||||
43 FEAT_EPIC_SKILL_FOCUS_PICKPOCKET 602 1 -1 0
|
||||
44 FEAT_EPIC_SKILL_FOCUS_SEARCH 603 1 -1 0
|
||||
45 FEAT_EPIC_SKILL_FOCUS_SETTRAP 604 1 -1 0
|
||||
46 FEAT_EPIC_SKILL_FOCUS_SPELLCRAFT 605 1 -1 0
|
||||
47 FEAT_EPIC_SKILL_FOCUS_SPOT 606 1 -1 0
|
||||
48 FEAT_EPIC_SKILL_FOCUS_TAUNT 607 1 -1 0
|
||||
49 FEAT_EPIC_SKILL_FOCUS_TUMBLE 608 1 -1 0
|
||||
50 FEAT_EPIC_SKILL_FOCUS_USEMAGICDEVICE 609 1 -1 0
|
||||
51 FEAT_EPIC_SELF_CONCEALMENT_10 748 1 -1 0
|
||||
52 FEAT_EPIC_SELF_CONCEALMENT_20 749 1 -1 0
|
||||
53 FEAT_EPIC_SELF_CONCEALMENT_30 750 1 -1 0
|
||||
54 FEAT_EPIC_SELF_CONCEALMENT_40 751 1 -1 0
|
||||
55 FEAT_EPIC_SELF_CONCEALMENT_50 752 1 -1 0
|
||||
56 FEAT_EPIC_SUPERIOR_INITIATIVE 753 1 -1 0
|
||||
57 FEAT_EPIC_DODGE 856 1 -1 0
|
||||
58 FEAT_IMPROVED_WHIRLWIND 868 1 -1 0
|
||||
59 FEAT_EPIC_SKILL_FOCUS_CRAFT_ARMOR 913 1 -1 0
|
||||
60 FEAT_EPIC_SKILL_FOCUS_CRAFT_WEAPON 914 1 -1 0
|
||||
61 FEAT_EPIC_SKILL_FOCUS_BLUFF 917 1 -1 0
|
||||
62 FEAT_EPIC_SKILL_FOCUS_INTIMIDATE 918 1 -1 0
|
||||
63 FEAT_EPIC_SHADOWDANCER 980 3 11 0
|
||||
64 FEAT_EPIC_EPIC_SHADOWLORD 1002 2 -1 0
|
||||
65 FEAT_EPIC_REFLEXES 585 1 -1 0
|
||||
66 FEAT_LINGERING_DAMAGE 3099 0 -1 0
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
36 WP_Falchion 7943 3 1 0
|
||||
37 WP_Maul 7947 3 1 0
|
||||
38 WP_Kukri 7922 3 1 0
|
||||
39 WP_Scythe 7926 3 1 1
|
||||
39 WP_Scythe 7926 3 1 0
|
||||
40 ReadyManeuver 1960 3 1 1
|
||||
41 RecoverManeuvers 1973 3 1 1
|
||||
42 **** **** **** **** ****
|
||||
|
||||
43
nwn/nwnprc/trunk/2das/cls_stat_baal.2da
Normal file
43
nwn/nwnprc/trunk/2das/cls_stat_baal.2da
Normal file
@@ -0,0 +1,43 @@
|
||||
2DA V2.0
|
||||
|
||||
Level Str Dex Con Wis Int Cha NaturalAC
|
||||
0 1 **** **** **** **** **** **** ****
|
||||
1 2 **** **** **** **** **** **** ****
|
||||
2 3 **** **** **** **** **** **** ****
|
||||
3 4 **** **** **** **** **** **** ****
|
||||
4 5 **** **** **** **** **** **** ****
|
||||
5 6 **** **** **** **** **** **** ****
|
||||
6 7 **** **** **** **** **** **** ****
|
||||
7 8 **** **** **** **** **** **** ****
|
||||
8 9 **** **** **** **** **** **** ****
|
||||
9 10 **** **** **** **** **** 4 ****
|
||||
10 11 **** **** **** **** **** **** ****
|
||||
11 12 **** **** **** **** **** **** ****
|
||||
12 13 **** **** **** **** **** **** ****
|
||||
13 14 **** **** **** **** **** **** ****
|
||||
14 15 **** **** **** **** **** **** ****
|
||||
15 16 **** **** **** **** **** **** ****
|
||||
16 17 **** **** **** **** **** **** ****
|
||||
17 18 **** **** **** **** **** **** ****
|
||||
18 19 **** **** **** **** **** **** ****
|
||||
19 20 **** **** **** **** **** **** ****
|
||||
20 21 **** **** **** **** **** **** ****
|
||||
21 22 **** **** **** **** **** **** ****
|
||||
22 23 **** **** **** **** **** **** ****
|
||||
23 24 **** **** **** **** **** **** ****
|
||||
24 25 **** **** **** **** **** **** ****
|
||||
25 26 **** **** **** **** **** **** ****
|
||||
26 27 **** **** **** **** **** **** ****
|
||||
27 28 **** **** **** **** **** **** ****
|
||||
28 29 **** **** **** **** **** **** ****
|
||||
29 30 **** **** **** **** **** **** ****
|
||||
30 31 **** **** **** **** **** **** ****
|
||||
31 32 **** **** **** **** **** **** ****
|
||||
32 33 **** **** **** **** **** **** ****
|
||||
33 34 **** **** **** **** **** **** ****
|
||||
34 35 **** **** **** **** **** **** ****
|
||||
35 36 **** **** **** **** **** **** ****
|
||||
36 37 **** **** **** **** **** **** ****
|
||||
37 38 **** **** **** **** **** **** ****
|
||||
38 39 **** **** **** **** **** **** ****
|
||||
39 40 **** **** **** **** **** **** ****
|
||||
@@ -2349,7 +2349,7 @@
|
||||
2345 ShieldCharge **** **** **** **** **** ****
|
||||
2346 ShieldSlam **** **** **** **** **** ****
|
||||
2347 PhantomSteed **** **** **** **** **** ****
|
||||
2348 GaseousForm **** **** **** **** **** ****
|
||||
2348 GaseousForm prc_scr_1564 **** **** **** **** prc_scr_1564
|
||||
2349 begin_psionics **** **** **** **** **** ****
|
||||
2350 Augment_QuickSelects **** **** **** **** **** ****
|
||||
2351 Augment_Digits_0_4 **** **** **** **** **** ****
|
||||
|
||||
@@ -2349,7 +2349,7 @@
|
||||
2345 ShieldCharge **** 1 1 1 **** 0
|
||||
2346 ShieldSlam **** 1 1 1 **** 0
|
||||
2347 PhantomSteed **** 1 1 1 3 0
|
||||
2348 GaseousForm **** 1 1 1 3 0
|
||||
2348 GaseousForm 1564 0 0 0 3 0
|
||||
2349 begin_psionics **** 1 1 1 **** 0
|
||||
2350 Augment_QuickSelects **** 1 1 1 **** 0
|
||||
2351 Augment_Digits_0_4 **** 1 1 1 **** 0
|
||||
@@ -12696,9 +12696,9 @@
|
||||
12692 Favoured_Soul_Enthrall **** 1 1 1 2 0
|
||||
12693 Favoured_Soul_SPIRITUAL_WEAPON **** 1 1 1 2 0
|
||||
12694 Favoured_Soul_REGEN_LIGHT_WOUNDS **** 1 1 1 1 0
|
||||
12695 Favoured_Soul_REGEN_MODERATE_WOUNDS **** 1 1 1 2 0
|
||||
12696 Favoured_Soul_REGEN_SERIOUS_WOUNDS **** 1 1 1 4 0
|
||||
12697 Favoured_Soul_REGEN_CRITICAL_WOUNDS **** 1 1 1 5 0
|
||||
12695 Favoured_Soul_REGEN_MODERATE_WOUNDS **** 1 1 1 3 0
|
||||
12696 Favoured_Soul_REGEN_SERIOUS_WOUNDS **** 1 1 1 5 0
|
||||
12697 Favoured_Soul_REGEN_CRITICAL_WOUNDS **** 1 1 1 6 0
|
||||
12698 Favoured_Soul_Hallow **** 1 1 1 6 0
|
||||
12699 Favoured_Soul_SPELL_CHASING_PERFECTION **** 1 1 1 6 0
|
||||
12700 Sohei_Silent_Bless_Weapon **** 1 1 1 2 0
|
||||
|
||||
@@ -300,3 +300,4 @@
|
||||
296 SPELL_MASS_INFLICT_MODERATE_DAMAGE 16976462 17111 6
|
||||
297 SPELL_MASS_INFLICT_SERIOUS_DAMAGE 16976468 17112 7
|
||||
298 SPELL_MASS_INFLICT_CRITICAL_DAMAGE 16976474 17113 8
|
||||
299 SPELL_GASEOUS_FORM 16835585 2348 3
|
||||
|
||||
@@ -1537,17 +1537,17 @@
|
||||
1522 SPELL_INFLICT_MODERATE_DAMAGE_3 16976416 3 2 1250 17096 1 1 1 iss_X1InfMod
|
||||
1523 SPELL_INFLICT_MODERATE_DAMAGE_6 16976417 6 2 2250 17096 1 1 1 iss_X1InfMod
|
||||
1524 SPELL_INFLICT_MODERATE_DAMAGE_10 16976418 10 2 3750 17096 1 1 1 iss_X1InfMod
|
||||
1525 SPELL_INFLICT_SERIOUS_DAMAGE_5 16976422 5 3 2500 17097 1 1 1 iss_X1InfSer
|
||||
1526 SPELL_INFLICT_SERIOUS_DAMAGE_10 16976423 10 3 5000 17097 1 1 1 iss_X1InfSer
|
||||
1527 SPELL_INFLICT_SERIOUS_DAMAGE_15 16976424 15 3 7500 17097 1 1 1 iss_X1InfSer
|
||||
1528 SPELL_INFLICT_CRITICAL_DAMAGE_7 16976428 7 4 10500 17098 1 1 1 iss_X1InfCri
|
||||
1529 SPELL_INFLICT_CRITICAL_DAMAGE_15 16976429 15 4 22500 17098 1 1 1 iss_X1InfCri
|
||||
1530 SPELL_INFLICT_CRITICAL_DAMAGE_20 16976430 20 4 30000 17098 1 1 1 iss_X1InfCri
|
||||
1531 SPELL_MASS_REPAIR_LIGHT_DAMAGE_9 16976434 9 5 16875 17106 0 0 1 is_CurLgtW
|
||||
1532 SPELL_MASS_REPAIR_LIGHT_DAMAGE_15 16976435 15 5 28125 17106 0 0 1 is_CurLgtW
|
||||
1533 SPELL_MASS_REPAIR_LIGHT_DAMAGE_20 16976436 20 5 37500 17106 0 0 1 is_CurLgtW
|
||||
1534 SPELL_MASS_REPAIR_MODERATE_DAMAGE_11 16976440 11 6 20625 17107 0 0 1 is_CurModW
|
||||
1535 SPELL_MASS_REPAIR_MODERATE_DAMAGE_15 16976441 15 6 28125 17107 0 0 1 is_CurModW
|
||||
1525 SPELL_INFLICT_SERIOUS_DAMAGE_5 16976422 5 3 11250 17097 1 1 1 iss_X1InfSer
|
||||
1526 SPELL_INFLICT_SERIOUS_DAMAGE_10 16976423 10 3 22500 17097 1 1 1 iss_X1InfSer
|
||||
1527 SPELL_INFLICT_SERIOUS_DAMAGE_15 16976424 15 3 33750 17097 1 1 1 iss_X1InfSer
|
||||
1528 SPELL_INFLICT_CRITICAL_DAMAGE_7 16976428 7 4 21000 17098 1 1 1 iss_X1InfCri
|
||||
1529 SPELL_INFLICT_CRITICAL_DAMAGE_15 16976429 15 4 45000 17098 1 1 1 iss_X1InfCri
|
||||
1530 SPELL_INFLICT_CRITICAL_DAMAGE_20 16976430 20 4 60000 17098 1 1 1 iss_X1InfCri
|
||||
1531 SPELL_MASS_REPAIR_LIGHT_DAMAGE_9 16976434 9 5 33750 17106 0 0 1 is_CurLgtW
|
||||
1532 SPELL_MASS_REPAIR_LIGHT_DAMAGE_15 16976435 15 5 56250 17106 0 0 1 is_CurLgtW
|
||||
1533 SPELL_MASS_REPAIR_LIGHT_DAMAGE_20 16976436 20 5 75000 17106 0 0 1 is_CurLgtW
|
||||
1534 SPELL_MASS_REPAIR_MODERATE_DAMAGE_11 16976440 11 6 49500 17107 0 0 1 is_CurModW
|
||||
1535 SPELL_MASS_REPAIR_MODERATE_DAMAGE_15 16976441 15 6 67500 17107 0 0 1 is_CurModW
|
||||
1536 SPELL_MASS_REPAIR_MODERATE_DAMAGE_20 16976442 20 6 37500 17107 0 0 1 is_CurModW
|
||||
1537 SPELL_MASS_REPAIR_SERIOUS_DAMAGE_13 16976446 13 7 24375 17108 0 0 1 is_CurSerW
|
||||
1538 SPELL_MASS_REPAIR_SERIOUS_DAMAGE_16 16976447 16 7 30000 17108 0 0 1 is_CurSerW
|
||||
@@ -1565,3 +1565,6 @@
|
||||
1550 SPELL_MASS_INFLICT_SERIOUS_DAMAGE_20 16976472 20 7 37500 17113 0 0 1 iss_infserwm
|
||||
1551 SPELL_MASS_INFLICT_CRITICAL_DAMAGE_15 16976476 15 8 28125 17114 0 0 1 iss_infcrwnm
|
||||
1552 SPELL_MASS_INFLICT_CRITICAL_DAMAGE_20 16976477 20 8 37500 17114 0 0 1 iss_infcrwnm
|
||||
1553 SPELL_GASEOUS_FORM_5 16976479 5 3 11250 2348 1 1 1 is_BullStr
|
||||
1554 SPELL_GASEOUS_FORM_10 16976480 10 3 22500 2348 1 1 1 is_BullStr
|
||||
1555 SPELL_GASEOUS_FORM_15 16976481 15 3 33750 2348 1 1 1 is_BullStr
|
||||
|
||||
@@ -4067,7 +4067,7 @@
|
||||
4063 Epic_Spell_The_Withering **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4064 Epic_Spell_Tolodines_Killing_Wind **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4065 Epic_Spell_Transcendent_Vitality **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4066 Epic_Spell_Twinfiend **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4066 Epic_Spell_Twinfiend 0x01000 0x00100 **** **** **** **** **** **** **** **** **** **** ****
|
||||
4067 Epic_Spell_Unholy_Disciple **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4068 Epic_Spell_Unimpinged **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
4069 Epic_Spell_Unseen_Wanderer **** **** **** **** **** **** **** **** **** **** **** **** ****
|
||||
|
||||
@@ -22,14 +22,14 @@ void main()
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3: sSummon = "ep_summonaberat1"; break;
|
||||
case 3: sSummon = "ep_summonaberat1"; break; //:: Summoned Drider Chief
|
||||
case 4:
|
||||
case 5:
|
||||
case 6: sSummon = "ep_summonaberat2"; break;
|
||||
case 6: sSummon = "ep_summonaberat2"; break; //:: Summoned Beholder
|
||||
case 7:
|
||||
case 8: sSummon = "ep_summonaberat3"; break;
|
||||
case 9: sSummon = "ep_summonaberat4"; break;
|
||||
case 10: sSummon = "ep_summonaberat5"; break;
|
||||
case 8: sSummon = "ep_summonaberat3"; break; //:: Summoned Mind Flayer Darkener
|
||||
case 9: sSummon = "ep_summonaberat4"; break; //:: Summoned Umber Hulk
|
||||
case 10: sSummon = "ep_summonaberat5"; break; //:: Summoned Battle Devourer
|
||||
}
|
||||
|
||||
effect eSummon = ExtraordinaryEffect(EffectSummonCreature(sSummon, VFX_FNF_SUMMON_EPIC_UNDEAD, 1.0f));
|
||||
|
||||
@@ -1,60 +1,317 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//::////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//::////////////////////////////////////////////////////////
|
||||
//;:
|
||||
//:: Epic Spell: Twinfiend
|
||||
//:: Author: Boneshank (Don Armstrong)
|
||||
//:: Updated By: Jaysyn
|
||||
//:: Updated on: 2025-11-18 18:18:09
|
||||
//::
|
||||
//::////////////////////////////////////////////////////////
|
||||
/*
|
||||
School: Conjuration (Summoning, Evil)
|
||||
Components: V,S
|
||||
Range: Short
|
||||
Effect: Summons two advanced pit fiends
|
||||
Duration: 1 Turn / Caster level
|
||||
Saving Throw: None
|
||||
Spell Resistance: No
|
||||
|
||||
You summon two advanced pit fiends from the Nine Hells
|
||||
to do your bidding. These devils recieve one bonus hit
|
||||
die for every 2 caster levels of the summoner & maximum
|
||||
hit points per die. The pit fiends follow your orders to
|
||||
the best of their abilities, for the duration of the spell.
|
||||
*/
|
||||
//::////////////////////////////////////////////////////////
|
||||
//#include "x2_inc_toollib"
|
||||
#include "prc_alterations"
|
||||
#include "inc_epicspells"
|
||||
//#include "x2_inc_spellhook"
|
||||
#include "nw_i0_generic"
|
||||
#include "prc_inc_json"
|
||||
#include "inc_ecl"
|
||||
|
||||
void main()
|
||||
void SpawnTwinFiend(object oPC, json jDevil, location lTarget, float fDuration)
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION);
|
||||
MultisummonPreSummon();
|
||||
|
||||
if (!X2PreSpellCastCode())
|
||||
object oFiend = JsonToObject(jDevil, lTarget);
|
||||
|
||||
int nCasterLvl = GetTotalCastingLevel(oPC);
|
||||
|
||||
if (!GetIsObjectValid(oFiend))
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend | SpawnTwinFiend() >> oFiend not passed to function.");
|
||||
return;
|
||||
}
|
||||
if (GetCanCastSpell(OBJECT_SELF, SPELL_EPIC_TWINF))
|
||||
{
|
||||
//Declare major variables
|
||||
float fDuration = RoundsToSeconds(20);
|
||||
object oFiend, oFiend2;
|
||||
|
||||
string sSummon = "twinfiend_demon";
|
||||
|
||||
// effect eSummon;
|
||||
effect eVis = EffectVisualEffect(460);
|
||||
effect eVis2 = EffectVisualEffect(VFX_IMP_UNSUMMON);
|
||||
|
||||
effect eSummon = EffectSummonCreature("", 460, 0.0, 0, VFX_IMP_UNSUMMON, oFiend);
|
||||
|
||||
//:: Set faction to caster<65>s
|
||||
ChangeFaction(oFiend, oPC);
|
||||
SetLocalObject(oFiend, "SUMMONER", oPC);
|
||||
|
||||
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, lTarget, fDuration);
|
||||
|
||||
if (!GetIsObjectValid(oFiend))
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend | SpawnTwinFiend() >> JsonToObject failed - could not create creature from edited template.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update creature weapons for Size increase
|
||||
if (nCasterLvl > 14)
|
||||
{
|
||||
if(DEBUG) DoDebug("ss_ep_twinfiend | SpawnTwinFiend() >> Updating Creature weapons for size increase.");
|
||||
|
||||
object oWeapCR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oFiend);
|
||||
MyDestroyObject(oWeapCR);
|
||||
object oWeapCL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oFiend);
|
||||
MyDestroyObject(oWeapCL);
|
||||
object oWeapCB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oFiend);
|
||||
MyDestroyObject(oWeapCB);
|
||||
|
||||
oWeapCR = CreateItemOnObject("nw_it_crewpsp010", oFiend);
|
||||
ForceEquip(oFiend, oWeapCR, INVENTORY_SLOT_CWEAPON_R);
|
||||
|
||||
oWeapCL = CreateItemOnObject("bite_pitfiend002", oFiend);
|
||||
ForceEquip(oFiend, oWeapCL, INVENTORY_SLOT_CWEAPON_L);
|
||||
|
||||
oWeapCB = CreateItemOnObject("prc_2d6_slamgrab", oFiend);
|
||||
ForceEquip(oFiend, oWeapCB, INVENTORY_SLOT_CWEAPON_B);
|
||||
|
||||
SetObjectVisualTransform(oFiend, OBJECT_VISUAL_TRANSFORM_SCALE, 1.1);
|
||||
}
|
||||
|
||||
AugmentSummonedCreature(sSummon);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
SetLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION);
|
||||
|
||||
if (!X2PreSpellCastCode())
|
||||
{
|
||||
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
return;
|
||||
}
|
||||
|
||||
// Target location
|
||||
location lTarget = PRCGetSpellTargetLocation();
|
||||
|
||||
int nCasterLvl = GetTotalCastingLevel(oPC);
|
||||
|
||||
//:: Load template
|
||||
json jDevil = TemplateToJson("twinfiend_demon", RESTYPE_UTC);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> TemplateToJson failed <20> bad resref or resource missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Get Original HD
|
||||
int nOriginalHD = json_GetCreatureHD(jDevil);
|
||||
if (nOriginalHD <= 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_GetCreatureHD failed <20> template missing HD data.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Stat boost calc
|
||||
int nStatBoost = GetStatBoostsFromHD(nOriginalHD, nCasterLvl/2);
|
||||
|
||||
//:: Add one hit dice per two caster levels
|
||||
jDevil = json_AddHitDice(jDevil, nCasterLvl/2);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_AddHitDice failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Recalculate & maximize HP
|
||||
int nCurrentHD = json_GetCreatureHD(jDevil);
|
||||
if (nCurrentHD <= 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_GetCreatureHD failed <20> template missing HD data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("ss_ep_twinfiend >> nCurrentHD is: "+IntToString(nCurrentHD)+ " entering json_RecalcMaxHP.");
|
||||
jDevil = json_RecalcMaxHP(jDevil, 8);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_RecalcMaxHP failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update feats
|
||||
jDevil = json_AddFeatsFromCreatureVars(jDevil, nOriginalHD);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_AddFeatsFromCreatureVars failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update stats
|
||||
jDevil = json_ApplyAbilityBoostFromHD(jDevil, nOriginalHD);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_ApplyAbilityBoostFromHD failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Size increase
|
||||
if (nCasterLvl > 14)
|
||||
{
|
||||
jDevil = json_AdjustCreatureSize(jDevil, 1);
|
||||
if (jDevil == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "ss_ep_twinfiend >> json_AdjustCreatureSize failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetCanCastSpell(oPC, SPELL_EPIC_TWINF))
|
||||
{
|
||||
//:: Declare major variables
|
||||
float fDuration = TurnsToSeconds(nCasterLvl);
|
||||
object oFiend;
|
||||
object oFiend2;
|
||||
|
||||
// effect eSummon;
|
||||
effect eVis = EffectVisualEffect(460);
|
||||
effect eVis2 = EffectVisualEffect(VFX_IMP_UNSUMMON);
|
||||
|
||||
string sSummon = "twinfiend_demon";
|
||||
|
||||
// Despawn existing Twinfiends
|
||||
object oArea = GetArea(oPC);
|
||||
object oObj = GetFirstObjectInArea(oArea);
|
||||
|
||||
while (GetIsObjectValid(oObj))
|
||||
{
|
||||
if (GetTag(oObj) == "TWINFIEND_DEMON")
|
||||
{
|
||||
if (GetLocalObject(oObj, "SUMMONER") == oPC)
|
||||
{
|
||||
DestroyObject(oObj);
|
||||
}
|
||||
}
|
||||
|
||||
oObj = GetNextObjectInArea(oArea);
|
||||
}
|
||||
|
||||
if(GetPRCSwitch(PRC_MULTISUMMON))
|
||||
{
|
||||
string sSummon = "twinfiend_demon";
|
||||
effect eSummon = EffectSummonCreature(sSummon, 460);
|
||||
MultisummonPreSummon();
|
||||
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon,
|
||||
PRCGetSpellTargetLocation(), fDuration);
|
||||
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon,
|
||||
PRCGetSpellTargetLocation(), fDuration);
|
||||
DelayCommand(0.5, AugmentSummonedCreature(sSummon));
|
||||
SpawnTwinFiend(oPC, jDevil, lTarget, fDuration);
|
||||
SpawnTwinFiend(oPC, jDevil, lTarget, fDuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, PRCGetSpellTargetLocation()));
|
||||
oFiend = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation());
|
||||
oFiend2 = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation());
|
||||
DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget));
|
||||
//oFiend = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation());
|
||||
oFiend = JsonToObject(jDevil, lTarget);
|
||||
DelayCommand(0.0, AugmentSummonedCreature(sSummon));
|
||||
SetCurrentHitPoints(oFiend, GetMaxPossibleHP(oFiend));
|
||||
|
||||
//:: Set faction to caster<65>s
|
||||
ChangeFaction(oFiend, oPC);
|
||||
SetLocalObject(oFiend, "SUMMONER", oPC);
|
||||
|
||||
SetLocalNPC(oPC, oFiend, ASSOCIATE_TYPE_SUMMONED);
|
||||
SetAssociateState(NW_ASC_HAVE_MASTER, TRUE, oFiend);
|
||||
SetAssociateState(NW_ASC_DISTANCE_2_METERS);
|
||||
SetAssociateState(NW_ASC_DISTANCE_4_METERS, FALSE);
|
||||
SetAssociateState(NW_ASC_DISTANCE_6_METERS, FALSE);
|
||||
|
||||
//oFiend2 = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation());
|
||||
oFiend2 = JsonToObject(jDevil, lTarget);
|
||||
DelayCommand(0.0, AugmentSummonedCreature(sSummon));
|
||||
SetCurrentHitPoints(oFiend2, GetMaxPossibleHP(oFiend2));
|
||||
|
||||
//:: Set faction to caster<65>s
|
||||
ChangeFaction(oFiend2, oPC);
|
||||
SetLocalObject(oFiend2, "SUMMONER", oPC);
|
||||
|
||||
SetLocalNPC(oPC, oFiend2, ASSOCIATE_TYPE_SUMMONED);
|
||||
SetAssociateState(NW_ASC_HAVE_MASTER, TRUE, oFiend2);
|
||||
SetAssociateState(NW_ASC_DISTANCE_2_METERS);
|
||||
SetAssociateState(NW_ASC_DISTANCE_4_METERS, FALSE);
|
||||
SetAssociateState(NW_ASC_DISTANCE_6_METERS, FALSE);
|
||||
|
||||
SetMaxHenchmen(GetMaxHenchmen() + 2);
|
||||
AddHenchman(OBJECT_SELF, oFiend);
|
||||
AddHenchman(OBJECT_SELF, oFiend2);
|
||||
AddHenchman(oPC, oFiend);
|
||||
AddHenchman(oPC, oFiend2);
|
||||
SetMaxHenchmen(GetMaxHenchmen() - 2);
|
||||
|
||||
//:: Update creature weapons for Size increase
|
||||
if (nCasterLvl > 14)
|
||||
{
|
||||
if(DEBUG) DoDebug("ss_ep_twinfiend >> Updating Creature weapons for size increase.");
|
||||
|
||||
object oWeapCR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oFiend);
|
||||
MyDestroyObject(oWeapCR);
|
||||
object oWeapCL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oFiend);
|
||||
MyDestroyObject(oWeapCL);
|
||||
object oWeapCB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oFiend);
|
||||
MyDestroyObject(oWeapCB);
|
||||
|
||||
oWeapCR = CreateItemOnObject("nw_it_crewpsp010", oFiend);
|
||||
ForceEquip(oFiend, oWeapCR, INVENTORY_SLOT_CWEAPON_R);
|
||||
|
||||
oWeapCL = CreateItemOnObject("bite_pitfiend002", oFiend);
|
||||
ForceEquip(oFiend, oWeapCL, INVENTORY_SLOT_CWEAPON_L);
|
||||
|
||||
oWeapCB = CreateItemOnObject("prc_2d6_slamgrab", oFiend);
|
||||
ForceEquip(oFiend, oWeapCB, INVENTORY_SLOT_CWEAPON_B);
|
||||
|
||||
oWeapCR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oFiend2);
|
||||
MyDestroyObject(oWeapCR);
|
||||
oWeapCL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oFiend2);
|
||||
MyDestroyObject(oWeapCL);
|
||||
oWeapCB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oFiend2);
|
||||
MyDestroyObject(oWeapCB);
|
||||
|
||||
oWeapCR = CreateItemOnObject("nw_it_crewpsp010", oFiend2);
|
||||
ForceEquip(oFiend2, oWeapCR, INVENTORY_SLOT_CWEAPON_R);
|
||||
|
||||
oWeapCL = CreateItemOnObject("bite_pitfiend002", oFiend2);
|
||||
ForceEquip(oFiend2, oWeapCL, INVENTORY_SLOT_CWEAPON_L);
|
||||
|
||||
oWeapCB = CreateItemOnObject("prc_2d6_slamgrab", oFiend2);
|
||||
ForceEquip(oFiend2, oWeapCB, INVENTORY_SLOT_CWEAPON_B);
|
||||
|
||||
SetObjectVisualTransform(oFiend, OBJECT_VISUAL_TRANSFORM_SCALE, 1.1);
|
||||
SetObjectVisualTransform(oFiend2, OBJECT_VISUAL_TRANSFORM_SCALE, 1.1);
|
||||
|
||||
}
|
||||
else DoDebug("ss_ep_twinfiend >> No size change detected.");
|
||||
|
||||
AssignCommand(oFiend, DetermineCombatRound());
|
||||
AssignCommand(oFiend2, DetermineCombatRound());
|
||||
|
||||
DestroyObject(oFiend, fDuration);
|
||||
DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend)));
|
||||
DestroyObject(oFiend2, fDuration);
|
||||
DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend2)));
|
||||
}
|
||||
}
|
||||
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
|
||||
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
int nConBonusHP = iMod * iHD;
|
||||
int iNewMaxHP = (iHitDieValue * iHD); /* nConBonusHP */
|
||||
//:: Retrieve the RacialType field
|
||||
json jRacialTypeField = JsonObjectGet(jCreature, "Race");
|
||||
int nRacialType = JsonGetInt(jRacialTypeField);
|
||||
|
||||
//jCreature = GffReplaceShort(jCreature, "MaxHitPoints", iNewMaxHP);
|
||||
//:: 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);
|
||||
|
||||
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, "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,7 +363,10 @@ int PRCIsFlying(object oCreature)
|
||||
bFlying = TRUE;
|
||||
}
|
||||
if(!bFlying
|
||||
&& ((nWings > 0 && nWings < 79) || nWings == 90))//CEP and Project Q wing models
|
||||
&& ((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))
|
||||
|
||||
@@ -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!!! */
|
||||
|
||||
|
||||
@@ -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,6 +1509,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1567,22 +1522,9 @@ void FinishLevelUp(int nClass, object oPC=OBJECT_SELF)
|
||||
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);
|
||||
if (nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel);
|
||||
}
|
||||
ClearLevelUpNUICaches(nClass, oPC);
|
||||
} */
|
||||
|
||||
void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF)
|
||||
{
|
||||
// clear the chosen spells you made
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void CheckIfDeleveled(object oPC);
|
||||
void UpdateLastKnownLevels(object oPC);
|
||||
void CheckSpellbooks(object oPC);
|
||||
void CheckPsionics(object oPC);
|
||||
void CheckInvocations(object oPC);
|
||||
@@ -71,9 +73,72 @@ void main()
|
||||
eTest = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
CheckIfDeleveled(oPC);
|
||||
|
||||
DelayCommand(0.0f, CheckSpellbooks(oPC));
|
||||
}
|
||||
|
||||
void CheckIfDeleveled(object oPC)
|
||||
{
|
||||
int lastKnownLevel = GetPersistantLocalInt(oPC, "PCLastKnownLevel");
|
||||
int currentLevel = GetHitDice(oPC);
|
||||
if (lastKnownLevel > 0 && currentLevel < lastKnownLevel)
|
||||
{
|
||||
if (DEBUG) DoDebug("The player has de-leveled, checking spells!");
|
||||
json changedClassList = JsonArray();
|
||||
int i;
|
||||
for (i = 1; i <= 8; i++)
|
||||
{
|
||||
int storedClass = GetPersistantLocalInt(oPC, "PCLastKnownClass" + IntToString(i));
|
||||
if (storedClass && storedClass != CLASS_TYPE_INVALID)
|
||||
{
|
||||
int storedLevel = GetPersistantLocalInt(oPC, "PCLastKnownClass" + IntToString(i) + "Levels");
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
int currentClassLevels = (GetIsArcaneClass(nClass, oPC) || GetIsDivineClass(nClass, oPC))
|
||||
? GetPrCAdjustedClassLevel(nClass, oPC) : GetLevelByClass(nClass, oPC);
|
||||
if (nClass == CLASS_TYPE_INVALID
|
||||
|| (nClass == storedClass && storedLevel != currentClassLevels))
|
||||
{
|
||||
DoDebug("Class " + IntToString(storedClass) + " lost levels!");
|
||||
changedClassList = JsonArrayInsert(changedClassList, JsonInt(storedClass));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (i = lastKnownLevel; i > currentLevel; i--)
|
||||
{
|
||||
int totalChangedClasses = JsonGetLength(changedClassList);
|
||||
|
||||
int j;
|
||||
for (j = 0; j < totalChangedClasses; j++)
|
||||
{
|
||||
int nClass = JsonGetInt(JsonArrayGet(changedClassList, j));
|
||||
DelayCommand(0.0f, CallSpellUnlevelScript(oPC, nClass, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
DoDebug("Setting last known player level to " + IntToString(currentLevel));
|
||||
UpdateLastKnownLevels(oPC);
|
||||
}
|
||||
|
||||
void UpdateLastKnownLevels(object oPC)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i <= 8; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
int classLevel = (GetIsArcaneClass(nClass, oPC) || GetIsDivineClass(nClass, oPC))
|
||||
? GetPrCAdjustedClassLevel(nClass, oPC) : GetLevelByClass(nClass, oPC);
|
||||
|
||||
SetPersistantLocalInt(oPC, "PCLastKnownClass" + IntToString(i), nClass);
|
||||
SetPersistantLocalInt(oPC, "PCLastKnownClass" + IntToString(i) + "Levels", classLevel);
|
||||
}
|
||||
|
||||
int currentLevel = GetHitDice(oPC);
|
||||
SetPersistantLocalInt(oPC, "PCLastKnownLevel", currentLevel);
|
||||
}
|
||||
|
||||
// Handle new spellbooks
|
||||
|
||||
void CheckSpellbooks(object oPC)
|
||||
|
||||
BIN
nwn/nwnprc/trunk/others/bite_pitfiend001.uti
Normal file
BIN
nwn/nwnprc/trunk/others/bite_pitfiend001.uti
Normal file
Binary file not shown.
BIN
nwn/nwnprc/trunk/others/bite_pitfiend002.uti
Normal file
BIN
nwn/nwnprc/trunk/others/bite_pitfiend002.uti
Normal file
Binary file not shown.
BIN
nwn/nwnprc/trunk/others/hide_pitfiend001.uti
Normal file
BIN
nwn/nwnprc/trunk/others/hide_pitfiend001.uti
Normal file
Binary file not shown.
BIN
nwn/nwnprc/trunk/others/prc_2d4_slamgrab.uti
Normal file
BIN
nwn/nwnprc/trunk/others/prc_2d4_slamgrab.uti
Normal file
Binary file not shown.
BIN
nwn/nwnprc/trunk/others/prc_2d6_slamgrab.uti
Normal file
BIN
nwn/nwnprc/trunk/others/prc_2d6_slamgrab.uti
Normal file
Binary file not shown.
BIN
nwn/nwnprc/trunk/others/prc_scr_1564.uti
Normal file
BIN
nwn/nwnprc/trunk/others/prc_scr_1564.uti
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -55,13 +55,25 @@ int DoPower(object oManifester, object oTarget, struct manifestation manif)
|
||||
// It's a creature, target their primary weapon
|
||||
oTarget = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
|
||||
}
|
||||
// Make sure the target is either weapon or ammo
|
||||
|
||||
// Validate that the target is a weapon or ammunition
|
||||
int bIsWeapon = GetWeaponRanged(oTarget) || IPGetIsMeleeWeapon(oTarget);
|
||||
|
||||
int nBase = GetBaseItemType(oTarget);
|
||||
int bIsAmmo = nBase == BASE_ITEM_ARROW || nBase == BASE_ITEM_BOLT || nBase == BASE_ITEM_BULLET;
|
||||
|
||||
if (!(bIsWeapon || bIsAmmo))
|
||||
{
|
||||
oTarget = OBJECT_INVALID;
|
||||
}
|
||||
|
||||
/* // Make sure the target is either weapon or ammo
|
||||
if(!(GetWeaponRanged(oTarget) || IPGetIsMeleeWeapon(oTarget) ||
|
||||
GetBaseItemType(oTarget) == BASE_ITEM_ARROW ||
|
||||
GetBaseItemType(oTarget) == BASE_ITEM_BOLT ||
|
||||
GetBaseItemType(oTarget) == BASE_ITEM_BULLET
|
||||
) )
|
||||
oTarget = OBJECT_INVALID;
|
||||
oTarget = OBJECT_INVALID; */
|
||||
|
||||
// Make sure we have a valid target
|
||||
if(!GetIsObjectValid(oTarget))
|
||||
|
||||
@@ -966,6 +966,17 @@ void main()
|
||||
sResRef += GetAffixForSize(nSize);
|
||||
AddNaturalPrimaryWeapon(oPC, sResRef, 2);
|
||||
}
|
||||
else if(nRace==RACIAL_TYPE_ZAKYA_RAKSHASA)
|
||||
{
|
||||
string sResRef = "prc_raks_bite_";
|
||||
int nSize = PRCGetCreatureSize(oPC);
|
||||
sResRef += GetAffixForSize(nSize);
|
||||
AddNaturalSecondaryWeapon(oPC, sResRef);
|
||||
//primary weapon
|
||||
sResRef = "prc_claw_1d6l_";
|
||||
sResRef += GetAffixForSize(nSize);
|
||||
AddNaturalPrimaryWeapon(oPC, sResRef, 1);
|
||||
}
|
||||
else if(nRace==RACIAL_TYPE_LIZARDFOLK)
|
||||
{
|
||||
string sResRef = "prc_lizf_bite_";
|
||||
|
||||
@@ -158,10 +158,6 @@ void main()
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oShadow);
|
||||
|
||||
// Full round wait then move
|
||||
AssignCommand(oShadow, ClearAllActions());
|
||||
AssignCommand(oShadow, ActionWait(6.0));
|
||||
AssignCommand(oShadow, ActionMoveToObject(oPC));
|
||||
|
||||
// Start watch loop
|
||||
DelayCommand(6.1, ShadowServantWatch(oShadow, oPC));
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_ecl"
|
||||
#include "prc_inc_assoc"
|
||||
#include "prc_inc_combmove"
|
||||
|
||||
void PreyOnTheWeak(object oDead)
|
||||
{
|
||||
@@ -49,6 +50,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)));
|
||||
|
||||
474
nwn/nwnprc/trunk/scripts/prc_unlvl_script.nss
Normal file
474
nwn/nwnprc/trunk/scripts/prc_unlvl_script.nss
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,9 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF);
|
||||
int nDuration = nCasterLevel;
|
||||
|
||||
int bIsPC = GetIsPC(OBJECT_SELF);
|
||||
|
||||
nDuration = 24;
|
||||
string sResRef;
|
||||
//effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||||
@@ -61,7 +64,7 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
|
||||
effect eSummon = EffectSummonCreature(sResRef,VFX_FNF_SUMMON_UNDEAD);
|
||||
//Apply summon effect and VFX impact.
|
||||
MultisummonPreSummon();
|
||||
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED))
|
||||
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED) && bIsPC)
|
||||
{
|
||||
object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation());
|
||||
//make it hostile
|
||||
|
||||
@@ -40,6 +40,7 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
|
||||
//Declare major variables
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF);
|
||||
int bIsPC = GetIsPC(OBJECT_SELF);
|
||||
int nDuration = nCasterLevel;
|
||||
nDuration = 24;
|
||||
string sResRef;
|
||||
@@ -62,7 +63,7 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
|
||||
|
||||
//Apply VFX impact and summon effect
|
||||
MultisummonPreSummon();
|
||||
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED))
|
||||
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED) && bIsPC)
|
||||
{
|
||||
object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation());
|
||||
//this is to
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include "prc_alterations"
|
||||
#include "inc_Timestop"
|
||||
#include "inc_timestop"
|
||||
void main()
|
||||
{
|
||||
object oTarget = GetExitingObject();
|
||||
|
||||
@@ -91,14 +91,15 @@ void main()
|
||||
{
|
||||
nArmor = nLevel + 5;
|
||||
DoCorruptionCost(oPC, ABILITY_STRENGTH, d2(1), 0);
|
||||
SignalEvent(oTarget, EventSpellCastAt(oPC, nSpell));
|
||||
}
|
||||
|
||||
else if(nSpell == SPELL_GREATER_LUMINOUS_ARMOR)
|
||||
{
|
||||
nArmor = nLevel + 8;
|
||||
DoCorruptionCost(oPC, ABILITY_STRENGTH, d3(), 0);
|
||||
SignalEvent(oTarget, EventSpellCastAt(oPC, nSpell));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -27,7 +27,7 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
|
||||
int nDuration = nCasterLevel; // * Duration 1 turn/level
|
||||
if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) //Duration is +100%
|
||||
nDuration *= 2;
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, 421, FALSE));
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SHIELD_OF_FAITH, FALSE));
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_AC_BONUS), oTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration),TRUE,-1,nCasterLevel);
|
||||
|
||||
|
||||
Binary file not shown.
@@ -27156,7 +27156,14 @@ A marshal can haste himself and his allies for 1 round. This ability may be use
|
||||
|
||||
Hit Die: d10
|
||||
Skill Points at Each Additional Level: 4+ Int Modifier
|
||||
Bonus Feats: The epic swashbuckler gains a bonus feat every three levels, starting at level 23 </entry>
|
||||
Bonus Feats: The epic swashbuckler gains a bonus feat every three levels.
|
||||
|
||||
Special:
|
||||
Swashbuckler Dodge: This bonus continues to increase by +1 at every five levels after 20th.
|
||||
Grace: An epic swashbuckler gains another +1 bonus on Reflex saves at 29th and 39th level. A swashbuckler loses this bonus when wearing medium or heavy armor or when encumbered.
|
||||
|
||||
Epic Swashbuckler Bonus Feat List:
|
||||
Armor Skin, Blinding Speed, Devastating Critical, Epic Damage Reduction, Epic Prowess, Epic Toughness, Epic Weapon Focus, Improved Stunning Fist, Improved Whirlwind Attack, Overwhelming Critical, Superior Initiative</entry>
|
||||
<entry id="51045" lang="en" sex="m">Epic Marshal</entry>
|
||||
<entry id="51046" lang="en" sex="m">An epic marshal commands legions of soldiers and sometimes rules his own nation.
|
||||
His followers are loyal to the death, and his empire is the stuff of legend.
|
||||
@@ -46024,15 +46031,15 @@ Spell Resistance: No (harmless)
|
||||
Physical frailty is but a memory for the subject of this spell. The targeted creature is granted permanent immunity to poison and disease, regeneration +1, and a Constitution bonus of +5.</entry>
|
||||
<entry id="56299" lang="en" sex="m">Epic Spell: Twinfiend</entry>
|
||||
<entry id="56300" lang="en" sex="m">Researched Epic Spell: Twinfiend</entry>
|
||||
<entry id="56301" lang="en" sex="m">School: Conjuration (Summoning)
|
||||
Components: V,S
|
||||
Range: Short
|
||||
Effect: Two summoned pit fiends
|
||||
Duration: 20 rounds
|
||||
Saving Throw: None
|
||||
Spell Resistance: No
|
||||
<entry id="56301" lang="en" sex="m"> School: Conjuration (Summoning, Evil)
|
||||
Components: V,S
|
||||
Range: Short
|
||||
Effect: Summons two advanced pit fiends
|
||||
Duration: 1 Turn / Caster level
|
||||
Saving Throw: None
|
||||
Spell Resistance: No
|
||||
|
||||
You summon two pit fiends from the abyss to do your bidding. These devils follow your orders to the best of their abilities, for the duration.</entry>
|
||||
You summon two advanced pit fiends from the Nine Hells to do your bidding. These devils recieve one bonus hit die for every 2 caster levels of the summoner and maximum hit points per die. The pit fiends follow your orders to the best of their abilities, for the duration of the spell.</entry>
|
||||
<entry id="56302" lang="en" sex="m">Epic Spell: Unholy Disciple</entry>
|
||||
<entry id="56303" lang="en" sex="m">Researched Epic Spell: Unholy Disciple</entry>
|
||||
<entry id="56304" lang="en" sex="m">School: Necromancy
|
||||
@@ -73578,9 +73585,9 @@ Transmuting energy spreads out around the targets, dealing 4d8 points of damage
|
||||
<entry id="199260" lang="en" sex="m">Mass Inflict Critical Damage (15)</entry>
|
||||
<entry id="199261" lang="en" sex="m">Mass Inflict Critical Damage (20)</entry>
|
||||
<entry id="199262" lang="en" sex="m">****</entry>
|
||||
<entry id="199263" lang="en" sex="m">****</entry>
|
||||
<entry id="199264" lang="en" sex="m">****</entry>
|
||||
<entry id="199265" lang="en" sex="m">****</entry>
|
||||
<entry id="199263" lang="en" sex="m">Gaseous Form (5)</entry>
|
||||
<entry id="199264" lang="en" sex="m">Gaseous Form (10)</entry>
|
||||
<entry id="199265" lang="en" sex="m">Gaseous Form (15)</entry>
|
||||
<entry id="199266" lang="en" sex="m">****</entry>
|
||||
<entry id="199267" lang="en" sex="m">****</entry>
|
||||
<entry id="199268" lang="en" sex="m">****</entry>
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user