diff --git a/ADnD_2E_Revised/2ESheet.html b/ADnD_2E_Revised/2ESheet.html index 75408cb1fe..7e22a80b36 100644 --- a/ADnD_2E_Revised/2ESheet.html +++ b/ADnD_2E_Revised/2ESheet.html @@ -2054,12 +2054,10 @@ - +
- -

Special Abilities and Attacks

@@ -2207,6 +2205,9 @@ Damage L Knockdown Amount + Size + Type + Crit II Spec @@ -2214,62 +2215,72 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StrDexAmmoPoint BlankDamage
Adj.
Damage S/MDamage LKnockdownAmount
SpecMast
-
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrDexAmmoPoint BlankDamage
Adj.
Damage S/MDamage LKnockdownAmountSizeType
SpecMast
+ +
+


@@ -18299,6 +18310,12 @@ Weapons, Spells, and Proficiencies + + Player's Option: Combat & Tactics + 1995 June + Weapons, Proficiencies, Talents, and Disadvantages + +

Optional rules for spells

@@ -20658,7 +20675,7 @@ - + @@ -20705,8 +20722,8 @@ - - + + @@ -48957,7 +48974,7 @@ const BOOK_FIELDS = [ 'book-tom', 'book-aaeg', 'book-dwarves', 'book-bards', 'book-elves', 'book-humanoids', 'book-rangers', 'book-paladins', 'book-druids', 'book-barbarians', 'book-necromancers', 'book-ninjas', - 'book-combat-and-tacticss', + 'book-combat-and-tactics', ]; const SCHOOL_FIELDS = ['school-spells-and-magic']; @@ -49018,6 +49035,10 @@ const displayWeaponType = function (type) { } } +const getRowId = function (triggerName) { + return triggerName.match(/repeating_[^_]+_([^_]+)_[^_]+/)[1]; +} + const conditionalLog = function (bool, msg) { if (bool) console.log(msg); @@ -49026,12 +49047,14 @@ const conditionalLog = function (bool, msg) { const extractQueryResult = async function(query){//Sends a message to query the user for some behavior, returns the selected option. let queryRoll = await startRoll(`!{{query=[[0[response=${query}]]]}}`); finishRoll(queryRoll.rollId); + console.log(queryRoll); return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,''); }; const extractRoll = async function(rollExpression) { let queryRoll = await startRoll(`!{{roll=[[${rollExpression}]]}}`); finishRoll(queryRoll.rollId); + console.log(queryRoll); return queryRoll.results.roll; }; @@ -49118,8 +49141,8 @@ const getActiveSettings = function (settingFields, values) { const isBookInactive = function (books, obj) { let activeBooks = getActiveSettings(BOOK_FIELDS, books); - if (Array.isArray(obj['book'])) - return !obj['book'].some(b => activeBooks.has(b)); + if (Array.isArray(obj)) + return obj.every(b => !activeBooks.has(b)); else return !activeBooks.has(obj['book']); } @@ -49127,9 +49150,9 @@ const isBookInactive = function (books, obj) { const bookInactiveShowToast = function(books, obj) { let bookInactive = isBookInactive(books, obj); if (bookInactive) { - if (Array.isArray(obj['book'])) { - let booksString = obj['book'].map(b => '\n* ' + b).join('') + '\n' - showToast(ERROR, 'Missing Book(s)', `The book(s) ${booksString} are currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); + if (Array.isArray(obj)) { + let booksString = obj.map(b => '\n* ' + b).join('') + showToast(ERROR, 'Missing Book(s)', `The book(s):${booksString}\nAre currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); } else { showToast(ERROR, 'Missing Book', `The book *${obj['book']}* is currently not active on your sheet.\nGo to the *Sheet Settings* and activate the book (if your DM allows for its usage)`); } @@ -50163,64 +50186,72 @@ on('change:thac0-base-calc', function(eventInfo) { }); //#region Weapons autofill -function setWeaponWithBonus(weaponName, setWeaponFunc, thac0Field) { +const PLAYERS_OPTIONS_FIELD = 'tab81'; +function setWeaponWithBonus(weaponName, setWeaponFunc, comparer, thac0Field, category) { if (!weaponName) return; weaponName = weaponName.toLowerCase(); - let fields = [...BOOK_FIELDS, thac0Field].filter(Boolean); - getAttrs(fields, function(values) { + let fields = [...BOOK_FIELDS, PLAYERS_OPTIONS_FIELD, thac0Field].filter(Boolean); + getAttrs(fields, async function (values) { + let bonus = 0; + let baseWeapons = WEAPONS_TABLE[weaponName] + if (!baseWeapons) { + let match = weaponName.match(/\s*\+([0-9]+)\s*/); + if (!match) + return; + + let baseWeaponName = weaponName.replace(match[0], ' ').trim(); + baseWeapons = WEAPONS_TABLE[baseWeaponName]; + if (!baseWeapons) + return; + + bonus = parseInt(match[1]); + if (isNaN(bonus)) + return; + } + if (category) + baseWeapons = baseWeapons.filter(w => w['category'].includes(category)); + + let activeBooks = getActiveSettings(BOOK_FIELDS, values); + let activeWeapons = baseWeapons.filter(w => w['book'].some(b => activeBooks.has(b))); + + + if (activeWeapons.length === 0) { + let booksString = baseWeapons.flatMap(w => w['book']).map(b => '\n* ' + b).join('') + showToast(ERROR, 'Missing Book(s)', `The book(s):${booksString}\nAre currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); + return; + } + + let baseWeapon; + let isPlayersOptions = values[PLAYERS_OPTIONS_FIELD] === '2'; + let isAllEqual = activeWeapons.every(w => comparer(w, activeWeapons[0], isPlayersOptions)); + if (isAllEqual) { + baseWeapon = activeWeapons[0]; + } else { + let options = activeWeapons + .map((w, i) => `${w.book.join('/')},${i}`) + .join('|'); + let answer = await extractRollResult(`?{Multiple versions of this weapon exists. Please select a version|${options}}`); + baseWeapon = activeWeapons[answer]; + } + let thac0 = parseInt(values[thac0Field]); thac0 = isNaN(thac0) ? 20 : thac0; - let baseWeapon = weapons[weaponName] - if (baseWeapon) { - if (bookInactiveShowToast(values, baseWeapon)) - return; - - setWeaponFunc({ - ...baseWeapon, - 'thac0' : thac0, - 'bonus' : '0' - }); - return; - } - - let match = weaponName.match(/\s*\+([0-9]+)\s*/); - if (!match) - return; - - let baseWeaponName = weaponName.replace(match[0], ' ').trim(); - baseWeapon = weapons[baseWeaponName]; - if (!baseWeapon) - return; - - if (bookInactiveShowToast(values, baseWeapon)) - return; - - let bonusString = match[1]; - let bonus = parseInt(bonusString) - if (isNaN(bonus)) - return; - - if (bonus < 1) { - setWeaponFunc({ - ...baseWeapon, - 'thac0' : thac0, - 'bonus' : '0', - 'bonusInt': 0 - }); - return; - } - - let weaponWithBonus = { + let weapon = { ...baseWeapon, 'thac0' : thac0, - 'speed' : Math.max(baseWeapon['speed'] - bonus, 0), - 'bonus' : `+${bonus}`, - 'bonusInt': bonus + }; + if (bonus < 1) { + weapon['bonus'] = '0'; + weapon['bonusInt'] = 0; + } else { + weapon['bonus'] = `+${bonus}`; + weapon['bonusInt'] = bonus; + weapon['speed'] = Math.max(weapon['speed'] - bonus, 0) } - setWeaponFunc(weaponWithBonus); + setWeaponFunc(weapon); }); } @@ -50232,21 +50263,21 @@ on('change:repeating_weapons:weaponname', function(eventInfo) { compareFields.push('reach'); return compareFields.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons_attackadj' : weapon['bonus'], - 'repeating_weapons_ThAC0' : weapon['thac0'], - 'repeating_weapons_range' : weapon['reach'] || 'Melee', - 'repeating_weapons_size' : weapon['size'], - 'repeating_weapons_weapspeed' : weapon['speed'], - 'repeating_weapons_weaptype-slash' : weapon['type'].includes('S') ? 1 : 0, - 'repeating_weapons_weaptype-pierce': weapon['type'].includes('P') ? 1 : 0, - 'repeating_weapons_weaptype-blunt' : weapon['type'].includes('B') ? 1 : 0, - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons_${rowId}_attackadj`] = weapon['bonus']; + weaponInfo[`repeating_weapons_${rowId}_ThAC0`] = weapon['thac0']; + weaponInfo[`repeating_weapons_${rowId}_range`] = weapon['reach'] || 'Melee'; + weaponInfo[`repeating_weapons_${rowId}_size`] = weapon['size']; + weaponInfo[`repeating_weapons_${rowId}_weapspeed`] = weapon['speed']; + weaponInfo[`repeating_weapons_${rowId}_weaptype-slash`] = weapon['type'].includes('S') ? 1 : 0; + weaponInfo[`repeating_weapons_${rowId}_weaptype-pierce`] = weapon['type'].includes('P') ? 1 : 0; + weaponInfo[`repeating_weapons_${rowId}_weaptype-blunt`] = weapon['type'].includes('B') ? 1 : 0; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, comparer, setWeaponFunc, 'thac0-base-calc'); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, 'thac0-base-calc', 'Melee'); }); //melee damage autofill @@ -50255,25 +50286,25 @@ on('change:repeating_weapons-damage:weaponname1', function(eventInfo) { let fisk = ['small-medium','large']; if (isPlayersOption) { fisk.push('size'); - fisk.push('type') + fisk.push('type'); fisk.push('knockdown'); } return fisk.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons-damage_damadj' : weapon['bonus'], - 'repeating_weapons-damage_damsm' : weapon['small-medium'], - 'repeating_weapons-damage_daml' : weapon['large'], - 'repeating_weapons-damage_damsize' : weapon['size'], - 'repeating_weapons-damage_damtype' : weapon['type'], - 'repeating_weapons-damage_knockdown1' : weapon['knockdown'] || '' - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons-damage_${rowId}_damadj`] = weapon['bonus']; + weaponInfo[`repeating_weapons-damage_${rowId}_damsm`] = weapon['small-medium']; + weaponInfo[`repeating_weapons-damage_${rowId}_daml`] = weapon['large']; + weaponInfo[`repeating_weapons-damage_${rowId}_knockdown1`] = weapon['knockdown'] || ''; + weaponInfo[`repeating_weapons-damage_${rowId}_size`] = weapon['size']; + weaponInfo[`repeating_weapons-damage_${rowId}_type`] = weapon['type']; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, '', 'Melee'); }); //range hit autofill @@ -50281,71 +50312,86 @@ on('change:repeating_weapons2:weaponname2', function(eventInfo) { let comparer = function (weapon1, weapon2, isPlayersOption) { return ['strength','rof','range','size','speed','type'].every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons2_strbonus2' : weapon['strength'] ? 1 : 0, - 'repeating_weapons2_attacknum2' : weapon['rof'] || '', - 'repeating_weapons2_attackadj2' : weapon['bonus'], - 'repeating_weapons2_ThAC02' : weapon['thac0'], - 'repeating_weapons2_range2' : weapon['range'] || '', - 'repeating_weapons2_size2' : weapon['size'], - 'repeating_weapons2_weapspeed2' : weapon['speed'], - 'repeating_weapons2_weaptype-slash2' : weapon['type'].includes('S') ? 1 : 0, - 'repeating_weapons2_weaptype-pierce2' : weapon['type'].includes('P') ? 1 : 0, - 'repeating_weapons2_weaptype-blunt2' : weapon['type'].includes('B') ? 1 : 0, - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons2_${rowId}_strbonus2`] = weapon['strength'] ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_attacknum2`] = weapon['rof'] || ''; + weaponInfo[`repeating_weapons2_${rowId}_attackadj2`] = weapon['bonus']; + weaponInfo[`repeating_weapons2_${rowId}_ThAC02`] = weapon['thac0']; + weaponInfo[`repeating_weapons2_${rowId}_range2`] = weapon['range'] || ''; + weaponInfo[`repeating_weapons2_${rowId}_size2`] = weapon['size']; + weaponInfo[`repeating_weapons2_${rowId}_weapspeed2`] = weapon['speed']; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-slash2`] = weapon['type'].includes('S') ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-pierce2`] = weapon['type'].includes('P') ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-blunt2`] = weapon['type'].includes('B') ? 1 : 0; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, 'thac0-base-calc'); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, 'thac0-base-calc', 'Range'); }); //range damage autofill on('change:repeating_ammo:ammoname', function(eventInfo) { - let comparer = function (weapon1, weapon2) { - return ['strength','small-medium','large','size'].every(f => weapon1[f] === weapon2[f]) + let comparer = function (weapon1, weapon2, isPlayersOption) { + let comparerFields = ['strength','small-medium','large']; + if (isPlayersOption) { + comparerFields.push('knockdown'); + comparerFields.push('size'); + comparerFields.push('ammo-size'); + comparerFields.push('type'); + } + return comparerFields.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons2_strbonus3' : weapon['strength'] ? 1 : 0, - 'repeating_ammo_damadj2' : weapon['bonus'], - 'repeating_ammo_damsm2' : weapon['small-medium'], - 'repeating_ammo_daml2' : weapon['large'], - 'repeating_weapons-damage_knockdown2' : weapon['knockdown'] || '' - }; + let weaponInfo = {}; + weaponInfo[`repeating_ammo_${rowId}_strbonus3`] = weapon['strength'] ? 1 : 0; + weaponInfo[`repeating_ammo_${rowId}_damadj2`] = weapon['bonus']; + weaponInfo[`repeating_ammo_${rowId}_damsm2`] = weapon['small-medium']; + weaponInfo[`repeating_ammo_${rowId}_daml2`] = weapon['large']; + weaponInfo[`repeating_ammo_${rowId}_knockdown2`] = weapon['knockdown'] || ''; + weaponInfo[`repeating_ammo_${rowId}_size`] = weapon['ammo-size'] || weapon['size']; + weaponInfo[`repeating_ammo_${rowId}_type`] = weapon['type']; setAttrs(weaponInfo); } - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, '', 'Range'); }); //Follower weapons function setupFollowerWeaponsAutoFill(repeating, sections) { let prefix = ''; - let onChange = ''; if (repeating !== '') { - prefix = `repeating_${repeating}_` - onChange = `repeating_${repeating}:` + prefix = `repeating_${repeating}` } sections.forEach(section => { - on(`change:${onChange}weaponnamehench${section}`, function(eventInfo) { + on(`change:${prefix}:weaponnamehench${section}`, function(eventInfo) { + let comparer = function (weapon1, weapon2, isPlayersOption) { + let comparerFields = ['rof','small-medium','large','range','type','speed']; + if (isPlayersOption) { + comparerFields.push('reach'); + comparerFields.push('knockdown'); + } + return comparerFields.every(f => weapon1[f] === weapon2[f]) + } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - [`${prefix}attacknumhench${section}`]: weapon['rof'] || '1', - [`${prefix}attackadjhench${section}`]: weapon['bonus'], - [`${prefix}damadjhench${section}`]: weapon['bonus'], - [`${prefix}damsmhench${section}`]: weapon['small-medium'], - [`${prefix}damlhench${section}`]: weapon['large'], - [`${prefix}rangehench${section}`]: weapon['range'] || weapon['reach'] || 'Melee', - [`${prefix}weaptypehench${section}`]: weapon['type'], - [`${prefix}weapspeedhench${section}`]: weapon['speed'], - }; + let weaponInfo = {}; + weaponInfo[`${prefix}_${rowId}_attacknumhench${section}`] = weapon['rof'] || '1'; + weaponInfo[`${prefix}_${rowId}_attackadjhench${section}`] = weapon['bonus']; + weaponInfo[`${prefix}_${rowId}_damadjhench${section}`] = weapon['bonus']; + weaponInfo[`${prefix}_${rowId}_damsmhench${section}`] = weapon['small-medium']; + weaponInfo[`${prefix}_${rowId}_damlhench${section}`] = weapon['large']; + weaponInfo[`${prefix}_${rowId}_rangehench${section}`] = weapon['range'] || weapon['reach'] || 'Melee'; + weaponInfo[`${prefix}_${rowId}_weaptypehench${section}`] = weapon['type']; + weaponInfo[`${prefix}_${rowId}_weapspeedhench${section}`] = weapon['speed']; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer); }); }); } @@ -50445,105 +50491,97 @@ on('clicked:grenade-miss', async function (eventInfo) { }); }); -on('clicked:crit-melee', function(eventInfo) { - TAS.repeating('weapons-damage') - .attrs(['strengthdmg', 'dexmissile', 'temp-damadj', 'misc-mod', ...BOOK_FIELDS]) - .fields('strbonus1', 'dexbonus1', 'weaponname1', 'specialist-damage', 'mastery-damage', 'damadj', 'damsm', 'daml') - .map(function (row){ - return row; - }, async function (rows, _, attrSet){ - let weaponSelect = rows.map(r => `${r['weaponname1']},${r.id}`) +on('clicked:repeating_weapons-damage:crit2-melee', function(eventInfo) { + console.log(eventInfo); + let fields = [ + 'strengthdmg', 'dexmissile', 'temp-damadj', 'misc-mod', + 'repeating_weapons-damage_strbonus1','repeating_weapons-damage_dexbonus1','repeating_weapons-damage_weaponname1', + 'repeating_weapons-damage_specialist-damage','repeating_weapons-damage_mastery-damage','repeating_weapons-damage_damadj', + 'repeating_weapons-damage_damsm','repeating_weapons-damage_daml','repeating_weapons-damage_size','repeating_weapons-damage_type']; + getAttrs(fields, async function (values) { + let finalRollText = `&{template:2Edefault} {{name=Test Critical hit}} {{Weapon name=${values['repeating_weapons-damage_weaponname1']}}} `; + + let attackType = await extractQueryResult('?{How are you attacking?|Regular Attack|Low Attack|High Attack}'); + let targetType = await extractQueryResult('?{What are you attacking?|Humanoid|Animal|Monster}'); + let targetSize = await extractQueryResult('?{Target size?|Tiny|Small|Medium|Large|Huge|Gargantuan}'); + + let weaponSize = displaySize(values['repeating_weapons-damage_size']); + let weaponType = values['repeating_weapons-damage_type']; + if (weaponType.includes('/')) { + let displayTypes = weaponType.split('/') + .map(s => displayWeaponType(s)) .join('|'); - let rowId = await extractQueryResult(`?{What weapon did you use?|${weaponSelect}}`); - let row = rows.find(row => row.id === rowId); - let finalRollText = '&{template:2Edefault} {{name=Test Critical hit}}'; + weaponType = await extractQueryResult(`?{How are your attack with your weapon?|${displayTypes}}`) + } else { + weaponType = displayWeaponType(weaponType); + } - let attackType = await extractQueryResult('?{How are you attacking?|Regular Attack|Low Attack|High Attack}'); - let targetType = await extractQueryResult('?{What are you attacking?|Humanoid|Animal|Monster}'); - let targetSize = await extractQueryResult('?{Target size?|Tiny|Small|Medium|Large|Huge|Gargantuan}'); + finalRollText += `{{Weapon type=${attackType}}} `; + finalRollText += `{{Weapon size=${weaponSize}}} `; + finalRollText += `{{Target type=${targetType}}} `; + finalRollText += `{{Target size=${targetSize}}} `; - let baseWeapon = getBaseWeapon(row['weaponname1'], attrSet); - let weaponSize; - let weaponType; - if (baseWeapon) { - weaponSize = displaySize(baseWeapon['size']); - weaponType = baseWeapon['type']; - if (weaponType.includes('/')) { - let displayTypes = weaponType.split('/') - .map(s => displayWeaponType(s)) - .join('|'); + let locationDice; + switch (attackType) { + case 'Regular Attack': locationDice = '1d10'; break; + case 'Low Attack': locationDice = '1d6'; break; + case 'High Attack': locationDice = '1d6+4'; break; + } + let locationRoll = await extractRollResult(locationDice); + let locationObject = LOCATION_TABLE[targetType][locationRoll]; - weaponType = await extractQueryResult(`?{How are your attack with your weapon?|${displayTypes}}`) - } else { - weaponType = displayWeaponType(weaponType); - } - } else { - weaponSize = await extractQueryResult('?{Weapon size?|Small|Medium|Large}'); - weaponType = await extractQueryResult('?{Weapon type?|Slashing|Piercing|Bludgeoning}') - } + let severityEffect; + let severityRoll; + const sizeDiff = sizeToInt(weaponSize) - sizeToInt(targetSize); + if (sizeDiff < 0) { + severityEffect = 'Minor'; + severityRoll = await extractRollResult('1d6'); + } else if (sizeDiff === 0) { + severityEffect = 'Major'; + severityRoll = await extractRollResult('2d4'); + } else if (sizeDiff === 1) { + severityEffect = 'Severe'; + severityRoll = await extractRollResult('2d6'); + } else if (sizeDiff > 1) { + severityEffect = 'Mortal'; + severityRoll = await extractRollResult('2d8'); + } - finalRollText += `{{Weapon name=${row['weaponname1']}}} `; - finalRollText += `{{Weapon type=${attackType}}} `; - finalRollText += `{{Weapon size=${weaponSize}}} `; - finalRollText += `{{Target type=${targetType}}} `; - finalRollText += `{{Target size=${targetSize}}} `; + finalRollText += `{{Severity effect=${severityEffect}}} `; + finalRollText += `{{Severity roll=${severityRoll}}} `; - let locationDice; - switch (attackType) { - case 'Regular Attack': locationDice = '1d10'; break; - case 'Low Attack': locationDice = '1d6'; break; - case 'High Attack': locationDice = '1d6+4'; break; - } - let locationResult = await extractRollResult(locationDice); - let location = LOCATION_TABLE[targetType][locationResult]; + let weaponDamage = sizeToInt(targetSize) < 3 ? values['repeating_weapons-damage_damsm'] : values['repeating_weapons-damage_daml']; + if (weaponDamage.match('/\d/')) + if (severityRoll > 12) { + finalRollText += `{{Critical damage=[[(${weaponDamage})*3]]}} `; + severityRoll = 12; + } else { + finalRollText += `{{Critical damage=[[(${weaponDamage})*2]]}} `; + } + finalRollText += `{{Location roll=[[${locationRoll}]]}} `; + if (locationObject) + finalRollText += `{{Location hit=${locationObject['hitLocation']}}} `; - const sizeDiff = sizeToInt(weaponSize) - sizeToInt(targetSize); - let severityEffect; - let severityResult; - if (sizeDiff < 0) { - severityEffect = 'Minor'; - severityResult = await extractRollResult('1d6'); - } else if (sizeDiff === 0) { - severityEffect = 'Major'; - severityResult = await extractRollResult('2d4'); - } else if (sizeDiff === 1) { - severityEffect = 'Severe'; - severityResult = await extractRollResult('2d6'); - } else if (sizeDiff > 1) { - severityEffect = 'Mortal'; - severityResult = await extractRollResult('2d8'); - } + let critEffect; + if (severityRoll < 4) { + critEffect = 'No unusual effect' + } else if (CRIT_EFFECT_TABLE[weaponType]) { + critEffect = CRIT_EFFECT_TABLE[weaponType][targetType][locationObject['location'][severityRoll]]; + } else { + critEffect = 'No unusual effect'; + } - finalRollText += `{{Severity effect=${severityEffect}}} `; - finalRollText += `{{Severity roll=${severityResult}}} `; + finalRollText += `{{Critical effect=${critEffect}}}`; + console.log(finalRollText); - let weaponDamage = sizeToInt(targetSize) < 3 ? row['damsm'] : row['daml']; - if (severityResult > 12) { - finalRollText += `{{Critical damage=[[(${weaponDamage})*3]]}} `; - severityResult = 12; - } else { - finalRollText += `{{Critical damage=[[(${weaponDamage})*2]]}} `; - } - - finalRollText += `{{Location roll=[[${locationResult}]]}} `; - finalRollText += `{{Location hit=${location['hitLocation']}}} `; - - let critEffect = severityResult < 4 - ? 'No unusual effect' - : CRIT_EFFECT_TABLE[weaponType][targetType][location['location']][severityResult]; - finalRollText += `{{Critical effect=${critEffect}}}`; - console.log(finalRollText) - - startRoll(finalRollText, function (roll) { - console.log(roll); - let computedRolls = {}; - finishRoll(roll.rollId, computedRolls); - }); - - }) - .execute(); + startRoll(finalRollText, function (roll) { + console.log(roll); + let computedRolls = {}; + finishRoll(roll.rollId, computedRolls); + }); + }); }); //#endregion diff --git a/ADnD_2E_Revised/2EStyle.css b/ADnD_2E_Revised/2EStyle.css index af2f0ea419..d9f999b131 100644 --- a/ADnD_2E_Revised/2EStyle.css +++ b/ADnD_2E_Revised/2EStyle.css @@ -1701,7 +1701,7 @@ img.expandable:hover { .sheet-toast textarea { border: 0; background-color: transparent; - pointer-events: none; + cursor: text; margin-bottom: 0; resize: none; } diff --git a/ADnD_2E_Revised/css/toast.css b/ADnD_2E_Revised/css/toast.css index 5a3d533f59..bdd14d387e 100644 --- a/ADnD_2E_Revised/css/toast.css +++ b/ADnD_2E_Revised/css/toast.css @@ -48,7 +48,7 @@ .sheet-toast textarea { border: 0; background-color: transparent; - pointer-events: none; + cursor: text; margin-bottom: 0; resize: none; } diff --git a/ADnD_2E_Revised/html/components/dynamicDatalists.html b/ADnD_2E_Revised/html/components/dynamicDatalists.html index 697c6b0296..3898e82eba 100644 --- a/ADnD_2E_Revised/html/components/dynamicDatalists.html +++ b/ADnD_2E_Revised/html/components/dynamicDatalists.html @@ -2029,7 +2029,7 @@ - + @@ -2076,8 +2076,8 @@ - - + + diff --git a/ADnD_2E_Revised/html/tabs/character-tab/weapons-tab/players-option-weapons-tab.html b/ADnD_2E_Revised/html/tabs/character-tab/weapons-tab/players-option-weapons-tab.html index 847d021604..6a37b79d08 100644 --- a/ADnD_2E_Revised/html/tabs/character-tab/weapons-tab/players-option-weapons-tab.html +++ b/ADnD_2E_Revised/html/tabs/character-tab/weapons-tab/players-option-weapons-tab.html @@ -178,12 +178,10 @@ - +
- -

Special Abilities and Attacks

@@ -331,6 +329,9 @@ Damage L Knockdown Amount + Size + Type + Crit II Spec @@ -338,62 +339,72 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StrDexAmmoPoint BlankDamage
Adj.
Damage S/MDamage LKnockdownAmount
SpecMast
-
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrDexAmmoPoint BlankDamage
Adj.
Damage S/MDamage LKnockdownAmountSizeType
SpecMast
+ +
+


diff --git a/ADnD_2E_Revised/html/tabs/sheet-settings.html b/ADnD_2E_Revised/html/tabs/sheet-settings.html index 49cfe23eb6..b49c700754 100644 --- a/ADnD_2E_Revised/html/tabs/sheet-settings.html +++ b/ADnD_2E_Revised/html/tabs/sheet-settings.html @@ -114,6 +114,12 @@ Weapons, Spells, and Proficiencies + + Player's Option: Combat & Tactics + 1995 June + Weapons, Proficiencies, Talents, and Disadvantages + +

Optional rules for spells

diff --git a/ADnD_2E_Revised/javascript/sheetWorkers.js b/ADnD_2E_Revised/javascript/sheetWorkers.js index 23aeba81cd..7383fcb9cc 100644 --- a/ADnD_2E_Revised/javascript/sheetWorkers.js +++ b/ADnD_2E_Revised/javascript/sheetWorkers.js @@ -9,7 +9,7 @@ const BOOK_FIELDS = [ 'book-tom', 'book-aaeg', 'book-dwarves', 'book-bards', 'book-elves', 'book-humanoids', 'book-rangers', 'book-paladins', 'book-druids', 'book-barbarians', 'book-necromancers', 'book-ninjas', - 'book-combat-and-tacticss', + 'book-combat-and-tactics', ]; const SCHOOL_FIELDS = ['school-spells-and-magic']; @@ -70,6 +70,10 @@ const displayWeaponType = function (type) { } } +const getRowId = function (triggerName) { + return triggerName.match(/repeating_[^_]+_([^_]+)_[^_]+/)[1]; +} + const conditionalLog = function (bool, msg) { if (bool) console.log(msg); @@ -78,12 +82,14 @@ const conditionalLog = function (bool, msg) { const extractQueryResult = async function(query){//Sends a message to query the user for some behavior, returns the selected option. let queryRoll = await startRoll(`!{{query=[[0[response=${query}]]]}}`); finishRoll(queryRoll.rollId); + console.log(queryRoll); return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,''); }; const extractRoll = async function(rollExpression) { let queryRoll = await startRoll(`!{{roll=[[${rollExpression}]]}}`); finishRoll(queryRoll.rollId); + console.log(queryRoll); return queryRoll.results.roll; }; @@ -170,8 +176,8 @@ const getActiveSettings = function (settingFields, values) { const isBookInactive = function (books, obj) { let activeBooks = getActiveSettings(BOOK_FIELDS, books); - if (Array.isArray(obj['book'])) - return !obj['book'].some(b => activeBooks.has(b)); + if (Array.isArray(obj)) + return obj.every(b => !activeBooks.has(b)); else return !activeBooks.has(obj['book']); } @@ -179,9 +185,9 @@ const isBookInactive = function (books, obj) { const bookInactiveShowToast = function(books, obj) { let bookInactive = isBookInactive(books, obj); if (bookInactive) { - if (Array.isArray(obj['book'])) { - let booksString = obj['book'].map(b => '\n* ' + b).join('') + '\n' - showToast(ERROR, 'Missing Book(s)', `The book(s) ${booksString} are currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); + if (Array.isArray(obj)) { + let booksString = obj.map(b => '\n* ' + b).join('') + showToast(ERROR, 'Missing Book(s)', `The book(s):${booksString}\nAre currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); } else { showToast(ERROR, 'Missing Book', `The book *${obj['book']}* is currently not active on your sheet.\nGo to the *Sheet Settings* and activate the book (if your DM allows for its usage)`); } @@ -1215,189 +1221,212 @@ on('change:thac0-base-calc', function(eventInfo) { }); //#region Weapons autofill -function setWeaponWithBonus(weaponName, setWeaponFunc, thac0Field) { +const PLAYERS_OPTIONS_FIELD = 'tab81'; +function setWeaponWithBonus(weaponName, setWeaponFunc, comparer, thac0Field, category) { if (!weaponName) return; weaponName = weaponName.toLowerCase(); - let fields = [...BOOK_FIELDS, thac0Field].filter(Boolean); - getAttrs(fields, function(values) { + let fields = [...BOOK_FIELDS, PLAYERS_OPTIONS_FIELD, thac0Field].filter(Boolean); + getAttrs(fields, async function (values) { + let bonus = 0; + let baseWeapons = WEAPONS_TABLE[weaponName] + if (!baseWeapons) { + let match = weaponName.match(/\s*\+([0-9]+)\s*/); + if (!match) + return; + + let baseWeaponName = weaponName.replace(match[0], ' ').trim(); + baseWeapons = WEAPONS_TABLE[baseWeaponName]; + if (!baseWeapons) + return; + + bonus = parseInt(match[1]); + if (isNaN(bonus)) + return; + } + if (category) + baseWeapons = baseWeapons.filter(w => w['category'].includes(category)); + + let activeBooks = getActiveSettings(BOOK_FIELDS, values); + let activeWeapons = baseWeapons.filter(w => w['book'].some(b => activeBooks.has(b))); + + + if (activeWeapons.length === 0) { + let booksString = baseWeapons.flatMap(w => w['book']).map(b => '\n* ' + b).join('') + showToast(ERROR, 'Missing Book(s)', `The book(s):${booksString}\nAre currently not active on your sheet.\nGo to the *Sheet Settings* and activate any of the listed book(s) (if your DM allows for its usage)`); + return; + } + + let baseWeapon; + let isPlayersOptions = values[PLAYERS_OPTIONS_FIELD] === '2'; + let isAllEqual = activeWeapons.every(w => comparer(w, activeWeapons[0], isPlayersOptions)); + if (isAllEqual) { + baseWeapon = activeWeapons[0]; + } else { + let options = activeWeapons + .map((w, i) => `${w.book.join('/')},${i}`) + .join('|'); + let answer = await extractRollResult(`?{Multiple versions of this weapon exists. Please select a version|${options}}`); + baseWeapon = activeWeapons[answer]; + } + let thac0 = parseInt(values[thac0Field]); thac0 = isNaN(thac0) ? 20 : thac0; - let baseWeapon = weapons[weaponName] - if (baseWeapon) { - if (bookInactiveShowToast(values, baseWeapon)) - return; - - setWeaponFunc({ - ...baseWeapon, - 'thac0' : thac0, - 'bonus' : '0' - }); - return; - } - - let match = weaponName.match(/\s*\+([0-9]+)\s*/); - if (!match) - return; - - let baseWeaponName = weaponName.replace(match[0], ' ').trim(); - baseWeapon = weapons[baseWeaponName]; - if (!baseWeapon) - return; - - if (bookInactiveShowToast(values, baseWeapon)) - return; - - let bonusString = match[1]; - let bonus = parseInt(bonusString) - if (isNaN(bonus)) - return; - - if (bonus < 1) { - setWeaponFunc({ - ...baseWeapon, - 'thac0' : thac0, - 'bonus' : '0', - 'bonusInt': 0 - }); - return; - } - - let weaponWithBonus = { + let weapon = { ...baseWeapon, 'thac0' : thac0, - 'speed' : Math.max(baseWeapon['speed'] - bonus, 0), - 'bonus' : `+${bonus}`, - 'bonusInt': bonus + }; + if (bonus < 1) { + weapon['bonus'] = '0'; + weapon['bonusInt'] = 0; + } else { + weapon['bonus'] = `+${bonus}`; + weapon['bonusInt'] = bonus; + weapon['speed'] = Math.max(weapon['speed'] - bonus, 0) } - setWeaponFunc(weaponWithBonus); + setWeaponFunc(weapon); }); } //melee hit autofill on('change:repeating_weapons:weaponname', function(eventInfo) { - let comparer = function (weapon1, weapon2, isPo) { - if (isPo) { - let reach = 'reach'; - } - return ['size','speed','type'].every(f => weapon1[f] === weapon2[f]) + let comparer = function (weapon1, weapon2, isPlayersOption) { + let compareFields = ['size','speed','type']; + if (isPlayersOption) + compareFields.push('reach'); + return compareFields.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons_attackadj' : weapon['bonus'], - 'repeating_weapons_ThAC0' : weapon['thac0'], - 'repeating_weapons_range' : weapon['reach'] || 'Melee', - 'repeating_weapons_size' : weapon['size'], - 'repeating_weapons_weapspeed' : weapon['speed'], - 'repeating_weapons_weaptype-slash' : weapon['type'].includes('S') ? 1 : 0, - 'repeating_weapons_weaptype-pierce': weapon['type'].includes('P') ? 1 : 0, - 'repeating_weapons_weaptype-blunt' : weapon['type'].includes('B') ? 1 : 0, - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons_${rowId}_attackadj`] = weapon['bonus']; + weaponInfo[`repeating_weapons_${rowId}_ThAC0`] = weapon['thac0']; + weaponInfo[`repeating_weapons_${rowId}_range`] = weapon['reach'] || 'Melee'; + weaponInfo[`repeating_weapons_${rowId}_size`] = weapon['size']; + weaponInfo[`repeating_weapons_${rowId}_weapspeed`] = weapon['speed']; + weaponInfo[`repeating_weapons_${rowId}_weaptype-slash`] = weapon['type'].includes('S') ? 1 : 0; + weaponInfo[`repeating_weapons_${rowId}_weaptype-pierce`] = weapon['type'].includes('P') ? 1 : 0; + weaponInfo[`repeating_weapons_${rowId}_weaptype-blunt`] = weapon['type'].includes('B') ? 1 : 0; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, comparer, setWeaponFunc, 'thac0-base-calc'); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, 'thac0-base-calc', 'Melee'); }); //melee damage autofill on('change:repeating_weapons-damage:weaponname1', function(eventInfo) { - let comparer = function (weapon1, weapon2) { + let comparer = function (weapon1, weapon2, isPlayersOption) { let fisk = ['small-medium','large']; - if (isPo) { + if (isPlayersOption) { fisk.push('size'); - fisk.push('type') + fisk.push('type'); fisk.push('knockdown'); } return fisk.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons-damage_damadj' : weapon['bonus'], - 'repeating_weapons-damage_damsm' : weapon['small-medium'], - 'repeating_weapons-damage_daml' : weapon['large'], - 'repeating_weapons-damage_damsize' : weapon['size'], - 'repeating_weapons-damage_damtype' : weapon['type'], - 'repeating_weapons-damage_knockdown1' : weapon['knockdown'] || '' - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons-damage_${rowId}_damadj`] = weapon['bonus']; + weaponInfo[`repeating_weapons-damage_${rowId}_damsm`] = weapon['small-medium']; + weaponInfo[`repeating_weapons-damage_${rowId}_daml`] = weapon['large']; + weaponInfo[`repeating_weapons-damage_${rowId}_knockdown1`] = weapon['knockdown'] || ''; + weaponInfo[`repeating_weapons-damage_${rowId}_size`] = weapon['size']; + weaponInfo[`repeating_weapons-damage_${rowId}_type`] = weapon['type']; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, '', 'Melee'); }); //range hit autofill on('change:repeating_weapons2:weaponname2', function(eventInfo) { - let comparer = function (weapon1, weapon2) { + let comparer = function (weapon1, weapon2, isPlayersOption) { return ['strength','rof','range','size','speed','type'].every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons2_strbonus2' : weapon['strength'] ? 1 : 0, - 'repeating_weapons2_attacknum2' : weapon['rof'] || '', - 'repeating_weapons2_attackadj2' : weapon['bonus'], - 'repeating_weapons2_ThAC02' : weapon['thac0'], - 'repeating_weapons2_range2' : weapon['range'] || '', - 'repeating_weapons2_size2' : weapon['size'], - 'repeating_weapons2_weapspeed2' : weapon['speed'], - 'repeating_weapons2_weaptype-slash2' : weapon['type'].includes('S') ? 1 : 0, - 'repeating_weapons2_weaptype-pierce2' : weapon['type'].includes('P') ? 1 : 0, - 'repeating_weapons2_weaptype-blunt2' : weapon['type'].includes('B') ? 1 : 0, - }; + let weaponInfo = {}; + weaponInfo[`repeating_weapons2_${rowId}_strbonus2`] = weapon['strength'] ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_attacknum2`] = weapon['rof'] || ''; + weaponInfo[`repeating_weapons2_${rowId}_attackadj2`] = weapon['bonus']; + weaponInfo[`repeating_weapons2_${rowId}_ThAC02`] = weapon['thac0']; + weaponInfo[`repeating_weapons2_${rowId}_range2`] = weapon['range'] || ''; + weaponInfo[`repeating_weapons2_${rowId}_size2`] = weapon['size']; + weaponInfo[`repeating_weapons2_${rowId}_weapspeed2`] = weapon['speed']; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-slash2`] = weapon['type'].includes('S') ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-pierce2`] = weapon['type'].includes('P') ? 1 : 0; + weaponInfo[`repeating_weapons2_${rowId}_weaptype-blunt2`] = weapon['type'].includes('B') ? 1 : 0; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, 'thac0-base-calc'); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, 'thac0-base-calc', 'Range'); }); //range damage autofill on('change:repeating_ammo:ammoname', function(eventInfo) { - let comparer = function (weapon1, weapon2) { - return ['strength','small-medium','large','size'].every(f => weapon1[f] === weapon2[f]) + let comparer = function (weapon1, weapon2, isPlayersOption) { + let comparerFields = ['strength','small-medium','large']; + if (isPlayersOption) { + comparerFields.push('knockdown'); + comparerFields.push('size'); + comparerFields.push('ammo-size'); + comparerFields.push('type'); + } + return comparerFields.every(f => weapon1[f] === weapon2[f]) } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - 'repeating_weapons2_strbonus3' : weapon['strength'] ? 1 : 0, - 'repeating_ammo_damadj2' : weapon['bonus'], - 'repeating_ammo_damsm2' : weapon['small-medium'], - 'repeating_ammo_daml2' : weapon['large'], - 'repeating_weapons-damage_knockdown2' : weapon['knockdown'] || '' - }; + let weaponInfo = {}; + weaponInfo[`repeating_ammo_${rowId}_strbonus3`] = weapon['strength'] ? 1 : 0; + weaponInfo[`repeating_ammo_${rowId}_damadj2`] = weapon['bonus']; + weaponInfo[`repeating_ammo_${rowId}_damsm2`] = weapon['small-medium']; + weaponInfo[`repeating_ammo_${rowId}_daml2`] = weapon['large']; + weaponInfo[`repeating_ammo_${rowId}_knockdown2`] = weapon['knockdown'] || ''; + weaponInfo[`repeating_ammo_${rowId}_size`] = weapon['ammo-size'] || weapon['size']; + weaponInfo[`repeating_ammo_${rowId}_type`] = weapon['type']; setAttrs(weaponInfo); } - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer, '', 'Range'); }); //Follower weapons function setupFollowerWeaponsAutoFill(repeating, sections) { let prefix = ''; - let onChange = ''; if (repeating !== '') { - prefix = `repeating_${repeating}_` - onChange = `repeating_${repeating}:` + prefix = `repeating_${repeating}` } sections.forEach(section => { - on(`change:${onChange}weaponnamehench${section}`, function(eventInfo) { + on(`change:${prefix}:weaponnamehench${section}`, function(eventInfo) { + let comparer = function (weapon1, weapon2, isPlayersOption) { + let comparerFields = ['rof','small-medium','large','range','type','speed']; + if (isPlayersOption) { + comparerFields.push('reach'); + comparerFields.push('knockdown'); + } + return comparerFields.every(f => weapon1[f] === weapon2[f]) + } + let rowId = getRowId(eventInfo.triggerName); let setWeaponFunc = function (weapon) { - let weaponInfo = { - [`${prefix}attacknumhench${section}`]: weapon['rof'] || '1', - [`${prefix}attackadjhench${section}`]: weapon['bonus'], - [`${prefix}damadjhench${section}`]: weapon['bonus'], - [`${prefix}damsmhench${section}`]: weapon['small-medium'], - [`${prefix}damlhench${section}`]: weapon['large'], - [`${prefix}rangehench${section}`]: weapon['range'] || weapon['reach'] || 'Melee', - [`${prefix}weaptypehench${section}`]: weapon['type'], - [`${prefix}weapspeedhench${section}`]: weapon['speed'], - }; + let weaponInfo = {}; + weaponInfo[`${prefix}_${rowId}_attacknumhench${section}`] = weapon['rof'] || '1'; + weaponInfo[`${prefix}_${rowId}_attackadjhench${section}`] = weapon['bonus']; + weaponInfo[`${prefix}_${rowId}_damadjhench${section}`] = weapon['bonus']; + weaponInfo[`${prefix}_${rowId}_damsmhench${section}`] = weapon['small-medium']; + weaponInfo[`${prefix}_${rowId}_damlhench${section}`] = weapon['large']; + weaponInfo[`${prefix}_${rowId}_rangehench${section}`] = weapon['range'] || weapon['reach'] || 'Melee'; + weaponInfo[`${prefix}_${rowId}_weaptypehench${section}`] = weapon['type']; + weaponInfo[`${prefix}_${rowId}_weapspeedhench${section}`] = weapon['speed']; setAttrs(weaponInfo); }; - setWeaponWithBonus(eventInfo.newValue, setWeaponFunc); + setWeaponWithBonus(eventInfo.newValue, setWeaponFunc, comparer); }); }); } @@ -1497,105 +1526,97 @@ on('clicked:grenade-miss', async function (eventInfo) { }); }); -on('clicked:crit-melee', function(eventInfo) { - TAS.repeating('weapons-damage') - .attrs(['strengthdmg', 'dexmissile', 'temp-damadj', 'misc-mod', ...BOOK_FIELDS]) - .fields('strbonus1', 'dexbonus1', 'weaponname1', 'specialist-damage', 'mastery-damage', 'damadj', 'damsm', 'daml') - .map(function (row){ - return row; - }, async function (rows, _, attrSet){ - let weaponSelect = rows.map(r => `${r['weaponname1']},${r.id}`) +on('clicked:repeating_weapons-damage:crit2-melee', function(eventInfo) { + console.log(eventInfo); + let fields = [ + 'strengthdmg', 'dexmissile', 'temp-damadj', 'misc-mod', + 'repeating_weapons-damage_strbonus1','repeating_weapons-damage_dexbonus1','repeating_weapons-damage_weaponname1', + 'repeating_weapons-damage_specialist-damage','repeating_weapons-damage_mastery-damage','repeating_weapons-damage_damadj', + 'repeating_weapons-damage_damsm','repeating_weapons-damage_daml','repeating_weapons-damage_size','repeating_weapons-damage_type']; + getAttrs(fields, async function (values) { + let finalRollText = `&{template:2Edefault} {{name=Test Critical hit}} {{Weapon name=${values['repeating_weapons-damage_weaponname1']}}} `; + + let attackType = await extractQueryResult('?{How are you attacking?|Regular Attack|Low Attack|High Attack}'); + let targetType = await extractQueryResult('?{What are you attacking?|Humanoid|Animal|Monster}'); + let targetSize = await extractQueryResult('?{Target size?|Tiny|Small|Medium|Large|Huge|Gargantuan}'); + + let weaponSize = displaySize(values['repeating_weapons-damage_size']); + let weaponType = values['repeating_weapons-damage_type']; + if (weaponType.includes('/')) { + let displayTypes = weaponType.split('/') + .map(s => displayWeaponType(s)) .join('|'); - let rowId = await extractQueryResult(`?{What weapon did you use?|${weaponSelect}}`); - let row = rows.find(row => row.id === rowId); - let finalRollText = '&{template:2Edefault} {{name=Test Critical hit}}'; + weaponType = await extractQueryResult(`?{How are your attack with your weapon?|${displayTypes}}`) + } else { + weaponType = displayWeaponType(weaponType); + } - let attackType = await extractQueryResult('?{How are you attacking?|Regular Attack|Low Attack|High Attack}'); - let targetType = await extractQueryResult('?{What are you attacking?|Humanoid|Animal|Monster}'); - let targetSize = await extractQueryResult('?{Target size?|Tiny|Small|Medium|Large|Huge|Gargantuan}'); + finalRollText += `{{Weapon type=${attackType}}} `; + finalRollText += `{{Weapon size=${weaponSize}}} `; + finalRollText += `{{Target type=${targetType}}} `; + finalRollText += `{{Target size=${targetSize}}} `; - let baseWeapon = getBaseWeapon(row['weaponname1'], attrSet); - let weaponSize; - let weaponType; - if (baseWeapon) { - weaponSize = displaySize(baseWeapon['size']); - weaponType = baseWeapon['type']; - if (weaponType.includes('/')) { - let displayTypes = weaponType.split('/') - .map(s => displayWeaponType(s)) - .join('|'); + let locationDice; + switch (attackType) { + case 'Regular Attack': locationDice = '1d10'; break; + case 'Low Attack': locationDice = '1d6'; break; + case 'High Attack': locationDice = '1d6+4'; break; + } + let locationRoll = await extractRollResult(locationDice); + let locationObject = LOCATION_TABLE[targetType][locationRoll]; - weaponType = await extractQueryResult(`?{How are your attack with your weapon?|${displayTypes}}`) - } else { - weaponType = displayWeaponType(weaponType); - } - } else { - weaponSize = await extractQueryResult('?{Weapon size?|Small|Medium|Large}'); - weaponType = await extractQueryResult('?{Weapon type?|Slashing|Piercing|Bludgeoning}') - } + let severityEffect; + let severityRoll; + const sizeDiff = sizeToInt(weaponSize) - sizeToInt(targetSize); + if (sizeDiff < 0) { + severityEffect = 'Minor'; + severityRoll = await extractRollResult('1d6'); + } else if (sizeDiff === 0) { + severityEffect = 'Major'; + severityRoll = await extractRollResult('2d4'); + } else if (sizeDiff === 1) { + severityEffect = 'Severe'; + severityRoll = await extractRollResult('2d6'); + } else if (sizeDiff > 1) { + severityEffect = 'Mortal'; + severityRoll = await extractRollResult('2d8'); + } - finalRollText += `{{Weapon name=${row['weaponname1']}}} `; - finalRollText += `{{Weapon type=${attackType}}} `; - finalRollText += `{{Weapon size=${weaponSize}}} `; - finalRollText += `{{Target type=${targetType}}} `; - finalRollText += `{{Target size=${targetSize}}} `; + finalRollText += `{{Severity effect=${severityEffect}}} `; + finalRollText += `{{Severity roll=${severityRoll}}} `; - let locationDice; - switch (attackType) { - case 'Regular Attack': locationDice = '1d10'; break; - case 'Low Attack': locationDice = '1d6'; break; - case 'High Attack': locationDice = '1d6+4'; break; - } - let locationResult = await extractRollResult(locationDice); - let location = LOCATION_TABLE[targetType][locationResult]; + let weaponDamage = sizeToInt(targetSize) < 3 ? values['repeating_weapons-damage_damsm'] : values['repeating_weapons-damage_daml']; + if (weaponDamage.match('/\d/')) + if (severityRoll > 12) { + finalRollText += `{{Critical damage=[[(${weaponDamage})*3]]}} `; + severityRoll = 12; + } else { + finalRollText += `{{Critical damage=[[(${weaponDamage})*2]]}} `; + } + finalRollText += `{{Location roll=[[${locationRoll}]]}} `; + if (locationObject) + finalRollText += `{{Location hit=${locationObject['hitLocation']}}} `; - const sizeDiff = sizeToInt(weaponSize) - sizeToInt(targetSize); - let severityEffect; - let severityResult; - if (sizeDiff < 0) { - severityEffect = 'Minor'; - severityResult = await extractRollResult('1d6'); - } else if (sizeDiff === 0) { - severityEffect = 'Major'; - severityResult = await extractRollResult('2d4'); - } else if (sizeDiff === 1) { - severityEffect = 'Severe'; - severityResult = await extractRollResult('2d6'); - } else if (sizeDiff > 1) { - severityEffect = 'Mortal'; - severityResult = await extractRollResult('2d8'); - } + let critEffect; + if (severityRoll < 4) { + critEffect = 'No unusual effect' + } else if (CRIT_EFFECT_TABLE[weaponType]) { + critEffect = CRIT_EFFECT_TABLE[weaponType][targetType][locationObject['location'][severityRoll]]; + } else { + critEffect = 'No unusual effect'; + } - finalRollText += `{{Severity effect=${severityEffect}}} `; - finalRollText += `{{Severity roll=${severityResult}}} `; + finalRollText += `{{Critical effect=${critEffect}}}`; + console.log(finalRollText); - let weaponDamage = sizeToInt(targetSize) < 3 ? row['damsm'] : row['daml']; - if (severityResult > 12) { - finalRollText += `{{Critical damage=[[(${weaponDamage})*3]]}} `; - severityResult = 12; - } else { - finalRollText += `{{Critical damage=[[(${weaponDamage})*2]]}} `; - } - - finalRollText += `{{Location roll=[[${locationResult}]]}} `; - finalRollText += `{{Location hit=${location['hitLocation']}}} `; - - let critEffect = severityResult < 4 - ? 'No unusual effect' - : CRIT_EFFECT_TABLE[weaponType][targetType][location['location']][severityResult]; - finalRollText += `{{Critical effect=${critEffect}}}`; - console.log(finalRollText) - - startRoll(finalRollText, function (roll) { - console.log(roll); - let computedRolls = {}; - finishRoll(roll.rollId, computedRolls); - }); - - }) - .execute(); + startRoll(finalRollText, function (roll) { + console.log(roll); + let computedRolls = {}; + finishRoll(roll.rollId, computedRolls); + }); + }); }); //#endregion diff --git a/ADnD_2E_Revised/pug/weaponsDatalists.pug b/ADnD_2E_Revised/pug/weaponsDatalists.pug index 6ad37959d4..e765ca8a32 100644 --- a/ADnD_2E_Revised/pug/weaponsDatalists.pug +++ b/ADnD_2E_Revised/pug/weaponsDatalists.pug @@ -13,7 +13,7 @@ datalist(id='melee-weapons') - continue; if processedWeapons.has(weapon.name.toLowerCase()) - continue - - books = 'Books: ' + bookShorthand(weaponList.flatMap(w => w.book)) + - books = 'Books: ' + bookShorthand(weaponList.filter(w => w['category'].includes('Melee')).flatMap(w => w.book)) - processedWeapons.add(weapon.name.toLowerCase()) - let group = weapon.group || '' - group += (group ? ', ' : '') + books @@ -30,7 +30,7 @@ datalist(id='ranged-weapons') - continue; if processedWeapons.has(weapon.name.toLowerCase()) - continue - - books = 'Books: ' + bookShorthand(weaponList.flatMap(w => w.book)) + - books = 'Books: ' + bookShorthand(weaponList.filter(w => w['category'].includes('Range')).flatMap(w => w.book)) - processedWeapons.add(weapon.name.toLowerCase()) - let group = weapon.group || '' - group += (group ? ', ' : '') + books