mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +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 ResourceDiceDialog } from './resourceDiceDialog.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 DaggerheartMenu from '../../sidebar/tabs/daggerheartMenu.mjs';
|
||||
import { socketEvent } from '../../../systemRegistration/socket.mjs';
|
||||
import GroupRollDialog from '../../dialogs/group-roll-dialog.mjs';
|
||||
|
||||
export default class Party extends DHBaseActorSheet {
|
||||
constructor(options) {
|
||||
|
|
@ -30,6 +31,7 @@ export default class Party extends DHBaseActorSheet {
|
|||
tempBrowser: Party.#tempBrowser,
|
||||
refeshActions: Party.#refeshActions,
|
||||
triggerRest: Party.#triggerRest,
|
||||
groupRoll: Party.#groupRoll,
|
||||
selectRefreshable: DaggerheartMenu.selectRefreshable,
|
||||
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.
|
||||
* @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 './reroll-dialog/sheet.less';
|
||||
|
||||
@import './group-roll/group-roll.less';
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.standard-form {
|
||||
font-family: @font-body;
|
||||
}
|
||||
|
||||
&.two-big-buttons {
|
||||
.window-content {
|
||||
padding-top: 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.theme-light .autocomplete {
|
||||
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||
color: black;
|
||||
|
|
@ -27,11 +30,15 @@
|
|||
}
|
||||
|
||||
li[role='option'] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: var(--font-size-14);
|
||||
padding-left: 10px;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
&:hover,
|
||||
&.selected {
|
||||
background-color: light-dark(@dark, @beige);
|
||||
color: light-dark(@beige, var(--color-dark-3));
|
||||
}
|
||||
|
|
@ -39,5 +46,16 @@
|
|||
> div {
|
||||
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>
|
||||
<span>Tag Team Roll</span>
|
||||
</button>
|
||||
<button>
|
||||
<button data-action="groupRoll">
|
||||
<i class="fa-solid fa-users"></i>
|
||||
<span>Group Roll</span>
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue