From 55a123759f94f365f6df9573fe4006e99183d832 Mon Sep 17 00:00:00 2001 From: Mike Bloy Date: Tue, 19 Dec 2023 22:12:58 -0600 Subject: [PATCH] roll modifier hooks --- CHANGELOG.md | 9 + packs/common-actions/CURRENT | 2 +- packs/common-actions/LOG | 8 +- packs/common-actions/LOG.old | 8 + packs/common-actions/MANIFEST-000002 | Bin 161 -> 0 bytes packs/common-actions/MANIFEST-000014 | Bin 0 -> 146 bytes packs/gear/CURRENT | 2 +- packs/gear/LOG | 8 +- packs/gear/LOG.old | 8 + packs/gear/MANIFEST-000002 | Bin 134 -> 0 bytes packs/gear/MANIFEST-000014 | Bin 0 -> 119 bytes packs/helper-actors/CURRENT | 2 +- packs/helper-actors/LOG | 8 +- packs/helper-actors/LOG.old | 8 + packs/helper-actors/MANIFEST-000002 | Bin 136 -> 0 bytes packs/helper-actors/MANIFEST-000014 | Bin 0 -> 121 bytes packs/helper-macros/CURRENT | 2 +- packs/helper-macros/LOG | 8 +- packs/helper-macros/LOG.old | 8 + packs/helper-macros/MANIFEST-000002 | Bin 137 -> 0 bytes packs/helper-macros/MANIFEST-000014 | Bin 0 -> 122 bytes packs/module-docs/{000005.ldb => 000014.ldb} | Bin 10624 -> 11373 bytes packs/module-docs/CURRENT | 2 +- packs/module-docs/LOG | 8 +- packs/module-docs/LOG.old | 15 ++ packs/module-docs/MANIFEST-000002 | Bin 161 -> 0 bytes packs/module-docs/MANIFEST-000015 | Bin 0 -> 205 bytes .../Setting_Adjustments_YSuk1v59tLaL9XUK.json | 37 +++- scripts/module.js | 5 + scripts/rollHelpers.js | 161 ++++++++++++++++++ 30 files changed, 278 insertions(+), 31 deletions(-) create mode 100644 packs/common-actions/LOG.old delete mode 100644 packs/common-actions/MANIFEST-000002 create mode 100644 packs/common-actions/MANIFEST-000014 create mode 100644 packs/gear/LOG.old delete mode 100644 packs/gear/MANIFEST-000002 create mode 100644 packs/gear/MANIFEST-000014 create mode 100644 packs/helper-actors/LOG.old delete mode 100644 packs/helper-actors/MANIFEST-000002 create mode 100644 packs/helper-actors/MANIFEST-000014 create mode 100644 packs/helper-macros/LOG.old delete mode 100644 packs/helper-macros/MANIFEST-000002 create mode 100644 packs/helper-macros/MANIFEST-000014 rename packs/module-docs/{000005.ldb => 000014.ldb} (70%) create mode 100644 packs/module-docs/LOG.old delete mode 100644 packs/module-docs/MANIFEST-000002 create mode 100644 packs/module-docs/MANIFEST-000015 create mode 100644 scripts/rollHelpers.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b8abb..b50403f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Trait and Damage Roll hooks to look for and apply modifiers for target + conditions: + - Vulnerable + - Deflection + - Arcane Protection + - Arcane Resistance + - Scale + - Gang Up + - Resistences and Weaknesses - New Macro: Set token vision - New Common Action: Illumination (for the darkness penalty effects) - New macro: Quick Damage Roll diff --git a/packs/common-actions/CURRENT b/packs/common-actions/CURRENT index 1a84852..23b73d9 100644 --- a/packs/common-actions/CURRENT +++ b/packs/common-actions/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000014 diff --git a/packs/common-actions/LOG b/packs/common-actions/LOG index cc909c1..d59dd93 100644 --- a/packs/common-actions/LOG +++ b/packs/common-actions/LOG @@ -1,5 +1,3 @@ -2023/12/18-23:38:01.173251 7fb80df3c700 Delete type=3 #1 -2023/12/18-23:38:01.175935 7fb80d481700 Level-0 table #5: started -2023/12/18-23:38:01.183313 7fb80d481700 Level-0 table #5: 12215 bytes OK -2023/12/18-23:38:01.192571 7fb80d481700 Delete type=0 #3 -2023/12/18-23:38:01.192679 7fb80d481700 Manual compaction at level-0 from '!folders!0nDRFmMBs5DBJU9M' @ 72057594037927935 : 1 .. '!items.effects!RC1Nz6iph8wPPK1B.g9W5hJisq3MsCpZW' @ 0 : 0; will stop at (end) +2023/12/19-22:11:46.585866 7f40dd7bc700 Recovering log #12 +2023/12/19-22:11:46.611108 7f40dd7bc700 Delete type=0 #12 +2023/12/19-22:11:46.611132 7f40dd7bc700 Delete type=3 #10 diff --git a/packs/common-actions/LOG.old b/packs/common-actions/LOG.old new file mode 100644 index 0000000..8d8b6ad --- /dev/null +++ b/packs/common-actions/LOG.old @@ -0,0 +1,8 @@ +2023/12/19-14:25:58.734016 7fb0acf3b700 Recovering log #8 +2023/12/19-14:25:58.748444 7fb0acf3b700 Delete type=3 #6 +2023/12/19-14:25:58.748474 7fb0acf3b700 Delete type=0 #8 +2023/12/19-22:08:59.600432 7fb086400700 Level-0 table #13: started +2023/12/19-22:08:59.600452 7fb086400700 Level-0 table #13: 0 bytes OK +2023/12/19-22:08:59.612412 7fb086400700 Delete type=0 #11 +2023/12/19-22:08:59.648733 7fb086400700 Manual compaction at level-0 from '!folders!0nDRFmMBs5DBJU9M' @ 72057594037927935 : 1 .. '!items.effects!RC1Nz6iph8wPPK1B.g9W5hJisq3MsCpZW' @ 0 : 0; will stop at (end) +2023/12/19-22:08:59.648868 7fb086400700 Manual compaction at level-1 from '!folders!0nDRFmMBs5DBJU9M' @ 72057594037927935 : 1 .. '!items.effects!RC1Nz6iph8wPPK1B.g9W5hJisq3MsCpZW' @ 0 : 0; will stop at (end) diff --git a/packs/common-actions/MANIFEST-000002 b/packs/common-actions/MANIFEST-000002 deleted file mode 100644 index 0916a641673cb50bb46c87418ef77de9ef7f9c95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE z7%tg3UCsbdDXB%piUxTuL2kLePQ|7!PF|swzKo&_U|^w` zS(2Jtte2XWmYQ5rtQh2M=vQTyS&(5-9uVMd=%kl!8E%^4m04V9>|5+y5EahI577t! DGLbCj diff --git a/packs/common-actions/MANIFEST-000014 b/packs/common-actions/MANIFEST-000014 new file mode 100644 index 0000000000000000000000000000000000000000..5d83e41819ba6b673cf0454204acd13492b8c380 GIT binary patch literal 146 zcmey-)7@Xgz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&PMDx;-mr;}f3@j8gOHy--^-|N)Qj<%H6@#1&{i@6|3o`pgoS$2eSd>_jU&PMD+H5MXm|2pVTde36 zUg;E=YEqKtADNTo=IF-A!~g~``I7MP;51j?T%X+XVzbC3LqvdiQ#l&Qw%3{S((=wBEH;=;7e1k~CV8=p6Mg}k-r~m-a C4vdiQ#l&PFyI3*Q pw9F*k&7-h1-yqU3*s+k2kpT<{DhTjgSH;1=$i&adz%0PR2mln=AbS7+ literal 0 HcmV?d00001 diff --git a/packs/helper-macros/CURRENT b/packs/helper-macros/CURRENT index 1a84852..23b73d9 100644 --- a/packs/helper-macros/CURRENT +++ b/packs/helper-macros/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000014 diff --git a/packs/helper-macros/LOG b/packs/helper-macros/LOG index 1098a98..948bac9 100644 --- a/packs/helper-macros/LOG +++ b/packs/helper-macros/LOG @@ -1,5 +1,3 @@ -2023/12/18-23:38:03.938107 7f566efbe700 Delete type=3 #1 -2023/12/18-23:38:03.940484 7f566d542700 Level-0 table #5: started -2023/12/18-23:38:03.948092 7f566d542700 Level-0 table #5: 12050 bytes OK -2023/12/18-23:38:03.956941 7f566d542700 Delete type=0 #3 -2023/12/18-23:38:03.957060 7f566d542700 Manual compaction at level-0 from '!folders!hIbrWxg1nDutCSwt' @ 72057594037927935 : 1 .. '!macros!wU2mAUnw3RW9qMT8' @ 0 : 0; will stop at (end) +2023/12/19-22:11:46.967222 7fb6ee7bf700 Recovering log #12 +2023/12/19-22:11:46.993517 7fb6ee7bf700 Delete type=0 #12 +2023/12/19-22:11:46.993540 7fb6ee7bf700 Delete type=3 #10 diff --git a/packs/helper-macros/LOG.old b/packs/helper-macros/LOG.old new file mode 100644 index 0000000..eb01f08 --- /dev/null +++ b/packs/helper-macros/LOG.old @@ -0,0 +1,8 @@ +2023/12/19-14:25:58.719315 7fb087fff700 Recovering log #8 +2023/12/19-14:25:58.732527 7fb087fff700 Delete type=3 #6 +2023/12/19-14:25:58.732555 7fb087fff700 Delete type=0 #8 +2023/12/19-22:08:59.638378 7fb086400700 Level-0 table #13: started +2023/12/19-22:08:59.638400 7fb086400700 Level-0 table #13: 0 bytes OK +2023/12/19-22:08:59.648647 7fb086400700 Delete type=0 #11 +2023/12/19-22:08:59.648837 7fb086400700 Manual compaction at level-0 from '!folders!hIbrWxg1nDutCSwt' @ 72057594037927935 : 1 .. '!macros!wU2mAUnw3RW9qMT8' @ 0 : 0; will stop at (end) +2023/12/19-22:08:59.677175 7fb086400700 Manual compaction at level-1 from '!folders!hIbrWxg1nDutCSwt' @ 72057594037927935 : 1 .. '!macros!wU2mAUnw3RW9qMT8' @ 0 : 0; will stop at (end) diff --git a/packs/helper-macros/MANIFEST-000002 b/packs/helper-macros/MANIFEST-000002 deleted file mode 100644 index 8562096ef76b914a69b9156f260bc428b6ccb919..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE z7+!4g3=RNtS%6$N7CCk%)=6=SifQ>dDXB%piW#0sMd20chIuZfCCr@cM2F10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei1tp>!dhE#kBmKl+>bP z#SG7+qVS4z!#tPL66fIZ5=Kr2Fi=p;O-wGzFIFrMHOh4i%_}z!3b!ou4Y6R9hA7y* S*5M)t10xeZCj+wpiyQ#4Ya$IF1K?yt9u)t$0r3Y_;Wy2FHZhf`Y;1FP#ZQQUQK3<7;BOq0GlOnYlX(P$*HAhs~tJ_h6G zKx~Z9z}Q$>C}$5HE(%^!;wP*i$mgsSw1$t02mMz;AaU7hH%8R+x9tWV9=+c-lkWzH zJ?74$8ncFS`&QWkD5(spSWb!AK?LX338Ji{43^Y%RzgBj`1upv+(ON>pa%0@s-vL7 zZZ{uLn+klhD6@<9!ftbzZlc>A?qiI3fxZFPnD1CGa%b!{O{kV{lcemRD3@F{Rol`0 zau$Vxv0T8TYsrc^tV;SOgmk2cN#rme#8u0gnbh}_B^ckp$yf<>gyu4u~^;Pxfv)2NP|xi^DKL2f-3rb zhUI#xY4I(D;fV&{QcGc(rbxP{!Dv46s#)YhMa>@~Wk|-Fo)J|TKV~+%{Dt%)ZX@Ap zK!!E%S0(fOS+G8rbI*Lp{!b7vvI`w>Q;`sa_JBv;TBYa) z8WKrfdWOWws<4w2$jYFPbL284on6O984^xzyF*+F8b-U~&LCPY$o+6>SwhLnSsm++ zZbp%%kzg+XE#qzU`nJbTm2Z?s(8o?r)f82MH&(e-O-F;m2uffi_RES!5>AYuWCkY( zhydU{3boN?4kvLs97J8p85J&t?=h-|Yl@d~f}A48*EwRGmFX1}P94wtbPng!X`Fl` z5>WZ>3`S{^vNA-=z7+oi6vw@3MI+(Jh=YqDe~k97%Sz-ug@lAh9-XXpHsQ2{lcP(# zs9GTGR8FS12UIs|NrBvFhn822^ajx4 z1J^J>omdx%Hsoad7T~&)f`qd2X4fVzdGAtw7=?r)}8+uuFG+Wz}}v9@42*vHyj{}#|Ihv=_%_gFslvx^r|*75jH zZsx#?VJqkO;>SIujN7`*?O9*}G_XFka1fOIgE?gO5)^_phyLKq6V*QM+PWoVifoyC=|H)Gpp00-qM=3d(0{u%Ss rd_Do82(}SW1aRRm7t8kdgs$``rr@7xs(yPR+3xvm`(AH$`FDQ;LC(hM delta 719 zcmXYsUr1A76u`gl`rW&G^IkW{G^=UXrP$ikyFYGj=F%yJ%S4-|lB7%Lzcx2^x7xyq zVisx`@mcs(;6vF%kW7*yC?g^2rAN_%jC_cQ{(wao+EqN99|sPc-#O=7)1aI9Yn>&! zlT=GYvpaIZaIwf1uJ%;hni@_*IUY#b+j-RKs|+-Eb<{_@V-?O?Q?s}1b_@b>GmDgR zEQ{oeiv_FAVl1|}V$k^l6vZ43uqc)x#A#tlUa;8WoTNa3qnAREGFDbl4jmTCPG^j@*arGCkiO@CUtp9X%004|QfwPoKzldws#qh>!PtIX8o^Asuw! zIaEvhT*or94GsOFMchl~z;b+ptdv<9H6IA^c!^wsrFfQlrI@DkD|wTn%IAytd-{~~ zctm#BXXbdJpeU}_h@ti@np2B0G3@ng>CJygG5OpiFUt=NpDZGQfCJz(8Q*n@Wq0x!*hxj=gCE#kp#w|ej z4sWFFL(5O1SWIUTq{EYq=6c-E^*Hv$xI~CKCv~~$Yqh0PV@C_zt_Ne&a0+OXFfZrvcO6~5l?k+H zpb(%wNam}zwytFTN(UJZ0f5t~2h|(q!8E`iO{$`0(DiX=U7;jvl^Bpf+v4Q8na%rk a!uz@auG6b 11373 bytes +2023/12/19-22:08:59.638172 7fb086400700 compacted to: files[ 0 0 1 0 0 0 0 ] +2023/12/19-22:08:59.638243 7fb086400700 Delete type=2 #5 +2023/12/19-22:08:59.638324 7fb086400700 Delete type=2 #13 +2023/12/19-22:08:59.648805 7fb086400700 Manual compaction at level-1 from '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 17 : 1 .. '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 0 : 0; will stop at (end) diff --git a/packs/module-docs/MANIFEST-000002 b/packs/module-docs/MANIFEST-000002 deleted file mode 100644 index 95cc45787939dfddcc3dbbe9ece1c5d6d46c8689..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE z7!pAd4{o)N(m- literal 0 HcmV?d00001 diff --git a/packs/module-docs/_source/Setting_Adjustments_YSuk1v59tLaL9XUK.json b/packs/module-docs/_source/Setting_Adjustments_YSuk1v59tLaL9XUK.json index 148aaa4..afa67b3 100644 --- a/packs/module-docs/_source/Setting_Adjustments_YSuk1v59tLaL9XUK.json +++ b/packs/module-docs/_source/Setting_Adjustments_YSuk1v59tLaL9XUK.json @@ -35,6 +35,41 @@ "lastModifiedBy": "sVoCvBU1knmXzoYe" }, "_key": "!journal.pages!YSuk1v59tLaL9XUK.BlDoYgdTxhyCBP3Y" + }, + { + "sort": 200000, + "name": "Roll Modifier Hooks", + "type": "text", + "_id": "BxFgDb91dqbkO9h4", + "title": { + "show": true, + "level": 1 + }, + "image": {}, + "text": { + "format": 1, + "content": "

