swade-mb-helpers/scripts/rollHelpers.js
2023-12-19 22:12:58 -06:00

162 lines
6.1 KiB
JavaScript

import { log, shim } from './shim.js'
export async function preTraitRollModifiers (actor, trait, roll, modifiers, options) {
const targets = Array.from(shim.targets)
const token = shim.canvas.tokens.controlled.length > 0 ? shim.canvas.tokens.controlled[0] : null
// log('ACTOR', actor)
// log('TOKEN', token)
// log('TRAIT', trait)
// log('ROLL', roll)
// log('MODIFIERS', modifiers)
// log('OPTIONS', options)
// log('TARGET', targets)
if (targets.some(target => target.actor.system.status.isVulnerable)) {
modifiers.push({ label: 'Target is Vulnerable', value: '+2', ignore: false })
}
if (targets.some(
target => target.actor.effects.filter(
e => !e.disabled && e.name.toLowerCase().includes('deflection')).length > 0)
) {
modifiers.push({ label: 'Target has Deflection', value: '-2', ignore: false })
}
if (targets.length === 1 && token) {
const target = targets[0]
_addArcaneModifiers(target, modifiers)
const scaleMod = calcScaleMod(token, target)
if (scaleMod !== 0) {
modifiers.push({ label: 'Scale', value: scaleMod, ignore: false })
}
if (trait?.type === 'skill' && trait?.system?.swid === 'fighting') {
const gangUpBonus = calcGangup(token, target)
if (gangUpBonus > 0) {
modifiers.push({ label: 'Gang Up', value: gangUpBonus, ignore: false })
}
}
}
}
export async function preDamageRollModifiers (actor, item, roll, modifiers, options) {
const targets = Array.from(shim.targets)
const token = shim.canvas.tokens.controlled.length > 0 ? shim.canvas.tokens.controlled[0] : null
// log('ACTOR', actor)
// log('TOKEN', token)
// log('ITEM', item)
// log('ROLL', roll)
// log('MODIFIERS', modifiers)
// log('OPTIONS', options)
// log('TARGET', targets)
if (targets.length === 1 && token) {
const target = targets[0]
_addArcaneModifiers(target, modifiers)
const weaknesses = target.actor.items.filter(
i => i.type === 'ability' && i.system.swid.toLowerCase().includes('weakness'))
if (weaknesses.length > 0) {
modifiers.push(...weaknesses.map(i => { return { label: i.name, value: '+4', ignore: true } }))
}
const resistances = target.actor.items.filter(
i => i.type === 'ability' && i.system.swid.toLowerCase().includes('resistance'))
if (resistances.length > 0) {
modifiers.push(...resistances.map(i => { return { label: i.name, value: '-4', ignore: true } }))
}
if (_findItem(token.actor, 'ability', 'pack-tactics')) {
const gangupBonus = calcGangup(token, target)
if (gangupBonus > 0) {
modifiers.push({ label: 'Gang Up (Pack Tactics)', value: gangupBonus, ignore: false })
}
}
}
}
function _addArcaneModifiers (target, modifiers) {
if (_findItem(target.actor, 'edge', 'improved-arcane-resistance')) {
modifiers.push({ label: 'Arcane Resistance', value: '-4', ignore: true })
} else if (_findItem(target.actor, 'edge', 'arcane-resistance')) {
modifiers.push({ label: 'Arcane Resistance', value: '-2', ignore: true })
}
const effect = target.actor.effects.find(
e => !e.disabled && e.name.toLowerCase().includes('arcane protection'))
if (effect) {
const effectName = effect.name.toLowerCase()
const effectMod = (
-2 +
(effectName.includes('major') ? -2 : 0) +
(effectName.includes('greater') ? -2 : 0)
)
modifiers.push({ label: 'Target Arcane Protection', value: effectMod, ignore: true })
}
}
function withinRange (origin, target, range) {
const ray = new Ray(origin, target)
const distance = shim.canvas.grid.measureDistances([{ ray }], { gridSpaces: true })[0]
const originScale = origin.actor.system.stats.scale
const targetScale = target.actor.system.stats.scale
range += (originScale > 0 ? originScale / 2 : 0) + (targetScale > 0 ? targetScale / 2 : 0)
return range >= distance
}
function _findItem (actor, type, swid) {
return actor.items.find(i => i.type === type && i.system.swid === swid)
}
function calcScaleMod (attacker, target) {
const attackerScale = attacker.actor.system.stats.scale
const targetScale = target.actor.system.stats.scale
const attackerHasSwat = !!_findItem(attacker.actor, 'ability', 'swat')
let modifier = targetScale - attackerScale
if (attackerHasSwat && modifier < 0) {
modifier = Math.min(modifier + 4, 0)
}
return modifier
}
function calcGangup (attacker, target, debug) {
debug = (typeof debug === 'undefined') ? false : debug
const range = 1.2
let modifier = 0
if (_findItem(target.actor, 'edge', 'improved-block')) {
modifier = -2
} else if (_findItem(target.actor, 'edge', 'block')) {
modifier = -1
}
const attackerHasFormationFighter = !!(_findItem(attacker.actor, 'edge', 'formation-fighter'))
const withinRangeOfToken = shim.canvas.tokens.placeables.filter(t =>
t.id !== attacker.id &&
t.id !== target.id &&
t.actor.system.status.isStunned === false &&
t.visible &&
withinRange(target, t, range)
)
const attackerAllies = withinRangeOfToken.filter(
t => t.document.disposition === attacker.document.disposition)
const targetAllies = withinRangeOfToken.filter(
t => t.document.disposition === target.document.disposition &&
withinRange(attacker, t, range)
)
const attackersWithFormationFighter = attackerAllies.filter(
t => !!_findItem(t.actor, 'edge', 'formation-fighter'))
const attackerCount = attackerAllies.length
const attackerFormationBonus = (
(attackerCount > 0 && attackerHasFormationFighter ? 1 : 0) +
attackersWithFormationFighter.length
)
const defenderCount = targetAllies.length
const gangUp = Math.max(
0,
Math.min(
4,
attackerCount + attackerFormationBonus - defenderCount + modifier))
if (debug) {
log('GANG UP | Attacker:', attacker)
log('GANG UP | Target:', target)
log('GANG UP | Others within range:', withinRangeOfToken)
log('GANG UP | Attacker Allies:', attackerCount)
log('GANG UP | Attacker Formation Bonus:', attackerFormationBonus)
log('GANG UP | Effective Defender Allies:', defenderCount)
log('GANG UP | Target Block Modifier:', modifier)
log('GANG UP | Total Bonus:', gangUp)
}
return gangUp
}