finish base power overhaul

This commit is contained in:
Mike Bloy 2024-05-12 23:19:36 -05:00
parent c8f27770b6
commit b5b0ad01f6
3 changed files with 100 additions and 119 deletions

View File

@ -40,7 +40,7 @@ export class ArcaneProtectionEffect extends PowerEffect {
} }
get _penaltyAmount() { get _penaltyAmount() {
return (this.data.raise ? -4 : -2) + (this.data.mods.has('greater') ? -2 : 0); return (this.data.raise ? -4 : -2) + (this.data.greater ? -2 : 0);
} }
get description() { get description() {
@ -51,7 +51,7 @@ export class ArcaneProtectionEffect extends PowerEffect {
} }
get effectName() { get effectName() {
const greater = this.data.mods.has('greater'); const greater = this.data.greater;
const raise = this.data.raise; const raise = this.data.raise;
const amount = this._penaltyAmount; const amount = this._penaltyAmount;
return `${greater ? 'Greater ' : ''}Arcane Protection (${raise ? 'major, ' : ''}${amount})`; return `${greater ? 'Greater ' : ''}Arcane Protection (${raise ? 'major, ' : ''}${amount})`;

View File

@ -58,19 +58,31 @@ export class PowerFormApplication extends FormApplication {
icon: this.powerEffect.icon, icon: this.powerEffect.icon,
basePowerPoints: this.powerEffect.basePowerPoints, basePowerPoints: this.powerEffect.basePowerPoints,
modifiers, modifiers,
additionalRecipientCost: 0, recipients: {
cost: 0,
number: 0,
total: 0,
},
targets: [], targets: [],
buttons: this.powerEffect.menuButtons, buttons: this.powerEffect.menuButtons,
}; };
if (this.powerEffect.isTargeted) { if (this.powerEffect.isTargeted) {
data.targets = this.powerEffect.targets.map((t) => t.name); data.targets = this.powerEffect.targets.map((t) => t.name);
} }
if (this.powerEffect.hasAdditionalRecipients && this.powerEffect.targets.length > 1) {
data.recipients.cost = this.powerEffect.additionalRecipientCost;
data.recipients.count = this.powerEffect.targets.length - 1;
data.recipients.total = data.recipients.cost * data.recipients.count;
}
return data; return data;
} }
async _updateObject(ev, formData) { async _updateObject(ev, formData) {
formData.submit = ev?.submitter?.value ?? 'cancel'; formData.submit = ev?.submitter?.value ?? 'cancel';
console.log(ev, formData); if (formData.submit !== 'cancel') {
this.powerEffect.formData = formData;
await this.powerEffect.applyEffect();
}
} }
} }
@ -218,6 +230,7 @@ export class PowerEffect {
effects: { effects: {
none: null, none: null,
glow: { glow: {
name: 'Glow',
icon: 'icons/magic/light/orb-shadow-blue.webp', icon: 'icons/magic/light/orb-shadow-blue.webp',
changes: [ changes: [
{ {
@ -229,6 +242,7 @@ export class PowerEffect {
], ],
}, },
shroud: { shroud: {
name: 'Shroud',
icon: 'icons/magic/perception/shadow-stealth-eyes-purple.webp', icon: 'icons/magic/perception/shadow-stealth-eyes-purple.webp',
changes: [ changes: [
{ {
@ -244,6 +258,17 @@ export class PowerEffect {
effect: true, effect: true,
}); });
if (this.isDamaging) { if (this.isDamaging) {
mods.push({
name: 'Armor Piercing',
id: 'ap',
type: 'select',
default: 'none',
choices: { none: 'None', 2: 'AP 2', 4: 'AP 4', 6: 'AP 6' },
values: { none: 0, 2: 1, 4: 2, 6: 3 },
effects: { none: null, 2: null, 4: null, 6: null },
epic: false,
isGlobal: true,
});
mods.push({ mods.push({
name: 'Lingering Damage', name: 'Lingering Damage',
id: 'lingeringdamage', id: 'lingeringdamage',
@ -269,7 +294,7 @@ export class PowerEffect {
name: 'Hinder/Hurry', name: 'Hinder/Hurry',
id: 'hinderhurry', id: 'hinderhurry',
type: 'radio', type: 'radio',
default: false, default: 'none',
value: 1, value: 1,
epic: false, epic: false,
effect: true, effect: true,
@ -279,6 +304,7 @@ export class PowerEffect {
effects: { effects: {
none: null, none: null,
hinder: { hinder: {
name: 'Hinder',
icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp', icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
changes: [ changes: [
{ {
@ -290,6 +316,7 @@ export class PowerEffect {
], ],
}, },
hurry: { hurry: {
name: 'Hurry',
icon: 'icons/skills/movement/feet-winged-sandals-tan.webp', icon: 'icons/skills/movement/feet-winged-sandals-tan.webp',
changes: [ changes: [
{ {
@ -314,59 +341,25 @@ export class PowerEffect {
isGlobal: true, isGlobal: true,
}); });
} }
return mods; mods.push({
}
get menuData() {
return {
inputs: this.menuInputs,
buttons: this.menuButtons,
};
}
get menuInputs() {
const inputs = [
{ type: 'header', label: `${this.name} Effect` },
{
type: 'info',
label: `Apply ${this.name} Effect (base cost ${this.basePowerPoints} pp)`,
},
];
if (this.isTargeted) {
let label = `<strong>Targets:</strong> ${this.targets.map((t) => t.name).join(',')}`;
if (this.targets.length > 1 && this.hasAdditionalRecipients) {
label += ` (${this.targets.length - 1} additional recipients ` + `+${this.additionalRecipientCost} ea.)`;
}
inputs.push({ type: 'info', label });
}
for (const mod of this.modifiers) {
inputs.push({
type: 'checkbox',
label: `${mod.epic ? '⭐ ' : ''}${mod.name} ` + `(${mod.value >= 0 ? '+' : ''}${mod.value})`,
});
}
if (this.isDamaging) {
inputs.push({
type: 'select',
label: 'Armor Piercing',
options: [
{ html: 'None', value: 0, selected: true },
{ html: 'AP 2 (+1)', value: 1, selected: false },
{ html: 'AP 4 (+2)', value: 2, selected: false },
{ html: 'AP 6 (+3)', value: 3, selected: false },
],
});
}
inputs.push({
type: 'select', type: 'select',
label: 'Range', default: 0,
options: [ name: 'Range',
{ html: 'Normal Range', value: 0, selected: true }, id: 'range',
{ html: 'Range ×2 (+1)', value: 1, selected: false }, choices: {
{ html: 'Range ×3 (+2)', value: 2, selected: false }, normal: 'Normal Range',
], x2: 'Range ×2',
x3: 'Range ×3',
},
values: {
normal: 0,
x2: 1,
x3: 2,
},
isGlobal: true,
effects: { normal: null, x2: null, x3: null },
}); });
return inputs; return mods;
} }
get menuButtons() { get menuButtons() {
@ -379,62 +372,33 @@ export class PowerEffect {
return data; return data;
} }
get menuOptions() {
return {
title: `${this.name} Effect`,
defaultButton: 'Cancel',
options: {},
};
}
render() { render() {
let app = new PowerFormApplication(this).render(true); let app = new PowerFormApplication(this).render(true);
} }
async applyEffect() { async applyEffect() {
log('Power Effect called'); await this.parseValues();
log(this); await this.apply();
} await this.sideEffects();
async powerEffect() {
const { buttons, inputs } = await warpgate.menu(this.menuData, this.menuOptions);
if (buttons && buttons !== 'cancel') {
this.data.button = buttons;
this.data.values = inputs;
await this.parseValues();
await this.apply();
await this.sideEffects();
await this.chatMessage();
}
} }
async parseValues() { async parseValues() {
this.data.rawValues = deepClone(this.data.values); this.data.raise = this.formData.submit === 'raise';
this.data.raise = this.data.button === 'raise'; this.data.button = this.formData.submit;
for (let i = 0; i < 2; i++) {
this.data.values.shift();
}
if (this.isTargeted) {
this.data.values.shift();
}
this.data.mods = new Set();
for (const mod of this.modifiers) { for (const mod of this.modifiers) {
const modEnabled = this.data.values.shift(); this.data[mod.id] = this.formData[mod.id];
if (modEnabled) {
this.data.mods.add(mod.id);
}
} }
if (this.isDamaging) {
this.data.armorPiercing = this.data.values.shift();
}
this.data.range = this.data.values.shift();
} }
async createSecondaryEffects(maintId) { async createSecondaryEffects(maintId) {
const docs = []; const docs = [];
for (const mod of this.modifiers) { for (const mod of this.modifiers) {
if (this.data.mods.has(mod.id) && mod.effect) { const modValue = this.data[mod.id];
const doc = this.createEffectDocument(mod.icon, mod.name, mod.changes); if (modValue && (mod?.effect || (mod?.effects?.[modValue] ?? false))) {
const icon = 'effects' in mod ? mod.effects[modValue].icon : mod.icon;
const name = 'effects' in mod ? mod.effects[modValue].name : mod.name;
const changes = 'effects' in mod ? mod.effects[modValue].changes : mod.changes;
const doc = this.createEffectDocument(icon, name, changes);
if (this.duration === 0 && !this.usePrimaryEffect) { if (this.duration === 0 && !this.usePrimaryEffect) {
// set secondary effects of instant spells to expire on victim's next // set secondary effects of instant spells to expire on victim's next
// turn // turn
@ -524,7 +488,7 @@ export class PowerEffect {
} }
async sideEffects() { async sideEffects() {
if (this.data.mods.has('fatigue') && this.isTargeted) { if (this.data.fatigue && this.isTargeted) {
for (const target of this.targets) { for (const target of this.targets) {
const actor = target.actor; const actor = target.actor;
const update = { const update = {
@ -544,17 +508,18 @@ export class PowerEffect {
get powerPoints() { get powerPoints() {
let total = this.basePowerPoints; let total = this.basePowerPoints;
for (const mod of this.modifiers) { for (const mod of this.modifiers) {
if (this.data.mods.has(mod.id)) { const modValue = this.data[mod.id];
total += mod.value; if (modValue) {
if ('values' in mod) {
total += mod.values[modValue];
} else {
total += mod.value;
}
} }
} }
if (this.targets.length > 1 && this.hasAdditionalRecipients) { if (this.targets.length > 1 && this.hasAdditionalRecipients) {
total += (this.targets.length - 1) * this.additionalRecipientCost; total += (this.targets.length - 1) * this.additionalRecipientCost;
} }
total += this.data.range;
if (this.isDamaging) {
total += this.data.armorPiercing;
}
return total; return total;
} }
@ -563,26 +528,26 @@ export class PowerEffect {
if (this.hasAdditionalRecipients && this.targets.length > 1) { if (this.hasAdditionalRecipients && this.targets.length > 1) {
list.push(`${this.targets.length - 1} Additional Recipients`); list.push(`${this.targets.length - 1} Additional Recipients`);
} }
if (this.data.mods.has('adaptable')) { if (this.data.adaptable) {
list.push('Different Trapping (Adaptable Caster)'); list.push('Different Trapping (Adaptable Caster)');
} }
if (this.data.mods.has('fatigue')) { if (this.data.fatigue) {
list.push('Fatigue (applied to targets'); list.push('Fatigue (applied to targets');
} }
if (this.data.mods.has('heavyweapon')) { if (this.data.heavyweapon) {
list.push('Heavy Weapon'); list.push('Heavy Weapon');
} }
if (this.data.mods.has('lingeringdamage')) { if (this.data.lingeringdamage) {
list.push('Lingering Damage'); list.push('Lingering Damage');
} }
if (this.data.mods.has('selective')) { if (this.data.selective) {
list.push('Selective'); list.push('Selective');
} }
if (this.isDamaging && this.data.armorPiercing > 0) { if (this.isDamaging && this.data.ap > 0) {
list.push(`AP ${this.data.armorPiercing * 2}`); list.push(`AP ${this.data.ap}`);
} }
if (this.data.range > 0) { if (this.data.range != 'none') {
list.push(`Range ×${this.data.range + 1}`); list.push(`Range ${this.data.range}`);
} }
return list; return list;
} }

View File

@ -6,17 +6,33 @@
<p>Apply the affects of {{name}}.</p> <p>Apply the affects of {{name}}.</p>
</section> </section>
</header> </header>
{{#if targets.length}}
<p> <p>
{{#if targets.length}} <strong>Targets</strong>: {{#each targets}}{{#if @index}}, {{/if}}{{this}}{{/each}} {{/if}} <strong>Targets</strong>:
{{#each targets}}{{#if @index}}, {{/if}}{{this}}{{/each}}
{{#if recipients.cost}}
<br>(Additional Recipients {{recipients.cost}}pp each × {{recipients.count}} = {{recipients.total}})
{{/if}}
</p> </p>
{{/if}}
{{#each modifiers}} {{#each modifiers}}
<div class="form-group"> <div class="form-group">
{{#if isCheckbox}} {{#if isCheckbox}}
<input type="checkbox" name="{{id}}" {{checked default}} /> <input type="checkbox" name="{{id}}" {{checked default}} />
<label for="{{id}}">{{#if epic}}⭐ {{/if}}{{name}} ({{numberFormat value decimals=0 sign=true}})</label> <label for="{{id}}">
{{/if}} {{#if isRadio}} {{#if epic}}⭐ {{/if}}{{name}} ({{numberFormat value decimals=0 sign=true}})
<label>{{#if epic}}⭐ {{/if}}{{name}}:</label> </label>
{{radioBoxes id choices checked=default}} {{/if}} {{/if}}
{{#if isSelect}}
<label>{{#if epic}}⭐ {{/if}}{{name}}:</label>
<select name="{{id}}">
{{selectOptions choices selected=default}}
</select>
{{/if}}
{{#if isRadio}}
<label>{{#if epic}}⭐ {{/if}}{{name}}:</label>
{{radioBoxes id choices checked=default}}
{{/if}}
</div> </div>
{{/each}} {{/each}}
<footer class="sheet-footer flexrow"> <footer class="sheet-footer flexrow">