Files

193 lines
8.3 KiB
JavaScript

/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
//Roll Functions
//Begins the parsing of a roll
const skillRollDetails = function({section,rowID,sections,attributes,rollObj,actionPenalty}){
rollObj.header = attributes[`${section}_${rowID}_name`];
rollObj.header = attributes[`${section}_${rowID}_raw`] ? `^{${rollObj.header}}` : rollObj.header;
let skill = attributes[`${section}_${rowID}_level`];
let stat = attributes[`${section}_${rowID}_stat`];
let penalty = determinePenalty('health',attributes,sections);
if(stat === 'query'){
stat = `?{${getTranslationByKey('stat query')}|${['body','mind','spirit'].map((s)=>`${getTranslationByKey(s)},@{${s}}[${s}]`).join('|')}}`;
}else{
stat = `[[0@{${stat}}]][${stat}]`;
}
rollObj.roll = `[[1d6 + ${stat} + [[0${skill}]][${rollObj.header}] + ${penalty}[Damage Penalty]${actionPenalty}]]`;
};
//determines which health track's penalties should affect an attribute
const determineHealthType = function(section,field){
const attrCharacterLookup = {
'situational-awareness':'structure',
'remnant-initiative':'structure',
'assault-roll':'structure',
'strike-roll':'structure',
'motion-roll':'structure',
repeating_drone:'structure',
'repeating_remnant-weapon':'structure'
};
return attrCharacterLookup[section] || attrCharacterLookup[field] || 'health';
};
const weaponRollDetails = function({section,rowID,field,sections,attributes,rollObj,actionPenalty}){
rollObj.header = attributes[`${section}_${rowID}_name`];
let skill;
let stat;
let healthType = determineHealthType(section,field);
let penalty = determinePenalty(healthType,attributes,sections);
debug({healthType,penalty});
if(section === 'repeating_weapon'){
let skillID = sections.repeating_skill.find((id)=>attributes[`repeating_skill_${id}_name`] === attributes[`${section}_${rowID}_skill`]);
let skillRef = `repeating_skill_${skillID}`;
skill = attributes[`${skillRef}_level`];
stat = attributes[`${skillRef}_stat`];
if(stat === 'query'){
stat = `?{${getTranslationByKey('stat query')}|${['body','mind','spirit'].map((s)=>`${getTranslationByKey(s)},@{${s}}[${s}]`).join('|')}}`;
}else{
stat = `@{${stat}}[${stat}]`;
}
rollObj.roll = `[[1d6 + ${stat} + ${skill}[${attributes[`${skillRef}_name`]}] + ${penalty}[Damage Penalty]${actionPenalty}]]`;
rollObj.damage = `[[${attributes[`${section}_${rowID}_damage`]} + Lead]]`;
}else if(section === 'repeating_remnant-weapon'){
let skillName = attributes[`${section}_${rowID}_skill`];
skill = attributes[`${skillName}_level`];
stat = attributes.situational_awareness;
rollObj.roll = `[[1d6 + [[0${stat}]][SA] + [[0${skill}]][${skillName}] + [[0${attributes[`${section}_${rowID}_bonus`]}]] + ${penalty}[Damage Penalty]${actionPenalty} ]]`;
rollObj.damage = `[[${attributes[`${section}_${rowID}_damage`]+ attributes[`${section}_${rowID}_damage_bonus`]} + Lead]]`;
}
debug({roll:rollObj.roll});
rollObj.description = `@{${section}_${rowID}_notes}`;
};
const droneRollDetails = async function({section,rowID,field,attributes,rollObj,actionPenalty}){
rollObj.header = attributes[`${section}_${rowID}_name`];
let numQuery = _.range(attributes[`${section}_${rowID}_active`]).map((num)=>{
return num +1;
});
let attackNum;
debug({numQuery});
if(numQuery.length <= 1){
attackNum = await pseudoQuery(1);
}else{
attackNum = await extractQueryResult(`${getTranslationByKey('drone query')}|${numQuery.join('|')}`);
}
debug({attackNum});
attackNum = +attackNum;
let bonus = Math.floor(attackNum / 2);
_.range(attackNum).forEach((n)=>{
let num = n+1;
rollObj[`roll${num}`] = `[[1d6 + [[0@{${section}_${rowID}_${field}}]][${field}] + ${bonus}[multiple attack]${actionPenalty}]]`;
rollObj[`status${num}`] = `[[0[computed value]]]`;
});
rollObj.damage = `[[${attributes[`${section}_${rowID}_${field}_dam`]} + Lead]]`;
rollObj.description = `@{${section}_${rowID}_description}`;
if(field === 'strike'){
rollObj.description = `^{strike range}: @{${section}_${rowID}_strikerange}\n@{${section}_${rowID}_description}`;
}
};
const initiateRoll = function(event){
let [section,rowID,field] = parseTriggerName(event.triggerName);
field = field.replace(/-action/,'');
const rollSwitch = {
repeating_weapon:weaponRollDetails,
repeating_skill:skillRollDetails,
'repeating_remnant-weapon':weaponRollDetails,
repeating_drone:droneRollDetails
};
getAllAttrs({props:['difficulty','action_penalty_automation',...baseGet],callback:async (attributes,sections)=>{
let rollObj = {status:'[[0[computed value]]]'};
let actionPenalty = determineActionPenalty(attributes);
if(/^(?:assault|strike|motion)-roll$/.test(field)){
let penalty = determinePenalty('structure',attributes,sections);
field = field.replace(/-roll/,'');
rollObj.header = `^{${field}}`;
rollObj.roll = `[[1d6 + [[0@{${field}_level}]][${field}] + [[0@{situational_awareness}]][SA] + ${penalty}[Damage Penalty]${actionPenalty}]]`;
rollObj.damage = /assault|strike/.test(field) ? `[[[[0@{${field}_damage}]] + Lead]]` : undefined;
}else if(!section){
//Base rolling for simple stats
let healthType = determineHealthType(section,field);
let penalty = determinePenalty(healthType,attributes,sections);
rollObj.header = `^{${field.replace(/-/g,' ')}}`;//output translation of name
rollObj.roll = `[[1d6 + [[0@{${field.replace(/-/g,'_')}}]][${field.replace(/-/g,' ')}] + ${penalty}[Damage Penalty]${actionPenalty}${/initiative/.test(field) ? '&{tracker}' : ''}]]`;
}else{
//rolling for more complex fields. These are typically repeating sections
if(section === 'repeating_drone'){
await rollSwitch[section]({section,rowID,field,sections,attributes,rollObj,actionPenalty});
}else{
rollSwitch[section]({section,rowID,field,sections,attributes,rollObj,actionPenalty});
}
}
if(attributes.difficulty && !/initiative/.test(field)){
rollObj.difficulty = `[[?{${getTranslationByKey('difficulty query')}|0}]]`;
rollObj.damage_label = rollObj.damage ? undefined : '[[0[computed value]]]';
rollObj.damage = rollObj.damage || `[[0[computed value]]]`;
}
if(!rollObj.damage && !rollObj.difficulty){
rollObj.singleroll = 'true';
}
executeRoll(rollObj);
}});
};
funcs.initiateRoll = initiateRoll;
const determineActionPenalty = function(attributes){
const stateSwitch = {
disabled:'',
ask:`+ [[abs(0?{${getTranslationByKey('action penalty query')}|0}) * -1]][Action Penalty]`,
'use input':`+ ${attributes.action_penalty}[Action Penalty]`
};
return stateSwitch[attributes.action_penalty_automation];
};
const executeRoll = async function(rollObj){
let rollText = Object.entries(rollObj).reduce((text,[field,content])=>{
if(content){
text += `{{${field}=${content}}}`;
}
return text;
},'@{template_start}');
let roll = await startRoll(rollText);
const computeObj = {};
if(roll.results.roll1){
computeMultipleRolls(roll.results,computeObj,rollObj);
}else{
computeSingleRoll(roll.results,computeObj,rollObj);
}
finishRoll(roll.rollId,computeObj);
};
const computeMultipleRolls = function(results,computeObj,rollObj){
let rollNums = [6,5,4,3,2,1].find((num)=>results.hasOwnProperty(`roll${num}`));
computeObj[`damage`] = rollObj[`damage`] && rollObj.difficulty ? 0 : undefined;
_.range(rollNums).forEach((n)=>{
let num = n + 1;
if(rollObj[`damage`] && rollObj.difficulty){
let damage = results[`damage`].result + (results[`roll${num}`].result - results.difficulty.result);
if(damage < results[`damage`].result){
damage = 0;
}
computeObj.damage += damage;
}
if(rollObj.difficulty){
computeObj[`status`] = checkResult(results[`roll${num}`],results.difficulty);
}
});
};
const computeSingleRoll = function(results,computeObj,rollObj){
if(rollObj.damage && rollObj.difficulty){
computeObj.damage = results.damage.result + (results.roll.result - results.difficulty.result);
}
if(results.damage_label){
computeObj.damage_label = getTranslationByKey(computeObj.damage < 0 ? 'trail' : 'lead');
}
if(rollObj.difficulty){
computeObj[`status`] = checkResult(results[`roll`],results.difficulty);
}
};
const checkResult = function(roll,difficulty){
return roll.result - difficulty.result;
};