mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Refactor/84 data models structure (#131)
* - Move all DataModel item files to a new 'items' subfolder for better organization - Add _module.mjs file to simplify imports - Update all import paths - Rename class for use the new acronym DH * FIX: remove unnecessary import * FEAT: BaseDataItem class add TODO comments for future improvements FIX: Remove effect field on template FIX: remove unused DhpEffects file * FEAT: new FormulaField class FEAT: add getRollData on BaseDataItem Class FEAT: weapon FIX: remove inventoryWeapon field on Weapon Data Model * FEAT: add class prepareBaseData for domains * FEAT: new ForeignDocumentUUIDField FIX: Remove unnecessary fields FEAT: use ForeignDocumentUUIDField in the Item Class DataModel * FIX: remove wrong option in String Field * FIX: remove unused import * FIX: ADD htmlFields description in manifest * FIX: minor fixes * REFACTOR: rename folder `data/items` -> `data/item` REFACTOR: rename folder `data/messages` -> `data/chat-message`. * FIX: imports FIX: items sheet new paths FIX: ItemDataModelMetadata type jsdoc * FEAT: formatting code FIX: fix fields used FEAT: add jsdoc * 110 - Class Data Model (#111) * Added PreCreate/Create/Delete logic for Class/Subclass and set it as foreignUUID fields in PC * Moved methods into TypedModelData * Simplified Subclass * Fixed up data model and a basic placeholder template (#117) * 118 - adversary data model (#119) * Fixed datamodel and set up basic template in new style * Added in a temp attack button, because why not * Restored HitPoints counting up * 113 - Character Data Model (#114) * Improved Character datamodel * Removed additional unneccessary getters * Preliminary cleanup in the class sheet * Cleanup of 'pc' references * Corrected Duality rolling from Character * Fix to damage roll * Added a basic BaseDataActor data model * Gathered exports * getRollData recursion fix * Feature/112 items use action datamodel (#127) * Create new actions classes * actions types - attack roll * fixes before merge * First PR * Add daggerheart.css to gitignore * Update ToDo * Remove console log * Fixed chat /dr roll * Remove jQuery * Fixed so the different chat themes work again * Fixed duality roll buttons * Fix to advantage/disadvantage shortcut * Extand action to other item types * Roll fixes * Fixes to adversary rolls * resources * Fixed adversary dice --------- Co-authored-by: WBHarry <williambjrklund@gmail.com> * Feature/116-implementation-of-pseudo-documents (#125) * FEAT: add baseDataModel logic * FEAT: new PseudoDocumentsField FIX: BasePseudoDocument 's getEmbeddedDocument * FEAT: PseudoDocument class * FEAT: add TypedPseudoDocument REFACTOR: PreudoDocument FIX: Typos Bug * FIX: CONFIG types * FEAT: basic PseudoDocumentSheet * FIX: remove schema ADD: input of example --------- Co-authored-by: Joaquin Pereyra <joaquinpereyra98@users.noreply.github.com> Co-authored-by: WBHarry <williambjrklund@gmail.com> * Levelup Followup (#126) * Levelup applies bonuses to character * Added visualisation of domain card levels * Fixed domaincard level max for selections in a tier * A trait can now only be level up once within the same tier --------- Co-authored-by: Joaquin Pereyra <joaquinpereyra98@users.noreply.github.com> Co-authored-by: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com> Co-authored-by: Dapoulp <74197441+Dapoulp@users.noreply.github.com>
This commit is contained in:
parent
90bc2dc488
commit
187ee3e1bd
153 changed files with 5481 additions and 4829 deletions
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
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue