mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 16:09:03 +01:00
Fix conflict
This commit is contained in:
commit
c3e7a3ea1a
132 changed files with 17213 additions and 1404 deletions
|
|
@ -10,10 +10,8 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
|
||||
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;
|
||||
const hasHordeDamage = this.actor.effects.find(x => x.type === 'horde');
|
||||
if (hasHordeDamage && !hasHordeDamage.disabled) return part.valueAlt;
|
||||
}
|
||||
|
||||
return formulaValue;
|
||||
|
|
@ -78,7 +76,9 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
formulas = this.formatFormulas(formulas, systemData);
|
||||
|
||||
const config = {
|
||||
title: game.i18n.format(`DAGGERHEART.UI.Chat.${ this.type === 'healing' ? 'healing' : 'damage'}Roll.title`, { damage: game.i18n.localize(this.name) }),
|
||||
title: game.i18n.format(`DAGGERHEART.UI.Chat.${this.type === 'healing' ? 'healing' : 'damage'}Roll.title`, {
|
||||
damage: game.i18n.localize(this.name)
|
||||
}),
|
||||
roll: formulas,
|
||||
targets: systemData.targets?.filter(t => t.hit) ?? data.targets,
|
||||
hasSave: this.hasSave,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import BaseEffect from './baseEffect.mjs';
|
||||
import BeastformEffect from './beastformEffect.mjs';
|
||||
import HordeEffect from './hordeEffect.mjs';
|
||||
|
||||
export { BaseEffect, BeastformEffect };
|
||||
export { BaseEffect, BeastformEffect, HordeEffect };
|
||||
|
||||
export const config = {
|
||||
base: BaseEffect,
|
||||
beastform: BeastformEffect
|
||||
beastform: BeastformEffect,
|
||||
horde: HordeEffect
|
||||
};
|
||||
|
|
|
|||
3
module/data/activeEffect/hordeEffect.mjs
Normal file
3
module/data/activeEffect/hordeEffect.mjs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import BaseEffect from './baseEffect.mjs';
|
||||
|
||||
export default class HordeEffect extends BaseEffect {}
|
||||
|
|
@ -87,7 +87,8 @@ 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 })
|
||||
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||
description: new fields.StringField()
|
||||
})
|
||||
),
|
||||
bonuses: new fields.SchemaField({
|
||||
|
|
@ -117,29 +118,46 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
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)
|
||||
);
|
||||
const autoHordeDamage = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.Automation
|
||||
).hordeDamage;
|
||||
if (autoHordeDamage && changes.system?.resources?.hitPoints?.value) {
|
||||
const hordeActiveEffect = this.parent.effects.find(x => x.type === 'horde');
|
||||
if (hordeActiveEffect) {
|
||||
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 hordeActiveEffect.update({ disabled: false });
|
||||
} else if (raisedAboveHalf) {
|
||||
await hordeActiveEffect.update({ disabled: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onUpdate(changes, options, userId) {
|
||||
super._onUpdate(changes, options, userId);
|
||||
|
||||
if (game.user.id === userId) {
|
||||
if (changes.system.type) {
|
||||
const existingHordeEffect = this.parent.effects.find(x => x.type === 'horde');
|
||||
if (changes.system.type === CONFIG.DH.ACTOR.adversaryTypes.horde.id) {
|
||||
if (!existingHordeEffect)
|
||||
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||
{
|
||||
type: 'horde',
|
||||
name: game.i18n.localize('DAGGERHEART.CONFIG.AdversaryType.horde.label'),
|
||||
img: 'icons/magic/movement/chevrons-down-yellow.webp',
|
||||
disabled: true
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
existingHordeEffect?.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import DhLevelData from '../levelData.mjs';
|
|||
import BaseDataActor from './base.mjs';
|
||||
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||
import { ActionField } from '../fields/actionField.mjs';
|
||||
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
|
||||
|
||||
export default class DhCharacter extends BaseDataActor {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
|
||||
|
|
@ -12,6 +13,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: 'TYPES.Actor.character',
|
||||
type: 'character',
|
||||
settingSheet: DHCharacterSettings,
|
||||
isNPC: false
|
||||
});
|
||||
}
|
||||
|
|
@ -22,7 +24,12 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return {
|
||||
...super.defineSchema(),
|
||||
resources: new fields.SchemaField({
|
||||
hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.HitPoints.plural', true),
|
||||
hitPoints: resourceField(
|
||||
0,
|
||||
'DAGGERHEART.GENERAL.HitPoints.plural',
|
||||
true,
|
||||
'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
||||
),
|
||||
stress: resourceField(6, 'DAGGERHEART.GENERAL.stress', true),
|
||||
hope: resourceField(6, 'DAGGERHEART.GENERAL.hope')
|
||||
}),
|
||||
|
|
@ -56,7 +63,8 @@ export default class DhCharacter extends BaseDataActor {
|
|||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField(),
|
||||
value: new fields.NumberField({ integer: true, initial: 0 })
|
||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
description: new fields.StringField()
|
||||
})
|
||||
),
|
||||
gold: new fields.SchemaField({
|
||||
|
|
@ -312,7 +320,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
get needsCharacterSetup() {
|
||||
return !this.class.value || !this.class.subclass;
|
||||
return !(this.class.value || this.class.subclass || this.ancestry || this.community);
|
||||
}
|
||||
|
||||
get spellcastModifier() {
|
||||
|
|
@ -399,11 +407,16 @@ export default class DhCharacter extends BaseDataActor {
|
|||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
||||
if (this.class.subclass) {
|
||||
const subclassState = this.class.subclass.system.featureState;
|
||||
const subType = item.system.subType;
|
||||
const subclass =
|
||||
item.system.identifier === 'multiclass' ? this.multiclass.subclass : this.class.subclass;
|
||||
const featureType = subclass
|
||||
? (subclass.system.features.find(x => x.item?.uuid === item.uuid)?.type ?? null)
|
||||
: null;
|
||||
|
||||
if (
|
||||
subType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(subType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
||||
(subType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
featureType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
) {
|
||||
subclassFeatures.push(item);
|
||||
}
|
||||
|
|
@ -502,7 +515,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareBaseData() {
|
||||
this.evasion = this.class.value?.system?.evasion ?? 0;
|
||||
this.evasion += this.class.value?.system?.evasion ?? 0;
|
||||
|
||||
const currentLevel = this.levelData.level.current;
|
||||
const currentTier =
|
||||
|
|
@ -511,37 +524,39 @@ export default class DhCharacter extends BaseDataActor {
|
|||
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
|
||||
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
|
||||
).tier;
|
||||
for (let levelKey in this.levelData.levelups) {
|
||||
const level = this.levelData.levelups[levelKey];
|
||||
if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto) {
|
||||
for (let levelKey in this.levelData.levelups) {
|
||||
const level = this.levelData.levelups[levelKey];
|
||||
|
||||
this.proficiency += level.achievements.proficiency;
|
||||
this.proficiency += level.achievements.proficiency;
|
||||
|
||||
for (let selection of level.selections) {
|
||||
switch (selection.type) {
|
||||
case 'trait':
|
||||
selection.data.forEach(data => {
|
||||
this.traits[data].value += 1;
|
||||
this.traits[data].tierMarked = selection.tier === currentTier;
|
||||
});
|
||||
break;
|
||||
case 'hitPoint':
|
||||
this.resources.hitPoints.max += selection.value;
|
||||
break;
|
||||
case 'stress':
|
||||
this.resources.stress.max += selection.value;
|
||||
break;
|
||||
case 'evasion':
|
||||
this.evasion += selection.value;
|
||||
break;
|
||||
case 'proficiency':
|
||||
this.proficiency += selection.value;
|
||||
break;
|
||||
case 'experience':
|
||||
Object.keys(this.experiences).forEach(key => {
|
||||
const experience = this.experiences[key];
|
||||
experience.value += selection.value;
|
||||
});
|
||||
break;
|
||||
for (let selection of level.selections) {
|
||||
switch (selection.type) {
|
||||
case 'trait':
|
||||
selection.data.forEach(data => {
|
||||
this.traits[data].value += 1;
|
||||
this.traits[data].tierMarked = selection.tier === currentTier;
|
||||
});
|
||||
break;
|
||||
case 'hitPoint':
|
||||
this.resources.hitPoints.max += selection.value;
|
||||
break;
|
||||
case 'stress':
|
||||
this.resources.stress.max += selection.value;
|
||||
break;
|
||||
case 'evasion':
|
||||
this.evasion += selection.value;
|
||||
break;
|
||||
case 'proficiency':
|
||||
this.proficiency += selection.value;
|
||||
break;
|
||||
case 'experience':
|
||||
selection.data.forEach(id => {
|
||||
const experience = this.experiences[id];
|
||||
if (experience) experience.value += selection.value;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@ const attributeField = label =>
|
|||
tierMarked: new fields.BooleanField({ initial: false })
|
||||
});
|
||||
|
||||
const resourceField = (max = 0, label, reverse = false) =>
|
||||
const resourceField = (max = 0, label, reverse = false, maxLabel) =>
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, min: 0, integer: true, label }),
|
||||
max: new fields.NumberField({ initial: max, integer: true }),
|
||||
max: new fields.NumberField({
|
||||
initial: max,
|
||||
integer: true,
|
||||
label:
|
||||
maxLabel ?? game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
|
||||
}),
|
||||
isReversed: new fields.BooleanField({ initial: reverse })
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -125,18 +125,36 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
if (this.actor && this.actor.type === 'character' && this.features) {
|
||||
const featureUpdates = {};
|
||||
for (let f of this.features) {
|
||||
const feature = f.item ?? f;
|
||||
const createData = foundry.utils.mergeObject(feature.toObject(), {
|
||||
system: {
|
||||
originItemType: this.parent.type,
|
||||
originId: data._id,
|
||||
identifier: feature.identifier,
|
||||
subType: feature.item ? feature.type : undefined
|
||||
}
|
||||
}, { inplace: false });
|
||||
await this.actor.createEmbeddedDocuments('Item', [createData]);
|
||||
const fBase = f.item ?? f;
|
||||
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
||||
const createData = foundry.utils.mergeObject(
|
||||
feature.toObject(),
|
||||
{
|
||||
system: {
|
||||
originItemType: this.parent.type,
|
||||
originId: data._id,
|
||||
identifier: this.isMulticlass ? 'multiclass' : null
|
||||
}
|
||||
},
|
||||
{ inplace: false }
|
||||
);
|
||||
const [doc] = await this.actor.createEmbeddedDocuments('Item', [createData]);
|
||||
|
||||
if (!featureUpdates.features)
|
||||
featureUpdates.features = this.features.map(x => (x.item ? { ...x, item: x.item.uuid } : x.uuid));
|
||||
|
||||
if (f.item) {
|
||||
const existingFeature = featureUpdates.features.find(x => x.item === f.item.uuid);
|
||||
existingFeature.item = doc.uuid;
|
||||
} else {
|
||||
const replaceIndex = featureUpdates.features.findIndex(x => x === f.uuid);
|
||||
featureUpdates.features.splice(replaceIndex, 1, doc.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
await this.updateSource(featureUpdates);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,16 +62,37 @@ export default class DHClass extends BaseDataItem {
|
|||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
|
||||
if (this.actor?.type === 'character') {
|
||||
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
|
||||
if (foundry.utils.getProperty(this.actor, path)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
|
||||
return false;
|
||||
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
|
||||
if (levelupAuto) {
|
||||
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
|
||||
if (foundry.utils.getProperty(this.actor, path)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (this.actor.system.class.value) {
|
||||
if (this.actor.system.multiclass.value) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.localize('DAGGERHEART.UI.Notifications.multiclassAlreadyPresent')
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
const selectedDomain =
|
||||
await game.system.api.applications.dialogs.MulticlassChoiceDialog.configure(
|
||||
this.actor,
|
||||
this
|
||||
);
|
||||
if (!selectedDomain) return false;
|
||||
|
||||
await this.updateSource({ isMulticlass: true, domains: [selectedDomain] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
}
|
||||
|
||||
_onCreate(data, options, userId) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export default class DHFeature extends BaseDataItem {
|
|||
nullable: true,
|
||||
initial: null
|
||||
}),
|
||||
subType: new fields.StringField({ choices: CONFIG.DH.ITEM.featureSubTypes, nullable: true, initial: null }),
|
||||
originId: new fields.StringField({ nullable: true, initial: null }),
|
||||
identifier: new fields.StringField()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,27 +41,48 @@ export default class DHSubclass extends BaseDataItem {
|
|||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
|
||||
if (this.actor?.type === 'character') {
|
||||
const classData = this.actor.items.find(
|
||||
x => x.type === 'class' && x.system.isMulticlass === data.system.isMulticlass
|
||||
);
|
||||
const subclassData = this.actor.items.find(
|
||||
x => x.type === 'subclass' && x.system.isMulticlass === data.system.isMulticlass
|
||||
);
|
||||
if (!classData) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
||||
return false;
|
||||
} else if (subclassData) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassAlreadySelected'));
|
||||
return false;
|
||||
} else if (classData.system.subclasses.every(x => x.uuid !== (data.uuid ?? `Item.${data._id}`))) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
||||
return false;
|
||||
if (this.actor.system.class.subclass) {
|
||||
if (this.actor.system.multiclass.subclass) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent'));
|
||||
return false;
|
||||
} else {
|
||||
if (!this.actor.system.multiclass.value) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingMulticlass'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
this.actor.system.multiclass.value.system.subclasses.every(
|
||||
x => x.uuid !== (data.uuid ?? `Item.${data._id}`)
|
||||
)
|
||||
) {
|
||||
ui.notifications.error(
|
||||
game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInMulticlass')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.updateSource({ isMulticlass: true });
|
||||
}
|
||||
} else {
|
||||
if (!this.actor.system.class.value) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
this.actor.system.class.value.system.subclasses.every(
|
||||
x => x.uuid !== (data.uuid ?? `Item.${data._id}`)
|
||||
)
|
||||
) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
}
|
||||
|
||||
_onCreate(data, options, userId) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.players.label'
|
||||
})
|
||||
}),
|
||||
levelupAuto: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.levelupAuto.label'
|
||||
}),
|
||||
actionPoints: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue