mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 16:09:03 +01:00
Action Refactor Part #2
This commit is contained in:
parent
479e147640
commit
9da6a13009
20 changed files with 324 additions and 340 deletions
|
|
@ -3,3 +3,4 @@ export { default as FormulaField } from './formulaField.mjs';
|
|||
export { default as ForeignDocumentUUIDField } from './foreignDocumentUUIDField.mjs';
|
||||
export { default as ForeignDocumentUUIDArrayField } from './foreignDocumentUUIDArrayField.mjs';
|
||||
export { default as MappingField } from './mappingField.mjs';
|
||||
export * as ActionFields from './action/_module.mjs';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ export { default as CostField } from './costField.mjs';
|
|||
export { default as UsesField } from './usesField.mjs';
|
||||
export { default as RangeField } from './rangeField.mjs';
|
||||
export { default as TargetField } from './targetField.mjs';
|
||||
export { default as EffectField } from './effectField.mjs';
|
||||
export { default as EffectsField } from './effectsField.mjs';
|
||||
export { default as SaveField } from './saveField.mjs';
|
||||
export { default as BeastformField } from './beastformField.mjs';
|
||||
export { default as BeastformField } from './beastformField.mjs';
|
||||
export { default as DamageField } from './damageField.mjs';
|
||||
export { default as HealingField } from './healingField.mjs';
|
||||
export { default as RollField } from './rollField.mjs';
|
||||
|
|
@ -15,4 +15,68 @@ export default class CostField extends fields.ArrayField {
|
|||
});
|
||||
super(element, options, context);
|
||||
}
|
||||
|
||||
static prepareConfig(config) {
|
||||
const costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : [];
|
||||
config.costs = CostField.calcCosts.call(this, costs);
|
||||
const hasCost = CostField.hasCost.call(this, config.costs);
|
||||
if(config.isFastForward && !hasCost)
|
||||
return ui.notifications.warn("You don't have the resources to use that action.");
|
||||
return hasCost;
|
||||
}
|
||||
|
||||
static calcCosts(costs) {
|
||||
return costs.map(c => {
|
||||
c.scale = c.scale ?? 1;
|
||||
c.step = c.step ?? 1;
|
||||
c.total = c.value * c.scale * c.step;
|
||||
c.enabled = c.hasOwnProperty('enabled') ? c.enabled : true;
|
||||
return c;
|
||||
});
|
||||
}
|
||||
|
||||
static hasCost(costs) {
|
||||
const realCosts = CostField.getRealCosts.call(this, costs),
|
||||
hasFearCost = realCosts.findIndex(c => c.key === 'fear');
|
||||
if (hasFearCost > -1) {
|
||||
const fearCost = realCosts.splice(hasFearCost, 1)[0];
|
||||
if (
|
||||
!game.user.isGM ||
|
||||
fearCost.total > game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* isReversed is a sign that the resource is inverted, IE it counts upwards instead of down */
|
||||
const resources = CostField.getResources.call(this, realCosts);
|
||||
return realCosts.reduce(
|
||||
(a, c) =>
|
||||
a && resources[c.key].isReversed
|
||||
? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max
|
||||
: resources[c.key]?.value >= (c.total ?? c.value),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
static getResources(costs) {
|
||||
const actorResources = this.actor.system.resources;
|
||||
const itemResources = {};
|
||||
for (var itemResource of costs) {
|
||||
if (itemResource.keyIsID) {
|
||||
itemResources[itemResource.key] = {
|
||||
value: this.parent.resource.value ?? 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...actorResources,
|
||||
...itemResources
|
||||
};
|
||||
}
|
||||
|
||||
static getRealCosts(costs) {
|
||||
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
||||
return realCosts;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import FormulaField from "../formulaField.mjs";
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
export default class DamageField extends fields.SchemaField {
|
||||
constructor(options, context = {}) {
|
||||
const damageFields = {
|
||||
parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)),
|
||||
includeBase: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.includeBase.label'
|
||||
})
|
||||
};
|
||||
super(damageFields, options, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class DHActionDiceData extends foundry.abstract.DataModel {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
multiplier: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.multiplierTypes,
|
||||
initial: 'prof',
|
||||
label: 'Multiplier'
|
||||
}),
|
||||
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
dice: new fields.StringField({ choices: CONFIG.DH.GENERAL.diceTypes, initial: 'd6', label: 'Dice' }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
|
||||
custom: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({ label: 'Custom Formula' }),
|
||||
formula: new FormulaField({ label: 'Formula' })
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
getFormula() {
|
||||
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`,
|
||||
bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : '';
|
||||
return this.custom.enabled ? this.custom.formula : `${multiplier ?? 1}${this.dice}${bonus}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class DHResourceData extends foundry.abstract.DataModel {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
applyTo: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.healingTypes,
|
||||
required: true,
|
||||
blank: false,
|
||||
initial: CONFIG.DH.GENERAL.healingTypes.hitPoints.id,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.applyTo.label'
|
||||
}),
|
||||
resultBased: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.resultBased.label'
|
||||
}),
|
||||
value: new fields.EmbeddedDataField(DHActionDiceData),
|
||||
valueAlt: new fields.EmbeddedDataField(DHActionDiceData)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DHDamageData extends DHResourceData {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }),
|
||||
type: new fields.SetField(
|
||||
new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.damageTypes,
|
||||
initial: 'physical',
|
||||
nullable: false,
|
||||
required: true
|
||||
}),
|
||||
{
|
||||
label: 'Type'
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
export default class EffectField extends fields.ArrayField {
|
||||
export default class EffectsField extends fields.ArrayField {
|
||||
constructor(options={}, context={}) {
|
||||
const element = new fields.SchemaField({
|
||||
_id: new fields.DocumentIdField(),
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { DHDamageData } from "./damageField.mjs";
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
export default class HealingField extends fields.EmbeddedDataField {
|
||||
constructor(options, context = {}) {
|
||||
super(DHDamageData, options, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,4 +9,6 @@ export default class RangeField extends fields.StringField {
|
|||
};
|
||||
super(options, context);
|
||||
}
|
||||
|
||||
static prepareConfig(config) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
export class DHActionRollData extends foundry.abstract.DataModel {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
type: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.GENERAL.rollTypes }),
|
||||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }),
|
||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
||||
advState: new fields.StringField({ choices: CONFIG.DH.ACTIONS.advandtageState, initial: 'neutral' }),
|
||||
diceRolling: new fields.SchemaField({
|
||||
multiplier: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceSetNumbers,
|
||||
initial: 'prof',
|
||||
label: 'Dice Number'
|
||||
}),
|
||||
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
dice: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceTypes,
|
||||
initial: 'd6',
|
||||
label: 'Dice Type'
|
||||
}),
|
||||
compare: new fields.StringField({
|
||||
choices: CONFIG.DH.ACTIONS.diceCompare,
|
||||
initial: 'above',
|
||||
label: 'Should be'
|
||||
}),
|
||||
treshold: new fields.NumberField({ initial: 1, integer: true, min: 1, label: 'Treshold' })
|
||||
}),
|
||||
useDefault: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
|
||||
getFormula() {
|
||||
if (!this.type) return;
|
||||
let formula = '';
|
||||
switch (this.type) {
|
||||
case 'diceSet':
|
||||
const multiplier =
|
||||
this.diceRolling.multiplier === 'flat'
|
||||
? this.diceRolling.flatMultiplier
|
||||
: `@${this.diceRolling.multiplier}`;
|
||||
formula = `${multiplier}${this.diceRolling.dice}cs${CONFIG.DH.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`;
|
||||
break;
|
||||
default:
|
||||
formula = '';
|
||||
break;
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
}
|
||||
|
||||
export default class RollField extends fields.EmbeddedDataField {
|
||||
constructor(options, context = {}) {
|
||||
super(DHActionRollData, options, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,4 +13,49 @@ export default class TargetField extends fields.SchemaField {
|
|||
};
|
||||
super(targetFields, options, context);
|
||||
}
|
||||
|
||||
static prepareConfig(config) {
|
||||
if (!this.target?.type) return [];
|
||||
let targets;
|
||||
if (this.target?.type === CONFIG.DH.ACTIONS.targetTypes.self.id)
|
||||
targets = TargetField.formatTarget.call(this, this.actor.token ?? this.actor.prototypeToken);
|
||||
targets = Array.from(game.user.targets);
|
||||
if (this.target.type !== CONFIG.DH.ACTIONS.targetTypes.any.id) {
|
||||
targets = targets.filter(t => TargetField.isTargetFriendly.call(this, t));
|
||||
if (this.target.amount && targets.length > this.target.amount) targets = [];
|
||||
}
|
||||
config.targets = targets.map(t => TargetField.formatTarget.call(this, t));
|
||||
const hasTargets = TargetField.checkTargets.call(this, this.target.amount, config.targets);
|
||||
if(config.isFastForward && !hasTargets)
|
||||
return ui.notifications.warn('Too many targets selected for that actions.');
|
||||
return hasTargets;
|
||||
}
|
||||
|
||||
static checkTargets(amount, targets) {
|
||||
return !amount || (targets.length > amount);
|
||||
}
|
||||
|
||||
static isTargetFriendly(target) {
|
||||
const actorDisposition = this.actor.token
|
||||
? this.actor.token.disposition
|
||||
: this.actor.prototypeToken.disposition,
|
||||
targetDisposition = target.document.disposition;
|
||||
return (
|
||||
(this.target.type === CONFIG.DH.ACTIONS.targetTypes.friendly.id &&
|
||||
actorDisposition === targetDisposition) ||
|
||||
(this.target.type === CONFIG.DH.ACTIONS.targetTypes.hostile.id &&
|
||||
actorDisposition + targetDisposition === 0)
|
||||
);
|
||||
}
|
||||
|
||||
static formatTarget(actor) {
|
||||
return {
|
||||
id: actor.id,
|
||||
actorId: actor.actor.uuid,
|
||||
name: actor.actor.name,
|
||||
img: actor.actor.img,
|
||||
difficulty: actor.actor.system.difficulty,
|
||||
evasion: actor.actor.system.evasion
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -13,4 +13,27 @@ export default class UsesField extends fields.SchemaField {
|
|||
};
|
||||
super(usesFields, options, context);
|
||||
}
|
||||
|
||||
static prepareConfig(config) {
|
||||
const uses = this.uses?.max ? foundry.utils.deepClone(this.uses) : null;
|
||||
if (uses && !uses.value) uses.value = 0;
|
||||
config.uses = uses;
|
||||
const hasUses = UsesField.hasUses.call(this, config.uses);
|
||||
if(config.isFastForward && !hasUses)
|
||||
return ui.notifications.warn("That action doesn't have remaining uses.");
|
||||
return hasUses;
|
||||
}
|
||||
|
||||
static calcUses(uses) {
|
||||
if (!uses) return null;
|
||||
return {
|
||||
...uses,
|
||||
enabled: uses.hasOwnProperty('enabled') ? uses.enabled : true
|
||||
};
|
||||
}
|
||||
|
||||
static hasUses(uses) {
|
||||
if (!uses) return true;
|
||||
return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= uses.max;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue