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() {
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() {
@ -51,7 +51,7 @@ export class ArcaneProtectionEffect extends PowerEffect {
}
get effectName() {
const greater = this.data.mods.has('greater');
const greater = this.data.greater;
const raise = this.data.raise;
const amount = this._penaltyAmount;
return `${greater ? 'Greater ' : ''}Arcane Protection (${raise ? 'major, ' : ''}${amount})`;

View File

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

View File

@ -6,17 +6,33 @@
<p>Apply the affects of {{name}}.</p>
</section>
</header>
{{#if targets.length}}
<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>
{{/if}}
{{#each modifiers}}
<div class="form-group">
{{#if isCheckbox}}
<input type="checkbox" name="{{id}}" {{checked default}} />
<label for="{{id}}">{{#if epic}}⭐ {{/if}}{{name}} ({{numberFormat value decimals=0 sign=true}})</label>
{{/if}} {{#if isRadio}}
<label>{{#if epic}}⭐ {{/if}}{{name}}:</label>
{{radioBoxes id choices checked=default}} {{/if}}
<input type="checkbox" name="{{id}}" {{checked default}} />
<label for="{{id}}">
{{#if epic}}⭐ {{/if}}{{name}} ({{numberFormat value decimals=0 sign=true}})
</label>
{{/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>
{{/each}}
<footer class="sheet-footer flexrow">