Simplify effect click event (#1748)

* Fixed a bunch of deprecations

* Corrected AgileScout Beastform json data

* Updated TokenHUD to the new v14

* Removed DestroyOnEmpty from consumables

* Fixed so that tooltips don't get stuck (#1745)

* [Feature] TagTeam Partial Rendering (#1735)

* I done did it, I think

* Think I fixed the partial rendering bug for gm->player

* [V14] 1743 - Damage Update Error (#1746)

* Fixed DamageParts causing errors on update

* Fixed ActionBaseConfig error when no damage present on the action

* Fix removal of damage field

* Removed unneccessary default value function for parts

---------

Co-authored-by: Carlos Fernandez <cfern1990@gmail.com>

* Simplify effect click event

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>
Co-authored-by: WBHarry <89362246+WBHarry@users.noreply.github.com>
This commit is contained in:
Carlos Fernandez 2026-03-25 05:57:43 -04:00 committed by GitHub
parent b2a900db16
commit 4652ccefbc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
85 changed files with 633 additions and 641 deletions

View file

@ -2522,8 +2522,7 @@
"featuresLabel": "Community Feature" "featuresLabel": "Community Feature"
}, },
"Consumable": { "Consumable": {
"consumeOnUse": "Consume On Use", "consumeOnUse": "Consume On Use"
"destroyOnEmpty": "Destroy On Empty"
}, },
"DomainCard": { "DomainCard": {
"type": "Type", "type": "Type",

View file

@ -70,8 +70,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
context.rollConfig = this.config; context.rollConfig = this.config;
context.hasRoll = !!this.config.roll; context.hasRoll = !!this.config.roll;
context.canRoll = true; context.canRoll = true;
context.selectedRollMode = this.config.selectedRollMode ?? game.settings.get('core', 'rollMode'); context.selectedMessageMode = this.config.selectedMessageMode ?? game.settings.get('core', 'messageMode');
context.rollModes = Object.entries(CONFIG.Dice.rollModes).map(([action, { label, icon }]) => ({ context.rollModes = Object.entries(CONFIG.ChatMessage.modes).map(([action, { label, icon }]) => ({
action, action,
label, label,
icon icon
@ -142,10 +142,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
})); }));
} }
static updateRollConfiguration(event, _, formData) { static updateRollConfiguration(_event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object); const { ...rest } = foundry.utils.expandObject(formData.object);
this.config.selectedRollMode = rest.selectedRollMode; this.config.selectedMessageMode = rest.selectedMessageMode;
if (this.config.costs) { if (this.config.costs) {
this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs);

View file

@ -52,8 +52,8 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
context.formula = this.roll.constructFormula(this.config); context.formula = this.roll.constructFormula(this.config);
context.hasHealing = this.config.hasHealing; context.hasHealing = this.config.hasHealing;
context.directDamage = this.config.directDamage; context.directDamage = this.config.directDamage;
context.selectedRollMode = this.config.selectedRollMode; context.selectedMessageMode = this.config.selectedMessageMode;
context.rollModes = Object.entries(CONFIG.Dice.rollModes).map(([action, { label, icon }]) => ({ context.rollModes = Object.entries(CONFIG.ChatMessage.modes).map(([action, { label, icon }]) => ({
action, action,
label, label,
icon icon
@ -69,7 +69,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
const { ...rest } = foundry.utils.expandObject(formData.object); const { ...rest } = foundry.utils.expandObject(formData.object);
foundry.utils.mergeObject(this.config.roll, rest.roll); foundry.utils.mergeObject(this.config.roll, rest.roll);
foundry.utils.mergeObject(this.config.modifiers, rest.modifiers); foundry.utils.mergeObject(this.config.modifiers, rest.modifiers);
this.config.selectedRollMode = rest.selectedRollMode; this.config.selectedMessageMode = rest.selectedMessageMode;
this.render(); this.render();
} }

View file

@ -58,6 +58,10 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
id: 'initialization', id: 'initialization',
template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/initialization.hbs' template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/initialization.hbs'
}, },
rollSelection: {
id: 'rollSelection',
template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/rollSelection.hbs'
},
tagTeamRoll: { tagTeamRoll: {
id: 'tagTeamRoll', id: 'tagTeamRoll',
template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs' template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs'
@ -78,15 +82,52 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
element.addEventListener('change', this.updateRollType.bind(this)); element.addEventListener('change', this.updateRollType.bind(this));
} }
_configureRenderParts(options) {
const { initialization, rollSelection, tagTeamRoll } = super._configureRenderParts(options);
const augmentedParts = { initialization };
for (const memberKey of Object.keys(this.party.system.tagTeam.members)) {
augmentedParts[memberKey] = {
id: memberKey,
template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamMember.hbs'
};
}
augmentedParts.rollSelection = rollSelection;
augmentedParts.tagTeamRoll = tagTeamRoll;
return augmentedParts;
}
/**@inheritdoc */
async _onRender(context, options) {
await super._onRender(context, options);
if (this.element.querySelector('.team-container')) return;
const initializationPart = this.element.querySelector('.initialization-container');
initializationPart.insertAdjacentHTML('afterend', '<div class="team-container"></div>');
const teamContainer = this.element.querySelector('.team-container');
for (const memberContainer of this.element.querySelectorAll('.team-member-container'))
teamContainer.appendChild(memberContainer);
}
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.isEditable = this.getIsEditable(); context.isEditable = this.getIsEditable();
context.fields = this.party.system.schema.fields.tagTeam.fields;
context.data = this.party.system.tagTeam;
context.rollTypes = CONFIG.DH.GENERAL.tagTeamRollTypes;
context.traitOptions = CONFIG.DH.ACTOR.abilities;
context.members = {};
context.allHaveRolled = Object.keys(this.party.system.tagTeam.members).every(key => {
const data = this.party.system.tagTeam.members[key];
return Boolean(data.rollData);
});
return context; return context;
} }
async _preparePartContext(partId, context, options) { async _preparePartContext(partId, context, options) {
const partContext = await super._preparePartContext(partId, context, options); const partContext = await super._preparePartContext(partId, context, options);
partContext.partId = partId;
switch (partId) { switch (partId) {
case 'initialization': case 'initialization':
partContext.tagTeamFields = this.party.system.schema.fields.tagTeam.fields; partContext.tagTeamFields = this.party.system.schema.fields.tagTeam.fields;
@ -100,31 +141,38 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
partContext.initiatorDisabled = !selectedMembers.length; partContext.initiatorDisabled = !selectedMembers.length;
partContext.openForAllPlayers = this.openForAllPlayers; partContext.openForAllPlayers = this.openForAllPlayers;
break;
case 'rollSelection':
partContext.members = Object.keys(this.party.system.tagTeam.members).reduce((acc, key) => {
const member = this.party.system.tagTeam.members[key];
acc[key] = { selected: member.selected };
return acc;
}, {});
break; break;
case 'tagTeamRoll': case 'tagTeamRoll':
partContext.fields = this.party.system.schema.fields.tagTeam.fields;
partContext.data = this.party.system.tagTeam;
partContext.rollTypes = CONFIG.DH.GENERAL.tagTeamRollTypes;
partContext.traitOptions = CONFIG.DH.ACTOR.abilities;
const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected); const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected);
const critSelected = !selectedRoll const critSelected = !selectedRoll
? undefined ? undefined
: (selectedRoll?.rollData?.options?.roll?.isCritical ?? false); : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false);
partContext.members = {}; partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members);
for (const actorId in this.party.system.tagTeam.members) { partContext.joinedRoll = await this.getJoinedRoll({
const data = this.party.system.tagTeam.members[actorId]; overrideIsCritical: critSelected,
const actor = game.actors.get(actorId); displayVersion: true
});
break;
}
if (Object.keys(this.party.system.tagTeam.members).includes(partId)) {
const data = this.party.system.tagTeam.members[partId];
const actor = game.actors.get(partId);
const rollOptions = []; const rollOptions = [];
const damageRollOptions = []; const damageRollOptions = [];
for (const item of actor.items) { for (const item of actor.items) {
if (item.system.metadata.hasActions) { if (item.system.metadata.hasActions) {
const actions = [ const actions = [...item.system.actions, ...(item.system.attack ? [item.system.attack] : [])];
...item.system.actions,
...(item.system.attack ? [item.system.attack] : [])
];
for (const action of actions) { for (const action of actions) {
if (action.hasRoll) { if (action.hasRoll) {
const actionItem = { const actionItem = {
@ -141,52 +189,60 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
} }
} }
const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected);
const critSelected = !selectedRoll
? undefined
: (selectedRoll?.rollData?.options?.roll?.isCritical ?? false);
const damage = data.rollData?.options?.damage; const damage = data.rollData?.options?.damage;
partContext.hasDamage |= Boolean(damage); partContext.hasDamage |= Boolean(damage);
const critHitPointsDamage = await this.getCriticalDamage(damage); const critHitPointsDamage = await this.getCriticalDamage(damage);
partContext.members[actorId] = { partContext.members[partId] = {
...data, ...data,
isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER), isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER),
key: actorId, key: partId,
readyToRoll: Boolean(data.rollChoice), readyToRoll: Boolean(data.rollChoice),
hasRolled: Boolean(data.rollData), hasRolled: Boolean(data.rollData),
rollOptions, rollOptions,
damageRollOptions, damageRollOptions,
damage: damage, damage: damage,
critDamage: critHitPointsDamage, critDamage: critHitPointsDamage,
useCritDamage: useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
}; };
} }
partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members);
partContext.joinedRoll = await this.getJoinedRoll({
overrideIsCritical: critSelected,
displayVersion: true
});
break;
}
return partContext; return partContext;
} }
static async updateData(_event, _, formData) { getUpdatingParts(target) {
const { initialization, rollSelection, tagTeamRoll } = this.constructor.PARTS;
const isInitialization = this.tabGroups.application === initialization.id;
const updatingMember = target.closest('.team-member-container')?.dataset?.memberKey;
return [
...(isInitialization ? [initialization.id] : []),
...(updatingMember ? [updatingMember] : []),
...(!isInitialization ? [rollSelection.id] : []),
...(!isInitialization ? [tagTeamRoll.id] : [])
];
}
static async updateData(event, _, formData) {
const { initiator, openForAllPlayers, ...partyData } = foundry.utils.expandObject(formData.object); const { initiator, openForAllPlayers, ...partyData } = foundry.utils.expandObject(formData.object);
this.initiator = initiator; this.initiator = initiator;
this.openForAllPlayers = openForAllPlayers !== undefined ? openForAllPlayers : this.openForAllPlayers; this.openForAllPlayers = openForAllPlayers !== undefined ? openForAllPlayers : this.openForAllPlayers;
this.updatePartyData(partyData); this.updatePartyData(partyData, this.getUpdatingParts(event.target));
} }
async updatePartyData(update, options = { render: true }) { async updatePartyData(update, updatingParts, options = { render: true }) {
const gmUpdate = async update => { const gmUpdate = async update => {
await this.party.update(update); await this.party.update(update);
this.render(); this.render({ parts: updatingParts });
game.socket.emit(`system.${CONFIG.DH.id}`, { game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh, action: socketEvent.Refresh,
data: { refreshType: RefreshType.TagTeamRoll, action: 'refresh' } data: { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts }
}); });
}; };
@ -195,7 +251,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
gmUpdate, gmUpdate,
update, update,
this.party.uuid, this.party.uuid,
options.render ? { refreshType: RefreshType.TagTeamRoll, action: 'refresh' } : undefined options.render
? { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts }
: undefined
); );
} }
@ -206,7 +264,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
}); });
} }
tagTeamRefresh = ({ refreshType, action }) => { tagTeamRefresh = ({ refreshType, action, parts }) => {
if (refreshType !== RefreshType.TagTeamRoll) return; if (refreshType !== RefreshType.TagTeamRoll) return;
switch (action) { switch (action) {
@ -214,7 +272,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
this.tabGroups.application = 'tagTeamRoll'; this.tabGroups.application = 'tagTeamRoll';
break; break;
case 'refresh': case 'refresh':
this.render(); this.render({ parts });
break; break;
case 'close': case 'close':
this.close(); this.close();
@ -304,22 +362,28 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
} }
async updateRollType(event) { async updateRollType(event) {
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${event.target.dataset.member}`]: { [`system.tagTeam.members.${event.target.dataset.member}`]: {
rollType: event.target.value, rollType: event.target.value,
rollChoice: null rollChoice: null
} }
}); },
this.getUpdatingParts(event.target)
);
} }
static async #removeRoll(_, button) { static async #removeRoll(_, button) {
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${button.dataset.member}`]: { [`system.tagTeam.members.${button.dataset.member}`]: {
rollData: null, rollData: null,
rollChoice: null, rollChoice: null,
selected: false selected: false
} }
}); },
this.getUpdatingParts(button)
);
} }
static async #makeRoll(event, button) { static async #makeRoll(event, button) {
@ -342,9 +406,12 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
const rollData = result.messageRoll.toJSON(); const rollData = result.messageRoll.toJSON();
delete rollData.options.messageRoll; delete rollData.options.messageRoll;
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${member}.rollData`]: rollData [`system.tagTeam.members.${member}.rollData`]: rollData
}); },
this.getUpdatingParts(button)
);
} }
async makeTraitRoll(memberKey) { async makeTraitRoll(memberKey) {
@ -389,7 +456,8 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
diceType diceType
); );
const rollData = parsedRoll.toJSON(); const rollData = parsedRoll.toJSON();
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${member}.rollData`]: { [`system.tagTeam.members.${member}.rollData`]: {
...rollData, ...rollData,
options: { options: {
@ -397,7 +465,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
roll: newRoll roll: newRoll
} }
} }
}); },
this.getUpdatingParts(button)
);
} }
static async #makeDamageRoll(event, button) { static async #makeDamageRoll(event, button) {
@ -423,7 +493,8 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
if (!config.damage) return; if (!config.damage) return;
const current = this.party.system.tagTeam.members[memberKey].rollData; const current = this.party.system.tagTeam.members[memberKey].rollData;
await this.updatePartyData({ await this.updatePartyData(
{
[`system.tagTeam.members.${memberKey}.rollData`]: { [`system.tagTeam.members.${memberKey}.rollData`]: {
...current, ...current,
options: { options: {
@ -431,13 +502,16 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
damage: config.damage damage: config.damage
} }
} }
}); },
this.getUpdatingParts(button)
);
} }
static async #removeDamageRoll(_, button) { static async #removeDamageRoll(_, button) {
const { memberKey } = button.dataset; const { memberKey } = button.dataset;
const current = this.party.system.tagTeam.members[memberKey].rollData; const current = this.party.system.tagTeam.members[memberKey].rollData;
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${memberKey}.rollData`]: { [`system.tagTeam.members.${memberKey}.rollData`]: {
...current, ...current,
options: { options: {
@ -445,7 +519,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
damage: null damage: null
} }
} }
}); },
this.getUpdatingParts(button)
);
} }
static async #rerollDamageDice(_, button) { static async #rerollDamageDice(_, button) {
@ -476,9 +552,12 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
return acc; return acc;
}, 0); }, 0);
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members.${memberKey}.rollData`]: rollData [`system.tagTeam.members.${memberKey}.rollData`]: rollData
}); },
this.getUpdatingParts(button)
);
} }
async getCriticalDamage(damage) { async getCriticalDamage(damage) {
@ -529,7 +608,8 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
static async #selectRoll(_, button) { static async #selectRoll(_, button) {
const { memberKey } = button.dataset; const { memberKey } = button.dataset;
this.updatePartyData({ this.updatePartyData(
{
[`system.tagTeam.members`]: Object.entries(this.party.system.tagTeam.members).reduce( [`system.tagTeam.members`]: Object.entries(this.party.system.tagTeam.members).reduce(
(acc, [key, member]) => { (acc, [key, member]) => {
acc[key] = { selected: key === memberKey ? !member.selected : false }; acc[key] = { selected: key === memberKey ? !member.selected : false };
@ -537,7 +617,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
}, },
{} {}
) )
}); },
this.getUpdatingParts(button)
);
} }
async getJoinedRoll({ overrideIsCritical, displayVersion } = {}) { async getJoinedRoll({ overrideIsCritical, displayVersion } = {}) {
@ -602,6 +684,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
members: _replace({}) members: _replace({})
} }
}, },
[],
{ render: false } { render: false }
); );

View file

@ -154,8 +154,13 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
context.openSection = this.openSection; context.openSection = this.openSection;
context.tabs = this._getTabs(this.constructor.TABS); context.tabs = this._getTabs(this.constructor.TABS);
context.config = CONFIG.DH; context.config = CONFIG.DH;
if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') if (this.action.hasDamage) {
context.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length;
if (this.action.damage.hasOwnProperty('includeBase') && this.action.type === 'attack')
context.hasBaseDamage = !!this.action.parent.attack; context.hasBaseDamage = !!this.action.parent.attack;
}
context.costOptions = this.getCostOptions(); context.costOptions = this.getCostOptions();
context.getRollTypeOptions = this.getRollTypeOptions(); context.getRollTypeOptions = this.getRollTypeOptions();
context.disableOption = this.disableOption.bind(this); context.disableOption = this.disableOption.bind(this);
@ -173,7 +178,6 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
revealed: this.openTrigger === index revealed: this.openTrigger === index
}; };
}); });
context.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length;
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers; const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
context.tierOptions = [ context.tierOptions = [
@ -312,8 +316,8 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
const callback = (_, button) => { const callback = (_, button) => {
const data = this.action.toObject(); const data = this.action.toObject();
const type = choices[button.form.elements.type.value].value; const type = choices[button.form.elements.type.value].value;
const part = { applyTo: type }; const part = this.action.schema.fields.damage.fields.parts.element.getInitialValue();
if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' }; part.applyTo = type;
data.damage.parts[type] = part; data.damage.parts[type] = part;
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
}; };

View file

@ -49,12 +49,9 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica
_attachPartListeners(partId, htmlElement, options) { _attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options); super._attachPartListeners(partId, htmlElement, options);
for (const element of this.element?.querySelectorAll('.effect-container a') ?? []) {
if (this.element) { element.addEventListener('click', e => this.#onClickEffect(e));
this.element.querySelectorAll('.effect-container a').forEach(element => { element.addEventListener('contextmenu', e => this.#onClickEffect(e, -1));
element.addEventListener('click', this.effectLeftclick.bind(this));
element.addEventListener('contextmenu', this.effectRightclick.bind(this));
});
} }
} }
@ -88,31 +85,21 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica
this.render(); this.render();
} }
async effectLeftclick(event) { async #onClickEffect(event, delta = 1) {
const element = event.target.closest('.effect-container'); const element = event.target.closest('.effect-container');
const effects = DhEffectsDisplay.getTokenEffects(); const effects = DhEffectsDisplay.getTokenEffects();
const effect = effects.find(x => x.id === element.dataset.effectId); const effect = effects.find(x => x.id === element.dataset.effectId);
if (!effect || (delta >= 0 && !effect.system.stacking?.enabled)) {
if (!effect.system.stacking?.enabled) return; return;
const incrementedValue = effect.system.stacking.value + 1;
const newValue = effect.system.stacking.max
? Math.min(incrementedValue, effect.system.stacking.max)
: incrementedValue;
await effect.update({ 'system.stacking.value': newValue });
this.render();
} }
async effectRightclick(event) { const maxValue = effect.system.stacking.max ?? Infinity;
const element = event.target.closest('.effect-container'); const newValue = Math.clamp((effect.system.stacking.value ?? 1) + delta, 0, maxValue);
const effects = DhEffectsDisplay.getTokenEffects(); if (newValue > 0) {
const effect = effects.find(x => x.id === element.dataset.effectId); await effect.update({ 'system.stacking.value': newValue });
if (effect.system.stacking?.enabled && effect.system.stacking.value > 1) {
await effect.update({ 'system.stacking.value': effect.system.stacking.value - 1 });
} else { } else {
await effect.delete(); await effect.delete();
} }
this.render(); this.render();
} }

View file

@ -264,12 +264,20 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
hasSave: this.hasSave, hasSave: this.hasSave,
onSave: this.save?.damageMod, onSave: this.save?.damageMod,
isDirect: !!this.damage?.direct, isDirect: !!this.damage?.direct,
selectedRollMode: game.settings.get('core', 'rollMode'), selectedMessageMode: game.settings.get('core', 'messageMode'),
data: this.getRollData(), data: this.getRollData(),
evaluate: this.hasRoll, evaluate: this.hasRoll,
resourceUpdates: new ResourceUpdateMap(this.actor), resourceUpdates: new ResourceUpdateMap(this.actor),
targetUuid: this.targetUuid, targetUuid: this.targetUuid,
...configOptions ...configOptions,
skips: {
resources: false,
triggers: false,
createMessage: false,
updateCountdowns: false,
reaction: false,
...(configOptions.skips ?? {})
}
}; };
DHBaseAction.applyKeybindings(config); DHBaseAction.applyKeybindings(config);
@ -329,6 +337,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
* @param {boolean} successCost * @param {boolean} successCost
*/ */
async consume(config, successCost = false) { async consume(config, successCost = false) {
config.resourceUpdates = new ResourceUpdateMap(config.actionActor);
await this.workflow.get('cost')?.execute(config, successCost); await this.workflow.get('cost')?.execute(config, successCost);
await this.workflow.get('uses')?.execute(config, successCost); await this.workflow.get('uses')?.execute(config, successCost);

View file

@ -89,6 +89,7 @@ export class ActionField extends foundry.data.fields.ObjectField {
/** @override */ /** @override */
_cleanType(value, options, _state) { _cleanType(value, options, _state) {
if (!(typeof value === 'object')) value = {}; if (!(typeof value === 'object')) value = {};
value = super._cleanType(value, options, _state);
const cls = this.getModel(value); const cls = this.getModel(value);
if (cls) return cls.cleanData(value, options, _state); if (cls) return cls.cleanData(value, options, _state);
return value; return value;
@ -309,7 +310,7 @@ export function ActionMixin(Base) {
} }
}; };
ChatMessage.applyRollMode(msg, game.settings.get('core', 'rollMode')); ChatMessage.applyMode(msg, game.settings.get('core', 'messageMode'));
cls.create(msg); cls.create(msg);
} }
} }

