mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-22 23:43:37 +02:00
Initial
This commit is contained in:
parent
01619ef067
commit
acb3e80b74
12 changed files with 155 additions and 445 deletions
24
lang/en.json
24
lang/en.json
|
|
@ -534,6 +534,18 @@
|
||||||
},
|
},
|
||||||
"takeDowntime": "Take Downtime"
|
"takeDowntime": "Take Downtime"
|
||||||
},
|
},
|
||||||
|
"GroupRoll": {
|
||||||
|
"title": "Group Roll",
|
||||||
|
"leader": "Leader",
|
||||||
|
"partyTeam": "Party Team",
|
||||||
|
"team": "Team",
|
||||||
|
"selectLeader": "Select a Leader",
|
||||||
|
"selectMember": "Select a Member",
|
||||||
|
"rerollTitle": "Reroll Group Roll",
|
||||||
|
"rerollContent": "Are you sure you want to reroll your {trait} roll?",
|
||||||
|
"rerollTooltip": "Reroll",
|
||||||
|
"wholePartySelected": "The whole party is selected"
|
||||||
|
},
|
||||||
"HUD": {
|
"HUD": {
|
||||||
"tokenHUD": {
|
"tokenHUD": {
|
||||||
"genericEffects": "Foundry Effects",
|
"genericEffects": "Foundry Effects",
|
||||||
|
|
@ -2965,18 +2977,6 @@
|
||||||
"immunityTo": "Immunity: {immunities}"
|
"immunityTo": "Immunity: {immunities}"
|
||||||
},
|
},
|
||||||
"featureTitle": "Class Feature",
|
"featureTitle": "Class Feature",
|
||||||
"groupRoll": {
|
|
||||||
"title": "Group Roll",
|
|
||||||
"leader": "Leader",
|
|
||||||
"partyTeam": "Party Team",
|
|
||||||
"team": "Team",
|
|
||||||
"selectLeader": "Select a Leader",
|
|
||||||
"selectMember": "Select a Member",
|
|
||||||
"rerollTitle": "Reroll Group Roll",
|
|
||||||
"rerollContent": "Are you sure you want to reroll your {trait} roll?",
|
|
||||||
"rerollTooltip": "Reroll",
|
|
||||||
"wholePartySelected": "The whole party is selected"
|
|
||||||
},
|
|
||||||
"healingRoll": {
|
"healingRoll": {
|
||||||
"title": "Heal - {damage}",
|
"title": "Heal - {damage}",
|
||||||
"heal": "Heal",
|
"heal": "Heal",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ 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';
|
|
||||||
export { default as TagTeamDialog } from './tagTeamDialog.mjs';
|
export { default as TagTeamDialog } from './tagTeamDialog.mjs';
|
||||||
|
export { default as GroupRollDialog } from './groupRollDialog.mjs';
|
||||||
export { default as RiskItAllDialog } from './riskItAllDialog.mjs';
|
export { default as RiskItAllDialog } from './riskItAllDialog.mjs';
|
||||||
export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs';
|
export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs';
|
||||||
|
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
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' },
|
|
||||||
window: {
|
|
||||||
title: 'DAGGERHEART.UI.Chat.groupRoll.title'
|
|
||||||
},
|
|
||||||
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 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(leaderChoices);
|
|
||||||
} else {
|
|
||||||
text = text.toLowerCase();
|
|
||||||
var suggestions = leaderChoices.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}`.replaceAll(
|
|
||||||
' ',
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
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: 'agility', 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(memberChoices);
|
|
||||||
} else {
|
|
||||||
text = text.toLowerCase();
|
|
||||||
var suggestions = memberChoices.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}`.replaceAll(
|
|
||||||
' ',
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
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: 'agility', 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 = 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static async #removeMember(_, button) {
|
|
||||||
this.actorsMembers = this.actorsMembers.filter(m => m.actor.uuid !== button.dataset.memberUuid);
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
137
module/applications/dialogs/groupRollDialog.mjs
Normal file
137
module/applications/dialogs/groupRollDialog.mjs
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { RefreshType } from '../../systemRegistration/socket.mjs';
|
||||||
|
import Party from '../sheets/actors/party.mjs';
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class GroupRollDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(party) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.party = party;
|
||||||
|
this.partyMembers = party.system.partyMembers
|
||||||
|
.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
||||||
|
.map(member => ({
|
||||||
|
...member.toObject(),
|
||||||
|
uuid: member.uuid,
|
||||||
|
id: member.id,
|
||||||
|
selected: false,
|
||||||
|
owned: member.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||||
|
}));
|
||||||
|
|
||||||
|
Hooks.on(socketEvent.Refresh, this.groupRollRefresh.bind());
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRoll.title');
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'form',
|
||||||
|
id: 'GroupRollDialog',
|
||||||
|
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll-dialog'],
|
||||||
|
position: { width: 550, height: 'auto' },
|
||||||
|
actions: {},
|
||||||
|
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
groupRoll: {
|
||||||
|
id: 'groupRoll',
|
||||||
|
template: 'systems/daggerheart/templates/dialogs/groupRollDialog/groupRoll.hbs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_configureRenderParts(options) {
|
||||||
|
const { groupRoll } = super._configureRenderParts(options);
|
||||||
|
const augmentedParts = { groupRoll };
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _preparePartContext(partId, context, options) {
|
||||||
|
const partContext = await super._preparePartContext(partId, context, options);
|
||||||
|
|
||||||
|
switch (partId) {
|
||||||
|
case 'groupRoll':
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async updateData(event, _, formData) {
|
||||||
|
const partyData = foundry.utils.expandObject(formData.object);
|
||||||
|
|
||||||
|
this.updatePartyData(partyData, this.getUpdatingParts(event.target));
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePartyData(update, updatingParts, options = { render: true }) {
|
||||||
|
if (!game.users.activeGM)
|
||||||
|
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.gmRequired'));
|
||||||
|
|
||||||
|
const gmUpdate = async update => {
|
||||||
|
await this.party.update(update);
|
||||||
|
this.render({ parts: updatingParts });
|
||||||
|
game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
await emitAsGM(
|
||||||
|
GMUpdateEvent.UpdateDocument,
|
||||||
|
gmUpdate,
|
||||||
|
update,
|
||||||
|
this.party.uuid,
|
||||||
|
options.render
|
||||||
|
? { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts }
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdatingParts(target) {
|
||||||
|
const updatingMember = target.closest('.team-member-container')?.dataset?.memberKey;
|
||||||
|
|
||||||
|
return [...(updatingMember ? [updatingMember] : []), rollSelection.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
groupRollRefresh = ({ refreshType, action, parts }) => {
|
||||||
|
if (refreshType !== RefreshType.GroupRoll) return;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'refresh':
|
||||||
|
this.render({ parts });
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
this.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async close(options = {}) {
|
||||||
|
/* Opt out of Foundry's standard behavior of closing all application windows marked as UI when Escape is pressed */
|
||||||
|
if (options.closeKey) return;
|
||||||
|
|
||||||
|
Hooks.off(socketEvent.Refresh, this.groupRollRefresh);
|
||||||
|
return super.close(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ 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';
|
|
||||||
import DhpActor from '../../../documents/actor.mjs';
|
import DhpActor from '../../../documents/actor.mjs';
|
||||||
|
|
||||||
export default class Party extends DHBaseActorSheet {
|
export default class Party extends DHBaseActorSheet {
|
||||||
|
|
@ -261,9 +260,7 @@ export default class Party extends DHBaseActorSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #groupRoll(_params) {
|
static async #groupRoll(_params) {
|
||||||
new GroupRollDialog(
|
new game.system.api.applications.dialogs.GroupRollDialog(this.document).render({ force: true });
|
||||||
this.document.system.partyMembers.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
|
||||||
).render({ force: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { abilities } from '../../config/actorConfig.mjs';
|
|
||||||
import { enrichedDualityRoll } from '../../enrichers/DualityRollEnricher.mjs';
|
import { enrichedDualityRoll } from '../../enrichers/DualityRollEnricher.mjs';
|
||||||
import { enrichedFateRoll, getFateTypeData } from '../../enrichers/FateRollEnricher.mjs';
|
import { enrichedFateRoll, getFateTypeData } from '../../enrichers/FateRollEnricher.mjs';
|
||||||
import { getCommandTarget, rollCommandToJSON } from '../../helpers/utils.mjs';
|
import { getCommandTarget, rollCommandToJSON } from '../../helpers/utils.mjs';
|
||||||
import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs';
|
|
||||||
|
|
||||||
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|
@ -150,18 +148,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
html.querySelectorAll('.reroll-button').forEach(element =>
|
html.querySelectorAll('.reroll-button').forEach(element =>
|
||||||
element.addEventListener('click', event => this.rerollEvent(event, message))
|
element.addEventListener('click', event => this.rerollEvent(event, message))
|
||||||
);
|
);
|
||||||
html.querySelectorAll('.group-roll-button').forEach(element =>
|
|
||||||
element.addEventListener('click', event => this.groupRollButton(event, message))
|
|
||||||
);
|
|
||||||
html.querySelectorAll('.group-roll-reroll').forEach(element =>
|
|
||||||
element.addEventListener('click', event => this.groupRollReroll(event, message))
|
|
||||||
);
|
|
||||||
html.querySelectorAll('.group-roll-success').forEach(element =>
|
|
||||||
element.addEventListener('click', event => this.groupRollSuccessEvent(event, message))
|
|
||||||
);
|
|
||||||
html.querySelectorAll('.group-roll-header-expand-section').forEach(element =>
|
|
||||||
element.addEventListener('click', this.groupRollExpandSection)
|
|
||||||
);
|
|
||||||
html.querySelectorAll('.risk-it-all-button').forEach(element =>
|
html.querySelectorAll('.risk-it-all-button').forEach(element =>
|
||||||
element.addEventListener('click', event => this.riskItAllClearStressAndHitPoints(event, data))
|
element.addEventListener('click', event => this.riskItAllClearStressAndHitPoints(event, data))
|
||||||
);
|
);
|
||||||
|
|
@ -305,174 +291,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async groupRollButton(event, message) {
|
|
||||||
const path = event.currentTarget.dataset.path;
|
|
||||||
const isLeader = path === 'leader';
|
|
||||||
const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path);
|
|
||||||
const actor = game.actors.get(actorData._id);
|
|
||||||
|
|
||||||
if (!actor) {
|
|
||||||
return ui.notifications.error(
|
|
||||||
game.i18n.format('DAGGERHEART.UI.Notifications.documentIsMissing', {
|
|
||||||
documentType: game.i18n.localize('TYPES.Actor.character')
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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: !isLeader,
|
|
||||||
updateCountdowns: !isLeader
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result) return;
|
|
||||||
|
|
||||||
const newMessageData = foundry.utils.deepClone(message.system);
|
|
||||||
foundry.utils.setProperty(newMessageData, `${path}.result`, result.roll);
|
|
||||||
const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) };
|
|
||||||
|
|
||||||
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,
|
|
||||||
updateCountdowns: 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 newMessageData = foundry.utils.deepClone(message.system);
|
|
||||||
foundry.utils.setProperty(newMessageData, `${path}.result`, { ...result.roll, rerolled: true });
|
|
||||||
const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) };
|
|
||||||
|
|
||||||
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 newMessageData = foundry.utils.deepClone(message.system);
|
|
||||||
foundry.utils.setProperty(newMessageData, `${path}.manualSuccess`, Boolean(success));
|
|
||||||
const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) };
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
async riskItAllClearStressAndHitPoints(event, data) {
|
async riskItAllClearStressAndHitPoints(event, data) {
|
||||||
const resourceValue = event.target.dataset.resourceValue;
|
const resourceValue = event.target.dataset.resourceValue;
|
||||||
const actor = game.actors.get(event.target.dataset.actorId);
|
const actor = game.actors.get(event.target.dataset.actorId);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import DHAbilityUse from './abilityUse.mjs';
|
import DHAbilityUse from './abilityUse.mjs';
|
||||||
import DHActorRoll from './actorRoll.mjs';
|
import DHActorRoll from './actorRoll.mjs';
|
||||||
import DHGroupRoll from './groupRoll.mjs';
|
|
||||||
import DHSystemMessage from './systemMessage.mjs';
|
import DHSystemMessage from './systemMessage.mjs';
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
|
|
@ -9,6 +8,5 @@ export const config = {
|
||||||
damageRoll: DHActorRoll,
|
damageRoll: DHActorRoll,
|
||||||
dualityRoll: DHActorRoll,
|
dualityRoll: DHActorRoll,
|
||||||
fateRoll: DHActorRoll,
|
fateRoll: DHActorRoll,
|
||||||
groupRoll: DHGroupRoll,
|
|
||||||
systemMessage: DHSystemMessage
|
systemMessage: DHSystemMessage
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
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))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get totalModifier() {
|
|
||||||
return this.members.reduce((acc, m) => {
|
|
||||||
if (m.manualSuccess === null) return acc;
|
|
||||||
|
|
||||||
return acc + (m.manualSuccess ? 1 : -1);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,6 +41,7 @@ export const GMUpdateEvent = {
|
||||||
export const RefreshType = {
|
export const RefreshType = {
|
||||||
Countdown: 'DhCoundownRefresh',
|
Countdown: 'DhCoundownRefresh',
|
||||||
TagTeamRoll: 'DhTagTeamRollRefresh',
|
TagTeamRoll: 'DhTagTeamRollRefresh',
|
||||||
|
GroupRoll: 'DhGroupRollRefresh',
|
||||||
EffectsDisplay: 'DhEffectsDisplayRefresh',
|
EffectsDisplay: 'DhEffectsDisplayRefresh',
|
||||||
Scene: 'DhSceneRefresh',
|
Scene: 'DhSceneRefresh',
|
||||||
CompendiumBrowser: 'DhCompendiumBrowserRefresh'
|
CompendiumBrowser: 'DhCompendiumBrowserRefresh'
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,6 @@
|
||||||
"damageRoll": {},
|
"damageRoll": {},
|
||||||
"abilityUse": {},
|
"abilityUse": {},
|
||||||
"tagTeam": {},
|
"tagTeam": {},
|
||||||
"groupRoll": {},
|
|
||||||
"systemMessage": {}
|
"systemMessage": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
3
templates/dialogs/groupRollDialog/groupRoll.hbs
Normal file
3
templates/dialogs/groupRollDialog/groupRoll.hbs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div>
|
||||||
|
Test
|
||||||
|
</div>
|
||||||
0
templates/dialogs/groupRollDialog/groupRollMember.hbs
Normal file
0
templates/dialogs/groupRollDialog/groupRollMember.hbs
Normal file
Loading…
Add table
Add a link
Reference in a new issue