buttons and descriptions for VAR module, added elemental manipulation
This commit is contained in:
parent
2870b6b587
commit
0d41527a5e
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [3.0.0] UNRELEASED
|
||||
|
||||
### Added
|
||||
|
||||
- Optional Visual Active Effect integration for power descriptions
|
||||
|
||||
### Changed
|
||||
|
||||
- Refactor and redo of powers handling
|
||||
|
||||
@ -23,6 +23,10 @@ export class moduleHelpers {
|
||||
return 'system';
|
||||
}
|
||||
|
||||
static get useVAE() {
|
||||
return !!game.modules.get('visual-active-effects')?.active;
|
||||
}
|
||||
|
||||
static getActorFolderByPath(path) {
|
||||
const names = path.split('/');
|
||||
if (names[0] === '') {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { PowerEffect } from './basePowers.js';
|
||||
import { requestRollFromTokens } from '../helpers.js';
|
||||
import { getPowerModifiers } from '../rollHelpers.js';
|
||||
|
||||
export class BanishEffect extends PowerEffect {
|
||||
get name() {
|
||||
|
||||
@ -426,11 +426,40 @@ export class PowerEffect {
|
||||
return '';
|
||||
}
|
||||
|
||||
get primaryEffectButtons() {
|
||||
// button objects should have a label and a type.
|
||||
// type should have one of the following, with the associated additional
|
||||
// fields:
|
||||
// roll:
|
||||
// formula: dice formula eg '3d6 + 3'
|
||||
// flavor: flavor text (optional)
|
||||
// trait:
|
||||
// rollType: 'attribute' or 'skill
|
||||
// rollDesc: name or swid of the attribute or skill
|
||||
// flavor: flavor text (optional)
|
||||
// mods: list of mods { label, value, ignore }
|
||||
// damage:
|
||||
// formula: dice formula for example '1d4x[Blades]'
|
||||
// ap: optional, a positive integer or 0, armor piercing
|
||||
// flavor: flavor text (optional)
|
||||
// callback:
|
||||
// callback: the function callback to run, takes a token as an argument
|
||||
return [];
|
||||
}
|
||||
|
||||
async createPrimaryEffect(maintId) {
|
||||
const doc = this.createEffectDocument(this.icon, this.effectName, this.getPrimaryEffectChanges());
|
||||
doc.description += this.description;
|
||||
if (moduleHelpers.useVAE) {
|
||||
doc.flags['visual-active-effects'] = { data: { content: this.description } };
|
||||
} else {
|
||||
doc.description += this.description;
|
||||
}
|
||||
doc.flags[moduleName].maintId = maintId;
|
||||
doc.duration.seconds = 594;
|
||||
const effectButtons = this.primaryEffectButtons;
|
||||
if (effectButtons.length > 0) {
|
||||
doc.flags[moduleName].buttons = effectButtons;
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -441,7 +470,11 @@ export class PowerEffect {
|
||||
}
|
||||
const doc = this.createEffectDocument(icon, `Maintaining ${this.effectName}`, []);
|
||||
doc.duration.rounds = this.duration;
|
||||
doc.description += this.description;
|
||||
if (moduleHelpers.useVAE) {
|
||||
doc.flags['visual-active-effects'] = { data: { content: this.description } };
|
||||
} else {
|
||||
doc.description += this.description;
|
||||
}
|
||||
doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnPrompt;
|
||||
doc.flags.swade.loseTurnOnHold = true;
|
||||
doc.flags[moduleName].maintainingId = maintId;
|
||||
@ -541,7 +574,7 @@ export class PowerEffect {
|
||||
if (this.isDamaging && this.data.ap > 0) {
|
||||
list.push(`AP ${this.data.ap}`);
|
||||
}
|
||||
if (this.data.range != 'none') {
|
||||
if (this.data.range ?? 'none' != 'none') {
|
||||
list.push(`Range ${this.data.range}`);
|
||||
}
|
||||
return list;
|
||||
|
||||
97
src/module/powers/elementalManipulation.js
Normal file
97
src/module/powers/elementalManipulation.js
Normal file
@ -0,0 +1,97 @@
|
||||
import { PowerEffect } from './basePowers.js';
|
||||
|
||||
export class ElementalManipulationEffect extends PowerEffect {
|
||||
get name() {
|
||||
return 'Elemental Manipulation';
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return 'icons/magic/earth/projectiles-stone-salvo-gray.webp';
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this.data?.weather ? 0 : 5;
|
||||
}
|
||||
|
||||
get isTargeted() {
|
||||
return this.data?.weather ? false : true;
|
||||
}
|
||||
|
||||
get isRaisable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get usePrimaryEffect() {
|
||||
return this.data?.weather ? false : true;
|
||||
}
|
||||
|
||||
get oneTarget() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get basePowerPoints() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
return [
|
||||
{
|
||||
name: 'Power',
|
||||
type: 'checkbox',
|
||||
value: 3,
|
||||
id: 'power',
|
||||
epic: true,
|
||||
effect: false,
|
||||
},
|
||||
{
|
||||
name: 'Weather',
|
||||
type: 'checkbox',
|
||||
value: 5,
|
||||
id: 'weather',
|
||||
epic: true,
|
||||
effect: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get primaryEffectButtons() {
|
||||
const dmg = `${this.data.raise ? 3 : 2}d${this.data.power ? 6 : 4}`;
|
||||
return [
|
||||
...super.primaryEffectButtons,
|
||||
{
|
||||
type: 'damage',
|
||||
label: `Damage (${dmg})`,
|
||||
formula: `${dmg}x`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get description() {
|
||||
if (this.data.weather) {
|
||||
return (
|
||||
super.description +
|
||||
`Bring or disperse rain, snow, sun, and wind in about a five mile radius.
|
||||
This takes 10 minutes and lasts an hour.
|
||||
`
|
||||
);
|
||||
}
|
||||
let damage = `${this.data.raise ? 3 : 2}d${this.data.power ? 6 : 4}x`;
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>Use the activation roll for:</p>
|
||||
<ul>
|
||||
<li><strong>Attack:</strong> activation roll is the attack roll,
|
||||
[[/r ${damage}]] damage within Range.</li>
|
||||
<li><strong>Move:</strong> move a cubic foot of air, earth, fire or water
|
||||
(half that of stone) up to the caster's Smarts as a limited action.</li>
|
||||
<li><strong>Push:</strong> Use the activation roll in place of Strength
|
||||
for a Push.</li>
|
||||
<li><strong>Special Effects:</strong> eg. purify a gallon of water,
|
||||
or conjure a quart, fix breaks in stone, conjure a flame or spread
|
||||
existing flame.</li>
|
||||
</ul>
|
||||
`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { moduleName, moduleHelpers } from '../globals.js';
|
||||
import { moduleName, moduleHelpers, log } from '../globals.js';
|
||||
import { firstOwner, deleteActiveEffectsFromToken } from '../helpers.js';
|
||||
import { ArcaneProtectionEffect } from './arcaneProtection.js';
|
||||
import { BanishEffect } from './banish.js';
|
||||
@ -20,6 +20,7 @@ import { DisguiseEffect } from './disguise.js';
|
||||
import { DispelEffect } from './dispel.js';
|
||||
import { DivinationEffect } from './divination.js';
|
||||
import { DrainPowerPointsEffect } from './drainPowerPoints.js';
|
||||
import { ElementalManipulationEffect } from './elementalManipulation.js';
|
||||
|
||||
const PowerClasses = {
|
||||
'arcane-protection': ArcaneProtectionEffect,
|
||||
@ -47,11 +48,75 @@ const PowerClasses = {
|
||||
dispel: DispelEffect,
|
||||
divination: DivinationEffect,
|
||||
'drain-power-points': DrainPowerPointsEffect,
|
||||
'elemental-manipulation': ElementalManipulationEffect,
|
||||
'lower-trait': BoostLowerTraitEffect,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
export function visualActiveEffectPowerButtons(effect, buttons) {
|
||||
if (!effect.flags?.[moduleName]?.buttons) {
|
||||
return;
|
||||
}
|
||||
for (const button of effect.flags[moduleName].buttons) {
|
||||
let callback = null;
|
||||
switch (button.type) {
|
||||
case 'roll':
|
||||
callback = function () {
|
||||
new CONFIG.Dice.SwadeRoll(button.formula ?? '3d6', null, {}).toMessage({
|
||||
flavor: button.flavor ?? `${effect.name} roll`,
|
||||
});
|
||||
};
|
||||
break;
|
||||
case 'trait':
|
||||
callback = function () {
|
||||
let rollFunc = 'rollAttribute';
|
||||
const rollType = button?.rollType ?? 'attribute';
|
||||
const rollDesc = button?.rollDesc ?? 'agility';
|
||||
let rollId = rollDesc.toLowerCase();
|
||||
if (rollType === 'skill') {
|
||||
rollFunc = 'rollSkill';
|
||||
rollId = effect.parent.items
|
||||
.filter((i) => i.type === 'skill')
|
||||
.find(
|
||||
(i) => i.system.swid === rollDesc.toLowerCase() || i.name.toLowerCase() === rollDesc.toLowerCase(),
|
||||
)?.id;
|
||||
}
|
||||
const options = {
|
||||
flavor: button?.flavor ?? `${effect.name} ${rollDesc} roll`,
|
||||
};
|
||||
if (button?.mods) {
|
||||
options.mods = button.mods;
|
||||
}
|
||||
effect.parent[rollFunc](rollId, options);
|
||||
};
|
||||
break;
|
||||
case 'damage':
|
||||
callback = function () {
|
||||
const formula = button?.formula ?? '2d6x';
|
||||
const ap = button?.ap ?? 0;
|
||||
const flavor = button?.flavor ?? `${effect.name} damage roll`;
|
||||
const options = {};
|
||||
if (ap > 0) {
|
||||
options.ap = ap;
|
||||
}
|
||||
new CONFIG.Dice.DamageRoll(formula, null, options).toMessage({ flavor });
|
||||
};
|
||||
break;
|
||||
case 'callback':
|
||||
callback =
|
||||
button?.callback ||
|
||||
function () {
|
||||
console.log('not implemented');
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (button?.label && callback) {
|
||||
buttons.push({ label: button.label, callback });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function powerEffectManagementHook(effect, data, userId) {
|
||||
if (game.user.id !== userId) {
|
||||
return;
|
||||
|
||||
@ -7,7 +7,7 @@ import { initVisionModes } from './visionModes.js';
|
||||
import { requestTokenRoll, addActiveEffectsToToken, deleteActiveEffectsFromToken } from './helpers.js';
|
||||
import { preDamageRollModifiers, preTraitRollModifiers } from './rollHelpers.js';
|
||||
import { log, moduleHelpers } from './globals.js';
|
||||
import { powerEffectManagementHook } from './powers/powers.js';
|
||||
import { powerEffectManagementHook, visualActiveEffectPowerButtons } from './powers/powers.js';
|
||||
|
||||
// Initialize module
|
||||
Hooks.once('init', async () => {
|
||||
@ -44,6 +44,7 @@ Hooks.on('swadePreRollAttribute', preTraitRollModifiers);
|
||||
Hooks.on('swadePreRollSkill', preTraitRollModifiers);
|
||||
Hooks.on('swadeRollDamage', preDamageRollModifiers);
|
||||
Hooks.on('deleteActiveEffect', powerEffectManagementHook);
|
||||
Hooks.on('visual-active-effects.createEffectButtons', visualActiveEffectPowerButtons);
|
||||
|
||||
Hooks.once('socketlib.ready', () => {
|
||||
const _socket = socketlib.registerModule('swade-mb-helpers');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user