Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a16237a78b | |||
| 8a7108bb04 | |||
| 0d045c9823 | |||
| 6580328746 | |||
| 7f2c4c56ba | |||
| 08bbb6de87 |
12
CHANGELOG.md
12
CHANGELOG.md
@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [4.3.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `@SWADEDamage` and `@SWADERequestRoll` text enrichers.
|
||||||
|
|
||||||
|
## [4.2.4]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Changed how summon powers spawn multiple tokens.
|
||||||
|
|
||||||
## [4.2.3]
|
## [4.2.3]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"url": "https://git.bloy.org/foundryvtt/swade-mb-helpers",
|
"url": "https://git.bloy.org/foundryvtt/swade-mb-helpers",
|
||||||
"version": "4.2.3",
|
"version": "4.3.0",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13"
|
"verified": "13"
|
||||||
|
|||||||
153
src/module/enrichers.js
Normal file
153
src/module/enrichers.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { requestRollFromTokens } from './helpers.js';
|
||||||
|
|
||||||
|
const enrichers = [
|
||||||
|
{
|
||||||
|
id: 'mb-swade-damage',
|
||||||
|
pattern: /@SWADEDamage\[\s*(?<roll>[\d+-dx]+)\s*\](?:\(\s*(?<ap>\d+)\s*\))?(?:\{(?<flavor>[^}]+)\})?/g,
|
||||||
|
enricher: swadeDamageEnricher,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mb-swade-trait',
|
||||||
|
pattern:
|
||||||
|
/@SWADERequestRoll\[\s*(?<traitType>skill|attribute),(?<traitName>[\w\s-]+)(?:,(?<tn>\d+))?\s*\](?:\(\s*(?<modVal>[-+]?\d+)(?:,(?<modDesc>[^)]+))?\s*\))?(?:\{(?<flavor>[^}]+)\})?/g,
|
||||||
|
enricher: swadeTraitRollEnricher,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function swadeDamageEnricher(match, options) {
|
||||||
|
if (!match.groups) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const roll = match.groups.roll;
|
||||||
|
const ap = parseInt(match.groups.ap ?? '0');
|
||||||
|
const flavor = match.groups.flavor ?? '';
|
||||||
|
const dataset = { roll, ap, flavor, rollType: 'damage' };
|
||||||
|
let text = '<strong>Damage</strong>';
|
||||||
|
if (flavor) {
|
||||||
|
text += ` ${flavor}`;
|
||||||
|
}
|
||||||
|
text += `: ${roll}`;
|
||||||
|
if (ap) {
|
||||||
|
text += ` AP ${ap}`;
|
||||||
|
}
|
||||||
|
if (!game.user.isGM) {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.innerHTML = text;
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
const classes = ['content-link', 'mb-swade-roll-damage-link', 'mb-swade-roll-link'];
|
||||||
|
for (const cls of classes) {
|
||||||
|
anchor.classList.add(cls);
|
||||||
|
}
|
||||||
|
for (let [k, v] of Object.entries(dataset)) {
|
||||||
|
anchor.dataset[k] = v;
|
||||||
|
}
|
||||||
|
anchor.innerHTML = `<i class="fas fa-heart-crack"></i> ${text}`;
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function swadeTraitRollEnricher(match, options) {
|
||||||
|
if (!match.groups) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const traitType = match.groups.traitType;
|
||||||
|
const traitName = match.groups.traitName;
|
||||||
|
if (!traitType || !traitName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const tn = parseInt(match.groups.tn ?? '4');
|
||||||
|
const modVal = parseInt(match.groups.modVal ?? '0');
|
||||||
|
const modDesc = match.groups.modDesc ?? 'Circumstance';
|
||||||
|
const flavor = match.groups.flavor ?? '';
|
||||||
|
const dataset = { traitType, traitName, tn, modVal, modDesc, flavor, rollType: 'trait' };
|
||||||
|
const displayTraitName = (traitName[0].toUpperCase() + traitName.slice(1).toLowerCase()).replace(/[-_]/, ' ');
|
||||||
|
let text = `<strong>Request Roll:</strong> ${displayTraitName}`;
|
||||||
|
if (modVal != 0) {
|
||||||
|
text += ` ${modVal}`;
|
||||||
|
}
|
||||||
|
if (tn !== 4) {
|
||||||
|
text += ` TN: ${tn}`;
|
||||||
|
}
|
||||||
|
if (flavor) {
|
||||||
|
text += ` (${flavor})`;
|
||||||
|
}
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
const classes = ['content-link', 'mb-swade-roll-request-link', 'mb-swade-roll-link'];
|
||||||
|
for (const cls of classes) {
|
||||||
|
anchor.classList.add(cls);
|
||||||
|
}
|
||||||
|
for (let [k, v] of Object.entries(dataset)) {
|
||||||
|
anchor.dataset[k] = v;
|
||||||
|
}
|
||||||
|
anchor.innerHTML = `<i class="fas fa-question"></i> <i class="fas fa-dice"></i> ${text}`;
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSwadeRollLink(ev) {
|
||||||
|
console.log('SWADE ROLL', ev);
|
||||||
|
const targetElement = ev.target.closest('a.mb-swade-roll-link');
|
||||||
|
if (!targetElement) return;
|
||||||
|
ev.preventDefault();
|
||||||
|
const rollType = targetElement.dataset.rollType;
|
||||||
|
switch (rollType) {
|
||||||
|
case 'trait':
|
||||||
|
return onRequestTraitRollLink(targetElement);
|
||||||
|
case 'damage':
|
||||||
|
return onDamageRollLink(targetElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRequestTraitRollLink(targetElement) {
|
||||||
|
const tokens = game.user.targets.size > 0 ? Array.from(game.user.targets) : canvas.tokens.controlled;
|
||||||
|
console.log(tokens);
|
||||||
|
if (tokens.length < 1) {
|
||||||
|
foundry.ui.notifications.error('Please target or select some tokens.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { traitType, traitName, modDesc, flavor } = targetElement.dataset;
|
||||||
|
const tn = parseInt(targetElement.dataset.tn ?? '4');
|
||||||
|
const modVal = parseInt(targetElement.dataset.modVal ?? '0');
|
||||||
|
const options = { targetNumber: 4, flavor };
|
||||||
|
if (tn != 4) {
|
||||||
|
options.targetNumber = tn;
|
||||||
|
}
|
||||||
|
if (modVal != 0) {
|
||||||
|
options.mods = [{ label: modDesc, value: modVal }];
|
||||||
|
}
|
||||||
|
requestRollFromTokens(tokens, traitType, traitName, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDamageRollLink(targetElement) {
|
||||||
|
const roll = targetElement.dataset.roll;
|
||||||
|
const ap = parseInt(targetElement.dataset.ap ?? '0');
|
||||||
|
let flavor = targetElement.dataset.flavor ?? '';
|
||||||
|
const options = {};
|
||||||
|
if (ap > 0) {
|
||||||
|
flavor = `${flavor ? flavor + ' - ' : ''}AP: ${ap}`;
|
||||||
|
options.ap = ap;
|
||||||
|
}
|
||||||
|
console.log('DamageRollLink', roll, ap, flavor, options);
|
||||||
|
new CONFIG.Dice.DamageRoll(roll, null, options).toMessage({ flavor });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupEnrichers() {
|
||||||
|
Hooks.once('ready', async () => {
|
||||||
|
for (const enricher of enrichers) {
|
||||||
|
CONFIG.TextEditor.enrichers.push(enricher);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Hooks.on('renderApplicationV1', (application, html, data) => {
|
||||||
|
$(html)
|
||||||
|
.find('a.mb-swade-roll-link')
|
||||||
|
.each((i, el) => $(el).click(onSwadeRollLink));
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderApplicationV2', (application, element, context, options) => {
|
||||||
|
element.querySelectorAll('a.mb-swade-roll-link').forEach((el) => el.addEventListener('click', onSwadeRollLink));
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderChatMessageHTML', (message, html, context) => {
|
||||||
|
html.querySelectorAll('a.mb-swade-roll-link').forEach((el) => el.addEventListener('click', onSwadeRollLink));
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -45,25 +45,28 @@ export class BaseSummonEffect extends ActorFolderEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async spawn() {
|
async spawn() {
|
||||||
const location = await Sequencer.Crosshair.show({
|
const spawned = [];
|
||||||
distance: this.targetTokenDoc.height / 2,
|
|
||||||
texture: this.targetTokenDoc.texture.src,
|
|
||||||
snap: {
|
|
||||||
position: CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.CENTER,
|
|
||||||
},
|
|
||||||
label: { text: this.targetTokenDoc.name },
|
|
||||||
});
|
|
||||||
const tokenDocs = [];
|
|
||||||
for (let i = 0; i < this.summonCount; i++) {
|
for (let i = 0; i < this.summonCount; i++) {
|
||||||
tokenDocs[i] = this.targetTokenDoc.clone({
|
let label = this.targetTokenDoc.name;
|
||||||
x: location.token.x + i * 5,
|
if (this.summonCount > 1) {
|
||||||
y: location.token.y + i * 5,
|
label = `${this.targetTokenDoc.name} #${i + 1}`;
|
||||||
|
}
|
||||||
|
const location = await Sequencer.Crosshair.show({
|
||||||
|
distance: this.targetTokenDoc.height / 2,
|
||||||
|
texture: this.targetTokenDoc.texture.src,
|
||||||
|
snap: {
|
||||||
|
position: CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.CENTER,
|
||||||
|
},
|
||||||
|
label: { text: label },
|
||||||
|
});
|
||||||
|
const tokenDoc = this.targetTokenDoc.clone({
|
||||||
|
x: location.token.x,
|
||||||
|
y: location.token.y,
|
||||||
elevation: this.source.elevation,
|
elevation: this.source.elevation,
|
||||||
});
|
});
|
||||||
|
const spawn = await this.source.scene.createEmbeddedDocuments('Token', [tokenDoc]);
|
||||||
|
spawned.push(...spawn);
|
||||||
}
|
}
|
||||||
log('token docs', tokenDocs);
|
|
||||||
const spawned = await this.source.scene.createEmbeddedDocuments('Token', tokenDocs);
|
|
||||||
log('Spawned', spawned);
|
|
||||||
return spawned;
|
return spawned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/* globals socketlib */
|
/* globals socketlib */
|
||||||
// Import JavaScript modules
|
// Import JavaScript modules
|
||||||
import { registerSettings } from './settings.js';
|
import { registerSettings } from './settings.js';
|
||||||
|
import { setupEnrichers } from './enrichers.js';
|
||||||
import { preloadTemplates } from './preloadTemplates.js';
|
import { preloadTemplates } from './preloadTemplates.js';
|
||||||
import { api } from './api.js';
|
import { api } from './api.js';
|
||||||
import { initVisionModes } from './visionModes.js';
|
import { initVisionModes } from './visionModes.js';
|
||||||
@ -32,6 +33,7 @@ Hooks.once('init', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup module
|
// Setup module
|
||||||
|
setupEnrichers();
|
||||||
Hooks.once('setup', async () => {
|
Hooks.once('setup', async () => {
|
||||||
api.registerFunctions();
|
api.registerFunctions();
|
||||||
// Register custom module settings
|
// Register custom module settings
|
||||||
|
|||||||
104
src/packsrc/module-docs/Text_Enrichers_SrSVRJkJT87Iz2Ed.json
Normal file
104
src/packsrc/module-docs/Text_Enrichers_SrSVRJkJT87Iz2Ed.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user