mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 11:41:08 +01:00
add group roll dialog
This commit is contained in:
parent
5a874ae268
commit
9e9c1d2ac0
9 changed files with 324 additions and 3 deletions
|
|
@ -10,3 +10,4 @@ export { default as OwnershipSelection } from './ownershipSelection.mjs';
|
||||||
export { default as RerollDamageDialog } from './rerollDamageDialog.mjs';
|
export { default as RerollDamageDialog } from './rerollDamageDialog.mjs';
|
||||||
export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
|
export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
|
||||||
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
|
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
|
||||||
|
export { default as GroupRollDialog } from './group-roll-dialog.mjs';
|
||||||
165
module/applications/dialogs/group-roll-dialog.mjs
Normal file
165
module/applications/dialogs/group-roll-dialog.mjs
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
import autocomplete from 'autocompleter';
|
||||||
|
import { abilities } from '../../config/actorConfig.mjs';
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class GroupRollDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(actors) {
|
||||||
|
super();
|
||||||
|
this.actors = actors;
|
||||||
|
this.actorLeader = {};
|
||||||
|
this.actorsMembers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return 'Group Roll';
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'form',
|
||||||
|
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll'],
|
||||||
|
position: { width: 'auto', height: 'auto' },
|
||||||
|
actions: {
|
||||||
|
roll: GroupRollDialog.#roll,
|
||||||
|
removeLeader: GroupRollDialog.#removeLeader,
|
||||||
|
removeMember: GroupRollDialog.#removeMember
|
||||||
|
},
|
||||||
|
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
application: {
|
||||||
|
id: 'group-roll',
|
||||||
|
template: 'systems/daggerheart/templates/dialogs/group-roll/group-roll.hbs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
const changeChoices = this.actors;
|
||||||
|
|
||||||
|
htmlElement.querySelectorAll('.leader-change-input').forEach(element => {
|
||||||
|
autocomplete({
|
||||||
|
input: element,
|
||||||
|
fetch: function (text, update) {
|
||||||
|
if (!text) {
|
||||||
|
update(changeChoices);
|
||||||
|
} else {
|
||||||
|
text = text.toLowerCase();
|
||||||
|
var suggestions = changeChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||||
|
update(suggestions);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: function (actor, search) {
|
||||||
|
const actorName = game.i18n.localize(actor.name);
|
||||||
|
const matchIndex = actorName.toLowerCase().indexOf(search);
|
||||||
|
|
||||||
|
const beforeText = actorName.slice(0, matchIndex);
|
||||||
|
const matchText = actorName.slice(matchIndex, matchIndex + search.length);
|
||||||
|
const after = actorName.slice(matchIndex + search.length, actorName.length);
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = actor.img;
|
||||||
|
|
||||||
|
const element = document.createElement('li');
|
||||||
|
element.appendChild(img);
|
||||||
|
|
||||||
|
const label = document.createElement('span');
|
||||||
|
label.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
||||||
|
element.appendChild(label);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
},
|
||||||
|
renderGroup: function (label) {
|
||||||
|
const itemElement = document.createElement('div');
|
||||||
|
itemElement.textContent = game.i18n.localize(label);
|
||||||
|
return itemElement;
|
||||||
|
},
|
||||||
|
onSelect: actor => {
|
||||||
|
element.value = actor.uuid;
|
||||||
|
this.actorLeader = { actor: actor, trait: '', difficulty: 0 };
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
click: e => e.fetch(),
|
||||||
|
customize: function (_input, _inputRect, container) {
|
||||||
|
container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ;
|
||||||
|
},
|
||||||
|
minLength: 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
htmlElement.querySelectorAll('.team-push-input').forEach(element => {
|
||||||
|
autocomplete({
|
||||||
|
input: element,
|
||||||
|
fetch: function (text, update) {
|
||||||
|
if (!text) {
|
||||||
|
update(changeChoices);
|
||||||
|
} else {
|
||||||
|
text = text.toLowerCase();
|
||||||
|
var suggestions = changeChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||||
|
update(suggestions);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: function (actor, search) {
|
||||||
|
const actorName = game.i18n.localize(actor.name);
|
||||||
|
const matchIndex = actorName.toLowerCase().indexOf(search);
|
||||||
|
|
||||||
|
const beforeText = actorName.slice(0, matchIndex);
|
||||||
|
const matchText = actorName.slice(matchIndex, matchIndex + search.length);
|
||||||
|
const after = actorName.slice(matchIndex + search.length, actorName.length);
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = actor.img;
|
||||||
|
|
||||||
|
const element = document.createElement('li');
|
||||||
|
element.appendChild(img);
|
||||||
|
|
||||||
|
const label = document.createElement('span');
|
||||||
|
label.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
||||||
|
element.appendChild(label);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
},
|
||||||
|
renderGroup: function (label) {
|
||||||
|
const itemElement = document.createElement('div');
|
||||||
|
itemElement.textContent = game.i18n.localize(label);
|
||||||
|
return itemElement;
|
||||||
|
},
|
||||||
|
onSelect: actor => {
|
||||||
|
element.value = actor.uuid;
|
||||||
|
this.actorsMembers.push({ actor: actor, trait: '', difficulty: 0 });
|
||||||
|
this.render({ force: true });
|
||||||
|
},
|
||||||
|
click: e => e.fetch(),
|
||||||
|
customize: function (_input, _inputRect, container) {
|
||||||
|
container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ;
|
||||||
|
},
|
||||||
|
minLength: 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
context.leader = this.actorLeader;
|
||||||
|
context.members = [...this.actorsMembers];
|
||||||
|
context.traitList = Object.values(abilities).map(trait => ({
|
||||||
|
label: game.i18n.localize(trait.label),
|
||||||
|
value: trait.id
|
||||||
|
}));
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #removeLeader(_, button) {
|
||||||
|
this.actorLeader = null;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #removeMember(_, button) {
|
||||||
|
this.actorsMembers = this.actorsMembers.filter(m => m.actor.uuid !== button.dataset.memberUuid);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #roll(_, button) {
|
||||||
|
console.log(this.leader, this.members);
|
||||||
|
console.log(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||||
import FilterMenu from '../../ux/filter-menu.mjs';
|
import FilterMenu from '../../ux/filter-menu.mjs';
|
||||||
import DaggerheartMenu from '../../sidebar/tabs/daggerheartMenu.mjs';
|
import DaggerheartMenu from '../../sidebar/tabs/daggerheartMenu.mjs';
|
||||||
import { socketEvent } from '../../../systemRegistration/socket.mjs';
|
import { socketEvent } from '../../../systemRegistration/socket.mjs';
|
||||||
|
import GroupRollDialog from '../../dialogs/group-roll-dialog.mjs';
|
||||||
|
|
||||||
export default class Party extends DHBaseActorSheet {
|
export default class Party extends DHBaseActorSheet {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|
@ -30,6 +31,7 @@ export default class Party extends DHBaseActorSheet {
|
||||||
tempBrowser: Party.#tempBrowser,
|
tempBrowser: Party.#tempBrowser,
|
||||||
refeshActions: Party.#refeshActions,
|
refeshActions: Party.#refeshActions,
|
||||||
triggerRest: Party.#triggerRest,
|
triggerRest: Party.#triggerRest,
|
||||||
|
groupRoll: Party.#groupRoll,
|
||||||
selectRefreshable: DaggerheartMenu.selectRefreshable,
|
selectRefreshable: DaggerheartMenu.selectRefreshable,
|
||||||
refreshActors: DaggerheartMenu.refreshActors
|
refreshActors: DaggerheartMenu.refreshActors
|
||||||
},
|
},
|
||||||
|
|
@ -268,6 +270,10 @@ export default class Party extends DHBaseActorSheet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #groupRoll(params) {
|
||||||
|
new GroupRollDialog(this.document.system.partyMembers).render({ force: true });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options for Consumable and Loot.
|
* Get the set of ContextMenu options for Consumable and Loot.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
|
|
||||||
47
styles/less/dialog/group-roll/group-roll.less
Normal file
47
styles/less/dialog/group-roll/group-roll.less
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
@import '../../utils/colors.less';
|
||||||
|
|
||||||
|
.application.daggerheart.group-roll {
|
||||||
|
fieldset.one-column {
|
||||||
|
min-width: 500px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.actor-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.actor-check-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.form-fields {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,3 +30,5 @@
|
||||||
@import './multiclass-choice/sheet.less';
|
@import './multiclass-choice/sheet.less';
|
||||||
|
|
||||||
@import './reroll-dialog/sheet.less';
|
@import './reroll-dialog/sheet.less';
|
||||||
|
|
||||||
|
@import './group-roll/group-roll.less';
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.standard-form {
|
||||||
|
font-family: @font-body;
|
||||||
|
}
|
||||||
|
|
||||||
&.two-big-buttons {
|
&.two-big-buttons {
|
||||||
.window-content {
|
.window-content {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
@import '../../utils/colors.less';
|
||||||
|
@import '../../utils/fonts.less';
|
||||||
|
|
||||||
.theme-light .autocomplete {
|
.theme-light .autocomplete {
|
||||||
background-image: url('../assets/parchments/dh-parchment-light.png');
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
color: black;
|
color: black;
|
||||||
|
|
@ -27,11 +30,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
li[role='option'] {
|
li[role='option'] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
font-size: var(--font-size-14);
|
font-size: var(--font-size-14);
|
||||||
padding-left: 10px;
|
padding: 0 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover,
|
||||||
|
&.selected {
|
||||||
background-color: light-dark(@dark, @beige);
|
background-color: light-dark(@dark, @beige);
|
||||||
color: light-dark(@beige, var(--color-dark-3));
|
color: light-dark(@beige, var(--color-dark-3));
|
||||||
}
|
}
|
||||||
|
|
@ -39,5 +46,16 @@
|
||||||
> div {
|
> div {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
78
templates/dialogs/group-roll/group-roll.hbs
Normal file
78
templates/dialogs/group-roll/group-roll.hbs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
<div class="group-roll">
|
||||||
|
<header class="dialog-header">
|
||||||
|
<h1>Group Roll</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<fieldset class="one-column">
|
||||||
|
<legend>Leader</legend>
|
||||||
|
{{#unless leader.actor}}
|
||||||
|
<input type="text" class="leader-change-input" name="leader"/>
|
||||||
|
<div class="drag-area">
|
||||||
|
<span>Select a Leader</span>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="actor-item">
|
||||||
|
<img src="{{leader.actor.img}}" alt="{{leader.actor.name}}">
|
||||||
|
<div class="actor-info">
|
||||||
|
<span class="actor-name">{{leader.actor.name}}</span>
|
||||||
|
<div class="actor-check-info">
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</label>
|
||||||
|
<select name="leader.trait" data-dtype="Number">
|
||||||
|
{{selectOptions traitList selected=leader.trait labelAttr="label" valueAttr="value" }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.difficulty"}}</label>
|
||||||
|
<input type="number" name="leader.difficulty" value="{{leader.difficulty}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a data-action="removeLeader" data-leader-uuid="{{leader.actor.uuid}}">
|
||||||
|
<i class="fa-solid fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset class="one-column">
|
||||||
|
<legend>Party Team</legend>
|
||||||
|
<input type="text" class="team-push-input" name="member"/>
|
||||||
|
{{#if (gt this.members.length 0)}}
|
||||||
|
{{#each members as |member|}}
|
||||||
|
<div class="actor-item">
|
||||||
|
<img src="{{member.actor.img}}" alt="{{member.actor.name}}">
|
||||||
|
<div class="actor-info">
|
||||||
|
<span class="actor-name">{{member.actor.name}}</span>
|
||||||
|
<div class="actor-check-info">
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</label>
|
||||||
|
<select name="member.trait" data-dtype="Number">
|
||||||
|
{{selectOptions traitList selected=member.trait labelAttr="label" valueAttr="value" }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.difficulty"}}</label>
|
||||||
|
<input type="number" name="member.difficulty" value="{{member.difficulty}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a data-action="removemember" data-member-uuid="{{member.actor.uuid}}">
|
||||||
|
<i class="fa-solid fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
<div class="drag-area">
|
||||||
|
<span>Select a Member</span>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<button class="submit-btn" data-action="roll">
|
||||||
|
<i class="fa-solid fa-dice"></i>
|
||||||
|
<span>Roll</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<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>
|
<button data-action="groupRoll">
|
||||||
<i class="fa-solid fa-users"></i>
|
<i class="fa-solid fa-users"></i>
|
||||||
<span>Group Roll</span>
|
<span>Group Roll</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue