Compare commits
No commits in common. "main" and "v4.2.3" have entirely different histories.
12
CHANGELOG.md
12
CHANGELOG.md
@ -5,18 +5,6 @@ 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.3.0",
|
"version": "4.2.3",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13"
|
"verified": "13"
|
||||||
|
|||||||
@ -1,153 +0,0 @@
|
|||||||
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,28 +45,25 @@ export class BaseSummonEffect extends ActorFolderEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async spawn() {
|
async spawn() {
|
||||||
const spawned = [];
|
|
||||||
for (let i = 0; i < this.summonCount; i++) {
|
|
||||||
let label = this.targetTokenDoc.name;
|
|
||||||
if (this.summonCount > 1) {
|
|
||||||
label = `${this.targetTokenDoc.name} #${i + 1}`;
|
|
||||||
}
|
|
||||||
const location = await Sequencer.Crosshair.show({
|
const location = await Sequencer.Crosshair.show({
|
||||||
distance: this.targetTokenDoc.height / 2,
|
distance: this.targetTokenDoc.height / 2,
|
||||||
texture: this.targetTokenDoc.texture.src,
|
texture: this.targetTokenDoc.texture.src,
|
||||||
snap: {
|
snap: {
|
||||||
position: CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.CENTER,
|
position: CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.CENTER,
|
||||||
},
|
},
|
||||||
label: { text: label },
|
label: { text: this.targetTokenDoc.name },
|
||||||
});
|
});
|
||||||
const tokenDoc = this.targetTokenDoc.clone({
|
const tokenDocs = [];
|
||||||
x: location.token.x,
|
for (let i = 0; i < this.summonCount; i++) {
|
||||||
y: location.token.y,
|
tokenDocs[i] = this.targetTokenDoc.clone({
|
||||||
|
x: location.token.x + i * 5,
|
||||||
|
y: location.token.y + i * 5,
|
||||||
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,7 +1,6 @@
|
|||||||
/* 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';
|
||||||
@ -33,7 +32,6 @@ 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
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user