Merge pull request #9936 from Kurohyou/rapidfireinitialrelease
Rapidfire system v1.0 for Outrider Studios
|
After Width: | Height: | Size: 459 KiB |
|
After Width: | Height: | Size: 555 KiB |
|
After Width: | Height: | Size: 5.7 MiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 297 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 297 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 269 KiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 607 KiB |
|
After Width: | Height: | Size: 268 KiB |
@@ -0,0 +1,69 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//Calculation Functions
|
||||
|
||||
const calcInitiative = function(trigger,attributes,sections){
|
||||
debug('calculating initiative');
|
||||
let awarenessID = sections.repeating_skill.find((id)=>attributes[`repeating_skill_${id}_name`] === 'awareness');
|
||||
let awareness = attributes[`repeating_skill_${awarenessID}_level`];
|
||||
return awareness + attributes.mind + attributes.initiative_mod;
|
||||
};
|
||||
|
||||
const calcDefence = function(trigger,attributes,sections){
|
||||
debug('calculating defense');
|
||||
let dodgeID = sections.repeating_skill.find((id)=>attributes[`repeating_skill_${id}_name`] === 'dodge');
|
||||
let dodge = attributes[`repeating_skill_${dodgeID}_level`];
|
||||
let damagePenalty = determinePenalty('health',attributes,sections);
|
||||
let total = 3 + attributes.body + dodge + attributes.shield_bonus + damagePenalty + attributes.defence_mod;
|
||||
return Math.max(total,0);
|
||||
};
|
||||
|
||||
const totalHealth = function(trigger,attributes,sections){
|
||||
const type = trigger.name.replace(/_max/,'');
|
||||
debug(`calculating total ${type}`);
|
||||
return sections[`repeating_${type}`].reduce((total,id)=>{
|
||||
total -= attributes[`repeating_${type}_${id}_damaged`] + attributes[`repeating_${type}_${id}_fill`];
|
||||
return total;
|
||||
},attributes[`${type}_max`]);
|
||||
};
|
||||
|
||||
const calcResist = function(trigger,attributes,sections){
|
||||
debug('calculating resist');
|
||||
return Math.max(attributes.spirit + attributes.armour_bonus + attributes.resist_mod,0);
|
||||
};
|
||||
|
||||
const calcSA = function(trigger,attributes,sections){
|
||||
debug('calculating situational awareness');
|
||||
return ['body','mind','spirit'].reduce((m,attr)=>{
|
||||
return m + attributes[attr];
|
||||
},0);
|
||||
};
|
||||
|
||||
const calcRemnantInitiative = function(trigger,attributes,sections){
|
||||
debug('calculating remnant initiative');
|
||||
let awarenessID = sections.repeating_skill.find((id)=>attributes[`repeating_skill_${id}_name`] === 'awareness');
|
||||
let awareness = attributes[`repeating_skill_${awarenessID}_level`];
|
||||
let penalty = determinePenalty('structure',attributes,sections);
|
||||
return attributes.situational_awareness + awareness + penalty;
|
||||
};
|
||||
|
||||
const calcRemnantDefence = function(trigger,attributes,sections){
|
||||
debug('calculating remnant defence');
|
||||
let damagePenalty = determinePenalty('structure',attributes,sections);
|
||||
debug({damagePenalty});
|
||||
return Math.max(attributes.speed + attributes.situational_awareness + attributes.motion_level + damagePenalty,0);
|
||||
};
|
||||
|
||||
const calcStrikeRange = function(trigger,attributes,sections){
|
||||
debug('calculating strike range');
|
||||
const [section,rowID,field] = parseTriggerName(trigger.name);
|
||||
let strike = section ? `${section}_${rowID}_strike` : 'strike_level';
|
||||
return attributes[strike] * 100;
|
||||
};
|
||||
|
||||
const calcRemnantDamage = function(trigger,attributes,sections){
|
||||
debug('calculating remnant damage');
|
||||
let [section,rowID,field] = parseTriggerName(trigger.name);
|
||||
let skill = attributes[`${section}_${rowID}_skill`];
|
||||
return attributes[`${skill}_damage`] + attributes[`${section}_${rowID}_damage_bonus`];
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//Expands/collapses the sections
|
||||
const expandHeader = function(jEvent){
|
||||
debug('entering expandHeader');
|
||||
const name = jEvent.htmlAttributes.name.replace(/act_/,'');
|
||||
const target = `.${name}.expandable-header`;
|
||||
_getAttrs(['collapsed'],(attributes)=>{
|
||||
attributes.collapsed = attributes.collapsed.split(/\s*,\s*/).filter(b => b!==name && !/^\s*$/.test(b) );
|
||||
if(!/collapse/.test(jEvent.htmlAttributes.class)){
|
||||
attributes.collapsed.push(name);
|
||||
}
|
||||
attributes.collapsed = attributes.collapsed.join(',');
|
||||
$20(target).toggleClass('collapse');
|
||||
attributes.set();
|
||||
});
|
||||
};
|
||||
|
||||
const imageInput = function(trigger,attributes,sections){
|
||||
debug('entering imageInput');
|
||||
let [section,rowID,field] = parseTriggerName(trigger.name);
|
||||
if(!field) return;
|
||||
if(!attributes[field]){
|
||||
attributes[field] = 'https://s3.amazonaws.com/files.d20.io/images/259054779/OzN3yQwg7MbfXNtMYs-iOg/original.png';
|
||||
}
|
||||
$20(`.${field.replace(/_/g,'-')} .image-container__input`).removeClass('active');
|
||||
};
|
||||
|
||||
const toggleImageInput = function(jEvent){
|
||||
let field = parseHTMLName(jEvent.htmlAttributes.name);
|
||||
$20(`.${field.replace(/_/g,'-')} .image-container__input`).toggleClass('active');
|
||||
};
|
||||
|
||||
//Calls the appropriate dynamic query function for the event
|
||||
const dynamicSelect = function(event){
|
||||
let[section,rowID,field] = parseClickTrigger(event.triggerName);
|
||||
field = field.replace(/-action$/,'');
|
||||
getAllAttrs({callback:async (attributes,sections)=>{
|
||||
let selection = await dynamicQueries[field]({section,rowID,field},attributes,sections);
|
||||
attributes[`${section}_${rowID}_${field}`] = selection;
|
||||
attributes[`${section}_${rowID}_translate_${field}`] = getTranslationByKey(selection) ? 1 : 0;
|
||||
attributes.set();
|
||||
}});
|
||||
};
|
||||
|
||||
const skillQuery = function(click,attributes,sections){
|
||||
let query = sections.repeating_skill.reduce((prompt,id)=>{
|
||||
if(attributes[`repeating_skill_${id}_raw`]){
|
||||
prompt.push(`${capitalize(getTranslationByKey(attributes[`repeating_skill_${id}_name`]))},${attributes[`repeating_skill_${id}_name`]}`);
|
||||
}else{
|
||||
prompt.push(capitalize(attributes[`repeating_skill_${id}_name`]));
|
||||
}
|
||||
return prompt;
|
||||
},[`${getTranslationByKey('skill query')}`]).join('|');
|
||||
query = `${query}`
|
||||
return extractQueryResult(query);
|
||||
};
|
||||
//Click Functions
|
||||
//These functions are fired in response to an action button being clicked.
|
||||
//Clears a tracker of all damage
|
||||
const clearTracker = function(event){
|
||||
debug('clearing tracker');
|
||||
let [section,rowID,field] = parseClickTrigger(event.triggerName);
|
||||
getAllAttrs({callback:(attributes,sections,casc)=>{
|
||||
sections[section].forEach((id)=>{
|
||||
attributes[`${section}_${id}_damaged`] = 0;
|
||||
attributes[`${section}_${id}_fill`] = 0;
|
||||
});
|
||||
let attr = section.replace(/repeating_/,'');
|
||||
attributes[attr] = attributes[`${attr}_max`];
|
||||
let trigger = casc[attr];
|
||||
processSheet(trigger,attributes,sections,casc);
|
||||
}});
|
||||
};
|
||||
|
||||
const addItem = function(event){
|
||||
debug(`adding repeating item from ${event.triggerName}`);
|
||||
let [,,section] = parseClickTrigger(event.triggerName);
|
||||
section = section.replace(/add-/,'');
|
||||
let rowID = generateRowID();
|
||||
const setObj = {};
|
||||
setObj[`repeating_${section}_${rowID}_name`] = '';
|
||||
set(setObj);
|
||||
};
|
||||
|
||||
const editSection = function(event){
|
||||
debug(`editing repeating section from ${event.triggerName}`);
|
||||
let [,,section] = parseClickTrigger(event.triggerName);
|
||||
section = section.replace(/edit-/,'');
|
||||
let target = `fieldset.repeating_${section} + .repcontainer`;
|
||||
$20(target).toggleClass('editmode');
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//Initial change functions
|
||||
const syncHealth = function(trigger,attributes,sections){
|
||||
debug('syncing token and character health');
|
||||
const type = trigger.name.replace(/_max/,'');
|
||||
let damage = attributes[`${type}_max`] - attributes[type];
|
||||
let damageIndex = damage - 1;
|
||||
sections[`repeating_${type}`].forEach((id,index)=>{
|
||||
attributes[`repeating_${type}_${id}_damaged`] = index === damageIndex ? 1 : 0;
|
||||
attributes[`repeating_${type}_${id}_fill`] = index < damageIndex ? 1 : 0;
|
||||
});
|
||||
if(attributes[type] > attributes[`${type}_max`]){
|
||||
attributes[type] = attributes[`${type}_max`];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//accesses the sheet and iterates through all changes necessary before calling setAttrs
|
||||
const accessSheet = function(event){
|
||||
debug({event});
|
||||
getAllAttrs({callback:(attributes,sections,casc)=>{
|
||||
let trigger = casc[event.sourceAttribute];
|
||||
processSheet(trigger,attributes,sections,casc);
|
||||
}});
|
||||
};
|
||||
|
||||
const processSheet = function(trigger,attributes,sections,casc){
|
||||
debug({trigger});
|
||||
if(!trigger){
|
||||
return;
|
||||
}
|
||||
initialFunction(trigger,attributes,sections);//functions that should only be run if the attribute was the thing changed
|
||||
triggerFunctions(trigger,attributes,sections);//functions that cause complex changes to the character
|
||||
let queue = [...trigger.affects];
|
||||
while(queue.length){
|
||||
let name = queue.shift();
|
||||
debug(`processing ${name}`);
|
||||
let obj = casc[name];
|
||||
triggerFunctions(obj,attributes,sections);
|
||||
if(obj.calculation){
|
||||
attributes[name] = obj.calculation(obj,attributes,sections);//Basic calculation of an attribute value
|
||||
}
|
||||
queue = [...queue,...obj.affects];
|
||||
}
|
||||
debug('sheet accessed, setting attributes');
|
||||
attributes.set();
|
||||
};
|
||||
const registerEventHandlers = function(){
|
||||
on('sheet:opened',updateSheet);
|
||||
toMonitor.forEach((m)=>{
|
||||
on(`change:${m}`,accessSheet);
|
||||
});
|
||||
|
||||
//Click Listeners
|
||||
navButtons.forEach((button)=>{
|
||||
on(`clicked:nav-${button}`,navigateSheet);
|
||||
});
|
||||
trackerMonitors.forEach((button)=>{
|
||||
on(`clicked:${button}`,clearTracker);
|
||||
});
|
||||
queryButtons.forEach((button)=>{
|
||||
on(`clicked:${button}`,dynamicSelect);
|
||||
});
|
||||
rollMonitor.forEach((button)=>{
|
||||
on(`clicked:${button}`,initiateRoll);
|
||||
});
|
||||
repeatAddMonitors.forEach((button)=>{
|
||||
on(`clicked:add-${button}`,addItem);
|
||||
on(`clicked:edit-${button}`,editSection);
|
||||
})
|
||||
//jQuery listeners
|
||||
$20('.expandable-header').on('click',expandHeader);
|
||||
$20('.image-container__button').on('click',toggleImageInput);
|
||||
};
|
||||
@@ -0,0 +1,178 @@
|
||||
/*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}]]`;
|
||||
};
|
||||
|
||||
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] = parseClickTrigger(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);
|
||||
}});
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
/*
|
||||
Sheet Styling
|
||||
*/
|
||||
const navigateSheet = function(event){
|
||||
debug('navigating sheet');
|
||||
const setObj = {};
|
||||
let [,,page] = parseClickTrigger(event.triggerName);
|
||||
page = page.replace(/nav-|-action/g,'');
|
||||
debug({page});
|
||||
navButtons.forEach((button)=>{
|
||||
let element = button.replace(/-action/,'');
|
||||
let action = element === page ? 'addClass' : 'removeClass';
|
||||
$20(`.${element}`)[action]('active');
|
||||
});
|
||||
setObj.sheet_state = page;
|
||||
debug({setObj});
|
||||
set(setObj);
|
||||
};
|
||||
const setupSystem = function(trigger,attributes,sections){
|
||||
setupAttributes(attributes,sections);
|
||||
setupSkills(attributes,sections);
|
||||
setupHealth(attributes,sections);
|
||||
};
|
||||
|
||||
const setupAttributes = function(attributes,sections){
|
||||
const attrDetails = systemDefaults[attributes.system].attributes;
|
||||
Object.entries(attrDetails).forEach(([attr,value])=>{
|
||||
attributes[attr] = value;
|
||||
});
|
||||
};
|
||||
|
||||
const setupSkills = function(attributes,sections){
|
||||
let skillDetails = systemDefaults[attributes.system].repeating_skill.values;
|
||||
let missingSkills = Object.keys(skillDetails).filter((skill)=>sections.repeating_skill.every((id)=>attributes[`repeating_skill_${id}_name`]===skill));
|
||||
missingSkills.forEach((skill)=>{
|
||||
let newID = generateRowID();
|
||||
attributes[`repeating_skill_${newID}_name`] = skill;
|
||||
attributes[`repeating_skill_${newID}_stat`] = /\//.test(skillDetails[skill]) ? 'query' : skillDetails[skill];
|
||||
attributes[`repeating_skill_${newID}_raw`] = 1;
|
||||
});
|
||||
};
|
||||
|
||||
const setupHealth = function(attributes,sections){
|
||||
let healthDetails = systemDefaults[attributes.system].repeating_health.values;
|
||||
if(healthDetails && !sections.repeating_health.length){
|
||||
healthDetails.forEach((penalty)=>{
|
||||
let newID = generateRowID();
|
||||
attributes[`repeating_health_${newID}_penalty`] = penalty;
|
||||
});
|
||||
attributes.health = healthDetails.length;
|
||||
attributes.health_max = attributes.health;
|
||||
}
|
||||
let structureDetails = systemDefaults[attributes.system].repeating_structure.values;
|
||||
if(structureDetails && !sections.repeating_structure.length){
|
||||
structureDetails.forEach((penalty)=>{
|
||||
let newID = generateRowID();
|
||||
attributes[`repeating_structure_${newID}_penalty`] = penalty;
|
||||
});
|
||||
attributes.structure = structureDetails.length;
|
||||
attributes.structure_max = attributes.structure;
|
||||
attributes.structure_base = attributes.structure;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
// Triggered Functions
|
||||
const setActionCalls = function(trigger,attributes,sections){
|
||||
debug('setting action calls');
|
||||
actionAttributes.forEach((base)=>{
|
||||
let [section,,field] = parseTriggerName(base);
|
||||
let fieldAction = field.replace(/_/g,'-');
|
||||
if(section){
|
||||
sections[section].forEach((id)=>{
|
||||
attributes[`${section}_${id}_${field}`] = `%{${attributes.character_name}|${section}_${id}_${fieldAction}}`;
|
||||
});
|
||||
}else{
|
||||
attributes[`${field}`] = `%{${attributes.character_name}|${fieldAction}}`;
|
||||
}
|
||||
});
|
||||
debug({updates:attributes.updates});
|
||||
};
|
||||
|
||||
const checkHealth = function(trigger,attributes,sections){
|
||||
debug('checking current health trackers')
|
||||
let [section,rowID] = parseRepeatName(trigger.name);
|
||||
let currDamage = sections[section].indexOf(rowID);
|
||||
sections[section].forEach((id,index)=>{
|
||||
if(index !== currDamage){
|
||||
attributes[`${section}_${id}_damaged`] = 0;
|
||||
}
|
||||
attributes[`${section}_${id}_fill`] = index < currDamage ? 1 : 0;
|
||||
});
|
||||
};
|
||||
|
||||
const updateTrack = function(section,attributes,sections){
|
||||
let newTracks = attributes[`${section}_max`] - sections[`repeating_${section}`].length;
|
||||
if(newTracks > 0){
|
||||
_.range(newTracks).forEach((n)=>{
|
||||
let newID = generateRowID();
|
||||
let priorPenalties = sections[`repeating_${section}`].slice(Math.max(0,sections[`repeating_${section}`].length - 2))
|
||||
.map((id)=>{
|
||||
return attributes[`repeating_${section}_${id}_penalty`];
|
||||
});
|
||||
let newPenalty;
|
||||
if(priorPenalties[0] !== priorPenalties[1]){
|
||||
newPenalty = priorPenalties[1] || priorPenalties[0];
|
||||
}else{
|
||||
let penStart = priorPenalties[1] || priorPenalties[0];
|
||||
newPenalty = Math.max(Math.min(-3,penStart),penStart - 1);
|
||||
}
|
||||
attributes[`repeating_${section}_${newID}_damaged`] = 0;
|
||||
attributes[`repeating_${section}_${newID}_penalty`] = newPenalty;
|
||||
sections[`repeating_${section}`].push(newID);
|
||||
});
|
||||
}else if(newTracks < 0){
|
||||
let slicePoint = Math.max(0,sections[`repeating_${section}`].length + newTracks);
|
||||
let extraTracks = sections[`repeating_${section}`].slice(slicePoint);
|
||||
extraTracks.forEach((id)=>{
|
||||
_removeRepeatingRow(`repeating_${section}_${id}`,attributes,sections);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const maxHealth = function(type,attributes){
|
||||
const typeSwitch = {
|
||||
structure:()=> attributes.structure_base,
|
||||
health:()=> 3 + attributes.body + attributes.spirit + attributes.health_mod
|
||||
}
|
||||
return Math.max(typeSwitch[type](),1);
|
||||
};
|
||||
|
||||
const calcHealth = function(trigger,attributes,sections){
|
||||
const type = trigger.name.replace(/_max/,'');
|
||||
debug(`calculating ${type}`);
|
||||
attributes[`${type}_max`] = maxHealth(type,attributes);
|
||||
let healthDiff = attributes[`${type}_max`] - value(attributes.attributes[`${type}_max`]);
|
||||
updateTrack(type,attributes,sections);
|
||||
attributes[type] = attributes[type] + healthDiff;
|
||||
syncHealth(trigger,attributes,sections);
|
||||
};
|
||||
|
||||
const skillEffects = function(trigger,attributes,sections){
|
||||
let [section,rowID,field] = parseRepeatName(trigger.name);
|
||||
let skillName = attributes[`${section}_${rowID}_name`];
|
||||
const skillSwitch = {
|
||||
dodge:['defence'],
|
||||
awareness:['initiative']
|
||||
};
|
||||
if(skillSwitch[skillName]){
|
||||
trigger.affects = [...trigger.affects,...skillSwitch[skillName]];
|
||||
}
|
||||
};
|
||||
|
||||
const validateActionPenalty = function(trigger,attributes,sections){
|
||||
if(attributes.action_penalty > 0){
|
||||
attributes.action_penalty = attributes.action_penalty * -1;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,354 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//# Attribute Obj Proxy handler
|
||||
const createAttrProxy = function(attributes){
|
||||
//creates a proxy for the attributes object so that values can be worked with more easily.
|
||||
const attrTarget = {
|
||||
updates:{},
|
||||
attributes:{...attributes},
|
||||
repOrders:{}
|
||||
};
|
||||
const attrHandler = {
|
||||
get:function(obj,prop){//gets the most value of the attribute.
|
||||
//If it is a repeating order, returns the array, otherwise returns the update value or the original value
|
||||
if(prop === 'set'){
|
||||
return function(){
|
||||
set(obj.updates,...arguments);
|
||||
}
|
||||
}else if(Object.keys(obj).some(key=>key===prop)){
|
||||
return Reflect.get(...arguments)
|
||||
}else{
|
||||
let retValue;
|
||||
switch(true){
|
||||
case obj.repOrders.hasOwnProperty(prop):
|
||||
retValue = obj.repOrders[prop];
|
||||
break;
|
||||
case obj.updates.hasOwnProperty(prop):
|
||||
retValue = obj.updates[prop];
|
||||
break;
|
||||
default:
|
||||
retValue = obj.attributes[prop];
|
||||
break;
|
||||
}
|
||||
let cascRef = prop.replace(/(repeating_[^_]+_)[^_]+/,'$1\$x');
|
||||
let numRetVal = +retValue;
|
||||
if(!Number.isNaN(numRetVal)){
|
||||
retValue = numRetVal;
|
||||
}else if(cascades[cascRef] && cascades[cascRef].type === 'number'){
|
||||
retValue = cascades[cascRef].defaultValue || 0;
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
},
|
||||
set:function(obj,prop,value){
|
||||
//Sets the value. Also verifies that the value is a valid attribute value
|
||||
//e.g. not undefined, null, or NaN
|
||||
if(value || value===0 || value===''){
|
||||
if(/reporder|^repeating_[^_]+$/.test(prop)){
|
||||
let section = prop.replace(/_reporder_/,'');
|
||||
obj.repOrders[section] = value;
|
||||
}else{
|
||||
obj.updates[prop] = value;
|
||||
}
|
||||
}else{
|
||||
debug(`!!!Warning: Attempted to set ${prop} to an invalid value:${value}; value not stored!!!`);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
deleteProperty(obj,prop){
|
||||
//removes the property from the original attributes, updates, and the reporders
|
||||
Object.keys(obj).forEach((key)=>{
|
||||
delete obj[key][prop.toLowerCase()];
|
||||
});
|
||||
}
|
||||
};
|
||||
return new Proxy(attrTarget,attrHandler);
|
||||
};
|
||||
|
||||
const _setSectionOrder = function(section,order){
|
||||
let trueSection = section.replace(/repeating_/,'');
|
||||
setSectionOrder(trueSection,order);
|
||||
};
|
||||
const _removeRepeatingRow = function(row,attributes,sections){
|
||||
debug(`removing ${row}`);
|
||||
Object.keys(attributes.attributes).forEach((key)=>{
|
||||
if(key.startsWith(row)){
|
||||
delete attributes[key];
|
||||
}
|
||||
});
|
||||
let [,section,rowID] = row.match(/(repeating_[^_]+)_(.+)/,'');
|
||||
sections[section] = sections[section].filter((id)=>id!==rowID);
|
||||
removeRepeatingRow(row);
|
||||
};
|
||||
const _getAttrs = function(props=baseGet,callback){
|
||||
getAttrs(props,(values)=>{
|
||||
const attributes = createAttrProxy(values);
|
||||
callback(attributes);
|
||||
});
|
||||
};
|
||||
const getAllAttrs = function({callback,props=baseGet,sectionDetails=repeatingSectionDetails}){
|
||||
getSections(sectionDetails,(repeats,sections)=>{
|
||||
getAttrs([...props,...repeats],(values)=>{
|
||||
const attributes = createAttrProxy(values);
|
||||
orderSections(attributes,sections);
|
||||
const casc = expandCascade(cascades,sections,attributes);
|
||||
callback(attributes,sections,casc);
|
||||
})
|
||||
});
|
||||
};
|
||||
const getSections = function(section_details,callback){
|
||||
let queueClone = _.clone(section_details);
|
||||
const worker = (queue,repeatAttrs=[],sections={})=>{
|
||||
let detail = queue.shift();
|
||||
getSectionIDs(detail.section,(IDs)=>{
|
||||
sections[detail.section] = IDs;
|
||||
IDs.forEach((id)=>{
|
||||
detail.fields.forEach((f)=>{
|
||||
repeatAttrs.push(`${detail.section}_${id}_${f}`);
|
||||
});
|
||||
});
|
||||
repeatAttrs.push(`_reporder_${detail.section}`);
|
||||
if(queue.length){
|
||||
worker(queue,repeatAttrs,sections);
|
||||
}else{
|
||||
callback(repeatAttrs,sections);
|
||||
}
|
||||
});
|
||||
};
|
||||
if(!queueClone[0]){
|
||||
callback([],{});
|
||||
}
|
||||
worker(queueClone);
|
||||
};
|
||||
// Sets the attributes while always calling with {silent:true}
|
||||
// Can be awaited to get the values returned from _setAttrs
|
||||
const set = function(obj,vocal=false){
|
||||
setAttrs(obj,{silent:!vocal});
|
||||
};
|
||||
//sanitizes text for use as a regex
|
||||
sanitizeForRegex = function(text){
|
||||
return text.replace(/\.|\||\(|\)|\[|\]|\-|\+|\?|\/|\{|\}|\^|\$|\*/g,'\\$&');
|
||||
};
|
||||
//converts a value to a number, it's default value, or 0
|
||||
const value = function(val,def){
|
||||
return (+val||def||0);
|
||||
};
|
||||
//extracts the section, rowID, and field name from a repeating attribute name
|
||||
/*
|
||||
e.g. repeating_equipment_-09Jhu89z_bulk would give:
|
||||
section: equipment
|
||||
rowID: -09Jhu89z
|
||||
field: bulk
|
||||
*/
|
||||
const parseRepeatName = function(string){
|
||||
let match = string.match(/(repeating_[^_]+)_([^_]+)(?:_(.+))?/);
|
||||
match.shift();
|
||||
return match;
|
||||
};
|
||||
|
||||
const parseTriggerName = function(string){
|
||||
let match = string.match(/(?:(repeating_[^_]+)_([^_]+)_)?(.+)/);
|
||||
match.shift();
|
||||
return match;
|
||||
};
|
||||
|
||||
const parseClickTrigger = function(string){
|
||||
let match = string.match(/clicked:(?:(repeating_[^_]+)_([^_]+)_)?(.+)/);
|
||||
match.shift();
|
||||
return match;
|
||||
};
|
||||
|
||||
const parseHTMLName = function(string){
|
||||
let match = string.match(/(?:attr|act|roll)_(.+)/);
|
||||
match.shift();
|
||||
return match[0];
|
||||
};
|
||||
|
||||
const capitalize = function(string){
|
||||
return string.replace(/(?:^|\s+|\/)[a-z]/ig,(letter)=>letter.toUpperCase());
|
||||
};
|
||||
|
||||
const extractQueryResult = async function(query){
|
||||
debug('entering extractQueryResult');
|
||||
let queryRoll = await startRoll(`!{{query=[[0[response=?{${query}}]]]}}`);
|
||||
finishRoll(queryRoll.rollId);
|
||||
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
|
||||
};
|
||||
|
||||
const pseudoQuery = async function(value){
|
||||
debug('entering pseudoQuery');
|
||||
let queryRoll = await startRoll(`!{{query=[[0[response=${value}]]]}}`);
|
||||
finishRoll(queryRoll.rollId);
|
||||
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
|
||||
};
|
||||
|
||||
//Determines which penalty to apply (if any)
|
||||
const determinePenalty = function(type,attributes,sections){
|
||||
let damageID = sections[`repeating_${type}`].find((id)=> attributes[`repeating_${type}_${id}_damaged`] === 1);
|
||||
return damageID ? attributes[`repeating_${type}_${damageID}_penalty`] : 0;
|
||||
};
|
||||
|
||||
//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';
|
||||
};
|
||||
|
||||
//# Utility Functions #
|
||||
const log = function(msg){
|
||||
if(typeof msg === 'string'){
|
||||
console.log(`%c${sheetName} log| ${msg}`,"background-color:#159ccf");
|
||||
}else if(typeof msg === 'object'){
|
||||
Object.keys(msg).forEach((m)=>{
|
||||
if(typeof msg[m] === 'string'){
|
||||
console.log(`%c${sheetName} log| ${m}: ${msg[m]}`,"background-color:#159ccf");
|
||||
}else{
|
||||
console.log(`%c${sheetName} log| ${typeof msg[m]} ${m}`,"background-color:#159ccf");
|
||||
console.table(msg[m]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
const debug = function(msg,force){
|
||||
if(!debugMode && !force && version > 0) return;
|
||||
if(typeof msg === 'string'){
|
||||
console.log(`%c${sheetName} DEBUG| ${msg}`,"background-color:tan;color:red;");
|
||||
}else if(typeof msg === 'object'){
|
||||
Object.keys(msg).forEach((m)=>{
|
||||
if(typeof msg[m] === 'string'){
|
||||
console.log(`%c${sheetName} DEBUG| ${m}: ${msg[m]}`,"background-color:tan;color:red;");
|
||||
}else{
|
||||
console.log(`%c${sheetName} DEBUG| ${typeof msg[m]} ${m}`,"background-color:tan;color:red;font-weight:bold;");
|
||||
console.table(msg[m]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
//Section ordering
|
||||
//orders the section id arrays to match the repOrder attribute
|
||||
const orderSections = function(attributes,sections){
|
||||
Object.keys(sections).forEach((section)=>{
|
||||
attributes.attributes[`_reporder_${section}`] = commaArray(attributes[`_reporder_${section}`]);
|
||||
orderSection(attributes.attributes[`_reporder_${section}`],sections[section]);
|
||||
});
|
||||
};
|
||||
//orders a single ID array
|
||||
const orderSection = function(repOrder,IDs=[]){
|
||||
IDs.sort((a,b)=>{
|
||||
return repOrder.indexOf(a.toLowerCase()) - repOrder.indexOf(b.toLowerCase());
|
||||
});
|
||||
};
|
||||
//splits a comma delimited string into an array
|
||||
const commaArray = function(string=''){
|
||||
return string.toLowerCase().split(/\s*,\s*/);
|
||||
};
|
||||
//Creates a row ID specific for an add section for pseudo nested repeating sections
|
||||
const generateCustomID = function(string,rowID){
|
||||
rowID = rowID || generateRowID();
|
||||
let re = new RegExp(`^.{${string.length}}`);
|
||||
return `${string}${rowID.replace(re,'')}`;
|
||||
};
|
||||
|
||||
//Sheet Updaters and styling functions
|
||||
const updateSheet = function(){
|
||||
debug('updating sheet');
|
||||
getAllAttrs({props:['sheet_version','debug_mode','collapsed',...baseGet],callback:(attributes,sections,casc)=>{
|
||||
debugMode = !!attributes.debug_mode;
|
||||
attributes.sheet_version = version;
|
||||
if(!attributes.sheet_version){
|
||||
initialSetup(attributes,sections);
|
||||
}
|
||||
log(`Sheet Update applied. Current Sheet Version ${version}`);
|
||||
styleOnOpen(attributes,sections);
|
||||
setActionCalls({},attributes,sections);
|
||||
attributes.set();
|
||||
log('Sheet ready for use');
|
||||
}})
|
||||
};
|
||||
const initialSetup = function(attributes,sections){
|
||||
debug('Initial sheet setup');
|
||||
};
|
||||
const styleOnOpen = function(attributes,sections){
|
||||
navigateSheet({triggerName:`clicked:${attributes.sheet_state}`});
|
||||
setupSystem({},attributes,sections);
|
||||
};
|
||||
|
||||
/*
|
||||
Cascade Expansion functions
|
||||
*/
|
||||
//Expands the repeating section templates in cascades to reflect the rows actually available
|
||||
const expandCascade = function(cascade,sections,attributes){
|
||||
return _.keys(cascade).reduce((memo,key)=>{//iterate through cascades and replace references to repeating attributes with correct row ids.
|
||||
if(/^repeating/.test(key)){//If the attribute is a repeating attribute, do special logic
|
||||
expandRepeating(memo,key,cascade,sections,attributes);
|
||||
}else{//for non repeating attributes do this logic
|
||||
expandNormal(memo,key,cascade,sections);
|
||||
}
|
||||
return memo;
|
||||
},{});
|
||||
};
|
||||
|
||||
const expandRepeating = function(memo,key,cascade,sections,attributes){
|
||||
key.replace(/(repeating_[^_]+)_[^_]+?_(.+)/,(match,section,field)=>{
|
||||
(sections[section]||[]).forEach((id)=>{
|
||||
memo[`${section}_${id}_${field}`]=_.clone(cascade[key]);//clone the details so that each row's attributes have correct ids
|
||||
memo[`${section}_${id}_${field}`].name = `${section}_${id}_${field}`;
|
||||
memo[`${section}_${id}_${field}`].affects = memo[`${section}_${id}_${field}`].affects.reduce((m,affected)=>{
|
||||
if(section === affected){//otherwise if the affected attribute is in the same section, simply set the affected attribute to have the same row id.
|
||||
m.push(applyID(affected,id));
|
||||
}else if(/repeating/.test(affected)){//If the affected attribute isn't in the same repeating section but is still a repeating attribute, add all the rows of that section
|
||||
addAllRows(affected,m,sections);
|
||||
}else{//otherwise the affected attribute is a non repeating attribute. Simply add it to the computed affected array
|
||||
m.push(affected);
|
||||
}
|
||||
return m;
|
||||
},[]);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const applyID = function(affected,id){
|
||||
return affected.replace(/(repeating_[^_]+_)[^_]+(.+)/,`$1${id}$2`);
|
||||
};
|
||||
|
||||
const expandNormal = function(memo,key,cascade,sections){
|
||||
memo[key] = _.clone(cascade[key]);
|
||||
memo[key].affects = memo[key].affects.reduce((m,a)=>{
|
||||
if(/^repeating/.test(a)){
|
||||
addAllRows(a,m,sections);
|
||||
}else{
|
||||
m.push(a);
|
||||
}
|
||||
return m;
|
||||
},[]);
|
||||
};
|
||||
|
||||
const triggerFunctions = function(obj,attributes,sections){
|
||||
debug(`triggering functions for ${obj.name}`);
|
||||
obj.triggeredFuncs && obj.triggeredFuncs.forEach(func=>func(obj,attributes,sections));
|
||||
};
|
||||
|
||||
const initialFunction = function(obj,attributes,sections){
|
||||
debug(`initial functions for ${obj.name}`);
|
||||
obj.initialFunc && obj.initialFunc(obj,attributes,sections);
|
||||
};
|
||||
|
||||
const addAllRows = function(affected,memo,sections){
|
||||
affected.replace(/(repeating_[^_]+?)_[^_]+?_(.+)/,(match,section,field)=>{
|
||||
sections[section].forEach(id=>memo.push(`${section}_${id}_${field}`));
|
||||
});
|
||||
};
|
||||
|
||||
let clickDelay = 500;
|
||||
const defaultThrottle = callback => _.throttle(callback,clickDelay,{trailing:false});
|
||||
const isDieRoll = function(field){
|
||||
return /(?:d(?:8|10|12)(?:Crit)?|exertion)/.test(field);
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||||
/*jshint -W014,-W084,-W030,-W033*/
|
||||
//Sheet Variables
|
||||
const sheetName = 'Rapidfire System';
|
||||
const version = 1.0;
|
||||
let debugMode = false;
|
||||
//Object that defines how the attributes affect each other
|
||||
const repeatingSectionDetails = [
|
||||
{section:'repeating_health',fields:['damaged','penalty','fill']},
|
||||
{section:'repeating_structure',fields:['damaged','penalty','fill']},
|
||||
{section:'repeating_skill',fields:['name','level','stat','xp','raw','roll_action']},
|
||||
{section:'repeating_weapon',fields:['name','skill','stat','translate skill','damage','notes','collapse','roll_action']},
|
||||
{section:'repeating_remnant-weapon',fields:['name','skill','bonus','damage','damage_bonus','type','notes','collapse','roll_action','notes']},
|
||||
{section:'repeating_drone',fields:['name','active','sa','collapse','def','arm','spd','struct','assault','assault_dam','strike','strike_dam','strikerange','strike_action','assault_action','description']}
|
||||
];
|
||||
//const actionAttributes = ['body','mind','spirit','initiative','repeating_skill_$x_roll','repeating_weapon_$x_roll','situational_awareness','remnant_initiative','assault_roll','strike_roll','motion_roll','repeating_remnant-weapon_$x_roll','repeating_drone_$x_assault','repeating_drone_$x_strike'];
|
||||
const systemDefaults = {
|
||||
'remnants':{
|
||||
repeating_skill:{field:'name',additional:true,values:{"archery / throwing":"body","athletics":"body","awareness":"mind","bureaucracy":"mind","command":"mind or spirit","craft":"body / mind / spirit","dodge":"body","etiquette":"spirit","history":"mind","investigation":"mind / spirit","language":"mind","larceny":"mind / body / spirit","lore":"mind","medicine":"mind","melee":"body","perform":"spirit","ride":"body / spirit","sail":"mind / spirit","sciences":"mind","social sciences":"mind","stealth":"body","survival":"mind","unarmed combat":"body"}},
|
||||
repeating_health:{field:'penalty',additional:true,values:[0,-1,-1],alternate:true},
|
||||
repeating_structure:{field:'penalty',additional:true,values:[0,0,-1,-1,-2],alternate:true},
|
||||
attributes:{system_header:'https://s3.amazonaws.com/files.d20.io/images/260489274/xCVgiDGF-dMYpVGKXL5UXA/original.png',armour:5,speed:3,assault_damage:4,strike_damage:2,inspiring:1,terrifying:1}
|
||||
}
|
||||
};
|
||||
|
||||
const cascades = {
|
||||
/*template
|
||||
attribute_name:{
|
||||
name:'attribute_name',
|
||||
affects:['array','of','attributes','affected'],
|
||||
calculation:funcCall,//Calculation for this attribute; optional property
|
||||
triggeredFuncs:[func,func]
|
||||
}*/
|
||||
// ## Character stats ##
|
||||
character_name:{name:'character_name',type:'text',affects:[],triggeredFuncs:[setActionCalls]},
|
||||
sheet_version:{name:'sheet_version',type:'number',defaultValue:0,affects:[]},
|
||||
system:{name:'system',affects:[],triggeredFuncs:[setupSystem]},
|
||||
|
||||
//Stats
|
||||
body:{name:'body',type:'number',defaultValue:0,affects:['defence','health_max','situational_awareness'],triggerdFuncs:[syncHealth]},
|
||||
mind:{name:'mind',type:'number',defaultValue:0,affects:['initiative','situational_awareness']},
|
||||
spirit:{name:'spirit',type:'number',defaultValue:0,affects:['resist','health_max','situational_awareness'],triggerdFuncs:[syncHealth]},
|
||||
|
||||
//Secondary Stats
|
||||
initiative:{name:'initiative',type:'number',defaultValue:0,affects:[],calculation:calcInitiative},
|
||||
initiative_mod:{name:'initiative_mod',type:'number',defaultValue:0,affects:['initiative']},
|
||||
defence:{name:'defence',type:'number',defaultValue:3,affects:[],calculation:calcDefence},
|
||||
resist:{name:'resist',type:'number',defaultValue:0,affects:[],calculation:calcResist},
|
||||
defence_mod:{name:'defence_mod',type:'number',defaultValue:0,affects:['defence']},
|
||||
resist_mod:{name:'resist_mod',type:'number',defaultValue:0,affects:['resist']},
|
||||
health:{name:'health',type:'number',defaultValue:3,affects:['defence'],calculation:totalHealth,initialFunc:syncHealth},
|
||||
health_max:{name:'health_max',type:'number',defaultValue:3,affects:['defence'],triggeredFuncs:[calcHealth]},
|
||||
health_mod:{name:'health_mod',type:'number',defaultValue:0,affects:['health_max']},
|
||||
|
||||
//Combat Gear
|
||||
armour_bonus:{name:'armour_bonus',type:'number',defaultValue:0,affects:['resist']},
|
||||
shield_bonus:{name:'shield_bonus',type:'number',defaultValue:0,affects:['defence']},
|
||||
action_penalty:{name:'action_penalty',type:'number',defaultValue:0,affects:[],triggeredFuncs:[validateActionPenalty]},
|
||||
|
||||
//Health Track
|
||||
repeating_health_$x_damaged:{name:'repeating_health_$x_damaged',type:'number',defaultValue:0,affects:['health'],triggeredFuncs:[checkHealth]},
|
||||
repeating_health_$x_fill:{name:'repeating_health_$x_fill',type:'number',defaultValue:0,affects:[]},
|
||||
repeating_health_$x_penalty:{name:'repeating_health_$x_penalty',type:'number',defaultValue:0,affects:['defence']},
|
||||
|
||||
//Skills
|
||||
repeating_skill_$x_level:{name:'repeating_skill_$x_level',type:'number',defaultValue:0,affects:[],triggeredFuncs:[skillEffects]},
|
||||
|
||||
// ## Remnant Attributes ##
|
||||
remnant_token:{name:'structure',type:'number',defaultValue:3,affects:[],triggeredFuncs:[imageInput]},
|
||||
|
||||
//Ratings
|
||||
situational_awareness:{name:'situational_awareness',type:'number',defaultValue:0,affects:['remnant_initiative','remnant_defence'],calculation:calcSA},
|
||||
remnant_defence:{name:'remnant_defence',type:'number',defaultValue:0,affects:[],calculation:calcRemnantDefence},
|
||||
remnant_initiative:{name:'remnant_initiative',type:'number',defaultValue:0,affects:[],calculation:calcRemnantInitiative},
|
||||
|
||||
//Stats
|
||||
speed:{name:'speed',type:'number',defaultValue:0,affects:['remnant_defence']},
|
||||
strike_range:{name:'strike_range',type:'number',defaultValue:0,affects:[],calculation:calcStrikeRange},
|
||||
|
||||
structure:{name:'structure',type:'number',defaultValue:5,affects:['remnant_defence'],calculation:totalHealth,initialFunc:syncHealth},
|
||||
structure_base:{name:'structure_base',type:'number',defaultValue:5,affects:['structure_max']},
|
||||
structure_max:{name:'structure_max',type:'number',defaultValue:5,affects:['remnant_defence'],triggeredFuncs:[calcHealth]},
|
||||
strike_damage:{name:'strike_damage',type:'number',defaultValue:0,affects:['repeating_remnant-weapon_$x_damage']},
|
||||
assault_damage:{name:'assault_damage',type:'number',defaultValue:0,affects:['repeating_remnant-weapon_$x_damage']},
|
||||
|
||||
//Remnant Skills
|
||||
strike_level:{name:'strike_level',type:'number',defaultValue:0,affects:['strike_range']},
|
||||
assault_level:{name:'assault_level',type:'number',defaultValue:0,affects:[]},
|
||||
motion_level:{name:'motion_level',type:'number',defaultValue:0,affects:['remnant_defence']},
|
||||
|
||||
//Structure Track
|
||||
repeating_structure_$x_damaged:{name:'repeating_structure_$x_damaged',type:'number',defaultValue:0,affects:['structure'],triggeredFuncs:[checkHealth]},
|
||||
repeating_structure_$x_fill:{name:'repeating_structure_$x_fill',type:'number',defaultValue:0,affects:[]},
|
||||
repeating_structure_$x_penalty:{name:'repeating_structure_$x_penalty',type:'number',defaultValue:0,affects:['remnant_defence']},
|
||||
|
||||
//remnant-weapons
|
||||
'repeating_remnant-weapon_$x_damage':{name:'repeating_remnant-weapon_$x_damage',type:'number',defaultValue:0,affects:[],calculation:calcRemnantDamage},
|
||||
'repeating_remnant-weapon_$x_skill':{name:'repeating_remnant-weapon_$x_skill',type:'text',defaultValue:'assault',affects:['repeating_remnant-weapon_$x_damage']},
|
||||
'repeating_remnant-weapon_$x_damage_bonus':{name:'repeating_remnant-weapon_$x_damage_bonus',type:'number',defaultValue:0,affects:['repeating_remnant-weapon_$x_damage']},
|
||||
|
||||
//remnant Drones
|
||||
'repeating_drone_$x_strike':{name:'repeating_drone_$x_strike',type:'number',defaultValue:0,affects:['repeating_drone_$x_strikerange']},
|
||||
'repeating_drone_$x_active':{name:'repeating_drone_$x_active',type:'number',defaultValue:0,affects:[]},
|
||||
'repeating_drone_$x_strikerange':{name:'repeating_drone_$x_strikerange',type:'number',defaultValue:0,affects:[],calculation:calcStrikeRange},
|
||||
};
|
||||
const systems = ['remnants'];
|
||||
const repeatMonitor = [];
|
||||
//const rollMonitor = ['body-action','mind-action','spirit-action','initiative-action','situational-awareness-action','remnant-initiative-action','assault-roll-action','strike-roll-action','motion-roll-action','repeating_skill:roll-action','repeating_weapon:roll-action','repeating_drone:assault-action','repeating_drone:strike-action','repeating_remnant-weapon:roll-action'];
|
||||
//const navButtons = ['character','settings','battle-remnant'];
|
||||
//const repeatAddMonitors = ['skill','weapon','advantage','disadvantage','adjustment','specialty','trait','drone','remnant-weapon'];
|
||||
//const queryButtons = ['repeating_weapon:skill'];
|
||||
//const trackerMonitors = ['repeating_structure:clear','repeating_health:clear'];
|
||||
const dynamicQueries = {skill:skillQuery};
|
||||
const baseGet = ['sheet_state','section_state','character_name'];
|
||||
let toMonitor = Object.keys(cascades).reduce((m,k)=>{
|
||||
if(!/repeating/.test(k)){
|
||||
baseGet.push(k);
|
||||
if(!/max/.test(k)){
|
||||
m.push(k);
|
||||
}
|
||||
}else if(/repeating/.test(k)){
|
||||
k.replace(/(repeating_[^_]+?)_[^_]+?_(.+)/,(match,section,field)=>{
|
||||
repeatMonitor.push(`${section}:${field}`);
|
||||
});
|
||||
}
|
||||
return m;
|
||||
},[]);
|
||||
debug({cascades,baseGet});
|
||||
toMonitor = [...toMonitor,...repeatMonitor];
|
||||
registerEventHandlers();
|
||||
log(`Sheet Loaded`);
|
||||
@@ -0,0 +1,42 @@
|
||||
//- File for system specific mixins
|
||||
- const characterFields = ['character name','player name','nationality','organization affiliations'];
|
||||
- const stats = ['body','mind','spirit'];
|
||||
- const secondaries = ['defence','resist'];
|
||||
- const secondaryDefaults = {defence:3,resist:0};
|
||||
- const combatGear = ['armour bonus','shield bonus','action penalty'];
|
||||
- const remnantRatings = ['situational awareness','remnant defence'];
|
||||
- const remnantStats = ['armour','speed','inspiring','terrifying','structure'];
|
||||
- const remnantCombatStats = ['assault damage','strike damage','strike range'];
|
||||
- const droneStats = ['sa','def','arm','spd','struct','assault','assault dam','strike','strike dam','strikerange'];
|
||||
- const abbreviations = {'situational awareness':'situation awareness abbreviation','remnant defence':'defence','strike dam':'strike damage','assault dam':'assault damage','strikerange':'strike range',sa:'situation awareness abbreviation',def:'defence',arm:'armour',spd:'speed',struct:'structure'};
|
||||
- const remnantSkills = ['assault','strike','motion'];
|
||||
- const remnantWeaponInputs = ['name','skill','bonus','damage','damage bonus','type'];
|
||||
- varObjects.trackerMonitors = [];
|
||||
mixin track(header,name)
|
||||
.health-track
|
||||
+h2({'data-i18n':header,class:'health-track__header'})
|
||||
+hidden({name:`${name} max`,value:'1',class:'health-track__max-control'})
|
||||
+fieldset(name)
|
||||
+checkbox({name:'fill',hidden:'',class:'health-track__fill-control',value:'1'})
|
||||
+checkbox({name:'damaged',class:'health-track__clear-control health-track__checkbox',value:'1',title:attrTitle('health','damaged')})
|
||||
- addIfUnique(`repeating_${name}:clear`,'trackerMonitors');
|
||||
+action({name:'clear',class:'health-track__clearer',title:buttonTitle('health','clear')})
|
||||
+number({name:'penalty',class:'boxed health-track__number',title:attrTitle('health','penalty')})
|
||||
//- End Mixin
|
||||
mixin hexagon(attribs={},status)
|
||||
.hexagon&attributes(attributes)&attributes(attribs)
|
||||
if status
|
||||
+rollLess({values:`computed::${status} -2`})
|
||||
span(hidden='').fumble-toggle
|
||||
+rollGreater({values:`computed::${status} 4`})
|
||||
span(hidden='').crit-toggle
|
||||
.hexagon__hex-wrapper
|
||||
.hexagon__hex-wrapper__hex-border
|
||||
.hexagon__hex-wrapper__hex-border__hex-content
|
||||
block
|
||||
//-End Mixin
|
||||
mixin userTemplateFields
|
||||
+allProps({values:`description damage difficulty roll ${[1,2,3,4,5,6].map((num)=>`roll${num}`).join(' ')} header footer character_id system single-roll custom_description status`})
|
||||
h4 {{key}}
|
||||
span {{value}}
|
||||
//- End Mixin
|
||||
@@ -0,0 +1,658 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Bakbak+One|Oxanium:wght@700|Raleway:wght@500;600;700;800&display=swap');
|
||||
//Mixins
|
||||
@mixin borderedLabel($color:black){
|
||||
color: $color;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
@mixin selectedLabel($backColor:black, $color:white){
|
||||
background-color: $backColor;
|
||||
color: $color;
|
||||
}
|
||||
@mixin pseudoRadio($backColor:black, $color:white){
|
||||
input:checked+label,
|
||||
label:hover{
|
||||
@include selectedLabel($backColor, $color);
|
||||
}
|
||||
}
|
||||
%font-vars{
|
||||
--topHeaderFont:Bakbak One;
|
||||
--midHeaderFont:Oxanium;
|
||||
--contentFont:Raleway;
|
||||
}
|
||||
//Placeholders
|
||||
// Clears the default Roll20 styling from all elements
|
||||
.ui-dialog{
|
||||
@extend %font-vars;
|
||||
.tab-content .charsheet{
|
||||
select,
|
||||
textarea,
|
||||
input,
|
||||
.uneditable-input,
|
||||
label,
|
||||
button{
|
||||
all: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
%stackedGrid{
|
||||
&.stacked{
|
||||
flex-direction:column-reverse;
|
||||
&.center>*{
|
||||
text-align: center;
|
||||
}
|
||||
&:not(.center)> *{
|
||||
text-align: left;
|
||||
}
|
||||
> [name]{
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
%inputHighlight{
|
||||
border-width: 1px 3px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
transition: var(--focusTrans);
|
||||
}
|
||||
%ratio1_1{
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
%grid{
|
||||
display:grid;
|
||||
}
|
||||
%inline-grid{
|
||||
display: inline-grid;
|
||||
}
|
||||
%circle{
|
||||
border-radius: 50%;
|
||||
}
|
||||
%split{
|
||||
display:flex;
|
||||
gap:var(--grid-gap);
|
||||
> *{
|
||||
width:0px !important;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
}
|
||||
%base-border{
|
||||
border-width: 1px 3px;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
border-color: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
%base-button{
|
||||
background-color: #DCDCDC33;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px black;
|
||||
border-width: 0;
|
||||
transition:{
|
||||
property:box-shadow,backdrop-filter;
|
||||
duration:200ms;
|
||||
timing-function:ease-out;
|
||||
};
|
||||
backdrop-filter:blur(1px);
|
||||
overflow:hidden;
|
||||
&:is(:hover,:focus){
|
||||
background-color: #85858580;
|
||||
box-shadow: 0 4px 6px black;
|
||||
backdrop-filter:blur(2px);
|
||||
}
|
||||
&:active{
|
||||
background-color: #858585ff;
|
||||
box-shadow: 0 1px 2px black;
|
||||
backdrop-filter:blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
%die-button{
|
||||
@extend %base-button;
|
||||
line-height: 14px;
|
||||
/*height to vertically center a 2rem dicefontd10*/
|
||||
font-size: 2rem;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
padding: 5px 3px 7px;
|
||||
}
|
||||
|
||||
%text-button{
|
||||
padding: 5px 7px;
|
||||
@extend %base-button;
|
||||
}
|
||||
%adaptiveText{
|
||||
@extend %grid;
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "content";
|
||||
>*{
|
||||
grid-area: content;
|
||||
}
|
||||
>span{
|
||||
opacity: 0;
|
||||
z-index: -10;
|
||||
white-space: pre-wrap;
|
||||
@extend %base-border;
|
||||
text-transform: initial;
|
||||
}
|
||||
textarea{
|
||||
resize: none;
|
||||
}
|
||||
}
|
||||
%pictos{
|
||||
font-family: pictos;
|
||||
text-transform: initial;
|
||||
}
|
||||
%pictos3{
|
||||
font-family: pictos three;
|
||||
text-transform: initial;
|
||||
}
|
||||
%pictosCustom{
|
||||
font-family: pictos custom;
|
||||
text-transform: initial;
|
||||
}
|
||||
%uppercase{
|
||||
text-transform:uppercase;
|
||||
}
|
||||
%roller{
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
align-self:start;
|
||||
gap: var(--half-gap);
|
||||
&:before{
|
||||
content:'L';
|
||||
font-family:dicefontd6;
|
||||
}
|
||||
}
|
||||
%hidden{
|
||||
display: none!important;
|
||||
}
|
||||
%italics{
|
||||
font-style: italic;
|
||||
}
|
||||
%baseText{
|
||||
line-height: normal;
|
||||
}
|
||||
%baseHeader{
|
||||
@extend %baseText;
|
||||
color:black;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
font-weight:normal;
|
||||
}
|
||||
%importantHeader{
|
||||
text-transform: uppercase;
|
||||
font-weight: normal;
|
||||
}
|
||||
%midHeader{
|
||||
&:not(input){
|
||||
text-transform:capitalize;
|
||||
}
|
||||
}
|
||||
%h1-style{
|
||||
@extend %baseHeader;
|
||||
@extend %importantHeader;
|
||||
font-size: 2rem;
|
||||
font-family: var(--topHeaderFont);
|
||||
&:not(input){
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
%h1{
|
||||
@extend %h1-style;
|
||||
*{
|
||||
@extend %h1-style;
|
||||
}
|
||||
}
|
||||
%h2-style{
|
||||
@extend %baseHeader;
|
||||
@extend %importantHeader;
|
||||
font-size: 1.75rem;
|
||||
font-family: var(--topHeaderFont);
|
||||
grid-area:header;
|
||||
&:not(input){
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
%h2{
|
||||
@extend %h2-style;
|
||||
*{
|
||||
@extend %h2-style;
|
||||
}
|
||||
}
|
||||
%h3-style{
|
||||
@extend %baseHeader;
|
||||
@extend %importantHeader;
|
||||
font-size: 1.5rem;
|
||||
font-family: var(--topHeaderFont);
|
||||
&:not(input){
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
%h3{
|
||||
@extend %h3-style;
|
||||
*{
|
||||
@extend %h3-style;
|
||||
}
|
||||
}
|
||||
%h4-style{
|
||||
@extend %baseHeader;
|
||||
@extend %midHeader;
|
||||
font-size: 1.25rem;
|
||||
font-family: var(--midHeaderFont);
|
||||
&:not(input){
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
%h4{
|
||||
@extend %h4-style;
|
||||
*{
|
||||
@extend %h4-style;
|
||||
}
|
||||
}
|
||||
%h5-style{
|
||||
@extend %baseHeader;
|
||||
@extend %midHeader;
|
||||
font-size: 1rem;
|
||||
font-style:normal;
|
||||
font-family: var(--midHeaderFont);
|
||||
&:not(input){
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
%h5{
|
||||
@extend %h5-style;
|
||||
*{
|
||||
@extend %h5-style;
|
||||
}
|
||||
}
|
||||
%contents{
|
||||
display:contents;
|
||||
}
|
||||
%checked{
|
||||
background-color: var(--selectedColor);
|
||||
}
|
||||
%boxed{
|
||||
border: 1px solid black;
|
||||
border-radius:0;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
//- Default styles
|
||||
%defaultStyles{
|
||||
--grid-gap: 1rem;
|
||||
--half-gap: calc(var(--grid-gap) / 2);
|
||||
--tiny-gap: calc(var(--half-gap) / 2);
|
||||
--big-gap: calc(var(--grid-gap) * 2);
|
||||
--revealTime: 500ms;
|
||||
--delayTime: 200ms;
|
||||
--inputSwap: opacity var(--revealTime) ease var(--delayTime);
|
||||
--focusTiming: 500ms ease;
|
||||
--focusTrans: all var(--focusTiming);
|
||||
--borderColor: black;
|
||||
--fontColor: black;
|
||||
--backColor: #ffffff;
|
||||
--spanSectionColumn:1/-1;
|
||||
--displayBorderWidth: 2px;
|
||||
--subHeadBackColor:grey;
|
||||
--unselectedColor:lightgrey;
|
||||
--selectedColor:black;
|
||||
//Images
|
||||
--topCorner:url('https://s3.amazonaws.com/files.d20.io/images/258525471/MZYT-HjOvfJOqUXufyBkww/original.png');
|
||||
--bottomCorner:url('https://s3.amazonaws.com/files.d20.io/images/258525472/d7gSQyNdXW4tfBUa3osltQ/original.png');
|
||||
--headerBottom:url('https://s3.amazonaws.com/files.d20.io/images/258525865/9moWl3pE8miL8gqQC2UPRw/original.png');
|
||||
--footerTop:url('https://s3.amazonaws.com/files.d20.io/images/258525864/dzZKV6kH_fltY8yH9D-ptA/original.png');
|
||||
position: relative;
|
||||
gap: var(--grid-gap);
|
||||
button{
|
||||
cursor: pointer;
|
||||
}
|
||||
textarea{
|
||||
resize: vertical;
|
||||
min-height: 3.5rem;
|
||||
white-space: pre-wrap;
|
||||
&.fixed{
|
||||
resize: none;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
.span-2{
|
||||
grid-column:span 2;
|
||||
}
|
||||
.span-all{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
select,
|
||||
.pseudo-select span,
|
||||
textarea,
|
||||
input:not(:is([type='radio'],[type='checkbox'])),
|
||||
.uneditable-input{
|
||||
padding: 2px;
|
||||
font-size:1rem;
|
||||
}
|
||||
input:is([type="text"],[type="number"]),textarea{
|
||||
cursor:auto;
|
||||
}
|
||||
select,
|
||||
.pseudo-select span,
|
||||
input:not(:where([type='checkbox'], [type='radio'])),
|
||||
.uneditable-input,
|
||||
textarea{
|
||||
@extend %base-border;
|
||||
}
|
||||
select,
|
||||
.pseudo-select span{
|
||||
-webkit-apperance: none;
|
||||
appearance: none;
|
||||
text-transform: capitalize;
|
||||
overflow: hidden!important;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
input{
|
||||
width: auto;
|
||||
&:placeholder{
|
||||
color: #ededed80;
|
||||
}
|
||||
&.plus-control:not([value*="-"])+span:before{
|
||||
content: '+';
|
||||
}
|
||||
}
|
||||
span,
|
||||
input,
|
||||
textarea{
|
||||
font-size: 1rem;
|
||||
@extend %baseText;
|
||||
}
|
||||
span,input,textarea,button,select{
|
||||
font-family:var(--contentFont);
|
||||
--fontWght: 600;
|
||||
font-weight: var(--fontWght);
|
||||
font-variation-settings: "wght" var(--fontWght);
|
||||
}
|
||||
.hidden,
|
||||
*[hidden]{
|
||||
@extend %hidden;
|
||||
}
|
||||
.italics{
|
||||
@extend %italics;
|
||||
}
|
||||
h1,
|
||||
*[aria-level='1']{
|
||||
@extend %h1;
|
||||
}
|
||||
h2,
|
||||
*[aria-level='2']{
|
||||
@extend %h2;
|
||||
}
|
||||
h3,
|
||||
*[aria-level='3']{
|
||||
@extend %h3;
|
||||
}
|
||||
h4,
|
||||
*[aria-level='4']{
|
||||
@extend %h4;
|
||||
}
|
||||
h5,
|
||||
*[aria-level='5']{
|
||||
@extend %h5;
|
||||
}
|
||||
input{
|
||||
&[type='checkbox']{
|
||||
align-self: center;
|
||||
border: 1px solid black;
|
||||
cursor: pointer;
|
||||
&:checked{
|
||||
@extend %checked;
|
||||
}
|
||||
}
|
||||
&[type='radio']{
|
||||
appearance: radio;
|
||||
}
|
||||
&[type='number']{
|
||||
width: 3rem;
|
||||
-moz-appearance: textfield !important;
|
||||
text-align: center;
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button{
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.number{
|
||||
width:2rem;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
section{
|
||||
@extend %grid;
|
||||
gap:var(--half-gap);
|
||||
align-self:start;
|
||||
&.page{
|
||||
display: none;
|
||||
}
|
||||
&.inactive{
|
||||
display:none !important;
|
||||
}
|
||||
}
|
||||
.pictos{
|
||||
@extend %pictos;
|
||||
}
|
||||
.pictos3{
|
||||
@extend %pictos3;
|
||||
}
|
||||
.pictoscustom{
|
||||
@extend %pictosCustom;
|
||||
}
|
||||
.pseudo-button{
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
text-transform: uppercase;
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.input-label{
|
||||
display: inline-flex;
|
||||
gap: var(--half-gap);
|
||||
align-items:center;
|
||||
@extend %stackedGrid;
|
||||
&:not(.stacked){
|
||||
> [name]:not([type="number"],[type="checkbox"],[type='radio']){
|
||||
width:0;
|
||||
flex:1 1 0;
|
||||
}
|
||||
>:not([name]){
|
||||
flex:0 0 auto;
|
||||
}
|
||||
&.large > [name]{
|
||||
@extend h2;
|
||||
}
|
||||
}
|
||||
}
|
||||
.input-label--dual{
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-areas: 'over over over' 'under under under';
|
||||
>span:last-of-type{
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
>input{
|
||||
width: 100%;
|
||||
}
|
||||
>.slash{
|
||||
line-height: 0rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.headed-textarea{
|
||||
@extend %grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: auto;
|
||||
h5{
|
||||
justify-self: start;
|
||||
}
|
||||
}
|
||||
.contents,
|
||||
.sheet-contents{
|
||||
@extend %contents;
|
||||
}
|
||||
.boxed,
|
||||
.sheet-boxed{
|
||||
@extend %boxed;
|
||||
&.thick-left{
|
||||
border-left-width: 5px;
|
||||
}
|
||||
&.thick-bottom{
|
||||
border-bottom-width: 5px;
|
||||
}
|
||||
&.thick-right{
|
||||
border-right-width: 5px;
|
||||
}
|
||||
&.thick-top{
|
||||
border-top-width: 5px;
|
||||
}
|
||||
}
|
||||
.underlined,
|
||||
.sheet-underlined{
|
||||
border-radius: 0;
|
||||
border-bottom: 1px solid black;
|
||||
transition: var(--focusTrans);
|
||||
}
|
||||
:is(.underlined,.boxed){
|
||||
&:not([readonly]):is(:hover, :focus,:focus-within){
|
||||
@extend %inputHighlight;
|
||||
}
|
||||
&:not([readonly]):is(:focus,:focus-within){
|
||||
background-color: #DCDCDC;
|
||||
transition: var(--focusTrans);
|
||||
}
|
||||
}
|
||||
.ratio1-1{
|
||||
@extend %ratio1_1;
|
||||
}
|
||||
.small-scale-grid,
|
||||
fieldset.small-scale-grid+.repcontainer{
|
||||
@extend %grid;
|
||||
grid-template-columns: [header-start]repeat(auto-fit, minmax(15rem, 1fr))[header-end];
|
||||
grid-template-rows: [header-start]auto[header-end];
|
||||
gap: var(--half-gap);
|
||||
>.repitem{
|
||||
display: flex;
|
||||
gap: var(--half-gap);
|
||||
> :is(.dot-row,input[type='text']){
|
||||
flex: 1 1 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.repcontrol_move{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.short-text{
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-transform: initial;
|
||||
}
|
||||
.roll-container{
|
||||
@extend %grid;
|
||||
align-self:center;
|
||||
opacity:0;
|
||||
grid-row:1 / 2;
|
||||
}
|
||||
.repitem{
|
||||
> input:not([type='checkbox']){
|
||||
width:100%;
|
||||
}
|
||||
.headed-textarea{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
.collapse{
|
||||
opacity:0;
|
||||
position:absolute;
|
||||
right:-10px;
|
||||
top:0px;
|
||||
border:0px solid black;
|
||||
border-radius:0;
|
||||
color:var(--selectedColor);
|
||||
text-transform:none;
|
||||
&:before{
|
||||
content:'y';
|
||||
font-family:pictos;
|
||||
}
|
||||
&:checked{
|
||||
background-color:transparent;
|
||||
color:var(--unselectedColor);
|
||||
~ .expanded{
|
||||
display:none;
|
||||
}
|
||||
~ .expanded--empty:is(:not([value]),[value='']) + *{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
color:var(--selectedColor);
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
.collapse,.roll-container{
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.repcontainer.editmode{
|
||||
.collapse{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.repcontainer{
|
||||
display:grid;
|
||||
row-gap:var(--grid-gap);
|
||||
}
|
||||
.repeating-container{
|
||||
&:is(:hover,:focus-within,:focus) .repcontrol-button{
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
.repcontrol-button{
|
||||
@extend %text-button;
|
||||
grid-area:header;
|
||||
align-self:center;
|
||||
text-transform:none;
|
||||
opacity:0;
|
||||
transition:opacity var(--revealTime);
|
||||
~ .repcontrol{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.repcontrol-button--add{
|
||||
justify-self:start;
|
||||
&:before{
|
||||
font-family:pictos;
|
||||
content:'&';
|
||||
}
|
||||
}
|
||||
.repcontrol-button--edit{
|
||||
justify-self:end;
|
||||
&:before{
|
||||
font-family:pictos;
|
||||
content:'p';
|
||||
}
|
||||
}
|
||||
.box{
|
||||
border-radius:0;
|
||||
width:10px;
|
||||
height:10px;
|
||||
}
|
||||
}
|
||||
#main{
|
||||
.uppercase{
|
||||
@extend %uppercase;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
|
||||
//- Element shortcut mixins
|
||||
- const varObjects = {};
|
||||
mixin input(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
input&attributes(obj)
|
||||
//-End Mixin
|
||||
mixin text(obj)
|
||||
-obj.type = 'text';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin checkbox(obj)
|
||||
-obj.type = 'checkbox';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin radio(obj)
|
||||
-obj.type = 'radio';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin number(obj)
|
||||
-obj.type = 'number';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin range(obj)
|
||||
-obj.type = 'range';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin hidden(obj)
|
||||
-obj.type = 'hidden';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin radioGroup(objArray)
|
||||
each obj in objArray
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.type='radio';
|
||||
+input(obj)
|
||||
//-End Mixin
|
||||
mixin textarea(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
textarea&attributes(obj)
|
||||
//-End Mixin
|
||||
mixin option(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
option&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin select(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
select&attributes(obj)
|
||||
if block
|
||||
block
|
||||
else
|
||||
+option({value:'empty select, PEBKAC',selected:true})
|
||||
//-End Mixin
|
||||
mixin img(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj['data-i18n-alt'] = obj['data-i18n-alt'] || obj.name;
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
img&attributes(obj)
|
||||
//-End Mixin
|
||||
mixin span(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
if obj.name
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
span&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin datalist(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
datalist&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin div(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
if obj.name
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || attrTitle(obj.name);
|
||||
- obj.name = `attr_${obj.name}`;
|
||||
div&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h1(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h1&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h2(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h2&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h3(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h3&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h4(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h4&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h5(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h5&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin h6(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
h6&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin p(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
p&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin button(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.name = replaceSpaces(obj.name);
|
||||
- obj.title = obj.title || `%{${obj.name}}`;
|
||||
if obj.type === 'action'
|
||||
- obj.name = `act_${obj.name}`;
|
||||
else
|
||||
- obj.type = 'roll';
|
||||
- obj.name = `roll_${obj.name}`;
|
||||
button&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin action(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
- obj.type = 'action';
|
||||
- obj.name = obj.name.replace(/\s+/g,'-');
|
||||
+button(obj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin navButton(obj)
|
||||
-obj.name = `nav ${obj.name}`;
|
||||
+action(obj)
|
||||
block
|
||||
- let actionTitle = obj.title.replace(/(repeating_[^_]+_).+/,`$1:${actionName}`).replace(/%{|}|nav-/g,'');
|
||||
- addIfUnique(actionTitle,'navButtons');
|
||||
//- End Mixin
|
||||
mixin actionQuery(obj)
|
||||
-obj.class = obj.class ? `${obj.class} pseudo-select` : 'pseudo-select';
|
||||
+action(obj)
|
||||
block
|
||||
- let actionTitle = obj.title.replace(/(repeating_[^_]+).+/,`$1:${actionButtonName(obj.name)}`).replace(/%{|}/g,'');
|
||||
- addIfUnique(actionTitle,'queryButtons');
|
||||
//- End Mixin
|
||||
mixin rollerExtras(obj)
|
||||
- obj.class = obj.class ? `${replaceProblems(obj.class)} roller` : 'roller';
|
||||
- let attrName = replaceSpaces(actionInputName(obj.name));
|
||||
- let actionName = actionButtonName(obj.name);
|
||||
- obj.value = `@{${attrName}}`;
|
||||
!=`<!-- ${obj.name} | attrName:${attrName} | actionName:${actionName} -->`
|
||||
block
|
||||
!=`<!-- ${obj.name} post block | attrName:${attrName} | actionName:${actionName} -->`
|
||||
- let actionTitle = /repeating/.test(obj.title) ? obj.title.replace(/(repeating_[^_]+).+/,`$1:${actionName}`).replace(/%{|}/g,'') : actionName;
|
||||
- actionTitle = `${actionTitle.replace(/-action$/,'')}-action`;
|
||||
- let attrTitle = `${obj.title.replace(/(repeating_[^_]+_).+/,`$1\$x_${attrName}`).replace(/%{|}/g,'').replace(/_action$/,'')}_action`;
|
||||
!=`<!-- ${obj.name} | attrName:${attrName} | actionName:${actionName} | actionTitle:${actionTitle} | attrTitle:${attrTitle} -->`
|
||||
- addIfUnique(actionTitle,'rollMonitor');
|
||||
- addIfUnique(attrTitle,'actionAttributes');
|
||||
+action({name:actionName,hidden:''})
|
||||
+hidden({name:attrName})
|
||||
//- End Mixin
|
||||
mixin roller(obj)
|
||||
+rollerExtras(obj)
|
||||
+button(obj)
|
||||
block
|
||||
mixin section(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
section&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin main(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
main&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin header(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
header&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin footer(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
footer&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin details(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
details&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin summary(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
summary&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin label(obj)
|
||||
- obj.class = obj.class ? replaceProblems(obj.class) : undefined;
|
||||
label&attributes(obj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin repeating_section(name,header,columnArr,id)
|
||||
section(class=`repeating-container--${name} repeating-container section` id=`${(id||name).replace(/\s+/g,'-')}`)
|
||||
if header
|
||||
h2(data-i18n=header)
|
||||
if columnArr
|
||||
.repeat-columns
|
||||
each head in columnArr
|
||||
h5(data-i18n=head)
|
||||
+customControlFieldset(name)
|
||||
block
|
||||
mixin customControlFieldset(name)
|
||||
- addIfUnique(name.replace(/\s+/g,'-'),'repeatAddMonitors');
|
||||
+action({name:`add ${name}`,class:'repcontrol-button repcontrol-button--add'})
|
||||
+action({name:`edit ${name}`,class:'repcontrol-button repcontrol-button--edit'})
|
||||
+fieldset(name)
|
||||
block
|
||||
mixin fieldset(name)
|
||||
- name = name.replace(/\s+/g,'-');
|
||||
fieldset(class=`repeating_${name}`)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin pseudo-button(label,inputObj)
|
||||
- inputObj.class = inputObj.class ? replaceProblems(inputObj.class) : undefined;
|
||||
- hiddenObj = inputObj;
|
||||
- hiddenObj.type = 'hidden';
|
||||
+input(hiddenObj)
|
||||
label.pseudo-button
|
||||
-inputObj.class = inputObj.class ? `${inputObj.class} pseudo-button__input` : 'pseudo-button__input';
|
||||
span(data-i18n=label class='pseudo-button__span')
|
||||
+input(inputObj)
|
||||
//-End Mixin
|
||||
mixin button-label(inputObj,buttonObj,divObj)
|
||||
if divObj
|
||||
- divObj.class = divObj.class ? replaceProblems(divObj.class) : undefined;
|
||||
- inputObj.class = inputObj.class ? replaceProblems(inputObj.class) : undefined;
|
||||
- buttonObj.class = buttonObj.class ? replaceProblems(buttonObj.class) : undefined;
|
||||
- inputObj.name = inputObj.name.replace(/\s+/g,'_');
|
||||
- buttonObj.name = (buttonObj.name || inputObj.name).replace(/\s+/g,'_');
|
||||
.input-label.input-label--button&attributes(divObj)
|
||||
- inputObj.class = inputObj.class ? `${inputObj.class} input-label__input` : 'input-label__input';
|
||||
if spanObj
|
||||
- buttonObj.class = buttonObj.class ? `${buttonObj.class} input-label__text` : 'input-label__text';
|
||||
+button(buttonObj)
|
||||
+input(inputObj)
|
||||
//-End Mixin
|
||||
mixin roller-label(inputObj,buttonObj,divObj)
|
||||
+rollerExtras(buttonObj)
|
||||
+button-label(inputObj,buttonObj,divObj)
|
||||
//-End Mixin
|
||||
mixin action-label(inputObj,buttonObj,divObj)
|
||||
- buttonObj.type = 'action';
|
||||
+button-label(inputObj,buttonObj,divObj)
|
||||
//-End Mixin
|
||||
mixin select-label(label,inputObj,divObj,spanObj)
|
||||
if divObj
|
||||
- divObj.class = divObj.class ? replaceProblems(divObj.class) : undefined;
|
||||
if inputObj
|
||||
- inputObj.class = inputObj.class ? replaceProblems(inputObj.class) : undefined;
|
||||
if spanObj
|
||||
- spanObj.class = spanObj.class ? replaceProblems(spanObj.class) : undefined;
|
||||
label.input-label&attributes(divObj)
|
||||
- inputObj.name = inputObj.name.replace(/\s+/g,'_');
|
||||
- inputObj.class = inputObj.class ? `${inputObj.class} input-label__input` : 'input-label__input';
|
||||
if spanObj
|
||||
- spanObj.class = spanObj.class ? `${spanObj.class} input-label__text` : 'input-label__text';
|
||||
span(data-i18n=label)&attributes(spanObj)
|
||||
+select(inputObj)
|
||||
block
|
||||
//-End Mixin
|
||||
mixin input-label(label,inputObj,divObj,spanObj)
|
||||
if divObj
|
||||
- divObj.class = divObj.class ? replaceProblems(divObj.class) : undefined;
|
||||
if inputObj
|
||||
- inputObj.class = inputObj.class ? replaceProblems(inputObj.class) : undefined;
|
||||
if spanObj
|
||||
- spanObj.class = spanObj.class ? replaceProblems(spanObj.class) : undefined;
|
||||
label.input-label&attributes(divObj)
|
||||
- inputObj.name = inputObj.name.replace(/\s+/g,'_');
|
||||
- inputObj.class = inputObj.class ? `${inputObj.class} input-label__input` : 'input-label__input';
|
||||
if spanObj
|
||||
- spanObj.class = spanObj.class ? `${spanObj.class} input-label__text` : 'input-label__text';
|
||||
span(data-i18n=label)&attributes(spanObj)
|
||||
+input(inputObj)
|
||||
//-End Mixin
|
||||
mixin dual-input-label(label,inputArr,divObj,spanObj)
|
||||
if divObj
|
||||
- divObj.class = divObj.class ? replaceProblems(divObj.class) : undefined;
|
||||
if spanObj
|
||||
- spanObj.class = spanObj.class ? replaceProblems(spanObj.class) : undefined;
|
||||
.input-label.input-label--dual&attributes(divObj)
|
||||
span(data-i18n=label)&attributes(spanObj)
|
||||
each inputObj,i in inputArr
|
||||
if inputObj
|
||||
- inputObj.class = inputObj.class ? replaceProblems(inputObj.class) : undefined;
|
||||
- inputObj.name = inputObj.name.replace(/\s+/g,'_');
|
||||
+input(inputObj)
|
||||
if i<1
|
||||
span(class='slash h2')='/'
|
||||
//-End Mixin
|
||||
mixin headedTextarea(obj,header)
|
||||
.headed-textarea&attributes(attributes)
|
||||
- obj.class = obj.class ? `${obj.class} headed-textarea__textarea` : 'headed-textarea__textarea';
|
||||
+h3({'data-i18n':header,class:'headed-textarea__header'})
|
||||
+textarea(obj)
|
||||
//-End Mixin
|
||||
mixin script()
|
||||
script(type='text/worker')
|
||||
block
|
||||
//-End Mixin
|
||||
mixin pseudoEdit(name)
|
||||
+action({name:`edit-${name}`,class:'repcontrol-edit','data-i18n-title':`edit section`})
|
||||
//- End Mixin
|
||||
mixin pseudoAdd(name,content)
|
||||
- let obj = {name:`add-${name}`,class:'repcontrol-add','data-i18n-title':`create a ${name}`};
|
||||
if content
|
||||
- obj['data-i18n'] = content;
|
||||
+action(obj)
|
||||
//- End Mixin
|
||||
mixin pseudoControl(name)
|
||||
.pseudo-control
|
||||
+pseudoAdd(name)
|
||||
+pseudoEdit(name)
|
||||
//- End Mixin
|
||||
mixin pseudoCollapse(attrName,labelObj)
|
||||
+hidden({name:attrName,value:'0',class:'collapse-control'})
|
||||
-labelObj.class = labelObj.class ? `${labelObj.class} collapse-interface`:'collapse-interface';
|
||||
+label(labelObj)
|
||||
+checkbox({name:attrName,value:'1',hidden:''})
|
||||
//- End Mixin
|
||||
mixin expandHeader(obj)
|
||||
- obj.role='heading';
|
||||
- obj['aria-level'] = obj['aria-level'] || 2;
|
||||
- obj.class = obj.class ? `${obj.class} expandable-header ${obj.name}` : `${replaceSpaces(obj.name)} expandable-header`;
|
||||
- obj['data-i18n-title'] = obj['data-i18n-title'] || 'collapse/expand the section';
|
||||
+action(obj)
|
||||
if !obj['data-i18n']
|
||||
block
|
||||
//- End Mixin
|
||||
mixin subsectionContent(attribs)
|
||||
.display-target&attributes(attribs)
|
||||
if value!=='add-detail'
|
||||
- collapseTitle;
|
||||
if value==='master'
|
||||
-collapseTitle = 'collapse/expand section';
|
||||
else if /short/.test(value)
|
||||
- collapseTitle = 'expand subsection';
|
||||
else
|
||||
- collapseTitle = 'collapse subsection';
|
||||
+pseudoCollapse('collapse',{'data-i18n-title':collapseTitle})
|
||||
block
|
||||
mixin subsection(value)
|
||||
+radio({name:'display state',value,class:'display-control',hidden:''})
|
||||
+subsectionContent(attributes)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin complexSubsection(def)
|
||||
+hidden({name:'display state',value:def,class:'expanded-control'})
|
||||
+subsectionContent(attributes)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin adaptiveTextarea(textObj)
|
||||
.adaptive-text&attributes(attributes)
|
||||
- let spanObj = {name:textObj.name,class:'adaptive-text__span'};
|
||||
- textObj.class = textObj.class ? `${textObj.class} adaptive-text__textarea` : 'adaptive-text__textarea';
|
||||
+span(spanObj)
|
||||
+textarea(textObj)
|
||||
//- Functions
|
||||
- const attrTitle = (string,section) => section ? repeatAttrTitle(string,section) : `@{${replaceSpaces(string).replace(/_max$/,'|max')}}`;
|
||||
- const buttonTitle = (string,section) => section ? repeatButtonTitle(string,section) : `%{${replaceSpaces(string)}}`;
|
||||
- const replaceSpaces = (string) => string.replace(/\s+/g,'_');
|
||||
- const replaceProblems = (string) => string.replace(/[\(\)\[\]\|\/\\]/g,'-');
|
||||
- const repeatAttrTitle = (section,attr) => `@{repeating_${section}_$X_${replaceSpaces(attr).replace(/_max$/,'|max')}}`;
|
||||
- const repeatButtonTitle = (section,attr) => `%{repeating_${section}_$X_${replaceSpaces(attr||'roll')}}`;
|
||||
- const actionButtonName = (name) => `${name.replace(/act_/,'').replace(/_|\s+/g,'-').replace(/-action$/,'')}-action`;
|
||||
- const actionInputName = (name) => `${name}_action`;
|
||||
-
|
||||
const addIfUnique = (item,arrName) => {
|
||||
varObjects[arrName] = varObjects[arrName] || [];
|
||||
if(varObjects[arrName].indexOf(item) === -1){
|
||||
varObjects[arrName].push(item);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
//-Roll Template Mixins to be included in Sheet files
|
||||
mixin rolltemplate(name)
|
||||
rolltemplate(class=`sheet-rolltemplate-${name}`)
|
||||
div(class=`template ${name} system-{{system}}`)
|
||||
block
|
||||
div(class='image-border{{#header}} has-header{{/header}}{{#footer}} has-footer{{/footer}}')
|
||||
mixin multiPartTemplate(name)
|
||||
rolltemplate(class=`sheet-rolltemplate-${name}`)
|
||||
+templateHelperFunction({func:'rollTotal',invert:true,values:'computed::finished 0'})
|
||||
div(class=`template ${name} system-{{system}}{{#continuation}} continuation{{/continuation}}{{#first}} first{{/first}} finished`)
|
||||
block
|
||||
+templateHelperFunction({func:'rollBetween',values:'computed::finished 0 0'})
|
||||
div(class=`template ${name} system-{{system}}{{#continuation}} continuation{{/continuation}}{{#first}} first{{/first}}`)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin characterLink()
|
||||
+templateConditionalDisplay('footer')
|
||||
.footer
|
||||
.footer__background.background
|
||||
+templateConditionalDisplay('character_id')
|
||||
h4(tabindex='-1').character_name [{{footer}}](http://journal.roll20.net/character/{{character_id}})
|
||||
+templateConditionalDisplay('character_id',true)
|
||||
h4(tabindex='-1').character_name {{footer}}
|
||||
.footer__content
|
||||
+templateConditionalDisplay('character_id')
|
||||
h4.character_name [{{footer}}](http://journal.roll20.net/character/{{character_id}})
|
||||
+templateConditionalDisplay('character_id',true)
|
||||
h4.character_name {{footer}}
|
||||
.footer__image
|
||||
//-End mixin
|
||||
mixin templateBase(name)
|
||||
- name = name.replace(/\s+/g,'_');
|
||||
+rolltemplate(name)
|
||||
+characterLink()
|
||||
block
|
||||
//-End mixin
|
||||
mixin templateConditionalDisplay(fieldBool,invert)
|
||||
!=`{{${invert ? '^' : '#'}${fieldBool}}}`
|
||||
block
|
||||
!=`{{/${fieldBool}}}`
|
||||
//- End mixin
|
||||
mixin templateHelperFunction(helperObj)
|
||||
!=`{{${helperObj.invert ? '#^':'#'}${helperObj.func ? `${helperObj.func}() `:''}${helperObj.values ? `${helperObj.values}` : ''}}}`
|
||||
block
|
||||
!=`{{/${(helperObj.invert) ? '^' : ''}${helperObj.func ? `${helperObj.func}() `:''}${helperObj.values}}}`
|
||||
//- End Mixin
|
||||
mixin rollWasCrit(helperObj)
|
||||
- helperObj.func = 'rollWasCrit';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin rollWasFumble(helperObj)
|
||||
- helperObj.func = 'rollWasFumble';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin rollTotal(helperObj)
|
||||
- helperObj.func = 'rollTotal';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin rollGreater(helperObj)
|
||||
- helperObj.func = 'rollGreater';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin rollLess(helperObj)
|
||||
- helperObj.func = 'rollLess';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin rollBetween(helperObj)
|
||||
- helperObj.func = 'rollBetween';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin allProps(helperObj)
|
||||
- helperObj.func = 'allprops';
|
||||
+templateHelperFunction(helperObj)
|
||||
block
|
||||
//- End Mixin
|
||||
mixin templateField(name)
|
||||
!= `${tField(name)}`
|
||||
//- End Mixin
|
||||
- const tField = name => `{{${name}}}`;
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Roll Template
|
||||
#rolltemplate
|
||||
*/
|
||||
|
||||
.sheet-rolltemplate-storypath{
|
||||
--templateRadius: 1rem;
|
||||
--dieSize: 50px;
|
||||
--templateBorderW: 2px 5px 2px 5px;
|
||||
--fumbleColor: red;
|
||||
--critColor: green;
|
||||
--innerBorderRadius: 5px;
|
||||
--borderSize:1px;
|
||||
margin:{//ensures that the template fills the chat window
|
||||
left: -40px;
|
||||
right: -5px;
|
||||
}
|
||||
&:not(:first-child){//Moves the template to accomodate the sender tag
|
||||
margin-top:10px;
|
||||
}
|
||||
> .sheet-template{
|
||||
overflow:hidden;
|
||||
span{
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
.inlinerollresult{
|
||||
position: relative;
|
||||
&[title*="[computed value]"],
|
||||
&[original-title*="[computed value]"]{
|
||||
pointer-events: none;
|
||||
}
|
||||
&,
|
||||
&.fullcrit,
|
||||
&.fullfail,
|
||||
&.importantroll{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
&.fullcrit{
|
||||
color: green;
|
||||
}
|
||||
&.fullfail{
|
||||
color: red;
|
||||
}
|
||||
&.importantroll{
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
.sheet-header{
|
||||
padding: 5px;
|
||||
display:grid;
|
||||
grid-template-columns:1fr 2rem 1fr;
|
||||
gap:var(--half-gap);
|
||||
.sheet-character_name{
|
||||
grid-column:1/-1;
|
||||
place-self:center end;
|
||||
}
|
||||
.sheet-title{
|
||||
grid-column:1/-1;
|
||||
place-self:center;
|
||||
}
|
||||
}
|
||||
.sheet-template-row{
|
||||
padding: 5px;
|
||||
@extend %grid;
|
||||
grid-template-columns: minmax(6em, 1fr) repeat(auto-fit, minmax(1rem, 1fr));
|
||||
place-items: center;
|
||||
&:nth-child(odd){
|
||||
background-color: lightgrey;
|
||||
}
|
||||
>*:first-child{
|
||||
place-self: center start;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
@forward '_genericplaceholders.scss';
|
||||
@mixin activeTab{
|
||||
--tabBorder:drop-shadow(1px 0 0 black) drop-shadow(-1px 0 0 black) drop-shadow(0 -1px 0 black);
|
||||
top:1px;
|
||||
color:black;
|
||||
}
|
||||
.ui-dialog .tab-content .charsheet{
|
||||
*[data-i18n='xp']{
|
||||
text-transform:uppercase;
|
||||
}
|
||||
.stat-grid{
|
||||
gap:var(--half-gap) var(--tiny-gap);
|
||||
> :not(input):not(h2){
|
||||
place-self:center end;
|
||||
}
|
||||
}
|
||||
.boxed.span-2{
|
||||
@extend %grid;
|
||||
grid-auto-flow: column;
|
||||
place-content:center;
|
||||
width:6.5rem;
|
||||
}
|
||||
.roll-plus{
|
||||
justify-self: center;
|
||||
}
|
||||
.health-track{
|
||||
.repcontainer{
|
||||
@extend %grid;
|
||||
grid-template-columns:repeat(auto-fill,2rem);
|
||||
row-gap:var(--tiny-gap);
|
||||
&:hover{
|
||||
.health-track__clearer{
|
||||
background-image:linear-gradient(45deg, transparent 0% 48%, white 48% calc(48% + 1px), transparent calc(48% + 1px)), linear-gradient(-45deg, transparent 0% 48%, white 48% calc(48% + 1px), transparent calc(48% + 1px));
|
||||
}
|
||||
}
|
||||
> .repitem{
|
||||
@extend %grid;
|
||||
grid-template:{
|
||||
columns:2rem;
|
||||
rows:repeat(2,2rem);
|
||||
areas:
|
||||
'check'
|
||||
'penalty'
|
||||
;
|
||||
}
|
||||
&:first-child{
|
||||
.itemcontrol{
|
||||
display:none !important;
|
||||
}
|
||||
}
|
||||
.repcontrol_move{
|
||||
display:none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.repcontrol{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.health-track__max-control[value="1"] ~ .repcontrol .repcontrol_edit{
|
||||
display:none;
|
||||
}
|
||||
.health-track__number{
|
||||
&:is(:hover,:focus){
|
||||
border-radius:0;
|
||||
}
|
||||
}
|
||||
.health-track__checkbox{
|
||||
border-radius:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
box-sizing:border-box;
|
||||
grid-area:check;
|
||||
}
|
||||
.health-track__clear-control:not(:checked) ~ .health-track__clearer{
|
||||
display:none;
|
||||
}
|
||||
.health-track__fill-control{
|
||||
&:checked + *{
|
||||
@extend %checked;
|
||||
}
|
||||
}
|
||||
.health-track__clearer{
|
||||
grid-area:check;
|
||||
button{
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
%hex-base{
|
||||
@extend %grid;
|
||||
overflow:hidden;
|
||||
grid-template-areas:'content';
|
||||
}
|
||||
%hex-component{
|
||||
@extend %hex-base;
|
||||
width:100%;
|
||||
height:100%;
|
||||
grid-area:content;
|
||||
}
|
||||
%hex-rotate{
|
||||
@extend %hex-component;
|
||||
transform:rotate(-60deg);
|
||||
}
|
||||
%hex-shape{
|
||||
box-sizing:border-box;
|
||||
content:'';
|
||||
box-shadow:0 0 0 1px black inset, 0 0 4px #ffffff inset;
|
||||
}
|
||||
%article-layout{
|
||||
@extend %grid;
|
||||
gap:var(--big-gap);
|
||||
&.system-remnant{
|
||||
grid-template-columns:repeat(auto-fill,minmax(280px,1fr));
|
||||
}
|
||||
}
|
||||
%repeat-section-layout{
|
||||
@extend %grid;
|
||||
grid-template-areas:"header";
|
||||
gap:var(--half-gap);
|
||||
align-self:start;
|
||||
}
|
||||
// End Placeholders
|
||||
@@ -0,0 +1,930 @@
|
||||
{
|
||||
"version": "7",
|
||||
"about": "This is a Prepros (https://prepros.io) configuration file. You can commit this file to a git repo to backup and sync project configurations.",
|
||||
"config": {
|
||||
"proxy": {
|
||||
"enable": false,
|
||||
"target": "",
|
||||
"useLocalAssets": false
|
||||
},
|
||||
"reload": {
|
||||
"enable": true,
|
||||
"delay": 0,
|
||||
"animate": true,
|
||||
"afterUpload": false
|
||||
},
|
||||
"sync": {
|
||||
"enable": false,
|
||||
"mouse": true,
|
||||
"keyboard": true,
|
||||
"form": true,
|
||||
"scroll": true
|
||||
},
|
||||
"watcher": {
|
||||
"enable": true,
|
||||
"maxFiles": 2000,
|
||||
"usePolling": false,
|
||||
"pollingInterval": 500,
|
||||
"extensions": [
|
||||
".html",
|
||||
".htm",
|
||||
".php"
|
||||
],
|
||||
"ignore": {
|
||||
"patterns": [
|
||||
".*",
|
||||
"wp-admin",
|
||||
"wp-includes",
|
||||
"node_modules",
|
||||
"Prepros Export",
|
||||
"bower_components"
|
||||
],
|
||||
"exceptions": []
|
||||
}
|
||||
},
|
||||
"exporter": {
|
||||
"ignore": {
|
||||
"patterns": [
|
||||
".*",
|
||||
"desktop.ini",
|
||||
"prepros.cfg",
|
||||
"node_modules",
|
||||
"Prepros Export",
|
||||
"prepros.config",
|
||||
"prepros-6.config",
|
||||
"*-original.jpg",
|
||||
"*-original.jpeg",
|
||||
"*-original.png",
|
||||
"*-original.svg",
|
||||
"*.scss",
|
||||
"*.sass",
|
||||
"*.less",
|
||||
"*.pug",
|
||||
"*.jade",
|
||||
"*.styl",
|
||||
"*.haml",
|
||||
"*.slim",
|
||||
"*.coffee",
|
||||
"*.kit",
|
||||
"*.turf",
|
||||
"*.ts"
|
||||
],
|
||||
"exceptions": []
|
||||
}
|
||||
},
|
||||
"uploader": {
|
||||
"remotePath": "",
|
||||
"timeout": 20000,
|
||||
"autoUpload": false,
|
||||
"reuseConnection": true,
|
||||
"connectionType": "ftp",
|
||||
"history": []
|
||||
},
|
||||
"packages": {
|
||||
"createPackageLock": true
|
||||
},
|
||||
"images": {
|
||||
"preserveOriginal": true
|
||||
},
|
||||
"tasks": {
|
||||
"autoprefixer": {
|
||||
"cascade": true,
|
||||
"add": true,
|
||||
"remove": true,
|
||||
"supports": true,
|
||||
"flexbox": true,
|
||||
"grid": "autoplace",
|
||||
"browsers": [
|
||||
"last 2 versions"
|
||||
],
|
||||
"sourceMap": false
|
||||
},
|
||||
"babel": {
|
||||
"sourceMap": false,
|
||||
"presets": {
|
||||
"@babel/preset-env": {
|
||||
"enable": true,
|
||||
"options": {
|
||||
"targets": [
|
||||
"last 2 versions"
|
||||
],
|
||||
"preserveImports": false,
|
||||
"polyfills": false
|
||||
}
|
||||
},
|
||||
"@babel/preset-react": true,
|
||||
"@babel/preset-flow": false
|
||||
},
|
||||
"plugins": {
|
||||
"@babel/plugin-proposal-class-static-block": false,
|
||||
"@babel/plugin-proposal-class-properties": false,
|
||||
"@babel/plugin-proposal-decorators": {
|
||||
"enable": false,
|
||||
"options": {
|
||||
"decoratorsBeforeExport": true
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-export-namespace-from": false,
|
||||
"@babel/plugin-proposal-function-sent": false,
|
||||
"@babel/plugin-proposal-logical-assignment-operators": false,
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": false,
|
||||
"@babel/plugin-proposal-numeric-separator": false,
|
||||
"@babel/plugin-proposal-optional-chaining": false,
|
||||
"@babel/plugin-proposal-private-methods": false,
|
||||
"@babel/plugin-proposal-throw-expressions": false
|
||||
},
|
||||
"customPresets": [],
|
||||
"customPlugins": []
|
||||
},
|
||||
"bundle-js": {
|
||||
"sourceMap": false,
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"bower_components"
|
||||
],
|
||||
"devMode": true,
|
||||
"globals": [],
|
||||
"externals": [],
|
||||
"babel": {
|
||||
"enable": true,
|
||||
"options": {
|
||||
"sourceMap": false,
|
||||
"presets": {
|
||||
"@babel/preset-env": {
|
||||
"enable": true,
|
||||
"options": {
|
||||
"targets": [
|
||||
"last 2 versions"
|
||||
],
|
||||
"preserveImports": false,
|
||||
"polyfills": false
|
||||
}
|
||||
},
|
||||
"@babel/preset-react": true,
|
||||
"@babel/preset-flow": false
|
||||
},
|
||||
"plugins": {
|
||||
"@babel/plugin-proposal-class-static-block": false,
|
||||
"@babel/plugin-proposal-class-properties": false,
|
||||
"@babel/plugin-proposal-decorators": {
|
||||
"enable": false,
|
||||
"options": {
|
||||
"decoratorsBeforeExport": true
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-export-namespace-from": false,
|
||||
"@babel/plugin-proposal-function-sent": false,
|
||||
"@babel/plugin-proposal-logical-assignment-operators": false,
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": false,
|
||||
"@babel/plugin-proposal-numeric-separator": false,
|
||||
"@babel/plugin-proposal-optional-chaining": false,
|
||||
"@babel/plugin-proposal-private-methods": false,
|
||||
"@babel/plugin-proposal-throw-expressions": false
|
||||
},
|
||||
"customPresets": [],
|
||||
"customPlugins": []
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"enable": true
|
||||
},
|
||||
"fonts": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"coffeescript": {
|
||||
"header": false,
|
||||
"bare": false,
|
||||
"sourceMap": false
|
||||
},
|
||||
"command": {
|
||||
"command": "",
|
||||
"rootDir": ""
|
||||
},
|
||||
"concat-js": {
|
||||
"sourceMap": false,
|
||||
"rootDir": ""
|
||||
},
|
||||
"copy": {
|
||||
"sourceMap": false
|
||||
},
|
||||
"dart-sass": {
|
||||
"indentType": "space",
|
||||
"allowWildcardImports": false,
|
||||
"indentWidth": 2,
|
||||
"linefeed": "lf",
|
||||
"sourceMap": false
|
||||
},
|
||||
"haml": {
|
||||
"doubleQuoteAttributes": true
|
||||
},
|
||||
"jpg": {
|
||||
"quality": 90
|
||||
},
|
||||
"less": {
|
||||
"javascriptEnabled": false,
|
||||
"strictImports": false,
|
||||
"insecure": false,
|
||||
"math": "always",
|
||||
"strictUnits": false,
|
||||
"dumpLineNumbers": false,
|
||||
"sourceMap": false
|
||||
},
|
||||
"markdown": {
|
||||
"githubFlavored": true,
|
||||
"wrapWithHtml": false
|
||||
},
|
||||
"minify-css": {
|
||||
"sourceMap": false
|
||||
},
|
||||
"minify-html": {
|
||||
"caseSensitive": false,
|
||||
"collapseBooleanAttributes": true,
|
||||
"collapseInlineTagWhitespace": false,
|
||||
"collapseWhitespace": true,
|
||||
"conservativeCollapse": false,
|
||||
"decodeEntities": false,
|
||||
"html5": true,
|
||||
"includeAutoGeneratedTags": true,
|
||||
"keepClosingSlash": false,
|
||||
"minifyCSS": true,
|
||||
"minifyJS": true,
|
||||
"preserveLineBreaks": false,
|
||||
"preventAttributesEscaping": false,
|
||||
"processConditionalComments": false,
|
||||
"removeAttributeQuotes": false,
|
||||
"removeComments": true,
|
||||
"removeEmptyAttributes": false,
|
||||
"removeEmptyElement": false,
|
||||
"removeOptionalTags": false,
|
||||
"removeRedundantAttributes": false,
|
||||
"removeScriptTypeAttributes": false,
|
||||
"removeStyleLinkTypeAttributes": false,
|
||||
"removeTagWhitespace": false,
|
||||
"sortAttributes": false,
|
||||
"sortClassName": false,
|
||||
"useShortDoctype": true
|
||||
},
|
||||
"minify-js": {
|
||||
"parse": {
|
||||
"bare_returns": false
|
||||
},
|
||||
"compress": {
|
||||
"arrows": true,
|
||||
"arguments": false,
|
||||
"booleans": true,
|
||||
"booleans_as_integers": false,
|
||||
"collapse_vars": true,
|
||||
"comparisons": true,
|
||||
"computed_props": true,
|
||||
"conditionals": true,
|
||||
"dead_code": true,
|
||||
"directives": true,
|
||||
"drop_console": false,
|
||||
"drop_debugger": true,
|
||||
"evaluate": true,
|
||||
"expression": false,
|
||||
"global_defs": [],
|
||||
"hoist_funs": false,
|
||||
"hoist_props": true,
|
||||
"hoist_vars": false,
|
||||
"if_return": true,
|
||||
"inline": 3,
|
||||
"join_vars": true,
|
||||
"keep_fargs": true,
|
||||
"keep_infinity": false,
|
||||
"loops": true,
|
||||
"negate_iife": true,
|
||||
"properties": true,
|
||||
"pure_funcs": [],
|
||||
"pure_getters": false,
|
||||
"reduce_funcs": true,
|
||||
"reduce_vars": true,
|
||||
"sequences": true,
|
||||
"side_effects": true,
|
||||
"switches": true,
|
||||
"top_retain": [],
|
||||
"typeofs": true,
|
||||
"unsafe": false,
|
||||
"unsafe_arrows": false,
|
||||
"unsafe_comps": false,
|
||||
"unsafe_Function": false,
|
||||
"unsafe_math": false,
|
||||
"unsafe_proto": false,
|
||||
"unsafe_regexp": false,
|
||||
"unsafe_undefined": false,
|
||||
"unused": true
|
||||
},
|
||||
"mangle": {
|
||||
"eval": false,
|
||||
"reserved": []
|
||||
},
|
||||
"output": {
|
||||
"ascii_only": false,
|
||||
"braces": false,
|
||||
"comments": "none",
|
||||
"inline_script": true,
|
||||
"keep_numbers": false,
|
||||
"keep_quoted_props": false,
|
||||
"preamble": null,
|
||||
"quote_keys": false,
|
||||
"quote_style": 0,
|
||||
"semicolons": true,
|
||||
"shebang": true,
|
||||
"webkit": false,
|
||||
"wrap_iife": false,
|
||||
"wrap_func_args": true
|
||||
},
|
||||
"sourceMap": false,
|
||||
"toplevel": false,
|
||||
"ie8": false,
|
||||
"keep_classnames": false,
|
||||
"keep_fnames": false,
|
||||
"safari10": false
|
||||
},
|
||||
"node-sass": {
|
||||
"indentType": "space",
|
||||
"allowWildcardImports": false,
|
||||
"indentWidth": 2,
|
||||
"linefeed": "lf",
|
||||
"outputStyle": "expanded",
|
||||
"precision": 10,
|
||||
"sourceMap": false,
|
||||
"sourceComments": false
|
||||
},
|
||||
"png": {
|
||||
"quality": 90
|
||||
},
|
||||
"postcss-import": {
|
||||
"ignoreKeywords": [],
|
||||
"sourceMap": false
|
||||
},
|
||||
"postcss-preset-env": {
|
||||
"stage": 2,
|
||||
"browsers": [
|
||||
"last 2 versions"
|
||||
],
|
||||
"sourceMap": false
|
||||
},
|
||||
"pug": {
|
||||
"pretty": true
|
||||
},
|
||||
"slim": {
|
||||
"indent": "space",
|
||||
"indentSize": 2,
|
||||
"pretty": true
|
||||
},
|
||||
"stylus": {
|
||||
"useNib": true,
|
||||
"sourceMap": false,
|
||||
"linenos": false
|
||||
},
|
||||
"svg": {
|
||||
"cleanupAttrs": true,
|
||||
"removeDoctype": true,
|
||||
"removeXMLProcInst": true,
|
||||
"removeComments": true,
|
||||
"removeMetadata": true,
|
||||
"removeTitle": true,
|
||||
"removeDesc": true,
|
||||
"removeUselessDefs": true,
|
||||
"removeEditorsNSData": true,
|
||||
"removeEmptyAttrs": true,
|
||||
"removeHiddenElems": true,
|
||||
"removeEmptyText": true,
|
||||
"removeEmptyContainers": true,
|
||||
"removeViewBox": false,
|
||||
"cleanupEnableBackground": true,
|
||||
"convertStyleToAttrs": true,
|
||||
"convertColors": true,
|
||||
"convertPathData": true,
|
||||
"convertTransform": true,
|
||||
"removeUnknownsAndDefaults": true,
|
||||
"removeNonInheritableGroupAttrs": true,
|
||||
"removeUselessStrokeAndFill": true,
|
||||
"removeUnusedNS": true,
|
||||
"cleanupIDs": true,
|
||||
"cleanupNumericValues": true,
|
||||
"moveElemsAttrsToGroup": true,
|
||||
"moveGroupAttrsToElems": true,
|
||||
"collapseGroups": true,
|
||||
"removeRasterImages": false,
|
||||
"mergePaths": true,
|
||||
"convertShapeToPath": true,
|
||||
"sortAttrs": true,
|
||||
"removeDimensions": true
|
||||
},
|
||||
"turf": {
|
||||
"rootDir": ""
|
||||
},
|
||||
"typescript": {
|
||||
"allowJs": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowUmdGlobalAccess": false,
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"alwaysStrict": false,
|
||||
"charset": "utf8",
|
||||
"checkJs": false,
|
||||
"declaration": false,
|
||||
"disableSizeLimit": false,
|
||||
"downlevelIteration": false,
|
||||
"emitBOM": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"importHelpers": false,
|
||||
"jsx": "React",
|
||||
"keyofStringsOnly": false,
|
||||
"lib": [],
|
||||
"maxNodeModuleJsDepth": 0,
|
||||
"module": "ES2015",
|
||||
"moduleResolution": "NodeJs",
|
||||
"newLine": "LineFeed",
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": false,
|
||||
"noImplicitThis": false,
|
||||
"noStrictGenericChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitUseStrict": false,
|
||||
"noLib": false,
|
||||
"noResolve": false,
|
||||
"preserveConstEnums": false,
|
||||
"jsxFactory": "React.createElement",
|
||||
"removeComments": false,
|
||||
"skipLibCheck": false,
|
||||
"sourceMap": false,
|
||||
"strict": false,
|
||||
"strictFunctionTypes": false,
|
||||
"strictBindCallApply": false,
|
||||
"strictNullChecks": false,
|
||||
"strictPropertyInitialization": false,
|
||||
"suppressExcessPropertyErrors": false,
|
||||
"suppressImplicitAnyIndexErrors": false,
|
||||
"target": "ES3",
|
||||
"resolveJsonModule": false,
|
||||
"esModuleInterop": false,
|
||||
"useDefineForClassFields": false
|
||||
}
|
||||
},
|
||||
"fileTypes": {
|
||||
"sass": {
|
||||
"extensions": [
|
||||
".scss",
|
||||
".sass"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "dart-sass",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "autoprefixer",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "minify-css",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".css",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "scss",
|
||||
"replaceWith": "css"
|
||||
},
|
||||
{
|
||||
"segment": "sass",
|
||||
"replaceWith": "css"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"less": {
|
||||
"extensions": [
|
||||
".less"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "less",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "autoprefixer",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-css",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".css",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "less",
|
||||
"replaceWith": "css"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"pug": {
|
||||
"extensions": [
|
||||
".pug",
|
||||
".jade"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "pug",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-html",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".html",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "pug",
|
||||
"replaceWith": "html"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"extensions": [
|
||||
".css"
|
||||
],
|
||||
"autoCompile": false,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "copy",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "postcss-import",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "postcss-preset-env",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "autoprefixer",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "minify-css",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".css",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"relativePath": "",
|
||||
"suffix": "-dist",
|
||||
"alwaysSuffix": false
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"extensions": [
|
||||
".js",
|
||||
".jsx"
|
||||
],
|
||||
"autoCompile": false,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "copy",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "concat-js",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "babel",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "bundle-js",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "minify-js",
|
||||
"enable": true
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".js",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"relativePath": "",
|
||||
"suffix": "-dist",
|
||||
"alwaysSuffix": false
|
||||
}
|
||||
},
|
||||
"stylus": {
|
||||
"extensions": [
|
||||
".styl"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "stylus",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "autoprefixer",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-css",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".css",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "stylus",
|
||||
"replaceWith": "css"
|
||||
},
|
||||
{
|
||||
"segment": "styl",
|
||||
"replaceWith": "css"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"extensions": [
|
||||
".md",
|
||||
".markdown",
|
||||
".mkd"
|
||||
],
|
||||
"autoCompile": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "markdown",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-html",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".html",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "markdown",
|
||||
"replaceWith": "html"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"haml": {
|
||||
"extensions": [
|
||||
".haml"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "haml",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-html",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".html",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "haml",
|
||||
"replaceWith": "html"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"slim": {
|
||||
"extensions": [
|
||||
".slim"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "slim",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-html",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".html",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "slim",
|
||||
"replaceWith": "html"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"coffeescript": {
|
||||
"extensions": [
|
||||
".coffee"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "coffeescript",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "babel",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "bundle-js",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "minify-js",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".js",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "coffee-script",
|
||||
"replaceWith": "js"
|
||||
},
|
||||
{
|
||||
"segment": "coffeescript",
|
||||
"replaceWith": "js"
|
||||
},
|
||||
{
|
||||
"segment": "coffee",
|
||||
"replaceWith": "js"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"turf": {
|
||||
"extensions": [
|
||||
".turf",
|
||||
".kit"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "turf",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "minify-html",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".html",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "turf",
|
||||
"replaceWith": "html"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"extensions": [
|
||||
".ts",
|
||||
".tsx"
|
||||
],
|
||||
"autoCompile": true,
|
||||
"sourceMap": false,
|
||||
"tasks": [
|
||||
{
|
||||
"task": "typescript",
|
||||
"enable": true
|
||||
},
|
||||
{
|
||||
"task": "babel",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "bundle-js",
|
||||
"enable": false
|
||||
},
|
||||
{
|
||||
"task": "minify-js",
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".js",
|
||||
"type": "REPLACE_SEGMENTS",
|
||||
"segments": [
|
||||
{
|
||||
"segment": "typescript",
|
||||
"replaceWith": "js"
|
||||
},
|
||||
{
|
||||
"segment": "ts",
|
||||
"replaceWith": "js"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"jpg": {
|
||||
"extensions": [
|
||||
".jpg",
|
||||
".jpeg"
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"task": "jpg",
|
||||
"enable": true
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".jpg",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"relativePath": ""
|
||||
}
|
||||
},
|
||||
"png": {
|
||||
"extensions": [
|
||||
".png"
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"task": "png",
|
||||
"enable": true
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".png",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"relativePath": ""
|
||||
}
|
||||
},
|
||||
"svg": {
|
||||
"extensions": [
|
||||
".svg"
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"task": "svg",
|
||||
"enable": true
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"extension": ".svg",
|
||||
"type": "SOURCE_RELATIVE",
|
||||
"relativePath": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"file": "style.scss",
|
||||
"config": {
|
||||
"customOutput": "style.css"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "system.pug",
|
||||
"config": {
|
||||
"customOutput": "system.html"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 362 KiB |
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"html": "system.html",
|
||||
"css": "style.css",
|
||||
"authors": "Scott Casey",
|
||||
"roll20userid": "459831",
|
||||
"preview": "rapidfire_preview.jpg",
|
||||
"instructions": "This sheet is compatible with all Rapidfire system games by [Outrider Studios](https://outriderstudios.com/). Check out the [Rapidfire System sheet guide](https://wiki.roll20.net/Rapidfire_System) for full details on how to use the sheet and all the features included in it.",
|
||||
"legacy": false
|
||||
}
|
||||
@@ -0,0 +1,902 @@
|
||||
@use 'Mixins/_systemplaceholders.scss';
|
||||
|
||||
//Sets the font-size to be used by rem unit calls
|
||||
html{
|
||||
font-size: 13px;
|
||||
}
|
||||
//Sets the bio/charsheet/a&a tab container to be sticky and float at the top
|
||||
ul.nav-tabs.nav{
|
||||
position:sticky;
|
||||
top:0;
|
||||
background-color:white;
|
||||
z-index:9999;
|
||||
margin-bottom:0px;
|
||||
}
|
||||
.nav-tabs li a{
|
||||
font-family:var(--midHeaderFont);
|
||||
padding:{
|
||||
top: 18px;
|
||||
bottom:15px;
|
||||
};
|
||||
&[data-tab='charsheet']{
|
||||
background-image: url(https://s3.amazonaws.com/files.d20.io/images/259063058/V4Hm27FqfgBujU8bI74Xaw/original.png);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
padding:{
|
||||
left:50px;
|
||||
right:12px;
|
||||
};
|
||||
}
|
||||
}
|
||||
.itemcontrol{
|
||||
z-index:10;
|
||||
}
|
||||
.image-input{
|
||||
cursor:pointer;
|
||||
}
|
||||
//Default settings for the .charsheet container
|
||||
.ui-dialog .tab-content .charsheet{
|
||||
padding-top:0px;
|
||||
@extend %defaultStyles;
|
||||
.adaptive-text{
|
||||
@extend %adaptiveText;
|
||||
}
|
||||
.repeat-columns{
|
||||
@extend %grid;
|
||||
> *{
|
||||
background-color:var(--subHeadBackColor);
|
||||
border:1px solid black;
|
||||
}
|
||||
}
|
||||
.image-container{
|
||||
@extend %grid;
|
||||
grid-template-columns:"content";
|
||||
}
|
||||
.image-container__input{
|
||||
z-index:10;
|
||||
background-color:white;
|
||||
box-shadow:0 0 var(--grid-gap) var(--grid-gap) white;
|
||||
grid-area:content;
|
||||
place-self:center;
|
||||
width:calc(100% - (var(--big-gap) * 2));
|
||||
transition:opacity var(--focusTiming),height var(--focusTiming);
|
||||
opacity:0;
|
||||
height:0;
|
||||
overflow:hidden;
|
||||
span{
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
input{
|
||||
width:100%;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
&.active{
|
||||
opacity:1;
|
||||
height:auto;
|
||||
}
|
||||
}
|
||||
.image-container__button{
|
||||
grid-area:content;
|
||||
}
|
||||
.base-container{
|
||||
@extend %grid;
|
||||
grid-template-areas:'content';
|
||||
}
|
||||
.base-container__actual{
|
||||
grid-area:content;
|
||||
}
|
||||
.base-container__interact{
|
||||
grid-area:content;
|
||||
z-index:1;
|
||||
}
|
||||
}
|
||||
#main-nav{
|
||||
--tabColor:white;
|
||||
--tabBorder:drop-shadow(1px 0 0 grey) drop-shadow(-1px 0 0 grey) drop-shadow(0 -1px 0 grey) drop-shadow(0 1px 0 black);
|
||||
display:grid;
|
||||
gap:var(--half-gap);
|
||||
grid-template-columns:1fr auto 1fr;
|
||||
align-items:center;
|
||||
position:sticky;
|
||||
top:60px;
|
||||
background:white;
|
||||
box-shadow:-10px 0 0 0 white,10px 0 0 0 white,0 -6px white;
|
||||
z-index:100;
|
||||
border-bottom:1px solid black;
|
||||
.nav__button{
|
||||
font-style:normal;
|
||||
color:grey;
|
||||
}
|
||||
.nav__button--settings{
|
||||
@extend %pictos;
|
||||
&.active,
|
||||
&:hover{
|
||||
color:black;
|
||||
}
|
||||
}
|
||||
&.system-remnant{
|
||||
.nav__button--tab {
|
||||
background-color: var(--tabColor);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
z-index: 2;
|
||||
padding:calc(var(--half-gap) + 0.1rem);
|
||||
filter:var(--tabBorder);
|
||||
&.active,
|
||||
&:hover{
|
||||
@include systemplaceholders.activeTab;
|
||||
}
|
||||
&.active{
|
||||
pointer-events: none;
|
||||
}
|
||||
&:before{
|
||||
height: calc(100% - 1px);
|
||||
width: 50px;
|
||||
background-color: var(--tabColor);
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
.nav__button--tab--left{
|
||||
border-radius:0 50% 0 0;
|
||||
margin-left:1px;
|
||||
justify-self:start;
|
||||
&:before{
|
||||
border-radius: 0 2px 0 0;
|
||||
left: calc(100% - 40px);
|
||||
top: 0px;
|
||||
-webkit-transform: skewX(45deg);
|
||||
transform: skewX(45deg);
|
||||
}
|
||||
}
|
||||
.nav__button--tab--right{
|
||||
border-radius:50% 0 0 0;
|
||||
margin-right:1px;
|
||||
justify-self:end;
|
||||
&:before{
|
||||
border-radius: 2px 0 0 0;
|
||||
left: -5px;
|
||||
top: 0px;
|
||||
-webkit-transform: skewX(-45deg);
|
||||
transform: skewX(-45deg);
|
||||
}
|
||||
}/*
|
||||
.tab:nth-of-type(2) {
|
||||
background-color: #555;
|
||||
top: 10px;
|
||||
left: 30px;
|
||||
z-index: 1;
|
||||
color: #EEE;
|
||||
}
|
||||
.tab:nth-of-type(2):before {
|
||||
background-color: #555;
|
||||
}
|
||||
.tab:nth-of-type(2):hover,
|
||||
.tab:nth-of-type(2):hover:before {
|
||||
background-color: #159;
|
||||
transition: 0.3s ease-out;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
#main{
|
||||
.system-header{
|
||||
margin:0 auto;
|
||||
width:200px;
|
||||
}
|
||||
article{
|
||||
padding:var(--grid-gap);
|
||||
}
|
||||
article:not(.active){
|
||||
display:none;
|
||||
}
|
||||
.roller{
|
||||
@extend %roller;
|
||||
}
|
||||
.translate-control{
|
||||
&:checked ~ .untranslated,
|
||||
&:not(:checked) ~ .translated{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.section{
|
||||
transition:box-shadow var(--focusTiming),transform;
|
||||
border-radius:6px;
|
||||
padding:var(--half-gap);
|
||||
&:hover{
|
||||
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Settings Styling
|
||||
#settings{
|
||||
@extend %article-layout;
|
||||
.input-label{
|
||||
justify-content: space-between;
|
||||
[name]:not([type=number], [type=checkbox], [type=radio]){
|
||||
width:auto;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
section{
|
||||
align-self:stretch;
|
||||
align-content:start;
|
||||
}
|
||||
}
|
||||
// Character styling
|
||||
#character{
|
||||
@extend %article-layout;
|
||||
&.system-remnant{
|
||||
grid-template-areas:
|
||||
"."
|
||||
"skills"
|
||||
"skills"
|
||||
;
|
||||
border:{
|
||||
left:1px solid black;
|
||||
}
|
||||
grid-template-rows:repeat(2,auto) 1fr;
|
||||
}
|
||||
}
|
||||
#character-info{
|
||||
@extend %repeat-section-layout;
|
||||
> .health-track{
|
||||
margin:0 -5px;
|
||||
}
|
||||
}
|
||||
#stats{
|
||||
grid-template-columns: auto 1fr repeat(2,auto);
|
||||
grid-template-areas:
|
||||
'header header header header'
|
||||
'stat_points . . .'
|
||||
'reserve . . .'
|
||||
'. . . .'
|
||||
'header2 header2 header2 header2'
|
||||
;
|
||||
h2{
|
||||
grid-area:auto;
|
||||
grid-column:1/-1;
|
||||
}
|
||||
> button{
|
||||
grid-column:2;
|
||||
}
|
||||
@each $point in stat_points,reserve{
|
||||
> .#{$point}{
|
||||
grid-area:$point;
|
||||
justify-self:end;
|
||||
}
|
||||
}
|
||||
> .reserve{
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.equipment{
|
||||
@extend %grid;
|
||||
grid-template-areas: 'header';
|
||||
gap:var(--half-gap);
|
||||
grid-column:1/-1;
|
||||
place-self:stretch;
|
||||
h2{
|
||||
grid-area:header;
|
||||
}
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
}
|
||||
.repeat-columns,
|
||||
.repitem{
|
||||
grid-template-columns: 1fr 2.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
#secondary{
|
||||
> .secondaries{
|
||||
@extend %grid;
|
||||
grid-template-columns:1fr repeat(3,auto);
|
||||
grid-template-areas:'header header header header';
|
||||
}
|
||||
> .combat-gear{
|
||||
@extend %grid;
|
||||
grid-template-areas:'header';
|
||||
}
|
||||
}
|
||||
#skill{
|
||||
@extend %repeat-section-layout;
|
||||
grid-area:skills;
|
||||
.repcontainer{
|
||||
gap:0;
|
||||
}
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
position:relative;
|
||||
span{
|
||||
align-self:center;
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
.repeat-columns,
|
||||
.repitem{
|
||||
grid-template-columns:1rem 1fr 3rem 4rem 2.5rem;
|
||||
> input{
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
.repeat-columns{
|
||||
@each $num in 1,2,3,4{
|
||||
:nth-child(#{$num}){
|
||||
grid-column:$num + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.raw-control:not(:checked) + .raw,
|
||||
.raw-control:checked ~ .custom{
|
||||
display:none;
|
||||
}
|
||||
.roller.raw{
|
||||
grid-column:span 2;
|
||||
}
|
||||
}
|
||||
@media (min-width:680px) {
|
||||
#weapon,#remnant-weapons{
|
||||
grid-column:span 2;
|
||||
}
|
||||
}
|
||||
@media(min-width:1300px){
|
||||
#main{
|
||||
display:grid;
|
||||
grid-template-columns:1fr 1fr;
|
||||
column-gap:var(--big-gap);
|
||||
.system-header{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
.sheet-state:not([value='settings']){
|
||||
~ article:not(#settings){
|
||||
display:grid;
|
||||
align-self:start;
|
||||
}
|
||||
~ #main-nav{
|
||||
.nav__button--tab{
|
||||
@include systemplaceholders.activeTab;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#settings{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
#main-nav{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
}
|
||||
#weapon{
|
||||
@extend %repeat-section-layout;
|
||||
input[type='text']{
|
||||
width:100%;
|
||||
}
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
row-gap:var(--half-gap);
|
||||
> .underlined{
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
span.underlined{
|
||||
display:block;
|
||||
text-align:center;
|
||||
padding:2px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border:{
|
||||
width:1px 3px;
|
||||
style:solid;
|
||||
color:transparent transparent black transparent;
|
||||
};
|
||||
}
|
||||
.repeat-columns,
|
||||
.repitem{
|
||||
grid-template-columns:1rem 1fr 10rem 7rem;
|
||||
align-items:end;
|
||||
}
|
||||
.repeat-columns{
|
||||
@each $num in 1,2,3{
|
||||
:nth-child(#{$num}){
|
||||
grid-column:$num + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.headed-textarea{
|
||||
grid-column:1/-1;
|
||||
}
|
||||
}
|
||||
#adjustments{
|
||||
display:contents;
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
gap:var(--half-gap);
|
||||
}
|
||||
input[type='text']{
|
||||
width:100%;
|
||||
}
|
||||
.subsection{
|
||||
@extend %repeat-section-layout;
|
||||
}
|
||||
}
|
||||
|
||||
// Battle Remnant Styling
|
||||
#remnant{
|
||||
@extend %article-layout;
|
||||
&.system-remnant{
|
||||
grid-template-areas:
|
||||
"image"
|
||||
"image"
|
||||
;
|
||||
border:{
|
||||
right:1px solid black;
|
||||
}
|
||||
grid-template-rows:auto 1fr;
|
||||
}
|
||||
}
|
||||
#remnant-pic{
|
||||
grid-area:image;
|
||||
>.input-label{
|
||||
justify-self:start;
|
||||
}
|
||||
}
|
||||
#remnant-ratings{
|
||||
@extend %grid;
|
||||
grid-template-columns:1fr repeat(2,auto);
|
||||
grid-template-areas:'header header header';
|
||||
.remnant-skills{
|
||||
@extend %repeat-section-layout;
|
||||
grid-template-areas:'header header header';
|
||||
place-self:stretch;
|
||||
grid-column:1/-1;
|
||||
gap:0;
|
||||
*{
|
||||
place-self:stretch;
|
||||
}
|
||||
input{
|
||||
width:100%;
|
||||
}
|
||||
&,
|
||||
.repeat-columns{
|
||||
grid-template-columns:1fr 4rem 3rem;
|
||||
*{
|
||||
align-self:center;
|
||||
}
|
||||
}
|
||||
.repeat-columns{
|
||||
grid-column:1/-1;
|
||||
:not(:first-child){
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
.roller{
|
||||
justify-self:start;
|
||||
}
|
||||
input{
|
||||
justify-self:center;
|
||||
}
|
||||
}
|
||||
}
|
||||
#remnant-stats{
|
||||
@extend %grid;
|
||||
grid-template-columns:1fr repeat(2,auto) 1fr repeat(2,auto);
|
||||
grid-template-areas:
|
||||
'header header header header header header'
|
||||
'. . . . . .'
|
||||
'. . . . . .'
|
||||
'. . . . . .'
|
||||
'assault_damage_label assault_damage_label assault_damage_label assault_damage_label assault_damage_label assault_damage_input'
|
||||
'strike_damage_label strike_damage_label strike_damage_label strike_damage_label strike_damage_label strike_damage_input'
|
||||
'strike_range_label strike_range_label strike_range_label strike_range_label strike_range_label strike_range_input'
|
||||
;
|
||||
@each $field in strike_damage,strike_range,assault_damage{
|
||||
.#{$field}_label{
|
||||
grid-area:#{$field}_label;
|
||||
}
|
||||
.#{$field}_input{
|
||||
grid-area:#{$field}_input;
|
||||
}
|
||||
}
|
||||
}
|
||||
#remnant-specialty{
|
||||
@extend %repeat-section-layout;
|
||||
}
|
||||
#remnant-trait{
|
||||
@extend %repeat-section-layout;
|
||||
.repeat-columns,
|
||||
.repitem{
|
||||
grid-template-columns:1fr 4rem 4rem;
|
||||
}
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
}
|
||||
}
|
||||
#remnant-drone{
|
||||
@extend %repeat-section-layout;
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
grid-template-columns:repeat(2,1fr);
|
||||
gap:var(--tiny-gap) var(--half-gap);
|
||||
}
|
||||
.input-label--button{
|
||||
grid-column:1;
|
||||
}
|
||||
.strikerange{
|
||||
grid-column:2;
|
||||
}
|
||||
.input-label{
|
||||
span,button{
|
||||
text-align:left;
|
||||
}
|
||||
&:not(.input-label--dual){
|
||||
:not([name]){
|
||||
flex:1 1 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.structure{
|
||||
display:flex;
|
||||
gap:var(--half-gap);
|
||||
grid-column:1/-1;
|
||||
place-self:center end;
|
||||
grid-column:span 2;
|
||||
*{
|
||||
align-self:center;
|
||||
}
|
||||
}
|
||||
}
|
||||
#remnant-weapons{
|
||||
@extend %repeat-section-layout;
|
||||
.repeat-columns,
|
||||
.repitem{
|
||||
grid-template-columns:1rem 1fr 5rem 4rem 7rem 8rem 5rem;
|
||||
}
|
||||
.repeat-columns{
|
||||
@each $num in 1,2,3,4,5,6{
|
||||
:nth-child(#{$num}){
|
||||
grid-column:$num + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.repitem{
|
||||
@extend %grid;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Roll Template
|
||||
#rolltemplate
|
||||
*/
|
||||
.sheet-rolltemplate-rapidfire{
|
||||
@extend %font-vars;
|
||||
--templateRadius: 1rem;
|
||||
--dieSize: 50px;
|
||||
--templateBorderW: 2px 5px 2px 5px;
|
||||
--fumbleColor: red;
|
||||
--critColor: green;
|
||||
--innerBorderRadius: 5px;
|
||||
--borderSize:1px;
|
||||
--sizeFactor: 6;
|
||||
--cornerSize: calc(1107px / var(--sizeFactor)) calc(952px / var(--sizeFactor));
|
||||
--headSideMargin:40px;
|
||||
--headVerticalMargin:10px;
|
||||
--circleSize:73px;
|
||||
--hexagonBackgroundImage:url('https://s3.amazonaws.com/files.d20.io/images/258492885/gzYgspdnfa8K2zUgTrgV3g/original.png');
|
||||
margin:{//ensures that the template fills the chat window
|
||||
left: -40px;
|
||||
right: -5px;
|
||||
}
|
||||
@extend %defaultStyles;
|
||||
a[href^='!'],
|
||||
a[href^='~']{
|
||||
font-family: var(--topHeaderFont);
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
font-weight: 700;
|
||||
padding: 0;
|
||||
}
|
||||
h1,h2,h3,h4,h5,a{
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
&:not(:first-child){//Moves the template to accomodate the sender tag
|
||||
margin-top:10px;
|
||||
}
|
||||
.sheet-content{
|
||||
@extend %grid;
|
||||
overflow:hidden;
|
||||
}
|
||||
> .sheet-template{
|
||||
overflow:hidden;
|
||||
--hexColor:#000000;
|
||||
&.sheet-system-remnants{
|
||||
padding:15px 10px;
|
||||
> .sheet-content{
|
||||
background-color: #c2c2c2;
|
||||
background:{
|
||||
image:var(--hexagonBackgroundImage);
|
||||
position:top left;
|
||||
size:400px auto;
|
||||
repeat:no-repeat;
|
||||
};
|
||||
padding:0 10px;
|
||||
border-radius:10px;
|
||||
border:5px solid black;
|
||||
grid-template-columns:[roll-start footer-start] var(--headSideMargin) [header-start] 1fr [damage-start] 1fr [roll-end difficulty-start] 1fr [damage-end] 1fr [footer-end] var(--headSideMargin)[difficulty-end header-end];
|
||||
grid-template-areas:
|
||||
'. header header header header header'
|
||||
'. . . . . .'
|
||||
'. . . . . .'
|
||||
'. . . . . .'
|
||||
'. . . . . .'
|
||||
'description description description description description description'
|
||||
'footer footer footer footer footer .'
|
||||
;
|
||||
&.sheet-single-roll{
|
||||
.sheet-hexagon{
|
||||
grid-column:damage-start / damage-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
+ .sheet-image-border{
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
background-repeat:no-repeat;
|
||||
&.sheet-has-header.sheet-has-footer{
|
||||
background:{
|
||||
image:var(--topCorner), var(--bottomCorner);
|
||||
position:top left, bottom right;
|
||||
size:var(--cornerSize),var(--cornerSize);
|
||||
};
|
||||
}
|
||||
&.sheet-has-header:not(.sheet-has-footer){
|
||||
background:{
|
||||
image:var(--topCorner);
|
||||
position:top left;
|
||||
size:var(--cornerSize);
|
||||
};
|
||||
}
|
||||
&.sheet-has-footer:not(.sheet-has-header){
|
||||
background:{
|
||||
image:var(--bottomCorner);
|
||||
position:bottom right;
|
||||
size:var(--cornerSize);
|
||||
};
|
||||
}
|
||||
}
|
||||
.sheet-header,.sheet-footer{
|
||||
@extend %grid;
|
||||
min-height: 30px;
|
||||
align-items: center;
|
||||
grid-template-areas:'content';
|
||||
*{
|
||||
box-sizing:border-box;
|
||||
grid-area:content;
|
||||
}
|
||||
}
|
||||
.sheet-header{
|
||||
--headBorder:0 3px 3px 3px;
|
||||
--headRadius:0 0 10px 10px;
|
||||
--headItems:center start;
|
||||
--headSelf:start;
|
||||
--headMargin:0 0 10px -3px;
|
||||
--headPadding:5px 10px 10px 15px;
|
||||
grid-column:2/7;
|
||||
*{
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
.sheet-footer{
|
||||
--headBorder:3px 3px 0 3px;
|
||||
--headRadius:10px 10px 0 0;
|
||||
--headItems:center end;
|
||||
--headSelf:end;
|
||||
--headMargin:9px -3px 0 0;
|
||||
--headPadding:15px 15px 5px 5px;
|
||||
grid-column:1/6;
|
||||
*{
|
||||
text-align:right;
|
||||
}
|
||||
}
|
||||
.sheet-background{
|
||||
@extend %grid;
|
||||
grid-template-areas: 'content';
|
||||
background-color: #aac1dd80;
|
||||
border-color:black;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width:var(--headBorder);
|
||||
border-radius:var(--headRadius);
|
||||
place-items:var(--headPlace);
|
||||
margin:var(--headMargin);
|
||||
place-self:var(--headSelf);
|
||||
padding:var(--headPadding);
|
||||
box-sizing:border-box;
|
||||
backdrop-filter: blur(2px);
|
||||
min-width:120px;
|
||||
*{
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
.sheet-header__content{
|
||||
@extend %grid;
|
||||
place-self:var(--headSelf);
|
||||
grid-template-areas:'content';
|
||||
padding:var(--headPadding);
|
||||
place-items:var(--headItems);
|
||||
margin:var(--headMargin);
|
||||
border-radius:var(--headRadius);
|
||||
}
|
||||
.sheet-header__image{
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:{
|
||||
image:var(--headerBottom);
|
||||
position:bottom left;
|
||||
size:calc(699px / var(--sizeFactor)) calc(130px / var(--sizeFactor));
|
||||
repeat:no-repeat;
|
||||
};
|
||||
z-index:1;
|
||||
}
|
||||
.sheet-footer__content{
|
||||
@extend %grid;
|
||||
place-self:var(--headSelf);
|
||||
grid-template-areas:'content';
|
||||
place-items:var(--headItems);
|
||||
padding: var(--headPadding);
|
||||
margin:var(--headMargin);
|
||||
border-radius:var(--headRadius);
|
||||
}
|
||||
.sheet-footer__image{
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:{
|
||||
image:var(--footerTop);
|
||||
position:top right;
|
||||
size:calc(699px / var(--sizeFactor)) calc(130px / var(--sizeFactor));
|
||||
repeat:no-repeat;
|
||||
};
|
||||
z-index:1;
|
||||
}
|
||||
.sheet-fumble-toggle + .sheet-hexagon__hex-wrapper{
|
||||
--hexColor:#db1a1a;
|
||||
}
|
||||
.sheet-crit-toggle + .sheet-hexagon__hex-wrapper{
|
||||
--hexColor:#02a98d;
|
||||
}
|
||||
.sheet-hexagon{
|
||||
@extend %hex-base;
|
||||
--shadow:black;
|
||||
width:var(--circleSize);
|
||||
aspect-ratio: 1 / 1.1547005;
|
||||
transform:rotate(150deg);
|
||||
h4 *{
|
||||
font-family:var(--midHeaderFont);
|
||||
font-weight:normal;
|
||||
}
|
||||
}
|
||||
.sheet-hexagon__hex-wrapper{
|
||||
@extend %hex-rotate;
|
||||
}
|
||||
.sheet-hexagon__hex-wrapper__hex-border{
|
||||
@extend %hex-rotate;
|
||||
@extend %hex-shape;
|
||||
background:radial-gradient(at 150%,#585858,var(--hexColor));
|
||||
&:before{
|
||||
@extend %hex-shape;
|
||||
@extend %hex-rotate;
|
||||
}
|
||||
&:after{
|
||||
@extend %hex-shape;
|
||||
@extend %hex-component;
|
||||
transform:rotate(-120deg);
|
||||
}
|
||||
}
|
||||
.sheet-hexagon__hex-wrapper__hex-border__hex-content{
|
||||
@extend %hex-component;
|
||||
transform:rotate(-30deg);
|
||||
grid-template-columns:auto;
|
||||
grid-template-rows:auto auto;
|
||||
gap:var(--half-gap);
|
||||
place-items:center;
|
||||
place-content:center;
|
||||
}
|
||||
.sheet-roll,
|
||||
.sheet-difficulty{
|
||||
align-self:start;
|
||||
}
|
||||
.sheet-container-background{
|
||||
background-color:white;
|
||||
margin:{
|
||||
right:-10px;
|
||||
left:-10px;
|
||||
bottom: -17px;
|
||||
};
|
||||
border:{
|
||||
top:2px solid black;
|
||||
bottom:2px solid black;
|
||||
}
|
||||
&,
|
||||
+ div{
|
||||
margin-top:15px;
|
||||
padding-block:5px;
|
||||
}
|
||||
}
|
||||
.sheet-description.sheet-text{
|
||||
h4{
|
||||
text-align:left;
|
||||
margin-top:var(--grid-gap);
|
||||
font-weight:700;
|
||||
}
|
||||
}
|
||||
}
|
||||
span:not(.inlinerollresult){
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
.sheet-roll,
|
||||
.sheet-difficulty{
|
||||
&:nth-child(even){
|
||||
grid-column:roll-start / roll-end;
|
||||
}
|
||||
&:nth-child(odd){
|
||||
grid-column:difficulty-start / difficulty-end;
|
||||
}
|
||||
}
|
||||
.sheet-damage{
|
||||
&:nth-child(even){
|
||||
grid-column:damage-start / damage-end;
|
||||
}
|
||||
&:nth-child(odd){
|
||||
grid-column:difficulty-start / difficulty-end;
|
||||
}
|
||||
}
|
||||
@each $area in header,description,footer{
|
||||
.sheet-#{$area}{
|
||||
grid-area:$area;
|
||||
}
|
||||
}
|
||||
:not(div),
|
||||
.sheet-hexagon,
|
||||
.sheet-hexagon div,
|
||||
.sheet-text,
|
||||
.sheet-description:not(.sheet-container-background){
|
||||
position:relative;
|
||||
z-index:10;
|
||||
}
|
||||
.inlinerollresult{
|
||||
font-size:1.5rem;
|
||||
&[title*="[computed value]"],
|
||||
&[original-title*="[computed value]"]{
|
||||
pointer-events: none;
|
||||
}
|
||||
&,
|
||||
&.fullcrit,
|
||||
&.fullfail,
|
||||
&.importantroll{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
&.fullcrit{
|
||||
|
||||
}
|
||||
&.fullfail{
|
||||
|
||||
}
|
||||
&.importantroll{
|
||||
|
||||
}
|
||||
}
|
||||
.sheet-hexagon,.sheet-circle{
|
||||
place-self:center;
|
||||
&.sheet-damage{
|
||||
justify-self:center;
|
||||
}
|
||||
:not(div){
|
||||
color:white;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
include Mixins/_htmlelements.pug
|
||||
include Mixins/_rolltemplate mixins.pug
|
||||
include Mixins/_Sheet Mixins.pug
|
||||
+hidden({name:'template_start',value:'&{template:rapidfire} {{footer=@{character_name}}} {{character_id=@{character_id}}} {{system=@{system}}}'})
|
||||
+hidden({name:'collapsed',value:''})
|
||||
+hidden({name:'system',value:'remnants'})
|
||||
main#main.subsystem-style.system-remnant
|
||||
+hidden({name:'sheet_state',value:'settings',class:'sheet-state'})
|
||||
+hidden({name:'system header'})
|
||||
+img({name:'system header',role:'heading','aria-level':1,class:'system-header','data-i18n':'system header'})
|
||||
nav#main-nav.subsystem-style.system-remnant
|
||||
+navButton({name:'character','data-i18n':'character',class:'nav__button nav__button--tab nav__button--tab--left character',role:'heading','aria-level':4})
|
||||
+navButton({name:'settings',class:'active nav__button nav__button--settings settings'})
|
||||
|y
|
||||
+navButton({name:'battle remnant','data-i18n':'battle remnant',class:'nav__button nav__button--tab nav__button--tab--right battle-remnant',role:'heading','aria-level':4})
|
||||
article#settings.subsystem-style.system-remnant.settings.active
|
||||
section#system-behavior.section
|
||||
+select-label('setting',{name:'system',class:'underlined'},null,{role:'heading','aria-level':4})
|
||||
+option({value:'remnants','data-i18n':'remnants',selected:''})
|
||||
+input-label('difficulty automation',{name:'difficulty',value:'1',checked:'',class:'box',type:'checkbox'},null,{role:'heading','aria-level':4})
|
||||
+select-label('action penalty automation',{name:'action penalty automation',class:'underlined'},null,{role:'heading','aria-level':4})
|
||||
each value,index in ['disabled','ask','use input']
|
||||
- let optObj = {value,'data-i18n':value};
|
||||
if index === 0
|
||||
- optObj.selected = '';
|
||||
+option({value,'data-i18n':value})
|
||||
section#sheet-behavior.section
|
||||
+select-label('whisper rolls to gm',{name:'whisper',class:'underlined'},null,{role:'heading','aria-level':4})
|
||||
+option({value:' ','data-i18n':'never',selected:''})
|
||||
+option({value:'/w gm ','data-i18n':'always'})
|
||||
+option({value:'?{Whisper|No, |Yes,/w gm }','data-i18n':'ask'})
|
||||
article#character.character.subsystem-style.system-remnant
|
||||
section#character-info.section
|
||||
+h2({'data-i18n':'character info'})
|
||||
each field in characterFields
|
||||
+input-label(field,{name:field,type:'text',class:`underlined ${replaceSpaces(field)}`},{},{role:'heading','aria-level':5})
|
||||
.headed-textarea.appearance
|
||||
+h5({'data-i18n':'appearance / mannerisms'})
|
||||
+adaptiveTextarea({name:'appearance/mannerisms',class:'underlined'})
|
||||
+track('health track','health')
|
||||
section#stats.stat-grid.section.repeating-container
|
||||
+h2({'data-i18n':'stats'})
|
||||
+input-label('stat points',{name:'stat points',class:'boxed',type:'number'},{class:'stat_points'},{role:'heading','aria-level':4})
|
||||
+input-label('reserve',{name:'reserve',class:'boxed',type:'number'},{class:'reserve'},{role:'heading','aria-level':4})
|
||||
each name in stats
|
||||
+roller({name,role:'heading','aria-level':4,'data-i18n':name})
|
||||
+select({name,class:'boxed number'})
|
||||
each value in [-3,-2,-1,0,1,2,3]
|
||||
- let optObj = {value};
|
||||
if value === 0
|
||||
- optObj.selected = '';
|
||||
+option(optObj)
|
||||
!=value
|
||||
+number({name:`${name} mod`,class:'boxed'})
|
||||
.repeating-container__equipment.equipment.subsection
|
||||
+h2({'data-i18n':'gear and money'})
|
||||
+input-label('easy living',{name:'easy living',class:'boxed',type:'number'},{},{role:'heading','aria-level':4})
|
||||
.repeat-columns
|
||||
h5(data-i18n='name')
|
||||
h5(data-i18n='quantity abbreviation')
|
||||
+customControlFieldset('equipment')
|
||||
+checkbox({name:'collapse',class:'collapse',title:attrTitle('equipment','collapse')})
|
||||
+text({name:'name',class:'underlined',role:'heading','aria-level':3,title:attrTitle('equipment','name')})
|
||||
+number({name:'quantity',class:'underlined',title:attrTitle('equipment','quantity')})
|
||||
.headed-textarea.notes.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('equipment','notes')})
|
||||
section#secondary.section
|
||||
.secondaries.stat-grid
|
||||
+h2({'data-i18n':'secondary stats'})
|
||||
+roller({name:'initiative',class:`initiative-label span-2`,'data-i18n':'initiative',role:'heading','aria-level':4})
|
||||
+number({name:'initiative',class:`boxed initiative`,readonly:'',value:'0'})
|
||||
+number({name:`initiative mod`,class:`boxed initiative_mod`})
|
||||
each name in secondaries
|
||||
label(for=`${name}-mod` class=`${name}-label span-2` data-i18n=name role='heading' aria-level=4)
|
||||
+number({name,class:`boxed ${name}`,readonly:'',value:secondaryDefaults[name]})
|
||||
+number({name:`${name} mod`,class:`boxed ${name}_mod`,id:`${name}-mod`})
|
||||
label(for='health' class='health-label' data-i18n='health',role='heading' aria-level=4)
|
||||
.boxed.span-2
|
||||
+number({name:'health',id:'health'})
|
||||
span.slash /
|
||||
+number({name:'health max',readonly:''})
|
||||
+number({name:`health mod`,class:`boxed health_mod`})
|
||||
.combat-gear.stat-grid
|
||||
+h2({'data-i18n':'combat gear'})
|
||||
each name in combatGear
|
||||
+input-label(name,{name,class:'boxed',type:'number'},{class:`${name} contents`},{role:'heading','aria-level':4})
|
||||
+repeating_section('skill','skills',['skills','level','stat','xp'])
|
||||
+checkbox({name:'raw',hidden:'',class:'raw-control',value:1,title:attrTitle('skill','raw')})
|
||||
+roller({name:'roll',title:buttonTitle('skill','roll'),class:'raw'})
|
||||
+span({name:'name','data-i18n-dynamic':'',role:'heading','aria-level':5,title:attrTitle('skill','name')})
|
||||
+roller({name:'roll',title:buttonTitle('skill','roll'),class:'custom'})
|
||||
+text({name:'name',role:'heading','aria-level':5,class:'custom underlined',title:attrTitle('skill','name')})
|
||||
+number({name:'level',class:'underlined',title:attrTitle('skill','level')})
|
||||
+select({name:'stat',class:'underlined',title:attrTitle('skill','stat')})
|
||||
+option({value:'query','data-i18n':'ask'})
|
||||
each value in stats
|
||||
+option({value,'data-i18n':value})
|
||||
+number({name:'xp',class:'underlined',title:attrTitle('skill','xp')})
|
||||
section#adjustments
|
||||
.repeating-container.repeating-container--advantages.advantages.subsection.section
|
||||
+h2({'data-i18n':'advantages'})
|
||||
.repeat-columns
|
||||
h5(data-i18n='name')
|
||||
+customControlFieldset('advantage')
|
||||
+checkbox({name:'collapse',class:'collapse',title:attrTitle('advantage','collapse')})
|
||||
+text({name:'name',class:'underlined',role:'heading','aria-level':3,title:attrTitle('advantage','name')})
|
||||
.headed-textarea.notes.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('advantage','notes')})
|
||||
.repeating-container.repeating-container--disadvantages.disadvantages.subsection.section
|
||||
+h2({'data-i18n':'disadvantages'})
|
||||
.repeat-columns
|
||||
h5(data-i18n='name')
|
||||
+customControlFieldset('disadvantage')
|
||||
+checkbox({name:'collapse',class:'collapse',title:attrTitle('disadvantage','collapse')})
|
||||
+text({name:'name',class:'underlined',role:'heading','aria-level':3,title:attrTitle('disadvantage','name')})
|
||||
.headed-textarea.notes.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('disadvantage','notes')})
|
||||
.repeating-container.repeating-container--adjustments.adjustments.subsection.section
|
||||
+h2({'data-i18n':'adjustments'})
|
||||
.repeat-columns
|
||||
h5(data-i18n='name')
|
||||
+customControlFieldset('adjustment')
|
||||
+checkbox({name:'collapse',class:'collapse',title:attrTitle('adjustment','collapse')})
|
||||
+text({name:'name',class:'underlined',role:'heading','aria-level':3,title:attrTitle('adjustment','name')})
|
||||
.headed-textarea.mod.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('adjustment','notes')})
|
||||
//-
|
||||
.headed-textarea.mods.expanded
|
||||
+h5({'data-i18n':'mods'})
|
||||
+adaptiveTextarea({name:'mods',class:'underlined',title:attrTitle('adjustment','mods')})
|
||||
+repeating_section('weapon','weapons',['weapon','skill','damage'])
|
||||
+checkbox({name:'collapse',class:'collapse'})
|
||||
+roller({name:'roll',title:buttonTitle('weapon','roll')})
|
||||
+text({name:'name',class:'underlined',title:attrTitle('weapon','name')})
|
||||
+hidden({name:'skill',value:'select',title:attrTitle('weapon','skill')})
|
||||
+actionQuery({name:'skill action',title:buttonTitle('weapon','skill')})
|
||||
+checkbox({name:'translate skill',hidden:'',value:'1',class:'translate-control',checked:''})
|
||||
+span({name:'skill',class:'underlined translated','data-i18n-dynamic':'',title:attrTitle('weapon','skill')})
|
||||
+span({name:'skill',class:'underlined untranslated',title:attrTitle('weapon','skill')})
|
||||
.roll-plus
|
||||
+span({'data-i18n':'lead'})
|
||||
span.plus +
|
||||
+number({name:'damage',class:'underlined',title:attrTitle('weapon','damage')})
|
||||
.headed-textarea.notes.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('weapon','notes')})
|
||||
article#remnant.battle-remnant.subsystem-style.system-remnant
|
||||
section#remnant-pic.section
|
||||
+track('structure track','structure')
|
||||
+input-label('duress',{name:'duress',type:'number',class:'boxed'},{},{role:'heading','aria-level':2})
|
||||
.image-container.remnant-token
|
||||
+input-label('image prompt',{name:'remnant token',type:'text',class:'boxed',value:'https://s3.amazonaws.com/files.d20.io/images/259054779/OzN3yQwg7MbfXNtMYs-iOg/original.png'},{class:'image-container__input stacked'},{role:'heading','aria-level':5})
|
||||
+action({name:'remnant token',class:'image-container__button'})
|
||||
+img({name:'remnant token',class:'image-container__image',src:'https://s3.amazonaws.com/files.d20.io/images/259054779/OzN3yQwg7MbfXNtMYs-iOg/original.png'})
|
||||
section#remnant-ratings.stat-grid.section
|
||||
+h2({'data-i18n':'total ratings'})
|
||||
each name in remnantRatings
|
||||
- let label = abbreviations[name] || name;
|
||||
if name === 'situational awareness'
|
||||
+roller({name:'situational awareness',class:'uppercase',role:'heading','aria-level':4,'data-i18n':label,class:'uppercase'})
|
||||
else
|
||||
h4(data-i18n=label)
|
||||
+number({name,readonly:'',class:'boxed'})
|
||||
+number({name:`${name} mod`,class:'boxed'})
|
||||
+roller({name:'remnant initiative','data-i18n':'initiative',role:'heading','aria-level':4})
|
||||
+number({name:'remnant initiative',readonly:'',class:'boxed'})
|
||||
+number({name:'remnant initiative mod',class:'boxed'})
|
||||
.remnant-skills
|
||||
+h2({'data-i18n':'skills'})
|
||||
.repeat-columns
|
||||
each value in ['skill','level','xp']
|
||||
+h5({'data-i18n':value})
|
||||
each name in remnantSkills
|
||||
+roller({name:`${name} roll`,'data-i18n':name,role:'heading','aria-level':4})
|
||||
+number({name:`${name} level`,class:'underlined'})
|
||||
+number({name:`${name} experience`,class:'underlined'})
|
||||
section#remnant-stats.stat-grid.section
|
||||
+h2({'data-i18n':'remnant stats'})
|
||||
each name in remnantStats
|
||||
if name === 'structure'
|
||||
.input-label.span-all.structure
|
||||
label(data-i18n='structure' for='structure' role='heading' aria-level=4)
|
||||
.boxed.span-2
|
||||
+number({name:'structure',id:'structure'})
|
||||
span.slash /
|
||||
+hidden({name:'structure max'})
|
||||
+number({name:'structure base',title:attrTitle('structure max')})
|
||||
else
|
||||
label(data-i18n=name for=replaceSpaces(name) role='heading' aria-level=4).span-2
|
||||
+number({name,class:'boxed',type:'number',id:replaceSpaces(name)})
|
||||
each name in remnantCombatStats
|
||||
- let inputObj = {name,class:`boxed ${replaceSpaces(name)}_input`,type:'number',id:replaceSpaces(name)};
|
||||
label(data-i18n=name role='heading' aria-level=4 for=replaceSpaces(name) class=`${replaceSpaces(name)}_label`)
|
||||
+input(inputObj)
|
||||
+repeating_section('specialty','specialty',['name'],'remnant-specialty')
|
||||
+checkbox({name:'collapse',class:'collapse'})
|
||||
+text({name:'name',class:'underlined',title:attrTitle('specialty','name')})
|
||||
.headed-textarea.description.expanded
|
||||
+h5({'data-i18n':'description'})
|
||||
+adaptiveTextarea({name:'description',class:'underlined',title:attrTitle('specialty','description')})
|
||||
+repeating_section('trait','traits',['name','duress','focus'],'remnant-trait')
|
||||
+checkbox({name:'collapse',class:'collapse'})
|
||||
+text({name:'name',class:'underlined'})
|
||||
+number({name:'duress',class:'underlined',title:attrTitle('trait','duress')})
|
||||
+number({name:'focus',class:'underlined',title:attrTitle('trait','focus')})
|
||||
.headed-textarea.description.expanded
|
||||
+h5({'data-i18n':'description'})
|
||||
+adaptiveTextarea({name:'description',class:'underlined',title:attrTitle('trait','description')})
|
||||
section#remnant-drone.repeating-container.repeating-container--drone.section
|
||||
+h2({'data-i18n':'drones'})
|
||||
+customControlFieldset('drone')
|
||||
+checkbox({name:'collapse',class:'collapse'})
|
||||
+text({name:'name',class:'underlined remnant-drone__name',role:'heading','aria-level':3,title:attrTitle('drone','name')})
|
||||
+input-label('# active',{name:'active',type:'number',class:'boxed'},null,{role:'heading','aria-level':5,'data-i18n':label,'data-i18n':'# active'})
|
||||
each name in droneStats
|
||||
- let label = abbreviations[name] || name;
|
||||
if /^(?:strike|assault)/.test(label)
|
||||
- let hiddenName = /strike/.test(label) ? 'strike' : 'assault';
|
||||
+hidden({name:hiddenName,type:'number',class:`underlined expanded--empty`})
|
||||
if /^(?:strike|assault)$/.test(name)
|
||||
+roller-label({name,type:'number',class:`boxed`,title:attrTitle('drone',name)},{name,role:'heading','aria-level':5,'data-i18n':label,title:buttonTitle('drone',name)},{class:`${replaceSpaces(name)}`})
|
||||
else if name === 'struct'
|
||||
.structure
|
||||
+span({role:'heading','aria-level':5,'data-i18n':label})
|
||||
.boxed.span-2
|
||||
+number({name:'structure',id:'structure'})
|
||||
span.slash /
|
||||
+number({name:'structure max'})
|
||||
else if name=== 'strikerange'
|
||||
+input-label(label,{name,type:'number',class:`boxed`,title:attrTitle('drone',name),readonly:''},{class:replaceSpaces(name)},{role:'heading','aria-level':5,'data-i18n':label})
|
||||
else
|
||||
+input-label(label,{name,type:'number',class:`boxed`,title:attrTitle('drone',name)},{class:replaceSpaces(name)},{role:'heading','aria-level':5,'data-i18n':label})
|
||||
.headed-textarea.description.expanded
|
||||
+h5({'data-i18n':'description'})
|
||||
+adaptiveTextarea({name:'description',class:'underlined',title:attrTitle('drone','description')})
|
||||
section#remnant-weapons.repeating-container.repeating-container--remnant-weapons.section
|
||||
+h2({'data-i18n':'weapons'})
|
||||
.repeat-columns
|
||||
each name in remnantWeaponInputs
|
||||
+h5({'data-i18n':name})
|
||||
+customControlFieldset('remnant weapon')
|
||||
+checkbox({name:'collapse',class:'collapse'})
|
||||
+roller({name:'roll',title:buttonTitle('remnant-weapon','roll')})
|
||||
+text({name:'name',class:'underlined',title:attrTitle('remnant-weapon','name'),role:'heading','aria-level':4})
|
||||
+select({name:'skill',class:'underlined',title:attrTitle('remnant-weapon','skill')})
|
||||
+option({value:' ','data-i18n':'select',selected:''})
|
||||
+option({value:'assault','data-i18n':'assault'})
|
||||
+option({value:'strike','data-i18n':'strike'})
|
||||
+number({name:'bonus',class:'underlined',title:attrTitle('remnant-weapon','bonus')})
|
||||
.roll-plus
|
||||
+span({'data-i18n':'lead'})
|
||||
span.plus +
|
||||
+number({name:'damage',class:'underlined',title:attrTitle('weapon','damage'),readonly:''})
|
||||
+number({name:'damage bonus',class:'underlined damage-bonus',title:attrTitle('remnant-weapon','damage bonus')})
|
||||
+text({name:'type',class:'underlined',title:attrTitle('remnant-weapon','type')})
|
||||
.headed-textarea.description.expanded
|
||||
+h5({'data-i18n':'notes'})
|
||||
+adaptiveTextarea({name:'notes',class:'underlined',title:attrTitle('remnant-weapon','notes')})
|
||||
//-Rolltemplate definitions
|
||||
+rolltemplate('rapidfire')
|
||||
.content(class='{{#singleroll}}single-roll{{/singleroll}}')
|
||||
+templateConditionalDisplay('header')
|
||||
.header
|
||||
.header__background.background
|
||||
h3(tabindex='-1') {{header}}
|
||||
.header__content
|
||||
h3 {{header}}
|
||||
.header__image
|
||||
+templateConditionalDisplay('roll')
|
||||
+hexagon({},'status').sheet-roll
|
||||
h4(data-i18n='roll')
|
||||
|{{roll}}
|
||||
each num in [1,2,3,4,5,6]
|
||||
+templateConditionalDisplay(`roll${num}`)
|
||||
- let hexObj = {class:`sheet-roll`};
|
||||
+hexagon(hexObj,`status${num}`)
|
||||
h4(data-i18n='roll')
|
||||
|{{roll#{num}}}
|
||||
+templateConditionalDisplay('difficulty')
|
||||
+hexagon().difficulty
|
||||
h4(data-i18n='difficulty')
|
||||
|{{difficulty}}
|
||||
+templateConditionalDisplay('damage')
|
||||
+hexagon().damage
|
||||
+templateConditionalDisplay('damage_label')
|
||||
h4 {{computed::damage_label}}
|
||||
+templateConditionalDisplay('damage_label',true)
|
||||
h4(data-i18n='damage')
|
||||
|{{computed::damage}}
|
||||
+templateConditionalDisplay('description')
|
||||
.container-background.description
|
||||
.description.text
|
||||
h4(data-i18n='notes')
|
||||
span {{description}}
|
||||
+userTemplateFields
|
||||
+templateConditionalDisplay('description',true)
|
||||
+templateConditionalDisplay('custom_description')
|
||||
.container-background.description
|
||||
.description.text
|
||||
+userTemplateFields
|
||||
+characterLink()
|
||||
+script()
|
||||
include Javascript/utility.js
|
||||
include Javascript/setupfunctions.js
|
||||
include Javascript/clickfunctions.js
|
||||
include Javascript/rollfunctions.js
|
||||
include Javascript/initialchangefunctions.js
|
||||
include Javascript/triggeredfunctions.js
|
||||
include Javascript/calculators.js
|
||||
include Javascript/listeners.js
|
||||
//- The below declarations import variables from the pug file and mixins into the sheetworker code
|
||||
each content,prop in varObjects
|
||||
|
|
||||
|const !{prop} = !{JSON.stringify(content)};
|
||||
|
|
||||
|
|
||||
include Javascript/variables.js
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"remnants":"remnants",
|
||||
"character info":"character info",
|
||||
"character name":"character name",
|
||||
"player name":"player name",
|
||||
"nationality":"nationality",
|
||||
"organization affiliations":"organization affiliations",
|
||||
"appearance / mannerisms":"appearance / mannerisms",
|
||||
"stats":"stats",
|
||||
"body":"body",
|
||||
"mind":"mind",
|
||||
"spirit":"spirit",
|
||||
"stat points":"stat points",
|
||||
"reserve":"reserve",
|
||||
"secondary stats":"secondary stats",
|
||||
"defence":"defence",
|
||||
"resist":"resist",
|
||||
"health":"health",
|
||||
"initiative":"initiative",
|
||||
"combat gear":"combat gear",
|
||||
"armour bonus":"armour bonus",
|
||||
"shield bonus":"shield bonus",
|
||||
"action penalty":"action penalty",
|
||||
"health track":"health track",
|
||||
"gear and money":"gear and money",
|
||||
"easy living":"easy living",
|
||||
"skills":"skills",
|
||||
"level":"level",
|
||||
"stat":"stat",
|
||||
"xp":"xp",
|
||||
"weapons":"weapons",
|
||||
"weapon":"weapon",
|
||||
"attack":"attack",
|
||||
"damage":"damage",
|
||||
"query":"query",
|
||||
"ask":"ask",
|
||||
"select":"select",
|
||||
"1d6":"1d6",
|
||||
"lead":"lead",
|
||||
"notes":"notes",
|
||||
"mods":"mods",
|
||||
"adjustments":"adjustments",
|
||||
"advantages":"advantages",
|
||||
"disadvantages":"disadvantages",
|
||||
"structure track":"structure track",
|
||||
"duress":"duress",
|
||||
"total ratings":"total ratings",
|
||||
"situational awareness":"situational awareness",
|
||||
"remnant stats":"remnant stats",
|
||||
"armour":"armour",
|
||||
"speed":"speed",
|
||||
"structure":"structure",
|
||||
"inspiring":"inspiring",
|
||||
"terrifying":"terrifying",
|
||||
"assault damage":"assault damage",
|
||||
"strike damage":"strike damage",
|
||||
"strike range":"strike range",
|
||||
"strike range (km)":"strike range (km)",
|
||||
"remnant skills":"remnant skills",
|
||||
"skill":"skill",
|
||||
"remnant weapons":"remnant weapons",
|
||||
"name":"name",
|
||||
"bonus":"bonus",
|
||||
"damage":"damage",
|
||||
"damage bonus":"damage bonus",
|
||||
"type":"type",
|
||||
"assault":"assault",
|
||||
"strike":"strike",
|
||||
"description":"description",
|
||||
"traits":"traits",
|
||||
"type":"type",
|
||||
"focus":"focus",
|
||||
"specialty":"specialty",
|
||||
"skill query":"Which skill would you like to use",
|
||||
"archery / throwing":"Archery / throwing",
|
||||
"athletics":"athletics",
|
||||
"awareness":"awareness",
|
||||
"bureaucracy":"bureaucracy",
|
||||
"command":"command",
|
||||
"craft":"craft",
|
||||
"dodge":"dodge",
|
||||
"etiquette":"etiquette",
|
||||
"history":"history",
|
||||
"investigation":"investigation",
|
||||
"language":"language",
|
||||
"larceny":"larceny",
|
||||
"lore":"lore",
|
||||
"medicine":"medicine",
|
||||
"melee":"melee",
|
||||
"perform":"perform",
|
||||
"ride":"ride",
|
||||
"sail":"sail",
|
||||
"sciences":"sciences",
|
||||
"social sciences":"social sciences",
|
||||
"stealth":"stealth",
|
||||
"survival":"survival",
|
||||
"unarmed combat":"unarmed combat",
|
||||
"drones":"drones",
|
||||
"difficulty query":"What is the difficulty of the roll",
|
||||
"stat query":"Which stat are you using",
|
||||
"roll":"roll",
|
||||
"difficulty":"difficulty",
|
||||
"character":"character",
|
||||
"battle remnant":"battle remnant",
|
||||
"whisper rolls to gm":"whisper rolls to gm",
|
||||
"setting":"setting",
|
||||
"difficulty automation":"difficulty automation",
|
||||
"never":"never",
|
||||
"always":"always",
|
||||
"ask":"ask",
|
||||
"enabled":"enabled",
|
||||
"disabled":"disabled",
|
||||
"motion":"motion",
|
||||
"remnant defence":"remnant defence",
|
||||
"situation awareness abbreviation":"sa",
|
||||
"image prompt":"Enter the url for the image you would like to add. Leave blank to reset.",
|
||||
"remnant token":"remnant token",
|
||||
"drone query":"How many drones are attacking",
|
||||
"remnant-initiative":"remnant initiative",
|
||||
"action penalty automation":"action penalty automation",
|
||||
"use input":"use input",
|
||||
"quantity abbreviation":"qty",
|
||||
"action penalty query":"What is your current action penalty",
|
||||
"system header":"system header",
|
||||
"# active":"# active",
|
||||
"lead":"lead",
|
||||
"trail":"trail"
|
||||
}
|
||||