burrow and boost lower trait
This commit is contained in:
parent
cf30214502
commit
f50a81a329
@ -25,12 +25,12 @@ export class PowerFormApplication extends FormApplication {
|
||||
if (a.isGlobal !== b.isGlobal) {
|
||||
return a.isGlobal ? -1 : 1;
|
||||
}
|
||||
if (a.type !== b.type) {
|
||||
return a.type === 'checkbox' ? -1 : 1;
|
||||
}
|
||||
if ((a.sortOrder ?? 0) !== (b.sortOrder ?? 0)) {
|
||||
return (a.sortOrder ?? 0) < (b.sortOrder ?? 0) ? -1 : 1;
|
||||
}
|
||||
if (a.type !== b.type) {
|
||||
return a.type === 'checkbox' ? -1 : 1;
|
||||
}
|
||||
return a.name === b.name ? 0 : a.name < b.name ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
204
src/module/powers/boostLowerTrait.js
Normal file
204
src/module/powers/boostLowerTrait.js
Normal file
@ -0,0 +1,204 @@
|
||||
import { moduleName } from '../globals.js';
|
||||
import { PowerEffect } from './basePowers.js';
|
||||
|
||||
export class BoostLowerTraitEffect extends PowerEffect {
|
||||
get name() {
|
||||
return 'Boost/Lower Trait';
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get additionalRecipientCost() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this?.data?.direction === 'Boost'
|
||||
? 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
|
||||
: 'icons/magic/movement/chevrons-down-yellow.webp';
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this?.data?.direction === 'Boost' ? 5 : 0;
|
||||
}
|
||||
|
||||
get isTargeted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get basePowerPoints() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
getPrimaryEffectChanges() {
|
||||
let modValue = '2';
|
||||
if (this.data.raise) {
|
||||
modValue = '4';
|
||||
}
|
||||
modValue = (this.data.direction === 'Boost' ? '+' : '-') + modValue;
|
||||
const changes = [
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
},
|
||||
];
|
||||
if (this.data.direction === 'Lower' && this.data.greater) {
|
||||
changes.push({
|
||||
key: this.data.trait.modkey,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
value: -2,
|
||||
priority: 0,
|
||||
});
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
async createSecondaryEffects(maintId) {
|
||||
const docs = await super.createSecondaryEffects(maintId);
|
||||
if (this.data.raise && this.data.direction === 'Lower') {
|
||||
const name = 'major ' + this.effectName;
|
||||
const modValue = this.data.direction === 'Boost' ? '+2' : '-2';
|
||||
const changes = [
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
},
|
||||
];
|
||||
const doc = this.createEffectDocument(this.icon, name, changes);
|
||||
doc.duration.seconds = 594;
|
||||
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
|
||||
doc.flags[moduleName].maintId = maintId;
|
||||
docs.push(doc);
|
||||
}
|
||||
return docs;
|
||||
}
|
||||
|
||||
get effectName() {
|
||||
let name = `${this.data.direction} ${this.data.trait.name}`;
|
||||
const nameMods = [];
|
||||
if (this.data.greater) {
|
||||
nameMods.push('Greater');
|
||||
}
|
||||
if (this.data.direction === 'Lower' && this.data.strong) {
|
||||
nameMods.push('Strong');
|
||||
}
|
||||
if (nameMods.length > 0) {
|
||||
name += ` (${nameMods.join(', ')})`;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
get description() {
|
||||
let desc = super.description;
|
||||
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' : ''}`;
|
||||
desc += `<p>${this.data.direction === 'Boost' ? 'Raise' : 'Lower'} the
|
||||
target's ${this.data.trait.name} die type ${amount}.`;
|
||||
if (this.data.greater) {
|
||||
if (this.data.direction === 'Boost') {
|
||||
desc += ` Additionally, the target gains a free ${this.data.trait.name}
|
||||
reroll once per ${this.data.raise ? 'action' : 'round'}.`;
|
||||
} else {
|
||||
desc += ` Additionally, the target suffers a -2 penalty to their
|
||||
${this.data.trait.name} rolls.`;
|
||||
}
|
||||
}
|
||||
desc += '</p>';
|
||||
if (this.data.direction === 'Lower') {
|
||||
desc += `<p>At the end of the target's following turns, they attempt to shake off
|
||||
the affect with a Spirit${this.data.strong ? ' -2' : ''}
|
||||
roll as a free action. Success reduces the effect one die type. A raise
|
||||
completely shakes off the effect.</p>`;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
const mods = super.modifiers;
|
||||
let traitOptions = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor'];
|
||||
const allSkills = new Set();
|
||||
const traits = {};
|
||||
for (const traitName of traitOptions) {
|
||||
const lower = traitName.toLowerCase();
|
||||
traits[traitName] = {
|
||||
name: traitName,
|
||||
type: 'attribute',
|
||||
modkey: `system.attributes.${lower}.die.modifier`,
|
||||
diekey: `system.attributes.${lower}.die.sides`,
|
||||
};
|
||||
}
|
||||
for (const token of this.targets) {
|
||||
const skills = token.actor.items.filter((item) => item.type === 'skill');
|
||||
for (const skill of skills) {
|
||||
const name = skill.name;
|
||||
traits[name] = {
|
||||
name,
|
||||
type: 'skill',
|
||||
modkey: `@Skill{${name}}[system.die.modifier]`,
|
||||
diekey: `@Skill{${name}}[system.die.sides]`,
|
||||
};
|
||||
if (name !== 'Unskilled') {
|
||||
allSkills.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
traitOptions = traitOptions.concat(Array.from(allSkills).sort());
|
||||
const traitChoices = {};
|
||||
const traitValues = {};
|
||||
const traitEffects = {};
|
||||
for (const trait of traitOptions) {
|
||||
traitChoices[trait] = trait;
|
||||
traitValues[trait] = 0;
|
||||
traitEffects[trait] = null;
|
||||
}
|
||||
this.data.traits = traits;
|
||||
mods.push({
|
||||
sortOrder: -2,
|
||||
name: 'Boost or Lower?',
|
||||
id: 'direction',
|
||||
type: 'radio',
|
||||
default: 'Boost',
|
||||
epic: false,
|
||||
choices: { Boost: 'Boost', Lower: 'Lower' },
|
||||
effects: { Boost: null, Lower: null },
|
||||
values: { Boost: 0, Lower: 0 },
|
||||
});
|
||||
mods.push({
|
||||
sortOrder: -1,
|
||||
name: 'Trait',
|
||||
id: 'traitName',
|
||||
type: 'select',
|
||||
epic: false,
|
||||
choices: traitChoices,
|
||||
values: traitValues,
|
||||
effects: traitEffects,
|
||||
});
|
||||
mods.push({
|
||||
name: 'Greater Boost/Lower Trailt',
|
||||
type: 'checkbox',
|
||||
value: 2,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false,
|
||||
});
|
||||
mods.push({
|
||||
name: 'Strong (lower only)',
|
||||
type: 'checkbox',
|
||||
value: 1,
|
||||
id: 'strong',
|
||||
epic: false,
|
||||
effect: false,
|
||||
});
|
||||
return mods;
|
||||
}
|
||||
|
||||
async parseValues() {
|
||||
await super.parseValues();
|
||||
this.data.trait = this.data.traits[this.data.traitName];
|
||||
}
|
||||
}
|
||||
58
src/module/powers/burrow.js
Normal file
58
src/module/powers/burrow.js
Normal file
@ -0,0 +1,58 @@
|
||||
import { PowerEffect } from './basePowers.js';
|
||||
|
||||
export class BurrowEffect extends PowerEffect {
|
||||
get name() {
|
||||
return 'Burrow';
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return 'icons/magic/earth/projectile-stone-landslide.webp';
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get additionalRecipientCost() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get basePowerPoints() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get isTargeted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
const mods = super.modifiers;
|
||||
mods.push({
|
||||
name: 'Power',
|
||||
type: 'checkbox',
|
||||
id: 'power',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false,
|
||||
});
|
||||
return mods;
|
||||
}
|
||||
|
||||
get effectName() {
|
||||
return `${this.name} ${this.data.power ? '[Power] ' : ''}` + `(${this.data.raise ? 'full' : 'half'} pace)`;
|
||||
}
|
||||
|
||||
get description() {
|
||||
let text =
|
||||
super.description +
|
||||
`<p>Meld into the ground. Move at ${this.data.raise ? 'full' : 'half'} pace. May not run.</p>`;
|
||||
if (this.data.power) {
|
||||
text += '<p>Can <em>burrow</em> through solid stone, concrete, etc</p>';
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@ -8,251 +8,8 @@ import { BeastFriendEffect } from './beastFriend.js';
|
||||
import { BlastEffect } from './blast.js';
|
||||
import { BlindEffect } from './blind.js';
|
||||
import { BoltEffect } from './bolt.js';
|
||||
|
||||
class BurrowEffect extends PowerEffect {
|
||||
get name() {
|
||||
return 'Burrow';
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return 'icons/magic/earth/projectile-stone-landslide.webp';
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get additionalRecipientCost() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get basePowerPoints() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get isTargeted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
const mods = super.modifiers;
|
||||
mods.push({
|
||||
name: 'Power',
|
||||
id: 'power',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false,
|
||||
});
|
||||
return mods;
|
||||
}
|
||||
|
||||
get effectName() {
|
||||
return (
|
||||
`${this.name} ${this.data.mods.has('power') ? '[Power] ' : ''}` + `(${this.data.raise ? 'full' : 'half'} pace)`
|
||||
);
|
||||
}
|
||||
|
||||
get description() {
|
||||
let text =
|
||||
super.description +
|
||||
`<p>Meld into the ground. Move at ${this.data.raise ? 'full' : 'half'} pace. May not run.</p>`;
|
||||
if (this.data.mods.has('power')) {
|
||||
text += '<p>Can <em>burrow</em> through solid stone, concrete, etc</p>';
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
class BoostLowerTraitEffect extends PowerEffect {
|
||||
get name() {
|
||||
return 'Boost/Lower Trait';
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get additionalRecipientCost() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this?.data?.direction === 'Boost'
|
||||
? 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
|
||||
: 'icons/magic/movement/chevrons-down-yellow.webp';
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this?.data?.direction === 'Boost' ? 5 : 0;
|
||||
}
|
||||
|
||||
get isTargeted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get basePowerPoints() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
getPrimaryEffectChanges() {
|
||||
let modValue = '2';
|
||||
if (this.data.raise && this.data.direction === 'Boost') {
|
||||
modValue = '4';
|
||||
}
|
||||
modValue = (this.data.direction === 'Boost' ? '+' : '-') + modValue;
|
||||
const changes = [
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
},
|
||||
];
|
||||
if (this.data.direction === 'Lower' && this.data.mods.has('greater')) {
|
||||
changes.push({
|
||||
key: this.data.trait.modkey,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
value: -2,
|
||||
priority: 0,
|
||||
});
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
async createSecondaryEffects(maintId) {
|
||||
const docs = await super.createSecondaryEffects(maintId);
|
||||
if (this.data.raise && this.data.direction === 'Lower') {
|
||||
const name = 'major ' + this.effectName;
|
||||
const modValue = this.data.direction === 'Boost' ? '+2' : '-2';
|
||||
const changes = [
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
},
|
||||
];
|
||||
const doc = this.createEffectDocument(this.icon, name, changes);
|
||||
doc.duration.seconds = 594;
|
||||
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
|
||||
doc.flags[moduleName].maintId = maintId;
|
||||
docs.push(doc);
|
||||
}
|
||||
return docs;
|
||||
}
|
||||
|
||||
get effectName() {
|
||||
let name = `${this.data.direction} ${this.data.trait.name}`;
|
||||
const nameMods = [];
|
||||
if (this.data.mods.has('greater')) {
|
||||
nameMods.push('Greater');
|
||||
}
|
||||
if (this.data.direction === 'Lower' && this.data.mods.has('strong')) {
|
||||
nameMods.push('Strong');
|
||||
}
|
||||
if (nameMods.length > 0) {
|
||||
name += ` (${nameMods.join(', ')})`;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
get description() {
|
||||
let desc = super.description;
|
||||
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' : ''}`;
|
||||
desc += `<p>${this.data.direction === 'Boost' ? 'Raise' : 'Lower'} the
|
||||
target's ${this.data.trait.name} die type ${amount}.`;
|
||||
if (this.data.mods.has('greater')) {
|
||||
if (this.data.direction === 'Boost') {
|
||||
desc += ` Additionally, the target gains a free ${this.data.trait.name}
|
||||
reroll once per ${this.data.raise ? 'action' : 'round'}.`;
|
||||
} else {
|
||||
desc += ` Additionally, the target suffers a -2 penalty to their
|
||||
${this.data.trait.name} rolls.`;
|
||||
}
|
||||
}
|
||||
desc += '</p>';
|
||||
if (this.data.direction === 'Lower') {
|
||||
desc += `<p>At the end of the target's following turns, they attempt to shake off
|
||||
the affect with a Spirit${this.data.mods.has('strong') ? ' -2' : ''}
|
||||
roll as a free action. Success reduces the effect one die type. A raise
|
||||
completely shakes off the effect.</p>`;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
const mods = super.modifiers;
|
||||
mods.push({
|
||||
name: 'Greater Boost/Lower Trailt',
|
||||
value: 2,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false,
|
||||
});
|
||||
mods.push({
|
||||
name: 'Strong (lower only)',
|
||||
value: 1,
|
||||
id: 'strong',
|
||||
epic: false,
|
||||
effect: false,
|
||||
});
|
||||
return mods;
|
||||
}
|
||||
|
||||
get menuInputs() {
|
||||
const inputs = super.menuInputs;
|
||||
let traitOptions = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor'];
|
||||
const allSkills = new Set();
|
||||
const traits = {};
|
||||
for (const traitName of traitOptions) {
|
||||
const lower = traitName.toLowerCase();
|
||||
traits[traitName] = {
|
||||
name: traitName,
|
||||
type: 'attribute',
|
||||
modkey: `system.attributes.${lower}.die.modifier`,
|
||||
diekey: `system.attributes.${lower}.die.sides`,
|
||||
};
|
||||
}
|
||||
for (const token of this.targets) {
|
||||
const skills = token.actor.items.filter((item) => item.type === 'skill');
|
||||
for (const skill of skills) {
|
||||
const name = skill.name;
|
||||
traits[name] = {
|
||||
name,
|
||||
type: 'skill',
|
||||
modkey: `@Skill{${name}}[system.die.modifier]`,
|
||||
diekey: `@Skill{${name}}[system.die.sides]`,
|
||||
};
|
||||
if (name !== 'Unskilled') {
|
||||
allSkills.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
traitOptions = traitOptions.concat(Array.from(allSkills).sort());
|
||||
this.data.traits = traits;
|
||||
inputs.push({ type: 'select', label: 'Trait', options: traitOptions });
|
||||
inputs.push({ type: 'info', label: 'Boost or Lower?' });
|
||||
inputs.push({ type: 'radio', label: 'Boost', options: ['isBoost', true] });
|
||||
inputs.push({ type: 'radio', label: 'Lower', options: ['isBoost', false] });
|
||||
return inputs;
|
||||
}
|
||||
|
||||
async parseValues() {
|
||||
await super.parseValues();
|
||||
this.data.trait = this.data.traits[this.data.values.shift()];
|
||||
this.data.values.shift();
|
||||
this.data.direction = this.data.values.shift() ? 'Boost' : 'Lower';
|
||||
}
|
||||
|
||||
get powerPoints() {
|
||||
const total = super.powerPoints;
|
||||
return total;
|
||||
}
|
||||
}
|
||||
import { BurrowEffect } from './burrow.js';
|
||||
import { BoostLowerTraitEffect } from './boostLowerTrait.js';
|
||||
|
||||
class BurstEffect extends PowerEffect {
|
||||
get name() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user