mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 06:26:13 +01:00
[Feature] 1383 - Companion Bonus Levelups (#1565)
* Fixed so that companions can get bonus levelupchoices from their partner * Fixed collection prep order * Added ActiveEffects to Beastbound features * Corrected styling * Added migration for overleveled companions * Raised version * Moved migration to 1.6.0. Sillyness
This commit is contained in:
parent
c42f876d4f
commit
ce96ffa0a3
15 changed files with 551 additions and 18 deletions
|
|
@ -3,6 +3,7 @@ import * as applications from './module/applications/_module.mjs';
|
|||
import * as data from './module/data/_module.mjs';
|
||||
import * as models from './module/data/_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 fields from './module/data/fields/_module.mjs';
|
||||
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
||||
|
|
@ -36,6 +37,7 @@ CONFIG.Dice.daggerheart = {
|
|||
|
||||
CONFIG.Actor.documentClass = documents.DhpActor;
|
||||
CONFIG.Actor.dataModels = models.actors.config;
|
||||
CONFIG.Actor.collection = collections.DhActorCollection;
|
||||
|
||||
CONFIG.Item.documentClass = documents.DHItem;
|
||||
CONFIG.Item.dataModels = models.items.config;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import BaseLevelUp from './levelup.mjs';
|
||||
import { defaultCompanionTier, LevelOptionType } from '../../data/levelTier.mjs';
|
||||
import { DhLevelup } from '../../data/levelup.mjs';
|
||||
import { DhCompanionLevelup as DhLevelup } from '../../data/companionLevelup.mjs';
|
||||
import { diceTypes, range } from '../../config/generalConfig.mjs';
|
||||
|
||||
export default class DhCompanionLevelUp extends BaseLevelUp {
|
||||
|
|
@ -9,7 +9,9 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
|
|||
|
||||
this.levelTiers = this.addBonusChoices(defaultCompanionTier);
|
||||
const playerLevelupData = actor.system.levelData;
|
||||
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
|
||||
this.levelup = new DhLevelup(
|
||||
DhLevelup.initializeData(this.levelTiers, playerLevelupData, actor.system.levelupChoicesLeft)
|
||||
);
|
||||
}
|
||||
|
||||
async _preparePartContext(partId, context) {
|
||||
|
|
|
|||
|
|
@ -38,15 +38,6 @@ 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 */
|
||||
/* -------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -662,6 +662,11 @@ export default class DhCharacter extends BaseDataActor {
|
|||
const globalHopeMax = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxHope;
|
||||
this.resources.hope.max = globalHopeMax - this.scars;
|
||||
this.resources.hitPoints.max += this.class.value?.system?.hitPoints ?? 0;
|
||||
|
||||
/* Companion Related Data */
|
||||
this.companionData = {
|
||||
levelupChoices: this.levelData.level.current - 1
|
||||
};
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
|
|
@ -733,6 +738,16 @@ 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() {
|
||||
|
|
|
|||
|
|
@ -109,6 +109,10 @@ export default class DhCompanion extends BaseDataActor {
|
|||
return this.partner?.system?.proficiency ?? 1;
|
||||
}
|
||||
|
||||
get canLevelUp() {
|
||||
return this.levelupChoicesLeft > 0;
|
||||
}
|
||||
|
||||
isItemValid() {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -147,6 +151,17 @@ 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) {
|
||||
const allowed = await super._preUpdate(changes, options, userId);
|
||||
if (allowed === false) return;
|
||||
|
|
@ -162,6 +177,16 @@ export default class DhCompanion extends BaseDataActor {
|
|||
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() {
|
||||
|
|
|
|||
370
module/data/companionLevelup.mjs
Normal file
370
module/data/companionLevelup.mjs
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
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,6 +241,11 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.system.companion) {
|
||||
this.system.companion.updateLevel(usedLevel);
|
||||
}
|
||||
|
||||
this.sheet.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
module/documents/collections/_module.mjs
Normal file
1
module/documents/collections/_module.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as DhActorCollection } from './actorCollection.mjs';
|
||||
14
module/documents/collections/actorCollection.mjs
Normal file
14
module/documents/collections/actorCollection.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -212,6 +212,7 @@ export async function runMigrations() {
|
|||
}
|
||||
|
||||
if (foundry.utils.isNewerVersion('1.5.5', lastMigrationVersion)) {
|
||||
/* Clear out Environments that were added directly from compendium */
|
||||
for (const scene of game.scenes) {
|
||||
if (!scene.flags.daggerheart) continue;
|
||||
const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart);
|
||||
|
|
@ -226,6 +227,25 @@ export async function runMigrations() {
|
|||
|
||||
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
|
||||
|
||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,51 @@
|
|||
"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,
|
||||
"ownership": {
|
||||
"default": 0,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,51 @@
|
|||
"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,
|
||||
"ownership": {
|
||||
"default": 0,
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@
|
|||
.input-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "daggerheart",
|
||||
"title": "Daggerheart",
|
||||
"description": "An unofficial implementation of the Daggerheart system",
|
||||
"version": "1.5.5",
|
||||
"version": "1.6.0",
|
||||
"compatibility": {
|
||||
"minimum": "13.346",
|
||||
"verified": "13.351",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<h3 class='label'>
|
||||
{{localize 'DAGGERHEART.GENERAL.level'}}
|
||||
<div class="input-section">
|
||||
{{#if document.system.levelData.canLevelUp}}
|
||||
{{#if document.system.canLevelUp}}
|
||||
<button
|
||||
type="button"
|
||||
class="level-button glow" data-tooltip="{{localize "DAGGERHEART.ACTORS.Character.levelUp"}}"
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
</button>
|
||||
{{/if}}
|
||||
<span {{#unless document.system.partner}}data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.companionPartnerLevelBlock"}}"{{/unless}}>
|
||||
<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)}} />
|
||||
{{document.system.levelData.level.changed}}
|
||||
</span>
|
||||
</div>
|
||||
</h3>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue