mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-13 12:11:07 +01:00
Levelup applies bonuses to character
This commit is contained in:
parent
044d0a5b21
commit
3717e2ddd4
20 changed files with 457 additions and 174 deletions
|
|
@ -6,12 +6,14 @@ import BaseDataActor from './base.mjs';
|
|||
const attributeField = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
tierMarked: new foundry.data.fields.BooleanField({ initial: false })
|
||||
});
|
||||
|
||||
const resourceField = max =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new foundry.data.fields.NumberField({ initial: max, integer: true })
|
||||
});
|
||||
|
||||
|
|
@ -40,12 +42,18 @@ export default class DhCharacter extends BaseDataActor {
|
|||
presence: attributeField(),
|
||||
knowledge: attributeField()
|
||||
}),
|
||||
proficiency: new fields.NumberField({ initial: 1, integer: true }),
|
||||
evasion: new fields.NumberField({ initial: 0, integer: true }),
|
||||
proficiency: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
evasion: new fields.SchemaField({
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
description: new fields.StringField({}),
|
||||
value: new fields.NumberField({ integer: true, nullable: true, initial: null })
|
||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
bonus: new fields.NumberField({ integer: true, initial: 0 })
|
||||
}),
|
||||
{
|
||||
initial: {
|
||||
|
|
@ -89,8 +97,8 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
get domains() {
|
||||
const classDomains = this.class ? this.class.system.domains : [];
|
||||
const multiclassDomains = this.multiclass ? this.multiclass.system.domains : [];
|
||||
const classDomains = this.class.value ? this.class.value.system.domains : [];
|
||||
const multiclassDomains = this.multiclass.value ? this.multiclass.value.system.domains : [];
|
||||
return [...classDomains, ...multiclassDomains];
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +171,38 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareBaseData() {
|
||||
for (var attributeKey in this.traits) {
|
||||
const attribute = this.traits[attributeKey];
|
||||
/* Levleup handling */
|
||||
for (let levelKey in this.levelData.levelups) {
|
||||
const level = this.levelData.levelups[levelKey];
|
||||
|
||||
this.proficiency.bonus += level.achievements.proficiency;
|
||||
|
||||
for (let selection of level.selections) {
|
||||
switch (selection.type) {
|
||||
case 'trait':
|
||||
selection.data.forEach(data => {
|
||||
this.traits[data].bonus += 1;
|
||||
});
|
||||
break;
|
||||
case 'hitPoint':
|
||||
this.resources.hitPoints.bonus += selection.value;
|
||||
break;
|
||||
case 'stress':
|
||||
this.resources.stress.bonus += selection.value;
|
||||
break;
|
||||
case 'evasion':
|
||||
this.evasion.bonus += selection.value;
|
||||
break;
|
||||
case 'proficiency':
|
||||
this.proficiency.bonus = selection.value;
|
||||
break;
|
||||
case 'experience':
|
||||
Object.keys(this.experiences).forEach(key => {
|
||||
const experience = this.experiences[key];
|
||||
experience.bonus += selection.value;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const armor = this.armor;
|
||||
|
|
@ -182,6 +219,21 @@ export default class DhCharacter extends BaseDataActor {
|
|||
prepareDerivedData() {
|
||||
this.resources.hope.max -= Object.keys(this.scars).length;
|
||||
this.resources.hope.value = Math.min(this.resources.hope.value, this.resources.hope.max);
|
||||
|
||||
for (var traitKey in this.traits) {
|
||||
var trait = this.traits[traitKey];
|
||||
trait.total = trait.value + trait.bonus;
|
||||
}
|
||||
|
||||
for (var experienceKey in this.experiences) {
|
||||
var experience = this.experiences[experienceKey];
|
||||
experience.total = experience.value + experience.bonus;
|
||||
}
|
||||
|
||||
this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus;
|
||||
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
|
||||
this.evasion.total = (this.class?.evasion ?? 0) + this.evasion.bonus;
|
||||
this.proficiency.total = this.proficiency.value + this.proficiency.bonus;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +277,7 @@ class DhPCLevelData extends foundry.abstract.DataModel {
|
|||
minCost: new fields.NumberField({ integer: true }),
|
||||
amount: new fields.NumberField({ integer: true }),
|
||||
data: new fields.ArrayField(new fields.StringField({ required: true })),
|
||||
secondaryData: new fields.StringField(),
|
||||
secondaryData: new fields.TypedObjectField(new fields.StringField({ required: true })),
|
||||
itemUuid: new fields.StringField({ required: true })
|
||||
})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -36,17 +36,12 @@ export default class DHDomainCard extends BaseDataItem {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!this.actor.system.domains.find(x => x === item.system.domain)) {
|
||||
if (!this.actor.system.domains.find(x => x === this.domain)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.LacksDomain'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.actor.system.domainCards.total.length === 5) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.MaxLoadoutReached'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.actor.system.domainCards.total.find(x => x.name === item.name)) {
|
||||
if (this.actor.system.domainCards.total.find(x => x.name === this.parent.name)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.DuplicateDomainCard'));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,24 +25,37 @@ export default class DHSubclass extends BaseDataItem {
|
|||
foundationFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
specializationFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
masteryFeature: new ForeignDocumentUUIDField({ type: 'Item' }),
|
||||
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
||||
isMulticlass: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
|
||||
get features() {
|
||||
return {
|
||||
foundation: this.foundationFeature,
|
||||
specialization: this.featureState >= 2 ? this.specializationFeature : null,
|
||||
mastery: this.featureState === 3 ? this.masteryFeature : null
|
||||
};
|
||||
}
|
||||
|
||||
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' : 'system.class';
|
||||
const classData = foundry.utils.getProperty(this.actor, path);
|
||||
if (!classData.value) {
|
||||
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.Item.Errors.MissingClass'));
|
||||
return false;
|
||||
} else if (classData.subclass) {
|
||||
} else if (subclassData) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassAlreadySelected'));
|
||||
return false;
|
||||
} else if (classData.value.system.subclasses.every(x => x.uuid !== `Item.${data._id}`)) {
|
||||
} else if (classData.system.subclasses.every(x => x.uuid !== `Item.${data._id}`)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassNotInClass'));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,11 +97,12 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
case 'experience':
|
||||
case 'domainCard':
|
||||
case 'subclass':
|
||||
return checkbox.amount ? checkbox.data.length === checkbox.amount : checkbox.data.length === 1;
|
||||
return checkbox.data.length === (checkbox.amount ?? 1);
|
||||
case 'multiclass':
|
||||
const classSelected = checkbox.data.length === 1;
|
||||
const domainSelected = checkbox.secondaryData;
|
||||
return classSelected && domainSelected;
|
||||
const domainSelected = checkbox.secondaryData.domain;
|
||||
const subclassSelected = checkbox.secondaryData.subclass;
|
||||
return classSelected && domainSelected && subclassSelected;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
|
@ -129,7 +130,7 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
}
|
||||
|
||||
get classUpgradeChoices() {
|
||||
let subclass = null;
|
||||
let subclasses = [];
|
||||
let multiclass = null;
|
||||
Object.keys(this.levels).forEach(levelKey => {
|
||||
const level = this.levels[levelKey];
|
||||
|
|
@ -138,21 +139,22 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
if (checkbox.type === 'multiclass') {
|
||||
multiclass = {
|
||||
class: checkbox.data.length > 0 ? checkbox.data[0] : null,
|
||||
domain: checkbox.secondaryData ?? null,
|
||||
domain: checkbox.secondaryData.domain ?? null,
|
||||
subclass: checkbox.secondaryData.subclass ?? null,
|
||||
tier: checkbox.tier,
|
||||
level: levelKey
|
||||
};
|
||||
}
|
||||
if (checkbox.type === 'subclass') {
|
||||
subclass = {
|
||||
subclasses.push({
|
||||
tier: checkbox.tier,
|
||||
level: levelKey
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return { subclass, multiclass };
|
||||
return { subclasses, multiclass };
|
||||
}
|
||||
|
||||
get tiersForRendering() {
|
||||
|
|
@ -179,11 +181,11 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
}, {})
|
||||
);
|
||||
|
||||
const { multiclass, subclass } = this.classUpgradeChoices;
|
||||
const { multiclass, subclasses } = this.classUpgradeChoices;
|
||||
return tierKeys.map(tierKey => {
|
||||
const tier = this.tiers[tierKey];
|
||||
const multiclassInTier = multiclass?.tier === Number(tierKey);
|
||||
const subclassInTier = subclass?.tier === Number(tierKey);
|
||||
const subclassInTier = subclasses.some(x => x.tier === Number(tierKey));
|
||||
|
||||
return {
|
||||
name: tier.name,
|
||||
|
|
@ -287,7 +289,7 @@ export class DhLevelupLevel extends foundry.abstract.DataModel {
|
|||
amount: new fields.NumberField({ integer: true }),
|
||||
value: new fields.StringField(),
|
||||
data: new fields.ArrayField(new fields.StringField()),
|
||||
secondaryData: new fields.StringField(),
|
||||
secondaryData: new fields.TypedObjectField(new fields.StringField()),
|
||||
type: new fields.StringField({ required: true })
|
||||
})
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue