Files
roll20-character-sheets/Delta Green 2/deltagreen_scripts.html
T
uriele f0119aa6df fix
- update version to correctly read weapons
- convert npc of previous sheet to npc of new one importing named skills
- fixed space between words
2024-09-02 08:34:20 +02:00

3531 lines
126 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// check initialization so it updates only once per game at most
var _isInitialized = false;
// === ATTRIBUTE ARRAYS
const arrays = {
_stats: ['strength', 'constitution', 'dexterity', 'intelligence', 'power', 'charisma'],
_derived_stats: ['hit_points', 'sanity_points', 'willpower_points', 'breaking_point'],
_derived_stats_max: ['sanity_points_max','hit_points_max', 'willpower_points_max', 'breaking_point_max'],
_hit_points: ['strength_score', 'constitution_score'],
_willpower_points: ['power_score'],
_toggles: ['settings'],
_sanity_loss: ['sanity_loss_success', 'sanity_loss_failure'],
_skills:['accounting', 'alertness', 'anthropology', 'archeology', 'art_1', 'art_2', 'artillery', 'athletics', 'bureaucracy', 'computer_science', 'craft_1', 'craft_2', 'criminology', 'demolitions', 'disguise', 'dodge', 'drive', 'firearms','first_aid', 'forensics', 'heavy_machinery', 'heavy_weapons', 'history', 'humint', 'law', 'medicine', 'melee_weapons', 'military_science_1', 'military_science_2', 'navigate', 'occult', 'persuade', 'pharmacy', 'pilot_1','pilot_2', 'psychotherapy','ride', 'science_1','science_2', 'search' , 'sigint' , 'stealth' , 'surgery' , 'survival', 'swim', 'unarmed_combat'],
_colored_derivative:['willpower','hit'],
_derived_rolls:['sanity_points','luck'],
_disorder_related:['sanity_points','breaking_point'],
_derived_modifiers:['willpower_points','low_willpower','zero_willpower'],
_settings_wp:[`mod_willpower_check`],
_adaptation:['violence','helplessness'],
_editable_skills:['art_1','art_2','craft_1','craft_2','military_science_1','military_science_2','pilot_1','pilot_2','science_1','science_2'],
_weapon :["name", "skill_percent", "base_range", "damage", "armor_piercing", "lethality_percent", "ammo"],
_rituals : ['name','skill_span','unnatural_gain','study_time','sanity_loss_for_learning','activation_time','description','complexity'],
_personal_data : [
'profession',
'employer',
'occupation',
'nationality_and_residence',
'sex',
'age',
'education',
'personal_details_and_notes',
'developments_which_affect_home_and_family',
'description',
'physical_description',
'npc_sources',
'npc_remarks'],
_advanced_weapons_featurs : [`shotgun`,`blast_radius`,`hasDoubleBarrel`,`selfire`,'accessories'],
_weapon_hidden_buttons : ['damage','lethality_percent','double_barrel','selective_fire'],
_ritual_hidden_buttons : ['pay_cost','force_connection','accept_failure','attack','heal','power'],
};
const _skill_percent = [
{section:'skills', field:'rank'},
{section:'special', field:'skill_or_stat_used'},
{section:'weapons' , field:'skill_percent'},
{section:'rituals', field:'skill_percent'}
];
const _initial_skills={'accounting': 10, 'alertness': 20, 'anthropology': 0, 'archeology': 0, 'art_1': 0,
'art_2': '0', 'artillery': 0, 'athletics': 30, 'bureaucracy': 10, 'computer_science': 0,
'craft_1': 0, 'craft_2': 0, 'criminology': 10, 'demolitions': 0, 'disguise': 10, 'dodge': 30,
'drive': 20, 'firearms': 20, 'first_aid': 10, 'forensics': 0, 'heavy_machinery': 10, 'heavy_weapons': 0,
'history': 10, 'humint': 10, 'law': 0, 'medicine': 0, 'melee_weapons': 30, 'military_science_1': 0,
'military_science_2': 0, 'navigate': 10, 'occult': 10, 'persuade': 20, 'pharmacy': 0, 'pilot_1': 0,
'pilot_2': 0, 'psychotherapy': 10, 'ride': 10, 'science_1': 0, 'science_2': 0, 'search': 20, 'sigint': 0,
'stealth': '10', 'surgery': 0, 'survival': 10, 'swim': 20, 'unarmed_combat': 40,'unnatural': 0};
const _repeating_sections={
'skill':'skills',
'bond':'bonds',
'special':'special',
'weapons':'weapons',
'ritual':'rituals'
};
const _score_info = [
`willpower_points_max`,
`character_creation_bonds`,
`repeating_bonds_setScore`,
`repeating_bonds_score`,
`repeating_bonds_score_old`,
`repeating_bonds_color`
];
const _bond_attributes = [
`name`,
`test`,
`score`,
`hurt`,
];
const _repeating_damages = [
'damage',
'damage_critical',
'lethality_percent',
'lethality_percent_critical',
'double_barrel',
'double_barrel_critical',
'selective_fire',
'selective_fire_critical',
]
const _repeating_ammo = [
'hasammo',
'ammo',
'ammo_total'
]
const _rd100 = `[[1d100]]`;
const _rd4 = `[[1d4]]`;
const _rd6 = `[[1d6]]`;
const _rd8 = `[[1d8]]`;
const _rd10 = `[[1d10]]`;
const _rd12 = `[[1d12]]`;
const _rd20 = `[[1d20]]`;
const _INHUMAN_STAT_ = 100;
const _criticals=[1,11,22,33,44,55,66,77,88,99,100];
const _queryModifier = `?{Modifier|0|+20%,20|+40%,40|-20%,-20|-40%,-40|custom (%),?{custom (%)}}`;
const prefix_skill_roll = `@{gm_toggle} &{template:fancy-rolls} {{name=@{character_name}}} {{dice=[[${_rd100}]]}}`;
const prefix_sanity_roll = `@{gm_toggle} &{template:fancy-sanloss} `;
// roll to use in rituals
// isHealing -> -1 for attack, 1 for heal, 0 for normal damages
const prefix_attack_roll = `@{gm_toggle} &{template:fancy-damages} {{name=@{character_name}}} {{isHealing=[[-1]]}} {{trackbullets=[[0]]}} {{header=^{attack}}}`;
const prefix_health_roll = `@{gm_toggle} &{template:fancy-damages} {{name=@{character_name}}} {{isHealing=[[1]]}} {{trackbullets=[[0]]}} {{header=^{heal} }}`;
// roll to use in weapons
const prefix_damage_roll = `@{gm_toggle} &{template:fancy-damages} {{name=@{character_name}}} {{isHealing=[[0]]}} {{usAiming=[[0]]}}`;
const prefix_bond_roll = `@{gm_toggle} &{template:fancy-bonds} {{character_id=@{character_id}}}{{name=@{character_name}}} {{dice=[[${_rd4}]]}}`;
const prefix_ritual_roll = `@{gm_toggle} &{template:fancy-rituals} {{name=@{character_name}}} {{dice=[[${_rd100}]]}}`;
const prefix_ritualloss_roll = `@{gm_toggle} &{template:fancy-ritualloss} {{name=@{character_name}}} {{header=^{ritual cost}}}`;
const _shotgun_or_blast_radius =[`shotgun`,`blast_radius`];
const _alldamages=['damage','damage_critical','double_barrel','double_barrel_critical',
'lethality_percent','lethality_percent_critical','selective_fire','selective_fire_critical'
];
const _ritual_damages=['attack','heal','power'];
const _type_damages=['damage','lethality_percent'];
const _ritual_losses=['pay_cost','force_connection','accept_failure'];
const _allrolls=arrays['_derived_rolls'].concat(arrays[`_stats`],arrays[`_skills`],['unnatural','sanity_loss']);
const RitualCosts = ['sanity_loss_success','sanity_loss_failure',
'willpower_points_cost','power_score_cost','hit_points_cost',
'strength_score_cost','constitution_score_cost',
'dexterity_score_cost','intelligence_score_cost',
'charisma_score_cost'];
const CurrentValues = ['sanity_points',
'willpower_points','power_score','hit_points',
'strength_score','constitution_score',
'dexterity_score','intelligence_score',
'charisma_score'];
const RitualRolls = ['name','skill_span','unnatural_gain',
'study_time','sanity_loss_for_learning','activation_time',
'description','complexity','flawed_ritual','power_reaction'];
const RitualDamages = ['attack_target_stat','attack_damage_amount','attack_lethality_percent_amount','attack_isLethal'];
const RitualHeals = ['heal_target_stat','heal_damage_amount','heal_lethality_percent_amount','heal_isLethal'];
const _ritualInfo=[
'complexity',
'activation_time',
'activation_time_unit',
'study_time',
'study_time_unit',
'unnatural_gain',
'sanity_loss_for_learning',
'willpower_points_cost',
'power_score_cost',
'hit_points_cost',
'strength_score_cost',
'constitution_score_cost',
'dexterity_score_cost',
'intelligence_score_cost',
'charisma_score_cost',
'sanity_loss_success',
'sanity_loss_failure'
]
const selector='button.roll';
const sanity_selector='button.sanroll';
let _globalModifier = 0;
const _number_or_roll= [
{section:'weapons', fields:['damage','double_barrel']},
{section:'rituals',fields:['sanity_loss_low','sanity_loss_high','attr_sanity_loss_for_learning','attr_unnatural_gain','heal_damage_amount','attack_damage_amount','willpower_points_cost','healpoints_cost','strength_score_cost','constitution_score_cost','dexterity_score_cost','intelligence_score_cost','charisma_score_cost','power_score_cost']}
];
const _only_number=[
{section:'weapons', fields:['lethality_percent','selfire_lethality_percent','accessory_modifier']},
{section:'rituals',fields:['attack_lethality_percent_amount','heallethality_percent_amount']}
];
const setWeaponOptions = ({isFlawed=0, isAiming=0 ,modifier=0,wp_mod={low_willpower:0,zero_willpower:0},hasLethality=0,
hasDamage=0,damage='',rating=0,lethality_percent=0,hasAdvancedWeapons=0,isShotgun=0,hasDoubleBarrel=0,hasSelectiveFire=0,
hasAccessories=0,hasBlastRadius=0, trackAmmo=0,current_ammo=0,double_barrel='',selfire_lethality_percent=0,selfire_type='',
accessory_modifier=0,accessory_name='',isSkill=1}) => {
const _hasAdvancedWeapons=hasAdvancedWeapons;
const _hasLethality= hasLethality;
const _hasDamage=hasDamage;
const _trackAmmo=trackAmmo;
const _rating=rating;
const _isSkill=isSkill;
const _modifier=modifier;
const _wp_mod=wp_mod;
const _isFlawed=isFlawed;
const _isAiming=isAiming;
var _isShotgun=0;
var _hasDoubleBarrel=0;
var _hasSelectiveFire=0;
var _hasAccessories=0;
var _hasBlastRadius=0;
var _double_barrel=double_barrel;
var _selfire_lethality_percent=selfire_lethality_percent;
var _selfire_type=selfire_type;
var _selfire_ammo=0;
var _current_ammo=current_ammo;
const _has_ammo=(_current_ammo>0) ? 1 : 0;
var _accessory_modifier=accessory_modifier;
var _accessory_name=(accessory_name==='') ? '^{accessory}' : accessory_name;
var _damage='';
var _lethality_percent=0;
var _low_willpower=0;
var _zero_willpower=0;
if (_wp_mod.hasOwnProperty('low_willpower')) { _low_willpower=_wp_mod.low_willpower; }
if (_wp_mod.hasOwnProperty('zero_willpower')) { _zero_willpower=_wp_mod.zero_willpower; }
if (_hasDamage==1) { _damage=damage; }
if (_hasLethality==1) { _lethality_percent=lethality_percent; }
if (_hasAdvancedWeapons==1) {
_isShotgun=isShotgun;
_hasDoubleBarrel=hasDoubleBarrel;
_hasSelectiveFire=hasSelectiveFire;
_hasAccessories=hasAccessories;
_hasBlastRadius=hasBlastRadius;
}
if (hasDoubleBarrel==1) { _double_barrel=double_barrel; }
if (hasSelectiveFire==1) {
_selfire_lethality_percent=selfire_lethality_percent;
_selfire_type=selfire_type;
_selfire_ammo=getRollDamage(selfire_type);
}
return { hasLethality: _hasLethality,lethality_percent: _lethality_percent, isSkill: _isSkill, rating: _rating,
hasDamage: _hasDamage,damage: _damage,
isShotgun: _isShotgun,hasDoubleBarrel: _hasDoubleBarrel,
hasSelectiveFire: _hasSelectiveFire,hasAccessories: _hasAccessories,hasBlastRadius: _hasBlastRadius,
trackAmmo: _trackAmmo,current_ammo: _current_ammo, double_barrel: _double_barrel,
selfire_lethality_percent: _selfire_lethality_percent, selfire_type: _selfire_type, selfire_ammo: _selfire_ammo,
accessory_modifier: _accessory_modifier,
accessory_name: _accessory_name,hasAdvancedWeapons: _hasAdvancedWeapons,
zero_willpower: _zero_willpower, low_willpower: _low_willpower, modifier: _modifier,
isFlawed: _isFlawed, isAiming: _isAiming};
};
const getInitializationFlags = (statInfo,values) => {
// note: flags are INITIALLY set to 1, it was a mistake but now it's better to keep it that way
const statName=statInfo['name'];
const _stat_used={
strength:'initial_str',
constitution:'initial_con',
};
const InitializationFlags={
'initial_hp':1,
'initial_str':1,
'initial_con':1,
'initial_san':1
};
Object.keys(InitializationFlags).forEach((key)=>{
if (values.hasOwnProperty(key) && values[key] == 0){ InitializationFlags[key]=0;}
});
if (_stat_used.hasOwnProperty(statName)) { InitializationFlags[_stat_used[statName]]=0;}
console.info('InitializationFlags:',InitializationFlags);
return InitializationFlags;
};
const setInitialHp = (update,values,statInfo,InitializationFlags) => {
if (statInfo['name'] !== 'strength' && statInfo['name'] !== 'constitution') { return; } // check if the stat is strength or constitution
if (statInfo['name'] == 'strength') {InitializationFlags[`initial_str`]=0;} // set the initial strength to 0
if (statInfo['name'] == 'constitution') {InitializationFlags[`initial_con`]=0;} // set the initial constitution to 0
if (InitializationFlags['initial_str']==1 || InitializationFlags['initial_con']==1) { return; } // if either flag is set, I cannot set the initial hp
///////// Set Hp regardless of the initial hp
const _strength_score=Math.max(0,parseInt(values['strength_score'],10)||0);
const _constitution_score=Math.max(0,parseInt(values['constitution_score'],10)||0);
const initial_hit_points= Math.ceil((_strength_score+_constitution_score)/2); // update max hp regardless of the initial hp
update['hit_points_max']=initial_hit_points;
//////// If the initial hp is not set yet, set it
if (InitializationFlags['initial_hp']==0) { return; } // check if initial hp is already set
update['hit_points']=initial_hit_points;
update['hit_points_old']=initial_hit_points;
InitializationFlags['initial_hp']=0;
};
const setInitialPower = (update,values,statInfo,InitializationFlags) => {
if (statInfo['name'] !== 'power') { return; } // only power can change the sanity points
const sanmax=setSanMax(values[`unnatural`]);
const InitialWillPower = statInfo.score;
update[`willpower_points_max`]=InitialWillPower;
// only updates if the flag is set
update['sanity_points_max']=sanmax;
if (InitializationFlags['initial_san']==0) { return; }
const InitialSanity = statInfo.stat;
const InitialBreakingPoint = statInfo.score*4;
//update['initial_san']=0;
update['sanity_points']= InitialSanity;
update['sanity_points_old']= InitialSanity;
update['breaking_point']= InitialBreakingPoint;
update['breaking_point_max']= InitialBreakingPoint;
update['willpower_points']=InitialWillPower;
InitializationFlags['initial_san']=0;
};
const setStatScore=(score,statName) =>{
const validNames=['strength','constitution','dexterity','power','intelligence','charisma'];
if (!validNames.includes(statName)) { return false; }
const _score = Math.max(0,parseInt(score));
return {name: statName, stat: _score*5, score: _score};
};
const setSanMax = (unnatural) => {
// Input:
// unnatural is the unnatural value
// Output:
// the maximum value for sanity points
return 99-setMinMax(unnatural,0,99);
};
const setDiceSection = (character_id,repsecid,use_=true) => {
// Input:
// charid is the character id
// repsecid is the repeating section id
// Output:
// ](~<charid>|<repsecid>_
return '](~'+ character_id +'|'+repsecid+ ((use_) ? '_' : '');
}
const setAdvancedWeaponsString = (options,character_id,repsecid) => {
var advancedWeaponsString='';
const dice_section = setDiceSection(character_id,repsecid);
const nothing_section = setDiceSection(character_id,'nothing)}}',false);
const rollEnding='-action)}}';
if (options.hasAdvancedWeapons===1) {
if (options.isShotgun===1) {advancedWeaponsString += '{{shotgun=[[1]]}}';}
if (options.hasDoubleBarrel===1) {
if (options.double_barrel != '') {
advancedWeaponsString += '{{double_barrel=['+options.double_barrel+dice_section+'double_barrel'+rollEnding;
advancedWeaponsString += '{{voiddouble_barrel=['+options.double_barrel+nothing_section;
advancedWeaponsString += '{{double_barrel_critical=[('+options.double_barrel+')×2'+dice_section+'double_barrel_critical'+rollEnding;
advancedWeaponsString += '{{voiddouble_barrel_critical=[('+options.double_barrel+')×2'+nothing_section;
}
}
if (options.hasSelectiveFire===1) {
if (options.selfire_lethality_percent>0) {
const critical_selfire_lethality_percent=options.selfire_lethality_percent*2;
advancedWeaponsString += '{{selective_fire=[' + options.selfire_type;
advancedWeaponsString += '('+options.selfire_lethality_percent + '%)'+dice_section+'selective_fire'+rollEnding;
advancedWeaponsString += '{{voidselective_fire=[' + options.selfire_type;
advancedWeaponsString += '(' + options.selfire_lethality_percent + '%)'+nothing_section;
advancedWeaponsString += '{{selective_fire_critical=[' + options.selfire_type;
advancedWeaponsString += '(' + critical_selfire_lethality_percent + '%)'+dice_section+'selective_fire_critical'+rollEnding;
advancedWeaponsString += '{{voidselective_fire_critical=[' + options.selfire_type;
advancedWeaponsString += '(' + critical_selfire_lethality_percent + '%)'+nothing_section;
}
if (options.selfire_ammo>=options.current_ammo && options.trackAmmo==1) {
advancedWeaponsString += '{{selfire_noammo=1}}';
}else{
advancedWeaponsString += '{{selfire_wammo=0}}';
}
}
if (options.hasAccessories===1) {
advancedWeaponsString += '{{accessories=[[1]]}}';
advancedWeaponsString += '{{accessory_name=' + options.accessory_name + '}}';
advancedWeaponsString += '{{accessory_modifier=[[' + options.accessory_modifier + ']]}}';
}
if (options.hasBlastRadius===1) {
advancedWeaponsString += '{{blast_radius=[[1]]}}';
}
}
if (options.trackAmmo) {
advancedWeaponsString += '{{trackbullets=1}}';
advancedWeaponsString += '{{current_ammo=[[' + options.current_ammo + ']]}}';
if (options.current_ammo==0) {
advancedWeaponsString += '{{noammo=1}}';
}else{
advancedWeaponsString += '{{wammo=0}}';
}
} else {
advancedWeaponsString += '{{wammo=0}}';
}
if (options.hasDamage==1) {
advancedWeaponsString += '{{damage= ['+options.damage+dice_section+'damage'+rollEnding;
advancedWeaponsString += '{{voiddamage= ['+options.damage+nothing_section;
advancedWeaponsString += '{{damage_critical= [('+options.damage+')×2'+dice_section+'damage_critical'+rollEnding;
advancedWeaponsString += '{{voiddamage_critical= [('+options.damage+')×2'+nothing_section;
}
if (options.hasLethality==1) {
const label_lethality = `^{Lethality}`;
advancedWeaponsString += '{{lethality_percent= [';
advancedWeaponsString += label_lethality+' ('+options.lethality_percent+'%)';
advancedWeaponsString += dice_section+'lethality_percent'+rollEnding;
advancedWeaponsString += '{{voidlethality_percent= [';
advancedWeaponsString += label_lethality+' ('+options.lethality_percent+'%)'+nothing_section;
advancedWeaponsString += '{{lethality_percent_critical= [';
advancedWeaponsString += label_lethality+' (2×'+options.lethality_percent+'%)';
advancedWeaponsString += dice_section+'lethality_percent_critical'+rollEnding;
advancedWeaponsString += '{{voidlethality_percent_critical= [';
advancedWeaponsString += label_lethality+' (2×'+options.lethality_percent+'%)'+ nothing_section;
}
return advancedWeaponsString;
}
const check_for_wp_modifiers = (values,roll) => {
const _willpower_points = parseInt(values[`willpower_points`]) || 0;
var flag_for_zero_willpower = values[`zero_willpower`]== 1;
flag_for_zero_willpower = flag_for_zero_willpower && _willpower_points== 0 && roll !== 'luck';
const _zero_willpower = (flag_for_zero_willpower) ? 1 : 0;
var flag_for_low_willpower = values[`low_willpower`]== 1;
flag_for_low_willpower = flag_for_low_willpower && _willpower_points <= 2;
flag_for_low_willpower = flag_for_low_willpower && roll !== 'luck' && roll !== 'sanity_points';
/// important it is either one or the other
flag_for_low_willpower = flag_for_low_willpower && flag_for_zero_willpower==false;
const _low_willpower = (flag_for_low_willpower) ? 1 : 0;
return {zero_willpower: _zero_willpower, low_willpower: _low_willpower};
};
const check_success= (dice,rating,isSkill=1) => {
// Input:
// dice is the result of the roll
// rollName is the name of the skill or stat
// rollFail used only for stats to check for failure
// rating is the rating of the skill or stat
// isSkill is the flag to check if it's a skill or a stat [0,1]
var isSuccess=0;
var isCritical=0;
if (dice==100){ // 100 is always a fumble
isCritical=1;
isSuccess=0;
} else { // check for criticals normally
isSuccess = dice<=rating ? 1 : 0;
isCritical = _criticals.includes(dice) ? 1 : 0;
}
const isInhuman=(isSkill==0 && rating>=_INHUMAN_STAT_);
const isNormalSuccess=(isSuccess==1 && isCritical==0);
if (isInhuman && isNormalSuccess){ // special case for stats to evaluate criticals
const score=Math.round(rating/5);
isCritical = (dice<=score) ? 1 : 0;
}
return {isSuccess:isSuccess,isCritical:isCritical};
};
const check_weapon_modifiers = (options) => {
const advanced_weapons = options.hasAdvancedWeapons;
var modifier = options.modifier;
const low_willpower = options.low_willpower;
if (advanced_weapons==0) { return correct_modifier(modifier,low_willpower) ;}
if (options.isShotgun==1 || options.hasBlastRadius==1){ modifier+=20;}
if (options.hasAccessories==1){modifier+=options.accessory_modifier;}
if (options.isFlawed==1){modifier-=20;}
if (options.isAiming==1){modifier+=20;}
return correct_modifier(modifier,low_willpower);
}
const correct_modifier = (modifier,low_willpower,limit_to_40=1) => {
// Input:
// modifier is the base modifier provided by the used
// low_willpowe is the low willpower flag [0,1]
// limit_to_40 is the flag to limit the upper bound modifier to 40% (not used but for future and debugging) [0,1]
// Output:
// the corrected modifier
var corrected_modifier=modifier - (20*low_willpower);
return limit_to_40==1 ? Math.min(40,corrected_modifier) : corrected_modifier;
}
const correct_rating = (rating,modifier,limit_to_99=1) => {
// Input:
// rating is the base rating of the skill
// modifier is the corrected modifier
// limit_to_99 is the flag to limit the upper bound rating to 99% (0 for inhuman stats) [0,1]
// Output:
// the corrected rating
var corrected_rating=rating+modifier;
return limit_to_99==1 ? Math.min(99,corrected_rating) : corrected_rating;
}
const check_sanloss = (sanloss,attrName) => {
if (attrName==='sanity_loss_success'){
return sanloss=='' ? 0 : sanloss;
} else if(attrName==='sanity_loss_failure'){
return sanloss=='' ? 1 : sanloss;
}
};
const check_track_ammo=(rollString,trackAmmo,currentAmmo,used_ammo=1) => {
if (trackAmmo==1) {
rollString = `${rollString} {{trackbullets=[[1]]}} {{used_ammo=[[${used_ammo}]]}}`;
rollString = `${rollString} {{current_ammo=[[${currentAmmo}]]}}`;
} else {
rollString = `${rollString} {{trackbullets=[[0]]}}`;
}
return rollString;
};
const getUsedAmmo=(selfire_type='') => {
if (selfire_type==='short burst'){return 3} ;
if (selfire_type==='long burst'){return 5} ;
if (selfire_type==='short spray'){return 10} ;
if (selfire_type==='long spray'){return 20} ;
return 1;
}
const need_to_track_ammo = (_values,_names)=>{
const track_bullets=_values[_names['track_bullets']]==='active' ? 1 : 0;
const hasammo=_values[_names['hasammo']]==='active' ? 1 : 0;
return (track_bullets==1 && hasammo==1) ? 1 : 0;
}
const setAttributes = (update, silent) => {
(silent === true) ? setAttrs(update, {silent:true}) : setAttrs(update);
};
// check skill value for weapons and special training
const isSkillNumber = (str) => {
let num=Number(str);
return !isNaN(num) && num>=0 && num<=99
};
const isSkillName= (rollName) => {return arrays[`_skills`].includes(rollName) ? 1 : 0;};
// check if linking skill in in linking form
const isStringInForm=(str)=> {
var regex = /^@\{[\w\s]+\}$/;
return regex.test(str);
};
// used for linking skills
const cleanedSkill= (str) =>{return String(str).toLowerCase().replace(' ','_').replace('@{','').replace('}','')};
// When the trigger comes from another call
const isMinorityReport = (eventInfo) => !(eventInfo.hasOwnProperty('newValue'));
// check if the format is the one of a linking skill
const isValidSkill=(str)=> {
const compar=cleanedSkill(String(str));
return arrays['_skills'].concat(arrays['_stats']).concat(['unnatural','ritual_skill']).includes(compar);
};
const isEmpty = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object;
const getSections = function(sectionDetails,callback){
let queueClone = _.clone(sectionDetails);
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([],{});
}else{
worker(queueClone);
}
};
const get_header_skills = (values,property) => {
var _header = ``;
if (values.hasOwnProperty(property['editable_name'])) {
_header = '{{header=^{'+property['editable_type']+'}';
_header = _header +' ('+values[property['editable_name']]+')}}';
}else {
_header = '{{header=^{'+property['name']+'} }}';
}
return _header;
}
const check_for_failed_skill = (rollName,isSuccess=0,isSkill=1) => {
// Input:
// rollName is the name of the skill if it's a skill, if it's a repeating section, it's the name of the section
// outcome is the result of the roll [0,1]
// isSkill is the flag to check if it's a skill [0,1]
var failure={};
if (isSkill==false) {return failure;}; // if it's not a skill, return empty object
if (isSuccess==1) {return failure;}; // if it's a success, return empty object
failure[`${rollName}_fail`]='on';
return failure;
}
const setMinMax = (skill, min=0, max=99) => {
const IntegerSkill=parseInt(skill)||0;
if (min>max) {return IntegerSkill}
return Math.min(Math.max(IntegerSkill,min),max);
};
const isValidLinkInput = (newValue) => {return (isStringInForm(newValue) && isValidSkill(newValue));};
const parseRoll = (roll) => {
const regex_int = /^(\s*[\+\-]?\d{1,100}\s*)$/;
const regex_roll = /^((\s*[\+\-\(\)]\s*){0,4}?\d{0,10}[dD]?\d{1,10}((\s*[\+\-\*\/\(\)]\s*){0,4}?\d{0,10}[dD]?\d{1,10})*(\s*[\)]\s*){0,4}?)+$/
if (regex_int.test(roll)) {return parseInt(roll);}
if (regex_roll.test(roll)) {return roll.replace(/\s/g, '').toUpperCase();}
return 0;
}
const maxRoll = (roll) => {
if (isNaN(Number(roll))==false) {return roll;}
return parseRoll(roll).replace(/[dD]/g, '*')
}
const minRoll = (roll) => {
if (isNaN(Number(roll))==false) {return roll;}
return parseRoll(roll).replace(/[dD]\d{1,100}/g,'')
}
const addTargetStat=(values,names,attrName) => {
var target_stat='';
if (attrName==='attack' || attrName==='heal'){
target_stat+=`{{target_unit=${name_to_shorthand(values[names['target_stat']])}}}`;
target_stat+=`{{target_stat=${values[names['target_stat']].replace(/_/g,' ')}}}`;
}
return target_stat;
};
const updatebondscore = (values,update,manualscore=true) => {
const character_creation_bonds = values[`character_creation_bonds`] === 'active' ? true : false;
const willpower_points_max = parseInt(values.willpower_points_max) || 0;
const initial_willpower = (character_creation_bonds) ? willpower_points_max : Math.floor(willpower_points_max/2);
const flag = (manualscore) ? 1 : parseInt(values[`repeating_bonds_setScore`]) || 0;
const bond_score_old = parseInt(values[`repeating_bonds_score_old`]) || 0;
var bond_score = 0;
if (flag === 0) {
bond_score = initial_willpower;
} else {
bond_score = parseInt(values[`repeating_bonds_score`]) || 0;
if (bond_score > willpower_points_max) {
if (willpower_points_max > bond_score_old) {
bond_score = willpower_points_max;
}
}
}
update[`repeating_bonds_score`] = bond_score;
update[`repeating_bonds_score_old`] = bond_score_old;
update[`repeating_bonds_setScore`] = 1;
update[`repeating_bonds_color`] = BondButtonColor(bond_score);
}
const DeltaGreenLethalityFail=(roll) => {
const quotient=Math.floor(roll/10)== 0 ? 10 : Math.round(roll/10);
const remainder= (roll%10 ==0) ? 10 : Math.round(roll%10);
return quotient+ remainder;
};
// Update span on change
const updateSkillSpanOnChange=(skill,value,update,isWhat) =>{
const sectionDetails = [{section:'repeating_special', fields:['skill_or_stat_used']},
{section:'repeating_weapons',fields:['skill_percent']},
{section:'repeating_rituals',fields:['skill_percent']}];
getSections(sectionDetails,(attr)=>{
const allskills1=attr.filter(el => el.startsWith(sectionDetails[0][`section`]) && el.endsWith(sectionDetails[0][`fields`][0]));
const allskills2=attr.filter(el => el.startsWith(sectionDetails[1][`section`]) && el.endsWith(sectionDetails[1][`fields`][0]));
const allskills3=attr.filter(el => el.startsWith(sectionDetails[2][`section`]) && el.endsWith(sectionDetails[2][`fields`][0]));
const allids1= allskills1.map(el => el.replace(`_${sectionDetails[0][`fields`][0]}`,''));
const allids2= allskills2.map(el => el.replace(`_${sectionDetails[1][`fields`][0]}`,''));
const allids3= allskills3.map(el => el.replace(`_${sectionDetails[2][`fields`][0]}`,''));
const len1=allids1.length;
const len2=allids2.length;
const len3=allids3.length;
getAttrs(allskills1.concat(allskills2).concat(allskills3),(v)=>{
for (i=0;i<len1; i++){
if (cleanedSkill(v[allskills1[i]])===skill){
update[`${allids1[i]}_skill_span`]=value;
}
}
for (i=0;i<len2; i++){
if (cleanedSkill(v[allskills2[i]])===skill){
update[`${allids2[i]}_skill_span`]=value;
}
}
for (i=0;i<len3; i++){
if (cleanedSkill(v[allskills3[i]])===skill){
update[`${allids3[i]}_skill_span`]=value;
}
}
setAttrs(update,{silent:true},()=>{
console.log(`Skill span updated for ${skill}`);
console.info(update);
});
});
});
}
const saneffects=(snew,sold,smax,bnew,bmax,bold,pow,trackbp) => {
const san = value_current(snew,sold,smax);
const diffsan=san-sold;
const flag_2san = (diffsan>=2) ? 1 : 0;
const flag_temp = (diffsan>=5) ? 1 : 0;
const flag_bp = (san<=bnew && trackbp==1) ? 1 : 0;
return {san2:flag_2san,temp:flag_temp,bp:flag_bp};
};
const definesanroll=(san,sold,bnew,bold,sanflags,character_name,San2_disorder={},Temp_disorder={}) => {
const diffsan=san-sold;
const flag_2san=(sanflags.san2 && !(isEmpty(San2_disorder)));
const flag_temp=sanflags.temp;
const flag_bp=sanflags.bp;
var rollString=`&{template:fancy-rolls} {{name=${character_name}}} {{header=^{sanity_loss}}} `;
rollString= `${rollString} {{sanity_loss=[[${diffsan}]]}} {{sanity_new=[[${san}]]}}`;
rollString= `${rollString} {{sanity_old=[[${sold}]]}} {{bp_old=[[${bold}]]}} {{bp_new=[[${bnew}]]}}`;
if (flag_bp == 1){
rollString= `${rollString} {{flag_bp=1}} `;
}
if (flag_temp==1){
rollString=`${rollString} {{flag_temp=1}}`;
if (!(isEmpty(Temp_disorder))){
Object.entries(Temp_disorder).forEach(([key,val],index)=>{
rollString= `${rollString} {{tdis_name${index}=${key}}} {{tdis_desc${index}=${val}}} `;
});
}
}
if (flag_2san==1){
rollString=`${rollString} {{flag_2san=1}}`;
if (!(isEmpty(Temp_disorder))){
Object.entries(Temp_disorder).forEach(([key,val],index)=>{
rollString= `${rollString} {{tdis_name${index}=${key}}} {{tdis_desc${index}=${val}}} `;
});
}
}
var update={};
update['sanity_points']=san;
update['sanity_points_old']=sold;
if (flag_bp==='on'){
update['breaking_point']=Math.max(0,san-pow);
update['breaking_point_max']=bold;
update['breaking_point_old']==Math.max(0,san-pow);
}
setAttrs(update, {silent:true},()=>{
});
startRoll(`${rollValue} {{isSkill=[[${_isSkill}]]}}`, (results)=> {
const sanity_old=results.results.sanity_old.result;
const sanity_new=results.results.sanity_new.result;
const sanity_loss=results.results.sanity_loss.result;
const bp_old=results.results.bp_old.result;
const bp_new=results.results.bp_new.result;
finishRoll(results.rollId,{});
});
}
const value_current = (current,old,max) => {
if (current>=max) {
return (current<=old) ? current : old;
}
return Math.max(current,0);
}
const setBondsLocalVariables = () => {
getAttrs(["willpower_points","sanity_points"],function(value){
let update={};
getSectionIDs(`bonds`,function(idarray){
idarray.forEach(id=>{
update["repeating_bonds_"+id+"_wp_points"]=value["willpower_points"];
update["repeating_bonds_"+id+"_sanity_points"]=value["sanity_points"];
});
console.log('inside repeating section');
setAttrs(update,{silent:true},()=>{
console.log('Bonds updated on open');
});
});
});
};
// === debug note: need to change repeating_special_training and repeating_weapons for visulization purposes
// === Update stats on change
const skill_in_bounds = (skill) => {
const skill_value = parseInt(skill) || 0;
return Math.min(99, Math.max(0, skill_value));
};
const updateadvancedweapons = () => {
getAttrs(['advanced_weapons'],(v)=>{
const advanced_weapons=v['advanced_weapons'];
getSectionIDs('repeating_weapons',(ids)=>{
const update={};
const prefix='repeating_weapons_';
ids.forEach((id)=>{
update[prefix+id+'_hasAdvancedWeapons']=advanced_weapons;
arrays['_advanced_weapons_featurs'].forEach((feat)=>{
update[prefix+id+'_'+feat]=0;
});
});
setAttrs(update,{silent:true});
});
});
};
/* visuar option: removes the "advanced weapons" button from the weapons section
*/"use strict";
on('clicked:reset_all', () =>{
const update = {};
resetStats(update,false);
resetBonds(update);
resetAdaptations(update);
resetEquipment(update);
resetSkills(update);
resetHistory(update);
// write all the reset functions here
setAttrs(update, {silent: true}, () => {
console.log('reset all');
console.info(update);
});
});
on('clicked:reset_stats', () =>{
const update = {};
resetStats(update);
setAttrs(update, {silent: true}, () => {
console.log('reset stats');
console.info(update);
});
});
on('clicked:reset_skills', () =>{
const update = {};
resetSkills(update);
setAttrs(update, {silent: true}, () => {
console.log('reset skills');
console.info(update);
});
});
on('clicked:reset_equipment', () =>{
const update = {};
resetEquipment(update);
setAttrs(update, {silent: true}, () => {
console.log('reset equipment');
console.info(update);
});
});
on('clicked:reset_breaking_point', () =>{
const update = {};
resetBreakingPoints(update);
console.info(update);
});
const resetBreakingPoints = (update) => {
getAttrs(['breaking_point_max', 'breaking_point', 'breaking_point_reset'], function (values) {
console.log('breaking_point_reset:',values);
var breaking_point_reset = parseInt(values.breaking_point_reset,10) || 0;
update['breaking_point_max']= breaking_point_reset;
update['breaking_point']= breaking_point_reset;
update['breaking_point_reset']= breaking_point_reset;
setAttrs(update, {silent: true}, () => {
console.log('reset breaking points');
console.info(update);
});
});
};
const resetStats = (update,reset_bonds=true) => {
var array_to_reset = arrays['_stats'];
const stat_score=arrays['_stats'].map(stat => stat+'_score');
array_to_reset=array_to_reset.concat(stat_score);
array_to_reset=array_to_reset.concat(arrays['_derived_stats'])
array_to_reset=array_to_reset.concat(arrays['_derived_stats_max'])
array_to_reset = array_to_reset;
array_to_reset.forEach(stat => {
update[stat] = '';
});
const old_values = [
'sanity_points_old',
'breaking_point_old',
];
old_values.forEach(stat => {
update[stat] = '';
});
const initial_flags=[
'initial_san',
'initial_con',
'initial_str',
'initial_hp',
];
initial_flags.forEach(flag => {
update[flag] = '1';
});
if (reset_bonds){
getSectionIDs('repeating_bonds',(ids) => {
ids.forEach(id => {
update[`repeating_bonds_${id}_test`] = 'editable';
update[`repeating_bonds_${id}_score`] = '';
});
});
}
};
const resetSkills = (update) => {
Object.entries(_initial_skills).forEach(([skill, value]) => {
update[skill] = value;
update[`${skill}_fail`] = value;
});
arrays['_editable_skills'].forEach(skill => {
update[`${skill}_name`] = '';
update[`${skill}_test`] = 0;
});
resetAllRepeatingSkills(update);
resetAllSpecialAbilities(update);
};
const resetBonds= (update) => {
getSectionIDs('repeating_bonds',(ids) => {
ids.forEach(id => {
removeRepeatingRow('repeating_bonds_'+id);
console.log('removing repeating_bonds_'+id);
});
});
};
const resetAdaptations= (update) => {
update['motivations'] = '';
console.log(arrays['_adaptation']);
arrays['_adaptation'].forEach(adaptation => {
update[adaptation] = -1;
update[`${adaptation}_adapted`] = 0;
});
};
const resetAllWeapons= (update) => {
getSectionIDs('repeating_weapons',(ids) => {
ids.forEach(id => {
removeRepeatingRow('repeating_weapons_'+id);
console.log('removing repeating_weapons_'+id);
});
});
}
const resetAllRituals= (update) => {
getSectionIDs('repeating_rituals',(ids) => {
ids.forEach(id => {
removeRepeatingRow('repeating_rituals_'+id);
console.log('removing repeating_rituals_'+id);
});
});
}
const resetEquipment= (update) => {
resetAllWeapons(update);
resetAllRituals(update);
update['armor_and_gear'] = '';
};
const resetAllRepeatingSkills= (update) => {
getSectionIDs('repeating_skills',(ids) => {
ids.forEach(id => {
removeRepeatingRow('repeating_skills_'+id);
console.log('removing repeating_skills_'+id);
});
});
}
const resetAllSpecialAbilities= (update) => {
getSectionIDs('repeating_special',(ids) => {
console.log('special:'+ids);
ids.forEach(id => {
removeRepeatingRow('repeating_special_'+id);
console.log('removing repeating_special_'+id);
});
});
}
const resetHistory = (update) => {
console.log(arrays['_personal_data']);
arrays['_personal_data'].forEach(data => {
update[data] = '';
});
resetInjuries(update);
}
const resetInjuries = (update) => {
update['injuries'] = '';
update['injuries_first_aid'] = 0;
}
const updatesanitypoints = (tmp_sanity_points,sanity_points_old,sanity_points_max,update) => {
const sanity_points = value_current(tmp_sanity_points, sanity_points_old, sanity_points_max);
update['sanity_points_old'] = sanity_points;
update['sanity_points'] = sanity_points;
update['ritual_skill'] = Math.max(99-sanity_points);
return {sanity_points:sanity_points,ritual_skill:Math.max(99-sanity_points)};
};
const updatebreakingpoints = () => {
getAttrs(['power_score','breaking_point','sanity_points','breaking_point_reset','sanity_points_max','sanity_points_old','track_breaking_points'], (values)=> {
const update = {};
const flag=values.track_breaking_points==='active' ? true : false;
const power_score = parseInt(values.power_score, 10) || 0;
const breaking_point = parseInt(values.breaking_point, 10) || 0;
const sanity_points_old = parseInt(values.sanity_points_old, 10) || 0;
const sanity_points_max = parseInt(values.sanity_points_max, 10) || 0;
const tmp_sanity_points = parseInt(values.sanity_points, 10) || 0;
update_bp_san_ritual(tmp_sanity_points,sanity_points_old,sanity_points_max,power_score,breaking_point,update,flag);
});
}
const update_bp_san_ritual = (tmp_sanity_points,sanity_points_old,sanity_points_max,power_score, breaking_point,update,flag) => {
const updated_values=updatesanitypoints(tmp_sanity_points,sanity_points_old,sanity_points_max,update);
var update_breaking_point = breaking_point;
if(flag && (updated_values.sanity_points<breaking_point)){
update_breaking_point = Math.max(0,updated_values.sanity_points-power_score);
}
update['breaking_point_reset'] = update_breaking_point;
update['breaking_point']=update_breaking_point;
updateSkillSpanOnChange('ritual_skill',updated_values.ritual_skill,update,'Rituals');
}
const setResetBreakingPointsOnOpen = () => {
getAttrs(['breaking_point','sanity_points','sanity_points_max','power_score','track_breaking_points'], (values)=> {
const breaking_point = Math.max(0,parseInt(values.breaking_point, 10) || 0);
const flag=values.track_breaking_points==='active' ? true : false;
const power_score = parseInt(values.power_score, 10) || 0;
const update = {};
const open_sanity_points = parseInt(values.sanity_points, 10) || 0;
const sanity_points_max = parseInt(values.sanity_points_max, 10) || 0;
update_bp_san_ritual(open_sanity_points,open_sanity_points,sanity_points_max,power_score,breaking_point,update,flag);
});
};const versioning = (version) => {
console.log(`%c Versioning, ${version}`, 'color: green; font-weight:bold');
if (version < 1.05) {
version_0_105();
}
if (version <1.5) {
version_105_150();
}
if (version<1.7) {
version_150_170();
}
if (version<2.0) {
version_170_200();
}
if (version<2.01) {
version_200_201();
}
};
// UPDATE TO VERSION 1.05
const version_0_105= () => {
getAttrs(['version'], function(v) {
let codeversion=1.05;
let update={version: codeversion,
initial_san: 0,
initial_hp: 0,
initial_str: 0,
initial_con: 0
};
setAttrs(update, //Update attributes
{silent:true}, // will not trigger sheet workers
versioning(codeversion)); // call versioning again
});
};
// UPDATE TO VERSION 1.5
const version_105_150 = () => {
let codeversion=1.5;
let update={};
getSectionIDs(`weapons`,function(idarray){
console.log(`%c idarray`, 'color: green; font-weight:bold');
console.info(idarray);
let fieldnames=['sheet_type','version'];
console.log(`%c did I found weapons?`, 'color: green; font-weight:bold');
idarray.forEach(id => {
console.log(`%c ${id}`, 'color: green; font-weight:bold');
fieldnames.push(`repeating_weapons_${id}_damage`,`repeating_weapons_${id}_lethality_percent`,`repeating_weapons_${id}_attack`);
});
getAttrs(fieldnames,function(v) {
console.log(`%c v`, 'color: green; font-weight:bold');
console.info(v);
update['version']=codeversion;
idarray.forEach(id=>{
console.log(`%c ${id}`, 'color: green; font-weight:bold');
if (v[`repeating_weapons_${id}_damage`]===""){
update["repeating_weapons_"+id+"_hasDamage"]="0";
} else{
update["repeating_weapons_"+id+"_hasDamage"]="1";
}
if (v[`repeating_weapons_${id}_lethality_percent`]>0){
update["repeating_weapons_"+id+"_hasLethality"]="1";
} else {
update["repeating_weapons_"+id+"_hasLethality"]="0";
}
if (v['sheet_type']==='npc'){
update["repeating_weapons_"+id+"_weapons"]=v[`repeating_weapons_${id}_attack`];
}
});
console.log(`%c update`, 'color: green; font-weight:bold');
setAttrs(update, //Update attributes
{silent:true}, // will not trigger sheet workers
versioning(codeversion)); // call versioning again
});
});
};
// UPDATE TO VERSION 1.7
const version_150_170 = () => {
let codeversion=1.7;
let update={};
update['version']=codeversion;
update['luck']=50;
update['luck_max']=50;
console.log(`%c update`, 'color: green; font-weight:bold');
setAttrs(update, //Update attributes
{silent:true}, // will not trigger sheet workers
versioning(codeversion)); // call versioning again
};
// UPDATE TO VERSION 2.0
const version_170_200 = () => {
let codeversion=2.0;
let update={};
update['version']=codeversion;
getAttrs(["motivations","character_name","name","sanity_points","violence_3","helplessness_3","violence_2","helplessness_2",
"sanity_points_old","sanity_points","breaking_point_old","breaking_point_old"],function(v){
let motivations=v["motivations"];
if (v["name"]!==""){
_name=v["name"];
}else{
_name=v["character_name"];
}
update["character_name"]=_name;
update["old_motivations"]=motivations.replace(/<br>/g,"\n");
const _violence_adapted = v["violence_2"]==='on';
const _helplessness_adapted = v["helplessness_2"]==='on';
if (v["violence_2"]==='on'){
update["violence_1"]='on';
}
if (v["helplessness_2"]==='on'){
update["helplessness_1"]='on';
}
if (_violence_adapted){
update["violence_adapted"]=1;
update["violence_2"]='on';
update["violence_1"]='on';
}
if (_helplessness_adapted){
update["helplessness_adapted"]=1;
update["helplessness_2"]='on';
update["helplessness_1"]='on';
}
update['sanity_points_old']=v['sanity_points'];
update['breaking_point_old']=v['breaking_point'];
console.log(`%c update`, 'color: green; font-weight:bold');
setAttrs(update, //Update attributes
{silent:true}, // will not trigger sheet workers
versioning(codeversion)); // call versioning again
});
};
// UPDATE TO VERSION 2.0
const version_200_201 = () => {
let codeversion=2.01;
let update1={};
console.log('verion:',codeversion);
update1['version']=codeversion;
// UPDATE NAMES FOR SPECIAL TRAINING AND WEAPONS AND TRIGGER TEST
const _sectionDetails = [
{section:'repeating_special', fields: ['name','special_training','skill_or_stat_used','skill_span',]},
{section:'repeating_weapons', fields: ['name','weapons','skill_percent','skill_span','ammo','hasammo','ammo_total','lethality_percent']},
{section:'repeating_bonds', fields: ['flag','setScore','score','score_old']}];
_sectionDetails.forEach(_group => {
const section = _group.section;
const fields = _group.fields;
getSectionIDs(section, (ids)=>{
console.log('in getSectionIDs section',section);
console.log('in getSectionIDs ids',ids);
const repfields=[];
ids.forEach(id => {
fields.forEach(field => {
repfields.push(`repeating_special_${id}_${field}`);
});
});
getAttrs(repfields,(values) => {
console.info('fullarray',values);
var update = {};
ids.forEach(id => {
const repsecid= `repeating_${section}_${id}_`;
/// bond update
if (values.hasOwnProperty(`${repsecid}flag`)){
update[`${repsecid}setScore`]=1;
}
if (values[`${repsecid}score`]!==''){
update[`${repsecid}score_old`]=values[`${repsecid}score`];
}
if (values.hasOwnProperty(`${repsecid}lethality_percent`)){
if (values[`${repsecid}lethality_percent`]===''){
const number=setMinMax(values[`${repsecid}lethality_percent`]);
update[`${repsecid}lethality_percent`]=number;
update[`${repsecid}lethality_percent`]='';
console.log(`%c update name ${repsecid}lethality_percent to empty`, 'color: green; font-weight:bold');
}
}
if (values.hasOwnProperty(`${repsecid}special_training`)){
if (values[`${repsecid}special_training`]!==''){
update[`${repsecid}name`]=values[`${repsecid}special_training`];
update[`${repsecid}special_training`]='';
console.log(`%c update name ${repsecid}special_training to ${repsecid}name`, 'color: green; font-weight:bold');
}
};
if (values.hasOwnProperty(`${repsecid}weapons`)){
if (values[`${repsecid}weapons`]!==''){
update[`${repsecid}name`]=values[`${repsecid}weapons`];
update[`${repsecid}weapons`]='';
console.log(`%c update name ${repsecid}weapons to ${repsecid}name`, 'color: green; font-weight:bold');
}
};
if (values.hasOwnProperty(`${repsecid}skill_or_stat_used`)){
const value_stat=setMinMax(values[`${repsecid}skill_or_stat_used`]) ;
update[`${repsecid}skill_span`]=value_stat;
update[`${repsecid}skill_or_stat_used`]=value_stat;
console.log(`%c update skill_span for ${repsecid}`, 'color: green; font-weight:bold');
};
if (values.hasOwnProperty(`${repsecid}skill_percent`)){
const value_skill = setMinMax(values[`${repsecid}skill_percent`]);
update[`${repsecid}skill_span`]=value_skill;
update[`${repsecid}skill_percent`]=value_skill;
console.log(`%c update skill_span for ${repsecid}`, 'color: green; font-weight:bold');
};
if (values.hasOwnProperty(`${repsecid}ammo`)){
const value_ammo = Math.max(parseInt(values[`${repsecid}ammo`],10) || 0,0) ;
if (value_ammo>0){
update[`${repsecid}ammo_total`]=value_ammo;
update[`${repsecid}hasammo`]=1;
update[`${repsecid}ammo`]=value_ammo;
} else {
update[`${repsecid}hasammo`]=0;
update[`${repsecid}ammo_total`]='';
update[`${repsecid}ammo`]='';
}
console.log(`%c update ammo for ${repsecid}: ammo_total=${update[`${repsecid}ammo_total`]} hasammo=${update[`${repsecid}hasammo`]}`, 'color: green; font-weight:bold');
}
});
console.log(`%c update`, 'color: green; font-weight:bold');
console.info('versioning',update1);
setAttrs(update1, //Update attributes
{silent:true}, // will not trigger sheet workers
versioning(codeversion)); // call versioning again
});
});
});
};
const BondButtonColor= (bondvalue) => {
const score = parseInt(bondvalue)||0;
const color = (score > 0) ? 'on' : 'off';
return color;
};
const changeBondButtonColorOnOpen = () => {
getSectionIDs(`repeating_bonds`, (idarray) => {
const allbonds=idarray.map(id =>`repeating_bonds_${id}_score`);
getAttrs(allbonds, (value) => {
const update={};
Object.entries(value).forEach(([key, value]) => {
const id = key.split('_')[2];
const score = parseInt(value)||0;
update['repeating_bonds_'+id+'_color'] = BondButtonColor(score);
});
setAttrs(update, {silent:true}, () => {
console.log('Bond color updated');
});
});
});
};
// update the rollDamage dice for the hidden buttons in the repeating sections
// it should only be used at creation of the field on in versioning
// since characterID and repeatingSectionID does not change
// if it does, using transmogrifer, I might have to add a reset button to reset the rolls
const updateRepeatingDamageRolls = (update,character_id,attrPrefix,nameRoll,hasCritical=false) => {
const fullAttrPrefix = (attrPrefix==='') ? nameRoll : `${attrPrefix}_${nameRoll}`;
const dicePrefix=`%{${character_id}|${fullAttrPrefix}`;
update[`${fullAttrPrefix}_action`] = `${dicePrefix}-action}`;
if (hasCritical) {
update[`${fullAttrPrefix}_critical_action`] = `${dicePrefix}_critical-action}`;
}
};
const updateRepeatingRolls = (section, attrName, id, character_id) => {
const update = {};
const attrPrefix = `repeating_${section}_${id}`;
const rep_attrName = `${attrPrefix}_${attrName}`;
const dicePrefix = `%{${character_id}|${rep_attrName}`;
update[`${rep_attrName}_action`] = `${dicePrefix}-action}`;
update[`${rep_attrName}_r`] = id;
update[`${rep_attrName}_initialized`] = `1`;
if (section === 'weapons') {
arrays['_weapon_hidden_buttons'].forEach((buttonName) => {
updateRepeatingDamageRolls(update,character_id,attrPrefix,buttonName,true);
});
}
if (section === 'rituals') {
arrays['_ritual_hidden_buttons'].forEach((buttonName) => {
updateRepeatingDamageRolls(update,character_id,attrPrefix,buttonName);
});
}
return update;
};
const updateAllRollsOnOpen = () => {
const update = {};
getAttrs(['character_id'], (values) => {
const character_id = values.character_id;
updateRollsOnOpen(update,character_id);
updateRepeatingRollsonOpen(update,character_id);
});
};
const updateRollsOnOpen= (update, character_id) => {
console.log('===update rolls===');
const fullrolls = _allrolls;
fullrolls.forEach(roll => {
const dicePrefix = `%{${character_id}|${roll}`;
update[`${roll}_action`] = `${dicePrefix}-action}`;
if (roll.includes('sanity_loss')) {
updateRepeatingDamageRolls(update,character_id,'',roll+'_success');
updateRepeatingDamageRolls(update,character_id,'',roll+'_failure');
}
});
};
const updateRepeatingRollsonOpen = (update,character_id) => {
Object.entries(_repeating_sections).forEach(([attrName,section])=> {
getSectionIDs(section, function(idarray) {
idarray.forEach(id => {
Object.assign(update, updateRepeatingRolls(section, attrName, id, character_id));
});
setAttrs(update, {silent:true}, () => {
console.log('Repeating and Normal Rolls updated');
});
});
});
};
const changeRepeatingRolls = (section,attrName,id) => {
getAttrs(['character_id',`repeating_${section}_${id}_initialized`], (values) => {
const character_id = values.character_id;
const isInitialized = parseInt(values[`repeating_${section}_${id}_initialized`],10) || 0;
const update = {};
if (isInitialized===0) {
console.log('===update rolls===');
Object.assign(update, updateRepeatingRolls(section, attrName, id, character_id));
} else {
console.log('===no need to update===');
}
setAttrs(update, {silent:true}, () => {
});
});
};
const rollwithmodifiers = (rollString,rollName,queryModifier,additionalParameters) => {
const attr_to_get=arrays['_derived_modifiers']
if (additionalParameters.hasOwnProperty('editable_name')) {
attr_to_get.push(additionalParameters['editable_name']);
}
getAttrs(attr_to_get, (values) => {
const wp_mod=check_for_wp_modifiers(values,rollName);
rollString += `{{rating=[[@{${rollName}}]]}}`;
rollString += `{{zero_willpower=[[${wp_mod.zero_willpower}]]}}`;
rollString += `{{low_willpower=[[${wp_mod.low_willpower}]]}}} `;
rollString += `{{modifier=[[${queryModifier}]]}}`;
rollString += `{{isCritical=[[0]]}} {{isSuccess=[[0]]}}`;
rollString += get_header_skills(values,additionalParameters);
rollFail=`${rollName}_fail`;
rollSkillAndStats(rollString,rollName,isSkillName(rollName));
});
};
const rollAttacks = (rollValue,options) => {
startRoll(rollValue, (results) => {
const dice=results.results.dice.result;
options.modifier=results.results.modifier.result;
const modifier=check_weapon_modifiers(options);
const rating=correct_rating(options.rating,modifier);
const outcome=check_success(dice,rating,options.isSkill);
newroll={
rating: rating,
modifier: modifier,
isSuccess: outcome.isSuccess,
isCritical: outcome.isCritical,
zero_willpower: options.zero_willpower,
low_willpower: options.low_willpower,
advanced_weapons: options.hasAdvancedWeapons
};
finishRoll(results.rollId,newroll);
});
};
const rollSkillAndStats=(rollValue,rollName,isSkill) => {
// Input:
// rollValue is the string to roll the dice
// rollName is the name of the skill or stat
// rollFail used only for stats to check for failure
// limit_to_99 is the flag to limit the upper bound rating to 99% (0 for inhuman stats) [0,1]
startRoll(rollValue, (results)=> {
// low and zero willpower flags only used if the setting is on
const zero_willpower=results.results.zero_willpower.result;
const low_willpower=results.results.low_willpower.result;
const _modifier= correct_modifier(results.results.modifier.result,low_willpower);
const _rating = correct_rating(results.results.rating.result,_modifier,isSkill);
const dice=results.results.dice.result;
var newroll={};
const outcome=check_success(dice,_rating,isSkill);
newroll={
rating: _rating,
modifier: _modifier,
isSuccess: outcome.isSuccess,
isCritical: outcome.isCritical,
zero_willpower: zero_willpower,
low_willpower: low_willpower
};
finishRoll(results.rollId,newroll);
update=check_for_failed_skill(rollName,outcome.isSuccess,isSkill);
setAttrs(update,{silent:false}, () => {
});
});
};
const rollBonds=(rollValue,_value,_names,_parameters) => {
startRoll(`${rollValue}`, (results)=> {
const dice=results.results.dice.result;
const local_wp=Math.max(0,parseInt(results.results.local_wp.result)-dice);
var score=Math.max(0,parseInt(results.results.score.result)-dice);
const original_wp=parseInt(results.results.local_wp.result) || 0;
const zerowp=local_wp==0 ? 1 : 0;
var update={};
update[_names['local_wp_points']]=local_wp;
update[`willpower_points`]=local_wp;
if (parseInt(results.results.local_wp.result)||0 !=0){
update[_names[`score`]]=score;
}else{
score=parseInt(results.results.score.result) || 0;
}
update[_names[`color`]]=BondButtonColor(score);
newroll={
dice: Math.min(dice,original_wp),
local_wp: local_wp,
score: score,
zerowp: zerowp
};
finishRoll(results.rollId,newroll);
setAttrs(update,{silent:false}, () => {
});
});
};
const clicked_repeating_rituals_cost = (parameters,names) => {
getAttrs(parameters, (values) => {
const ritual_type = names['ritual_type'];
// cost of the ritual
const other_costs={};
getOtherCosts(other_costs,values,names,RitualCosts);
getOtherCosts(other_costs,values,names,CurrentValues);
if(ritual_type==='pay_cost'){
paythecost(other_costs['sanity_loss_failure'],other_costs);
}
if(ritual_type==='force_connection'){
forceconnection(other_costs['sanity_loss_failure'],other_costs);
}
if(ritual_type==='accept_failure'){
acceptfailure(other_costs['sanity_loss_success'],other_costs);
}
});
};
const setDamageParametersAndInputNames=(id,attrName, _parameters, _input_names) => {
_input_names[`name`] = `repeating_weapons_${id}_name`;
_input_names[`repsecid`] = `repeating_weapons_${id}`;
_parameters.push(_input_names[`name`]);
_input_names[`hasammo`] = `repeating_weapons_${id}_hasammo`;
_parameters.push(_input_names[`hasammo`]);
var flagCritical=false;
flagCritical= flagCritical || (attrName==='damage_critical');
flagCritical= flagCritical || (attrName==='double_barrel_critical');
flagCritical= flagCritical || (attrName==='lethality_percent_critical');
flagCritical= flagCritical || (attrName==='selective_fire_critical');
_input_names[`isCritical`] = (flagCritical==true) ? 1 : 0;
const isCritical=_input_names[`isCritical`];
if (attrName==='damage' || attrName==='damage_critical') {
if (isCritical==1){
_input_names[`header`] = `damage (×2)`;
}else{
_input_names[`header`] = `damage`;
}
_input_names[`damage`] = `repeating_weapons_${id}_damage`;
_parameters.push(_input_names[`damage`]);
_input_names[`damage_type`]='damage';
}else if (attrName==='double_barrel' || attrName==='double_barrel_critical') {
_input_names[`damage_type`]='damage';
if (isCritical==1){
_input_names[`header`] = `damage (×2)`;
}else{
_input_names[`header`] = `damage`;
}
_input_names[`damage`] = `repeating_weapons_${id}_double_barrel`;
_parameters.push(_input_names[`damage`]);
}else if (attrName==='lethality_percent' || attrName==='lethality_percent_critical') {
_input_names[`damage_type`]='lethality_percent';
if (isCritical==1){
_input_names[`header`] = `lethality (×2)`;
}else{
_input_names[`header`] = `lethality`;
}
_input_names[`damage`] = `repeating_weapons_${id}_lethality_percent`;
_parameters.push(_input_names[`damage`]);
}else if (attrName==='selective_fire' || attrName==='selective_fire_critical') {
if (isCritical==1){
_input_names[`header`] = `_tmp_header_ (×2)`;
}else{
_input_names[`header`] = `_tmp_header_`;
}
_input_names[`damage_type`]='lethality_percent';
_input_names[`damage`] = `repeating_weapons_${id}_selfire_lethality_percent`;
_parameters.push(_input_names[`damage`]);
_input_names[`selfire_type`] = `repeating_weapons_${id}_selfire_type`;
_parameters.push(_input_names[`selfire_type`]);
}
_input_names[`ammo`] = `repeating_weapons_${id}_ammo`;
_parameters.push(_input_names[`ammo`]);
_input_names[`track_bullets`] = `track_bullets`;
_parameters.push(_input_names[`track_bullets`]);
};
const addAttackHeader=(values,names) => {
if (names.hasOwnProperty('header')){
return `{{header=^{${realDmgHeader(values,names)}}}}`;
}
return '';
};
const realDmgHeader=(values,names) => {
if (names.hasOwnProperty)
var header=names['header'];
if (header.includes('_tmp_header_')){ // I can use it for other things
//if (names['rollName']==='selective_fire'){
return header.replace('_tmp_header_',values[names[`selfire_type`]]);
//}
}
return header;
};
const prefixDamageRoll = (type_prefix) => {
if (type_prefix==='damage'){ return prefix_damage_roll;}
if (type_prefix==='heal'){ return prefix_health_roll;}
if (type_prefix==='attack'){ return prefix_attack_roll;}
};
const clicked_repeating_damages = (parameters,names,type_prefix='damage') => {
getAttrs(parameters, (values) => {
const isCritical=names['isCritical'];
const track_bullets=values[names['track_bullets']]==='active' ? 1 : 0;
const hasammo=values[names['hasammo']]==='active' ? 1 : 0;
const trackAmmo=track_bullets==1 && hasammo==1 ? 1 : 0;
const currentAmmo=Math.max(0,parseInt(values[names['ammo']]) || 0);
const selfire_type=(values[names['selfire_type']]) || '';
const used_ammo=getUsedAmmo(selfire_type);
const damage_type=names['damage_type'];
var damage=values[names['damage']];
var rollString=``;
rollString += prefixDamageRoll(type_prefix);
rollString += addAttackHeader(values,names)
rollString += addTargetStat(values,names,type_prefix);
var damageString='';
if (damage_type === 'damage') {
if (isCritical==1){
damageString=`{{damage=[[2*${damage}]]}}`;
}else{
damageString=`{{damage=[[${damage}]]}}`;
}
rollString = `${rollString} ${damageString}`;
rollString = check_track_ammo(rollString,trackAmmo,currentAmmo,used_ammo)
}else if (damage_type === 'lethality_percent') {
if (isCritical==1){
damage=2*damage;
}
damageString=`{{lethality_percent=[[${damage}]]}}`;
rollString = `${rollString} ${damageString}`;
rollString = `${rollString} {{roll=[[1d100]]}}`;
rollString = check_track_ammo(rollString,trackAmmo,currentAmmo,used_ammo)
}
rollString = `${rollString} {{isCritical=[[${isCritical}]]}}`;
startRoll(rollString, (results) => {
const newroll = getRollDamage(results,trackAmmo,damage_type,isCritical);
newroll['isCritical']=isCritical;
newroll['trackbullets']=trackAmmo;
finishRoll(results.rollId,newroll);
if (trackAmmo==1){
const update={};
update[names['ammo']]=newroll['current_ammo'];
setAttrs(update, () => {
});
}
});
});
};
const setDamageRitualParametersAndInputNames=(id, _parameters, _input_names) => {
_input_names[`name`] = `repeating_rituals_${id}_name`;
_input_names[`isCritical`]=0;
const damage_type=_input_names[`damage_type`];
const attack_or_heal = _input_names[`attack_or_heal`];
const repsecid=_input_names[`repsecid`]; //
_parameters.push(_input_names[`name`]);
var prefix_names=`${repsecid}_${attack_or_heal}`;
_input_names[`repsecid`] = prefix_names;
_input_names[`damage`]=`${prefix_names}_${damage_type}_amount`;
_parameters.push(_input_names[`damage`]);
_input_names[`target_stat`] = `${prefix_names}_target_stat`;
_parameters.push(_input_names[`target_stat`]);
};
const getRollDamage= (results,trackammo,damage_type,critical) =>{
const newroll={};
if (trackammo==1){
const trackbullets=[[1]];
newroll['trackbullets']=trackbullets;
const used_ammo=results.results.used_ammo.result;
const current_ammo=results.results.current_ammo.result;
const expended_ammo= current_ammo - used_ammo;
newroll['current_ammo']= expended_ammo;
}
if (damage_type==='damage'){
const damage=results.results.damage.result;
newroll['damage']=damage;
}
if (damage_type==='lethality_percent'){
const lethality_percent=results.results.lethality_percent.result;
const roll=results.results.roll.result;
var computed_lethality_percent=lethality_percent;
var computed_roll=DeltaGreenLethalityFail(roll);
if (critical==1) {
computed_lethality_percent=lethality_percent*2;
computed_roll= computed_roll*2;
}
newroll['roll']=computed_roll;
newroll['lethality_percent']=computed_lethality_percent;
}
return newroll;
};
const clicked_repeating_weapons= (parameters,names,queryModifier) => {
getAttrs(parameters, (values) => {
// used to set the roll string
const character_id=values['character_id'];
const repsecid= names['repsecid'];
const skillname=values[names['name']];
const skillrank=setMinMax(values[names['rank']]);
const trackAmmo= need_to_track_ammo(values,names);
const current_ammo=Math.max(0,parseInt(values[names['ammo']]) || 0);
const hasAdvancedWeapons=values[names['advanced_weapons']] === 'active' ? 1 : 0;
const isShotgun = values[names['shotgun']] === 'active' ? 1 : 0;
const hasDoubleBarrel = values[names['hasDoubleBarrel']] === 'active' ? 1 : 0;
const hasSelectiveFire = values[names['selfire']] === 'active' ? 1 : 0;
const hasAccessories = values[names['accessories']] === 'active' ? 1 : 0;
const hasBlastRadius = values[names['blast_radius']] === 'active' ? 1 : 0;
const isAiming = values[names['aiming']] === 'active' ? 1 : 0;
const lethality_percent=setMinMax(values[names['lethality_percent']]);
const damage= parseRoll(values[names['damage']]);
const armor_piercing=Math.min(parseInt(values[names['armor_piercing']],10)||0,0);
const base_range=values[names['range']];
const kill_radius=values[names['kill_radius']];
var _options={};
_options['rating']=skillrank;
_options['hasLethality']= lethality_percent>0 ? 1 : 0;
_options['hasDamage']= damage !=0 ? 1 : 0;
_options['isAiming']= isAiming;
if (_options['hasDamage']===1) {_options['damage']=damage;}
if (_options['hasLethality']===1) {_options['lethality_percent']=lethality_percent;}
if (trackAmmo==1) {_options['trackAmmo']=1;_options['current_ammo']=current_ammo;}
if (hasAdvancedWeapons===1) {_options['hasAdvancedWeapons']=1;}
if (isShotgun===1) {_options['isShotgun']=1;}
if (hasDoubleBarrel===1) {_options['hasDoubleBarrel']=1;_options['double_barrel']=parseRoll(values[names['double_barrel']]);}
if (hasSelectiveFire===1) {
_options['hasSelectiveFire']=1;
_options['selfire_lethality_percent']=setMinMax(values[names['selfire_lethality_percent']]);
_options['selfire_type']=values[names['selfire_type']];}
if (hasAccessories===1) {
_options['hasAccessories']=1;
_options['accessory_modifier']=values[names['accessory_modifier']];
_options['accessory_name']=values[names['accessory_name']];
}
if (hasBlastRadius===1) {_options['hasBlastRadius']=1;}
const wp_mod=check_for_wp_modifiers(values);
_options['wp_mod']=wp_mod
const rollString=`${prefix_skill_roll} {{header=${skillname}}} {{subheader=${skillrank}}}`;
var rollValue = `${rollString} {{rating=[[${skillrank}]]}} {{modifier=[[${queryModifier}]]}} `;
rollValue += ` {{low_willpower=[[${wp_mod.low_willpower}]]}} {{zero_willpower=[[${wp_mod.zero_willpower}]]}}`;
rollValue += ` {{isCritical=[[0]]}} {{isSuccess=[[0]]}}`;
rollValue += ` {{advanced_weapons=[[${hasAdvancedWeapons}]]}}`;
if (base_range != "") {rollValue += '{{base_range=' + base_range + '}}';}
if (armor_piercing !=0) {rollValue += '{{armor_piercing=' + armor_piercing + '}}';}
if (kill_radius != "") {rollValue += '{{kill_radius=' + kill_radius + '}}';}
const options = setWeaponOptions(_options)
rollValue += setAdvancedWeaponsString(options,character_id,repsecid);
//********************************************
rollAttacks(rollValue,options);
});
};
const clicked_repeating_actions = (section,parameters,names,queryModifier) => {
initializeRolls(); // Initialize the rolls if flag is not set
if (section==='weapons'){
clicked_repeating_weapons(parameters,names,queryModifier);
}
if (section==='bonds'){
clicked_repeating_bonds(parameters,names,queryModifier);
}
if (section==='special'){
clicked_repeating_skills(parameters,names,queryModifier,0);
}
if (section==='skills'){
clicked_repeating_skills(parameters,names,queryModifier,1);
}
if (section==='rituals'){
clicked_repeating_rituals(parameters,names,queryModifier);
}
}
const clicked_repeating_skills = (parameters,names,queryModifier,isRepSkill) => {
getAttrs(parameters, (values) => {
const skillname=values[names['name']];
const skillrank=parseInt(values[names['rank']]) || 0;
const rollString=`${prefix_skill_roll} {{header=${skillname}}} {{subheader=${skillrank}}} `;
const wp_modifiers=check_for_wp_modifiers(values);
const _zero_willpower = wp_modifiers.zero_willpower;
const _low_willpower = wp_modifiers.low_willpower;
const rating=parseInt(values[parameters[names['rank']]]) || 0;
var rollValue = `${rollString} {{rating=[[${skillrank}]]}} {{zero_willpower=[[${_zero_willpower}]]}} {{low_willpower=[[${_low_willpower}]]}}} {{modifier=[[${queryModifier}]]}} {{isCritical=[[0]]}} {{isSuccess=[[0]]}}`;
if(_zero_willpower!='[[1]]') {
rollValue = `${rollValue}`;
}
attrName=names['repsecid'];
rollSkillAndStats(rollValue,attrName,isRepSkill);
});
};
const clicked_repeating_bonds = (parameters,names) => {
getAttrs(parameters, (values) => {
const bondname=values[names['name']];
const bondscore=parseInt(values[names['score']]) || 0;
const local_wp_points=parseInt(values[names['local_wp_points']]) || 0;
const local_sanity_points=parseInt(values[names['local_sanity_points']]) || 0;
const character_id=values['character_id'];
if (bondscore<=0) {return;} // No need to roll if the bond is already broken
const rollString=`${prefix_bond_roll} {{header=${bondname}}} {{subheader=${bondscore}}} `;
var rollValue = `${rollString} {{zerowp=[[0]]}} {{score=[[${bondscore}]]}} {{local_wp=[[${local_wp_points}]]}} {{local_sanity=[[${local_sanity_points}}]]}} {{repress= [^{repress}](~${character_id}|sanity_points)}}`;
rollValue=`${rollValue} {{projection=1}} {{repression=1}}`;
rollBonds(rollValue,values,names,parameters);
});
};
// Important functions
const setCommonParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`name`] = `${repsecid}_name`;
_input_names[`repsecid`] = `${repsecid}`;
_parameters.push(_input_names[`name`]);
_input_names[`willpower_points`] = `willpower_points`;
_parameters.push(`willpower_points`);
_input_names[`sanity_points`] = `sanity_points`;
_parameters.push(`sanity_points`);
_input_names[`low_willpower`] = `low_willpower`;
_parameters.push(`low_willpower`);
_input_names[`zero_willpower`] = `zero_willpower`;
_parameters.push(`zero_willpower`);
_input_names[`character_id`] = `character_id`;
_parameters.push(`character_id`);
}
const setSkillsParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`rank`] = `${repsecid}_rank`;
_input_names[`fail`] = `${repsecid}_fail`;
_parameters.push(_input_names[`rank`]);
_parameters.push(_input_names[`fail`]);
}
const setBondsParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`local_wp_points`] = `willpower_points`;
_input_names[`local_sanity_points`] = `sanity_points`;
_input_names[`score`] = `${repsecid}_score`;
_input_names[`color`] = `${repsecid}_color`;
_parameters.push(_input_names[`local_wp_points`]);
_parameters.push(_input_names[`local_sanity_points`]);
_parameters.push(_input_names[`score`]);
_parameters.push(_input_names[`color`]);
};
const setSpecialParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`rank`] = `${repsecid}_skill_span`;
_parameters.push(_input_names[`rank`]);
};
const setGeneralWeaponParametersAndInputNames=(repsecid, _parameters, _input_names)=>{
_input_names[`rank`] = `${repsecid}_skill_span`;
_parameters.push(_input_names[`rank`]);
_input_names[`range`] = `${repsecid}_base_range`;
_parameters.push(_input_names[`range`]);
_input_names[`damage`] = `${repsecid}_damage`;
// write the push in function of the input name
_parameters.push(_input_names[`damage`]);
_input_names[`armor_piercing`] = `${repsecid}_armor_piercing`;
_parameters.push(_input_names[`armor_piercing`]);
_input_names[`ammo`] = `${repsecid}_ammo`;
_parameters.push(_input_names[`ammo`]);
_input_names[`hasammo`] = `${repsecid}_hasammo`;
_parameters.push(_input_names[`hasammo`]);
_input_names[`lethality_percent`]=`${repsecid}_lethality_percent`;
_parameters.push(_input_names[`lethality_percent`]);
_input_names[`kill_radius`]=`${repsecid}_kill_radius`;
_parameters.push(_input_names[`kill_radius`]);
};
const setShotgunParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`shotgun`] = `${repsecid}_shotgun`;
_parameters.push(_input_names[`shotgun`]);
_input_names[`hasDoubleBarrel`] = `${repsecid}_hasDoubleBarrel`;
_parameters.push(_input_names[`hasDoubleBarrel`]);
_input_names[`double_barrel`] = `${repsecid}_double_barrel`;
_parameters.push(_input_names[`double_barrel`]);
};
const setAccessoriesParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`accessories`]=`${repsecid}_hasAccessories`;
_parameters.push(_input_names[`accessories`]);
_input_names[`accessory_name`]=`${repsecid}_accessory_name`;
_parameters.push(_input_names[`accessory_name`]);
_input_names[`accessory_modifier`]=`${repsecid}_accessory_modifier`;
_parameters.push(_input_names[`accessory_modifier`]);
};
const setBlastRadiusParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`blast_radius`]=`${repsecid}_blast_radius`;
_parameters.push(_input_names[`blast_radius`]);
};
const setSelectiveFireParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`selfire`]=`${repsecid}_selfire`;
_parameters.push(_input_names[`selfire`]);
_input_names[`selfire_lethality_percent`]=`${repsecid}_selfire_lethality_percent`;
_parameters.push(_input_names[`selfire_lethality_percent`]);
_input_names[`selfire_type`]=`${repsecid}_selfire_type`;
_parameters.push(_input_names[`selfire_type`]);
};
const setAdvancedWeaponParametersAndInputNames=(repsecid, _parameters, _input_names) => {
_input_names[`advanced_weapons`]=`advanced_weapons`;
_parameters.push(_input_names[`advanced_weapons`]);
setShotgunParametersAndInputNames(repsecid, _parameters, _input_names);
setAccessoriesParametersAndInputNames(repsecid, _parameters, _input_names);
setBlastRadiusParametersAndInputNames(repsecid, _parameters, _input_names);
setSelectiveFireParametersAndInputNames(repsecid, _parameters, _input_names);
}
const setRepeatingParametersAndInputNames=(section, id, _parameters, _input_names) => {
const repsecid = `repeating_${section}_${id}`;
_input_names[`section`] = section;
_input_names[`id`] = id;
setCommonParametersAndInputNames(repsecid, _parameters, _input_names);
if (section === 'skills') {
setSkillsParametersAndInputNames(repsecid, _parameters, _input_names);
} else if (section === 'bonds') {
setBondsParametersAndInputNames(repsecid, _parameters, _input_names);
} else if (section === 'special') {
setSpecialParametersAndInputNames(repsecid, _parameters, _input_names);
} else if (section==='rituals') {
setRitualParametersAndInputNames(repsecid, _parameters, _input_names);
} else if (section==='weapons') {
setGeneralWeaponParametersAndInputNames(repsecid, _parameters, _input_names);
setAdvancedWeaponParametersAndInputNames(repsecid, _parameters, _input_names);
_input_names[`track_bullets`]=`track_bullets`;
_parameters.push(_input_names[`track_bullets`]);
} else {
console.error(`Section ${section} not found`);
}
}
//levelup character
const initializeRolls = () => {
if (!_isInitialized) {
// Perform the necessary setup for rolls
// Example setup code
updateAllRollsOnOpen();
setResetBreakingPointsOnOpen();
updateRitualInfoOnOpen();
updateadvancedweapons();
// Set the flag to true after initialization
_isInitialized = true;
}
};
const rollSanityDamages = (sanloss) => {
const standard =`{{trackbullets=[[0]]}} {{isCritical=[[0]]}}`;
var rollString= `${prefix_damage_roll} {{header=^{sanity loss}}}`
rollString+=`{{subheader=${sanloss}}} {{damage=[[${sanloss}]]}} ${standard}`;
startRoll(rollString, (results) => {
const newroll = getRollDamage(results,0,'damage',0);
newroll['isCritical']=0;
newroll['trackbullets']=0;
finishRoll(results.rollId,newroll);
});
};
const paythecost=(sanity_loss,other_costs,fraction=1) => {
// lower sanity loss (not half)
rollSan= `${prefix_ritualloss_roll}`;
//used for before the roll
var hasCosts = {};
CurrentValues.forEach((attrName) => {
const current=parseInt(other_costs[attrName]) || 0;
var price= other_costs[attrName+'_cost'];
if (attrName !== 'sanity_points') {
rollSan += ` {{${attrName}_cost=[[floor(${price}/${fraction})]]}}`
rollSan += ` {{${attrName}=${current}}}`
if (price !== 0 && price !== '0') {
rollSan += ` {{has_${attrName}=1}}`
hasCosts[attrName] = 1;
} else {
};
}
});
rollSan += ` {{sanity_points_cost=[[${sanity_loss}]]}}`;
rollSan += ` {{sanity_points=${other_costs.sanity_points}}}`;
rollSan += ` {{has_sanity_points=1}}`;
hasCosts['sanity_points'] = 1;
startRoll(rollSan, (results) => {
const newroll = {};
const update = {};
CurrentValues.forEach((attrName) => {
const attrCost=attrName+'_cost';
const old_value=parseInt(other_costs[attrName]) || 0;
const cost = parseInt(results.results[attrCost].result) || 0;
const new_value = Math.max(0,old_value - cost);
newroll[attrCost] = new_value;
if (hasCosts.hasOwnProperty(attrName)) {
update[attrName] = new_value;
}
});
finishRoll(results.rollId,newroll);
setAttrs(update, {silent:true}, () => {
updatebreakingpoints() // I need to update the breaking points in the callback
});
});
};
const acceptfailure=(sanity_loss_success,other_costs) => {
paythecost(sanity_loss_success,other_costs,2);
};
const forceconnection=(sanity_loss_failure,other_costs) => {
other_costs['power_score'] = other_costs['power_score']+1 ;
paythecost(sanity_loss_failure,other_costs,1);
};
const name_and_param=(repsecid,attrName, _parameters, _input_names) => {
_input_names[attrName] = `${repsecid}_${attrName}`;
_parameters.push(_input_names[attrName]);
};
const setRitualCostParametersAndInputNames = (repsecid, _parameters, _input_names) => {
RitualCosts.forEach((attrName) => {
name_and_param(repsecid,attrName, _parameters, _input_names);
});
};
const setRitualDamageParametersAndInputNames = (repsecid, _parameters, _input_names) => {
RitualDamages.forEach((attrName) => {
name_and_param(repsecid,attrName, _parameters, _input_names);
});
RitualHeals.forEach((attrName) => {
name_and_param(repsecid,attrName, _parameters, _input_names);
});
};
const setRitualParametersAndInputNames = (repsecid, _parameters, _input_names) => {
// general informations
RitualRolls.forEach((attrName) => {
name_and_param(repsecid,attrName, _parameters, _input_names);
});
setRitualCostParametersAndInputNames(repsecid, _parameters, _input_names);
setRitualDamageParametersAndInputNames(repsecid, _parameters, _input_names);
};
const getOtherCosts = (other_costs,values,names,array) => {
array.forEach((attrName) => {
other_costs[attrName]=(values[names[attrName]] != '') ? values[names[attrName]] : 0;;
});
};
const name_to_shorthand = (name) => {
if (name === 'willpower_points') {return 'WP';}
if (name === 'hit_points') {return 'HP';}
if (name === 'strength_score') {return 'STR';}
if (name === 'constitution_score') {return 'CON';}
if (name === 'dexterity_score') {return 'DEX';}
if (name === 'intelligence_score') {return 'INT';}
if (name === 'charisma_score') {return 'CHA';}
if (name === 'power_score') {return 'POW';}
};
const ritual_power_action = (character_id,repsecid,other_costs) => {
const const_button_part = '](~'+character_id+'|';
const prefix_power_reaction='{{power_button=[';
const suffix_power_reaction = const_button_part+'power)}}';
return prefix_power_reaction+'^{power}'+suffix_power_reaction;
}
/*
const ritual_attack_or_heal_action = (character_id,repsecid,other_costs,heal_or_attack='attack') => {
const value_target=heal_or_attack.replace('_damage','').replace('_lethality_percent','');
const value = real_damage(other_costs,value_target);
if (value === '') {return '';}
const const_button_part = '](~'+character_id+'|'+repsecid+'_';
const target_stat=name_to_shorthand(other_costs[`${value_target}_target_stat`]);
const prefix_button = `{{${heal_or_attack}_button=[`;
const suffix_button = target_stat+const_button_part+heal_or_attack+'-action)}}';
return prefix_button+value+suffix_button;
};
const ritual_attack_action = (character_id,repsecid,other_costs) => {
var ritual_rolls='';
ritual_rolls+= ritual_attack_or_heal_action(character_id,repsecid,other_costs,'attack_damage');
ritual_rolls+= ritual_attack_or_heal_action(character_id,repsecid,other_costs,'attack_lethality_percent');
return ritual_rolls;
};
const ritual_heal_action = (character_id,repsecid,other_costs) => {
var ritual_rolls='';
ritual_rolls+= ritual_attack_or_heal_action(character_id,repsecid,other_costs,'heal_damage');
ritual_rolls+= ritual_attack_or_heal_action(character_id,repsecid,other_costs,'heal_lethality_percent');
return ritual_rolls;
};
*/
const real_damage = (other_costs,heal_or_damage,damage_type) => {
if (damage_type === 'lethality_percent') {
return `${setMinMax(other_costs[`${heal_or_damage}_${damage_type}_amount`])}% `;
} else if (damage_type === 'damage') {
return parseRoll(other_costs[`${heal_or_damage}_${damage_type}_amount`]);
}
return '';
};
const ritual_attack_or_heal_action = (character_id,repsecid,other_costs,heal_or_attack,damage_type) => {
const value = real_damage(other_costs,heal_or_attack,damage_type);
if (value === '') {return '';}
const const_button_part = '](~'+character_id+'|'+repsecid+'_';
const target_stat=name_to_shorthand(other_costs[`${heal_or_attack}_target_stat`]);
const prefix_button = `{{${heal_or_attack}_button=[`;
const suffix_button = ` ${target_stat}${const_button_part}${heal_or_attack}_${damage_type}-action)}}`;
return prefix_button+value+suffix_button;
};
const ritual_attack_action = (character_id,repsecid,other_costs,damage_type) => {
return ritual_attack_or_heal_action(character_id,repsecid,other_costs,'attack',damage_type);
};
const ritual_heal_action = (character_id,repsecid,other_costs,damage_type) => {
return ritual_attack_or_heal_action(character_id,repsecid,other_costs,'heal',damage_type);
};
const prepare_ritual_rolls = (other_costs,values,names) => {
var localString='';
const attack_type = other_costs['attack_isLethal']
const heal_type = other_costs['heal_isLethal']
localString += ritual_attack_action(values[names['character_id']],names['repsecid'],other_costs,attack_type);
localString += ritual_heal_action(values[names['character_id']],names['repsecid'],other_costs,heal_type);
if (values[names['power_reaction']] === 'active') {
localString += ritual_power_action(values[names['character_id']],names['repsecid']);
}
return localString;
};
const clicked_repeating_rituals = (parameters,names,queryModifier) => {
getAttrs(parameters, (values) => {
// cost of the ritual
const other_costs={};
getOtherCosts(other_costs,values,names,RitualCosts);
getOtherCosts(other_costs,values,names,RitualDamages);
getOtherCosts(other_costs,values,names,RitualHeals);
//----------------------------------------------------------------------------------------------
//---------Not used for the roll, they are always zero. Ask Shane if he wants it----------------
//const wp_mod=check_for_wp_modifiers(values,rollName);
const low_willpower = 0 //wp_mod.low_willpower;
const zero_willpower = 0 //wp_mod.zero_willpower;
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
// what is needed to roll
const rating = values[names['skill_span']];
const sanity_loss_success = other_costs['sanity_loss_success'];
const sanity_loss_failure = other_costs['sanity_loss_failure'];
// info ritual
const ritual_name = values[names['name']];
const description = values[names['description']];
var rollString=`${prefix_ritual_roll} {{header=${ritual_name}}}`;
rollString +=` {{subheader=${rating}}}`;
rollString +=` {{rating=[[${rating}]]}}`;
rollString +=` {{queryModifier=${queryModifier}}}`;
if (description !=='') {rollString += `{{description=${description}}}`;}
rollString += `{{sanity_loss_success=${sanity_loss_success}}}`;
rollString += `{{sanity_loss_failure=${sanity_loss_failure}}}`;
rollString += `{{zero_willpower=[[${zero_willpower}]]}}`;
rollString += `{{low_willpower=[[${low_willpower}]]}}`;
var hasOtherCosts = false;
var costString = '';
Object.entries(other_costs).forEach(([key, value]) => {
if (value != '' && value!= '0') {costString += `{{${key}=${value}}}`; hasOtherCosts = true;}
});
rollString += costString;
rollString += `{{hasCost=[[0]]}}`;
rollString += prepare_ritual_rolls(other_costs,values,names);
const flawed_ritual = values[names['flawed_ritual']] === 'active' ? 1 : 0;
if (flawed_ritual === 1) {rollString += `{{flawed_ritual=${flawed_ritual}}}`;}
rollString += `{{modifier=[[${queryModifier}]]}}`;
const character_id=values['character_id'];
const repsecid=names['repsecid']; // ritualid is the repeating section id, not a parameter
rollString += `{{pay_cost=[^{pay the cost}](~${character_id}|${repsecid}_pay_cost)}}`;
rollString += `{{accept_failure=[^{accept}](~${character_id}|${repsecid}_accept_failure)}}`;
rollString += `{{reject_failure=[^{reject}](~${character_id}|${repsecid}_force_connection)}}`;
/// This are the only quantities than I need to manupulate
rollString += `{{isSuccess=[[0]]}}`;
startRoll(rollString, (results) => {
const activation_rating = parseInt(results.results.rating.result) || 0;
const dice = parseInt(results.results.dice.result) || 0;
const _flawed_ritual = (flawed_ritual ===1) ? -20 : 0;
const _modifier = correct_modifier((parseInt(results.results.modifier.result) || 0)+flawed_ritual,low_willpower);
const _rating = correct_rating(activation_rating,_modifier);
const hasCost = hasOtherCosts ? 1 : 0;
const outcome=check_success(dice,_rating);
newroll = {
isSuccess: outcome.isSuccess,
IsCritical: outcome.IsCritical,
dice: dice,
modifier: _modifier,
hasCost: hasCost,
flawed_ritual: _flawed_ritual,
low_willpower: low_willpower,
zero_willpower: zero_willpower,
};
finishRoll(results.rollId,newroll);
});
});
};
const empty_to_zero=(value) => {
return (value !== '' || value !=='0') ? value : 0;
}
const updateRitualInfoOnOpen = () => {
getSectionIDs('repeating_rituals', (ids) => {
ids.forEach((id) => {
ritual_rolls_info(`repeating_rituals_${id}`);
});
});
};
const ritual_rolls_info = (repsecid) => {
const update = {};
const _names={};
const _parameters=[];
_ritualInfo.forEach((ritual_name) => {
_names[ritual_name] = `${repsecid}_${ritual_name}`;
_parameters.push(_names[ritual_name]);
});
getAttrs(_parameters, (values) => {
const complexity = values[_names['complexity']];
const sanity_loss_success = empty_to_zero(values[_names['sanity_loss_success']]);
const sanity_loss_failure = empty_to_zero(values[_names['sanity_loss_failure']]);
const activation_time = empty_to_zero(values[_names['activation_time']])==0 ? '' : empty_to_zero(values[_names['activation_time']]);
const activation_time_unit = values[_names['activation_time_unit']];
const study_time = empty_to_zero(values[_names['study_time']])==0 ? '' : empty_to_zero(values[_names['study_time']]);
const study_time_unit = values[_names['study_time_unit']];
const unnatural_gain = empty_to_zero(values[_names['unnatural_gain']]);
const sanity_loss_for_learning = empty_to_zero(values[_names['sanity_loss_for_learning']]);
const willpower_points_cost = empty_to_zero(values[_names['willpower_points_cost']]);
const power_score_cost = empty_to_zero(values[_names['power_score_cost']]);
const hit_points_cost = empty_to_zero(values[_names['hit_points_cost']]);
const strength_score_cost = empty_to_zero(values[_names['strength_score_cost']]);
const constitution_score_cost = empty_to_zero(values[_names['constitution_score_cost']]);
const dexterity_score_cost = empty_to_zero(values[_names['dexterity_score_cost']]);
const intelligence_score_cost = empty_to_zero(values[_names['intelligence_score_cost']]);
const charisma_score_cost = empty_to_zero(values[_names['charisma_score_cost']]);
// complexity text
update[`${repsecid}_complexity_text`] = `${complexity} ritual`;
// study time text
var study_time_text = '';
if (study_time != '') {
study_time_text = `${study_time} ${study_time_unit}`;
} else {
study_time_text = study_time_unit;
}
update[`${repsecid}_study_time_text`] = `${study_time_text}`;
// learning text
var learning_cost_text = `${String(sanity_loss_for_learning).toUpperCase()}SAN`;
if (unnatural_gain != 0) {learning_cost_text += `; ${unnatural_gain} Unnatural`;}
update[`${repsecid}_study_cost_text`] = `${learning_cost_text}`;
// activation time text
var activation_time_text = '';
if (activation_time != '') {
activation_time_text = `${activation_time} ${activation_time_unit}`;
} else {
activation_time_text = activation_time_unit;
}
update[`${repsecid}_activation_time_text`] = `${String(activation_time_text).toUpperCase()}`;
// costs text
var costs_text = '';
if (willpower_points_cost != 0) {costs_text += `${willpower_points_cost}WP, `;}
if (hit_points_cost != 0) {costs_text += `${hit_points_cost}HP, `;}
if (power_score_cost != 0) {costs_text += `${power_score_cost}POW, `;}
if (strength_score_cost != 0) {costs_text += `${strength_score_cost}STR, `;}
if (constitution_score_cost != 0) {costs_text += `${constitution_score_cost}CON, `;}
if (dexterity_score_cost != 0) {costs_text += `${dexterity_score_cost}DEX, `;}
if (intelligence_score_cost != 0) {costs_text += `${intelligence_score_cost}INT, `;}
if (charisma_score_cost != 0) {costs_text += `${charisma_score_cost}CHA, `;}
if (sanity_loss_success != 0) {costs_text += `${sanity_loss_success}SAN/`;}
costs_text += `${sanity_loss_failure}SAN`;
update[`${repsecid}_cost_text`] = `${String(costs_text).toUpperCase()}`;
setAttrs(update, {silent:true}, () => {
});
});
};
usedModifier = (e,callback) => {
var queryModifier = 0;
getAttrs(['useKey','global_modifier_number'], (values) => {
const useKey = values['useKey'];
const globalModifier = parseInt(values['global_modifier_number']) || 0;
if (useKey === 'global') {
queryModifier = globalModifier;
}
if (e.altKey && useKey === 'alt') {queryModifier=_queryModifier;}
if (e.ctrlKey && useKey === 'ctrl') {queryModifier=_queryModifier;}
if (e.metaKey && useKey === 'meta') {queryModifier=_queryModifier;}
if (e.shiftKey && useKey === 'shift') {queryModifier=_queryModifier;}
if (useKey === 'none') {queryModifier=_queryModifier;}
console.log(`queryModifier: ${queryModifier}`);
callback(queryModifier);
});
}
on(`clicked:reset_global_modifier`, () => {
const update={'global_modifier_number':''};
setAttrs(update, {silent:true}, () => {
});
});
$20(selector).on(`click`, e => {
const roll = e.htmlAttributes.name.match(/^attr_(.*)_r$/)[1];
const _roll = (roll === 'sanity_points') ? 'sanity' : roll;
usedModifier(e,(queryModifier) =>{
console.log(`queryModifier: ${queryModifier}`);
const additionalParameters={}
if (arrays[`_editable_skills`].includes(_roll)){
const prefix_skill=_roll.slice(0,-2);
additionalParameters['editable_name']=`${_roll}_name`;
additionalParameters['editable_type']=prefix_skill.replace('_',' ');
}else{
const caps = (_roll === 'humint' || _roll === 'sigint') ? _roll.toUpperCase() : _roll.replace('_',' ')
additionalParameters['name']=caps.replace('_',' ');
}
const rollString=`${prefix_skill_roll} {{subheader=@{${roll}}}} `;
rollwithmodifiers(rollString,roll,queryModifier,additionalParameters);
});
});
$20(sanity_selector).on(`click`, e => {
const _input_name={};
var _parameters = [];
_input_name['success'] = 'sanity_loss_success';
_parameters.push(_input_name['success']);
_input_name['failure'] = 'sanity_loss_failure';
_parameters.push(_input_name['failure']);
getAttrs(['character_id','sanity_loss_success','sanity_loss_failure',
'sanity_type','violence_adapted','helplessness_adapted'], (values) => {
const charid=values['character_id'];
const sanity_loss_success=values['sanity_loss_success'] !== '' ? values['sanity_loss_success'] : 0;
const sanity_loss_failure=values['sanity_loss_failure'] !== '' ? values['sanity_loss_failure'] : 1;
const sanity_loss_type=values['sanity_type'];
console.log(sanity_loss_type);
var rollString = `${prefix_sanity_roll} {{header=@{character_name}}}`;
rollString += ` {{sanity_type=^{@{sanity_type}}}}`;
rollString += ` {{description=@{npc_description}}}`;
rollString += ` {{success_roll=[${sanity_loss_success}](~${charid}|sanity_loss_success)}}`;
rollString += ` {{failure_roll=[${sanity_loss_failure}](~${charid}|sanity_loss_failure)}}`;
console.info(sanity_loss_success);
console.info(sanity_loss_failure);
console.info('min roll:',minRoll(sanity_loss_success));
console.info('max roll:',maxRoll(sanity_loss_failure));
startRoll(rollString,results =>{
finishRoll(results.rollId)
});
});
});
$20('button.repeating_roll').on(`click`, e => {
const id = e.htmlAttributes.value;
const section = _repeating_sections[e.htmlAttributes.name.split('_')[1]];
usedModifier(e,(queryModifier) => {
var _input_names = {};
var _parameters = [];
setRepeatingParametersAndInputNames(section, id, _parameters, _input_names)
clicked_repeating_actions(section, _parameters, _input_names, queryModifier);
});
});
arrays['_sanity_loss'].forEach((attrName) => {
on(`clicked:${attrName}-action`, (eventInfo) => {
getAttrs([attrName],(values) => {
const sanloss=check_sanloss(values[attrName],attrName);
rollSanityDamages(sanloss,attrName);
});
});
});
_allrolls.forEach(roll => {
const _roll = (roll === 'sanity_points') ? 'sanity' : roll;
on(`clicked:${roll}-action`, (eventInfo) => {
const additionalParameters={}
if (arrays[`_editable_skills`].includes(_roll)){
const prefix_skill=_roll.slice(0,-2);
additionalParameters['editable_name']=`${_roll}_name`;
additionalParameters['editable_type']=prefix_skill.replace('_',' ');
}else{
const caps = (_roll === 'humint' || _roll === 'sigint') ? _roll.toUpperCase() : _roll.replace('_',' ')
additionalParameters['name']=caps.replace('_',' ');
}
const rollString=`${prefix_skill_roll} {{subheader=@{${roll}}}} `;
rollwithmodifiers(rollString,roll,_queryModifier,additionalParameters);
});
});
Object.entries(_repeating_sections).forEach(([attrName,section]) => {
on(`clicked:repeating_${section}:${attrName}-action`, (eventInfo) => {
const id = eventInfo.sourceAttribute.split('_')[2];
const queryModifier=_queryModifier;
var _input_names = {};
var _parameters =[];
setRepeatingParametersAndInputNames(section, id, _parameters, _input_names)
clicked_repeating_actions(section, _parameters, _input_names, queryModifier);
});
});
_ritual_damages.forEach((attrName) => {
_type_damages.forEach((type) => {
on(`clicked:repeating_rituals:${attrName}_${type}-action`, (eventInfo) => {
const id = eventInfo.sourceAttribute.split('_')[2];
const input_names = {};
var parameters =[];
input_names[`ritual_type`]=attrName;
parameters.push(`repeating_rituals_${id}_ritual_type`);
const repsecid = `repeating_rituals_${id}`;
input_names[`repsecid`]=repsecid;
input_names[`name`]=`${repsecid}_name`;
input_names[`damage_type`]=`${type}`;
input_names[`attack_or_heal`]=`${attrName}`;
parameters.push(input_names[`name`]);
setDamageRitualParametersAndInputNames(id, parameters, input_names);
clicked_repeating_damages(parameters,input_names,attrName);
});
});
});
_ritual_losses.forEach((attrName) => {
on(`clicked:repeating_rituals:${attrName}-action`, (eventInfo) => {
const id = eventInfo.sourceAttribute.split('_')[2];
const input_names = {};
var parameters =[];
input_names[`ritual_type`]=attrName;
parameters.push(`repeating_rituals_${id}_ritual_type`);
const repsecid = `repeating_rituals_${id}`;
input_names[`repsecid`]=repsecid;
input_names[`name`]=`${repsecid}_name`;
parameters.push(input_names[`name`]);
setRitualCostParametersAndInputNames(repsecid, parameters, input_names);
CurrentValues.forEach((attrName) => {
input_names[attrName]=`${attrName}`;
parameters.push(attrName);
});
clicked_repeating_rituals_cost(parameters,input_names);
});
});
_alldamages.forEach((attrName) => {
on(`clicked:repeating_weapons:${attrName}-action`, (eventInfo) => {
const id = eventInfo.sourceAttribute.split('_')[2];
var _input_names = {};
var _parameters =[];
setDamageParametersAndInputNames(id,attrName, _parameters, _input_names)
_input_names['rollName']=attrName;
clicked_repeating_damages(_parameters,_input_names);
});
});
// levelup character
on("clicked:levelup", () =>{
const copyarray=arrays['_skills']; // copy of the array containing all skills ranks
console.dir(copyarray);
getSectionIDs(`repeating_summary`, function(idarray) {
for(var i=0; i < idarray.length; i++) {
removeRepeatingRow("repeating_summary_" + idarray[i]);
}
});
const summary={}; // object to store the summary of the changes
const update={}; // object to update the attributes
const newrowattrs={}; // object to create a new row in the repeating_summary section
const named_skills = copyarray.map((sk) => `${sk}_name`);
const failed_skills = copyarray.map((sk) => `${sk}_fail`);
getAttrs(copyarray.concat(named_skills,failed_skills),(val)=>{
var newrowid;
var oldval=0;
var newval=0;
var name;
var var_rnd=0; // random variable of 1d4
copyarray.forEach( (sk) => {
if (val[`${sk}_fail`]=='on'){ //if the checkbox is checked
var_rnd=Math.ceil(Math.random() * 4); // generate a random number for each checked value (less number generated)
oldval=(parseInt(val[`${sk}`])||0);
newval=oldval+var_rnd;
name=val[`${sk}_name`];
summary[`${sk}`]=var_rnd; // how much the skill has changed 0-3
update[`${sk}`]=newval; // new value of the skill
update[`${sk}_fail`]='off'; // uncheck checkbox
newrowid = generateRowID();
newrowattrs['repeating_summary_' + newrowid + '_skillname'] = name;
newrowattrs['repeating_summary_' + newrowid + '_oldval'] = oldval;
newrowattrs['repeating_summary_' + newrowid + '_newval'] = newval;
}
});
});
getSectionIDs(`repeating_skills`, function(idarray) {
var rep_array=[];
var rep_rank=[];
var rep_name=[];
var rep_fail=[];
idarray.forEach((id) => {
rep_array.push(`repeating_skills_${id}`);
});
rep_rank=rep_array.map((sk) => `${sk}_rank`);
rep_name=rep_array.map((sk) => `${sk}_name`);
rep_fail=rep_array.map((sk) => `${sk}_fail`);
getAttrs(rep_rank.concat(rep_name,rep_fail),(val)=>{
var newrowid;
var oldval=0;
var newval=0;
var name;
var var_rnd=0; // random variable of 1d4
rep_array.forEach( (sk) => {
if (val[`${sk}_fail`]=='on'){ //if the checkbox is checked
var_rnd=Math.ceil(Math.random() * 4); // generate a random number for each checked value (less number generated)
oldval=(parseInt(val[`${sk}_rank`])||0);
newval=oldval+var_rnd;
name=val[`${sk}_name`];
summary[`${sk}`]=var_rnd; // how much the skill has changed 0-3
update[`${sk}_rank`]=newval; // new value of the skill
update[`${sk}_fail`]='off'; // uncheck checkbox
newrowid = generateRowID();
newrowattrs['repeating_summary_' + newrowid + '_skillname'] = name;
newrowattrs['repeating_summary_' + newrowid + '_oldval'] = oldval;
newrowattrs['repeating_summary_' + newrowid + '_newval'] = newval;
}
});
setAttrs(Object.assign(update,newrowattrs),{silent:true},()=>{
console.log('inside repeating section');
console.info(newrowattrs);
console.info(update);
});
});
});
});
arrays['_colored_derivative'].forEach(vitality => {
on(`change:${vitality}_points`, (eventInfo) => {
var value = parseInt(eventInfo.newValue) || 0;
value = (value < 0) ? 0 : value;
const maxval=`${vitality}_points_max`;
getAttrs([maxval], function(v) {
const max_val = parseInt(v[maxval]) || 0;
const low_val=2;
var update={};
update[`color_${vitality}`]='normal';
update[`${vitality}_modifier`]=0;
if (value > max_val) {
update[`color_${vitality}`]='extra';
}
if (value <= low_val) {
update[`color_${vitality}`]='low';
update[`${vitality}_modifier`]=1;
}
if (value == 0) {
update[`color_${vitality}`]='zero';
update[`${vitality}_modifier`]=2;
}
update[`${vitality}_points`]=value;
setAttrs(update, {silent:false}, ()=>{
});
});
});
});
_skill_percent.forEach(_skill_sec_percent => {
const section=_skill_sec_percent.section;
const field=_skill_sec_percent.field;
const input=`repeating_${section}_${field}`;
const skillspan=`repeating_${section}_skill_span`;
on(`change:repeating_${section}:${field}`, () => {
getAttrs([input], (value) => {
const SkillPercent = value[`repeating_${section}_${field}`];
const isInLinkingForm=isValidLinkInput(SkillPercent);
const isInNumericalForm=isSkillNumber(SkillPercent);
const update={};
var skillname='';
if (isInLinkingForm===false && isInNumericalForm===false) {
update[input]=0;
if (section !=='skills') {update[skillspan]=update[input];}
setAttrs(update,{silent:true},()=>{
});
}
if (isInNumericalForm){
const number= setMinMax(SkillPercent);
update[input]=number;
if (section !=='skills') {update[skillspan]=update[input];}
setAttrs(update,{silent:true},()=>{
});
}
if (isInLinkingForm) {
const skill=cleanedSkill(SkillPercent);
skillname=skill;
getAttrs([`${skillname}`], (values) => {
const number= setMinMax(values[skillname]);
if (section !=='skills') {update[skillspan]=number;}
setAttrs(update,{silent:true},()=>{
});
});
};
});
});
});
_only_number.forEach(_sect_object => {
const section=_sect_object.section;
const fields=_sect_object.fields;
if (Array.isArray(fields)) {
fields.forEach(field => {
const input=`repeating_${section}_${field}`;
on(`change:repeating_${section}:${field}`, () => {
getAttrs([input], (value) => {
const update={};
const number=setMinMax(value[input]);
update[input]=number;
setAttrs(update,{silent:true},()=>{
});
});
});
});
};
});
_number_or_roll.forEach(_sect_object => {
const section=_sect_object.section;
const fields=_sect_object.fields;
if (Array.isArray(fields)) {
fields.forEach(field => {
const input=`repeating_${section}_${field}`;
on(`change:repeating_${section}:${field}`, () => {
getAttrs([input], (value) => {
const update={};
const number=parseRoll(value[input]);
update[input]=number;
setAttrs(update,{silent:true},()=>{
});
});
});
});
};
});
arrays['_sanity_loss'].forEach(sanity => {
on(`change:${sanity}`, () => {
getAttrs([`${sanity}`], (v) => {
const value= parseRoll(v[sanity]);
const update={};
update[sanity]=value;
setAttrs(update, {silent:true}, () => {
console.info(`Sanity points updated`);
});
});
});
});
_shotgun_or_blast_radius.forEach(main => {
other= _shotgun_or_blast_radius.filter(el => el == main);
on(`change:repeating_weapons:${main}`, (eventInfo) => {
id = eventInfo.sourceAttribute.split('_')[2];
const main_name=`repeating_weapons_${id}_${main}`;
const other_name=`repeating_weapons_${id}_${other}`;
const double_barrel_name=`repeating_weapons_${id}_hasDoubleBarrel`;
getAttrs([main_name,other_name], (values) => {
console.info(values);
const main_value=values[main_name]==='active' ? 1 : 0;
const update={};
if (main_value===1 ){
if (main==='shotgun'){
update[`repeating_weapons_${id}_blast_radius`]=0;
update[double_barrel_name]='active';
}else{
update[double_barrel_name]=0;
update[`repeating_weapons_${id}_shotgun`]=0;
}
}
if (main_value===0){
update[double_barrel_name]=0;
}
setAttrs(update,{silent:true},()=>{
console.log('Shotgun or Blast Radius updated');
});
});
});
});
arrays['_settings_wp'].forEach(wp_setting => {
on(`change:${wp_setting}`, (eventInfo) => {
console.log('wp_setting changed:'+eventInfo.triggerName);
getAttrs(arrays['_settings_wp'].concat(arrays['_derived_modifiers']), (values) => {
var update = {};
if (values['mod_willpower_check'] === 'none'){
update[`low_willpower`] = 0;
update[`zero_willpower`] = 0;
}
if (values['mod_willpower_check'] === 'lowonly'){
update[`zero_willpower`] = 0;
update[`low_willpower`] = 1;
}
if (values['mod_willpower_check'] === 'all'){
update[`low_willpower`] = 1;
update[`zero_willpower`] = 1;
}
setAttrs(update, {silent:true}, () => {
console.log('Willpower Settings updated');
});
});
});
});
on(`change:repeating_skills:rank`, (eventInfo) => {
const newValue = setMinMax(parseInt(eventInfo.newValue) || 0, 0, 99);
update={};
update[eventInfo.sourceAttribute]=newValue;
setAttrs(update,{silent:true},()=>{
console.log('Repeating Skills updated on change');
});
});
Object.entries(_repeating_sections).forEach(([attrName,section]) => {
on(`change:repeating_${section}`, (eventInfo) => {
const id = eventInfo.sourceAttribute.split('_')[2];
changeRepeatingRolls(section,attrName,id);
});
});
// new function to compute san point max
on(`change:unnatural`, function(eventInfo) {
const newvalue = setMinMax(parseInt(eventInfo.newValue) || 0,0,99);
update={sanity_points_max: 99-newvalue, unnatural: newvalue};
setAttrs(update,{silent:true},()=>{
console.log('Sanity points updated');
});
});
arrays['_stats'].forEach(stat => {
const stat_score = `${stat}_score`;
const _sanity_array=['sanity_points', 'breaking_point','initial_san'];
const _initial_hp=['initial_str','initial_con','initial_hp'];
on(`change:${stat_score}`, () => {
var update = {};
getAttrs(arrays['_stats'].concat(_sanity_array,_initial_hp,['unnatural'],arrays['_stats'].map(el=> `${el}_score`)), function(values) {
const stat_score_value=parseInt(values[stat_score],10) || 0;
statInfo=setStatScore(stat_score_value,stat);
InitializationFlags=getInitializationFlags(statInfo,values)
setInitialPower(update,values,statInfo,InitializationFlags);
setInitialHp(update,values,statInfo,InitializationFlags)
update[stat]=statInfo[`stat`];
update[stat_score]=statInfo[`score`];
Object.assign(update,InitializationFlags);
updateSkillSpanOnChange(statInfo[`name`],statInfo[`score`],update,'Stats')
});
});
});
on(`change:ritual_skill`, (eventInfo) => {
const value = skill_in_bounds(eventInfo.newValue);
var update = {};
console.log('ritual_skill:',value);
update['ritual_skill'] = value;
updateSkillSpanOnChange('ritual_skill',value,update,'Rituals');
});
// === Update skills on change
arrays['_skills'].forEach(skill => {
on(`change:${skill}`, (eventInfo) => {
const value= skill_in_bounds(eventInfo.newValue);
var update={};
update[skill]=value;
updateSkillSpanOnChange(skill,value,update,'Skills')
});
});
on(`change:sanity_points`, () => {
updatebreakingpoints();
});
on(`change:breaking_point`, () => {
getAttrs(['breaking_point'], (values)=> {
const breaking_point = Math.max(0,parseInt(values.breaking_point, 10) || 0);
const update = {};
update['breaking_point_reset'] = breaking_point;
update['breaking_point']=breaking_point;
setAttrs(update, {silent:true}, () => {
});
});
});
on(`change:breaking_point_reset`,(eventInfo)=>{
const breaking_point_reset = parseInt(eventInfo.newValue, 10) || 0;
getAttrs(['breaking_point_reset'], (values)=> {
const breaking_point_reset = parseInt(values.breaking_point_reset, 10) || 0;
const update = {};
update['breaking_point_reset'] = Math.min(Math.max(0,breaking_point_reset),99);
setAttrs(update, {silent:true}, () => {
});
});
});
on(`clicked:breaking_point_resets`, () => {
resetBreakingPoints();
});
on(`change:global_modifier_number`, () => {
getAttrs(['global_modifier_number'], (values) => {
const modifier = parseInt(values['global_modifier_number']) || 0;
const update = {global_modifier_number:modifier};
setAttrs(update, {silent:true}, () => {
});
});
});
on(`change:repeating_skills remove:repeating_skills`, () => {
update_additionalskills();
});
on(`change:repeating_weapons:armor_piercing`, () => {
getAttrs(['repeating_weapons_armor_piercing'], (values) => {
const update = {};
update_armor_piercing(values.repeating_weapons_armor_piercing,update);
setAttrs(update, {silent:true}, () => {
});
});
});
on(`change:repeating_weapons:ammo_total remove:repeating_weapons`, (values) => {
const ammo_total = Math.max(0,parseInt(values.newValue)||0);
const update = {};
update[`repeating_weapons_ammo_total`] = ammo_total;
update[`repeating_weapons_ammo`] = ammo_total;
update[`repeating_weapons_hasammo`] = ammo_total > 0 ? 'active' : '0';
setAttrs(update, {silent:true}, () => {
});
});
on(`change:repeating_weapons:ammo`, (values) => {
const ammo = Math.max(0,parseInt(values.newValue)||0);
const update = {};
update[`repeating_weapons_ammo`] = ammo;
setAttrs(update, {silent:true}, () => {
});
});
_bond_attributes.forEach(attrName => {
on(`change:repeating_bonds:${attrName}`, (eventInfo) => {
const update={};
getAttrs(_score_info, (values) => {
updatebondscore(values,update,attrName==='score');
setAttrs(update, {silent:true}, () => {
console.log('Bond color updated');
console.info(update);
});
});
});
});
on(`change:repeating_rituals`, (eventinfo) => {
const id = eventinfo.sourceAttribute.split('_')[2];
ritual_rolls_info(`repeating_rituals_${id}`);
});
arrays['_adaptation'].forEach(adaptation => {
on(`change:${adaptation}`, () => {
getAttrs([adaptation], (values) => {
console.log('values:',values);
const value=parseInt(values[adaptation]) || 0;
console.log('adaptation changed:'+value);
const update={};
update[`${adaptation}_adapted`]= value===2 ? 1 : 0;
setAttrs(update, {silent:true}, () => {
update[`${adaptation}_adapted`] == 1 ? console.log(`${adaptation} adapted`) : console.log(`${adaptation} not adapted`);
});
});
});
});
on(`change:advanced_weapons`,()=>{
updateadvancedweapons()
});
on(`change:useKey`, () => {
getAttrs(['useKey'], (values) => {
const val = values['useKey'];
const update = {use_global_modifier:'inactive'};
if (val === 'global') {update['use_global_modifier']='active'};
console.log(`useKey: ${val}`);
setAttrs(update, {silent:true}, () => {
});
});
});
// === Update repeating skills on change
on(`change:repeating_skills:rank`, function(eventInfo) {
const value = parseInt(eventInfo.newValue) || 0;
if (value < 0) {
setAttributes({[eventInfo.sourceAttribute]: 0}, false);
}
if (value > 99) {
setAttributes({[eventInfo.sourceAttribute]: 99}, false);
}
});
const update_armor_piercing = (value,update) => {
const armor_piercing_text = value;
const armor_piercing_number = parseInt(armor_piercing_text) || 0;
if (armor_piercing_text !== '') { update[`repeating_weapons_armor_piercing`] = armor_piercing_number; }
};
//= force the stats to be positive and the skills to be between 0 and 99
on(`sheet:opened`, () => {
// === Versioning
getAttrs(['version'], values => { versioning(parseFloat(values.version) || 1); });
changeBondButtonColorOnOpen();
initializeRolls();
});
const isJSONString = (string) => {
let json= {};
try {
json = JSON.parse(string);
} catch (e) {
console.info('it is not a JSON');
return false;
}
console.info(`string`,json)
return json;
}
const arrays_drop={
fields : [
"employer","profession",
"accounting","alertness","anthropology","archeology","art_1","art_1_name","art_2","art_2_name","artillery","athletics","bureaucracy",
"computer_science","craft_1","craft_1_name","craft_2","craft_2_name","criminology","demolitions","disguise","dodge","drive","firearms",
"first_aid","forensics","heavy_machinery","heavy_weapons","history","humint","law","medicine","melee_weapons","military_science_1",
"military_science_1_name","military_science_2","military_science_2_name","navigate","occult","persuade","pharmacy","pilot_1","pilot_1_name",
"pilot_2","pilot_","psychotherapy","ride","science_1","science_1_name","science_1","science_2_name","search","sigint", "stealth","surgery",
"survival", "swim","unarmed_combat","unnatural",
"armor_and_gear","personal_details_and_notes","motivations","bond_number"],
visible: ["accounting","alertness","anthropology","archeology","art_1","art_1_name","art_2","art_2_name","artillery","athletics","bureaucracy",
"computer_science","craft_1","craft_1_name","craft_2","craft_2_name","criminology","demolitions","disguise","dodge","drive","firearms",
"first_aid","forensics","heavy_machinery","heavy_weapons","history","humint","law","medicine","melee_weapons","military_science_1",
"military_science_1_name","military_science_2","military_science_2_name","navigate","occult","persuade","pharmacy","pilot_1","pilot_1_name",
"pilot_2","pilot_","psychotherapy","ride","science_1","science_1_name","science_1","science_2_name","search","sigint", "stealth","surgery",
"survival", "swim","unarmed_combat","unnatural"],
bond: ["name","bond_score"],
skill: ["name","rank"],
special_training:["name","skill_or_stat_used"],
weapon :["name", "skill_percent", "base_range", "damage", "armor_piercing", "lethality_percent", "ammo"],
rep: {bond: "repeating_bonds_",special: "repeating_special_",skill:"repeating_skills_",ritual:"repeating_rituals_",weapon:"repeating_weapons_"},
}
const dropAgent = (data) => {
const updateAttrs = {};
updateAttrs[`sheet_type`] = "pc";
// First of all reset skills and repeating sections for skills and abilities
resetBonds(updateAttrs);
resetSkills(updateAttrs);
resetAllRepeatingSkills(updateAttrs);
resetAllSpecialAbilities(updateAttrs);
console.log(`Agent Reset:`,updateAttrs);
// bonds
const special_trainings = isJSONString(data.repeated_special_trainings);
const rituals= isJSONString(data.repeating_rituals);
const weapons= isJSONString(data.repeating_weapons);
const repSkills= isJSONString(data.repeating_skills);
const dropfields= arrays_drop[`fields`];
const visible=arrays_drop['visible'];
console.log(`special_trainings: ${special_trainings}`);
console.log(`rituals: ${rituals}`);
console.log(`weapons: ${weapons}`);
console.log(`repSkills: ${repSkills}`);
if (repSkills){
for (const skill of repSkills){
let dRepSkills=dropRepSkills(skill);
Object.keys(dRepSkills).forEach(key => updateAttrs[key] = dRepSkills[key]);
}
}
if (special_trainings){
for (const special_training of special_trainings){
let dSpecialTraining=dropSpecialTraining(special_training);
Object.keys(dSpecialTraining).forEach(key => updateAttrs[key] = dSpecialTraining[key]);
}
}
/*
if (rituals){
for (const ritual of rituals){
let dRitual=dropRitual(ritual);
Object.keys(dRitual).forEach(key => updateAttrs[key] = dRitual[key]);
}
}
*/
if (weapons){
for (const weapon of weapons){
let dWeapons=dropWeapon(weapon);
Object.keys(dWeapons).forEach(key => updateAttrs[key] = dWeapons[key]);
}
}
console.info('drop fields:',dropfields);
for (const field of dropfields){
console.log(field);
console.log(data[field]);
if (data[field]){
if (field === "bond_number") {
for (i=0; i<data[field]; i++){
let UIDD = generateRowID();
let prefix=`${arrays_drop[`rep`][`bond`]}${UIDD}`;
updateAttrs[`${prefix}_name`] = `bond_${i}`;
updateAttrs[`${prefix}_test`] = `editable`;
}
}else if (data[field]==="name"){
updateAttrs[`profession`] = data[field];
}else{
updateAttrs[field] = data[field];
}
if (visible.includes(field)){
updateAttrs[`${field}_visible`]=`visible`;
}
}
}
console.info(`Agent:`,updateAttrs);
return updateAttrs;
}
const dropRepSkills = (data) => {
const updateAttrs = {};
let UIDD = generateRowID();
let prefix=`${arrays_drop[`rep`][`skill`]}${UIDD}`;
const dropskillfields=arrays_drop[`skill`];
dropskillfields.forEach(field =>{
updateAttrs[`${prefix}_${field}`] = data[field];
});
updateAttrs[`${prefix}_test`] = `editable`;
console.info(`repeating skills:`,updateAttrs);
return updateAttrs;
}
const dropSpecialTraining = (data) => {
const updateAttrs = {};
let UIDD = generateRowID();
var prefix=`${arrays_drop[`rep`][`special`]}${UIDD}`;
const dropspecialtrainingfields=arrays_drop[`special_training`];
dropspecialtrainingfields.forEach(field =>{
if (data[field]){
if (field === "skill_or_stat_used"){
let skillname=data[`skill_or_stat_used`].toLowerCase().replace(/ /g, "_");
updateAttrs[`${prefix}_skill_or_stat_used`] = `@{${skillname}}`;
}else{
updateAttrs[`${prefix}_${field}`] = data[field];
}
}
});
updateAttrs[`${prefix}_test`] = `editable`;
console.info(`special training:`, updateAttrs);
return updateAttrs;
}
/*
const dropRitual = (data) => {
const updateAttrs = {};
const UIDD = generateRowID();
const prefix=`repeating_rituals_${UIDD}`;
// to be updated when the format is decided
console.log(updateAttrs);
return updateAttrs;
}
const dropMonster = (data) => {
const updateAttrs = {};
updateAttrs[`sheet_type`] = "npc";
// to be updated when the format is decided
console.log(updateAttrs);
return updateAttrs;
}
*/
const dropWeapon = (data) => {
const updateAttrs = {};
let UIDD = generateRowID();
var prefix=`${arrays_drop[`rep`][`weapon`]}${UIDD}`;
const weaponfields=arrays_drop[`weapon`];
if (data.hasOwnProperty(weaponfields[2])==false){
console.warn(`weapon uses the repeating field format`);
data=isJSONString(data.repeating_weapons);
console.log(data);
}
updateAttrs[`${prefix}_test`] = 'editable';
for (const field of weaponfields){
if (data[field]){
if (field === "skill_percent"){
let skillname=cleanedSkill(data[field]);
console.info(skillname);
if (isSkillNumber(skillname)){
updateAttrs[`${prefix}_skill_percent`] = skillname;
}else if (isValidSkill(skillname)){
updateAttrs[`${prefix}_skill_percent`] = `@{${skillname}}`;
}else{
console.error(`skill not found: ${skillname}`);
}
}else{
updateAttrs[`${prefix}_${field}`] = data[field];
}
}
}
console.log(`weapon:`, updateAttrs);
return updateAttrs;
}
const getDropType = data => data.Category || false;
const handleDragandDrop = () => {
getAttrs(["drop_name","drop_data"], (v) => {
const {drop_name, drop_data} = v;
if (drop_name==="" || drop_data===""){return;}
const dropDataParsed =JSON.parse(drop_data);
const dropType = getDropType(dropDataParsed);
console.info(`drop type:`, dropType);
console.info('data:',dropDataParsed);
var updateAttrs = false;
if (dropType === "Agents"){
console.log("It's an Agent");
updateAttrs= dropAgent(dropDataParsed);
}
if (dropType === "Bonds"){
console.log("It's a Bond");
updateAttrs= dropBond(dropDataParsed);
}
if (dropType === "SpecialTrainings"){
console.log("It's an Special Training");
updateAttrs= dropSpecialTraining(dropDataParsed);
}
if (dropType === "Weapons"){
console.log("It's a Weapon");
updateAttrs= dropWeapon(dropDataParsed);
}
if (updateAttrs === false) {
updateAttrs = {...{drop_name:"", drop_data:"",drop_category:""}};
setAttrs(updateAttrs);
return console.warn("Drag and drop could not identify the type of drop");
}
if (typeof updateAttrs !== "object") {
updateAttrs = {...{drop_name:"", drop_data:"",drop_category:""}};
setAttrs(updateAttrs);
return console.warn("Drag and drop returned broken value");
}
const updateAttrsTot = {...updateAttrs, ...{drop_name:"", drop_data:"",drop_category:""}};
console.log(updateAttrsTot);
setAttrs(updateAttrsTot);
});
}
on("change:drop_data", (eventInfo) => {
const jsonData = JSON.parse(eventInfo.newValue);
console.log(jsonData);
handleDragandDrop();
// do something with data
});
on(`change:repeating_agents:name change:repeating_agents:test`, (eventInfo)=> {
const id = eventInfo.sourceAttribute.split(`_`)[2];
const repsecid = `repeating_agents_${id}`;
getAttrs([`${repsecid}_name`],(values)=> {
const update = {};
const info_to_get=['hit_points', 'willpower_points', 'sanity_points', 'strength_score', 'constitution_score']
const character_name = values[`repeating_agents_${`id`}_name`];
var string = ``;
info_to_get.forEach((field)=>{
string += `{{${field}=[[@{${character_name}|${field}]]}} `;
});
startRoll(string,results=>{
info_to_get.forEach((field)=>{
update[`${repsecid}_${field}`] = results.results[field].result;
});
setAttrs(update);
})
});
});