mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-31 04:02:29 +00:00
1867 lines
56 KiB
JavaScript
1867 lines
56 KiB
JavaScript
var genefunk2090 = genefunk2090 || (function() {
|
|
const version = 1.20;
|
|
const displayControllers = ['sheet_view','advantage_state','character_type','whisper_state'],
|
|
importControls = ['import','import_cancel'],
|
|
abilityScores = {str:'strength',dex:'dexterity',con:'constitution',int:'intelligence',wis:'wisdom',cha:'charisma'},
|
|
skillNames = ['athletics','acrobatics','drive','sleight_of_hand','stealth','bureaucracy','computers','investigation','life_science','mechanics','physical_science','social_science','streetwise','insight','perception','survival','deception','intimidation','performance','persuasion'],
|
|
skillList = {athletics:'strength',acrobatics:'dexterity',drive:'dexterity',sleight_of_hand:'dexterity',stealth:'dexterity',bureaucracy:'intelligence',computers:'intelligence',investigation:'intelligence',life_science:'intelligence',mechanics:'intelligence',physical_science:'intelligence',social_science:'intelligence',streetwise:'intelligence',insight:'wisdom',perception:'wisdom',survival:'wisdom',deception:'charisma',intimidation:'charisma',performance:'charisma',persuasion:'charisma'},
|
|
hackLevels = ['1st','2nd','3rd','4th','5th'],
|
|
repeating_section_details = [
|
|
{
|
|
section:'repeating_equipment',
|
|
fields:['name','quantity','weight','cost','mods','description','id']
|
|
},
|
|
{
|
|
section:'repeating_hack',
|
|
fields:['name','level','launch_time','duration','hack_type','source','action_proficiency','attack_enable_item','save_enable_item','damage_1_enable_item','damage_2_enable_item','attack_ability','attack_bonus','save_ability','save_type','dc_bonus','damage_1','critical_damage_1','damage_ability_1','damage_type_1','damage_2','critical_damage_2','damage_ability_2','damage_type_2','range','properties','description','id']
|
|
},
|
|
{
|
|
section:'repeating_action',
|
|
fields:['name','action_proficiency','attack_enable_item','save_enable_item','damage_1_enable_item','damage_2_enable_item','attack_ability','attack_bonus','save_ability','save_type','dc_bonus','damage_1','critical_damage_1','damage_ability_1','damage_type_1','damage_2','critical_damage_2','damage_ability_2','damage_type_2','range','properties','description','id']
|
|
},
|
|
{
|
|
section:'repeating_trait',
|
|
fields:['name','source','mods','description','id']
|
|
}
|
|
],
|
|
cascades = {
|
|
pc:{
|
|
class_level:{
|
|
name:'class_level',
|
|
defaultValue:'',
|
|
type:'text',
|
|
affects:['level']
|
|
},
|
|
level:{
|
|
name:'level',
|
|
defaultValue:'',
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:['proficiency']
|
|
},
|
|
proficiency:{
|
|
name:'proficiency',
|
|
defaultValue:'',
|
|
type:'number',
|
|
calculation:'2+floor((@{level}-1)/4)',
|
|
affects:['variable']
|
|
},
|
|
ac_formula:{
|
|
name:'ac_formula',
|
|
defaultValue:'10+@{dexterity_mod}',
|
|
type:'text',
|
|
calculation:'custom',
|
|
affects:['ac']
|
|
},
|
|
ac:{
|
|
name:'ac',
|
|
defaultValue:'10',
|
|
type:'number',
|
|
calculation:'@{ac_formula}',
|
|
affects:[]
|
|
},
|
|
base_strength:{
|
|
name:'base_strength',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['strength']
|
|
},
|
|
base_dexterity:{
|
|
name:'base_dexterity',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['dexterity']
|
|
},
|
|
base_constitution:{
|
|
name:'base_constitution',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['constitution']
|
|
},
|
|
base_intelligence:{
|
|
name:'base_intelligence',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['intelligence']
|
|
},
|
|
base_wisdom:{
|
|
name:'base_wisdom',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['wisdom']
|
|
},
|
|
base_charisma:{
|
|
name:'base_charisma',
|
|
defaultValue:10,
|
|
type:'number',
|
|
affects:['charisma']
|
|
},
|
|
strength:{
|
|
name:'strength',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_strength} @{strength_modded}',
|
|
affects:['strength_mod']
|
|
},
|
|
dexterity:{
|
|
name:'dexterity',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_dexterity} @{dexterity_modded}',
|
|
affects:['dexterity_mod']
|
|
},
|
|
constitution:{
|
|
name:'constitution',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_constitution} @{constitution_modded}',
|
|
affects:['constitution_mod']
|
|
},
|
|
intelligence:{
|
|
name:'intelligence',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_intelligence} @{intelligence_modded}',
|
|
affects:['intelligence_mod']
|
|
},
|
|
wisdom:{
|
|
name:'wisdom',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_wisdom} @{wisdom_modded}',
|
|
affects:['wisdom_mod']
|
|
},
|
|
charisma:{
|
|
name:'charisma',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'@{base_charisma} @{charisma_modded}',
|
|
affects:['charisma_mod']
|
|
},
|
|
strength_mod:{
|
|
name:'strength_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{strength}-10)/2)',
|
|
affects:['athletics','strength_save','variable']
|
|
},
|
|
strength_save_proficiency:{
|
|
name:'strength_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['strength_save']
|
|
},
|
|
strength_save:{
|
|
name:'strength_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{strength_mod} + @{strength_save_proficiency}@{strength_save_modded}',
|
|
affects:[]
|
|
},
|
|
dexterity_mod:{
|
|
name:'dexterity_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{dexterity}-10)/2)',
|
|
affects:['acrobatics','drive','sleight_of_hand','stealth','dexterity_save','initiative','variable']
|
|
},
|
|
dexterity_save_proficiency:{
|
|
name:'dexterity_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['dexterity_save']
|
|
},
|
|
dexterity_save:{
|
|
name:'dexterity_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod} + @{dexterity_save_proficiency}@{dexterity_save_modded}',
|
|
affects:[]
|
|
},
|
|
constitution_mod:{
|
|
name:'constitution_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{constitution}-10)/2)',
|
|
affects:['constitution_save','variable']
|
|
},
|
|
constitution_save_proficiency:{
|
|
name:'constitution_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['constitution_save']
|
|
},
|
|
constitution_save:{
|
|
name:'constitution_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{constitution_mod} + @{constitution_save_proficiency}@{constitution_save_modded}',
|
|
affects:[]
|
|
},
|
|
intelligence_mod:{
|
|
name:'intelligence_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{intelligence}-10)/2)',
|
|
affects:['bureaucracy','computers','investigation','life_science','mechanics','physical_science','social_science','streetwise','intelligence_save','variable']
|
|
},
|
|
intelligence_save_proficiency:{
|
|
name:'intelligence_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['intelligence_save']
|
|
},
|
|
intelligence_save:{
|
|
name:'intelligence_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{intelligence_save_proficiency}@{intelligence_save_modded}',
|
|
affects:[]
|
|
},
|
|
wisdom_mod:{
|
|
name:'wisdom_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{wisdom}-10)/2)',
|
|
affects:['insight','perception','survival','wisdom_save','variable']
|
|
},
|
|
wisdom_save_proficiency:{
|
|
name:'wisdom_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['wisdom_save']
|
|
},
|
|
wisdom_save:{
|
|
name:'wisdom_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{wisdom_mod} + @{wisdom_save_proficiency}@{wisdom_save_modded}',
|
|
affects:[]
|
|
},
|
|
charisma_mod:{
|
|
name:'charisma_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{charisma}-10)/2)',
|
|
affects:['deception','intimidation','performance','persuasion','charisma_save','variable']
|
|
},
|
|
charisma_save_proficiency:{
|
|
name:'charisma_save_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['charisma_save']
|
|
},
|
|
charisma_save:{
|
|
name:'charisma_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{charisma_mod} + @{charisma_save_proficiency}@{charisma_save_modded}',
|
|
affects:[]
|
|
},
|
|
initiative:{
|
|
name:'initiative',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod}@{initiative_modded}',
|
|
affects:[]
|
|
},
|
|
initiative_modded:{
|
|
name:'initiative_modded',
|
|
defaultValue:'',
|
|
type:'text',
|
|
affects:['initiative']
|
|
},
|
|
athletics_proficiency:{
|
|
name:'athletics_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['athletics']
|
|
},
|
|
athletics:{
|
|
name:'athletics',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{strength_mod} + @{athletics_proficiency}@{athletics_modded}',
|
|
affects:[]
|
|
},
|
|
acrobatics_proficiency:{
|
|
name:'acrobatics_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['acrobatics']
|
|
},
|
|
acrobatics:{
|
|
name:'acrobatics',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod} + @{acrobatics_proficiency}@{acrobatics_modded}',
|
|
affects:[]
|
|
},
|
|
drive_proficiency:{
|
|
name:'drive_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['drive']
|
|
},
|
|
drive:{
|
|
name:'drive',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod} + @{drive_proficiency}@{drive_modded}',
|
|
affects:[]
|
|
},
|
|
sleight_of_hand_proficiency:{
|
|
name:'sleight_of_hand_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['sleight_of_hand']
|
|
},
|
|
sleight_of_hand:{
|
|
name:'sleight_of_hand',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod} + @{sleight_of_hand_proficiency}@{sleight_of_hand_modded}',
|
|
affects:[]
|
|
},
|
|
stealth_proficiency:{
|
|
name:'stealth_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['stealth']
|
|
},
|
|
stealth:{
|
|
name:'stealth',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{dexterity_mod} + @{stealth_proficiency}@{stealth_modded}',
|
|
affects:[]
|
|
},
|
|
bureaucracy_proficiency:{
|
|
name:'bureaucracy_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['bureaucracy']
|
|
},
|
|
bureaucracy:{
|
|
name:'bureaucracy',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{bureaucracy_proficiency}@{bureaucracy_modded}',
|
|
affects:[]
|
|
},
|
|
computers_proficiency:{
|
|
name:'computers_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['computers']
|
|
},
|
|
computers:{
|
|
name:'computers',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{computers_proficiency}@{computers_modded}',
|
|
affects:[]
|
|
},
|
|
investigation_proficiency:{
|
|
name:'investigation_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['investigation']
|
|
},
|
|
investigation:{
|
|
name:'investigation',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{investigation_proficiency}@{investigation_modded}',
|
|
affects:[]
|
|
},
|
|
life_science_proficiency:{
|
|
name:'life_science_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['life_science']
|
|
},
|
|
life_science:{
|
|
name:'life_science',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{life_science_proficiency}@{life_science_modded}',
|
|
affects:[]
|
|
},
|
|
mechanics_proficiency:{
|
|
name:'mechanics_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['mechanics']
|
|
},
|
|
mechanics:{
|
|
name:'mechanics',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{mechanics_proficiency}@{mechanics_modded}',
|
|
affects:[]
|
|
},
|
|
physical_science_proficiency:{
|
|
name:'physical_science_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['physical_science']
|
|
},
|
|
physical_science:{
|
|
name:'physical_science',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{physical_science_proficiency}@{physical_science_modded}',
|
|
affects:[]
|
|
},
|
|
social_science_proficiency:{
|
|
name:'social_science_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['social_science']
|
|
},
|
|
social_science:{
|
|
name:'social_science',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{social_science_proficiency}@{social_science_modded}',
|
|
affects:[]
|
|
},
|
|
streetwise_proficiency:{
|
|
name:'streetwise_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['streetwise']
|
|
},
|
|
streetwise:{
|
|
name:'streetwise',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{intelligence_mod} + @{streetwise_proficiency}@{streetwise_modded}',
|
|
affects:[]
|
|
},
|
|
insight_proficiency:{
|
|
name:'insight_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['insight']
|
|
},
|
|
insight:{
|
|
name:'insight',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{wisdom_mod} + @{insight_proficiency}@{insight_modded}',
|
|
affects:['passive_insight']
|
|
},
|
|
passive_insight:{
|
|
name:'passive_insight',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'10 +@{insight}@{passive_insight_modded}',
|
|
affects:[]
|
|
},
|
|
passive_insight_modded:{
|
|
name:'passive_insight_modded',
|
|
defaultValue:'',
|
|
type:'text',
|
|
affects:['passive_insight']
|
|
},
|
|
perception_proficiency:{
|
|
name:'perception_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['perception']
|
|
},
|
|
perception:{
|
|
name:'perception',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{wisdom_mod} + @{perception_proficiency}@{perception_modded}',
|
|
affects:['passive_perception']
|
|
},
|
|
passive_perception:{
|
|
name:'passive_perception',
|
|
defaultValue:10,
|
|
type:'number',
|
|
calculation:'10 + @{perception}@{passive_perception_modded}',
|
|
affects:[]
|
|
},
|
|
passive_perception_modded:{
|
|
name:'passive_perception_modded',
|
|
defaultValue:'',
|
|
type:'text',
|
|
affects:['passive_perception']
|
|
},
|
|
survival_proficiency:{
|
|
name:'survival_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['survival']
|
|
},
|
|
survival:{
|
|
name:'survival',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{wisdom_mod} + @{survival_proficiency}@{survival_modded}',
|
|
affects:[]
|
|
},
|
|
deception_proficiency:{
|
|
name:'deception_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['deception']
|
|
},
|
|
deception:{
|
|
name:'deception',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{charisma_mod} + @{deception_proficiency}@{deception_modded}',
|
|
affects:[]
|
|
},
|
|
intimidation_proficiency:{
|
|
name:'intimidation_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['intimidation']
|
|
},
|
|
intimidation:{
|
|
name:'intimidation',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{charisma_mod} + @{intimidation_proficiency}@{intimidation_modded}',
|
|
affects:[]
|
|
},
|
|
performance_proficiency:{
|
|
name:'performance_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['performance']
|
|
},
|
|
performance:{
|
|
name:'performance',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{charisma_mod} + @{performance_proficiency}@{performance_modded}',
|
|
affects:[]
|
|
},
|
|
persuasion_proficiency:{
|
|
name:'persuasion_proficiency',
|
|
defaultValue:0,
|
|
type:'text',
|
|
affects:['persuasion']
|
|
},
|
|
persuasion:{
|
|
name:'persuasion',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{charisma_mod} + @{persuasion_proficiency}@{persuasion_modded}',
|
|
affects:[]
|
|
},
|
|
repeating_action_$X_bonus:{
|
|
name:'repeating_action_$X_bonus',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'@{repeating_action_$X_attack_ability} + @{repeating_action_$X_attack_bonus} + @{repeating_action_$X_action_proficiency}@{repeating_action_$X_attack_modded}',
|
|
affects:[]
|
|
},
|
|
repeating_action_$X_action_proficiency:{
|
|
name:'repeating_action_$X_action_proficiency',
|
|
defaultValue:'0',
|
|
type:'text',
|
|
affects:['repeating_action_$X_bonus']
|
|
},
|
|
repeating_action_$X_attack_ability:{
|
|
name:'repeating_action_$X_attack_ability',
|
|
defaultValue:'0',
|
|
type:'text',
|
|
affects:['repeating_action_$X_bonus']
|
|
},
|
|
repeating_action_$X_attack_bonus:{
|
|
name:'repeating_action_$X_attack_bonus',
|
|
defaultValue:'',
|
|
type:'text',
|
|
affects:['repeating_action_$X_bonus']
|
|
}
|
|
},
|
|
npc:{
|
|
/*character_name:{
|
|
name:'character_name',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},*/
|
|
size:{
|
|
name:'size',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
genome:{
|
|
name:'genome',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
modification:{
|
|
name:'modification',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
ac:{
|
|
name:'ac' ,
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
damage_reduction:{
|
|
name:'damage_reduction',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hp:{
|
|
name:'hp',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hp_max:{
|
|
name:'hp_max',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hit_dice:{
|
|
name:'hit_dice',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
speed:{
|
|
name:'speed',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
strength:{
|
|
name:'strength',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['strength_mod']
|
|
},
|
|
strength_save_base:{
|
|
name:'strength_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['strength_save']
|
|
},
|
|
dexterity:{
|
|
name:'dexterity',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['dexterity_mod']
|
|
},
|
|
dexterity_save_base:{
|
|
name:'dexterity_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['dexterity_save']
|
|
},
|
|
constitution:{
|
|
name:'constitution',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['constitution_mod']
|
|
},
|
|
constitution_save_base:{
|
|
name:'constitution_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['constitution_save']
|
|
},
|
|
intelligence:{
|
|
name:'intelligence',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['intelligence_mod']
|
|
},
|
|
intelligence_save_base:{
|
|
name:'intelligence_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['intelligence_save']
|
|
},
|
|
wisdom:{
|
|
name:'wisdom',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['wisdom_mod']
|
|
},
|
|
wisdom_save_base:{
|
|
name:'wisdom_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['wisdom_save']
|
|
},
|
|
charisma:{
|
|
name:'charisma',
|
|
type:'text',
|
|
defaultValue:10,
|
|
affects:['charisma_mod']
|
|
},
|
|
charisma_save_base:{
|
|
name:'charisma_save_base',
|
|
type:'number',
|
|
defaultValue:'',
|
|
affects:['charisma_save']
|
|
},
|
|
strength_mod:{
|
|
name:'strength_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{strength}-10)/2)',
|
|
affects:['strength_save']
|
|
},
|
|
dexterity_mod:{
|
|
name:'dexterity_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{dexterity}-10)/2)',
|
|
affects:['dexterity_save']
|
|
},
|
|
constitution_mod:{
|
|
name:'constitution_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{constitution}-10)/2)',
|
|
affects:['constitution_save']
|
|
},
|
|
intelligence_mod:{
|
|
name:'intelligence_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{intelligence}-10)/2)',
|
|
affects:['intelligence_save']
|
|
},
|
|
wisdom_mod:{
|
|
name:'wisdom_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{wisdom}-10)/2)',
|
|
affects:['wisdom_save']
|
|
},
|
|
charisma_mod:{
|
|
name:'charisma_mod',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'floor((@{charisma}-10)/2)',
|
|
affects:['charisma_save']
|
|
},
|
|
strength_save:{
|
|
name:'strength_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
dexterity_save:{
|
|
name:'dexterity_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
constitution_save:{
|
|
name:'constitution_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
intelligence_save:{
|
|
name:'intelligence_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
wisdom_save:{
|
|
name:'wisdom_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
charisma_save:{
|
|
name:'charisma_save',
|
|
defaultValue:0,
|
|
type:'number',
|
|
calculation:'custom',
|
|
affects:[]
|
|
},
|
|
condition_immunities:{
|
|
name:'condition_immunities',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
damage_immunities:{
|
|
name:'damage_immunities',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
damage_resistances:{
|
|
name:'damage_resistances',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
damage_vulnerability:{
|
|
name:'damage_vulnerability',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
athletics:{
|
|
name:'athletics',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
acrobatics:{
|
|
name:'acrobatics',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
drive:{
|
|
name:'drive',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
sleight_of_hand:{
|
|
name:'sleight_of_hand',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
stealth:{
|
|
name:'stealth',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
bureaucracy:{
|
|
name:'bureaucracy',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
computers:{
|
|
name:'computers',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
investigation:{
|
|
name:'investigation',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
life_science:{
|
|
name:'life_science',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
mechanics:{
|
|
name:'mechanics',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
physical_science:{
|
|
name:'physical_science',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
social_science:{
|
|
name:'social_science',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
streetwise:{
|
|
name:'streetwise',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
insight:{
|
|
name:'insight',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
perception:{
|
|
name:'perception',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
survival:{
|
|
name:'survival',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
deception:{
|
|
name:'deception',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
intimidation:{
|
|
name:'intimidation',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
performance:{
|
|
name:'performance',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
persuasion:{
|
|
name:'persuasion',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
skill_notes:{
|
|
name:'skill_notes',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
senses:{
|
|
name:'senses',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
passive_perception:{
|
|
name:'passive_perception',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
languages:{
|
|
name:'languages',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
challenge:{
|
|
name:'challenge',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
experience_points:{
|
|
name:'experience_points',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hacker_level:{
|
|
name:'hacker_level',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hacking_ability:{
|
|
name:'hacking_ability',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hack_dc:{
|
|
name:'hack_dc',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
hack_attack:{
|
|
name:'hack_attack',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'1st_level_slots':{
|
|
name:'1st_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'1st_level_slots':{
|
|
name:'1st_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'2nd_level_slots':{
|
|
name:'2nd_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'3rd_level_slots':{
|
|
name:'3rd_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'4th_level_slots':{
|
|
name:'4th_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
'5th_level_slots':{
|
|
name:'5th_level_slots',
|
|
defaultValue:'',
|
|
affects:[]
|
|
},
|
|
}
|
|
},
|
|
dropDowns = ['repeating_action_$X_attack_ability'],
|
|
hitDice = ['d8_hd','d10_hd','d12_hd'],
|
|
toMonitor = ['strength','dexterity','constitution','intelligence','wisdom','charisma','base_strength','base_dexterity','base_constitution','base_intelligence','base_wisdom','base_charisma','strength_save_proficiency','dexterity_save_proficiency','constitution_save_proficiency','intelligence_save_proficiency','wisdom_save_proficiency','charisma_save_proficiency','class_level','level','athletics_proficiency','acrobatics_proficiency','drive_proficiency','sleight_of_hand_proficiency','stealth_proficiency','bureaucracy_proficiency','computers_proficiency','investigation_proficiency','life_science_proficiency','mechanics_proficiency','physical_science_proficiency','social_science_proficiency','streetwise_proficiency','insight_proficiency','perception_proficiency','survival_proficiency','deception_proficiency','intimidation_proficiency','performance_proficiency','persuasion_proficiency','athletics_proficiency','acrobatics_proficiency','drive_proficiency','sleight_of_hand_proficiency','stealth_proficiency','bureaucracy_proficiency','computers_proficiency','investigation_proficiency','life_science_proficiency','mechanics_proficiency','physical_science_proficiency','social_science_proficiency','streetwise_proficiency','insight_proficiency','perception_proficiency','survival_proficiency','deception_proficiency','intimidation_proficiency','performance_proficiency','persuasion_proficiency','strength_save_base','dexterity_save_base','constitution_save_base','intelligence_save_base','wisdom_save_base','charisma_save_base'],
|
|
repeatingSections = ['repeating_action','repeating_hack','repeating_trait','repeating_equipment'],
|
|
baseGet = [...toMonitor,'proficiency','character_type','strength_mod','dexterity_mod','constitution_mod','intelligence_mod','wisdom_mod','charisma_mod','strength_save','dexterity_save','constitution_save','intelligence_save','wisdom_save','charisma_save','athletics','acrobatics','drive','sleight_of_hand','stealth','bureaucracy','computers','investigation','life_science','mechanics','physical_science','social_science','streetwise','insight','perception','survival','deception','intimidation','performance','persuasion'],
|
|
challengeToXP = {
|
|
'0':10,'1/8':25,'1/4':50,'1/2':100,'1':200,'2':450,'3':700,'4':1100,'5':1800,'6':2300,'7':2900,'8':3900,'9':5000,
|
|
'10':5900,'11':7200,'12':8400,'13':10000,'14':11500,'15':13000,'16':15000,'17':18000,'18':20000,'19':22000,'20':25000,
|
|
'21':33000,'22':41000,'23':50000,'24':62000,'25':75000,'26':90000,'27':105000,'28':120000,'29':135000,'30':155000
|
|
};
|
|
|
|
var registerEventHandlers = function(){
|
|
on('sheet:opened',openSheet);
|
|
['repeating_action:attack_enable_item','repeating_hack:attack_enable_item','repeating_action:damage_1_enable_item','repeating_hack:damage_1_enable_item','repeating_action:damage_2_enable_item','repeating_hack:damage_2_enable_item'].forEach((name)=>{
|
|
on(`change:${name}`,updateActionMacro);
|
|
});
|
|
displayControllers.forEach((attr)=>{
|
|
on(`change:${attr}`,importReact);
|
|
});
|
|
importControls.forEach((attr)=>{
|
|
on(`change:${attr}`,importReact);
|
|
});
|
|
hackLevels.forEach((attr)=>{
|
|
on(`clicked:add_${attr}_hack`,createHack);
|
|
});
|
|
on('change:character_type',changeCharacter);
|
|
on('change:challenge',convertChallenge);
|
|
on('change:hit_dice',averageHP);
|
|
hitDice.forEach((attr)=>{
|
|
on(`change:${attr}`,updateHDmacro);
|
|
});
|
|
[...toMonitor,...repeatingSections].forEach((attr)=>{
|
|
on(`change:${attr}${/repeating/.test(attr) ? ` remove:${attr}` :''}`,(event)=>{
|
|
let triggers = [event.sourceAttribute];
|
|
if(/_mods$/.test(event.sourceAttribute)){
|
|
triggers = extractModTrigger(`${event.newValue},${event.previousValue}`,triggers);
|
|
}else if(event.removedInfo && _.contains(_.keys(event.removedInfo),`${triggers[0]}_mods`)){
|
|
triggers = extractModTrigger(event.removedInfo[`${event.sourceAttribute}_mods`],[]);
|
|
}else if(event.removedInfo){
|
|
return;
|
|
}
|
|
getSections(accessSheet,baseGet,triggers);
|
|
});
|
|
});
|
|
},
|
|
|
|
extractModTrigger = function(string,triggers){
|
|
string.replace(/([+\-=].+?)\s+([^\s,]+)(?:,|$)/ig,(match,value,target)=>{
|
|
target = target.toLowerCase();
|
|
if(/=/.test(value) && target ==='ac'){
|
|
target = 'ac_formula';
|
|
}
|
|
if(!_.contains(triggers,target)){
|
|
triggers.push(target);
|
|
}
|
|
});
|
|
return triggers;
|
|
},
|
|
|
|
accessSheet = function(getArray,sections,triggers){
|
|
const setObj = {};
|
|
getAttrs(getArray,(attributes)=>{
|
|
const buffs = parseBuffs(attributes,sections,triggers);
|
|
if(attributes.character_type === 'pc' && !buffs.ac_formula){
|
|
buffs.ac_formula = [{value:cascades.pc.ac_formula.defaultValue,label:'AC'}];
|
|
}
|
|
triggers = parseTrigger(triggers,attributes.character_type,attributes,buffs,sections);
|
|
triggers = sortTrigger(triggers);
|
|
reactToTrigger(triggers,attributes,setObj,buffs);
|
|
});
|
|
},
|
|
|
|
parseBuffs = function(attributes,sections,triggers){ //parses all of the buffs contained in the repeating_trait, and repeating_equipment items
|
|
// creates an object indexed by attribute to be buffed containing objects that have all of the buffs for that attribute
|
|
// indexed by buff type
|
|
const modRegex = /([+\-=].+?)\s+([^\s,]+)(?:,|$)/ig;//mod expression +X target,+X target,...
|
|
//mod expression can use attribute calls, queries, roll expressions, etc.
|
|
return _.chain(_.keys(attributes))
|
|
.filter((attr_name)=>{
|
|
return /_mods$/.test(attr_name);
|
|
})
|
|
.reject((attr_name)=>{
|
|
return attributes[attr_name] === '' || !attributes[attr_name];
|
|
})
|
|
.reduce((memo,attr_name)=>{
|
|
attributes[attr_name].toLowerCase().replace(modRegex,(match,value,target)=>{
|
|
if(/=/.test(value) && target === 'ac'){
|
|
target = 'ac_formula';
|
|
triggers.push('ac_formula');
|
|
}
|
|
if(/repeating_[^_]+_\$/i.test(target)){
|
|
target.replace(/(repeating_[^_]+_)[^_]+(.+)/,(match,section,field)=>{
|
|
_.each(sections[section],(id)=>{
|
|
memo[`${section}${id}${field}`] = memo[`${section}${id}${field}`] || [];
|
|
let targObj = {
|
|
value:value,
|
|
label:attributes[attr_name.replace('mods','name')]
|
|
};
|
|
memo[`${section}${id}${field}`].push(targObj);
|
|
});
|
|
});
|
|
}else{
|
|
memo[target] = memo[target] || [];
|
|
let targObj = {
|
|
value:value,
|
|
label:attributes[attr_name.replace('mods','name')]
|
|
};
|
|
memo[target].push(targObj);
|
|
}
|
|
});
|
|
return memo;
|
|
},{})
|
|
.tap(log)
|
|
.value();
|
|
},
|
|
|
|
expandRepeating = function(cascade,sections){
|
|
let tempCasc = trueCopy(cascade);
|
|
tempCasc = _.keys(tempCasc).reduce((memo,key)=>{
|
|
if(/^repeating/.test(key)){
|
|
key.replace(/(repeating_[^_]+)_[^_]+_(.+)/,(match,section,field)=>{
|
|
_.each(sections[section].id,(id)=>{
|
|
memo[`${section}_${id}_${field}`]=trueCopy(tempCasc[key]);
|
|
memo[`${section}_${id}_${field}`].affects = memo[`${section}_${id}_${field}`].affects.map((affected)=>{
|
|
return affected.replace(/(repeating_[^_]+_)[^_]+(.+)/,`$1${id}$2`);
|
|
});
|
|
});
|
|
});
|
|
}else{
|
|
memo[key] = trueCopy(tempCasc[key]);
|
|
}
|
|
return memo;
|
|
},{});
|
|
return tempCasc;
|
|
},
|
|
|
|
updateActionMacro = function(event){
|
|
if(event.sourceAttribute === 'attack_enable_item'){
|
|
return;
|
|
}
|
|
getAttrs(['character_type'],(attributes)=>{
|
|
const setObj = {};
|
|
adjustActionMacro(event,attributes,setObj);
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
adjustActionMacro = function(event,attributes,setObj = {}){
|
|
let macroAttr = event.sourceAttribute.replace(/enable_item/,'macro');
|
|
if(event.newValue*1){
|
|
setObj[macroAttr] = `{{d20=[[@{advantage_state} ${attributes.character_type === 'pc' ? '+ @{attack_ability} + @{action_proficiency}' : ''} + 0@{attack_bonus}]]}}`;
|
|
}else if(/{{damage_type_\d=@{damage_type_\d}}} @{damage_\d_macro}/.test(event.newValue)){
|
|
event.sourceAttribute.replace(/_(\d)_/,(match,num)=>{
|
|
setObj[macroAttr] = `{{damage_${num}=[[0@{damage_${num}}${attributes.character_type === 'pc' ? `+ @{damage_ability_${num}}` : ''}]]}} {{regular_critical_${num}=[[0@{damage_${num}}]]}} {{is_custom_crit_${num}=@{critical_damage_${num}}}} {{custom_critical_${num}=[[0@{critical_damage_${num}}]]}}`;
|
|
});
|
|
}else{
|
|
setObj[macroAttr] = ' ';
|
|
}
|
|
set(setObj);
|
|
},
|
|
|
|
trueCopy = function(obj){
|
|
return JSON.parse(JSON.stringify(obj));
|
|
},
|
|
|
|
applyBuffsToCascades = function(cascade,buffs,sections){
|
|
let tempCasc = expandRepeating(cascade,sections);
|
|
_.keys(buffs).forEach((key)=>{
|
|
buffs[key].forEach((buff)=>{
|
|
buff.value.replace(/@{(.+?)}/g,(match,attr)=>{
|
|
if(/repeating_[^_]+_\$[X\d]+/i.test(attr)){
|
|
attr.replace(/(repeating_[^_]+)_[^_]+_(.+)/,(match,section,field)=>{
|
|
sections[section].id.forEach((id)=>{
|
|
if(!_.contains(tempCasc[`${section}_${id}_${field}`].affects)){
|
|
tempCasc[`${section}_${id}_${field}`].affects.push(key);
|
|
}
|
|
});
|
|
});
|
|
}else{
|
|
if(!_.contains(tempCasc[attr].affects)){
|
|
tempCasc[attr].affects.push(key);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return tempCasc;
|
|
},
|
|
|
|
parseTrigger = function(triggers,character_type,attributes,buffs,sections){
|
|
let cascadeCopy = character_type==='pc' ? applyBuffsToCascades(cascades[character_type],buffs,sections) : expandRepeating(cascades[character_type],sections),
|
|
trigQueue,
|
|
trigWorker = (queue,arr) =>{
|
|
arr = arr || [];
|
|
let item = queue.shift(),
|
|
rowID,
|
|
itemLookup = item.replace(/(repeating_[^_]+_)([^_]+)/,(match,section,id)=>{
|
|
rowID = /\$/.test(id) ? undefined : id;
|
|
return `${section}$X`;
|
|
});
|
|
if(cascadeCopy[itemLookup]){
|
|
let parsedItem = {};
|
|
_.keys(cascadeCopy[itemLookup]).forEach((key)=>{
|
|
if(key === 'affects'){
|
|
parsedItem[key] = [];
|
|
let affectArray = cascadeCopy[itemLookup][key];
|
|
_.keys(buffs).forEach((key)=>{
|
|
if(new RegExp(`@{${itemLookup}}`).test(buffs[key].value)){
|
|
affectArray.push(key);
|
|
}
|
|
});
|
|
affectArray = _.unique(affectArray);
|
|
_.each(affectArray,(affected)=>{
|
|
if(/^repeating_/.test(affected)){
|
|
affected.replace(/(repeating_[^_]+_)[^_]+(.+)/,(match,section,field)=>{
|
|
if(rowID){
|
|
parsedItem[key].push(`${section}${rowID}${field}`);
|
|
if(_.every(arr,(item)=>{
|
|
return item.name !== `${section}${rowID}${field}`;
|
|
}) && !_.contains(queue,`${section}${rowID}${field}`)){
|
|
queue.push(`${section}${rowID}${field}`);
|
|
}
|
|
}else{
|
|
_.each(sections[section],(id)=>{
|
|
parsedItem[key].push(`${section}${id}${field}`);
|
|
if(_.every(arr,(item)=>{
|
|
return item.name !== `${section}${id}${field}`;
|
|
}) && !_.contains(queue,`${section}${id}${field}`)){
|
|
queue.push(`${section}${id}${field}`);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}else if(/^variable$/.test(affected)){
|
|
dropDowns.forEach((dropDown)=>{
|
|
dropDown.replace(/(?:(repeating_[^_]+)_[^_]+_)?(.+)/,(match,section,field)=>{
|
|
sections[section].forEach((id)=>{
|
|
if(attributes[`${section}_${id}_${field}`]===`@{${key}}`){
|
|
parsedItem[key].push(`${section}_${id}_${field}`);
|
|
queue.push(`${section}_${id}_${field}`);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}else{
|
|
parsedItem[key].push(affected);
|
|
if(_.every(arr,(item)=>{
|
|
return item.name !== affected;
|
|
}) && !_.contains(queue,affected)){
|
|
queue.push(affected);
|
|
}
|
|
}
|
|
});
|
|
}else{
|
|
parsedItem[key] = `${cascadeCopy[itemLookup][key]}`.replace(/(repeating_[^_]+_)[^_]+/,`$1${rowID||''}`);
|
|
}
|
|
});
|
|
if((cascadeCopy[itemLookup].calculation || itemLookup === 'ac_formula') && _.every(arr,(item)=>{
|
|
return item.name !== parsedItem.name;
|
|
})){
|
|
arr.push(parsedItem);
|
|
}
|
|
}
|
|
if(_.isEmpty(queue)){
|
|
return arr;
|
|
}else{
|
|
return trigWorker(queue,arr);
|
|
}
|
|
};
|
|
return trigWorker(triggers);
|
|
},
|
|
|
|
sortTrigger = function(triggers){
|
|
_.each(triggers,(trigger)=>{
|
|
trigger.order = triggers.reduce((memo,trig,index)=>{
|
|
if(_.contains(trig.affects,trigger.name)){
|
|
memo = trig.order + 1 || index;
|
|
}
|
|
return memo;
|
|
},0);
|
|
});
|
|
return _.sortBy(triggers,(obj)=>{return obj.order});
|
|
},
|
|
|
|
reactToTrigger = function(triggers,attributes,setObj,buffs){
|
|
_.each(triggers,(obj)=>{
|
|
let calc;
|
|
if(obj.calculation === 'custom'){
|
|
calc = customCalcs[obj.name](attributes,triggers,setObj,buffs,obj);
|
|
}else{
|
|
calc = sheetCalc(obj.name,obj.calculation,attributes,setObj,buffs);
|
|
}
|
|
if(!calc && calc !== 0){
|
|
calc = obj.defaultValue;
|
|
}
|
|
attributes[obj.name] = calc;
|
|
setObj[obj.name] = calc;
|
|
});
|
|
set(setObj);
|
|
},
|
|
|
|
calcLevel = function(attributes){
|
|
let level = 0;
|
|
attributes.class_level.replace(/\d+/g,(classLevel)=>{
|
|
level += classLevel*1;
|
|
});
|
|
return level;
|
|
},
|
|
|
|
calcAC = function(attributes,triggers,setObj,buffs){
|
|
return buffs.ac_formula.reduce((memo,buffObj)=>{
|
|
let calc = sheetCalc('ac_formula',buffObj.value,attributes,setObj,buffs);
|
|
if(calc >= memo.value){
|
|
memo = {value:calc,formula:buffObj.value};
|
|
}
|
|
return memo;
|
|
},{value:0}).formula || triggers.ac_formula.defaultValue;
|
|
},
|
|
|
|
npcSaveCalc = function(attributes,triggers,setObj,buffs,trigger){
|
|
let attr = trigger.name.replace(/_save.*/,'');
|
|
return (attributes[`${attr}_save_base`]*1||attributes[`${attr}_save_base`]!=='') ? attributes[`${attr}_save_base`] : attributes[`${attr}_mod`];
|
|
},
|
|
|
|
customCalcs = {
|
|
level:calcLevel,
|
|
ac_formula:calcAC,
|
|
strength_save:npcSaveCalc,
|
|
dexterity_save:npcSaveCalc,
|
|
constitution_save:npcSaveCalc,
|
|
intelligence_save:npcSaveCalc,
|
|
wisdom_save:npcSaveCalc,
|
|
charisma_save:npcSaveCalc
|
|
},
|
|
|
|
sheetCalc = function(name,calculation,attributes,setObj,buffs){
|
|
let parsedCalc = calculation;
|
|
while(/@{([^}]+)}/.test(parsedCalc)){
|
|
parsedCalc.replace(/@{(([^}]+)_modded)}/,(match,store,target)=>{
|
|
attributes[store] = (buffs[target]||[]).map((buffObj)=>{
|
|
return `+ [[${buffObj.value}]][${buffObj.label}]`;
|
|
}).join(' ');
|
|
setObj[store]=attributes[store];
|
|
});
|
|
parsedCalc = attributeParse(parsedCalc,attributes);
|
|
}
|
|
parsedCalc = parsedCalc.replace(/floor|ceil|round|abs/g,'Math.$&').replace(/\[\[|\]\]|\[.*?\]|=/g,'');
|
|
let finalCalc;
|
|
try{
|
|
finalCalc = eval(parsedCalc);
|
|
}catch(err){
|
|
finalCalc = undefined;
|
|
}
|
|
return finalCalc;
|
|
},
|
|
|
|
attributeParse = function(string,attributes){
|
|
return string.replace(/@{([^}]+)}/g,(match,name)=>{
|
|
return attributes[name.toLowerCase()];
|
|
});
|
|
},
|
|
|
|
updateHDmacro = function(event){
|
|
const setObj = {};
|
|
getAttrs(hitDice,(attributes)=>{
|
|
let hdAccumulator = [];
|
|
hitDice.forEach((hd)=>{
|
|
if(attributes[hd] && (attributes[hd]*1!==0 && attributes[hd]!=='')){
|
|
hdAccumulator.push(hd.replace(/_hd/,''));
|
|
}
|
|
});
|
|
hdAccumulator = hdAccumulator.join('|');
|
|
if(/\|/.test(hdAccumulator)){
|
|
hdAccumulator = `?{Die Size|${hdAccumulator}}`;
|
|
}
|
|
setObj.hit_dice_macro = `{{d20=[[?{Number of dice|1}${hdAccumulator} + [[?{Number of dice}*@{constitution_mod}]]]]}}`;
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
convertChallenge = function(event){
|
|
set({experience_points:challengeToXP[event.newValue]||10});
|
|
},
|
|
|
|
averageHP = function(event){
|
|
const setObj = {};
|
|
let numDie,die,bonus;
|
|
event.newValue.replace(/(\d+)\s*d\s*(\d+)(?:\s*([+\-]\s*\d+))?/,(match,n,d,b)=>{
|
|
numDie = n*1||1;
|
|
die = d*1||6;
|
|
bonus = (b+'').replace(/\s*\+\s*/,'')*1||0;
|
|
});
|
|
setObj.hp = bonus + Math.floor(numDie*(die/2+0.5));
|
|
setObj.hp_max = setObj.hp;
|
|
set(setObj);
|
|
},
|
|
|
|
changeDisplay = function(){
|
|
getAttrs([...displayControllers,...importControls],(attributes)=>{
|
|
const setObj = processDisplayChange(attributes);
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
processDisplayChange = function(attributes){
|
|
const setObj = {};
|
|
setObj.master_display_controller = displayControllers.map((attr)=>{
|
|
return `${attr}:${attributes[attr]}`
|
|
}).join(' | ');
|
|
setObj.master_display_controller = `${setObj.master_display_controller} | import:${attributes.import}`;
|
|
return setObj;
|
|
},
|
|
|
|
importReact = function(event){
|
|
const attrToGet = [...displayControllers,...importControls],
|
|
setObj = {};
|
|
let processImport = false;
|
|
if(event.newValue === '0' && event.sourceAttribute === 'import'){
|
|
attrToGet.push('importer');
|
|
processImport = true;
|
|
}else if(event.sourceAttribute === 'import_cancel'){
|
|
setObj.import = '0';
|
|
setObj.import_cancel = '0';
|
|
}
|
|
if(!processImport){
|
|
displayImportChange(attrToGet,setObj);
|
|
}else{
|
|
getSections(beginImport,[...baseGet,...attrToGet]);
|
|
}
|
|
},
|
|
|
|
displayImportChange = function(toGet,setObj){
|
|
getAttrs(toGet,(attributes)=>{
|
|
_.extend(attributes,setObj);
|
|
_.extend(setObj,processDisplayChange(attributes));
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
beginImport = function(toGet,sections){
|
|
let setObj = {};
|
|
wipeSheet(sections,setObj);
|
|
getAttrs(toGet,(attributes)=>{
|
|
if(attributes.importer.trim() === ''){
|
|
setObj.import = 'import';
|
|
}else{
|
|
setObj = {...setObj,...parseStatblock(attributes.importer)};
|
|
setObj.sheet_view = 'in-play';
|
|
attributes = {...attributes,...setObj};
|
|
setObj = {...setObj,...processDisplayChange(attributes)};
|
|
}
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
wipeSheet = function(sections){
|
|
const setObj = {};
|
|
Object.keys(cascades.npc).forEach((k)=>setObj[k]=cascades.npc[k].defaultValue);
|
|
setObj.import = 'import-process';
|
|
_.each(sections,(idArray,section)=>{
|
|
resetRepeatingSection(section,idArray);
|
|
});
|
|
},
|
|
|
|
resetRepeatingSection = function(section,idArray){
|
|
idArray.forEach((id)=>{
|
|
removeRepeatingRow(`${section}_${id}`);
|
|
});
|
|
},
|
|
|
|
parseStatblock = function(statblock){
|
|
if(statblock.trim() === ''){
|
|
return {};
|
|
}
|
|
let parser = headerParser,
|
|
section = 'header',
|
|
lines = statblock.replace(/\s+\n/g,'\n').replace(/[\-–—―−]/g,'-').split(/\n+/),
|
|
setObj = {};
|
|
const Parsers = {//regex as strings for matching against each line to determine if we continue with the current recursive parse, or move onto a new section
|
|
'^\\s*str\\s+dex\\s+con\\s+int\\s+wis\\s+cha':abilityScoreParser,
|
|
'^\\s*(?:saves|skills|senses|languages|challenge|damage resistance)\\s+':detailParser,
|
|
'^\\s*hacking\\.\\s+':hackParser,
|
|
'^\\s*traits$':traitParser,
|
|
'^\\s*actions\\s*$':actionParser
|
|
},
|
|
setParser = (lines) => {//Tests the line and changes the parser if necessary
|
|
return !!Object.keys(Parsers).find( (regexp) => {
|
|
if(new RegExp(regexp,"i").test(lines[0])){
|
|
section = regexp;
|
|
parser = Parsers[regexp];
|
|
if(/actions|^\s*str\s+dex\s+con\s+int\s+wis\s+cha/i.test(lines[0])){//if the section is one of these, then jump to the next line (shift it out of the array)
|
|
lines.shift();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
};
|
|
setObj.character_name = lines.shift();
|
|
while(lines.length){//while there are lines
|
|
setParser(lines);//check the line and see if the parser needs to be changed
|
|
[setObj,lines] = parser(setObj,lines);//call the parser in question, and modify setObj and lines to be what the parser returns
|
|
};
|
|
return setObj;
|
|
},
|
|
|
|
processRegex = function(setObj,currLine,regexs){
|
|
_.keys(regexs).find((r)=>{
|
|
if(new RegExp(r,'i').test(currLine)){
|
|
let objMatch = currLine.match(new RegExp(r,'i'));
|
|
_.each(_.range(regexs[r].length),(l)=>{
|
|
_.each(regexs[r][l],(o)=>{
|
|
setObj[o]=objMatch[l + 1]||'';
|
|
});
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
},
|
|
|
|
headerParser = function(setObj,lines){
|
|
const regexs = {//regexs as strings for matching against lines. the properties are arrays of what attributes (in a sub array) receive the value from each matching group
|
|
'^\\s*(medium|tiny|large|huge)\\s+(.+?)(?:\\s+\\(\\s*(.+?)\\s*\\)|$)':[['size'],['genome'],['modification']],//size and type,
|
|
'^\\s*armor\\s+class\\s+(\\d+)':[['ac']],
|
|
'^\\s*damage\\s+reduction\\s+(\\d+)':[['damage_reduction']],
|
|
'^\\s*hit\\s+points\\s+(\\d+)\\s*\\((.+?)\\)':[['hp','hp_max'],['hit_dice']],
|
|
'^\\s*speed\\s+(.+)':[['speed']]
|
|
};
|
|
processRegex(setObj,lines.shift(),regexs);
|
|
return [setObj,lines];
|
|
},
|
|
|
|
abilityScoreParser = function(setObj,lines){
|
|
const regexs = {//regexs as strings for matching against lines. the properties are arrays of what attributes (in a sub array) receive the value from each matching group
|
|
'^\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)\\s*(\\d+)\\s*\\(\\+?(\\-?\\d+)\\)':[['strength'],['strength_mod'],['dexterity'],['dexterity_mod'],['constitution'],['constitution_mod'],['intelligence'],['intelligence_mod'],['wisdom'],['wisdom_mod'],['charisma'],['charisma_mod']]
|
|
};
|
|
processRegex(setObj,lines.shift(),regexs);
|
|
return [setObj,lines];
|
|
},
|
|
|
|
detailParser = function(setObj,lines){
|
|
const regexs = {//regexs as strings for matching against lines. the properties are arrays of what attributes (in a sub array) receive the value from each matching group
|
|
'^\\s*senses\\s+passive perception (\\d+)(?:,\\s*(.+?))?$':[['passive_perception'],['senses']],
|
|
'^\\s*damage\\s+resistance\s+(.+)':[['damage_resistance']],
|
|
'^\\s*languages\\s+(.+)':[['languages']],
|
|
'^\\s*challenge\\s+([\\d\\/]+)\\s*\\(([\\d,]+)\\s*xp\\)':[['challenge'],['experience_points']]
|
|
};
|
|
let line = assembleDetailLine(lines);
|
|
if(/^\s*skills\s+/i.test(line)){
|
|
parseSkills(setObj,line);
|
|
}else if(/^\s*senses\s+/i.test(line)){
|
|
parseSenses(setObj,line);
|
|
}else{
|
|
processRegex(setObj,line,regexs);
|
|
}
|
|
if(/^\s*challenge/i.test(line) && !/^\s*(hacking\.|actions)/i.test(lines[0])){
|
|
lines.unshift('trait');
|
|
}
|
|
return [setObj,lines];
|
|
},
|
|
|
|
assembleDetailLine = function(lines,line){
|
|
line = line ? `${line} ${lines.shift()}` : lines.shift();
|
|
return /^\s*(?:saves|skills|senses|languages|challenge|damage resistance|hacking|actions)/i.test(lines[0]) ? line : assembleDetailLine(lines,line);
|
|
},
|
|
|
|
parseSkills = function(setObj,line){
|
|
line.replace(/(?:,\s*|skills\s+)(.+?)\s+\+?(\-?\d+)/ig,(match,skill,bonus)=>{
|
|
setObj[skill.replace(/\s+/,'_').toLowerCase()]=bonus;
|
|
});
|
|
},
|
|
|
|
parseSenses = function(setObj,line){
|
|
line.replace(/senses\s*(?:(.+?),\s*)?passive \s*perception\s*(\d+)(?:,\s*(.+?))?$/i,(match,senses,pp='',senses2)=>{
|
|
setObj.passive_perception = pp;
|
|
setObj.senses = [senses,senses2].filter(a=>a).join(', ');
|
|
});
|
|
},
|
|
|
|
hackParser = function(setObj,lines){
|
|
let line = assembleHackerDetails(lines);
|
|
line.replace(/.+?(\d+)(?:st|th|rd).+?ability is (strength|dexterity|constitution|intelligence|wisdom|charisma).+?DC\s*(\d+).+?(\-?\d+) to hit/,(match,level,ability,dc,attack)=>{
|
|
setObj.hacker_level = level;
|
|
setObj.hacking_ability = ability;
|
|
setObj.hack_dc = dc;
|
|
setObj.hack_attack = attack;
|
|
});
|
|
processHacks(setObj,lines);
|
|
if(/.+\./.test(lines[0])){
|
|
lines.unshift('traits')
|
|
}
|
|
return [setObj,lines];
|
|
},
|
|
|
|
assembleHackerDetails = function(lines){
|
|
let line = lines.shift();
|
|
while(!/:/.test(line) && lines.length){
|
|
line = `${line} ${lines.shift()}`;
|
|
}
|
|
return line.toLowerCase();
|
|
},
|
|
|
|
processHacks = function(setObj,lines){
|
|
while(lines.length && !/.+\.|actions/i.test(lines[0])){
|
|
let line = assembleHackLevel(lines);
|
|
line.replace(/(\d+)(st|rd|th)\s+level\s*\((\d+)\s+slots\):(.+)/,(match,level,ordinal,slots,hacks)=>{
|
|
setObj[`${level}${ordinal}_level_slots`] = slots;
|
|
hacks = hacks.trim().split(/\s*,\s*/);
|
|
hacks.forEach((hack)=>{
|
|
importHack(setObj,hack,level);
|
|
});
|
|
});
|
|
}
|
|
},
|
|
|
|
assembleHackLevel = function(lines){
|
|
let line = lines.shift();
|
|
while(lines.length && !/.+(?:\.|:)|actions/i.test(lines[0])){
|
|
line = `${line} ${lines.shift()}`;
|
|
}
|
|
return line;
|
|
},
|
|
|
|
importHack = function(setObj,hack,level){
|
|
const rowID = generateRowID();
|
|
setObj[`repeating_hack_${rowID}_level`] = level;
|
|
setObj[`repeating_hack_${rowID}_hack_type`] = 'injection';
|
|
setObj[`repeating_hack_${rowID}_id`] = rowID;
|
|
setObj[`repeating_hack_${rowID}_name`] = hack;
|
|
},
|
|
|
|
traitParser = function(setObj,lines){
|
|
if(/^\s*traits$/.test(lines[0])){
|
|
lines.shift();
|
|
}
|
|
let regex = /(?:.+\.|actions)\s*$/i;
|
|
do{
|
|
let line = assembleTraitDetails(lines);
|
|
importTrait(setObj,line);
|
|
}while(lines.length && !regex.test(lines[0]))
|
|
return [setObj,lines];
|
|
},
|
|
|
|
importTrait = function(setObj,line){
|
|
const rowID = generateRowID();
|
|
line.replace(/^(.+?)\.\s*(.+)/,(match,name,description)=>{
|
|
setObj[`repeating_trait_${rowID}_description`] = description;
|
|
setObj[`repeating_trait_${rowID}_id`] = rowID;
|
|
setObj[`repeating_trait_${rowID}_name`] = name;
|
|
setObj[`repeating_trait_${rowID}_expand_item`] = 0;
|
|
});
|
|
},
|
|
|
|
//collects lines to create the entire paragraph of a trait. If action is truthy, then it will parse for an action's details
|
|
assembleTraitDetails = function(lines,action){
|
|
let line = lines.shift();
|
|
while(lines.length && !/\.\s*$/.test(line)){
|
|
line = `${line} ${lines.shift()}`;
|
|
}
|
|
return line;
|
|
},
|
|
|
|
actionParser = function(setObj,lines){
|
|
do{
|
|
let line = assembleTraitDetails(lines,true);
|
|
importAction(setObj,line);
|
|
}while(lines.length && /^(?:.+\.).+/.test(lines[0]))
|
|
return [setObj,lines];
|
|
},
|
|
|
|
importAction = function(setObj,line){
|
|
const rowID = generateRowID();
|
|
line.replace(/^(.+?)\.\s+((?:ranged|melee)\s+weapon\s+attack:.+?(\-?\d+).+?(?:range|reach)\s+(.+?),\s*(.+?)\..+?\((.+?)\)\s*(.*?)\.\s*(.+)?|.+)/i,(match,name,details,attack,range,target,damageRoll,damageType,description)=>{
|
|
setObj[`repeating_action_${rowID}_id`] = rowID;
|
|
setObj[`repeating_action_${rowID}_name`] = name;
|
|
if(attack){
|
|
setObj[`repeating_action_${rowID}_attack_bonus`] = attack;
|
|
setObj[`repeating_action_${rowID}_bonus`] = attack;
|
|
setObj[`repeating_action_${rowID}_attack_enable_item`] = 1;
|
|
setObj[`repeating_action_${rowID}_attack_macro`] = '{{d20=[[@{advantage_state} + 0@{attack_bonus}]]}}';
|
|
}
|
|
if(damageRoll){
|
|
setObj[`repeating_action_${rowID}_damage_1`] = damageRoll;
|
|
setObj[`repeating_action_${rowID}_damage_type_1`] = damageType||'';
|
|
setObj[`repeating_action_${rowID}_damage_1_enable_item`] = '{{damage_type_1=@{damage_type_1}}} @{damage_1_macro}';
|
|
setObj[`repeating_action_${rowID}_damage_1_macro`] = `{{damage_${num}=[[0@{damage_${num}}]]}} {{regular_critical_${num}=[[0@{damage_${num}}]]}} {{is_custom_crit_${num}=@{critical_damage_${num}}}} {{custom_critical_${num}=[[0@{critical_damage_${num}}]]}}`;
|
|
}
|
|
if(description){
|
|
setObj[`repeating_action_${rowID}_description`] = description||'';
|
|
}else if(!attack&&!range&&!target&&!damageRoll&&!damageType){
|
|
setObj[`repeating_action_${rowID}_description`] = details;
|
|
}
|
|
setObj[`repeating_action_${rowID}_range`] = range||'';
|
|
setObj[`repeating_action_${rowID}_expand_item`] = 0;
|
|
});
|
|
},
|
|
|
|
createHack = function(event){
|
|
const setObj = {},
|
|
rowID = generateRowID(),
|
|
[hackLevel] = event.triggerName.match(/\d+/);
|
|
setObj[`repeating_hack_${rowID}_level`] = hackLevel;
|
|
setObj[`repeating_hack_${rowID}_hack_type`] = 'injection';
|
|
setObj[`repeating_hack_${rowID}_id`] = rowID;
|
|
set(setObj);
|
|
},
|
|
|
|
changeCharacter = function(event){
|
|
const switcher = {
|
|
npc:NPC,
|
|
pc:PC
|
|
};
|
|
getSections(switcher[event.newValue]);
|
|
},
|
|
|
|
PC = function(getArray,sections){
|
|
const setObj = {
|
|
whisper_state:''
|
|
};
|
|
_.keys(skillList).forEach((skill)=>{
|
|
setObj[`${skill}_macro`]=`{{d20=[[@{advantage_state} + @{${skill}_proficiency}[Proficiency] + @{${skillList[skill]}_mod}[${skillList[skill].toUpperCase()}] @{${skill}_bonus}]]}}`
|
|
});
|
|
_.keys(abilityScores).forEach((abbreviation)=>{
|
|
setObj[`${abilityScores[abbreviation]}_check_macro`]=`{{d20=[[@{advantage_state} + @{${abilityScores[abbreviation]}_mod}[${abbreviation.toUpperCase()}] @{${abilityScores[abbreviation]}_bonus}]]}}`;
|
|
setObj[`${abilityScores[abbreviation]}_save_macro`]=`{{d20=[[@{advantage_state} + @{${abilityScores[abbreviation]}_mod}[${abbreviation.toUpperCase()}] + @{${abilityScores[abbreviation]}_save_proficiency}[Proficiency] @{${abilityScores[abbreviation]}_save_bonus}]]}}`;
|
|
});
|
|
sections.repeating_trait.forEach((id)=>{
|
|
setObj[`repeating_trait_${id}_macro`]='{{source=@{source}}}';
|
|
});
|
|
['repeating_hack','repeating_action'].forEach((section)=>{
|
|
sections[section].forEach((id)=>{
|
|
setObj[`repeating_hack_${id}_attack_macro`]='{{d20=[[@{advantage_state} + @{attack_ability} + @{action_proficiency} + 0@{attack_bonus}]]}}';
|
|
setObj[`repeating_hack_${id}_save_macro`]='{{dc=[[8 + @{save_ability} + @{action_proficiency} + 0@{dc_bonus}]]}}';
|
|
[1,2].forEach((num)=>{
|
|
setObj[`${section}_${id}_damage_${num}_macro`]=`{{damage_${num}=[[0@{damage_${num}} + @{damage_ability_${num}}]]}} {{regular_critical_${num}=[[0@{damage_${num}}]]}} {{is_custom_crit_${num}=@{critical_damage_${num}}}} {{custom_critical_${num}=[[0@{critical_damage_${num}}]]}}`;
|
|
});
|
|
});
|
|
});
|
|
set(setObj,changeDisplay);
|
|
},
|
|
|
|
NPC = function(getArray,sections){
|
|
const setObj = {
|
|
whisper_state:'/w gm'
|
|
};
|
|
_.keys(skillList).forEach((skill)=>{
|
|
setObj[`${skill}_macro`]=`{{d20=[[@{advantage_state} + @{${skill}} @{${skill}_bonus}]]}}`
|
|
});
|
|
_.keys(abilityScores).forEach((abbreviation)=>{
|
|
setObj[`${abilityScores[abbreviation]}_check_macro`]=`{{d20=[[@{advantage_state} + @{${abilityScores[abbreviation]}_mod}[${abbreviation.toUpperCase()}] @{${abilityScores[abbreviation]}_bonus}]]}}`;
|
|
setObj[`${abilityScores[abbreviation]}_save_macro`]=`{{d20=[[@{advantage_state} + @{${abilityScores[abbreviation]}_save}[${abbreviation.toUpperCase()}] @{${abilityScores[abbreviation]}_save_bonus}]]}}`;
|
|
});
|
|
sections.repeating_trait.forEach((id)=>{
|
|
setObj[`repeating_trait_${id}_macro`]='';
|
|
});
|
|
['repeating_hack','repeating_action'].forEach((section)=>{
|
|
sections[section].forEach((id)=>{
|
|
setObj[`${section}_${id}_attack_macro`]='{{d20=[[@{advantage_state} + 0@{attack_bonus}]]}}';
|
|
setObj[`${section}_${id}_save_macro`]='{{dc=[[0@{dc_bonus}]]}}';
|
|
[1,2].forEach((num)=>{
|
|
setObj[`${section}_${id}_damage_${num}_macro`]=`{{damage_${num}=[[0@{damage_${num}}]]}} {{regular_critical_${num}=[[0@{damage_${num}}]]}} {{is_custom_crit_${num}=@{critical_damage_${num}}}} {{custom_critical_${num}=[[0@{critical_damage_${num}}]]}}`;
|
|
});
|
|
});
|
|
});
|
|
|
|
set(setObj,changeDisplay);
|
|
},
|
|
|
|
getSections = function(callback,getArray,trigger,sections,queue){
|
|
queue = queue || JSON.parse(JSON.stringify(repeating_section_details));
|
|
getArray = getArray || [];
|
|
sections = sections || {};
|
|
let section = queue.shift();
|
|
getSectionIDs(section.section,(idArray)=>{
|
|
sections[section.section]=[];
|
|
idArray.forEach((id)=>{
|
|
sections[section.section].push(id);
|
|
section.fields.forEach((field)=>{
|
|
getArray.push(`${section.section}_${id}_${field}`);
|
|
});
|
|
});
|
|
if(_.isEmpty(queue)){
|
|
callback(getArray,sections,trigger);
|
|
}else{
|
|
getSections(callback,getArray,trigger,sections,queue);
|
|
}
|
|
});
|
|
},
|
|
|
|
log = function(msg){
|
|
const sheetName = 'Genefunk2090';
|
|
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]);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
openSheet = function(){
|
|
getSections(updateSheet,baseGet);
|
|
},
|
|
|
|
updateSheet = function(getArray,sections){
|
|
const setObj = {};
|
|
getAttrs([...getArray,'sheet_version'],(attr)=>{
|
|
if(!attr.sheet_version){
|
|
attr.sheet_version = 0;
|
|
}
|
|
if(attr.sheet_version*1 < 1.1) updateTo1_1(attr,setObj);//First update applied
|
|
if(attr.sheet_version*1 < 1.12) updateTo1_12(attr,setObj);//update 1.12; npc hp attribute change
|
|
if(attr.sheet_version*1 < 1.20) updateTo1_20(attr,setObj);
|
|
set(setObj);
|
|
});
|
|
},
|
|
|
|
updateTo1_20 = function(attr,setObj){
|
|
const damageEnablers = Object.keys(attr).filter(k => /(?:attack|damage_\d)_enable_item/.test(k));
|
|
damageEnablers.forEach(d => adjustActionMacro({sourceAttribute:d,triggerName:d,newValue:attr[d]},attr,setObj));
|
|
if(attr.character_type === 'npc'){
|
|
setObj.hit_points = attr.hp
|
|
setObj.hit_points_max = attr.hp_max;
|
|
}
|
|
attr = {...attr,...setObj};
|
|
setObj.sheet_version = 1.20;
|
|
},
|
|
|
|
updateTo1_12 = function(attr,setObj){
|
|
if(attr.character_type === 'npc'){
|
|
setObj.hp = attr.hit_points;
|
|
setObj.hp_max = attr.hit_points_max;
|
|
}
|
|
attr = {...attr,...setObj};
|
|
setObj.sheet_version = 1.12;
|
|
},
|
|
|
|
updateTo1_1 = function(attr,setObj){
|
|
let enableItems = Object.keys(attr).filter((a)=>/attack_enable_item/.test(a));
|
|
enableItems.forEach((check)=>{
|
|
let macroName = check.replace(/attack_enable_item/,'attack_macro');
|
|
if(/@/.test(attr[check])){
|
|
setObj[check] = 1;
|
|
setObj[macroName] = `{{d20=[[@{advantage_state} ${attr.character_type === 'pc' ? '+ @{attack_ability} + @{action_proficiency}' : ''} + 0@{attack_bonus}]]}}`;
|
|
}else if(!attr[check]*1){
|
|
setObj[macroName] = ' ';
|
|
setObj[check] = 0;
|
|
}
|
|
});
|
|
setObj.sheet_version = 1.1;
|
|
attr = {...attr,...setObj};
|
|
},
|
|
|
|
bootUp = function(){
|
|
log(`Sheet Starting up`);
|
|
},
|
|
|
|
set = function(obj,callback){
|
|
setAttrs(obj,{silent:true},callback)
|
|
};
|
|
return {
|
|
BootUp: bootUp,
|
|
RegisterEventHandlers: registerEventHandlers
|
|
};
|
|
}());
|
|
genefunk2090.BootUp();
|
|
genefunk2090.RegisterEventHandlers(); |