From 157382e60dc2bc3add0fdc12b96d6f3608154b7b Mon Sep 17 00:00:00 2001 From: Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com> Date: Mon, 9 Feb 2026 08:18:11 -0500 Subject: [PATCH] 2026/02/09 Update Added and activated PRCX. Updated PRC8 includes. --- src/include/inc_item_props.nss | 6 +- src/include/inc_nwnx_funcs.nss | 293 +++++-- src/include/inc_persistsql.nss | 15 +- src/include/inc_switch_setup.nss | 7 +- src/include/inv_invokehook.nss | 6 +- src/include/prc_craft_inc.nss | 344 ++++++++- src/include/prc_effect_inc.nss | 1 + src/include/prc_feat_const.nss | 69 +- src/include/prc_inc_assoc.nss | 9 +- src/include/prc_inc_breath.nss | 84 +- src/include/prc_inc_castlvl.nss | 14 +- src/include/prc_inc_chat_dm.nss | 4 +- src/include/prc_inc_combat.nss | 65 +- src/include/prc_inc_combmove.nss | 207 ++++- src/include/prc_inc_core.nss | 34 +- src/include/prc_inc_function.nss | 5 +- src/include/prc_inc_json.nss | 144 +++- src/include/prc_inc_leadersh.nss | 2 +- src/include/prc_inc_nat_hb.nss | 39 +- src/include/prc_inc_nwscript.nss | 3 +- src/include/prc_inc_racial.nss | 4 +- src/include/prc_inc_shifting.nss | 6 +- src/include/prc_inc_skills.nss | 4 +- src/include/prc_inc_sp_tch.nss | 2 +- src/include/prc_inc_spells.nss | 22 +- src/include/prc_inc_switch.nss | 21 +- src/include/prc_inc_unarmed.nss | 158 ---- src/include/prc_inc_wpnrest.nss | 12 +- src/include/prc_nui_lv_inc.nss | 76 +- src/include/prc_nui_sb_inc.nss | 10 +- src/include/prc_racial_const.nss | 133 ++-- src/include/prc_shifter_info.nss | 4 +- src/include/prc_spell_const.nss | 21 +- src/include/prc_x2_craft.nss | 89 ++- src/include/prc_x2_itemprop.nss | 1 + src/include/prcsp_engine.nss | 29 +- src/include/psi_inc_augment.nss | 3 + src/include/psi_inc_const.nss | 1 + src/include/psi_inc_core.nss | 11 +- src/include/psi_inc_powknown.nss | 69 +- src/include/psi_inc_psifunc.nss | 43 +- src/include/psi_power_const.nss | 5 + src/include/tob_inc_tobfunc.nss | 8 +- src/include/x2_inc_spellhook.nss | 54 +- src/module/ifo/module.ifo.json | 22 + src/module/nss/prc_nui_consts.nss | 113 --- src/module/nss/prc_nui_sb_inc.nss | 1148 ---------------------------- src/module/nss/prc_nui_sbd_inc.nss | 98 --- 48 files changed, 1684 insertions(+), 1834 deletions(-) delete mode 100644 src/module/nss/prc_nui_consts.nss delete mode 100644 src/module/nss/prc_nui_sb_inc.nss delete mode 100644 src/module/nss/prc_nui_sbd_inc.nss diff --git a/src/include/inc_item_props.nss b/src/include/inc_item_props.nss index b912fad..c31e8d2 100644 --- a/src/include/inc_item_props.nss +++ b/src/include/inc_item_props.nss @@ -880,7 +880,8 @@ void SetCompositeBonusT(object oItem, string sBonus, int iVal, int iType, int iS AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyAttackBonusVsSAlign(iSubType, iCurVal + iChange), oItem,9999.0); break; case ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP: - iCurVal = TotalAndRemoveProperty(oItem, iType, iSubType); + //iCurVal = TotalAndRemoveProperty(oItem, iType, iSubType); + iCurVal = TotalAndRemovePropertyT(oItem, iType, iSubType); if ((iCurVal + iChange) > 20) { iVal -= iCurVal + iChange - 20; @@ -888,7 +889,8 @@ void SetCompositeBonusT(object oItem, string sBonus, int iVal, int iType, int iS iChange = 0; } if(iCurVal+iChange > 0) - AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonusVsRace(iSubType, DAMAGE_TYPE_SLASHING, iCurVal + iChange), oItem); + //AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonusVsRace(iSubType, DAMAGE_TYPE_SLASHING, iCurVal + iChange), oItem); + AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonusVsRace(iSubType, DAMAGE_TYPE_SLASHING, iCurVal + iChange), oItem); break; case ITEM_PROPERTY_DECREASED_ABILITY_SCORE: iCurVal = TotalAndRemovePropertyT(oItem, iType, iSubType); diff --git a/src/include/inc_nwnx_funcs.nss b/src/include/inc_nwnx_funcs.nss index ad48c0c..97a48b6 100644 --- a/src/include/inc_nwnx_funcs.nss +++ b/src/include/inc_nwnx_funcs.nss @@ -2,21 +2,23 @@ /* Combined wrappers for both Win32 and Linux NWNX funcs */ //////////////////////////////////////////////////////////////////////////////////// +#include "inc_debug" + ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// -// Used in OnModuleLoad event to auto-detect if NWNX_Funcs plugin is enabled +// Used in OnModuleLoad event to auto-detect if NWNX_Funcs plugin is enabled (DEFUNCT) void PRC_Funcs_Init(object oModule); // Sets the amount of hitpoints oObject has currently to nHP void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP); // Sets the amount of hitpoints oObject can maximally have to nHP -void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP); +void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP, int nLevel = 0); // Changes the skill ranks for nSkill on oObject by iValue -void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue); +void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue, int nLevel = 0); // Sets a base ability score nAbility (ABILITY_STRENGTH, ABILITY_DEXTERITY, etc) to nValue // The range of nValue is 3 to 255 @@ -44,17 +46,17 @@ void PRC_Funcs_SetBaseNaturalAC(object oCreature, int nValue); int PRC_Funcs_GetBaseNaturalAC(object oCreature); // Sets the specialist spell school of a Wizard -void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization); +void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization, int nClass = CLASS_TYPE_WIZARD); // Returns the specialist spell school of a Wizard -int PRC_Funcs_GetWizardSpecialization(object oCreature); +int PRC_Funcs_GetWizardSpecialization(object oCreature, int nClass = CLASS_TYPE_WIZARD); ////////////////////////////////////////////////// /* Function definitions */ ////////////////////////////////////////////////// int _PRC_NWNXFuncsZero(object oObject, string sFunc) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) SetLocalString(oObject, sFunc, "-"); else if (nVersion == 2) @@ -65,7 +67,7 @@ int _PRC_NWNXFuncsZero(object oObject, string sFunc) { } int _PRC_NWNXFuncsOne(object oObject, string sFunc, int nVal1) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) SetLocalString(oObject, sFunc, IntToString(nVal1)); else if (nVersion == 2) @@ -76,7 +78,7 @@ int _PRC_NWNXFuncsOne(object oObject, string sFunc, int nVal1) { } int _PRC_NWNXFuncsTwo(object oObject, string sFunc, int nVal1, int nVal2) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2)); else if (nVersion == 2) @@ -87,7 +89,7 @@ int _PRC_NWNXFuncsTwo(object oObject, string sFunc, int nVal1, int nVal2) { } int _PRC_NWNXFuncsThree(object oObject, string sFunc, int nVal1, int nVal2, int nVal3) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3)); else if (nVersion == 2) @@ -98,7 +100,7 @@ int _PRC_NWNXFuncsThree(object oObject, string sFunc, int nVal1, int nVal2, int } int _PRC_NWNXFuncsFour(object oObject, string sFunc, int nVal1, int nVal2, int nVal3, int nVal4) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) SetLocalString(oObject, sFunc, IntToString(nVal1) + " " + IntToString(nVal2) + " " + IntToString(nVal3) + " " + IntToString(nVal4)); else if (nVersion == 2) @@ -114,13 +116,13 @@ void PRC_Funcs_Init(object oModule) string sTestVariable = "PRC_TEST_NWNX_FUNCS"; SetLocalString(oModule, sTestVariable, "1"); SetLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE", sTestVariable + " 3"); //3 is the variable type - //NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNX_FUNCS that we haven't set yet + //NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNXEE_ENABLED that we haven't set yet int iTest = StringToInt(GetLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE")); DeleteLocalString(oModule, "NWNX!FUNCS!GETHASLOCALVARIABLE"); DeleteLocalString(oModule, sTestVariable); if (iTest) - SetLocalInt(oModule, "PRC_NWNX_FUNCS", 1); //1 == win32 + SetLocalInt(oModule, "PRC_NWNXEE_ENABLED", 1); //1 == win32 else { //NWNX GetLocalVariableCount behaves differently for win32 and linux, @@ -132,7 +134,7 @@ void PRC_Funcs_Init(object oModule) //the call failed because NWNX funcs is not present. string sFunc = "NWNX!FUNCS!GETLOCALVARIABLECOUNT"; SetLocalString(oModule, sFunc, " "); - //NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNX_FUNCS that we haven't set yet + //NOTE: don't use _PRC_NWNXFuncsX functions here; they depend on the PRC_NWNXEE_ENABLED that we haven't set yet //NOTE: the number being returned by GetLocalVariableCount() on Linux seems bogus to me (it's huge, e.g. 294,654,504), //but it does seem to be reliably zero when NWNX funcs is not present, and so far has been reliably non-zero //when it is present. That's all we need here. @@ -140,50 +142,116 @@ void PRC_Funcs_Init(object oModule) int nVariables = StringToInt(GetLocalString(oModule, sFunc)); DeleteLocalString(oModule, sFunc); if (nVariables) - SetLocalInt(oModule, "PRC_NWNX_FUNCS", 2); //2 == linux + SetLocalInt(oModule, "PRC_NWNXEE_ENABLED", 2); //2 == linux } } -void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP) +void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP, int nLevel = 0) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Default to total hit dice if not provided + if (nLevel <= 0) + nLevel = GetHitDice(oCreature); + + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_MAXHP", nHP); + SetLocalInt(oCreature, "PRC_EE_MAXHP_LEVEL", nLevel); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_maxhp", oCreature); +} + +/* void PRC_Funcs_SetMaxHitPoints(object oCreature, int nHP) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1 || nVersion == 2) { _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETMAXHITPOINTS", nHP); DeleteLocalString(oCreature, "NWNX!FUNCS!SETMAXHITPOINTS"); } +} */ + +void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue, int nLevel = 0) +{ + //:: Default to current level if not provided + if (nLevel <= 0) + nLevel = GetHitDice(oCreature); + + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_SKILL", nSkill); + SetLocalInt(oCreature, "PRC_EE_SKILL_DELTA", nValue); + SetLocalInt(oCreature, "PRC_EE_SKILL_LEVEL", nLevel); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_mod_skill", oCreature); } -void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue) +/* void PRC_Funcs_ModSkill(object oCreature, int nSkill, int nValue) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsThree(oCreature, "NWNX!FUNCS!SETSKILL", nSkill, nValue, 1); //The 1 is a flag specifying modify instead of set else if (nVersion == 2) _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!MODIFYSKILLRANK", nSkill, nValue); -} +} */ void PRC_Funcs_SetAbilityScore(object oCreature, int nAbility, int nValue) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_ABILITY", nAbility); + SetLocalInt(oCreature, "PRC_EE_ABILITY_VALUE", nValue); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_ability", oCreature); +} + +/* void PRC_Funcs_SetAbilityScore(object oCreature, int nAbility, int nValue) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsFour(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue, 0, 0); //The first 0 is a flag specifying set instead of modify else if (nVersion == 2) _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue); -} +} */ void PRC_Funcs_ModAbilityScore(object oCreature, int nAbility, int nValue) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + if(DEBUG) DoDebug("============================================"); + if(DEBUG) DoDebug("PRC_Funcs_ModAbiltyScore: Starting function."); + if(DEBUG) DoDebug("============================================"); + + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_ABILITY", nAbility); + SetLocalInt(oCreature, "PRC_EE_ABILITY_DELTA", nValue); + + if(DEBUG) DoDebug("PRC_Funcs_ModAbiltyScore: Variables Set"); + + //:: Fire NWNxEE shim + if(DEBUG) DoDebug("PRC_Funcs_ModAbiltyScore: Firing prc_mod_ability"); + ExecuteScript("prcx_mod_ability", oCreature); +} + +/* void PRC_Funcs_ModAbilityScore(object oCreature, int nAbility, int nValue) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsFour(oCreature, "NWNX!FUNCS!SETABILITYSCORE", nAbility, nValue, 1, 0); //The 1 is a flag specifying modify instead of set else if (nVersion == 2) _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!MODIFYABILITYSCORE", nAbility, nValue); +} */ + +void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel = 0) +{ + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_FEAT", nFeat); + SetLocalInt(oCreature, "PRC_EE_FEAT_LEVEL", nLevel); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_add_feat", oCreature); } -void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel=0) +/* void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel=0) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) { if (!nLevel) @@ -198,21 +266,88 @@ void PRC_Funcs_AddFeat(object oCreature, int nFeat, int nLevel=0) else if(nLevel > 0) _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!ADDKNOWNFEATATLEVEL", nLevel, nFeat); } +} */ + +/** + * @brief Determines whether a creature inherently knows a feat. + * + * This function returns TRUE only if the specified feat is an inherent + * (true) feat possessed by the creature. Bonus feats granted via + * EFFECT_TYPE_BONUS_FEAT effects are explicitly ignored. + * + * This allows reliable differentiation between permanent feats + * (e.g. class, racial, or template feats) and temporary or granted + * bonus feats applied through effects. + * + * No NWNxEE shim is required; this function operates entirely using + * stock NWScript functionality. + * + * @param oCreature The creature to check. + * @param nFeatIndex The feat constant to test. + * + * @return TRUE if the creature inherently knows the feat and does not + * possess it solely via a bonus feat effect; FALSE otherwise. + */ +int PRC_Funcs_GetFeatKnown(object oCreature, int nFeatIndex) +{ + //:: Check for an EffectBonusFeat with this feat ID + effect eCheck = GetFirstEffect(oCreature); + int bHasBonusFeatEffect = FALSE; + while (GetIsEffectValid(eCheck)) + { + if (GetEffectType(eCheck) == EFFECT_TYPE_BONUS_FEAT && GetEffectInteger(eCheck, 0) == nFeatIndex) + { + bHasBonusFeatEffect = TRUE; + break; + } + eCheck = GetNextEffect(oCreature); + } + + //;: Return TRUE only if inherent and no matching bonus feat effect + return (!bHasBonusFeatEffect && GetHasFeat(nFeatIndex, oCreature)); } -int PRC_Funcs_GetFeatKnown(object oCreature, int nFeatIndex) +/* int PRC_Funcs_GetFeatKnown(object oCreature, int nFeatIndex) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_FEAT", nFeatIndex); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_knows_feat", oCreature); + + //:: Read result + int nResult = GetLocalInt(oCreature, "PRC_EE_FEAT_RESULT"); + + //:: Clean up locals + DeleteLocalInt(oCreature, "PRC_EE_FEAT"); + DeleteLocalInt(oCreature, "PRC_EE_FEAT_RESULT"); + + return nResult; +} */ + +/* int PRC_Funcs_GetFeatKnown(object oCreature, int nFeatIndex) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETFEATKNOWN", nFeatIndex); else if (nVersion == 2) return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETKNOWNFEAT", nFeatIndex); return 0; -} +} */ void PRC_Funcs_ModSavingThrowBonus(object oCreature, int nSavingThrow, int nValue) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_STYPE", nSavingThrow); + SetLocalInt(oCreature, "PRC_EE_SDELTA", nValue); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_mod_save", oCreature); +} + +/* void PRC_Funcs_ModSavingThrowBonus(object oCreature, int nSavingThrow, int nValue) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsThree(oCreature, "NWNX!FUNCS!SETSAVINGTHROWBONUS", nSavingThrow, nValue, 1); //The 1 is a flag specifying modify instead of set else if (nVersion == 2) @@ -224,61 +359,133 @@ void PRC_Funcs_ModSavingThrowBonus(object oCreature, int nSavingThrow, int nValu nNewValue = 127; _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETSAVINGTHROWBONUS", nSavingThrow, nNewValue); } -} +} */ void PRC_Funcs_SetBaseNaturalAC(object oCreature, int nValue) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Payload for NWNxEE shim + SetLocalInt(oCreature, "PRC_EE_BASEAC", nValue); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_ac", oCreature); +} + +/* void PRC_Funcs_SetBaseNaturalAC(object oCreature, int nValue) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsTwo(oCreature, "NWNX!FUNCS!SETBASEAC", nValue, AC_NATURAL_BONUS); else if (nVersion == 2) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETACNATURALBASE", nValue); -} +} */ int PRC_Funcs_GetBaseNaturalAC(object oCreature) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + //:: Fire NWNxEE shim + ExecuteScript("prcx_get_ac", oCreature); + + //:: Read result + int nAC = GetLocalInt(oCreature, "PRC_EE_BASEAC_RESULT"); + + //:: Clean up + DeleteLocalInt(oCreature, "PRC_EE_BASEAC_RESULT"); + + return nAC; +} + +/* int PRC_Funcs_GetBaseNaturalAC(object oCreature) +{ + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) return _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!GETBASEAC", AC_NATURAL_BONUS); else if (nVersion == 2) return _PRC_NWNXFuncsZero(oCreature, "NWNX!FUNCS!GETACNATURALBASE"); return 0; +} */ + +void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP) +{ + //:: Sanity check + if (nHP < 0) + nHP = 0; + + //:: Set current hit points directly + //:: Was this not a native function in the past? + SetCurrentHitPoints(oCreature, nHP); } -void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP) +/* void PRC_Funcs_SetCurrentHitPoints(object oCreature, int nHP) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1 || nVersion == 2) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETCURRENTHITPOINTS", nHP); +} */ + +void PRC_Funcs_SetCreatureSize(object oCreature, int nSize) +{ + //:: Pass parameters via locals + SetLocalInt(oCreature, "PRC_EE_CREATURESIZE", nSize); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_size", oCreature); + } -void PRC_Funcs_SetCreatureSize (object oCreature, int nSize) +/* void PRC_Funcs_SetCreatureSize (object oCreature, int nSize) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1 || nVersion == 2) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETCREATURESIZE", nSize); +} */ + +void PRC_Funcs_SetRace(object oCreature, int nRace) +{ + //:: Pass parameters via locals + SetLocalInt(oCreature, "PRC_EE_RACETYPE", nRace); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_race", oCreature); } -void PRC_Funcs_SetRace(object oCreature, int nRace) + +/* void PRC_Funcs_SetRace(object oCreature, int nRace) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETRACE", nRace); else if (nVersion == 2) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETRACIALTYPE", nRace); +} */ + +void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization, int nClass = CLASS_TYPE_WIZARD) +{ + //:: Pass parameters via locals + SetLocalInt(oCreature, "PRC_EE_WIZCLASS", nClass); + SetLocalInt(oCreature, "PRC_EE_WIZSCHOOL", iSpecialization); + + //:: Fire NWNxEE shim + ExecuteScript("prcx_set_spec", oCreature); } -void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization) +/* void PRC_Funcs_SetWizardSpecialization(object oCreature, int iSpecialization) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1 || nVersion == 2) _PRC_NWNXFuncsOne(oCreature, "NWNX!FUNCS!SETWIZARDSPECIALIZATION", iSpecialization); +} */ + +//:: This is a native function now. +int PRC_Funcs_GetWizardSpecialization(object oCreature, int nClass = CLASS_TYPE_WIZARD) +{ + return GetSpecialization(oCreature, nClass); } -int PRC_Funcs_GetWizardSpecialization(object oCreature) +/* int PRC_Funcs_GetWizardSpecialization(object oCreature) { - int nVersion = GetLocalInt(GetModule(), "PRC_NWNX_FUNCS"); + int nVersion = GetLocalInt(GetModule(), "PRC_NWNXEE_ENABLED"); if (nVersion == 1 || nVersion == 2) return _PRC_NWNXFuncsZero(oCreature, "NWNX!FUNCS!GETWIZARDSPECIALIZATION"); return 0; -} \ No newline at end of file +} */ + +//:: void main(){} \ No newline at end of file diff --git a/src/include/inc_persistsql.nss b/src/include/inc_persistsql.nss index 3f642a0..4c88cba 100644 --- a/src/include/inc_persistsql.nss +++ b/src/include/inc_persistsql.nss @@ -685,4 +685,17 @@ string SQLocalsPlayer_GetLastUpdated_UTC(object oPlayer, string sVarName, int nT return SqlGetString(sql, 0); else return ""; -} \ No newline at end of file +} + + +// Returns the current Unix timestamp (seconds since 1970-01-01) +int GetCurrentUnixTimestamp() +{ + sqlquery sql = SqlPrepareQueryObject(GetModule(), + "SELECT strftime('%s','now');"); + + if (SqlStep(sql)) + return SqlGetInt(sql, 0); + else + return 0; +} diff --git a/src/include/inc_switch_setup.nss b/src/include/inc_switch_setup.nss index 86c526c..c264ecc 100644 --- a/src/include/inc_switch_setup.nss +++ b/src/include/inc_switch_setup.nss @@ -867,6 +867,7 @@ void CreateSwitchNameArray() //if you add more switches, add them to this list array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DEBUG); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_COMBAT_DEBUG); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PRCX_ENABLED); //craft array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DISABLE_CRAFT); @@ -892,6 +893,7 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_OPTIONAL_HERBS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_SCEPTER_CASTER_LEVEL); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_SHOW_SR_CHECK_DETAILS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_MATERIAL_COMPONENTS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_DISABLE_COMPONENTS_SHOP); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_PNP_TRUESEEING); @@ -1115,7 +1117,8 @@ void CreateSwitchNameArray() //general //PW - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_ENABLE); +// ConvoCC is unneeded now. +/* array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_ENABLE); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_AVARIEL_WINGS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_FEYRI_WINGS); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_AASIMAR_WINGS); @@ -1145,7 +1148,7 @@ void CreateSwitchNameArray() array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_MAX_STAT); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_SKILL_MULTIPLIER); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_SKILL_BONUS); - array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_CUSTOM_EXIT_SCRIPT); + array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CONVOCC_CUSTOM_EXIT_SCRIPT); */ array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TRUENAME_CR_MULTIPLIER); array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TRUENAME_LEVEL_BONUS); diff --git a/src/include/inv_invokehook.nss b/src/include/inv_invokehook.nss index 53010f3..99d45cd 100644 --- a/src/include/inv_invokehook.nss +++ b/src/include/inv_invokehook.nss @@ -39,8 +39,10 @@ int InvocationASFCheck(object oInvoker, int nClass) case 1: nASF -= 5; break;//light case 2: nASF -= 10; break;//light case 3: nASF -= 20; break;//light - case 4: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 20 : 0; break;//medium; - case 5: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 30 : 0; break;//medium + //case 4: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 20 : 0; break; //medium; + //case 5: nASF -= GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 30 : 0; break; //medium + case 4: nASF = GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 0 : nASF; break; //medium + case 5: nASF = GetHasFeat(FEAT_BATTLE_CASTER, oInvoker) ? 0 : nASF; break; //medium; default: break; } } diff --git a/src/include/prc_craft_inc.nss b/src/include/prc_craft_inc.nss index ee87ad8..bc28738 100644 --- a/src/include/prc_craft_inc.nss +++ b/src/include/prc_craft_inc.nss @@ -40,6 +40,7 @@ struct ipstruct GetIpStructFromString(string sIp); //#include "prc_inc_listener" #include "prc_inc_chat" #include "prc_x2_craft" +#include "prc_inc_material" const int NUM_MAX_PROPERTIES = 200; const int NUM_MAX_SUBTYPES = 256; @@ -1807,6 +1808,11 @@ int GetCraftingDC(object oItem) void MakeMasterwork(object oItem) { if(GetPlotFlag(oItem)) return; //sanity check + + itemproperty ip = ItemPropertyQuality(IP_CONST_QUALITY_MASTERWORK); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + int nBase = GetBaseItemType(oItem); if((nBase == BASE_ITEM_ARMOR) || (nBase == BASE_ITEM_SMALLSHIELD) || @@ -1816,6 +1822,70 @@ void MakeMasterwork(object oItem) { //no armour check penalty here if(GetItemArmourCheckPenalty(oItem) == 0) return; + + ip = ItemPropertySkillBonus(SKILL_BALANCE, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_CLIMB, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_HIDE, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_MOVE_SILENTLY, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_PICK_POCKET, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_SET_TRAP, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_TUMBLE, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_JUMP, 1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + } + else if(GetWeaponType(nBase)) + { + ip = ItemPropertyAttackBonus(1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + } + else if(StringToInt(Get2DACache("prc_craft_gen_it", "Type", nBase)) == PRC_CRAFT_ITEM_TYPE_AMMO) + { + ip = ItemPropertyAttackBonus(1); + ip = TagItemProperty(ip, "Quality_Masterwork"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + } + else + return; +} + +/* void MakeMasterwork(object oItem) +{ + if(GetPlotFlag(oItem)) return; //sanity check + + int nBase = GetBaseItemType(oItem); + if((nBase == BASE_ITEM_ARMOR) || + (nBase == BASE_ITEM_SMALLSHIELD) || + (nBase == BASE_ITEM_LARGESHIELD) || + (nBase == BASE_ITEM_TOWERSHIELD) + ) + { + //no armour check penalty here + if(GetItemArmourCheckPenalty(oItem) == 0) return; + IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_HIDE, 1) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_MOVE_SILENTLY, 1), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_PICK_POCKET, 1) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); @@ -1829,17 +1899,226 @@ void MakeMasterwork(object oItem) } else if(StringToInt(Get2DACache("prc_craft_gen_it", "Type", nBase)) == PRC_CRAFT_ITEM_TYPE_AMMO) { - /* - int nDamageType = (nBase == BASE_ITEM_BULLET) ? DAMAGE_TYPE_BLUDGEONING : DAMAGE_TYPE_PIERCING; - itemproperty ip1 = ItemPropertyDamageBonus(nDamageType, IP_CONST_DAMAGEBONUS_1); - */ + + //int nDamageType = (nBase == BASE_ITEM_BULLET) ? DAMAGE_TYPE_BLUDGEONING : DAMAGE_TYPE_PIERCING; + //itemproperty ip1 = ItemPropertyDamageBonus(nDamageType, IP_CONST_DAMAGEBONUS_1); + IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(1), 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); } else return; } + */ -void MakeAdamantine(object oItem) +void MakeAdamantine(object oItem) +{ + if(GetPlotFlag(oItem)) return; //sanity check + if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR) + { + int nBonus = 0; + switch(GetItemBaseAC(oItem)) + { + case 1: + case 2: + case 3: nBonus = IP_CONST_DAMAGERESIST_1; break; + case 4: + case 5: nBonus = IP_CONST_DAMAGERESIST_2; break; + case 6: + case 7: + case 8: nBonus = IP_CONST_DAMAGERESIST_3; break; + } + if(nBonus) + { + itemproperty ip = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_BLUDGEONING, nBonus); + ip = TagItemProperty(ip, "Material_Adamantine"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_PIERCING, nBonus); + ip = TagItemProperty(ip, "Material_Adamantine"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SLASHING, nBonus); + ip = TagItemProperty(ip, "Material_Adamantine"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertyMaterial(IP_MATERIAL_ADAMANTINE); + ip = TagItemProperty(ip, "Material_Adamantine"); + IPSafeAddItemProperty(oItem, ip, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + } + } +} + +void MakeDarkwood(object oItem) +{ + if(GetPlotFlag(oItem)) return; //sanity check + + itemproperty ip = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_50_PERCENT); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + + int nBase = GetBaseItemType(oItem); + if(((nBase == BASE_ITEM_SMALLSHIELD) || + (nBase == BASE_ITEM_LARGESHIELD) || + (nBase == BASE_ITEM_TOWERSHIELD)) + ) + { + int nBonus = 2; + if(nBase == BASE_ITEM_SMALLSHIELD) nBonus = 1; + + ip = ItemPropertySkillBonus(SKILL_BALANCE, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_CLIMB, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_HIDE, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_MOVE_SILENTLY, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_PICK_POCKET, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_SET_TRAP, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_TUMBLE, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_JUMP, nBonus); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertyMaterial(IP_MATERIAL_WOOD_DARKWOOD_ZALANTAR); + ip = TagItemProperty(ip, "Material_Darkwood"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + } +} + +void MakeDragonhide(object oItem) +{ + //Does nothing so far +} + +void MakeMithral(object oItem) +{ + if(GetPlotFlag(oItem)) return; //sanity check + + itemproperty ip = ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_50_PERCENT); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); + + int nBase = GetBaseItemType(oItem); + + if(GetWeaponType(nBase)) + { + ip = ItemPropertyMaterial(IP_MATERIAL_MITHRAL); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + } + else if(((nBase == BASE_ITEM_ARMOR) || + (nBase == BASE_ITEM_SMALLSHIELD) || + (nBase == BASE_ITEM_LARGESHIELD) || + (nBase == BASE_ITEM_TOWERSHIELD)) + ) + { + int nBonus = 3; + int nPenalty = GetItemArmourCheckPenalty(oItem); + if(nBonus > nPenalty) nBonus = nPenalty; + + ip = ItemPropertySkillBonus(SKILL_BALANCE, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_CLIMB, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_HIDE, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_MOVE_SILENTLY, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_PICK_POCKET, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_SET_TRAP, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_TUMBLE, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertySkillBonus(SKILL_JUMP, nBonus); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + ip = ItemPropertyMaterial(IP_MATERIAL_MITHRAL); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + if(GetItemBaseAC(oItem) == 1) + { + ip = ItemPropertyArcaneSpellFailure(IP_CONST_ARCANE_SPELL_FAILURE_MINUS_5_PERCENT); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + } + else + { + ip = ItemPropertyArcaneSpellFailure(IP_CONST_ARCANE_SPELL_FAILURE_MINUS_10_PERCENT); + ip = TagItemProperty(ip, "Material_Mithral"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + } + + } +} + +void MakeColdIron(object oItem) +{ + //Does nothing so far + itemproperty ip = ItemPropertyMaterial(IP_MATERIAL_COLD_IRON); + ip = TagItemProperty(ip, "Material_ColdIron"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); +} + +void MakeSilver(object oItem) +{ + //Does nothing so far + itemproperty ip = ItemPropertyMaterial(IP_MATERIAL_SILVER); + ip = TagItemProperty(ip, "Material_ColdIron"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); +} + +void MakeMundaneCrystal(object oItem) +{ + //Does nothing so far + itemproperty ip = ItemPropertyMaterial(IP_MATERIAL_GEM_CRYSTAL_MUNDANE); + ip = TagItemProperty(ip, "Material_MundaneCrystal"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); +} + +void MakeDeepCrystal(object oItem) +{ + //Does nothing so far + itemproperty ip = ItemPropertyMaterial(IP_MATERIAL_GEM_CRYSTAL_DEEP); + ip = TagItemProperty(ip, "Material_DeepCrystal"); + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); +} + +/* void MakeAdamantine(object oItem) { if(GetPlotFlag(oItem)) return; //sanity check if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR) @@ -1861,11 +2140,14 @@ void MakeAdamantine(object oItem) IPSafeAddItemProperty(oItem, ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_BLUDGEONING, nBonus), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_PIERCING, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SLASHING, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + itemproperty ipAdamantine = ItemPropertyMaterial(IP_MATERIAL_ADAMANTINE); + IPSafeAddItemProperty(oItem, ipAdamantine, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } } -} +} */ -void MakeDarkwood(object oItem) +/* void MakeDarkwood(object oItem) { if(GetPlotFlag(oItem)) return; //sanity check IPSafeAddItemProperty(oItem, ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_50_PERCENT), 0.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); @@ -1883,10 +2165,14 @@ void MakeDarkwood(object oItem) IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_SET_TRAP, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_TUMBLE, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_JUMP, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + itemproperty ipDarkwood = ItemPropertyMaterial(IP_MATERIAL_WOOD_DARKWOOD_ZALANTAR); + IPSafeAddItemProperty(oItem, ipDarkwood, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } } + */ -void MakeDragonhide(object oItem) +/* void MakeDragonhide(object oItem) { //Does nothing so far } @@ -1911,35 +2197,51 @@ void MakeMithral(object oItem) IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_SET_TRAP, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_TUMBLE, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_JUMP, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); - IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_BALANCE, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); - IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_CLIMB, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_BALANCE, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + IPSafeAddItemProperty(oItem, ItemPropertySkillBonus(SKILL_CLIMB, nBonus) , 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); if(GetItemBaseAC(oItem) == 1) IPSafeAddItemProperty(oItem, ItemPropertyArcaneSpellFailure(IP_CONST_ARCANE_SPELL_FAILURE_MINUS_5_PERCENT), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); else IPSafeAddItemProperty(oItem, ItemPropertyArcaneSpellFailure(IP_CONST_ARCANE_SPELL_FAILURE_MINUS_10_PERCENT), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + + itemproperty ipMithral = ItemPropertyMaterial(IP_MATERIAL_MITHRAL); + IPSafeAddItemProperty(oItem, ipMithral, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } } + */ -void MakeColdIron(object oItem) +/* void MakeColdIron(object oItem) { - //Does nothing so far + //Does nothing so far + itemproperty ipColdIron = ItemPropertyMaterial(IP_MATERIAL_COLD_IRON); + IPSafeAddItemProperty(oItem, ipColdIron, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } + */ -void MakeSilver(object oItem) +/* void MakeSilver(object oItem) { - //Does nothing so far + //Does nothing so far + itemproperty ipSilver = ItemPropertyMaterial(IP_MATERIAL_SILVER); + IPSafeAddItemProperty(oItem, ipSilver, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } - -void MakeMundaneCrystal(object oItem) + */ + +/* void MakeMundaneCrystal(object oItem) { - //Does nothing so far + //Does nothing so far + itemproperty ipCrystal = ItemPropertyMaterial(IP_MATERIAL_GEM_CRYSTAL_MUNDANE); + IPSafeAddItemProperty(oItem, ipCrystal, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } + */ -void MakeDeepCrystal(object oItem) +/* void MakeDeepCrystal(object oItem) { - //Does nothing so far + //Does nothing so far + itemproperty ipDeepCrystal = ItemPropertyMaterial(IP_MATERIAL_GEM_CRYSTAL_DEEP); + IPSafeAddItemProperty(oItem, ipDeepCrystal, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); } - + */ + //Creates an item on oOwner, from the baseitemtype and base AC (for armour) object CreateStandardItem(object oOwner, int nBaseItemType, int nBaseAC = -1) { @@ -2967,4 +3269,4 @@ int ITEM_APPR_WEAPON_COLOR_MIDDLE = 1; int ITEM_APPR_WEAPON_COLOR_TOP = 2; */ -// void main () {} +//:: void main () {} diff --git a/src/include/prc_effect_inc.nss b/src/include/prc_effect_inc.nss index a41f7d9..15ccc42 100644 --- a/src/include/prc_effect_inc.nss +++ b/src/include/prc_effect_inc.nss @@ -498,6 +498,7 @@ effect EffectFatigue(){ effect eReturn = EffectAbilityDecrease(ABILITY_STRENGTH, 2); eReturn = EffectLinkEffects(eReturn, EffectAbilityDecrease(ABILITY_DEXTERITY, 2)); eReturn = EffectLinkEffects(eReturn, EffectMovementSpeedDecrease(25)); + eReturn = EffectLinkEffects(eReturn, EffectIcon(EFFECT_ICON_FATIGUE)); eReturn = TagEffect(eReturn, "PRCFatigue"); return eReturn; } diff --git a/src/include/prc_feat_const.nss b/src/include/prc_feat_const.nss index 6fd8c94..47d3893 100644 --- a/src/include/prc_feat_const.nss +++ b/src/include/prc_feat_const.nss @@ -341,6 +341,16 @@ const int FEAT_FOG_CLOUD_BREATH = 5434; //:: Spiretop Dragon const int FEAT_LTSENSE = 4700; const int FEAT_LTBLIND = 4701; +const int FEAT_RESIST_SONIC5 = 26398; //:: Shyft +const int FEAT_SHYFT_ETHEREAL_JAUNT = 26399; + +const int FEAT_MECHA_ELECTRICY_HEALING = 4431; //:: Mechanatrix +const int FEAT_MECHA_SHOCKING_GRASP = 4432; + +const int FEAT_WISPLING_CHANGE_SHAPE = 4433; //:: Wispling + +const int FEAT_MAELUTH_FIEND_HAMMER = 4434; //:: Maeluth + const int FEAT_SPELL5 = 4702; const int FEAT_SPELL10 = 4420; const int FEAT_SPELL11 = 4703; @@ -404,6 +414,8 @@ const int FEAT_CONSTRICT = 4740; const int FEAT_REGEN5 = 4741; const int FEAT_REND = 4742; const int FEAT_RESIST_FIRE5 = 4743; +const int FEAT_RESIST_COLD5 = 4430; + const int FEAT_SUFFOCATION = 4744; const int FEAT_VERYHEROIC = 4745; const int FEAT_VULN_COLD = 4746; @@ -966,32 +978,35 @@ const int FEAT_KOB_DRAGONWROUGHT_SR = 3855; const int FEAT_DRAGON_AUGMENT_STR_1 = 3857; const int FEAT_DRAGON_AUGMENT_STR_2 = 3858; const int FEAT_DRAGON_AUGMENT_STR_3 = 3859; -const int FEAT_DRAGON_AUGMENT_STR_4 = 26382; -const int FEAT_DRAGON_AUGMENT_STR_5 = 26383; -const int FEAT_DRAGON_AUGMENT_STR_6 = 26384; -const int FEAT_DRAGON_AUGMENT_STR_7 = 26385; -const int FEAT_DRAGON_AUGMENT_STR_8 = 26386; -const int FEAT_DRAGON_AUGMENT_STR_9 = 26387; +const int FEAT_DRAGON_AUGMENT_STR_4 = 25645; +const int FEAT_DRAGON_AUGMENT_STR_5 = 25646; +const int FEAT_DRAGON_AUGMENT_STR_6 = 25647; +const int FEAT_DRAGON_AUGMENT_STR_7 = 25648; +const int FEAT_DRAGON_AUGMENT_STR_8 = 25649; +const int FEAT_DRAGON_AUGMENT_STR_9 = 25650; +const int FEAT_DRAGON_AUGMENT_STR_10 = 25651; const int FEAT_DRAGON_AUGMENT_DEX_1 = 3860; const int FEAT_DRAGON_AUGMENT_DEX_2 = 3861; const int FEAT_DRAGON_AUGMENT_DEX_3 = 3862; -const int FEAT_DRAGON_AUGMENT_DEX_4 = 26388; -const int FEAT_DRAGON_AUGMENT_DEX_5 = 26389; -const int FEAT_DRAGON_AUGMENT_DEX_6 = 26390; -const int FEAT_DRAGON_AUGMENT_DEX_7 = 26391; -const int FEAT_DRAGON_AUGMENT_DEX_8 = 26392; -const int FEAT_DRAGON_AUGMENT_DEX_9 = 26393; +const int FEAT_DRAGON_AUGMENT_DEX_4 = 25653; +const int FEAT_DRAGON_AUGMENT_DEX_5 = 25654; +const int FEAT_DRAGON_AUGMENT_DEX_6 = 25655; +const int FEAT_DRAGON_AUGMENT_DEX_7 = 25656; +const int FEAT_DRAGON_AUGMENT_DEX_8 = 25657; +const int FEAT_DRAGON_AUGMENT_DEX_9 = 25658; +const int FEAT_DRAGON_AUGMENT_DEX_10 = 25659; const int FEAT_DRAGON_AUGMENT_CON_1 = 3863; const int FEAT_DRAGON_AUGMENT_CON_2 = 3864; const int FEAT_DRAGON_AUGMENT_CON_3 = 3865; -const int FEAT_DRAGON_AUGMENT_CON_4 = 26394; -const int FEAT_DRAGON_AUGMENT_CON_5 = 26395; -const int FEAT_DRAGON_AUGMENT_CON_6 = 26396; -const int FEAT_DRAGON_AUGMENT_CON_7 = 26397; -const int FEAT_DRAGON_AUGMENT_CON_8 = 26398; -const int FEAT_DRAGON_AUGMENT_CON_9 = 26399; +const int FEAT_DRAGON_AUGMENT_CON_4 = 25661; +const int FEAT_DRAGON_AUGMENT_CON_5 = 25662; +const int FEAT_DRAGON_AUGMENT_CON_6 = 25663; +const int FEAT_DRAGON_AUGMENT_CON_7 = 25664; +const int FEAT_DRAGON_AUGMENT_CON_8 = 25665; +const int FEAT_DRAGON_AUGMENT_CON_9 = 25666; +const int FEAT_DRAGON_AUGMENT_CON_10 = 25667; const int FEAT_CHANNEL_DRACLAWS = 3866; const int FEAT_PSIONIC_BREATH = 3867; @@ -1482,9 +1497,13 @@ const int FEAT_VILE_MARTIAL_MINDBLADE = 3624; const int FEAT_VILE_MARTIAL_WHIP = 3598; const int FEAT_VILE_MARTIAL_TRIDENT = 3599; -// Weapon Focus (Ray) -const int FEAT_WEAPON_FOCUS_RAY = 4819; -const int FEAT_EPIC_WEAPON_FOCUS_RAY = 4820; +//:: Spell-like Weapons +const int FEAT_WEAPON_FOCUS_RAY = 4819; +const int FEAT_EPIC_WEAPON_FOCUS_RAY = 4820; +const int FEAT_IMPROVED_CRITICAL_TOUCH = 26009; +const int FEAT_IMPROVED_CRITICAL_RAY = 26010; +const int FEAT_WEAPON_FOCUS_TOUCH = 26011; +const int FEAT_EPIC_WEAPON_FOCUS_TOUCH = 26012; // Battleguard Tempus const int TEMPUS_ABILITY_ENHANC1 = 1; @@ -3025,6 +3044,7 @@ const int FEAT_SPLIT_PSIONIC_RAY = 4941; const int FEAT_TWIN_POWER = 4942; const int FEAT_WIDEN_POWER = 4943; const int FEAT_QUICKEN_POWER = 4944; +const int FEAT_DEFENSIVE_MANIFESTATION = 2350; // Sanctified Mind const int FEAT_SANCMIND_PARTITION_MIND = 2231; @@ -6335,6 +6355,13 @@ const int FEAT_HIDDEN_TALENT_THICKSKIN = 25944; const int FEAT_HIDDEN_TALENT_VIGOR = 25945; const int FEAT_HIDDEN_TALENT_GRIP_IRON = 25946; +//:: Player's Handbook II feats +const int FEAT_COMBAT_FOCUS = -9999; +const int FEAT_COMBAT_STABILITY = -9998; +const int FEAT_COMBAT_DEFENSE = -9997; +const int FEAT_COMBAT_VIGOR = -9996; +const int FEAT_COMBAT_AWARENESS = -9995; +const int FEAT_COMBAT_STRIKE = -9994; diff --git a/src/include/prc_inc_assoc.nss b/src/include/prc_inc_assoc.nss index 165242d..d88a0fe 100644 --- a/src/include/prc_inc_assoc.nss +++ b/src/include/prc_inc_assoc.nss @@ -244,7 +244,7 @@ void ApplyPseudonatural(object oFamiliar, object oFamSkin) void ApplyIllmaster(object oCompanion, object oCompSkin) { //Give the companion permanent Str +4, Con +2, Wis -2, and Cha -2 - if(GetPRCSwitch(PRC_NWNX_FUNCS)) + if(GetPRCSwitch(PRC_NWNXEE_ENABLED)) { PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_STRENGTH, 4); PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_CONSTITUTION, 2); @@ -305,7 +305,7 @@ void WinterWolfProperties(object oCompanion, int nLevel) object oCreR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCompanion); - if(GetPRCSwitch(PRC_NWNX_FUNCS)) + if(GetPRCSwitch(PRC_NWNXEE_ENABLED)) { if(iStr > 0) PRC_Funcs_ModAbilityScore(oCompanion, ABILITY_STRENGTH, iStr); @@ -358,7 +358,10 @@ void WinterWolfProperties(object oCompanion, int nLevel) void ApplyPnPFamiliarProperties(object oPC, object oFam) { - int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS); + int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED); + int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED); + int bFuncs = (nNWNxEE && nPRCx); + effect eBonus; //get familiar level diff --git a/src/include/prc_inc_breath.nss b/src/include/prc_inc_breath.nss index 094029c..70e1b34 100644 --- a/src/include/prc_inc_breath.nss +++ b/src/include/prc_inc_breath.nss @@ -168,8 +168,8 @@ void ExhaleImmunity(object oDragon, int nDamageType, location lTargetArea) effect eLink = EffectLinkEffects(eImmune, eVis2); //apply effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmune, oTarget, fDuration)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmune, oTarget, fDuration)); } } @@ -603,15 +603,15 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE)) { //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 12.0)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 12.0)); } //1 round otherwise else { //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0)); } } @@ -659,16 +659,16 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE)) { //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSlowDuration))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSlowDuration))); SetLocalInt(oTarget, "AffectedByBreath", TRUE); } //Adept breath effect still lasts for one round if save is made else if(IsAdeptBreath()) { //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1))); SetLocalInt(oTarget, "AffectedByBreath", TRUE); } } @@ -685,10 +685,10 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F //Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally eVis = EffectVisualEffect(VFX_IMP_POISON_L); //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); //adept breath penalty only last 4 rounds on failure, gold breath has no duration if(IsAdeptBreath()) - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 24.0)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 24.0)); else DelayCommand(fDelay, ApplyAbilityDamage(oTarget, ABILITY_STRENGTH, BreathUsed.nDiceNumber, DURATION_TYPE_PERMANENT, TRUE)); SetLocalInt(oTarget, "AffectedByBreath", TRUE); @@ -699,8 +699,8 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F //Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally eVis = EffectVisualEffect(VFX_IMP_POISON_L); //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 12.0)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 12.0)); SetLocalInt(oTarget, "AffectedByBreath", TRUE); } bCanCling = TRUE; @@ -729,7 +729,7 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE)) { //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nParalDuration))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nParalDuration))); SetLocalInt(oTarget, "AffectedByBreath", TRUE); } } @@ -749,8 +749,8 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F eBreath = EffectNegativeLevel(nLevelDrain); eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); SetLocalInt(oTarget, "AffectedByBreath", TRUE); } } @@ -769,11 +769,11 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if (nAdjustedDamage > 0) { //Set Damage and VFX - eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType); + eBreath = PRCEffectDamage(oTarget, nAdjustedDamage, BreathUsed.nDamageType); eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE); //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); SetLocalInt(oTarget, "AffectedByBreath", TRUE); bCanCling = TRUE; } @@ -830,8 +830,8 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if(GetLocalInt(oTarget, "DragonWard")) nAdjustedDamage -= 40; - effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE); - effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC); + effect eBreath1 = PRCEffectDamage(oTarget, nAdjustedDamage/2, DAMAGE_TYPE_FIRE); + effect eBreath2 = PRCEffectDamage(oTarget, nAdjustedDamage/2, DAMAGE_TYPE_SONIC); eBreath = EffectLinkEffects(eBreath1, eBreath2); eVis = EffectVisualEffect(chVisual); } @@ -839,12 +839,12 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F { if(GetLocalInt(oTarget, "DragonWard")) nAdjustedDamage -= 20; - eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType); + eBreath = PRCEffectDamage(oTarget, nAdjustedDamage, BreathUsed.nDamageType); eVis = EffectVisualEffect(nVisualType); } //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); SetLocalInt(oTarget, "AffectedByBreath", TRUE); bCanCling = TRUE; } @@ -859,7 +859,7 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nKnockdownDC, SAVING_THROW_TYPE_NONE)) { effect eWindblown = EffectKnockdown(); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWindblown, oTarget, 6.0)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWindblown, oTarget, 6.0)); } } } @@ -879,10 +879,10 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F //Warforged are only healed for half if(GetIsWarforged(oTarget)) nHeal /= 2; - eBreath = EffectHeal(nHeal); + eBreath = PRCEffectHeal(nHeal, oTarget); effect eHealVis = EffectVisualEffect(VFX_IMP_HEALING_S); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHealVis, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget)); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eHealVis, oTarget)); } //Entangling Exhalation @@ -896,22 +896,22 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F //only does damage if the original breath did damage if(BreathUsed.nDamageType > 0) { - effect eDamage = EffectDamage(d6(), BreathUsed.nDamageType); + effect eDamage = PRCEffectDamage(oTarget, d6(), BreathUsed.nDamageType); switch(nEntangleRounds) { case 4: - DelayCommand(fDelay + RoundsToSeconds(4), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); + DelayCommand(fDelay + RoundsToSeconds(4), SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); case 3: - DelayCommand(fDelay + RoundsToSeconds(3), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); + DelayCommand(fDelay + RoundsToSeconds(3), SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); case 2: - DelayCommand(fDelay + RoundsToSeconds(2), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); + DelayCommand(fDelay + RoundsToSeconds(2), SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); case 1: - DelayCommand(fDelay + RoundsToSeconds(1), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); break; + DelayCommand(fDelay + RoundsToSeconds(1), SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); break; } } //but always entangles if the breath affects the target - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEntangled, oTarget, RoundsToSeconds(nEntangleRounds))); + DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEntangled, oTarget, RoundsToSeconds(nEntangleRounds))); } DeleteLocalInt(oTarget, "AffectedByBreath"); @@ -937,18 +937,18 @@ void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = F { if(nAdjustedDamage < 3) nCount = BreathUsed.nClinging; - effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE); - effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC); + effect eBreath1 = PRCEffectDamage(oTarget, nAdjustedDamage/2, DAMAGE_TYPE_FIRE); + effect eBreath2 = PRCEffectDamage(oTarget, nAdjustedDamage/2, DAMAGE_TYPE_SONIC); effect eAfterBreath = EffectLinkEffects(eBreath1, eBreath2); - DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget)); + DelayCommand(fNewDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget)); } else { if(nAdjustedDamage < 2) nCount = BreathUsed.nClinging; - effect eAfterBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType); - DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget)); + effect eAfterBreath = PRCEffectDamage(oTarget, nAdjustedDamage, BreathUsed.nDamageType); + DelayCommand(fNewDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget)); } - DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); + DelayCommand(fNewDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); } } } @@ -988,3 +988,5 @@ void PRCPlayDragonBattleCry() PlayVoiceChat(VOICE_CHAT_BATTLECRY2); } } + +//:: void main() {} \ No newline at end of file diff --git a/src/include/prc_inc_castlvl.nss b/src/include/prc_inc_castlvl.nss index 0c1a8be..bad5ba2 100644 --- a/src/include/prc_inc_castlvl.nss +++ b/src/include/prc_inc_castlvl.nss @@ -551,7 +551,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) if(!iReturnLevel && GetIsArcaneClass(iCastingClass, oCaster)) { iReturnLevel = GetLevelByClass(iCastingClass, oCaster) / GetCasterLevelModifier(iCastingClass); - + // Casting as a sorc but don't have any levels in the class if(iCastingClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oCaster)) { @@ -576,7 +576,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) } // Casting as a bard but don't have any levels in the class //:: Double-dipping? -/* if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { int nRace = GetRacialType(oCaster); @@ -584,7 +584,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF) //otherwise use RHD instead of bard levels if(nRace == RACIAL_TYPE_GLOURA) iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY); - } */ + } //Spell Rage ability if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster) @@ -797,10 +797,14 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if (nCastingClass == CLASS_TYPE_BARD || GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { + // Don't execute for Gloura Fey spellcasters - they're handled in the Fey section + if(GetRacialType(oCaster) == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + return nArcane; + //:: Includes RHD as bard. If they started with bard levels, then it //:: counts as a prestige class, otherwise RHD is used instead of bard levels. if(nRace == RACIAL_TYPE_GLOURA) - nArcane += GetLevelByClass(CLASS_TYPE_FEY, oCaster); + nArcane += GetLevelByClass(CLASS_TYPE_FEY, oCaster); if(GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_BARD, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster); @@ -960,7 +964,7 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) } //:: End Bard Arcane PrC casting calculations - if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_FEY && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)"); diff --git a/src/include/prc_inc_chat_dm.nss b/src/include/prc_inc_chat_dm.nss index 45596a1..28d8c92 100644 --- a/src/include/prc_inc_chat_dm.nss +++ b/src/include/prc_inc_chat_dm.nss @@ -480,7 +480,7 @@ int Debug_ProcessChatCommand(object oPC, string sCommand) HelpText(oPC, "=== INT: " + IntToString(GetAbilityScore(oTarget, ABILITY_INTELLIGENCE, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_INTELLIGENCE, FALSE))); HelpText(oPC, "=== WIS: " + IntToString(GetAbilityScore(oTarget, ABILITY_WISDOM, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_WISDOM, FALSE))); HelpText(oPC, "=== CHA: " + IntToString(GetAbilityScore(oTarget, ABILITY_CHARISMA, TRUE)) + " / " + IntToString(GetAbilityScore(oTarget, ABILITY_CHARISMA, FALSE))); - if (GetPersistantLocalInt(oTarget, SHIFTER_ISSHIFTED_MARKER) && GetPRCSwitch(PRC_NWNX_FUNCS)) + if (GetPersistantLocalInt(oTarget, SHIFTER_ISSHIFTED_MARKER) && GetPRCSwitch(PRC_NWNXEE_ENABLED)) { int iSTR = GetPersistantLocalInt(oTarget, "Shifting_NWNXSTRAdjust"); int iDEX = GetPersistantLocalInt(oTarget, "Shifting_NWNXDEXAdjust"); @@ -664,7 +664,7 @@ int Debug_ProcessChatCommand(object oPC, string sCommand) } /* else if (GetStringMatchesAbbreviation(sChangeWhat, CMD_ABILITY)) { - if (!GetPRCSwitch(PRC_NWNX_FUNCS)) + if (!GetPRCSwitch(PRC_NWNXEE_ENABLED)) HelpText(oPC, "This command only works if NWNX funcs is installed"); else { diff --git a/src/include/prc_inc_combat.nss b/src/include/prc_inc_combat.nss index 6b143b5..e36d5c9 100644 --- a/src/include/prc_inc_combat.nss +++ b/src/include/prc_inc_combat.nss @@ -265,7 +265,8 @@ struct WeaponFeat GetAllFeatsOfWeaponType(int iWeaponType); // Returns the low end of oWeap's critical threat range // Accounts for Keen and Improved Critical bonuses -int GetWeaponCriticalRange(object oPC, object oWeap); +//int GetWeaponCriticalRange(object oPC, object oWeap); +int GetWeaponCriticalRange(object oPC, object oWeap, int iTouchAttackType = FALSE); // returns the critical multiplier of the weapons base type int GetCriticalMultiplierOfWeaponType(int iWeaponType); @@ -1999,11 +2000,37 @@ object GetAmmunitionFromWeapon(object oWeapon, object oAttacker) return GetAmmunitionFromWeaponType(GetBaseItemType(oWeapon), oAttacker); } -int GetWeaponCriticalRange(object oPC, object oWeap) +//int GetWeaponCriticalRange(object oPC, object oWeap) // for a ranged weapon we should call this *after* we have ammo equipped, because it checks the ammo for keen // if we (re)equip the ammo later, we don't get the right keen property +int GetWeaponCriticalRange(object oPC, object oWeap, int iTouchAttackType = FALSE) { - //no weapon, touch attacks mainly + // Check for spell-based touch attacks + if(iTouchAttackType == TOUCH_ATTACK_MELEE_SPELL) + { + if (DEBUG) DoDebug("prc_inc_combat >> GetWeaponCriticalRange() | TOUCH_ATTACK_MELEE_SPELL detected."); + // Spell-based melee touch attacks + if(GetHasFeat(FEAT_IMPROVED_CRITICAL_TOUCH, oPC)) + { + if (DEBUG) DoDebug("prc_inc_combat >> GetWeaponCriticalRange() | Improved Critical: Touch detected."); + return 19; // Doubles threat range from 20 to 19-20 + } + else + return 20; + } + else if(iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL) + { + if (DEBUG) DoDebug("prc_inc_combat >> GetWeaponCriticalRange() | TOUCH_ATTACK_RANGED_SPELL detected."); + // Ray attacks + if(GetHasFeat(FEAT_IMPROVED_CRITICAL_RAY, oPC)) + { + if (DEBUG) DoDebug("prc_inc_combat >> GetWeaponCriticalRange() | Improved Critical: Ray detected."); + return 19; // Doubles threat range from 20 to 19-20 + } + else + return 20; + } + //no weapon, touch attacks mainly if(!GetIsObjectValid(oWeap)) return 20; @@ -3306,7 +3333,33 @@ int GetAttackBonus(object oDefender, object oAttacker, object oWeap, int iOffhan // weapon specific feats sWeaponFeat = GetAllFeatsOfWeaponType(iWeaponType); - int bFocus = 0; + int bFocus = 0; + int bEpicFocus = 0; + int bIsRangedTouchAttack = iTouchAttackType == TOUCH_ATTACK_RANGED || iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL; + int bIsMeleeTouchAttack = iTouchAttackType == TOUCH_ATTACK_MELEE_SPELL; + + if(bIsRangedTouchAttack) + { + // Weapon Focus(Ray) applies to ranged touch attacks + bFocus = GetHasFeat(FEAT_WEAPON_FOCUS_RAY, oAttacker); + if (bFocus) // no need to look for epic focus, if we don't have focus + bEpicFocus = GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_RAY, oAttacker); + } + else if(bIsMeleeTouchAttack) + { + // Weapon Focus(Touch Attack) applies to melee touch attacks + bFocus = GetHasFeat(FEAT_WEAPON_FOCUS_TOUCH, oAttacker); + if (bFocus) // no need to look for epic focus, if we don't have focus + bEpicFocus = GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_TOUCH, oAttacker); + } + else + { // no touch attack, normal weapon focus feats + bFocus = GetHasFeat(sWeaponFeat.Focus, oAttacker); + if (bFocus) // no need to look for epic focus, if we don't have focus + bEpicFocus = GetHasFeat(sWeaponFeat.EpicFocus, oAttacker); + } + +/* int bFocus = 0; int bEpicFocus = 0; int bIsRangedTouchAttack = iTouchAttackType == TOUCH_ATTACK_RANGED || iTouchAttackType == TOUCH_ATTACK_RANGED_SPELL; @@ -3322,7 +3375,7 @@ int GetAttackBonus(object oDefender, object oAttacker, object oWeap, int iOffhan bFocus = GetHasFeat(sWeaponFeat.Focus, oAttacker); if (bFocus) // no need to look for epic focus, if we don't have focus bEpicFocus = GetHasFeat(sWeaponFeat.EpicFocus, oAttacker); - } + } */ int bEpicProwess = GetHasFeat(FEAT_EPIC_PROWESS, oAttacker); @@ -3937,7 +3990,7 @@ int GetAttackRoll(object oDefender, object oAttacker, object oWeapon, int iOffha //if (bDebug) sDebugFeedback = COLOR_WHITE + "Attack Roll = " + IntToString(iAttackBonus + iDiceRoll) + ": " + sDebugFeedback; //if (DEBUG) DoDebug("GetAttackRoll: End Section #1"); int iWeaponType = GetBaseItemType(oWeapon); - int iCritThreat = GetWeaponCriticalRange(oAttacker, oWeapon); + int iCritThreat = GetWeaponCriticalRange(oAttacker, oWeapon, iTouchAttackType); //If using Killing Shot, ciritical range improves by 2; if(GetLocalInt(oAttacker, "KillingShotCritical") ) diff --git a/src/include/prc_inc_combmove.nss b/src/include/prc_inc_combmove.nss index 180925b..4b2bf11 100644 --- a/src/include/prc_inc_combmove.nss +++ b/src/include/prc_inc_combmove.nss @@ -355,6 +355,16 @@ int _DoGrappleCheck(object oPC, object oTarget, int nExtraBonus, int nSwitch = - int nPCCheck = nPCBAB + nPCStr + nPCBonus + d20(); int nTargetCheck = nTargetBAB + nTargetStr + nTargetBonus + d20(); + + if (DEBUG) + { + DoDebug("Grapple Check - " + GetName(oPC) + ": " + IntToString(nPCCheck) + + " vs " + GetName(oTarget) + ": " + IntToString(nTargetCheck)); + DoDebug("PC BAB:" + IntToString(nPCBAB) + " STR:" + IntToString(nPCStr) + + " Bonus:" + IntToString(nPCBonus)); + DoDebug("Target BAB:" + IntToString(nTargetBAB) + " STR:" + IntToString(nTargetStr) + + " Bonus:" + IntToString(nTargetBonus)); + } // Now roll the ability check SendMessageToPC(oPC, "PC Grapple Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (GetIsPC(oTarget)) @@ -1502,7 +1512,46 @@ int DoGrapple(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TR { FloatingTextStringOnCreature("You have successfully grappled " + GetName(oTarget), oPC, FALSE); int nBearFang = GetLocalInt(oPC, "BearFangGrapple"); - SetGrapple(oPC); + + SetGrapple(oPC); + SetGrapple(oTarget); + SetLocalInt(oPC, "GrappleOriginator", TRUE); + SetLocalObject(oTarget, "GrappledBy", oPC); + SetGrappleTarget(oPC, oTarget); + + if (DEBUG) + { + DoDebug("DoGrapple: Set grapple state for " + GetName(oPC) + " -> " + GetName(oTarget)); + DoDebug("DoGrapple: oPC IsGrappled = " + IntToString(GetLocalInt(oPC, "IsGrappled"))); + DoDebug("DoGrapple: oTarget IsGrappled = " + IntToString(GetLocalInt(oTarget, "IsGrappled"))); + DoDebug("DoGrapple: oPC GrappleTarget = " + GetName(GetLocalObject(oPC, "GrappleTarget"))); + } + + effect eHold = EffectCutsceneParalyze(); + effect eEntangle = EffectVisualEffect(VFX_DUR_SPELLTURNING_R); + effect eLink = EffectLinkEffects(eHold, eEntangle); + + if (!GetLocalInt(oPC, "Flay_Grapple")) + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oPC, 9999.0); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oTarget, 9999.0); + + nSucceed = TRUE; + + if (nBearFang) + { + //DelayCommand(0.1, PerformAttack(oTarget, oPC, eNone, 0.0, -4, 0, 0, "Bear Fang Attack Hit", "Bear Fang Attack Miss")); + PerformAttack(oTarget, oPC, eNone, 0.0, -4, 0, 0, "Bear Fang Attack Hit", "Bear Fang Attack Miss"); + DeleteLocalInt(oPC, "BearFangGrapple"); + } + else + { + object oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); + effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); + //DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); // Delay damage + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); + } + +/* SetGrapple(oPC); SetGrapple(oTarget); SetLocalInt(oPC, "GrappleOriginator", TRUE); effect eHold = EffectCutsceneParalyze(); @@ -1526,23 +1575,43 @@ int DoGrapple(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TR effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); } - _HeartOfFireGrapple(oPC, oTarget); + */ _HeartOfFireGrapple(oPC, oTarget); // If you kill them with this, best to clean up right away if (GetIsDead(oTarget) || !GetIsObjectValid(oTarget)) { EndGrapple(oPC, oTarget); // Remove the hooks - if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); + if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); FloatingTextStringOnCreature("Your target is dead, ending grapple", oPC, FALSE); } else { - // Hook in the events and save the target for an ongoing grapple - if(DEBUG) DoDebug("prc_grapple: Adding eventhooks"); - SetGrappleTarget(oPC, oTarget); - AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + // //::Hook in the events and save the target for an ongoing grapple + // if(DEBUG) DoDebug("prc_grapple: Adding eventhooks"); + // SetGrappleTarget(oPC, oTarget); + // AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + + // Hook in the events and save the target for an ongoing grapple + if(DEBUG) DoDebug("prc_grapple: Adding eventhooks"); + SetGrappleTarget(oPC, oTarget); + + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + { + AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + if(DEBUG) DoDebug("DoGrapple: Set Heartbeat event for " + GetName(oPC)); + } + else + { + // For summons, set a flag that prc_npc_hb.nss can check + SetLocalInt(oPC, "GrappleHeartbeatTimer", 1); + if(DEBUG) DoDebug("DoGrapple: Set GrappleHeartbeatTimer for " + GetName(oPC)); + + // Add this debug to verify the timer was set + if(DEBUG) DoDebug("DoGrapple: Verification - GrappleHeartbeatTimer = " + + IntToString(GetLocalInt(oPC, "GrappleHeartbeatTimer"))); + } } } else @@ -1555,12 +1624,16 @@ int DoGrapple(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TR void SetGrapple(object oTarget) { - SetLocalInt(oTarget, "IsGrappled", TRUE); + if(DEBUG) DoDebug("SetGrapple called on " + GetName(oTarget)); + SetLocalInt(oTarget, "IsGrappled", TRUE); } int GetGrapple(object oTarget) { - return GetLocalInt(oTarget, "IsGrappled"); + int nResult = GetLocalInt(oTarget, "IsGrappled"); + if(DEBUG) DoDebug("GetGrapple(" + GetName(oTarget) + ") = " + IntToString(nResult)); + return nResult; + //return GetLocalInt(oTarget, "IsGrappled"); } void SetGrappleTarget(object oPC, object oTarget) @@ -1591,16 +1664,20 @@ void BreakPin(object oTarget) void EndGrapple(object oPC, object oTarget) { - DeleteLocalInt(oPC, "IsGrappled"); + if(DEBUG) DoDebug("EndGrapple called for " + GetName(oPC) + " -> " + GetName(oTarget)); + + DeleteLocalInt(oPC, "IsGrappled"); DeleteLocalInt(oTarget, "IsGrappled"); + DeleteLocalInt(oPC, "GrappleHeartbeatTimer"); DeleteLocalInt(oTarget, "PinnedRounds"); DeleteLocalObject(oPC, "GrappleTarget"); + DeleteLocalObject(oTarget, "GrappledBy"); DeleteLocalInt(oTarget, "UnconsciousGrapple"); DeleteLocalInt(oPC, "GrappleOriginator"); DeleteLocalInt(oPC, "ScorpionLight"); DeleteLocalInt(oPC, "Flay_Grapple"); RemoveEventScript(oPC, EVENT_ITEM_ONHIT, "wol_m_flay", TRUE, FALSE); - BreakPin(oTarget); + BreakPin(oTarget); effect eBad = GetFirstEffect(oTarget); //Search for negative effects while(GetIsEffectValid(eBad)) @@ -1679,6 +1756,20 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = int nPen = -4; if (GetLocalInt(oPC, "ScorpionLight")) nPen = 0; DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, nPen, 0, 0, "Grapple Light Weapon Attack Hit", "Grapple Light Weapon Attack Miss")); + + if (GetIsDead(oPC) || GetIsDead(oTarget) || !GetIsObjectValid(oPC) || !GetIsObjectValid(oTarget)) + { + EndGrapple(oPC, oTarget); + //RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + else + DeleteLocalInt(oPC, "PRC_GrappleActive"); + + if (GetIsDead(oPC)) FloatingTextStringOnCreature("You have died, ending grapple", oPC, FALSE); + if (GetIsDead(oTarget)) FloatingTextStringOnCreature("Your target is dead, ending grapple", oPC, FALSE); + return nSuccess; + } } } else @@ -1730,6 +1821,7 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = // Now hit them with an unarmed strike object oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); FloatingTextStringOnCreature("Grapple Unarmed Damage Hit",oPC, FALSE); } @@ -1743,6 +1835,21 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam), oTarget); FloatingTextStringOnCreature("Zagan Constrict Hit",oPC, FALSE); } + + if (GetIsDead(oPC) || GetIsDead(oTarget) || !GetIsObjectValid(oPC) || !GetIsObjectValid(oTarget)) + { + EndGrapple(oPC, oTarget); + //RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + else + DeleteLocalInt(oPC, "PRC_GrappleActive"); + + if (GetIsDead(oPC)) FloatingTextStringOnCreature("You have died, ending grapple", oPC, FALSE); + if (GetIsDead(oTarget)) FloatingTextStringOnCreature("Your target is dead, ending grapple", oPC, FALSE); + return nSuccess; + } } else if (nSwitch == GRAPPLE_ESCAPE) { @@ -1765,14 +1872,24 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = { // Remove the hooks if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); - RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + //RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + else + DeleteLocalInt(oPC, "PRC_GrappleActive"); + FloatingTextStringOnCreature("You have escaped the grapple", oPC, FALSE); } else { // Remove the hooks if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); - RemoveEventScript(oTarget, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + //RemoveEventScript(oTarget, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + else + DeleteLocalInt(oPC, "PRC_GrappleActive"); + FloatingTextStringOnCreature("Your target has escaped your grapple", oTarget, FALSE); // Target is valid and we know it's an enemy and we're in combat DelayCommand(0.25, AssignCommand(oTarget, ActionAttack(oPC))); @@ -1830,6 +1947,22 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING), oTarget); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACDecrease(4)), oPC, 6.0); } + else + FloatingTextStringOnCreature("You have failed your Grapple Pin Attempt",oPC, FALSE); + + if (GetIsDead(oPC) || GetIsDead(oTarget) || !GetIsObjectValid(oPC) || !GetIsObjectValid(oTarget)) + { + EndGrapple(oPC, oTarget); + //RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + if(GetIsPC(oPC) || GetIsDMPossessed(oPC)) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + else + DeleteLocalInt(oPC, "PRC_GrappleActive"); + + if (GetIsDead(oPC)) FloatingTextStringOnCreature("You have died, ending grapple", oPC, FALSE); + if (GetIsDead(oTarget)) FloatingTextStringOnCreature("Your target is dead, ending grapple", oPC, FALSE); + return nSuccess; + } } else FloatingTextStringOnCreature("You have failed your Grapple Pin Attempt",oPC, FALSE); @@ -1844,6 +1977,54 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = return nSuccess; } +int OptimalGrapple(object oPC, object oTarget) +{ + int nMauler = GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC); + int nBBC = GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oPC); + int nDC = 10 + nMauler + GetAbilityModifier(ABILITY_WISDOM, oPC); + + if (GetLocalInt(oPC, "Flay_Grapple")) + return GRAPPLE_DAMAGE; + + // You need a greater than 10% chance of it happening to trigger these options + if (nMauler && (nDC > GetFortitudeSavingThrow(oTarget) + 2)) + { + if (nMauler == 5 && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) // Devastating Grapple + return GRAPPLE_PIN; + if (nMauler >= 3 && !GetLocalInt(oTarget, "UnconsciousGrapple") && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) // Target isn't unconscious + return GRAPPLE_PIN; + } + if (GetHasSpellEffect(MOVE_SD_CRUSHING_WEIGHT, oPC)) + return GRAPPLE_TOB_CRUSHING; + if ((nBBC >= 8 && GetHasSpellEffect(SPELLABILITY_BARBARIAN_RAGE, oPC)) || nBBC >= 10 || GetHasSpellEffect(VESTIGE_ZAGAN, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_ZAGAN_CONSTRICT) + return GRAPPLE_DAMAGE; + if (GetIsMeldBound(oPC, MELD_RAGECLAWS) == CHAKRA_TOTEM) + return GRAPPLE_ATTACK; + // You've got an ability that wants a light weapon + if (GetHasSpellEffect(MOVE_TC_WOLVERINE_STANCE, oPC) || GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) || GetLocalInt(oPC, "ScorpionLight")) + return GRAPPLE_ATTACK; + if (GetHasFeat(FEAT_EARTHS_EMBRACE, oPC) && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) // Earth's Embrace + return GRAPPLE_PIN; + + if (FindUnarmedDamage(oPC) > 2) + return GRAPPLE_DAMAGE; + + object oPCWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); + object oMonster = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); + int nPCGold; + int nMonster; + + if(GetIsLightWeapon(oTarget)) nMonster = GetGoldPieceValue(oMonster); + if(GetIsLightWeapon(oPC)) nPCGold = GetGoldPieceValue(oPCWeapon); + if (nMonster > nPCGold) + return GRAPPLE_OPPONENT_WEAPON; + else if (GetIsLightWeapon(oPC)) + return GRAPPLE_ATTACK; + + return GRAPPLE_DAMAGE; +} + + int GetIsLightWeapon(object oPC) { // You may use any weapon in a grapple with this stance. diff --git a/src/include/prc_inc_core.nss b/src/include/prc_inc_core.nss index df73451..b3b34a0 100644 --- a/src/include/prc_inc_core.nss +++ b/src/include/prc_inc_core.nss @@ -7,6 +7,8 @@ /* Function Prototypes */ ////////////////////////////////////////////////// +string GetSpellsKnown_Array(int nClass, int nSpellLevel = -1); + //:: Returns true if oCaster's race can naturally cast sorcerer spells. int GetIsRHDSorcerer(object oCaster = OBJECT_SELF); @@ -680,8 +682,36 @@ int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJ // at this stage, prepared casters know the spell and only spontaneous classes need checking // there are exceptions and these need hardcoding: - if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST) - return TRUE; + // Archivist special case - check both feats and persistant arrays + if (nClass == CLASS_TYPE_ARCHIVIST) + { + // First check feat system (for backward compatibility) + int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookSpell)); + if (GetHasFeat(nFeatID, oPC)) + return TRUE; + + // Then check persistant spell arrays using GetSpellsKnown_Array() + int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookSpell)); + string sSpellbookArray = GetSpellsKnown_Array(nClass, nSpellLevel); + + int nSize = persistant_array_get_size(oPC, sSpellbookArray); + int i; + for (i = 0; i < nSize; i++) + { + int nStoredSpellbookID = persistant_array_get_int(oPC, sSpellbookArray, i); + if (nStoredSpellbookID == nSpellbookSpell) + return TRUE; + } + + return FALSE; + } + + // Other prepared casters use original logic + if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST) + return TRUE; + +/* if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST) + return TRUE; */ // spontaneous casters have all their known spells as hide feats // get the featID of the spell diff --git a/src/include/prc_inc_function.nss b/src/include/prc_inc_function.nss index a3b24e5..c7d6804 100644 --- a/src/include/prc_inc_function.nss +++ b/src/include/prc_inc_function.nss @@ -187,6 +187,7 @@ void SetupCharacterData(object oPC) case CLASS_TYPE_MASTER_OF_SHADOW: sScript = "shd_mastershadow"; break; case CLASS_TYPE_MIGHTY_CONTENDER_KORD: sScript = "prc_contendkord"; break; case CLASS_TYPE_MORNINGLORD: sScript = "prc_morninglord"; break; + case CLASS_TYPE_MONK: sScript = "prc_monk"; break; case CLASS_TYPE_NIGHTSHADE: sScript = "prc_nightshade"; break; case CLASS_TYPE_NINJA: sScript = "prc_ninjca"; break; case CLASS_TYPE_OLLAM: sScript = "prc_ollam"; break; @@ -366,7 +367,7 @@ void EvalPRCFeats(object oPC) SetLocalInt(oPC, PRC_EvalPRCFeats_Generation, nGeneration); //permanent ability changes - if(GetPRCSwitch(PRC_NWNX_FUNCS)) + if(GetPRCSwitch(PRC_NWNXEE_ENABLED)) ExecuteScript("prc_nwnx_funcs", oPC); //Add IP Feats to the hide @@ -1571,7 +1572,7 @@ void BarbarianRage(object oPC) if (nLevel > 0) { // Spell Rage: starts at 1st level, +1 use every 5 Rage Mage levels - int nUses = 1 + ((nLevel - 1) / 5); + int nUses = 1 + (nLevel / 5); FeatUsePerDay(oPC, FEAT_SPELL_RAGE, -1, nUses); } diff --git a/src/include/prc_inc_json.nss b/src/include/prc_inc_json.nss index f15c675..cf5824b 100644 --- a/src/include/prc_inc_json.nss +++ b/src/include/prc_inc_json.nss @@ -582,8 +582,6 @@ effect CelestialTemplateEffects(int nHD) return eEffects; } - - void ReallyEquipItemInSlot(object oNPC, object oItem, int nSlot) { if (GetItemInSlot(nSlot) != oItem) @@ -688,6 +686,148 @@ void ApplyPseudonaturalEffects(object oCreature) //:: JSON functions | //::---------------------------------------------| +//:: Get the first spell ID that a creature knows (not memorized, but known) +//:: Returns -1 if no spells are found +int json_GetFirstKnownSpell(json jCreature) +{ + // Store the creature JSON for later use by GetNext + SetLocalJson(GetModule(), "JSON_SPELL_CREATURE", jCreature); + SetLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX", 0); + SetLocalInt(GetModule(), "JSON_SPELL_LEVEL", 0); + SetLocalInt(GetModule(), "JSON_SPELL_INDEX", 0); + + // Get the ClassList + json jClassList = GffGetList(jCreature, "ClassList"); + if (jClassList == JsonNull()) + { + if(DEBUG) DoDebug("json_GetFirstKnownSpell: No ClassList found"); + return -1; + } + + int nClassCount = JsonGetLength(jClassList); + int iClass, iSpellLevel, iSpell; + + // Iterate through all classes + for (iClass = 0; iClass < nClassCount; iClass++) + { + json jClass = JsonArrayGet(jClassList, iClass); + if (jClass == JsonNull()) continue; + + // Check all spell levels (0-9) + for (iSpellLevel = 0; iSpellLevel <= 9; iSpellLevel++) + { + string sKnownList = "KnownList" + IntToString(iSpellLevel); + json jKnownList = GffGetList(jClass, sKnownList); + if (jKnownList == JsonNull()) continue; + + int nSpellCount = JsonGetLength(jKnownList); + + // Look for the first spell + for (iSpell = 0; iSpell < nSpellCount; iSpell++) + { + json jSpell = JsonArrayGet(jKnownList, iSpell); + if (jSpell == JsonNull()) continue; + + json jSpellID = GffGetWord(jSpell, "Spell"); + if (jSpellID != JsonNull()) + { + int nSpellID = JsonGetInt(jSpellID); + + // Update tracking variables for next call + SetLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX", iClass); + SetLocalInt(GetModule(), "JSON_SPELL_LEVEL", iSpellLevel); + SetLocalInt(GetModule(), "JSON_SPELL_INDEX", iSpell + 1); + + return nSpellID; + } + } + } + } + + // Clean up when done + DeleteLocalJson(GetModule(), "JSON_SPELL_CREATURE"); + DeleteLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX"); + DeleteLocalInt(GetModule(), "JSON_SPELL_LEVEL"); + DeleteLocalInt(GetModule(), "JSON_SPELL_INDEX"); + + return -1; // No more spells found +} + +//:: Get the next spell ID from the creature's known spells +//:: Returns -1 if no more spells are found +int json_GetNextKnownSpell() +{ + json jCreature = GetLocalJson(GetModule(), "JSON_SPELL_CREATURE"); + if (jCreature == JsonNull()) + return -1; + + int nClassIndex = GetLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX"); + int nSpellLevel = GetLocalInt(GetModule(), "JSON_SPELL_LEVEL"); + int nSpellIndex = GetLocalInt(GetModule(), "JSON_SPELL_INDEX"); + + // Get the ClassList + json jClassList = GffGetList(jCreature, "ClassList"); + if (jClassList == JsonNull()) + return -1; + + int nClassCount = JsonGetLength(jClassList); + int iClass, iSpellLevel, iSpell; + + // Continue from where we left off + for (iClass = nClassIndex; iClass < nClassCount; iClass++) + { + json jClass = JsonArrayGet(jClassList, iClass); + if (jClass == JsonNull()) continue; + + // Check all spell levels (0-9) + for (iSpellLevel = nSpellLevel; iSpellLevel <= 9; iSpellLevel++) + { + string sKnownList = "KnownList" + IntToString(iSpellLevel); + json jKnownList = GffGetList(jClass, sKnownList); + if (jKnownList == JsonNull()) continue; + + int nSpellCount = JsonGetLength(jKnownList); + + // Start from saved index if same class and level, otherwise start from 0 + int nStartIndex = (iClass == nClassIndex && iSpellLevel == nSpellLevel) ? nSpellIndex : 0; + + for (iSpell = nStartIndex; iSpell < nSpellCount; iSpell++) + { + json jSpell = JsonArrayGet(jKnownList, iSpell); + if (jSpell == JsonNull()) continue; + + json jSpellID = GffGetWord(jSpell, "Spell"); + if (jSpellID != JsonNull()) + { + int nSpellID = JsonGetInt(jSpellID); + + // Update tracking variables for next call + SetLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX", iClass); + SetLocalInt(GetModule(), "JSON_SPELL_LEVEL", iSpellLevel); + SetLocalInt(GetModule(), "JSON_SPELL_INDEX", iSpell + 1); + + return nSpellID; + } + } + + // Reset spell index for next spell level + nSpellIndex = 0; + } + + // Reset spell level for next class + nSpellLevel = 0; + } + + // Clean up when done + DeleteLocalJson(GetModule(), "JSON_SPELL_CREATURE"); + DeleteLocalInt(GetModule(), "JSON_SPELL_CLASS_INDEX"); + DeleteLocalInt(GetModule(), "JSON_SPELL_LEVEL"); + DeleteLocalInt(GetModule(), "JSON_SPELL_INDEX"); + + return -1; // No more spells found +} + + //:: Returns the Constitution value from a GFF creature UTC int json_GetCONValue(json jCreature) { diff --git a/src/include/prc_inc_leadersh.nss b/src/include/prc_inc_leadersh.nss index 32b67a5..b176133 100644 --- a/src/include/prc_inc_leadersh.nss +++ b/src/include/prc_inc_leadersh.nss @@ -249,7 +249,7 @@ void CancelGreatFeats(object oSpawn) else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_1, oSpawn)) nGreatCha = 1; //apply penalties to counter the GreatX feats - if(GetPRCSwitch(PRC_NWNX_FUNCS)) + if(GetPRCSwitch(PRC_NWNXEE_ENABLED)) { if(nGreatStr) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_STRENGTH, -nGreatStr); if(nGreatDex) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_DEXTERITY, -nGreatDex); diff --git a/src/include/prc_inc_nat_hb.nss b/src/include/prc_inc_nat_hb.nss index 10bc2fb..ce710e0 100644 --- a/src/include/prc_inc_nat_hb.nss +++ b/src/include/prc_inc_nat_hb.nss @@ -174,20 +174,31 @@ void DoNaturalAttack(object oWeapon) if(DEBUG) DoDebug(PRC_TEXT_WHITE + "initiating a secondary natural attack with "+GetName(oWeapon)+", attack mod " + IntToString(nAttackMod) + ", nStrHalf " + IntToString(nStrHalf)); PerformAttack(oTarget, - oPC, // - eInvalid, //effect eSpecialEffect, - 0.0, //float eDuration = 0.0 - nAttackMod, //int iAttackBonusMod = 0 - nStrHalf, //int iDamageModifier = Half strength - DAMAGE_TYPE_SLASHING, //int iDamageType = DAMAGE_TYPE_SLASHING, otherwise it uses magical damage. - sMessageSuccess, //sMessageSuccess - sMessageFailure, //sMessageFailure - FALSE, //int iTouchAttackType = FALSE - oWeaponR, // we should have something in the right hand (might need it for some calculations) - oWeapon, // we put the creature weapon in the left hand slot - FALSE, //offhand override (for half strength) - bCombatMode // prc scripted combat mode - ); + oPC, // + eInvalid, //effect eSpecialEffect, + 0.0, //float eDuration = 0.0 + nAttackMod, //int iAttackBonusMod = 0 + nStrHalf, //int iDamageModifier = Half strength + DAMAGE_TYPE_SLASHING, //int iDamageType = DAMAGE_TYPE_SLASHING, otherwise it uses magical damage. + sMessageSuccess, //sMessageSuccess + sMessageFailure, //sMessageFailure + FALSE, //int iTouchAttackType = FALSE + oWeaponR, // we should have something in the right hand (might need it for some calculations) + oWeapon, // we put the creature weapon in the left hand slot + FALSE, //offhand override (for half strength) + bCombatMode // prc scripted combat mode + ); + + //:: onHit processing for secondary natural attacks + if(GetLocalInt(oPC, "PRCCombat_StruckByAttack")) + { + // Apply onHit abilities from the creature weapon + ApplyAllOnHitCastSpellsOnItemExcludingSubType( + IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, oTarget, oWeapon, oPC); + + // Clear the combat struck flag + DeleteLocalInt(oPC, "PRCCombat_StruckByAttack"); + } } void DoOffhandAttack(int nAttackMod) diff --git a/src/include/prc_inc_nwscript.nss b/src/include/prc_inc_nwscript.nss index 4671756..e4599c0 100644 --- a/src/include/prc_inc_nwscript.nss +++ b/src/include/prc_inc_nwscript.nss @@ -9,6 +9,8 @@ const int PRC_SIZEMASK_SIMPLE = 4; // 'simple' size changes that have si const int PRC_SIZEMASK_ALL = 7; // PRC_SIZEMASK_NORMAL | PRC_SIZEMASK_NOABIL | PRC_SIZEMASK_SIMPLE +const int PRC_SIZEMASK_PRC = 0x08; // For systems that need PRC size scale + //wrapper for biowares GetSpellId() //used for actioncastspell int PRCGetSpellId(object oCaster = OBJECT_SELF); @@ -559,7 +561,6 @@ int PRCGetCreatureSize(object oObject = OBJECT_SELF, int nSizeMask = PRC_SIZEMAS if (DEBUG) DoDebug("PRCGetCreatureSize, returning size: "+IntToString(nSize)); return nSize; } - int GetIsChakraBound(object oMeldshaper, int nChakra) { int nTest = GetLocalInt(oMeldshaper, "BoundMeld"+IntToString(nChakra)); diff --git a/src/include/prc_inc_racial.nss b/src/include/prc_inc_racial.nss index 101d794..a546faf 100644 --- a/src/include/prc_inc_racial.nss +++ b/src/include/prc_inc_racial.nss @@ -97,7 +97,9 @@ int GetIsWarforged(object oCreature) { int nRace = GetRacialType(oCreature); - if (nRace == RACIAL_TYPE_WARFORGED || nRace == RACIAL_TYPE_WARFORGED_CHARGER) return TRUE; + if (nRace == RACIAL_TYPE_WARFORGED || + nRace == RACIAL_TYPE_WARFORGED_CHARGER || + nRace == RACIAL_TYPE_WARFORGED_SCOUT) return TRUE; return FALSE; } \ No newline at end of file diff --git a/src/include/prc_inc_shifting.nss b/src/include/prc_inc_shifting.nss index 1e0fadc..7426c69 100644 --- a/src/include/prc_inc_shifting.nss +++ b/src/include/prc_inc_shifting.nss @@ -2459,6 +2459,7 @@ int GetCanShiftIntoCreature(object oShifter, int nShifterType, object oTemplate) nRacialType == RACIAL_TYPE_HALFELF || nRacialType == RACIAL_TYPE_HALFLING || nRacialType == RACIAL_TYPE_HUMANOID_ORC || + nRacialType == RACIAL_TYPE_HUMANOID_GOBLINOID || nRacialType == RACIAL_TYPE_HUMANOID_REPTILIAN )) { @@ -2488,6 +2489,7 @@ int GetCanShiftIntoCreature(object oShifter, int nShifterType, object oTemplate) nRacialType == RACIAL_TYPE_HALFELF || nRacialType == RACIAL_TYPE_HALFLING || nRacialType == RACIAL_TYPE_HUMANOID_ORC || + nRacialType == RACIAL_TYPE_HUMANOID_GOBLINOID || nRacialType == RACIAL_TYPE_HUMANOID_REPTILIAN )) { @@ -2523,6 +2525,7 @@ int GetCanShiftIntoCreature(object oShifter, int nShifterType, object oTemplate) nTargetRacialType == RACIAL_TYPE_HALFORC || nTargetRacialType == RACIAL_TYPE_HALFELF || nTargetRacialType == RACIAL_TYPE_HALFLING || + nTargetRacialType == RACIAL_TYPE_HUMANOID_GOBLINOID || nTargetRacialType == RACIAL_TYPE_HUMANOID_ORC || nTargetRacialType == RACIAL_TYPE_HUMANOID_REPTILIAN ) && @@ -2533,6 +2536,7 @@ int GetCanShiftIntoCreature(object oShifter, int nShifterType, object oTemplate) nShifterRacialType == RACIAL_TYPE_HALFORC || nShifterRacialType == RACIAL_TYPE_HALFELF || nShifterRacialType == RACIAL_TYPE_HALFLING || + nShifterRacialType == RACIAL_TYPE_HUMANOID_GOBLINOID || nShifterRacialType == RACIAL_TYPE_HUMANOID_ORC || nShifterRacialType == RACIAL_TYPE_HUMANOID_REPTILIAN )) @@ -3094,7 +3098,7 @@ void HandleApplyShiftTemplate(object oPC) int PnPShifterFeats() { - if(GetPRCSwitch(PRC_NWNX_FUNCS)) + if(GetPRCSwitch(PRC_NWNXEE_ENABLED)) { //If any stats have been changed by NWNX, this could qualify the PC for feats they should //not actually qualify for, so force unshifting before levelling up. diff --git a/src/include/prc_inc_skills.nss b/src/include/prc_inc_skills.nss index 1bfc354..5c70f5f 100644 --- a/src/include/prc_inc_skills.nss +++ b/src/include/prc_inc_skills.nss @@ -112,13 +112,13 @@ int PerformJump(object oPC, location lLoc, int bDoKnockDown = TRUE) if (Ninja_AbilitiesEnabled(oPC)) { bIsRunningJump = TRUE; - iBonus = 4; + iBonus += 4; } } if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC)) { bIsRunningJump = TRUE; - //iBonus = 10; //:: This is granted in the stance. + //iBonus += 10; //:: This is handled in the stance now. } // PnP rules are height * 6 for run and height * 2 for jump. // I can't get height so that is assumed to be 6. diff --git a/src/include/prc_inc_sp_tch.nss b/src/include/prc_inc_sp_tch.nss index 45dc2b4..88f14fa 100644 --- a/src/include/prc_inc_sp_tch.nss +++ b/src/include/prc_inc_sp_tch.nss @@ -47,7 +47,7 @@ int PRCDoRangedTouchAttack(object oTarget, int nDisplayFeedback = TRUE, object o { SetLocalInt(oCaster, "RangedRecall", nRecall+1); // Reroll with a -5 penalty - nResult = GetAttackRoll(oTarget,oCaster,OBJECT_INVALID,0,nAttackBonus-5,0,nDisplayFeedback,0.0,TOUCH_ATTACK_MELEE_SPELL); + nResult = GetAttackRoll(oTarget,oCaster,OBJECT_INVALID,0,nAttackBonus-5,0,nDisplayFeedback,0.0,TOUCH_ATTACK_RANGED_SPELL); } } } diff --git a/src/include/prc_inc_spells.nss b/src/include/prc_inc_spells.nss index 1c7ad71..768f9a2 100644 --- a/src/include/prc_inc_spells.nss +++ b/src/include/prc_inc_spells.nss @@ -417,7 +417,10 @@ int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF) // is it arcane, divine or neither? if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD) { - if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs + if(nClass == CLASS_TYPE_FEY && GetRacialType(oCaster) == RACIAL_TYPE_GLOURA) + iTemp = GetArcanePRCLevels(oCaster, nClass); + + else if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs iTemp = GetArcanePRCLevels(oCaster, nClass); } else if(GetIsDivineClass(nClass, oCaster)) @@ -1069,6 +1072,10 @@ int PRCMySavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = nDC -= 1 + (GetHitDice(oTarget) / 5); else if(GetHasFeat(FEAT_HARD_ELEC, oTarget)) nDC -= 2; + + //:: Mechanatrix always fail saves vs electricity. + if(GetRacialType(oTarget) == RACIAL_TYPE_MECHANATRIX) + return 0; } else if(nSaveType == SAVING_THROW_TYPE_SONIC) { @@ -2788,6 +2795,19 @@ effect PRCEffectDamage(object oTarget, int nDamageAmount, int nDamageType=DAMAGE effect eEffect; return eEffect; //Doesn't hurt him } + + // Mechanatrix heals from electrical damage. +1 HP for every 3 electrical damage. + if (GetRacialType(oTarget) == RACIAL_TYPE_MECHANATRIX && nDamageType == DAMAGE_TYPE_ELECTRICAL) + { + nDamageAmount /= 3; + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nDamageAmount), oTarget); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEAD_ELECTRICITY), oTarget); + + FloatingTextStringOnCreature("Electricty Healing restored " + IntToString(nDamageAmount) +" HP.", oTarget, FALSE); + effect eEffect; + return eEffect; //Doesn't hurt him + } + // Phoenix Belt gains fast healing when hit by fire damage if (GetHasSpellEffect(MELD_PHOENIX_BELT, oTarget) && nDamageType == DAMAGE_TYPE_FIRE) { diff --git a/src/include/prc_inc_switch.nss b/src/include/prc_inc_switch.nss index e2a3dfe..10c7ce7 100644 --- a/src/include/prc_inc_switch.nss +++ b/src/include/prc_inc_switch.nss @@ -76,7 +76,7 @@ /* This variable MUST be updated with every new version of the PRC!!! */ - const string PRC_VERSION = "PRC8 4.76"; + const string PRC_VERSION = "PRC8 4.84"; /* This variable MUST be updated every time 'assemble_spellbooks.bat' is run!!! */ @@ -86,6 +86,13 @@ * Spell switches * \******************************************************************************/ +/** + * Show detailed spell resistance check information to the caster + * When enabled, displays the roll vs SR values when checking spell resistance + */ +const string PRC_SHOW_SR_CHECK_DETAILS = "PRC_SHOW_SR_CHECK_DETAILS"; + + /** Material Components * Set switch to 1 to activate this * This allows material components in NWN through the materialcomp.2da @@ -2386,7 +2393,15 @@ const string PRC_XP_MAX_LEVEL_DIFF = "PRC_XP_MAX_LEVEL_DIFF"; */ const string PRC_XP_GIVE_XP_TO_NON_PC_FACTIONS = "PRC_XP_GIVE_XP_TO_NON_PC_FACTIONS"; +/******************************************************************************\ +* NWNxEE switches * +\******************************************************************************/ +//:: This switch enables the PRC8 -> NWNxEE shims. Don't use without NWNxEE +const string PRC_PRCX_ENABLED = "PRC_PRCX_ENABLED"; + +//:: This switch is set automatically after prc_onmodload detects NWNxEE. +const string PRC_NWNXEE_ENABLED = "PRC_NWNXEE_ENABLED"; /******************************************************************************\ @@ -2510,10 +2525,6 @@ const string PRC_LETOSCRIPT_PORTAL_PASSWORD = "PRC_LETOSCRIPT_PORTAL_PA */ const string PRC_LETOSCRIPT_GETNEWESTBIC = "PRC_LETOSCRIPT_GETNEWESTBIC"; -//This switch is set automatically after prc_onmodload detects NWNX_Funcs plugin -const string PRC_NWNX_FUNCS = "PRC_NWNX_FUNCS"; - - /******************************************************************************\ * ConvoCC switches [DEFUNCT] * \******************************************************************************/ diff --git a/src/include/prc_inc_unarmed.nss b/src/include/prc_inc_unarmed.nss index 27c3245..8f629cb 100644 --- a/src/include/prc_inc_unarmed.nss +++ b/src/include/prc_inc_unarmed.nss @@ -275,163 +275,6 @@ void ApplyUnarmedAttackEffects(object oCreature) // Monk: 1d6 at level 1, 1d8 at level 4, 1d10 at level 8, 2d6 at level 12, 2d8 at level 16, 2d10 at level 20 // Frostrager: 1d6 at level 1, 1d8 at level 4 int FindUnarmedDamage(object oCreature) -{ - int iDamage = 0; - int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk"); - int iShou = GetLevelByClass(CLASS_TYPE_SHOU, oCreature); - int iBrawler = GetLevelByClass(CLASS_TYPE_BRAWLER, oCreature); - int iSacredFist = GetLevelByClass(CLASS_TYPE_SACREDFIST, oCreature); - int iEnlightenedFist = GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCreature); - int iHenshin = GetLevelByClass(CLASS_TYPE_HENSHIN_MYSTIC, oCreature); - int iZuoken = GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature); - int iShadowSunNinja = GetLevelByClass(CLASS_TYPE_SHADOW_SUN_NINJA, oCreature); - int iFrost = GetLevelByClass(CLASS_TYPE_FROSTRAGER, oCreature); - int iAscetic = GetLevelByClass(CLASS_TYPE_NINJA, oCreature); - int iRonove = 0; - int iMonkDamage = 1; - int iShouDamage = 1; - int iBrawlerDamage = 1; - int iFrostDamage = 1; - int iSUSDamage = 1; - int iDieIncrease = 0; - int iSize; - - if (GetHasSpellEffect(VESTIGE_RONOVE, oCreature) && GetLevelByClass(CLASS_TYPE_BINDER, oCreature)) - iRonove = GetLocalInt(oCreature, "RonovesFists"); - - //:: Determine creature size - if( GetIsPolyMorphedOrShifted(oCreature) || GetPRCSwitch(PRC_APPEARANCE_SIZE)) - { - iSize = PRCGetCreatureSize(oCreature) - CREATURE_SIZE_MEDIUM + 5; - } - else - { - iSize = 5; // medium - if (GetHasFeat(FEAT_TINY, oCreature)) iSize = 3; - if (GetHasFeat(FEAT_SMALL, oCreature)) iSize = 4; - if (GetHasFeat(FEAT_LARGE, oCreature)) iSize = 6; - if (GetHasFeat(FEAT_HUGE, oCreature)) iSize = 7; - iSize += PRCGetCreatureSize(oCreature) - PRCGetCreatureSize(oCreature, PRC_SIZEMASK_NONE); - if (iSize < 1) iSize = 1; - if (iSize > 9) iSize = 9; - } - - // Sacred Fist code break protection - if (GetHasFeat(FEAT_SF_CODE, oCreature)) iSacredFist = 0; - - // Combine monk-like levels - iMonk += iSacredFist + iHenshin + iEnlightenedFist + iShou + iZuoken + iShadowSunNinja; - - // Superior Unarmed Strike - if (GetHasFeat(FEAT_SUPERIOR_UNARMED_STRIKE, oCreature)) - { - iMonk += 4; - int nHD = GetHitDice(oCreature); - if (nHD >= 16) iSUSDamage = IP_CONST_MONSTERDAMAGE_2d6; - else if (nHD >= 12) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d10; - else if (nHD >= 8) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d8; - else if (nHD >= 4) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d6; - else if (nHD >= 3) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d4; - } - - // Ascetic Stalker - if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature)) - iMonk += iAscetic; - - // Cap monk progression - if (iMonk > 16 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) iMonk = 16; - else if (iMonk > 20) iMonk = 20; - - // Ronove replacement - if (iRonove > iMonk) iMonk = iRonove; - - // Monk damage calculation (2DA row) - if (iMonk > 0) iMonkDamage = iMonk / 4 + 3; - if (iSize == 5 && iMonkDamage == 7 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) - iMonkDamage = 8; - - // Shou Disciple base damage - if (iShou > 0) - { - int nRow; - if (iShou == 1) nRow = 3; - else if (iShou == 2) nRow = 4; - else if (iShou == 3) nRow = 5; - else if (iShou == 4) nRow = 5; - else if (iShou == 5) nRow = 6; - else nRow = 3; - - if (nRow > 6) nRow = 6; - - iShouDamage = StringToInt(Get2DACache("unarmed_dmg", "size" + IntToString(iSize), nRow)); - } - - // Frostrager - if (iFrost > 0) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d6; - if (iFrost > 3) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d8; - - // Brawler - if (iBrawler > 0) iBrawlerDamage = iBrawler / 6 + 3; - if (iBrawler >= 36) iBrawlerDamage += 2; - - // Armor/shield penalties - if (iMonkDamage > 1) - { - object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); - object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); - int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD || - GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD || - GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; - if (GetBaseAC(oArmor) > 0 || bShieldEq) - iMonkDamage = 1; - } - - if (iShouDamage > 1) - { - object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature); - object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature); - int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD || - GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD || - GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD; - if (GetBaseAC(oArmor) > 3 || bShieldEq) - iShouDamage = 1; - } - - // Determine IoDM die increase - if (GetHasFeat(FEAT_INCREASE_DAMAGE2, oCreature)) iDieIncrease = 2; - else if (GetHasFeat(FEAT_INCREASE_DAMAGE1, oCreature)) iDieIncrease = 1; - - // Lookup monk damage in 2DA - iMonkDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iMonkDamage)); - - // 3.0e monk special cases - if (iSize <= 5 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE)) - { - if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d6) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d12; - if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d10) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d20; - } - - // Apply IoDM die increase last, after 2DA lookups - if (iMonkDamage > 0) iMonkDamage = StepDie(iMonkDamage, iDieIncrease); - if (iShouDamage > 0) iShouDamage = StepDie(iShouDamage, iDieIncrease); - if (iBrawlerDamage > 0) iBrawlerDamage = StepDie(iBrawlerDamage, iDieIncrease); - if (iFrostDamage > 0) iFrostDamage = StepDie(iFrostDamage, iDieIncrease); - if (iSUSDamage > 0) iSUSDamage = StepDie(iSUSDamage, iDieIncrease); - - // Select best damage - iDamage = iMonkDamage; - iDamage = (DamageAvg(iShouDamage ) > DamageAvg(iDamage)) ? iShouDamage : iDamage; - iDamage = (DamageAvg(iFrostDamage ) > DamageAvg(iDamage)) ? iFrostDamage : iDamage; - iDamage = (DamageAvg(iSUSDamage ) > DamageAvg(iDamage)) ? iSUSDamage : iDamage; - iDamage = (DamageAvg(iBrawlerDamage) > DamageAvg(iDamage)) ? iBrawlerDamage : iDamage; - - if (DEBUG) DoDebug("prc_inc_unarmed: iDamage "+IntToString(iDamage)); - - return iDamage; -} - - -/* int FindUnarmedDamage(object oCreature) { int iDamage = 0; int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk"); @@ -598,7 +441,6 @@ int FindUnarmedDamage(object oCreature) return iDamage; } - */ // Adds appropriate feats to the skin. Stolen from SoulTaker + expanded with overwhelming/devastating critical. diff --git a/src/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss index 0a59892..6e1f84a 100644 --- a/src/include/prc_inc_wpnrest.nss +++ b/src/include/prc_inc_wpnrest.nss @@ -1074,8 +1074,8 @@ void DoWeaponEquip(object oPC, object oItem, int nHand) if(GetTag(oItem) == "PRC_PYRO_LASH_WHIP") return; //initialize variables - int nRealSize = PRCGetCreatureSize(oPC); //size for Finesse/TWF - int nSize = nRealSize; //size for equipment restrictions + int nRealSize = PRCGetCreatureSize(oPC); //:: size for Finesse/TWF + int nSize = nRealSize-2; //:: size for equipment restrictions int nWeaponSize = GetWeaponSize(oItem); int nStrMod = GetAbilityModifier(ABILITY_STRENGTH, oPC); int nElfFinesse = GetAbilityModifier(ABILITY_DEXTERITY, oPC) - nStrMod; @@ -1208,7 +1208,13 @@ void DoWeaponEquip(object oPC, object oItem, int nHand) else if(nBaseType == BASE_ITEM_ELVEN_COURTBLADE) DoEquipCourtblade(oPC, oItem); - DoRacialEquip(oPC, nBaseType); + DoRacialEquip(oPC, nBaseType); + + if(DEBUG) DoDebug("GetWeaponRanged: " + IntToString(GetWeaponRanged(oItem))); + if(DEBUG) DoDebug("PRCLargeWeaponCheck: " + IntToString(PRCLargeWeaponCheck(nBaseType, nWeaponSize))); + if(DEBUG) DoDebug("Size check - Weapon: " + IntToString(nWeaponSize) + ", Size: " + IntToString(nSize) + ", RealSize: " + IntToString(nRealSize)); + if(DEBUG) DoDebug("Offhand empty: " + IntToString(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC) == OBJECT_INVALID)); + if(DEBUG) DoDebug("RealSize > Small: " + IntToString(nRealSize > CREATURE_SIZE_SMALL)); } void DoWeaponsEquip(object oPC) diff --git a/src/include/prc_nui_lv_inc.nss b/src/include/prc_nui_lv_inc.nss index b3d862f..95441e5 100644 --- a/src/include/prc_nui_lv_inc.nss +++ b/src/include/prc_nui_lv_inc.nss @@ -2528,7 +2528,79 @@ int IsRequiredForOtherManeuvers(int nClass, int prereq, string discipline, objec return FALSE; } -int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) +int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + string discipline = Get2DACache(sFile, "Discipline", spellbookId); + + // First check if this class is allowed to access this discipline + if (!IsAllowedDiscipline(nClass, spellbookId, oPC)) + return FALSE; + + // If no prerequisites required and class has access, allow it + if (!prereqs) + return TRUE; + + // For maneuvers with prerequisites, count across all Blade Magic classes + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json classDisc2Info = JsonObject(); + json classDisc3Info = JsonObject(); + + if (nClass == CLASS_TYPE_SWORDSAGE) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + } + if (nClass == CLASS_TYPE_CRUSADER) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + if (nClass == CLASS_TYPE_WARBLADE) + { + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + + // Sum up maneuver counts from all classes for this discipline + int nManCount = 0; + + // Check primary class + json chosenDisc = JsonObjectGet(discInfo, discipline); + if (chosenDisc != JsonNull()) + { + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))); + } + + // Check second class + chosenDisc = JsonObjectGet(classDisc2Info, discipline); + if (chosenDisc != JsonNull()) + { + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))); + } + + // Check third class + chosenDisc = JsonObjectGet(classDisc3Info, discipline); + if (chosenDisc != JsonNull()) + { + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nManCount += JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))); + } + + // Check if we have enough maneuvers for the prerequisite + return nManCount >= prereqs; +} + +/* int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_SELF) { string sFile = GetClassSpellbookFile(nClass); int prereqs = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); @@ -2546,7 +2618,7 @@ int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_S } return FALSE; -} +} */ int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF) { diff --git a/src/include/prc_nui_sb_inc.nss b/src/include/prc_nui_sb_inc.nss index 7148413..e743ad5 100644 --- a/src/include/prc_nui_sb_inc.nss +++ b/src/include/prc_nui_sb_inc.nss @@ -361,6 +361,12 @@ int IsSpellKnown(object oPlayer, int nClass, int spellId) int featID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); return GetHasFeat(featID, oPlayer); } + + // Divine Surge Greater hardcoding to fix NUI display issue + if (spellId == 15840 || spellId == 16051 || spellId == 16262) + { + spellId = MOVE_DS_GREATER_DIVINE_SURGE; // 17337 + } int currentSpell = spellId; int masterSpell = StringToInt(Get2DACache("spells", "Master", currentSpell)); @@ -842,4 +848,6 @@ int IsSpellbookNUIOpen(object oPC) } return FALSE; -} \ No newline at end of file +} + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_racial_const.nss b/src/include/prc_racial_const.nss index f99b8e6..3f7b9a3 100644 --- a/src/include/prc_racial_const.nss +++ b/src/include/prc_racial_const.nss @@ -29,6 +29,7 @@ const int RACIAL_TYPE_SILVANESTI_ELF = 999; const int RACIAL_TYPE_TINK_GNOME = 999; //Eberron Races +const int RACIAL_TYPE_WARFORGED_SCOUT = 144; const int RACIAL_TYPE_WARFORGED_CHARGER = 145; const int RACIAL_TYPE_SHIFTER = 146; const int RACIAL_TYPE_CHANGELING = 147; @@ -39,15 +40,15 @@ const int RACIAL_TYPE_EMPTY_VESSEL = 154; //Planescape Races const int RACIAL_TYPE_BARIAUR = 207; -const int RACIAL_TYPE_BLADELING = 195; -const int RACIAL_TYPE_CHAOND = 196; +const int RACIAL_TYPE_BLADELING = 999; +const int RACIAL_TYPE_CHAOND = 999; const int RACIAL_TYPE_NATHRI = 237; -const int RACIAL_TYPE_TULADHARA = 197; -const int RACIAL_TYPE_ZENYRTHRI = 206; +const int RACIAL_TYPE_TULADHARA = 999; +const int RACIAL_TYPE_ZENYRTHRI = 999; //Ravenloft Races -const int RACIAL_TYPE_HVISTANI = 146; -const int RACIAL_TYPE_VISTANI = 147; +const int RACIAL_TYPE_HVISTANI = 999; +const int RACIAL_TYPE_VISTANI = 999; //:: Rokugan/Kara-Tur Races const int RACIAL_TYPE_TASLOI = 140; @@ -57,85 +58,89 @@ const int RACIAL_TYPE_NEZUMI = 246; //Spelljammer Races -const int RACIAL_TYPE_SCRO = 182; -const int RACIAL_TYPE_XIXCHIL = 181; +const int RACIAL_TYPE_SCRO = 999; +const int RACIAL_TYPE_XIXCHIL = 999; // DMG const int RACIAL_TYPE_PLANT = 52; //Draconic Races -const int RACIAL_TYPE_DRAGONBORN = 128; -const int RACIAL_TYPE_SPELLSCALE = 129; +const int RACIAL_TYPE_DRAGONBORN = 999; +const int RACIAL_TYPE_SPELLSCALE = 999; const int RACIAL_TYPE_REDSPAWN_ARCANISS = 72; const int RACIAL_TYPE_SPIRETOPDRAGON = 77; //Fey-type Races const int RACIAL_TYPE_BRALANI = 159; const int RACIAL_TYPE_BROWNIE = 53; -const int RACIAL_TYPE_GRIG = 133; +const int RACIAL_TYPE_GRIG = 999; const int RACIAL_TYPE_JAEBRIN = 78; -const int RACIAL_TYPE_NIXIE = 134; -const int RACIAL_TYPE_NYMPH = 135; +const int RACIAL_TYPE_NIXIE = 999; +const int RACIAL_TYPE_NYMPH = 999; const int RACIAL_TYPE_PIXIE = 226; -const int RACIAL_TYPE_SATYR = 136; +const int RACIAL_TYPE_SATYR = 999; const int RACIAL_TYPE_HYBSIL = 66; //Outsider Races -const int RACIAL_TYPE_ASURA = 80; +const int RACIAL_TYPE_ASURA = 999; const int RACIAL_TYPE_AZER = 227; const int RACIAL_TYPE_BUOMMANS = 238; -const int RACIAL_TYPE_DJINNI = 81; -const int RACIAL_TYPE_EFREETI = 82; -const int RACIAL_TYPE_FORMIAN = 232; +const int RACIAL_TYPE_DJINNI = 999; +const int RACIAL_TYPE_EFREETI = 999; +const int RACIAL_TYPE_FORMIAN = 999; const int RACIAL_TYPE_GITHYANKI = 222; const int RACIAL_TYPE_GITHZERAI = 223; -const int RACIAL_TYPE_GLOAMING = 83; +const int RACIAL_TYPE_GLOAMING = 999; const int RACIAL_TYPE_HOUND_ARCHON = 84; const int RACIAL_TYPE_KHAASTA = 94; -const int RACIAL_TYPE_JANNI = 85; -const int RACIAL_TYPE_MEPHIT_AIR = 86; -const int RACIAL_TYPE_MEPHIT_EARTH = 87; -const int RACIAL_TYPE_MEPHIT_FIRE = 88; -const int RACIAL_TYPE_MEPHIT_WATER = 89; +const int RACIAL_TYPE_JANNI = 999; +const int RACIAL_TYPE_MEPHIT_AIR = 999; +const int RACIAL_TYPE_MEPHIT_EARTH = 999; +const int RACIAL_TYPE_MEPHIT_FIRE = 999; +const int RACIAL_TYPE_MEPHIT_WATER = 999; const int RACIAL_TYPE_MEPHLING_AIR = 90; const int RACIAL_TYPE_MEPHLING_EARTH = 91; const int RACIAL_TYPE_MEPHLING_FIRE = 92; const int RACIAL_TYPE_MEPHLING_WATER = 93; const int RACIAL_TYPE_NERAPHIM = 235; const int RACIAL_TYPE_RAKSHASA = 224; -const int RACIAL_TYPE_SALAMANDER = 95; -const int RACIAL_TYPE_SHADE = 210; +const int RACIAL_TYPE_SALAMANDER = 999; +const int RACIAL_TYPE_SHADE = 999; const int RACIAL_TYPE_SPIKER = 239; const int RACIAL_TYPE_WILDREN = 240; const int RACIAL_TYPE_NAZTHARUNE_RAKSHASA = 96; const int RACIAL_TYPE_RETH_DEKALA = 67; //Planetouched Races -const int RACIAL_TYPE_AASIMAR = 198; -const int RACIAL_TYPE_AIR_GEN = 199; -const int RACIAL_TYPE_EARTH_GEN = 200; -const int RACIAL_TYPE_FEYRI = 201; -const int RACIAL_TYPE_FIRE_GEN = 202; -const int RACIAL_TYPE_MORTIF = 132; -const int RACIAL_TYPE_TANARUKK = 203; -const int RACIAL_TYPE_TIEFLING = 204; -const int RACIAL_TYPE_WATER_GEN = 205; -const int RACIAL_TYPE_SHADOWSWYFT = 236; +const int RACIAL_TYPE_WISPLING = 195; +const int RACIAL_TYPE_SHYFT = 196; +const int RACIAL_TYPE_MECHANATRIX = 197; +const int RACIAL_TYPE_AASIMAR = 198; +const int RACIAL_TYPE_AIR_GEN = 199; +const int RACIAL_TYPE_EARTH_GEN = 200; +const int RACIAL_TYPE_FEYRI = 201; +const int RACIAL_TYPE_FIRE_GEN = 202; +const int RACIAL_TYPE_MAELUTH = 206; +const int RACIAL_TYPE_MORTIF = 999; +const int RACIAL_TYPE_TANARUKK = 203; +const int RACIAL_TYPE_TIEFLING = 204; +const int RACIAL_TYPE_WATER_GEN = 205; +const int RACIAL_TYPE_SHADOWSWYFT = 236; //Serpent Kingdom and Reptillian Races -const int RACIAL_TYPE_ABOM_YUAN = 228; +const int RACIAL_TYPE_ABOM_YUAN = 999; const int RACIAL_TYPE_ASABI = 999; const int RACIAL_TYPE_ASABI_STINGTAIL = 999; const int RACIAL_TYPE_KUOTOA = 999; const int RACIAL_TYPE_LIZARDFOLK = 219; -const int RACIAL_TYPE_LIZARDKING = 68; -const int RACIAL_TYPE_MEDUSA = 69; +const int RACIAL_TYPE_LIZARDKING = 999; +const int RACIAL_TYPE_MEDUSA = 999; const int RACIAL_TYPE_OPHIDIAN = 999; const int RACIAL_TYPE_POISON_DUSK = 248; const int RACIAL_TYPE_PURE_YUAN = 220; -const int RACIAL_TYPE_SAHUAGIN = 71; -const int RACIAL_TYPE_SK_YUANTI = 233; -const int RACIAL_TYPE_TREN = 72; +const int RACIAL_TYPE_SAHUAGIN = 999; +const int RACIAL_TYPE_SK_YUANTI = 999; +const int RACIAL_TYPE_TREN = 999; const int RACIAL_TYPE_VILETOOTH_LIZARDFOLK = 112; const int RACIAL_TYPE_MUCKDWELLER = 74; @@ -143,32 +148,32 @@ const int RACIAL_TYPE_MUCKDWELLER = 74; const int RACIAL_TYPE_ARANEA = 75; const int RACIAL_TYPE_BEHOLDER = -1; const int RACIAL_TYPE_DRIDER = 50; -const int RACIAL_TYPE_GRIMLOCK = 77; +const int RACIAL_TYPE_GRIMLOCK = 999; const int RACIAL_TYPE_ILLITHID = 225; const int RACIAL_TYPE_IMASKARI = 230; -const int RACIAL_TYPE_SLYTH = 78; +const int RACIAL_TYPE_SLYTH = 999; const int RACIAL_TYPE_TROGLODYTE = 234; -const int RACIAL_TYPE_UMBER_HULK = 79; +const int RACIAL_TYPE_UMBER_HULK = 999; const int RACIAL_TYPE_GLOURA = 73; //Other Monsterous Races const int RACIAL_TYPE_CENTAUR = 208; const int RACIAL_TYPE_CATFOLK = 209; -const int RACIAL_TYPE_DIABOLUS = 113; -const int RACIAL_TYPE_DIOPSID = 114; -const int RACIAL_TYPE_DRAGONKIN = 58; -const int RACIAL_TYPE_ETTERCAP = 73; -const int RACIAL_TYPE_FIRENEWT = 59; -const int RACIAL_TYPE_GARGOYLE = 185; -const int RACIAL_TYPE_KIRLANAN = 60; -const int RACIAL_TYPE_LUPIN = 186; -const int RACIAL_TYPE_PTERAFOLK = 61; -const int RACIAL_TYPE_RAPTORAN = 130; -const int RACIAL_TYPE_SAURIAL_BLADEBACK = 62; -const int RACIAL_TYPE_SAURIAL_FINHEAD = 63; -const int RACIAL_TYPE_SAURIAL_FLYER = 64; -const int RACIAL_TYPE_SAURIAL_HORNHEAD = 65; -const int RACIAL_TYPE_TORTLE = 118; +const int RACIAL_TYPE_DIABOLUS = 999; +const int RACIAL_TYPE_DIOPSID = 999; +const int RACIAL_TYPE_DRAGONKIN = 999; +const int RACIAL_TYPE_ETTERCAP = 999; +const int RACIAL_TYPE_FIRENEWT = 999; +const int RACIAL_TYPE_GARGOYLE = 999; +const int RACIAL_TYPE_KIRLANAN = 999; +const int RACIAL_TYPE_LUPIN = 999; +const int RACIAL_TYPE_PTERAFOLK = 999; +const int RACIAL_TYPE_RAPTORAN = 999; +const int RACIAL_TYPE_SAURIAL_BLADEBACK = 999; +const int RACIAL_TYPE_SAURIAL_FINHEAD = 999; +const int RACIAL_TYPE_SAURIAL_FLYER = 999; +const int RACIAL_TYPE_SAURIAL_HORNHEAD = 999; +const int RACIAL_TYPE_TORTLE = 999; const int RACIAL_TYPE_VOLODNI = 131; const int RACIAL_TYPE_WEMIC = 51; const int RACIAL_TYPE_ARKAMOI = 68; @@ -226,7 +231,7 @@ const int RACIAL_TYPE_MARRUSAULT = 119; const int RACIAL_TYPE_MARRUTACT = 120; //Stormwrack -const int RACIAL_TYPE_DARFELLAN = 117; +const int RACIAL_TYPE_DARFELLAN = 999; const int RACIAL_TYPE_HADOZEE = 180; //Champions of Ruin @@ -257,7 +262,7 @@ const int RACIAL_TYPE_GREY_ELF = 169; //:: Dwarf const int RACIAL_TYPE_ARC_DWARF = 151; -const int RACIAL_TYPE_DREAM_DWARF = 157; +const int RACIAL_TYPE_DREAM_DWARF = 999; const int RACIAL_TYPE_FIREBLOOD_DWARF = 106; const int RACIAL_TYPE_FROST_DWARF = 158; const int RACIAL_TYPE_GOLD_DWARF = 152; @@ -267,11 +272,11 @@ const int RACIAL_TYPE_URDINNIR = 155; const int RACIAL_TYPE_WILD_DWARF = 156; //:: Gnome -const int RACIAL_TYPE_CHAOS_GNOME = 177; +const int RACIAL_TYPE_CHAOS_GNOME = 999; const int RACIAL_TYPE_DEEP_GNOME = 174; const int RACIAL_TYPE_FIRE_GNOME = 173; const int RACIAL_TYPE_FOR_GNOME = 175; -const int RACIAL_TYPE_ICE_GNOME = 178; +const int RACIAL_TYPE_ICE_GNOME = 999; const int RACIAL_TYPE_ROCK_GNOME = 176; const int RACIAL_TYPE_STONEHUNTER_GNOME = 105; const int RACIAL_TYPE_SVIRFNEBLIN = 174; diff --git a/src/include/prc_shifter_info.nss b/src/include/prc_shifter_info.nss index 2a9ed78..4eef025 100644 --- a/src/include/prc_shifter_info.nss +++ b/src/include/prc_shifter_info.nss @@ -93,7 +93,9 @@ struct _prc_inc_ability_info_struct _prc_inc_CountItemAbilities(object oCreature struct _prc_inc_ability_info_struct _prc_inc_shifter_GetAbilityInfo(object oTemplate, object oShifter) { - int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS); + int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED); + int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED); + int bFuncs = (nNWNxEE && nPRCx); //Initialize with item ability bonuses diff --git a/src/include/prc_spell_const.nss b/src/include/prc_spell_const.nss index c93417f..d0bec82 100644 --- a/src/include/prc_spell_const.nss +++ b/src/include/prc_spell_const.nss @@ -443,14 +443,14 @@ const int SPELL_PHANTOM_STEED = 2347; const int SPELL_GASEOUS_FORM = 2348; //:: Racial spell additions -const int SPIRETOP_FOG_CLOUD_BREATH = 1487; //:: Spiretop Dragon -const int MEPHLING_BREATH_WEAPON = 1488; //:: Mephlings -const int SPELL_ARANEA_ALTER = 1489; //:: Aranea +const int SPIRETOP_FOG_CLOUD_BREATH = 1487; //:: Spiretop Dragon +const int MEPHLING_BREATH_WEAPON = 1488; //:: Mephlings +const int SPELL_ARANEA_ALTER = 1489; //:: Aranea const int SPELL_ARANEA_ALTER_HUMANOID = 1490; const int SPELL_ARANEA_ALTER_HYBRID = 1491; const int SPELL_ARANEA_ALTER_SPIDER = 1492; const int SPELL_ARANEA_WEB = 1493; -const int SPELL_MUCK_SQUIRT = 1494; //:: Muckdweller +const int SPELL_MUCK_SQUIRT = 1494; //:: Muckdweller const int SPELL_RAKSHASA_DISGUISE = 1951; const int SPELL_FEYRI_ALTER = 1955; const int SPELL_NIXIE_WATERBREATHING = 1956; @@ -547,6 +547,18 @@ const int SPELL_TURLEMOI_STRENGTH = 19013; const int SPELL_HADRIMOI_STRENGTH = 19014; const int SPELL_GLOURA_GRACE = 19015; +const int SPELL_SHYFT_ETHEREAL_JAUNT = 17977; //:: Shyft + +const int SPELL_MECHA_SHOCKING_GRASP = 17978; //:: Mechanatrix + +const int SPELL_MAELUTH_FIEND_HAMMER = 17979; //:: Maeloth + +const int SPELL_WISPLING_CHANGE_SHAPE_LEARN = 17980; //:: Wispling +const int SPELL_WISPLING_CHANGE_SHAPE_OPTIONS = 17981; +const int SPELL_WISPLING_CHANGE_SHAPE_TRUE = 17982; +const int SPELL_WISPLING_CHANGE_SHAPE_QS1 = 17983; +const int SPELL_WISPLING_CHANGE_SHAPE_QS2 = 17984; + // Poison system spells const int SPELL_POISONED_WEAPON = 2880; const int SPELL_GRENADE_POISONVIAL = 2881; @@ -555,7 +567,6 @@ const int SPELL_POISON_ITEM = 2883; const int SPELL_POISON_FOOD = 2884; const int SPELL_CLEAN_POISON_OFF = 2885; - // Psionic feat spells const int SPELL_FEAT_SPEED_OF_THOUGHT_BONUS = 2820; diff --git a/src/include/prc_x2_craft.nss b/src/include/prc_x2_craft.nss index c18dcc3..f793f9a 100644 --- a/src/include/prc_x2_craft.nss +++ b/src/include/prc_x2_craft.nss @@ -120,6 +120,10 @@ const int PRC_GEM_PERLEVEL = 6; // Craft Skull Talisman constants const int PRC_SKULL_BASECOST = 7; +int GetWeaponType(int nBaseItem); + +void RemoveMasterworkProperties(object oItem); + // * Returns TRUE if an item is a Craft Base Item // * to be used in spellscript that can be cast on items - i.e light int CIGetIsCraftFeatBaseItem( object oItem ); @@ -214,6 +218,78 @@ int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0) /* Function definitions */ ////////////////////////////////////////////////// +void RemoveMasterworkProperties(object oItem) +{ + if(DEBUG) DoDebug("RemoveMasterworkProperties() called on: " + DebugObject2Str(oItem)); + + int nBase = GetBaseItemType(oItem); + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Item base type: " + IntToString(nBase)); + + int nRemoved = 0; + + // For armor/shields: remove only the Quality property, keep skill bonuses + if((nBase == BASE_ITEM_ARMOR) || + (nBase == BASE_ITEM_SMALLSHIELD) || + (nBase == BASE_ITEM_LARGESHIELD) || + (nBase == BASE_ITEM_TOWERSHIELD)) + { + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Processing armor/shield"); + + itemproperty ip = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ip)) + { + string sTag = GetItemPropertyTag(ip); + int nType = GetItemPropertyType(ip); + + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Found property - Type: " + IntToString(nType) + + ", Tag: " + sTag + + ", String: " + DebugIProp2Str(ip)); + + if(sTag == "Quality_Masterwork" && nType == ITEM_PROPERTY_QUALITY) + { + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Removing Quality property"); + RemoveItemProperty(oItem, ip); + nRemoved++; + ip = GetFirstItemProperty(oItem); // Restart iteration + continue; + } + ip = GetNextItemProperty(oItem); + } + } + + // For weapons/ammo: remove both Quality and Attack Bonus properties + if(GetWeaponType(nBase) || + StringToInt(Get2DACache("prc_craft_gen_it", "Type", nBase)) == 4) + { + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Processing weapon/ammo"); + + itemproperty ip = GetFirstItemProperty(oItem); + while(GetIsItemPropertyValid(ip)) + { + string sTag = GetItemPropertyTag(ip); + int nType = GetItemPropertyType(ip); + + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Found property - Type: " + IntToString(nType) + + ", Tag: " + sTag + + ", String: " + DebugIProp2Str(ip)); + + // Check for both Quality and Attack Bonus with Quality_Masterwork tag + if(sTag == "Quality_Masterwork" && + (nType == ITEM_PROPERTY_QUALITY || nType == ITEM_PROPERTY_ATTACK_BONUS)) + { + if(DEBUG) DoDebug("prc_x2_craft >> RemoveMasterworkProperties(): Removing property type " + IntToString(nType)); + RemoveItemProperty(oItem, ip); + nRemoved++; + ip = GetFirstItemProperty(oItem); // Restart iteration + continue; + } + ip = GetNextItemProperty(oItem); + } + } + + if(DEBUG) DoDebug("prc_x2_craft: RemoveMasterworkProperties() completed. Removed " + + IntToString(nRemoved) + " properties."); +} // * Returns the innate level of a spell. If bDefaultZeroToOne is given // * Level 0 spell will be returned as level 1 spells @@ -2416,8 +2492,8 @@ int CIDoCraftItemFromConversation(int nNumber) DeleteLocalObject(oPC,"X2_CI_CRAFT_MAJOR"); DeleteLocalObject(oPC,"X2_CI_CRAFT_MINOR"); - - if (!GetIsObjectValid(oMajor)) + + if (!GetIsObjectValid(oMajor)) { FloatingTextStrRefOnCreature(83374,oPC); //"Invalid target" DeleteLocalInt(oPC,"X2_CRAFT_SUCCESS"); @@ -2472,7 +2548,7 @@ int CIDoCraftItemFromConversation(int nNumber) { oContainer = GetItemPossessedBy(oPC,"x2_it_craftcont"); } - + // Do the crafting... object oRet = CIUseCraftItemSkill( oPC, nSkill, stItem.sResRef, stItem.nDC, oContainer) ; @@ -2481,7 +2557,9 @@ int CIDoCraftItemFromConversation(int nNumber) if (GetIsObjectValid(oRet)) { - // ----------------------------------------------------------------------- + RemoveMasterworkProperties(oMajor); + + // ----------------------------------------------------------------------- // Copy all item properties from the major object on the resulting item // Through we problably won't use this, its a neat thing to have for the // community @@ -2499,7 +2577,8 @@ int CIDoCraftItemFromConversation(int nNumber) { //TakeGoldFromCreature(stItem.nCost, oPC,TRUE); SpendGP(oPC, stItem.nCost); - IPCopyItemProperties(oMajor,oRet); + RemoveMasterworkProperties(oMajor); + IPCopyItemProperties(oMajor,oRet); } // set success variable for conversation SetLocalInt(oPC,"X2_CRAFT_SUCCESS",TRUE); diff --git a/src/include/prc_x2_itemprop.nss b/src/include/prc_x2_itemprop.nss index 1abf20c..5754382 100644 --- a/src/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -210,6 +210,7 @@ int IPDamageConstant(int nDamBon); #include "prc_ipfeat_const" #include "inc_utility" +#include "prc_craft_inc" //------------------------------------------------------------------------------ // I M P L E M E N T A T I O N diff --git a/src/include/prcsp_engine.nss b/src/include/prcsp_engine.nss index 833ec49..d1c1d05 100644 --- a/src/include/prcsp_engine.nss +++ b/src/include/prcsp_engine.nss @@ -304,10 +304,31 @@ int PRCDoResistSpell(object oCaster, object oTarget, int nEffCasterLvl=0, float } } + //:: A tie favors the caster. + int nSRValue = PRCGetSpellResistance(oTarget, oCaster); + int nD20Roll = d20(1); + int nCasterTotal = nEffCasterLvl + nD20Roll + iWeav; + + if (nCasterTotal < nSRValue) + nResist = SPELL_RESIST_PASS; + + //:: Optional Detailed SR check to caster + if (GetIsPC(oCaster) && nResist != SPELL_RESIST_MANTLE && nResist != SPELL_RESIST_GLOBE && nSRValue > 0 && GetPRCSwitch(PRC_SHOW_SR_CHECK_DETAILS)) + { + string message = nResist == SPELL_RESIST_FAIL ? + "Target affected. Roll: " + IntToString(nCasterTotal) + " vs SR: " + IntToString(nSRValue) : + "Target resisted. Roll: " + IntToString(nCasterTotal) + " vs SR: " + IntToString(nSRValue) + + " (missed by " + IntToString(nSRValue - nCasterTotal) + ")"; + SendMessageToPC(oCaster, message); + } + + //:: Basic pass/fail messages + PRCShowSpellResist(oCaster, oTarget, nResist, fDelay); - // A tie favors the caster. + +/* // A tie favors the caster. if ((nEffCasterLvl + d20(1)+iWeav) < PRCGetSpellResistance(oTarget, oCaster)) - nResist = SPELL_RESIST_PASS; + nResist = SPELL_RESIST_PASS; */ } } @@ -398,4 +419,6 @@ int CheckSpellfire(object oCaster, object oTarget, int bFriendly = FALSE) //absorbed return 1; -} \ No newline at end of file +} + +//:; void main(){} \ No newline at end of file diff --git a/src/include/psi_inc_augment.nss b/src/include/psi_inc_augment.nss index 6bbac45..2689869 100644 --- a/src/include/psi_inc_augment.nss +++ b/src/include/psi_inc_augment.nss @@ -713,5 +713,8 @@ void SetAugmentationOverride(object oCreature, struct user_augment_profile uap) SetLocalInt(oCreature, PRC_AUGMENT_OVERRIDE, _EncodeProfile(uap) + 1); } + + + // Test main //void main(){} \ No newline at end of file diff --git a/src/include/psi_inc_const.nss b/src/include/psi_inc_const.nss index 5256beb..c194a37 100644 --- a/src/include/psi_inc_const.nss +++ b/src/include/psi_inc_const.nss @@ -70,6 +70,7 @@ const int METAPSIONIC_WIDEN = 0x80; /// Quicken Power const int METAPSIONIC_QUICKEN = 0x100; + /// How much PP Chain Power costs to use const int METAPSIONIC_CHAIN_COST = 6; /// How much PP Empower Power costs to use diff --git a/src/include/psi_inc_core.nss b/src/include/psi_inc_core.nss index b4ca245..d58d5b5 100644 --- a/src/include/psi_inc_core.nss +++ b/src/include/psi_inc_core.nss @@ -443,6 +443,8 @@ struct manifestation{ int bWiden; /// Whether Quicken Power was used with this manifestation int bQuicken; + //:: Whether Defensive Manifesation was used with this manifestation + int bDefensive; }; ////////////////////////////////////////////////// @@ -1722,7 +1724,7 @@ int IsHiddenTalent(object oPC = OBJECT_SELF) GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC) || GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC) || GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC) || - //GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC) || + GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC) || GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC) || GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC) || GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC) || @@ -1834,7 +1836,7 @@ int GetHiddenTalentCount(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC)) nCount++; if (GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC)) nCount++; if (GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC)) nCount++; - //if (GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) nCount++; + if (GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) nCount++; if (GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC)) nCount++; if (GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC)) nCount++; if (GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC)) nCount++; @@ -1887,7 +1889,10 @@ int GetIsHiddenTalentPower(object oPC, int nPower) if(nPower == POWER_ELFSIGHT && GetHasFeat(FEAT_HIDDEN_TALENT_ELFSIGHT, oPC)) return TRUE; if(nPower == POWER_EMPATHY && GetHasFeat(FEAT_HIDDEN_TALENT_EMPATHY, oPC)) return TRUE; if(nPower == POWER_EMPTYMIND && GetHasFeat(FEAT_HIDDEN_TALENT_EMPTYMIND, oPC)) return TRUE; - //if(nPower == POWER_ENERGYRAY && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; + if(nPower == POWER_ENERGYRAY_FIRE && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; + if(nPower == POWER_ENERGYRAY_COLD && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; + if(nPower == POWER_ENERGYRAY_ELEC && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; + if(nPower == POWER_ENERGYRAY_SONIC && GetHasFeat(FEAT_HIDDEN_TALENT_ENERGYRAY, oPC)) return TRUE; if(nPower == POWER_ENTANGLE && GetHasFeat(FEAT_HIDDEN_TALENT_ENTANGLE, oPC)) return TRUE; if(nPower == POWER_EXPANSION && GetHasFeat(FEAT_HIDDEN_TALENT_EXPANSION, oPC)) return TRUE; if(nPower == POWER_FARHAND && GetHasFeat(FEAT_HIDDEN_TALENT_FARHAND, oPC)) return TRUE; diff --git a/src/include/psi_inc_powknown.nss b/src/include/psi_inc_powknown.nss index 20c1951..25486c3 100644 --- a/src/include/psi_inc_powknown.nss +++ b/src/include/psi_inc_powknown.nss @@ -29,7 +29,7 @@ */ //::////////////////////////////////////////////// //::////////////////////////////////////////////// - +#include "prc_inc_spells" ////////////////////////////////////////////////// /* Constants */ ////////////////////////////////////////////////// @@ -572,32 +572,49 @@ int GetMaxPowerCount(object oCreature, int nList) int GetHasPower(int nPower, object oCreature = OBJECT_SELF) { - // Check MISC list first (for Hidden Talent and similar feats) - if(GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_INVALID), oCreature)) - return TRUE; + // Debug output + if (DEBUG) DoDebug("GetHasPower: Checking power " + IntToString(nPower)); + + // Check if it's a subradial spell first + if (GetIsSubradialSpell(nPower)) + { + if(DEBUG) DoDebug("GetHasPower: " + IntToString(nPower) + " is a subradial"); + int nMasterSpell = GetMasterSpellFromSubradial(nPower); + if (nMasterSpell != -1) + { + if(DEBUG) DoDebug("GetHasPower: Master spell is " + IntToString(nMasterSpell)); + nPower = nMasterSpell; + } + } + + + // Check MISC list first (for Hidden Talent and similar feats) + if(GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_INVALID), oCreature)) + return TRUE; - if((GetLevelByClass(CLASS_TYPE_PSION, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSION), oCreature) - ) || - (GetLevelByClass(CLASS_TYPE_PSYWAR, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSYWAR), oCreature) - ) || - (GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSYCHIC_ROGUE), oCreature) - ) || - (GetLevelByClass(CLASS_TYPE_WILDER, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_WILDER), oCreature) - ) || - (GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_FIST_OF_ZUOKEN), oCreature) - ) || - (GetLevelByClass(CLASS_TYPE_WARMIND, oCreature) - && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_WARMIND), oCreature) - ) - // add new psionic classes here - ) - return TRUE; - return FALSE; + if((GetLevelByClass(CLASS_TYPE_PSION, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSION), oCreature) + ) || + (GetLevelByClass(CLASS_TYPE_PSYWAR, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSYWAR), oCreature) + ) || + (GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_PSYCHIC_ROGUE), oCreature) + ) || + (GetLevelByClass(CLASS_TYPE_WILDER, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_WILDER), oCreature) + ) || + (GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_FIST_OF_ZUOKEN), oCreature) + ) || + (GetLevelByClass(CLASS_TYPE_WARMIND, oCreature) + && GetHasFeat(GetClassFeatFromPower(nPower, CLASS_TYPE_WARMIND), oCreature) + ) + // add new psionic classes here + ) + return TRUE; + + return FALSE; } string DebugListKnownPowers(object oCreature) diff --git a/src/include/psi_inc_psifunc.nss b/src/include/psi_inc_psifunc.nss index c35b122..798f6f8 100644 --- a/src/include/psi_inc_psifunc.nss +++ b/src/include/psi_inc_psifunc.nss @@ -557,6 +557,9 @@ void _ManifestationHB(object oManifester, location lManifester, object oMfToken) { if(DEBUG) DoDebug("_ManifestationHB(): Manifester moved or lost concentration, destroying token"); _DestroyManifestationToken(oManifester, oMfToken); + + //:: Clean up variables + _CleanManifestationVariables(oManifester); // Inform manifester FloatingTextStrRefOnCreature(16828435, oManifester, FALSE); // "You have lost concentration on the power you were attempting to manifest!" @@ -810,6 +813,25 @@ struct manifestation EvaluateManifestation(object oManifester, object oTarget, s manif.bCanManifest = FALSE; } + // Check defensive manifestation BEFORE PP deduction + if(GetLocalInt(oManifester, "PRC_DefensiveManifestActive")) + { + int nPowerLevel = GetPowerLevel(oManifester); + int nDC = 15 + nPowerLevel; + + if(!GetPRCIsSkillSuccessful(oManifester, SKILL_CONCENTRATION, nDC)) + { + // Failed - deduct PP and prevent manifestation + LosePowerPoints(oManifester, manif.nPPCost, TRUE); + PayMetapsionicsFocuses(manif); + manif.bCanManifest = FALSE; + SendMessageToPC(oManifester, "Defensive manifestation concentration check failed."); + return manif; + } + + manif.bDefensive = TRUE; + } + // Psi-like abilities ignore PP costs and metapsi if(!bIsPsiLike) { @@ -819,6 +841,25 @@ struct manifestation EvaluateManifestation(object oManifester, object oTarget, s // Psionic focus loss from using metapsionics. Has a side effect of telling the manifester which metapsionics were actually active PayMetapsionicsFocuses(manif); } + +/* if(GetLocalInt(oManifester, "PRC_DefensiveManifestActive")) + { + // Concentration check (DC 15 + power level) + int nPowerLevel = GetPowerLevel(oManifester); + int nDC = 15 + nPowerLevel; + + if(!GetPRCIsSkillSuccessful(oManifester, SKILL_CONCENTRATION, nDC)) + { + // Failed - PP already deducted, but prevent manifestation + manif.bCanManifest = FALSE; + SendMessageToPC(oManifester, "Defensive manifestion concentration check failed."); + return manif; + } + + // Set defensive flag for any other systems that need it + SendMessageToPC(oManifester, "Defensive manifestion concentration check successful."); + manif.bDefensive = TRUE; + } */ //* APPLY SIDE-EFFECTS THAT RESULT FROM SUCCESSFULL MANIFESTATION HERE *// // Psicraft for all those who can see @@ -1099,4 +1140,4 @@ struct manifestation EvaluateDiaDragChannel(object oManifester, object oTarget, } // Test main -//void main(){} +//:: void main(){} diff --git a/src/include/psi_power_const.nss b/src/include/psi_power_const.nss index 4d599c9..830dd47 100644 --- a/src/include/psi_power_const.nss +++ b/src/include/psi_power_const.nss @@ -1,3 +1,6 @@ + +const int DEFENSIVE_MANIFESTATION = 2375; + //real power spell constants // Level 1 Powers @@ -173,6 +176,7 @@ const int POWER_PSYCHICREFORMATION = 14155; const int POWER_TELEKINETICMANEUVER = 14156; const int POWER_DIMENSIONALANCHOR = 14157; const int POWER_DISMISSAL = 14158; +const int POWER_DIMENSIONDOOR = 14162; const int POWER_DIMENSIONDOOR_SELFONLY = 14159; const int POWER_DIMENSIONDOOR_PARTY = 14160; const int POWER_DOMINATE = 14161; @@ -183,6 +187,7 @@ const int POWER_ENERGYBALL_ELEC = 14166; const int POWER_ENERGYBALL_FIRE = 14167; const int POWER_ENERGYBALL_SONIC = 14168; const int POWER_PSYCHICVAMPIRE = 14169; +const int POWER_CLAW_ENERGY = 14350; const int POWER_CLAW_ENERGY_COLD = 14170; const int POWER_CLAW_ENERGY_ELEC = 14171; const int POWER_CLAW_ENERGY_FIRE = 14172; diff --git a/src/include/tob_inc_tobfunc.nss b/src/include/tob_inc_tobfunc.nss index d339082..f08997d 100644 --- a/src/include/tob_inc_tobfunc.nss +++ b/src/include/tob_inc_tobfunc.nss @@ -783,13 +783,17 @@ int GetFirstBladeMagicClassPosition(object oCreature = OBJECT_SELF) int CheckManeuverPrereqs(int nClass, int nPrereqs, int nDiscipline, object oPC) { // Checking to see what the name of the feat is, and the row number - /*if (DEBUG) +/* if (DEBUG) { DoDebug("CheckManeuverPrereqs: nFeat: " + IntToString(nFeat)); string sFeatName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat))); DoDebug("CheckManeuverPrereqs: sFeatName: " + sFeatName); - }*/ + } */ + DoDebug("CheckManeuverPrereqs: nClass=" + IntToString(nClass) + + " nDiscipline=" + IntToString(nDiscipline) + + " nPrereqs=" + IntToString(nPrereqs)); + // Prestige classes can only access certain disciplines if(!_AllowedDiscipline(oPC, nClass, nDiscipline)) return FALSE; diff --git a/src/include/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss index 5449590..54b4c57 100644 --- a/src/include/x2_inc_spellhook.nss +++ b/src/include/x2_inc_spellhook.nss @@ -327,8 +327,25 @@ int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int n default: break; } } - // Hexblade can cast in light/medium armour and while using small shield. - else if(nCastingClass == CLASS_TYPE_HEXBLADE) + + // Hexblade can cast in light armour only. + else if(nCastingClass == CLASS_TYPE_HEXBLADE) + { + //armors + switch(nAC) + { + case 1: nASF -= 5; break; //light + case 2: nASF -= 10; break; //light + case 3: nASF -= 20; break; //light + case 4: nASF = bBattleCaster ? 0 : nASF; break; //medium with Battlecaster + case 5: nASF = bBattleCaster ? 0 : nASF; break; //medium with Battlecaster + default: break; + } + } + + // WRONG: Hexblade can cast in light/medium armour and while using small shield. + //:: RIGHT: Hexblades are proficient with all simple and martial weapons, and with light armor but not with shields. +/* else if(nCastingClass == CLASS_TYPE_HEXBLADE) { //shields if(GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD) nASF -= 5; @@ -345,7 +362,7 @@ int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int n case 8: nASF -= bBattleCaster ? 45 : 0; break; default: break; } - } + } */ // Bards cannot cast in light armour and while using small shield in 3e /* else if(nCastingClass == CLASS_TYPE_BARD) { @@ -2161,10 +2178,35 @@ int PRCSpellEffects(object oCaster, object oTarget, int nSpellID, int nSpellLeve { // Pnp Tensers Transformation if(GetPRCSwitch(PRC_PNP_TENSERS_TRANSFORMATION)) - { + { + if(GetHasSpellEffect(SPELL_TENSERS_TRANSFORMATION, oCaster)) + { + // Allow potions - they are not spell trigger/completion items + object oSpellCastItem = PRCGetSpellCastItem(); + if(GetIsObjectValid(oSpellCastItem)) + { + int nItemType = GetBaseItemType(oSpellCastItem); + if(nItemType == BASE_ITEM_ENCHANTED_POTION + || nItemType == BASE_ITEM_POTIONS) + { + // Continue with other checks + } + else + { + return FALSE; // Block other magic items + } + } + else + { + return FALSE; // Block regular spellcasting + } + } + } +/* { if(GetHasSpellEffect(SPELL_TENSERS_TRANSFORMATION, oCaster)) return FALSE; - } + } */ + // Gaseous Form check if(GetHasSpellEffect(SPELL_GASEOUS_FORM, oCaster)) @@ -3757,4 +3799,4 @@ int X2PreSpellCastCode2() // Test main -//::void main(){} \ No newline at end of file +//:: void main(){} \ No newline at end of file diff --git a/src/module/ifo/module.ifo.json b/src/module/ifo/module.ifo.json index 0d1b7a1..271f23b 100644 --- a/src/module/ifo/module.ifo.json +++ b/src/module/ifo/module.ifo.json @@ -2545,6 +2545,13 @@ "value": "peps_prc8" } }, + { + "__struct_id": 8, + "Mod_Hak": { + "type": "cexostring", + "value": "prcx_shims" + } + }, { "__struct_id": 8, "Mod_Hak": { @@ -3050,6 +3057,21 @@ "type": "int", "value": 1 } + }, + { + "__struct_id": 0, + "Name": { + "type": "cexostring", + "value": "PRC_PRCX_ENABLED" + }, + "Type": { + "type": "dword", + "value": 1 + }, + "Value": { + "type": "int", + "value": 1 + } } ] } diff --git a/src/module/nss/prc_nui_consts.nss b/src/module/nss/prc_nui_consts.nss deleted file mode 100644 index 0cb0efa..0000000 --- a/src/module/nss/prc_nui_consts.nss +++ /dev/null @@ -1,113 +0,0 @@ -//:://///////////////////////////////////////////// -//:: NUI Constants -//:: prc_nui_consts -//::////////////////////////////////////////////// -/* - This file holds all the constants used by the various PRC NUI scripts. -*/ -//::////////////////////////////////////////////// -//:: Created By: Rakiov -//:: Created On: 24.05.2005 -//::////////////////////////////////////////////// - -const int NUI_PAYLOAD_BUTTON_LEFT_CLICK = 0; -const int NUI_PAYLOAD_BUTTON_MIDDLE_CLICK = 1; -const int NUI_PAYLOAD_BUTTON_RIGHT_CLICK = 2; - - -////////////////////////////////////////////////// -// // -// NUI Spellbook // -// // -////////////////////////////////////////////////// - -// This is the NUI Spellbook window ID -const string PRC_SPELLBOOK_NUI_WINDOW_ID = "prcSpellbookNui"; - -// This is the base Id for the Class buttons in the NUI Spellbook, the ID will -// have the ClassID attached to it (i.e. spellbookClassButton_123) -const string PRC_SPELLBOOK_NUI_CLASS_BUTTON_BASEID = "spellbookClassButton_"; - -// This is the base Id for the Spell Circle buttons in the NUI Spellbook, the ID will -// have the Circle attached to it (i.e. spellbookCircleButton__6) -const string PRC_SPELLBOOK_NUI_CIRCLE_BUTTON_BASEID = "spellbookCircleButton_"; - -// This is the base Id for the Spell Buttons in the NUI Spellbook, the ID will -// have the SpellbookId (the row of the class's spell's 2da or equivalent) -// attached to it (i.e. spellbookSpellButton_6) -const string PRC_SPELLBOOK_NUI_SPELL_BUTTON_BASEID = "spellbookSpellButton_"; - -// This is the base Id for the Meta Feat buttons in the NUI Spellbook, the ID will -// have the FeatID attached to it (i.e. spellbookMetaButton_12345) -const string PRC_SPELLBOOK_NUI_META_BUTTON_BASEID = "spellbookMetaButton_"; - -// This is the selected ClassID var used to store what class was selected to the Player -// locally -const string PRC_SPELLBOOK_SELECTED_CLASSID_VAR = "prcSpellbookSelectedClassID"; - -// This is the selected Circle var used to store what spell circle was selected -// to the Player locally -const string PRC_SPELLBOOK_SELECTED_CIRCLE_VAR = "prcSpellbookSelectedCircle"; - -// This is the Spellbook NUI geomeotry var, used to allow the location and sizing -// of the NUI to be remembered if it is ever rerendered. -const string PRC_SPELLBOOK_NUI_GEOMETRY_VAR = "sbNuiGeometry"; - -// This is the Selected SpellID Var, used to tell the OnTarget script what spell -// we are using after manual targetting -const string NUI_SPELLBOOK_SELECTED_SPELLID_VAR = "NUI_Spellbook_SpellId"; - -// This is the Selected FeatID Var, used to tell the OnTarget script what feat -// we are using after manual targetting -const string NUI_SPELLBOOK_SELECTED_FEATID_VAR = "NUI_Spellbook_FeatID"; - -// This is the Selected SubSpellID Var, used in conjuncture with the Selected FeatID -// to allow radial spells to work (it needs the master spell's featID and the sub spell's -// SpellID for it to work. -const string NUI_SPELLBOOK_SELECTED_SUBSPELL_SPELLID_VAR = "NUI_Spellbook_SubSpellID"; - -// This is the OnTarget action var saved to the player locally to say if we are -// using the NUI Spellbook spell or not. -const string NUI_SPELLBOOK_ON_TARGET_ACTION_VAR = "ONPLAYERTARGET_ACTION"; - -// This is a Boolean to tell the target script if the selected feat is a persoanl feat -// and can only be used on the executing object. -const string NUI_SPELLBOOK_ON_TARGET_IS_PERSONAL_FEAT = "NUI_Spellbook_IsPersonalFeat"; - -const string NUI_SPELL_DESCRIPTION_WINDOW_ID = "NUI_Spell_Description"; -const string NUI_SPELL_DESCRIPTION_OK_BUTTON = "NUIDescriptionOKButton"; - -// This is the limit of how many spell buttons we can have in a row before we -// need to start a new row on the NUI Spellbook. -const int NUI_SPELLBOOK_SPELL_BUTTON_LENGTH = 9; - -const string NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR = "NUI_Spellbook_GetBinderSpellToFeatDictionaryCache"; -const string NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR = "NUI_Spellbook_GetToBStanceSpellListCache_"; -const string NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR = "NUI_Spellbook_GetInvokerShapeSpellListCache_"; -const string NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR = "NUISpellbookClassEssence_"; - - - -////////////////////////////////////////////////// -// // -// NUI Power Attack // -// // -////////////////////////////////////////////////// - -// The Window ID for the Power Attack NUI -const string NUI_PRC_POWER_ATTACK_WINDOW = "nui_prc_power_attack_window"; - -// LocalVar for the geometry of the Power Attack NUI window -const string NUI_PRC_PA_GEOMETRY_VAR = "paNuiGeometry"; - -// Event For Left "-" button of the Power Attack NUI -const string NUI_PRC_PA_LEFT_BUTTON_EVENT = "nui_prc_pa_left_button_event"; -// Event For Right "+" Button of the Power Attack NUI -const string NUI_PRC_PA_RIGHT_BUTTON_EVENT = "nui_prc_pa_right_button_event"; - -// Bind for Text of the Power Attack NUI saying what the current Power Attack level is -const string NUI_PRC_PA_TEXT_BIND = "nui_prc_pa_text_bind"; -// Left Button Enabled Bind for Power Attack NUI -const string NUI_PRC_PA_LEFT_BUTTON_ENABLED_BIND = "leftButtonEnabled"; -// Right Button Enabled Bind for Power Attack NUI -const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled"; \ No newline at end of file diff --git a/src/module/nss/prc_nui_sb_inc.nss b/src/module/nss/prc_nui_sb_inc.nss deleted file mode 100644 index a1a768e..0000000 --- a/src/module/nss/prc_nui_sb_inc.nss +++ /dev/null @@ -1,1148 +0,0 @@ -//:://///////////////////////////////////////////// -//:: PRC Spellbook Script -//:: prc_nui_sb_inc -//::////////////////////////////////////////////// -/* - This is the script that handles some backend work for the PRC Spellbook - NUI View -*/ -//::////////////////////////////////////////////// -//:: Created By: Rakiov -//:: Created On: 24.05.2005 -//::////////////////////////////////////////////// -#include "inc_newspellbook" -#include "psi_inc_psifunc" -#include "inc_lookups" -#include "prc_nui_consts" - -// -// GetSpellListForCircle -// Gets the spell list for a specified class at the specified circle. -// -// Arguments: -// oPlayer:object the player -// nClass:int the ClassID -// circle:int the circle we want to grab for -// -// Returns: -// json:Array a list of all the spellIDs of the given circle -// -json GetSpellListForCircle(object oPlayer, int nClass, int circle); - -// -// GetSupportedNUISpellbookClasses -// Gets the list of support PRC classes that can use the NUi spellbook that -// the player has. -// -// Arguments: -// oPlayer:object the player this is being determined for -// -// Returns: -// json:int list of class ids that have the player has that can use the -// NUI spellbook. -// -json GetSupportedNUISpellbookClasses(object oPlayer); - -// -// GetCurrentSpellLevel -// Gets the current spell level the class can achieve at the current -// caster level (ranging from 0-9) -// -// Arguments: -// nClass:int the ClassID -// nLevel:int the caster level -// -// Returns: -// int the circle the class can achieve currently -// -int GetCurrentSpellLevel(int nClass, int nLevel); - -// -// GetMaxSpellLevel -// Gets the highest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest circle that can be achieved -// -int GetMaxSpellLevel(int nClass); - -// -// GetMinSpellLevel -// Gets the lowest possible circle the class can achieve (from 0-9) -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the lowest circle that can be achieved -// -int GetMinSpellLevel(int nClass); - -// -// GetHighestLevelPossibleInClass -// Given a class Id this will determine what the max level of a class can be -// achieved -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int the highest possible level the class can achieve -// -int GetHighestLevelPossibleInClass(int nClass); - -// -// GetClassSpellbookFile -// Gets the class 2da spellbook/ability for the given class Id -// -// Arguments: -// nClass:int the classID -// -// Returns: -// string the 2da file name for the spell/abilities of the ClassID -// -string GetClassSpellbookFile(int nClass); - -// -// IsSpellKnown -// Returns whether the player with the given class, spell file, and spellbook id -// knows the spell or not -// -// Arguments: -// oPlayer;Object the player -// nClass:int the class ID -// spellId:int the spell ID to check -// -// Returns: -// int:Boolean TRUE if spell is known, FALSE otherwise -// -int IsSpellKnown(object oPlayer, int nClass, int spellId); - -// -// IsClassAllowedToUseNUISpellbook -// Takes a player and a classId and determines if thee class is allowed to -// be using the NUI spellbook. -// -// Arguments: -// oPlayer:Object the player -// nClass:int the ClassID -// -// Returns: -// int:Boolean TRUE if allowed to use the spellbook, FALSE otherwise -// -int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass); - -// -// CanClassUseMetamagicFeats -// Given a class id determines if it is allowed to use the Metamagic feats -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise -// -int CanClassUseMetamagicFeats(int nClass); - -// -// CanClassUseSuddenMetamagicFeats -// Given a class id determines if it is allowed to use the Sudden Metamagic feats -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise -// -int CanClassUseSuddenMetamagicFeats(int nClass); - -// -// CanClassUseMetaPsionicFeats -// Given a class id determines if it is allowed to use the MetaPsionic feats -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise -// -int CanClassUseMetaPsionicFeats(int nClass); - -// -// CanClassUseMetaMysteryFeats -// Given a class id determines if it is allowed to use the MetaMystery feats -// -// Arguments: -// nClass:int the ClassID -// -// Returns: -// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise -// -int CanClassUseMetaMysteryFeats(int nClass); - -// -// GetMetaMagicFeatList -// Gets the list of MetaMagic featIDs -// -// Returns: -// json:Array the list of FeatIDs associated with the meta feats -// -json GetMetaMagicFeatList(); - -// -// GetSuddenMetaMagicFeatList -// Gets the list of Sudden MetaMagic featIDs -// -// Returns: -// json:Array the list of FeatIDs associated with the meta feats -// -json GetSuddenMetaMagicFeatList(); - -// -// GetMetaPsionicFeatList -// Gets the list of MetaPsionic featIDs -// -// Returns: -// json:Array the list of FeatIDs associated with the meta feats -// -json GetMetaPsionicFeatList(); - -// -// GetMetaMagicMysteryList -// Gets the list of MetaMystery featIDs -// -// Returns: -// json:Array the list of FeatIDs associated with the meta feats -// -json GetMetaMysteryFeatList(); - -// -// GetTrueClassIfRHD -// Checks to make sure if the provided RHD class and player's race -// match up to give them their proper spell caster class (ie Glouras have -// bard spells and thus should be treated like a bard class) -// -// Arguments: -// oPlayer:object the player -// nClass:int the ClassID -// -// Returns: -// int the true ClassID to use, otherwise nClass -// -int GetTrueClassIfRHD(object oPlayer, int nClass); - -// -// GetBinderSpellToFeatDictionary -// Sets up the Binder Spell Dictionary that is used to match a binder's vestige -// to their feat. This is constructed based off the binder's known location of -// their feat and spell ranges in the base 2das respectivly. After constructing -// this it will be saved to the player locally as a cached result since we do -// not need to call this again. -// -// Argument: -// oPlayer:object the player -// -// Returns: -// json:Dictionary a dictionary of mapping between the SpellID -// and the FeatID of a vestige ability -// -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF); - -// -// ShouldAddSpell -// Given a spellId and a class, determines if the spell should be added to the -// spellbook (as some are added in it's own special row or for other reasons) -// -// Arguments: -// nClass:int the ClassID -// spellId:int the SpellID -// oPlayer:object the player -// -// Returns: -// int:Boolean TRUE if the spell should be added, FALSE otherwise -// -int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF); - -// -// GetToBStanceSpellList -// Gets the ToB Stance Spell List for the given class -// -// Arguments: -// nClass:int ClassID -// oPlayer:object the player -// -// Returns: -// json:Array the list of stances' SpellIDs -// -json GetToBStanceSpellList(int nClass, object oPlayer=OBJECT_SELF); - -// -// GetInvokerShapeSpellList -// Gets the Invoker Shapes Spell List for the given class -// -// Arguments: -// nClass:int ClassID -// oPlayer:object the player -// -// Returns: -// json:Array the list of shapes' SpellIDs -// -json GetInvokerShapeSpellList(int nClass, object oPlayer=OBJECT_SELF); - -// -// GetInvokerEssenceSpellList -// Gets the Invoker Essences Spell List for the given class -// -// Arguments: -// nClass:int ClassID -// oPlayer:object the player -// -// Returns: -// json:Array the list of essences' SpellIDs -// -json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF); - -// -// JsonArrayContainsInt -// A helper function that takes a json array list and sees if the int item is within i -// -// Arguments: -// list:json:Array the list of ints -// item:int the item we are looking for -// -// Returns: -// int:Boolean TRUE if item is found, FALSE otherwise -// -int JsonArrayContainsInt(json list, int item); - -json GetSpellListForCircle(object oPlayer, int nClass, int circle) -{ - json retValue = JsonArray(); - string sFile = GetClassSpellbookFile(nClass); - int totalSpells; - json binderDictKeys; - //Special case for Binder since they don't have their own spellbook 2da - if (nClass == CLASS_TYPE_BINDER) - { - json binderDict = GetBinderSpellToFeatDictionary(oPlayer); - - // we loop through the list of SpellIDs - binderDictKeys = JsonObjectKeys(binderDict); - totalSpells = JsonGetLength(binderDictKeys); - } - else - totalSpells = Get2DARowCount(sFile); - - int i; - for (i = 0; i < totalSpells; i++) - { - int currentSpell; - if (nClass == CLASS_TYPE_BINDER) - currentSpell = StringToInt(JsonGetString(JsonArrayGet(binderDictKeys, i))); - else - currentSpell = StringToInt(Get2DACache(sFile, "SpellID", i)); - - if (ShouldAddSpell(nClass, currentSpell, oPlayer)) - { - string sSpellLevel = Get2DACache("spells", "Innate", currentSpell); - int iSpellLevel = StringToInt(sSpellLevel); - - if (nClass == CLASS_TYPE_BINDER && IsSpellKnown(oPlayer, nClass, currentSpell)) - { - retValue = JsonArrayInsert(retValue, JsonInt(currentSpell)); - } - else if ((iSpellLevel == circle && IntToString(iSpellLevel) == sSpellLevel)) - { - // We add the spell if it is known and is not a radial master spell (since those don't work) - if (IsSpellKnown(oPlayer, nClass, currentSpell)) - retValue = JsonArrayInsert(retValue, JsonInt(i)); - } - } - } - - return retValue; -} - -int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF) -{ - int isRadialMasterSpell = StringToInt(Get2DACache("spells", "SubRadSpell1", spellId)); - // We don't add radial master spells - if (isRadialMasterSpell) - return FALSE; - // we don't add essences and shapes - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT - || nClass == CLASS_TYPE_DRAGON_SHAMAN) - { - json ignoreList = GetInvokerShapeSpellList(nClass, oPlayer); - if (JsonArrayContainsInt(ignoreList, spellId)) - return FALSE; - ignoreList = GetInvokerEssenceSpellList(nClass, oPlayer); - if (JsonArrayContainsInt(ignoreList, spellId)) - return FALSE; - } - // we don't add stances - if (nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER) - { - json ignoreList = GetToBStanceSpellList(nClass, oPlayer); - if (JsonArrayContainsInt(ignoreList, spellId)) - return FALSE; - } - - return TRUE; -} - -json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF) -{ - // a dictionary of - json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR); - // if this hasn't been created, create it now. - if (binderDict == JsonNull()) - binderDict = JsonObject(); - else - return binderDict; - - // the starting row for binder spells - int spellIndex = 19070; - // the starting row for binder feats - int featIndex = 9030; - //the end of the binder spells/feats - while (spellIndex <= 19156 && featIndex <= 9104) - { - // get the SpellID tied to the feat - int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex)); - // if the spellID matches the current index, then this is the spell - // attached to the feat - if (spellID == spellIndex) - { - binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex)); - - // move to next spell/feat - featIndex++; - spellIndex++; - } - // else we have reached a subdial spell - else - { - // loop through until we reach back at spellID - while (spellIndex < spellID) - { - int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex)); - - // add the sub radial to the dict, tied to the master's FeatID - int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell))); - binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId)); - - spellIndex++; - } - - - // some feats overlap the same FeatID, can cause this to get stuck. - // if it happens then move on - if (spellIndex > spellID) - featIndex++; - } - } - - // cache the result - SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict); - return binderDict; -} - -string GetClassSpellbookFile(int nClass) -{ - string sFile; - // Spontaneous casters use a specific file name structure - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = GetFileForClass(nClass); - } - // everyone else uses this structure - else - { - sFile = GetAMSDefinitionFileName(nClass); - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "vestiges"; - } - } - - return sFile; -} - -json GetSupportedNUISpellbookClasses(object oPlayer) -{ - json retValue = JsonArray(); - int i = 1; - while(i >= 1) - { - int classId = GetClassByPosition(i, oPlayer); - if (classId != CLASS_TYPE_INVALID) - { - if (IsClassAllowedToUseNUISpellbook(oPlayer, classId)) - { - classId = GetTrueClassIfRHD(oPlayer, classId); - retValue = JsonArrayInsert(retValue, JsonInt(classId)); - } - i++; - } - else - { - i = -1; - } - } - - return retValue; -} - -int IsSpellKnown(object oPlayer, int nClass, int spellId) -{ - // special case for Binders since they don't have a spell book 2da. - if (nClass == CLASS_TYPE_BINDER) - { - json binderDict = GetBinderSpellToFeatDictionary(oPlayer); - int featID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); - return GetHasFeat(featID, oPlayer); - } - - int currentSpell = spellId; - int masterSpell = StringToInt(Get2DACache("spells", "Master", currentSpell)); - if (masterSpell) // If this is not 0 then this is a radial spell, check the radial master - currentSpell = masterSpell; - - string sFeatID = Get2DACache("spells", "FeatID", currentSpell); - int iFeatID = StringToInt(sFeatID); - - if (IntToString(iFeatID) == sFeatID) - return GetHasFeat(iFeatID, oPlayer); - - return FALSE; -} - -int GetCurrentSpellLevel(int nClass, int nLevel) -{ - int currentLevel = nLevel; - - // ToB doesn't have a concept of spell levels, but still match up to it - if(nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_SHADOWCASTER) - { - return 9; - } - - - // Binders don't really have a concept of spell level - if (nClass == CLASS_TYPE_BINDER - || nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle - return 1; - - //Shadowsmith has no concept of spell levels - if (nClass == CLASS_TYPE_SHADOWSMITH) - return 2; - - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - return 4; - - // Spont casters have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - - int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel); - return maxLevel; - } - else - { - // everyone else uses this - string spellLevel2da = GetAMSKnownFileName(nClass); - - currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da - - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND) - currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1; - - int totalLevel = Get2DARowCount(spellLevel2da); - - // in case we somehow go over bounds just don't :) - if (currentLevel >= totalLevel) - currentLevel = totalLevel - 1; - - //Psionics have MaxPowerLevel as their column name - string columnName = "MaxPowerLevel"; - - //Invokers have MaxInvocationLevel - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - columnName = "MaxInvocationLevel"; - - // Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range - if (nClass == CLASS_TYPE_TRUENAMER) - { - columnName = "EvolvingMind"; - spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - columnName = "VestigeLvl"; - spellLevel2da = "cls_bind_binder"; - } - - // ToB doesn't have a concept of this, but we don't care. - - int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel)); - return maxLevel; - } -} - -int GetMinSpellLevel(int nClass) -{ - // again sponts have their own function - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass)); - } - else - { - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND - || nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER - || nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_SHADOWCASTER - || nClass == CLASS_TYPE_SHADOWSMITH - || nClass == CLASS_TYPE_BINDER) - return 1; - - return GetCurrentSpellLevel(nClass, 1); - } - -} - -int GetMaxSpellLevel(int nClass) -{ - if (nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSION) - return 9; - if (nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_WARMIND) - return 5; - if (nClass == CLASS_TYPE_PSYWAR) - return 6; - - return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass)); -} - -int GetHighestLevelPossibleInClass(int nClass) -{ - string sFile; - - //sponts have their spells in the classes.2da - if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS - || nClass == CLASS_TYPE_ARCHIVIST) - { - sFile = Get2DACache("classes", "SpellGainTable", nClass); - } - else - { - // everyone else uses this - sFile = GetAMSKnownFileName(nClass); - - if (nClass == CLASS_TYPE_TRUENAMER) - { - sFile = "cls_true_maxlvl"; //has a different 2da we want to look at - } - - if (nClass == CLASS_TYPE_BINDER) - { - sFile = "cls_bind_binder"; - } - } - - return Get2DARowCount(sFile); -} - -int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) -{ - // This controls who can use the Spellbook NUI, if for some reason you don't - // want a class to be allowed to use this you can comment out their line here - - // Bard and Sorc are allowed if they took a PRC that makes them use the spellbook - if ((nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER) - && GetPrCAdjustedClassLevel(nClass, oPlayer) > GetLevelByClass(nClass, oPlayer)) - return TRUE; - - // Arcane Spont - if (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BEGUILER - || nClass == CLASS_TYPE_CELEBRANT_SHARESS - || nClass == CLASS_TYPE_DREAD_NECROMANCER - || nClass == CLASS_TYPE_DUSKBLADE - || nClass == CLASS_TYPE_HARPER - || nClass == CLASS_TYPE_HEXBLADE - || nClass == CLASS_TYPE_KNIGHT_WEAVE - || nClass == CLASS_TYPE_SHADOWLORD - || nClass == CLASS_TYPE_SUBLIME_CHORD - || nClass == CLASS_TYPE_SUEL_ARCHANAMACH - || nClass == CLASS_TYPE_WARMAGE) - return TRUE; - - // Psionics - if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WILDER - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_WARMIND) - return TRUE; - - // Invokers - if (nClass == CLASS_TYPE_WARLOCK - || nClass == CLASS_TYPE_DRAGON_SHAMAN - || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - return TRUE; - - // Divine Spont - if (nClass == CLASS_TYPE_ARCHIVIST //while technically prepared, they use the spont system of casting - || nClass == CLASS_TYPE_FAVOURED_SOUL - || nClass == CLASS_TYPE_JUSTICEWW) - return TRUE; - - // ToB Classes - if (nClass == CLASS_TYPE_WARBLADE - || nClass == CLASS_TYPE_SWORDSAGE - || nClass == CLASS_TYPE_CRUSADER) - return TRUE; - - // Mystery Classes - if (nClass == CLASS_TYPE_SHADOWCASTER - || nClass == CLASS_TYPE_SHADOWSMITH) - return TRUE; - - // Truenamers - if (nClass == CLASS_TYPE_TRUENAMER) - return TRUE; - - // RHD Casters - if ((nClass == CLASS_TYPE_SHAPECHANGER - && GetRacialType(oPlayer) == RACIAL_TYPE_ARANEA - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_OUTSIDER - && GetRacialType(oPlayer) == RACIAL_TYPE_RAKSHASA - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_ABERRATION - && GetRacialType(oPlayer) == RACIAL_TYPE_DRIDER - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_ARKAMOI - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_HOBGOBLIN_WARSOUL - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_REDSPAWN_ARCANISS - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_MARRUTACT - && !GetLevelByClass(CLASS_TYPE_SORCERER)) - || (nClass == CLASS_TYPE_FEY - && GetRacialType(oPlayer) == RACIAL_TYPE_GLOURA - && !GetLevelByClass(CLASS_TYPE_BARD))) - return TRUE; - - // Binders - if (nClass == CLASS_TYPE_BINDER) - return TRUE; - - return FALSE; -} - -int GetTrueClassIfRHD(object oPlayer, int nClass) -{ - if (nClass == CLASS_TYPE_SHAPECHANGER - && GetRacialType(oPlayer) == RACIAL_TYPE_ARANEA) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_OUTSIDER - && GetRacialType(oPlayer) == RACIAL_TYPE_RAKSHASA) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_ABERRATION - && GetRacialType(oPlayer) == RACIAL_TYPE_DRIDER) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_ARKAMOI) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_HOBGOBLIN_WARSOUL) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_REDSPAWN_ARCANISS) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_MONSTROUS - && GetRacialType(oPlayer) == RACIAL_TYPE_MARRUTACT) - return CLASS_TYPE_SORCERER; - if (nClass == CLASS_TYPE_FEY - && GetRacialType(oPlayer) == RACIAL_TYPE_GLOURA) - return CLASS_TYPE_BARD; - - return nClass; -} - -int CanClassUseMetamagicFeats(int nClass) -{ - // I don't want to spend the time looping through each class's - // feat 2da so this is the list of all classes that are allowed to use the - // Spellbook NUI and can use Metamagic - return (nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_BEGUILER - || nClass == CLASS_TYPE_DREAD_NECROMANCER - || nClass == CLASS_TYPE_DUSKBLADE - || nClass == CLASS_TYPE_HEXBLADE - || nClass == CLASS_TYPE_JUSTICEWW - || nClass == CLASS_TYPE_SUBLIME_CHORD - || nClass == CLASS_TYPE_SUEL_ARCHANAMACH - || nClass == CLASS_TYPE_FAVOURED_SOUL - || nClass == CLASS_TYPE_WARMAGE); -} - -int CanClassUseSuddenMetamagicFeats(int nClass) -{ - // I don't want to spend the time looping through each class's - // feat 2da so this is the list of all classes that are allowed to use the - // Spellbook NUI and can use Sudden Metamagic - return (nClass == CLASS_TYPE_SHADOWLORD - || nClass == CLASS_TYPE_ARCHIVIST - || nClass == CLASS_TYPE_ASSASSIN - || nClass == CLASS_TYPE_BARD - || nClass == CLASS_TYPE_BEGUILER - || nClass == CLASS_TYPE_DREAD_NECROMANCER - || nClass == CLASS_TYPE_DUSKBLADE - || nClass == CLASS_TYPE_FAVOURED_SOUL - || nClass == CLASS_TYPE_HEXBLADE - || nClass == CLASS_TYPE_JUSTICEWW - || nClass == CLASS_TYPE_KNIGHT_WEAVE - || nClass == CLASS_TYPE_SUBLIME_CHORD - || nClass == CLASS_TYPE_SORCERER - || nClass == CLASS_TYPE_SUEL_ARCHANAMACH - || nClass == CLASS_TYPE_WARMAGE); -} - -int CanClassUseMetaPsionicFeats(int nClass) -{ - // I don't want to spend the time looping through each class's - // feat 2da so this is the list of all classes that are allowed to use the - // Spellbook NUI and can use Metapsionics - return (nClass == CLASS_TYPE_FIST_OF_ZUOKEN - || nClass == CLASS_TYPE_PSION - || nClass == CLASS_TYPE_PSYCHIC_ROGUE - || nClass == CLASS_TYPE_PSYWAR - || nClass == CLASS_TYPE_WARMIND - || nClass == CLASS_TYPE_WILDER); -} - -int CanClassUseMetaMysteryFeats(int nClass) -{ - // I don't want to spend the time looping through each class's - // feat 2da so this is the list of all classes that are allowed to use the - // Spellbook NUI and can use Metamysteries - return (nClass == CLASS_TYPE_SHADOWCASTER - || nClass == CLASS_TYPE_SHADOWSMITH); -} - -json GetMetaMagicFeatList() -{ - json metaFeats = JsonArray(); - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_STILL_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SILENT_SPELL_ABILITY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - - return metaFeats; -} - -json GetSuddenMetaMagicFeatList() -{ - json metaFeats = JsonArray(); - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_EXTEND)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_EMPOWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_MAXIMIZE)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_WIDEN)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - - return metaFeats; -} - -json GetMetaPsionicFeatList() -{ - json metaFeats = JsonArray(); - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_WIDEN_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_CHAIN_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_TWIN_POWER)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SPLIT_PSIONIC_RAY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - - return metaFeats; -} - -json GetMetaMysteryFeatList() -{ - json metaFeats = JsonArray(); - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_MYSTERY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_MYSTERY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_MYSTERY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_MYSTERY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_STILL_MYSTERY)); - metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); - - return metaFeats; -} - -json GetToBStanceSpellList(int nClass, object oPlayer=OBJECT_SELF) -{ - // caching - json stanceSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR + IntToString(nClass)); - if (stanceSpells == JsonNull()) - stanceSpells = JsonArray(); - else - return stanceSpells; - - string sFile = GetClassSpellbookFile(nClass); - int totalRows = Get2DARowCount(sFile); - - int i; - for (i = 0; i < totalRows; i++) - { - int Type = StringToInt(Get2DACache(sFile, "Type", i)); - if (Type == 1) - { - int spellId = StringToInt(Get2DACache(sFile, "SpellID", i)); - stanceSpells = JsonArrayInsert(stanceSpells, JsonInt(spellId)); - } - } - - SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR + IntToString(nClass), stanceSpells); - return stanceSpells; -} - -json GetInvokerShapeSpellList(int nClass, object oPlayer=OBJECT_SELF) -{ - // caching - json shapeSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR + IntToString(nClass)); - if (shapeSpells == JsonNull()) - shapeSpells = JsonArray(); - else - return shapeSpells; - - string sFile = GetClassSpellbookFile(nClass); - int totalRows = Get2DARowCount(sFile); - - if (nClass == CLASS_TYPE_WARLOCK) - { - // Add the ELdritch Blast shapes - // TODO: Replace these magic SpellID ints with consts - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(INVOKE_ELDRITCH_BLAST)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18216)); // Eldritch Chain - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18245)); // Eldritch Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18261)); // Eldritch Doom - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18172)); // Glaive - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18246)); // Eldritch Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18173)); // Eldritch Spear - } - - if (nClass == CLASS_TYPE_DRAGON_SHAMAN) - { - // Add the Dragon Shaman Auras - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_ENERGY)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_ENERGYSHLD)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_INSIGHT)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_MAGICPOWER)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_POWER)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_PRESENCE)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_RESISTANCE)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_RESOLVE)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_SENSES)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_STAMINA)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_SWIFTNESS)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_TOUGHNESS)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_VIGOR)); - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); - } - - if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - { - // Add Dragon Adept Breaths - // TODO: Replace these magic SpellID ints with consts - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2102)); // Fire Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2103)); // Fire Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2104)); // Frost Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2105)); // Electric Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2106)); // Sickness Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2108)); // Acid Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2109)); // Acid Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2111)); // Slow Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2112)); // Weakening Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2115)); // Sleep Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2116)); // Thunder Cone - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2117)); // Bahamut Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2118)); // Force Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2119)); // Paralyzation Line - shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2120)); // Tiamat Breath - } - - - SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR + IntToString(nClass), shapeSpells); - return shapeSpells; -} - -json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF) -{ - //caching - json essenceSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR + IntToString(nClass)); - if (essenceSpells == JsonNull()) - essenceSpells = JsonArray(); - else - return essenceSpells; - - if (nClass == CLASS_TYPE_WARLOCK) - { - // Add Eldritch Essences - // TODO: Replace these magic SpellID ints with consts - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18177)); // Hideous Blow - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18189)); // Baneful Abberation - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18190)); // Baneful Beast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18191)); // Baneful Construct - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18192)); // Baneful Dragon - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18193)); // Baneful Dwarf - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18194)); // Baneful Elemental - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18195)); // Baneful Elf - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18196)); // baneful Fey - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18197)); // Baneful Giant - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18198)); // Baneful Goblinoid - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18199)); // Baneful Gnome - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18200)); // Baneful Halfling - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18201)); // Baneful Human - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18202)); // Baneful Monsterous - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18203)); // Baneful Orc - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18204)); // Baneful Outsider - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18205)); // Baneful Plant - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18206)); // Baneful Reptilian - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18207)); // Baneful Shapechanger - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18208)); // Baneful Undead - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18209)); // Baneful Vermin - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18210)); // Beshadowed Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18240)); // Bewitching Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18257)); // Binding Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18211)); // Brimstone Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18175)); // Frightful Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18176)); // Hammer Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18183)); // Sickening Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HEALING_BLAST)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_BLAST)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_BLOW)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_CHAIN)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_CONE)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_DOOM)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_GLAIVE)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_LINE)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_SPEAR)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18220)); // Hellrime Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18177)); // Hideous Blow - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18249)); // Hindering Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18251)); // Noxious Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18253)); // Penetrating Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18267)); // Utterdark Blast - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18255)); // Vitriolic Blast - } - - if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) - { - // Add the Dragonfire Adept Shapes - int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SHAPED_ADEPTBREATH)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_CLOUD_ADEPTBREATH)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); - spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_ENDURE_ADEPTBREATH)); - essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); - } - - SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR + IntToString(nClass), essenceSpells); - return essenceSpells; -} - -int JsonArrayContainsInt(json list, int item) -{ - int totalCount = JsonGetLength(list); - - int i; - for (i = 0; i < totalCount; i++) - { - if (JsonGetInt(JsonArrayGet(list, i)) == item) - return TRUE; - } - - return FALSE; -} \ No newline at end of file diff --git a/src/module/nss/prc_nui_sbd_inc.nss b/src/module/nss/prc_nui_sbd_inc.nss deleted file mode 100644 index 4f84658..0000000 --- a/src/module/nss/prc_nui_sbd_inc.nss +++ /dev/null @@ -1,98 +0,0 @@ -//:://///////////////////////////////////////////// -//:: PRC Spellbook Description NUI -//:: prc_nui_sbd_inc -//::////////////////////////////////////////////// -/* - This is the view for the Spell Description NUI -*/ -//::////////////////////////////////////////////// -//:: Created By: Rakiov -//:: Created On: 29.05.2005 -//::////////////////////////////////////////////// -#include "nw_inc_nui" -#include "prc_nui_consts" -#include "inc_2dacache" - -// -// CreateSpellDescriptionNUI -// Creates a Spell Description NUI mimicing the description GUI of NWN -// -// Arguments: -// oPlayer:Object the player object -// featID:int the FeatID -// spellId:int the SpellID -// realSpellId:int the RealSpellID -// -void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0); - -void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0) -{ - // look for existing window and destroy - int nPreviousToken = NuiFindWindow(OBJECT_SELF, NUI_SPELL_DESCRIPTION_WINDOW_ID); - if(nPreviousToken != 0) - { - NuiDestroy(OBJECT_SELF, nPreviousToken); - } - - // in order of accuracy for names it goes RealSpellID > SpellID > FeatID - string spellName; - if (realSpellId) - spellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellId))); - else if (spellId) - spellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); - else - spellName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featID))); - // Descriptions and Icons are accuratly stored on the feat - string spellDesc = GetStringByStrRef(StringToInt(Get2DACache("feat", "DESCRIPTION", featID))); - string spellIcon = Get2DACache("feat", "ICON", featID); - - json jRoot = JsonArray(); - json jGroup = JsonArray(); - - json jRow = JsonArray(); - - json jImage = NuiImage(JsonString(spellIcon), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_TOP)); - jImage = NuiWidth(jImage, 32.0f); - jRow = JsonArrayInsert(jRow, jImage); - jRow = NuiCol(jRow); - jGroup = JsonArrayInsert(jGroup, jRow); - - jRow = JsonArray(); - json jText = NuiText(JsonString(spellDesc), FALSE, NUI_SCROLLBARS_AUTO); - jRow = JsonArrayInsert(jRow, jText); - jRow = NuiCol(jRow); - jGroup = JsonArrayInsert(jGroup, jRow); - - jGroup = NuiRow(jGroup); - jGroup = NuiGroup(jGroup, TRUE, NUI_SCROLLBARS_NONE); - jRoot = JsonArrayInsert(jRoot, jGroup); - - jRow = JsonArray(); - jRow = JsonArrayInsert(jRow, NuiSpacer()); - json jButton = NuiId(NuiButton(JsonString("OK")), NUI_SPELL_DESCRIPTION_OK_BUTTON); - jButton = NuiWidth(jButton, 175.0f); - jButton = NuiHeight(jButton, 48.0f); - jRow = JsonArrayInsert(jRow, jButton); - jRow = NuiRow(jRow); - - jRoot = JsonArrayInsert(jRoot, jRow); - jRoot = NuiCol(jRoot); - - - // This is the main window with jRoot as the main pane. It includes titles and parameters (more on those later) - json nui = NuiWindow(jRoot, JsonString(spellName), NuiBind("geometry"), NuiBind("resizable"), JsonBool(FALSE), NuiBind("closable"), NuiBind("transparent"), NuiBind("border")); - - // finally create it and it'll return us a non-zero token. - int nToken = NuiCreate(oPlayer, nui, NUI_SPELL_DESCRIPTION_WINDOW_ID); - - // get the geometry of the window in case we opened this before and have a - // preference for location - json geometry = NuiRect(893.0f,346.0f, 426.0f, 446.0f); - - // Set the binds to their default values - NuiSetBind(oPlayer, nToken, "geometry", geometry); - NuiSetBind(oPlayer, nToken, "resizable", JsonBool(FALSE)); - NuiSetBind(oPlayer, nToken, "closable", JsonBool(FALSE)); - NuiSetBind(oPlayer, nToken, "transparent", JsonBool(FALSE)); - NuiSetBind(oPlayer, nToken, "border", JsonBool(TRUE)); -}