several changes that were not properly split up

- Macro: Request fear check specialization macro
- Macro: Fear Table to call the new fearTable api endpoint
- API: rulesVersion property
- API: fearTable(actor) calls the relevant premium core rules module's fear
  table
- API: added requestFearRollFromTokens special helper
- Trait roll hooks for:
    - Glow/Shroud
    - Range modifiers
- added a summary chat message for the roll results to requested rolls.
- added a target number option to requested rolls.
This commit is contained in:
Mike Bloy 2023-12-23 19:56:26 -06:00
parent c43fafa7df
commit 6ed989c4bc
44 changed files with 514 additions and 95 deletions

View File

@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Macro: Request fear check specialization macro
- Macro: Fear Table to call the new fearTable api endpoint
- API: rulesVersion property
- API: fearTable(actor) calls the relevant premium core rules module's fear
table
- API: added requestFearRollFromTokens special helper
- Trait roll hooks for:
- Glow/Shroud
- Range modifiers
### Changed
- added a summary chat message for the roll results to requested rolls.
- added a target number option to requested rolls.
## [2.3.0] 2023-12-19
### Added

39
macros/requestFearRoll.js Normal file
View File

@ -0,0 +1,39 @@
const requestFearRollFromTokens = game.modules.get('swade-mb-helpers').api.requestRollFromTokens
async function main () {
let tokens = Array.from(game.user.targets)
if (tokens.length < 1) {
tokens = canvas.tokens.controlled
}
if (tokens.length < 1) {
ui.notifications.error('Please target or select some tokens')
return
}
const menuData = {
inputs: [
{ type: 'info', label: `Requesting Fear roll from ${tokens.map(t => t.name).join(', ')}` },
{ type: 'number', label: 'Fear Check Penalty', options: 0 }
],
buttons: [
{ label: 'Request roll', value: 'ok', default: true },
{ label: 'Cancel', value: 'cancel' }
]
}
const menuConfig = {
title: 'Request Fear roll...'
}
const result = await warpgate.menu(menuData, menuConfig)
if (result.buttons !== 'ok') {
return
}
console.log(result)
const fear = result.inputs[1] || 0
const targetNumber = 4
const options = { targetNumber, fear }
requestFearRollFromTokens(tokens, options)
}
main()

View File

@ -19,7 +19,8 @@ async function main () {
options: []
},
{ type: 'number', label: 'Roll Modifier', options: 0 },
{ type: 'text', label: 'Roll Modifier Description', options: 'Roll Modifier' }
{ type: 'text', label: 'Roll Modifier Description', options: 'Roll Modifier' },
{ type: 'number', label: 'Target Number', options: 4 }
],
buttons: [
{ label: 'Request roll', value: 'ok', default: true },
@ -59,7 +60,8 @@ async function main () {
const rollParts = result.inputs[1].split('|')
const rollType = (rollParts[0] === 'a' ? 'attribute' : 'skill')
const rollDesc = rollParts[1]
const options = {}
const targetNumber = result.inputs[4] || 4
const options = { targetNumber }
if (rollMod !== 0) {
options.mods = [{ label: rollModDesc, value: rollMod }]
}

View File

@ -1 +1 @@
MANIFEST-000014
MANIFEST-000002

View File

@ -1,3 +1,5 @@
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
2023/12/23-19:53:30.442930 7f73537bf700 Delete type=3 #1
2023/12/23-19:53:30.445253 7f7351501700 Level-0 table #5: started
2023/12/23-19:53:30.448202 7f7351501700 Level-0 table #5: 12215 bytes OK
2023/12/23-19:53:30.451038 7f7351501700 Delete type=0 #3
2023/12/23-19:53:30.451169 7f7351501700 Manual compaction at level-0 from '!folders!0nDRFmMBs5DBJU9M' @ 72057594037927935 : 1 .. '!items.effects!RC1Nz6iph8wPPK1B.g9W5hJisq3MsCpZW' @ 0 : 0; will stop at (end)

View File

@ -1,8 +0,0 @@
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)

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
MANIFEST-000014
MANIFEST-000002

View File

@ -1,3 +1,5 @@
2023/12/19-22:11:46.716627 7f5d39ffb700 Recovering log #12
2023/12/19-22:11:46.739685 7f5d39ffb700 Delete type=0 #12
2023/12/19-22:11:46.739711 7f5d39ffb700 Delete type=3 #10
2023/12/23-19:53:31.230991 7f2e1bfff700 Delete type=3 #1
2023/12/23-19:53:31.233147 7f2e19ffb700 Level-0 table #5: started
2023/12/23-19:53:31.235972 7f2e19ffb700 Level-0 table #5: 6787 bytes OK
2023/12/23-19:53:31.238668 7f2e19ffb700 Delete type=0 #3
2023/12/23-19:53:31.238744 7f2e19ffb700 Manual compaction at level-0 from '!items!JWyBQe4tnOYljFAF' @ 72057594037927935 : 1 .. '!items!tWWSfEMmLmws6Yb1' @ 0 : 0; will stop at (end)

View File

@ -1,8 +0,0 @@
2023/12/19-14:25:58.761898 7fb0acf3b700 Recovering log #8
2023/12/19-14:25:58.781218 7fb0acf3b700 Delete type=3 #6
2023/12/19-14:25:58.781255 7fb0acf3b700 Delete type=0 #8
2023/12/19-22:08:59.648947 7fb086400700 Level-0 table #13: started
2023/12/19-22:08:59.648972 7fb086400700 Level-0 table #13: 0 bytes OK
2023/12/19-22:08:59.658595 7fb086400700 Delete type=0 #11
2023/12/19-22:08:59.677223 7fb086400700 Manual compaction at level-0 from '!items!JWyBQe4tnOYljFAF' @ 72057594037927935 : 1 .. '!items!tWWSfEMmLmws6Yb1' @ 0 : 0; will stop at (end)
2023/12/19-22:08:59.677310 7fb086400700 Manual compaction at level-1 from '!items!JWyBQe4tnOYljFAF' @ 72057594037927935 : 1 .. '!items!tWWSfEMmLmws6Yb1' @ 0 : 0; will stop at (end)

BIN
packs/gear/MANIFEST-000002 Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
MANIFEST-000014
MANIFEST-000002

View File

@ -1,3 +1,5 @@
2023/12/19-22:11:46.843641 7ff2615a2700 Recovering log #12
2023/12/19-22:11:46.864924 7ff2615a2700 Delete type=0 #12
2023/12/19-22:11:46.864950 7ff2615a2700 Delete type=3 #10
2023/12/23-19:53:31.842430 7f67a8d9f700 Delete type=3 #1
2023/12/23-19:53:31.844543 7f67837fe700 Level-0 table #5: started
2023/12/23-19:53:31.847334 7f67837fe700 Level-0 table #5: 1751 bytes OK
2023/12/23-19:53:31.850174 7f67837fe700 Delete type=0 #3
2023/12/23-19:53:31.850251 7f67837fe700 Manual compaction at level-0 from '!actors!U5v4gFHquo0Y1SAq' @ 72057594037927935 : 1 .. '!actors!U5v4gFHquo0Y1SAq' @ 0 : 0; will stop at (end)

View File

@ -1,8 +0,0 @@
2023/12/19-14:25:58.750811 7fb087fff700 Recovering log #8
2023/12/19-14:25:58.759586 7fb087fff700 Delete type=3 #6
2023/12/19-14:25:58.759616 7fb087fff700 Delete type=0 #8
2023/12/19-22:08:59.612497 7fb086400700 Level-0 table #13: started
2023/12/19-22:08:59.612518 7fb086400700 Level-0 table #13: 0 bytes OK
2023/12/19-22:08:59.622048 7fb086400700 Delete type=0 #11
2023/12/19-22:08:59.648768 7fb086400700 Manual compaction at level-0 from '!actors!U5v4gFHquo0Y1SAq' @ 72057594037927935 : 1 .. '!actors!U5v4gFHquo0Y1SAq' @ 0 : 0; will stop at (end)
2023/12/19-22:08:59.648884 7fb086400700 Manual compaction at level-1 from '!actors!U5v4gFHquo0Y1SAq' @ 72057594037927935 : 1 .. '!actors!U5v4gFHquo0Y1SAq' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
MANIFEST-000014
MANIFEST-000002

View File

@ -1,3 +1,5 @@
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
2023/12/23-19:53:32.597429 7efcc4fbd700 Delete type=3 #1
2023/12/23-19:53:32.599577 7efcc3fbb700 Level-0 table #5: started
2023/12/23-19:53:32.602517 7efcc3fbb700 Level-0 table #5: 13110 bytes OK
2023/12/23-19:53:32.605253 7efcc3fbb700 Delete type=0 #3
2023/12/23-19:53:32.605331 7efcc3fbb700 Manual compaction at level-0 from '!folders!hIbrWxg1nDutCSwt' @ 72057594037927935 : 1 .. '!macros!wU2mAUnw3RW9qMT8' @ 0 : 0; will stop at (end)

View File

@ -1,8 +0,0 @@
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)

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,25 @@
{
"name": "Fear Table",
"type": "script",
"_id": "S6HY6RqjPTt0z0yY",
"author": "sVoCvBU1knmXzoYe",
"img": "icons/magic/death/undead-ghost-scream-teal.webp",
"scope": "global",
"command": "game.modules.get('swade-mb-helpers').api.fearTable(actor)",
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"sVoCvBU1knmXzoYe": 3
},
"flags": {},
"_stats": {
"systemId": "swade",
"systemVersion": "3.2.5",
"coreVersion": "11.315",
"createdTime": 1703096862424,
"modifiedTime": 1703096940207,
"lastModifiedBy": "sVoCvBU1knmXzoYe"
},
"_key": "!macros!S6HY6RqjPTt0z0yY"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
MANIFEST-000015
MANIFEST-000002

View File

@ -1,3 +1,5 @@
2023/12/19-22:11:47.107915 7f81967fc700 Recovering log #12
2023/12/19-22:11:47.129799 7f81967fc700 Delete type=0 #12
2023/12/19-22:11:47.129819 7f81967fc700 Delete type=3 #10
2023/12/23-19:53:33.321181 7f1ac1fbd700 Delete type=3 #1
2023/12/23-19:53:33.323246 7f1ac0fbb700 Level-0 table #5: started
2023/12/23-19:53:33.326242 7f1ac0fbb700 Level-0 table #5: 14296 bytes OK
2023/12/23-19:53:33.328910 7f1ac0fbb700 Delete type=0 #3
2023/12/23-19:53:33.328990 7f1ac0fbb700 Manual compaction at level-0 from '!journal!HbtPlHNFO1L6RVj0' @ 72057594037927935 : 1 .. '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 0 : 0; will stop at (end)

View File

@ -1,15 +0,0 @@
2023/12/19-14:25:58.704299 7fb0acf3b700 Recovering log #8
2023/12/19-14:25:58.717166 7fb0acf3b700 Delete type=3 #6
2023/12/19-14:25:58.717190 7fb0acf3b700 Delete type=0 #8
2023/12/19-22:08:59.583949 7fb086400700 Level-0 table #13: started
2023/12/19-22:08:59.590634 7fb086400700 Level-0 table #13: 7975 bytes OK
2023/12/19-22:08:59.600142 7fb086400700 Delete type=0 #11
2023/12/19-22:08:59.600341 7fb086400700 Manual compaction at level-0 from '!journal!HbtPlHNFO1L6RVj0' @ 72057594037927935 : 1 .. '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 0 : 0; will stop at (end)
2023/12/19-22:08:59.622125 7fb086400700 Manual compaction at level-1 from '!journal!HbtPlHNFO1L6RVj0' @ 72057594037927935 : 1 .. '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 0 : 0; will stop at '!journal.pages!YSuk1v59tLaL9XUK.BxFgDb91dqbkO9h4' @ 17 : 1
2023/12/19-22:08:59.622154 7fb086400700 Compacting 1@1 + 1@2 files
2023/12/19-22:08:59.629116 7fb086400700 Generated table #14@1: 17 keys, 11373 bytes
2023/12/19-22:08:59.629154 7fb086400700 Compacted 1@1 + 1@2 files => 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)

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -249,6 +249,76 @@
"lastModifiedBy": "sVoCvBU1knmXzoYe"
},
"_key": "!journal.pages!Mw1g2Fx5dp4SoqVP.mT3lMGUo9zvqQsOh"
},
{
"sort": 500000,
"name": "Fear Table",
"type": "text",
"_id": "RxGaSpV6FStZyyBX",
"title": {
"show": true,
"level": 1
},
"image": {},
"text": {
"format": 1,
"content": "<p>This macro will call the Fear Table macro from whichever premium ruleset (SPWF or SWADE) is active, preferring SWPF.</p><p>It will not work if no premium module is active.</p>"
},
"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": 1703097037538,
"modifiedTime": 1703097110707,
"lastModifiedBy": "sVoCvBU1knmXzoYe"
},
"_key": "!journal.pages!Mw1g2Fx5dp4SoqVP.RxGaSpV6FStZyyBX"
},
{
"sort": 500000,
"name": "Request Fear Check",
"type": "text",
"title": {
"show": true,
"level": 1
},
"image": {},
"text": {
"format": 1,
"content": "<p>This macro will prompt for a fear penalty and request a spirit roll with that penalty from targeted or selected tokens.</p>"
},
"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": 1703097037538,
"modifiedTime": 1703376053416,
"lastModifiedBy": "sVoCvBU1knmXzoYe"
},
"_id": "CRgBHcoOmH5hvadF",
"_key": "!journal.pages!Mw1g2Fx5dp4SoqVP.CRgBHcoOmH5hvadF"
}
],
"flags": {
@ -261,7 +331,7 @@
"systemVersion": "3.2.5",
"coreVersion": "11.315",
"createdTime": 1678169291843,
"modifiedTime": 1702960233927,
"modifiedTime": 1703376053416,
"lastModifiedBy": "sVoCvBU1knmXzoYe"
},
"_id": "Mw1g2Fx5dp4SoqVP",

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import { log } from './shim.js'
import { requestRollFromTokens } from './helpers.js'
import { log, shim } from './shim.js'
import { requestFearRollFromTokens, requestRollFromTokens } from './helpers.js'
import { powerEffects } from './powerEffects.js'
export class api {
@ -11,8 +11,11 @@ export class api {
static globals () {
const moduleName = 'swade-mb-helpers'
game.modules.get(moduleName).api = {
rulesVersion: shim.rulesVersion,
fearTable: shim.fearTableHelper,
powerEffects,
requestRollFromTokens
requestRollFromTokens,
requestFearRollFromTokens
}
}
}

View File

@ -1,5 +1,25 @@
import { shim } from './shim.js'
export async function requestFearRollFromTokens (tokens, options = {}) {
// tokens: list of tokens to request the roll from
// options:
// title: tile for the roll dialog. Will have "- {{ token name }}" appended
// flavour: flavor text for the roll card. Defaults to title
// fear: value of the fear modifier. Defaults to 0. Positive number.
const requestingUser = shim.user
const title = options?.title || `${requestingUser.name} requests a Fear check`
const flavour = options?.flavour || options?.flavor || title
const fear = options.fear || 0
const rollOpts = {
title,
flavour,
mods: [
{ label: 'Fear Penalty', value: Math.abs(fear) * -1, ignore: false }
]
}
return requestRollFromTokens(tokens, 'attribute', 'spirit', rollOpts)
}
export async function requestRollFromTokens (tokens, rollType, rollDesc, options = {}) {
// tokens: list of tokens to request a roll from
// rollType: 'attribute' or 'skill
@ -8,17 +28,20 @@ export async function requestRollFromTokens (tokens, rollType, rollDesc, options
// title: title for the roll dialog. Will have "- {{ token name }}"
// appended
// flavour: flavor text for the roll card. Defaults to title
// targetNumber: defaults to 4
// mods: list of modifiers {label: "", value: 0, ignore: false}
// modCallback: callback function that takes a token and returns a list of
// modifiers in the same format as modifiers, above
const requestingUser = shim.user
const title = options?.title || `${requestingUser.name} requests a ${rollDesc} roll`
const flavour = options?.flavour || options?.flavor || title
const targetNumber = options?.targetNumber || 4
const promises = []
for (const token of tokens) {
const owner = shim.warpgateUtil.firstOwner(token.document)
const rollOpts = {
title: `${title} - ${token.name}`,
targetNumber,
flavour
}
const additionalMods = []
@ -39,7 +62,45 @@ export async function requestRollFromTokens (tokens, rollType, rollDesc, options
promises.push(shim.socket.executeAsUser(requestTokenRoll, owner.id,
token.scene.id, token.id, rollType, rollDesc, rollOpts))
}
const results = await Promise.allSettled(promises)
const results = (await Promise.allSettled(promises)).map(r => r.value)
const contentExtra = targetNumber === 4 ? '' : ` vs TN: ${targetNumber}`
const messageData = {
flavor: flavour,
speaker: { alias: 'Requested Roll Results' },
whisper: [...shim.ChatMessage.getWhisperRecipients('GM'), requestingUser],
content: `<p>Results of ${rollDesc[0].toUpperCase()}${rollDesc.slice(1)} roll${contentExtra}:</p>
<table><thead><tr><th>Token</th><th>Roll</th><th>Result</th></tr></thead><tbody>`,
rolls: []
}
for (const result of results) {
const token = shim.game.scenes.get(result.sceneId).tokens.get(result.tokenId)
const roll = (
result.result instanceof shim.CONFIG.Dice.SwadeRoll
? result.result
: shim.CONFIG.Dice[result.result.class].fromData(result.result)
)
roll.targetNumber = targetNumber
let textResult = ''
if (roll.successes === -1) {
textResult = 'CRITICAL FAILURE'
} else if (roll.successes === 0) {
textResult = 'failed'
} else if (roll.successes === 1) {
textResult = 'success'
} else {
textResult = `success and ${roll.successes - 1} raise${roll.successes > 2 ? 's' : ''}`
}
messageData.content += ('<tr>' +
`<th>${token.name}</th>` +
`<td>${roll ? roll.total : '<i>Canceled</i>'}</td>` +
`<td>${textResult}</td>` +
'</tr>')
if (roll) {
messageData.rolls.unshift(roll)
}
}
messageData.content += '</tbody></table>'
shim.ChatMessage.create(messageData, {})
return results
}

View File

@ -51,7 +51,7 @@ Hooks.on('init', () => {
vision: {
darkness: { adaptive: false },
defaults: { attenuation: 0.1, contrast: 0, saturation: 0, brightness: 0.75 },
preferred: true
preferred: false
}
})
CONFIG.Canvas.visionModes.lowlight = new VisionMode({
@ -67,7 +67,7 @@ Hooks.on('init', () => {
vision: {
darkness: { adaptive: false },
defaults: { attenuation: 0.1, contrast: 0, saturation: -0.5, brightness: -0.2 },
preferred: true
preferred: false
}
})
})

View File

@ -1,5 +1,5 @@
import { CONST, log, shim } from './shim.js'
import { requestRollFromTokens } from './helpers.js'
import { requestFearRollFromTokens, requestRollFromTokens } from './helpers.js'
class PowerEffect {
constructor (token, targets) {
@ -546,6 +546,34 @@ class EntangleEffect extends TargetedPowerEffect {
}
}
class FearEffect extends TargetedPowerEffect {
get name () {
return 'Fear'
}
get baseDurationRounds () {
return 1
}
async prepResult () {
this.raise = (this.buttons === 'raise')
}
async applyResult () {
await super.applyResult()
await shim.wait(1000)
const options = {
title: 'Fear check!',
flavor: 'Failure: roll on the Fear Table if wildcard, Panicked if extra',
mods: []
}
if (this.raise) {
options.fear = '-2'
}
await requestFearRollFromTokens(this.targets, options)
}
}
class HavocEffect extends TargetedPowerEffect {
get name () {
return 'Havoc'
@ -1555,6 +1583,7 @@ const PowerClasses = {
'detectconceal-aracana': DetectConcealArcanaEffect,
disguise: DisguiseEffect,
entangle: EntangleEffect,
fear: FearEffect,
havoc: HavocEffect,
intangibility: IntangibilityEffect,
invisibility: InvisibilityEffect,

View File

@ -19,9 +19,30 @@ export async function preTraitRollModifiers (actor, trait, roll, modifiers, opti
) {
modifiers.push({ label: 'Target has Deflection', value: '-2', ignore: false })
}
if (targets.some(
target => target.actor.effects.filter(
e => !e.disabled && e.name.toLowerCase().includes('glow')).length > 0)
) {
modifiers.push({
label: 'Glowing target (negate 1 point of illumination penalty)',
value: '+1',
ignore: true
})
}
if (targets.some(
target => target.actor.effects.filter(
e => !e.disabled && e.name.toLowerCase().includes('shroud')).length > 0)
) {
modifiers.push({
label: 'Shrouded target',
value: '-1',
ignore: false
})
}
if (targets.length === 1 && token) {
const target = targets[0]
_addArcaneModifiers(target, modifiers)
_addRangeModifiers(token, target, options, modifiers)
const scaleMod = calcScaleMod(token, target)
if (scaleMod !== 0) {
modifiers.push({ label: 'Scale', value: scaleMod, ignore: false })
@ -67,6 +88,25 @@ export async function preDamageRollModifiers (actor, item, roll, modifiers, opti
}
}
function _addRangeModifiers (token, target, options, modifiers) {
if (options?.item?.type !== 'weapon' || !options?.item?.system?.range.includes('/')) {
return
}
const ranges = options.item.system.range.split('/').map(x => parseInt(x))
const distance = getDistance(token, target)
const rollmods = shim.CONFIG.SWADE.prototypeRollGroups.find(g => g.name === 'Range').modifiers
log('ITEM RANGES:', ranges)
if (distance <= ranges[0]) {
// nothing here
} else if (ranges.length >= 2 && distance <= ranges[1]) {
modifiers.push(rollmods[0])
} else if (ranges.length >= 3 && distance <= ranges[2]) {
modifiers.push(rollmods[1])
} else {
modifiers.push(rollmods[2]) // extreme range
}
}
function _addArcaneModifiers (target, modifiers) {
if (_findItem(target.actor, 'edge', 'improved-arcane-resistance')) {
modifiers.push({ label: 'Arcane Resistance', value: '-4', ignore: true })
@ -86,12 +126,21 @@ function _addArcaneModifiers (target, modifiers) {
}
}
function withinRange (origin, target, range) {
function getScaleDistanceMod (token) {
const scale = token.actor.system.stats.scale
return (scale > 0 ? (scale / 2) : 0)
}
function getDistance (origin, target) {
const ray = new Ray(origin, target)
const originScale = getScaleDistanceMod(origin)
const targetScale = getScaleDistanceMod(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 distance - (originScale + targetScale)
}
function withinRange (origin, target, range) {
const distance = getDistance(origin, target)
return range >= distance
}

View File

@ -17,10 +17,22 @@ export class shim {
return ActiveEffect
}
static get CONFIG () {
return CONFIG
}
static get Actor () {
return Actor
}
static get ChatMessage () {
return ChatMessage
}
static get game () {
return game
}
static get canvas () {
return game.canvas
}
@ -63,6 +75,16 @@ export class shim {
return shim._socket
}
static get rulesVersion () {
if (game.modules.get('swpf-core-rules')?.active) {
return 'swpf'
}
if (game.modules.get('swade-core-rules')?.active) {
return 'swade'
}
return 'system'
}
static mergeObject (...args) {
return mergeObject(...args)
}
@ -136,6 +158,14 @@ export class shim {
return warpgate.util
}
static get fearTableHelper () {
switch (shim.rulesVersion) {
case 'swade': return coreFearDialog
case 'swpf': return swpfFearDialog
}
throw new ReferenceError('No premium module active. No fear table found')
}
static getActorFolderByPath (path) {
const names = path.split('/')
if (names[0] === '') {