Fixed Vow of Poverty. Fixed Vow of Poverty bonus feats not being restored onClientEnter. Added PRC option for spontaneous casters unlearning spells (@Rakiov) Gloura was double dipping caster level. Added NUI levelup spellpicker for most AMS classes (@Rakiov) Tweaked Tactical Insight. Updated ToB maneuver TLK entries to display correct prerequisites.
		
			
				
	
	
		
			683 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			683 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //:://////////////////////////////////////////////
 | |
| //:: 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_ASSASSIN, 1, 4);
 | |
|     CheckMissingSpells(oPC, CLASS_TYPE_CELEBRANT_SHARESS, 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));
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |