Merged with action branch

This commit is contained in:
WBHarry 2025-06-24 23:30:37 +02:00
commit 90e7000b9c
19 changed files with 280 additions and 496 deletions

View file

@ -60,9 +60,12 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
context.tabs = this._getTabs(); context.tabs = this._getTabs();
context.config = SYSTEM; context.config = SYSTEM;
if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id)); if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id));
if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') context.hasBaseDamage = !!this.action.parent.damage; if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack')
context.hasBaseDamage = !!this.action.parent.damage;
context.getRealIndex = this.getRealIndex.bind(this); context.getRealIndex = this.getRealIndex.bind(this);
context.disableOption = this.disableOption.bind(this); context.disableOption = this.disableOption.bind(this);
context.isNPC = this.action.actor.type !== 'character';
return context; return context;
} }
@ -74,9 +77,9 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
disableOption(index, options, choices) { disableOption(index, options, choices) {
const filtered = foundry.utils.deepClone(options); const filtered = foundry.utils.deepClone(options);
Object.keys(filtered).forEach(o => { Object.keys(filtered).forEach(o => {
if(choices.find((c, idx) => c.type === o && index !== idx)) delete filtered[o]; if (choices.find((c, idx) => c.type === o && index !== idx)) delete filtered[o];
}); });
return filtered return filtered;
} }
getRealIndex(index) { getRealIndex(index) {
@ -95,11 +98,18 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
const submitData = this._prepareSubmitData(event, formData), const submitData = this._prepareSubmitData(event, formData),
data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)), data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)),
container = foundry.utils.getProperty(this.action.parent, this.action.systemPath);
let newActions;
if (Array.isArray(container)) {
newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way
if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data);
} else newActions = data;
const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions }); const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions });
if (!updates) return; if (!updates) return;
this.action = foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index]; this.action = Array.isArray(container)
? foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index]
: foundry.utils.getProperty(updates.system, this.action.systemPath);
this.render(); this.render();
} }

View file

@ -42,6 +42,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
} }
async _prepareContext(_options) { async _prepareContext(_options) {
console.log(this.costs);
const updatedCosts = this.action.calcCosts(this.costs), const updatedCosts = this.action.calcCosts(this.costs),
updatedUses = this.action.calcUses(this.uses); updatedUses = this.action.calcUses(this.uses);
return { return {

View file

@ -38,7 +38,7 @@ export class DHRoll extends Roll {
config = await DialogClass.configure(config, message); config = await DialogClass.configure(config, message);
if (!config) return; if (!config) return;
} }
let roll = new this(config.formula, config.actor, config); let roll = new this(config.formula, config.data, config);
for (const hook of config.hooks) { for (const hook of config.hooks) {
if (Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false) if (Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false)
@ -101,9 +101,6 @@ export class DualityDie extends foundry.dice.terms.Die {
export class D20Roll extends DHRoll { export class D20Roll extends DHRoll {
constructor(formula, data = {}, options = {}) { constructor(formula, data = {}, options = {}) {
super(formula, data, options); super(formula, data, options);
// console.log(data, options)
// this.options = this._prepareData(data);
// this.options = options;
this.createBaseDice(); this.createBaseDice();
this.configureModifiers(); this.configureModifiers();
@ -194,10 +191,10 @@ export class D20Roll extends DHRoll {
this.applyBaseBonus(); this.applyBaseBonus();
this.options.experiences?.forEach(m => { this.options.experiences?.forEach(m => {
if (this.options.actor.experiences?.[m]) if (this.options.data.experiences?.[m])
this.options.roll.modifiers.push({ this.options.roll.modifiers.push({
label: this.options.actor.experiences[m].description, label: this.options.data.experiences[m].description,
value: this.options.actor.experiences[m].total value: this.options.data.experiences[m].total
}); });
}); });
this.options.roll.modifiers?.forEach(m => { this.options.roll.modifiers?.forEach(m => {
@ -214,31 +211,17 @@ export class D20Roll extends DHRoll {
} }
applyBaseBonus() { applyBaseBonus() {
// if(this.options.action) {
if (this.options.type === 'attack') if (this.options.type === 'attack')
this.terms.push(...this.formatModifier(this.options.actor.system.attack.modifier)); this.terms.push(...this.formatModifier(this.options.data.attack.roll.bonus));
/* this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m));
}) */
// }
} }
static async postEvaluate(roll, config = {}) { static async postEvaluate(roll, config = {}) {
if (config.targets?.length) { if (config.targets?.length) {
/* targets = config.targets.map(target => {
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion
target.hit = roll.total >= difficulty;
return target;
}); */
config.targets.forEach(target => { config.targets.forEach(target => {
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion; const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
target.hit = roll.total >= difficulty; target.hit = roll.total >= difficulty;
}); });
} else if (config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty; } else if (config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty;
// config.roll.advantage = {
// dice: roll.dHope.faces,
// value: roll.dHope.total
// }
config.roll.total = roll.total; config.roll.total = roll.total;
config.roll.formula = roll.formula; config.roll.formula = roll.formula;
config.roll.advantage = { config.roll.advantage = {
@ -247,10 +230,19 @@ export class D20Roll extends DHRoll {
value: roll.dAdvantage?.total value: roll.dAdvantage?.total
}; };
config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + c.value, 0); config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + c.value, 0);
config.roll.dice = [];
roll.dice.forEach(d => {
config.roll.dice.push({
dice: d.denomination,
total: d.total,
formula: d.formula,
results: d.results
});
});
} }
getRollData() { getRollData() {
return this.options.actor.getRollData(); return this.options.data();
} }
formatModifier(modifier) { formatModifier(modifier) {
@ -357,7 +349,6 @@ export class DualityRoll extends D20Roll {
const dieFaces = 6, const dieFaces = 6,
bardRallyFaces = this.hasBarRally, bardRallyFaces = this.hasBarRally,
advDie = new foundry.dice.terms.Die({ faces: dieFaces }); advDie = new foundry.dice.terms.Die({ faces: dieFaces });
// console.log(this.hasAdvantage, this.hasDisadvantage)
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces)
this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: '+' })); this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: '+' }));
if (bardRallyFaces) { if (bardRallyFaces) {
@ -376,22 +367,15 @@ export class DualityRoll extends D20Roll {
} }
applyBaseBonus() { applyBaseBonus() {
// if(this.options.action) {
// console.log(this.options, this.options.actor.system.traits[this.options.roll.trait].bonus)
// console.log(this.options.actor.system);
/* if(this.options.roll?.trait) this.terms.push(...this.formatModifier(this.options.actor.traits[this.options.roll.trait].total)); */
if (!this.options.roll.modifiers) this.options.roll.modifiers = []; if (!this.options.roll.modifiers) this.options.roll.modifiers = [];
if (this.options.roll?.trait) if (this.options.roll?.trait)
this.options.roll.modifiers.push({ this.options.roll.modifiers.push({
label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`,
value: this.options.actor.traits[this.options.roll.trait].total value: this.options.data.traits[this.options.roll.trait].total
}); });
console.log(this.options);
// } else if(this.options.trait) this.terms.push(...this.formatModifier(this.options.actor.system.traits[this.options.roll.trait].total));
} }
static async postEvaluate(roll, config = {}) { static async postEvaluate(roll, config = {}) {
console.log(roll, config);
super.postEvaluate(roll, config); super.postEvaluate(roll, config);
config.roll.hope = { config.roll.hope = {
dice: roll.dHope.denomination, dice: roll.dHope.denomination,
@ -427,30 +411,10 @@ export class DamageRoll extends DHRoll {
static DefaultDialog = DamageDialog; static DefaultDialog = DamageDialog;
static async postEvaluate(roll, config = {}) { static async postEvaluate(roll, config = {}) {
console.log(roll, config);
config.roll = { config.roll = {
// formula : config.formula,
result: roll.total, result: roll.total,
dice: roll.dice dice: roll.dice
}; };
if (roll.healing) config.roll.type = roll.healing.type; if (roll.healing) config.roll.type = roll.healing.type;
/* const dice = [];
const modifiers = [];
for (var i = 0; i < roll.terms.length; i++) {
const term = roll.terms[i];
if (term.faces) {
dice.push({
type: `d${term.faces}`,
rolls: term.results.map(x => x.result),
total: term.results.reduce((acc, x) => acc + x.result, 0)
});
} else if (term.operator) {
} else if (term.number) {
const operator = i === 0 ? '' : roll.terms[i - 1].operator;
modifiers.push({ value: term.number, operator: operator });
}
}
config.roll.dice = dice;
config.roll.modifiers = modifiers; */
} }
} }

View file

@ -1,3 +1,4 @@
import DHActionConfig from '../config/Action.mjs';
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ActorSheetV2 } = foundry.applications.sheets; const { ActorSheetV2 } = foundry.applications.sheets;
@ -9,6 +10,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
actions: { actions: {
reactionRoll: this.reactionRoll, reactionRoll: this.reactionRoll,
attackRoll: this.attackRoll, attackRoll: this.attackRoll,
attackConfigure: this.attackConfigure,
addExperience: this.addExperience, addExperience: this.addExperience,
removeExperience: this.removeExperience, removeExperience: this.removeExperience,
toggleHP: this.toggleHP, toggleHP: this.toggleHP,
@ -51,7 +53,9 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.document = this.document; context.document = this.document;
context.tabs = super._getTabs(this.constructor.TABS); context.tabs = super._getTabs(this.constructor.TABS);
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
context.isNPC = true;
console.log(context);
return context; return context;
} }
@ -78,25 +82,11 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
} }
static async attackRoll(event) { static async attackRoll(event) {
const { modifier, damage, name: attackName } = this.actor.system.attack, this.actor.system.attack.use(event);
config = { }
event: event,
title: attackName, static async attackConfigure(event) {
roll: { await new DHActionConfig(this.document.system.attack).render(true);
modifier: modifier,
type: 'action'
},
chatMessage: {
type: 'adversaryRoll',
template: 'systems/daggerheart/templates/chat/adversary-attack-roll.hbs'
},
damage: {
value: damage.value,
type: damage.type
},
checkTarget: true
};
this.actor.diceRoll(config);
} }
static async addExperience() { static async addExperience() {

View file

@ -300,13 +300,15 @@ export const diceTypes = {
d4: 'd4', d4: 'd4',
d6: 'd6', d6: 'd6',
d8: 'd8', d8: 'd8',
d10: 'd10',
d12: 'd12', d12: 'd12',
d20: 'd20' d20: 'd20'
}; };
export const multiplierTypes = { export const multiplierTypes = {
proficiency: 'Proficiency', proficiency: 'Proficiency',
spellcast: 'Spellcast' spellcast: 'Spellcast',
flat: 'Flat'
}; };
export const getDiceSoNicePresets = () => { export const getDiceSoNicePresets = () => {

View file

@ -2,6 +2,7 @@ import DamageSelectionDialog from '../../applications/damageSelectionDialog.mjs'
import CostSelectionDialog from '../../applications/costSelectionDialog.mjs'; import CostSelectionDialog from '../../applications/costSelectionDialog.mjs';
import { abilities } from '../../config/actorConfig.mjs'; import { abilities } from '../../config/actorConfig.mjs';
import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs'; import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs';
import DhpActor from '../../documents/actor.mjs';
const fields = foundry.data.fields; const fields = foundry.data.fields;
@ -86,8 +87,8 @@ export class DHBaseAction extends foundry.abstract.DataModel {
range: new fields.StringField({ range: new fields.StringField({
choices: SYSTEM.GENERAL.range, choices: SYSTEM.GENERAL.range,
required: false, required: false,
blank: true, blank: true
initial: null // initial: null
}), }),
...this.defineExtraSchema() ...this.defineExtraSchema()
}; };
@ -99,7 +100,8 @@ export class DHBaseAction extends foundry.abstract.DataModel {
roll: new fields.SchemaField({ roll: new fields.SchemaField({
type: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.GENERAL.rollTypes }), type: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.GENERAL.rollTypes }),
trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }),
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }) difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 })
}), }),
save: new fields.SchemaField({ save: new fields.SchemaField({
trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }),
@ -151,7 +153,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
} }
get actor() { get actor() {
return this.item?.actor; return this.item instanceof DhpActor ? this.item : this.item?.actor;
} }
get chatTemplate() { get chatTemplate() {
@ -203,6 +205,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
source: { source: {
item: this.item._id, item: this.item._id,
action: this._id action: this._id
// action: this
}, },
type: this.type, type: this.type,
hasDamage: !!this.damage?.parts?.length, hasDamage: !!this.damage?.parts?.length,
@ -236,25 +239,25 @@ export class DHBaseAction extends foundry.abstract.DataModel {
this.spendCost(config.costs.values); this.spendCost(config.costs.values);
this.spendUses(config.uses); this.spendUses(config.uses);
// console.log(config)
return config; return config;
} }
/* ROLL */ /* ROLL */
hasRoll() { hasRoll() {
return this.roll?.type && this.roll?.trait; // return this.roll?.type && this.roll?.trait;
return this.roll?.type;
} }
async proceedRoll(config) { async proceedRoll(config) {
if (!this.hasRoll()) return config; if (!this.hasRoll()) return config;
const modifierValue = this.actor.system.traits[this.roll.trait].value; // const modifierValue = this.actor.system.traits[this.roll.trait].value;
config = { config = {
...config, ...config,
roll: { roll: {
modifiers: [], modifiers: [],
trait: this.roll?.trait, trait: this.roll?.trait,
label: game.i18n.localize(abilities[this.roll.trait].label), // label: game.i18n.localize(abilities[this.roll.trait].label),
label: 'Attack',
type: this.actionType, type: this.actionType,
difficulty: this.roll?.difficulty difficulty: this.roll?.difficulty
} }
@ -359,7 +362,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
name: actor.actor.name, name: actor.actor.name,
img: actor.actor.img, img: actor.actor.img,
difficulty: actor.actor.system.difficulty, difficulty: actor.actor.system.difficulty,
evasion: actor.actor.system.evasion?.value evasion: actor.actor.system.evasion?.total
}; };
} }
/* TARGET */ /* TARGET */
@ -375,7 +378,6 @@ export class DHBaseAction extends foundry.abstract.DataModel {
async applyEffects(event, data, force = false) { async applyEffects(event, data, force = false) {
if (!this.effects?.length || !data.system.targets.length) return; if (!this.effects?.length || !data.system.targets.length) return;
data.system.targets.forEach(async token => { data.system.targets.forEach(async token => {
// console.log(token, force)
if (!token.hit && !force) return; if (!token.hit && !force) return;
this.effects.forEach(async e => { this.effects.forEach(async e => {
const actor = canvas.tokens.get(token.id)?.actor, const actor = canvas.tokens.get(token.id)?.actor,
@ -497,7 +499,6 @@ export class DHHealingAction extends DHBaseAction {
} }
async rollHealing(event, data) { async rollHealing(event, data) {
console.log(event, data);
let formula = this.healing.value.getFormula(this.actor); let formula = this.healing.value.getFormula(this.actor);
if (!formula || formula == '') return; if (!formula || formula == '') return;

View file

@ -11,6 +11,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
initial: 'proficiency', initial: 'proficiency',
label: 'Multiplier' label: 'Multiplier'
}), }),
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }), dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }),
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }), bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
custom: new fields.SchemaField({ custom: new fields.SchemaField({
@ -21,9 +22,10 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
} }
getFormula(actor) { getFormula(actor) {
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total;
return this.custom.enabled return this.custom.enabled
? this.custom.formula ? this.custom.formula
: `${actor.system[this.multiplier]?.total ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`; : `${multiplier ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`;
} }
} }

View file

@ -1,3 +1,6 @@
import DhpItem from '../../documents/item.mjs';
import ActionField from '../fields/actionField.mjs';
import DHWeapon from '../item/weapon.mjs';
import BaseDataActor from './base.mjs'; import BaseDataActor from './base.mjs';
const resourceField = () => const resourceField = () =>
@ -39,7 +42,7 @@ export default class DhpAdversary extends BaseDataActor {
hitPoints: resourceField(), hitPoints: resourceField(),
stress: resourceField() stress: resourceField()
}), }),
attack: new fields.SchemaField({ /* attack: new fields.SchemaField({
name: new fields.StringField({}), name: new fields.StringField({}),
modifier: new fields.NumberField({ required: true, integer: true, initial: 0 }), modifier: new fields.NumberField({ required: true, integer: true, initial: 0 }),
range: new fields.StringField({ range: new fields.StringField({
@ -55,6 +58,45 @@ export default class DhpAdversary extends BaseDataActor {
initial: SYSTEM.GENERAL.damageTypes.physical.id initial: SYSTEM.GENERAL.damageTypes.physical.id
}) })
}) })
}), */
/* attack: new fields.EmbeddedDocumentField(DhpItem,
{
// type: 'weapon'
// initial: new DhpItem(
// {
// name: 'Attack',
// type: 'weapon'
// },
// {
// parent: this.parent,
// parentCollection: 'items'
// }
// )
// initial: {type: 'weapon'}
}
), */
attack: new ActionField({
initial: {
name: 'Attack',
_id: foundry.utils.randomID(),
systemPath: 'attack',
type: 'attack',
range: 'melee',
target: {
type: 'any',
amount: 1
},
roll: {
type: 'weapon'
},
damage: {
parts: [
{
multiplier: 'flat'
}
]
}
}
}), }),
experiences: new fields.TypedObjectField( experiences: new fields.TypedObjectField(
new fields.SchemaField({ new fields.SchemaField({
@ -65,4 +107,21 @@ export default class DhpAdversary extends BaseDataActor {
/* Features waiting on pseudo-document data model addition */ /* Features waiting on pseudo-document data model addition */
}; };
} }
prepareBaseData() {
// console.log(this.attack)
/* if(!this.attack) {
this.attack = new DhpItem(
{
name: 'Attack',
type: 'weapon',
_id: foundry.utils.randomID()
},
{
parent: this.parent,
parentCollection: 'items'
}
)
} */
}
} }

View file

@ -1,23 +1,13 @@
import DhpActor from '../../documents/actor.mjs';
import ActionField from '../fields/actionField.mjs';
export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel { export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
title: new fields.StringField(), title: new fields.StringField(),
origin: new fields.StringField({ required: true }),
dice: new fields.DataField(),
roll: new fields.DataField(), roll: new fields.DataField(),
modifiers: new fields.ArrayField(
new fields.SchemaField({
value: new fields.NumberField({ integer: true }),
label: new fields.StringField({})
})
),
advantageState: new fields.BooleanField({ nullable: true, initial: null }),
advantage: new fields.SchemaField({
dice: new fields.StringField({}),
value: new fields.NumberField({ integer: true })
}),
targets: new fields.ArrayField( targets: new fields.ArrayField(
new fields.SchemaField({ new fields.SchemaField({
id: new fields.StringField({}), id: new fields.StringField({}),
@ -29,24 +19,13 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
}) })
), ),
hasDamage: new fields.BooleanField({ initial: false }), hasDamage: new fields.BooleanField({ initial: false }),
hasHealing: new fields.BooleanField({ initial: false }),
hasEffect: new fields.BooleanField({ initial: false }), hasEffect: new fields.BooleanField({ initial: false }),
/* damage: new fields.SchemaField( source: new fields.SchemaField({
{ actor: new fields.StringField(),
value: new fields.StringField({}), item: new fields.StringField(),
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }) action: new fields.StringField()
},
{ nullable: true, initial: null }
), */
action: new fields.SchemaField({
itemId: new fields.StringField(),
actionId: new fields.StringField()
}) })
}; };
} }
prepareDerivedData() {
this.targets.forEach(target => {
target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion;
});
}
} }

View file

@ -1,11 +1,4 @@
import { DualityRollColor } from '../settings/Appearance.mjs';
const fields = foundry.data.fields; const fields = foundry.data.fields;
const diceField = () =>
new fields.SchemaField({
dice: new fields.StringField({}),
value: new fields.NumberField({ integer: true })
});
export default class DHDualityRoll extends foundry.abstract.TypeDataModel { export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
static dualityResult = { static dualityResult = {
@ -17,18 +10,7 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
return { return {
title: new fields.StringField(), title: new fields.StringField(),
/* origin: new fields.StringField({ required: true }), */
roll: new fields.DataField({}), roll: new fields.DataField({}),
/* modifiers: new fields.ArrayField(
new fields.SchemaField({
value: new fields.NumberField({ integer: true }),
label: new fields.StringField({})
})
), */
/* hope: diceField(),
fear: diceField(),
advantageState: new fields.BooleanField({ nullable: true, initial: null }), */
/* advantage: diceField(), */
targets: new fields.ArrayField( targets: new fields.ArrayField(
new fields.SchemaField({ new fields.SchemaField({
id: new fields.StringField({}), id: new fields.StringField({}),
@ -49,47 +31,4 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
}) })
}; };
} }
/* get diceTotal() {
return this.hope.value + this.fear.value;
}
get modifierTotal() {
const total = this.modifiers.reduce((acc, x) => acc + x.value, 0);
return {
value: total,
label: total > 0 ? `+${total}` : total < 0 ? `${total}` : ''
};
}
get dualityResult() {
return this.hope.value > this.fear.value
? this.constructor.dualityResult.hope
: this.fear.value > this.hope.value
? this.constructor.dualityResult.fear
: this.constructor.dualityResult.critical;
}
get totalLabel() {
const label =
this.hope.value > this.fear.value
? 'DAGGERHEART.General.Hope'
: this.fear.value > this.hope.value
? 'DAGGERHEART.General.Fear'
: 'DAGGERHEART.General.CriticalSuccess';
return game.i18n.localize(label);
}
get colorful() {
return (
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
DualityRollColor.colorful.value
);
}
prepareDerivedData() {
this.hope.discarded = this.hope.value < this.fear.value;
this.fear.discarded = this.fear.value < this.hope.value;
} */
} }

View file

@ -8,8 +8,11 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.experiences = []; this.config.experiences = [];
if (config.source?.action) { if (config.source?.action) {
this.item = config.actor.parent.items.get(config.source.item); this.item = config.data.parent.items.get(config.source.item);
this.action = this.item.system.actions.find(a => a._id === config.source.action); this.action =
config.data.attack?._id == config.source.action
? config.data.attack
: this.item.system.actions.find(a => a._id === config.source.action);
} }
} }
@ -47,9 +50,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.experiences = Object.keys(this.config.actor.experiences).map(id => ({ context.experiences = Object.keys(this.config.data.experiences).map(id => ({
id, id,
...this.config.actor.experiences[id] ...this.config.data.experiences[id]
})); }));
context.selectedExperiences = this.config.experiences; context.selectedExperiences = this.config.experiences;
context.advantage = this.config.advantage; context.advantage = this.config.advantage;

View file

@ -266,153 +266,14 @@ export default class DhpActor extends Actor {
* @param {object} [config.costs] * @param {object} [config.costs]
*/ */
async diceRoll(config, action) { async diceRoll(config, action) {
// console.log(config) config.source = { ...(config.source ?? {}), actor: this._id };
config.source = { ...(config.source ?? {}), actor: this.id }; config.data = this.getRollData();
const newConfig = { const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(config);
...config,
actor: this.system
};
const roll =
await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(newConfig);
return config; return config;
/* let hopeDice = 'd12', }
fearDice = 'd12',
advantageDice = 'd6',
disadvantageDice = 'd6',
advantage = config.event.altKey ? true : config.event.ctrlKey ? false : null,
targets,
modifiers = this.formatRollModifier(config.roll),
rollConfig,
formula,
hope,
fear;
if (!config.event.shiftKey && !config.event.altKey && !config.event.ctrlKey) { getRollData() {
const dialogClosed = new Promise((resolve, _) => { return this.system;
this.type === 'character'
? new RollSelectionDialog(
this.system.experiences,
config.costs,
action,
resolve
).render(true)
: new NpcRollSelectionDialog(
this.system.experiences,
resolve
).render(true);
});
rollConfig = await dialogClosed;
advantage = rollConfig.advantage;
hopeDice = rollConfig.hope;
fearDice = rollConfig.fear;
if(rollConfig.costs) config.costs = rollConfig.costs;
rollConfig.experiences.forEach(x =>
modifiers.push({
value: x.value,
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
title: x.description
})
);
if (this.type === 'character') {
const automateHope = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope;
if (automateHope && result.hopeUsed) {
await this.update({
'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed
});
}
}
}
if (this.type === 'character') {
formula = `1${hopeDice} + 1${fearDice}${advantage === true ? ` + 1d6` : advantage === false ? ` - 1d6` : ''}`;
} else {
formula = `${advantage === true || advantage === false ? 2 : 1}d20${advantage === true ? 'kh' : advantage === false ? 'kl' : ''}`;
}
formula += ` ${modifiers.map(x => `+ ${x.value}`).join(' ')}`;
const roll = await Roll.create(formula).evaluate(),
dice = roll.dice.flatMap(dice => ({
denomination: dice.denomination,
number: dice.number,
total: dice.total,
results: dice.results.map(result => ({ result: result.result, discarded: !result.active }))
}));
config.roll.evaluated = roll;
if (this.type === 'character') {
setDiceSoNiceForDualityRoll(roll, advantage);
hope = roll.dice[0].results[0].result;
fear = roll.dice[1].results[0].result;
if (
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope &&
config.roll.type === 'action'
) {
if (hope > fear) {
await this.update({
'system.resources.hope.value': Math.min(
this.system.resources.hope.value + 1,
this.system.resources.hope.max
)
});
} else if (hope === fear) {
await this.update({
'system.resources': {
'hope.value': Math.min(
this.system.resources.hope.value + 1,
this.system.resources.hope.max
),
'stress.value': Math.max(this.system.resources.stress.value - 1, 0)
}
});
}
}
}
if (config.targets?.length) {
targets = config.targets.map(target => {
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion
target.hit = roll.total >= difficulty;
return target;
});
} else if(config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty;
if (config.chatMessage) {
const configRoll = {
title: config.title,
origin: this.id,
dice,
roll,
modifiers: modifiers.filter(x => x.label),
advantageState: advantage,
action: config.source,
hasDamage: config.hasDamage,
hasEffect: config.hasEffect
};
if (this.type === 'character') {
configRoll.hope = { dice: hopeDice, value: hope };
configRoll.fear = { dice: fearDice, value: fear };
configRoll.advantage = { dice: advantageDice, value: roll.dice[2]?.results[0].result ?? null };
}
// if (damage) configRoll.damage = damage;
if (targets) configRoll.targets = targets;
const systemData =
this.type === 'character' && !config.roll.simple ? new DHDualityRoll(configRoll) : configRoll,
cls = getDocumentClass('ChatMessage'),
msg = new cls({
type: config.chatMessage.type ?? 'dualityRoll',
sound: config.chatMessage.mute ? null : CONFIG.sounds.dice,
system: systemData,
content: config.chatMessage.template,
rolls: [roll]
});
await cls.create(msg.toObject());
}
return config; */
} }
formatRollModifier(roll) { formatRollModifier(roll) {
@ -575,104 +436,4 @@ export default class DhpActor extends Actor {
} }
}); });
} }
/* async takeHealing(healing, type) {
let update = {};
switch (type) {
case SYSTEM.GENERAL.healingTypes.health.id:
update = {
'system.resources.hitPoints.value': Math.min(
this.system.resources.hitPoints.value + healing,
this.system.resources.hitPoints.max
)
};
break;
case SYSTEM.GENERAL.healingTypes.stress.id:
update = {
'system.resources.stress.value': Math.min(
this.system.resources.stress.value + healing,
this.system.resources.stress.max
)
};
break;
}
if (game.user.isGM) {
await this.update(update);
} else {
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateDocument,
uuid: this.uuid,
update: update
}
});
}
} */
//Move to action-scope?
/* async useAction(action) {
const userTargets = Array.from(game.user.targets);
const otherTarget = action.target.type === SYSTEM.ACTIONS.targetTypes.other.id;
if (otherTarget && userTargets.length === 0) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.ActionRequiresTarget'));
return;
}
if (action.cost.type != null && action.cost.value != null) {
if (
this.system.resources[action.cost.type].value - action.cost.value <=
this.system.resources[action.cost.type].min
) {
ui.notifications.error(game.i18n.localize(`Insufficient ${action.cost.type} to use this ability`));
return;
}
}
// const targets = otherTarget ? userTargets : [game.user.character];
if (action.damage.type) {
let roll = { formula: action.damage.value, result: action.damage.value };
if (Number.isNaN(Number.parseInt(action.damage.value))) {
roll = await new Roll(`1${action.damage.value}`).evaluate();
}
const cls = getDocumentClass('ChatMessage');
const msg = new cls({
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/damage-roll.hbs',
{
roll: roll.formula,
total: roll.result,
type: action.damage.type
}
)
});
cls.create(msg.toObject());
}
if (action.healing.type) {
let roll = { formula: action.healing.value, result: action.healing.value };
if (Number.isNaN(Number.parseInt(action.healing.value))) {
roll = await new Roll(`1${action.healing.value}`).evaluate();
}
const cls = getDocumentClass('ChatMessage');
const msg = new cls({
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/healing-roll.hbs',
{
roll: roll.formula,
total: roll.result,
type: action.healing.type
}
)
});
cls.create(msg.toObject());
}
} */
} }

View file

@ -60,48 +60,51 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
super.close(options); super.close(options);
} }
getActor(id) {
return game.actors.get(id);
}
getAction(actor, itemId, actionId) {
const item = actor.items.get(itemId),
action =
actor.system.attack?._id === actionId
? actor.system.attack
: item?.system?.actions?.find(a => a._id === actionId);
return action;
}
onRollDamage = async (event, message) => { onRollDamage = async (event, message) => {
event.stopPropagation(); event.stopPropagation();
const actor = game.actors.get(message.system.source.actor); const actor = this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true; if (!actor || !game.user.isGM) return true;
if(message.system.source.item && message.system.source.action) { if (message.system.source.item && message.system.source.action) {
const item = actor.items.get(message.system.source.item), const action = this.getAction(actor, message.system.source.item, message.system.source.action);
action = item?.system?.actions?.find(a => a._id === message.system.source.action); if (!action || !action?.rollDamage) return;
if(!item || !action || !action?.rollDamage) return;
await action.rollDamage(event, message); await action.rollDamage(event, message);
} else {
await actor.damageRoll(
message.system.title,
message.system.damage,
message.system.targets.filter(x => x.hit).map(x => ({ id: x.id, name: x.name, img: x.img })),
event.shiftKey
);
} }
}; };
onRollHealing = async (event, message) => { onRollHealing = async (event, message) => {
event.stopPropagation(); event.stopPropagation();
const actor = game.actors.get(message.system.source.actor); const actor = this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true; if (!actor || !game.user.isGM) return true;
if(message.system.source.item && message.system.source.action) { if (message.system.source.item && message.system.source.action) {
const item = actor.items.get(message.system.source.item), const action = this.getAction(actor, message.system.source.item, message.system.source.action);
action = item?.system?.actions?.find(a => a._id === message.system.source.action); if (!action || !action?.rollHealing) return;
if(!item || !action || !action?.rollHealing) return;
await action.rollHealing(event, message); await action.rollHealing(event, message);
} }
}; };
onApplyEffect = async (event, message) => { onApplyEffect = async (event, message) => {
event.stopPropagation(); event.stopPropagation();
const actor = game.actors.get(message.system.source.actor); const actor = this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true; if (!actor || !game.user.isGM) return true;
if(message.system.source.item && message.system.source.action) { if (message.system.source.item && message.system.source.action) {
const item = actor.items.get(message.system.source.item), const action = this.getAction(actor, message.system.source.item, message.system.source.action);
action = item?.system?.actions?.find(a => a._id === message.system.source.action); if (!action || !action?.applyEffects) return;
if(!item || !action || !action.applyEffects) return;
await action.applyEffects(event, message); await action.applyEffects(event, message);
} }
} };
hoverTarget = event => { hoverTarget = event => {
event.stopPropagation(); event.stopPropagation();
@ -148,7 +151,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected')); ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
for (var target of targets) { for (var target of targets) {
await target.actor.modifyResource([{value: healing, type: event.currentTarget.dataset.type}]); await target.actor.modifyResource([{ value: healing, type: event.currentTarget.dataset.type }]);
} }
}; };

View file

@ -1,33 +1,51 @@
<div class="dice-roll daggerheart chat roll" data-action="expandRoll"> <div class="dice-roll daggerheart chat roll" data-action="expandRoll">
<div class="dice-flavor">{{title}}</div>
<div class="dice-result"> <div class="dice-result">
<div class="dice-formula">{{roll.formula}}</div> <div class="dice-formula">{{roll.formula}}</div>
<div class="dice-tooltip"> <div class="dice-tooltip">
<ol class="dice-rolls"> <div class="wrapper">
<div class="dice-hope-container"> <section class="tooltip-part">
{{#each dice}} <div class="dice">
{{#each roll.dice}}
<header class="part-header flexrow"> <header class="part-header flexrow">
<span class="part-formula">{{number}}{{denomination}}</span> <span class="part-formula">{{formula}}</span>
<span class="part-total">{{total}}</span> <span class="part-total">{{total}}</span>
</header> </header>
<div class="flexrow"> <div class="flexrow">
<ol class="dice-rolls"> <ol class="dice-rolls">
{{#each results}} {{#each results}}
<li class="roll die {{../denomination}}{{#if discarded}} discarded{{/if}} min">{{result}}</li> <li class="roll die {{../dice}}{{#if discarded}} discarded{{/if}} min">{{result}}</li>
{{/each}} {{/each}}
</ol> </ol>
<div class="attack-roll-advantage-container">{{#if ../advantageState}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq ../advantageState false)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}}</div> <div class="attack-roll-advantage-container">
{{#if (eq ../roll.advantage.type 1)}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq ../roll.advantage.type -1)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}}
</div>
</div> </div>
{{/each}} {{/each}}
</div> </div>
<div class="modifiers-container"> </section>
{{#each modifiers}} </div>
<li class="modifier-value" data-value="{{value}}" title="{{title}}">{{label}}</li>
{{/each}}
</div>
</ol>
</div> </div>
<div class="dice-total"> <div class="dice-total">
<div class="dice-total-value">{{roll.total}}</div> <div class="dice-total-value">{{roll.total}}</div>
</div> </div>
{{#if (gt targets.length 0)}}
<div class="target-section">
{{#each targets as |target|}}
<div class="dice-total target-container {{#if target.hit}}hit{{else}}miss{{/if}}" data-token="{{target.id}}">
<img src="{{target.img}}" />
<div class="target-inner-container">
{{#if target.hit}}{{localize "Hit"}}{{else}}{{localize "Miss"}}{{/if}}
</div>
</div>
{{/each}}
</div>
{{/if}}
{{#if hasDamage}}
<div class="flexrow">
<button class="duality-action duality-action-damage" data-value="{{roll.total}}"><span>Roll Damage</span></button>
</div>
{{/if}}
</div> </div>
</div> </div>

View file

@ -49,13 +49,43 @@
<fieldset class="two-columns even"> <fieldset class="two-columns even">
<legend>{{localize "DAGGERHEART.Sheets.Adversary.Attack"}}</legend> <legend>{{localize "DAGGERHEART.Sheets.Adversary.Attack"}}</legend>
<button data-action="attackConfigure">Configure</button>
<button data-action="attackRoll">Attack</button>
<fieldset class="action-category" style="grid-column: 1 / -1;">
<legend class="action-category-label" data-action="toggleSection" data-section="range">
<div>Name</div>
</legend>
<div class="action-category-data open">
{{formGroup systemFields.attack.fields.name value=source.system.attack.name name="system.attack.name"}}
{{formGroup systemFields.attack.fields.img value=source.img label="Icon" name="system.attack.img"}}
</div>
</fieldset>
<div>
<fieldset class="action-category">
<legend class="action-category-label" data-action="toggleSection" data-section="range">
<div>Bonus</div>
</legend>
<div class="action-category-data open">
{{formField systemFields.attack.fields.roll.fields.bonus value=source.system.attack.roll.bonus name="system.attack.roll.bonus"}}
</div>
</fieldset>
{{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=systemFields.attack.fields.range target=systemFields.attack.fields.target.fields) source=(object target=source.system.attack.target range=source.system.attack.range) path="system.attack."}}
</div>
{{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=source.system.attack.damage path="system.attack."}}
<div style="grid-column: 1 / -1;">
{{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs'}}
</div>
{{!-- <legend>{{localize "DAGGERHEART.Sheets.Adversary.Attack"}}</legend>
{{formGroup systemFields.attack.fields.name value=source.system.attack.name}} {{formGroup systemFields.attack.fields.name value=source.system.attack.name}}
<button data-action="attackRoll">Attack</button> <button data-action="attackRoll">Attack</button>
{{formGroup systemFields.attack.fields.modifier value=source.system.attack.modifier}} {{formGroup systemFields.attack.fields.modifier value=source.system.attack.modifier}}
{{formGroup systemFields.attack.fields.range value=source.system.attack.range localize=true}} {{formGroup systemFields.attack.fields.range value=source.system.attack.range localize=true}}
{{formGroup systemFields.attack.fields.damage.fields.value value=source.system.attack.damage.value}} {{formGroup systemFields.attack.fields.damage.fields.value value=source.system.attack.damage.value}}
{{formGroup systemFields.attack.fields.damage.fields.type value=source.system.attack.damage.type localize=true}} {{formGroup systemFields.attack.fields.damage.fields.type value=source.system.attack.damage.type localize=true}} --}}
</fieldset> </fieldset>
</div> </div>
</section> </section>

View file

@ -33,8 +33,10 @@
</fieldset> </fieldset>
</div> </div>
<div class="tab {{this.tabs.config.cssClass}}" data-group="primary" data-tab="config"> <div class="tab {{this.tabs.config.cssClass}}" data-group="primary" data-tab="config">
{{#unless isNPC}}
{{> 'systems/daggerheart/templates/views/actionTypes/uses.hbs' fields=fields.uses.fields source=source.uses}} {{> 'systems/daggerheart/templates/views/actionTypes/uses.hbs' fields=fields.uses.fields source=source.uses}}
{{> 'systems/daggerheart/templates/views/actionTypes/cost.hbs' fields=fields.cost.element.fields source=source.cost}} {{> 'systems/daggerheart/templates/views/actionTypes/cost.hbs' fields=fields.cost.element.fields source=source.cost}}
{{/unless}}
{{#if fields.target}}{{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=fields.range target=fields.target.fields) source=(object target=source.target range=source.range)}}{{/if}} {{#if fields.target}}{{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=fields.range target=fields.target.fields) source=(object target=source.target range=source.range)}}{{/if}}
</div> </div>
<div class="tab {{this.tabs.effect.cssClass}}" data-group="primary" data-tab="effect"> <div class="tab {{this.tabs.effect.cssClass}}" data-group="primary" data-tab="effect">

View file

@ -4,33 +4,49 @@
<div>Damage</div> <div>Damage</div>
</legend> </legend>
<div class="action-category-data open"> <div class="action-category-data open">
<div class="fas fa-plus icon-button" data-action="addDamage"></div> {{#unless @root.isNPC}}
{{#if @root.hasBaseDamage}} <div class="fas fa-plus icon-button" data-action="addDamage"></div>
<div> {{#if @root.hasBaseDamage}}
{{!-- <input type="checkbox" data-action="addBaseDamage"{{#if @root.hasBaseDamage}} checked{{/if}}> --}} <div>
{{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} {{!-- <input type="checkbox" data-action="addBaseDamage"{{#if @root.hasBaseDamage}} checked{{/if}}> --}}
</div> {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }}
{{/if}} </div>
{{/if}}
{{/unless}}
{{#each source.parts as |dmg index|}} {{#each source.parts as |dmg index|}}
{{#with (@root.getRealIndex index) as | realIndex |}} {{#if @root.isNPC}}
<fieldset{{#if dmg.base}} disabled{{/if}}> {{formField ../fields.custom.fields.enabled value=dmg.custom.enabled name=(concat ../path "damage.parts." index ".custom.enabled")}}
{{#unless dmg.base}}
{{formField ../../fields.custom.fields.enabled value=dmg.custom.enabled name=(concat "damage.parts." realIndex ".custom.enabled")}}
{{/unless}}
{{#if dmg.custom.enabled}} {{#if dmg.custom.enabled}}
{{formField ../../fields.custom.fields.formula value=dmg.custom.formula name=(concat "damage.parts." realIndex ".custom.formula") localize=true}} {{formField ../fields.custom.fields.formula value=dmg.custom.formula name=(concat ../path "damage.parts." index ".custom.formula") localize=true}}
{{else}} {{else}}
<div class="multi-display"> <div class="multi-display">
{{formField ../../fields.multiplier value=dmg.multiplier name=(concat "damage.parts." realIndex ".multiplier") localize=true}} {{formField ../fields.flatMultiplier value=dmg.flatMultiplier name=(concat "damage.parts." realIndex ".flatMultiplier") label="Multiplier" }}
{{formField ../../fields.dice value=dmg.dice name=(concat "damage.parts." realIndex ".dice")}} {{formField ../fields.dice value=dmg.dice name=(concat ../path "damage.parts." index ".dice")}}
{{formField ../../fields.bonus value=dmg.bonus name=(concat "damage.parts." realIndex ".bonus") localize=true}} {{formField ../fields.bonus value=dmg.bonus name=(concat ../path "damage.parts." index ".bonus") localize=true}}
</div> </div>
{{/if}} {{/if}}
{{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} {{else}}
<input type="hidden" name="damage.parts.{{realIndex}}.base" value="{{dmg.base}}"> {{#with (@root.getRealIndex index) as | realIndex |}}
{{#unless dmg.base}}<div class="fas fa-trash" data-action="removeDamage" data-index="{{realIndex}}"></div>{{/unless}} <fieldset{{#if dmg.base}} disabled{{/if}}>
</fieldset> {{#unless dmg.base}}
{{/with}} {{formField ../../fields.custom.fields.enabled value=dmg.custom.enabled name=(concat "damage.parts." realIndex ".custom.enabled")}}
{{/unless}}
{{#if dmg.custom.enabled}}
{{formField ../../fields.custom.fields.formula value=dmg.custom.formula name=(concat "damage.parts." realIndex ".custom.formula") localize=true}}
{{else}}
<div class="multi-display">
{{formField ../../fields.multiplier value=dmg.multiplier name=(concat "damage.parts." realIndex ".multiplier") localize=true}}
{{#if (eq dmg.multiplier 'flat')}}{{formField ../../fields.flatMultiplier value=dmg.flatMultiplier name=(concat "damage.parts." realIndex ".flatMultiplier") }}{{/if}}
{{formField ../../fields.dice value=dmg.dice name=(concat "damage.parts." realIndex ".dice")}}
{{formField ../../fields.bonus value=dmg.bonus name=(concat "damage.parts." realIndex ".bonus") localize=true}}
</div>
{{/if}}
{{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}}
<input type="hidden" name="damage.parts.{{realIndex}}.base" value="{{dmg.base}}">
{{#unless dmg.base}}<div class="fas fa-trash" data-action="removeDamage" data-index="{{realIndex}}"></div>{{/unless}}
</fieldset>
{{/with}}
{{/if}}
{{/each}} {{/each}}
</div> </div>
</fieldset> </fieldset>

View file

@ -3,15 +3,15 @@
<div>Range{{#if fields.target}} & Target{{/if}}</div> <div>Range{{#if fields.target}} & Target{{/if}}</div>
</legend> </legend>
<div class="action-category-data open"> <div class="action-category-data open">
{{formField fields.range value=source.range label="Range" name="range" localize=true}} {{formField fields.range value=source.range label="Range" name=(concat path "range") localize=true}}
</div> </div>
{{#if fields.target}} {{#if fields.target}}
<div class="action-category-data open"> <div class="action-category-data open">
<div class="multi-display"> <div class="multi-display">
{{#if (and source.target.type (not (eq source.target.type 'self')))}} {{#if (and source.target.type (not (eq source.target.type 'self')))}}
{{ formField fields.target.amount value=source.target.amount label="Amount" name="target.amount" }} {{ formField fields.target.amount value=source.target.amount label="Amount" name=(concat path "target.amount") }}
{{/if}} {{/if}}
{{ formField fields.target.type value=source.target.type label="Target" name="target.type" localize=true }} {{ formField fields.target.type value=source.target.type label="Target" name=(concat path "target.type") localize=true }}
</div> </div>
</div> </div>
{{/if}} {{/if}}

View file

@ -3,8 +3,12 @@
<div>Roll</div> <div>Roll</div>
</legend> </legend>
<div class="action-category-data open"> <div class="action-category-data open">
{{formField fields.type label="Type" name="roll.type" value=source.type localize=true}} {{#if @root.isNPC}}
{{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true}} {{formField fields.bonus label="Bonus" name="roll.bonus" value=source.bonus}}
{{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty}} {{else}}
{{formField fields.type label="Type" name="roll.type" value=source.type localize=true}}
{{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true}}
{{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty}}
{{/if}}
</div> </div>
</fieldset> </fieldset>