add illusion, invisibility, intangibility

This commit is contained in:
Mike Bloy 2024-05-21 23:49:40 -05:00
parent b4fd301a4f
commit 3d6a561929
6 changed files with 276 additions and 1 deletions

View File

@ -81,6 +81,7 @@ export class PowerFormApplication extends FormApplication {
data.recipients.cost = this.powerEffect.additionalRecipientCost;
data.recipients.count = this.powerEffect.targets.length - 1;
data.recipients.total = data.recipients.cost * data.recipients.count;
data.recipients.epic = this.powerEffect.additionalRecipientsIsEpic;
}
return data;
}
@ -186,6 +187,10 @@ export class PowerEffect {
return false;
}
get additionalRecipientsIsEpic() {
return false;
}
get additionalRecipientCost() {
return 0;
}

View File

@ -0,0 +1,113 @@
import { PowerEffect } from './basePowers.js';
export class IllusionEffect extends PowerEffect {
get name() {
return 'Illusion';
}
get icon() {
return 'icons/magic/defensive/illusion-evasion-echo-purple.webp';
}
get duration() {
return this.data.duration ? 50 : 5;
}
get isTargeted() {
return false;
}
get isRaisable() {
return true;
}
get usePrimaryEffect() {
return false;
}
get basePowerPoints() {
return 5;
}
get modifiers() {
return [
{
name: 'Area of Effect',
type: 'checkbox',
value: 1,
id: 'aoe',
epic: false,
effect: false,
},
{
name: 'Deadly Illusion',
type: 'checkbox',
value: 3,
id: 'deadly',
epic: true,
effect: false,
},
{
name: 'Duration',
type: 'checkbox',
value: 2,
id: 'duration',
epic: true,
effect: false,
},
{
name: 'Mobility',
type: 'select',
default: 'none',
id: 'mobility',
choices: {
none: 'None',
12: 'Move and fly at Pace 12',
24: 'Move and fly at Pace 24',
},
values: { none: 0, 12: 1, 24: 2 },
effects: { none: null, 12: null, 24: null },
epic: false,
},
{
name: 'Sound',
id: 'sound',
type: 'checkbox',
epic: false,
effect: false,
value: 1,
},
{
name: 'Strong',
id: 'strong',
type: 'checkbox',
epic: false,
effect: false,
value: 2,
},
];
}
get description() {
const size = this.data.aoe ? 'LBT' : 'MBT';
const penalty = (this.data.raise ? -2 : 0) + (this.data.strong ? -2 : 0);
const motion = this.data.mobility === 'none' ? '(stationary)' : `that can move at pace ${this.data.mobility}`;
let text =
super.description +
`<p>
Create an illusion ${motion} ${this.data.sound ? 'with sound' : ''}.
Its effects must remain within a sphere the size of a ${size}. </p>
<p>Creatures can actively disbelieve in the illusion with a Smarts roll
${penalty === 0 ? '' : `at ${penalty}`}.</p>
`;
if (this.data.deadly) {
text += `<p>The caster can 'attack' targets while the illusion is active
with an opposed roll of the caster's arcane skill versus the target's
Smarts${penalty === 0 ? '' : ` at ${penalty}`}. If the caster wins the
target is Shaken (cannot incapacitate). With a raise, the target suffers
a Wound.</p>.
`;
}
return text;
}
}

View File

@ -0,0 +1,70 @@
import { moduleName } from '../globals.js';
import { PowerEffect } from './basePowers.js';
export class IntangibilityEffect extends PowerEffect {
get name() {
return 'Intangility';
}
get duration() {
return 5;
}
get icon() {
return 'icons/magic/control/debuff-energy-hold-levitate-blue-yellow.webp';
}
get hasAdditionalRecipients() {
return true;
}
get additionalRecipientCost() {
return 3;
}
get additionalRecipientsIsEpic() {
return true;
}
get basePowerPoints() {
return 5;
}
get isTargeted() {
return true;
}
get isRaisable() {
return true;
}
get modifiers() {
const mods = super.modifiers;
mods.push({
name: 'Duration',
type: 'checkbox',
id: 'Duration',
value: 3,
epic: true,
effect: false,
});
return mods;
}
get description() {
let text =
super.description +
`<p>
The subject becomes incorporeal. Non magical weapons and walls can't
affect him. The character may affect other incorporeal beings, and is still
susceptible to supernatural attacks. Unwilling targets resist with Spirit,
and shake off the effect with a Spirit roll at the end of following turns.</p>
<p>The being is Stunned and shunted to an open space if it is within
something solid when the power ends.</p>
`;
if (this.data.raise) {
text += '<p>Reduce damage taken from supernatural effects and magic weapons by 4.</p>';
}
return text;
}
}

View File

@ -0,0 +1,80 @@
import { moduleName } from '../globals.js';
import { PowerEffect } from './basePowers.js';
export class InvisibliltyEffect extends PowerEffect {
get name() {
return 'Invisibility';
}
get duration() {
return 5;
}
get icon() {
return 'icons/svg/invisible.svg';
}
get hasAdditionalRecipients() {
return true;
}
get additionalRecipientCost() {
return 3;
}
get basePowerPoints() {
return 5;
}
get isTargeted() {
return true;
}
get isRaisable() {
return true;
}
get modifiers() {
const mods = super.modifiers;
mods.push({
name: 'Duration',
type: 'checkbox',
id: 'Duration',
value: 2,
epic: true,
effect: false,
});
return mods;
}
get description() {
let text =
super.description +
`
<p>The subject is invisible, except for a vague blur or outline.
Any action taken against it that requires sight is made at
${this.data.raise ? -6 : -4}, including Notice rolls. This penalty is
reduced by 2 if the invisible character's position is given away by some
environmental circumstance.</p>
`;
if (this.data.duration) {
text += `<p>This long-duration invisibility ends immediately if the subject
attempts a damage-causing attack or targets an unwilling character with a
power.</p>`;
}
return text;
}
async parseValues() {
await super.parseValues();
const doc = await PowerEffect.getStatus('EFFECT.StatusInvisible', 'Invisible');
doc.description = `<p>From <strong>${this.source.name}</strong> casting <em>${this.name}</em></p>`;
doc.flags = mergeObject(doc.flags ?? {}, { [moduleName]: { powerEffect: true } });
(doc.duration = { rounds: 99 }), (this.baseEffectDoc = doc);
this.basePrimaryEffectDoc = doc;
}
get basePrimaryEffect() {
return this.basePrimaryEffectDoc;
}
}

View File

@ -31,6 +31,9 @@ import { FlyEffect } from './fly.js';
import { GrowthShrinkEffect } from './growthShrink.js';
import { HavocEffect } from './havoc.js';
import { HealingEffect } from './healing.js';
import { IllusionEffect } from './illusion.js';
import { IntangibilityEffect } from './intangibility.js';
import { InvisibliltyEffect } from './invisibility.js';
const PowerClasses = {
'arcane-protection': ArcaneProtectionEffect,
@ -71,6 +74,9 @@ const PowerClasses = {
growthshrink: GrowthShrinkEffect,
havoc: HavocEffect,
healing: HealingEffect,
illusion: IllusionEffect,
intangibility: IntangibilityEffect,
invisibility: InvisibliltyEffect,
'lower-trait': BoostLowerTraitEffect,
shrink: GrowthShrinkEffect,
};

View File

@ -19,7 +19,8 @@
<strong>Targets</strong>:
{{#each targets}}{{#if @index}}, {{/if}}{{this}}{{/each}}
{{#if recipients.cost}}
<br>(Additional Recipients {{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
<br>({{#if recipients.epic}}⭐ {{/if}}Additional Recipients
{{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
{{/if}}
</p>
{{/if}}