SWADE Trait and Damage Rolls can now take into account common modifiers based on the target, if there is exactly one attacker and one target. Most will show up on all trait rolls if the target conditions are right. Gang up bonuses will only show up on Fighting rolls.

Any of the proposed modifiers may be ignored by checking the Ignore checkbox. Some modifiers are pre-ignored and must be unchecked to take effect.

The following target conditions are checked for before trait rolls:

  1. Vulnerable

  2. Deflection (as applied by the Deflection power effect from this module)

  3. Arcane Protection (as applied by the Arcane Protection power effect from this module)

  4. Arcane Resistance

  5. Scale Modifiers

  6. Gang Up, taking into account Block and Formation Fighter

The following target conditions are checked for before damage rolls:

  1. Arcane Protection (as applied by the Arcane Protection power effect from this module)

  2. Arcane Resistance

  3. Special Abilities with 'weakness' in the swid (ignored by default, +4 damage)

  4. Special Abilities with 'resistance' in the swid (ignored by default, -4 damage)

  5. Gang Up bonus if the attacker has Pack Tactics

" + }, + "video": { + "controls": true, + "volume": 0.5 + }, + "src": null, + "system": {}, + "ownership": { + "default": -1, + "sVoCvBU1knmXzoYe": 3 + }, + "flags": {}, + "_stats": { + "systemId": "swade", + "systemVersion": "3.2.5", + "coreVersion": "11.315", + "createdTime": 1703044226574, + "modifiedTime": 1703044226574, + "lastModifiedBy": "sVoCvBU1knmXzoYe" + }, + "_key": "!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4" } ], "folder": null, @@ -50,7 +85,7 @@ "systemVersion": "3.2.5", "coreVersion": "11.315", "createdTime": 1695618001902, - "modifiedTime": 1702880796286, + "modifiedTime": 1703044226574, "lastModifiedBy": "sVoCvBU1knmXzoYe" }, "_id": "YSuk1v59tLaL9XUK", diff --git a/scripts/module.js b/scripts/module.js index 922c32a..9e81b1e 100644 --- a/scripts/module.js +++ b/scripts/module.js @@ -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') diff --git a/scripts/rollHelpers.js b/scripts/rollHelpers.js new file mode 100644 index 0000000..8bbf41c --- /dev/null +++ b/scripts/rollHelpers.js @@ -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 +}