mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Merged with data-models-structure branch
This commit is contained in:
commit
d1c968d0a2
62 changed files with 1760 additions and 956 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,4 +3,5 @@ node_modules
|
|||
/packs
|
||||
Build
|
||||
/build
|
||||
foundry
|
||||
foundry
|
||||
styles/daggerheart.css
|
||||
115
daggerheart.mjs
115
daggerheart.mjs
|
|
@ -135,43 +135,24 @@ Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
|
|||
});
|
||||
|
||||
const renderDualityButton = async event => {
|
||||
const button = event.currentTarget;
|
||||
const attributeValue = button.dataset.attribute?.toLowerCase();
|
||||
|
||||
const target = getCommandTarget();
|
||||
const button = event.currentTarget,
|
||||
traitValue = button.dataset.trait?.toLowerCase(),
|
||||
target = getCommandTarget();
|
||||
if (!target) return;
|
||||
|
||||
const rollModifier = attributeValue ? target.system.attributes[attributeValue].data.value : null;
|
||||
const { roll, hope, fear, advantage, disadvantage, modifiers } = await target.diceRoll({
|
||||
title: button.dataset.label,
|
||||
value: rollModifier
|
||||
});
|
||||
|
||||
const systemData = new DHDualityRoll({
|
||||
title: button.dataset.label,
|
||||
origin: target.id,
|
||||
roll: roll._formula,
|
||||
modifiers: modifiers,
|
||||
hope: hope,
|
||||
fear: fear,
|
||||
advantage: advantage,
|
||||
disadvantage: disadvantage
|
||||
});
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msgData = {
|
||||
type: 'dualityRoll',
|
||||
sound: CONFIG.sounds.dice,
|
||||
system: systemData,
|
||||
user: game.user.id,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/chat/duality-roll.hbs',
|
||||
systemData
|
||||
),
|
||||
rolls: [roll]
|
||||
const config = {
|
||||
event: event,
|
||||
title: button.dataset.title,
|
||||
roll: {
|
||||
modifier: traitValue ? target.system.traits[traitValue].value : null,
|
||||
label: button.dataset.label,
|
||||
type: button.dataset.actionType ?? null // Need check
|
||||
},
|
||||
chatMessage: {
|
||||
template: 'systems/daggerheart/templates/chat/duality-roll.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
await cls.create(msgData);
|
||||
await target.diceRoll(config);
|
||||
};
|
||||
|
||||
Hooks.on('renderChatMessageHTML', (_, element) => {
|
||||
|
|
@ -200,64 +181,54 @@ Hooks.on('chatMessage', (_, message) => {
|
|||
return false;
|
||||
}
|
||||
|
||||
const attributeValue = rollCommand.attribute?.toLowerCase();
|
||||
const traitValue = rollCommand.trait?.toLowerCase();
|
||||
const advantageState = rollCommand.advantage ? true : rollCommand.disadvantage ? false : null;
|
||||
|
||||
// Target not required if an attribute is not used.
|
||||
const target = attributeValue ? getCommandTarget() : undefined;
|
||||
if (target || !attributeValue) {
|
||||
const target = traitValue ? getCommandTarget() : undefined;
|
||||
if (target || !traitValue) {
|
||||
new Promise(async (resolve, reject) => {
|
||||
const attribute = target ? target.system.attributes[attributeValue] : undefined;
|
||||
if (attributeValue && !attribute) {
|
||||
const trait = target ? target.system.traits[traitValue] : undefined;
|
||||
if (traitValue && !trait) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.AttributeFaulty'));
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
const title = attributeValue
|
||||
const title = traitValue
|
||||
? game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', {
|
||||
ability: game.i18n.localize(abilities[attributeValue].label)
|
||||
ability: game.i18n.localize(abilities[traitValue].label)
|
||||
})
|
||||
: game.i18n.localize('DAGGERHEART.General.Duality');
|
||||
|
||||
const hopeAndFearRoll = `1${rollCommand.hope ?? 'd12'}+1${rollCommand.fear ?? 'd12'}`;
|
||||
const advantageRoll = `${rollCommand.advantage && !rollCommand.disadvantage ? '+d6' : rollCommand.disadvantage && !rollCommand.advantage ? '-d6' : ''}`;
|
||||
const attributeRoll = `${attribute?.data?.value ? `${attribute.data.value > 0 ? `+${attribute.data.value}` : `${attribute.data.value}`}` : ''}`;
|
||||
const roll = new Roll(`${hopeAndFearRoll}${advantageRoll}${attributeRoll}`);
|
||||
await roll.evaluate();
|
||||
const advantageRoll = `${advantageState === true ? '+d6' : advantageState === false ? '-d6' : ''}`;
|
||||
const attributeRoll = `${trait?.value ? `${trait.value > 0 ? `+${trait.value}` : `${trait.value}`}` : ''}`;
|
||||
const roll = await Roll.create(`${hopeAndFearRoll}${advantageRoll}${attributeRoll}`).evaluate();
|
||||
|
||||
setDiceSoNiceForDualityRoll(
|
||||
roll,
|
||||
rollCommand.advantage && !rollCommand.disadvantage,
|
||||
rollCommand.disadvantage && !rollCommand.advantage
|
||||
);
|
||||
setDiceSoNiceForDualityRoll(roll, advantageState);
|
||||
|
||||
resolve({
|
||||
roll,
|
||||
attribute: attribute
|
||||
trait: trait
|
||||
? {
|
||||
value: attribute.data.value,
|
||||
label: `${game.i18n.localize(abilities[attributeValue].label)} ${attribute.data.value >= 0 ? `+` : ``}${attribute.data.value}`
|
||||
value: trait.value,
|
||||
label: `${game.i18n.localize(abilities[traitValue].label)} ${trait.value >= 0 ? `+` : ``}${trait.value}`
|
||||
}
|
||||
: undefined,
|
||||
title
|
||||
});
|
||||
}).then(async ({ roll, attribute, title }) => {
|
||||
}).then(async ({ roll, trait, title }) => {
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const systemData = new DHDualityRoll({
|
||||
title: title,
|
||||
origin: target?.id,
|
||||
roll: roll._formula,
|
||||
modifiers: attribute ? [attribute] : [],
|
||||
roll: roll,
|
||||
modifiers: trait ? [trait] : [],
|
||||
hope: { dice: rollCommand.hope ?? 'd12', value: roll.dice[0].total },
|
||||
fear: { dice: rollCommand.fear ?? 'd12', value: roll.dice[1].total },
|
||||
advantage:
|
||||
rollCommand.advantage && !rollCommand.disadvantage
|
||||
? { dice: 'd6', value: roll.dice[2].total }
|
||||
: undefined,
|
||||
disadvantage:
|
||||
rollCommand.disadvantage && !rollCommand.advantage
|
||||
? { dice: 'd6', value: roll.dice[2].total }
|
||||
: undefined
|
||||
advantage: advantageState !== null ? { dice: 'd6', value: roll.dice[2].total } : undefined,
|
||||
advantageState
|
||||
});
|
||||
|
||||
const msgData = {
|
||||
|
|
@ -265,10 +236,7 @@ Hooks.on('chatMessage', (_, message) => {
|
|||
sound: CONFIG.sounds.dice,
|
||||
system: systemData,
|
||||
user: game.user.id,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/chat/duality-roll.hbs',
|
||||
systemData
|
||||
),
|
||||
content: 'systems/daggerheart/templates/chat/duality-roll.hbs',
|
||||
rolls: [roll]
|
||||
};
|
||||
|
||||
|
|
@ -302,6 +270,15 @@ const preloadHandlebarsTemplates = async function () {
|
|||
'systems/daggerheart/templates/components/card-preview.hbs',
|
||||
'systems/daggerheart/templates/views/levelup/parts/selectable-card-preview.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
||||
'systems/daggerheart/templates/ui/combat/combatTrackerSection.hbs'
|
||||
'systems/daggerheart/templates/ui/combat/combatTrackerSection.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/damage.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/healing.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/resource.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/uuid.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/uses.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/roll.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/cost.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/range-target.hbs',
|
||||
'systems/daggerheart/templates/views/actionTypes/effect.hbs'
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
45
lang/en.json
45
lang/en.json
|
|
@ -146,6 +146,7 @@
|
|||
}
|
||||
},
|
||||
"General": {
|
||||
"Name": "Name",
|
||||
"Hope": "Hope",
|
||||
"Fear": "Fear",
|
||||
"Duality": "Duality",
|
||||
|
|
@ -478,6 +479,10 @@
|
|||
"twoHanded": "Two-Handed"
|
||||
},
|
||||
"Range": {
|
||||
"self": {
|
||||
"name": "Self",
|
||||
"description": "means yourself."
|
||||
},
|
||||
"melee": {
|
||||
"name": "Melee",
|
||||
"description": "means a character is within touching distance of the target. PCs can generally touch targets up to a few feet away from them, but melee range may be greater for especially large NPCs."
|
||||
|
|
@ -1284,10 +1289,48 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
"Tooltip": {
|
||||
"openItemWorld": "Open Item World",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"Actions": {
|
||||
"Types": {
|
||||
"Attack": {
|
||||
"Name": "Attack"
|
||||
},
|
||||
"Spellcast": {
|
||||
"Name": "Spellcast"
|
||||
},
|
||||
"Resource": {
|
||||
"Name": "Resource"
|
||||
},
|
||||
"Damage": {
|
||||
"Name": "Damage"
|
||||
},
|
||||
"Healing": {
|
||||
"Name": "Healing"
|
||||
},
|
||||
"Summon": {
|
||||
"Name": "Summon"
|
||||
},
|
||||
"Effect": {
|
||||
"Name": "Effect"
|
||||
},
|
||||
"Macro": {
|
||||
"Name": "Macro"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RollTypes": {
|
||||
"ability": {
|
||||
"name": "Ability"
|
||||
},
|
||||
"weapon": {
|
||||
"name": "Weapon"
|
||||
},
|
||||
"spellcast": {
|
||||
"name": "SpellCast"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import DHDualityRoll from '../data/chat-message/dualityRoll.mjs';
|
|||
|
||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||
async renderHTML() {
|
||||
if (this.type === 'dualityRoll' || this.type === 'adversaryRoll') {
|
||||
this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system);
|
||||
}
|
||||
|
||||
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
|
||||
const html = await super.renderHTML();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs';
|
||||
|
||||
const { ApplicationV2 } = foundry.applications.api;
|
||||
export default class DaggerheartActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||
export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||
constructor(action) {
|
||||
super({});
|
||||
|
||||
|
|
@ -9,21 +9,25 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
|
|||
this.openSection = null;
|
||||
}
|
||||
|
||||
// get title(){
|
||||
// return `Action - ${this.action.name}`;
|
||||
// }
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
id: 'daggerheart-action',
|
||||
classes: ['daggerheart', 'views', 'action'],
|
||||
position: { width: 600, height: 'auto' },
|
||||
actions: {
|
||||
toggleSection: this.toggleSection
|
||||
toggleSection: this.toggleSection,
|
||||
addEffect: this.addEffect,
|
||||
removeEffect: this.removeEffect,
|
||||
addElement: this.addElement,
|
||||
removeElement: this.removeElement,
|
||||
editEffect: this.editEffect,
|
||||
addDamage: this.addDamage,
|
||||
removeDamage: this.removeDamage
|
||||
},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
closeOnSubmit: true
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -36,16 +40,9 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
|
|||
|
||||
_getTabs() {
|
||||
const tabs = {
|
||||
effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' },
|
||||
useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' },
|
||||
conditions: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'conditions',
|
||||
icon: null,
|
||||
label: 'Conditions'
|
||||
}
|
||||
base: { active: true, cssClass: '', group: 'primary', id: 'base', icon: null, label: 'Base' },
|
||||
config: { active: false, cssClass: '', group: 'primary', id: 'config', icon: null, label: 'Configuration' },
|
||||
effect: { active: false, cssClass: '', group: 'primary', id: 'effect', icon: null, label: 'Effect' }
|
||||
};
|
||||
|
||||
for (const v of Object.values(tabs)) {
|
||||
|
|
@ -58,9 +55,13 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
|
|||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options, 'action');
|
||||
context.source = this.action.toObject(false);
|
||||
context.openSection = this.openSection;
|
||||
context.tabs = this._getTabs();
|
||||
|
||||
context.config = SYSTEM;
|
||||
if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id));
|
||||
if (this.action.damage?.hasOwnProperty('includeBase')) context.hasBaseDamage = !!this.action.parent.damage;
|
||||
context.getRealIndex = this.getRealIndex.bind(this);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -69,15 +70,91 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
|
|||
this.render(true);
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
const data = foundry.utils.expandObject(
|
||||
foundry.utils.mergeObject(this.action.toObject(), foundry.utils.expandObject(formData.object))
|
||||
);
|
||||
const newActions = this.action.parent.actions.map(x => x.toObject());
|
||||
if (!newActions.findSplice(x => x.id === data.id, data)) {
|
||||
newActions.push(data);
|
||||
}
|
||||
|
||||
await this.action.parent.parent.update({ 'system.actions': newActions });
|
||||
getRealIndex(index) {
|
||||
const data = this.action.toObject(false);
|
||||
return data.damage.parts.find(d => d.base) ? index - 1 : index;
|
||||
}
|
||||
|
||||
_prepareSubmitData(event, formData) {
|
||||
const submitData = foundry.utils.expandObject(formData.object);
|
||||
// this.element.querySelectorAll("fieldset[disabled] :is(input, select)").forEach(input => {
|
||||
// foundry.utils.setProperty(submitData, input.name, input.value);
|
||||
// });
|
||||
return submitData;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
const submitData = this._prepareSubmitData(event, formData),
|
||||
data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)),
|
||||
newActions = this.action.parent.actions.map(x => x.toObject()); // Find better way
|
||||
if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data);
|
||||
const updates = await this.action.parent.parent.update({ 'system.actions': newActions });
|
||||
if (!updates) return;
|
||||
this.action = updates.system.actions[this.action.index];
|
||||
this.render();
|
||||
}
|
||||
|
||||
static addElement(event) {
|
||||
const data = this.action.toObject(),
|
||||
key = event.target.closest('.action-category-data').dataset.key;
|
||||
if (!this.action[key]) return;
|
||||
data[key].push({});
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
static removeElement(event) {
|
||||
const data = this.action.toObject(),
|
||||
key = event.target.closest('.action-category-data').dataset.key,
|
||||
index = event.target.dataset.index;
|
||||
data[key].splice(index, 1);
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
static addDamage(event) {
|
||||
if (!this.action.damage.parts) return;
|
||||
const data = this.action.toObject();
|
||||
data.damage.parts.push({});
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
static removeDamage(event) {
|
||||
if (!this.action.damage.parts) return;
|
||||
const data = this.action.toObject(),
|
||||
index = event.target.dataset.index;
|
||||
data.damage.parts.splice(index, 1);
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
static async addEffect(event) {
|
||||
if (!this.action.effects) return;
|
||||
const effectData = this._addEffectData.bind(this)(),
|
||||
[created] = await this.action.item.createEmbeddedDocuments('ActiveEffect', [effectData], { render: false }),
|
||||
data = this.action.toObject();
|
||||
data.effects.push({ _id: created._id });
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
/**
|
||||
* The data for a newly created applied effect.
|
||||
* @returns {object}
|
||||
* @protected
|
||||
*/
|
||||
_addEffectData() {
|
||||
return {
|
||||
name: this.action.item.name,
|
||||
img: this.action.item.img,
|
||||
origin: this.action.item.uuid,
|
||||
transfer: false
|
||||
};
|
||||
}
|
||||
|
||||
static removeEffect(event) {
|
||||
if (!this.action.effects) return;
|
||||
const index = event.target.dataset.index,
|
||||
effectId = this.action.effects[index]._id;
|
||||
this.constructor.removeElement.bind(this)(event);
|
||||
this.action.item.deleteEmbeddedDocuments('ActiveEffect', [effectId]);
|
||||
}
|
||||
|
||||
static editEffect(event) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export default class NpcRollSelectionDialog extends HandlebarsApplicationMixin(A
|
|||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize('DAGGERHEART.Application.Settings.Title');
|
||||
return game.i18n.localize('DAGGERHEART.Application.RollSelection.Title');
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
hope: ['d12'],
|
||||
fear: ['d12'],
|
||||
advantage: null,
|
||||
disadvantage: null,
|
||||
hopeResource: hopeResource
|
||||
};
|
||||
}
|
||||
|
|
@ -30,9 +29,8 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
height: 'auto'
|
||||
},
|
||||
actions: {
|
||||
updateIsAdvantage: this.updateIsAdvantage,
|
||||
selectExperience: this.selectExperience,
|
||||
setAdvantage: this.setAdvantage,
|
||||
setDisadvantage: this.setDisadvantage,
|
||||
finish: this.finish
|
||||
},
|
||||
form: {
|
||||
|
|
@ -61,7 +59,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
context.hope = this.data.hope;
|
||||
context.fear = this.data.fear;
|
||||
context.advantage = this.data.advantage;
|
||||
context.disadvantage = this.data.disadvantage;
|
||||
context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] }));
|
||||
context.hopeResource = this.data.hopeResource + 1;
|
||||
|
||||
|
|
@ -85,18 +82,10 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
this.render();
|
||||
}
|
||||
|
||||
static setAdvantage() {
|
||||
this.data.advantage = this.data.advantage ? null : 'd6';
|
||||
this.data.disadvantage = null;
|
||||
|
||||
this.render(true);
|
||||
}
|
||||
|
||||
static setDisadvantage() {
|
||||
this.data.advantage = null;
|
||||
this.data.disadvantage = this.data.disadvantage ? null : 'd6';
|
||||
|
||||
this.render(true);
|
||||
static updateIsAdvantage(_, button) {
|
||||
const advantage = Boolean(button.dataset.advantage);
|
||||
this.data.advantage = this.data.advantage === advantage ? null : advantage;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async finish() {
|
||||
|
|
|
|||
|
|
@ -166,8 +166,6 @@ class DhpRangeSettings extends FormApplication {
|
|||
}
|
||||
|
||||
export const registerDHSettings = () => {
|
||||
// const debouncedReload = foundry.utils.debounce(() => window.location.reload(), 100);
|
||||
|
||||
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray, {
|
||||
name: game.i18n.localize('DAGGERHEART.Settings.General.AbilityArray.Name'),
|
||||
hint: game.i18n.localize('DAGGERHEART.Settings.General.AbilityArray.Hint'),
|
||||
|
|
@ -274,7 +272,7 @@ export const registerDHSettings = () => {
|
|||
name: game.i18n.localize('DAGGERHEART.Settings.DualityRollColor.Name'),
|
||||
hint: game.i18n.localize('DAGGERHEART.Settings.DualityRollColor.Hint'),
|
||||
scope: 'world',
|
||||
config: true,
|
||||
config: false,
|
||||
type: Number,
|
||||
choices: Object.values(DualityRollColor),
|
||||
default: DualityRollColor.colorful.value
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
|
||||
static async save() {
|
||||
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance, this.settings.toObject());
|
||||
const reload = await foundry.applications.api.DialogV2.confirm({
|
||||
id: 'reload-world-confirm',
|
||||
modal: true,
|
||||
rejectClose: false,
|
||||
window: { title: 'SETTINGS.ReloadPromptTitle' },
|
||||
position: { width: 400 },
|
||||
content: `<p>${game.i18n.localize('SETTINGS.ReloadPromptBody')}</p>`
|
||||
});
|
||||
|
||||
if (reload) {
|
||||
await game.socket.emit('reload');
|
||||
foundry.utils.debouncedReload();
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,70 +61,42 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
}
|
||||
|
||||
static async reactionRoll(event) {
|
||||
const { roll, diceResults, modifiers } = await this.actor.diceRoll(
|
||||
{ title: `${this.actor.name} - Reaction Roll`, value: 0 },
|
||||
event.shiftKey
|
||||
);
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const systemData = {
|
||||
roll: roll._formula,
|
||||
total: roll._total,
|
||||
modifiers: modifiers,
|
||||
diceResults: diceResults
|
||||
const config = {
|
||||
event: event,
|
||||
title: `${this.actor.name} - Reaction Roll`,
|
||||
roll: {
|
||||
modifier: null,
|
||||
type: 'reaction'
|
||||
},
|
||||
chatMessage: {
|
||||
type: 'adversaryRoll',
|
||||
template: 'systems/daggerheart/templates/chat/adversary-roll.hbs',
|
||||
mute: true
|
||||
}
|
||||
};
|
||||
const msg = new cls({
|
||||
type: 'adversaryRoll',
|
||||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/chat/adversary-roll.hbs',
|
||||
systemData
|
||||
),
|
||||
rolls: [roll]
|
||||
});
|
||||
|
||||
cls.create(msg.toObject());
|
||||
this.actor.diceRoll(config);
|
||||
}
|
||||
|
||||
static async attackRoll() {
|
||||
const { modifier, damage, name: attackName } = this.actor.system.attack;
|
||||
const { roll, dice, advantageState, modifiers } = await this.actor.diceRoll(
|
||||
{ title: `${this.actor.name} - Attack Roll`, value: modifier },
|
||||
event.shiftKey
|
||||
);
|
||||
|
||||
const targets = Array.from(game.user.targets).map(x => ({
|
||||
id: x.id,
|
||||
name: x.actor.name,
|
||||
img: x.actor.img,
|
||||
difficulty: x.actor.system.difficulty,
|
||||
evasion: x.actor.system.evasion
|
||||
}));
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const systemData = {
|
||||
title: attackName,
|
||||
origin: this.document.id,
|
||||
roll: roll._formula,
|
||||
advantageState,
|
||||
total: roll._total,
|
||||
modifiers: modifiers,
|
||||
dice: dice,
|
||||
targets: targets,
|
||||
damage: { value: damage.value, type: damage.type }
|
||||
};
|
||||
const msg = new cls({
|
||||
type: 'adversaryRoll',
|
||||
sound: CONFIG.sounds.dice,
|
||||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/chat/adversary-attack-roll.hbs',
|
||||
systemData
|
||||
),
|
||||
rolls: [roll]
|
||||
});
|
||||
|
||||
cls.create(msg.toObject());
|
||||
static async attackRoll(event) {
|
||||
const { modifier, damage, name: attackName } = this.actor.system.attack,
|
||||
config = {
|
||||
event: event,
|
||||
title: attackName,
|
||||
roll: {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
selectAncestry: this.selectAncestry,
|
||||
selectCommunity: this.selectCommunity,
|
||||
viewObject: this.viewObject,
|
||||
useItem: this.useItem,
|
||||
useFeature: this.useFeature,
|
||||
takeShortRest: this.takeShortRest,
|
||||
takeLongRest: this.takeLongRest,
|
||||
|
|
@ -150,6 +151,10 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
super._attachPartListeners(partId, htmlElement, options);
|
||||
|
||||
htmlElement.querySelector('.level-value').addEventListener('change', this.onLevelChange.bind(this));
|
||||
// To Remove when ContextMenu Handler is made
|
||||
htmlElement
|
||||
.querySelectorAll('[data-item-id]')
|
||||
.forEach(element => element.addEventListener('contextmenu', this.editItem.bind(this)));
|
||||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
|
|
@ -280,7 +285,24 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
}
|
||||
|
||||
static async rollAttribute(event, button) {
|
||||
const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll(
|
||||
const abilityLabel = game.i18n.localize(abilities[button.dataset.attribute].label);
|
||||
const config = {
|
||||
event: event,
|
||||
title: game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', {
|
||||
ability: abilityLabel
|
||||
}),
|
||||
roll: {
|
||||
label: abilityLabel,
|
||||
modifier: button.dataset.value
|
||||
},
|
||||
chatMessage: {
|
||||
template: 'systems/daggerheart/templates/chat/duality-roll.hbs'
|
||||
}
|
||||
};
|
||||
this.document.diceRoll(config);
|
||||
|
||||
// Delete when new roll logic test done
|
||||
/* const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll(
|
||||
{ title: game.i18n.localize(abilities[button.dataset.attribute].label), value: button.dataset.value },
|
||||
event.shiftKey
|
||||
);
|
||||
|
|
@ -310,7 +332,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
systemContent
|
||||
),
|
||||
rolls: [roll]
|
||||
});
|
||||
}); */
|
||||
}
|
||||
|
||||
static async toggleMarks(_, button) {
|
||||
|
|
@ -348,51 +370,8 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
|
||||
static async attackRoll(event, button) {
|
||||
const weapon = await fromUuid(button.dataset.weapon);
|
||||
const damage = {
|
||||
value: `${this.document.system.proficiency}${weapon.system.damage.value}`,
|
||||
type: weapon.system.damage.type
|
||||
};
|
||||
const modifier = this.document.system.traits[weapon.system.trait].value;
|
||||
|
||||
const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll(
|
||||
{ title: game.i18n.localize(abilities[weapon.system.trait].label), value: modifier },
|
||||
event.shiftKey
|
||||
);
|
||||
|
||||
const targets = Array.from(game.user.targets).map(x => ({
|
||||
id: x.id,
|
||||
name: x.actor.name,
|
||||
img: x.actor.img,
|
||||
difficulty: x.actor.system.difficulty,
|
||||
evasion: x.actor.system.evasion
|
||||
}));
|
||||
|
||||
const systemData = new DHDualityRoll({
|
||||
title: weapon.name,
|
||||
origin: this.document.id,
|
||||
roll: roll._formula,
|
||||
modifiers: modifiers,
|
||||
hope: hope,
|
||||
fear: fear,
|
||||
advantage: advantage,
|
||||
disadvantage: disadvantage,
|
||||
damage: damage,
|
||||
targets: targets
|
||||
});
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = new cls({
|
||||
type: 'dualityRoll',
|
||||
sound: CONFIG.sounds.dice,
|
||||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/chat/attack-roll.hbs',
|
||||
systemData
|
||||
),
|
||||
rolls: [roll]
|
||||
});
|
||||
|
||||
await cls.create(msg.toObject());
|
||||
if (!weapon) return;
|
||||
weapon.use(event);
|
||||
}
|
||||
|
||||
static openLevelUp() {
|
||||
|
|
@ -470,6 +449,12 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
(await game.packs.get('daggerheart.communities'))?.render(true);
|
||||
}
|
||||
|
||||
static useItem(event) {
|
||||
const uuid = event.target.closest('[data-item-id]').dataset.itemId,
|
||||
item = this.document.items.find(i => i.uuid === uuid);
|
||||
item.use(event);
|
||||
}
|
||||
|
||||
static async viewObject(_, button) {
|
||||
const object = await fromUuid(button.dataset.value);
|
||||
if (!object) return;
|
||||
|
|
@ -482,6 +467,16 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
object.sheet.render(true);
|
||||
}
|
||||
|
||||
editItem(event) {
|
||||
const uuid = event.target.closest('[data-item-id]').dataset.itemId,
|
||||
item = this.document.items.find(i => i.uuid === uuid);
|
||||
if (!item) return;
|
||||
|
||||
if (item.sheet.editMode) item.sheet.editMode = false;
|
||||
|
||||
item.sheet.render(true);
|
||||
}
|
||||
|
||||
static async takeShortRest() {
|
||||
await new DhpDowntime(this.document, true).render(true);
|
||||
await this.minimize();
|
||||
|
|
|
|||
132
module/applications/sheets/item.mjs
Normal file
132
module/applications/sheets/item.mjs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import DhpApplicationMixin from './daggerheart-sheet.mjs';
|
||||
import DHActionConfig from '../config/Action.mjs';
|
||||
import { actionsTypes } from '../../data/_module.mjs';
|
||||
|
||||
export default function DHItemMixin(Base) {
|
||||
return class DHItemSheetV2 extends DhpApplicationMixin(Base) {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style'],
|
||||
position: { width: 600 },
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
},
|
||||
actions: {
|
||||
addAction: this.addAction,
|
||||
editAction: this.editAction,
|
||||
removeAction: this.removeAction
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
actions: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'actions',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Actions'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.config = CONFIG.daggerheart;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async selectActionType() {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/views/actionType.hbs',
|
||||
{ types: SYSTEM.ACTIONS.actionTypes }
|
||||
),
|
||||
title = 'Select Action Type',
|
||||
type = 'form',
|
||||
data = {};
|
||||
return Dialog.prompt({
|
||||
title,
|
||||
label: title,
|
||||
content,
|
||||
type,
|
||||
callback: html => {
|
||||
const form = html[0].querySelector('form'),
|
||||
fd = new foundry.applications.ux.FormDataExtended(form);
|
||||
foundry.utils.mergeObject(data, fd.object, { inplace: true });
|
||||
// if (!data.name?.trim()) data.name = game.i18n.localize(SYSTEM.ACTIONS.actionTypes[data.type].name);
|
||||
return data;
|
||||
},
|
||||
rejectClose: false
|
||||
});
|
||||
}
|
||||
|
||||
static async addAction() {
|
||||
const actionType = await DHItemSheetV2.selectActionType(),
|
||||
actionIndexes = this.document.system.actions.map(x => x._id.split('-')[2]).sort((a, b) => a - b);
|
||||
try {
|
||||
const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack,
|
||||
action = new cls(
|
||||
{
|
||||
// id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0] + 1 : 1}`
|
||||
_id: foundry.utils.randomID(),
|
||||
type: actionType.type,
|
||||
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
|
||||
...cls.getSourceConfig(this.document)
|
||||
},
|
||||
{
|
||||
parent: this.document
|
||||
}
|
||||
);
|
||||
await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
|
||||
await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(
|
||||
true
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
static async editAction(_, button) {
|
||||
const action = this.document.system.actions[button.dataset.index];
|
||||
await new DHActionConfig(action).render(true);
|
||||
}
|
||||
|
||||
static async removeAction(event, button) {
|
||||
event.stopPropagation();
|
||||
await this.document.update({
|
||||
'system.actions': this.document.system.actions.filter(
|
||||
(_, index) => index !== Number.parseInt(button.dataset.index)
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,16 +1,9 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class ArmorSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'armor'],
|
||||
position: { width: 600 },
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
},
|
||||
classes: ['armor'],
|
||||
dragDrop: [{ dragSelector: null, dropSelector: null }]
|
||||
};
|
||||
|
||||
|
|
@ -18,42 +11,13 @@ export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
header: { template: 'systems/daggerheart/templates/sheets/items/armor/header.hbs' },
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' },
|
||||
actions: {
|
||||
template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs',
|
||||
scrollable: ['.actions']
|
||||
},
|
||||
settings: {
|
||||
template: 'systems/daggerheart/templates/sheets/items/armor/settings.hbs',
|
||||
scrollable: ['.settings']
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.config = CONFIG.daggerheart;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,23 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class ConsumableSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class ConsumableSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'consumable'],
|
||||
position: { width: 550 },
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
classes: ['consumable'],
|
||||
position: { width: 550 }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
header: { template: 'systems/daggerheart/templates/sheets/items/consumable/header.hbs' },
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' },
|
||||
actions: {
|
||||
template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs',
|
||||
scrollable: ['.actions']
|
||||
},
|
||||
settings: {
|
||||
template: 'systems/daggerheart/templates/sheets/items/consumable/settings.hbs',
|
||||
scrollable: ['.settings']
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,10 @@
|
|||
import DaggerheartAction from '../../../data/action.mjs';
|
||||
import DaggerheartActionConfig from '../../config/Action.mjs';
|
||||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class DomainCardSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'domain-card'],
|
||||
position: { width: 450, height: 700 },
|
||||
actions: {
|
||||
addAction: this.addAction,
|
||||
editAction: this.editAction,
|
||||
removeAction: this.removeAction
|
||||
},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
classes: ['domain-card'],
|
||||
position: { width: 450, height: 700 }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -33,74 +20,4 @@ export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
scrollable: ['.settings']
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
actions: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'actions',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Actions'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.config = CONFIG.daggerheart;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async addAction() {
|
||||
const actionIndexes = this.document.system.actions.map(x => x.id.split('-')[2]).sort((a, b) => a - b);
|
||||
const action = await new DaggerheartAction(
|
||||
{
|
||||
id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0] + 1 : 1}`
|
||||
},
|
||||
{
|
||||
parent: this.document
|
||||
}
|
||||
);
|
||||
await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
|
||||
await new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
static async editAction(_, button) {
|
||||
const action = this.document.system.actions[button.dataset.index];
|
||||
await new DaggerheartActionConfig(action).render(true);
|
||||
}
|
||||
|
||||
static async removeAction(event, button) {
|
||||
event.stopPropagation();
|
||||
await this.document.update({
|
||||
'system.actions': this.document.system.actions.filter(
|
||||
(_, index) => index !== Number.parseInt(button.dataset.index)
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import DaggerheartAction from '../../../data/action.mjs';
|
||||
import DaggerheartActionConfig from '../../config/Action.mjs';
|
||||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class FeatureSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
|
||||
|
|
@ -11,22 +9,13 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
id: 'daggerheart-feature',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'feature'],
|
||||
classes: ['feature'],
|
||||
position: { width: 600, height: 600 },
|
||||
window: { resizable: true },
|
||||
actions: {
|
||||
addEffect: this.addEffect,
|
||||
removeEffect: this.removeEffect,
|
||||
addAction: this.addAction,
|
||||
editAction: this.editAction,
|
||||
removeAction: this.removeAction
|
||||
},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
removeEffect: this.removeEffect
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -49,30 +38,7 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
actions: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'actions',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Actions'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
},
|
||||
...super.TABS,
|
||||
effects: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
|
|
@ -102,11 +68,6 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
effectSelect(event) {
|
||||
this.selectedEffectType = event.currentTarget.value;
|
||||
this.render(true);
|
||||
|
|
@ -130,26 +91,4 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
|
|||
const path = `system.effects.-=${button.dataset.effect}`;
|
||||
await this.item.update({ [path]: null });
|
||||
}
|
||||
|
||||
static async addAction() {
|
||||
const action = await new DaggerheartAction({ img: this.document.img }, { parent: this.document });
|
||||
await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
|
||||
await new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
static async editAction(_, button) {
|
||||
const action = this.document.system.actions[button.dataset.index];
|
||||
await new DaggerheartActionConfig(action).render(true);
|
||||
}
|
||||
|
||||
static async removeAction(event, button) {
|
||||
event.stopPropagation();
|
||||
await this.document.update({
|
||||
'system.actions': this.document.system.actions.filter(
|
||||
(_, index) => index !== Number.parseInt(button.dataset.index)
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,23 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class MiscellaneousSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class MiscellaneousSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'miscellaneous'],
|
||||
position: { width: 550 },
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
classes: ['miscellaneous'],
|
||||
position: { width: 550 }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
header: { template: 'systems/daggerheart/templates/sheets/items/miscellaneous/header.hbs' },
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' },
|
||||
actions: {
|
||||
template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs',
|
||||
scrollable: ['.actions']
|
||||
},
|
||||
settings: {
|
||||
template: 'systems/daggerheart/templates/sheets/items/miscellaneous/settings.hbs',
|
||||
scrollable: ['.settings']
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,22 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHItemSheetV2 from '../item.mjs';
|
||||
|
||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||
export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) {
|
||||
export default class WeaponSheet extends DHItemSheetV2(ItemSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'weapon'],
|
||||
position: { width: 600 },
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
classes: ['weapon']
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
header: { template: 'systems/daggerheart/templates/sheets/items/weapon/header.hbs' },
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' },
|
||||
actions: {
|
||||
template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs',
|
||||
scrollable: ['.actions']
|
||||
},
|
||||
settings: {
|
||||
template: 'systems/daggerheart/templates/sheets/items/weapon/settings.hbs',
|
||||
scrollable: ['.settings']
|
||||
}
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
description: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'description',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Description'
|
||||
},
|
||||
settings: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'settings',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Feature.Tabs.Settings'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.config = CONFIG.daggerheart;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,43 @@
|
|||
export const actionTypes = {
|
||||
attack: {
|
||||
id: 'attack',
|
||||
name: 'DAGGERHEART.Actions.Types.Attack.Name',
|
||||
icon: 'fa-swords'
|
||||
},
|
||||
spellcast: {
|
||||
id: 'spellcast',
|
||||
name: 'DAGGERHEART.Actions.Types.Spellcast.Name',
|
||||
icon: 'fa-book-sparkles'
|
||||
},
|
||||
healing: {
|
||||
id: 'healing',
|
||||
name: 'DAGGERHEART.Actions.Types.Healing.Name',
|
||||
icon: 'fa-kit-medical'
|
||||
},
|
||||
resource: {
|
||||
id: 'resource',
|
||||
name: 'DAGGERHEART.Actions.Types.Resource.Name',
|
||||
icon: 'fa-honey-pot'
|
||||
},
|
||||
damage: {
|
||||
id: 'damage',
|
||||
name: 'DAGGERHEART.Effects.Types.Health.Name'
|
||||
name: 'DAGGERHEART.Actions.Types.Damage.Name',
|
||||
icon: 'fa-bone-break'
|
||||
},
|
||||
summon: {
|
||||
id: 'summon',
|
||||
name: 'DAGGERHEART.Actions.Types.Summon.Name',
|
||||
icon: 'fa-ghost'
|
||||
},
|
||||
effect: {
|
||||
id: 'effect',
|
||||
name: 'DAGGERHEART.Actions.Types.Effect.Name',
|
||||
icon: 'fa-person-rays'
|
||||
},
|
||||
macro: {
|
||||
id: 'macro',
|
||||
name: 'DAGGERHEART.Actions.Types.Macro.Name',
|
||||
icon: 'fa-scroll'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
export const range = {
|
||||
self: {
|
||||
label: 'DAGGERHEART.Range.self.name',
|
||||
description: 'DAGGERHEART.Range.self.description',
|
||||
distance: 0
|
||||
},
|
||||
melee: {
|
||||
id: 'melee',
|
||||
label: 'DAGGERHEART.Range.melee.name',
|
||||
|
|
@ -248,6 +253,11 @@ export const diceTypes = {
|
|||
d20: 'd20'
|
||||
};
|
||||
|
||||
export const multiplierTypes = {
|
||||
proficiency: 'Proficiency',
|
||||
spellcast: 'Spellcast'
|
||||
};
|
||||
|
||||
export const getDiceSoNicePresets = () => {
|
||||
const { diceSoNice } = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance);
|
||||
|
||||
|
|
@ -312,3 +322,18 @@ export const abilityCosts = {
|
|||
label: 'Stress'
|
||||
}
|
||||
};
|
||||
|
||||
export const rollTypes = {
|
||||
weapon: {
|
||||
id: 'weapon',
|
||||
label: 'DAGGERHEART.RollTypes.weapon.name'
|
||||
},
|
||||
spellcast: {
|
||||
id: 'spellcast',
|
||||
label: 'DAGGERHEART.RollTypes.spellcast.name'
|
||||
},
|
||||
ability: {
|
||||
id: 'ability',
|
||||
label: 'DAGGERHEART.RollTypes.ability.name'
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export { default as DhCombatant } from './combatant.mjs';
|
|||
|
||||
export * as actors from './actor/_module.mjs';
|
||||
export * as items from './item/_module.mjs';
|
||||
export { actionsTypes } from './action/_module.mjs';
|
||||
export * as messages from './chat-message/_modules.mjs';
|
||||
export * as fields from './fields/_module.mjs';
|
||||
export * as pseudoDocuments from './pseudo-documents/_module.mjs';
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
export default class DaggerheartAction extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
id: new fields.DocumentIdField(),
|
||||
name: new fields.StringField({ initial: 'New Action' }),
|
||||
damage: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }),
|
||||
value: new fields.StringField({})
|
||||
}),
|
||||
healing: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }),
|
||||
value: new fields.StringField()
|
||||
}),
|
||||
conditions: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField(),
|
||||
icon: new fields.StringField(),
|
||||
description: new fields.StringField()
|
||||
})
|
||||
),
|
||||
cost: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }),
|
||||
value: new fields.NumberField({ nullable: true, initial: null })
|
||||
}),
|
||||
target: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.ACTIONS.targetTypes,
|
||||
initial: SYSTEM.ACTIONS.targetTypes.other.id
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
23
module/data/action/_module.mjs
Normal file
23
module/data/action/_module.mjs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
DHAttackAction,
|
||||
DHBaseAction,
|
||||
DHDamageAction,
|
||||
DHEffectAction,
|
||||
DHHealingAction,
|
||||
DHMacroAction,
|
||||
DHResourceAction,
|
||||
DHSpellCastAction,
|
||||
DHSummonAction
|
||||
} from './action.mjs';
|
||||
|
||||
export const actionsTypes = {
|
||||
base: DHBaseAction,
|
||||
attack: DHAttackAction,
|
||||
spellcast: DHSpellCastAction,
|
||||
resource: DHResourceAction,
|
||||
damage: DHDamageAction,
|
||||
healing: DHHealingAction,
|
||||
summon: DHSummonAction,
|
||||
effect: DHEffectAction,
|
||||
macro: DHMacroAction
|
||||
};
|
||||
386
module/data/action/action.mjs
Normal file
386
module/data/action/action.mjs
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
import { abilities } from '../../config/actorConfig.mjs';
|
||||
import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs';
|
||||
|
||||
export default class DHAction extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
id: new fields.DocumentIdField(),
|
||||
name: new fields.StringField({ initial: 'New Action' }),
|
||||
damage: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }),
|
||||
value: new fields.StringField({})
|
||||
}),
|
||||
healing: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }),
|
||||
value: new fields.StringField()
|
||||
}),
|
||||
conditions: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField(),
|
||||
icon: new fields.StringField(),
|
||||
description: new fields.StringField()
|
||||
})
|
||||
),
|
||||
cost: new fields.SchemaField({
|
||||
type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }),
|
||||
value: new fields.NumberField({ nullable: true, initial: null })
|
||||
}),
|
||||
target: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.ACTIONS.targetTypes,
|
||||
initial: SYSTEM.ACTIONS.targetTypes.other.id
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
/*
|
||||
ToDo
|
||||
- Apply ActiveEffect => Add to Chat message like Damage Button ?
|
||||
- Add Drag & Drop for documentUUID field (Macro & Summon)
|
||||
- Add optionnal Role for Healing ?
|
||||
- Handle Roll result as part of formula if needed
|
||||
- Target Check
|
||||
- Cost Check
|
||||
- Range Check
|
||||
- Area of effect and measurement placement
|
||||
- Auto use costs and action
|
||||
*/
|
||||
|
||||
export class DHBaseAction extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
_id: new fields.DocumentIdField(),
|
||||
type: new fields.StringField({ initial: undefined, readonly: true, required: true }),
|
||||
name: new fields.StringField({ initial: undefined }),
|
||||
img: new fields.FilePathField({ initial: undefined, categories: ['IMAGE'], base64: false }),
|
||||
actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: 'action', nullable: true }),
|
||||
cost: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.abilityCosts,
|
||||
nullable: false,
|
||||
required: true,
|
||||
initial: 'hope'
|
||||
}),
|
||||
value: new fields.NumberField({ nullable: true, initial: 1 }),
|
||||
scalable: new fields.BooleanField({ initial: false }),
|
||||
step: new fields.NumberField({ nullable: true, initial: null })
|
||||
})
|
||||
),
|
||||
uses: new fields.SchemaField({
|
||||
value: new fields.NumberField({ nullable: true, initial: null }),
|
||||
max: new fields.NumberField({ nullable: true, initial: null }),
|
||||
recovery: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.refreshTypes,
|
||||
initial: null,
|
||||
nullable: true
|
||||
})
|
||||
}),
|
||||
range: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.range,
|
||||
required: true,
|
||||
blank: false,
|
||||
initial: 'self'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
prepareData() {}
|
||||
|
||||
get index() {
|
||||
return this.parent.actions.indexOf(this);
|
||||
}
|
||||
|
||||
get item() {
|
||||
return this.parent.parent;
|
||||
}
|
||||
|
||||
get actor() {
|
||||
return this.item?.actor;
|
||||
}
|
||||
|
||||
get chatTemplate() {
|
||||
return 'systems/daggerheart/templates/chat/attack-roll.hbs';
|
||||
}
|
||||
|
||||
static getRollType() {
|
||||
return 'ability';
|
||||
}
|
||||
|
||||
static getSourceConfig(parent) {
|
||||
const updateSource = {};
|
||||
updateSource.img ??= parent?.img ?? parent?.system?.img;
|
||||
if (parent?.system?.trait) {
|
||||
updateSource['roll'] = {
|
||||
type: this.getRollType(),
|
||||
trait: parent.system.trait
|
||||
};
|
||||
}
|
||||
if (parent?.system?.range) {
|
||||
updateSource['range'] = parent?.system?.range;
|
||||
}
|
||||
return updateSource;
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
if (this.roll.type && this.roll.trait) {
|
||||
const modifierValue = this.actor.system.traits[this.roll.trait].value;
|
||||
const config = {
|
||||
event: event,
|
||||
title: this.item.name,
|
||||
roll: {
|
||||
modifier: modifierValue,
|
||||
label: game.i18n.localize(abilities[this.roll.trait].label),
|
||||
type: this.actionType,
|
||||
difficulty: this.roll?.difficulty
|
||||
},
|
||||
chatMessage: {
|
||||
template: this.chatTemplate
|
||||
}
|
||||
};
|
||||
if (this.target?.type) config.checkTarget = true;
|
||||
if (this.damage.parts.length) {
|
||||
config.damage = {
|
||||
value: this.damage.parts.map(p => p.getFormula(this.actor)).join(' + '),
|
||||
type: this.damage.parts[0].type
|
||||
};
|
||||
}
|
||||
if (this.effects.length) {
|
||||
// Apply Active Effects. In Chat Message ?
|
||||
}
|
||||
return this.actor.diceRoll(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const extraDefineSchema = (field, option) => {
|
||||
return {
|
||||
[field]: {
|
||||
// damage: new fields.SchemaField({
|
||||
// parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData))
|
||||
// }),
|
||||
damage: new DHDamageField(option),
|
||||
roll: new fields.SchemaField({
|
||||
type: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.GENERAL.rollTypes }),
|
||||
trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }),
|
||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 })
|
||||
}),
|
||||
target: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.ACTIONS.targetTypes,
|
||||
initial: SYSTEM.ACTIONS.targetTypes.other.id
|
||||
})
|
||||
}),
|
||||
effects: new fields.ArrayField( // ActiveEffect
|
||||
new fields.SchemaField({
|
||||
_id: new fields.DocumentIdField()
|
||||
})
|
||||
)
|
||||
}[field]
|
||||
};
|
||||
};
|
||||
|
||||
export class DHAttackAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
...extraDefineSchema('damage', true),
|
||||
...extraDefineSchema('roll'),
|
||||
...extraDefineSchema('target'),
|
||||
...extraDefineSchema('effects')
|
||||
};
|
||||
}
|
||||
|
||||
static getRollType() {
|
||||
return 'weapon';
|
||||
}
|
||||
|
||||
prepareData() {
|
||||
super.prepareData();
|
||||
if (this.damage.includeBase && !!this.item?.system?.damage) {
|
||||
const baseDamage = this.getParentDamage();
|
||||
this.damage.parts.unshift(new DHDamageData(baseDamage));
|
||||
}
|
||||
}
|
||||
|
||||
getParentDamage() {
|
||||
return {
|
||||
multiplier: 'proficiency',
|
||||
dice: this.item?.system?.damage.value,
|
||||
bonus: this.item?.system?.damage.bonus ?? 0,
|
||||
type: this.item?.system?.damage.type,
|
||||
base: true
|
||||
};
|
||||
}
|
||||
|
||||
// Temporary until full formula parser
|
||||
// getDamageFormula() {
|
||||
// return this.damage.parts.map(p => p.formula).join(' + ');
|
||||
// }
|
||||
}
|
||||
|
||||
export class DHSpellCastAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
...extraDefineSchema('damage'),
|
||||
...extraDefineSchema('roll'),
|
||||
...extraDefineSchema('target'),
|
||||
...extraDefineSchema('effects')
|
||||
};
|
||||
}
|
||||
|
||||
static getRollType() {
|
||||
return 'spellcast';
|
||||
}
|
||||
}
|
||||
|
||||
export class DHDamageAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
...extraDefineSchema('damage', false),
|
||||
...extraDefineSchema('target'),
|
||||
...extraDefineSchema('effects')
|
||||
};
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
const formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + ');
|
||||
if (!formula || formula == '') return;
|
||||
|
||||
let roll = { formula: formula, total: formula };
|
||||
if (isNaN(formula)) {
|
||||
roll = await new Roll(formula).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.total,
|
||||
type: this.damage.parts.map(p => p.type)
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
cls.create(msg.toObject());
|
||||
}
|
||||
}
|
||||
|
||||
export class DHHealingAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
healing: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.healingTypes,
|
||||
required: true,
|
||||
blank: false,
|
||||
initial: SYSTEM.GENERAL.healingTypes.health.id,
|
||||
label: 'Healing'
|
||||
}),
|
||||
value: new fields.EmbeddedDataField(DHActionDiceData)
|
||||
}),
|
||||
...extraDefineSchema('target'),
|
||||
...extraDefineSchema('effects')
|
||||
};
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
const formula = this.healing.value.getFormula(this.actor);
|
||||
if (!formula || formula == '') return;
|
||||
|
||||
// const roll = await super.use(event);
|
||||
let roll = { formula: formula, total: formula };
|
||||
if (isNaN(formula)) {
|
||||
roll = await new Roll(formula).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.total,
|
||||
type: this.healing.type
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
cls.create(msg.toObject());
|
||||
}
|
||||
|
||||
get chatTemplate() {
|
||||
return 'systems/daggerheart/templates/chat/healing-roll.hbs';
|
||||
}
|
||||
}
|
||||
|
||||
export class DHResourceAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
// ...extraDefineSchema('roll'),
|
||||
...extraDefineSchema('target'),
|
||||
...extraDefineSchema('effects'),
|
||||
resource: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: [],
|
||||
blank: true,
|
||||
required: false,
|
||||
initial: '',
|
||||
label: 'Resource'
|
||||
}),
|
||||
value: new fields.NumberField({ initial: 0, label: 'Value' })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DHSummonAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
documentUUID: new fields.StringField({ blank: true, initial: '', placeholder: 'Enter a Creature UUID' })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DHEffectAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
...extraDefineSchema('effects')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DHMacroAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
documentUUID: new fields.StringField({ blank: true, initial: '', placeholder: 'Enter a macro UUID' })
|
||||
};
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
const fixUUID = !this.documentUUID.includes('Macro.') ? `Macro.${this.documentUUID}` : this.documentUUID,
|
||||
macro = await fromUuid(fixUUID);
|
||||
try {
|
||||
if (!macro) throw new Error(`No macro found for the UUID: ${this.documentUUID}.`);
|
||||
macro.execute();
|
||||
} catch (error) {
|
||||
ui.notifications.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
module/data/action/actionDice.mjs
Normal file
55
module/data/action/actionDice.mjs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import FormulaField from '../fields/formulaField.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
export class DHActionDiceData extends foundry.abstract.DataModel {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
multiplier: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.multiplierTypes,
|
||||
initial: 'proficiency',
|
||||
label: 'Multiplier'
|
||||
}),
|
||||
dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }),
|
||||
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(actor) {
|
||||
return this.custom.enabled
|
||||
? this.custom.formula
|
||||
: `${actor.system[this.multiplier] ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class DHDamageField extends fields.SchemaField {
|
||||
constructor(hasBase, options, context = {}) {
|
||||
const damageFields = {
|
||||
parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData))
|
||||
};
|
||||
if (hasBase) damageFields.includeBase = new fields.BooleanField({ initial: true });
|
||||
super(damageFields, options, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class DHDamageData extends DHActionDiceData {
|
||||
/** @override */
|
||||
static defineSchema() {
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }),
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.damageTypes,
|
||||
initial: 'physical',
|
||||
label: 'Type',
|
||||
nullable: false,
|
||||
required: true
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -5,17 +5,19 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
|||
return {
|
||||
title: new fields.StringField(),
|
||||
origin: new fields.StringField({ required: true }),
|
||||
roll: new fields.StringField({}),
|
||||
total: new fields.NumberField({ integer: true }),
|
||||
dice: new fields.DataField(),
|
||||
roll: new fields.DataField(),
|
||||
modifiers: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ integer: true }),
|
||||
label: new fields.StringField({}),
|
||||
title: new fields.StringField({})
|
||||
label: new fields.StringField({})
|
||||
})
|
||||
),
|
||||
advantageState: new fields.NumberField({ required: true, choices: [0, 1, 2], initial: 0 }),
|
||||
dice: new fields.EmbeddedDataField(DhpAdversaryRollDice),
|
||||
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(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({}),
|
||||
|
|
@ -37,42 +39,8 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
const diceKeys = Object.keys(this.dice.rolls);
|
||||
const highestDiceIndex =
|
||||
diceKeys.length < 2
|
||||
? null
|
||||
: this.dice.rolls[diceKeys[0]].value > this.dice.rolls[diceKeys[1]].value
|
||||
? 0
|
||||
: 1;
|
||||
if (highestDiceIndex !== null) {
|
||||
this.dice.rolls = this.dice.rolls.map((roll, index) => ({
|
||||
...roll,
|
||||
discarded: this.advantageState === 1 ? index !== highestDiceIndex : index === highestDiceIndex
|
||||
}));
|
||||
}
|
||||
|
||||
this.targets.forEach(target => {
|
||||
target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DhpAdversaryRollDice extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
type: new fields.StringField({ required: true }),
|
||||
rolls: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ required: true, integer: true }),
|
||||
discarded: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
get rollTotal() {
|
||||
return this.rolls.reduce((acc, roll) => acc + (!roll.discarded ? roll.value : 0), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
|
|||
total: new fields.NumberField({ required: true, integer: true }),
|
||||
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false })
|
||||
}),
|
||||
dice: new fields.ArrayField(new fields.EmbeddedDataField(DhpDamageDice)),
|
||||
dice: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
type: new fields.StringField({ required: true }),
|
||||
rolls: new fields.ArrayField(new fields.NumberField({ required: true, integer: true })),
|
||||
total: new fields.NumberField({ integer: true })
|
||||
})
|
||||
),
|
||||
modifiers: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ required: true, integer: true }),
|
||||
|
|
@ -26,18 +32,3 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
class DhpDamageDice extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
type: new fields.StringField({ required: true }),
|
||||
rolls: new fields.ArrayField(new fields.NumberField({ required: true, integer: true }))
|
||||
};
|
||||
}
|
||||
|
||||
get rollTotal() {
|
||||
return this.rolls.reduce((acc, roll) => acc + roll, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { DualityRollColor } from "../settings/Appearance.mjs";
|
||||
import { DualityRollColor } from '../settings/Appearance.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
const diceField = () =>
|
||||
|
|
@ -18,18 +18,17 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
|
|||
return {
|
||||
title: new fields.StringField(),
|
||||
origin: new fields.StringField({ required: true }),
|
||||
roll: new fields.StringField({}),
|
||||
roll: new fields.DataField({}),
|
||||
modifiers: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ integer: true }),
|
||||
label: new fields.StringField({}),
|
||||
title: new fields.StringField({})
|
||||
label: new fields.StringField({})
|
||||
})
|
||||
),
|
||||
hope: diceField(),
|
||||
fear: diceField(),
|
||||
advantageState: new fields.BooleanField({ nullable: true, initial: null }),
|
||||
advantage: diceField(),
|
||||
disadvantage: diceField(),
|
||||
targets: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({}),
|
||||
|
|
@ -64,15 +63,6 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
|
|||
};
|
||||
}
|
||||
|
||||
get total() {
|
||||
const advantage = this.advantage.value
|
||||
? this.advantage.value
|
||||
: this.disadvantage.value
|
||||
? -this.disadvantage.value
|
||||
: 0;
|
||||
return this.diceTotal + advantage + this.modifierTotal.value;
|
||||
}
|
||||
|
||||
get diceTotal() {
|
||||
return this.hope.value + this.fear.value;
|
||||
}
|
||||
|
|
@ -112,13 +102,7 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
const total = this.total;
|
||||
|
||||
this.hope.discarded = this.hope.value < this.fear.value;
|
||||
this.fear.discarded = this.fear.value < this.hope.value;
|
||||
|
||||
this.targets.forEach(target => {
|
||||
target.hit = target.difficulty ? total >= target.difficulty : total >= target.evasion;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
module/data/fields/actionField.mjs
Normal file
40
module/data/fields/actionField.mjs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { actionsTypes } from '../action/_module.mjs';
|
||||
|
||||
// Temporary Solution
|
||||
export default class ActionField extends foundry.data.fields.ObjectField {
|
||||
getModel(value) {
|
||||
return actionsTypes[value.type] ?? actionsTypes.attack;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_cleanType(value, options) {
|
||||
if (!(typeof value === 'object')) value = {};
|
||||
|
||||
const cls = this.getModel(value);
|
||||
if (cls) return cls.cleanData(value, options);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
initialize(value, model, options = {}) {
|
||||
const cls = this.getModel(value);
|
||||
if (cls) return new cls(value, { parent: model, ...options });
|
||||
return foundry.utils.deepClone(value);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Migrate this field's candidate source data.
|
||||
* @param {object} sourceData Candidate source data of the root model.
|
||||
* @param {any} fieldData The value of this field within the source data.
|
||||
*/
|
||||
migrateSource(sourceData, fieldData) {
|
||||
const cls = this.getModel(fieldData);
|
||||
if (cls) cls.migrateDataSafe(fieldData);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,27 +10,27 @@ import DHSubclass from './subclass.mjs';
|
|||
import DHWeapon from './weapon.mjs';
|
||||
|
||||
export {
|
||||
DHAncestry,
|
||||
DHArmor,
|
||||
DHClass,
|
||||
DHCommunity,
|
||||
DHConsumable,
|
||||
DHDomainCard,
|
||||
DHFeature,
|
||||
DHMiscellaneous,
|
||||
DHSubclass,
|
||||
DHWeapon,
|
||||
}
|
||||
DHAncestry,
|
||||
DHArmor,
|
||||
DHClass,
|
||||
DHCommunity,
|
||||
DHConsumable,
|
||||
DHDomainCard,
|
||||
DHFeature,
|
||||
DHMiscellaneous,
|
||||
DHSubclass,
|
||||
DHWeapon
|
||||
};
|
||||
|
||||
export const config = {
|
||||
ancestry: DHAncestry,
|
||||
armor: DHArmor,
|
||||
class: DHClass,
|
||||
community: DHCommunity,
|
||||
consumable: DHConsumable,
|
||||
domainCard: DHDomainCard,
|
||||
feature: DHFeature,
|
||||
miscellaneous: DHMiscellaneous,
|
||||
subclass: DHSubclass,
|
||||
weapon: DHWeapon,
|
||||
};
|
||||
ancestry: DHAncestry,
|
||||
armor: DHArmor,
|
||||
class: DHClass,
|
||||
community: DHCommunity,
|
||||
consumable: DHConsumable,
|
||||
domainCard: DHDomainCard,
|
||||
feature: DHFeature,
|
||||
miscellaneous: DHMiscellaneous,
|
||||
subclass: DHSubclass,
|
||||
weapon: DHWeapon
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import DaggerheartAction from '../action.mjs';
|
||||
import DHAction from '../action/action.mjs';
|
||||
import BaseDataItem from './base.mjs';
|
||||
|
||||
export default class DHDomainCard extends BaseDataItem {
|
||||
|
|
@ -22,7 +22,7 @@ export default class DHDomainCard extends BaseDataItem {
|
|||
type: new fields.StringField({ choices: SYSTEM.DOMAIN.cardTypes, required: true, blank: true }),
|
||||
foundation: new fields.BooleanField({ initial: false }),
|
||||
inVault: new fields.BooleanField({ initial: false }),
|
||||
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction))
|
||||
actions: new fields.ArrayField(new fields.EmbeddedDataField(DHAction))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { getTier } from '../../helpers/utils.mjs';
|
||||
import DaggerheartAction from '../action.mjs';
|
||||
import DHAction from '../action/action.mjs';
|
||||
import BaseDataItem from './base.mjs';
|
||||
|
||||
export default class DHFeature extends BaseDataItem {
|
||||
/** @inheritDoc */
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: "TYPES.Item.feature",
|
||||
type: "feature",
|
||||
hasDescription: true,
|
||||
label: 'TYPES.Item.feature',
|
||||
type: 'feature',
|
||||
hasDescription: true
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ export default class DHFeature extends BaseDataItem {
|
|||
const fields = foundry.data.fields;
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
|
||||
|
||||
//A type of feature seems unnecessary
|
||||
type: new fields.StringField({ choices: SYSTEM.ITEM.featureTypes }),
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ export default class DHFeature extends BaseDataItem {
|
|||
choices: SYSTEM.ITEM.actionTypes,
|
||||
initial: SYSTEM.ITEM.actionTypes.passive.id
|
||||
}),
|
||||
//TODO: remove featureType field
|
||||
//TODO: remove featureType field
|
||||
featureType: new fields.SchemaField({
|
||||
type: new fields.StringField({
|
||||
choices: SYSTEM.ITEM.valueTypes,
|
||||
|
|
@ -75,9 +75,10 @@ export default class DHFeature extends BaseDataItem {
|
|||
{ nullable: true, initial: null }
|
||||
),
|
||||
dataField: new fields.StringField({}),
|
||||
appliesOn: new fields.StringField({
|
||||
choices: SYSTEM.EFFECTS.applyLocations,
|
||||
},
|
||||
appliesOn: new fields.StringField(
|
||||
{
|
||||
choices: SYSTEM.EFFECTS.applyLocations
|
||||
},
|
||||
{ nullable: true, initial: null }
|
||||
),
|
||||
applyLocationChoices: new fields.TypedObjectField(new fields.StringField({}), {
|
||||
|
|
@ -92,7 +93,7 @@ export default class DHFeature extends BaseDataItem {
|
|||
})
|
||||
})
|
||||
),
|
||||
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction))
|
||||
actions: new fields.ArrayField(new fields.EmbeddedDataField(DHAction))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import BaseDataItem from './base.mjs';
|
|||
import FormulaField from '../fields/formulaField.mjs';
|
||||
import PseudoDocumentsField from '../fields/pseudoDocumentsField.mjs';
|
||||
import BaseFeatureData from '../pseudo-documents/feature/baseFeatureData.mjs';
|
||||
import ActionField from '../fields/actionField.mjs';
|
||||
|
||||
export default class DHWeapon extends BaseDataItem {
|
||||
/** @inheritDoc */
|
||||
|
|
@ -38,14 +39,15 @@ export default class DHWeapon extends BaseDataItem {
|
|||
initial: 'physical'
|
||||
})
|
||||
}),
|
||||
|
||||
feature: new fields.StringField({ choices: SYSTEM.ITEM.weaponFeatures, blank: true }),
|
||||
featureTest: new PseudoDocumentsField(BaseFeatureData, {
|
||||
required: true,
|
||||
nullable: true,
|
||||
max: 1,
|
||||
validTypes: ['weapon']
|
||||
})
|
||||
}),
|
||||
// actions: new fields.ArrayField(new fields.EmbeddedDataField(DHAttackAction))
|
||||
actions: new fields.ArrayField(new ActionField())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import NpcRollSelectionDialog from '../applications/npcRollSelectionDialog.mjs';
|
|||
import RollSelectionDialog from '../applications/rollSelectionDialog.mjs';
|
||||
import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
|
||||
import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
||||
import DHDualityRoll from '../data/chat-message/dualityRoll.mjs';
|
||||
|
||||
export default class DhpActor extends Actor {
|
||||
async _preCreate(data, options, user) {
|
||||
|
|
@ -123,87 +124,52 @@ export default class DhpActor extends Actor {
|
|||
});
|
||||
}
|
||||
|
||||
async diceRoll(modifier, shiftKey) {
|
||||
if (this.type === 'character') {
|
||||
return await this.dualityRoll(modifier, shiftKey);
|
||||
} else {
|
||||
return await this.npcRoll(modifier, shiftKey);
|
||||
}
|
||||
}
|
||||
|
||||
async npcRoll(modifier, shiftKey) {
|
||||
let advantage = null;
|
||||
|
||||
const modifiers = [
|
||||
{
|
||||
value: Number.parseInt(modifier.value),
|
||||
label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`,
|
||||
title: modifier.title
|
||||
}
|
||||
];
|
||||
if (!shiftKey) {
|
||||
const dialogClosed = new Promise((resolve, _) => {
|
||||
new NpcRollSelectionDialog(this.system.experiences, resolve).render(true);
|
||||
});
|
||||
const result = await dialogClosed;
|
||||
|
||||
advantage = result.advantage;
|
||||
result.experiences.forEach(x =>
|
||||
modifiers.push({
|
||||
value: x.value,
|
||||
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
|
||||
title: x.description
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const roll = Roll.create(
|
||||
`${advantage === true || advantage === false ? 2 : 1}d20${advantage === true ? 'kh' : advantage === false ? 'kl' : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
|
||||
);
|
||||
let rollResult = await roll.evaluate();
|
||||
const dice = [];
|
||||
for (var i = 0; i < rollResult.terms.length; i++) {
|
||||
const term = rollResult.terms[i];
|
||||
if (term.faces) {
|
||||
dice.push({ type: `d${term.faces}`, rolls: term.results.map(x => ({ value: x.result })) });
|
||||
}
|
||||
}
|
||||
|
||||
// There is Only ever one dice term here
|
||||
return { roll, dice: dice[0], modifiers, advantageState: advantage === true ? 1 : advantage === false ? 2 : 0 };
|
||||
}
|
||||
|
||||
async dualityRoll(modifier, shiftKey) {
|
||||
/**
|
||||
* @param {object} config
|
||||
* @param {Event} config.event
|
||||
* @param {string} config.title
|
||||
* @param {object} config.roll
|
||||
* @param {number} config.roll.modifier
|
||||
* @param {boolean} [config.roll.simple=false]
|
||||
* @param {string} [config.roll.type]
|
||||
* @param {number} [config.roll.difficulty]
|
||||
* @param {any} [config.damage]
|
||||
* @param {object} [config.chatMessage]
|
||||
* @param {string} config.chatMessage.template
|
||||
* @param {boolean} [config.chatMessage.mute]
|
||||
* @param {boolean} [config.checkTarget]
|
||||
*/
|
||||
async diceRoll(config) {
|
||||
let hopeDice = 'd12',
|
||||
fearDice = 'd12',
|
||||
advantageDice = null,
|
||||
disadvantageDice = null;
|
||||
advantageDice = 'd6',
|
||||
disadvantageDice = 'd6',
|
||||
advantage = config.event.altKey ? true : config.event.ctrlKey ? false : null,
|
||||
targets,
|
||||
damage = config.damage,
|
||||
modifiers = this.formatRollModifier(config.roll),
|
||||
rollConfig,
|
||||
formula,
|
||||
hope,
|
||||
fear;
|
||||
|
||||
const modifiers =
|
||||
modifier.value !== null
|
||||
? [
|
||||
{
|
||||
value: modifier.value ? Number.parseInt(modifier.value) : 0,
|
||||
label:
|
||||
modifier.value >= 0
|
||||
? `${modifier.title} +${modifier.value}`
|
||||
: `${modifier.title} ${modifier.value}`,
|
||||
title: modifier.title
|
||||
}
|
||||
]
|
||||
: [];
|
||||
if (!shiftKey) {
|
||||
if (!config.event.shiftKey && !config.event.altKey && !config.event.ctrlKey) {
|
||||
const dialogClosed = new Promise((resolve, _) => {
|
||||
new RollSelectionDialog(this.system.experiences, this.system.resources.hope.value, resolve).render(
|
||||
true
|
||||
);
|
||||
this.type === 'character'
|
||||
? new RollSelectionDialog(
|
||||
this.system.experiences,
|
||||
this.system.resources.hope.value,
|
||||
resolve
|
||||
).render(true)
|
||||
: new NpcRollSelectionDialog(this.system.experiences, resolve).render(true);
|
||||
});
|
||||
const result = await dialogClosed;
|
||||
(hopeDice = result.hope),
|
||||
(fearDice = result.fear),
|
||||
(advantageDice = result.advantage),
|
||||
(disadvantageDice = result.disadvantage);
|
||||
result.experiences.forEach(x =>
|
||||
rollConfig = await dialogClosed;
|
||||
|
||||
advantage = rollConfig.advantage;
|
||||
hopeDice = rollConfig.hope;
|
||||
fearDice = rollConfig.fear;
|
||||
|
||||
rollConfig.experiences.forEach(x =>
|
||||
modifiers.push({
|
||||
value: x.value,
|
||||
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
|
||||
|
|
@ -211,60 +177,123 @@ export default class DhpActor extends Actor {
|
|||
})
|
||||
);
|
||||
|
||||
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
|
||||
if (this.type === 'character') {
|
||||
const automateHope = await 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 (automateHope && result.hopeUsed) {
|
||||
await this.update({
|
||||
'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const roll = new Roll(
|
||||
`1${hopeDice} + 1${fearDice}${advantageDice ? ` + 1${advantageDice}` : disadvantageDice ? ` - 1${disadvantageDice}` : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
|
||||
);
|
||||
let rollResult = await roll.evaluate();
|
||||
setDiceSoNiceForDualityRoll(rollResult, advantageDice, disadvantageDice);
|
||||
|
||||
const hope = rollResult.dice[0].results[0].result;
|
||||
const fear = rollResult.dice[1].results[0].result;
|
||||
const advantage = advantageDice ? rollResult.dice[2].results[0].result : null;
|
||||
const disadvantage = disadvantageDice ? rollResult.dice[2].results[0].result : null;
|
||||
|
||||
if (disadvantage) {
|
||||
rollResult = { ...rollResult, total: rollResult.total - Math.max(hope, disadvantage) };
|
||||
}
|
||||
if (advantage) {
|
||||
rollResult = { ...rollResult, total: 'Select Hope Die' };
|
||||
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();
|
||||
const 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 }))
|
||||
}));
|
||||
|
||||
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
|
||||
if (automateHope && hope > fear) {
|
||||
await this.update({
|
||||
'system.resources.hope.value': Math.min(
|
||||
this.system.resources.hope.value + 1,
|
||||
this.system.resources.hope.max
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
if (automateHope && 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 (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.checkTarget) {
|
||||
targets = Array.from(game.user.targets).map(x => {
|
||||
const target = {
|
||||
id: x.id,
|
||||
name: x.actor.name,
|
||||
img: x.actor.img,
|
||||
difficulty: x.actor.system.difficulty,
|
||||
evasion: x.actor.system.evasion?.value
|
||||
};
|
||||
|
||||
target.hit = target.difficulty ? roll.total >= target.difficulty : roll.total >= target.evasion;
|
||||
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
roll,
|
||||
rollResult,
|
||||
hope: { dice: hopeDice, value: hope },
|
||||
fear: { dice: fearDice, value: fear },
|
||||
advantage: { dice: advantageDice, value: advantage },
|
||||
disadvantage: { dice: disadvantageDice, value: disadvantage },
|
||||
modifiers: modifiers
|
||||
};
|
||||
if (config.chatMessage) {
|
||||
const configRoll = {
|
||||
title: config.title,
|
||||
origin: this.id,
|
||||
dice,
|
||||
roll,
|
||||
modifiers: modifiers.filter(x => x.label),
|
||||
advantageState: advantage
|
||||
};
|
||||
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 roll;
|
||||
}
|
||||
|
||||
formatRollModifier(roll) {
|
||||
const modifier = roll.modifier !== null ? Number.parseInt(roll.modifier) : null;
|
||||
return modifier !== null
|
||||
? [
|
||||
{
|
||||
value: modifier,
|
||||
label: roll.label
|
||||
? modifier >= 0
|
||||
? `${roll.label} +${modifier}`
|
||||
: `${roll.label} ${modifier}`
|
||||
: null,
|
||||
title: roll.label
|
||||
}
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
async damageRoll(title, damage, targets, shiftKey) {
|
||||
|
|
@ -294,7 +323,11 @@ export default class DhpActor extends Actor {
|
|||
for (var i = 0; i < rollResult.terms.length; i++) {
|
||||
const term = rollResult.terms[i];
|
||||
if (term.faces) {
|
||||
dice.push({ type: `d${term.faces}`, rolls: term.results.map(x => x.result) });
|
||||
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 ? '' : rollResult.terms[i - 1].operator;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ export default class DhpItem extends Item {
|
|||
return super.getEmbeddedDocument(embeddedName, id, { invalid, strict });
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
prepareEmbeddedDocuments() {
|
||||
super.prepareEmbeddedDocuments();
|
||||
for (const action of this.system.actions ?? []) action.prepareData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @param {object} options - Options which modify the getRollData method.
|
||||
|
|
@ -92,4 +98,47 @@ export default class DhpItem extends Item {
|
|||
options
|
||||
});
|
||||
}
|
||||
|
||||
async selectActionDialog() {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/views/actionSelect.hbs',
|
||||
{ actions: this.system.actions }
|
||||
),
|
||||
title = 'Select Action',
|
||||
type = 'div',
|
||||
data = {};
|
||||
return Dialog.prompt({
|
||||
title,
|
||||
// label: title,
|
||||
content,
|
||||
type,
|
||||
callback: html => {
|
||||
const form = html[0].querySelector('form'),
|
||||
fd = new foundry.applications.ux.FormDataExtended(form);
|
||||
return this.system.actions.find(a => a._id === fd.object.actionId);
|
||||
},
|
||||
rejectClose: false
|
||||
});
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
const actions = this.system.actions;
|
||||
let response;
|
||||
if (actions?.length) {
|
||||
let action = actions[0];
|
||||
if (actions.length > 1 && !event?.shiftKey) {
|
||||
// Actions Choice Dialog
|
||||
action = await this.selectActionDialog();
|
||||
}
|
||||
if (action) response = action.use(event);
|
||||
// Check Target
|
||||
// If action.roll => Roll Dialog
|
||||
// Else If action.cost => Cost Dialog
|
||||
// Then
|
||||
// Apply Cost
|
||||
// Apply Effect
|
||||
}
|
||||
// Display Item Card in chat
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,26 @@ export function dualityRollEnricher(match, _options) {
|
|||
}
|
||||
|
||||
export function getDualityMessage(roll) {
|
||||
const attributeLabel =
|
||||
roll.attribute && abilities[roll.attribute]
|
||||
const traitLabel =
|
||||
roll.trait && abilities[roll.trait]
|
||||
? game.i18n.format('DAGGERHEART.General.Check', {
|
||||
check: game.i18n.localize(abilities[roll.attribute].label)
|
||||
check: game.i18n.localize(abilities[roll.trait].label)
|
||||
})
|
||||
: null;
|
||||
const label = attributeLabel ?? game.i18n.localize('DAGGERHEART.General.Duality');
|
||||
|
||||
const label = traitLabel ?? game.i18n.localize('DAGGERHEART.General.Duality');
|
||||
const dataLabel = traitLabel
|
||||
? game.i18n.localize(abilities[roll.trait].label)
|
||||
: game.i18n.localize('DAGGERHEART.General.Duality');
|
||||
|
||||
const dualityElement = document.createElement('span');
|
||||
dualityElement.innerHTML = `
|
||||
<button class="duality-roll-button"
|
||||
data-label="${label}"
|
||||
data-title="${label}"
|
||||
data-label="${dataLabel}"
|
||||
data-hope="${roll.hope ?? 'd12'}"
|
||||
data-fear="${roll.fear ?? 'd12'}"
|
||||
${roll.attribute && abilities[roll.attribute] ? `data-attribute="${roll.attribute}"` : ''}
|
||||
${roll.trait && abilities[roll.trait] ? `data-trait="${roll.trait}"` : ''}
|
||||
${roll.advantage ? 'data-advantage="true"' : ''}
|
||||
${roll.disadvantage ? 'data-disadvantage="true"' : ''}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -122,14 +122,16 @@ export const getCommandTarget = () => {
|
|||
return target;
|
||||
};
|
||||
|
||||
export const setDiceSoNiceForDualityRoll = (rollResult, advantage, disadvantage) => {
|
||||
export const setDiceSoNiceForDualityRoll = (rollResult, advantageState) => {
|
||||
const diceSoNicePresets = getDiceSoNicePresets();
|
||||
rollResult.dice[0].options.appearance = diceSoNicePresets.hope;
|
||||
rollResult.dice[1].options.appearance = diceSoNicePresets.fear;
|
||||
if (advantage) {
|
||||
rollResult.dice[2].options.appearance = diceSoNicePresets.advantage;
|
||||
} else if (disadvantage) {
|
||||
rollResult.dice[2].options.appearance = diceSoNicePresets.disadvantage;
|
||||
if (rollResult.dice[2]) {
|
||||
if (advantageState === true) {
|
||||
rollResult.dice[2].options.appearance = diceSoNicePresets.advantage;
|
||||
} else if (advantageState === false) {
|
||||
rollResult.dice[2].options.appearance = diceSoNicePresets.disadvantage;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -222,3 +224,14 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue
|
|||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// Fix on Foundry native formula replacement for DH
|
||||
const nativeReplaceFormulaData = Roll.replaceFormulaData;
|
||||
Roll.replaceFormulaData = function (formula, data, { missing, warn = false } = {}) {
|
||||
const terms = [
|
||||
{ term: 'prof', default: 1 },
|
||||
{ term: 'cast', default: 1 }
|
||||
];
|
||||
formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula);
|
||||
return nativeReplaceFormulaData(formula, data, { missing, warn });
|
||||
};
|
||||
|
|
|
|||
|
|
@ -452,6 +452,37 @@ div.daggerheart.views.multiclass {
|
|||
&.open {
|
||||
max-height: initial;
|
||||
}
|
||||
|
||||
.multi-display {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
.form-group {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
label {
|
||||
flex: 2;
|
||||
}
|
||||
.form-fields {
|
||||
flex: 3;
|
||||
}
|
||||
img {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.data-form-array {
|
||||
border: 1px solid var(--color-fieldset-border);
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2216,6 +2216,34 @@ div.daggerheart.views.multiclass {
|
|||
.daggerheart.views.action .action-category .action-category-data.open {
|
||||
max-height: initial;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .multi-display {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .multi-display .form-group {
|
||||
flex: 1;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .form-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .form-group label {
|
||||
flex: 2;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .form-group .form-fields {
|
||||
flex: 3;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .form-group img {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
.daggerheart.views.action .action-category .action-category-data .data-form-array {
|
||||
border: 1px solid var(--color-fieldset-border);
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.daggerheart.views.ancestry-selection .ancestry-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -3705,3 +3733,34 @@ div.daggerheart.views.multiclass {
|
|||
cursor: pointer;
|
||||
filter: drop-shadow(0 0 3px red);
|
||||
}
|
||||
.unlist {
|
||||
list-style: none;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
.list-select {
|
||||
margin: 1rem;
|
||||
}
|
||||
.list-select li:not(:last-child) {
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
.list-select li label {
|
||||
padding: 4px 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-select li label > span {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-16);
|
||||
}
|
||||
dh-icon,
|
||||
dh-icon > img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,3 +130,39 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unlist {
|
||||
list-style: none;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
.list-select {
|
||||
margin: 1rem;
|
||||
li {
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
label {
|
||||
padding: 4px 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
cursor: pointer;
|
||||
> span {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dh-icon,
|
||||
dh-icon > img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,32 @@
|
|||
<div class="dice-roll daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="dice-flavor">{{localize "DAGGERHEART.Chat.AttackRoll.Title" attack=this.title}}</div>
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{roll}}</div>
|
||||
<div class="dice-formula">{{roll.formula}}</div>
|
||||
<div class="dice-tooltip">
|
||||
<div class="wrapper">
|
||||
<section class="tooltip-part">
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{this.dice.rolls.length}}{{this.dice.type}}</span>
|
||||
<span class="part-total">{{this.dice.rollTotal}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
{{#each this.dice.rolls}}
|
||||
<li class="roll die {{../dice.type}} {{#if this.discarded}}discarded{{/if}} min">{{this.value}}</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
<div class="attack-roll-advantage-container">{{#if (eq this.advantageState 1)}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq this.advantageState 2)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}}</div>
|
||||
</div>
|
||||
{{#each dice}}
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{number}}{{denomination}}</span>
|
||||
<span class="part-total">{{total}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
{{#each results}}
|
||||
<li class="roll die {{../denomination}}{{#if discarded}} discarded{{/if}} min">{{result}}</li>
|
||||
{{/each}}
|
||||
</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>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dice-total">
|
||||
<div class="dice-total-value">{{this.total}}</div>
|
||||
<div class="dice-total-value">{{roll.total}}</div>
|
||||
</div>
|
||||
{{#if (gt targets.length 0)}}
|
||||
<div class="target-section">
|
||||
|
|
@ -39,7 +41,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
<div class="flexrow">
|
||||
<button class="duality-action" data-value="{{this.total.normal}}" data-damage="{{this.damage.value}}" data-damage-type="{{this.damage.type}}" {{#if this.damage.disabled}}disabled{{/if}}><span>Roll Damage</span></button>
|
||||
<button class="duality-action" data-value="{{roll.total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}"{{#if damage.disabled}} disabled{{/if}}><span>Roll Damage</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,22 +1,33 @@
|
|||
<div class="dice-roll daggerheart chat roll">
|
||||
<div class="dice-roll daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{roll}}</div>
|
||||
<div class="dice-formula">{{roll.formula}}</div>
|
||||
<div class="dice-tooltip">
|
||||
<ol class="dice-rolls">
|
||||
<div class="dice-hope-container">
|
||||
{{#each diceResults}}
|
||||
<li class="roll die d20 {{#if this.discarded}}discarded{{/if}}">{{this.value}}</li>
|
||||
{{/each}}
|
||||
{{#each dice}}
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{number}}{{denomination}}</span>
|
||||
<span class="part-total">{{total}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
{{#each results}}
|
||||
<li class="roll die {{../denomination}}{{#if discarded}} discarded{{/if}} min">{{result}}</li>
|
||||
{{/each}}
|
||||
</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>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="modifiers-container">
|
||||
{{#each modifiers}}
|
||||
<li class="modifier-value" data-value="{{this.value}}" title="{{this.title}}">{{this.label}}</li>
|
||||
<li class="modifier-value" data-value="{{value}}" title="{{title}}">{{label}}</li>
|
||||
{{/each}}
|
||||
</div>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="dice-total">
|
||||
<div class="dice-total-value">{{total}}</div>
|
||||
<div class="dice-total-value">{{roll.total}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
{{#if this.colorful}}
|
||||
{{#if colorful}}
|
||||
<div class="daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="duality-data">
|
||||
<div class="duality-title">
|
||||
<div>{{localize "DAGGERHEART.Chat.AttackRoll.Title" attack=this.title}}</div>
|
||||
<div>{{localize "DAGGERHEART.Chat.AttackRoll.Title" attack=title}}</div>
|
||||
</div>
|
||||
<div class="duality-modifiers">
|
||||
{{#each this.modifiers}}
|
||||
{{#each modifiers}}
|
||||
<div class="duality-modifier">
|
||||
{{this.label}}
|
||||
{{label}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#if this.advantage.value}}
|
||||
{{#if advantageState}}
|
||||
<div class="duality-modifier">
|
||||
{{localize "DAGGERHEART.General.Advantage.Full"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.disadvantage.value}}
|
||||
{{#if (eq advantageState false)}}
|
||||
<div class="duality-modifier">
|
||||
{{localize "DAGGERHEART.General.Disadvantage.Full"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="duality-line {{#if (not this.damage.value)}}simple{{/if}}">
|
||||
<div class="duality-line {{#if (not damage.value)}}simple{{/if}}">
|
||||
<div class="dice-outer-container">
|
||||
<div class="dice-container">
|
||||
<div class="dice-title">{{localize "DAGGERHEART.General.Hope"}}</div>
|
||||
|
|
@ -41,27 +41,27 @@
|
|||
<div class="dice-value">{{fear.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if this.advantage.value}}
|
||||
{{#if advantageState}}
|
||||
<div class="advantage-container advantage">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d6-grey.svg"/>
|
||||
<div class="dice-value">{{this.advantage.value}}</div>
|
||||
<div class="dice-value">{{advantage.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.disadvantage.value}}
|
||||
{{#if (eq advantageState false)}}
|
||||
<div class="advantage-container disadvantage">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d6-grey.svg"/>
|
||||
<div class="dice-value">{{this.disadvantage.value}}</div>
|
||||
<div class="dice-value">{{advantage.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.modifierTotal.value}}<div class="duality-modifier">{{this.modifierTotal.label}}</div>{{/if}}
|
||||
{{#if modifierTotal.value}}<div class="duality-modifier">{{modifierTotal.label}}</div>{{/if}}
|
||||
</div>
|
||||
{{#if (not this.damage.value)}}
|
||||
{{#if (not damage.value)}}
|
||||
<div class="duality-result">
|
||||
<div>{{this.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
<div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
@ -78,18 +78,18 @@
|
|||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.damage.value}}
|
||||
{{#if damage.value}}
|
||||
<div class="duality-actions">
|
||||
<button class="duality-action" data-value="{{this.total}}" data-damage="{{this.damage.value}}" data-damage-type="{{this.damage.type}}" {{#if this.damage.disabled}}disabled{{/if}}><span>Roll Damage</span></button>
|
||||
<button class="duality-action" data-value="{{roll.total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>Roll Damage</span></button>
|
||||
<div class="duality-result">
|
||||
<div>{{this.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
<div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="dice-roll daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="dice-flavor">{{localize "DAGGERHEART.Chat.AttackRoll.Title" attack=this.title}}</div>
|
||||
<div class="dice-flavor">{{localize "DAGGERHEART.Chat.AttackRoll.Title" attack=title}}</div>
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{roll}}</div>
|
||||
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
|
|
||||
<span>1{{fear.dice}}</span>
|
||||
</span>
|
||||
<span class="part-total">{{this.diceTotal}}</span>
|
||||
<span class="part-total">{{diceTotal}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls duality">
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{{#if advantage.value}}
|
||||
{{#if (eq advantageState 1)}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">
|
||||
|
|
@ -127,17 +127,17 @@
|
|||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if disadvantage.value}}
|
||||
{{#if (eq advantageState 2)}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">
|
||||
<span>1{{disadvantage.dice}}</span>
|
||||
<span>1{{advantage.dice}}</span>
|
||||
</span>
|
||||
<span class="part-total">{{disadvantage.value}}</span>
|
||||
<span class="part-total">{{advantage.value}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
<li class="roll die {{disadvantage.dice}} hope min">{{disadvantage.value}}</li>
|
||||
<li class="roll die {{advantage.dice}} hope min">{{advantage.value}}</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}">
|
||||
<div class="dice-total-label">{{totalLabel}}</div>
|
||||
<div class="dice-total-value">
|
||||
{{this.total}}
|
||||
{{roll.total}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if (gt targets.length 0)}}
|
||||
|
|
@ -164,7 +164,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
<div class="dice-actions">
|
||||
<button class="duality-action" data-value="{{this.total}}" data-damage="{{this.damage.value}}" data-damage-type="{{this.damage.type}}" {{#if this.damage.disabled}}disabled{{/if}}><span>{{localize "DAGGERHEART.Chat.AttackRoll.RollDamage"}}</span></button>
|
||||
<button class="duality-action" data-value="{{roll.total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>{{localize "DAGGERHEART.Chat.AttackRoll.RollDamage"}}</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="dice-roll daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="dice-flavor">{{this.title}}</div>
|
||||
<div class="dice-flavor">{{title}}</div>
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{this.roll}}</div>
|
||||
<div class="dice-formula">{{roll}}</div>
|
||||
|
||||
<div class="dice-tooltip">
|
||||
<div class="wrapper">
|
||||
|
|
@ -9,12 +9,12 @@
|
|||
{{#each dice}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{this.rolls.length}}{{this.type}}</span>
|
||||
<span class="part-formula">{{rolls.length}}{{type}}</span>
|
||||
|
||||
<span class="part-total">{{this.rollTotal}}</span>
|
||||
<span class="part-total">{{this.total}}</span>
|
||||
</header>
|
||||
<ol class="dice-rolls">
|
||||
{{#each this.rolls}}
|
||||
{{#each rolls}}
|
||||
<li class="roll die {{../type}} min">{{this}}</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
|
@ -23,9 +23,9 @@
|
|||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dice-total">{{this.damage.total}}</div>
|
||||
<div class="dice-total">{{damage.total}}</div>
|
||||
<div class="dice-actions">
|
||||
<button class="damage-button" data-target-hit="true" {{#if (eq this.targets.length 0)}}disabled{{/if}}>{{localize "DAGGERHEART.Chat.DamageRoll.DealDamageToTargets"}}</button>
|
||||
<button class="damage-button" data-target-hit="true" {{#if (eq targets.length 0)}}disabled{{/if}}>{{localize "DAGGERHEART.Chat.DamageRoll.DealDamageToTargets"}}</button>
|
||||
<button class="damage-button">{{localize "DAGGERHEART.Chat.DamageRoll.DealDamage"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
{{#if this.colorful}}
|
||||
{{#if colorful}}
|
||||
<div class="daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="duality-data">
|
||||
<div class="duality-title">
|
||||
<div>{{this.title}}</div>
|
||||
<div>{{title}}</div>
|
||||
</div>
|
||||
<div class="duality-modifiers">
|
||||
{{#each this.modifiers}}
|
||||
{{#each modifiers}}
|
||||
<div class="duality-modifier">
|
||||
{{this.label}}
|
||||
{{label}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#if this.advantage.value}}
|
||||
{{#if advantageState}}
|
||||
<div class="duality-modifier">
|
||||
{{localize "DAGGERHEART.General.Advantage.Full"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.disadvantage.value}}
|
||||
{{#if (eq advantageState false)}}
|
||||
<div class="duality-modifier">
|
||||
{{localize "DAGGERHEART.General.Disadvantage.Full"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="duality-line {{#if (not this.damage.value)}}simple{{/if}}">
|
||||
<div class="duality-line {{#if (not damage.value)}}simple{{/if}}">
|
||||
<div class="dice-outer-container">
|
||||
<div class="dice-container">
|
||||
<div class="dice-title">{{localize "DAGGERHEART.General.Hope"}}</div>
|
||||
|
|
@ -41,32 +41,32 @@
|
|||
<div class="dice-value">{{fear.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if this.advantage.value}}
|
||||
{{#if advantageState}}
|
||||
<div class="advantage-container advantage">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d6-grey.svg"/>
|
||||
<div class="dice-value">{{this.advantage.value}}</div>
|
||||
<div class="dice-value">{{advantage.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.disadvantage.value}}
|
||||
{{#if (eq advantageState false)}}
|
||||
<div class="advantage-container disadvantage">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d6-grey.svg"/>
|
||||
<div class="dice-value">{{this.disadvantage.value}}</div>
|
||||
<div class="dice-value">{{advantage.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.modifierTotal.value}}<div class="duality-modifier">{{this.modifierTotal.label}}</div>{{/if}}
|
||||
{{#if modifierTotal.value}}<div class="duality-modifier">{{modifierTotal.label}}</div>{{/if}}
|
||||
</div>
|
||||
{{#if (not this.damage.value)}}
|
||||
{{#if (not damage.value)}}
|
||||
<div class="duality-result">
|
||||
<div>{{this.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
<div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if this.damage.value}}
|
||||
{{#if damage.value}}
|
||||
<div class="duality-actions">
|
||||
<div></div>
|
||||
<div class="duality-result">
|
||||
|
|
@ -77,9 +77,9 @@
|
|||
</div>
|
||||
{{else}}
|
||||
<div class="dice-roll daggerheart chat roll" data-action="expandRoll">
|
||||
<div class="dice-flavor">{{this.title}}</div>
|
||||
<div class="dice-flavor">{{title}}</div>
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{roll}}</div>
|
||||
<div class="dice-formula">{{roll.formula}}</div>
|
||||
<div class="dice-tooltip">
|
||||
<div class="wrapper">
|
||||
<section class="tooltip-part">
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
|
|
||||
<span>1{{fear.dice}}</span>
|
||||
</span>
|
||||
<span class="part-total">{{this.diceTotal}}</span>
|
||||
<span class="part-total">{{diceTotal}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls duality">
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{{#if advantage.value}}
|
||||
{{#if (eq advantageState 1)}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">
|
||||
|
|
@ -114,17 +114,17 @@
|
|||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if disadvantage.value}}
|
||||
{{#if (eq advantageState 2)}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">
|
||||
<span>1{{disadvantage.dice}}</span>
|
||||
<span>1{{advantage.dice}}</span>
|
||||
</span>
|
||||
<span class="part-total">{{disadvantage.value}}</span>
|
||||
<span class="part-total">{{advantage.value}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
<li class="roll die {{disadvantage.dice}} hope min">{{disadvantage.value}}</li>
|
||||
<li class="roll die {{advantage.dice}} hope min">{{advantage.value}}</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
<div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}">
|
||||
<div class="dice-total-label">{{totalLabel}}</div>
|
||||
<div class="dice-total-value">
|
||||
{{total}}
|
||||
{{roll.total}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
data-tab='{{tabs.information.id}}'
|
||||
data-group='{{tabs.information.group}}'
|
||||
>
|
||||
<fieldset>
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Adversary.Description" }}</legend>
|
||||
{{!-- <fieldset>
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Adversary.FIELDS.description.label" }}</legend>
|
||||
|
||||
{{formGroup systemFields.description value=source.system.description}}
|
||||
</fieldset>
|
||||
{{formInput systemFields.description value=source.system.description}}
|
||||
</fieldset> --}}
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Adversary.MotivesAndTactics" }}</legend>
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Adversary.FIELDS.motivesAndTactics.label" }}</legend>
|
||||
|
||||
{{formGroup systemFields.motivesAndTactics value=source.system.motivesAndTactics}}
|
||||
{{formInput systemFields.motivesAndTactics value=source.system.motivesAndTactics}}
|
||||
</fieldset>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
data-group='{{tabs.main.group}}'
|
||||
>
|
||||
<div class="adversary-container">
|
||||
<button data-action="reactionRoll">Reaction Test</button>
|
||||
<fieldset class="two-columns even">
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Adversary.General"}}</legend>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<li class="item inventory-item">
|
||||
<div class="inventory-row" data-item-id="{{item.uuid}}">
|
||||
<div class="inventory-item-title-container">
|
||||
<div data-action="viewObject" data-value="{{item.uuid}}" class="inventory-item-title">
|
||||
<div data-action="useItem" data-value="{{item.uuid}}" class="inventory-item-title">
|
||||
<img src="{{item.img}}" />
|
||||
{{item.name}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<header>
|
||||
{{formField fields.name value=source.name label="Name" name="name" rootId=partId}}
|
||||
{{!-- {{formField fields.name value=source.name label="Name" name="name" rootId=partId}} --}}
|
||||
<nav class="sheet-tabs tabs">
|
||||
{{#each tabs as |tab|}}
|
||||
<a class="{{tab.cssClass}}" data-action="tab" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
||||
|
|
@ -11,51 +11,30 @@
|
|||
</nav>
|
||||
</header>
|
||||
<section>
|
||||
<div class="tab {{this.tabs.effects.cssClass}}" data-group="primary" data-tab="effects">
|
||||
<div class="tab {{this.tabs.base.cssClass}}" data-group="primary" data-tab="base">
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="damage">
|
||||
<div>Damage</div>
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="identity">
|
||||
<div>Identity</div>
|
||||
</legend>
|
||||
|
||||
<div class="action-category-data open">
|
||||
{{formField fields.damage.fields.type value=source.damage.type label="Damage Type" name="damage.type" rootId=partId localize=true}}
|
||||
{{formField fields.damage.fields.value value=source.damage.value label="Damage" name="damage.value" rootId=partId localize=true}}
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="healing">
|
||||
<div>Healing</div>
|
||||
</legend>
|
||||
|
||||
<div class="action-category-data open ">
|
||||
{{formField fields.healing.fields.type value=source.healing.type label="Healing Type" name="healing.type" rootId=partId localize=true}}
|
||||
{{formField fields.healing.fields.value value=source.healing.value label="Healing" name="healing.value" rootId=partId localize=true}}
|
||||
{{formField fields.name value=source.name label="Name" name="name"}}
|
||||
{{formField fields.img value=source.img label="Icon" name="img"}}
|
||||
{{formField fields.actionType value=source.actionType label="Type" name="actionType" localize=true}}
|
||||
</div>
|
||||
</fieldset>
|
||||
{{#if fields.roll}}{{> 'systems/daggerheart/templates/views/actionTypes/roll.hbs' fields=fields.roll.fields source=source.roll}}{{/if}}
|
||||
</div>
|
||||
<div class="tab {{this.tabs.useage.cssClass}}" data-group="primary" data-tab="useage">
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="cost">
|
||||
<div>Cost</div>
|
||||
</legend>
|
||||
|
||||
<div class="action-category-data open ">
|
||||
{{formField fields.cost.fields.type value=source.cost.type label="Cost Type" name="cost.type" rootId=partId}}
|
||||
{{formField fields.cost.fields.value value=source.cost.value label="Value" name="cost.value" rootId=partId}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{formField fields.target.fields.type value=source.target.type label="Target Type" name="target.type" rootId=partId}}
|
||||
<div class="tab {{this.tabs.config.cssClass}}" data-group="primary" data-tab="config">
|
||||
{{> '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}}
|
||||
{{#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 class="tab {{this.tabs.conditions.cssClass}}" data-group="primary" data-tab="conditions">
|
||||
{{!-- <h2>
|
||||
{{localize "Conditions"}}
|
||||
<select class="effect-select">
|
||||
{{selectOptions this.config.effectTypes selected=this.selectedEffectType labelAttr="name" localize=true blank=""}}
|
||||
</select>
|
||||
<i class="fa-solid fa-plus icon-button {{#if (not this.selectedEffectType)}}disabled{{/if}}" data-action="addCondition"></i>
|
||||
</h2> --}}
|
||||
<div class="tab {{this.tabs.effect.cssClass}}" data-group="primary" data-tab="effect">
|
||||
{{#if fields.damage}}{{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=fields.damage.fields.parts.element.fields source=source.damage}}{{/if}}
|
||||
{{#if fields.healing}}{{> 'systems/daggerheart/templates/views/actionTypes/healing.hbs' fields=fields.healing.fields source=source.healing}}{{/if}}
|
||||
{{#if fields.resource}}{{> 'systems/daggerheart/templates/views/actionTypes/resource.hbs' fields=fields.resource.fields source=source.resource}}{{/if}}
|
||||
{{#if fields.documentUUID}}{{> 'systems/daggerheart/templates/views/actionTypes/uuid.hbs' fields=fields.documentUUID source=source.documentUUID}}{{/if}}
|
||||
{{#if fields.effects}}{{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs'}}{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
<button type="submit">Save</button>
|
||||
</div>
|
||||
13
templates/views/actionSelect.hbs
Normal file
13
templates/views/actionSelect.hbs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<form id="item-action-select">
|
||||
<ul class="unlist list-select">
|
||||
{{#each actions}}
|
||||
<li>
|
||||
<label>
|
||||
<dh-icon><img src="{{ img }}"></dh-icon>
|
||||
<span>{{ name }}</span>
|
||||
<input type="radio" name="actionId" value="{{_id}}" {{#if (eq @index 0)}}checked{{/if}}>
|
||||
</label>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</form>
|
||||
13
templates/views/actionType.hbs
Normal file
13
templates/views/actionType.hbs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<form id="action-type-select">
|
||||
<ul class="unlist list-select">
|
||||
{{#each types}}
|
||||
<li>
|
||||
<label>
|
||||
<dh-icon class="dh-icon fas {{icon}}"></dh-icon>
|
||||
<span>{{localize name}}</span>
|
||||
<input type="radio" name="type" value="{{id}}" {{#if (eq @index 0)}}checked{{/if}}>
|
||||
</label>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</form>
|
||||
21
templates/views/actionTypes/cost.hbs
Normal file
21
templates/views/actionTypes/cost.hbs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="cost">
|
||||
<div>Cost</div>
|
||||
</legend>
|
||||
<div class="action-category-data open" data-key="cost">
|
||||
<div class="fas fa-plus icon-button" data-action="addElement"></div>
|
||||
{{#each source as |cost index|}}
|
||||
<fieldset>
|
||||
<div class="multi-display">
|
||||
{{formField ../fields.type label="Resource" value=cost.type name=(concat "cost." index ".type") localize=true}}
|
||||
{{formField ../fields.value label="Value" value=cost.value name=(concat "cost." index ".value")}}
|
||||
</div>
|
||||
<div class="multi-display">
|
||||
{{formField ../fields.scalable label="Scalable" value=cost.scalable name=(concat "cost." index ".scalable")}}
|
||||
{{formField ../fields.step label="Step" value=cost.step name=(concat "cost." index ".step")}}
|
||||
</div>
|
||||
<div class="fas fa-trash" data-action="removeElement" data-index="{{index}}"></div>
|
||||
</fieldset>
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
36
templates/views/actionTypes/damage.hbs
Normal file
36
templates/views/actionTypes/damage.hbs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="effects">
|
||||
<div>Damage</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
<div class="fas fa-plus icon-button" data-action="addDamage"></div>
|
||||
{{#if @root.hasBaseDamage}}
|
||||
<div>
|
||||
{{!-- <input type="checkbox" data-action="addBaseDamage"{{#if @root.hasBaseDamage}} checked{{/if}}> --}}
|
||||
{{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#each source.parts as |dmg index|}}
|
||||
{{#with (@root.getRealIndex index) as | realIndex |}}
|
||||
<fieldset{{#if dmg.base}} disabled{{/if}}>
|
||||
{{#unless dmg.base}}
|
||||
{{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}}
|
||||
{{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}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
19
templates/views/actionTypes/effect.hbs
Normal file
19
templates/views/actionTypes/effect.hbs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="effects">
|
||||
<div>Effects</div>
|
||||
</legend>
|
||||
<div class="action-category-data open" data-key="effects">
|
||||
<div class="fas fa-plus icon-button" data-action="addEffect"></div>
|
||||
{{#each @root.effects as | effect index | }}
|
||||
<fieldset>
|
||||
{{!-- <div class="multi-display"> --}}
|
||||
<div class="form-group">
|
||||
<img src="{{img}}">
|
||||
<label data-action="editEffect">{{name}}</label>
|
||||
<div class="fas fa-trash" data-action="removeEffect" data-index="{{index}}"></div>
|
||||
</div>
|
||||
{{!-- </div> --}}
|
||||
</fieldset>
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
21
templates/views/actionTypes/healing.hbs
Normal file
21
templates/views/actionTypes/healing.hbs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="effects">
|
||||
<div>Healing</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
<fieldset>
|
||||
{{formField fields.type value=source.type name="healing.type" localize=true}}
|
||||
<div class="multi-display">
|
||||
{{formField fields.value.fields.custom.fields.enabled value=source.value.custom.enabled name="healing.value.custom.enabled"}}
|
||||
{{#if source.value.custom.enabled}}
|
||||
{{formField fields.value.fields.custom.fields.formula value=source.value.custom.formula name="healing.value.custom.formula" localize=true}}
|
||||
{{else}}
|
||||
{{formField fields.value.fields.multiplier value=source.value.multiplier name="healing.value.multiplier" localize=true}}
|
||||
{{formField fields.value.fields.dice value=source.value.dice name="healing.value.dice"}}
|
||||
{{formField fields.value.fields.bonus value=source.value.bonus name="healing.value.bonus" localize=true}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</fieldset>
|
||||
13
templates/views/actionTypes/range-target.hbs
Normal file
13
templates/views/actionTypes/range-target.hbs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="range">
|
||||
<div>Range{{#if fields.target}} & Target{{/if}}</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
{{formField fields.range value=source.range label="Range" name="range" localize=true}}
|
||||
</div>
|
||||
{{#if fields.target}}
|
||||
<div class="action-category-data open">
|
||||
{{formField fields.target.type value=source.target.type label="Target" name="target.type" localize=true}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</fieldset>
|
||||
14
templates/views/actionTypes/resource.hbs
Normal file
14
templates/views/actionTypes/resource.hbs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="effects">
|
||||
<div>Resource</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
<fieldset>
|
||||
<div class="multi-display">
|
||||
{{formField fields.type value=source.type name="resource.type" localize=true}}
|
||||
{{formField fields.value value=source.value name="resource.value"}}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</fieldset>
|
||||
10
templates/views/actionTypes/roll.hbs
Normal file
10
templates/views/actionTypes/roll.hbs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="roll">
|
||||
<div>Roll</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
{{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}}
|
||||
</div>
|
||||
</fieldset>
|
||||
8
templates/views/actionTypes/target.hbs
Normal file
8
templates/views/actionTypes/target.hbs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="target">
|
||||
<div>Target</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
{{formField targetField.type label="Target" name="target" rootId=partId localize=true}}
|
||||
</div>
|
||||
</fieldset>
|
||||
12
templates/views/actionTypes/uses.hbs
Normal file
12
templates/views/actionTypes/uses.hbs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="uses">
|
||||
<div>Uses</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
<div class="multi-display">
|
||||
{{formField fields.value label="Value" value=source.value name="uses.value" rootId=partId}}
|
||||
{{formField fields.max label="Max" value=source.max name="uses.max" rootId=partId}}
|
||||
</div>
|
||||
{{formField fields.recovery label="Recovery" value=source.recovery name="uses.recovery" rootId=partId localize=true}}
|
||||
</div>
|
||||
</fieldset>
|
||||
9
templates/views/actionTypes/uuid.hbs
Normal file
9
templates/views/actionTypes/uuid.hbs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
<fieldset class="action-category">
|
||||
<legend class="action-category-label" data-action="toggleSection" data-section="effects">
|
||||
<div>Macro</div>
|
||||
</legend>
|
||||
<div class="action-category-data open">
|
||||
{{formInput fields value=source name="documentUUID" placeholder=fields.options.placeholder}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
{{/each}}
|
||||
</div>
|
||||
<div class="flexrow">
|
||||
<button class="disadvantage flex1 {{#if this.advantage}}selected{{/if}}" data-action="setAdvantage">Advantage</button>
|
||||
<button class="disadvantage flex1 {{#if this.disadvantage}}selected{{/if}}" data-action="setDisadvantage">Disadvantage</button>
|
||||
<button class="disadvantage flex1 {{#if this.advantage}}selected{{/if}}" data-action="updateIsAdvantage" data-advantage="true">{{localize "DAGGERHEART.General.Advantage.Full"}}</button>
|
||||
<button class="disadvantage flex1 {{#if (eq this.advantage false)}}selected{{/if}}" data-action="updateIsAdvantage">{{localize "DAGGERHEART.General.Disadvantage.Full"}}</button>
|
||||
</div>
|
||||
{{#if (not this.isNpc)}}
|
||||
<div class="form-group">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue