roll modifier hooks
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { api } from './api.js'
|
||||
import { requestTokenRoll } from './helpers.js'
|
||||
import { preDamageRollModifiers, preTraitRollModifiers } from './rollHelpers.js'
|
||||
import { shapeChangeOnDismiss } from './powerEffects.js'
|
||||
import { log, shim } from './shim.js'
|
||||
|
||||
@@ -71,6 +72,10 @@ Hooks.on('init', () => {
|
||||
})
|
||||
})
|
||||
|
||||
Hooks.on('swadePreRollAttribute', preTraitRollModifiers)
|
||||
Hooks.on('swadePreRollSkill', preTraitRollModifiers)
|
||||
Hooks.on('swadeRollDamage', preDamageRollModifiers)
|
||||
|
||||
Hooks.on('ready', () => {
|
||||
_checkModule('warpgate')
|
||||
_checkModule('socketlib')
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user