View file

@ -18,8 +18,7 @@ export default class DHConsumable extends BaseDataItem {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
...super.defineSchema(), ...super.defineSchema(),
consumeOnUse: new fields.BooleanField({ initial: true }), consumeOnUse: new fields.BooleanField({ initial: true })
destroyOnEmpty: new fields.BooleanField({ initial: true })
}; };
} }

View file

@ -33,7 +33,7 @@ export default class DamageRoll extends DHRoll {
static async buildPost(roll, config, message) { static async buildPost(roll, config, message) {
const chatMessage = config.source?.message const chatMessage = config.source?.message
? ui.chat.collection.get(config.source.message) ? ui.chat.collection.get(config.source.message)
: getDocumentClass('ChatMessage').applyRollMode({}, config.rollMode ?? CONST.DICE_ROLL_MODES.PUBLIC); : getDocumentClass('ChatMessage').applyMode({}, config.rollMode ?? 'public');
if (game.modules.get('dice-so-nice')?.active) { if (game.modules.get('dice-so-nice')?.active) {
const pool = foundry.dice.terms.PoolTerm.fromRolls( const pool = foundry.dice.terms.PoolTerm.fromRolls(
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll)) Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))

View file

@ -117,10 +117,10 @@ export default class DHRoll extends Roll {
rolls: [roll] rolls: [roll]
}; };
config.selectedRollMode ??= game.settings.get('core', 'rollMode'); config.selectedMessageMode ??= game.settings.get('core', 'messageMode');
if (roll._evaluated) { if (roll._evaluated) {
const message = await cls.create(msgData, { rollMode: config.selectedRollMode }); const message = await cls.create(msgData, { messageMode: config.selectedMessageMode });
if (config.tagTeamSelected) { if (config.tagTeamSelected) {
game.system.api.applications.dialogs.TagTeamDialog.assignRoll(message.speakerActor, message); game.system.api.applications.dialogs.TagTeamDialog.assignRoll(message.speakerActor, message);

View file

@ -771,20 +771,10 @@ export default class DhpActor extends Actor {
resources.forEach(r => { resources.forEach(r => {
if (r.itemId) { if (r.itemId) {
const { path, value } = game.system.api.fields.ActionFields.CostField.getItemIdCostUpdate(r); const { path, value } = game.system.api.fields.ActionFields.CostField.getItemIdCostUpdate(r);
if (
r.key === 'quantity' &&
r.target.type === 'consumable' &&
value === 0 &&
r.target.system.destroyOnEmpty
) {
r.target.delete();
} else {
updates.items[r.key] = { updates.items[r.key] = {
target: r.target, target: r.target,
resources: { [path]: value } resources: { [path]: value }
}; };
}
} else { } else {
const valueFunc = (base, resource, baseMax) => { const valueFunc = (base, resource, baseMax) => {
if (resource.clear) return baseMax && base.inverted ? baseMax : 0; if (resource.clear) return baseMax && base.inverted ? baseMax : 0;

View file

@ -76,7 +76,7 @@ export default class DhRollTable extends foundry.documents.RollTable {
} }
async toMessage(results, { roll, messageData = {}, messageOptions = {} } = {}) { async toMessage(results, { roll, messageData = {}, messageOptions = {} } = {}) {
messageOptions.rollMode ??= game.settings.get('core', 'rollMode'); messageOptions.rollMode ??= game.settings.get('core', 'messageMode');
// Construct chat data // Construct chat data
messageData = foundry.utils.mergeObject( messageData = foundry.utils.mergeObject(

View file

@ -169,70 +169,19 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
} }
} }
this.baseActivate(element, { ...options, html: html }); this.noOffset = options.noOffset;
super.activate(element, { ...options, html: html });
} }
/* Need to pass more options to _setAnchor, so have to copy whole foundry method >_< */ _setAnchor(direction) {
async baseActivate(element, options) {
let { text, direction, cssClass, locked = false, html, content } = options;
if (content && !html) {
foundry.utils.logCompatibilityWarning(
'The content option has been deprecated in favor of the html option',
{ since: 13, until: 15, once: true }
);
html = content;
}
if (text && html) throw new Error('Cannot provide both text and html options to TooltipManager#activate.');
// Deactivate currently active element
this.deactivate();
// Check if the element still exists in the DOM.
if (!document.body.contains(element)) return;
// Mark the new element as active
this.#active = true;
this.element = element;
element.setAttribute('aria-describedby', 'tooltip');
html ||= element.dataset.tooltipHtml;
if (html) {
if (typeof html === 'string') this.tooltip.innerHTML = foundry.utils.cleanHTML(html);
else {
this.tooltip.innerHTML = ''; // Clear existing HTML
this.tooltip.appendChild(html);
}
} else {
text ||= element.dataset.tooltipText;
if (text) this.tooltip.textContent = text;
else {
text = element.dataset.tooltip;
// Localized message should be safe
if (game.i18n.has(text)) this.tooltip.innerHTML = game.i18n.localize(text);
else this.tooltip.innerHTML = foundry.utils.cleanHTML(text);
}
}
// Activate display of the tooltip
this.tooltip.removeAttribute('class');
this.tooltip.classList.add('active', 'themed', 'theme-dark');
this.tooltip.showPopover();
cssClass ??= element.closest('[data-tooltip-class]')?.dataset.tooltipClass;
if (cssClass) this.tooltip.classList.add(...cssClass.split(' '));
// Set tooltip position
direction ??= element.closest('[data-tooltip-direction]')?.dataset.tooltipDirection;
if (!direction) direction = this._determineDirection();
this._setAnchor(direction, options);
if (locked || element.dataset.hasOwnProperty('locked')) this.lockTooltip();
}
_setAnchor(direction, options = {}) {
const directions = this.constructor.TOOLTIP_DIRECTIONS; const directions = this.constructor.TOOLTIP_DIRECTIONS;
const pad = this.constructor.TOOLTIP_MARGIN_PX; const pad = this.constructor.TOOLTIP_MARGIN_PX;
const pos = this.element.getBoundingClientRect(); const pos = this.element.getBoundingClientRect();
const { innerHeight, innerWidth } = this.tooltip.ownerDocument.defaultView; const { innerHeight, innerWidth } = this.tooltip.ownerDocument.defaultView;
const tooltipPadding = 16; const tooltipPadding = 16;
const horizontalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetWidth / 2 - pos.width / 2; const horizontalOffset = this.noOffset ? tooltipPadding : this.tooltip.offsetWidth / 2 - pos.width / 2;
const verticalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetHeight / 2 - pos.height / 2; const verticalOffset = this.noOffset ? tooltipPadding : this.tooltip.offsetHeight / 2 - pos.height / 2;
const style = {}; const style = {};
switch (direction) { switch (direction) {

View file

@ -29,8 +29,7 @@
"Compendium.daggerheart.beastforms.Item.QFg1hNCEoKVDd9Zo" "Compendium.daggerheart.beastforms.Item.QFg1hNCEoKVDd9Zo"
], ],
"evolved": { "evolved": {
"mainTraitBonus": 0, "mainTraitBonus": 0
"maximumTier": 1
}, },
"hybrid": { "hybrid": {
"beastformOptions": 2, "beastformOptions": 2,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -48,7 +48,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -89,7 +89,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -71,7 +71,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -134,7 +134,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -91,7 +91,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -71,7 +71,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -89,7 +89,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -85,7 +85,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -85,7 +85,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -84,7 +84,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -71,7 +71,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -64,7 +64,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -159,7 +159,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 62, "page": 62,

View file

@ -91,7 +91,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -85,7 +85,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -40,7 +40,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 60, "page": 60,

View file

@ -45,7 +45,6 @@
} }
}, },
"consumeOnUse": true, "consumeOnUse": true,
"destroyOnEmpty": true,
"attribution": { "attribution": {
"source": "Daggerheart SRD", "source": "Daggerheart SRD",
"page": 61, "page": 61,

View file

@ -1,25 +1,20 @@
.daggerheart.dialog.dh-style.views.tag-team-dialog { .daggerheart.dialog.dh-style.views.tag-team-dialog {
.tag-team-roll-container {
display: flex;
flex-direction: column;
gap: 16px;
&.inactive {
opacity: 0.4;
pointer-events: none;
}
.team-container { .team-container {
display: flex; display: flex;
gap: 16px; gap: 16px;
margin-bottom: 16px;
.member-container { .team-member-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
gap: 8px; gap: 8px;
flex: 1; flex: 1;
&.select-padding {
padding-bottom: 64px;
}
&.inactive { &.inactive {
opacity: 0.4; opacity: 0.4;
pointer-events: none; pointer-events: none;
@ -180,9 +175,25 @@
padding: 3px; padding: 3px;
} }
} }
}
}
.roll-selection {
position: relative;
top: -80px;
&.rendered {
margin-bottom: -56px;
}
.roll-selection-container {
display: flex;
.select-roll-button { .select-roll-button {
margin-top: 8px; margin-top: 8px;
flex: 1;
display: flex;
justify-content: center;
i { i {
color: light-dark(@dark-blue, @golden); color: light-dark(@dark-blue, @golden);
@ -196,6 +207,16 @@
} }
} }
.tag-team-roll-container {
display: flex;
flex-direction: column;
gap: 16px;
&.inactive {
opacity: 0.4;
pointer-events: none;
}
.results-container { .results-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -243,9 +264,9 @@
grid-column: span 2; grid-column: span 2;
} }
} }
}
.hint { .hint {
text-align: center; text-align: center;
} }
}
} }

View file

@ -16,50 +16,52 @@
{{formField directField value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}} {{formField directField value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}}
{{/unless}} {{/unless}}
</div> </div>
{{#each source.parts as |dmg key|}}
{{!-- Handlebars uses Symbol.Iterator to produce index|key. This isn't compatible with our parts object, so we instead use applyTo, which is the same value --}}
{{#each source.parts as |dmg|}}
<div class="nest-inputs"> <div class="nest-inputs">
<fieldset{{#if dmg.base}} disabled{{/if}} class="one-column{{#if ../path}} no-style{{/if}}"> <fieldset{{#if dmg.base}} disabled{{/if}} class="one-column{{#if ../path}} no-style{{/if}}">
<legend class="with-icon"> <legend class="with-icon">
{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}} {{localize (concat "DAGGERHEART.CONFIG.HealingType." dmg.applyTo ".name")}}
{{#unless (or dmg.base ../path)}} {{#unless (or dmg.base ../path)}}
<a data-action="removeDamage" data-key="{{key}}"><i class="fas fa-trash"></i></a> <a data-action="removeDamage" data-key="{{dmg.applyTo}}"><i class="fas fa-trash"></i></a>
{{/unless}} {{/unless}}
</legend> </legend>
{{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}}
{{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." key ".resultBased") localize=true classes="checkbox"}} {{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." dmg.applyTo ".resultBased") localize=true classes="checkbox"}}
{{/if}} {{/if}}
{{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}} {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}}
<div class="nest-inputs"> <div class="nest-inputs">
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}</legend>
{{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=key path=../path}} {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}}
</fieldset> </fieldset>
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}</legend>
{{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" key=key path=../path}} {{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" key=dmg.applyTo path=../path}}
</fieldset> </fieldset>
</div> </div>
{{else}} {{else}}
{{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=key path=../path}} {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}}
{{/if}} {{/if}}
{{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}} {{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}}
{{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." key ".type") localize=true}} {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." dmg.applyTo ".type") localize=true}}
{{/if}} {{/if}}
{{#if ../horde}} {{#if ../horde}}
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}}</legend> <legend>{{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}}</legend>
<div class="nest-inputs"> <div class="nest-inputs">
<input type="hidden" name="{{../path}}damage.parts.{{key}}.valueAlt.multiplier" value="flat"> <input type="hidden" name="{{../path}}damage.parts.{{dmg.applyTo}}.valueAlt.multiplier" value="flat">
{{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." key ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} {{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }}
{{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." key ".valueAlt.dice") classes="inline-child" localize=true}} {{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.dice") classes="inline-child" localize=true}}
{{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." key ".valueAlt.bonus") localize=true classes="inline-child"}} {{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.bonus") localize=true classes="inline-child"}}
</div> </div>
</fieldset> </fieldset>
{{/if}} {{/if}}
<input type="hidden" name="damage.parts.{{key}}.base" value="{{dmg.base}}"> <input type="hidden" name="{{concat ../path "damage.parts." dmg.applyTo ".base"}}" value="{{dmg.base}}">
</fieldset> </fieldset>
</div> </div>
{{/each}} {{/each}}

View file

@ -56,8 +56,8 @@
{{/unless}} {{/unless}}
<div class="damage-section-controls"> <div class="damage-section-controls">
{{#if directDamage}} {{#if directDamage}}
<select class="roll-mode-select" name="selectedRollMode"> <select class="roll-mode-select" name="selectedMessageMode">
{{selectOptions rollModes selected=selectedRollMode valueAttr="action" labelAttr="label" localize=true}} {{selectOptions rollModes selected=selectedMessageMode valueAttr="action" labelAttr="label" localize=true}}
</select> </select>
{{/if}} {{/if}}
<button class="submit-btn" data-action="submitRoll"> <button class="submit-btn" data-action="submitRoll">

View file

@ -189,8 +189,8 @@
{{/if}} {{/if}}
<div class="roll-dialog-controls"> <div class="roll-dialog-controls">
<select class="roll-mode-select" name="selectedRollMode"> <select class="roll-mode-select" name="selectedMessageMode">
{{selectOptions rollModes selected=selectedRollMode valueAttr="action" labelAttr="label" localize=true}} {{selectOptions rollModes selected=selectedMessageMode valueAttr="action" labelAttr="label" localize=true}}
</select> </select>
<button class="submit-btn" data-action="submitRoll"{{#unless canRoll}} disabled{{/unless}}> <button class="submit-btn" data-action="submitRoll"{{#unless canRoll}} disabled{{/unless}}>
<i class="fa-solid fa-dice"></i> <i class="fa-solid fa-dice"></i>

View file

@ -1,4 +1,5 @@
<section class="initialization-container tab {{#if tabs.initialization.active}} active{{/if}}" data-group="{{tabs.initialization.group}}" data-tab="{{tabs.initialization.id}}"> <section class="initialization-container tab {{#if tabs.initialization.active}} active{{/if}}" data-group="{{tabs.initialization.group}}" data-tab="{{tabs.initialization.id}}">
{{partId}}
<h2>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.selectParticipants"}}</h2> <h2>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.selectParticipants"}}</h2>
<div class="members-container"> <div class="members-container">
{{#each memberSelection as |member|}} {{#each memberSelection as |member|}}

View file

@ -0,0 +1,11 @@
<section class="roll-selection {{#if (and allHaveRolled tabs.tagTeamRoll.active)}}rendered{{/if}} tab {{#if tabs.tagTeamRoll.active}} active{{/if}}" data-group="{{tabs.tagTeamRoll.group}}">
{{#if allHaveRolled}}
<div class="roll-selection-container">
{{#each members as |member key|}}
<a class="select-roll-button" data-action="selectRoll" data-member-key="{{key}}">
<i class="{{#if member.selected}}fa-solid fa-circle-check{{else}}fa-regular fa-circle inactive{{/if}}"></i>
</a>
{{/each}}
</div>
{{/if}}
</section>

View file

@ -0,0 +1,126 @@
{{#with (lookup members partId)}}
<fieldset class="team-member-container {{#if @root.allHaveRolled}}select-padding{{/if}} {{#unless isEditable}}inactive{{/unless}}" data-member-key="{{@root.partId}}">
<div class="data-container">
<div class="member-info">
<img src="{{img}}" />
<span class="member-name">{{name}}</span>
</div>
<div class="roll-setup">
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.rollType"}}</label>
<select class="roll-type-select" data-member="{{@root.partId}}" {{#if hasRolled}}disabled{{/if}}>
{{selectOptions ../rollTypes selected=rollType localize=true}}
</select>
</div>
</div>
{{#if (or (not rollType) (eq rollType 'trait'))}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</label>
<select name="{{concat "system.tagTeam.members." @root.partId ".rollChoice"}}" {{#if hasRolled}}disabled{{/if}}>
{{selectOptions ../traitOptions selected=rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{else if (eq rollType 'damageAbility')}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.CONFIG.TagTeamRollTypes.damageAbility"}}</label>
<select name="{{concat "system.tagTeam.members." @root.partId ".rollChoice"}}" {{#if hasRolled}}disabled{{/if}}>
{{selectOptions damageRollOptions selected=rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{else}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.GENERAL.Ability.single"}}</label>
<select name="{{concat "system.tagTeam.members." @root.partId ".rollChoice"}}" {{#if hasRolled}}disabled{{/if}}>
{{selectOptions rollOptions selected=rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{/if}}
</div>
{{#if readyToRoll}}
<div class="roll-container">
<span class="roll-title">
{{localize "DAGGERHEART.GENERAL.roll"}}
<div class="roll-tools">
<a class="roll-button" data-action="makeRoll" data-member="{{@root.partId}}">
<img src="systems/daggerheart/assets/icons/dice/hope/d12.svg" />
</a>
{{#if hasRolled}}
<a class="delete-button" data-action="removeRoll" data-member="{{@root.partId}}">
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
</div>
</span>
{{#if rollData}}
{{#with rollData.options.roll}}
<div class="roll-data {{#if this.isCritical}}critical{{else}}{{#if (eq this.result.duality 1)}}hope{{else}}fear{{/if}}{{/if}}">
<div class="duality-label">{{this.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=this.result.label}}</div>
<div class="roll-dice-container">
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="hope">
<span class="dice-label">{{this.hope.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" this.hope.dice ".svg"}}" />
</a>
<span class="roll-operator">+</span>
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="fear">
<span class="dice-label">{{this.fear.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/fear/" this.fear.dice ".svg"}}" />
</a>
{{#if this.advantage.type}}
<span class="roll-operator">{{#if (eq this.advantage.type 1)}}+{{else}}-{{/if}}</span>
<span class="roll-dice">
<span class="dice-label">{{this.advantage.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/" (ifThen (eq this.advantage.type 1) "adv/" "disadv/") this.advantage.dice ".svg"}}" />
</span>
{{/if}}
<span class="roll-operator">{{#if (gte this.modifierTotal 0)}}+{{else}}-{{/if}}</span>
<span class="roll-value">{{positive this.modifierTotal}}</span>
</div>
</div>
{{/with}}
{{else}}
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
{{/if}}
</div>
{{/if}}
{{#if rollData.options.hasDamage}}
<div class="roll-container">
<span class="roll-title">
{{localize "DAGGERHEART.GENERAL.damage"}}
<div class="roll-tools">
<a class="roll-button" data-action="makeDamageRoll" data-member-key="{{@root.partId}}" {{#unless readyToRoll}}disabled{{/unless}}>
<img src="systems/daggerheart/assets/icons/dice/hope/d20.svg" />
</a>
{{#if damage}}
<a class="delete-button" data-action="removeDamageRoll" data-member-key="{{@root.partId}}" {{#unless rollData.options.damage}}disabled{{/unless}}>
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
</div>
</span>
{{#if damage}}
{{#if useCritDamage}}
{{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=critDamage isCritical=true }}
{{else}}
{{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=damage }}
{{/if}}
{{else}}
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
{{/if}}
</div>
{{/if}}
</div>
</fieldset>
{{/with}}

View file

@ -1,140 +1,5 @@
<section class="tag-team-roll tab {{#if tabs.tagTeamRoll.active}} active{{/if}}" data-group="{{tabs.tagTeamRoll.group}}" data-tab="{{tabs.tagTeamRoll.id}}"> <section class="tag-team-roll tab {{#if tabs.tagTeamRoll.active}} active{{/if}}" data-group="{{tabs.tagTeamRoll.group}}" data-tab="{{tabs.tagTeamRoll.id}}">
<div class="tag-team-roll-container {{#unless isEditable}}inactive{{/unless}}"> <div class="tag-team-roll-container {{#unless isEditable}}inactive{{/unless}}">
<div class="team-container">
{{#each members as |member key|}}
<fieldset class="member-container {{#unless member.isEditable}}inactive{{/unless}}">
<div class="data-container">
<div class="member-info">
<img src="{{member.img}}" />
<span class="member-name">{{member.name}}</span>
</div>
<div class="roll-setup">
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.rollType"}}</label>
<select class="roll-type-select" data-member="{{key}}" {{#if member.hasRolled}}disabled{{/if}}>
{{selectOptions ../rollTypes selected=member.rollType localize=true}}
</select>
</div>
</div>
{{#if (eq member.rollType 'trait')}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</label>
<select name="{{concat "system.tagTeam.members." key ".rollChoice"}}" {{#if member.hasRolled}}disabled{{/if}}>
{{selectOptions ../traitOptions selected=member.rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{else if (eq member.rollType 'damageAbility')}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.CONFIG.TagTeamRollTypes.damageAbility"}}</label>
<select name="{{concat "system.tagTeam.members." key ".rollChoice"}}" {{#if member.hasRolled}}disabled{{/if}}>
{{selectOptions member.damageRollOptions selected=member.rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{else}}
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.GENERAL.Ability.single"}}</label>
<select name="{{concat "system.tagTeam.members." key ".rollChoice"}}" {{#if member.hasRolled}}disabled{{/if}}>
{{selectOptions member.rollOptions selected=member.rollChoice localize=true blank=""}}
</select>
</div>
</div>
{{/if}}
</div>
{{#if member.readyToRoll}}
<div class="roll-container">
<span class="roll-title">
{{localize "DAGGERHEART.GENERAL.roll"}}
<div class="roll-tools">
<a class="roll-button" data-action="makeRoll" data-member="{{key}}">
<img src="systems/daggerheart/assets/icons/dice/hope/d12.svg" />
</a>
{{#if member.hasRolled}}
<a class="delete-button" data-action="removeRoll" data-member="{{key}}">
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
</div>
</span>
{{#if member.rollData}}
{{#with member.rollData.options.roll}}
<div class="roll-data {{#if this.isCritical}}critical{{else}}{{#if (eq this.result.duality 1)}}hope{{else}}fear{{/if}}{{/if}}">
<div class="duality-label">{{this.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=this.result.label}}</div>
<div class="roll-dice-container">
<a class="roll-dice" data-action="rerollDice" data-member="{{../key}}" data-dice-type="hope">
<span class="dice-label">{{this.hope.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" this.hope.dice ".svg"}}" />
</a>
<span class="roll-operator">+</span>
<a class="roll-dice" data-action="rerollDice" data-member="{{../key}}" data-dice-type="fear">
<span class="dice-label">{{this.fear.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/fear/" this.fear.dice ".svg"}}" />
</a>
{{#if this.advantage.type}}
<span class="roll-operator">{{#if (eq this.advantage.type 1)}}+{{else}}-{{/if}}</span>
<span class="roll-dice">
<span class="dice-label">{{this.advantage.value}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/" (ifThen (eq this.advantage.type 1) "adv/" "disadv/") this.advantage.dice ".svg"}}" />
</span>
{{/if}}
<span class="roll-operator">{{#if (gte this.modifierTotal 0)}}+{{else}}-{{/if}}</span>
<span class="roll-value">{{positive this.modifierTotal}}</span>
</div>
</div>
{{/with}}
{{else}}
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
{{/if}}
</div>
{{/if}}
{{#if member.rollData.options.hasDamage}}
<div class="roll-container">
<span class="roll-title">
{{localize "DAGGERHEART.GENERAL.damage"}}
<div class="roll-tools">
<a class="roll-button" data-action="makeDamageRoll" data-member-key="{{key}}" {{#unless member.readyToRoll}}disabled{{/unless}}>
<img src="systems/daggerheart/assets/icons/dice/hope/d20.svg" />
</a>
{{#if damage}}
<a class="delete-button" data-action="removeDamageRoll" data-member-key="{{key}}" {{#unless member.rollData.options.damage}}disabled{{/unless}}>
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
</div>
</span>
{{#if damage}}
{{#if useCritDamage}}
{{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=critDamage isCritical=true }}
{{else}}
{{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=damage }}
{{/if}}
{{else}}
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
{{/if}}
</div>
{{/if}}
</div>
{{#if member.hasRolled}}
<a class="select-roll-button" data-action="selectRoll" data-member-key="{{key}}">
<i class="{{#if member.selected}}fa-solid fa-circle-check{{else}}fa-regular fa-circle inactive{{/if}}"></i>
</a>
{{/if}}
</fieldset>
{{/each}}
</div>
<div class="results-container"> <div class="results-container">
<span class="result-container-label">{{localize "DAGGERHEART.GENERAL.result.plural"}}</span> <span class="result-container-label">{{localize "DAGGERHEART.GENERAL.result.plural"}}</span>
<div class="results-inner-container"> <div class="results-inner-container">

View file

@ -4,13 +4,22 @@
<input type="text" name="elevation" value="{{elevation}}" {{disabled (or locked (and isGamePaused (not isGM)))}}> <input type="text" name="elevation" value="{{elevation}}" {{disabled (or locked (and isGamePaused (not isGM)))}}>
</div> </div>
<button type="button" class="control-icon" data-action="sort" data-direction="up" data-tooltip="HUD.ToFront"> <button type="button" class="control-icon" data-action="sort" data-tooltip="HUD.ToFrontOrBack">
<img src="{{icons.up}}"> <i class="fa-solid fa-arrow-down-arrow-up" inert></i>
</button> </button>
<button type="button" class="control-icon" data-action="sort" data-direction="down" data-tooltip="HUD.ToBack"> {{#if canChangeLevel}}
<img src="{{icons.down}}"> <button type="button" class="control-icon" data-action="togglePalette" data-palette="levels"
aria-label="{{ localize "HUD.ChangeLevel" }}" data-tooltip>
<i class="fa-solid fa-stairs" inert></i>
</button> </button>
<div class="palette palette-list" data-palette="levels">
{{#each levels as |level|}}
<a class="palette-list-entry {{level.cssClass}}" data-action="level" data-level-id="{{level.id}}"><span>{{level.name}}</span></a>
{{/each}}
</div>
{{/if}}
{{#if hasCompanion}} {{#if hasCompanion}}
<button type="button" class="control-icon clown-car" data-action="toggleCompanions" data-tooltip="{{#if companionOnCanvas}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.retrieveCompanionTokens"}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.depositCompanionTokens"}}{{/if}}"> <button type="button" class="control-icon clown-car" data-action="toggleCompanions" data-tooltip="{{#if companionOnCanvas}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.retrieveCompanionTokens"}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.depositCompanionTokens"}}{{/if}}">
<img {{#if companionOnCanvas}}class="flipped"{{/if}} src="{{icons.toggleClowncar}}"> <img {{#if companionOnCanvas}}class="flipped"{{/if}} src="{{icons.toggleClowncar}}">

View file

@ -10,8 +10,5 @@
<span>{{localize "DAGGERHEART.ITEMS.Consumable.consumeOnUse"}}</span> <span>{{localize "DAGGERHEART.ITEMS.Consumable.consumeOnUse"}}</span>
{{formField systemFields.consumeOnUse value=source.system.consumeOnUse}} {{formField systemFields.consumeOnUse value=source.system.consumeOnUse}}
<span>{{localize "DAGGERHEART.ITEMS.Consumable.destroyOnEmpty"}}</span>
{{formField systemFields.destroyOnEmpty value=source.system.destroyOnEmpty}}
</fieldset> </fieldset>
</section> </section>