mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-19 00:19:03 +01:00
Merge branch 'main' into bug/103-enrich-htmlfield-content-before-its-used-in-applications
This commit is contained in:
commit
f56c2482cb
551 changed files with 2831 additions and 14203 deletions
|
|
@ -5,7 +5,7 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
static extraSchemas = [...super.extraSchemas, ...['roll', 'save']];
|
||||
|
||||
static getRollType(parent) {
|
||||
return parent.type === 'weapon' ? 'weapon' : 'spellcast';
|
||||
return parent.type === 'weapon' ? 'attack' : 'spellcast';
|
||||
}
|
||||
|
||||
get chatTemplate() {
|
||||
|
|
@ -21,7 +21,7 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
}
|
||||
if (this.roll.useDefault) {
|
||||
this.roll.trait = this.item.system.attack.roll.trait;
|
||||
this.roll.type = 'weapon';
|
||||
this.roll.type = 'attack';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,4 +37,17 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
base: true
|
||||
};
|
||||
}
|
||||
|
||||
async use(event, ...args) {
|
||||
const result = await super.use(event, args);
|
||||
|
||||
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.characterAttack.id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// get modifiers() {
|
||||
// return [];
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
}
|
||||
|
||||
static getRollType(parent) {
|
||||
return 'ability';
|
||||
return 'trait';
|
||||
}
|
||||
|
||||
static getSourceConfig(parent) {
|
||||
|
|
@ -268,7 +268,8 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
hasDamage: !!this.damage?.parts?.length,
|
||||
hasHealing: !!this.healing,
|
||||
hasEffect: !!this.effects?.length,
|
||||
hasSave: this.hasSave
|
||||
hasSave: this.hasSave,
|
||||
selectedRollMode: game.settings.get('core', 'rollMode')
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +309,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
|
||||
prepareRoll() {
|
||||
const roll = {
|
||||
modifiers: [],
|
||||
modifiers: this.modifiers,
|
||||
trait: this.roll?.trait,
|
||||
label: 'Attack',
|
||||
type: this.actionType,
|
||||
|
|
@ -362,6 +363,13 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
get hasRoll() {
|
||||
return !!this.roll?.type || !!this.roll?.bonus;
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
if (!this.actor) return [];
|
||||
const modifiers = [];
|
||||
/** Placeholder for specific bonuses **/
|
||||
return modifiers;
|
||||
}
|
||||
/* ROLL */
|
||||
|
||||
/* SAVE */
|
||||
|
|
|
|||
|
|
@ -6,10 +6,20 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
getFormulaValue(part, data) {
|
||||
let formulaValue = part.value;
|
||||
if (this.hasRoll && part.resultBased && data.system.roll.result.duality === -1) return part.valueAlt;
|
||||
|
||||
const isAdversary = this.actor.type === 'adversary';
|
||||
if (isAdversary && this.actor.system.type === CONFIG.DH.ACTOR.adversaryTypes.horde.id) {
|
||||
const hasHordeDamage = this.actor.effects.find(
|
||||
x => x.name === game.i18n.localize('DAGGERHEART.CONFIG.AdversaryType.horde.label')
|
||||
);
|
||||
if (hasHordeDamage) return part.valueAlt;
|
||||
}
|
||||
|
||||
return formulaValue;
|
||||
}
|
||||
|
||||
async rollDamage(event, data) {
|
||||
const systemData = data.system ?? data;
|
||||
let formula = this.damage.parts.map(p => this.getFormulaValue(p, data).getFormula(this.actor)).join(' + '),
|
||||
damageTypes = [...new Set(this.damage.parts.reduce((a, c) => a.concat([...c.type]), []))];
|
||||
|
||||
|
|
@ -19,15 +29,16 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
let roll = { formula: formula, total: formula },
|
||||
bonusDamage = [];
|
||||
|
||||
if (isNaN(formula)) formula = Roll.replaceFormulaData(formula, this.getRollData(data.system ?? data));
|
||||
if (isNaN(formula)) formula = Roll.replaceFormulaData(formula, this.getRollData(systemData));
|
||||
|
||||
const config = {
|
||||
title: game.i18n.format('DAGGERHEART.UI.Chat.damageRoll.title', { damage: this.name }),
|
||||
roll: { formula },
|
||||
targets: data.system?.targets.filter(t => t.hit) ?? data.targets,
|
||||
targets: systemData.targets.filter(t => t.hit) ?? data.targets,
|
||||
hasSave: this.hasSave,
|
||||
isCritical: data.system?.roll?.isCritical ?? false,
|
||||
source: data.system?.source,
|
||||
isCritical: systemData.roll?.isCritical ?? false,
|
||||
source: systemData.source,
|
||||
data: this.getRollData(),
|
||||
damageTypes,
|
||||
event
|
||||
};
|
||||
|
|
@ -35,8 +46,14 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
if (data.system) {
|
||||
config.source.message = data._id;
|
||||
config.directDamage = false;
|
||||
} else {
|
||||
config.directDamage = true;
|
||||
}
|
||||
|
||||
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config);
|
||||
}
|
||||
|
||||
// get modifiers() {
|
||||
// return [];
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@ export default class DHHealingAction extends DHBaseAction {
|
|||
get chatTemplate() {
|
||||
return 'systems/daggerheart/templates/ui/chat/healing-roll.hbs';
|
||||
}
|
||||
|
||||
get modifiers() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs';
|
||||
import ActionField from '../fields/actionField.mjs';
|
||||
import BaseDataActor from './base.mjs';
|
||||
|
||||
const resourceField = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
isReversed: new foundry.data.fields.BooleanField({ initial: true })
|
||||
});
|
||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
||||
|
||||
export default class DhpAdversary extends BaseDataActor {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Adversary'];
|
||||
|
|
@ -37,14 +31,29 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
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 }),
|
||||
hordeHp: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 1,
|
||||
integer: true,
|
||||
label: 'DAGGERHEART.GENERAL.hordeHp'
|
||||
}),
|
||||
damageThresholds: new fields.SchemaField({
|
||||
major: new fields.NumberField({ required: true, initial: 0, integer: true }),
|
||||
severe: new fields.NumberField({ required: true, initial: 0, integer: true })
|
||||
major: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 0,
|
||||
integer: true,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold'
|
||||
}),
|
||||
severe: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 0,
|
||||
integer: true,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
||||
})
|
||||
}),
|
||||
resources: new fields.SchemaField({
|
||||
hitPoints: resourceField(),
|
||||
stress: resourceField()
|
||||
hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.hitPoints.plural', true),
|
||||
stress: resourceField(0, 'DAGGERHEART.GENERAL.stress', true)
|
||||
}),
|
||||
attack: new ActionField({
|
||||
initial: {
|
||||
|
|
@ -59,7 +68,7 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
amount: 1
|
||||
},
|
||||
roll: {
|
||||
type: 'weapon'
|
||||
type: 'attack'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
@ -80,9 +89,14 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
})
|
||||
),
|
||||
bonuses: new fields.SchemaField({
|
||||
difficulty: new fields.SchemaField({
|
||||
all: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
reaction: new fields.NumberField({ integer: true, initial: 0 })
|
||||
roll: new fields.SchemaField({
|
||||
attack: bonusField('DAGGERHEART.GENERAL.Roll.attack'),
|
||||
action: bonusField('DAGGERHEART.GENERAL.Roll.action'),
|
||||
reaction: bonusField('DAGGERHEART.GENERAL.Roll.reaction')
|
||||
}),
|
||||
damage: new fields.SchemaField({
|
||||
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
|
||||
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage')
|
||||
})
|
||||
})
|
||||
};
|
||||
|
|
@ -95,4 +109,37 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
get features() {
|
||||
return this.parent.items.filter(x => x.type === 'feature');
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, user) {
|
||||
const allowed = await super._preUpdate(changes, options, user);
|
||||
if (allowed === false) return false;
|
||||
|
||||
if (this.type === CONFIG.DH.ACTOR.adversaryTypes.horde.id) {
|
||||
if (changes.system?.resources?.hitPoints?.value) {
|
||||
const halfHP = Math.ceil(this.resources.hitPoints.max / 2);
|
||||
const newHitPoints = changes.system.resources.hitPoints.value;
|
||||
const previouslyAboveHalf = this.resources.hitPoints.value < halfHP;
|
||||
const loweredBelowHalf = previouslyAboveHalf && newHitPoints >= halfHP;
|
||||
const raisedAboveHalf = !previouslyAboveHalf && newHitPoints < halfHP;
|
||||
if (loweredBelowHalf) {
|
||||
await this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||
{
|
||||
name: game.i18n.localize('DAGGERHEART.CONFIG.AdversaryType.horde.label'),
|
||||
img: 'icons/magic/movement/chevrons-down-yellow.webp',
|
||||
disabled: !game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation)
|
||||
.hordeDamage
|
||||
}
|
||||
]);
|
||||
} else if (raisedAboveHalf) {
|
||||
const hordeEffects = this.parent.effects.filter(
|
||||
x => x.name === game.i18n.localize('DAGGERHEART.CONFIG.AdversaryType.horde.label')
|
||||
);
|
||||
await this.parent.deleteEmbeddedDocuments(
|
||||
'ActiveEffect',
|
||||
hordeEffects.map(x => x.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
|
||||
|
||||
const resistanceField = () =>
|
||||
const resistanceField = reductionLabel =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
resistance: new foundry.data.fields.BooleanField({ initial: false }),
|
||||
immunity: new foundry.data.fields.BooleanField({ initial: false }),
|
||||
reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0 })
|
||||
reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0, label: reductionLabel })
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -40,8 +40,8 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
if (this.metadata.isNPC) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
if (this.metadata.hasResistances)
|
||||
schema.resistance = new fields.SchemaField({
|
||||
physical: resistanceField(),
|
||||
magical: resistanceField()
|
||||
physical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.physicalReduction'),
|
||||
magical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.magicalReduction')
|
||||
});
|
||||
return schema;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,11 @@ import { burden } from '../../config/generalConfig.mjs';
|
|||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||
import DhLevelData from '../levelData.mjs';
|
||||
import BaseDataActor from './base.mjs';
|
||||
|
||||
const attributeField = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
tierMarked: new foundry.data.fields.BooleanField({ initial: false })
|
||||
});
|
||||
|
||||
const resourceField = (max, reverse = false) =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new foundry.data.fields.NumberField({ initial: max, integer: true }),
|
||||
isReversed: new foundry.data.fields.BooleanField({ initial: reverse })
|
||||
});
|
||||
|
||||
const stressDamageReductionRule = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }),
|
||||
cost: new foundry.data.fields.NumberField({ integer: true })
|
||||
});
|
||||
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||
|
||||
export default class DhCharacter extends BaseDataActor {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
|
||||
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: 'TYPES.Actor.character',
|
||||
|
|
@ -37,24 +21,36 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return {
|
||||
...super.defineSchema(),
|
||||
resources: new fields.SchemaField({
|
||||
hitPoints: resourceField(0, true),
|
||||
stress: resourceField(6, true),
|
||||
hope: resourceField(6)
|
||||
hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.hitPoints.plural', true),
|
||||
stress: resourceField(6, 'DAGGERHEART.GENERAL.stress', true),
|
||||
hope: resourceField(6, 'DAGGERHEART.GENERAL.hope')
|
||||
}),
|
||||
traits: new fields.SchemaField({
|
||||
agility: attributeField(),
|
||||
strength: attributeField(),
|
||||
finesse: attributeField(),
|
||||
instinct: attributeField(),
|
||||
presence: attributeField(),
|
||||
knowledge: attributeField()
|
||||
agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'),
|
||||
strength: attributeField('DAGGERHEART.CONFIG.Traits.strength.name'),
|
||||
finesse: attributeField('DAGGERHEART.CONFIG.Traits.finesse.name'),
|
||||
instinct: attributeField('DAGGERHEART.CONFIG.Traits.instinct.name'),
|
||||
presence: attributeField('DAGGERHEART.CONFIG.Traits.presence.name'),
|
||||
knowledge: attributeField('DAGGERHEART.CONFIG.Traits.knowledge.name')
|
||||
}),
|
||||
proficiency: new fields.NumberField({ initial: 1, integer: true }),
|
||||
evasion: new fields.NumberField({ initial: 0, integer: true }),
|
||||
armorScore: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
proficiency: new fields.NumberField({
|
||||
initial: 1,
|
||||
integer: true,
|
||||
label: 'DAGGERHEART.GENERAL.proficiency'
|
||||
}),
|
||||
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
||||
armorScore: new fields.NumberField({ integer: true, initial: 0, label: 'DAGGERHEART.GENERAL.armorScore' }),
|
||||
damageThresholds: new fields.SchemaField({
|
||||
severe: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
major: new fields.NumberField({ integer: true, initial: 0 })
|
||||
severe: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold'
|
||||
}),
|
||||
major: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
||||
})
|
||||
}),
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
|
|
@ -91,24 +87,82 @@ export default class DhCharacter extends BaseDataActor {
|
|||
value: new ForeignDocumentUUIDField({ type: 'Item', nullable: true }),
|
||||
subclass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true })
|
||||
}),
|
||||
advantageSources: new fields.ArrayField(new fields.StringField()),
|
||||
disadvantageSources: new fields.ArrayField(new fields.StringField()),
|
||||
levelData: new fields.EmbeddedDataField(DhLevelData),
|
||||
bonuses: new fields.SchemaField({
|
||||
roll: new fields.SchemaField({
|
||||
attack: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
primaryWeapon: new fields.SchemaField({
|
||||
attack: new fields.NumberField({ integer: true, initial: 0 })
|
||||
}),
|
||||
spellcast: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
action: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
hopeOrFear: new fields.NumberField({ integer: true, initial: 0 })
|
||||
attack: bonusField('DAGGERHEART.GENERAL.Roll.attack'),
|
||||
spellcast: bonusField('DAGGERHEART.GENERAL.Roll.spellcast'),
|
||||
trait: bonusField('DAGGERHEART.GENERAL.Roll.trait'),
|
||||
action: bonusField('DAGGERHEART.GENERAL.Roll.action'),
|
||||
reaction: bonusField('DAGGERHEART.GENERAL.Roll.reaction'),
|
||||
primaryWeapon: bonusField('DAGGERHEART.GENERAL.Roll.primaryWeaponAttack'),
|
||||
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Roll.secondaryWeaponAttack')
|
||||
}),
|
||||
damage: new fields.SchemaField({
|
||||
all: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
physical: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
magic: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
primaryWeapon: new fields.SchemaField({
|
||||
bonus: new fields.NumberField({ integer: true }),
|
||||
extraDice: new fields.NumberField({ integer: true })
|
||||
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
|
||||
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage'),
|
||||
primaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.primaryWeapon'),
|
||||
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.secondaryWeapon')
|
||||
}),
|
||||
healing: bonusField('DAGGERHEART.GENERAL.Healing.healingAmount'),
|
||||
range: new fields.SchemaField({
|
||||
weapon: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Range.weapon'
|
||||
}),
|
||||
spell: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Range.spell'
|
||||
}),
|
||||
other: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Range.other'
|
||||
})
|
||||
}),
|
||||
rally: new fields.ArrayField(new fields.StringField(), {
|
||||
label: 'DAGGERHEART.CLASS.Feature.rallyDice'
|
||||
}),
|
||||
rest: new fields.SchemaField({
|
||||
shortRest: new fields.SchemaField({
|
||||
shortMoves: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
min: 0,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.hint'
|
||||
}),
|
||||
longMoves: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
min: 0,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.hint'
|
||||
})
|
||||
}),
|
||||
longRest: new fields.SchemaField({
|
||||
shortMoves: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
min: 0,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.hint'
|
||||
}),
|
||||
longMoves: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
min: 0,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.hint'
|
||||
})
|
||||
})
|
||||
})
|
||||
}),
|
||||
|
|
@ -117,25 +171,34 @@ export default class DhCharacter extends BaseDataActor {
|
|||
damageReduction: new fields.SchemaField({
|
||||
maxArmorMarked: new fields.SchemaField({
|
||||
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||
bonus: new fields.NumberField({ required: true, integer: true, initial: 0 }),
|
||||
stressExtra: new fields.NumberField({ required: true, integer: true, initial: 0 })
|
||||
bonus: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus'
|
||||
}),
|
||||
stressExtra: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.hint'
|
||||
})
|
||||
}),
|
||||
stressDamageReduction: new fields.SchemaField({
|
||||
severe: stressDamageReductionRule(),
|
||||
major: stressDamageReductionRule(),
|
||||
minor: stressDamageReductionRule()
|
||||
severe: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'),
|
||||
major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'),
|
||||
minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor')
|
||||
}),
|
||||
increasePerArmorMark: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint'
|
||||
}),
|
||||
increasePerArmorMark: new fields.NumberField({ integer: true, initial: 1 }),
|
||||
magical: new fields.BooleanField({ initial: false }),
|
||||
physical: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
strangePatterns: new fields.NumberField({
|
||||
integer: true,
|
||||
min: 1,
|
||||
max: 12,
|
||||
nullable: true,
|
||||
initial: null
|
||||
}),
|
||||
weapon: new fields.SchemaField({
|
||||
/* Unimplemented
|
||||
-> Should remove the lowest damage dice from weapon damage
|
||||
|
|
@ -181,6 +244,11 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return !this.class.value || !this.class.subclass;
|
||||
}
|
||||
|
||||
get spellcastModifier() {
|
||||
const subClasses = this.parent.items.filter(x => x.type === 'subclass') ?? [];
|
||||
return Math.max(subClasses?.map(sc => this.traits[sc.system.spellcastingTrait]?.value));
|
||||
}
|
||||
|
||||
get spellcastingModifiers() {
|
||||
return {
|
||||
main: this.class.subclass?.system?.spellcastingTrait,
|
||||
|
|
@ -219,23 +287,23 @@ export default class DhCharacter extends BaseDataActor {
|
|||
features = [];
|
||||
|
||||
for (let item of this.parent.items) {
|
||||
if (item.system.type === CONFIG.DH.ITEM.featureTypes.ancestry.id) {
|
||||
if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.ancestry.id) {
|
||||
ancestryFeatures.push(item);
|
||||
} else if (item.system.type === CONFIG.DH.ITEM.featureTypes.community.id) {
|
||||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.community.id) {
|
||||
communityFeatures.push(item);
|
||||
} else if (item.system.type === CONFIG.DH.ITEM.featureTypes.class.id) {
|
||||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.class.id) {
|
||||
classFeatures.push(item);
|
||||
} else if (item.system.type === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
||||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
||||
const subclassState = this.class.subclass.system.featureState;
|
||||
const identifier = item.system.identifier;
|
||||
const subType = item.system.subType;
|
||||
if (
|
||||
identifier === 'foundationFeature' ||
|
||||
(identifier === 'specializationFeature' && subclassState >= 2) ||
|
||||
(identifier === 'masterFeature' && subclassState >= 3)
|
||||
subType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(subType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
||||
(subType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
) {
|
||||
subclassFeatures.push(item);
|
||||
}
|
||||
} else if (item.system.type === CONFIG.DH.ITEM.featureTypes.companion.id) {
|
||||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.companion.id) {
|
||||
companionFeatures.push(item);
|
||||
} else if (item.type === 'feature' && !item.system.type) {
|
||||
features.push(item);
|
||||
|
|
@ -323,6 +391,8 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareBaseData() {
|
||||
this.evasion = this.class.value?.system?.evasion ?? 0;
|
||||
|
||||
const currentLevel = this.levelData.level.current;
|
||||
const currentTier =
|
||||
currentLevel === 1
|
||||
|
|
@ -380,7 +450,8 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
this.resources.hope.value = Math.min(this.resources.hope.value, this.resources.hope.max);
|
||||
const baseHope = this.resources.hope.value + (this.companion?.system?.resources?.hope ?? 0);
|
||||
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
||||
}
|
||||
|
||||
getRollData() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
|||
import ActionField from '../fields/actionField.mjs';
|
||||
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
||||
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
|
||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
||||
|
||||
export default class DhCompanion extends BaseDataActor {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Companion'];
|
||||
|
|
@ -23,14 +24,16 @@ export default class DhCompanion extends BaseDataActor {
|
|||
...super.defineSchema(),
|
||||
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
|
||||
resources: new fields.SchemaField({
|
||||
stress: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 3, integer: true }),
|
||||
isReversed: new foundry.data.fields.BooleanField({ initial: true })
|
||||
}),
|
||||
hope: new fields.NumberField({ initial: 0, integer: true })
|
||||
stress: resourceField(3, 'DAGGERHEART.GENERAL.stress', true),
|
||||
hope: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.hope' })
|
||||
}),
|
||||
evasion: new fields.NumberField({
|
||||
required: true,
|
||||
min: 1,
|
||||
initial: 10,
|
||||
integer: true,
|
||||
label: 'DAGGERHEART.GENERAL.evasion'
|
||||
}),
|
||||
evasion: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }),
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({}),
|
||||
|
|
@ -56,9 +59,8 @@ export default class DhCompanion extends BaseDataActor {
|
|||
amount: 1
|
||||
},
|
||||
roll: {
|
||||
type: 'weapon',
|
||||
bonus: 0,
|
||||
trait: 'instinct'
|
||||
type: 'attack',
|
||||
bonus: 0
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
@ -74,13 +76,13 @@ export default class DhCompanion extends BaseDataActor {
|
|||
}
|
||||
}),
|
||||
actions: new fields.ArrayField(new ActionField()),
|
||||
levelData: new fields.EmbeddedDataField(DhLevelData)
|
||||
};
|
||||
}
|
||||
|
||||
get traits() {
|
||||
return {
|
||||
instinct: { value: this.attack.roll.bonus }
|
||||
levelData: new fields.EmbeddedDataField(DhLevelData),
|
||||
bonuses: new fields.SchemaField({
|
||||
damage: new fields.SchemaField({
|
||||
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
|
||||
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage')
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -89,9 +91,7 @@ export default class DhCompanion extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareBaseData() {
|
||||
const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main;
|
||||
const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.value;
|
||||
this.attack.roll.bonus = spellcastingModifier ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing;
|
||||
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
||||
|
||||
for (let levelKey in this.levelData.levelups) {
|
||||
const level = this.levelData.levelups[levelKey];
|
||||
|
|
@ -124,12 +124,6 @@ export default class DhCompanion extends BaseDataActor {
|
|||
}
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
if (this.partner) {
|
||||
this.partner.system.resources.hope.max += this.resources.hope;
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
if (this.partner) {
|
||||
await this.partner.update({ 'system.companion': null });
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class DhCountdown extends foundry.abstract.DataModel {
|
|||
value: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.countdownTypes,
|
||||
initial: CONFIG.DH.GENERAL.countdownTypes.spotlight.id,
|
||||
initial: CONFIG.DH.GENERAL.countdownTypes.custom.id,
|
||||
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.type.value.label'
|
||||
}),
|
||||
label: new fields.StringField({
|
||||
|
|
@ -132,7 +132,13 @@ class DhCountdown extends foundry.abstract.DataModel {
|
|||
export const registerCountdownHooks = () => {
|
||||
Hooks.on(socketEvent.Refresh, ({ refreshType, application }) => {
|
||||
if (refreshType === RefreshType.Countdown) {
|
||||
foundry.applications.instances.get(application)?.render();
|
||||
if (application) {
|
||||
foundry.applications.instances.get(application)?.render();
|
||||
} else {
|
||||
foundry.applications.instances.get('narrative-countdowns')?.render();
|
||||
foundry.applications.instances.get('encounter-countdowns')?.render();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
35
module/data/fields/actorField.mjs
Normal file
35
module/data/fields/actorField.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
const attributeField = label =>
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true, label }),
|
||||
tierMarked: new fields.BooleanField({ initial: false })
|
||||
});
|
||||
|
||||
const resourceField = (max = 0, label, reverse = false) =>
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true, label }),
|
||||
max: new fields.NumberField({ initial: max, integer: true }),
|
||||
isReversed: new fields.BooleanField({ initial: reverse })
|
||||
});
|
||||
|
||||
const stressDamageReductionRule = localizationPath =>
|
||||
new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({ required: true, initial: false }),
|
||||
cost: new fields.NumberField({
|
||||
integer: true,
|
||||
label: `${localizationPath}.label`,
|
||||
hint: `${localizationPath}.hint`
|
||||
})
|
||||
});
|
||||
|
||||
const bonusField = label =>
|
||||
new fields.SchemaField({
|
||||
bonus: new fields.NumberField({ integer: true, initial: 0, label: `${game.i18n.localize(label)} Value` }),
|
||||
dice: new fields.ArrayField(
|
||||
new fields.StringField(),
|
||||
{ label: `${game.i18n.localize(label)} Dice` }
|
||||
)
|
||||
});
|
||||
|
||||
export { attributeField, resourceField, stressDamageReductionRule, bonusField };
|
||||
|
|
@ -53,11 +53,14 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
}),
|
||||
diceStates: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ integer: true, nullable: true, initial: null }),
|
||||
value: new fields.NumberField({ integer: true, initial: 1, min: 1 }),
|
||||
used: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
),
|
||||
dieFaces: new fields.StringField({ initial: '4' })
|
||||
dieFaces: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceTypes,
|
||||
initial: CONFIG.DH.GENERAL.diceTypes.d4
|
||||
})
|
||||
},
|
||||
{ nullable: true, initial: null }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export default class DHBeastform extends BaseDataItem {
|
|||
|
||||
const beastformEffect = this.parent.effects.find(x => x.type === 'beastform');
|
||||
await beastformEffect.updateSource({
|
||||
changes: [...beastformEffect.changes, { key: 'system.advantageSources', mode: 2, value: this.advantageOn }],
|
||||
system: {
|
||||
characterTokenData: {
|
||||
tokenImg: this.parent.parent.prototypeToken.texture.src,
|
||||
|
|
|
|||
|
|
@ -24,11 +24,10 @@ export default class DHClass extends BaseDataItem {
|
|||
integer: true,
|
||||
min: 1,
|
||||
initial: 5,
|
||||
label: 'DAGGERHEART.GENERAL.hitPoints'
|
||||
label: 'DAGGERHEART.GENERAL.hitPoints.plural'
|
||||
}),
|
||||
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
||||
hopeFeatures: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
||||
classFeatures: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
||||
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
||||
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||
inventory: new fields.SchemaField({
|
||||
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||
|
|
@ -52,12 +51,18 @@ export default class DHClass extends BaseDataItem {
|
|||
};
|
||||
}
|
||||
|
||||
get hopeFeature() {
|
||||
return this.hopeFeatures.length > 0 ? this.hopeFeatures[0] : null;
|
||||
get hopeFeatures() {
|
||||
return (
|
||||
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.hope) ??
|
||||
(this.features.filter(x => !x).length > 0 ? {} : null)
|
||||
);
|
||||
}
|
||||
|
||||
get features() {
|
||||
return [...this.hopeFeatures.filter(x => x), ...this.classFeatures.filter(x => x)];
|
||||
get classFeatures() {
|
||||
return (
|
||||
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.class) ??
|
||||
(this.features.filter(x => !x).length > 0 ? {} : null)
|
||||
);
|
||||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export default class DHDomainCard extends BaseDataItem {
|
|||
required: true,
|
||||
initial: CONFIG.DH.DOMAIN.cardTypes.ability.id
|
||||
}),
|
||||
foundation: new fields.BooleanField({ initial: false }),
|
||||
inVault: new fields.BooleanField({ initial: false }),
|
||||
actions: new fields.ArrayField(new ActionField())
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
||||
import BaseDataItem from './base.mjs';
|
||||
|
||||
export default class DHSubclass extends BaseDataItem {
|
||||
|
|
@ -22,20 +22,22 @@ export default class DHSubclass extends BaseDataItem {
|
|||
nullable: true,
|
||||
initial: null
|
||||
}),
|
||||
foundationFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
specializationFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
masteryFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
||||
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
||||
isMulticlass: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
|
||||
get features() {
|
||||
return [
|
||||
{ ...this.foundationFeature?.toObject(), identifier: 'foundationFeature' },
|
||||
{ ...this.specializationFeature?.toObject(), identifier: 'specializationFeature' },
|
||||
{ ...this.masteryFeature?.toObject(), identifier: 'masteryFeature' }
|
||||
];
|
||||
get foundationFeatures() {
|
||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.foundation);
|
||||
}
|
||||
|
||||
get specializationFeatures() {
|
||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.specialization);
|
||||
}
|
||||
|
||||
get masteryFeatures() {
|
||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.mastery);
|
||||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default class DHWeapon extends AttachableItem {
|
|||
},
|
||||
roll: {
|
||||
trait: 'agility',
|
||||
type: 'weapon'
|
||||
type: 'attack'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
|
|||
|
|
@ -1,23 +1,28 @@
|
|||
export default class DhAutomation extends foundry.abstract.DataModel {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Automation']; // Doesn't work for some reason
|
||||
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
hope: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hope.label'
|
||||
}), // Label need to be updated into something like "Duality Roll Auto Gain" + a hint
|
||||
hopeFear: new fields.SchemaField({
|
||||
gm: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.gm.label'
|
||||
}),
|
||||
players: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.players.label'
|
||||
})
|
||||
}),
|
||||
actionPoints: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.actionPoints.label'
|
||||
}),
|
||||
countdowns: new fields.BooleanField({
|
||||
requireD: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.countdowns.label'
|
||||
hordeDamage: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hordeDamage.label'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
moves: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true }),
|
||||
icon: new fields.StringField({ required: true }),
|
||||
img: new fields.FilePathField({
|
||||
initial: 'icons/magic/life/cross-worn-green.webp',
|
||||
categories: ['IMAGE'],
|
||||
|
|
@ -70,6 +71,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
moves: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true }),
|
||||
icon: new fields.StringField({ required: true }),
|
||||
img: new fields.FilePathField({
|
||||
initial: 'icons/magic/life/cross-worn-green.webp',
|
||||
categories: ['IMAGE'],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue