diff --git a/src/include/inc_item_props.nss b/src/include/inc_item_props.nss index b912fad..6d64181 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); @@ -1231,6 +1233,12 @@ void DeletePRCLocalIntsT(object oPC, object oItem = OBJECT_INVALID) DeleteLocalInt(oItem,"DispIronPowerD"); // Dragonwrack DeleteLocalInt(oItem,"DWright"); + // Circle Magic + DeleteLocalInt(OBJECT_SELF, "CircleMagicActive"); + DeleteLocalInt(OBJECT_SELF, "CircleMagicTotal"); + DeleteLocalString(OBJECT_SELF, "CircleMagicClass"); + DeleteLocalInt(OBJECT_SELF, "CircleMagicMaxParticipants"); + DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_ADJUSTMENT); } // LEFT HAND diff --git a/src/include/inc_newspellbook.nss b/src/include/inc_newspellbook.nss index 5a06b4d..e39b95f 100644 --- a/src/include/inc_newspellbook.nss +++ b/src/include/inc_newspellbook.nss @@ -1621,3 +1621,6 @@ void DoCleanUp(int nMetamagic) DeleteLocalInt(OBJECT_SELF, "NSB_SpellLevel"); DeleteLocalInt(OBJECT_SELF, "NSB_SpellbookID"); } + +//:: Test Void +//:: void main (){} \ No newline at end of file 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_inc_invoke.nss b/src/include/inv_inc_invoke.nss index da67444..094c252 100644 --- a/src/include/inv_inc_invoke.nss +++ b/src/include/inv_inc_invoke.nss @@ -478,7 +478,8 @@ void UseInvocation(int nInvocation, int nClass, int nLevelOverride = 0, int bIns ActionDoCommand(_SetInvocationVariables(oInvoker, nClass, StringToInt(lookup_spell_innate(nInvocation)))); // Cast the actual invocation - ActionCastSpell(nInvocation, nLevelOverride, 0, 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstant); + //ActionCastSpell(nInvocation, nLevelOverride, 0, 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstant); + ActionCastSpell(nInvocation, nLevelOverride, 0, 0, METAMAGIC_NONE, nClass, 0, 0, OBJECT_INVALID, bInstant); // Initiate invocation-related variable CleanUp ActionDoCommand(_CleanInvocationVariables(oInvoker)); 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_cv_inc.nss b/src/include/prc_craft_cv_inc.nss new file mode 100644 index 0000000..9081ba0 --- /dev/null +++ b/src/include/prc_craft_cv_inc.nss @@ -0,0 +1,1057 @@ + +//:: prc_craft_cv_inc.nss + +#include "prc_craft_inc" +#include "inc_dynconv" + +////////////////////////////////////////////////// +/* Constant defintions */ +////////////////////////////////////////////////// + +//const int STAGE_ = ; + +const int STAGE_START = 0; +const int STAGE_SELECT_SUBTYPE = 1; +const int STAGE_SELECT_COSTTABLEVALUE = 2; +const int STAGE_SELECT_PARAM1VALUE = 3; +const int STAGE_CONFIRM = 4; +const int STAGE_BANE = 5; + +const int STAGE_CONFIRM_MAGIC = 7; +const int STAGE_APPEARANCE = 8; +const int STAGE_CLONE = 9; +const int STAGE_APPEARANCE_LIST = 10; +const int STAGE_APPEARANCE_VALUE = 11; +const int STAGE_CRAFT_GOLEM = 12; +const int STAGE_CRAFT_GOLEM_HD = 13; +const int STAGE_CRAFT_ALCHEMY = 14; +const int STAGE_CONFIRM_ALCHEMY = 15; +const int STAGE_CRAFT_POISON = 16; +const int STAGE_CONFIRM_POISON = 17; +const int STAGE_CRAFT_LICH = 18; +const int STAGE_CRAFT = 101; +const int STAGE_CRAFT_SELECT = 102; +const int STAGE_CRAFT_MASTERWORK = 103; +const int STAGE_CRAFT_AC = 104; +const int STAGE_CRAFT_MIGHTY = 105; +const int STAGE_CRAFT_CONFIRM = 106; + +//const int STAGE_CRAFT = 101; + + +//const int CHOICE_ = ; + +//these must be past the highest 2da entry to be read +const int CHOICE_FORGE = 20001; +const int CHOICE_BOOST = 20002; +const int CHOICE_BACK = 20003; +const int CHOICE_CLEAR = 20004; +const int CHOICE_CONFIRM = 20005; +const int CHOICE_SETNAME = 20006; +const int CHOICE_SETAPPEARANCE = 20007; +const int CHOICE_CLONE = 20008; + +const int CHOICE_APPEARANCE_SHOUT = 20009; +const int CHOICE_APPEARANCE_SELECT = 20010; + +const int CHOICE_PLUS_1 = 20011; +const int CHOICE_PLUS_10 = 20012; +const int CHOICE_MINUS_1 = 20013; +const int CHOICE_MINUS_10 = 20014; + +const int CHOICE_CRAFT = 20101; + +//const int NUM_MAX_COSTTABLEVALUES = 70; +//const int NUM_MAX_PARAM1VALUES = 70; + +const int HAS_SUBTYPE = 1; +const int HAS_COSTTABLE = 2; +const int HAS_PARAM1 = 4; + +const int STRREF_YES = 4752; // "Yes" +const int STRREF_NO = 4753; // "No" + +const string PRC_CRAFT_ITEM = "PRC_CRAFT_ITEM"; +const string PRC_CRAFT_TYPE = "PRC_CRAFT_TYPE"; +const string PRC_CRAFT_SUBTYPE = "PRC_CRAFT_SUBTYPE"; +const string PRC_CRAFT_SUBTYPEVALUE = "PRC_CRAFT_SUBTYPEVALUE"; +const string PRC_CRAFT_COSTTABLE = "PRC_CRAFT_COSTTABLE"; +const string PRC_CRAFT_COSTTABLEVALUE = "PRC_CRAFT_COSTTABLEVALUE"; +const string PRC_CRAFT_PARAM1 = "PRC_CRAFT_PARAM1"; +const string PRC_CRAFT_PARAM1VALUE = "PRC_CRAFT_PARAM1VALUE"; +const string PRC_CRAFT_PROPLIST = "PRC_CRAFT_PROPLIST"; +const string PRC_CRAFT_COST = "PRC_CRAFT_COST"; +const string PRC_CRAFT_XP = "PRC_CRAFT_XP"; +const string PRC_CRAFT_TIME = "PRC_CRAFT_TIME"; +//const string PRC_CRAFT_BLUEPRINT = "PRC_CRAFT_BLUEPRINT"; +const string PRC_CRAFT_CONVO_ = "PRC_CRAFT_CONVO_"; +const string PRC_CRAFT_BASEITEMTYPE = "PRC_CRAFT_BASEITEMTYPE"; +const string PRC_CRAFT_AC = "PRC_CRAFT_AC"; +const string PRC_CRAFT_MIGHTY = "PRC_CRAFT_MIGHTY"; +const string PRC_CRAFT_MATERIAL = "PRC_CRAFT_MATERIAL"; +const string PRC_CRAFT_TAG = "PRC_CRAFT_TAG"; +const string PRC_CRAFT_LINE = "PRC_CRAFT_LINE"; +const string PRC_CRAFT_FILE = "PRC_CRAFT_FILE"; + +const string PRC_CRAFT_MAGIC_ENHANCE = "PRC_CRAFT_MAGIC_ENHANCE"; +const string PRC_CRAFT_MAGIC_ADDITIONAL = "PRC_CRAFT_MAGIC_ADDITIONAL"; +const string PRC_CRAFT_MAGIC_EPIC = "PRC_CRAFT_MAGIC_EPIC"; + +const string PRC_CRAFT_SCRIPT_STATE = "PRC_CRAFT_SCRIPT_STATE"; + +const string ARTIFICER_PREREQ_RACE = "ARTIFICER_PREREQ_RACE"; +const string ARTIFICER_PREREQ_ALIGN = "ARTIFICER_PREREQ_ALIGN"; +const string ARTIFICER_PREREQ_CLASS = "ARTIFICER_PREREQ_CLASS"; +const string ARTIFICER_PREREQ_SPELL1 = "ARTIFICER_PREREQ_SPELL1"; +const string ARTIFICER_PREREQ_SPELL2 = "ARTIFICER_PREREQ_SPELL2"; +const string ARTIFICER_PREREQ_SPELL3 = "ARTIFICER_PREREQ_SPELL3"; +const string ARTIFICER_PREREQ_SPELLOR1 = "ARTIFICER_PREREQ_SPELLOR1"; +const string ARTIFICER_PREREQ_SPELLOR2 = "ARTIFICER_PREREQ_SPELLOR2"; +const string ARTIFICER_PREREQ_COMPLETE = "ARTIFICER_PREREQ_COMPLETE"; + +const int PRC_CRAFT_STATE_NORMAL = 1; +const int PRC_CRAFT_STATE_MAGIC = 2; + +const string PRC_CRAFT_HB = "PRC_CRAFT_HB"; + +const int SORT = TRUE; // If the sorting takes too much CPU, set to FALSE +const int DEBUG_LIST = FALSE; + + +////////////////////////////////////////////////// +/* Function defintions */ +////////////////////////////////////////////////// + +void PrintList(object oPC) +{ + string tp = "Printing list:\n"; + string s = GetLocalString(oPC, "ForgeConvo_List_Head"); + if(s == ""){ + tp += "Empty\n"; + } + else{ + tp += s + "\n"; + s = GetLocalString(oPC, "ForgeConvo_List_Next_" + s); + while(s != ""){ + tp += "=> " + s + "\n"; + s = GetLocalString(oPC, "ForgeConvo_List_Next_" + s); + } + } + + DoDebug(tp); +} + +/** + * Creates a linked list of entries that is sorted into alphabetical order + * as it is built. + * Assumption: Power names are unique. + * + * @param oPC The storage object aka whomever is gaining powers in this conversation + * @param sChoice The choice string + * @param nChoice The choice value + */ + +void AddToTempList(object oPC, string sChoice, int nChoice) +{ + if(DEBUG_LIST) DoDebug("\nAdding to temp list: '" + sChoice + "' - " + IntToString(nChoice)); + if(DEBUG_LIST) PrintList(oPC); + // If there is nothing yet + if(!GetLocalInt(oPC, "PRC_CRAFT_CONVO_ListInited")) + { + SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head", sChoice); + SetLocalInt(oPC, "PRC_CRAFT_CONVO_List_" + sChoice, nChoice); + + SetLocalInt(oPC, "PRC_CRAFT_CONVO_ListInited", TRUE); + } + else + { + // Find the location to instert into + string sPrev = "", sNext = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head"); + while(sNext != "" && StringCompare(sChoice, sNext) >= 0) + { + if(DEBUG_LIST) DoDebug("Comparison between '" + sChoice + "' and '" + sNext + "' = " + IntToString(StringCompare(sChoice, sNext))); + sPrev = sNext; + sNext = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sNext); + } + + // Insert the new entry + // Does it replace the head? + if(sPrev == "") + { + if(DEBUG_LIST) DoDebug("New head"); + SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head", sChoice); + } + else + { + if(DEBUG_LIST) DoDebug("Inserting into position between '" + sPrev + "' and '" + sNext + "'"); + SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sPrev, sChoice); + } + + SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sChoice, sNext); + SetLocalInt(oPC, "PRC_CRAFT_CONVO_List_" + sChoice, nChoice); + } +} + +/** + * Reads the linked list built with AddToTempList() to AddChoice() and + * deletes it. + * + * @param oPC A PC gaining powers at the moment + */ + +void TransferTempList(object oPC) +{ + string sChoice = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head"); + int nChoice = GetLocalInt (oPC, "PRC_CRAFT_CONVO_List_" + sChoice); + + DeleteLocalString(oPC, "PRC_CRAFT_CONVO_List_Head"); + string sPrev; + + if(DEBUG_LIST) DoDebug("Head is: '" + sChoice + "' - " + IntToString(nChoice)); + + while(sChoice != "") + { + // Add the choice + AddChoice(sChoice, nChoice, oPC); + + // Get next + sChoice = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + (sPrev = sChoice)); + nChoice = GetLocalInt (oPC, "PRC_CRAFT_CONVO_List_" + sChoice); + + if(DEBUG_LIST) DoDebug("Next is: '" + sChoice + "' - " + IntToString(nChoice) + "; previous = '" + sPrev + "'"); + + // Delete the already handled data + DeleteLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sPrev); + DeleteLocalInt (oPC, "PRC_CRAFT_CONVO_List_" + sPrev); + } + + DeleteLocalInt(oPC, "PRC_CRAFT_CONVO_ListInited"); +} + +//Returns the next conversation stage according +// to item property +int GetNextItemPropStage(int nStage, object oPC, int nPropList) +{ + nStage++; + if(nStage == STAGE_SELECT_SUBTYPE && !(nPropList & HAS_SUBTYPE)) + nStage++; + if(nStage == STAGE_SELECT_COSTTABLEVALUE && !(nPropList & HAS_COSTTABLE)) + nStage++; + if(nStage == STAGE_SELECT_PARAM1VALUE && !(nPropList & HAS_PARAM1)) + nStage++; + MarkStageNotSetUp(nStage, oPC); + return nStage; +} + +//Returns the previous conversation stage according +// to item property +int GetPrevItemPropStage(int nStage, object oPC, int nPropList) +{ + nStage--; + if(nStage == STAGE_SELECT_PARAM1VALUE && !(nPropList & HAS_PARAM1)) + nStage--; + if(nStage == STAGE_SELECT_COSTTABLEVALUE && !(nPropList & HAS_COSTTABLE)) + nStage--; + if(nStage == STAGE_SELECT_SUBTYPE && !(nPropList & HAS_SUBTYPE)) + nStage--; + MarkStageNotSetUp(nStage, oPC); + return nStage; +} + + //hardcoded to save time/prevent tmi +int SkipLineSpells(int i) +{ + switch(i) + { + //i +2 + case 3: + case 6: + case 16: + case 22: + case 26: + case 29: + case 38: + case 41: + case 44: + case 58: + case 61: + case 64: + case 70: + case 73: + case 79: + case 82: + case 96: + case 111: + case 116: + case 134: + case 145: + case 165: + case 185: + case 193: + case 202: + case 289: + case 292: + case 295: + case 312: + case 516: + case 1017: + case 1038: + case 1041: + case 1068: + case 1082: + case 1090: + case 1099: + case 1104: + case 1107: + case 1134: + case 1363: + case 1430: + case 1435: i = i + 2; break; + + //i +1 + case 10: + case 12: + case 19: + case 21: + case 24: + case 32: + case 34: + case 36: + case 47: + case 51: + case 53: + case 56: + case 67: + case 85: + case 91: + case 93: + case 102: + case 107: + case 109: + case 114: + case 124: + case 132: + case 138: + case 141: + case 156: + case 163: + case 181: + case 191: + case 196: + case 199: + case 214: + case 218: + case 220: + case 222: + case 224: + case 235: + case 237: + case 248: + case 252: + case 256: + case 258: + case 263: + case 276: + case 285: + case 306: + case 309: + case 315: + case 325: + case 397: + case 462: + case 475: + case 485: + case 514: + case 949: + case 953: + case 1001: + case 1003: + case 1005: + case 1007: + case 1009: + case 1011: + case 1013: + case 1020: + case 1031: + case 1034: + case 1043: + case 1045: + case 1048: + case 1050: + case 1052: + case 1055: + case 1057: + case 1059: + case 1061: + case 1063: + case 1076: + case 1078: + case 1086: + case 1088: + case 1095: + case 1097: + case 1102: + case 1111: + case 1113: + case 1119: + case 1121: + case 1124: + case 1126: + case 1128: + case 1145: + case 1147: + case 1196: + case 1205: + case 1215: + case 1260: + case 1350: i = i + 1; break; + case 173: i = 179; break; + case 317: i = 321; break; + case 328: i = 345; break; + case 359: i = 360; break; + case 400: i = 450; break; + case 487: i = 514; break; + case 520: i = 538; break; + case 540: i = 899; break; + case 902: i = 903; break; + case 914: i = 928; break; + case 967: i = 1000; break; + case 1366: i = 1369; break; + case 1389: i = 1416; break; + } + return i; +} + + +//added by MSB - hardcoded to prevent TMI +int SkipLineFeats(int i) +{ + switch (i) + { + case 40: i = 99; break; + case 141: i = 201; break; + case 213: i = 257; break; + case 259: i = 260; break; + case 262: i = 264; break; + case 266: i = 343; break; + case 381: i = 394; break; + case 395: i = 24813; break; + } + return i; +} + +//hardcoded to save time/prevent tmi +int SkipLineItemprops(int i) +{ + switch(i) + { + case 94: i = 100; break; + case 102: i = 133; break; + case 135: i = 150; break; + case 151: i = 200; break; + } + return i; +} + +//Adds names to a list based on sTable (2da), delayed recursion +// to avoid TMI +void PopulateList(object oPC, int MaxValue, int bSort, string sTable, object oItem = OBJECT_INVALID, int i = 0) +{ + if(GetLocalInt(oPC, "DynConv_Waiting") == FALSE) + return; + if(i <= MaxValue) + { + int bValid = TRUE; + string sTemp = ""; + if(sTable == "iprp_spells") + { + i = SkipLineSpells(i); + MaxValue = 1150; //MSB changed this from 540 + } + else if(sTable == "IPRP_FEATS") + { + MaxValue = 24819; + i = SkipLineFeats(i); + } + else if(sTable == "itempropdef") + { + i = SkipLineItemprops(i); + bValid = ValidProperty(oItem, i); + if(bValid) + bValid = !GetPRCSwitch("PRC_CRAFT_DISABLE_itempropdef_" + IntToString(i)); + } + else if(GetStringLeft(sTable, 6) == "craft_") + bValid = array_get_int(oPC, PRC_CRAFT_ITEMPROP_ARRAY, i); + sTemp = Get2DACache(sTable, "Name", i); + if((sTemp != "") && bValid)//this is going to kill + { + if(sTable == "iprp_spells") + { + AddToTempList(oPC, ActionString(GetStringByStrRef(StringToInt(sTemp))), i); + } + else + { + if(bSort) + AddToTempList(oPC, ActionString(GetStringByStrRef(StringToInt(sTemp))), i); + else + AddChoice(ActionString(GetStringByStrRef(StringToInt(sTemp))), i, oPC); + } + } + if(!(i % 100) && i) //i != 0, i % 100 == 0 + //following line is for debugging + //FloatingTextStringOnCreature(sTable, oPC, FALSE); + FloatingTextStringOnCreature("*Tick*", oPC, FALSE); + + } + else + { + if(bSort) TransferTempList(oPC); + DeleteLocalInt(oPC, "DynConv_Waiting"); + FloatingTextStringOnCreature("*Done*", oPC, FALSE); + return; + } + DelayCommand(0.01, PopulateList(oPC, MaxValue, bSort, sTable, oItem, i + 1)); +} + +//use heartbeat +void ApplyProperties(object oPC, object oItem, itemproperty ip, int nCost, int nXP, string sFile, int nLine) +{ + if(DEBUG) DoDebug("ApplyProperties: Starting with nCost=" + IntToString(nCost) + + ", and Crafter GP =" + IntToString(GetGold(oPC))); + + if(GetGold(oPC) < nCost) + { + FloatingTextStringOnCreature("Crafting: Insufficient gold!", oPC); + return; + } + int nHD = GetHitDice(oPC); + int nMinXP = nHD * (nHD - 1) * 500; + int nCurrentXP = GetXP(oPC); + if((nCurrentXP - nMinXP) < nXP) + { + FloatingTextStringOnCreature("Crafting: Insufficient XP!", oPC); + return; + } + if(GetItemPossessor(oItem) != oPC) + { + FloatingTextStringOnCreature("Crafting: You do not have the item!", oPC); + return; + } + + if(DEBUG) DoDebug("ApplyProperties: Passed validation, about to apply properties"); + + if(nLine == -1) + IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING); + else if(nLine == -2) + { //clone item + CopyItem(oItem, oPC, TRUE); + } + else + { + string sPropertyType = Get2DACache(sFile, "PropertyType", nLine); + if(sPropertyType == "M") + { //checking required spells + if(!CheckCraftingSpells(oPC, sFile, nLine, TRUE)) + { + FloatingTextStringOnCreature("Crafting: Required spells not available!", oPC); + return; + } + } + else if(sPropertyType == "P") + { + if(!CheckCraftingPowerPoints(oPC, sFile, nLine, TRUE)) + { + FloatingTextStringOnCreature("Crafting: Insufficient power points!", oPC); + return; + } + } + if(DEBUG) DoDebug("ApplyProperties: Calling ApplyItemProps()"); + ApplyItemProps(oItem, sFile, nLine); + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_BREACH), oPC); + + // With this conditional logic: + if(GetLocalInt(oPC, "PRC_CRAFT_RESTORED")) + { + AssignCommand(oPC, ClearAllActions()); + if(DEBUG) DoDebug("ApplyProperties: About to call TakeGoldFromCreature() with cost=" + IntToString(nCost)); + AssignCommand(oPC, TakeGoldFromCreature(nCost, oPC, TRUE)); + SpendXP(oPC, nXP); + + DeleteLocalInt(oPC, "PRC_CRAFT_RESTORED"); + } + else + { + AssignCommand(oPC, ClearAllActions()); + if(DEBUG) DoDebug("ApplyProperties: About to call TakeGoldFromCreature() with cost=" + IntToString(nCost)); + AssignCommand(oPC, TakeGoldFromCreature(nCost, oPC, TRUE)); + if(DEBUG) DoDebug("ApplyProperties: TakeGoldFromCreature() completed, new gold =" + IntToString(GetGold(oPC))); + SpendXP(oPC, nXP); + if(DEBUG) DoDebug("ApplyProperties: XP deduction completed, new XP=" + IntToString(GetXP(oPC))); + } + + //if(DEBUG) DoDebug("ApplyProperties: About to deduct gold ("+IntToString(nCost)+") and XP ("+IntToString(nCost)+")."); + //TakeGoldFromCreature(nCost, oPC, TRUE); + //SetXP(oPC, GetXP(oPC) - nXP); + + if(DEBUG) DoDebug("ApplyProperties: Completed successfully"); +} + +//use heartbeat +void CreateGolem(object oPC, int nCost, int nXP, string sFile, int nLine) +{ + if(GetGold(oPC) < nCost) + { + FloatingTextStringOnCreature("Crafting: Insufficient gold!", oPC); + return; + } + int nHD = GetHitDice(oPC); + int nMinXP = nHD * (nHD - 1) * 500; + int nCurrentXP = GetXP(oPC); + if((nCurrentXP - nMinXP) < nXP) + { + FloatingTextStringOnCreature("Crafting: Insufficient XP!", oPC); + return; + } + string sPropertyType = Get2DACache(sFile, "CasterType", nLine); + if(sPropertyType == "M") + { //checking required spells + if(!CheckCraftingSpells(oPC, sFile, nLine, TRUE)) + { + FloatingTextStringOnCreature("Crafting: Required spells not available!", oPC); + return; + } + } + else if(sPropertyType == "P") + { + if(!CheckCraftingPowerPoints(oPC, sFile, nLine, TRUE)) + { + FloatingTextStringOnCreature("Crafting: Insufficient power points!", oPC); + return; + } + } + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_BREACH), oPC); + TakeGoldFromCreature(nCost, oPC, TRUE); + SetXP(oPC, GetXP(oPC) - nXP); +} + +int ArtificerPrereqCheck(object oPC, string sFile, int nLine, int nCost) +{ + string sTemp, sSub, sSpell; + int nRace, nAlignGE, nAlignLC, nClass, i, j, bBreak, nLength, nPosition, nTemp; + int nSpell1, nSpell2, nSpell3, nSpellOR1, nSpellOR2; + int nDays = nCost / 1000; //one set of UMD checks per "day" spent crafting + if(nCost % 1000) nDays++; + sTemp = Get2DACache(sFile, "PrereqMisc", nLine); + sSpell = Get2DACache(sFile, "Spells", nLine); + if(sTemp == "") + { + bBreak = TRUE; + nRace = -1; + nAlignGE = -1; + nAlignLC = -1; + nClass = -1; + } + nLength = GetStringLength(sTemp); + for(i = 0; i < 5; i++) + { + if(bBreak) + break; + nPosition = FindSubString(sTemp, "_"); + sSub = (nPosition == -1) ? sTemp : GetStringLeft(sTemp, nPosition); + nLength -= (nPosition + 1); + if(sSub == "*") + nTemp = -1; + else + nTemp = StringToInt(sSub); + switch(i) + { + case 0: + { + nRace = (MyPRCGetRacialType(oPC) == nTemp) ? -1 : nTemp; + break; + } + case 1: + { + //can't emulate feat requirement + break; + } + case 2: + { + nAlignGE = -1; + if(sSub == "G") nAlignGE = (GetAlignmentGoodEvil(oPC) == ALIGNMENT_GOOD) ? -1 : ALIGNMENT_GOOD; + else if(sSub == "E") nAlignGE = (GetAlignmentGoodEvil(oPC) == ALIGNMENT_EVIL) ? -1 : ALIGNMENT_EVIL; + else if(sSub == "N") nAlignGE = (GetAlignmentGoodEvil(oPC) == ALIGNMENT_NEUTRAL) ? -1 : ALIGNMENT_NEUTRAL; + break; + } + case 3: + { + nAlignLC = -1; + if(sSub == "L") nAlignLC = (GetAlignmentLawChaos(oPC) == ALIGNMENT_LAWFUL) ? -1 : ALIGNMENT_LAWFUL; + if(sSub == "C") nAlignLC = (GetAlignmentLawChaos(oPC) == ALIGNMENT_CHAOTIC) ? -1 : ALIGNMENT_CHAOTIC; + if(sSub == "N") nAlignLC = (GetAlignmentLawChaos(oPC) == ALIGNMENT_NEUTRAL) ? -1 : ALIGNMENT_NEUTRAL; + break; + } + case 4: + { + nClass = (GetLevelByClass(nTemp, oPC)) ? -1 : nTemp; + break; + } + } + sTemp = GetSubString(sTemp, nPosition + 1, nLength); + } + if(sSpell == "") + { + nSpell1 = -1; + nSpell2 = -1; + nSpell3 = -1; + nSpellOR1 = -1; + nSpellOR2 = -1; + } + else + { + for(i = 0; i < 5; i++) + { + nPosition = FindSubString(sTemp, "_"); + sSub = (nPosition == -1) ? sTemp : GetStringLeft(sTemp, nPosition); + nLength -= (nPosition + 1); + if(sSub == "*") + nTemp = -1; + else + { + nTemp = StringToInt(sSub); + switch(i) + { + case 0: + { //storing the spell level and assuming it's a valid number + nSpell1 = (PRCGetHasSpell(nTemp, oPC)) ? -1 : StringToInt(Get2DACache("spells", "Innate", nTemp)) + 20; + break; + } + case 1: + { + nSpell2 = (PRCGetHasSpell(nTemp, oPC)) ? -1 : StringToInt(Get2DACache("spells", "Innate", nTemp)) + 20; + break; + } + case 2: + { + nSpell3 = (PRCGetHasSpell(nTemp, oPC)) ? -1 : StringToInt(Get2DACache("spells", "Innate", nTemp)) + 20; + break; + } + case 3: + { + nSpellOR1 = (PRCGetHasSpell(nTemp, oPC)) ? -1 : StringToInt(Get2DACache("spells", "Innate", nTemp)) + 20; + break; + } + case 4: + { + nSpellOR2 = (PRCGetHasSpell(nTemp, oPC)) ? -1 : StringToInt(Get2DACache("spells", "Innate", nTemp)) + 20; + break; + } + } + } + sTemp = GetSubString(sTemp, nPosition + 1, nLength); + } + } + int bTake10 = GetHasFeat(FEAT_SKILL_MASTERY_ARTIFICER, oPC) ? 10 : -1; + for(i = 0; i <= nDays; i++) //with extra last-ditch roll + { + if((nRace == -1) && + (nAlignGE == -1) && + (nAlignLC == -1) && + (nClass == -1) && + (nSpell1 == -1) && + (nSpell2 == -1) && + (nSpell3 == -1) && + (nSpellOR1 == -1) && + (nSpellOR2 == -1) + ) + return TRUE; + + if(nRace != -1) nRace = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, 25, bTake10)) ? -1 : nRace; + if(nAlignGE != -1) nAlignGE = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, 30, bTake10)) ? -1 : nAlignGE; + if(nAlignLC != -1) nAlignLC = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, 30, bTake10)) ? -1 : nAlignLC; + if(nClass != -1) nClass = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, 21, bTake10)) ? -1 : nClass; + if(nSpell1 != -1) nSpell1 = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, nSpell1, bTake10)) ? -1 : nSpell1; + if(nSpell2 != -1) nSpell2 = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, nSpell2, bTake10)) ? -1 : nSpell2; + if(nSpell3 != -1) nSpell3 = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, nSpell3, bTake10)) ? -1 : nSpell3; + if(nSpellOR1 != -1) nSpellOR1 = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, nSpellOR1, bTake10)) ? -1 : nSpellOR1; + if(nSpellOR2 != -1) nSpellOR2 = (GetPRCIsSkillSuccessful(oPC, SKILL_USE_MAGIC_DEVICE, nSpellOR2, bTake10)) ? -1 : nSpellOR2; + } + if((nRace == -1) && + (nAlignGE == -1) && + (nAlignLC == -1) && + (nClass == -1) && + (nSpell1 == -1) && + (nSpell2 == -1) && + (nSpell3 == -1) && + (nSpellOR1 == -1) && + (nSpellOR2 == -1) + ) + return TRUE; + else + return FALSE; //made all the UMD rolls allocated and still failed +} + +// Save crafting state during crafting +void SaveCraftingState(object oPC) +{ + if(DEBUG) DoDebug("prc_craft_cv_inc >> SaveCraftingState called for " + GetName(oPC)); + + if(GetLocalInt(oPC, PRC_CRAFT_HB)) + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> SaveCraftingState: Player is crafting, saving state..."); + + // Get the crafting item + object oItem = GetLocalObject(oPC, PRC_CRAFT_ITEM); + + // Save item identification info + SQLocalsPlayer_SetString(oPC, "crafting_item_name", GetName(oItem)); + SQLocalsPlayer_SetString(oPC, "crafting_item_tag", GetTag(oItem)); + SQLocalsPlayer_SetInt(oPC, "crafting_item_basetype", GetBaseItemType(oItem)); + + // Save UUID if not already saved + string sItemUUID = SQLocalsPlayer_GetString(oPC, "crafting_item_uuid"); + if(sItemUUID == "") + { + sItemUUID = GetObjectUUID(oItem); + SQLocalsPlayer_SetString(oPC, "crafting_item_uuid", sItemUUID); + if(DEBUG) DoDebug("prc_craft_cv_inc >> SaveCraftingState: Generated and saved new UUID: " + sItemUUID); + } + + // Get crafting cost values + int nCostDiff = GetLocalInt(oPC, PRC_CRAFT_COST); + int nXPDiff = GetLocalInt(oPC, PRC_CRAFT_XP); + int nRounds = GetLocalInt(oPC, PRC_CRAFT_TIME); + + // Save all basic crafting parameters + SQLocalsPlayer_SetInt(oPC, "crafting_cost", nCostDiff); + SQLocalsPlayer_SetInt(oPC, "crafting_xp", nXPDiff); + SQLocalsPlayer_SetInt(oPC, "crafting_rounds", nRounds); + SQLocalsPlayer_SetString(oPC, "crafting_file", GetLocalString(oPC, PRC_CRAFT_FILE)); + SQLocalsPlayer_SetInt(oPC, "crafting_line", GetLocalInt(oPC, PRC_CRAFT_LINE)); + SQLocalsPlayer_SetInt(oPC, "crafting_active", 1); + + // Save item property components for reconstruction + SQLocalsPlayer_SetInt(oPC, "crafting_ip_type", GetLocalInt(oPC, "PRC_CRAFT_IP_TYPE")); + SQLocalsPlayer_SetInt(oPC, "crafting_ip_subtype", GetLocalInt(oPC, "PRC_CRAFT_IP_SUBTYPE")); + SQLocalsPlayer_SetInt(oPC, "crafting_ip_costtable", GetLocalInt(oPC, "PRC_CRAFT_IP_COSTTABLE")); + SQLocalsPlayer_SetInt(oPC, "crafting_ip_param1", GetLocalInt(oPC, "PRC_CRAFT_IP_PARAM1")); + + // Save item property parameters + SQLocalsPlayer_SetInt(oPC, "crafting_type", GetLocalInt(oPC, PRC_CRAFT_TYPE)); + SQLocalsPlayer_SetString(oPC, "crafting_subtype", GetLocalString(oPC, PRC_CRAFT_SUBTYPE)); + SQLocalsPlayer_SetInt(oPC, "crafting_subtypevalue", GetLocalInt(oPC, PRC_CRAFT_SUBTYPEVALUE)); + SQLocalsPlayer_SetString(oPC, "crafting_costtable", GetLocalString(oPC, PRC_CRAFT_COSTTABLE)); + SQLocalsPlayer_SetInt(oPC, "crafting_costtablevalue", GetLocalInt(oPC, PRC_CRAFT_COSTTABLEVALUE)); + SQLocalsPlayer_SetString(oPC, "crafting_param1", GetLocalString(oPC, PRC_CRAFT_PARAM1)); + SQLocalsPlayer_SetInt(oPC, "crafting_param1value", GetLocalInt(oPC, PRC_CRAFT_PARAM1VALUE)); + SQLocalsPlayer_SetInt(oPC, "crafting_proplist", GetLocalInt(oPC, PRC_CRAFT_PROPLIST)); + + // Save item properties + SQLocalsPlayer_SetInt(oPC, "crafting_baseitemtype", GetLocalInt(oPC, PRC_CRAFT_BASEITEMTYPE)); + SQLocalsPlayer_SetInt(oPC, "crafting_time", nRounds); + SQLocalsPlayer_SetInt(oPC, "crafting_material", GetLocalInt(oPC, PRC_CRAFT_MATERIAL)); + SQLocalsPlayer_SetInt(oPC, "crafting_mighty", GetLocalInt(oPC, PRC_CRAFT_MIGHTY)); + SQLocalsPlayer_SetInt(oPC, "crafting_ac", GetLocalInt(oPC, PRC_CRAFT_AC)); + SQLocalsPlayer_SetString(oPC, "crafting_tag", GetLocalString(oPC, PRC_CRAFT_TAG)); + + // Save magic crafting variables + SQLocalsPlayer_SetInt(oPC, "crafting_enhancement", GetLocalInt(oPC, PRC_CRAFT_MAGIC_ENHANCE)); + SQLocalsPlayer_SetInt(oPC, "crafting_additional", GetLocalInt(oPC, PRC_CRAFT_MAGIC_ADDITIONAL)); + SQLocalsPlayer_SetInt(oPC, "crafting_epic", GetLocalInt(oPC, PRC_CRAFT_MAGIC_EPIC)); + + // Save system state variables + SQLocalsPlayer_SetInt(oPC, "crafting_script_state", GetLocalInt(oPC, PRC_CRAFT_SCRIPT_STATE)); + SQLocalsPlayer_SetInt(oPC, "crafting_token", GetLocalInt(oPC, PRC_CRAFT_TOKEN)); + + if(DEBUG) DoDebug("DEBUG: Crafting state saved - rounds: " + IntToString(nRounds)); + } +} + + +/* // Save crafting state on logout, pause concentration checks & time tracking +void SaveCraftingState(object oPC) +{ + if(GetLocalInt(oPC, "PRC_CRAFT_HB")) + { + // Get all crafting parameters + object oItem = GetLocalObject(oPC, "PRC_CRAFT_ITEM"); + int nCost = GetLocalInt(oPC, "PRC_CRAFT_COST"); + int nXP = GetLocalInt(oPC, "PRC_CRAFT_XP"); + int nRounds = GetLocalInt(oPC, "PRC_CRAFT_ROUNDS"); + string sFile = GetLocalString(oPC, "PRC_CRAFT_FILE"); + int nLine = GetLocalInt(oPC, "PRC_CRAFT_LINE"); + + // Save all parameters to database + SQLocalsPlayer_SetObject(oPC, "crafting_item", oItem); + SQLocalsPlayer_SetInt(oPC, "crafting_cost", nCost); + SQLocalsPlayer_SetInt(oPC, "crafting_xp", nXP); + SQLocalsPlayer_SetInt(oPC, "crafting_rounds", nRounds); + SQLocalsPlayer_SetString(oPC, "crafting_file", sFile); + SQLocalsPlayer_SetInt(oPC, "crafting_line", nLine); + SQLocalsPlayer_SetInt(oPC, "crafting_active", 1); + + // Save logout time using PRC time system + struct time tLogoutTime = GetTimeAndDate(); + SetPersistantLocalTime(oPC, "crafting_logout_time", tLogoutTime); + + // Remove concentration monitoring and clear heartbeat + RemoveEventScript(oPC, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc"); + DeleteLocalInt(oPC, "PRC_CRAFT_HB"); + } +} */ + +object GetItemByUUID(object oPC, string sUUID) +{ + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Searching for item with UUID: " + sUUID); + + // Check player's inventory + object oItem = GetFirstItemInInventory(oPC); + while(GetIsObjectValid(oItem)) + { + if(GetObjectUUID(oItem) == sUUID) + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Found item in player inventory: " + GetName(oItem)); + return oItem; + } + oItem = GetNextItemInInventory(oPC); + } + + // Check equipped slots + int i; + for(i = 0; i < NUM_INVENTORY_SLOTS; i++) + { + oItem = GetItemInSlot(i, oPC); + if(GetIsObjectValid(oItem) && GetObjectUUID(oItem) == sUUID) + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Found equipped item: " + GetName(oItem)); + return oItem; + } + } + + // Check the craft storage chest + object oChest = GetCraftChest(); + if(GetIsObjectValid(oChest)) + { + oItem = GetFirstItemInInventory(oChest); + while(GetIsObjectValid(oItem)) + { + if(GetObjectUUID(oItem) == sUUID) + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Found item in craft chest: " + GetName(oItem)); + return oItem; + } + oItem = GetNextItemInInventory(oChest); + } + } + + // Check temporary craft chest + object oTempChest = GetTempCraftChest(); + if(GetIsObjectValid(oTempChest)) + { + oItem = GetFirstItemInInventory(oTempChest); + while(GetIsObjectValid(oItem)) + { + if(GetObjectUUID(oItem) == sUUID) + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Found item in temp craft chest: " + GetName(oItem)); + return oItem; + } + oItem = GetNextItemInInventory(oTempChest); + } + } + + if(DEBUG) DoDebug("prc_craft_cv_inc >> GetItemByUUID | Item not found with UUID: " + sUUID); + return OBJECT_INVALID; +} + + +void CraftingHB(object oPC, object oItem, itemproperty ip, int nCost, int nXP, string sFile, int nLine, int nRounds) +{ + // Save current timestamp for offline progress calculation + int nCurrentTime = GetCurrentUnixTimestamp(); + if(nCurrentTime > 0) + { + SQLocalsPlayer_SetInt(oPC, "crafting_last_timestamp", nCurrentTime); + } + + // Set the heartbeat flag + SetLocalInt(oPC, PRC_CRAFT_HB, 1); + + // Set database flag for persistence tracking + SQLocalsPlayer_SetInt(oPC, "crafting_active", 1); + + // Update local variables for heartbeat logic + SetLocalInt(oPC, PRC_CRAFT_TIME, nRounds); + SetLocalInt(oPC, PRC_CRAFT_COST, nCost); + SetLocalInt(oPC, PRC_CRAFT_XP, nXP); + SetLocalString(oPC, PRC_CRAFT_FILE, sFile); + SetLocalInt(oPC, PRC_CRAFT_LINE, nLine); + + // Store the item property components for reconstruction + if(GetIsItemPropertyValid(ip)) + { + SetLocalInt(oPC, "PRC_CRAFT_IP_TYPE", GetItemPropertyType(ip)); + SetLocalInt(oPC, "PRC_CRAFT_IP_SUBTYPE", GetItemPropertySubType(ip)); + SetLocalInt(oPC, "PRC_CRAFT_IP_COSTTABLE", GetItemPropertyCostTableValue(ip)); + SetLocalInt(oPC, "PRC_CRAFT_IP_PARAM1", GetItemPropertyParam1Value(ip)); + } + + // Save current crafting state continuously for persistence + if(GetPRCSwitch(PRC_CRAFTING_TIME_SCALE) > 1) + { + // Store the CURRENT rounds value in database + SQLocalsPlayer_SetInt(oPC, "crafting_rounds", nRounds); + SaveCraftingState(oPC); + } + + if(GetBreakConcentrationCheck(oPC)) + { + FloatingTextStringOnCreature("Crafting: Concentration lost!", oPC); + DeleteLocalInt(oPC, PRC_CRAFT_HB); + RemoveEventScript(oPC, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc"); + // Clear database state + SQLocalsPlayer_SetInt(oPC, "crafting_active", 0); + return; + } + + if(nRounds == 0 || GetPCPublicCDKey(oPC) == "") //default to zero time if single player + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> CraftHB() | Crafting completion - nCost: " + IntToString(nCost) + ", nLine: " + IntToString(nLine)); + + RemoveEventScript(oPC, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc"); + if(GetLevelByClass(CLASS_TYPE_ARTIFICER, oPC)) + { + if(!ArtificerPrereqCheck(oPC, sFile, nLine, nCost)) + { + FloatingTextStringOnCreature("Crafting Failed!", oPC); + DeleteLocalInt(oPC, PRC_CRAFT_HB); + TakeGoldFromCreature(nCost, oPC, TRUE); + SetXP(oPC, PRCMax(GetXP(oPC) - nXP, GetHitDice(oPC) * (GetHitDice(oPC) - 1) * 500)); + SQLocalsPlayer_SetInt(oPC, "crafting_active", 0); + return; + } + } + FloatingTextStringOnCreature("Crafting Complete!", oPC); + if(DEBUG) DoDebug("prc_craft_cv_inc >> CraftHB() | Entering ApplyProperties() - nCost: " + IntToString(nCost) + ", nLine: " + IntToString(nLine)); + ApplyProperties(oPC, oItem, ip, nCost, nXP, sFile, nLine); + DeleteLocalInt(oPC, PRC_CRAFT_HB); + + if(GetLocalInt(oPC, "PRC_CRAFT_REMOVE_MASTERWORK")) + { + RemoveMasterworkProperties(oItem); + DeleteLocalInt(oPC, "PRC_CRAFT_REMOVE_MASTERWORK"); + } + + // Clear database state on completion + SQLocalsPlayer_SetInt(oPC, "crafting_active", 0); + } + else + { + if(DEBUG) DoDebug("prc_craft_cv_inc >> CraftHB() | Continuing CraftingHB() - nCost: " + IntToString(nCost) + ", nLine: " + IntToString(nLine)); + FloatingTextStringOnCreature("Crafting: " + IntToString(nRounds) + " round(s) remaining", oPC); + DelayCommand(6.0, CraftingHB(oPC, oItem, ip, nCost, nXP, sFile, nLine, nRounds - 1)); + } +} + +//;: void main(){} \ No newline at end of file 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..2ba4e40 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; } @@ -811,4 +812,4 @@ void DelayedSetVisualTransform(int nExpectedGeneration, object oTarget, int nTra void DelaySetVisualTransform(float fDelay, object oTarget, string sGenerationName, int nTransform, float fValue); //:: Test void -//::void main() {} \ No newline at end of file +//::void main(){} \ No newline at end of file diff --git a/src/include/prc_feat_const.nss b/src/include/prc_feat_const.nss index 6fd8c94..0f41adc 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; @@ -1320,9 +1335,15 @@ const int FEAT_CLOUDY_CONJURATION = 3001; const int FEAT_RANGED_RECALL = 5187; const int FEAT_SOMATIC_WEAPONRY = 5186; -// Forgotten Realms Campaign Setting -const int FEAT_INSCRIBE_RUNE = 2462; -const int EPIC_FEAT_INSCRIBE_EPIC_RUNES = 2549; +//:: Forgotten Realms Campaign Setting +const int FEAT_INSCRIBE_RUNE = 2462; +const int EPIC_FEAT_INSCRIBE_EPIC_RUNES = 2549; +const int FEAT_CIRCLE_MAGIC = 4350; +const int FEAT_CIRCLE_LEADER_RASHEMAN = 4351; +const int FEAT_CIRCLE_LEADER_THAYAN = 4352; +const int FEAT_GREAT_CIRCLE_LEADER_THAYAN = 4353; +const int FEAT_GREAT_CIRCLE_LEADER_RASHEMAN = 4435; + // Miniature Handbook const int FEAT_SHIELDMATE = 3258; @@ -1482,9 +1503,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 +3050,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; @@ -3504,7 +3530,6 @@ const int FEAT_WARLOCK_SHADOWMASTER_SHADES = 4485; const int FEAT_VERMINLORD = 5323; //Master Alchemist and various crafting - const int FEAT_SKILL_FOCUS_ALCHEMY = 24000; const int FEAT_EPIC_SKILL_FOCUS_ALCHEMY = 24001; const int FEAT_MAGICAL_ARTISAN_CRAFT_MAGIC_ARMS = 24002; @@ -3917,22 +3942,24 @@ const int FEAT_BRUTAL_THROW = 2689; const int FEAT_MARTIAL_STALKER = 25998; // Complete Warrior Feats -const int FEAT_EXTRA_RAGE = 2690; -const int FEAT_FLYING_KICK = 2802; -const int FEAT_ANVIL_OF_THUNDER = 5290; -const int FEAT_HAMMERS_EDGE = 5289; -const int FEAT_HIGH_SWORD_LOW_AXE = 5288; -const int FEAT_SPINNING_HALBERD = 5287; -const int FEAT_THREE_MOUNTAINS = 5286; -const int FEAT_MONKEY_GRIP = 5197; -const int FEAT_CRESCENT_MOON = 5194; -const int FEAT_QUICK_STAFF = 5190; -const int FEAT_RANGED_DISARM = 5192; -const int FEAT_BEAR_FANG = 5189; -const int FEAT_IMPROVED_RAPID_SHOT = 5188; -const int FEAT_EARTHS_EMBRACE = 5177; -const int FEAT_SHIELD_CHARGE = 3256; -const int FEAT_SHIELD_SLAM = 3257; +const int FEAT_EXTRA_RAGE = 2690; +const int FEAT_FLYING_KICK = 2802; +const int FEAT_ANVIL_OF_THUNDER = 5290; +const int FEAT_HAMMERS_EDGE = 5289; +const int FEAT_HIGH_SWORD_LOW_AXE = 5288; +const int FEAT_SPINNING_HALBERD = 5287; +const int FEAT_THREE_MOUNTAINS = 5286; +const int FEAT_MONKEY_GRIP = 5197; +const int FEAT_CRESCENT_MOON = 5194; +const int FEAT_QUICK_STAFF = 5190; +const int FEAT_RANGED_DISARM = 5192; +const int FEAT_BEAR_FANG = 5189; +const int FEAT_IMPROVED_RAPID_SHOT = 5188; +const int FEAT_EARTHS_EMBRACE = 5177; +const int FEAT_SHIELD_CHARGE = 3256; +const int FEAT_SHIELD_SLAM = 3257; +const int FEAT_FREEZING_THE_LIFEBLOOD = 26016; +const int FEAT_CW_PAIN_TOUCH = 26018; // CityScape Feats const int FEAT_EFFICIENT_DEFENDER = 5293; @@ -3957,7 +3984,12 @@ const int FEAT_WAND_MASTERY = 5314; const int FEAT_MOUNTAIN_STANCE = 5193; // Oriental Adventures Feats -const int FEAT_GREAT_DIPLOMAT = 5274; +const int FEAT_GREAT_DIPLOMAT = 5274; +const int FEAT_CHOKE_HOLD = 26013; +const int FEAT_FALLING_STAR_STRIKE = 26014; +const int FEAT_GREAT_KI_SHOUT = 26016; +const int FEAT_KI_SHOUT = 26017; +const int FEAT_UNBALANCING_STRIKE = 26019; // DungeonScape Feats const int FEAT_TRAP_ENGINEER = 5292; @@ -4015,12 +4047,18 @@ const int FEAT_IMPROVED_SHIELD_BASH = 3250; const int FEAT_INVESTIGATOR = 25998; // Player's Handbook II Feats -const int FEAT_STEADFAST_DETERMINATION = 3267; -const int FEAT_CROSSBOW_SNIPER = 5311; -const int FEAT_SHIELD_SPECIALIZATION_LIGHT = 3251; -const int FEAT_SHIELD_SPECIALIZATION_HEAVY = 3252; -const int FEAT_SHIELD_WARD = 3253; -const int FEAT_AGILE_SHIELD_FIGHTER = 3254; +const int FEAT_STEADFAST_DETERMINATION = 3267; +const int FEAT_CROSSBOW_SNIPER = 5311; +const int FEAT_SHIELD_SPECIALIZATION_LIGHT = 3251; +const int FEAT_SHIELD_SPECIALIZATION_HEAVY = 3252; +const int FEAT_SHIELD_WARD = 3253; +const int FEAT_AGILE_SHIELD_FIGHTER = 3254; +const int FEAT_COMBAT_FOCUS = 26020; +const int FEAT_COMBAT_AWARENESS = 26021; +const int FEAT_COMBAT_DEFENSE = 26022; +const int FEAT_COMBAT_STABILITY = 26023; +const int FEAT_COMBAT_STRIKE = 26024; +const int FEAT_COMBAT_VIGOR = 26025; // Weapons of Legacy Feats const int FEAT_LEAST_LEGACY = 5300; @@ -6337,6 +6375,5 @@ const int FEAT_HIDDEN_TALENT_GRIP_IRON = 25946; - //:: Test void // void main (){} \ No newline at end of file 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..878c777 100644 --- a/src/include/prc_inc_castlvl.nss +++ b/src/include/prc_inc_castlvl.nss @@ -797,6 +797,7 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if (nCastingClass == CLASS_TYPE_BARD || GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { + //:: 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) @@ -904,8 +905,12 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID) if(GetHasFeat(FEAT_UNSEEN_SPELLCASTING_BARD, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster); - if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_BARD, oCaster)) - nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + // if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_BARD, oCaster)) + // nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_BARD, oCaster) + && !(GetRacialType(oCaster) == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))) + nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster); + if(GetHasFeat(FEAT_WWOC_SPELLCASTING_BARD, oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster); @@ -960,7 +965,8 @@ 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_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) + if((nCastingClass == CLASS_TYPE_FEY || nCastingClass == CLASS_TYPE_BARD) && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster)) { if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)"); @@ -6468,9 +6474,12 @@ int TherapeuticMantle(object oCaster, int nSpellID) { int nReturn; // Boosts Caster level with healing spells - if (GetIsMeldBound(oCaster, MELD_THERAPEUTIC_MANTLE) == CHAKRA_SHOULDERS && GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING)) + if (GetIsMeldBound(oCaster, MELD_THERAPEUTIC_MANTLE) == CHAKRA_SHOULDERS || + GetIsMeldBound(oCaster, MELD_THERAPEUTIC_MANTLE) == CHAKRA_DOUBLE_SHOULDERS && + GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING)) + { nReturn = GetEssentiaInvested(oCaster, MELD_THERAPEUTIC_MANTLE); - + } return nReturn; } 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_cmbtform.nss b/src/include/prc_inc_cmbtform.nss new file mode 100644 index 0000000..9e1a687 --- /dev/null +++ b/src/include/prc_inc_cmbtform.nss @@ -0,0 +1,257 @@ +//::////////////////////////////////////////////// +//:: ;-. ,-. ,-. ,-. +//:: | ) | ) / ( ) +//:: |-' |-< | ;-: +//:: | | \ \ ( ) +//:: ' ' ' `-' `-' +//::////////////////////////////////////////////// +//:: +/* + Library for Combat Form related functions. + +*/ +//:: +//::////////////////////////////////////////////// +//:: Script: prc_inc_cmbtform.nss +//:: Author: Jaysyn +//:: Created: 2026-02-22 12:34:01 +//::////////////////////////////////////////////// +#include "prc_feat_const" +#include "inc_item_props" +#include "inc_eventhook" + +const string COMBAT_FOCUS_VAR = "CombatFocus_Active"; +const string COMBAT_FOCUS_END = "CombatFocus_EndTime"; +const string COMBAT_FOCUS_ENC = "CombatFocus_Encounter"; +const string CA_BLIND_VAR = "CombatAwareness_Blindsight"; + +void CombatFocus_EndAfterGrace(object oPC); + +//:: Count Combat Form feats (excluding Combat Focus itself) +int CountCombatFormFeats(object oPC) +{ + int nCount = GetHasFeat(FEAT_COMBAT_AWARENESS, oPC) + + GetHasFeat(FEAT_COMBAT_DEFENSE, oPC) + + GetHasFeat(FEAT_COMBAT_STABILITY, oPC) + + GetHasFeat(FEAT_COMBAT_STRIKE, oPC) + + GetHasFeat(FEAT_COMBAT_VIGOR, oPC); + return nCount; +} + +//:; Will save bonus helpers +void ApplyCombatFocusWillBonus(object oPC) +{ + object oSkin = GetPCSkin(oPC); + int nForms = CountCombatFormFeats(oPC); + int nBonus = (nForms >= 3) ? 4 : 2; + SetCompositeBonus(oSkin, "CombatFocus_Will", nBonus, + ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC, + IP_CONST_SAVEBASETYPE_WILL); +} + +void RemoveCombatFocusWillBonus(object oPC) +{ + object oSkin = GetPCSkin(oPC); + SetCompositeBonus(oSkin, "CombatFocus_Will", 0, + ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC, + IP_CONST_SAVEBASETYPE_WILL); +} + +//:: Reset encounter flag +void CombatFocus_ResetEncounter(object oPC) +{ + DeleteLocalInt(oPC, COMBAT_FOCUS_ENC); +} + +void CombatFocus_CombatEndHeartbeat(object oPC) +{ + if (GetIsInCombat(oPC)) + { + DelayCommand(6.0, CombatFocus_CombatEndHeartbeat(oPC)); + } + else + { + if (GetLocalInt(oPC, COMBAT_FOCUS_VAR)) + { + // Schedule grace period end + DelayCommand(6.0, CombatFocus_EndAfterGrace(oPC)); + } + else + { + // Clear encounter flag if focus not active + DeleteLocalInt(oPC, COMBAT_FOCUS_ENC); + } + } +} + +//:; Combat Stability bonus helpers +void ApplyCombatStabilityBonus(object oPC) +{ + int nForms = CountCombatFormFeats(oPC); + int nBonus = (nForms >= 3) ? 8 : 4; + SetLocalInt(oPC, "CombatStability_Bonus", nBonus); +} + +void RemoveCombatStabilityBonus(object oPC) +{ + DeleteLocalInt(oPC, "CombatStability_Bonus"); +} + +//:: Fast healing helpers for Combat Vigor +void ApplyCombatVigorFastHeal(object oPC) +{ + int nForms = CountCombatFormFeats(oPC); + int nHeal = (nForms >= 3) ? 4 : 2; + effect eRegen = EffectRegenerate(nHeal, 6.0f); + eRegen = TagEffect(eRegen, "CombatVor_FastHeal"); + eRegen = SupernaturalEffect(eRegen); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eRegen, oPC); + SetLocalInt(oPC, "CombatVigor_Active", TRUE); +} + +void RemoveCombatVigorFastHeal(object oPC) +{ + effect eCheck = GetFirstEffect(oPC); + while (GetIsEffectValid(eCheck)) + { + if (GetEffectTag(eCheck) == "CombatVor_FastHeal") + RemoveEffect(oPC, eCheck); + eCheck = GetNextEffect(oPC); + } + DeleteLocalInt(oPC, "CombatVigor_Active"); +} + +//;: Dodge AC helpers for Combat Defense +void ApplyCombatDefenseAC(object oPC) +{ + object oSkin = GetPCSkin(oPC); + int nForms = CountCombatFormFeats(oPC); + int nBonus = (nForms >= 3) ? 2 : 1; + SetCompositeBonus(oSkin, "CombatDefense_AC", nBonus, ITEM_PROPERTY_AC_BONUS); + SetLocalInt(oPC, "CombatDefense_Active", TRUE); +} + +void RemoveCombatDefenseAC(object oPC) +{ + object oSkin = GetPCSkin(oPC); + SetCompositeBonus(oSkin, "CombatDefense_AC", 0, ITEM_PROPERTY_AC_BONUS); + DeleteLocalInt(oPC, "CombatDefense_Active"); +} + +//:: Blindsight helpers for Combat Awareness +void ApplyCombatAwarenessBlindsight(object oPC) +{ + effect eBlind = EffectBonusFeat(FEAT_BLINDSIGHT_5_FEET); + eBlind = TagEffect(eBlind, "CombatAwareness_Blindsight"); + eBlind = SupernaturalEffect(eBlind); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBlind, oPC); + SetLocalInt(oPC, CA_BLIND_VAR, TRUE); +} + +void RemoveCombatAwarenessBlindsight(object oPC) +{ + effect eCheck = GetFirstEffect(oPC); + while (GetIsEffectValid(eCheck)) + { + if (GetEffectTag(eCheck) == "CombatAwareness_Blindsight") + RemoveEffect(oPC, eCheck); + eCheck = GetNextEffect(oPC); + } + DeleteLocalInt(oPC, CA_BLIND_VAR); +} + +//:: Show HP of adjacent creatures while focus is active +void ShowAdjacentHP(object oPC) +{ + if (!GetLocalInt(oPC, COMBAT_FOCUS_VAR)) return; + location lPC = GetLocation(oPC); + object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 5.0f, lPC, FALSE, OBJECT_TYPE_CREATURE); + while (GetIsObjectValid(oTarget)) + { + if (oTarget != oPC) + { + int nHP = GetCurrentHitPoints(oTarget); + string sName = GetName(oTarget); + FloatingTextStringOnCreature(sName + ": " + IntToString(nHP) + " HP", oPC); + } + oTarget = GetNextObjectInShape(SHAPE_SPHERE, 5.0f, lPC, FALSE, OBJECT_TYPE_CREATURE); + } +} + +void CombatFocus_EndAfterGrace(object oPC) +{ + // If combat resumed, do nothing + if (GetIsInCombat(oPC)) return; + + // Remove effects and clear state + RemoveCombatFocusWillBonus(oPC); + RemoveCombatAwarenessBlindsight(oPC); + RemoveCombatDefenseAC(oPC); + RemoveCombatVigorFastHeal(oPC); + RemoveCombatStabilityBonus(oPC); + DeleteLocalInt(oPC, COMBAT_FOCUS_VAR); + DeleteLocalInt(oPC, COMBAT_FOCUS_END); + DeleteLocalInt(oPC, COMBAT_FOCUS_ENC); + // Unregister heartbeat if it was registered + if (GetLocalInt(oPC, "CmbtFocus_HB_Registered")) + { + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_combatfocus", TRUE, FALSE); + DeleteLocalInt(oPC, "CmbtFocus_HB_Registered"); + } + FloatingTextStringOnCreature("Your Combat Focus fades", oPC); +} + +void CombatFocus_DecayRounds(object oPC) +{ + if (!GetLocalInt(oPC, COMBAT_FOCUS_VAR)) return; + + int nRounds = GetLocalInt(oPC, "CombatFocus_RoundsRemaining") - 1; + if (nRounds <= 0) + { + // Expired + RemoveCombatFocusWillBonus(oPC); + RemoveCombatAwarenessBlindsight(oPC); + RemoveCombatDefenseAC(oPC); + RemoveCombatVigorFastHeal(oPC); + RemoveCombatStabilityBonus(oPC); + DeleteLocalInt(oPC, COMBAT_FOCUS_VAR); + DeleteLocalInt(oPC, "CombatFocus_RoundsRemaining"); + // Unregister heartbeat + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_combatfocus", TRUE, FALSE); + DeleteLocalInt(oPC, "CmbtFocus_HB_Registered"); + } + else + { + SetLocalInt(oPC, "CombatFocus_RoundsRemaining", nRounds); + // Schedule next decrement in 6 seconds + DelayCommand(6.0, CombatFocus_DecayRounds(oPC)); + } +} + +//:: External call: trigger on first successful attack of an encounter +void CombatFocus_OnAttackHit(object oPC) +{ + if (!GetHasFeat(FEAT_COMBAT_FOCUS, oPC)) return; + if (GetLocalInt(oPC, COMBAT_FOCUS_VAR)) return; + if (GetLocalInt(oPC, COMBAT_FOCUS_ENC)) return; + + int nDurationRounds = 10 + CountCombatFormFeats(oPC); + SetLocalInt(oPC, COMBAT_FOCUS_VAR, TRUE); + SetLocalInt(oPC, COMBAT_FOCUS_ENC, TRUE); + // Store remaining rounds instead of end timestamp + SetLocalInt(oPC, "CombatFocus_RoundsRemaining", nDurationRounds); + + ApplyCombatFocusWillBonus(oPC); + + // Apply Combat Form feat bonuses if possessed. + if (GetHasFeat(FEAT_COMBAT_VIGOR, oPC) && !GetLocalInt(oPC, "CombatVigor_Active")) + ApplyCombatVigorFastHeal(oPC); + if (GetHasFeat(FEAT_COMBAT_AWARENESS, oPC) && !GetLocalInt(oPC, CA_BLIND_VAR)) + ApplyCombatAwarenessBlindsight(oPC); + if (GetHasFeat(FEAT_COMBAT_DEFENSE, oPC) && !GetLocalInt(oPC, "CombatDefense_Active")) + ApplyCombatDefenseAC(oPC); + if (GetHasFeat(FEAT_COMBAT_STABILITY, oPC) && !GetLocalInt(oPC, "CombatStability_Bonus")) + ApplyCombatStabilityBonus(oPC); + + FloatingTextStringOnCreature("Combat Focus gained", oPC, FALSE); +} \ No newline at end of file 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..29dcdba 100644 --- a/src/include/prc_inc_combmove.nss +++ b/src/include/prc_inc_combmove.nss @@ -715,6 +715,34 @@ void _DoReapingMauler(object oPC, object oTarget, int nRounds) } } } + +void _DoChokeHold(object oPC, object oTarget) +{ + // Size immunity: more than one size larger blocks effect + int nAttackerSize = GetCreatureSize(oPC); + int nTargetSize = GetCreatureSize(oTarget); + if (nTargetSize > nAttackerSize + 1) return; + + // Stunning immunity blocks Choke Hold + if (GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) return; + + int nDC = 10 + (GetHitDice(oPC) / 2) + GetAbilityModifier(ABILITY_WISDOM, oPC); + if (!FortitudeSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oPC)) + { + SetLocalInt(oTarget, "UnconsciousGrapple", TRUE); + effect eUncon = EffectLinkEffects(EffectSleep(), EffectVisualEffect(VFX_IMP_SLEEP)); + eUncon = EffectLinkEffects(eUncon, EffectKnockdown()); + float fDur = RoundsToSeconds(d3()); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eUncon), oTarget, fDur); + FloatingTextStringOnCreature("Choke Hold Success", oPC, FALSE); + DelayCommand(fDur, DeleteLocalInt(oTarget, "UnconsciousGrapple")); + + // End the grapple after knocking the target out + EndGrapple(oPC, oTarget); + if (GetLocalInt(oPC, "GrappleOriginator")) + RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); + } +} void _PostCharge(object oPC, object oTarget) { @@ -769,8 +797,27 @@ void _PostCharge(object oPC, object oTarget) { ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectStunned()), oTarget, 6.0); } - // Applies to all charges, Thunderstep Boots meld - if (GetHasSpellEffect(MELD_THUNDERSTEP_BOOTS, oPC) && nSucceed) + + // Applies to all charges, Thunderstep Boots meld + if (GetHasSpellEffect(MELD_THUNDERSTEP_BOOTS, oPC) && nSucceed) + { + int nDice = GetEssentiaInvested(oPC, MELD_THUNDERSTEP_BOOTS) + 1; + ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(d4(nDice), DAMAGE_TYPE_SONIC)), oTarget); + // Check Feet bind (regular or double) + int nBoundToFeet = FALSE; + if (GetIsMeldBound(oTarget, MELD_THUNDERSTEP_BOOTS) == CHAKRA_FEET || + GetIsMeldBound(oTarget, MELD_THUNDERSTEP_BOOTS) == CHAKRA_DOUBLE_FEET) + nBoundToFeet = TRUE; + + if (nBoundToFeet) + { + int nDC = GetMeldshaperDC(oPC, CLASS_TYPE_SOULBORN, MELD_THUNDERSTEP_BOOTS); + if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE)) + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(), oTarget, 6.0); + } + } + +/* if (GetHasSpellEffect(MELD_THUNDERSTEP_BOOTS, oPC) && nSucceed) { int nDice = GetEssentiaInvested(oPC, MELD_STRONGHEART_VEST) + 1; ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(d4(nDice), DAMAGE_TYPE_SONIC)), oTarget); @@ -780,12 +827,12 @@ void _PostCharge(object oPC, object oTarget) if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(), oTarget, 6.0); } - } + } */ // Applies to all charges, Urskan Greaves meld if (GetHasSpellEffect(MELD_URSKAN_GREAVES, oPC) && nSucceed) { int nDice = GetEssentiaInvested(oPC, MELD_URSKAN_GREAVES); - if (GetIsMeldBound(oTarget, MELD_URSKAN_GREAVES) == CHAKRA_FEET) + if (GetIsMeldBound(oTarget, MELD_URSKAN_GREAVES) == CHAKRA_FEET || GetIsMeldBound(oTarget, MELD_URSKAN_GREAVES) == CHAKRA_DOUBLE_FEET) ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(d4(nDice), DAMAGE_TYPE_BLUDGEONING)), oTarget); } } @@ -812,7 +859,7 @@ void _DoTrampleDamage(object oPC, object oTarget) void _HeartOfFireGrapple(object oPC, object oTarget) { - if (GetIsMeldBound(oTarget, MELD_HEART_OF_FIRE) == CHAKRA_WAIST) + if (GetIsMeldBound(oTarget, MELD_HEART_OF_FIRE) == CHAKRA_WAIST || GetIsMeldBound(oTarget, MELD_HEART_OF_FIRE) == CHAKRA_DOUBLE_WAIST) { int nEssentia = GetEssentiaInvested(oPC, MELD_HEART_OF_FIRE); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(nEssentia), DAMAGE_TYPE_FIRE), oTarget); @@ -823,7 +870,7 @@ int _TotemAvatar(object oPC, int nCombatMove) { int nReturn; - if (GetIsMeldBound(oPC, MELD_HEART_OF_FIRE) == CHAKRA_FEET && nCombatMove != COMBAT_MOVE_GRAPPLE) + if (GetIsMeldBound(oPC, MELD_HEART_OF_FIRE) == CHAKRA_FEET || GetIsMeldBound(oPC, MELD_HEART_OF_FIRE) == CHAKRA_DOUBLE_FEET && nCombatMove != COMBAT_MOVE_GRAPPLE) nReturn = 4; if (nCombatMove == COMBAT_MOVE_GRAPPLE || @@ -839,7 +886,7 @@ int _UrskanGreaves(object oPC) { int nReturn; - if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM) + if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM || GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_DOUBLE_TOTEM) nReturn = 2 + GetEssentiaInvested(oPC, MELD_URSKAN_GREAVES); return nReturn; @@ -977,7 +1024,11 @@ int GetCombatMoveCheckBonus(object oPC, int nCombatMove, int nDefender = FALSE, } else if (nDefender) { - if(GetHasFeat(FEAT_MOUNTAIN_STANCE, oPC)) nBonus += 2; + if(GetHasFeat(FEAT_MOUNTAIN_STANCE, oPC)) nBonus += 2; + + int nStabBonus = GetLocalInt(oPC, "CombatStability_Bonus"); + if (nStabBonus > 0) nBonus += nStabBonus; + if(GetHasSpellEffect(SPELL_UNMOVABLE, oPC)) nBonus += 20; if(GetHasFeat(FEAT_SHIELD_WARD, oPC)) { @@ -1101,7 +1152,7 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO // Dread Carapace Totem Bind if(GetIsIncarnumUser(oPC)) { - if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM) // CHAKRA_TOTEM + if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM || GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_DOUBLE_TOTEM) // CHAKRA_TOTEM { location lTargetLocation = GetLocation(oPC); int nSaveDC = GetMeldshaperDC(oPC, CLASS_TYPE_TOTEMIST, MELD_DREAD_CARAPACE); // MELD_DREAD_CARAPACE @@ -1120,7 +1171,8 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO } } - if (GetIsMeldBound(oPC, MELD_SPHINX_CLAWS) == CHAKRA_HANDS && !GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC))) // CHAKRA_HANDS, empty hand + if (GetIsMeldBound(oPC, MELD_SPHINX_CLAWS) == CHAKRA_HANDS || GetIsMeldBound(oPC, MELD_SPHINX_CLAWS) == CHAKRA_DOUBLE_HANDS && + !GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC))) // CHAKRA_HANDS, empty hand nPounce = TRUE; } @@ -1324,7 +1376,7 @@ int DoTrip(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, } else // If you fail, enemy gets a counter trip attempt, using Strength { - if(!nCounterTrip) + if(nCounterTrip) { nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_TRIP, FALSE, TRUE); FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); @@ -1502,7 +1554,35 @@ 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); + SetGrappleTarget(oPC, oTarget); // Move this up from line 1544 + + 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")); + 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 + } + +/* SetGrapple(oPC); SetGrapple(oTarget); SetLocalInt(oPC, "GrappleOriginator", TRUE); effect eHold = EffectCutsceneParalyze(); @@ -1526,7 +1606,7 @@ 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)) @@ -1794,7 +1874,51 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = else FloatingTextStringOnCreature("You have failed your Crushing Weight Attempt",oPC, FALSE); } - else if (nSwitch == GRAPPLE_PIN) + else if (nSwitch == GRAPPLE_PIN) + { + // Pins the target + if (nSuccess) + { + FloatingTextStringOnCreature("You have pinned your target", oPC, FALSE); + SetIsPinned(oTarget); + int nRounds = _CountPinRounds(oTarget); // always increment + int nClass = GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC); + if (nClass) + { + _DoReapingMauler(oPC, oTarget, nRounds); + } + else if (GetHasFeat(FEAT_CHOKE_HOLD, oPC)) + { + DelayCommand(6.0, _DoChokeHold(oPC, oTarget)); + } + if (GetHasFeat(FEAT_EARTHS_EMBRACE, oPC)) + { + // Add in unarmed damage + int nDamageSize = FindUnarmedDamage(oPC); + + int nDie = StringToInt(Get2DACache("iprp_monstcost", "Die", nDamageSize)); + int nNum = StringToInt(Get2DACache("iprp_monstcost", "NumDice", nDamageSize)); + int nRoll; + + //Potential die options + if(nDie == 4) nRoll = d4(nNum); + else if(nDie == 6) nRoll = d6(nNum); + else if(nDie == 8) nRoll = d8(nNum); + else if(nDie == 10) nRoll = d10(nNum); + else if(nDie == 12) nRoll = d12(nNum); + else if(nDie == 20) nRoll = d20(nNum); + + FloatingTextStringOnCreature("Earth's Embrace chokes the life from your foe", oPC, FALSE); + + int nDam = d12() + nRoll; + 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); + } +/* else if (nSwitch == GRAPPLE_PIN) { // Pins the target if (nSuccess) @@ -1807,6 +1931,24 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = int nRounds = _CountPinRounds(oTarget); _DoReapingMauler(oPC, oTarget, nRounds); } + if (GetHasFeat(FEAT_CHOKE_HOLD, oPC)) + { + int nRounds = GetLocalInt(oTarget, "PinnedRounds"); + if (nRounds >= 1) + { + int nDC = 10 + (GetHitDice(oPC) / 2) + GetAbilityModifier(ABILITY_WISDOM, oPC); + if(!FortitudeSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oPC)) + { + SetLocalInt(oTarget, "UnconsciousGrapple", TRUE); + effect eUncon = EffectLinkEffects(EffectStunned(), EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED)); + eUncon = EffectLinkEffects(eUncon, EffectKnockdown()); + float fDur = RoundsToSeconds(d3()); + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eUncon), oTarget, fDur); + FloatingTextStringOnCreature("Choke Hold Success", oPC, FALSE); + DelayCommand(fDur, DeleteLocalInt(oTarget, "UnconsciousGrapple")); + } + } + } if (GetHasFeat(FEAT_EARTHS_EMBRACE, oPC)) { // Add in unarmed damage @@ -1834,7 +1976,7 @@ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = else FloatingTextStringOnCreature("You have failed your Grapple Pin Attempt",oPC, FALSE); } - else + */ else { FloatingTextStringOnCreature("DoGrappleOptions: Error, invalid option "+IntToString(nSwitch)+" passed to function by "+GetName(oPC),oPC, FALSE); FloatingTextStringOnCreature("DoGrappleOptions: Error, GetGrapple(oPC) "+IntToString(GetGrapple(oPC))+" GetGrapple(oTarget) "+IntToString(GetGrapple(oTarget)),oPC, FALSE); @@ -1863,7 +2005,7 @@ void DoOverrun(object oPC, object oTarget, location lTarget, int nGenerateAoO = float fLength = GetDistanceBetweenLocations(GetLocation(oPC), lTarget); vector vOrigin = GetPosition(oPC); - if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM) + if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM || GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_DOUBLE_TOTEM) nAvoid = FALSE; if (GetHasFeat(FEAT_CENTAUR_TRAMPLE, oPC)) nAvoid = FALSE; @@ -2317,7 +2459,7 @@ void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE) // Dread Carapace Totem Bind if(GetIsIncarnumUser(oPC)) { - if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM) // CHAKRA_TOTEM + if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM || GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_DOUBLE_TOTEM) // CHAKRA_TOTEM { location lTargetLocation = GetLocation(oPC); int nSaveDC = GetMeldshaperDC(oPC, CLASS_TYPE_TOTEMIST, MELD_DREAD_CARAPACE); // MELD_DREAD_CARAPACE diff --git a/src/include/prc_inc_damage.nss b/src/include/prc_inc_damage.nss index 869514c..8da1581 100644 --- a/src/include/prc_inc_damage.nss +++ b/src/include/prc_inc_damage.nss @@ -102,7 +102,7 @@ void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDuration if (GetLocalInt(oTarget, "IncarnumDefenseCE") && nAbility == ABILITY_STRENGTH) return; - if (GetIsMeldBound(oTarget, MELD_VITALITY_BELT) == CHAKRA_WAIST && nAbility == ABILITY_CONSTITUTION) + if (GetIsMeldBound(oTarget, MELD_VITALITY_BELT) == CHAKRA_WAIST || GetIsMeldBound(oTarget, MELD_VITALITY_BELT) == CHAKRA_DOUBLE_WAIST && nAbility == ABILITY_CONSTITUTION) return; if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oTarget) && nAbility == ABILITY_WISDOM && GetLocalInt(oTarget, "ExploitVestige") != VESTIGE_DAHLVERNAR_MAD_SOUL) @@ -116,7 +116,7 @@ void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDuration // If there's no damage, jump out. if (0 >= nAmount) return; } - else if (GetIsMeldBound(oTarget, MELD_STRONGHEART_VEST) == CHAKRA_WAIST && !bHealable) + else if (GetIsMeldBound(oTarget, MELD_STRONGHEART_VEST) == CHAKRA_WAIST || GetIsMeldBound(oTarget, MELD_STRONGHEART_VEST) == CHAKRA_DOUBLE_WAIST && !bHealable) { int nEssentia = GetEssentiaInvested(oTarget, MELD_STRONGHEART_VEST); nAmount = nAmount - (nEssentia + 1); diff --git a/src/include/prc_inc_function.nss b/src/include/prc_inc_function.nss index a3b24e5..758f773 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; @@ -361,12 +362,14 @@ void EvalPRCFeats(object oPC) if(oPC == GetLocalObject(GetModule(), "ccc_active_pc")) return; + if(GetHasFeat(FEAT_COMBAT_FOCUS, oPC)) ExecuteScript("prc_combatfocus", oPC); + int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_EvalPRCFeats_Generation)); if (DEBUG > 1) DoDebug("EvalPRCFeats Generation: " + IntToString(nGeneration)); 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 +1574,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..35b7ca5 100644 --- a/src/include/prc_inc_leadersh.nss +++ b/src/include/prc_inc_leadersh.nss @@ -7,7 +7,7 @@ const string COHORT_DATABASE = "PRCCOHORTS"; const string COHORT_TAG = "prc_cohort"; -//in the database there is the folloxing data structures: +//in the database there is the following data structures: /* int CohortCount (total number of cohorts) object Cohort_X_obj (cohort itself) @@ -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); @@ -287,6 +287,95 @@ void CancelGreatFeats(object oSpawn) } } +// Generates a random name for a creature based on their race and gender +string GenerateRandomName(object oCreature) +{ + string sName; + int nRace = MyPRCGetRacialType(oCreature); + int nGender = GetGender(oCreature); + + // First name based on race and gender + switch(nRace) + { + case RACIAL_TYPE_DWARF: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_DWARF_FEMALE); + else + sName += RandomName(NAME_FIRST_DWARF_MALE); + break; + case RACIAL_TYPE_ELF: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_ELF_FEMALE); + else + sName += RandomName(NAME_FIRST_ELF_MALE); + break; + case RACIAL_TYPE_GNOME: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_GNOME_FEMALE); + else + sName += RandomName(NAME_FIRST_GNOME_MALE); + break; + case RACIAL_TYPE_HUMAN: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_HUMAN_FEMALE); + else + sName += RandomName(NAME_FIRST_HUMAN_MALE); + break; + case RACIAL_TYPE_HALFELF: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_HALFELF_FEMALE); + else + sName += RandomName(NAME_FIRST_HALFELF_MALE); + break; + case RACIAL_TYPE_HALFORC: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_HALFORC_FEMALE); + else + sName += RandomName(NAME_FIRST_HALFORC_MALE); + break; + case RACIAL_TYPE_HALFLING: + if(nGender == GENDER_FEMALE) + sName += RandomName(NAME_FIRST_HALFLING_FEMALE); + else + sName += RandomName(NAME_FIRST_HALFLING_MALE); + break; + } + + sName += " "; + + // Surname based on race + switch(nRace) + { + case RACIAL_TYPE_DWARF: + sName += RandomName(NAME_LAST_DWARF); + break; + case RACIAL_TYPE_ELF: + sName += RandomName(NAME_LAST_ELF); + break; + case RACIAL_TYPE_GNOME: + sName += RandomName(NAME_LAST_GNOME); + break; + case RACIAL_TYPE_HUMAN: + sName += RandomName(NAME_LAST_HUMAN); + break; + case RACIAL_TYPE_HALFELF: + sName += RandomName(NAME_LAST_HALFELF); + break; + case RACIAL_TYPE_HALFORC: + sName += RandomName(NAME_LAST_HALFORC); + break; + case RACIAL_TYPE_HALFLING: + sName += RandomName(NAME_LAST_HALFLING); + break; + } + + // Sanity check + if(sName == " ") + sName = ""; + + return sName; +} + void AddCohortToPlayerByObject(object oCohort, object oPC, int bDoSetup = TRUE) { //add it to the pc @@ -296,6 +385,164 @@ void AddCohortToPlayerByObject(object oCohort, object oPC, int bDoSetup = TRUE) SetMaxHenchmen(nMaxHenchmen); object oSkin = GetPCSkin(oCohort); + if(bDoSetup) + { + //if it was a premade one, give it a random name + //randomize its appearance using DoRandomAppearance + if(GetResRef(oCohort) != "") + { + // Generate and assign random name + string sName = GenerateRandomName(oCohort); + AssignCommand(oCohort, SetName(oCohort, sName)); + + //use disguise code to alter head etc + DoRandomAppearance(MyPRCGetRacialType(oCohort), oCohort); + + //DoRandomAppearance removed wings/tails need to re-add + if(GetRacialType(oCohort) == RACIAL_TYPE_FEYRI) + SetCreatureWingType(CREATURE_WING_TYPE_DEMON, oCohort); + else if(GetRacialType(oCohort) == RACIAL_TYPE_AVARIEL) + SetCreatureWingType(CREATURE_WING_TYPE_BIRD, oCohort); + else if(GetRacialType(oCohort) == RACIAL_TYPE_GLOURA) + SetCreatureWingType(CREATURE_WING_TYPE_BUTTERFLY, oCohort); + } + //if its a custom made cohort, need to cancel GreatX feats + else + CancelGreatFeats(oCohort); + + //set it to the pcs level + int nLevel = GetCohortMaxLevel(GetLeadershipScore(oPC), oPC); + SetXP(oCohort, nLevel*(nLevel-1)*500); + SetLocalInt(oCohort, "MastersXP", GetXP(oPC)); + DelayCommand(1.0, AssignCommand(oCohort, SetIsDestroyable(FALSE, TRUE, TRUE))); + DelayCommand(1.0, AssignCommand(oCohort, SetLootable(oCohort, TRUE))); + //set its maximum level lag + if(GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)) + { + //bonus cohort, no cap + } + else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP) + && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC) + && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+1) + { + //thrallherd with switch, 1 level lag + SetLocalInt(oCohort, "CohortLevelLag", 1); + } + else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP) + && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC) >= 10 + && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+2) + { + //twofold master with switch, 2 level lag + SetLocalInt(oCohort, "CohortLevelLag", 2); + } + else + { + //other cohort have a 2 level lag + SetLocalInt(oCohort, "CohortLevelLag", 2); + } + + //strip its equipment & inventory + object oTest = GetFirstItemInInventory(oCohort); + object oToken = GetHideToken(oCohort); + while(GetIsObjectValid(oTest)) + { + if(GetHasInventory(oTest)) + { + object oTest2 = GetFirstItemInInventory(oTest); + while(GetIsObjectValid(oTest2)) + { + // Avoid blowing up the hide and token that just had the eventscripts stored on them + if(oTest2 != oSkin && oTest2 != oToken) + DestroyObject(oTest2); + oTest2 = GetNextItemInInventory(oTest); + } + } + // Avoid blowing up the hide and token that just had the eventscripts stored on them + if(oTest != oSkin && oTest != oToken) + DestroyObject(oTest); + oTest = GetNextItemInInventory(oCohort); + } + int nSlot; + for(nSlot = 0;nSlot<14;nSlot++) + { + oTest = GetItemInSlot(nSlot, oCohort); + DestroyObject(oTest); + } + //get rid of any gold it has + TakeGoldFromCreature(GetGold(oCohort), oCohort, TRUE); + } + //clean up any leftovers on the skin + ScrubPCSkin(oCohort, oSkin); + DeletePRCLocalInts(oSkin); + + //turn on its scripts + //normal MoB set + AddEventScript(oCohort, EVENT_VIRTUAL_ONPHYSICALATTACKED, "prc_ai_mob_attck", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONBLOCKED, "prc_ai_mob_block", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONCOMBATROUNDEND, "prc_ai_mob_combt", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONDAMAGED, "prc_ai_mob_damag", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONDISTURBED, "prc_ai_mob_distb", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONPERCEPTION, "prc_ai_mob_percp", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONSPAWNED, "prc_ai_mob_spawn", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONSPELLCASTAT, "prc_ai_mob_spell", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONDEATH, "prc_ai_mob_death", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONRESTED, "prc_ai_mob_rest", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONUSERDEFINED, "prc_ai_mob_userd", TRUE, FALSE); + //dont run this, cohort-specific script replaces it + //AddEventScript(oCohort, EVENT_VIRTUAL_ONCONVERSATION, "prc_ai_mob_conv", TRUE, TRUE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONHEARTBEAT, "prc_ai_mob_heart", TRUE, FALSE); + //cohort specific ones + AddEventScript(oCohort, EVENT_VIRTUAL_ONCONVERSATION, "prc_ai_coh_conv", TRUE, FALSE); + AddEventScript(oCohort, EVENT_VIRTUAL_ONHEARTBEAT, "prc_ai_coh_hb", TRUE, FALSE); + + //mark the master on the cohort + SetLocalObject(oCohort, "MasterObject", oPC); + + //DEBUG + //various tests + if (DEBUG) DoDebug("Cohort Name="+GetName(oCohort)); + if (DEBUG) DoDebug("Cohort HD="+IntToString(GetHitDice(oCohort))); + if (DEBUG) DoDebug("Cohort XP="+IntToString(GetXP(oCohort))); + if (DEBUG) DoDebug("Cohort GetIsPC="+IntToString(GetIsPC(oCohort))); + + // And now gear it up + if (!GetPRCSwitch(PRC_DISABLE_COHORT_STARTING_GEAR)) + { + int i; + int nHD = GetHitDice(oCohort); + for(i = 0;i> DoNaturalWeaponHB: creature has natural secondary weapons"); + if(DEBUG) DoDebug("prc_inc_nat_hb >> DoNaturalWeaponHB: creature has natural secondary weapons"); UpdateSecondaryWeaponSizes(oPC); int i; while(i < array_get_size(oPC, ARRAY_NAT_SEC_WEAP_RESREF)) @@ -507,7 +507,7 @@ void DoNaturalWeaponHB(object oPC = OBJECT_SELF) if(!GetIsObjectValid(oLimbo)) lLimbo = GetStartingLocation(); oWeapon = CreateObject(OBJECT_TYPE_ITEM, sResRef, lLimbo); - DoDebug(PRC_TEXT_WHITE + "prc_inc_nat_hb >> DoNaturalWeaponHB: creature weapon object found!!!"); + if(DEBUG) DoDebug(PRC_TEXT_WHITE + "prc_inc_nat_hb >> DoNaturalWeaponHB: creature weapon object found!!!"); } // Check for enhancements after creating the weapon object 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..5f4aa22 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)) @@ -1019,8 +1022,6 @@ int PRCMySavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = nDC -= 4; else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 3) nDC -= 2; - - } else if(nSaveType == SAVING_THROW_TYPE_POISON) { @@ -1069,6 +1070,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 +2793,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..fea1e53 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.85"; /* 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 @@ -608,7 +615,7 @@ const string PRC_PSIONIC_SLAYER_REQUIRE_KILL_TOKEN = "PRC_PSIONIC_SLAYER_R * Hybrid Form Shapchange. * * This switch allows the Werewolf class to be toggled to use the PRC Shifter - * Shapchange code instead. + * Shapechange code instead. * * Type: Int * Values: 0 [Default] (Werewolf Hybrid Shapchange uses Bioware Polymorph) @@ -1574,7 +1581,7 @@ const string PRC_PSI_ASTRAL_SEED_RESPAWN_DELAY_X1000 = "PRC_PSI_ASTRAL_SE * If this flag is set, the XP loss is completely eliminated. The standard PRC event hook script * of "prc_pw_astralseed" may be used to script any additional effects to occure upon Astral Seed * respawning, including scripting specific XP loss amount. - * Type: Int + * Type: Int * Values: 0 [Default] (Not set: lose 1 level worth of XP upon Astral Seed respawn) * 1 (Any potitive value: Remove all XP loss from Astral Seed respawn) */ @@ -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_util.nss b/src/include/prc_inc_util.nss index 0d4ac47..2f3d48d 100644 --- a/src/include/prc_inc_util.nss +++ b/src/include/prc_inc_util.nss @@ -16,6 +16,9 @@ const string PRC_ForcedRestDetector_Generation = "PRC_ForcedRestDetector_Generat // FUNCTION DECLARATIONS /////////////////////////////////////////////////////////////////////////////// +//:: Returns TRUE is the item is on the Alchemy crafting 2DA. +int GetIsAlchemical(object oItem); + // Returns the number of henchmen a player has. int GetNumHenchmen(object oPC); @@ -35,6 +38,36 @@ void PRCForceRested(object oPC); // FUNCTION DEFINITIONS /////////////////////////////////////////////////////////////////////////////// +/** + * Returns a perpendicular vector to the input vector + * Rotates the vector 90 degrees in the XY plane while preserving Z + * + * @param vInput The input vector + * @return A perpendicular vector + */ +vector VectorToPerpendicular(vector vInput) +{ + return Vector(-vInput.y, vInput.x, vInput.z); +} + +int GetIsAlchemical(object oItem) +{ + if(!GetIsObjectValid(oItem)) return FALSE; + + string sResRef = GetResRef(oItem); + int nRows = StringToInt(Get2DACache("prc_craft_alchem", "ResRef", -1)); + + // Check if item's ResRef exists in alchemical crafting 2DA + int i; + for(i = 0; i < nRows; i++) + { + if(sResRef == Get2DACache("prc_craft_alchem", "ResRef", i)) + return TRUE; + } + + return FALSE; +} + int GetNumHenchmen(object oPC) { if (!GetIsPC(oPC)) return -1; @@ -225,4 +258,6 @@ void PRCForceRested(object oPC) //The PC has been forced rested--fix the problems this causes. SetLocalInt(oPC, "PRC_ForceRested", 1); ExecuteScript("prc_rest", oPC); -} \ No newline at end of file +} + +//:: void main (){} \ No newline at end of file diff --git a/src/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss index 0a59892..6a8baaf 100644 --- a/src/include/prc_inc_wpnrest.nss +++ b/src/include/prc_inc_wpnrest.nss @@ -1090,7 +1090,8 @@ void DoWeaponEquip(object oPC, object oItem, int nHand) { nSize++; // If you try and use the big weapons - if (nWeaponSize > nRealSize) + //if (nWeaponSize > nRealSize) + if (nWeaponSize > nRealSize && GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC) != OBJECT_INVALID) { SetCompositeAttackBonus(oPC, "MonkeyGripL", -2, ATTACK_BONUS_OFFHAND); SetCompositeAttackBonus(oPC, "MonkeyGripR", -2, ATTACK_BONUS_ONHAND); diff --git a/src/include/prc_nui_lv_inc.nss b/src/include/prc_nui_lv_inc.nss index b3d862f..dffc040 100644 --- a/src/include/prc_nui_lv_inc.nss +++ b/src/include/prc_nui_lv_inc.nss @@ -8,7 +8,7 @@ */ //::////////////////////////////////////////////// //:: Created By: Rakiov -//:: Created On: 20.06.2005 +//:: Created On: 20.08.2025 //::////////////////////////////////////////////// #include "prc_nui_com_inc" @@ -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_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..3c4a90d 100644 --- a/src/include/prc_spell_const.nss +++ b/src/include/prc_spell_const.nss @@ -24,6 +24,15 @@ const int SPELL_BCM_RENDING_CLAWS = 17997; //:: Complete Warrior const int SPELL_RANGED_DISARM = 3493; +const int SPELL_FT_FREEZING_LIFEBLOOD = 17968; +const int SPELL_FT_PAIN_TOUCH = 17970; + +//:: Oriental Adventures +const int SPELL_FT_CHOKE_HOLD = 17966; +const int SPELL_FT_FALLING_STAR_STRIKE = 17967; +const int SPELL_FT_KI_SHOUT = 17969; +const int SPELL_FT_UNBALANCING_STRIKE = 17971; + //:: Tome of Battle const int SPELL_TOB_SNAP_KICK = 3794; @@ -443,14 +452,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 +556,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; 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..829fd80 100644 --- a/src/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -754,7 +754,6 @@ if(nItem == BASE_ITEM_BASTARDSWORD // ---------------------------------------------------------------------------- // Returns TRUE if weapon is a blugeoning weapon -// Uses Get2DAString! // ---------------------------------------------------------------------------- int IPGetIsBludgeoningWeapon(object oItem) { diff --git a/src/include/prcsp_engine.nss b/src/include/prcsp_engine.nss index 833ec49..3e82a07 100644 --- a/src/include/prcsp_engine.nss +++ b/src/include/prcsp_engine.nss @@ -171,7 +171,7 @@ int PRCGetSpellResistance(object oTarget, object oCaster) // Dread Carapace Heart Bind if(GetIsIncarnumUser(oTarget)) { - if (GetIsMeldBound(oTarget, MELD_DREAD_CARAPACE) == CHAKRA_CROWN) + if (GetIsMeldBound(oTarget, MELD_DREAD_CARAPACE) == CHAKRA_CROWN || GetIsMeldBound(oTarget, MELD_DREAD_CARAPACE) == CHAKRA_DOUBLE_CROWN) { int nCont = 5 + (4 * GetEssentiaInvested(oTarget, MELD_DREAD_CARAPACE)); if(nCont > iSpellRes) @@ -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_core.nss b/src/include/psi_inc_core.nss index b4ca245..168eaae 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; }; ////////////////////////////////////////////////// @@ -892,7 +894,7 @@ int GetTargetSpecificChangesToDamage(object oTarget, object oManifester, int nDa // Reasonable return values only if(nDamage < 0) nDamage = 0; - if (GetIsMeldBound(oManifester, MELD_PSYCHIC_FOCUS) == CHAKRA_THROAT && nDamage > 0 && !GetLocalInt(oManifester, "PsychicFocusMeld") && bIsHitPointDamage) + if (GetIsMeldBound(oManifester, MELD_PSYCHIC_FOCUS) == CHAKRA_THROAT || GetIsMeldBound(oManifester, MELD_PSYCHIC_FOCUS) == CHAKRA_DOUBLE_THROAT && nDamage > 0 && !GetLocalInt(oManifester, "PsychicFocusMeld") && bIsHitPointDamage) { SetLocalInt(oManifester, "PsychicFocusMeld", TRUE); DelayCommand(6.0, DeleteLocalInt(oManifester, "PsychicFocusMeld")); @@ -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..c28ab7b 100644 --- a/src/include/psi_inc_psifunc.nss +++ b/src/include/psi_inc_psifunc.nss @@ -29,6 +29,8 @@ /* Function prototypes */ ////////////////////////////////////////////////// +int IsUnagumentablePower(int nPower); + /** * Determines if the power that is currently being attempted to be manifested * can in fact be manifested. Calculates PP cost and pays it. Determines @@ -143,6 +145,131 @@ struct manifestation EvaluateDiaDragChannel(object oManifester, object oTarget, /* Internal functions */ ////////////////////////////////////////////////// +//:: Returns TRUE if nPower is a power that can't +//:: normally be augmented. +int IsUnagumentablePower(int nPower) +{ + switch (nPower) + { + case POWER_ANIMAL_AFFINITY: + case POWER_ASSIMILATE: + case POWER_ASTRALSEED: + case POWER_BITE_WOLF: + case POWER_BODY_EQUILIBRIUM: + case POWER_BODYPURIFICATION: + case POWER_BURST: + case POWER_CATAPSI: + case POWER_CHAMELEON: + case POWER_CLAIRTANGENT_HAND: + case POWER_CLAIRVOYANT_SENSE: + case POWER_CLAW_ENERGY_COLD: + case POWER_CLAW_ENERGY_ELEC: + case POWER_CLAW_ENERGY_FIRE: + case POWER_CLAW_OF_THE_VAMPIRE: + case POWER_CLOUD_MIND: + case POWER_CLOUD_MIND_MASS: + case POWER_CONCEALTHOUGHT: + case POWER_CONCEALAMORPHA: + case POWER_GREATAMORPHA: + case POWER_CONTROLAIR: + case POWER_CONTROL_OBJECT: + case POWER_CONTROLSOUND: + case POWER_CREATESOUND: + case POWER_CRYSTALLIZE: + case POWER_DARKVISION: + case POWER_DECEREBRATE: + case POWER_DESTINYDISSONANCE: + case POWER_DETECT_REMOTE_VIEWING: + case POWER_DIMENSIONDOOR: + case POWER_DIMENSION_SLIDE: + case POWER_DIMENSIONALANCHOR: + case POWER_DISMISSAL: + case POWER_DISPELLING_BUFFER: + case POWER_DISTRACT: + case POWER_DUODIMENSIONAL_CLAW: + case POWER_ECTOPLASMICFORM: + case POWER_ECTOSHAMBLER: + case POWER_GREASE: + case POWER_ELFSIGHT: + case POWER_EMPATHY: + case POWER_ENERGYADAPTION: + case POWER_ENERGYADAPTACID: + case POWER_ENERGYADAPTCOLD: + case POWER_ENERGYADAPTELEC: + case POWER_ENERGYADAPTFIRE: + case POWER_ENERGYADAPTSONIC: + case POWER_ENERGYWALL_COLD: + case POWER_ENERGYWALL_ELEC: + case POWER_ENERGYWALL_FIRE: + case POWER_ENERGYWALL_SONIC: + case POWER_ESCAPE_DETECTION: + case POWER_ETHEREALJAUNT: + case POWER_ETHEREALNESS: + case POWER_FREEDOM: + case POWER_GENESIS: + case POWER_HUSTLE: + case POWER_IDENTIFY: + case POWER_IMMOVABILITY: + case POWER_INERTBARRIER: + case POWER_IRONBODY: + case POWER_KEENEDGE: + case POWER_KNOCK: + case POWER_MATTERAGITATION: + case POWER_MINDBLANKPERSONAL: + case POWER_PSIMINDBLANK: + case POWER_MOMENTOFPRESCIENCEATTACK: + case POWER_MOMENTOFPRESCIENCEARMOUR: + case POWER_MOMENTOFPRESCIENCESAVES: + case POWER_MOMENTOFPRESCIENCESKILLS: + case POWER_MYLIGHT: + case POWER_NULL_PSIONICS_FIELD: + case POWER_PAINFUL_STRIKE: + case POWER_POWERLEECH: + case POWER_POWERRESISTANCE: + case POWER_PRECOGNITION_MAIN: + case POWER_GREATERPRECOGNITION_MAIN: + case POWER_LOCK: + case POWER_PSIONICREVIVIFY: + case POWER_PSYCHICCHIR_REPAIR: + case POWER_PSYCHICCHIR_TRANSFER: + case POWER_PSYCHICVAMPIRE: + case POWER_PSYCHOFEEDBACK: + case POWER_RECALLDEATH: + case POWER_REDDOPSI: + case POWER_REMOTE_VIEW_TRAP: + case POWER_REMOTE_VIEWING: + case POWER_PSIONICRESTORATION: + case POWER_SECONDCHANCE: + case POWER_SEQUESTER: + case POWER_SHADOWBODY: + case POWER_SHAREPAIN: + case POWER_SHATTERMINDBLANK: + case POWER_SKATE: + case POWER_STEADFASTPERCEP: + case POWER_SYNESTHETE: + case POWER_TELEMPATHICPRO: + case POWER_TELEPORT_SELFONLY: + case POWER_TELEPORT_PARTY: + case POWER_GREATER_TELEPORT_SELFONLY: + case POWER_GREATER_TELEPORT_PARTY: + case POWER_TELEPORTATIONCIRCLE_VISIBLE: + case POWER_TELEPORTATIONCIRCLE_HIDDEN: + case POWER_TIMELESSBODY: + case POWER_TOUCHSIGHT: + case POWER_TRUEMETABOLISM: + case POWER_TRUESEEING: + case POWER_TRUEVENOM: + case POWER_TRUEVENOM_WEAPON: + case POWER_UBIQVISION: + case POWER_VAMPIRIC_WEAPON: + case POWER_WEAPON_ENERGY_COLD: + case POWER_WEAPON_ENERGY_ELEC: + case POWER_WEAPON_ENERGY_FIRE: + return TRUE; + } + return FALSE; +} + /** Internal function. * Calculates PP cost reduction from various factors. Currently accounts for: * - Thrallherd @@ -557,6 +684,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 +940,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 +968,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 +1267,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/shd_inc_mystknwn.nss b/src/include/shd_inc_mystknwn.nss index 0189d05..1c65ef5 100644 --- a/src/include/shd_inc_mystknwn.nss +++ b/src/include/shd_inc_mystknwn.nss @@ -520,7 +520,7 @@ int GetMaxMysteryLevelLearnable(object oShadow, int nClass, int nType) if(DEBUG) DoDebug("GetMaxMysteryLevelLearnable nType: " + IntToString(nType)); // Rules Quote: - // Within a category�Apprentice, Initiate, Master�you must have at least two mysteries of any given level + // Within a category -Apprentice, Initiate, Master- you must have at least two mysteries of any given level // before you can take any mysteries of the next higher level. For instance, you must have two 1st-level // mysteries before you can take any 2nds, and at least two 2nds before you can take any 3rds. int nMaxLrn, i, nMystLevel, nCount1, nCount2; diff --git a/src/include/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss index 5449590..b8648b7 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) { @@ -519,7 +536,34 @@ int SilenceDeafnessFailure(object oCaster, int nSpellLevel, int nMetamagic, stri return FALSE; } -int Forsaker(object oCaster, object oTarget) +int Forsaker(object oCaster, object oTarget) +{ + // Friendly spells autofail on Forsakers + if (GetLevelByClass(CLASS_TYPE_FORSAKER, oTarget) && GetIsFriend(oTarget, oCaster)) + { + FloatingTextStringOnCreature("Target is a Forsaker, spell failed!", oCaster, FALSE); + return FALSE; + } + + // Forsakers can't use magic + if (GetLevelByClass(CLASS_TYPE_FORSAKER, oCaster)) + { + object oSpellCastItem = PRCGetSpellCastItem(); + + // Allow alchemical items + if(GetIsObjectValid(oSpellCastItem) && GetIsAlchemical(oSpellCastItem)) + { + return TRUE; + } + + FloatingTextStringOnCreature("Forsakers cannot cast spells!", oCaster, FALSE); + return FALSE; + } + + return TRUE; +} + +/* int Forsaker(object oCaster, object oTarget) { // Friendly spells autofail on Forsakers if (GetLevelByClass(CLASS_TYPE_FORSAKER, oTarget) && GetIsFriend(oTarget, oCaster)) @@ -536,7 +580,7 @@ int Forsaker(object oCaster, object oTarget) } return TRUE; -} +} */ int NSB_SpellCast(object oCaster, int nSpellID, int nCastingClass, int nMetamagic, int nSpellbookType, string sComponent, object oSpellCastItem) { @@ -1585,11 +1629,7 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_UNSEEN_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_BEGUILER)) return TRUE; if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_BEGUILER)) return TRUE; - if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BEGUILER)) return TRUE; - - - - + if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BEGUILER)) return TRUE; } if (bDuskblade) { @@ -1636,9 +1676,7 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF) if (GetHasFeat(FEAT_UNSEEN_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_DUSKBLADE)) return TRUE; if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_DUSKBLADE)) return TRUE; - if (GetHasFeat(FEAT_WWOC_SPELLCASTING_DUSKBLADE)) return TRUE; - - + if (GetHasFeat(FEAT_WWOC_SPELLCASTING_DUSKBLADE)) return TRUE; } if (bSorcerer) { @@ -2161,10 +2199,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)) @@ -3284,7 +3347,80 @@ int X2PreSpellCastCode2() int bSpellIsHostile = Get2DACache("spells", "HostileSetting", nOrigSpellID) == "1"; int nSpellbookType = GetSpellbookTypeForClass(nCastingClass); int nCasterAlignment = GetAlignmentGoodEvil(oCaster); - string sComponent = GetStringUpperCase(Get2DACache("spells", "VS", nSpellID)); + string sComponent = GetStringUpperCase(Get2DACache("spells", "VS", nSpellID)); + + //--------------------------------------------------------------------------- + // Check for Circle Magic participant sacrifices. + //--------------------------------------------------------------------------- + if (GetLocalInt(oCaster, "CircleMagicSacrifice")) + { + object oLeader = GetLocalObject(oCaster, "CircleMagicLeader"); + string sCircleClass = GetLocalString(oLeader, "CircleMagicClass"); + + // Validate class compatibility + if (sCircleClass == "RED_WIZARD" && GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster) == 0) + { + FloatingTextStringOnCreature("Only Red Wizards may join this circle.", oCaster); + DeleteLocalInt(oCaster, "CircleMagicSacrifice"); + DeleteLocalObject(oCaster, "CircleMagicLeader"); + return FALSE; + } + if (sCircleClass == "HATHRAN" && GetLevelByClass(CLASS_TYPE_HATHRAN, oCaster) == 0) + { + FloatingTextStringOnCreature("Only Hathrans may join this circle.", oCaster); + DeleteLocalInt(oCaster, "CircleMagicSacrifice"); + DeleteLocalObject(oCaster, "CircleMagicLeader"); + return FALSE; + } + + // Valid case: record contribution and suppress spell + if (oTarget == oLeader && GetLocalInt(oLeader, "CircleMagicActive")) + { + int nLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass); + int nTotal = GetLocalInt(oLeader, "CircleMagicTotal") + nLevel; + int nParticipants = GetLocalInt(oLeader, "CircleMagicParticipants") + 1; + SetLocalInt(oLeader, "CircleMagicTotal", nTotal); + SetLocalInt(oLeader, "CircleMagicParticipants", nParticipants); + + // Suppress the spell + DeleteLocalInt(oCaster, "CircleMagicSacrifice"); + DeleteLocalObject(oCaster, "CircleMagicLeader"); + PRCSetUserSpecificSpellScriptFinished(); + return FALSE; // Prevents spell effects + } + else + { + FloatingTextStringOnCreature("Invalid target or circle not active.", oCaster); + DeleteLocalInt(oCaster, "CircleMagicSacrifice"); + DeleteLocalObject(oCaster, "CircleMagicLeader"); + return FALSE; + } + } + + //--------------------------------------------------------------------------- + // Check for Circle Leader finalization. + //--------------------------------------------------------------------------- + if (GetLocalInt(oCaster, "CircleMagicActive")) + { + int nTotal = GetLocalInt(oCaster, "CircleMagicTotal"); + int nParticipants = GetLocalInt(oCaster, "CircleMagicParticipants"); + if (nParticipants >= 2 && nTotal > 0) + { + // Apply augmentation via caster level adjustment variable + SetLocalInt(oCaster, PRC_CASTERLEVEL_ADJUSTMENT, nTotal / 2); + FloatingTextStringOnCreature("Circle Magic augmentation applied (" + IntToString(nTotal) + " levels).", oCaster); + } + else + { + FloatingTextStringOnCreature("Circle Magic requires at least two participants to apply a bonus.", oCaster); + } + // Clear circle state + DeleteLocalInt(oCaster, "CircleMagicActive"); + DeleteLocalInt(oCaster, "CircleMagicTotal"); + DeleteLocalString(oCaster, "CircleMagicClass"); + DeleteLocalInt(oCaster, "CircleMagicMaxParticipants"); + DeleteLocalInt(oCaster, "CircleMagicParticipants"); + } //--------------------------------------------------------------------------- // This small addition will check to see if the target is mounted and the @@ -3366,11 +3502,11 @@ int X2PreSpellCastCode2() ApplyInfusionPoison(oCaster, nItemCL); nContinue = FALSE; } - } + } //--------------------------------------------------------------------------- - // No casting while using expertise - //--------------------------------------------------------------------------- + // No casting while using expertise + //--------------------------------------------------------------------------- if(nContinue) if (GetActionMode(oCaster, ACTION_MODE_EXPERTISE) || GetActionMode(oCaster, ACTION_MODE_IMPROVED_EXPERTISE)) { @@ -3757,4 +3893,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/are/serverentranc001.are.json b/src/module/are/serverentranc001.are.json index 68a6199..9b841e1 100644 --- a/src/module/are/serverentranc001.are.json +++ b/src/module/are/serverentranc001.are.json @@ -87,7 +87,7 @@ "Name": { "type": "cexolocstring", "value": { - "0": "Server Entrance - Welcome to the World of Greyhawk" + "0": "| Server Entrance - Welcome to the World of Greyhawk |" } }, "NoRest": { diff --git a/src/module/ifo/module.ifo.json b/src/module/ifo/module.ifo.json index 5b64446..b7d6584 100644 --- a/src/module/ifo/module.ifo.json +++ b/src/module/ifo/module.ifo.json @@ -3709,7 +3709,7 @@ }, "Value": { "type": "int", - "value": 1 + "value": 0 } }, { @@ -3739,7 +3739,7 @@ }, "Value": { "type": "cexostring", - "value": "pwdata" + "value": "wogpw_data" } }, { diff --git a/src/module/itp/creaturepalcus.itp.json b/src/module/itp/creaturepalcus.itp.json index c243f87..5056b03 100644 --- a/src/module/itp/creaturepalcus.itp.json +++ b/src/module/itp/creaturepalcus.itp.json @@ -5849,7 +5849,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 13.0 + "value": 14.0 }, "FACTION": { "type": "cexostring", @@ -7933,7 +7933,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 3.0 + "value": 4.0 }, "FACTION": { "type": "cexostring", @@ -10718,7 +10718,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 18.0 + "value": 20.0 }, "FACTION": { "type": "cexostring", @@ -14208,7 +14208,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 19.0 + "value": 20.0 }, "FACTION": { "type": "cexostring", @@ -14246,7 +14246,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 14.0 + "value": 15.0 }, "FACTION": { "type": "cexostring", @@ -14284,7 +14284,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 7.0 + "value": 6.0 }, "FACTION": { "type": "cexostring", @@ -14303,7 +14303,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 2.0 + "value": 1.0 }, "FACTION": { "type": "cexostring", @@ -14360,7 +14360,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 3.0 + "value": 2.0 }, "FACTION": { "type": "cexostring", @@ -14474,7 +14474,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 17.0 + "value": 19.0 }, "FACTION": { "type": "cexostring", @@ -14550,7 +14550,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 10.0 + "value": 11.0 }, "FACTION": { "type": "cexostring", @@ -14569,7 +14569,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 12.0 + "value": 13.0 }, "FACTION": { "type": "cexostring", @@ -14588,7 +14588,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 2.0 + "value": 3.0 }, "FACTION": { "type": "cexostring", @@ -14607,7 +14607,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 4.0 + "value": 5.0 }, "FACTION": { "type": "cexostring", @@ -14816,7 +14816,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 19.0 + "value": 20.0 }, "FACTION": { "type": "cexostring", @@ -14892,7 +14892,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 12.0 + "value": 13.0 }, "FACTION": { "type": "cexostring", @@ -14930,7 +14930,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 6.0 + "value": 7.0 }, "FACTION": { "type": "cexostring", @@ -17286,7 +17286,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 2.0 + "value": 3.0 }, "FACTION": { "type": "cexostring", @@ -17305,7 +17305,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 12.0 + "value": 13.0 }, "FACTION": { "type": "cexostring", @@ -27622,7 +27622,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 9.0 + "value": 10.0 }, "FACTION": { "type": "cexostring", @@ -29143,7 +29143,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 7.0 + "value": 6.0 }, "FACTION": { "type": "cexostring", @@ -31872,7 +31872,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 8.0 + "value": 7.0 }, "FACTION": { "type": "cexostring", @@ -33107,7 +33107,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 16.0 + "value": 18.0 }, "FACTION": { "type": "cexostring", @@ -35457,7 +35457,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 18.0 + "value": 19.0 }, "FACTION": { "type": "cexostring", @@ -35682,7 +35682,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 19.0 + "value": 20.0 }, "FACTION": { "type": "cexostring", @@ -35907,7 +35907,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 35.0 + "value": 37.0 }, "FACTION": { "type": "cexostring", @@ -35926,7 +35926,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 30.0 + "value": 31.0 }, "FACTION": { "type": "cexostring", @@ -37706,7 +37706,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 16.0 + "value": 17.0 }, "FACTION": { "type": "cexostring", @@ -38653,7 +38653,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 42.0 + "value": 45.0 }, "FACTION": { "type": "cexostring", @@ -53150,7 +53150,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 23.0 + "value": 24.0 }, "FACTION": { "type": "cexostring", @@ -53397,7 +53397,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 15.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -53454,7 +53454,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 13.0 + "value": 14.0 }, "FACTION": { "type": "cexostring", @@ -53511,7 +53511,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 1.0 + "value": 2.0 }, "FACTION": { "type": "cexostring", @@ -53549,7 +53549,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 9.0 + "value": 10.0 }, "FACTION": { "type": "cexostring", @@ -74361,7 +74361,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 20.0 + "value": 17.0 }, "FACTION": { "type": "cexostring", @@ -74380,7 +74380,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 16.0 + "value": 18.0 }, "FACTION": { "type": "cexostring", @@ -74399,7 +74399,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 16.0 + "value": 17.0 }, "FACTION": { "type": "cexostring", @@ -74418,7 +74418,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 15.0 + "value": 18.0 }, "FACTION": { "type": "cexostring", @@ -74646,7 +74646,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 17.0 + "value": 15.0 }, "FACTION": { "type": "cexostring", @@ -74665,7 +74665,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 18.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -74703,7 +74703,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 14.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -74722,7 +74722,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 15.0 + "value": 17.0 }, "FACTION": { "type": "cexostring", @@ -74760,7 +74760,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 14.0 + "value": 15.0 }, "FACTION": { "type": "cexostring", @@ -74779,7 +74779,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 15.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -74817,7 +74817,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 13.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -74836,7 +74836,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 14.0 + "value": 16.0 }, "FACTION": { "type": "cexostring", @@ -74988,7 +74988,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 13.0 + "value": 12.0 }, "FACTION": { "type": "cexostring", @@ -75007,7 +75007,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 11.0 + "value": 13.0 }, "FACTION": { "type": "cexostring", @@ -75045,7 +75045,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 11.0 + "value": 13.0 }, "FACTION": { "type": "cexostring", @@ -75083,7 +75083,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 7.0 + "value": 6.0 }, "FACTION": { "type": "cexostring", @@ -75102,7 +75102,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 6.0 + "value": 7.0 }, "FACTION": { "type": "cexostring", @@ -75140,7 +75140,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 6.0 + "value": 7.0 }, "FACTION": { "type": "cexostring", @@ -75691,7 +75691,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 18.0 + "value": 19.0 }, "FACTION": { "type": "cexostring", @@ -75748,7 +75748,7 @@ "__struct_id": 0, "CR": { "type": "float", - "value": 22.0 + "value": 21.0 }, "FACTION": { "type": "cexostring", diff --git a/src/module/nss/xp1_pcisdwarf.nss b/src/module/nss/xp1_pcisdwarf.nss new file mode 100644 index 0000000..fd02f78 --- /dev/null +++ b/src/module/nss/xp1_pcisdwarf.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// the PC is a dwarf + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_DWARF; + return iResult; +} diff --git a/src/module/nss/xp1_pciself.nss b/src/module/nss/xp1_pciself.nss new file mode 100644 index 0000000..a8d52c2 --- /dev/null +++ b/src/module/nss/xp1_pciself.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// checks to see if the PC is an elf + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_ELF; + return iResult; +} diff --git a/src/module/nss/xp1_pcisgnome.nss b/src/module/nss/xp1_pcisgnome.nss new file mode 100644 index 0000000..81ef4c7 --- /dev/null +++ b/src/module/nss/xp1_pcisgnome.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// the PC is a gnome + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_GNOME; + return iResult; +} diff --git a/src/module/nss/xp1_pcishalfelf.nss b/src/module/nss/xp1_pcishalfelf.nss new file mode 100644 index 0000000..3640c15 --- /dev/null +++ b/src/module/nss/xp1_pcishalfelf.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// the PC is a half-elf + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_HALFELF; + return iResult; +} diff --git a/src/module/nss/xp1_pcishalfling.nss b/src/module/nss/xp1_pcishalfling.nss new file mode 100644 index 0000000..a63ab79 --- /dev/null +++ b/src/module/nss/xp1_pcishalfling.nss @@ -0,0 +1,8 @@ +#include "prc_inc_racial" + +// the PC is a halfling + +int StartingConditional() +{ + return MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_HALFLING; +} diff --git a/src/module/nss/xp1_pcishalforc.nss b/src/module/nss/xp1_pcishalforc.nss new file mode 100644 index 0000000..d93cee8 --- /dev/null +++ b/src/module/nss/xp1_pcishalforc.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// the PC is a half-orc + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_HALFORC; + return iResult; +} diff --git a/src/module/nss/xp1_pcishuman.nss b/src/module/nss/xp1_pcishuman.nss new file mode 100644 index 0000000..62a0727 --- /dev/null +++ b/src/module/nss/xp1_pcishuman.nss @@ -0,0 +1,11 @@ +#include "prc_inc_racial" + +// check if the PC is human + +int StartingConditional() +{ + int iResult; + + iResult = MyPRCGetRacialType(GetPCSpeaker()) == RACIAL_TYPE_HUMAN; + return iResult; +}