diff --git a/nwn/nwnprc/trunk/2das/classes.2da b/nwn/nwnprc/trunk/2das/classes.2da index f6a9cc0a..4af84abc 100644 --- a/nwn/nwnprc/trunk/2das/classes.2da +++ b/nwn/nwnprc/trunk/2das/classes.2da @@ -39,7 +39,7 @@ 35 Shifter 112222 9026 9027 9028 9029 IR_SHIFTR 8 CLS_ATK_2 CLS_FEAT_SHIFTR CLS_SAVTHR_WILD CLS_SKILL_SHIFTR CLS_BFEAT_SHIFTR 4 **** **** 1 0 12 16 14 8 14 12 WIS 0X00 0X0 0 CLASS_TYPE_SHIFTER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHIFTR 40 0 0 0 10 108 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 36 Dwarven_Defender 112223 76418 76419 76420 76422 IR_DWDEF 12 CLS_ATK_1 CLS_FEAT_DWDEF CLS_SAVTHR_CLER CLS_SKILL_DWDEF CLS_BFEAT_DWDEF 2 **** **** 1 0 16 8 15 14 10 12 STR 0X05 0X1 0 CLASS_TYPE_DWARVEN_DEFENDER 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DWDEF 40 0 0 0 10 89 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 37 Dragon_Disciple 112224 16832127 16832128 16832129 16832130 IR_DRAGOND 6 CLS_ATK_2 CLS_FEAT_DRADIS CLS_SAVTHR_CLER CLS_SKILL_DRADIS CLS_BFEAT_DRADIS 2 **** **** 1 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_DRAGON_DISCIPLE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_DRADIS 40 0 0 0 10 111 0 cls_stat_dradis **** **** **** **** **** **** **** **** **** **** **** **** **** **** -38 Ooze 112225 84438 84438 84437 8154 IR_CLERIC 10 CLS_ATK_2 CLS_FEAT_CLER CLS_SAVTHR_CLER CLS_SKILL_CLER CLS_BFEAT_CLER 0 **** **** 1 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_OOZE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** +38 Ooze 112225 84438 84438 84437 8154 IR_CLERIC 10 CLS_ATK_2 CLS_FEAT_CLER CLS_SAVTHR_CLER CLS_SKILL_CLER CLS_BFEAT_CLER 0 **** **** 0 0 14 8 14 16 10 14 STR 0X00 0X0 0 CLASS_TYPE_OOZE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_OOZE 0 0 0 0 -1 75 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 39 Eye_of_Gruumsh 16790665 16824294 16824295 16824296 16824297 IR_GRUUMSH 12 CLS_ATK_1 CLS_FEAT_EOG CLS_SAVTHR_BARB CLS_SKILL_EOG CLS_BFEAT_EOG 2 **** **** 1 0 16 14 14 14 10 8 STR 0X0A 0X3 0 CLASS_TYPE_PRC_EYE_OF_GRUUMSH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_EOG 40 0 0 0 10 17 0 cls_stat_eog **** **** **** **** **** **** **** **** **** **** **** **** **** **** 40 Shou_Disciple 16790649 16823346 16823347 16823348 16823349 IR_SHOUDISC 10 CLS_ATK_1 CLS_FEAT_SHOU CLS_SAVTHR_WILD CLS_SKILL_SHOU CLS_BFEAT_SHOU 2 **** **** 1 0 12 16 14 8 14 12 DEX 0X00 0X0 0 CLASS_TYPE_SHOU 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_SHOU 5 0 0 0 5 4 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 41 Purple_Dragon_Knight 112226 111710 111711 111712 111713 IR_PDK 10 CLS_ATK_1 CLS_FEAT_PDK CLS_SAVTHR_FIGHT CLS_SKILL_PDK CLS_BFEAT_PDK 2 **** **** 1 0 12 16 14 8 14 12 STR 0X14 0X3 0 CLASS_TYPE_PDK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CLS_PRES_PDK 5 0 0 0 5 131 0 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** diff --git a/nwn/nwnprc/trunk/gfx/iit_herb_254.tga b/nwn/nwnprc/trunk/gfx/iit_herb_254.tga new file mode 100644 index 00000000..796a6323 Binary files /dev/null and b/nwn/nwnprc/trunk/gfx/iit_herb_254.tga differ diff --git a/nwn/nwnprc/trunk/gfx/iit_infusion_000.tga b/nwn/nwnprc/trunk/gfx/iit_infusion_000.tga new file mode 100644 index 00000000..796a6323 Binary files /dev/null and b/nwn/nwnprc/trunk/gfx/iit_infusion_000.tga differ diff --git a/nwn/nwnprc/trunk/include/inc_newspellbook.nss b/nwn/nwnprc/trunk/include/inc_newspellbook.nss index 12655813..542e2d50 100644 --- a/nwn/nwnprc/trunk/include/inc_newspellbook.nss +++ b/nwn/nwnprc/trunk/include/inc_newspellbook.nss @@ -8,7 +8,7 @@ Make cls_spcr_*.2da Make blank cls_spell_*.2da Add cls_spgn_*.2da to classes.2da Add class entry in prc_classes.2da -Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level +Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level (not needed for NWN:EE) Add class to PRCGetSpellSaveDC() in prc_add_spell_dc Add class to GetSpellbookTypeForClass() below Add class to GetAbilityScoreForClass() below @@ -580,7 +580,79 @@ int bKnowsAllClassSpells(int nClass) return TRUE; } + int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) +{ + // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either + if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass)) + { + if(DEBUG) DoDebug("GetSpellKnownMaxCount: No slots available for " + IntToString(nClass) + " level " + IntToString(nLevel) + " circle " + IntToString(nSpellLevel)); + return 0; + } + + int nKnown; + string sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); + + if(DEBUG) + { + DoDebug("GetSpellKnownMaxCount Details:"); + DoDebug("- Class: " + IntToString(nClass)); + DoDebug("- Passed Level: " + IntToString(nLevel)); + DoDebug("- Base Class Level: " + IntToString(GetLevelByClass(nClass, oPC))); + DoDebug("- Effective Level: " + IntToString(GetSpellslotLevel(nClass, oPC))); + DoDebug("- Spell Level: " + IntToString(nSpellLevel)); + DoDebug("- SpellKnownTable: " + sFile); + DoDebug("- MaxKnown from 2DA: " + sKnown); + } + + if(sKnown == "") + { + nKnown = -1; + if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers"); + } + else + nKnown = StringToInt(sKnown); + + if(nKnown == -1) + return 0; + + // COMPLETELY REWROTE THIS SECTION + // Bard and Sorcerer logic for prestige class advancement + if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD) + { + int baseClassLevel = GetLevelByClass(nClass, oPC); + int effectiveLevel = GetSpellslotLevel(nClass, oPC); + + // Debug the values we're checking + if(DEBUG) + { + DoDebug("Spont caster check - Base level: " + IntToString(baseClassLevel) + + ", Effective level: " + IntToString(effectiveLevel)); + } + + // If they have prestige class advancement OR special feats, they should get spells + if(effectiveLevel > baseClassLevel || + GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || + GetHasFeat(FEAT_DRACONIC_BREATH, oPC)) + { + // Allow them to get spells - do nothing here, return nKnown at the end + if(DEBUG) DoDebug("Spontaneous caster eligible for new spells"); + } + else + { + // No advancement, no special feats - no new spells + if(DEBUG) DoDebug("Spontaneous caster NOT eligible for new spells"); + return 0; + } + } + + if(DEBUG) DoDebug("Final spell known count: " + IntToString(nKnown)); + return nKnown; +} + + +/* int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) { // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either // @todo Check rules. There might be cases where this doesn't hold @@ -588,22 +660,9 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) return 0; int nKnown; string sFile; - // Bioware casters use their classes.2da-specified tables - /*if( nClass == CLASS_TYPE_WIZARD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_CLERIC - || nClass == CLASS_TYPE_DRUID - || nClass == CLASS_TYPE_PALADIN - || nClass == CLASS_TYPE_RANGER) - {*/ - sFile = Get2DACache("classes", "SpellKnownTable", nClass); - /*} - else - { - sFile = Get2DACache("classes", "FeatsTable", nClass); - sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231 - }*/ + + sFile = Get2DACache("classes", "SpellKnownTable", nClass); + string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1); if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown); @@ -626,6 +685,7 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC) } return nKnown; } + */ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) { @@ -693,6 +753,44 @@ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass) } int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) +{ + // Get the lookup token created by MakeSpellbookLevelLoop() + string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); + object oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid"); + + // Add code to create the missing lookup object + if(DEBUG) DoDebug("Attempting to create missing spell lookup token"); + ExecuteScript("prc_create_spellb", oPC); + + // Try again after creating it + oCache = GetObjectByTag(sTag); + if(!GetIsObjectValid(oCache)) + { + if(DEBUG) DoDebug("Still couldn't create spell lookup token"); + return 0; + } + else + { + if(DEBUG) DoDebug("Successfully created spell lookup token"); + } + } + + // Read the total number of spells on the given level and determine how many are already known + int nTotal = array_get_size(oCache, "Lkup"); + int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass); + int nUnknown = nTotal - nKnown; + + if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); + if(DEBUG) DoDebug(" Total spells in lookup: " + IntToString(nTotal) + ", Known spells: " + IntToString(nKnown)); + + return nUnknown; +} + + +/* int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) { // Get the lookup token created by MakeSpellbookLevelLoop() string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel); @@ -709,7 +807,7 @@ int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass) if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown)); return nUnknown; -} +} */ void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "") { diff --git a/nwn/nwnprc/trunk/include/prc_inc_spells.nss b/nwn/nwnprc/trunk/include/prc_inc_spells.nss index 72930a28..18c0efae 100644 --- a/nwn/nwnprc/trunk/include/prc_inc_spells.nss +++ b/nwn/nwnprc/trunk/include/prc_inc_spells.nss @@ -385,10 +385,10 @@ const int TYPE_DIVINE = -2; // Returns TRUE if nSpellID is a subradial spell, FALSE otherwise int GetIsSubradialSpell(int nSpellID) { - string sMaster = Get2DAString("spells", "Master", nSpellID); + string sMaster = Get2DACache("spells", "Master", nSpellID); - // A subradial will have a numeric master ID here, not **** - if (sMaster != "****") + // If the Master column is numeric, this spell is a subradial of that master + if (sMaster != "" && sMaster != "****") { return TRUE; } diff --git a/nwn/nwnprc/trunk/include/prc_x2_craft.nss b/nwn/nwnprc/trunk/include/prc_x2_craft.nss index cdeb1ff2..ac1d795a 100644 --- a/nwn/nwnprc/trunk/include/prc_x2_craft.nss +++ b/nwn/nwnprc/trunk/include/prc_x2_craft.nss @@ -3309,21 +3309,23 @@ object CICreateInfusion(object oCreator, int nSpellID) // Keep the original spell id the engine gave us (may be a subradial) int nSpellOriginal = nSpellID; + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellOriginal is "+IntToString(nSpellOriginal)+"."); - // Compute the master (one-step) if this is a subradial. Keep original intact. - int nSpellMaster = nSpellOriginal; + // Compute the master if this is a subradial. Keep original intact. + int nSpellMaster = nSpellOriginal; if (GetIsSubradialSpell(nSpellOriginal)) { nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal); if (DEBUG) DoDebug("CICreateInfusion: detected subradial " + IntToString(nSpellOriginal) + " master -> " + IntToString(nSpellMaster)); } + if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellMaster is "+IntToString(nSpellMaster)+"."); // Try to find an iprp_spells row for the original subradial first (preferred). int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal); int nSpellUsedForIP = nSpellOriginal; // If not found for original, fall back to the master/base spell. - if (nPropID < 0) + if (nPropID < 0) { if (DEBUG) DoDebug("CICreateInfusion: no iprp row for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster)); nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster);