Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
		
			
				
	
	
		
			1173 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1173 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
//::///////////////////////////////////////////////
 | 
						||
//:: Name   New Spellbooks spell learning conversation
 | 
						||
//:: FileName   prc_s_spellgain.nss
 | 
						||
//:://////////////////////////////////////////////
 | 
						||
/**
 | 
						||
New spellbooks spell learning conversation.
 | 
						||
To be called after a level up event.
 | 
						||
Allows to learn new spells, and to unlearn spells
 | 
						||
Each conversation instance is tied to some class's spellbook
 | 
						||
 | 
						||
so far only relevant for spontaneous casters, because the prepared
 | 
						||
caster classes provided by the PRC know all spells of their class spellbook
 | 
						||
 | 
						||
Author:    ?
 | 
						||
Created:   ?
 | 
						||
*/
 | 
						||
 | 
						||
//:://////////////////////////////////////////////
 | 
						||
//:://////////////////////////////////////////////
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
modified on Apr 2008 by motu99
 | 
						||
added choices to unlearn spells for spont casters, added switches for Bioware or PnP unlearning
 | 
						||
*/
 | 
						||
 | 
						||
/**
 | 
						||
PnP rules for unlearning spells:
 | 
						||
 | 
						||
Sorcerer:
 | 
						||
Upon reaching 4th level, and at every even-numbered sorcerer level
 | 
						||
after that (6th, 8th, and so on), a sorcerer can choose to learn a
 | 
						||
new spell in place of one he already knows. In effect, the
 | 
						||
sorcerer “loses” the old spell in exchange for the new one.
 | 
						||
The new spell’s level must be the same as that of the spell
 | 
						||
being exchanged, and it must be at least two levels lower than
 | 
						||
the highest-level sorcerer spell the sorcerer can cast. A
 | 
						||
sorcerer may swap only a single spell at any given level, and
 | 
						||
must choose whether or not to swap the spell at the same time
 | 
						||
that he gains new spells known for the level.
 | 
						||
 | 
						||
Bard:
 | 
						||
Upon reaching 5th level, and at every third bard level after that
 | 
						||
(8th, 11th, and so on), a bard can choose to learn a new spell in
 | 
						||
place of one he already knows. In effect, the bard “loses” the
 | 
						||
old spell in exchange for the new one. The new spell’s level must be
 | 
						||
the same as that of the spell being exchanged, and it must be at least
 | 
						||
two levels lower than the highest-level bard spell the bard can cast.
 | 
						||
A bard may swap only a single spell at any given level, and must choose
 | 
						||
whether or not to swap the spell at the same time that he gains new spells
 | 
						||
known for the level.
 | 
						||
 | 
						||
Favored Soul:
 | 
						||
Upon reaching 4th level, and at every even-numbered 
 | 
						||
favored soul level after that (6th, 8th, and so on), a favored 
 | 
						||
soul can choose to learn a new spell in place of one she 
 | 
						||
already knows. In effect, the favored soul “loses” the old 
 | 
						||
spell in exchange for the new one. The new spell’s level 
 | 
						||
must be the same as that of the spell being exchanged, and 
 | 
						||
it must be at least two levels lower than the highest-level 
 | 
						||
favored soul spell the favored soul can cast. A favored soul 
 | 
						||
may swap only a single spell at any given level, and must 
 | 
						||
choose whether or not to swap the spell at the same time 
 | 
						||
that she gains new spells known for the level.
 | 
						||
 | 
						||
Warmage:
 | 
						||
When a warmage gains access to a 
 | 
						||
new level of spells, he automatically knows all the spells for 
 | 
						||
that level listed on the warmage’s spell list. Essentially, his 
 | 
						||
spell list is the same as his spells known list. Warmages also 
 | 
						||
have the option of adding to their existing spell list through 
 | 
						||
their advanced learning ability as they increase in level (see 
 | 
						||
below). See page 90 for the warmage’s spell list.
 | 
						||
 | 
						||
Advanced Learning (Ex): At 3rd, 6th, 11th, and 16th 
 | 
						||
level, a warmage can add a new spell to his list, representing 
 | 
						||
the result of personal study and experimentation. The spell 
 | 
						||
must be a wizard spell of the evocation school, and of a level 
 | 
						||
no higher than that of the highest-level spell the warmage 
 | 
						||
already knows. Once a new spell is selected, it is forever added 
 | 
						||
to that warmage’s spell list and can be cast just like any other 
 | 
						||
spell on the warmage’s list.
 | 
						||
 | 
						||
Hexblade:
 | 
						||
Upon reaching 12th level, and at every third hexblade level 
 | 
						||
after that (15th and 18th), a hexblade can choose to learn a new spell in place of one he 
 | 
						||
already knows. In effect, the hexblade “loses” the 
 | 
						||
old spell in exchange for the new one. The new spell’s 
 | 
						||
level must be the same as that of the spell being exchanged, 
 | 
						||
and it must be at least two levels lower than the highest-level 
 | 
						||
hexblade spell the hexblade can cast. For instance, upon 
 | 
						||
reaching 12th level, a hexblade could trade in a single 1st-
 | 
						||
level spell (two spell levels below the highest-level hexblade 
 | 
						||
spell he can cast, which is 3rd) for a different 1st-level spell. 
 | 
						||
At 15th level, he could trade in a single 1st-level or 2nd-level 
 | 
						||
spell (since he now can cast 4th-level hexblade spells) for a 
 | 
						||
different spell of the same level. A hexblade may swap only
 | 
						||
a single spell at any given level, and must choose whether or 
 | 
						||
not to swap the spell at the same time that he gains new spells 
 | 
						||
known for the level.
 | 
						||
 Through 3rd level, a hexblade has no caster level. At 4th 
 | 
						||
level and higher, his caster level is one-half his hexblade 
 | 
						||
 | 
						||
Duskblade:
 | 
						||
Upon reaching 5th level, and at every odd-numbered 
 | 
						||
Duskblade level after that (7th, 9th, and so on), a Duskblade
 | 
						||
 can choose to learn a new spell in place of one she 
 | 
						||
already knows. In effect, the Duskblade “loses” the old 
 | 
						||
spell in exchange for the new one. The new spell’s level 
 | 
						||
must be the same as that of the spell being exchanged, and 
 | 
						||
it must be at least two levels lower than the highest-level 
 | 
						||
Duskblade spell the Duskblade can cast. A Duskblade
 | 
						||
may swap only a single spell at any given level, and must 
 | 
						||
choose whether or not to swap the spell at the same time 
 | 
						||
that she gains new spells known for the level.
 | 
						||
 | 
						||
Suel Archanamach:
 | 
						||
He has access to any spell of the 
 | 
						||
abjuration, divination, illusion, and transmutation schools 
 | 
						||
on the sorcerer/wizard spell list. He casts spells just as a 
 | 
						||
sorcerer does, including the ability to replace a known Suel 
 | 
						||
arcanamach spell with a new spell at every even-numbered 
 | 
						||
class level beginning at 4th
 | 
						||
*/
 | 
						||
 | 
						||
#include "prc_inc_function"
 | 
						||
#include "inc_dynconv"
 | 
						||
#include "inc_newspellbook"
 | 
						||
#include "inc_sp_gain_mem"
 | 
						||
#include "x3_inc_string"
 | 
						||
 | 
						||
//////////////////////////////////////////////////
 | 
						||
/* Constant definitions                         */
 | 
						||
//////////////////////////////////////////////////
 | 
						||
 | 
						||
const int STAGE_UNLEARN_CHOICE = 0;
 | 
						||
const int STAGE_SELECT_UNLEARN_LEVEL = 1;
 | 
						||
const int STAGE_SELECT_UNLEARN_SPELL = 2;
 | 
						||
const int STAGE_CONFIRM_UNLEARN = 3;
 | 
						||
const int STAGE_SELECT_LEVEL = 4;
 | 
						||
const int STAGE_SELECT_SPELL = 5;
 | 
						||
const int STAGE_CONFIRM      = 6;
 | 
						||
const int STAGE_CONFIRM_ALL  = 7;
 | 
						||
const int STAGE_ADVLEARN_LEVEL = 8;
 | 
						||
const int STAGE_ADVLEARN_SPELL = 9;
 | 
						||
const int STAGE_ADVLEARN_CONFIRM = 10;
 | 
						||
 | 
						||
const int STRREF_SELECTED_HEADER1   = 16824209; // "You have selected:"
 | 
						||
const int STRREF_SELECTED_HEADER2   = 16824210; // "Is this correct?"
 | 
						||
const int STRREF_END_CONVO_SELECT   = 16824212; // "Finish"
 | 
						||
const int LEVEL_STRREF_START        = 16824809;
 | 
						||
const int STRREF_YES                = 4752;     // "Yes"
 | 
						||
const int STRREF_NO                 = 4753;     // "No"
 | 
						||
const int CHOICE_RETURN_TO_PREVIOUS = 0xEFFFFFFF;
 | 
						||
 | 
						||
const string SPELLGAIN_CONV_CLASS = "SpellGainClass";
 | 
						||
const string SPELLGAIN_CONV_LEVEL = "SelectedLevel";
 | 
						||
const string SPELLGAIN_CONV_SPELL = "SelectedSpell";
 | 
						||
const string SPELLGAIN_CONV_UNLEARN_LEVEL = "UnlrnLvl"; // maximum spell level that can be unlearned at level up
 | 
						||
const string SPELLGAIN_CONV_UNLEARN_COUNT = "UnlrnCnt"; // max nr of spells that can be unlearned at level up
 | 
						||
const string SPELLGAIN_CONV_LEARN_LEVELUP = "LrnLvlUp"; // prep casters: nr of new spells to be learned at level up
 | 
						||
 | 
						||
 | 
						||
//////////////////////////////////////////////////
 | 
						||
/* Aid functions                                */
 | 
						||
//////////////////////////////////////////////////
 | 
						||
 | 
						||
// all spells known by a (spont) caster are stored in one single array, with no differentiation for spell level
 | 
						||
// Here we need to determine the spells known at specific spell levels. This requires a pass over the whole array.
 | 
						||
// For efficiency we determine the spells known for ALL spell levels and cache the result
 | 
						||
const string SPELLS_KNOWN_CACHE = "SKCCCache";
 | 
						||
 | 
						||
void DeleteSKCCCache(object oPC)
 | 
						||
{
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "0");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "1");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "2");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "3");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "4");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "5");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "6");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "7");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "8");
 | 
						||
  DeleteLocalInt(oPC, SPELLS_KNOWN_CACHE + "9");
 | 
						||
}
 | 
						||
 | 
						||
// caches the nr of spells that oPC currently knows at the different spell levels
 | 
						||
void CacheSpellsKnown(int nClass, object oPC)
 | 
						||
{
 | 
						||
  // Loop over all spells known and count the number of spells of each level known
 | 
						||
  int nKnown0, nKnown1, nKnown2, nKnown3, nKnown4;
 | 
						||
  int nKnown5, nKnown6, nKnown7, nKnown8, nKnown9;
 | 
						||
 | 
						||
  // persistant storage of spellbook on the hide
 | 
						||
  //object oToken = GetHideToken(oPC);
 | 
						||
  string sSpellbook = GetSpellsKnown_Array(nClass);
 | 
						||
  int nSpellsKnown_AllLevels = persistant_array_get_size(oPC, sSpellbook);
 | 
						||
 | 
						||
  string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
  int i;
 | 
						||
  for(i = 0; i < nSpellsKnown_AllLevels; i++)
 | 
						||
  {
 | 
						||
    int nSpellbookID = persistant_array_get_int(oPC, sSpellbook, i);
 | 
						||
    int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
 | 
						||
    switch(nSpellLevel)
 | 
						||
    {
 | 
						||
      case 0: nKnown0++; break; case 1: nKnown1++; break;
 | 
						||
      case 2: nKnown2++; break; case 3: nKnown3++; break;
 | 
						||
      case 4: nKnown4++; break; case 5: nKnown5++; break;
 | 
						||
      case 6: nKnown6++; break; case 7: nKnown7++; break;
 | 
						||
      case 8: nKnown8++; break; case 9: nKnown9++; break;
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  // Cache the values (one higher)
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "0", ++nKnown0);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "1", ++nKnown1);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "2", ++nKnown2);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "3", ++nKnown3);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "4", ++nKnown4);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "5", ++nKnown5);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "6", ++nKnown6);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "7", ++nKnown7);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "8", ++nKnown8);
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + "9", ++nKnown9);
 | 
						||
}
 | 
						||
 | 
						||
// updates the cached values of spells known for nSpellLevel
 | 
						||
int UpdateSpellsKnown(int nClass, int nSpellLevel, object oPC)
 | 
						||
{
 | 
						||
  // persistant storage of spellbook on the hide
 | 
						||
  //object oToken = GetHideToken(oPC);
 | 
						||
  string sSpellbook = GetSpellsKnown_Array(nClass);
 | 
						||
  int nSpellsKnown_AllLevels = persistant_array_get_size(oPC, sSpellbook);
 | 
						||
 | 
						||
  int nKnown;
 | 
						||
  string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
  int i;
 | 
						||
  for(i = 0; i < nSpellsKnown_AllLevels; i++)
 | 
						||
  {
 | 
						||
    int nSpellbookID = persistant_array_get_int(oPC, sSpellbook, i);
 | 
						||
    if (nSpellLevel == StringToInt(Get2DACache(sFile, "Level", nSpellbookID)))
 | 
						||
    {
 | 
						||
      nKnown++;
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  // Cache the value (one higher)
 | 
						||
  SetLocalInt(oPC, SPELLS_KNOWN_CACHE + IntToString(nSpellLevel), nKnown + 1);
 | 
						||
  return nKnown;
 | 
						||
}
 | 
						||
 | 
						||
// gets the nr of spells that oPC currently knows at nSpellLevel with nClass
 | 
						||
int GetSpellsKnown(int nClass, int nSpellLevel, object oPC)
 | 
						||
{
 | 
						||
  // Check cache
 | 
						||
  string sCache = SPELLS_KNOWN_CACHE + IntToString(nSpellLevel);
 | 
						||
  int nKnown = GetLocalInt(oPC, sCache);
 | 
						||
 | 
						||
  // Cache not yet set up?
 | 
						||
  if(!nKnown)
 | 
						||
  {
 | 
						||
    // then set the cache up and get the nr of spells known at nSpellLevel from the cache
 | 
						||
    CacheSpellsKnown(nClass, oPC);
 | 
						||
    nKnown = GetLocalInt(oPC, sCache);
 | 
						||
  }
 | 
						||
 | 
						||
  // decrement the value retrieved from cache, because we stored one higher than the actual value to catch a legitimate count of 0
 | 
						||
  --nKnown;
 | 
						||
 | 
						||
  if(DEBUG) DoDebug("GetSpellsKnown(" + GetName(oPC) + ", " +IntToString(nSpellLevel)+ ", " +IntToString(nClass)+ ") = " + IntToString(nKnown));
 | 
						||
  return nKnown;
 | 
						||
}
 | 
						||
 | 
						||
// gets the total nr of spells up to nMaxSpellLevel that oPC currently knows
 | 
						||
// caches results for all spell levels (because all spells known are stored in one single array)
 | 
						||
int GetTotalNrOfSpellsKnown(int nClass, int nMaxSpellLevel, object oPC)
 | 
						||
{
 | 
						||
  // Check cache at spell level 0
 | 
						||
  string sCache = SPELLS_KNOWN_CACHE + "0";
 | 
						||
  int nKnown = GetLocalInt(oPC, sCache);
 | 
						||
  // cache not present? Then make it
 | 
						||
  if(!nKnown)
 | 
						||
  {
 | 
						||
    CacheSpellsKnown(nClass, oPC);
 | 
						||
    nKnown = GetLocalInt(oPC, sCache);
 | 
						||
  }
 | 
						||
 | 
						||
  // nr of known level 0 spells (cached value minus 1)
 | 
						||
  --nKnown;
 | 
						||
 | 
						||
  // get other spell levels, up to max level
 | 
						||
  int nSpellLevel;
 | 
						||
  for (nSpellLevel = 1; nSpellLevel <= nMaxSpellLevel; nSpellLevel++)
 | 
						||
  {
 | 
						||
    // cached value is one higher than the actual value, so decrement by one
 | 
						||
    nKnown += (GetLocalInt(oPC, SPELLS_KNOWN_CACHE + IntToString(nSpellLevel)) - 1);
 | 
						||
  }
 | 
						||
 | 
						||
  if(DEBUG) DoDebug("GetTotalNrOfSpellsKnown(" + GetName(oPC) + ", " + IntToString(nMaxSpellLevel) + ", " +IntToString(nClass)+ ") = " + IntToString(nKnown));
 | 
						||
  return nKnown;
 | 
						||
}
 | 
						||
 | 
						||
// gets the maximum spell level, at which nClass can unlearn a spell at nCasterLevel according to PnP rules
 | 
						||
// if nClass cannot unlearn a spell at nCasterLevel, we return -1
 | 
						||
int GetPnPUnlearnMaxSpellLevel(int nClass, int nCasterLevel)
 | 
						||
{
 | 
						||
  int nLevelModifier;
 | 
						||
  
 | 
						||
  if(  nClass == CLASS_TYPE_SORCERER
 | 
						||
    || nClass == CLASS_TYPE_SUEL_ARCHANAMACH
 | 
						||
    || nClass == CLASS_TYPE_FAVOURED_SOUL
 | 
						||
    || nClass == CLASS_TYPE_MYSTIC
 | 
						||
    || nClass == CLASS_TYPE_SUBLIME_CHORD)
 | 
						||
  {
 | 
						||
    // casterlevel must be at least four and an even nur
 | 
						||
    if (nCasterLevel >= 4 && ((nCasterLevel & 0x1) == 0))
 | 
						||
      nLevelModifier = 2;
 | 
						||
  }
 | 
						||
  else if (nClass == CLASS_TYPE_BARD)
 | 
						||
  {
 | 
						||
    // casterlevel must be at least five; then every three levels
 | 
						||
    if (nCasterLevel >= 5 && ((nCasterLevel - 2) % 3 == 0))
 | 
						||
      nLevelModifier = 2;
 | 
						||
  }
 | 
						||
  else if (nClass == CLASS_TYPE_DUSKBLADE)
 | 
						||
  {
 | 
						||
    // casterlevel must be at least five; then every odd level
 | 
						||
    if (nCasterLevel >= 5 && (nCasterLevel & 0x1))
 | 
						||
      nLevelModifier = 2;
 | 
						||
  }
 | 
						||
  else if (nClass == CLASS_TYPE_HEXBLADE)
 | 
						||
  {
 | 
						||
    // casterlevel must be at least twelve; then every three levels
 | 
						||
    if (nCasterLevel >= 12 && (nCasterLevel % 3 == 0))
 | 
						||
      nLevelModifier = 2;
 | 
						||
  }
 | 
						||
 | 
						||
  if (nLevelModifier)
 | 
						||
    return GetMaxSpellLevelForCasterLevel(nClass, nCasterLevel) - nLevelModifier;
 | 
						||
  else
 | 
						||
    return -1;
 | 
						||
}
 | 
						||
 | 
						||
// note that this also sets the local variables SPELLGAIN_CONV_UNLEARN_LEVEL and SPELLGAIN_CONV_UNLEARN_COUNT
 | 
						||
int DetermineNrOfSpellsToUnlearn(int nClass, object oPC)
 | 
						||
{
 | 
						||
  int nUnlearnCount = GetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT);
 | 
						||
  if (!nUnlearnCount)
 | 
						||
  {
 | 
						||
    int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
 | 
						||
    int bBioUnlearn = GetPRCSwitch(PRC_BIO_UNLEARN);
 | 
						||
    int nMaxSpellLevel_Unlearn;
 | 
						||
    int nKnown_Total;
 | 
						||
 | 
						||
    // determine the maximum level at which we can unlearn spells
 | 
						||
    if (bBioUnlearn)
 | 
						||
      // Bioware rules allow to unlearn spells up to the maximum level nClass can cast
 | 
						||
      nMaxSpellLevel_Unlearn = GetMaxSpellLevelForCasterLevel(nClass, nCasterLevel);
 | 
						||
    else
 | 
						||
      // in PnP we can only unlearn a limited amount of spells; at very specific casterlevels; and only some levels below our max
 | 
						||
      // if the function returns -1, we cannot unlearn any spells at this nCasterLevel
 | 
						||
      nMaxSpellLevel_Unlearn = GetPnPUnlearnMaxSpellLevel(nClass, nCasterLevel);
 | 
						||
 | 
						||
    // are we able to unlearn spells at this nCasterlevel?
 | 
						||
    if (nMaxSpellLevel_Unlearn >= 0
 | 
						||
      // can only unlearn spells, if we know at least one spell up to the max level we may unlearn
 | 
						||
      && ((nKnown_Total = GetTotalNrOfSpellsKnown(nClass, nMaxSpellLevel_Unlearn, oPC)) > 0))
 | 
						||
    {
 | 
						||
      // set the maximum caster level we can unlearn
 | 
						||
      SetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_LEVEL, nMaxSpellLevel_Unlearn);
 | 
						||
 | 
						||
      // get the max nr of spells that can be unlearned from the switch
 | 
						||
      nUnlearnCount = GetPRCSwitch(PRC_UNLEARN_SPELL_MAXNR);
 | 
						||
 | 
						||
      // if switch is not set, use default rules to determine max nr of spells that can be unlearned
 | 
						||
      if (!nUnlearnCount)
 | 
						||
      {
 | 
						||
        if (bBioUnlearn)
 | 
						||
        {
 | 
						||
          // Bioware casters can in principle unlearn all spells they know
 | 
						||
          nUnlearnCount = nKnown_Total;
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          // in full PnP we can only unlearn one single spell
 | 
						||
          nUnlearnCount = 1;
 | 
						||
        }
 | 
						||
      }
 | 
						||
 | 
						||
      // make sure we never unlearn more than we actually know
 | 
						||
      if (nUnlearnCount > nKnown_Total) nUnlearnCount = nKnown_Total;
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
      // if we cannot unlearn at this level, set the unlearn count to -1, so we know we cannot unlearn and that we already set up this stage
 | 
						||
      nUnlearnCount = -1;
 | 
						||
    }
 | 
						||
 | 
						||
    SetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT, nUnlearnCount);
 | 
						||
  }
 | 
						||
  return nUnlearnCount;
 | 
						||
}
 | 
						||
 | 
						||
void LearnSpecificSpell(int nClass, int nSpellLevel, int nSpellbookID, object oPC)
 | 
						||
{
 | 
						||
  // get location of persistant storage on the hide
 | 
						||
  string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel);
 | 
						||
  //object oPC = GetHideToken(oPC);
 | 
						||
 | 
						||
  // 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;
 | 
						||
  }
 | 
						||
 | 
						||
  // Mark the spell as known (e.g. add it to the end of oPCs spellbook)
 | 
						||
  persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
 | 
						||
 | 
						||
  // increment the spells known value in the cache
 | 
						||
  string sCache = SPELLS_KNOWN_CACHE + IntToString(nSpellLevel);
 | 
						||
  int nKnown = GetLocalInt(oPC, sCache);
 | 
						||
  if (nKnown) SetLocalInt(oPC, sCache, ++nKnown);
 | 
						||
 | 
						||
  if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
 | 
						||
  {
 | 
						||
    // get the associated feat and IPfeat IDs
 | 
						||
    string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
    int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
 | 
						||
    int nFeatID   = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
    // Add spell use feats (this also places the bonus feat on the hide, so we can check whether oPC knows this spell by testing for the featID on the hide)
 | 
						||
    AddSpellUse(oPC, nSpellbookID, nClass, sFile, "NewSpellbookMem_" + IntToString(nClass), SPELLBOOK_TYPE_SPONTANEOUS, GetPCSkin(oPC), nFeatID, nIPFeatID);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//////////////////////////////////////////////////
 | 
						||
/* Main function                                */
 | 
						||
//////////////////////////////////////////////////
 | 
						||
 | 
						||
void main()
 | 
						||
{
 | 
						||
  object oPC = GetPCSpeaker();
 | 
						||
  int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
 | 
						||
  int nStage = GetStage(oPC);
 | 
						||
  int nClass = GetLocalInt(oPC, SPELLGAIN_CONV_CLASS);
 | 
						||
 | 
						||
  // Check which of the conversation scripts called the scripts
 | 
						||
  if(nValue == 0) // All of them set the DynConv_Var to non-zero value, so something is wrong -> abort
 | 
						||
    return;
 | 
						||
 | 
						||
  // this conversation is always called for a specific class!
 | 
						||
 | 
						||
  if(nValue == DYNCONV_SETUP_STAGE)
 | 
						||
  {
 | 
						||
    // Check if this stage is marked as already set up
 | 
						||
    // This stops list duplication when scrolling
 | 
						||
    if(!GetIsStageSetUp(nStage, oPC))
 | 
						||
    {
 | 
						||
      // variable named nStage determines the current conversation node
 | 
						||
      // Function SetHeader to set the text displayed to the PC
 | 
						||
      // Function AddChoice to add a response option for the PC. The responses are shown in order added
 | 
						||
      if (nStage == STAGE_UNLEARN_CHOICE)
 | 
						||
      {
 | 
						||
        // first determine the nr of spells that might be unlearned
 | 
						||
        int nUnlearnCount = DetermineNrOfSpellsToUnlearn(nClass, oPC);
 | 
						||
 | 
						||
        // if we can unlearn spells, give oPC a choice
 | 
						||
        if (nUnlearnCount > 0)
 | 
						||
        {
 | 
						||
          SetHeader("You can unlearn " +IntToString(nUnlearnCount) +" spells\nDo you want to unlearn a spell?");
 | 
						||
          SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
 | 
						||
          AddChoice(GetStringByStrRef(STRREF_YES), TRUE);
 | 
						||
          AddChoice(GetStringByStrRef(STRREF_NO), FALSE);
 | 
						||
        }
 | 
						||
        //check if it's Advanced Learning dialog
 | 
						||
        else if(GetLocalInt(oPC, "AdvancedLearning"))
 | 
						||
        {
 | 
						||
          nStage = STAGE_ADVLEARN_LEVEL;
 | 
						||
          SetStage(nStage, oPC);
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          // otherwise proceed directly to spell learning stage
 | 
						||
          nStage = STAGE_SELECT_LEVEL;
 | 
						||
          SetStage(nStage, oPC);
 | 
						||
        }
 | 
						||
        MarkStageSetUp(STAGE_UNLEARN_CHOICE, oPC);
 | 
						||
      }
 | 
						||
      
 | 
						||
      // the second if is intentional, Dont change to else if!!
 | 
						||
      if(nStage == STAGE_SELECT_UNLEARN_LEVEL)
 | 
						||
      {
 | 
						||
                int nSpellLevelMin = GetLocalInt(oPC, "SpellbookMinSpelllevel");
 | 
						||
        // the maximum spell level at which we can unlearn spells was already set up in the previous phase, just retrieve it
 | 
						||
                int nSpellLevelMax = GetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_LEVEL);
 | 
						||
 | 
						||
        int nChoiceAdded = FALSE;
 | 
						||
 | 
						||
        int nSpellLevel;
 | 
						||
        // go through all spell levels, starting at the minimum level for nClass and ending at the maximum level that can be unlearned
 | 
						||
        for(nSpellLevel = nSpellLevelMin; nSpellLevel <= nSpellLevelMax; nSpellLevel++)
 | 
						||
        {
 | 
						||
          // get spells known to oPC at the given level
 | 
						||
          int nSpells_Known  = GetSpellsKnown(nClass, nSpellLevel, oPC);
 | 
						||
 | 
						||
          // only add a choice, if we know spells at that level
 | 
						||
          if(nSpells_Known > 0)
 | 
						||
          {
 | 
						||
            AddChoice(GetStringByStrRef(7544)/*"Spell Level"*/ + " " + IntToString(nSpellLevel), nSpellLevel);
 | 
						||
            nChoiceAdded = TRUE;
 | 
						||
          }
 | 
						||
        }
 | 
						||
 | 
						||
        // if we added at least one spell level, set the header
 | 
						||
        if (nChoiceAdded == TRUE)
 | 
						||
        {
 | 
						||
          SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
 | 
						||
          SetHeader("Select a level from which to unlearn a spell");
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          SetHeader("You do not have any spells to unlearn");
 | 
						||
          // if we didn't find a single spell to unlearn (shouldn't happen), set the unlearn count to -1 to indicate that cannot unlearn any spells at this point
 | 
						||
          SetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT, -1);
 | 
						||
        }
 | 
						||
        MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_SELECT_UNLEARN_SPELL)
 | 
						||
      {
 | 
						||
        // get the level at which we want to unlearn the spell
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
        // Determine the array where the spells known to oPC are stored (one array for all spell levels)
 | 
						||
        string sSpellbook = GetSpellsKnown_Array(nClass);
 | 
						||
        //object oToken = GetHideToken(oPC);
 | 
						||
 | 
						||
        // determine the total nr of spells known to oPC
 | 
						||
        int nSpellsKnown_AllLevels = persistant_array_get_size(oPC, sSpellbook);
 | 
						||
 | 
						||
        // Set up header
 | 
						||
        SetHeader("Select a spell to unlearn");
 | 
						||
 | 
						||
        // List all spells known at the given level
 | 
						||
        int i;
 | 
						||
        for(i = 0; i < nSpellsKnown_AllLevels; i++)
 | 
						||
        {
 | 
						||
          // get the spellbookID (= row nr in cls_spell_*) for the i-th spell known
 | 
						||
          int nSpellbookID = persistant_array_get_int(oPC, sSpellbook, i);
 | 
						||
          // get the level of that spell  and check whether it is equal to the spell level we selected
 | 
						||
          int nLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
 | 
						||
          if (nLevel == nSpellLevel)
 | 
						||
          {
 | 
						||
            // get the real spellID, get the spell name from the real SpellID and add a choice
 | 
						||
            int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
 | 
						||
            string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
 | 
						||
            AddChoice(sName, nSpellbookID, oPC);
 | 
						||
          }
 | 
						||
        }
 | 
						||
 | 
						||
        SetDefaultTokens();
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_CONFIRM_UNLEARN)
 | 
						||
      {
 | 
						||
        // get the spellbookID  (= row nr in cls_spell_*) for the spell we want to unlearn
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
 | 
						||
        // get the real spellID and the feat ID from cls_spell_*
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
        int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
 | 
						||
        int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
        // show the full spell description (as determined from the feat)
 | 
						||
        string sToken  = GetStringByStrRef(16824209) + "\n\n"; // "You have selected:"
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT",        nFeatID))) + "\n";
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "DESCRIPTION", nFeatID))) + "\n\n";
 | 
						||
             sToken += GetStringByStrRef(16824210); // "Is this correct?"
 | 
						||
        SetHeader(sToken);
 | 
						||
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_YES), TRUE);
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_NO), FALSE);
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
        SetDefaultTokens();
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_SELECT_LEVEL)
 | 
						||
      {
 | 
						||
        int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
 | 
						||
                int nSpellLevelMin = GetLocalInt(oPC, "SpellbookMinSpelllevel");
 | 
						||
                // int nSpellLevelMax = GetLocalInt(oPC, "SpellbookMaxSpelllevel");
 | 
						||
        int nSpellLevelMax = GetMaxSpellLevelForCasterLevel(nClass, nCasterLevel);
 | 
						||
 | 
						||
        int nSpellLevel;
 | 
						||
        int nAddedASpellLevel = FALSE;
 | 
						||
 | 
						||
        if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
 | 
						||
        {
 | 
						||
          // go through all spell levels that are available for nClass up to the maximum spell level that oPC can cast
 | 
						||
          for(nSpellLevel = nSpellLevelMin; nSpellLevel <= nSpellLevelMax; nSpellLevel++)
 | 
						||
          {
 | 
						||
            // get the maximum nr of spells oPC is allowed to know at the given spell level
 | 
						||
            int nSpells_Max = GetSpellsKnown_MaxCount(nCasterLevel, nClass, nSpellLevel, oPC);
 | 
						||
            // if we cannot know any spells yet, no sense to do something
 | 
						||
            if (nSpells_Max > 0)
 | 
						||
            {
 | 
						||
              // get the nr of spells oPC knows at the given nSpellLevel and nClass
 | 
						||
                        int nSpells_Known  = GetSpellsKnown(nClass, nSpellLevel, oPC);
 | 
						||
 | 
						||
              // we can only learn more spells, when the spells currently known at the given nSpellLevel are less than the max
 | 
						||
              if(nSpells_Known < nSpells_Max)
 | 
						||
              {
 | 
						||
                // get total nr of spells available for the given class and spell level
 | 
						||
                int nSpells_Total  = GetSpellsInClassSpellbook_Count(nClass, nSpellLevel);
 | 
						||
                // are there still unknown spells in the class spellbook that we can transfer?
 | 
						||
                if(nSpells_Total > nSpells_Known)
 | 
						||
                {
 | 
						||
                  nAddedASpellLevel = TRUE;
 | 
						||
                  AddChoice(GetStringByStrRef(7544)/*"Spell Level"*/ + " " + IntToString(nSpellLevel), nSpellLevel);
 | 
						||
                }
 | 
						||
                else
 | 
						||
                  if(DEBUG) DoDebug("ERROR: prc_s_spellgain: Insufficient spells to fill level " + IntToString(nSpellLevel) + "; Class: " + IntToString(nClass));
 | 
						||
              }
 | 
						||
            }
 | 
						||
          }
 | 
						||
        }
 | 
						||
        else if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED && GetLocalInt(oPC, SPELLGAIN_CONV_LEARN_LEVELUP) > 0)
 | 
						||
        {
 | 
						||
          nAddedASpellLevel = TRUE;
 | 
						||
          // go through all spell levels that are available for nClass up to the maximum spell level that oPC can cast
 | 
						||
          // 0-level spells already added
 | 
						||
          for(nSpellLevel = nSpellLevelMin + 1; nSpellLevel <= nSpellLevelMax; nSpellLevel++)
 | 
						||
          {
 | 
						||
              AddChoice(GetStringByStrRef(7544)/*"Spell Level"*/ + " " + IntToString(nSpellLevel), nSpellLevel);
 | 
						||
          }
 | 
						||
        }
 | 
						||
 | 
						||
        // if there is at least one spell level at which we can still learn spells, go to the spel level selection phase
 | 
						||
        if(nAddedASpellLevel)
 | 
						||
        {
 | 
						||
          SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
 | 
						||
          // "<classname> spellbook.\nSelect a spell level to gain spells from."
 | 
						||
          SetHeader(ReplaceChars(GetStringByStrRef(16828405), "<classname>", GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", nClass)))));
 | 
						||
        }
 | 
						||
        // if we couldn't add a single level from which to learn spells, we are finished, so allow exit
 | 
						||
        else
 | 
						||
        {
 | 
						||
          /*SetHeaderStrRef(16828406); // "You can select more spells when you next gain a level."
 | 
						||
          AllowExit(DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, oPC);
 | 
						||
          SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(STRREF_END_CONVO_SELECT));*/
 | 
						||
          AllowExit(DYNCONV_EXIT_FORCE_EXIT);
 | 
						||
        }
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_SELECT_SPELL)
 | 
						||
      {
 | 
						||
        int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        // class spellbook (one array for each spell level)
 | 
						||
        //object oToken_Class = GetSpellsOfClass_Token(nClass, nSpellLevel);
 | 
						||
        string sSpellBook_Class = GetSpellsOfClass_Array();
 | 
						||
 | 
						||
        // get the total nr of spells in the class spellbook at the given spell level
 | 
						||
        int nSpells_Total  = persistant_array_get_size(oPC, sSpellBook_Class);
 | 
						||
 | 
						||
        // now determine storage location of the spellbook of oPC (all spell levels stored in one array)
 | 
						||
        string sSpellBook = GetSpellsKnown_Array(nClass, nSpellLevel);
 | 
						||
        //object oToken = GetHideToken(oPC);
 | 
						||
 | 
						||
                // Create spells known array if it is missing
 | 
						||
                if(!persistant_array_exists(oPC, sSpellBook)) persistant_array_create(oPC, sSpellBook);
 | 
						||
 | 
						||
        // Determine how many spells the character knows and how many
 | 
						||
        // he is maximally allowed to know (at the given nClass, nCasterLevel and nSpellLevel)
 | 
						||
        int nSpells_Max;
 | 
						||
        int nSpells_ToSelect;
 | 
						||
        if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
 | 
						||
        {
 | 
						||
          int nSpells_Known  = GetSpellsKnown(nClass, nSpellLevel, oPC);
 | 
						||
          nSpells_Max = GetSpellsKnown_MaxCount(nCasterLevel, nClass, nSpellLevel, oPC);
 | 
						||
 | 
						||
          // cannot learn more spells than there are in the class spellbook
 | 
						||
          if (nSpells_Max > nSpells_Total)  nSpells_Max = nSpells_Total;
 | 
						||
 | 
						||
          nSpells_ToSelect = nSpells_Max - nSpells_Known;
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          nSpells_ToSelect = GetLocalInt(oPC, SPELLGAIN_CONV_LEARN_LEVELUP);
 | 
						||
        }
 | 
						||
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
        // Set up header
 | 
						||
        // "You have <selectcount> level <spelllevel> spells remaining to select."
 | 
						||
        SetHeader(ReplaceChars(ReplaceChars(GetStringByStrRef(16828404),
 | 
						||
              "<selectcount>", IntToString(nSpells_ToSelect)),
 | 
						||
              "<spelllevel>", IntToString(nSpellLevel))
 | 
						||
              );
 | 
						||
 | 
						||
        // 2009-9-20: Add a "learn all" option if he can do so. -N-S
 | 
						||
        if (nSpells_Max >= nSpells_Total)
 | 
						||
          // "[Learn all available spells]"
 | 
						||
          // Use the constant -1 to indicate all spells are desired.
 | 
						||
          AddChoice(StringToRGBString(GetStringByStrRef(16847627), STRING_COLOR_GREEN), -1, oPC);
 | 
						||
 | 
						||
        // List all spells not yet selected of this level
 | 
						||
        int i;
 | 
						||
        for(i = 0; i < nSpells_Total; i++)
 | 
						||
        {
 | 
						||
          // get the nSpellbookID (= row nr in the cls_spell_* file) out of the class spellbook and determine the associated feat
 | 
						||
          int nSpellbookID = persistant_array_get_int(oPC, sSpellBook_Class, i);
 | 
						||
          int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
          if (GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
 | 
						||
          {
 | 
						||
              // only if oPC doesn't have the feat, she doesn have the spell
 | 
						||
              if (!GetHasFeat(nFeatID, oPC))
 | 
						||
              {
 | 
						||
                // get the real spellID, get the spell name from the real spellID and add a choice
 | 
						||
                int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
 | 
						||
                string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
 | 
						||
                AddChoice(sName, nSpellbookID, oPC);
 | 
						||
 | 
						||
                if(DEBUG) DoDebug("prc_s_spellgain: Adding spell selection choice:\n"
 | 
						||
                        + "spell ID     = " + IntToString(nSpellID) + "\n"
 | 
						||
                        + "spellbook ID = " + IntToString(nSpellbookID) + "\n"
 | 
						||
                          );
 | 
						||
              }
 | 
						||
          }
 | 
						||
          else
 | 
						||
          {
 | 
						||
              //check if oPC doesn't have the spell and can learn it
 | 
						||
              if (IsIntSet(oPC, sSpellBook, nSpellbookID) == -1 && StringToInt(Get2DACache(sFile, "AL", nSpellbookID)) != 1)
 | 
						||
              {
 | 
						||
                // get the real spellID, get the spell name from the real spellID and add a choice
 | 
						||
                int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
 | 
						||
                string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
 | 
						||
                AddChoice(sName, nSpellbookID, oPC);
 | 
						||
 | 
						||
                if(DEBUG) DoDebug("prc_s_spellgain: Adding spell selection choice:\n"
 | 
						||
                        + "spell ID     = " + IntToString(nSpellID) + "\n"
 | 
						||
                        + "spellbook ID = " + IntToString(nSpellbookID) + "\n"
 | 
						||
                          );
 | 
						||
              }
 | 
						||
          }
 | 
						||
        }
 | 
						||
        
 | 
						||
        if (DEBUG)
 | 
						||
        {
 | 
						||
            DoDebug("Spellbook nCasterLevel: "+IntToString(nCasterLevel));
 | 
						||
            DoDebug("Spellbook nSpellLevel: "+IntToString(nSpellLevel));
 | 
						||
            DoDebug("Spellbook nSpells_ToSelect: "+IntToString(nSpells_ToSelect));
 | 
						||
            DoDebug("Spellbook sFile: "+sFile);
 | 
						||
        }        
 | 
						||
 | 
						||
        SetDefaultTokens();
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_CONFIRM)
 | 
						||
      {
 | 
						||
        // get the spellbookID and the feat ID for the new spell to be learned
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
        int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
        // get the full description according from the feat ID
 | 
						||
        string sToken  = GetStringByStrRef(16824209) + "\n\n"; // "You have selected:"
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT",        nFeatID))) + "\n";
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "DESCRIPTION", nFeatID))) + "\n\n";
 | 
						||
             sToken += GetStringByStrRef(16824210); // "Is this correct?"
 | 
						||
 | 
						||
        SetHeader(sToken);
 | 
						||
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_YES), TRUE);
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_NO), FALSE);
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
        SetDefaultTokens();
 | 
						||
      }
 | 
						||
      // 2009-9-20: Add a "learn all" stage. -N-S
 | 
						||
      else if(nStage == STAGE_CONFIRM_ALL)
 | 
						||
      {
 | 
						||
        int nSpellLevel = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        // class spellbook (one array for each spell level)
 | 
						||
        //object oToken_Class = GetSpellsOfClass_Token(nClass, nSpellLevel);
 | 
						||
        string sSpellBook_Class = GetSpellsOfClass_Array();
 | 
						||
 | 
						||
        // get the total nr of spells in the class spellbook at the given spell level
 | 
						||
        int nSpells_Total = persistant_array_get_size(oPC, sSpellBook_Class);
 | 
						||
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
        string sToken = GetStringByStrRef(16847628) + "\n\n"; // "You have selected the following spells:"
 | 
						||
        int i;
 | 
						||
        for(i = 0; i < nSpells_Total; i++)
 | 
						||
        {
 | 
						||
          // get the nSpellbookID (= row nr in the cls_spell_* file) out of the class spellbook and determine the associated feat
 | 
						||
          int nSpellbookID = persistant_array_get_int(oPC, sSpellBook_Class, i);
 | 
						||
          int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
          // only if oPC doesn't have the feat, she doesn have the spell
 | 
						||
          if (!GetHasFeat(nFeatID, oPC))
 | 
						||
            sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeatID))) + "\n";
 | 
						||
        }
 | 
						||
        sToken += "\n" + GetStringByStrRef(16824210); // "Is this correct?"
 | 
						||
 | 
						||
        SetHeader(sToken);
 | 
						||
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_YES), TRUE);
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_NO), FALSE);
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
        SetDefaultTokens();
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_ADVLEARN_LEVEL)
 | 
						||
      {
 | 
						||
        int nAL = GetLocalInt(oPC, "AdvancedLearning");
 | 
						||
 | 
						||
        if(nAL)
 | 
						||
        {
 | 
						||
          int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
 | 
						||
          int nSpellLevelMin = GetLocalInt(oPC, "SpellbookMinSpelllevel");
 | 
						||
          int nSpellLevelMax = GetMaxSpellLevelForCasterLevel(nClass, nCasterLevel);
 | 
						||
 | 
						||
          int nSpellLevel;
 | 
						||
          // go through all spell levels that are available for nClass up to the maximum spell level that oPC can cast
 | 
						||
          for(nSpellLevel = nSpellLevelMin; nSpellLevel <= nSpellLevelMax; nSpellLevel++)
 | 
						||
          {
 | 
						||
              AddChoice(GetStringByStrRef(7544)/*"Spell Level"*/ + " " + IntToString(nSpellLevel), nSpellLevel);
 | 
						||
          }
 | 
						||
 | 
						||
          SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
 | 
						||
          // "<classname> spellbook.\nSelect a spell level to gain spells from."
 | 
						||
          SetHeader(ReplaceChars(GetStringByStrRef(16828405), "<classname>", GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", nClass)))));
 | 
						||
        }
 | 
						||
        // if we couldn't add a single level from which to learn spells, we are finished, so allow exit
 | 
						||
        else
 | 
						||
        {
 | 
						||
          /*SetHeaderStrRef(16828406); // "You can select more spells when you next gain a level."
 | 
						||
          AllowExit(DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, oPC);
 | 
						||
          SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(STRREF_END_CONVO_SELECT));*/
 | 
						||
          AllowExit(DYNCONV_EXIT_FORCE_EXIT);
 | 
						||
        }
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_ADVLEARN_SPELL)
 | 
						||
      {
 | 
						||
        int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        // class spellbook (one array for each spell level)
 | 
						||
        //object oToken_Class = GetSpellsOfClass_Token(nClass, nSpellLevel);
 | 
						||
        string sSpellBook_Class = GetSpellsOfClass_Array();
 | 
						||
 | 
						||
        // get the total nr of spells in the class spellbook at the given spell level
 | 
						||
        int nSpells_Total  = persistant_array_get_size(oPC, sSpellBook_Class);
 | 
						||
 | 
						||
        // now determine storage location of the spellbook of oPC (all spell levels stored in one array)
 | 
						||
        string sSpellBook = GetSpellsKnown_Array(nClass);
 | 
						||
        //object oToken = GetHideToken(oPC);
 | 
						||
 | 
						||
        // Create spells known array if it is missing
 | 
						||
        if(!persistant_array_exists(oPC, sSpellBook)) persistant_array_create(oPC, sSpellBook);
 | 
						||
 | 
						||
        // Only one AL spell at a time
 | 
						||
        int nSpells_ToSelect = 1;
 | 
						||
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
        // Set up header
 | 
						||
        // "You have <selectcount> spells remaining to select."
 | 
						||
        SetHeader(ReplaceChars(ReplaceChars(GetStringByStrRef(16828404),
 | 
						||
              "<selectcount>", IntToString(nSpells_ToSelect)),
 | 
						||
              "<spelllevel>", IntToString(nSpellLevel))
 | 
						||
              );
 | 
						||
 | 
						||
        AddChoice(StringToRGBString(GetStringByStrRef(16847645), STRING_COLOR_GREEN), CHOICE_RETURN_TO_PREVIOUS);
 | 
						||
        // List all spells not yet selected of this level
 | 
						||
        int i;
 | 
						||
        for(i = 0; i < nSpells_Total; i++)
 | 
						||
        {
 | 
						||
          // get the nSpellbookID (= row nr in the cls_spell_* file) out of the class spellbook and determine the associated feat
 | 
						||
          int nSpellbookID = persistant_array_get_int(oPC, sSpellBook_Class, i);
 | 
						||
          //select only spells marked for Advanced Learning
 | 
						||
          if(Get2DACache(sFile, "AL", nSpellbookID) == "1")
 | 
						||
          {
 | 
						||
            int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
            // only if oPC doesn't have the feat, she doesn have the spell
 | 
						||
            if (!GetHasFeat(nFeatID, oPC))
 | 
						||
            {
 | 
						||
              // get the real spellID, get the spell name from the real spellID and add a choice
 | 
						||
              int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
 | 
						||
              string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
 | 
						||
              AddChoice(sName, nSpellbookID, oPC);
 | 
						||
 | 
						||
              if(DEBUG) DoDebug("prc_s_spellgain: Adding spell selection choice:\n"
 | 
						||
                      + "spell ID     = " + IntToString(nSpellID) + "\n"
 | 
						||
                      + "spellbook ID = " + IntToString(nSpellbookID) + "\n"
 | 
						||
                        );
 | 
						||
            }
 | 
						||
          }
 | 
						||
        }
 | 
						||
 | 
						||
        SetDefaultTokens();
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
      }
 | 
						||
      else if(nStage == STAGE_ADVLEARN_CONFIRM)
 | 
						||
      {
 | 
						||
        // get the spellbookID and the feat ID for the new spell to be learned
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
        int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
        // get the full description according from the feat ID
 | 
						||
        string sToken  = GetStringByStrRef(16824209) + "\n\n"; // "You have selected:"
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT",        nFeatID))) + "\n";
 | 
						||
             sToken += GetStringByStrRef(StringToInt(Get2DACache("feat", "DESCRIPTION", nFeatID))) + "\n\n";
 | 
						||
             sToken += GetStringByStrRef(16824210); // "Is this correct?"
 | 
						||
 | 
						||
        SetHeader(sToken);
 | 
						||
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_YES), TRUE);
 | 
						||
        AddChoice(GetStringByStrRef(STRREF_NO), FALSE);
 | 
						||
 | 
						||
        MarkStageSetUp(nStage, oPC);
 | 
						||
        SetDefaultTokens();
 | 
						||
      }
 | 
						||
      //add more stages for more nodes with Else If clauses
 | 
						||
    }
 | 
						||
 | 
						||
    // Do token setup
 | 
						||
    SetupTokens();
 | 
						||
  }
 | 
						||
  // Abort or exit conversation cleanup.
 | 
						||
  // NOTE: This section is only run when the conversation is aborted
 | 
						||
  // while aborting is allowed. When it isn't, the dynconvo infrastructure
 | 
						||
  // handles restoring the conversation in a transparent manner
 | 
						||
  else if(nValue == DYNCONV_EXITED ||
 | 
						||
      nValue == DYNCONV_ABORTED )
 | 
						||
  {
 | 
						||
    // Add any locals set through this conversation
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_CLASS);
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_LEVEL);
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT);
 | 
						||
    DeleteLocalInt(oPC, SPELLGAIN_CONV_LEARN_LEVELUP);
 | 
						||
    DeleteLocalInt(oPC, "AdvancedLearning");
 | 
						||
 | 
						||
    DeleteSKCCCache(oPC);
 | 
						||
 | 
						||
    DelayCommand(1.0, EvalPRCFeats(oPC));
 | 
						||
  }
 | 
						||
  // Handle PC responses
 | 
						||
  else
 | 
						||
  {
 | 
						||
    // variable named nChoice is the value of the player's choice as stored when building the choice list
 | 
						||
    // variable named nStage determines the current conversation node
 | 
						||
    int nChoice = GetChoice(oPC);
 | 
						||
    if(nStage == STAGE_UNLEARN_CHOICE)
 | 
						||
    {
 | 
						||
      // if spells can be unlearned and oPC wants to unlearn them, proceed to node that selects the level of the spell to be unlearned
 | 
						||
      if( GetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT) > 0
 | 
						||
        && nChoice == TRUE)
 | 
						||
      {
 | 
						||
        nStage = STAGE_SELECT_UNLEARN_LEVEL;
 | 
						||
      }
 | 
						||
      //check if it's Advanced Learning dialog
 | 
						||
      else if(GetLocalInt(oPC, "AdvancedLearning"))
 | 
						||
      {
 | 
						||
        nStage = STAGE_ADVLEARN_LEVEL;
 | 
						||
      }
 | 
						||
      // otherwise proceed to first node of the "learn new spells" section (= select level)
 | 
						||
      else
 | 
						||
      {
 | 
						||
        nStage = STAGE_SELECT_LEVEL;
 | 
						||
      }
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_SELECT_UNLEARN_LEVEL)
 | 
						||
    {
 | 
						||
      // if the nr of spells that can be unlearned is zero (or less), proceed to first node of the "learn new spells" section (= select level)
 | 
						||
      if(GetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT) <= 0)
 | 
						||
        nStage = STAGE_SELECT_LEVEL;
 | 
						||
      else
 | 
						||
      {
 | 
						||
        // otherwise remember the spell level at which to unlearn the spell and proceed to unlearn spell selection stage
 | 
						||
        SetLocalInt(oPC, SPELLGAIN_CONV_LEVEL, nChoice);
 | 
						||
        nStage = STAGE_SELECT_UNLEARN_SPELL;
 | 
						||
      }
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_SELECT_UNLEARN_SPELL)
 | 
						||
    {
 | 
						||
      // record the spell that oPC selected as her unlearn choice and proceed to confirmation stage
 | 
						||
      SetLocalInt(oPC, SPELLGAIN_CONV_SPELL, nChoice);
 | 
						||
      nStage = STAGE_CONFIRM_UNLEARN;
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_CONFIRM_UNLEARN)
 | 
						||
    {
 | 
						||
      // we really want to unlearn the spell?
 | 
						||
      if (nChoice == TRUE)
 | 
						||
      {
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
 | 
						||
        // extract the spell from oPCs spellbook
 | 
						||
        string sSpellBook = GetSpellsKnown_Array(nClass);
 | 
						||
        //object oToken = GetHideToken(oPC);
 | 
						||
        array_extract_int(oPC, sSpellBook, nSpellbookID);
 | 
						||
 | 
						||
        // get the associated IPFeatID and remove it from the hide
 | 
						||
        // we dont remove the metamagic versions here, they will be removed by the hide cleaner at next rest
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
        int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
 | 
						||
        WipeSpellFromHide(nIPFeatID, oPC);
 | 
						||
 | 
						||
        // decrement the spells known value in the cache
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
        string sCache = SPELLS_KNOWN_CACHE + IntToString(nSpellLevel);
 | 
						||
        int nKnown = GetLocalInt(oPC, sCache);
 | 
						||
        if (nKnown) SetLocalInt(oPC, sCache, --nKnown);
 | 
						||
 | 
						||
        // decrement the nr of spells that can be unlearned
 | 
						||
        int nUnlearnCount = GetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT);
 | 
						||
        nUnlearnCount--;
 | 
						||
        if (nUnlearnCount == 0)
 | 
						||
        {
 | 
						||
          // make it -1, so that no new setup occurs (with more spells unlearned, than allowed)
 | 
						||
          nUnlearnCount--;
 | 
						||
          nStage = STAGE_SELECT_LEVEL;
 | 
						||
        }
 | 
						||
        else
 | 
						||
          nStage = STAGE_UNLEARN_CHOICE;
 | 
						||
 | 
						||
        // remember the new nr of spells that can (still) be unlearned
 | 
						||
        SetLocalInt(oPC, SPELLGAIN_CONV_UNLEARN_COUNT, nUnlearnCount);
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        // this was not the spell oPC wanted to unlearn? Then give oPC  a new choice
 | 
						||
        nStage = STAGE_UNLEARN_CHOICE;
 | 
						||
      }
 | 
						||
    }
 | 
						||
    // BEGIN OF LEARN NEW SPELLS SECTION
 | 
						||
    else if(nStage == STAGE_SELECT_LEVEL)
 | 
						||
    {
 | 
						||
      // remember the spell level at which to learn the new spell and proceed to the spell selection phase
 | 
						||
      SetLocalInt(oPC, SPELLGAIN_CONV_LEVEL, nChoice);
 | 
						||
      nStage = STAGE_SELECT_SPELL;
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_SELECT_SPELL)
 | 
						||
    {
 | 
						||
      // 2009-9-20: Add a "learn all" stage. -N-S
 | 
						||
      if (nChoice != -1)
 | 
						||
      {
 | 
						||
        // remember the new spell to learn and proceed to the confirmation phase
 | 
						||
        SetLocalInt(oPC, SPELLGAIN_CONV_SPELL, nChoice);
 | 
						||
        nStage = STAGE_CONFIRM;
 | 
						||
      }
 | 
						||
      else
 | 
						||
        nStage = STAGE_CONFIRM_ALL;
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_CONFIRM)
 | 
						||
    {
 | 
						||
      // If this really is the new spell we want to learn:
 | 
						||
      if(nChoice == TRUE)
 | 
						||
      {
 | 
						||
        // get the new spell's nSpellbookID and nSpellLevel
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        LearnSpecificSpell(nClass, nSpellLevel, nSpellbookID, oPC);
 | 
						||
 | 
						||
        if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED)
 | 
						||
        {
 | 
						||
            int nSpellsToLearn = GetLocalInt(oPC, "LrnLvlUp");
 | 
						||
            --nSpellsToLearn;
 | 
						||
            SetLocalInt(oPC, "LrnLvlUp", nSpellsToLearn);
 | 
						||
 | 
						||
            if(nClass == CLASS_TYPE_ARCHIVIST)
 | 
						||
            {
 | 
						||
                int nLvl = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
 | 
						||
                SetPersistantLocalInt(oPC, "LastSpellGainLevel", nLvl);
 | 
						||
            }
 | 
						||
        }
 | 
						||
      }
 | 
						||
 | 
						||
      nStage = STAGE_SELECT_LEVEL;
 | 
						||
    }
 | 
						||
    // 2009-9-20: Add a "learn all" stage handler. -N-S
 | 
						||
    else if(nStage == STAGE_CONFIRM_ALL)
 | 
						||
    {
 | 
						||
      if (nChoice == TRUE)
 | 
						||
      {
 | 
						||
        int nSpellLevel = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        // class spellbook (one array for each spell level)
 | 
						||
 | 
						||
        //object oToken_Class = GetSpellsOfClass_Token(nClass, nSpellLevel);
 | 
						||
        string sSpellBook_Class = GetSpellsOfClass_Array();
 | 
						||
 | 
						||
        // get the total nr of spells in the class spellbook at the given spell level
 | 
						||
        int nSpells_Total = persistant_array_get_size(oPC, sSpellBook_Class);
 | 
						||
 | 
						||
        string sFile = GetNSBDefinitionFileName(nClass);
 | 
						||
 | 
						||
        int i;
 | 
						||
        for(i = 0; i < nSpells_Total; i++)
 | 
						||
        {
 | 
						||
          // get the nSpellbookID (= row nr in the cls_spell_* file) out of the class spellbook and determine the associated feat
 | 
						||
          int nSpellbookID = persistant_array_get_int(oPC, sSpellBook_Class, i);
 | 
						||
          int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
 | 
						||
 | 
						||
          // only if oPC doesn't have the feat, she doesn have the spell
 | 
						||
          if (!GetHasFeat(nFeatID, oPC))
 | 
						||
            LearnSpecificSpell(nClass, nSpellLevel, nSpellbookID, oPC);
 | 
						||
        }
 | 
						||
      }
 | 
						||
 | 
						||
      nStage = STAGE_SELECT_LEVEL;
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_ADVLEARN_LEVEL)
 | 
						||
    {
 | 
						||
      // remember the spell level at which to learn the new spell and proceed to the spell selection phase
 | 
						||
      SetLocalInt(oPC, SPELLGAIN_CONV_LEVEL, nChoice);
 | 
						||
      nStage = STAGE_ADVLEARN_SPELL;
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_ADVLEARN_SPELL)
 | 
						||
    {
 | 
						||
      if(nChoice == CHOICE_RETURN_TO_PREVIOUS)
 | 
						||
           nStage = STAGE_ADVLEARN_LEVEL;
 | 
						||
      else
 | 
						||
      {
 | 
						||
          SetLocalInt(oPC, SPELLGAIN_CONV_SPELL, nChoice);
 | 
						||
          nStage = STAGE_ADVLEARN_CONFIRM;
 | 
						||
      }
 | 
						||
    }
 | 
						||
    else if(nStage == STAGE_ADVLEARN_CONFIRM)
 | 
						||
    {
 | 
						||
      // If this really is the new spell we want to learn:
 | 
						||
      if(nChoice == TRUE)
 | 
						||
      {
 | 
						||
        // get the new spell's nSpellbookID and nSpellLevel
 | 
						||
        int nSpellbookID = GetLocalInt(oPC, SPELLGAIN_CONV_SPELL);
 | 
						||
        int nSpellLevel  = GetLocalInt(oPC, SPELLGAIN_CONV_LEVEL);
 | 
						||
 | 
						||
        LearnSpecificSpell(nClass, nSpellLevel, nSpellbookID, oPC);
 | 
						||
 | 
						||
        DeleteLocalInt(oPC, "AdvancedLearning");
 | 
						||
        int nAdvLearn = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass));
 | 
						||
        nAdvLearn++;
 | 
						||
        SetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass), nAdvLearn);
 | 
						||
      }
 | 
						||
 | 
						||
      nStage = STAGE_ADVLEARN_LEVEL;
 | 
						||
    }
 | 
						||
 | 
						||
    MarkStageNotSetUp(nStage, oPC);
 | 
						||
    // Store the stage value. If it has been changed, this clears out the choices
 | 
						||
    SetStage(nStage, oPC);
 | 
						||
  }
 | 
						||
}
 |