/// @addtogroup skillranks SkillRanks /// @brief Enhances and allows for manipulation of skill rank calculations including the ability to build custom /// skill related feats as well as modifying stock feats. /// @{ /// @file nwnx_skillranks.nss #include "nwnx" const string NWNX_SkillRanks = "NWNX_SkillRanks"; ///< @private /// @name SkillRanks Key Abilities /// @anchor skr_key_abilities /// /// The abilities as bits /// @{ const int NWNX_SKILLRANKS_KEY_ABILITY_STRENGTH = 1; ///< Strength const int NWNX_SKILLRANKS_KEY_ABILITY_DEXTERITY = 2; ///< Dexterity const int NWNX_SKILLRANKS_KEY_ABILITY_CONSTITUTION = 4; ///< Constitution const int NWNX_SKILLRANKS_KEY_ABILITY_INTELLIGENCE = 8; ///< Intelligence const int NWNX_SKILLRANKS_KEY_ABILITY_WISDOM = 16; ///< Wisdom const int NWNX_SKILLRANKS_KEY_ABILITY_CHARISMA = 32; ///< Charisma ///@} /// @name SkillRanks Key Ability Calculation Method /// @anchor skr_key_ability_calc_bits /// /// Constants used to calculate the ability modifier for a skill. /// @{ /// @warning Use only one of these calculations in your mask! If you use more than one the first will be used. const int NWNX_SKILLRANKS_KEY_ABILITY_CALC_MIN = 64; ///< Use the minimum value of the provided ability scores. const int NWNX_SKILLRANKS_KEY_ABILITY_CALC_MAX = 128; ///< Use the maximum value of the provided ability scores. const int NWNX_SKILLRANKS_KEY_ABILITY_CALC_AVERAGE = 256; ///< Use the average value of the provided ability scores. const int NWNX_SKILLRANKS_KEY_ABILITY_CALC_SUM = 512; ///< Use the sum of the provided ability scores. ///@} /// @brief A feat that manipulates skill ranks. struct NWNX_SkillRanks_SkillFeat { int iSkill; ///< The skill this feat impacts int iFeat; ///< The feat /// Skill feat bonus/penalty int iModifier; /// 1 for Focus, 2 for Epic Focus. This can be set on a feat so NWNX_SkillRanks_SetFocusMod /// can mass change the modifier for the Skill Focus and Epic Skill Focus feats. int iFocusFeat; /// @brief 255 char bitset string for skill ranks impacted by class levels (like Bardic Knowledge). /// /// The right most bit is barbarian (class 0), second from right is bard (class 1) etc. /// It's not necessary to pass in the entire string, for example Ranger is class 7 and Fighter is 4 /// If you wanted those class levels to impact the skill modifier you could set sClasses equal to /// "10010000". From right to left = Barbarian, Bard, Cleric, Druid, Fighter, Monk, Paladin, Ranger /// You can alternatively use NWNX_SkillRanks_AddSkillFeatClass() for each class /// @remark If unset but #fClassLevelMod is set, then all classes will be included. string sClasses; /// Levels in class multiplier gives you skill modifier, for example 0.5f would mean 1 point for /// every two class levels. If #sClasses is not set and this is set then all class levels will be modified. float fClassLevelMod; /// Used for feats like Stonecunning or Trackless Step which restrict skill modifiers by area types. int iAreaFlagsRequired; /// Used for feats like Stonecunning or Trackless Step which restrict skill modifiers by area types. int iAreaFlagsForbidden; /// 1 for Day, 2 for Night - if skill modifiers only take effect based on the day/night cycle or an area /// that's set to always night. 0 is all hours. int iDayOrNight; /// This allows for feats that bypass the armor check penalty on skill rank calculations. int bBypassArmorCheckPenalty; /// @brief Bitmask of @ref skr_key_abilities "abilities" and @ref skr_key_ability_calc_bits "method to calculate" /// the ability modifier for a skill. /// /// Example **Doctor** Feat that used INT instead of WIS (if higher) for Heal skill would set to: /// #NWNX_SKILLRANKS_KEY_ABILITY_INTELLIGENCE | #NWNX_SKILLRANKS_KEY_ABILITY_WISDOM | #NWNX_SKILLRANKS_KEY_ABILITY_CALC_MAX; int iKeyAbilityMask; }; /// @param iSkill The skill to check the feat count. /// @return The count of feats for a specific skill. int NWNX_SkillRanks_GetSkillFeatCountForSkill(int iSkill); /// @brief Returns a skill feat. /// @param iSkill The skill. /// @param iFeat The feat. /// @return A constructed NWNX_SkillRanks_SkillFeat. struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_GetSkillFeat(int iSkill, int iFeat); /// @brief Returns a skill feat by index. /// @remark Generally used in a loop with NWNX_SkillRanks_GetSkillFeatCountForSkill(). /// @param iSkill The skill. /// @param iIndex The index in the list of feats for the skill. /// @return A constructed NWNX_SkillRanks_SkillFeat. struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_GetSkillFeatForSkillByIndex(int iSkill, int iIndex); /// @brief Modifies or creates a skill feat. /// @param skillFeat The defined NWNX_SkillRanks_SkillFeat. /// @param createIfNonExistent TRUE to create if the feat does not exist. void NWNX_SkillRanks_SetSkillFeat(struct NWNX_SkillRanks_SkillFeat skillFeat, int createIfNonExistent = FALSE); /// @brief Add classes to a skill feat instead of working with the NWNX_SkillRanks_SkillFeat::sClasses string. /// /// Manipulating the sClasses string in the NWNX_SkillRanks_SkillFeat struct can be difficult. This /// function allows the builder to enter one class at a time. /// @param skillFeat The NWNX_SkillRanks_SkillFeat for which the sClasses field will be modifier. /// @param iClass The class to add to the Skill Feat. /// @return The updated NWNX_SkillRanks_SkillFeat. struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_AddSkillFeatClass(struct NWNX_SkillRanks_SkillFeat skillFeat, int iClass); /// @brief Change the modifier value for Skill Focus and Epic Skill Focus feats. /// /// The stock modifier on Skill Focus and Epic Skill Focus are 3 and 10 respectively, these can be /// changed with this function. /// @param iModifier The new value for the feat modifier. /// @param iEpic Set to TRUE to change the value for Epic Skill Focus. void NWNX_SkillRanks_SetSkillFeatFocusModifier(int iModifier, int iEpic = FALSE); /// @brief Gets the current penalty to Dexterity based skills when blind. /// @return The penalty to Dexterity when blind. int NWNX_SkillRanks_GetBlindnessPenalty(); /// @brief Set the value the Dexterity based skills get decreased due to blindness. /// @remark Default is 4. /// @param iModifier The penalty to Dexterity when blind. void NWNX_SkillRanks_SetBlindnessPenalty(int iModifier); /// @brief Get a skill modifier for an area. /// @param oArea The area. /// @param iSkill The skill to check. /// @return The modifier to that skill in the area. int NWNX_SkillRanks_GetAreaModifier(object oArea, int iSkill); /// @brief Sets a skill modifier for the area. /// @param oArea The area. /// @param iSkill The skill to change. /// @param iModifier The modifier to the skill in the area. void NWNX_SkillRanks_SetAreaModifier(object oArea, int iSkill, int iModifier); /// @} int NWNX_SkillRanks_GetSkillFeatCountForSkill(int iSkill) { string sFunc = "GetSkillFeatCountForSkill"; NWNX_PushArgumentInt(iSkill); NWNX_CallFunction(NWNX_SkillRanks, sFunc); return NWNX_GetReturnValueInt(); } struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_GetSkillFeatForSkillByIndex(int iSkill, int iIndex) { string sFunc = "GetSkillFeatForSkillByIndex"; NWNX_PushArgumentInt(iIndex); NWNX_PushArgumentInt(iSkill); NWNX_CallFunction(NWNX_SkillRanks, sFunc); struct NWNX_SkillRanks_SkillFeat skillFeat; skillFeat.iSkill = iSkill; skillFeat.iFeat = NWNX_GetReturnValueInt(); skillFeat.iModifier = NWNX_GetReturnValueInt(); skillFeat.iFocusFeat = NWNX_GetReturnValueInt(); skillFeat.sClasses = NWNX_GetReturnValueString(); skillFeat.fClassLevelMod = NWNX_GetReturnValueFloat(); skillFeat.iAreaFlagsRequired = NWNX_GetReturnValueInt(); skillFeat.iAreaFlagsForbidden = NWNX_GetReturnValueInt(); skillFeat.iDayOrNight = NWNX_GetReturnValueInt(); skillFeat.bBypassArmorCheckPenalty = NWNX_GetReturnValueInt(); skillFeat.iKeyAbilityMask = NWNX_GetReturnValueInt(); return skillFeat; } struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_GetSkillFeat(int iSkill, int iFeat) { string sFunc = "GetSkillFeat"; NWNX_PushArgumentInt(iFeat); NWNX_PushArgumentInt(iSkill); NWNX_CallFunction(NWNX_SkillRanks, sFunc); struct NWNX_SkillRanks_SkillFeat skillFeat; skillFeat.iSkill = iSkill; skillFeat.iFeat = iFeat; skillFeat.iModifier = NWNX_GetReturnValueInt(); skillFeat.iFocusFeat = NWNX_GetReturnValueInt(); skillFeat.sClasses = NWNX_GetReturnValueString(); skillFeat.fClassLevelMod = NWNX_GetReturnValueFloat(); skillFeat.iAreaFlagsRequired = NWNX_GetReturnValueInt(); skillFeat.iAreaFlagsForbidden = NWNX_GetReturnValueInt(); skillFeat.iDayOrNight = NWNX_GetReturnValueInt(); skillFeat.bBypassArmorCheckPenalty = NWNX_GetReturnValueInt(); skillFeat.iKeyAbilityMask = NWNX_GetReturnValueInt(); return skillFeat; } void NWNX_SkillRanks_SetSkillFeat(struct NWNX_SkillRanks_SkillFeat skillFeat, int createIfNonExistent = FALSE) { string sFunc = "SetSkillFeat"; NWNX_PushArgumentInt(createIfNonExistent); NWNX_PushArgumentInt(skillFeat.iKeyAbilityMask); NWNX_PushArgumentInt(skillFeat.bBypassArmorCheckPenalty); NWNX_PushArgumentInt(skillFeat.iDayOrNight); NWNX_PushArgumentInt(skillFeat.iAreaFlagsForbidden); NWNX_PushArgumentInt(skillFeat.iAreaFlagsRequired); NWNX_PushArgumentFloat(skillFeat.fClassLevelMod); // We only need to send the string from the point of the first set bit NWNX_PushArgumentString(GetStringRight(skillFeat.sClasses,GetStringLength(skillFeat.sClasses)-FindSubString(skillFeat.sClasses,"1"))); NWNX_PushArgumentInt(skillFeat.iFocusFeat); NWNX_PushArgumentInt(skillFeat.iModifier); NWNX_PushArgumentInt(skillFeat.iFeat); NWNX_PushArgumentInt(skillFeat.iSkill); NWNX_CallFunction(NWNX_SkillRanks, sFunc); } struct NWNX_SkillRanks_SkillFeat NWNX_SkillRanks_AddSkillFeatClass(struct NWNX_SkillRanks_SkillFeat skillFeat, int iClass) { if (GetStringLength(skillFeat.sClasses) < 255) { int i; string sPad; for (i = 0; i < 255-GetStringLength(skillFeat.sClasses); i++) { sPad = sPad + "0"; } skillFeat.sClasses = sPad + skillFeat.sClasses; } skillFeat.sClasses = GetStringLeft(skillFeat.sClasses, 254 - iClass) + "1" + GetStringRight(skillFeat.sClasses, iClass); return skillFeat; } void NWNX_SkillRanks_SetSkillFeatFocusModifier(int iModifier, int epicFocus = FALSE) { string sFunc = "SetSkillFeatFocusModifier"; NWNX_PushArgumentInt(epicFocus); NWNX_PushArgumentInt(iModifier); NWNX_CallFunction(NWNX_SkillRanks, sFunc); } int NWNX_SkillRanks_GetBlindnessPenalty() { string sFunc = "GetBlindnessPenalty"; NWNX_CallFunction(NWNX_SkillRanks, sFunc); return NWNX_GetReturnValueInt(); } void NWNX_SkillRanks_SetBlindnessPenalty(int iModifier) { string sFunc = "SetBlindnessPenalty"; NWNX_PushArgumentInt(iModifier); NWNX_CallFunction(NWNX_SkillRanks, sFunc); } int NWNX_SkillRanks_GetAreaModifier(object oArea, int iSkill) { string sFunc = "GetAreaModifier"; NWNX_PushArgumentInt(iSkill); NWNX_PushArgumentObject(oArea); NWNX_CallFunction(NWNX_SkillRanks, sFunc); return NWNX_GetReturnValueInt(); } void NWNX_SkillRanks_SetAreaModifier(object oArea, int iSkill, int iModifier) { string sFunc = "SetAreaModifier"; NWNX_PushArgumentInt(iModifier); NWNX_PushArgumentInt(iSkill); NWNX_PushArgumentObject(oArea); NWNX_CallFunction(NWNX_SkillRanks, sFunc); }