Files
roll20-character-sheets/Pathfinder Community/dev/src/PFSkills.js
T

1131 lines
44 KiB
JavaScript

'use strict';
import _ from 'underscore';
import TAS from './TheAaronSheet.js';
import {PFLog, PFConsole} from './PFLog';
import PFConst from './PFConst';
import * as SWUtils from './SWUtils';
import * as PFUtils from './PFUtils';
import * as PFMacros from './PFMacros';
import * as PFMigrate from './PFMigrate';
import * as PFUtilsAsync from './PFUtilsAsync';
import * as PFAbilityScores from './PFAbilityScores';
export var regularCoreSkills = ["Appraise", "Acrobatics", "Bluff", "Climb", "Diplomacy", "Disable-Device", "Disguise", "Escape-Artist", "Fly", "Handle-Animal", "Heal", "Intimidate", "Linguistics", "Perception", "Ride", "Sense-Motive", "Sleight-of-Hand", "Spellcraft", "Stealth", "Survival", "Swim", "Use-Magic-Device"],
regularBackgroundSkills = ["Appraise", "Handle-Animal", "Linguistics", "Sleight-of-Hand"],
regularAdventureSkills = ["Acrobatics", "Bluff", "Climb", "Diplomacy", "Disable-Device", "Disguise", "Escape-Artist", "Fly", "Heal", "Intimidate", "Perception", "Ride", "Sense-Motive", "Spellcraft", "Stealth", "Survival", "Swim", "Use-Magic-Device"],
regularBackgroundSkillsPlusKnow = regularBackgroundSkills.concat(["Knowledge-Engineering", "Knowledge-Geography", "Knowledge-History", "Knowledge-Nobility"]).sort(),
regularAdventurePlusKnow = regularAdventureSkills.concat(["Knowledge-Arcana", "Knowledge-Dungeoneering", "Knowledge-Local", "Knowledge-Nature", "Knowledge-Planes", "Knowledge-Religion"]).sort(),
//number that is appended to 10 versions of skills with subskills.
skillAppendNums = ["", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
//same but for misc-skill
miscSkillAppendNums = ["-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9"],
coreSkillsWithFillInNames = ["Craft", "Misc-Skill", "Perform", "Profession"],
backgroundOnlySkillsWithFillinNames = ["Artistry", "Lore"],
skillsWithFillInNames = coreSkillsWithFillInNames.concat(backgroundOnlySkillsWithFillinNames).concat(["CS-Misc-Skill"]).sort(),
backgroundOnlySkills = SWUtils.cartesianAppend(backgroundOnlySkillsWithFillinNames, skillAppendNums),
knowledgeSubSkills = ["Arcana", "Dungeoneering", "Engineering", "Geography", "History", "Local", "Nature", "Nobility", "Planes", "Religion"],
coreSkillsWithSubSkills = coreSkillsWithFillInNames.concat(["Knowledge"]).sort(),
skillsWithSubSkills = skillsWithFillInNames.concat(["Knowledge"]).sort(),
knowledgeSkillAppends = _.map(knowledgeSubSkills, function (subskill) {
return "-" + subskill;
}),
//for each skill array of the possible skills {"Craft":["Craft","Craft2"...],"Perform":["Perform","Perform2"...] }
subskillArrays = _.reduce(skillsWithSubSkills, function (memo, skill) {
var appenders = (skill === "Misc-Skill") ? miscSkillAppendNums : (skill === "CS-Misc-Skill") ? miscSkillAppendNums :
(skill === "Knowledge") ? knowledgeSkillAppends : skillAppendNums;
memo[skill] = SWUtils.cartesianAppend([skill], skillAppendNums);
return memo;
}, {}),
backgroundCoreSkills = regularBackgroundSkillsPlusKnow.concat(subskillArrays["Craft"]).concat(subskillArrays["Perform"]).concat(subskillArrays["Profession"]).concat(["Misc-Skill-5", "Misc-Skill-6", "Misc-Skill-7", "Misc-Skill-8", "Misc-Skill-9"]).sort(),
adventureSkills = regularAdventurePlusKnow.concat(["Misc-Skill-0", "Misc-Skill-1", "Misc-Skill-2", "Misc-Skill-3", "Misc-Skill-4"]).sort(),
checkRTArray = ["-ReqTrain", "-ranks"],
baseGenMacro = "&{template:pf_generic} @{toggle_accessible_flag} @{toggle_rounded_flag} {{font=@{apply_specfont_chat}@{use_specfont}}} {{scroll_desc=@{scroll-desc}}} {{color=@{rolltemplate_color}}} {{header_image=@{header_image-pf_generic-skill}}} {{character_name=@{character_name}}} {{character_id=@{character_id}}} {{subtitle}} ",
skillHeaderMacro = "{{name=^{REPLACELOWER} ^{skills} }} ",
npcSkillHeaderMacro = "{{name=^{npc} ^{REPLACELOWER} ^{skills} }} ",
// 1 is the normal size modifier in size_skill, 2 is size_skill_double
sizeSkills = {
"Fly": 1,
"Stealth": 2,
"CS-Stealth": 2
},
//these are for building the macros
knowledgeSubSkillsTranslateKeys = _.map(knowledgeSubSkills, function (key) {
return key.toLowerCase();
}),
skillsWithSpaces = ["disable device", "escape artist", "sense motive", "handle animal", "use magic device", "sleight of hand"],
knowledgeSkills = _.map(knowledgeSubSkills, function (subskill) {
return "Knowledge-" + subskill;
}),
backgroundSkills = backgroundCoreSkills.concat(backgroundOnlySkills).sort(),
allCoreSkills = adventureSkills.concat(backgroundCoreSkills).sort(),
consolidatedSkills = ["CS-Acrobatics", "CS-Athletics", "CS-Finesse", "CS-Influence", "CS-Nature", "CS-Perception", "CS-Performance", "CS-Religion", "CS-Society", "CS-Spellcraft", "CS-Stealth", "CS-Survival"],
consolidatedMiscSkills = ["CS-Misc-Skill-0", "CS-Misc-Skill-1", "CS-Misc-Skill-2", "CS-Misc-Skill-3", "CS-Misc-Skill-4","CS-Misc-Skill-5", "CS-Misc-Skill-6", "CS-Misc-Skill-7", "CS-Misc-Skill-8", "CS-Misc-Skill-9"],
allNonFillInSkills = regularCoreSkills.concat(knowledgeSkills).concat(consolidatedSkills).sort(),
nonMiscFillInSkillsInstances = SWUtils.cartesianAppend(["Craft", "Perform", "Profession", "Artistry", "Lore"], skillAppendNums),
miscFillInSkillsInstances =SWUtils.cartesianAppend(["Misc-Skill"], miscSkillAppendNums).concat(consolidatedMiscSkills),
allFillInSkillInstances = nonMiscFillInSkillsInstances.concat(miscFillInSkillsInstances).sort(),
allTheSkills = allNonFillInSkills.concat(allFillInSkillInstances).sort(),
coreSkillAbilityDefaults = {
"Acrobatics": "dex",
"Appraise": "int",
"Bluff": "cha",
"Climb": "str",
"Craft": "int",
"Diplomacy": "cha",
"Disable-Device": "dex",
"Disguise": "cha",
"Escape-Artist": "dex",
"Fly": "dex",
"Handle-Animal": "cha",
"Heal": "wis",
"Intimidate": "cha",
"Knowledge-Arcana": "int",
"Knowledge-Dungeoneering": "int",
"Knowledge-Engineering": "int",
"Knowledge-Geography": "int",
"Knowledge-History": "int",
"Knowledge-Local": "int",
"Knowledge-Nature": "int",
"Knowledge-Nobility": "int",
"Knowledge": "int",
"Knowledge-Planes": "int",
"Knowledge-Religion": "int",
"Linguistics": "int",
"Perception": "wis",
"Perform": "cha",
"Profession": "wis",
"Ride": "dex",
"Sense-Motive": "wis",
"Sleight-of-Hand": "dex",
"Spellcraft": "int",
"Stealth": "dex",
"Survival": "wis",
"Swim": "str",
"Use-Magic-Device": "cha"
},
consolidatedSkillAbilityDefaults = {
"CS-Acrobatics": "dex",
"CS-Athletics": "str",
"CS-Finesse": "dex",
"CS-Influence": "cha",
"CS-Nature": "int",
"CS-Perception": "wis",
"CS-Performance": "cha",
"CS-Religion": "int",
"CS-Society": "int",
"CS-Spellcraft": "int",
"CS-Stealth": "dex",
"CS-Survival": "wis"
},
globalSkillModAttrs = ['enforce_requires_training', 'size_skill', 'size_skill_double', 'acp', 'Phys-skills-cond',
'Perception-cond', 'STR-mod','DEX-mod','CON-mod','INT-mod','WIS-mod','CHA-mod',
'buff_STR_skills-total','buff_DEX_skills-total','buff_CON_skills-total',
'buff_INT_skills-total','buff_WIS_skills-total','buff_CHA_skills-total',
'checks-cond','buff_Check-total','buff_check_skills-total'],
skillNameAppends = ['', '-cs', '-ranks', '-ability', '-racial', '-trait', '-feat', '-item', '-misc-mod', '-ReqTrain', '-ut'],
//ability based skill buffs events located in PFBuffs
events = {
skillGlobalPhysEventAuto: "change:phys-skills-cond change:acp",
skillEventsAuto: "change:REPLACE-misc-mod",
skillEventsPlayer: "change:REPLACE-ability change:REPLACE-ranks change:REPLACE-racial change:REPLACE-trait change:REPLACE-feat change:REPLACE-item change:REPLACE-ReqTrain"
};
/**appendToSubSkills - util to append the string to all 10 names of one type of skill (perform, craft, knowledge, etc)
* adds the numbers from 0-9 or 1-10 or knowledge, then appends the string , to generate all 10 versions.
* @param {string} skilllist The name of the skill in, member of skillsWithSubSkills
* @param {string} appendToEnd The string to append.
* @returns {Array[string]} array of skill names
*/
function appendToSubSkills (skilllist, appendToEnd) {
return _.reduce(skilllist, function (memo, skill) {
var appendnums = (skill === "Misc-Skill") ? miscSkillAppendNums : (skill === "CS-Misc-Skill") ? miscSkillAppendNums : (skill === "Knowledge") ? knowledgeSkillAppends : skillAppendNums,
appendArray = SWUtils.cartesianAppend([skill], appendnums, appendToEnd);
return memo.concat(appendArray);
}, []);
}
/* updateMaxSkills Calculates and sets maximum skill ranks. Minimum 1 per level.
* divides by 2 if using consolidated skills
* @param {event} eventInfo - from event
* @callback {function} - callback when done
*/
function updateMaxSkills (eventInfo, callback) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
}),
fields=["total-skill", "total-fcskill", "INT-mod", "level", "Max-Skill-Ranks-mod", "Max-Skill-Ranks",
"unchained_skills-show", "BG-Skill-Use","npc-skill","npc-hd-num",
"class-0-skill","class-1-skill","class-2-skill","class-3-skill","class-4-skill","class-5-skill",
"class-0-level","class-1-level","class-2-level","class-3-level","class-4-level","class-5-level"
];
getAttrs(fields, function (v) {
var intMod = parseInt(v["INT-mod"], 10) || 0,
classSkills = parseInt(v["total-skill"], 10) || 0,
level = parseInt(v.level, 10) || 0,
fcSkills = parseInt(v["total-fcskill"], 10) || 0,
extra = parseInt(v["Max-Skill-Ranks-mod"], 10) || 0,
currSkills = parseInt(v["Max-Skill-Ranks"], 10) || 0,
totIntMod = 0,
minSkills=0,
i=0,
thislvl=0,
classPlusInt = 0,
thisSkill=0,
totAllSkills = 0,
isConsolidated=0,
setter = {};
try {
if(parseInt(v["unchained_skills-show"],10)===1){
if((parseInt(v["BG-Skill-Use"],10)||0) === 0){
isConsolidated =1;
}
}
for(i=0;i<6;i++){
thislvl=parseInt(v['class-'+i+'-level'],10)||0;
if (thislvl>0){
thisSkill=( (parseInt(v['class-'+i+'-skill'],10)||0) * thislvl ) + (intMod * thislvl);
if (thisSkill < thislvl){
thisSkill=thislvl;
}
classPlusInt += thisSkill;
}
}
thislvl = parseInt(v['npc-hd-num'],10)||0;
thisSkill = parseInt(v['npc-skill'],10)||0;
if (thislvl && thisSkill){
thisSkill = thislvl * thisSkill + intMod * thislvl;
if (thisSkill < thislvl){
thisSkill=thislvl;
}
classPlusInt += thisSkill;
}
if (isConsolidated){
classPlusInt = Math.floor(classPlusInt / 2);
}
totAllSkills = classPlusInt + extra;
if (totAllSkills < level){
totAllSkills = level;
}
totAllSkills += fcSkills;
if (currSkills !== totAllSkills) {
setter["Max-Skill-Ranks"] = totAllSkills;
}
} catch (err) {
TAS.error("PFSkills.updateMaxSkills", err);
} finally {
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, {
silent: true
}, done);
} else {
done();
}
}
});
}
/** verifyHasSkill - Checks to see if skill is in list of valid skills for this character (consolidated, background, core).
* @param {string} skill = the skill name
* @param {function} callback = a function that takes a a boolean as a first parameter.
* called with true if skill is part of valid list, or false if not.
*/
export function verifyHasSkill (skill, callback) {
var first3 = '',
first4 = '',
core = false,
bg = false,
cs = false,
isSub = false,
fields = ["BG-Skill-Use", "unchained_skills-show"];
try {
if (skill && typeof callback === "function") {
first4 = skill.slice(0, 4).toLowerCase();
first3 = first4.slice(0, 3);
if (first3 === 'cs-') {
cs = true;
} else if (first4 === 'arti' || first4 === 'lore') {
bg = true;
} else {
core = true;
}
if (_.contains(allFillInSkillInstances, skill)) {
isSub = true;
fields = fields.concat([skill + "-name", skill + "-ranks"]);
}
getAttrs(fields, function (v) {
var retval = false,
usesBG=parseInt(v["BG-Skill-Use"],10)||0,
usesUnchained=parseInt(v["unchained_skills-show"],10)||0;
if (!isSub || v[skill + "-name"] || (parseInt(v[skill+"-ranks"],10)||0)>0) {
if (core) {
if (!usesUnchained || usesBG) {
retval = true;
}
} else if (bg) {
if (usesUnchained && usesBG) {
retval = true;
}
} else {
if (usesUnchained && !usesBG) {
retval = true;
}
}
}
callback(retval);
});
}
} catch (err) {
TAS.error("PFSkills.verifyHasSkill", err);
callback(false);
}
}
/** synchronously calculates new value for skill and returns values for setAttrs
* @param {string} skill name of skill to update
* @param {Map<string,string>} v attributes and values from sheet
* @param {Map<string,Number>} setter optional, map to send to setAttrs so far
* @returns {Map<string,Number>} setter with additional values, or new map, for setAttrs
*/
function setSkillVal (skill, v, setter){
var skillSize = 0,
watchrt = parseInt(v["enforce_requires_training"], 10) || 0,
csNm = skill + "-cs",
ranksNm = skill + "-ranks",
abNm = skill + "-ability",
racialNm = skill + "-racial",
traitNm = skill + "-trait",
featNm = skill + "-feat",
itemNm = skill + "-item",
miscNm = skill + "-misc-mod",
utNm = skill + "-ut",
rtNm = skill + "-ReqTrain",
adj,
skillTot = 0,
setAny = 0,
cond = 0,
cs = parseInt(v[csNm], 10) || 0,
currSkill = parseInt(v[skill], 10), //no default
ranks = parseInt(v[ranksNm], 10) || 0,
rt = parseInt(v[rtNm], 10) || 0,
allCond = 0,
buffs= 0,
abilityModName = '',
abilityName='',
physCond = 0,
perCond = 0,
globalBuffCond=0;
try {
setter = setter || {};
abilityModName = v[abNm]; //PFUtils.findAbilityInString(v[abNm]);
if (rt && ranks === 0) {
if (v[utNm] !== "{{untrained=1}}") {
setter[utNm] = "{{untrained=1}}";
}
} else if (v[utNm] !== "{{untrained=}}") {
setter[utNm] = "{{untrained=}}"; //cannot set to "" because then it chooses the default which is "{{untrained=1}}"
}
if (ranks && cs) {
skillTot += 3;
}
if (abilityModName === "DEX-mod" || abilityModName === "STR-mod") {
adj = parseInt(v["acp"], 10) || 0;
skillTot += adj;
physCond = parseInt(v["Phys-skills-cond"], 10) || 0;
}
if (abilityModName){
abilityName = abilityModName.slice(0,3).toUpperCase();
buffs += parseInt(v['buff_'+abilityName+'_skills-total'],10)||0;
}
if(skill==='Stealth'||skill==='CS-Stealth'){
skillSize=2;
}else if (skill==='Fly'){
skillSize=1;
} else {
skillSize=0;
}
//skillSize = sizeSkills[skill];
if (skillSize) {
if (skillSize === 1) {
adj = parseInt(v["size_skill"], 10) || 0;
skillTot += adj;
} else if (skillSize === 2) {
adj = parseInt(v["size_skill_double"], 10) || 0;
//if(skill==='Stealth'){TAS.notice("adjusting stealth by "+adj);}
skillTot += adj;
}
}
if (skill === "Perception" || skill === "CS-Perception") {
perCond = parseInt(v["Perception-cond"], 10) || 0;
}
globalBuffCond=(parseInt(v['checks-cond'],10)||0)+(parseInt(v['buff_Check-total'],10)||0)+
(parseInt(v['buff_check_skills-total'],10)||0);
cond = allCond + physCond + perCond+globalBuffCond;
skillTot += ranks + cond + buffs+ (parseInt(v[abilityModName], 10) || 0) + (parseInt(v[racialNm], 10) || 0) + (parseInt(v[traitNm], 10) || 0) + (parseInt(v[featNm], 10) || 0) + (parseInt(v[itemNm], 10) || 0) + (parseInt(v[miscNm], 10) || 0);
if (currSkill !== skillTot) {
setter[skill] = skillTot;
}
} catch (erskill){
TAS.error("PFSkills.setNewSkillVal",erskill);
} finally {
return setter;
}
}
/** updates one skill row reading all values on row
* @param {string} skill to update, must have same capitalization as on HTML
* @param {function} callback = callback after done with params newvalue, oldvalue.
* @param {boolean} silently = whether to update silently or not. ignored, always silent.
*/
export function updateSkillAsync (skill, callback, silently) {
var done = function (newVal, oldVal) {
if (typeof callback === "function") {
callback(newVal, oldVal);
}
},
fields = skillNameAppends.map(function(append){return skill+append;});
fields = fields.concat(globalSkillModAttrs);
getAttrs(fields,function (v) {
var setter = {},
params = {},
currSkill=0;
try {
currSkill = parseInt(v[skill], 10);
setter = setSkillVal(skill,v,setter);
} catch (err) {
TAS.error(err);
} finally {
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silentParams, function () {
done(setter[skill] , currSkill);
});
} else {
done(currSkill, currSkill);
}
}
});
}
/** Sets new skill value by applying diff
* @param {string} skill skill to update
* @param {Number} diff difference to apply
* @param {Map<string,string>} v current values from getAttrs
* @param {Map<string,Number>} setter current map for setAttrs if provided this is used
* @returns {Map<string,Number>} setter or map of skill to new number for setAttrs
*/
function setSkillValByDiff(skill,diff,v,setter){
var tot=0;
setter= setter||{};
tot=parseInt(v[skill],10)||0;
tot+=diff;
setter[skill]=tot;
return setter;
}
/** when user checks class skill, +3 or -3 depending on if ranks > 0, if ranks 0 no change
* @param {string} skill - from allTheSkills
*/
function updateSkillByClassChkAsync(skill){
getAttrs([skill,skill+'-ranks',skill+'-cs'],function(v){
var tot=0,cs=0,ranks=0,newtot=0,setter={};
tot=parseInt(v[skill],10)||0;
cs=parseInt(v[skill+'-cs'],10)||0;
ranks=parseInt(v[skill+'-ranks'],10)||0;
if(ranks){
if(cs){
newtot=tot+3;
} else {
newtot = tot-3;
}
setter[skill]=newtot;
SWUtils.setWrapper(setter);
}
});
}
function recalculateSkillArrayMiscFields (skills, callback){
var doneOneMisc = _.after(_.size(skills),callback);
_.each(skills, function (skill) {
SWUtils.evaluateAndSetNumber(skill + "-misc", skill + "-misc-mod", 0, function () {
doneOneMisc();
}, true);
});
}
/** Recalcs the array of skills but does NOT recalc the misc macro fields
*
* @param {*} skills
* @param {*} callback
* @param {*} silently
*/
function recalcSkillTotals (skills,callback,silently){
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
}),
fields, subfields;
fields = globalSkillModAttrs;
_.each(skills, function (skill) {
var subfields=skillNameAppends.map(function(append){return skill+append;});
fields = fields.concat(subfields);
});
getAttrs(fields,function(v){
var setter={};
setter=_.reduce(skills,function(m,skill){
try {setSkillVal(skill,v,m);} catch (e){} finally {
return m;
}
},{});
if(_.size(setter)){
SWUtils.setWrapper(setter,PFConst.silentParams,done);
} else {
done();
}
});
}
/** recalcSkillArray recalculates skill misc macro fields then totals.
* @param {Array} skills array of skills to update.
* @param {function} callback when done
* @param {boolean} silently whether to call SWUtils.setWrapper of skill total with silent or not.
*/
function recalcSkillArray (skills, callback, silently) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
}),
skillCount = _.size(skills),
skillsHandled = 0,
doneMisc = function () {
recalcSkillTotals(skills,done,silently);
};
recalculateSkillArrayMiscFields(skills,doneMisc)
}
export function recalculateSkills (callback, silently, onlySkills) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
});
getAttrs(["unchained_skills-show", "BG-Skill-Use"], function (v) {
try {
if (parseInt(v["unchained_skills-show"],10)) {
if (parseInt(v["BG-Skill-Use"],10)) {
if(onlySkills){
recalcSkillTotals(backgroundOnlySkills, null, silently);
recalcSkillTotals(allCoreSkills, done, silently);
}else {
//TAS.debug("PFSkills.recalculate: has background skills");
recalcSkillArray(backgroundOnlySkills, null, silently);
//return after long one
recalcSkillArray(allCoreSkills, done, silently);
}
} else {
if (onlySkills){
recalcSkillTotals(consolidatedSkills, done, silently);
recalcSkillTotals(consolidatedMiscSkills, null, silently);
}else {
//TAS.debug("PFSkills.recalculate: has consolidatedSkills skills");
recalcSkillArray(consolidatedSkills, done, silently);
recalcSkillArray(consolidatedMiscSkills, null, silently);
}
}
} else {
if (onlySkills){
recalcSkillTotals(allCoreSkills, done, silently);
}else {
//TAS.debug("PFSkills.recalculate:has core skills skills");
recalcSkillArray(allCoreSkills, done, silently);
}
}
} catch (err) {
TAS.error("PFSKills.recalculate", err);
done();
}
});
}
export function updateAllSkillsDiff (newmod,oldmod){
TAS.notice("PFSkills updateallskills diff updating by " +newmod+", from "+ oldmod);
getAttrs(allTheSkills,function(v){
var diff = newmod - oldmod,setter={};
setter= _.mapObject(v,function(val,key){
return (parseInt(val,10)||0)+diff;
});
TAS.debug("SPSkills.updateAllSkillsDiff setting",setter);
SWUtils.setWrapper(setter,PFConst.silentParams);
});
}
export function recalculateAbilityBasedSkills (abilityBuff,eventInfo,callback,silently){
var done=function(){
if (typeof callback === "function"){ callback();}
},
updatedAttr ,tempstr='',matches,fields;
if(abilityBuff) {
tempstr = abilityBuff;
} else if(eventInfo){
tempstr = eventInfo.sourceAttribute;
if(tempstr.indexOf('repeating_')>=0){
tempstr = SWUtils.getAttributeName(tempstr);
}
}
if(tempstr){
if (tempstr==='physical'||tempstr==='acp'){
updatedAttr = /STR\-mod|DEX\-mod/;
} else {
matches=tempstr.match(/str|dex|con|int|wis|cha/i);
if(matches){
//TAS.debug("recalculateAbilityBasedSkills the match is: "+matches[0],matches);
updatedAttr= new RegExp(matches[0].toUpperCase()+'\-mod');
}
}
//TAS.debug("recalculateAbilityBasedSkills updatedAttr is now "+updatedAttr);
}
if(!updatedAttr){
done();
return;
}
fields = allTheSkills.map(function(skill){
return skill+'-ability';
});
//TAS.debug("recalculateAbilityBasedSkills getting all skill abilities");
getAttrs(fields,function(v){
var skillArray=[];
//TAS.debug("recalculateAbilityBasedSkills skill abilities are ",fields,v);
skillArray = _.reduce(v,function(m,val,field){
if(updatedAttr.test(val)){
//TAS.debug("recalculateAbilityBasedSkills field "+field+" matches and skill is "+ field.slice(0,-8));
m.push(field.slice(0,-8));
}
return m;
},[]);
TAS.notice("PFSkills updateAbilityBasedSkills getting array:",skillArray);
if(_.size(skillArray)){
recalcSkillTotals(skillArray,done,silently);
} else {
done();
}
});
}
/** updates the macros for only the 7 subskill rolltemplates
* @param {boolean} background -if background skills turned on
* @param {boolean} rt - if Enforce Requires Training checked
* @param {event} eventInfo ?
* @param {jsobject_map} currMacros map of parent skill button name to command macro. (knowledge, Perform, etc)
* @param {boolean} isNPC - if sheet is NPC
* @param {boolean} showBonus - if skill total should be displayed on button.
*/
function updateSubSkillMacroBook (background, rt, eventInfo, currMacros, isNPC, showBonus) {
var headerString = isNPC ? npcSkillHeaderMacro : skillHeaderMacro,
skillPrefix = isNPC ? "NPC-" : "",
assembleSubSkillButtonArray = function (skill, shouldEnforce, v) {
var appendnums = (skill === "Misc-Skill") ? miscSkillAppendNums : (skill === "CS-Misc-Skill") ? miscSkillAppendNums : (skill === "Knowledge") ? knowledgeSkillAppends : skillAppendNums,
subskills = SWUtils.cartesianAppend([skill], appendnums),
firstPass = [];
if (skill === "Knowledge") {
firstPass = subskills;
return firstPass; //knowledge rollable even if untrained
}
firstPass = _.filter(subskills, function (subskill) {
if (v[subskill + "-name"]) {
return true;
}
return false;
});
if (!shouldEnforce) {
return firstPass;
}
return _.filter(firstPass, function (skill) {
if ((parseInt(v[skill + "-ReqTrain"], 10) || 0) === 0 || (parseInt(v[skill + "-ranks"], 10) || 0) > 0) {
return true;
}
return false;
});
},
getKnowledgeButtonMacro = function (showBonus) {
var bonusStr = showBonus ? "+ @{REPLACE}" : "",
knowledgebutton = "[^{REPLACENAME}" + bonusStr + "](~@{character_id}|" + skillPrefix + "REPLACE-check) ";
return headerString.replace('REPLACELOWER', 'knowledge') + "{{ " + _.reduce(knowledgeSubSkillsTranslateKeys, function (memo, subskill, idx) {
memo += knowledgebutton.replace(/REPLACENAME/g, subskill).replace(/REPLACE/g, knowledgeSkills[idx]);
return memo;
}, "") + " }}";
},
getSubSkillButtonMacro = function (skill, skillArray, showBonus,v) {
var skillTransKey = skill.toLowerCase(),
bonusStr = showBonus ? "+ @{REPLACE}" : "",
baseMacro = headerString.replace('REPLACELOWER', skillTransKey),
singleRowButton = "[REPLACENAME" + bonusStr + "](~@{character_id}|" + skillPrefix + "REPLACE-check) ",
tempstr = "";
if (skill === "Knowledge") {
return getKnowledgeButtonMacro();
}
tempstr = _.reduce(skillArray, function (memo, subskill, idx) {
var buttonName = v[subskill+"-name"];
if (buttonName){
buttonName = SWUtils.escapeForChatLinkButton(buttonName);
buttonName = SWUtils.escapeForRollTemplate(buttonName);
} else {
buttonName = "@{"+subskill+"-name}";
}
memo += singleRowButton.replace(/REPLACENAME/g, buttonName).replace(/REPLACE/g, subskill);
return memo;
}, "");
if (!tempstr) {
tempstr = "description = ^{no-skills-available}";
}
return baseMacro + "{{ " + tempstr + " }}";
},
subskillParents = background ? skillsWithFillInNames : coreSkillsWithFillInNames,
allsubskillFields = appendToSubSkills(subskillParents, ["-name"]);
if (rt) {
allsubskillFields = allsubskillFields.concat(
appendToSubSkills(subskillParents, checkRTArray)
);
allsubskillFields = allsubskillFields.sort();
//allsubskillFields.concat(appendToSubSkills(subskillParents, checkRTArray)).sort();
}
//TAS.debug("updateSubSkillMacroBook: allsubskillFields are:", allsubskillFields);
getAttrs(allsubskillFields, function (v) {
var setter = {},
tempKMac = "";
//TAS.debug("updateSubSkillMacroBook: event and data are:", eventInfo, v);
_.each(subskillParents, function (skill) {
var canshowarray = assembleSubSkillButtonArray(skill, rt, v),
tempMacro = getSubSkillButtonMacro(skill, canshowarray, showBonus,v);
tempMacro = baseGenMacro + tempMacro;
if (currMacros[skillPrefix + skill.toLowerCase() + "_skills-macro"] !== tempMacro) {
setter[skillPrefix + skill.toLowerCase() + "_skills-macro"] = tempMacro;
}
});
if (currMacros[skillPrefix + "knowledge_skills-macro"]) {
tempKMac = baseGenMacro + getKnowledgeButtonMacro(showBonus);
if (currMacros[skillPrefix + "knowledge_skills-macro"] !== tempKMac) {
setter[skillPrefix + "knowledge_skills-macro"] = tempKMac;
}
}
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silentParams);
}
});
}
function assembleSkillButtonArray (skills, shouldEnforce, sv) {
if (!shouldEnforce) {
return skills;
}
return _.filter(skills, function (skill) {
if (/^Knowled|^Linguis|^Sleight/i.test(skill.slice(0, 7)) || (parseInt(sv[skill + "-ReqTrain"],10)||0) !== 1 || (parseInt(sv[skill + "-ranks"], 10) || 0) > 0) {
return true;
}
return false;
});
}
function getSkillButtonMacro (name, skillArray, showBonus, isNPC) {
var skillTransKey = name.toLowerCase(),
skillPrefix = isNPC ? "NPC-" : "",
bonusStr = showBonus ? " + @{REPLACE}" : "",
baseMacro = "{{name= ^{" + skillTransKey + "} }} ",
npcBaseMacro = "{{name= ^{npc} ^{" + skillTransKey + "} }} ",
rowbutton = "[^{REPLACELOWER}" + bonusStr + "](~@{character_id}|" + skillPrefix + "REPLACE-check) ",
subskillbutton = "[^{REPLACELOWER}](~@{character_id}|" + skillPrefix + "REPLACELOWERMAC_skills_buttons_macro) ",
baseToSend = isNPC?npcBaseMacro:baseMacro,
tempstr="";
try {
tempstr = _.reduce(skillArray, function (memo, skill, idx) {
var thistranskey = skill.toLowerCase(),
thisbutton = (_.contains(skillsWithSubSkills, skill)) ? subskillbutton : rowbutton;
thisbutton = thisbutton.replace(/REPLACELOWERMAC/g, thistranskey);
thisbutton = thisbutton.replace(/REPLACELOWER/g, thistranskey);
thisbutton = thisbutton.replace(/REPLACE/g, skill);
memo += thisbutton + " ";
return memo;
}, "");
if (!tempstr) {
tempstr = "^{no-skills-available} ";
}
} finally {
return baseToSend + "{{ " + tempstr + "}}";
}
}
function resetOneCommandMacro (callback, eventInfo, isNPC,showBonus,unchained,background,consolidated,rt){
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
}),
skillPrefix = isNPC ? "NPC-" : "";
getAttrs([skillPrefix+"skills-macro", skillPrefix+"background_skills-macro", skillPrefix+"adventure_skills-macro",
skillPrefix+"artistry_skills-macro", skillPrefix+"lore_skills-macro", skillPrefix+"craft_skills-macro", skillPrefix+"knowledge_skills-macro",
skillPrefix+"perform_skills-macro", skillPrefix+"profession_skills-macro", skillPrefix+"misc-skill_skills-macro",
skillPrefix+"CS-misc-skill_skills-macro"], function (v) {
var i = 0,
setter = {},
tempSkillArray = [],
tempMacro = "",
allskillstitle = "skills",
coreArray;
if (!consolidated) {
updateSubSkillMacroBook(background, rt, eventInfo, v, isNPC, showBonus);
getAttrs(SWUtils.cartesianAppend(regularCoreSkills, checkRTArray), function (v) {
var canshowarray = [],
tempRTMacro = "",
temparray = [];
try {
if (background) {
canshowarray = assembleSkillButtonArray(regularBackgroundSkills, rt, v) || [];
temparray = temparray.concat(canshowarray);
canshowarray = canshowarray.concat(skillsWithSubSkills).sort();
tempRTMacro = baseGenMacro + getSkillButtonMacro("background-skills", canshowarray, showBonus, isNPC);
if (v[skillPrefix + "background_skills-macro"] !== tempRTMacro) {
setter[skillPrefix + "background_skills-macro"] = tempRTMacro;
}
canshowarray = assembleSkillButtonArray(regularAdventureSkills, rt, v) || [];
temparray = temparray.concat(canshowarray);
canshowarray = canshowarray.concat(["Knowledge","Misc-Skill"]).sort();
tempRTMacro = baseGenMacro + getSkillButtonMacro("adventure-skills", canshowarray, showBonus, isNPC);
if (v[skillPrefix + "adventure_skills-macro"] !== tempRTMacro) {
setter[skillPrefix + "adventure_skills-macro"] = tempRTMacro;
}
temparray = temparray.concat(skillsWithSubSkills).sort();
} else {
canshowarray = assembleSkillButtonArray(regularCoreSkills, rt, v) || [];
temparray = temparray.concat(canshowarray).concat(coreSkillsWithSubSkills).sort();
}
tempRTMacro = baseGenMacro + getSkillButtonMacro("skills", temparray, showBonus, isNPC);
if (v[skillPrefix + "skills-macro"] !== tempRTMacro) {
setter[skillPrefix + "skills-macro"] = tempRTMacro;
}
} catch (errRT){
TAS.error("PFSkills.resetOneCommandMacro errRT",errRT);
} finally {
if (_.size(setter) > 0) {
SWUtils.setWrapper(setter, PFConst.silentParams, done);
} else {
done();
}
}
});
} else {
//consolidated
tempSkillArray = consolidatedSkills;//.concat(consolidatedMiscSkills);
getAttrs(SWUtils.cartesianAppend(tempSkillArray, ["-ReqTrain", "-ranks"]), function (sv) {
var canshowarray, setter = {}, tempMacro ;
canshowarray = assembleSkillButtonArray(tempSkillArray, rt, sv);
canshowarray.push("CS-Misc-Skill");
tempMacro = getSkillButtonMacro("consolidated-skills", canshowarray, showBonus, isNPC);
setter[skillPrefix + "consolidated_skills-macro"] = baseGenMacro + tempMacro;
SWUtils.setWrapper(setter,PFConst.silentParams, done);
});
}
});
}
export function resetCommandMacro (eventInfo, callback) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
});
getAttrs(["BG-Skill-Use", "unchained_skills-show", "enforce_requires_training", "is_npc", "include_skill_totals"],function(vout){
var isNPC = parseInt(vout["is_npc"], 10) || 0,
skillPrefix = isNPC ? "NPC-" : "",
showBonus = parseInt(vout.include_skill_totals, 10) || 0,
unchained = parseInt(vout["unchained_skills-show"], 10) || 0,
background = unchained && (parseInt(vout["BG-Skill-Use"], 10) || 0),
consolidated = unchained && (!background),
rt = parseInt(vout["enforce_requires_training"], 10) || 0;
resetOneCommandMacro(done,eventInfo,isNPC,showBonus,unchained,background,consolidated,rt);
if (isNPC){
resetOneCommandMacro(done,eventInfo,false,showBonus,unchained,background,consolidated,rt);
}
});
}
/** migrate skills
* @param {function} callback callback when done
* @param {number} oldversion old version , -1 if hit recalc
*/
export function migrate (callback, oldversion) {
var done = _.once(function () {
// TAS.debug("leaving PFSkills.migrate");
if (typeof callback === "function") {
callback();
}
}),
doneOne = _.after(4,done),
/** migrateOldClassSkillValue - converts class skill checkboxes from old autocalc string to number "" or 3.
* @param {function} callback when done
* @param {number} oldversion currversionnumber
*/
migrateOldClassSkillValue = function (callback, oldversion) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
}),
migrateClassSkill = function (skill) {
var csNm = skill + "-cs";
getAttrs([csNm], function (v) {
var setter = {};
if (isNaN(parseInt(v[csNm], 10))) {
if (! (!v[csNm] || v[csNm] == "0") ) {
//TAS.debug({"function":"migrateClassSkill","raw":v[csNm],"cs":cs});
setter[csNm] = 3;
SWUtils.setWrapper(setter, PFConst.silentParams);
}
}
});
},
migrateClassSkillArray = function (skills) {
skills.forEach(function (skill) {
migrateClassSkill(skill);
});
},
determineArray = function () {
migrateClassSkillArray(allTheSkills);
//not bothering to code correctly to wait since this is almost a year old.
SWUtils.setWrapper({classSkillsMigrated: 1}, PFConst.silentParams,done);
};
getAttrs(["classSkillsMigrated"], function (vm) {
if (!(parseInt(vm.classSkillsMigrated, 10) || 0)) {
determineArray();
}
done();
});
},
/** setAdvancedMacroCheckbox - part of migrate .66 to 1.00 sets checkbox to unhide advanced
* skillmacro (investigator) if character sheet already using it.)
* @param {function} callback whendone
*/
setAdvancedMacroCheckbox = function (callback) {
var done = _.once(function () {
if (typeof callback === "function") {
callback();
}
});
getAttrs(["adv_macro_show", "skill-invest-query"], function (v) {
var showAdv = parseInt(v.adv_macro_show, 10) || 0;
if (v["skill-invest-query"] && !showAdv) {
SWUtils.setWrapper({adv_macro_show: 1}, PFConst.silentParams, done);
}
});
},
migrateMacros2 = function(callback){
getAttrs(['migrated_skill_speedup3'],function(vout){
var fields;
if(vout.migrated_skill_speedup3*1){
if (typeof callback === "function") {
callback();
}
//return;
}
fields = allTheSkills.map(function(skill){return skill+'-macro';});
getAttrs(fields,function(v){
var setter={};
try{
setter=_.reduce(v,function(m,macro,attr){
try {
m[attr]=macro.replace(/ \+ \[\[ @{checks\-cond} \+ @{buff_check_skills-total} \+ @{buff_Check-total} \]\] /,"");
// TAS.debug("removed cond and buffs macro from skill macro-text");
}catch (ierr){
TAS.error("PFBuffs.migrate add buff checks for "+attr,ierr);
} finally {
return m;
}
},{});
} catch (err){
TAS.error("PFSkills.migrate skill speedup",err);
} finally {
setter.migrated_skill_speedup3=1;
setAttrs(setter,PFConst.silentParams,callback);
}
});
});
},
migrateTake10Dropdown = function(callback,oldversion){
var done = function(){
if (typeof callback === "function"){
callback();
}
};
getAttrs(['migrated_take10_dropdown','skill-query','investigator_dice','skill-invest-query'],function(v){
var setter={};
//TAS.notice("########################","PFSkills.migrate",v,"################3");
//TAS.debug("V 13 just to make sure the damn thing is working");
if((parseInt(v.migrated_take10_dropdown,10)||0)===0){
if(v['skill-query']==='?{Roll or Take 10/20?|1d20,1d20+@{skill-invest-query&#125;|10,10+@{skill-invest-query&#125;|20,20+@{skill-invest-query&#125;}'){
setter['skill-query']='?{Roll or Take 10/20?|1d20,1d20|10,10|20,20}+@{skill-invest-query}';
} else if (v['skill-query']==='@{skill-invest-query}'){
setter['skill-query']='@{skill-invest-query}+@{custom_dice}';
} else if (!v['skill-query'] || v['skill-query']==="0"){
setter['skill-query']='1d20+@{skill-invest-query}';
} else if (v['skill-query']!=='@{skill-invest-query}+@{custom_dice}' &&
v['skill-query']!=='?{Roll or Take 10/20?|1d20,1d20|10,10|20,20}+@{skill-invest-query}' &&
v['skill-query']!=='1d20+@{skill-invest-query}'){
setter['skill-query']='1d20+@{skill-invest-query}';
}
if (v.investigator_dice==="0" || !v.investigator_dice){
setter.investigator_dice="[[ 1d6 ]] [custom bonus]";
}
if (!v['skill-invest-query']){
setter['skill-invest-query']="0";
} else if ( v['skill-invest-query'] !== '@{investigator_dice}' && v['skill-invest-query'] !== "0" ){
setter['skill-invest-query']="0";
}
setter.migrated_take10_dropdown=1;
//TAS.debug("#####################","PFBuffs.migrate setting",setter);
SWUtils.setWrapper(setter,PFConst.silentParams,done);
} else {
done();
}
});
};
//TAS.debug("at PFSkills.migrate");
migrateTake10Dropdown(doneOne);
migrateOldClassSkillValue(doneOne);
migrateMacros2(doneOne);
PFMigrate.migrateMaxSkills(doneOne);
}
/* recalculate - updates ALL skills - calls PFUtilsAsync.setDropdownValue for ability then updateSkill */
export var recalculate = TAS.callback(function PFSkillsRecalculate(callback, silently, oldversion) {
var done = _.once(function () {
TAS.info("leaving PFSkills.recalculate");
resetCommandMacro();
if (typeof callback === "function") {
callback();
}
});
//TAS.debug("PFSkills.recalculate");
migrate(function () {
//TAS.debug"PFSkills.recalculate back from PFSkills.migrate");
updateMaxSkills();
recalculateSkills(done, silently);
}, oldversion);
});
function registerEventHandlers () {
on("change:str-mod change:dex-mod change:con-mod change:int-mod change:wis-mod change:cha-mod",TAS.callback(function eventAbilityScoreToSkill(eventInfo){
TAS.notice("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
recalculateAbilityBasedSkills(null,eventInfo);
}
}));
//SKILLS************************************************************************
on("change:total-skill change:total-fcskill change:int-mod change:level change:max-skill-ranks-mod change:unchained_skills-show change:BG-Skill-Use", TAS.callback(function eventUpdateMaxSkills(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
updateMaxSkills(eventInfo);
}
}));
on(events.skillGlobalPhysEventAuto, TAS.callback(function eventGlobalConditionAffectingSkill(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event for " + eventInfo.sourceType);
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
recalculateAbilityBasedSkills('physical',eventInfo);
}
}));
//each skill has a dropdown handler and a skill update handler
//concat them all up, only happens once so no big deal
_.each(allTheSkills, function (skill) {
on((events.skillEventsAuto.replace(/REPLACE/g, skill)), TAS.callback(function eventSkillsAuto(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event for " + skill + ", " + eventInfo.sourceType);
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
verifyHasSkill(skill, function (hasSkill) {
if (hasSkill) {
updateSkillAsync(skill, eventInfo);
}
});
}
}));
on((events.skillEventsPlayer.replace(/REPLACE/g, skill)), TAS.callback(function eventSkillsPlayer(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event for " + skill + ", " + eventInfo.sourceType);
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
updateSkillAsync(skill);
}
}));
on("change:" + skill + "-misc", TAS.callback(function eventSkillMiscFieldUpdate(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
//tests that -misc field can evaluate to a number.
SWUtils.evaluateAndSetNumber(skill + '-misc', skill + '-misc-mod', 0);
}
TAS.debug("calling evalute for "+skill);
SWUtils.evaluateAndAddToTotAsync(null, null, skill + '-misc', skill + '-misc-mod', skill);
}));
on("change:" + skill + "-cs", TAS.callback(function eventClassSkillCheckbox(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
updateSkillByClassChkAsync(skill);
}
}));
//these always displayed if rt or not
if (skill.slice(0, 9) !== "Knowledge" && skill !== "Linguistics" && skill !== "Sleight-of-Hand") {
on("change:" + skill + "-ReqTrain change:" + skill + "-ranks", TAS.callback(function eventSkillRequiresTrainingRanks(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event for " + skill + ", " + eventInfo.sourceType);
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
getAttrs(["enforce_requires_training"], function (v) {
if (parseInt(v.enforce_requires_training,10)) {
resetCommandMacro(eventInfo);
}
});
}
}));
}
//end of skill loop
});
//skills affected by size
_.each(sizeSkills, function (mult, skill) {
if (mult === 1) {
on("change:size_skill", TAS.callback(function eventUpdateSizeSkill(eventInfo) {
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
updateSkillAsync(skill);
}
}));
} else if (mult === 2) {
on("change:size_skill_double", TAS.callback(function eventUpdateSizeSkillDouble(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "sheetworker" || eventInfo.sourceType === "api") {
updateSkillAsync(skill);
}
}));
}
});
on("change:enforce_requires_training", TAS.callback(function eventRequiresTraining(eventInfo) {
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
resetCommandMacro(eventInfo);
}
}));
_.each(SWUtils.cartesianAppend(allFillInSkillInstances, ["-name"]), function (skill) {
on("change:" + skill, TAS.callback(function eventSkillsWithFillInNames(eventInfo) {
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
var rt = skill.slice(0, -4) + "ReqTrain",
r = skill.slice(0, -4) + "ranks";
//if we changed name on a skill that isn't choose-able don't bother.
getAttrs(["enforce_requires_training", rt, r, "unchained_skills-show", "BG-Skill-Use", "artistry_skills-macro", "lore_skills-macro", "craft_skills-macro", "knowledge_skills-macro", "perform_skills-macro", "profession_skills-macro", "misc-skill_skills-macro", "is_npc", "include_skill_totals", "NPC-craft_skills-macro", "NPC-knowledge_skills-macro", "NPC-perform_skills-macro", "NPC-profession_skills-macro", "NPC-misc-skill_skills-macro"], function (v) {
var isrt = parseInt(v.enforce_requires_training, 10),
bg = 0,
isNPC = parseInt(v.is_npc, 10) || 0,
showBonus = parseInt(v.include_skill_totals, 10) || 0;
if (!(isrt && parseInt(v[rt], 10) && isNaN(parseInt(v[r], 10)))) {
bg = isNPC ? 0 : ((parseInt(v["unchained_skills-show"], 10) || 0) && (parseInt(v["BG-Skill-Use"], 10) || 0));
//TAS.debug"calling updatesubskillmacro: bg:" + bg + ",isrt:" + isrt);
updateSubSkillMacroBook(bg, isrt, eventInfo, v, isNPC, showBonus);
}
});
}
}));
});
//reset based on config changes
on("change:unchained_skills-show change:BG-Skill-Use change:include_skill_totals", TAS.callback(function eventResetUnchainedSkills(eventInfo) {
TAS.debug("caught " + eventInfo.sourceAttribute + " event: " + eventInfo.sourceType);
if (eventInfo.sourceType === "player" || eventInfo.sourceType === "api") {
recalculate(eventInfo, function(){resetCommandMacro(eventInfo);});
}
}));
}
registerEventHandlers();