Compare commits

..

No commits in common. "2a294684d4d70a3d1984facac75a67c7f89acc46" and "8d8fa983ef18863c21882b963de97d4ac865cd47" have entirely different histories.

27 changed files with 494 additions and 449 deletions

View file

@ -89,14 +89,9 @@
}, },
"Config": { "Config": {
"beastform": { "beastform": {
"exact": { "label": "Beastform Max Tier", "hint": "The Character's Tier is used if empty" }, "exact": "Beastform Max Tier",
"modifications": { "exactHint": "The Character's Tier is used if empty",
"traitBonuses": { "label": "Beastform"
"label": { "single": "Trait Bonus", "plural": "Trait Bonuses" },
"hint": "Pick bonuses you apply to freely chosen traits at the time of transforming",
"bonus": "Bonus Amount"
}
}
}, },
"countdown": { "countdown": {
"defaultOwnership": "Default Ownership", "defaultOwnership": "Default Ownership",

View file

@ -10,12 +10,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
this.selected = null; this.selected = null;
this.evolved = { form: null }; this.evolved = { form: null };
this.hybrid = { forms: {}, advantages: {}, features: {} }; this.hybrid = { forms: {}, advantages: {}, features: {} };
this.modifications = {
traitBonuses: configData.modifications.traitBonuses.map(x => ({
trait: null,
bonus: x.bonus
}))
};
this._dragDrop = this._createDragDropHandlers(); this._dragDrop = this._createDragDropHandlers();
} }
@ -34,7 +28,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
selectBeastform: this.selectBeastform, selectBeastform: this.selectBeastform,
toggleHybridFeature: this.toggleHybridFeature, toggleHybridFeature: this.toggleHybridFeature,
toggleHybridAdvantage: this.toggleHybridAdvantage, toggleHybridAdvantage: this.toggleHybridAdvantage,
toggleTraitBonus: this.toggleTraitBonus,
submitBeastform: this.submitBeastform submitBeastform: this.submitBeastform
}, },
form: { form: {
@ -55,7 +48,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
tabs: { template: 'systems/daggerheart/templates/dialogs/beastform/tabs.hbs' }, tabs: { template: 'systems/daggerheart/templates/dialogs/beastform/tabs.hbs' },
beastformTier: { template: 'systems/daggerheart/templates/dialogs/beastform/beastformTier.hbs' }, beastformTier: { template: 'systems/daggerheart/templates/dialogs/beastform/beastformTier.hbs' },
advanced: { template: 'systems/daggerheart/templates/dialogs/beastform/advanced.hbs' }, advanced: { template: 'systems/daggerheart/templates/dialogs/beastform/advanced.hbs' },
modifications: { template: 'systems/daggerheart/templates/dialogs/beastform/modifications.hbs' },
footer: { template: 'systems/daggerheart/templates/dialogs/beastform/footer.hbs' } footer: { template: 'systems/daggerheart/templates/dialogs/beastform/footer.hbs' }
}; };
@ -154,9 +146,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
{} {}
); );
context.modifications = this.modifications;
context.traits = CONFIG.DH.ACTOR.abilities;
context.tier = beastformTiers[this.tabGroups.primary]; context.tier = beastformTiers[this.tabGroups.primary];
context.tierKey = this.tabGroups.primary; context.tierKey = this.tabGroups.primary;
@ -166,9 +155,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
} }
canSubmit() { canSubmit() {
const modificationsFinished = this.modifications.traitBonuses.every(x => x.trait);
if (!modificationsFinished) return false;
if (this.selected) { if (this.selected) {
switch (this.selected.system.beastformType) { switch (this.selected.system.beastformType) {
case 'normal': case 'normal':
@ -275,13 +261,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
this.render(); this.render();
} }
static toggleTraitBonus(_, button) {
const { index, trait } = button.dataset;
this.modifications.traitBonuses[index].trait =
this.modifications.traitBonuses[index].trait === trait ? null : trait;
this.render();
}
static async submitBeastform() { static async submitBeastform() {
await this.close({ submitted: true }); await this.close({ submitted: true });
} }
@ -313,23 +292,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
} }
} }
const beastformEffect = selected.effects.find(x => x.type === 'beastform');
for (const traitBonus of app.modifications.traitBonuses) {
const existingChange = beastformEffect.changes.find(
x => x.key === `system.traits.${traitBonus.trait}.value`
);
if (existingChange) {
existingChange.value = Number.parseInt(existingChange.value) + traitBonus.bonus;
} else {
beastformEffect.changes.push({
key: `system.traits.${traitBonus.trait}.value`,
mode: 2,
priority: null,
value: traitBonus.bonus
});
}
}
resolve({ resolve({
selected: selected, selected: selected,
evolved: { ...app.evolved, form: evolved }, evolved: { ...app.evolved, form: evolved },

View file

@ -453,8 +453,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
const { parsedRoll, newRoll } = await game.system.api.dice.DualityRoll.reroll( const { parsedRoll, newRoll } = await game.system.api.dice.DualityRoll.reroll(
memberData.rollData, memberData.rollData,
dieIndex, dieIndex,
diceType, diceType
false
); );
const rollData = parsedRoll.toJSON(); const rollData = parsedRoll.toJSON();
this.updatePartyData( this.updatePartyData(

View file

@ -36,9 +36,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
editDoc: this.editDoc, editDoc: this.editDoc,
addTrigger: this.addTrigger, addTrigger: this.addTrigger,
removeTrigger: this.removeTrigger, removeTrigger: this.removeTrigger,
expandTrigger: this.expandTrigger, expandTrigger: this.expandTrigger
addBeastformTraitBonus: this.addBeastformTraitBonus,
removeBeastformTraitBonus: this.removeBeastformTraitBonus
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
@ -414,21 +412,6 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
} }
} }
static async addBeastformTraitBonus() {
const data = this.action.toObject();
data.beastform.modifications.traitBonuses = [
...data.beastform.modifications.traitBonuses,
this.action.schema.fields.beastform.fields.modifications.fields.traitBonuses.element.getInitialValue()
];
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
}
static async removeBeastformTraitBonus(_event, button) {
const data = this.action.toObject();
data.beastform.modifications.traitBonuses.splice(button.dataset.index, 1);
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
}
updateSummonCount(event) { updateSummonCount(event) {
event.stopPropagation(); event.stopPropagation();
const wrapper = event.target.closest('.summon-count-wrapper'); const wrapper = event.target.closest('.summon-count-wrapper');

View file

@ -25,7 +25,7 @@ export default class BeastformEffect extends BaseEffect {
width: new fields.NumberField({ integer: false, nullable: true }) width: new fields.NumberField({ integer: false, nullable: true })
}) })
}), }),
advantageOn: new fields.TypedObjectField(new fields.SchemaField({ value: new fields.StringField() })), advantageOn: new fields.ArrayField(new fields.StringField()),
featureIds: new fields.ArrayField(new fields.StringField()), featureIds: new fields.ArrayField(new fields.StringField()),
effectIds: new fields.ArrayField(new fields.StringField()) effectIds: new fields.ArrayField(new fields.StringField())
}; };

View file

@ -28,21 +28,8 @@ export default class BeastformField extends fields.SchemaField {
{ 1: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') } { 1: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') }
); );
}, },
label: 'DAGGERHEART.ACTIONS.Config.beastform.exact.label', hint: 'DAGGERHEART.ACTIONS.Config.beastform.exactHint'
hint: 'DAGGERHEART.ACTIONS.Config.beastform.exact.hint'
}) })
}),
modifications: new fields.SchemaField({
traitBonuses: new fields.ArrayField(
new fields.SchemaField({
bonus: new fields.NumberField({
integer: true,
initial: 1,
min: 1,
label: 'DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.bonus'
})
})
)
}) })
}; };
super(beastformFields, options, context); super(beastformFields, options, context);
@ -79,9 +66,15 @@ export default class BeastformField extends fields.SchemaField {
) ?? 1; ) ?? 1;
config.tierLimit = this.beastform.tierAccess.exact ?? actorTier; config.tierLimit = this.beastform.tierAccess.exact ?? actorTier;
config.modifications = this.beastform.modifications;
} }
/**
* TODO by Harry
* @param {*} selectedForm
* @param {*} evolvedData
* @param {*} hybridData
* @returns
*/
static async transform(selectedForm, evolvedData, hybridData) { static async transform(selectedForm, evolvedData, hybridData) {
const formData = evolvedData?.form ?? selectedForm; const formData = evolvedData?.form ?? selectedForm;
const beastformEffect = formData.effects.find(x => x.type === 'beastform'); const beastformEffect = formData.effects.find(x => x.type === 'beastform');

View file

@ -99,14 +99,10 @@ export default class DHBeastform extends BaseDataItem {
get beastformAttackData() { get beastformAttackData() {
const effect = this.parent.effects.find(x => x.type === 'beastform'); const effect = this.parent.effects.find(x => x.type === 'beastform');
return DHBeastform.getBeastformAttackData(effect);
}
static getBeastformAttackData(effect) {
if (!effect) return null; if (!effect) return null;
const mainTrait = effect.system.changes.find(x => x.key === 'system.rules.attack.roll.trait')?.value; const traitBonus =
const traitBonus = effect.system.changes.find(x => x.key === `system.traits.${mainTrait}.value`)?.value ?? 0; effect.system.changes.find(x => x.key === `system.traits.${this.mainTrait}.value`)?.value ?? 0;
const evasionBonus = effect.system.changes.find(x => x.key === 'system.evasion')?.value ?? 0; const evasionBonus = effect.system.changes.find(x => x.key === 'system.evasion')?.value ?? 0;
const damageDiceIndex = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex'); const damageDiceIndex = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex');
@ -114,7 +110,7 @@ export default class DHBeastform extends BaseDataItem {
const damageBonus = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0; const damageBonus = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0;
return { return {
trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[mainTrait]?.label), trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.mainTrait].label),
traitBonus: traitBonus ? Number(traitBonus).signedString() : '', traitBonus: traitBonus ? Number(traitBonus).signedString() : '',
evasionBonus: evasionBonus ? Number(evasionBonus).signedString() : '', evasionBonus: evasionBonus ? Number(evasionBonus).signedString() : '',
damageDice: damageDice, damageDice: damageDice,

View file

@ -122,6 +122,10 @@ export default class DHRoll extends Roll {
if (roll._evaluated) { if (roll._evaluated) {
const message = await cls.create(msgData, { messageMode: config.selectedMessageMode }); const message = await cls.create(msgData, { messageMode: config.selectedMessageMode });
if (config.tagTeamSelected) {
game.system.api.applications.dialogs.TagTeamDialog.assignRoll(message.speakerActor, message);
}
if (roll.formula !== '' && game.modules.get('dice-so-nice')?.active) { if (roll.formula !== '' && game.modules.get('dice-so-nice')?.active) {
await game.dice3d.waitFor3DAnimationByMessageID(message.id); await game.dice3d.waitFor3DAnimationByMessageID(message.id);
} }

View file

@ -305,6 +305,7 @@ export default class DualityRoll extends D20Roll {
!config.source?.actor || !config.source?.actor ||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) || (game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
config.actionType === 'reaction' || config.actionType === 'reaction' ||
config.tagTeamSelected ||
config.skips?.resources config.skips?.resources
) )
return; return;
@ -345,6 +346,7 @@ export default class DualityRoll extends D20Roll {
if ( if (
automationSettings.countdownAutomation && automationSettings.countdownAutomation &&
config.actionType !== 'reaction' && config.actionType !== 'reaction' &&
!config.tagTeamSelected &&
!config.skips?.updateCountdowns !config.skips?.updateCountdowns
) { ) {
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns; const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
@ -372,7 +374,7 @@ export default class DualityRoll extends D20Roll {
} }
} }
static async reroll(rollBase, dieIndex, diceType, updateResources = true) { static async reroll(rollBase, dieIndex, diceType) {
let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollBase, evaluated: false }); let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollBase, evaluated: false });
const term = parsedRoll.terms[dieIndex]; const term = parsedRoll.terms[dieIndex];
await term.reroll(`/r1=${term.total}`); await term.reroll(`/r1=${term.total}`);
@ -419,14 +421,12 @@ export default class DualityRoll extends D20Roll {
source: { actor: parsedRoll.options.source.actor ?? '' }, source: { actor: parsedRoll.options.source.actor ?? '' },
targets: parsedRoll.targets, targets: parsedRoll.targets,
roll: newRoll, roll: newRoll,
rerolledRoll: parsedRoll.options.roll, rerolledRoll: parsedRoll.roll,
resourceUpdates: new ResourceUpdateMap(actor) resourceUpdates: new ResourceUpdateMap(actor)
}; };
if (updateResources) { await DualityRoll.addDualityResourceUpdates(config);
await DualityRoll.addDualityResourceUpdates(config); await config.resourceUpdates.updateResources();
await config.resourceUpdates.updateResources();
}
return { newRoll, parsedRoll }; return { newRoll, parsedRoll };
} }

View file

@ -1,4 +1,5 @@
import { itemAbleRollParse } from '../helpers/utils.mjs'; import { itemAbleRollParse } from '../helpers/utils.mjs';
import { RefreshType } from '../systemRegistration/socket.mjs';
export default class DhActiveEffect extends foundry.documents.ActiveEffect { export default class DhActiveEffect extends foundry.documents.ActiveEffect {
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -107,41 +108,37 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
update.img = 'icons/magic/life/heart-cross-blue.webp'; update.img = 'icons/magic/life/heart-cross-blue.webp';
} }
if (this.actor && data.origin) { const existingEffect = this.actor.effects.find(x => x.origin === data.origin);
const existingEffect = this.actor.effects.find(x => x.origin === data.origin); const stacks = Boolean(data.system?.stacking);
const stacks = Boolean(data.system?.stacking); if (existingEffect && !stacks) return false;
if (existingEffect && !stacks) return false;
if (existingEffect && stacks) { if (existingEffect && stacks) {
const incrementedValue = existingEffect.system.stacking.value + 1; const incrementedValue = existingEffect.system.stacking.value + 1;
await existingEffect.update({ await existingEffect.update({
'system.stacking.value': Math.min(incrementedValue, existingEffect.system.stacking.max ?? Infinity) 'system.stacking.value': Math.min(incrementedValue, existingEffect.system.stacking.max ?? Infinity)
}); });
return false; return false;
}
} }
if (this.parent) { const statuses = Object.keys(data.statuses ?? {});
const statuses = Object.keys(data.statuses ?? {}); const immuneStatuses =
const immuneStatuses = statuses.filter(
statuses.filter( status =>
status => this.parent.system.rules?.conditionImmunities &&
this.parent.system.rules?.conditionImmunities && this.parent.system.rules.conditionImmunities[status]
this.parent.system.rules.conditionImmunities[status] ) ?? [];
) ?? []; if (immuneStatuses.length > 0) {
if (immuneStatuses.length > 0) { update.statuses = statuses.filter(x => !immuneStatuses.includes(x));
update.statuses = statuses.filter(x => !immuneStatuses.includes(x)); const conditions = CONFIG.DH.GENERAL.conditions();
const conditions = CONFIG.DH.GENERAL.conditions(); const scrollingTexts = immuneStatuses.map(status => ({
const scrollingTexts = immuneStatuses.map(status => ({ text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', {
text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', { status: game.i18n.localize(conditions[status].name)
status: game.i18n.localize(conditions[status].name) })
}) }));
})); if (update.statuses.length > 0) {
if (update.statuses.length > 0) { setTimeout(() => scrollingTexts, 500);
setTimeout(() => scrollingTexts, 500); } else {
} else { this.parent.queueScrollText(scrollingTexts);
this.parent.queueScrollText(scrollingTexts);
}
} }
} }
@ -152,6 +149,20 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
await super._preCreate(data, options, user); await super._preCreate(data, options, user);
} }
/** @inheritdoc */
_onCreate(data, options, userId) {
super._onCreate(data, options, userId);
Hooks.callAll(RefreshType.EffectsDisplay);
}
/** @inheritdoc */
_onDelete(data, options, userId) {
super._onDelete(data, options, userId);
Hooks.callAll(RefreshType.EffectsDisplay);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Methods */ /* Methods */
/* -------------------------------------------- */ /* -------------------------------------------- */

View file

@ -31,39 +31,12 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
this.#bordered = true; this.#bordered = true;
let effect = {}; let effect = {};
if (element.dataset.uuid) { if (element.dataset.uuid) {
const effectItem = await foundry.utils.fromUuid(element.dataset.uuid); const effectData = (await foundry.utils.fromUuid(element.dataset.uuid)).toObject();
const effectData = effectItem.toObject();
effect = { effect = {
...effectData, ...effectData,
name: game.i18n.localize(effectData.name) name: game.i18n.localize(effectData.name),
description: game.i18n.localize(effectData.description ?? effectData.parent.system.description)
}; };
if (effectData.type === 'beastform') {
const beastformData = {
features: [],
advantageOn: effectData.system.advantageOn,
beastformAttackData: game.system.api.data.items.DHBeastform.getBeastformAttackData(effectItem)
};
const features = effectItem.parent.items.filter(x => effectItem.system.featureIds.includes(x.id));
for (const feature of features) {
const featureData = feature.toObject();
featureData.enrichedDescription = await feature.system.getEnrichedDescription();
beastformData.features.push(featureData);
}
effect.description = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs',
{
item: { system: beastformData }
}
);
} else {
effect.description = game.i18n.localize(
effectData.description ?? effectData.parent.system.description
);
}
} else { } else {
const conditions = CONFIG.DH.GENERAL.conditions(); const conditions = CONFIG.DH.GENERAL.conditions();
const condition = conditions[element.dataset.condition]; const condition = conditions[element.dataset.condition];

View file

@ -36,7 +36,6 @@ export const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/actionTypes/summon.hbs', 'systems/daggerheart/templates/actionTypes/summon.hbs',
'systems/daggerheart/templates/actionTypes/transform.hbs', 'systems/daggerheart/templates/actionTypes/transform.hbs',
'systems/daggerheart/templates/settings/components/settings-item-line.hbs', 'systems/daggerheart/templates/settings/components/settings-item-line.hbs',
'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs',
'systems/daggerheart/templates/ui/tooltip/parts/tooltipChips.hbs', 'systems/daggerheart/templates/ui/tooltip/parts/tooltipChips.hbs',
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs', 'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs',
'systems/daggerheart/templates/dialogs/downtime/activities.hbs', 'systems/daggerheart/templates/dialogs/downtime/activities.hbs',

View file

@ -5,7 +5,7 @@
"_id": "6rlxhrRwFaVgq9fe", "_id": "6rlxhrRwFaVgq9fe",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"system": { "system": {
"description": "<p><strong>Spend 3 Hope</strong> to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.</p>", "description": "<p><strong>Spend 3 Hope</strong> to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.<br /><br /><strong>Note: Toggle one of the Evolution Traits in the effects tab to raise a trait by 1, e.g. Evolution: Agility</strong></p>",
"resource": null, "resource": null,
"actions": { "actions": {
"bj4m9E8ObFT0xDQ4": { "bj4m9E8ObFT0xDQ4": {
@ -31,13 +31,6 @@
"beastform": { "beastform": {
"tierAccess": { "tierAccess": {
"exact": null "exact": null
},
"modifications": {
"traitBonuses": [
{
"bonus": 1
}
]
} }
}, },
"name": "Beastform", "name": "Beastform",
@ -53,7 +46,266 @@
"artist": "" "artist": ""
} }
}, },
"effects": [], "effects": [
{
"name": "Evolution: Agility",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "vQOqLZAxOltAzsVv",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.agility.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Agility when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.vQOqLZAxOltAzsVv"
},
{
"name": "Evolution: Strength",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "cwEsO1NZpkQHuoTT",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.strength.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Strength when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.cwEsO1NZpkQHuoTT"
},
{
"name": "Evolution: Finesse",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "8P0nwRHNsVnHVPjq",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.finesse.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Finesse when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.8P0nwRHNsVnHVPjq"
},
{
"name": "Evolution: Instinct",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "i2GhNGo5TnGtLuA0",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.instinct.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Instinct when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.i2GhNGo5TnGtLuA0"
},
{
"name": "Evolution: Presence",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "APQF1in1LXjBZh9n",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.presence.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Presence when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.APQF1in1LXjBZh9n"
},
{
"name": "Evolution: Knowledge",
"type": "base",
"system": {
"rangeDependence": {
"enabled": false,
"type": "withinRange",
"target": "hostile",
"range": "melee"
}
},
"_id": "WwOvGJYJb4d37cOy",
"img": "icons/magic/nature/wolf-paw-glow-large-orange.webp",
"changes": [
{
"key": "system.traits.knowledge.value",
"mode": 2,
"value": "1",
"priority": null
}
],
"disabled": true,
"duration": {
"startTime": null,
"combat": null,
"seconds": null,
"rounds": null,
"turns": null,
"startRound": null,
"startTurn": null
},
"description": "<p>Toggle this for +1 to Knowledge when using Evolution. Turn it off when you leave Beastform.</p>",
"origin": null,
"tint": "#ffffff",
"transfer": true,
"statuses": [],
"sort": 0,
"flags": {},
"_stats": {
"compendiumSource": null
},
"_key": "!items.effects!6rlxhrRwFaVgq9fe.WwOvGJYJb4d37cOy"
}
],
"sort": 100000, "sort": 100000,
"ownership": { "ownership": {
"default": 0, "default": 0,

View file

@ -204,44 +204,6 @@
} }
} }
.modifications-container {
display: flex;
flex-direction: column;
gap: 16px;
.trait-bonuses-container {
display: flex;
flex-direction: column;
gap: 8px;
.bonus-separator {
background: light-dark(@dark-blue, @golden);
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
}
.trait-bonus-container {
display: flex;
gap: 4px;
.trait-card {
border: 1px solid light-dark(@dark-blue, @golden);
border-radius: 6px;
padding: 2px;
opacity: 0.4;
flex: 1;
white-space: nowrap;
text-align: center;
&.selected {
opacity: 1;
}
}
}
}
}
footer { footer {
margin-top: 8px; margin-top: 8px;
display: flex; display: flex;

View file

@ -133,18 +133,4 @@
height: 300px; height: 300px;
} }
} }
.deletable-row {
display: flex;
align-items: end;
gap: 8px;
input {
flex: 1;
}
a {
padding-bottom: 7px;
}
}
} }

View file

@ -339,8 +339,7 @@
background: light-dark(@light-black, @dark-blue); background: light-dark(@light-black, @dark-blue);
border: 1px solid light-dark(@dark-blue, @golden); border: 1px solid light-dark(@dark-blue, @golden);
h4, h4, i {
i {
color: light-dark(@dark-blue, @golden); color: light-dark(@dark-blue, @golden);
} }
} }
@ -381,7 +380,7 @@
} }
} }
} }
.slot-label { .slot-label {
display: flex; display: flex;
align-items: center; align-items: center;
color: light-dark(@beige, @dark-blue); color: light-dark(@beige, @dark-blue);
@ -400,9 +399,7 @@
background: light-dark(@light-black, @dark-blue); background: light-dark(@light-black, @dark-blue);
border: 1px solid light-dark(@dark-blue, @golden); border: 1px solid light-dark(@dark-blue, @golden);
.label, .label, .value, i {
.value,
i {
color: light-dark(@dark-blue, @golden); color: light-dark(@dark-blue, @golden);
} }
} }

View file

@ -1,4 +1,3 @@
@import './tooltip/sheet.less';
@import './tooltip/tooltip.less'; @import './tooltip/tooltip.less';
@import './tooltip/armorManagement.less'; @import './tooltip/armorManagement.less';
@import './tooltip/battlepoints.less'; @import './tooltip/battlepoints.less';

View file

@ -18,7 +18,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
text-align: center; text-align: start;
padding: 5px; padding: 5px;
gap: 0px; gap: 0px;

View file

@ -1,129 +0,0 @@
#tooltip:has(div.daggerheart.dh-style.tooltip.card-style),
aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip),
#tooltip.bordered-tooltip {
.tooltip-title {
font-size: var(--font-size-20);
color: light-dark(@dark-blue, @golden);
font-weight: 700;
}
.tooltip-description {
font-style: inherit;
text-align: inherit;
width: 100%;
padding: 5px 10px;
position: relative;
margin-top: 5px;
&::before {
content: '';
background: @golden;
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
}
&::before {
position: absolute;
top: -5px;
}
}
.tooltip-separator {
background: @golden;
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
margin-bottom: 2px;
}
.tooltip-tags {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
padding: 5px 10px;
position: relative;
max-height: 150px;
overflow-y: auto;
position: relative;
scrollbar-width: thin;
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
.tooltip-tag {
display: flex;
gap: 10px;
flex-direction: column;
.tooltip-tag-label-container {
display: flex;
align-items: center;
gap: 5px;
img {
width: 40px;
height: 40px;
border-radius: 3px;
}
}
}
}
.tags {
display: flex;
gap: 5px 10px;
padding-bottom: 16px;
flex-wrap: wrap;
justify-content: center;
&.advantages {
width: 100%;
padding: 5px 10px;
padding-bottom: 16px;
position: relative;
margin-top: 5px;
&::before {
content: '';
background: @golden;
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
}
&::before {
position: absolute;
top: -5px;
}
.tag {
background: @green-10;
color: @green;
border-color: @green;
}
}
.tag {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 3px 5px;
font-size: var(--font-size-12);
font: @font-body;
background: light-dark(@dark-15, @beige-15);
border: 1px solid light-dark(@dark, @beige);
border-radius: 3px;
}
.label {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: var(--font-size-12);
}
}
}

View file

@ -13,6 +13,13 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) {
outline: 1px solid light-dark(@dark-80, @beige-80); outline: 1px solid light-dark(@dark-80, @beige-80);
box-shadow: 0 0 25px rgba(0, 0, 0, 0.8); box-shadow: 0 0 25px rgba(0, 0, 0, 0.8);
.tooltip-title {
font-size: var(--font-size-20);
color: light-dark(@dark-blue, @golden);
font-weight: 700;
margin-bottom: 5px;
}
.tooltip-subtitle { .tooltip-subtitle {
margin: 0; margin: 0;
} }
@ -73,6 +80,110 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) {
} }
} }
.tooltip-tags {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
padding: 5px 10px;
position: relative;
padding-top: 10px;
max-height: 150px;
overflow-y: auto;
position: relative;
scrollbar-width: thin;
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
&::before {
content: '';
background: @golden;
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
}
&::before {
position: absolute;
top: 0px;
}
.tooltip-tag {
display: flex;
gap: 10px;
flex-direction: column;
.tooltip-tag-label-container {
display: flex;
align-items: center;
gap: 5px;
img {
width: 40px;
height: 40px;
border-radius: 3px;
}
}
}
}
.tags {
display: flex;
gap: 5px 10px;
padding-bottom: 16px;
flex-wrap: wrap;
justify-content: center;
&.advantages {
width: 100%;
padding: 5px 10px;
padding-bottom: 16px;
position: relative;
margin-top: 5px;
&::before {
content: '';
background: @golden;
mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%);
height: 2px;
width: calc(100% - 10px);
}
&::before {
position: absolute;
top: -5px;
}
.tag {
background: @green-10;
color: @green;
border-color: @green;
}
}
.tag {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 3px 5px;
font-size: var(--font-size-12);
font: @font-body;
background: light-dark(@dark-15, @beige-15);
border: 1px solid light-dark(@dark, @beige);
border-radius: 3px;
}
.label {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: var(--font-size-12);
}
}
.item-icons-list { .item-icons-list {
position: absolute; position: absolute;
display: flex; display: flex;

View file

@ -5,7 +5,7 @@
"version": "2.0.0", "version": "2.0.0",
"compatibility": { "compatibility": {
"minimum": "14.355", "minimum": "14.355",
"verified": "14.358", "verified": "14.357",
"maximum": "14" "maximum": "14"
}, },
"authors": [ "authors": [

View file

@ -1,16 +1,4 @@
{{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}}
<fieldset> <fieldset>
<legend>{{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.plural"}} <a data-action="addBeastformTraitBonus"><i class="fa-solid fa-plus"></i></a></legend> <legend>{{localize "DAGGERHEART.ACTIONS.Config.beastform.label"}}</legend>
{{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}}
{{#if source.modifications.traitBonuses.length}}
{{#each source.modifications.traitBonuses as |traitBonus index|}}
<div class="deletable-row">
{{formGroup ../fields.modifications.fields.traitBonuses.element.fields.bonus value=traitBonus.bonus name=(concat "beastform.modifications.traitBonuses." index ".bonus") localize=true}}
<a data-action="removeBeastformTraitBonus" data-index="{{index}}"><i class="fa-solid fa-trash"></i></a>
</div>
{{/each}}
{{else}}
<span class="hint">{{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.hint"}}</span>
{{/if}}
</fieldset> </fieldset>

View file

@ -1,28 +0,0 @@
<div class="modifications-container">
{{#if modifications.traitBonuses.length}}
<fieldset>
<legend>
{{#if (gt modifications.traitBonuses.length 1)}}
{{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.plural"}}
{{else}}
{{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.single"}}
{{/if}}
</legend>
<div class="trait-bonuses-container">
{{#each modifications.traitBonuses as |traitBonus index|}}
<div class="trait-bonus-container">
{{#each @root.traits as |trait|}}
<a class="trait-card {{#if (eq trait.id traitBonus.trait)}}selected{{/if}}"
data-action="toggleTraitBonus" data-index="{{index}}" data-trait="{{trait.id}}"
>
{{localize trait.label}} +{{traitBonus.bonus}}
</a>
{{/each}}
</div>
{{#unless @last}}<div class="bonus-separator"></div>{{/unless}}
{{/each}}
</div>
</fieldset>
{{/if}}
</div>

View file

@ -3,7 +3,37 @@
<h2 class="tooltip-title">{{item.name}}</h2> <h2 class="tooltip-title">{{item.name}}</h2>
<p class="tooltip-subtitle"><i>{{item.system.examples}}</i></p> <p class="tooltip-subtitle"><i>{{item.system.examples}}</i></p>
{{> "systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs" }} {{#if description}}
<div class="tooltip-description">{{{description}}}</div>
{{/if}}
<div class="tags">
{{#with item.system.beastformAttackData}}
<div class="tag">
<span>{{localize "DAGGERHEART.ITEMS.Beastform.mainTrait"}} {{this.trait}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.ITEMS.Beastform.traitBonus"}} {{this.traitBonus}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.GENERAL.evasion"}} {{this.evasionBonus}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.GENERAL.damage"}} {{concat this.damageDice ' ' this.damageBonus}} <i class="fa-solid fa-hand-fist"></i></span>
</div>
{{/with}}
</div>
<h2 class="tooltip-title">{{localize "DAGGERHEART.ITEMS.Beastform.FIELDS.advantageOn.label"}}</h2>
<div class="tags advantages">
{{#each item.system.advantageOn as | chip |}}
<div class="tag">
<span>{{ifThen chip.value chip.value chip}}</span>
</div>
{{/each}}
</div>
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.features label=(localize "DAGGERHEART.GENERAL.features")}}
<p class="tooltip-hint"> <p class="tooltip-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.Tooltip.middleClick"}} <i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.Tooltip.middleClick"}}

View file

@ -41,32 +41,26 @@
</div> </div>
{{/if}} {{/if}}
{{#unless effect.isLockedCondition}}
<div class="close-hints"> <div class="close-hints">
{{#if (eq effect.type 'beastform')}} {{#if effect.system.stacking}}
<p class="close-hint"> <p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.Tooltip.middleClick"}} <i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.increaseStacks"}}
</p> </p>
{{/if}} {{#if (gt effect.system.stacking.value 1)}}
{{#unless effect.isLockedCondition}}
{{#if effect.system.stacking}}
<p class="close-hint"> <p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.increaseStacks"}} <i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.decreaseStacks"}}
</p> </p>
{{#if (gt effect.system.stacking.value 1)}}
<p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.decreaseStacks"}}
</p>
{{else}}
<p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}}
</p>
{{/if}}
{{else}} {{else}}
<p class="close-hint"> <p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} <i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}}
</p> </p>
{{/if}} {{/if}}
{{/unless}} {{else}}
<p class="close-hint">
<i class="fa-solid fa-computer-mouse"></i> {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}}
</p>
{{/if}}
</div> </div>
{{/unless}}
</div> </div>

View file

@ -1,31 +0,0 @@
{{#if description}}
<div class="tooltip-description">{{{description}}}</div>
{{/if}}
<div class="tags">
{{#with item.system.beastformAttackData}}
<div class="tag">
<span>{{localize "DAGGERHEART.ITEMS.Beastform.mainTrait"}} {{this.trait}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.ITEMS.Beastform.traitBonus"}} {{this.traitBonus}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.GENERAL.evasion"}} {{this.evasionBonus}}</span>
</div>
<div class="tag">
<span>{{localize "DAGGERHEART.GENERAL.damage"}} {{concat this.damageDice ' ' this.damageBonus}} <i class="fa-solid fa-hand-fist"></i></span>
</div>
{{/with}}
</div>
<h2 class="tooltip-title">{{localize "DAGGERHEART.ITEMS.Beastform.FIELDS.advantageOn.label"}}</h2>
<div class="tags advantages">
{{#each item.system.advantageOn as | chip |}}
<div class="tag">
<span>{{ifThen chip.value chip.value chip}}</span>
</div>
{{/each}}
</div>
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.features label=(localize "DAGGERHEART.GENERAL.features")}}

View file

@ -1,5 +1,4 @@
{{#if (gt features.length 0)}}<h2 class="tooltip-title">{{label}}</h2>{{/if}} {{#if (gt features.length 0)}}<h2 class="tooltip-title">{{label}}</h2>{{/if}}
<div class="tooltip-separator"></div>
<div class="tooltip-tags"> <div class="tooltip-tags">
{{#each features as | feature |}} {{#each features as | feature |}}
{{#with (ifThen ../isAction feature (ifThen feature.item feature.item feature))}} {{#with (ifThen ../isAction feature (ifThen feature.item feature.item feature))}}