Merge branch 'main' into bug/229-Narrative-Countdown-Window

This commit is contained in:
WBHarry 2025-07-02 23:29:18 +02:00
commit 939712f8f8
91 changed files with 3499 additions and 1423 deletions

View file

@ -1,6 +1,6 @@
export { default as DhCharacterSheet } from './sheets/character.mjs';
export { default as DhCharacterSheet } from './sheets/actors/character.mjs';
export { default as DhpAdversarySheet } from './sheets/actors/adversary.mjs';
export { default as DhCompanionSheet } from './sheets/companion.mjs';
export { default as DhpAdversarySheet } from './sheets/adversary.mjs';
export { default as DhpClassSheet } from './sheets/items/class.mjs';
export { default as DhpSubclass } from './sheets/items/subclass.mjs';
export { default as DhpFeatureSheet } from './sheets/items/feature.mjs';
@ -12,8 +12,9 @@ export { default as DhpConsumable } from './sheets/items/consumable.mjs';
export { default as DhpWeapon } from './sheets/items/weapon.mjs';
export { default as DhpArmor } from './sheets/items/armor.mjs';
export { default as DhpChatMessage } from './chatMessage.mjs';
export { default as DhpEnvironment } from './sheets/environment.mjs';
export { default as DhpEnvironment } from './sheets/actors/environment.mjs';
export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs';
export { default as DhContextMenu } from './contextMenu.mjs';
export { default as DhTooltipManager } from './tooltipManager.mjs';
export * as api from './sheets/api/_modules.mjs';

View file

@ -1,3 +1,5 @@
/** NOT USED ANYMORE - TO BE DELETED **/
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class NpcRollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {

View file

@ -8,6 +8,7 @@ import DamageDialog from '../dialogs/damageDialog.mjs';
*/
export class DHRoll extends Roll {
baseTerms = [];
constructor(formula, data, options) {
super(formula, data, options);
}
@ -37,6 +38,7 @@ export class DHRoll extends Roll {
if (config.dialog.configure !== false) {
// Open Roll Dialog
const DialogClass = config.dialog?.class ?? this.DefaultDialog;
console.log(roll, config)
const configDialog = await DialogClass.configure(roll, config, message);
if (!configDialog) return;
}
@ -97,9 +99,27 @@ export class DHRoll extends Roll {
config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey);
}
formatModifier(modifier) {
const numTerm = modifier < 0 ? '-' : '+';
return [
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
];
}
getFaces(faces) {
return Number((faces.startsWith('d') ? faces.replace('d', '') : faces));
}
constructFormula(config) {
// const formula = Roll.replaceFormulaData(this.options.roll.formula, config.data);
this.terms = Roll.parse(this.options.roll.formula, config.data);
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(this.options.extraFormula, this.options.data)
);
}
return (this._formula = this.constructor.getFormula(this.terms));
}
}
@ -111,12 +131,9 @@ export class DualityDie extends foundry.dice.terms.Die {
}
export class D20Roll extends DHRoll {
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
// this.createBaseDice();
// this.configureModifiers();
// this._formula = this.resetFormula();
this.constructFormula();
}
@ -139,7 +156,7 @@ export class D20Roll extends DHRoll {
set d20(faces) {
if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
this.terms[0].faces = faces;
this.terms[0].faces = this.getFaces(faces);
}
get dAdvantage() {
@ -152,11 +169,11 @@ export class D20Roll extends DHRoll {
}
get hasAdvantage() {
return this.options.advantage === this.constructor.ADV_MODE.ADVANTAGE;
return this.options.roll.advantage === this.constructor.ADV_MODE.ADVANTAGE;
}
get hasDisadvantage() {
return this.options.advantage === this.constructor.ADV_MODE.DISADVANTAGE;
return this.options.roll.advantage === this.constructor.ADV_MODE.DISADVANTAGE;
}
static applyKeybindings(config) {
@ -170,18 +187,55 @@ export class D20Roll extends DHRoll {
config.dialog.configure ??= !Object.values(keys).some(k => k);
// Determine advantage mode
const advantage = config.advantage || keys.advantage;
const disadvantage = config.disadvantage || keys.disadvantage;
if (advantage && !disadvantage) config.advantage = this.ADV_MODE.ADVANTAGE;
else if (!advantage && disadvantage) config.advantage = this.ADV_MODE.DISADVANTAGE;
else config.advantage = this.ADV_MODE.NORMAL;
const advantage = config.roll.advantage === this.ADV_MODE.ADVANTAGE || keys.advantage;
const disadvantage = config.roll.advantage === this.ADV_MODE.DISADVANTAGE || keys.disadvantage;
if (advantage && !disadvantage) config.roll.advantage = this.ADV_MODE.ADVANTAGE;
else if (!advantage && disadvantage) config.roll.advantage = this.ADV_MODE.DISADVANTAGE;
else config.roll.advantage = this.ADV_MODE.NORMAL;
}
constructFormula(config) {
// this.terms = [];
this.createBaseDice();
this.configureModifiers();
this.resetFormula();
return this._formula;
}
createBaseDice() {
if (this.terms[0] instanceof foundry.dice.terms.Die) return;
if (this.terms[0] instanceof foundry.dice.terms.Die) {
this.terms = [this.terms[0]];
return;
}
this.terms[0] = new foundry.dice.terms.Die({ faces: 20 });
}
configureModifiers() {
this.applyAdvantage();
this.applyBaseBonus();
this.options.experiences?.forEach(m => {
if (this.options.data.experiences?.[m])
this.options.roll.modifiers.push({
label: this.options.data.experiences[m].name,
value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value
});
});
this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m.value));
});
this.baseTerms = foundry.utils.deepClone(this.terms);
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(this.options.extraFormula, this.options.data)
);
}
}
applyAdvantage() {
this.d20.modifiers.findSplice(m => ['kh', 'kl'].includes(m));
if (!this.hasAdvantage && !this.hasDisadvantage) this.number = 1;
@ -191,47 +245,16 @@ export class D20Roll extends DHRoll {
}
}
// Trait bonus != Adversary
configureModifiers() {
this.applyAdvantage();
// this.options.roll.modifiers = [];
this.applyBaseBonus();
this.options.experiences?.forEach(m => {
if (this.options.data.experiences?.[m])
this.options.roll.modifiers.push({
label: this.options.data.experiences[m].name,
value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value
});
});
this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m.value));
});
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(this.options.extraFormula, this.getRollData())
);
}
// this.resetFormula();
}
constructFormula(config) {
this.terms = [];
this.createBaseDice();
this.configureModifiers();
this.resetFormula();
return this._formula;
}
applyBaseBonus() {
this.options.roll.modifiers = [
this.options.roll.modifiers = [];
if(!this.options.roll.bonus) return;
this.options.roll.modifiers.push(
{
label: 'Bonus to Hit',
value: Roll.replaceFormulaData('@attackBonus', this.data)
value: this.options.roll.bonus
// value: Roll.replaceFormulaData('@attackBonus', this.data)
}
];
);
}
static postEvaluate(roll, config = {}) {
@ -241,26 +264,22 @@ export class D20Roll extends DHRoll {
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
target.hit = this.isCritical || roll.total >= difficulty;
});
} else if (config.roll.difficulty)
config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty;
} else if (config.roll.difficulty) config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty;
config.roll.advantage = {
type: config.advantage,
type: config.roll.advantage,
dice: roll.dAdvantage?.denomination,
value: roll.dAdvantage?.total
};
config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + Number(c.value), 0);
}
getRollData() {
return this.options.data;
}
formatModifier(modifier) {
const numTerm = modifier < 0 ? '-' : '+';
return [
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
];
config.roll.extra = roll.dice.filter(d => !roll.baseTerms.includes(d)).map(d => {
return {
dice: d.denomination,
value: d.total
}
})
config.roll.modifierTotal = 0;
for(let i = 0; i < roll.terms.length; i++) {
if(roll.terms[i] instanceof foundry.dice.terms.NumericTerm && !!roll.terms[i-1] && roll.terms[i-1] instanceof foundry.dice.terms.OperatorTerm) config.roll.modifierTotal += Number(`${roll.terms[i-1].operator}${roll.terms[i].total}`);
}
}
resetFormula() {
@ -269,6 +288,8 @@ export class D20Roll extends DHRoll {
}
export class DualityRoll extends D20Roll {
_advantageFaces = 6;
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
}
@ -286,7 +307,7 @@ export class DualityRoll extends D20Roll {
set dHope(faces) {
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
this.terms[0].faces = faces;
this.terms[0].faces = this.getFaces(faces);
// this.#hopeDice = `d${face}`;
}
@ -299,7 +320,7 @@ export class DualityRoll extends D20Roll {
set dFear(faces) {
if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
this.dice[1].faces = faces;
this.dice[1].faces = this.getFaces(faces);
// this.#fearDice = `d${face}`;
}
@ -307,6 +328,14 @@ export class DualityRoll extends D20Roll {
return this.dice[2];
}
get advantageFaces() {
return this._advantageFaces;
}
set advantageFaces(faces) {
this._advantageFaces = this.getFaces(faces);
}
get isCritical() {
if (!this.dHope._evaluated || !this.dFear._evaluated) return;
return this.dHope.total === this.dFear.total;
@ -336,25 +365,25 @@ export class DualityRoll extends D20Roll {
return game.i18n.localize(label);
}
updateFormula() {
}
createBaseDice() {
if (
this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie &&
this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie
)
if (this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie && this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie) {
this.terms = [this.terms[0], this.terms[1], this.terms[2]];
return;
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie))
this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie();
}
this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie();
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
if (!(this.dice[2] instanceof CONFIG.Dice.daggerheart.DualityDie))
this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie();
this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie();
}
applyAdvantage() {
const dieFaces = 6,
const dieFaces = this.advantageFaces,
bardRallyFaces = this.hasBarRally,
advDie = new foundry.dice.terms.Die({ faces: dieFaces });
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces)
this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }));
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }));
if (bardRallyFaces) {
const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces });
if (this.hasAdvantage) {
@ -371,12 +400,14 @@ export class DualityRoll extends D20Roll {
}
applyBaseBonus() {
this.options.roll.modifiers = [
this.options.roll.modifiers = [];
if(!this.options.roll.trait) return;
this.options.roll.modifiers.push(
{
label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`,
value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data)
}
];
);
}
static postEvaluate(roll, config = {}) {

View file

@ -1,3 +1,5 @@
/** NOT USED ANYMORE - TO BE DELETED **/
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {

View file

@ -1,20 +1,23 @@
import DHActionConfig from '../config/Action.mjs';
import DaggerheartSheet from './daggerheart-sheet.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DaggerheartSheet from '../daggerheart-sheet.mjs';
import DHAdversarySettings from '../applications/adversary-settings.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'adversary'],
position: { width: 450, height: 1000 },
position: { width: 660, height: 766 },
actions: {
reactionRoll: this.reactionRoll,
attackRoll: this.attackRoll,
useItem: this.useItem,
toChat: this.toChat,
attackConfigure: this.attackConfigure,
addExperience: this.addExperience,
removeExperience: this.removeExperience,
toggleHP: this.toggleHP,
toggleStress: this.toggleStress
toggleStress: this.toggleStress,
openSettings: this.openSettings
},
form: {
handler: this.updateForm,
@ -24,28 +27,37 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
};
static PARTS = {
sidebar: { template: 'systems/daggerheart/templates/sheets/actors/adversary/sidebar.hbs' },
header: { template: 'systems/daggerheart/templates/sheets/actors/adversary/header.hbs' },
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
main: { template: 'systems/daggerheart/templates/sheets/actors/adversary/main.hbs' },
information: { template: 'systems/daggerheart/templates/sheets/actors/adversary/information.hbs' }
actions: { template: 'systems/daggerheart/templates/sheets/actors/adversary/actions.hbs' },
notes: { template: 'systems/daggerheart/templates/sheets/actors/adversary/notes.hbs' },
effects: { template: 'systems/daggerheart/templates/sheets/actors/adversary/effects.hbs' }
};
static TABS = {
main: {
actions: {
active: true,
cssClass: '',
group: 'primary',
id: 'main',
id: 'actions',
icon: null,
label: 'DAGGERHEART.Sheets.Adversary.Tabs.Main'
label: 'DAGGERHEART.General.tabs.actions'
},
information: {
notes: {
active: false,
cssClass: '',
group: 'primary',
id: 'information',
id: 'notes',
icon: null,
label: 'DAGGERHEART.Sheets.Adversary.Tabs.Information'
label: 'DAGGERHEART.Sheets.Adversary.Tabs.notes'
},
effects: {
active: false,
cssClass: '',
group: 'primary',
id: 'effects',
icon: null,
label: 'DAGGERHEART.Sheets.Adversary.Tabs.effects'
}
};
@ -56,10 +68,15 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
context.getEffectDetails = this.getEffectDetails.bind(this);
context.isNPC = true;
console.log(context)
return context;
}
getAction(element) {
const itemId = (element.target ?? element).closest('[data-item-id]').dataset.itemId,
item = this.document.system.actions.find(x => x.id === itemId);
return item;
}
static async updateForm(event, _, formData) {
await this.document.update(formData.object);
this.render();
@ -70,7 +87,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
event: event,
title: `${this.actor.name} - Reaction Roll`,
roll: {
modifier: null,
// modifier: null,
type: 'reaction'
},
chatMessage: {
@ -86,8 +103,40 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
return {};
}
static async attackRoll(event) {
this.actor.system.attack.use(event);
static async openSettings() {
await new DHAdversarySettings(this.document).render(true);
}
static async useItem(event) {
const action = this.getAction(event) ?? this.actor.system.attack;
action.use(event);
}
static async toChat(event, button) {
if (button?.dataset?.type === 'experience') {
const experience = this.document.system.experiences[button.dataset.uuid];
const cls = getDocumentClass('ChatMessage');
const systemData = {
name: game.i18n.localize('DAGGERHEART.General.Experience.Single'),
description: `${experience.name} ${
experience.modifier < 0 ? experience.modifier : `+${experience.modifier}`
}`
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
} else {
const item = this.getAction(event) ?? this.document.system.attack;
item.toChat(this.document.id);
}
}
static async attackConfigure(event) {

View file

@ -1,11 +1,11 @@
import { capitalize } from '../../helpers/utils.mjs';
import DhpDeathMove from '../deathMove.mjs';
import DhpDowntime from '../downtime.mjs';
import AncestrySelectionDialog from '../ancestrySelectionDialog.mjs';
import DaggerheartSheet from './daggerheart-sheet.mjs';
import { abilities } from '../../config/actorConfig.mjs';
import DhCharacterlevelUp from '../levelup/characterLevelup.mjs';
import DhCharacterCreation from '../characterCreation.mjs';
import { capitalize } from '../../../helpers/utils.mjs';
import DhpDeathMove from '../../deathMove.mjs';
import DhpDowntime from '../../downtime.mjs';
import AncestrySelectionDialog from '../../ancestrySelectionDialog.mjs';
import DaggerheartSheet from '.././daggerheart-sheet.mjs';
import { abilities } from '../../../config/actorConfig.mjs';
import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs';
import DhCharacterCreation from '../../characterCreation.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux;
@ -727,9 +727,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
const cls = getDocumentClass('ChatMessage');
const systemData = {
name: game.i18n.localize('DAGGERHEART.General.Experience.Single'),
description: `${experience.description} ${
experience.total < 0 ? experience.total : `+${experience.total}`
}`
description: `${experience.name} ${experience.total < 0 ? experience.total : `+${experience.total}`}`
};
const msg = new cls({
type: 'abilityUse',

View file

@ -0,0 +1,131 @@
import DaggerheartSheet from '../daggerheart-sheet.mjs';
import DHEnvironmentSettings from '../applications/environment-settings.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'environment'],
position: {
width: 500
},
actions: {
addAdversary: this.addAdversary,
deleteProperty: this.deleteProperty,
viewAdversary: this.viewAdversary,
openSettings: this.openSettings,
useItem: this.useItem,
toChat: this.toChat
},
form: {
handler: this._updateForm,
submitOnChange: true,
closeOnSubmit: false
},
dragDrop: [{ dragSelector: '.action-section .inventory-item', dropSelector: null }]
};
static PARTS = {
header: { template: 'systems/daggerheart/templates/sheets/actors/environment/header.hbs' },
actions: { template: 'systems/daggerheart/templates/sheets/actors/environment/actions.hbs' },
potentialAdversaries: {
template: 'systems/daggerheart/templates/sheets/actors/environment/potentialAdversaries.hbs'
},
notes: { template: 'systems/daggerheart/templates/sheets/actors/environment/notes.hbs' }
};
static TABS = {
actions: {
active: true,
cssClass: '',
group: 'primary',
id: 'actions',
icon: null,
label: 'DAGGERHEART.General.tabs.actions'
},
potentialAdversaries: {
active: false,
cssClass: '',
group: 'primary',
id: 'potentialAdversaries',
icon: null,
label: 'DAGGERHEART.General.tabs.potentialAdversaries'
},
notes: {
active: false,
cssClass: '',
group: 'primary',
id: 'notes',
icon: null,
label: 'DAGGERHEART.Sheets.Adversary.Tabs.notes'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.document = this.document;
context.tabs = super._getTabs(this.constructor.TABS);
context.getEffectDetails = this.getEffectDetails.bind(this);
return context;
}
getAction(element) {
const itemId = (element.target ?? element).closest('[data-item-id]').dataset.itemId,
item = this.document.system.actions.find(x => x.id === itemId);
return item;
}
static async openSettings() {
await new DHEnvironmentSettings(this.document).render(true);
}
static async _updateForm(event, _, formData) {
await this.document.update(formData.object);
this.render();
}
getEffectDetails(id) {
return {};
}
static async addAdversary() {
await this.document.update({
[`system.potentialAdversaries.${foundry.utils.randomID()}.label`]: game.i18n.localize(
'DAGGERHEART.Sheets.Environment.newAdversary'
)
});
this.render();
}
static async deleteProperty(_, target) {
await this.document.update({ [`${target.dataset.path}.-=${target.id}`]: null });
this.render();
}
static async viewAdversary(_, button) {
const adversary = await foundry.utils.fromUuid(button.dataset.adversary);
adversary.sheet.render(true);
}
static async useItem(event) {
const action = this.getAction(event);
action.use(event);
}
static async toChat(event) {
const item = this.getAction(event);
item.toChat(this.document.id);
}
async _onDragStart(event) {
const item = event.currentTarget.closest('.inventory-item');
if (item) {
const adversary = game.actors.find(x => x.type === 'adversary' && x.id === item.dataset.itemId);
const adversaryData = { type: 'Actor', uuid: adversary.uuid };
event.dataTransfer.setData('text/plain', JSON.stringify(adversaryData));
event.dataTransfer.setDragImage(item, 60, 0);
}
}
}

View file

@ -0,0 +1,181 @@
import DHActionConfig from '../../config/Action.mjs';
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DHAdversarySettings extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor) {
super({});
this.actor = actor;
}
get title() {
return `${game.i18n.localize('DAGGERHEART.Sheets.TABS.settings')}`;
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'dh-style', 'dialog', 'adversary-settings'],
window: {
icon: 'fa-solid fa-wrench',
resizable: false
},
position: { width: 455, height: 'auto' },
actions: {
addExperience: this.#addExperience,
removeExperience: this.#removeExperience,
addAction: this.#addAction,
editAction: this.#editAction,
removeAction: this.#removeAction
},
form: {
handler: this.updateForm,
submitOnChange: true,
closeOnSubmit: false
}
};
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/details.hbs'
},
attack: {
id: 'attack',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/attack.hbs'
},
experiences: {
id: 'experiences',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/experiences.hbs'
},
actions: {
id: 'actions',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/actions.hbs'
}
};
static TABS = {
details: {
active: true,
cssClass: '',
group: 'primary',
id: 'details',
icon: null,
label: 'DAGGERHEART.General.tabs.details'
},
attack: {
active: false,
cssClass: '',
group: 'primary',
id: 'attack',
icon: null,
label: 'DAGGERHEART.General.tabs.attack'
},
experiences: {
active: false,
cssClass: '',
group: 'primary',
id: 'experiences',
icon: null,
label: 'DAGGERHEART.General.tabs.experiences'
},
actions: {
active: false,
cssClass: '',
group: 'primary',
id: 'actions',
icon: null,
label: 'DAGGERHEART.General.tabs.actions'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.document = this.actor;
context.tabs = this._getTabs(this.constructor.TABS);
context.systemFields = this.actor.system.schema.fields;
context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
context.isNPC = true;
console.log(context)
return context;
}
_getTabs(tabs) {
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? 'active' : '';
}
return tabs;
}
static async #addExperience() {
const newExperience = {
name: 'Experience',
modifier: 0
};
await this.actor.update({ [`system.experiences.${foundry.utils.randomID()}`]: newExperience });
this.render();
}
static async #removeExperience(_, target) {
await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null });
this.render();
}
static async #addAction(_event, _button) {
const actionType = await DHBaseItemSheet.selectActionType();
if (!actionType) return;
try {
const cls = actionsTypes[actionType] ?? actionsTypes.attack,
action = new cls(
{
_id: foundry.utils.randomID(),
type: actionType,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name),
...cls.getSourceConfig(this.actor)
},
{
parent: this.actor
}
);
await this.actor.update({ 'system.actions': [...this.actor.system.actions, action] });
await new DHActionConfig(this.actor.system.actions[this.actor.system.actions.length - 1]).render({
force: true
});
this.render();
} catch (error) {
console.log(error);
}
}
static async #editAction(event, target) {
event.stopPropagation();
const actionIndex = target.dataset.index;
await new DHActionConfig(this.actor.system.actions[actionIndex]).render({
force: true
});
}
static async #removeAction(event, target) {
event.stopPropagation();
const actionIndex = target.dataset.index;
await this.actor.update({
'system.actions': this.actor.system.actions.filter((_, index) => index !== Number.parseInt(actionIndex))
});
this.render();
}
static async updateForm(event, _, formData) {
await this.actor.update(formData.object);
this.render();
}
}

View file

@ -0,0 +1,213 @@
import DHActionConfig from '../../config/Action.mjs';
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DHEnvironmentSettings extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor) {
super({});
this.actor = actor;
this._dragDrop = this._createDragDropHandlers();
}
get title() {
return `${game.i18n.localize('DAGGERHEART.Sheets.TABS.settings')}`;
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'dh-style', 'dialog', 'environment-settings'],
window: {
icon: 'fa-solid fa-wrench',
resizable: false
},
position: { width: 455, height: 'auto' },
actions: {
addAction: this.#addAction,
editAction: this.#editAction,
removeAction: this.#removeAction,
addCategory: this.#addCategory,
deleteProperty: this.#deleteProperty,
viewAdversary: this.#viewAdversary,
deleteAdversary: this.#deleteAdversary
},
form: {
handler: this.updateForm,
submitOnChange: true,
closeOnSubmit: false
},
dragDrop: [{ dragSelector: null, dropSelector: '.category-container' }]
};
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/details.hbs'
},
actions: {
id: 'actions',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/actions.hbs'
},
adversaries: {
id: 'adversaries',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/adversaries.hbs'
}
};
static TABS = {
details: {
active: true,
cssClass: '',
group: 'primary',
id: 'details',
icon: null,
label: 'DAGGERHEART.General.tabs.details'
},
actions: {
active: false,
cssClass: '',
group: 'primary',
id: 'actions',
icon: null,
label: 'DAGGERHEART.General.tabs.actions'
},
adversaries: {
active: false,
cssClass: '',
group: 'primary',
id: 'adversaries',
icon: null,
label: 'DAGGERHEART.General.tabs.adversaries'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.document = this.actor;
context.tabs = this._getTabs(this.constructor.TABS);
context.systemFields = this.actor.system.schema.fields;
context.isNPC = true;
return context;
}
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
this._dragDrop.forEach(d => d.bind(htmlElement));
}
_createDragDropHandlers() {
return this.options.dragDrop.map(d => {
d.callbacks = {
drop: this._onDrop.bind(this)
};
return new foundry.applications.ux.DragDrop.implementation(d);
});
}
_getTabs(tabs) {
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? 'active' : '';
}
return tabs;
}
static async #addAction(_event, _button) {
const actionType = await DHBaseItemSheet.selectActionType();
if (!actionType) return;
try {
const cls = actionsTypes[actionType] ?? actionsTypes.attack,
action = new cls(
{
_id: foundry.utils.randomID(),
type: actionType,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name),
...cls.getSourceConfig(this.actor)
},
{
parent: this.actor
}
);
await this.actor.update({ 'system.actions': [...this.actor.system.actions, action] });
await new DHActionConfig(this.actor.system.actions[this.actor.system.actions.length - 1]).render({
force: true
});
this.render();
} catch (error) {
console.log(error);
}
}
static async #editAction(event, target) {
event.stopPropagation();
const actionIndex = target.dataset.index;
await new DHActionConfig(this.actor.system.actions[actionIndex]).render({
force: true
});
}
static async #removeAction(event, target) {
event.stopPropagation();
const actionIndex = target.dataset.index;
await this.actor.update({
'system.actions': this.actor.system.actions.filter((_, index) => index !== Number.parseInt(actionIndex))
});
this.render();
}
static async #addCategory() {
await this.actor.update({
[`system.potentialAdversaries.${foundry.utils.randomID()}.label`]: game.i18n.localize(
'DAGGERHEART.Sheets.Environment.newAdversary'
)
});
this.render();
}
static async #deleteProperty(_, target) {
await this.actor.update({ [`${target.dataset.path}.-=${target.id}`]: null });
this.render();
}
static async #viewAdversary(_, button) {
const adversary = await foundry.utils.fromUuid(button.dataset.adversary);
adversary.sheet.render(true);
}
static async #deleteAdversary(event, target) {
const adversaryKey = target.dataset.adversary;
const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries`;
const newAdversaries = foundry.utils.getProperty(this.actor, path).filter(x => x.uuid !== adversaryKey);
await this.actor.update({ [path]: newAdversaries });
this.render();
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid);
if (item.type === 'adversary') {
const target = event.target.closest('.category-container');
const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries`;
const current = foundry.utils.getProperty(this.actor, path).map(x => x.uuid);
await this.actor.update({
[path]: [...current, item.uuid]
});
this.render();
}
}
static async updateForm(event, _, formData) {
await this.actor.update(formData.object);
this.render();
}
}

View file

@ -60,7 +60,7 @@ export default function DhpApplicationMixin(Base) {
// drop: this._canDragDrop.bind(this)
// };
d.callbacks = {
// dragstart: this._onDragStart.bind(this),
dragstart: this._onDragStart.bind(this),
// dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this)
};
@ -68,6 +68,7 @@ export default function DhpApplicationMixin(Base) {
});
}
async _onDragStart(event) {}
_onDrop(event) {}
_getTabs(tabs) {

View file

@ -1,107 +0,0 @@
import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'environment'],
position: {
width: 450,
height: 1000
},
actions: {
addAdversary: this.addAdversary,
addFeature: this.addFeature,
deleteProperty: this.deleteProperty,
viewAdversary: this.viewAdversary
},
form: {
handler: this._updateForm,
submitOnChange: true,
closeOnSubmit: false
},
dragDrop: [{ dragSelector: null, dropSelector: '.adversary-container' }]
};
static PARTS = {
header: { template: 'systems/daggerheart/templates/sheets/actors/environment/header.hbs' },
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
main: { template: 'systems/daggerheart/templates/sheets/actors/environment/main.hbs' },
information: { template: 'systems/daggerheart/templates/sheets/actors/environment/information.hbs' }
};
static TABS = {
main: {
active: true,
cssClass: '',
group: 'primary',
id: 'main',
icon: null,
label: 'DAGGERHEART.Sheets.Environment.Tabs.Main'
},
information: {
active: false,
cssClass: '',
group: 'primary',
id: 'information',
icon: null,
label: 'DAGGERHEART.Sheets.Environment.Tabs.Information'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.document = this.document;
context.tabs = super._getTabs(this.constructor.TABS);
context.getEffectDetails = this.getEffectDetails.bind(this);
return context;
}
static async _updateForm(event, _, formData) {
await this.document.update(formData.object);
this.render();
}
getEffectDetails(id) {
return {};
}
static async addAdversary() {
await this.document.update({
[`system.potentialAdversaries.${foundry.utils.randomID()}.label`]: game.i18n.localize(
'DAGGERHEART.Sheets.Environment.newAdversary'
)
});
this.render();
}
static async addFeature() {
ui.notifications.error('Not Implemented yet. Awaiting datamodel rework');
}
static async deleteProperty(_, target) {
await this.document.update({ [`${target.dataset.path}.-=${target.id}`]: null });
this.render();
}
static async viewAdversary(_, button) {
const adversary = foundry.utils.getProperty(
this.document.system.potentialAdversaries,
`${button.dataset.potentialAdversary}.adversaries.${button.dataset.adversary}`
);
adversary.sheet.render(true);
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid);
if (item.type === 'adversary') {
const target = event.target.closest('.adversary-container');
const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries.${item.id}`;
await this.document.update({
[path]: item.uuid
});
}
}
}

View file

@ -0,0 +1,16 @@
export default class DhTooltipManager extends TooltipManager {
async activate(element, options = {}) {
let html = options.html;
if (element.dataset.tooltip.startsWith('#item#')) {
const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6));
if (item) {
html = await foundry.applications.handlebars.renderTemplate(
`systems/daggerheart/templates/tooltip/${item.type}.hbs`,
item
);
}
}
super.activate(element, { ...options, html: html });
}
}

View file

@ -1,42 +1,42 @@
export const actionTypes = {
attack: {
id: 'attack',
name: 'DAGGERHEART.Actions.Types.Attack.Name',
name: 'DAGGERHEART.Actions.Types.attack.name',
icon: 'fa-swords'
},
// spellcast: {
// id: 'spellcast',
// name: 'DAGGERHEART.Actions.Types.Spellcast.Name',
// name: 'DAGGERHEART.Actions.Types.spellcast.name',
// icon: 'fa-book-sparkles'
// },
healing: {
id: 'healing',
name: 'DAGGERHEART.Actions.Types.Healing.Name',
name: 'DAGGERHEART.Actions.Types.healing.name',
icon: 'fa-kit-medical'
},
// resource: {
// id: 'resource',
// name: 'DAGGERHEART.Actions.Types.Resource.Name',
// name: 'DAGGERHEART.Actions.Types.resource.name',
// icon: 'fa-honey-pot'
// },
damage: {
id: 'damage',
name: 'DAGGERHEART.Actions.Types.Damage.Name',
name: 'DAGGERHEART.Actions.Types.damage.name',
icon: 'fa-bone-break'
},
summon: {
id: 'summon',
name: 'DAGGERHEART.Actions.Types.Summon.Name',
name: 'DAGGERHEART.Actions.Types.summon.name',
icon: 'fa-ghost'
},
effect: {
id: 'effect',
name: 'DAGGERHEART.Actions.Types.Effect.Name',
name: 'DAGGERHEART.Actions.Types.effect.name',
icon: 'fa-person-rays'
},
macro: {
id: 'macro',
name: 'DAGGERHEART.Actions.Types.Macro.Name',
name: 'DAGGERHEART.Actions.Types.macro.name',
icon: 'fa-scroll'
}
};
@ -105,3 +105,18 @@ export const diceCompare = {
operator: '>'
}
};
export const advandtageState = {
disadvantage: {
label: 'DAGGERHEART.General.Disadvantage.Full',
value: -1
},
neutral: {
label: 'DAGGERHEART.General.Neutral.Full',
value: 0
},
advantage: {
label: 'DAGGERHEART.General.Advantage.Full',
value: 1
}
}

View file

@ -83,72 +83,72 @@ export const featureProperties = {
export const adversaryTypes = {
bruiser: {
id: 'bruiser',
label: 'DAGGERHEART.Adversary.Type.Bruiser.label',
description: 'DAGGERHEART.Adversary.Bruiser.Description'
label: 'DAGGERHEART.Adversary.Type.bruiser.label',
description: 'DAGGERHEART.Adversary.bruiser.description'
},
horde: {
id: 'horde',
label: 'DAGGERHEART.Adversary.Type.Horde.label',
description: 'DAGGERHEART.Adversary.Horde.Description'
label: 'DAGGERHEART.Adversary.Type.horde.label',
description: 'DAGGERHEART.Adversary.horde.description'
},
leader: {
id: 'leader',
label: 'DAGGERHEART.Adversary.Type.Leader.label',
description: 'DAGGERHEART.Adversary.Leader.Description'
label: 'DAGGERHEART.Adversary.Type.leader.label',
description: 'DAGGERHEART.Adversary.leader.description'
},
minion: {
id: 'minion',
label: 'DAGGERHEART.Adversary.Type.Minion.label',
description: 'DAGGERHEART.Adversary.Minion.Description'
label: 'DAGGERHEART.Adversary.Type.minion.label',
description: 'DAGGERHEART.Adversary.minion.description'
},
ranged: {
id: 'ranged',
label: 'DAGGERHEART.Adversary.Type.Ranged.label',
description: 'DAGGERHEART.Adversary.Ranged.Description'
label: 'DAGGERHEART.Adversary.Type.ranged.label',
description: 'DAGGERHEART.Adversary.ranged.description'
},
skulk: {
id: 'skulk',
label: 'DAGGERHEART.Adversary.Type.Skulk.label',
description: 'DAGGERHEART.Adversary.Skulk.Description'
label: 'DAGGERHEART.Adversary.Type.skulk.label',
description: 'DAGGERHEART.Adversary.skulk.description'
},
social: {
id: 'social',
label: 'DAGGERHEART.Adversary.Type.Social.label',
description: 'DAGGERHEART.Adversary.Social.Description'
label: 'DAGGERHEART.Adversary.Type.social.label',
description: 'DAGGERHEART.Adversary.social.description'
},
solo: {
id: 'solo',
label: 'DAGGERHEART.Adversary.Type.Solo.label',
description: 'DAGGERHEART.Adversary.Solo.Description'
label: 'DAGGERHEART.Adversary.Type.solo.label',
description: 'DAGGERHEART.Adversary.solo.description'
},
standard: {
id: 'standard',
label: 'DAGGERHEART.Adversary.Type.Standard.label',
description: 'DAGGERHEART.Adversary.Standard.Description'
label: 'DAGGERHEART.Adversary.Type.standard.label',
description: 'DAGGERHEART.Adversary.standard.description'
},
support: {
id: 'support',
label: 'DAGGERHEART.Adversary.Type.Support.label',
description: 'DAGGERHEART.Adversary.Support.Description'
label: 'DAGGERHEART.Adversary.Type.support.label',
description: 'DAGGERHEART.Adversary.support.description'
}
};
export const environmentTypes = {
exploration: {
label: 'DAGGERHEART.Environment.Type.Exploration.label',
description: 'DAGGERHEART.Environment.Type.Exploration.description'
label: 'DAGGERHEART.Environment.Type.exploration.label',
description: 'DAGGERHEART.Environment.Type.exploration.description'
},
social: {
label: 'DAGGERHEART.Environment.Type.Social.label',
description: 'DAGGERHEART.Environment.Type.Social.description'
label: 'DAGGERHEART.Environment.Type.social.label',
description: 'DAGGERHEART.Environment.Type.social.description'
},
traversal: {
label: 'DAGGERHEART.Environment.Type.Traversal.label',
description: 'DAGGERHEART.Environment.Type.Traversal.description'
label: 'DAGGERHEART.Environment.Type.traversal.label',
description: 'DAGGERHEART.Environment.Type.traversal.description'
},
event: {
label: 'DAGGERHEART.Environment.Type.Event.label',
description: 'DAGGERHEART.Environment.Type.Event.description'
label: 'DAGGERHEART.Environment.Type.event.label',
description: 'DAGGERHEART.Environment.Type.event.description'
}
};

View file

@ -712,14 +712,14 @@ export const valueTypes = {
export const actionTypes = {
passive: {
id: 'passive',
label: 'DAGGERHEART.ActionType.Passive'
label: 'DAGGERHEART.ActionType.passive'
},
action: {
id: 'action',
label: 'DAGGERHEART.ActionType.Action'
label: 'DAGGERHEART.ActionType.action'
},
reaction: {
id: 'reaction',
label: 'DAGGERHEART.ActionType.Reaction'
label: 'DAGGERHEART.ActionType.reaction'
}
};

View file

@ -1,4 +1,3 @@
import CostSelectionDialog from '../../applications/costSelectionDialog.mjs';
import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField } from './actionDice.mjs';
import DhpActor from '../../documents/actor.mjs';
import D20RollDialog from '../../dialogs/d20RollDialog.mjs';
@ -343,7 +342,9 @@ export class DHBaseAction extends foundry.abstract.DataModel {
label: 'Attack',
type: this.actionType,
difficulty: this.roll?.difficulty,
formula: this.roll.getFormula()
formula: this.roll.getFormula(),
bonus: this.roll.bonus,
advantage: SYSTEM.ACTIONS.advandtageState[this.roll.advState].value
};
if (this.roll?.type === 'diceSet') roll.lite = true;
@ -372,7 +373,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
/* ROLL */
get hasRoll() {
return !!this.roll?.type;
return !!this.roll?.type || !!this.roll?.bonus;
}
/* ROLL */
@ -544,6 +545,29 @@ export class DHBaseAction extends foundry.abstract.DataModel {
}
}
/* SAVE */
async toChat(origin) {
const cls = getDocumentClass('ChatMessage');
const systemData = {
title: game.i18n.localize('DAGGERHEART.ActionType.action'),
origin: origin,
img: this.img,
name: this.name,
description: this.description,
actions: []
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
}
}
export class DHDamageAction extends DHBaseAction {

View file

@ -11,7 +11,8 @@ export class DHActionRollData extends foundry.abstract.DataModel {
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 }),
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
advState: new fields.StringField({ choices: SYSTEM.ACTIONS.advandtageState, initial: 'neutral' }),
diceRolling: new fields.SchemaField({
multiplier: new fields.StringField({
choices: SYSTEM.GENERAL.diceSetNumbers,
@ -62,7 +63,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
label: 'Multiplier'
}),
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }),
dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Dice' }),
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
custom: new fields.SchemaField({
enabled: new fields.BooleanField({ label: 'Custom Formula' }),

View file

@ -30,8 +30,11 @@ export default class DhpAdversary extends BaseDataActor {
choices: SYSTEM.ACTOR.adversaryTypes,
initial: SYSTEM.ACTOR.adversaryTypes.standard.id
}),
motivesAndTactics: new fields.HTMLField(),
description: new fields.StringField(),
motivesAndTactics: new fields.StringField(),
notes: new fields.HTMLField(),
difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }),
hordeHp: new fields.NumberField({ required: true, initial: 1, integer: true }),
damageThresholds: new fields.SchemaField({
major: new fields.NumberField({ required: true, initial: 0, integer: true }),
severe: new fields.NumberField({ required: true, initial: 0, integer: true })
@ -40,6 +43,7 @@ export default class DhpAdversary extends BaseDataActor {
hitPoints: resourceField(),
stress: resourceField()
}),
actions: new fields.ArrayField(new ActionField()),
attack: new ActionField({
initial: {
name: 'Attack',
@ -66,7 +70,7 @@ export default class DhpAdversary extends BaseDataActor {
experiences: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField(),
value: new fields.NumberField({ required: true, integer: true, initial: 1 })
modifier: new fields.NumberField({ required: true, integer: true, initial: 1 })
})
),
bonuses: new fields.SchemaField({

View file

@ -1,6 +1,8 @@
import { environmentTypes } from '../../config/actorConfig.mjs';
import BaseDataActor from './base.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ActionField from '../fields/actionField.mjs';
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
export default class DhEnvironment extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Environment'];
@ -21,15 +23,17 @@ export default class DhEnvironment extends BaseDataActor {
initial: SYSTEM.GENERAL.tiers.tier1.id
}),
type: new fields.StringField({ choices: environmentTypes }),
impulses: new fields.HTMLField(),
description: new fields.StringField(),
impulses: new fields.StringField(),
difficulty: new fields.NumberField({ required: true, initial: 11, integer: true }),
potentialAdversaries: new fields.TypedObjectField(
new fields.SchemaField({
label: new fields.StringField(),
adversaries: new fields.TypedObjectField(new ForeignDocumentUUIDField({ type: 'Actor' }))
adversaries: new ForeignDocumentUUIDArrayField({ type: 'Actor' })
})
)
/* Features pending datamodel rework */
),
actions: new fields.ArrayField(new ActionField()),
notes: new fields.HTMLField()
};
}
}

View file

@ -1,9 +1,9 @@
import { actionsTypes } from '../action/_module.mjs';
// 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;
return game.system.api.models.actionsTypes[value.type] ?? game.system.api.models.actionsTypes.attack;
}
/* -------------------------------------------- */

View file

@ -1,4 +1,4 @@
import { actionsTypes } from '../action/_module.mjs';
// import { actionsTypes } from '../action/_module.mjs';
/**
* Describes metadata about the item data model type
@ -60,7 +60,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
const actionType = {
weapon: 'attack'
}[this.constructor.metadata.type],
cls = actionsTypes.attack,
cls = game.system.api.models.actionsTypes[actionType],
// cls = actionsTypes.attack,
action = new cls(
{
_id: foundry.utils.randomID(),

View file

@ -9,7 +9,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.experiences = [];
if (config.source?.action) {
this.item = config.data.parent.items.get(config.source.item);
console.log(config)
this.item = config.data.parent.items.get(config.source.item) ?? config.data.parent;
this.action =
config.data.attack?._id == config.source.action
? config.data.attack
@ -50,15 +51,18 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
};
async _prepareContext(_options) {
console.log(this.config, this.roll)
const context = await super._prepareContext(_options);
context.hasRoll = !!this.config.roll;
context.roll = this.roll;
context.rollType = this.roll?.constructor.name;
context.experiences = Object.keys(this.config.data.experiences).map(id => ({
id,
...this.config.data.experiences[id]
}));
context.selectedExperiences = this.config.experiences;
context.advantage = this.config.advantage;
/* context.diceOptions = this.diceOptions; */
context.advantage = this.config.roll?.advantage;
context.diceOptions = SYSTEM.GENERAL.diceTypes;
context.canRoll = true;
context.isLite = this.config.roll?.lite;
if (this.config.costs?.length) {
@ -71,7 +75,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
context.uses = this.action.calcUses(this.config.uses);
context.canRoll = context.canRoll && this.action.hasUses(context.uses);
}
context.extraFormula = this.config.extraFormula;
context.formula = this.roll.constructFormula(this.config);
return context;
}
@ -81,12 +87,18 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs);
}
if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses);
if(rest.roll?.dice) {
Object.entries(rest.roll.dice).forEach(([key, value]) => {
this.roll[key] = value;
})
}
this.config.extraFormula = rest.extraFormula;
this.render();
}
static updateIsAdvantage(_, button) {
const advantage = Number(button.dataset.advantage);
this.config.advantage = this.config.advantage === advantage ? 0 : advantage;
this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage;
this.render();
}

View file

@ -37,10 +37,17 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.title = this.config.title;
context.formula = this.config.roll.formula;
context.extraFormula = this.config.extraFormula;
context.formula = this.roll.constructFormula(this.config);;
return context;
}
static updateRollConfiguration(event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object);
this.config.extraFormula = rest.extraFormula;
this.render();
}
static async submitRoll() {
await this.close({ submitted: true });
}