[Feature] TagTeam Partial Rendering (#1735)

* I done did it, I think

* Think I fixed the partial rendering bug for gm->player
This commit is contained in:
WBHarry 2026-03-23 17:07:22 +01:00 committed by GitHub
parent 7a7940aa04
commit f119daff07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 545 additions and 438 deletions

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,66 +141,20 @@ 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 = {};
for (const actorId in this.party.system.tagTeam.members) {
const data = this.party.system.tagTeam.members[actorId];
const actor = game.actors.get(actorId);
const rollOptions = [];
const damageRollOptions = [];
for (const item of actor.items) {
if (item.system.metadata.hasActions) {
const actions = [
...item.system.actions,
...(item.system.attack ? [item.system.attack] : [])
];
for (const action of actions) {
if (action.hasRoll) {
const actionItem = {
value: action.uuid,
label: action.name,
group: item.name,
baseAction: action.baseAction
};
if (action.hasDamage) damageRollOptions.push(actionItem);
else rollOptions.push(actionItem);
}
}
}
}
const damage = data.rollData?.options?.damage;
partContext.hasDamage |= Boolean(damage);
const critHitPointsDamage = await this.getCriticalDamage(damage);
partContext.members[actorId] = {
...data,
isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER),
key: actorId,
readyToRoll: Boolean(data.rollChoice),
hasRolled: Boolean(data.rollData),
rollOptions,
damageRollOptions,
damage: damage,
critDamage: critHitPointsDamage,
useCritDamage:
critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
};
}
partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members); partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members);
partContext.joinedRoll = await this.getJoinedRoll({ partContext.joinedRoll = await this.getJoinedRoll({
overrideIsCritical: critSelected, overrideIsCritical: critSelected,
@ -169,24 +164,85 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
break; 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 damageRollOptions = [];
for (const item of actor.items) {
if (item.system.metadata.hasActions) {
const actions = [...item.system.actions, ...(item.system.attack ? [item.system.attack] : [])];
for (const action of actions) {
if (action.hasRoll) {
const actionItem = {
value: action.uuid,
label: action.name,
group: item.name,
baseAction: action.baseAction
};
if (action.hasDamage) damageRollOptions.push(actionItem);
else rollOptions.push(actionItem);
}
}
}
}
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;
partContext.hasDamage |= Boolean(damage);
const critHitPointsDamage = await this.getCriticalDamage(damage);
partContext.members[partId] = {
...data,
isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER),
key: partId,
readyToRoll: Boolean(data.rollChoice),
hasRolled: Boolean(data.rollData),
rollOptions,
damageRollOptions,
damage: damage,
critDamage: critHitPointsDamage,
useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
};
}
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}`]: { {
rollType: event.target.value, [`system.tagTeam.members.${event.target.dataset.member}`]: {
rollChoice: null rollType: event.target.value,
} rollChoice: null
}); }
},
this.getUpdatingParts(event.target)
);
} }
static async #removeRoll(_, button) { static async #removeRoll(_, button) {
this.updatePartyData({ this.updatePartyData(
[`system.tagTeam.members.${button.dataset.member}`]: { {
rollData: null, [`system.tagTeam.members.${button.dataset.member}`]: {
rollChoice: null, rollData: null,
selected: false rollChoice: null,
} 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,15 +456,18 @@ 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`]: { {
...rollData, [`system.tagTeam.members.${member}.rollData`]: {
options: { ...rollData,
...rollData.options, options: {
roll: newRoll ...rollData.options,
roll: newRoll
}
} }
} },
}); this.getUpdatingParts(button)
);
} }
static async #makeDamageRoll(event, button) { static async #makeDamageRoll(event, button) {
@ -423,29 +493,35 @@ 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`]: { {
...current, [`system.tagTeam.members.${memberKey}.rollData`]: {
options: { ...current,
...current.options, options: {
damage: config.damage ...current.options,
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`]: { {
...current, [`system.tagTeam.members.${memberKey}.rollData`]: {
options: { ...current,
...current.options, options: {
damage: null ...current.options,
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,15 +608,18 @@ 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( {
(acc, [key, member]) => { [`system.tagTeam.members`]: Object.entries(this.party.system.tagTeam.members).reduce(
acc[key] = { selected: key === memberKey ? !member.selected : false }; (acc, [key, member]) => {
return acc; acc[key] = { selected: key === memberKey ? !member.selected : false };
}, return acc;
{} },
) {}
}); )
},
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

@ -1,4 +1,212 @@
.daggerheart.dialog.dh-style.views.tag-team-dialog { .daggerheart.dialog.dh-style.views.tag-team-dialog {
.team-container {
display: flex;
gap: 16px;
margin-bottom: 16px;
.team-member-container {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 8px;
flex: 1;
&.select-padding {
padding-bottom: 64px;
}
&.inactive {
opacity: 0.4;
pointer-events: none;
}
.data-container {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.member-info {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
img {
height: 64px;
border-radius: 6px;
border: 1px solid light-dark(@dark-blue, @golden);
}
.member-name {
flex: 1;
text-align: center;
font-size: var(--font-size-18);
}
}
.roll-setup {
width: 100%;
}
.roll-container {
display: flex;
flex-direction: column;
}
.roll-title {
font-size: var(--font-size-20);
font-weight: bold;
color: light-dark(@dark-blue, @golden);
text-align: center;
display: flex;
align-items: center;
gap: 8px;
&::before,
&::after {
color: light-dark(@dark-blue, @golden);
content: '';
flex: 1;
height: 2px;
}
&::before {
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%);
}
&::after {
background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%);
}
}
.roll-tools {
display: flex;
gap: 4px;
align-items: center;
img {
height: 16px;
}
a {
display: flex;
font-size: 16px;
&:hover {
text-shadow: none;
filter: drop-shadow(0 0 8px var(--golden));
}
}
}
.roll-data {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
&.hope {
--text-color: @golden;
--bg-color: @golden-40;
}
&.fear {
--text-color: @chat-blue;
--bg-color: @chat-blue-40;
}
&.critical {
--text-color: @chat-purple;
--bg-color: @chat-purple-40;
}
.duality-label {
color: var(--text-color);
font-size: var(--font-size-20);
font-weight: bold;
text-align: center;
.unused-damage {
text-decoration: line-through;
}
}
.roll-dice-container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
.roll-dice {
position: relative;
display: flex;
align-items: center;
justify-content: center;
.dice-label {
position: absolute;
color: white;
font-size: 1rem;
paint-order: stroke fill;
-webkit-text-stroke: 2px black;
}
img {
height: 32px;
}
}
.roll-operator {
font-size: var(--font-size-24);
}
.roll-value {
font-size: 18px;
}
}
.roll-total {
background: var(--bg-color);
color: var(--text-color);
border-radius: 4px;
padding: 3px;
}
}
}
}
.roll-selection {
position: relative;
top: -80px;
&.rendered {
margin-bottom: -56px;
}
.roll-selection-container {
display: flex;
.select-roll-button {
margin-top: 8px;
flex: 1;
display: flex;
justify-content: center;
i {
color: light-dark(@dark-blue, @golden);
font-size: 48px;
&.inactive {
opacity: 0.4;
}
}
}
}
}
.tag-team-roll-container { .tag-team-roll-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -9,193 +217,6 @@
pointer-events: none; pointer-events: none;
} }
.team-container {
display: flex;
gap: 16px;
.member-container {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 8px;
flex: 1;
&.inactive {
opacity: 0.4;
pointer-events: none;
}
.data-container {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.member-info {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
img {
height: 64px;
border-radius: 6px;
border: 1px solid light-dark(@dark-blue, @golden);
}
.member-name {
flex: 1;
text-align: center;
font-size: var(--font-size-18);
}
}
.roll-setup {
width: 100%;
}
.roll-container {
display: flex;
flex-direction: column;
}
.roll-title {
font-size: var(--font-size-20);
font-weight: bold;
color: light-dark(@dark-blue, @golden);
text-align: center;
display: flex;
align-items: center;
gap: 8px;
&::before,
&::after {
color: light-dark(@dark-blue, @golden);
content: '';
flex: 1;
height: 2px;
}
&::before {
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%);
}
&::after {
background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%);
}
}
.roll-tools {
display: flex;
gap: 4px;
align-items: center;
img {
height: 16px;
}
a {
display: flex;
font-size: 16px;
&:hover {
text-shadow: none;
filter: drop-shadow(0 0 8px var(--golden));
}
}
}
.roll-data {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
&.hope {
--text-color: @golden;
--bg-color: @golden-40;
}
&.fear {
--text-color: @chat-blue;
--bg-color: @chat-blue-40;
}
&.critical {
--text-color: @chat-purple;
--bg-color: @chat-purple-40;
}
.duality-label {
color: var(--text-color);
font-size: var(--font-size-20);
font-weight: bold;
text-align: center;
.unused-damage {
text-decoration: line-through;
}
}
.roll-dice-container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
.roll-dice {
position: relative;
display: flex;
align-items: center;
justify-content: center;
.dice-label {
position: absolute;
color: white;
font-size: 1rem;
paint-order: stroke fill;
-webkit-text-stroke: 2px black;
}
img {
height: 32px;
}
}
.roll-operator {
font-size: var(--font-size-24);
}
.roll-value {
font-size: 18px;
}
}
.roll-total {
background: var(--bg-color);
color: var(--text-color);
border-radius: 4px;
padding: 3px;
}
}
.select-roll-button {
margin-top: 8px;
i {
color: light-dark(@dark-blue, @golden);
font-size: 48px;
&.inactive {
opacity: 0.4;
}
}
}
}
}
.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

@ -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">