mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-06-08 13:48:11 +02:00
Compare commits
No commits in common. "bae9470a4fbf3f9fd16b8ba7215ba7ac8bef44c7" and "c42f876d4f8028a111e98c6be831d5e475208865" have entirely different histories.
bae9470a4f
...
c42f876d4f
17 changed files with 31 additions and 556 deletions
|
|
@ -3,7 +3,6 @@ import * as applications from './module/applications/_module.mjs';
|
||||||
import * as data from './module/data/_module.mjs';
|
import * as data from './module/data/_module.mjs';
|
||||||
import * as models from './module/data/_module.mjs';
|
import * as models from './module/data/_module.mjs';
|
||||||
import * as documents from './module/documents/_module.mjs';
|
import * as documents from './module/documents/_module.mjs';
|
||||||
import * as collections from './module/documents/collections/_module.mjs';
|
|
||||||
import * as dice from './module/dice/_module.mjs';
|
import * as dice from './module/dice/_module.mjs';
|
||||||
import * as fields from './module/data/fields/_module.mjs';
|
import * as fields from './module/data/fields/_module.mjs';
|
||||||
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
||||||
|
|
@ -37,7 +36,6 @@ CONFIG.Dice.daggerheart = {
|
||||||
|
|
||||||
CONFIG.Actor.documentClass = documents.DhpActor;
|
CONFIG.Actor.documentClass = documents.DhpActor;
|
||||||
CONFIG.Actor.dataModels = models.actors.config;
|
CONFIG.Actor.dataModels = models.actors.config;
|
||||||
CONFIG.Actor.collection = collections.DhActorCollection;
|
|
||||||
|
|
||||||
CONFIG.Item.documentClass = documents.DHItem;
|
CONFIG.Item.documentClass = documents.DHItem;
|
||||||
CONFIG.Item.dataModels = models.items.config;
|
CONFIG.Item.dataModels = models.items.config;
|
||||||
|
|
@ -425,8 +423,8 @@ Hooks.on('targetToken', () => {
|
||||||
debouncedRangeEffectCall();
|
debouncedRangeEffectCall();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('refreshToken', (token, options) => {
|
Hooks.on('refreshToken', (_, options) => {
|
||||||
if (options.refreshPosition && !token._original) {
|
if (options.refreshPosition) {
|
||||||
debouncedRangeEffectCall();
|
debouncedRangeEffectCall();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import BaseLevelUp from './levelup.mjs';
|
import BaseLevelUp from './levelup.mjs';
|
||||||
import { defaultCompanionTier, LevelOptionType } from '../../data/levelTier.mjs';
|
import { defaultCompanionTier, LevelOptionType } from '../../data/levelTier.mjs';
|
||||||
import { DhCompanionLevelup as DhLevelup } from '../../data/companionLevelup.mjs';
|
import { DhLevelup } from '../../data/levelup.mjs';
|
||||||
import { diceTypes, range } from '../../config/generalConfig.mjs';
|
import { diceTypes, range } from '../../config/generalConfig.mjs';
|
||||||
|
|
||||||
export default class DhCompanionLevelUp extends BaseLevelUp {
|
export default class DhCompanionLevelUp extends BaseLevelUp {
|
||||||
|
|
@ -9,9 +9,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
|
||||||
|
|
||||||
this.levelTiers = this.addBonusChoices(defaultCompanionTier);
|
this.levelTiers = this.addBonusChoices(defaultCompanionTier);
|
||||||
const playerLevelupData = actor.system.levelData;
|
const playerLevelupData = actor.system.levelData;
|
||||||
this.levelup = new DhLevelup(
|
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
|
||||||
DhLevelup.initializeData(this.levelTiers, playerLevelupData, actor.system.levelupChoicesLeft)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preparePartContext(partId, context) {
|
async _preparePartContext(partId, context) {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,15 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async _onRender(context, options) {
|
||||||
|
await super._onRender(context, options);
|
||||||
|
|
||||||
|
this.element
|
||||||
|
.querySelector('.level-value')
|
||||||
|
?.addEventListener('change', event => this.document.updateLevel(Number(event.currentTarget.value)));
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
||||||
|
|
@ -662,11 +662,6 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
const globalHopeMax = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxHope;
|
const globalHopeMax = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxHope;
|
||||||
this.resources.hope.max = globalHopeMax - this.scars;
|
this.resources.hope.max = globalHopeMax - this.scars;
|
||||||
this.resources.hitPoints.max += this.class.value?.system?.hitPoints ?? 0;
|
this.resources.hitPoints.max += this.class.value?.system?.hitPoints ?? 0;
|
||||||
|
|
||||||
/* Companion Related Data */
|
|
||||||
this.companionData = {
|
|
||||||
levelupChoices: this.levelData.level.current - 1
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
|
|
@ -682,6 +677,8 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.companion.system.attack.roll.bonus = this.traits.instinct.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
||||||
|
|
@ -736,16 +733,6 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force companion data prep */
|
|
||||||
if (this.companion) {
|
|
||||||
if (
|
|
||||||
changes.system?.levelData?.level?.current !== undefined &&
|
|
||||||
changes.system.levelData.level.current !== this._source.levelData.level.current
|
|
||||||
) {
|
|
||||||
this.companion.update(this.companion.toObject(), { diff: false, recursive: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preDelete() {
|
async _preDelete() {
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,6 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
return this.partner?.system?.proficiency ?? 1;
|
return this.partner?.system?.proficiency ?? 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
get canLevelUp() {
|
|
||||||
return this.levelupChoicesLeft > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
isItemValid() {
|
isItemValid() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +127,7 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
if (selection.data[0] === 'damage') {
|
if (selection.data[0] === 'damage') {
|
||||||
this.attack.damage.parts[0].value.dice = adjustDice(this.attack.damage.parts[0].value.dice);
|
this.attack.damage.parts[0].value.dice = adjustDice(this.attack.damage.parts[0].value.dice);
|
||||||
} else {
|
} else {
|
||||||
this.attack.range = adjustRange(this.attack.range).id;
|
this.attack.range = adjustRange(this.attack.range);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'stress':
|
case 'stress':
|
||||||
|
|
@ -151,17 +147,6 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
|
||||||
/* Partner Related Setup */
|
|
||||||
if (this.partner) {
|
|
||||||
this.levelData.level.changed = this.partner.system.levelData.level.current;
|
|
||||||
this.levelupChoicesLeft = Object.values(this.levelData.levelups).reduce((acc, curr) => {
|
|
||||||
acc = Math.max(acc - curr.selections.length, 0);
|
|
||||||
return acc;
|
|
||||||
}, this.partner.system.companionData.levelupChoices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preUpdate(changes, options, userId) {
|
async _preUpdate(changes, options, userId) {
|
||||||
const allowed = await super._preUpdate(changes, options, userId);
|
const allowed = await super._preUpdate(changes, options, userId);
|
||||||
if (allowed === false) return;
|
if (allowed === false) return;
|
||||||
|
|
@ -177,16 +162,6 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
changes.system.experiences[experience].core = true;
|
changes.system.experiences[experience].core = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force partner data prep */
|
|
||||||
if (this.partner) {
|
|
||||||
if (
|
|
||||||
changes.system?.levelData?.level?.current !== undefined &&
|
|
||||||
changes.system.levelData.level.current !== this._source.levelData.level.current
|
|
||||||
) {
|
|
||||||
this.partner.update(this.partner.toObject(), { diff: false, recursive: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preDelete() {
|
async _preDelete() {
|
||||||
|
|
|
||||||
|
|
@ -1,370 +0,0 @@
|
||||||
import { abilities } from '../config/actorConfig.mjs';
|
|
||||||
import { chunkify } from '../helpers/utils.mjs';
|
|
||||||
import { LevelOptionType } from './levelTier.mjs';
|
|
||||||
|
|
||||||
export class DhCompanionLevelup extends foundry.abstract.DataModel {
|
|
||||||
static initializeData(levelTierData, pcLevelData, origChoicesLeft) {
|
|
||||||
let choicesLeft = origChoicesLeft;
|
|
||||||
|
|
||||||
const { current, changed } = pcLevelData.level;
|
|
||||||
const bonusChoicesOnly = current === changed;
|
|
||||||
const startLevel = bonusChoicesOnly ? current : current + 1;
|
|
||||||
const endLevel = bonusChoicesOnly ? startLevel : changed;
|
|
||||||
|
|
||||||
const tiers = {};
|
|
||||||
const levels = {};
|
|
||||||
const tierKeys = Object.keys(levelTierData.tiers);
|
|
||||||
tierKeys.forEach(key => {
|
|
||||||
const tier = levelTierData.tiers[key];
|
|
||||||
const belongingLevels = [];
|
|
||||||
for (var i = tier.levels.start; i <= tier.levels.end; i++) {
|
|
||||||
if (i <= endLevel) {
|
|
||||||
const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {};
|
|
||||||
const experiences = initialAchievements.experience
|
|
||||||
? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => {
|
|
||||||
acc[foundry.utils.randomID()] = {
|
|
||||||
name: '',
|
|
||||||
modifier: initialAchievements.experience.modifier
|
|
||||||
};
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
: {};
|
|
||||||
|
|
||||||
const currentChoices = pcLevelData.levelups[i]?.selections?.length;
|
|
||||||
const maxSelections =
|
|
||||||
i === endLevel
|
|
||||||
? choicesLeft + (currentChoices ?? 0)
|
|
||||||
: (currentChoices ?? tier.maxSelections[i]);
|
|
||||||
if (!pcLevelData.levelups[i]) choicesLeft -= maxSelections;
|
|
||||||
|
|
||||||
levels[i] = DhLevelupLevel.initializeData(pcLevelData.levelups[i], maxSelections, {
|
|
||||||
...initialAchievements,
|
|
||||||
experiences,
|
|
||||||
domainCards: {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
belongingLevels.push(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Improve. Temporary handling for Companion new experiences */
|
|
||||||
Object.keys(tier.extraAchievements ?? {}).forEach(key => {
|
|
||||||
const level = Number(key);
|
|
||||||
if (level >= startLevel && level <= endLevel) {
|
|
||||||
const levelExtras = tier.extraAchievements[level];
|
|
||||||
if (levelExtras.experience) {
|
|
||||||
levels[level].achievements.experiences[foundry.utils.randomID()] = {
|
|
||||||
name: '',
|
|
||||||
modifier: levelExtras.experience.modifier
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
tiers[key] = {
|
|
||||||
name: tier.name,
|
|
||||||
belongingLevels: belongingLevels,
|
|
||||||
options: Object.keys(tier.options).reduce((acc, key) => {
|
|
||||||
acc[key] = tier.options[key].toObject?.() ?? tier.options[key];
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
tiers,
|
|
||||||
levels,
|
|
||||||
startLevel,
|
|
||||||
currentLevel: startLevel,
|
|
||||||
endLevel
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static defineSchema() {
|
|
||||||
const fields = foundry.data.fields;
|
|
||||||
|
|
||||||
return {
|
|
||||||
tiers: new fields.TypedObjectField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
name: new fields.StringField({ required: true }),
|
|
||||||
belongingLevels: new fields.ArrayField(new fields.NumberField({ required: true, integer: true })),
|
|
||||||
options: new fields.TypedObjectField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
label: new fields.StringField({ required: true }),
|
|
||||||
checkboxSelections: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
minCost: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
type: new fields.StringField({ required: true, choices: LevelOptionType }),
|
|
||||||
value: new fields.NumberField({ integer: true }),
|
|
||||||
amount: new fields.NumberField({ integer: true })
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
),
|
|
||||||
levels: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupLevel)),
|
|
||||||
startLevel: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
currentLevel: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
endLevel: new fields.NumberField({ required: true, integer: true })
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#levelFinished(levelKey) {
|
|
||||||
const allSelectionsMade = this.levels[levelKey].nrSelections.available === 0;
|
|
||||||
const allChoicesMade = Object.keys(this.levels[levelKey].choices).every(choiceKey => {
|
|
||||||
const choice = this.levels[levelKey].choices[choiceKey];
|
|
||||||
return Object.values(choice).every(checkbox => {
|
|
||||||
switch (choiceKey) {
|
|
||||||
case 'trait':
|
|
||||||
case 'experience':
|
|
||||||
case 'domainCard':
|
|
||||||
case 'subclass':
|
|
||||||
case 'vicious':
|
|
||||||
return checkbox.data.length === (checkbox.amount ?? 1);
|
|
||||||
case 'multiclass':
|
|
||||||
const classSelected = checkbox.data.length === 1;
|
|
||||||
const domainSelected = checkbox.secondaryData.domain;
|
|
||||||
const subclassSelected = checkbox.secondaryData.subclass;
|
|
||||||
return classSelected && domainSelected && subclassSelected;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const experiencesSelected = !this.levels[levelKey].achievements.experiences
|
|
||||||
? true
|
|
||||||
: Object.values(this.levels[levelKey].achievements.experiences).every(exp => exp.name);
|
|
||||||
const domainCardsSelected = Object.values(this.levels[levelKey].achievements.domainCards)
|
|
||||||
.filter(x => x.level <= this.endLevel)
|
|
||||||
.every(card => card.uuid);
|
|
||||||
const allAchievementsSelected = experiencesSelected && domainCardsSelected;
|
|
||||||
|
|
||||||
return allSelectionsMade && allChoicesMade && allAchievementsSelected;
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentLevelFinished() {
|
|
||||||
return this.#levelFinished(this.currentLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
get allLevelsFinished() {
|
|
||||||
return Object.keys(this.levels)
|
|
||||||
.filter(level => Number(level) >= this.startLevel)
|
|
||||||
.every(this.#levelFinished.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
get unmarkedTraits() {
|
|
||||||
const possibleLevels = Object.values(this.tiers).reduce((acc, tier) => {
|
|
||||||
if (tier.belongingLevels.includes(this.currentLevel)) acc = tier.belongingLevels;
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return Object.keys(this.levels)
|
|
||||||
.filter(key => possibleLevels.some(x => x === Number(key)))
|
|
||||||
.reduce(
|
|
||||||
(acc, levelKey) => {
|
|
||||||
const level = this.levels[levelKey];
|
|
||||||
Object.values(level.choices).forEach(choice =>
|
|
||||||
Object.values(choice).forEach(checkbox => {
|
|
||||||
if (
|
|
||||||
checkbox.type === 'trait' &&
|
|
||||||
checkbox.data.length > 0 &&
|
|
||||||
Number(levelKey) !== this.currentLevel
|
|
||||||
) {
|
|
||||||
checkbox.data.forEach(data => delete acc[data]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{ ...abilities }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get classUpgradeChoices() {
|
|
||||||
let subclasses = [];
|
|
||||||
let multiclass = null;
|
|
||||||
Object.keys(this.levels).forEach(levelKey => {
|
|
||||||
const level = this.levels[levelKey];
|
|
||||||
Object.values(level.choices).forEach(choice => {
|
|
||||||
Object.values(choice).forEach(checkbox => {
|
|
||||||
if (checkbox.type === 'multiclass') {
|
|
||||||
multiclass = {
|
|
||||||
class: checkbox.data.length > 0 ? checkbox.data[0] : null,
|
|
||||||
domain: checkbox.secondaryData.domain ?? null,
|
|
||||||
subclass: checkbox.secondaryData.subclass ?? null,
|
|
||||||
tier: checkbox.tier,
|
|
||||||
level: levelKey
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (checkbox.type === 'subclass') {
|
|
||||||
subclasses.push({
|
|
||||||
tier: checkbox.tier,
|
|
||||||
level: levelKey
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return { subclasses, multiclass };
|
|
||||||
}
|
|
||||||
|
|
||||||
get tiersForRendering() {
|
|
||||||
const tierKeys = Object.keys(this.tiers);
|
|
||||||
const selections = Object.keys(this.levels).reduce(
|
|
||||||
(acc, key) => {
|
|
||||||
const level = this.levels[key];
|
|
||||||
Object.keys(level.choices).forEach(optionKey => {
|
|
||||||
const choice = level.choices[optionKey];
|
|
||||||
Object.keys(choice).forEach(checkboxNr => {
|
|
||||||
const checkbox = choice[checkboxNr];
|
|
||||||
if (!acc[checkbox.tier][optionKey]) acc[checkbox.tier][optionKey] = {};
|
|
||||||
Object.keys(choice).forEach(checkboxNr => {
|
|
||||||
acc[checkbox.tier][optionKey][checkboxNr] = { ...checkbox, level: Number(key) };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
tierKeys.reduce((acc, key) => {
|
|
||||||
acc[key] = {};
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
);
|
|
||||||
|
|
||||||
const { multiclass, subclasses } = this.classUpgradeChoices;
|
|
||||||
return tierKeys.map((tierKey, tierIndex) => {
|
|
||||||
const tier = this.tiers[tierKey];
|
|
||||||
const multiclassInTier = multiclass?.tier === Number(tierKey);
|
|
||||||
const subclassInTier = subclasses.some(x => x.tier === Number(tierKey));
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: game.i18n.localize(tier.name),
|
|
||||||
active: this.currentLevel >= Math.min(...tier.belongingLevels),
|
|
||||||
groups: Object.keys(tier.options).map(optionKey => {
|
|
||||||
const option = tier.options[optionKey];
|
|
||||||
|
|
||||||
const checkboxes = [...Array(option.checkboxSelections).keys()].flatMap(index => {
|
|
||||||
const checkboxNr = index + 1;
|
|
||||||
const checkboxData = selections[tierKey]?.[optionKey]?.[checkboxNr];
|
|
||||||
const checkbox = { ...option, checkboxNr, tier: tierKey };
|
|
||||||
|
|
||||||
if (checkboxData) {
|
|
||||||
checkbox.level = checkboxData.level;
|
|
||||||
checkbox.selected = true;
|
|
||||||
checkbox.disabled = checkbox.level !== this.currentLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optionKey === 'multiclass') {
|
|
||||||
if ((multiclass && !multiclassInTier) || subclassInTier) {
|
|
||||||
checkbox.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optionKey === 'subclass' && multiclassInTier) {
|
|
||||||
checkbox.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkbox;
|
|
||||||
});
|
|
||||||
|
|
||||||
let label = game.i18n.localize(option.label);
|
|
||||||
if (optionKey === 'domainCard') {
|
|
||||||
const maxLevel = tier.belongingLevels[tier.belongingLevels.length - 1];
|
|
||||||
label = game.i18n.format(option.label, { maxLevel });
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
label: label,
|
|
||||||
checkboxGroups: chunkify(checkboxes, option.minCost, chunkedBoxes => {
|
|
||||||
const anySelected = chunkedBoxes.some(x => x.selected);
|
|
||||||
const anyDisabled = chunkedBoxes.some(x => x.disabled);
|
|
||||||
return {
|
|
||||||
multi: option.minCost > 1,
|
|
||||||
checkboxes: chunkedBoxes.map(x => ({
|
|
||||||
...x,
|
|
||||||
selected: anySelected,
|
|
||||||
disabled: anyDisabled
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DhLevelupLevel extends foundry.abstract.DataModel {
|
|
||||||
static initializeData(levelData = { selections: [] }, maxSelections, achievements) {
|
|
||||||
return {
|
|
||||||
maxSelections: maxSelections,
|
|
||||||
achievements: {
|
|
||||||
experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {},
|
|
||||||
domainCards: levelData.achievements?.domainCards
|
|
||||||
? levelData.achievements.domainCards.reduce((acc, card, index) => {
|
|
||||||
acc[index] = { ...card };
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
: (achievements.domainCards ?? {}),
|
|
||||||
proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null
|
|
||||||
},
|
|
||||||
choices: levelData.selections.reduce((acc, data) => {
|
|
||||||
if (!acc[data.optionKey]) acc[data.optionKey] = {};
|
|
||||||
acc[data.optionKey][data.checkboxNr] = { ...data };
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static defineSchema() {
|
|
||||||
const fields = foundry.data.fields;
|
|
||||||
|
|
||||||
return {
|
|
||||||
maxSelections: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
achievements: new fields.SchemaField({
|
|
||||||
experiences: new fields.TypedObjectField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
name: new fields.StringField({ required: true }),
|
|
||||||
modifier: new fields.NumberField({ required: true, integer: true })
|
|
||||||
})
|
|
||||||
),
|
|
||||||
domainCards: new fields.TypedObjectField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
uuid: new fields.StringField({ required: true, nullable: true, initial: null }),
|
|
||||||
itemUuid: new fields.StringField({ required: true }),
|
|
||||||
level: new fields.NumberField({ required: true, integer: true })
|
|
||||||
})
|
|
||||||
),
|
|
||||||
proficiency: new fields.NumberField({ integer: true })
|
|
||||||
}),
|
|
||||||
choices: new fields.TypedObjectField(
|
|
||||||
new fields.TypedObjectField(
|
|
||||||
new fields.SchemaField({
|
|
||||||
tier: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
minCost: new fields.NumberField({ required: true, integer: true }),
|
|
||||||
amount: new fields.NumberField({ integer: true }),
|
|
||||||
value: new fields.StringField(),
|
|
||||||
data: new fields.ArrayField(new fields.StringField()),
|
|
||||||
secondaryData: new fields.TypedObjectField(new fields.StringField()),
|
|
||||||
type: new fields.StringField({ required: true })
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get nrSelections() {
|
|
||||||
const selections = Object.keys(this.choices).reduce((acc, choiceKey) => {
|
|
||||||
const choice = this.choices[choiceKey];
|
|
||||||
acc += Object.values(choice).reduce((acc, x) => acc + x.minCost, 0);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return {
|
|
||||||
selections: selections,
|
|
||||||
available: this.maxSelections - selections
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -241,11 +241,6 @@ export default class DhpActor extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.system.companion) {
|
|
||||||
this.system.companion.updateLevel(usedLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sheet.render();
|
this.sheet.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as DhActorCollection } from './actorCollection.mjs';
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
export default class DhActorCollection extends foundry.documents.collections.Actors {
|
|
||||||
/** Ensure companions are initialized after all other subtypes. */
|
|
||||||
_initialize() {
|
|
||||||
super._initialize();
|
|
||||||
const companions = [];
|
|
||||||
for (const actor of this.values()) {
|
|
||||||
if (actor.type === 'companion') companions.push(actor);
|
|
||||||
}
|
|
||||||
for (const actor of companions) {
|
|
||||||
this.delete(actor.id);
|
|
||||||
this.set(actor.id, actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default class DhScene extends Scene {
|
||||||
|
|
||||||
if (changes.flags?.daggerheart) {
|
if (changes.flags?.daggerheart) {
|
||||||
if (this._source.flags.daggerheart) {
|
if (this._source.flags.daggerheart) {
|
||||||
const unregisterTriggerData = (this._source.flags.daggerheart.sceneEnvironments ?? []).reduce(
|
const unregisterTriggerData = this._source.flags.daggerheart.sceneEnvironments.reduce(
|
||||||
(acc, env) => {
|
(acc, env) => {
|
||||||
if (!changes.flags.daggerheart.sceneEnvironments.includes(env)) acc.sceneEnvironments.push(env);
|
if (!changes.flags.daggerheart.sceneEnvironments.includes(env)) acc.sceneEnvironments.push(env);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,6 @@ export async function runMigrations() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundry.utils.isNewerVersion('1.5.5', lastMigrationVersion)) {
|
if (foundry.utils.isNewerVersion('1.5.5', lastMigrationVersion)) {
|
||||||
/* Clear out Environments that were added directly from compendium */
|
|
||||||
for (const scene of game.scenes) {
|
for (const scene of game.scenes) {
|
||||||
if (!scene.flags.daggerheart) continue;
|
if (!scene.flags.daggerheart) continue;
|
||||||
const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart);
|
const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart);
|
||||||
|
|
@ -227,25 +226,6 @@ export async function runMigrations() {
|
||||||
|
|
||||||
lastMigrationVersion = '1.5.5';
|
lastMigrationVersion = '1.5.5';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundry.utils.isNewerVersion('1.6.0', lastMigrationVersion)) {
|
|
||||||
/* Delevel any companions that are higher level than their partner character */
|
|
||||||
for (const companion of game.actors.filter(x => x.type === 'companion')) {
|
|
||||||
if (companion.system.levelData.level.current <= 1) continue;
|
|
||||||
|
|
||||||
if (!companion.system.partner) {
|
|
||||||
await companion.updateLevel(1);
|
|
||||||
} else {
|
|
||||||
const endLevel = companion.system.partner.system.levelData.level.current;
|
|
||||||
if (endLevel < companion.system.levelData.level.current) {
|
|
||||||
companion.system.levelData.level.changed = companion.system.levelData.level.current;
|
|
||||||
await companion.updateLevel(endLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastMigrationVersion = '1.6.0';
|
|
||||||
}
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,13 @@
|
||||||
"name": "Spend Hope",
|
"name": "Spend Hope",
|
||||||
"img": "icons/skills/melee/maneuver-sword-katana-yellow.webp",
|
"img": "icons/skills/melee/maneuver-sword-katana-yellow.webp",
|
||||||
"range": "",
|
"range": "",
|
||||||
"triggers": []
|
"triggers": [
|
||||||
|
{
|
||||||
|
"trigger": "postDamageReduction",
|
||||||
|
"triggeringActorType": "other",
|
||||||
|
"command": "/* Check if sufficient hope */\nif (this.actor.system.resources.hope.value < 2) return;\n\n/* Check if hit point damage was dealt */\nconst hpDamage = damageUpdates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id);\nif (hpDamage.value < 0) return;\n\n/* Dialog to give player choice */\nconst confirmed = await foundry.applications.api.DialogV2.confirm({\n window: { title: this.item?.name ?? '' },\n content: game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.ferocityContent', { bonus: hpDamage.value }),\n});\n\nif (!confirmed) return;\n\n/* Create the effect */\nthis.actor.createEmbeddedDocuments('ActiveEffect', [{\n name: this.item.name,\n img: 'icons/skills/melee/maneuver-sword-katana-yellow.webp',\n description: game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.ferocityEffectDescription', { bonus: hpDamage.value }),\n changes: [{ key: 'system.evasion', mode: 2, value: hpDamage.value }]\n}]);\n\n/* Update hope */\nreturn { updates: [{ \n originActor: this.actor, \n updates: [{\n key: CONFIG.DH.GENERAL.healingTypes.hope.id,\n value: -2,\n total: 2\n }] \n}]}"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attribution": {
|
"attribution": {
|
||||||
|
|
|
||||||
|
|
@ -16,51 +16,7 @@
|
||||||
"artist": ""
|
"artist": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"effects": [
|
"effects": [],
|
||||||
{
|
|
||||||
"name": "Advanced Training",
|
|
||||||
"type": "base",
|
|
||||||
"system": {
|
|
||||||
"rangeDependence": {
|
|
||||||
"enabled": false,
|
|
||||||
"type": "withinRange",
|
|
||||||
"target": "hostile",
|
|
||||||
"range": "melee"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_id": "bKOuMxhB2Jth3j2T",
|
|
||||||
"img": "icons/creatures/mammals/wolf-howl-moon-gray.webp",
|
|
||||||
"changes": [
|
|
||||||
{
|
|
||||||
"key": "system.companionData.levelupChoices",
|
|
||||||
"mode": 2,
|
|
||||||
"value": "2",
|
|
||||||
"priority": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"disabled": false,
|
|
||||||
"duration": {
|
|
||||||
"startTime": null,
|
|
||||||
"combat": null,
|
|
||||||
"seconds": null,
|
|
||||||
"rounds": null,
|
|
||||||
"turns": null,
|
|
||||||
"startRound": null,
|
|
||||||
"startTurn": null
|
|
||||||
},
|
|
||||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.565);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">Choose two additional level-up options for your companion.</span></p>",
|
|
||||||
"origin": null,
|
|
||||||
"tint": "#ffffff",
|
|
||||||
"transfer": true,
|
|
||||||
"statuses": [],
|
|
||||||
"sort": 0,
|
|
||||||
"flags": {},
|
|
||||||
"_stats": {
|
|
||||||
"compendiumSource": null
|
|
||||||
},
|
|
||||||
"_key": "!items.effects!uGcs785h94RMtueH.bKOuMxhB2Jth3j2T"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"ownership": {
|
"ownership": {
|
||||||
"default": 0,
|
"default": 0,
|
||||||
|
|
|
||||||
|
|
@ -16,51 +16,7 @@
|
||||||
"artist": ""
|
"artist": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"effects": [
|
"effects": [],
|
||||||
{
|
|
||||||
"name": "Expert Training",
|
|
||||||
"type": "base",
|
|
||||||
"system": {
|
|
||||||
"rangeDependence": {
|
|
||||||
"enabled": false,
|
|
||||||
"type": "withinRange",
|
|
||||||
"target": "hostile",
|
|
||||||
"range": "melee"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_id": "rknTONvaUDZ2Yz1W",
|
|
||||||
"img": "icons/creatures/mammals/dog-husky-white-blue.webp",
|
|
||||||
"changes": [
|
|
||||||
{
|
|
||||||
"key": "system.companionData.levelupChoices",
|
|
||||||
"mode": 2,
|
|
||||||
"value": "1",
|
|
||||||
"priority": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"disabled": false,
|
|
||||||
"duration": {
|
|
||||||
"startTime": null,
|
|
||||||
"combat": null,
|
|
||||||
"seconds": null,
|
|
||||||
"rounds": null,
|
|
||||||
"turns": null,
|
|
||||||
"startRound": null,
|
|
||||||
"startTurn": null
|
|
||||||
},
|
|
||||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.565);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">Choose an additional level-up option for your companion.</span></p>",
|
|
||||||
"origin": null,
|
|
||||||
"tint": "#ffffff",
|
|
||||||
"transfer": true,
|
|
||||||
"statuses": [],
|
|
||||||
"sort": 0,
|
|
||||||
"flags": {},
|
|
||||||
"_stats": {
|
|
||||||
"compendiumSource": null
|
|
||||||
},
|
|
||||||
"_key": "!items.effects!iCXtOWBKv1FdKdWz.rknTONvaUDZ2Yz1W"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"ownership": {
|
"ownership": {
|
||||||
"default": 0,
|
"default": 0,
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@
|
||||||
.input-section {
|
.input-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "daggerheart",
|
"id": "daggerheart",
|
||||||
"title": "Daggerheart",
|
"title": "Daggerheart",
|
||||||
"description": "An unofficial implementation of the Daggerheart system",
|
"description": "An unofficial implementation of the Daggerheart system",
|
||||||
"version": "1.6.0",
|
"version": "1.5.5",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13.346",
|
"minimum": "13.346",
|
||||||
"verified": "13.351",
|
"verified": "13.351",
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
<h3 class='label'>
|
<h3 class='label'>
|
||||||
{{localize 'DAGGERHEART.GENERAL.level'}}
|
{{localize 'DAGGERHEART.GENERAL.level'}}
|
||||||
<div class="input-section">
|
<div class="input-section">
|
||||||
{{#if document.system.canLevelUp}}
|
{{#if document.system.levelData.canLevelUp}}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="level-button glow" data-tooltip="{{localize "DAGGERHEART.ACTORS.Character.levelUp"}}"
|
class="level-button glow" data-tooltip="{{localize "DAGGERHEART.ACTORS.Character.levelUp"}}"
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span {{#unless document.system.partner}}data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.companionPartnerLevelBlock"}}"{{/unless}}>
|
<span {{#unless document.system.partner}}data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.companionPartnerLevelBlock"}}"{{/unless}}>
|
||||||
{{document.system.levelData.level.changed}}
|
<input type="text" data-dtype="Number" class="level-value" value={{document.system.levelData.level.changed}} {{#if document.system.needsCharacterSetup}}disabled{{/if}} {{disabled (not document.system.partner)}} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue