1 Commits
4.69 ... 4.70

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

View 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

Binary file not shown.

View 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));
}
}
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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);
}

View File

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

View File

@@ -22,6 +22,7 @@
18 FEAT_EKNIGHT_SPELLCASTING_SUEL_ARCHANAMACH 18960 2 1 0 18 FEAT_EKNIGHT_SPELLCASTING_SUEL_ARCHANAMACH 18960 2 1 0
19 FEAT_EKNIGHT_SPELLCASTING_WARMAGE 19002 2 1 0 19 FEAT_EKNIGHT_SPELLCASTING_WARMAGE 19002 2 1 0
20 FEAT_EKNIGHT_SPELLCASTING_WIZARD 19047 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 21 Ambidex 1 1 -1 0
22 CShot 5 1 -1 0 22 CShot 5 1 -1 0
23 Cleave 6 1 -1 0 23 Cleave 6 1 -1 0

View File

@@ -78,7 +78,7 @@
74 Bane_Magic_Undead 23578 0 -1 0 74 Bane_Magic_Undead 23578 0 -1 0
75 Bane_Magic_Vermin 23579 0 -1 0 75 Bane_Magic_Vermin 23579 0 -1 0
76 **Epic_Feats** **** **** **** **** 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 78 FEAT_CRAFT_EPIC_WONDROUS_ITEM 3488 0 -1 0
79 FEAT_CRAFT_EPIC_MAGIC_ARMS_AND_ARMOR 3489 0 -1 0 79 FEAT_CRAFT_EPIC_MAGIC_ARMS_AND_ARMOR 3489 0 -1 0
80 FEAT_CRAFT_EPIC_ROD 3490 0 -1 0 80 FEAT_CRAFT_EPIC_ROD 3490 0 -1 0

View File

@@ -20,54 +20,51 @@
16 WeapProfSim_Dart 7914 3 1 0 16 WeapProfSim_Dart 7914 3 1 0
17 WeapProfSim_Light_Mace 7908 3 1 0 17 WeapProfSim_Light_Mace 7908 3 1 0
18 WeapProfSim_Morningstar 7923 3 1 0 18 WeapProfSim_Morningstar 7923 3 1 0
19 WeapProfSim_Sickle 7929 3 1 0 19 WP_Sap 7944 3 1 0
20 WeapProfSim_Sling 7930 3 1 0 20 WP_LightCrossbow 7951 3 1 0
21 WP_Katar 7945 3 1 0 21 WP_HeavyCrossbow 7952 3 1 0
22 WP_Sap 7944 3 1 0 22 WP_Quarterstaff 7953 3 1 0
23 WP_LightCrossbow 7951 3 1 0 23 WP_Dagger 7954 3 1 0
24 WP_HeavyCrossbow 7952 3 1 0 24 WP_Club 7955 3 1 0
25 WP_Quarterstaff 7953 3 1 0 25 WP_Shortsword 7901 3 1 0
26 WP_Dagger 7954 3 1 0 26 WP_Shortbow 7910 3 1 0
27 WP_Club 7955 3 1 0 27 WP_Rapier 7924 3 1 0
28 WP_Shortsword 7901 3 1 0 28 ArmProfLgt 3 3 1 0
29 WP_Shortbow 7910 3 1 0 29 FEAT_EPIC_BLINDING_SPEED 491 1 -1 1
30 WP_Rapier 7924 3 1 0 30 FEAT_EPIC_SKILL_FOCUS_APPRAISE 588 1 -1 0
31 ArmProfLgt 3 3 1 0 31 FEAT_EPIC_SKILL_FOCUS_CONCENTRATION 589 1 -1 0
32 FEAT_EPIC_BLINDING_SPEED 491 1 -1 1 32 FEAT_EPIC_SKILL_FOCUS_CRAFT_TRAP 590 1 -1 0
33 FEAT_EPIC_SKILL_FOCUS_APPRAISE 588 1 -1 0 33 FEAT_EPIC_SKILL_FOCUS_DISABLETRAP 591 1 -1 0
34 FEAT_EPIC_SKILL_FOCUS_CONCENTRATION 589 1 -1 0 34 FEAT_EPIC_SKILL_FOCUS_DISCIPLINE 592 1 -1 0
35 FEAT_EPIC_SKILL_FOCUS_CRAFT_TRAP 590 1 -1 0 35 FEAT_EPIC_SKILL_FOCUS_HEAL 593 1 -1 0
36 FEAT_EPIC_SKILL_FOCUS_DISABLETRAP 591 1 -1 0 36 FEAT_EPIC_SKILL_FOCUS_HIDE 594 1 -1 0
37 FEAT_EPIC_SKILL_FOCUS_DISCIPLINE 592 1 -1 0 37 FEAT_EPIC_SKILL_FOCUS_LISTEN 595 1 -1 0
38 FEAT_EPIC_SKILL_FOCUS_HEAL 593 1 -1 0 38 FEAT_EPIC_SKILL_FOCUS_LORE 596 1 -1 0
39 FEAT_EPIC_SKILL_FOCUS_HIDE 594 1 -1 0 39 FEAT_EPIC_SKILL_FOCUS_MOVESILENTLY 597 1 -1 0
40 FEAT_EPIC_SKILL_FOCUS_LISTEN 595 1 -1 0 40 FEAT_EPIC_SKILL_FOCUS_OPENLOCK 598 1 -1 0
41 FEAT_EPIC_SKILL_FOCUS_LORE 596 1 -1 0 41 FEAT_EPIC_SKILL_FOCUS_PARRY 599 1 -1 0
42 FEAT_EPIC_SKILL_FOCUS_MOVESILENTLY 597 1 -1 0 42 FEAT_EPIC_SKILL_FOCUS_PERSUADE 601 1 -1 0
43 FEAT_EPIC_SKILL_FOCUS_OPENLOCK 598 1 -1 0 43 FEAT_EPIC_SKILL_FOCUS_PICKPOCKET 602 1 -1 0
44 FEAT_EPIC_SKILL_FOCUS_PARRY 599 1 -1 0 44 FEAT_EPIC_SKILL_FOCUS_SEARCH 603 1 -1 0
45 FEAT_EPIC_SKILL_FOCUS_PERSUADE 601 1 -1 0 45 FEAT_EPIC_SKILL_FOCUS_SETTRAP 604 1 -1 0
46 FEAT_EPIC_SKILL_FOCUS_PICKPOCKET 602 1 -1 0 46 FEAT_EPIC_SKILL_FOCUS_SPELLCRAFT 605 1 -1 0
47 FEAT_EPIC_SKILL_FOCUS_SEARCH 603 1 -1 0 47 FEAT_EPIC_SKILL_FOCUS_SPOT 606 1 -1 0
48 FEAT_EPIC_SKILL_FOCUS_SETTRAP 604 1 -1 0 48 FEAT_EPIC_SKILL_FOCUS_TAUNT 607 1 -1 0
49 FEAT_EPIC_SKILL_FOCUS_SPELLCRAFT 605 1 -1 0 49 FEAT_EPIC_SKILL_FOCUS_TUMBLE 608 1 -1 0
50 FEAT_EPIC_SKILL_FOCUS_SPOT 606 1 -1 0 50 FEAT_EPIC_SKILL_FOCUS_USEMAGICDEVICE 609 1 -1 0
51 FEAT_EPIC_SKILL_FOCUS_TAUNT 607 1 -1 0 51 FEAT_EPIC_SELF_CONCEALMENT_10 748 1 -1 0
52 FEAT_EPIC_SKILL_FOCUS_TUMBLE 608 1 -1 0 52 FEAT_EPIC_SELF_CONCEALMENT_20 749 1 -1 0
53 FEAT_EPIC_SKILL_FOCUS_USEMAGICDEVICE 609 1 -1 0 53 FEAT_EPIC_SELF_CONCEALMENT_30 750 1 -1 0
54 FEAT_EPIC_SELF_CONCEALMENT_10 748 1 -1 0 54 FEAT_EPIC_SELF_CONCEALMENT_40 751 1 -1 0
55 FEAT_EPIC_SELF_CONCEALMENT_20 749 1 -1 0 55 FEAT_EPIC_SELF_CONCEALMENT_50 752 1 -1 0
56 FEAT_EPIC_SELF_CONCEALMENT_30 750 1 -1 0 56 FEAT_EPIC_SUPERIOR_INITIATIVE 753 1 -1 0
57 FEAT_EPIC_SELF_CONCEALMENT_40 751 1 -1 0 57 FEAT_EPIC_DODGE 856 1 -1 0
58 FEAT_EPIC_SELF_CONCEALMENT_50 752 1 -1 0 58 FEAT_IMPROVED_WHIRLWIND 868 1 -1 0
59 FEAT_EPIC_SUPERIOR_INITIATIVE 753 1 -1 0 59 FEAT_EPIC_SKILL_FOCUS_CRAFT_ARMOR 913 1 -1 0
60 FEAT_EPIC_DODGE 856 1 -1 0 60 FEAT_EPIC_SKILL_FOCUS_CRAFT_WEAPON 914 1 -1 0
61 FEAT_IMPROVED_WHIRLWIND 868 1 -1 0 61 FEAT_EPIC_SKILL_FOCUS_BLUFF 917 1 -1 0
62 FEAT_EPIC_SKILL_FOCUS_CRAFT_ARMOR 913 1 -1 0 62 FEAT_EPIC_SKILL_FOCUS_INTIMIDATE 918 1 -1 0
63 FEAT_EPIC_SKILL_FOCUS_CRAFT_WEAPON 914 1 -1 0 63 FEAT_EPIC_SHADOWDANCER 980 3 11 0
64 FEAT_EPIC_SKILL_FOCUS_BLUFF 917 1 -1 0 64 FEAT_EPIC_EPIC_SHADOWLORD 1002 2 -1 0
65 FEAT_EPIC_SKILL_FOCUS_INTIMIDATE 918 1 -1 0 65 FEAT_EPIC_REFLEXES 585 1 -1 0
66 FEAT_EPIC_SHADOWDANCER 980 3 11 0 66 FEAT_LINGERING_DAMAGE 3099 0 -1 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

View File

@@ -40,7 +40,7 @@
36 WP_Falchion 7943 3 1 0 36 WP_Falchion 7943 3 1 0
37 WP_Maul 7947 3 1 0 37 WP_Maul 7947 3 1 0
38 WP_Kukri 7922 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 40 ReadyManeuver 1960 3 1 1
41 RecoverManeuvers 1973 3 1 1 41 RecoverManeuvers 1973 3 1 1
42 **** **** **** **** **** 42 **** **** **** **** ****

View 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 **** **** **** **** **** **** ****

View File

@@ -2349,7 +2349,7 @@
2345 ShieldCharge **** **** **** **** **** **** 2345 ShieldCharge **** **** **** **** **** ****
2346 ShieldSlam **** **** **** **** **** **** 2346 ShieldSlam **** **** **** **** **** ****
2347 PhantomSteed **** **** **** **** **** **** 2347 PhantomSteed **** **** **** **** **** ****
2348 GaseousForm **** **** **** **** **** **** 2348 GaseousForm prc_scr_1564 **** **** **** **** prc_scr_1564
2349 begin_psionics **** **** **** **** **** **** 2349 begin_psionics **** **** **** **** **** ****
2350 Augment_QuickSelects **** **** **** **** **** **** 2350 Augment_QuickSelects **** **** **** **** **** ****
2351 Augment_Digits_0_4 **** **** **** **** **** **** 2351 Augment_Digits_0_4 **** **** **** **** **** ****

View File

@@ -2349,7 +2349,7 @@
2345 ShieldCharge **** 1 1 1 **** 0 2345 ShieldCharge **** 1 1 1 **** 0
2346 ShieldSlam **** 1 1 1 **** 0 2346 ShieldSlam **** 1 1 1 **** 0
2347 PhantomSteed **** 1 1 1 3 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 2349 begin_psionics **** 1 1 1 **** 0
2350 Augment_QuickSelects **** 1 1 1 **** 0 2350 Augment_QuickSelects **** 1 1 1 **** 0
2351 Augment_Digits_0_4 **** 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 12692 Favoured_Soul_Enthrall **** 1 1 1 2 0
12693 Favoured_Soul_SPIRITUAL_WEAPON **** 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 12694 Favoured_Soul_REGEN_LIGHT_WOUNDS **** 1 1 1 1 0
12695 Favoured_Soul_REGEN_MODERATE_WOUNDS **** 1 1 1 2 0 12695 Favoured_Soul_REGEN_MODERATE_WOUNDS **** 1 1 1 3 0
12696 Favoured_Soul_REGEN_SERIOUS_WOUNDS **** 1 1 1 4 0 12696 Favoured_Soul_REGEN_SERIOUS_WOUNDS **** 1 1 1 5 0
12697 Favoured_Soul_REGEN_CRITICAL_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 12698 Favoured_Soul_Hallow **** 1 1 1 6 0
12699 Favoured_Soul_SPELL_CHASING_PERFECTION **** 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 12700 Sohei_Silent_Bless_Weapon **** 1 1 1 2 0

View File

@@ -300,3 +300,4 @@
296 SPELL_MASS_INFLICT_MODERATE_DAMAGE 16976462 17111 6 296 SPELL_MASS_INFLICT_MODERATE_DAMAGE 16976462 17111 6
297 SPELL_MASS_INFLICT_SERIOUS_DAMAGE 16976468 17112 7 297 SPELL_MASS_INFLICT_SERIOUS_DAMAGE 16976468 17112 7
298 SPELL_MASS_INFLICT_CRITICAL_DAMAGE 16976474 17113 8 298 SPELL_MASS_INFLICT_CRITICAL_DAMAGE 16976474 17113 8
299 SPELL_GASEOUS_FORM 16835585 2348 3

View File

@@ -1537,17 +1537,17 @@
1522 SPELL_INFLICT_MODERATE_DAMAGE_3 16976416 3 2 1250 17096 1 1 1 iss_X1InfMod 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 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 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 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 5000 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 7500 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 10500 17098 1 1 1 iss_X1InfCri 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 22500 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 30000 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 16875 17106 0 0 1 is_CurLgtW 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 28125 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 37500 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 20625 17107 0 0 1 is_CurModW 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 28125 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 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 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 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 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 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 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

View File

@@ -4067,7 +4067,7 @@
4063 Epic_Spell_The_Withering **** **** **** **** **** **** **** **** **** **** **** **** **** 4063 Epic_Spell_The_Withering **** **** **** **** **** **** **** **** **** **** **** **** ****
4064 Epic_Spell_Tolodines_Killing_Wind **** **** **** **** **** **** **** **** **** **** **** **** **** 4064 Epic_Spell_Tolodines_Killing_Wind **** **** **** **** **** **** **** **** **** **** **** **** ****
4065 Epic_Spell_Transcendent_Vitality **** **** **** **** **** **** **** **** **** **** **** **** **** 4065 Epic_Spell_Transcendent_Vitality **** **** **** **** **** **** **** **** **** **** **** **** ****
4066 Epic_Spell_Twinfiend **** **** **** **** **** **** **** **** **** **** **** **** **** 4066 Epic_Spell_Twinfiend 0x01000 0x00100 **** **** **** **** **** **** **** **** **** **** ****
4067 Epic_Spell_Unholy_Disciple **** **** **** **** **** **** **** **** **** **** **** **** **** 4067 Epic_Spell_Unholy_Disciple **** **** **** **** **** **** **** **** **** **** **** **** ****
4068 Epic_Spell_Unimpinged **** **** **** **** **** **** **** **** **** **** **** **** **** 4068 Epic_Spell_Unimpinged **** **** **** **** **** **** **** **** **** **** **** **** ****
4069 Epic_Spell_Unseen_Wanderer **** **** **** **** **** **** **** **** **** **** **** **** **** 4069 Epic_Spell_Unseen_Wanderer **** **** **** **** **** **** **** **** **** **** **** **** ****

View File

@@ -22,14 +22,14 @@ void main()
{ {
case 1: case 1:
case 2: case 2:
case 3: sSummon = "ep_summonaberat1"; break; case 3: sSummon = "ep_summonaberat1"; break; //:: Summoned Drider Chief
case 4: case 4:
case 5: case 5:
case 6: sSummon = "ep_summonaberat2"; break; case 6: sSummon = "ep_summonaberat2"; break; //:: Summoned Beholder
case 7: case 7:
case 8: sSummon = "ep_summonaberat3"; break; case 8: sSummon = "ep_summonaberat3"; break; //:: Summoned Mind Flayer Darkener
case 9: sSummon = "ep_summonaberat4"; break; case 9: sSummon = "ep_summonaberat4"; break; //:: Summoned Umber Hulk
case 10: sSummon = "ep_summonaberat5"; break; case 10: sSummon = "ep_summonaberat5"; break; //:: Summoned Battle Devourer
} }
effect eSummon = ExtraordinaryEffect(EffectSummonCreature(sSummon, VFX_FNF_SUMMON_EPIC_UNDEAD, 1.0f)); effect eSummon = ExtraordinaryEffect(EffectSummonCreature(sSummon, VFX_FNF_SUMMON_EPIC_UNDEAD, 1.0f));

View File

@@ -1,60 +1,317 @@
//:://///////////////////////////////////////////// //::////////////////////////////////////////////////////////
//:: ;-. ,-. ,-. ,-.
//:: | ) | ) / ( )
//:: |-' |-< | ;-:
//:: | | \ \ ( )
//:: ' ' ' `-' `-'
//::////////////////////////////////////////////////////////
//;:
//:: Epic Spell: Twinfiend //:: Epic Spell: Twinfiend
//:: Author: Boneshank (Don Armstrong) //:: 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 "x2_inc_toollib"
#include "prc_alterations" #include "prc_alterations"
#include "inc_epicspells" #include "inc_epicspells"
//#include "x2_inc_spellhook" //#include "x2_inc_spellhook"
#include "nw_i0_generic" #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"); MultisummonPreSummon();
SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION);
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; return;
} }
if (GetCanCastSpell(OBJECT_SELF, SPELL_EPIC_TWINF))
{ string sSummon = "twinfiend_demon";
//Declare major variables
float fDuration = RoundsToSeconds(20);
object oFiend, oFiend2;
// effect eSummon; // effect eSummon;
effect eVis = EffectVisualEffect(460); effect eVis = EffectVisualEffect(460);
effect eVis2 = EffectVisualEffect(VFX_IMP_UNSUMMON); 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)) if(GetPRCSwitch(PRC_MULTISUMMON))
{ {
string sSummon = "twinfiend_demon"; SpawnTwinFiend(oPC, jDevil, lTarget, fDuration);
effect eSummon = EffectSummonCreature(sSummon, 460); SpawnTwinFiend(oPC, jDevil, lTarget, fDuration);
MultisummonPreSummon();
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon,
PRCGetSpellTargetLocation(), fDuration);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon,
PRCGetSpellTargetLocation(), fDuration);
DelayCommand(0.5, AugmentSummonedCreature(sSummon));
} }
else else
{ {
DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, PRCGetSpellTargetLocation())); DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget));
oFiend = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation()); //oFiend = CreateObject(OBJECT_TYPE_CREATURE, "twinfiend_demon", PRCGetSpellTargetLocation());
oFiend2 = 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); SetMaxHenchmen(GetMaxHenchmen() + 2);
AddHenchman(OBJECT_SELF, oFiend); AddHenchman(oPC, oFiend);
AddHenchman(OBJECT_SELF, oFiend2); AddHenchman(oPC, oFiend2);
SetMaxHenchmen(GetMaxHenchmen() - 2); 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(oFiend, DetermineCombatRound());
AssignCommand(oFiend2, DetermineCombatRound()); AssignCommand(oFiend2, DetermineCombatRound());
DestroyObject(oFiend, fDuration); DestroyObject(oFiend, fDuration);
DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend))); DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend)));
DestroyObject(oFiend2, fDuration); DestroyObject(oFiend2, fDuration);
DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend2))); DelayCommand(fDuration, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis2, GetLocation(oFiend2)));
} }
} }
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
DeleteLocalInt(oPC, "X2_L_LAST_SPELLSCHOOL_VAR");
} }

View File

@@ -18,6 +18,8 @@
//::////////////////////////////////////////////// //:://////////////////////////////////////////////
#include "nw_inc_gff" #include "nw_inc_gff"
#include "inc_debug" #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 nMaxHP = 0; // Stores the total maximum hitpoints
int i = 1; // Initialize position for class index int i = 1; // Initialize position for class index
int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature); 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 // Loop through each class position the creature may have, checking each class in turn
while (TRUE) while (TRUE)
@@ -54,8 +58,25 @@ int GetMaxPossibleHP(object oCreature)
i++; i++;
} }
if(nRacial == RACIAL_TYPE_CONSTRUCT || nRacial == RACIAL_TYPE_UNDEAD)
{
nConb = 0;
}
nMaxHP += nConb * GetHitDice(oCreature); 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; return nMaxHP;
} }
@@ -202,13 +223,44 @@ int json_GetCreatureHD(json jCreature)
json json_RecalcMaxHP(json jCreature, int iHitDieValue) json json_RecalcMaxHP(json jCreature, int iHitDieValue)
{ {
int iHD = json_GetCreatureHD(jCreature); int iHD = json_GetCreatureHD(jCreature);
int iCON = json_GetCONValue(jCreature);
int iMod = GetAbilityModFromValue(iCON);
int nConBonusHP = iMod * iHD; //:: Retrieve the RacialType field
int iNewMaxHP = (iHitDieValue * iHD); /* nConBonusHP */ 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, "CurrentHitPoints", iNewMaxHP);
jCreature = GffReplaceShort(jCreature, "HitPoints", 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)); if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount));
int nAdded = 0; int nAdded = 0;
int i = 1; int i = 0;
int nMaxIterations = 100; // Safety valve int nMaxIterations = 100; // Safety valve
int nIterations = 0; int nIterations = 0;

View File

@@ -277,6 +277,32 @@ void ClearNaturalWeapons(object oPC)
array_delete(oPC, ARRAY_NAT_PRI_WEAP_ATTACKS); 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) void AddNaturalPrimaryWeapon(object oPC, string sResRef, int nCount = 1, int nForceUse = FALSE)
{ {
int nFirstNaturalWeapon = FALSE; int nFirstNaturalWeapon = FALSE;

View File

@@ -363,7 +363,10 @@ int PRCIsFlying(object oCreature)
bFlying = TRUE; bFlying = TRUE;
} }
if(!bFlying 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; bFlying = TRUE;
if (GetHasSpellEffect(MOVE_SH_BALANCE_SKY, oCreature)) if (GetHasSpellEffect(MOVE_SH_BALANCE_SKY, oCreature))

View File

@@ -76,7 +76,7 @@
/* This variable MUST be updated with every new version of the PRC!!! */ /* 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!!! */ /* This variable MUST be updated every time 'assemble_spellbooks.bat' is run!!! */

View File

@@ -3,6 +3,7 @@
#include "psi_inc_psifunc" #include "psi_inc_psifunc"
#include "inc_lookups" #include "inc_lookups"
#include "nw_inc_nui" #include "nw_inc_nui"
#include "tob_inc_tobfunc"
// //
// GetCurrentSpellLevel // GetCurrentSpellLevel
@@ -153,8 +154,53 @@ json GreyOutButton(json jButton, float w, float h);
// //
json CreateGreyOutRectangle(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 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 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) int GetCurrentSpellLevel(int nClass, int nLevel)
{ {
@@ -528,3 +574,39 @@ void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF)
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR); 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;
}

View File

@@ -98,21 +98,9 @@ void OpenNUILevelUpWindow(int nClass, object oPC=OBJECT_SELF);
// //
// CloseNUILevelUpWindow // CloseNUILevelUpWindow
// Closes the NUI Level Up Window if its open // 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); void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0);
//
// 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);
// //
// GetRemainingSpellChoices // GetRemainingSpellChoices
@@ -432,7 +420,7 @@ json GetChosenReplaceListObject(object oPC=OBJECT_SELF);
// Returns: // Returns:
// int:Boolean TRUE if the spell is a expanded knowledge spell, FALSE otherwise // 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 // 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 // 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 // extra list, otherwise check to make sure we have made all choices in our
// base list first before adding it to the extra list. // 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) || GetRemainingPowerChoices(nClass, spellCircle, oPC, FALSE) == 0)
{ {
string sFile = GetClassSpellbookFile(nClass); 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 // 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. // or not. The id of the list is -1 or -2.
int i; 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) : json expList = (i == -1) ? GetExpandedChoicesList(nClass, oPC) :
GetEpicExpandedChoicesList(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) // figure out what the true base class is (mostly true for RHD)
int chosenClass = GetTrueClassType(nClass, oPC); int chosenClass = GetTrueClassType(nClass, oPC);
SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass); SetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR, chosenClass);
ExecuteScript("prc_nui_lv_view", oPC); ExecuteScript("prc_nui_lv_view", oPC);
} }
int GetTrueClassType(int nClass, object oPC=OBJECT_SELF) void CloseNUILevelUpWindow(object oPC=OBJECT_SELF, int reset=0)
{
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)
{ {
int currentClass = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CLASS_VAR); 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 // 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. // to save computation time as they will need to be reprocessed.
DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass)); DeleteLocalJson(oPC, NUI_LEVEL_UP_DISCIPLINE_INFO_VAR + IntToString(currentClass));
SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20); SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, -20);
if (reset)
{
ClearLevelUpNUICaches(currentClass, oPC);
}
int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID); int nPreviousToken = NuiFindWindow(oPC, NUI_LEVEL_UP_WINDOW_ID);
if (nPreviousToken != 0) 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 // if its an expanded knowledge choice and we have already made all our
// exp knowledge choices then it needs to be disabled. // 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) int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)
+ GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_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 // default logic for spont casters
totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC); totalSpellsKnown = GetSpellKnownMaxCount(casterLevel, circleLevel, nClass, oPC);
// Favoured Soul has more 0 choices than there are spells for some reason // 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; totalSpellsKnown = 7;
// logic for spont casters // logic for spont casters
@@ -1555,6 +1509,7 @@ int GetRemainingSpellChoices(int nClass, int circleLevel, object oPC=OBJECT_SELF
if (chosenCircle == circleLevel) if (chosenCircle == circleLevel)
SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices); SetLocalInt(oPC, NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR, remainingChoices);
if (DEBUG) DoDebug("Remaining spell choices is " + IntToString(remainingChoices));
return remainingChoices; return remainingChoices;
} }
@@ -1567,22 +1522,9 @@ void FinishLevelUp(int nClass, object oPC=OBJECT_SELF)
int nLevel = GetLevelByClass(nClass, oPC); int nLevel = GetLevelByClass(nClass, oPC);
SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel); SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLevel);
} }
CloseNUILevelUpWindow(oPC); // Close while selected-class var is still set
ClearLevelUpNUICaches(nClass, oPC); 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) void ClearLevelUpNUICaches(int nClass, object oPC=OBJECT_SELF)
{ {
// clear the chosen spells you made // clear the chosen spells you made
@@ -1678,11 +1620,13 @@ void RemoveSpells(int nClass, object oPC=OBJECT_SELF)
{ {
string sFile = GetClassSpellbookFile(nClass); string sFile = GetClassSpellbookFile(nClass);
string sSpellBook = GetSpellsKnown_Array(nClass); string sSpellBook = GetSpellsKnown_Array(nClass);
string spellsAtLevelList = "SpellsKnown_" + IntToString(nClass) + "_AtLevel" + IntToString(GetHitDice(oPC));
// remove the spell from the spellbook // remove the spell from the spellbook
array_extract_int(oPC, sSpellBook, nSpellbookID); array_extract_int(oPC, sSpellBook, nSpellbookID);
array_extract_int(oPC, spellsAtLevelList, nSpellbookID);
// wipe the spell from the player // wipe the spell from the player
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)); 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 // get location of persistant storage on the hide
string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel); string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel);
if (DEBUG) DoDebug("Adding spell " + IntToString(nSpellbookID) + "to " + sSpellbook);
//object oToken = GetHideToken(oPC); //object oToken = GetHideToken(oPC);
// Create spells known persistant array if it is missing // Create spells known persistant array if it is missing
@@ -1803,13 +1748,25 @@ void LearnSpells(int nClass, object oPC=OBJECT_SELF)
nSize = 0; 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) // Mark the spell as known (e.g. add it to the end of oPCs spellbook)
persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID); persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS) if (nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
{ {
// add spell // add spell
string sFile = GetClassSpellbookFile(nClass);
string sArrayName = "NewSpellbookMem_" + IntToString(nClass); string sArrayName = "NewSpellbookMem_" + IntToString(nClass);
int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID)); int featId = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", 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 we could not find the spell here, something went wrong
if (persistant_array_extract_int(oPC, sTestArray, spellID) < 0) 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; return;
} }
} }
@@ -2016,10 +1973,7 @@ void RemoveSpellKnown(int nClass, int spellbookId, object oPC=OBJECT_SELF, int n
// remove spell from player // remove spell from player
int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId)); int ipFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", spellbookId));
itemproperty ipFeat = PRCItemPropertyBonusFeat(ipFeatID); RemoveIPFeat(oPC, ipFeatID);
object oSkin = GetPCSkin(oPC);
RemoveItemProperty(oSkin, ipFeat);
CheckAndRemoveFeat(oSkin, ipFeat);
} }
json GetSpellIDsKnown(int nClass, object oPC=OBJECT_SELF, int nList=0) 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 // if its an expanded knowledge choice and we have already made all our
// exp knowledge choices then it needs to be disabled. // 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) int remainingExp = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC)
+ GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_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); string sFile = GetClassSpellbookFile(nClass);
int isExp = StringToInt(Get2DACache(sFile, "Exp", spellbookId)); 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) json GetCurrentPowerList(object oPC=OBJECT_SELF)
@@ -2360,12 +2318,8 @@ int ShouldAddPower(int nClass, int spellbookId, object oPC=OBJECT_SELF)
string sFile = GetClassSpellbookFile(nClass); string sFile = GetClassSpellbookFile(nClass);
int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId)); int featId = StringToInt(Get2DACache(sFile, "FeatID", spellbookId));
int isExp = StringToInt(Get2DACache(sFile, "Exp", 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 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 // and we have a expanded knowledge choice left to make then show
// the button // 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 currentCircle = GetLocalInt(oPC, NUI_LEVEL_UP_SELECTED_CIRCLE_VAR);
int choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EXP_KNOWLEDGE, oPC); 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))) if (choicesLeft && (currentCircle <= (maxLevel-1)))
addPower = TRUE; addPower = TRUE;
choicesLeft = GetRemainingExpandedChoices(nClass, POWER_LIST_EPIC_EXP_KNOWLEDGE, oPC); 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; addPower = TRUE;
// otherwise don't show the button. // otherwise don't show the button.
return addPower; return addPower;
@@ -2397,7 +2353,7 @@ void LearnPowers(int nClass, object oPC=OBJECT_SELF)
int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i)); int nSpellbookID = JsonGetInt(JsonArrayGet(powerList, i));
// get the expanded knowledge list we are adding to if any // get the expanded knowledge list we are adding to if any
int expKnow = GetExpKnowledgePowerListRequired(nClass, nSpellbookID, oPC); 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); 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; return knownObject;
} }
int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) 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 remaining = 0;
int nLevel = GetInvokerLevel(oPC, nClass); 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 knownObject = GetInvokerKnownListObject(nClass, oPC);
json chosenInv = GetChosenSpellListObject(nClass, oPC); json chosenInv = GetChosenSpellListObject(nClass, oPC);
@@ -3214,8 +3175,10 @@ int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJEC
currentChosen += 1; currentChosen += 1;
} }
} }
if (DEBUG) DoDebug(IntToString(currentChosen) + " incantations chosen at " + IntToString(chosenCircle) + " circle");
int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i))); int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i)));
if (DEBUG) DoDebug(IntToString(allowedAtCircle) + " incantations allowed at " + IntToString(chosenCircle) + " circle");
remaining = (allowedAtCircle - currentChosen + remaining); remaining = (allowedAtCircle - currentChosen + remaining);
// if the circle is below the chosen circle and we have a positive remaining, // if the circle is below the chosen circle and we have a positive remaining,

View File

@@ -93,9 +93,8 @@ void GainPowerPoints(object oChar, int nGain, int bCanExceedMax = FALSE, int bIn
* @param bInform If TRUE, runs TellCharacterPowerPointStatus() on oChar * @param bInform If TRUE, runs TellCharacterPowerPointStatus() on oChar
* after making the modification. * after making the modification.
*/ */
/*
void GainTemporaryPowerPoints(object oChar, int nGain, float fDuration, int bInform = TRUE); void GainTemporaryPowerPoints(object oChar, int nGain, float fDuration, int bInform = TRUE);
*/
/** /**
* Decreases the character's current power point count by up to the given * Decreases the character's current power point count by up to the given
* amount, limited to not going below 0. * amount, limited to not going below 0.

View File

@@ -37,6 +37,8 @@
/* Function prototypes */ /* Function prototypes */
////////////////////////////////////////////////// //////////////////////////////////////////////////
void CheckIfDeleveled(object oPC);
void UpdateLastKnownLevels(object oPC);
void CheckSpellbooks(object oPC); void CheckSpellbooks(object oPC);
void CheckPsionics(object oPC); void CheckPsionics(object oPC);
void CheckInvocations(object oPC); void CheckInvocations(object oPC);
@@ -71,9 +73,72 @@ void main()
eTest = GetNextEffect(oPC); eTest = GetNextEffect(oPC);
} }
CheckIfDeleveled(oPC);
DelayCommand(0.0f, CheckSpellbooks(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 // Handle new spellbooks
void CheckSpellbooks(object oPC) void CheckSpellbooks(object oPC)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -55,13 +55,25 @@ int DoPower(object oManifester, object oTarget, struct manifestation manif)
// It's a creature, target their primary weapon // It's a creature, target their primary weapon
oTarget = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); 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) || if(!(GetWeaponRanged(oTarget) || IPGetIsMeleeWeapon(oTarget) ||
GetBaseItemType(oTarget) == BASE_ITEM_ARROW || GetBaseItemType(oTarget) == BASE_ITEM_ARROW ||
GetBaseItemType(oTarget) == BASE_ITEM_BOLT || GetBaseItemType(oTarget) == BASE_ITEM_BOLT ||
GetBaseItemType(oTarget) == BASE_ITEM_BULLET GetBaseItemType(oTarget) == BASE_ITEM_BULLET
) ) ) )
oTarget = OBJECT_INVALID; oTarget = OBJECT_INVALID; */
// Make sure we have a valid target // Make sure we have a valid target
if(!GetIsObjectValid(oTarget)) if(!GetIsObjectValid(oTarget))

View File

@@ -966,6 +966,17 @@ void main()
sResRef += GetAffixForSize(nSize); sResRef += GetAffixForSize(nSize);
AddNaturalPrimaryWeapon(oPC, sResRef, 2); 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) else if(nRace==RACIAL_TYPE_LIZARDFOLK)
{ {
string sResRef = "prc_lizf_bite_"; string sResRef = "prc_lizf_bite_";

View File

@@ -158,10 +158,6 @@ void main()
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oShadow); 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 // Start watch loop
DelayCommand(6.1, ShadowServantWatch(oShadow, oPC)); DelayCommand(6.1, ShadowServantWatch(oShadow, oPC));

View File

@@ -3,8 +3,19 @@
void main() void main()
{ {
ExecuteScript("nw_ch_summon_9", OBJECT_SELF); object oNPC = OBJECT_SELF;
ExecuteScript("prc_npc_spawn", 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 //use companion appearances
/*if(GetPRCSwitch(MARKER_PRC_COMPANION)) /*if(GetPRCSwitch(MARKER_PRC_COMPANION))

View File

@@ -31,7 +31,7 @@ void main()
int bKing = GetHasFeat(FEAT_KING_LIES, oPC) ? 4 : 0; int bKing = GetHasFeat(FEAT_KING_LIES, oPC) ? 4 : 0;
int bDevil = GetHasFeat(FEAT_TONGUE_DEVIL, oPC) ? iInt : 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); if (bDevil>0) DevilTongue(oPC, oSkin,bDevil);
} }

View File

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

View File

@@ -34,6 +34,28 @@ const string CHAT_COMMAND_INDICATOR_1 = "~~";
const string CHAT_COMMAND_INDICATOR_2 = ".."; const string CHAT_COMMAND_INDICATOR_2 = "..";
const int CHAT_COMMAND_INDICATOR_LENGHT = 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) int GetIsChatCommand(string sString)
{ {
string sTest = GetStringLeft(sString, CHAT_COMMAND_INDICATOR_LENGHT); string sTest = GetStringLeft(sString, CHAT_COMMAND_INDICATOR_LENGHT);
@@ -111,6 +133,50 @@ void main()
string firstWord = JsonGetString(JsonArrayGet(sCommandSplit, 0)); string firstWord = JsonGetString(JsonArrayGet(sCommandSplit, 0));
// if first word is /pa we are using the power attack interface // 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(firstWord == "/pa")
{ {
if(JsonGetLength(sCommandSplit) >= 2) if(JsonGetLength(sCommandSplit) >= 2)
@@ -147,17 +213,6 @@ void main()
SetPCChatMessage(); SetPCChatMessage();
return; 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 // Execute scripts hooked to this event for the player triggering it

View File

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

View File

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

View File

@@ -41,6 +41,9 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
int nMetaMagic = PRCGetMetaMagicFeat(); int nMetaMagic = PRCGetMetaMagicFeat();
int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF); int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF);
int nDuration = nCasterLevel; int nDuration = nCasterLevel;
int bIsPC = GetIsPC(OBJECT_SELF);
nDuration = 24; nDuration = 24;
string sResRef; string sResRef;
//effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); //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); effect eSummon = EffectSummonCreature(sResRef,VFX_FNF_SUMMON_UNDEAD);
//Apply summon effect and VFX impact. //Apply summon effect and VFX impact.
MultisummonPreSummon(); MultisummonPreSummon();
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED)) if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED) && bIsPC)
{ {
object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation()); object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation());
//make it hostile //make it hostile

View File

@@ -40,6 +40,7 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
//Declare major variables //Declare major variables
int nMetaMagic = PRCGetMetaMagicFeat(); int nMetaMagic = PRCGetMetaMagicFeat();
int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF); int nCasterLevel = PRCGetCasterLevel(OBJECT_SELF);
int bIsPC = GetIsPC(OBJECT_SELF);
int nDuration = nCasterLevel; int nDuration = nCasterLevel;
nDuration = 24; nDuration = 24;
string sResRef; string sResRef;
@@ -62,7 +63,7 @@ SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
//Apply VFX impact and summon effect //Apply VFX impact and summon effect
MultisummonPreSummon(); MultisummonPreSummon();
if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED)) if(GetPRCSwitch(PRC_CREATE_UNDEAD_UNCONTROLLED) && bIsPC)
{ {
object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation()); object oSummon = CreateObject(OBJECT_TYPE_CREATURE, sResRef, PRCGetSpellTargetLocation());
//this is to //this is to

View File

@@ -1,6 +1,6 @@
#include "prc_alterations" #include "prc_alterations"
#include "inc_Timestop" #include "inc_timestop"
void main() void main()
{ {
object oTarget = GetExitingObject(); object oTarget = GetExitingObject();

View File

@@ -91,14 +91,15 @@ void main()
{ {
nArmor = nLevel + 5; nArmor = nLevel + 5;
DoCorruptionCost(oPC, ABILITY_STRENGTH, d2(1), 0); DoCorruptionCost(oPC, ABILITY_STRENGTH, d2(1), 0);
SignalEvent(oTarget, EventSpellCastAt(oPC, nSpell));
} }
else if(nSpell == SPELL_GREATER_LUMINOUS_ARMOR) else if(nSpell == SPELL_GREATER_LUMINOUS_ARMOR)
{ {
nArmor = nLevel + 8; nArmor = nLevel + 8;
DoCorruptionCost(oPC, ABILITY_STRENGTH, d3(), 0); DoCorruptionCost(oPC, ABILITY_STRENGTH, d3(), 0);
SignalEvent(oTarget, EventSpellCastAt(oPC, nSpell));
} }
else else
{ {
return; return;

View File

@@ -27,7 +27,7 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
int nDuration = nCasterLevel; // * Duration 1 turn/level int nDuration = nCasterLevel; // * Duration 1 turn/level
if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) //Duration is +100% if (CheckMetaMagic(nMetaMagic, METAMAGIC_EXTEND)) //Duration is +100%
nDuration *= 2; 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_INSTANT, EffectVisualEffect(VFX_IMP_AC_BONUS), oTarget);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration),TRUE,-1,nCasterLevel); SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration),TRUE,-1,nCasterLevel);

View File

@@ -27156,7 +27156,14 @@ A marshal can haste himself and his allies for 1 round. This ability may be use
Hit Die: d10 Hit Die: d10
Skill Points at Each Additional Level: 4+ Int Modifier 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="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. <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. 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> 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="56299" lang="en" sex="m">Epic Spell: Twinfiend</entry>
<entry id="56300" lang="en" sex="m">Researched 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) <entry id="56301" lang="en" sex="m"> School: Conjuration (Summoning, Evil)
Components: V,S Components: V,S
Range: Short Range: Short
Effect: Two summoned pit fiends Effect: Summons two advanced pit fiends
Duration: 20 rounds Duration: 1 Turn / Caster level
Saving Throw: None Saving Throw: None
Spell Resistance: No 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="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="56303" lang="en" sex="m">Researched Epic Spell: Unholy Disciple</entry>
<entry id="56304" lang="en" sex="m">School: Necromancy <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="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="199261" lang="en" sex="m">Mass Inflict Critical Damage (20)</entry>
<entry id="199262" lang="en" sex="m">****</entry> <entry id="199262" lang="en" sex="m">****</entry>
<entry id="199263" lang="en" sex="m">****</entry> <entry id="199263" lang="en" sex="m">Gaseous Form (5)</entry>
<entry id="199264" lang="en" sex="m">****</entry> <entry id="199264" lang="en" sex="m">Gaseous Form (10)</entry>
<entry id="199265" lang="en" sex="m">****</entry> <entry id="199265" lang="en" sex="m">Gaseous Form (15)</entry>
<entry id="199266" lang="en" sex="m">****</entry> <entry id="199266" lang="en" sex="m">****</entry>
<entry id="199267" lang="en" sex="m">****</entry> <entry id="199267" lang="en" sex="m">****</entry>
<entry id="199268" lang="en" sex="m">****</entry> <entry id="199268" lang="en" sex="m">****</entry>