Improvements

This commit is contained in:
WBHarry 2026-04-11 02:02:32 +02:00
parent 303f2fdae7
commit 154c1c939b
10 changed files with 197 additions and 138 deletions

View file

@ -747,7 +747,8 @@
}, },
"GroupRollSelect": { "GroupRollSelect": {
"title": "Group Roll", "title": "Group Roll",
"mainCharacter": "Main Character", "leader": "Leader",
"leaderRoll": "Leader Roll",
"openDialogForAll": "Open Dialog For All", "openDialogForAll": "Open Dialog For All",
"startGroupRoll": "Start Group Roll", "startGroupRoll": "Start Group Roll",
"cancelGroupRoll": "Cancel", "cancelGroupRoll": "Cancel",

View file

@ -1,3 +1,4 @@
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs';
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
import Party from '../sheets/actors/party.mjs'; import Party from '../sheets/actors/party.mjs';
@ -109,16 +110,20 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
await super._onRender(context, options); await super._onRender(context, options);
if (this.element.querySelector('.team-container')) return; if (this.element.querySelector('.team-container')) return;
if (this.tabGroups.application !== this.constructor.PARTS.initialization.id) {
const initializationPart = this.element.querySelector('.initialization-container'); const initializationPart = this.element.querySelector('.initialization-container');
initializationPart.insertAdjacentHTML('afterend', '<div class="team-container"></div>'); initializationPart.insertAdjacentHTML('afterend', '<div class="team-container"></div>');
initializationPart.insertAdjacentHTML( initializationPart.insertAdjacentHTML(
'afterend', 'afterend',
`<div class="section-title">${game.i18n.localize('Aiding Characters')}</div>` `<div class="section-title">${game.i18n.localize('Aiding Characters')}</div>`
); );
const teamContainer = this.element.querySelector('.team-container'); const teamContainer = this.element.querySelector('.team-container');
for (const memberContainer of this.element.querySelectorAll('.team-member-container')) for (const memberContainer of this.element.querySelectorAll('.team-member-container'))
teamContainer.appendChild(memberContainer); teamContainer.appendChild(memberContainer);
} }
}
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -161,6 +166,12 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
partContext.mainCharacter = this.getRollCharacterData(this.party.system.groupRoll.mainCharacter); partContext.mainCharacter = this.getRollCharacterData(this.party.system.groupRoll.mainCharacter);
break; break;
case 'groupRoll': case 'groupRoll':
const leader = this.party.system.groupRoll.mainCharacter;
partContext.hasRolled =
leader?.rollData ||
Object.values(this.party.system.groupRoll?.aidingCharacters ?? {}).some(
x => x.successfull !== null
);
const { modifierTotal, modifiers } = Object.values(this.party.system.groupRoll.aidingCharacters).reduce( const { modifierTotal, modifiers } = Object.values(this.party.system.groupRoll.aidingCharacters).reduce(
(acc, curr) => { (acc, curr) => {
const modifier = curr.successfull === true ? 1 : curr.successfull === false ? -1 : null; const modifier = curr.successfull === true ? 1 : curr.successfull === false ? -1 : null;
@ -173,15 +184,14 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
}, },
{ modifierTotal: 0, modifiers: [] } { modifierTotal: 0, modifiers: [] }
); );
const mainCharacterTotal = this.party.system.groupRoll.mainCharacter?.rollData const mainCharacterTotal = leader?.rollData ? leader.roll.total : null;
? this.party.system.groupRoll.mainCharacter.roll.total
: null;
partContext.groupRoll = { partContext.groupRoll = {
totalLabel: this.party.system.groupRoll.mainCharacter?.rollData totalLabel: leader?.rollData
? game.i18n.format('DAGGERHEART.GENERAL.withThing', { ? game.i18n.format('DAGGERHEART.GENERAL.withThing', {
thing: this.party.system.groupRoll.mainCharacter.roll.totalLabel thing: leader.roll.totalLabel
}) })
: null, : null,
totalDualityClass: leader?.roll?.isCritical ? 'critical' : leader?.roll?.withHope ? 'hope' : 'fear',
total: mainCharacterTotal + modifierTotal, total: mainCharacterTotal + modifierTotal,
mainCharacterTotal, mainCharacterTotal,
modifiers modifiers
@ -333,13 +343,10 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
} }
//#endregion //#endregion
static async #makeRoll(_event, button) { async makeRoll(button, characterData, path) {
const { member } = button.dataset; const actor = game.actors.find(x => x.id === characterData.id);
const actor = game.actors.find(x => x.id === member);
if (!actor) return; if (!actor) return;
const characterData = this.party.system.groupRoll.aidingCharacters[member];
const result = await actor.rollTrait(characterData.rollChoice, { const result = await actor.rollTrait(characterData.rollChoice, {
skips: { skips: {
createMessage: true, createMessage: true,
@ -354,36 +361,43 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
delete rollData.options.messageRoll; delete rollData.options.messageRoll;
this.updatePartyData( this.updatePartyData(
{ {
[`system.groupRoll.aidingCharacters.${member}.rollData`]: rollData [path]: rollData
}, },
this.getUpdatingParts(button) this.getUpdatingParts(button)
); );
} }
static async #removeRoll(_, button) { static async #makeRoll(_event, button) {
const { member } = button.dataset;
const character = this.party.system.groupRoll.aidingCharacters[member];
this.makeRoll(button, character, `system.groupRoll.aidingCharacters.${member}.rollData`);
}
static async #makeMainCharacterRoll(_event, button) {
const character = this.party.system.groupRoll.mainCharacter;
this.makeRoll(button, character, 'system.groupRoll.mainCharacter.rollData');
}
async removeRoll(button, path) {
this.updatePartyData( this.updatePartyData(
{ {
[`system.groupRoll.aidingCharacters.${button.dataset.member}`]: { [path]: {
rollData: null, rollData: null,
rollChoice: null, rollChoice: null,
selected: false selected: false,
successfull: null
} }
}, },
this.getUpdatingParts(button) this.getUpdatingParts(button)
); );
} }
static async #rerollDice(_, button) { static async #removeRoll(_event, button) {
const { member } = button.dataset; this.removeRoll(button, `system.groupRoll.aidingCharacters.${button.dataset.member}`);
this.rerollDice(
button,
this.party.system.groupRoll.aidingCharacters[member],
`system.groupRoll.aidingCharacters.${member}.rollData`
);
} }
static async #rerollMainCharacterDice(_, button) { static async #removeMainCharacterRoll(_event, button) {
this.rerollDice(button, this.party.system.groupRoll.mainCharacter, `system.groupRoll.mainCharacter.rollData`); this.removeRoll(button, 'system.groupRoll.mainCharacter');
} }
async rerollDice(button, data, path) { async rerollDice(button, data, path) {
@ -407,42 +421,17 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
); );
} }
static async #makeMainCharacterRoll(_event, button) { static async #rerollDice(_, button) {
const actor = game.actors.find(x => x.id === this.party.system.groupRoll.mainCharacter.id); const { member } = button.dataset;
if (!actor) return; this.rerollDice(
button,
const characterData = this.party.system.groupRoll.mainCharacter; this.party.system.groupRoll.aidingCharacters[member],
const result = await actor.rollTrait(characterData.rollChoice, { `system.groupRoll.aidingCharacters.${member}.rollData`
skips: {
createMessage: true,
resources: true,
triggers: true
}
});
if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
const rollData = result.messageRoll.toJSON();
delete rollData.options.messageRoll;
this.updatePartyData(
{
[`system.groupRoll.mainCharacter.rollData`]: rollData
},
this.getUpdatingParts(button)
); );
} }
static async #removeMainCharacterRoll(_event, button) { static async #rerollMainCharacterDice(_, button) {
this.updatePartyData( this.rerollDice(button, this.party.system.groupRoll.mainCharacter, `system.groupRoll.mainCharacter.rollData`);
{
[`system.groupRoll.mainCharacter`]: {
rollData: null,
rollChoice: null,
selected: false
}
},
this.getUpdatingParts(button)
);
} }
static #markSuccessfull(_event, button) { static #markSuccessfull(_event, button) {
@ -517,6 +506,20 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
await cls.create(msgData); await cls.create(msgData);
const resourceMap = new ResourceUpdateMap(actor);
if (totalRoll.isCritical) {
resourceMap.addResources([
{ key: 'stress', value: -1, total: 1 },
{ key: 'hope', value: 1, total: 1 }
]);
} else if (totalRoll.withHope) {
resourceMap.addResources([{ key: 'hope', value: 1, total: 1 }]);
} else {
resourceMap.addResources([{ key: 'fear', value: 1, total: 1 }]);
}
resourceMap.updateResources();
/* Fin */ /* Fin */
this.cancelRoll({ confirm: false }); this.cancelRoll({ confirm: false });
} }

View file

@ -116,6 +116,7 @@ export default class Party extends DHBaseActorSheet {
relativeTo: this.document relativeTo: this.document
}); });
context.tagTeamActive = Boolean(this.document.system.tagTeam.initiator); context.tagTeamActive = Boolean(this.document.system.tagTeam.initiator);
context.groupRollActive = Boolean(this.document.system.groupRoll.mainCharacter);
} }
async _prepareMembersContext(context, _options) { async _prepareMembersContext(context, _options) {

View file

@ -1,3 +1,11 @@
.theme-light .daggerheart.dialog.dh-style.views.group-roll-dialog {
.initialization-container .members-container .member-container {
.member-name {
background-image: url('../assets/parchments/dh-parchment-light.png');
}
}
}
.daggerheart.dialog.dh-style.views.group-roll-dialog { .daggerheart.dialog.dh-style.views.group-roll-dialog {
.initialization-container { .initialization-container {
h2 { h2 {
@ -20,6 +28,17 @@
.member-name { .member-name {
position: absolute; position: absolute;
padding: 0 2px;
border: 1px solid;
border-radius: 6px;
margin-top: 4px;
color: light-dark(@dark, @beige);
background-image: url('../assets/parchments/dh-parchment-dark.png');
}
img {
border-radius: 6px;
border: 1px solid light-dark(@dark-blue, @golden);
} }
} }
} }

View file

@ -12,6 +12,11 @@
gap: 8px; gap: 8px;
flex: 1; flex: 1;
&.inactive {
opacity: 0.3;
pointer-events: none;
}
.data-container { .data-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -59,9 +64,27 @@
align-items: center; align-items: center;
gap: 8px; gap: 8px;
&.hope,
&.fear,
&.critical {
color: var(--text-color);
}
&.hope {
--text-color: @golden;
}
&.fear {
--text-color: @chat-blue;
}
&.critical {
--text-color: @chat-purple;
}
&::before, &::before,
&::after { &::after {
color: light-dark(@dark-blue, @golden); color: var(--text-color);
content: ''; content: '';
flex: 1; flex: 1;
height: 2px; height: 2px;

View file

@ -20,6 +20,17 @@
.member-name { .member-name {
position: absolute; position: absolute;
padding: 0 2px;
border: 1px solid;
border-radius: 6px;
margin-top: 4px;
color: light-dark(@dark, @beige);
background-image: url('../assets/parchments/dh-parchment-dark.png');
}
img {
border-radius: 6px;
border: 1px solid light-dark(@dark-blue, @golden);
} }
} }
} }

View file

@ -3,13 +3,17 @@
<legend>{{localize "Result"}}</legend> <legend>{{localize "Result"}}</legend>
<div class="group-roll-results"> <div class="group-roll-results">
<span class="roll-title">{{groupRoll.total}} {{groupRoll.totalLabel}}</span> {{#if hasRolled}}<span class="roll-title {{groupRoll.totalDualityClass}}">{{groupRoll.total}} {{groupRoll.totalLabel}}</span>{{/if}}
<div class="group-roll-container"> <div class="group-roll-container">
<span>{{#if groupRoll.mainCharacterTotal includeZero=true}}{{groupRoll.mainCharacterTotal}}{{else}}{{localize "<Main Character Roll>"}}{{/if}}</span> <span>{{#if groupRoll.mainCharacterTotal includeZero=true}}{{groupRoll.mainCharacterTotal}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leaderRoll"}}{{/if}}</span>
{{#each groupRoll.modifiers as |modifier|}} {{#each groupRoll.modifiers as |modifier|}}
<span>{{#if (gte modifier 0)}}+{{else}}-{{/if}}</span> <span>{{#if (gte modifier 0)}}+{{else}}-{{/if}}</span>
<span>{{positive modifier}}</span> <span>{{positive modifier}}</span>
{{/each}} {{/each}}
{{#unless groupRoll.modifiers.length}}
<span>+</span>
<span>{{localize "DAGGERHEART.GENERAL.Modifier.plural"}}</span>
{{/unless}}
</div> </div>
</div> </div>
</fieldset> </fieldset>

View file

@ -1,6 +1,7 @@
{{#with mainCharacter}} <section class="tab {{#if tabs.groupRoll.active}} active{{/if}}" data-group="{{tabs.groupRoll.group}}" data-tab="{{tabs.groupRoll.id}}">
{{#with mainCharacter}}
<div class="main-character-outer-container"> <div class="main-character-outer-container">
<div class="section-title">{{localize "Main Character"}}</div> <div class="section-title">{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}</div>
<fieldset> <fieldset>
<div class="main-character-container"> <div class="main-character-container">
<div class="character-info"> <div class="character-info">
@ -68,4 +69,5 @@
{{/if}} {{/if}}
</fieldset> </fieldset>
</div> </div>
{{/with}} {{/with}}
</section>

View file

@ -13,7 +13,7 @@
<div class="main-roll {{#if selectedMainCharacterDisabled}}inactive{{/if}}"> <div class="main-roll {{#if selectedMainCharacterDisabled}}inactive{{/if}}">
<div class="form-group"> <div class="form-group">
<label>{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.mainCharacter"}}</label> <label>{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}</label>
<div class="form-fields"> <div class="form-fields">
<select class="main-character-field" {{#if selectedMainCharacterDisabled}}disabled{{/if}}> <select class="main-character-field" {{#if selectedMainCharacterDisabled}}disabled{{/if}}>
{{selectOptions selectedMainCharacterOptions selected=selectedMainCharacter.memberId blank="" }} {{selectOptions selectedMainCharacterOptions selected=selectedMainCharacter.memberId blank="" }}

View file

@ -9,15 +9,10 @@
<i class="fa-solid fa-user-group"></i> <i class="fa-solid fa-user-group"></i>
<span>Tag Team Roll</span> <span>Tag Team Roll</span>
</button> </button>
<button data-action="groupRoll"> <button data-action="groupRoll" class="{{#if groupRollActive}}active-action{{/if}}">
<i class="fa-solid fa-users"></i> <i class="fa-solid fa-users"></i>
<span>Group Roll</span> <span>Group Roll</span>
</button> </button>
{{!-- NOT YET IMPLEMENTED --}}
{{!-- <button>
<i class="fa-solid fa-handshake-angle"></i>
<span>Help Action</span>
</button> --}}
<button data-action="triggerRest" data-action="triggerRest" data-type="shortRest"> <button data-action="triggerRest" data-action="triggerRest" data-type="shortRest">
<i class="fa-solid fa-utensils"></i> <i class="fa-solid fa-utensils"></i>
<span>{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}</span> <span>{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}</span>