mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-13 12:11:07 +01:00
Finished GroupRoll
This commit is contained in:
parent
a442cb904b
commit
c49079c57c
15 changed files with 632 additions and 42 deletions
|
|
@ -123,7 +123,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
|
||||
const tagTeamSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||
if (tagTeamSetting.members[this.actor.id]) {
|
||||
if (tagTeamSetting.members[this.actor.id] && !this.config.skips?.createMessage) {
|
||||
context.activeTagTeamRoll = true;
|
||||
context.tagTeamSelected = this.config.tagTeamSelected;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
tag: 'form',
|
||||
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll'],
|
||||
position: { width: 'auto', height: 'auto' },
|
||||
window: {
|
||||
title: 'DAGGERHEART.UI.Chat.groupRoll.title'
|
||||
},
|
||||
actions: {
|
||||
roll: GroupRollDialog.#roll,
|
||||
removeLeader: GroupRollDialog.#removeLeader,
|
||||
|
|
@ -36,17 +39,20 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
|
||||
_attachPartListeners(partId, htmlElement, options) {
|
||||
super._attachPartListeners(partId, htmlElement, options);
|
||||
const changeChoices = this.actors;
|
||||
const leaderChoices = this.actors.filter(x => this.actorsMembers.every(member => member.actor?.id !== x.id));
|
||||
const memberChoices = this.actors.filter(
|
||||
x => this.actorLeader?.actor?.id !== x.id && this.actorsMembers.every(member => member.actor?.id !== x.id)
|
||||
);
|
||||
|
||||
htmlElement.querySelectorAll('.leader-change-input').forEach(element => {
|
||||
autocomplete({
|
||||
input: element,
|
||||
fetch: function (text, update) {
|
||||
if (!text) {
|
||||
update(changeChoices);
|
||||
update(leaderChoices);
|
||||
} else {
|
||||
text = text.toLowerCase();
|
||||
var suggestions = changeChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||
var suggestions = leaderChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||
update(suggestions);
|
||||
}
|
||||
},
|
||||
|
|
@ -76,7 +82,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
},
|
||||
onSelect: actor => {
|
||||
element.value = actor.uuid;
|
||||
this.actorLeader = { actor: actor, trait: '', difficulty: 0 };
|
||||
this.actorLeader = { actor: actor, trait: 'agility', difficulty: 0 };
|
||||
this.render();
|
||||
},
|
||||
click: e => e.fetch(),
|
||||
|
|
@ -92,10 +98,10 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
input: element,
|
||||
fetch: function (text, update) {
|
||||
if (!text) {
|
||||
update(changeChoices);
|
||||
update(memberChoices);
|
||||
} else {
|
||||
text = text.toLowerCase();
|
||||
var suggestions = changeChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||
var suggestions = memberChoices.filter(n => n.name.toLowerCase().includes(text));
|
||||
update(suggestions);
|
||||
}
|
||||
},
|
||||
|
|
@ -125,7 +131,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
},
|
||||
onSelect: actor => {
|
||||
element.value = actor.uuid;
|
||||
this.actorsMembers.push({ actor: actor, trait: '', difficulty: 0 });
|
||||
this.actorsMembers.push({ actor: actor, trait: 'agility', difficulty: 0 });
|
||||
this.render({ force: true });
|
||||
},
|
||||
click: e => e.fetch(),
|
||||
|
|
@ -140,14 +146,22 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
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
|
||||
}));
|
||||
context.members = this.actorsMembers;
|
||||
context.traitList = abilities;
|
||||
|
||||
context.allSelected = this.actorsMembers.length + (this.actorLeader?.actor ? 1 : 0) === this.actors.length;
|
||||
context.rollDisabled = context.members.length === 0 || !this.actorLeader?.actor;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static updateData(event, _, formData) {
|
||||
const { actorLeader, actorsMembers } = foundry.utils.expandObject(formData.object);
|
||||
this.actorLeader = foundry.utils.mergeObject(this.actorLeader, actorLeader);
|
||||
this.actorsMembers = foundry.utils.mergeObject(this.actorsMembers, actorsMembers);
|
||||
this.render(true);
|
||||
}
|
||||
|
||||
static async #removeLeader(_, button) {
|
||||
this.actorLeader = null;
|
||||
this.render();
|
||||
|
|
@ -158,8 +172,25 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
this.render();
|
||||
}
|
||||
|
||||
static async #roll(_, button) {
|
||||
console.log(this.leader, this.members);
|
||||
console.log(this);
|
||||
static async #roll() {
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const systemData = {
|
||||
leader: this.actorLeader,
|
||||
members: this.actorsMembers
|
||||
};
|
||||
const msg = {
|
||||
type: 'groupRoll',
|
||||
user: game.user.id,
|
||||
speaker: cls.getSpeaker(),
|
||||
title: game.i18n.localize('DAGGERHEART.UI.Chat.groupRoll.title'),
|
||||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/groupRoll.hbs',
|
||||
{ system: systemData }
|
||||
)
|
||||
};
|
||||
|
||||
cls.create(msg);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
import { abilities } from '../../config/actorConfig.mjs';
|
||||
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
|
||||
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
||||
constructor(options) {
|
||||
|
|
@ -67,6 +68,18 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
html.querySelectorAll('.reroll-button').forEach(element =>
|
||||
element.addEventListener('click', event => this.rerollEvent(event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.group-roll-button').forEach(element =>
|
||||
element.addEventListener('click', event => this.groupRollButton(event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.group-roll-reroll').forEach(element =>
|
||||
element.addEventListener('click', event => this.groupRollReroll(event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.group-roll-success').forEach(element =>
|
||||
element.addEventListener('click', event => this.groupRollSuccessEvent(event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.group-roll-header-expand-section').forEach(element =>
|
||||
element.addEventListener('click', this.groupRollExpandSection)
|
||||
);
|
||||
};
|
||||
|
||||
setupHooks() {
|
||||
|
|
@ -176,4 +189,156 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
async groupRollButton(event, message) {
|
||||
const path = event.currentTarget.dataset.path;
|
||||
const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path);
|
||||
const actor = game.actors.get(actorData._id);
|
||||
|
||||
if (!actor.testUserPermission(game.user, 'OWNER')) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership'));
|
||||
}
|
||||
|
||||
const traitLabel = game.i18n.localize(abilities[trait].label);
|
||||
const config = {
|
||||
event: event,
|
||||
title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`,
|
||||
headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||
ability: traitLabel
|
||||
}),
|
||||
roll: {
|
||||
trait: trait,
|
||||
advantage: 0,
|
||||
modifiers: [{ label: traitLabel, value: actor.system.traits[trait].value }]
|
||||
},
|
||||
hasRoll: true,
|
||||
skips: {
|
||||
createMessage: true,
|
||||
resources: true
|
||||
}
|
||||
};
|
||||
const result = await actor.diceRoll({
|
||||
...config,
|
||||
headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`,
|
||||
title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||
ability: traitLabel
|
||||
})
|
||||
});
|
||||
|
||||
const renderData = { system: foundry.utils.deepClone(message.system) };
|
||||
foundry.utils.setProperty(renderData.system, `${path}.result`, result.roll);
|
||||
|
||||
const updatedContent = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/groupRoll.hbs',
|
||||
{ ...renderData, user: game.user }
|
||||
);
|
||||
const mess = game.messages.get(message._id);
|
||||
|
||||
await emitAsGM(
|
||||
GMUpdateEvent.UpdateDocument,
|
||||
mess.update.bind(mess),
|
||||
{
|
||||
...renderData,
|
||||
content: updatedContent
|
||||
},
|
||||
mess.uuid
|
||||
);
|
||||
}
|
||||
|
||||
async groupRollReroll(event, message) {
|
||||
const path = event.currentTarget.dataset.path;
|
||||
const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path);
|
||||
const actor = game.actors.get(actorData._id);
|
||||
|
||||
if (!actor.testUserPermission(game.user, 'OWNER')) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership'));
|
||||
}
|
||||
|
||||
const traitLabel = game.i18n.localize(abilities[trait].label);
|
||||
|
||||
const config = {
|
||||
event: event,
|
||||
title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`,
|
||||
headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||
ability: traitLabel
|
||||
}),
|
||||
roll: {
|
||||
trait: trait,
|
||||
advantage: 0,
|
||||
modifiers: [{ label: traitLabel, value: actor.system.traits[trait].value }]
|
||||
},
|
||||
hasRoll: true,
|
||||
skips: {
|
||||
createMessage: true
|
||||
}
|
||||
};
|
||||
const result = await actor.diceRoll({
|
||||
...config,
|
||||
headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`,
|
||||
title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||
ability: traitLabel
|
||||
})
|
||||
});
|
||||
|
||||
const renderData = { system: foundry.utils.deepClone(message.system) };
|
||||
foundry.utils.setProperty(renderData.system, `${path}.result`, { ...result.roll, rerolled: true });
|
||||
|
||||
const updatedContent = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/groupRoll.hbs',
|
||||
{ ...renderData, user: game.user }
|
||||
);
|
||||
const mess = game.messages.get(message._id);
|
||||
await emitAsGM(
|
||||
GMUpdateEvent.UpdateDocument,
|
||||
mess.update.bind(mess),
|
||||
{
|
||||
...renderData,
|
||||
content: updatedContent
|
||||
},
|
||||
mess.uuid
|
||||
);
|
||||
}
|
||||
|
||||
async groupRollSuccessEvent(event, message) {
|
||||
if (!game.user.isGM) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.gmOnly'));
|
||||
}
|
||||
|
||||
const { path, success } = event.currentTarget.dataset;
|
||||
const { actor: actorData } = foundry.utils.getProperty(message.system, path);
|
||||
const actor = game.actors.get(actorData._id);
|
||||
|
||||
if (!actor.testUserPermission(game.user, 'OWNER')) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership'));
|
||||
}
|
||||
|
||||
const renderData = { system: foundry.utils.deepClone(message.system) };
|
||||
foundry.utils.setProperty(renderData.system, `${path}.manualSuccess`, Boolean(success));
|
||||
|
||||
const updatedContent = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/groupRoll.hbs',
|
||||
{ ...renderData, user: game.user }
|
||||
);
|
||||
const mess = game.messages.get(message._id);
|
||||
await emitAsGM(
|
||||
GMUpdateEvent.UpdateDocument,
|
||||
mess.update.bind(mess),
|
||||
{
|
||||
...renderData,
|
||||
content: updatedContent
|
||||
},
|
||||
mess.uuid
|
||||
);
|
||||
}
|
||||
|
||||
async groupRollExpandSection(event) {
|
||||
event.target
|
||||
.closest('.group-roll-header-expand-section')
|
||||
.querySelectorAll('i')
|
||||
.forEach(element => {
|
||||
element.classList.toggle('fa-angle-up');
|
||||
element.classList.toggle('fa-angle-down');
|
||||
});
|
||||
event.target.closest('.group-roll-section').querySelector('.group-roll-content').classList.toggle('closed');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { emitAsGM, GMUpdateEvent, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import DHAbilityUse from './abilityUse.mjs';
|
||||
import DHActorRoll from './actorRoll.mjs';
|
||||
import DHGroupRoll from './groupRoll.mjs';
|
||||
import DHSystemMessage from './systemMessage.mjs';
|
||||
|
||||
export const config = {
|
||||
|
|
@ -7,5 +8,6 @@ export const config = {
|
|||
adversaryRoll: DHActorRoll,
|
||||
damageRoll: DHActorRoll,
|
||||
dualityRoll: DHActorRoll,
|
||||
groupRoll: DHGroupRoll,
|
||||
systemMessage: DHSystemMessage
|
||||
};
|
||||
|
|
|
|||
31
module/data/chat-message/groupRoll.mjs
Normal file
31
module/data/chat-message/groupRoll.mjs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { abilities } from '../../config/actorConfig.mjs';
|
||||
|
||||
export default class DHGroupRoll extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
leader: new fields.EmbeddedDataField(GroupRollMemberField),
|
||||
members: new fields.ArrayField(new fields.EmbeddedDataField(GroupRollMemberField))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class GroupRollMemberField extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
actor: new fields.ObjectField(),
|
||||
trait: new fields.StringField({ choices: abilities }),
|
||||
difficulty: new fields.StringField(),
|
||||
result: new fields.ObjectField({ nullable: true, initial: null }),
|
||||
manualSuccess: new fields.BooleanField({ nullable: true, initial: null })
|
||||
};
|
||||
}
|
||||
|
||||
/* Can be expanded if we handle automation of success/failure */
|
||||
get success() {
|
||||
return manualSuccess;
|
||||
}
|
||||
}
|
||||
|
|
@ -70,8 +70,11 @@ export default class DHRoll extends Roll {
|
|||
if (Hooks.call(`${CONFIG.DH.id}.postRoll${hook.capitalize()}`, config, message) === false) return null;
|
||||
}
|
||||
|
||||
// Create Chat Message
|
||||
if (!config.source?.message) config.message = await this.toMessage(roll, config);
|
||||
if (config.skips?.createMessage && game.modules.get('dice-so-nice')?.active) {
|
||||
await game.dice3d.showForRoll(roll, game.user, true);
|
||||
} else if (!config.source?.message) {
|
||||
config.message = await this.toMessage(roll, config);
|
||||
}
|
||||
}
|
||||
|
||||
static postEvaluate(roll, config = {}) {
|
||||
|
|
@ -237,7 +240,8 @@ export const registerRollDiceHooks = () => {
|
|||
!config.source?.actor ||
|
||||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
|
||||
config.actionType === 'reaction' ||
|
||||
config.tagTeamSelected
|
||||
config.tagTeamSelected ||
|
||||
config.skips?.resources
|
||||
)
|
||||
return;
|
||||
const actor = await fromUuid(config.source.actor);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ export default class RegisterHandlebarsHelpers {
|
|||
setVar: this.setVar,
|
||||
empty: this.empty,
|
||||
pluralize: this.pluralize,
|
||||
positive: this.positive
|
||||
positive: this.positive,
|
||||
isNullish: this.isNullish
|
||||
});
|
||||
}
|
||||
static add(a, b) {
|
||||
|
|
@ -94,4 +95,8 @@ export default class RegisterHandlebarsHelpers {
|
|||
static positive(a) {
|
||||
return Math.abs(Number(a));
|
||||
}
|
||||
|
||||
static isNullish(a) {
|
||||
return a === null || a === undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue