mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
[PR] [Feature] Party Sheet (#1230)
* start development * finish party members tab * start resources tab * finish resources tab * finish inventory tab and add inital template to projects tab * add resource buttons actions methods * add group roll dialog * Main implementation * Fixed costs * Minor fixes and tweaks for the party sheet (#1239) * Minor fixes and tweaks for the party sheet * Fix scroll restoration for party sheet tabs * Finished GroupRoll * Removed/commented-out not yet implemented things * Commented out Difficulty since it's not used yet * Re-render party when members update (#1242) * Fixed so style applies in preview chat message * Added the clown car * Fixed so items can be dropped into the Party sheet * Added delete icon to inventory * Fixed TokenHUD token property useage. Fixed skipping roll message * Added visible modifier to GroupRoll leader result * Leader roll displays the large result display right away after rolling * Corrected tokenHUD for non-player-tokens * Fixed clowncar tokenData * Fixed TagTeam roll message and sound * Removed final TagTeamRoll roll sound * [PR] [Party Sheets] Sidebar character sheet changes (#1249) * Something experimenting * I am silly (wearning Dunce hat) * Stressful task * Armor functional to be hit * CSS Changes to accomadate pip boy * last minute change to resource section for better visual feeling * restoring old css for toggle * Added setting to toggle pip/number display * toggle functionality added * Fixed light-mode in characterSheet * Fixed multi-row resource pips display for character * Fixed separators * Added pip-display to Adversary and Companion. Some fixing on armor display --------- Co-authored-by: WBHarry <williambjrklund@gmail.com> * Fixed party height and resource armor update * Fixed deletebutton padding * Only showing expand-me icon on InventoryItem if there is a description to show * . * Fixed menu icon to be beige instead of white in dark mode --------- Co-authored-by: moliloo <dev.murilobrito@gmail.com> Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com> Co-authored-by: Nikhil Nagarajan <potter.nikhil@gmail.com>
This commit is contained in:
parent
f53252a369
commit
261a3a68b0
91 changed files with 3769 additions and 271 deletions
BIN
assets/icons/arrow-dunk.png
Normal file
BIN
assets/icons/arrow-dunk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
1
assets/icons/documents/actors/dark-squad.svg
Normal file
1
assets/icons/documents/actors/dark-squad.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><path d="M0 0h512v512H0z" fill="#000" fill-opacity="1"></path><g class="" transform="translate(0,0)" style=""><path d="M369.1 21.22c-19.2 0-36.2 10.63-47.9 26.47-11.7 15.84-18.6 37.03-18.6 60.31 0 21.1 5.7 40.5 15.5 55.7-5.7 1.6-11 3.9-15.9 6.6-10.2-8.5-22.6-13.6-35.9-13.6-19.3 0-36.3 10.6-48 26.4-4.7 6.4-8.6 13.6-11.6 21.5-4.8-2.4-9.9-4.3-15.5-5.6 9.4-15.1 14.8-34.1 14.8-54.7 0-23.2-6.9-44.43-18.6-60.27-11.7-15.84-28.7-26.5-47.9-26.5s-36.2 10.66-47.94 26.5C79.87 99.87 73 121.1 73 144.3c0 21.1 5.69 40.5 15.47 55.8-32.07 9.1-50.29 37.1-59.44 70-9.79 35.2-10.87 77.3-10.87 115.6v9.4h45.5l6.78 99.3h18.75l-7.28-106.5-4.1-80-18.65 1 3.47 67.5H36.97c.24-35.2 1.97-72.1 10.09-101.2 8.78-31.6 23.32-52.8 51.25-58.2l4.69-.1c10.3 8.8 22.9 14.2 36.5 14.2 14.1 0 26.9-5.7 37.4-15h4.6c7.8 1.2 14.4 3.5 20.1 6.7-1.2 6.6-1.9 13.5-1.9 20.6 0 21.1 5.7 40.5 15.5 55.8-32.1 9.1-50.3 37.2-59.4 70-9.8 35.2-10.9 77.3-10.9 115.6v9.4c21.7-.3 42.8.2 64.3.2l-.5-7.3-4.1-80-18.7.9 3.4 67.5h-25.6c.3-35.2 2-72.1 10.1-101.2 8.7-31.6 23.3-52.7 51.1-58.2l4.9-.1c10.3 8.8 22.8 14.2 36.4 14.2 14.1 0 27-5.7 37.5-15h4.4c15.4 2.4 26.1 8.9 34.5 18.6 8.5 9.7 14.5 23.2 18.5 39.2 7.3 29.5 7.7 66.9 7.7 102.5h-23.4l3.5-67.5-18.7-.9-4.2 82-.3 5.3c20.8 0 43.3-.3 61.9-.2v-9.4c0-38.1.5-80.6-8.4-116.3-4.4-17.8-11.3-34.1-22.4-47-9.7-11.1-22.7-19.4-38.8-23.4 9.4-15.1 14.7-34.1 14.7-54.7 0-22.5-6.4-43.2-17.5-58.8 3.9-1.8 8.1-3.1 12.7-4h4.7c10.3 8.8 22.9 14.2 36.5 14.2 14.1 0 27-5.8 37.4-15l4.6-.1c15.4 2.5 26 8.9 34.4 18.6 8.5 9.8 14.5 23.3 18.5 39.3 7.3 29.4 7.7 66.8 7.7 102.4h-23.4l3.5-67.4-18.7-1-4.1 79.7-8.6 143.1h18.7l8.2-135.7h43.1v-9.3c0-38.2.6-80.7-8.3-116.3-4.5-17.9-11.4-34.2-22.5-47-9.6-11.2-22.6-19.5-38.8-23.5 9.4-15.1 14.8-34 14.8-54.6 0-23.28-6.9-44.47-18.6-60.31-11.6-15.29-31.5-26.13-47.9-26.47zm0 18.69c12.4 0 23.9 6.69 32.9 18.87 9 12.19 14.9 29.67 14.9 49.22 0 19.5-5.9 37-14.9 49.2-9 12.2-20.5 18.9-32.9 18.9-12.3 0-23.9-6.7-32.9-18.9s-14.9-29.7-14.9-49.2c0-19.55 5.9-37.03 14.9-49.22 9-12.18 20.6-18.87 32.9-18.87zM139.5 76.22c12.4 0 23.9 6.72 32.9 18.9s14.9 29.68 14.9 49.18-5.9 37-14.9 49.2c-9 12.2-20.5 18.9-32.9 18.9-12.4 0-23.9-6.7-32.9-18.9-8.97-12.2-14.91-29.7-14.91-49.2 0-19.5 5.94-37 14.91-49.17 9-12.19 20.5-18.91 32.9-18.91zm197.8 22.34v18.64h22.5V98.56h-22.5zm41.1 0v18.64h22.5V98.56h-22.5zM107.7 134.9v18.7h22.5v-18.7h-22.5zm41.1 0v18.7h22.5v-18.7h-22.5zm117.5 40.4c12.3 0 23.8 6.7 32.8 18.9 9 12.2 15 29.7 15 49.2 0 19.6-6 37-15 49.2-9 12.2-20.5 18.9-32.8 18.9-12.4 0-24-6.7-33-18.9-8.9-12.2-14.9-29.6-14.9-49.2 0-19.5 6-37 14.9-49.2 9-12.2 20.6-18.9 33-18.9zM234.5 234v18.7h22.4V234zm41.1 0v18.7H298V234h-22.4z" fill="#fff" fill-opacity="1"></path></g></svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -85,6 +85,10 @@ Hooks.once('init', () => {
|
||||||
types: ['environment'],
|
types: ['environment'],
|
||||||
makeDefault: true
|
makeDefault: true
|
||||||
});
|
});
|
||||||
|
Actors.registerSheet(SYSTEM.id, applications.sheets.actors.Party, {
|
||||||
|
types: ['party'],
|
||||||
|
makeDefault: true
|
||||||
|
});
|
||||||
|
|
||||||
CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect;
|
CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect;
|
||||||
CONFIG.ActiveEffect.dataModels = models.activeEffects.config;
|
CONFIG.ActiveEffect.dataModels = models.activeEffects.config;
|
||||||
|
|
|
||||||
54
lang/en.json
54
lang/en.json
|
|
@ -20,7 +20,8 @@
|
||||||
"character": "Character",
|
"character": "Character",
|
||||||
"companion": "Companion",
|
"companion": "Companion",
|
||||||
"adversary": "Adversary",
|
"adversary": "Adversary",
|
||||||
"environment": "Environment"
|
"environment": "Environment",
|
||||||
|
"party": "Party"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CONTROLS": {
|
"CONTROLS": {
|
||||||
|
|
@ -437,7 +438,9 @@
|
||||||
},
|
},
|
||||||
"HUD": {
|
"HUD": {
|
||||||
"tokenHUD": {
|
"tokenHUD": {
|
||||||
"genericEffects": "Foundry Effects"
|
"genericEffects": "Foundry Effects",
|
||||||
|
"depositPartyTokens": "Deposit Party Tokens",
|
||||||
|
"retrievePartyTokens": "Retrieve Party Tokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ImageSelect": {
|
"ImageSelect": {
|
||||||
|
|
@ -568,6 +571,19 @@
|
||||||
"ResourceDice": {
|
"ResourceDice": {
|
||||||
"title": "{name} Resource",
|
"title": "{name} Resource",
|
||||||
"rerollDice": "Reroll Dice"
|
"rerollDice": "Reroll Dice"
|
||||||
|
},
|
||||||
|
"TagTeamSelect": {
|
||||||
|
"title": "Tag Team Roll",
|
||||||
|
"leaderTitle": "Initiating Character",
|
||||||
|
"membersTitle": "Participants",
|
||||||
|
"partyTeam": "Party Team",
|
||||||
|
"hopeCost": "Hope Cost",
|
||||||
|
"initiatingCharacter": "Initiating Character",
|
||||||
|
"linkMessageHint": "Make a roll from your character sheet to link it to the Tag Team Roll",
|
||||||
|
"damageNotRolled": "Damage not rolled in chat message yet",
|
||||||
|
"insufficientHope": "The initiating character doesn't have enough hope",
|
||||||
|
"createTagTeam": "Create TagTeam Roll",
|
||||||
|
"chatMessageRollTitle": "Roll"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CLASS": {
|
"CLASS": {
|
||||||
|
|
@ -1936,6 +1952,7 @@
|
||||||
"story": "Story",
|
"story": "Story",
|
||||||
"biography": "Biography",
|
"biography": "Biography",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
|
"resources": "Resources",
|
||||||
"foundation": "Foundation",
|
"foundation": "Foundation",
|
||||||
"specialization": "Specialization",
|
"specialization": "Specialization",
|
||||||
"mastery": "Mastery",
|
"mastery": "Mastery",
|
||||||
|
|
@ -1953,6 +1970,8 @@
|
||||||
"downtime": "Downtime",
|
"downtime": "Downtime",
|
||||||
"roll": "Roll",
|
"roll": "Roll",
|
||||||
"rules": "Rules",
|
"rules": "Rules",
|
||||||
|
"partyMembers": "Party Members",
|
||||||
|
"projects": "Projects",
|
||||||
"types": "Types",
|
"types": "Types",
|
||||||
"itemFeatures": "Item Features",
|
"itemFeatures": "Item Features",
|
||||||
"questions": "Questions",
|
"questions": "Questions",
|
||||||
|
|
@ -2233,7 +2252,8 @@
|
||||||
"target": {
|
"target": {
|
||||||
"label": "Target"
|
"label": "Target"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"useResourcePips": { "label": "Pip Display For Resources" }
|
||||||
},
|
},
|
||||||
"fearDisplay": {
|
"fearDisplay": {
|
||||||
"token": "Tokens",
|
"token": "Tokens",
|
||||||
|
|
@ -2480,6 +2500,17 @@
|
||||||
"title": "Effects Applied"
|
"title": "Effects Applied"
|
||||||
},
|
},
|
||||||
"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} check?",
|
||||||
|
"rerollTooltip": "Reroll"
|
||||||
|
},
|
||||||
"healingRoll": {
|
"healingRoll": {
|
||||||
"title": "Heal - {damage}",
|
"title": "Heal - {damage}",
|
||||||
"heal": "Heal",
|
"heal": "Heal",
|
||||||
|
|
@ -2496,8 +2527,16 @@
|
||||||
},
|
},
|
||||||
"resourceRoll": {
|
"resourceRoll": {
|
||||||
"playerMessage": "{user} rerolled their {name}"
|
"playerMessage": "{user} rerolled their {name}"
|
||||||
|
},
|
||||||
|
"tagTeam": {
|
||||||
|
"title": "Tag Team",
|
||||||
|
"membersTitle": "Members"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ChatLog": {
|
||||||
|
"rerollDamage": "Reroll Damage",
|
||||||
|
"assignTagRoll": "Assign as Tag Roll"
|
||||||
|
},
|
||||||
"Countdowns": {
|
"Countdowns": {
|
||||||
"title": "Countdowns",
|
"title": "Countdowns",
|
||||||
"toggleIconMode": "Toggle Icon Only",
|
"toggleIconMode": "Toggle Icon Only",
|
||||||
|
|
@ -2577,6 +2616,8 @@
|
||||||
"wrongDomain": "The card isn't from one of your class domains.",
|
"wrongDomain": "The card isn't from one of your class domains.",
|
||||||
"cardTooHighLevel": "The card is too high level!",
|
"cardTooHighLevel": "The card is too high level!",
|
||||||
"duplicateCard": "You cannot select the same card more than once.",
|
"duplicateCard": "You cannot select the same card more than once.",
|
||||||
|
"duplicateCharacter": "This actor is already registered in the party members list.",
|
||||||
|
"onlyCharactersInPartySheet": "You can drag only characters to a party sheet.",
|
||||||
"notPrimary": "The weapon is not a primary weapon!",
|
"notPrimary": "The weapon is not a primary weapon!",
|
||||||
"notSecondary": "The weapon is not a secondary weapon!",
|
"notSecondary": "The weapon is not a secondary weapon!",
|
||||||
"itemTooHighTier": "The item must be from Tier1",
|
"itemTooHighTier": "The item must be from Tier1",
|
||||||
|
|
@ -2611,7 +2652,9 @@
|
||||||
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice",
|
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice",
|
||||||
"gmMenuRefresh": "You refreshed all actions and resources {types}",
|
"gmMenuRefresh": "You refreshed all actions and resources {types}",
|
||||||
"subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.",
|
"subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.",
|
||||||
"gmRequired": "This action requires an online GM"
|
"gmRequired": "This action requires an online GM",
|
||||||
|
"gmOnly": "This can only be accessed by the GM",
|
||||||
|
"noActorOwnership": "You do not have permissions for this character"
|
||||||
},
|
},
|
||||||
"Sidebar": {
|
"Sidebar": {
|
||||||
"daggerheartMenu": {
|
"daggerheartMenu": {
|
||||||
|
|
@ -2646,7 +2689,8 @@
|
||||||
"remainingUses": "Uses refresh on {type}",
|
"remainingUses": "Uses refresh on {type}",
|
||||||
"rightClickExtand": "Right-Click to extand",
|
"rightClickExtand": "Right-Click to extand",
|
||||||
"companionPartnerLevelBlock": "The companion needs an assigned partner to level up.",
|
"companionPartnerLevelBlock": "The companion needs an assigned partner to level up.",
|
||||||
"configureAttribution": "Configure Attribution"
|
"configureAttribution": "Configure Attribution",
|
||||||
|
"deleteItem": "Delete Item"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,5 @@ 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';
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
updateIsAdvantage: this.updateIsAdvantage,
|
updateIsAdvantage: this.updateIsAdvantage,
|
||||||
selectExperience: this.selectExperience,
|
selectExperience: this.selectExperience,
|
||||||
toggleReaction: this.toggleReaction,
|
toggleReaction: this.toggleReaction,
|
||||||
|
toggleTagTeamRoll: this.toggleTagTeamRoll,
|
||||||
submitRoll: this.submitRoll
|
submitRoll: this.submitRoll
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
|
@ -120,6 +121,13 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll';
|
context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll';
|
||||||
context.reactionOverride = this.reactionOverride;
|
context.reactionOverride = this.reactionOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tagTeamSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
if (tagTeamSetting.members[this.actor.id] && !this.config.skips?.createMessage) {
|
||||||
|
context.activeTagTeamRoll = true;
|
||||||
|
context.tagTeamSelected = this.config.tagTeamSelected;
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,6 +203,11 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static toggleTagTeamRoll() {
|
||||||
|
this.config.tagTeamSelected = !this.config.tagTeamSelected;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
static async submitRoll() {
|
static async submitRoll() {
|
||||||
await this.close({ submitted: true });
|
await this.close({ submitted: true });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
196
module/applications/dialogs/group-roll-dialog.mjs
Normal file
196
module/applications/dialogs/group-roll-dialog.mjs
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
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}`;
|
||||||
|
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}`;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||||
|
|
||||||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
|
||||||
export default class RerollDamageDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
export default class RerollDamageDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
|
@ -122,6 +124,15 @@ export default class RerollDamageDialog extends HandlebarsApplicationMixin(Appli
|
||||||
}, {})
|
}, {})
|
||||||
};
|
};
|
||||||
await this.message.update(update);
|
await this.message.update(update);
|
||||||
|
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await this.close();
|
await this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
315
module/applications/dialogs/tagTeamDialog.mjs
Normal file
315
module/applications/dialogs/tagTeamDialog.mjs
Normal file
|
|
@ -0,0 +1,315 @@
|
||||||
|
import { GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class TagTeamDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(party) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.data = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
this.party = party;
|
||||||
|
|
||||||
|
this.setupHooks = Hooks.on(socketEvent.Refresh, ({ refreshType }) => {
|
||||||
|
if (refreshType === RefreshType.TagTeamRoll) {
|
||||||
|
this.data = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title');
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'form',
|
||||||
|
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'tag-team-dialog'],
|
||||||
|
position: { width: 550, height: 'auto' },
|
||||||
|
actions: {
|
||||||
|
removeMember: TagTeamDialog.#removeMember,
|
||||||
|
unlinkMessage: TagTeamDialog.#unlinkMessage,
|
||||||
|
selectMessage: TagTeamDialog.#selectMessage,
|
||||||
|
createTagTeam: TagTeamDialog.#createTagTeam
|
||||||
|
},
|
||||||
|
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
application: {
|
||||||
|
id: 'tag-team-dialog',
|
||||||
|
template: 'systems/daggerheart/templates/dialogs/tagTeamDialog.hbs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
context.hopeCost = this.hopeCost;
|
||||||
|
context.data = this.data;
|
||||||
|
|
||||||
|
context.memberOptions = this.party.filter(c => !this.data.members[c.id]);
|
||||||
|
context.selectedCharacterOptions = this.party.filter(c => this.data.members[c.id]);
|
||||||
|
|
||||||
|
context.members = Object.keys(this.data.members).map(id => {
|
||||||
|
const roll = this.data.members[id].messageId ? game.messages.get(this.data.members[id].messageId) : null;
|
||||||
|
|
||||||
|
context.usesDamage =
|
||||||
|
context.usesDamage === undefined
|
||||||
|
? roll?.system.hasDamage
|
||||||
|
: context.usesDamage && roll?.system.hasDamage;
|
||||||
|
return {
|
||||||
|
character: this.party.find(x => x.id === id),
|
||||||
|
selected: this.data.members[id].selected,
|
||||||
|
roll: roll,
|
||||||
|
damageValues: roll
|
||||||
|
? Object.keys(roll.system.damage).map(key => ({
|
||||||
|
key: key,
|
||||||
|
name: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[key].label),
|
||||||
|
total: roll.system.damage[key].total
|
||||||
|
}))
|
||||||
|
: null
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const initiatorChar = this.party.find(x => x.id === this.data.initiator.id);
|
||||||
|
context.initiator = {
|
||||||
|
character: initiatorChar,
|
||||||
|
cost: this.data.initiator.cost
|
||||||
|
};
|
||||||
|
|
||||||
|
context.selectedData = Object.values(context.members).reduce(
|
||||||
|
(acc, member) => {
|
||||||
|
if (!member.roll) return acc;
|
||||||
|
if (member.selected) {
|
||||||
|
acc.result = `${member.roll.system.roll.total} ${member.roll.system.roll.result.label}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.usesDamage) {
|
||||||
|
if (!acc.damageValues) acc.damageValues = {};
|
||||||
|
for (let damage of member.damageValues) {
|
||||||
|
if (acc.damageValues[damage.key]) {
|
||||||
|
acc.damageValues[damage.key].total += damage.total;
|
||||||
|
} else {
|
||||||
|
acc.damageValues[damage.key] = foundry.utils.deepClone(damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ result: null, damageValues: null }
|
||||||
|
);
|
||||||
|
context.showResult = Object.values(context.members).reduce((enabled, member) => {
|
||||||
|
if (!member.roll) return enabled;
|
||||||
|
if (context.usesDamage) {
|
||||||
|
enabled = enabled === null ? member.damageValues.length > 0 : enabled && member.damageValues.length > 0;
|
||||||
|
} else {
|
||||||
|
enabled = enabled === null ? Boolean(member.roll) : enabled && Boolean(member.roll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
context.createDisabled =
|
||||||
|
!context.selectedData.result ||
|
||||||
|
!this.data.initiator.id ||
|
||||||
|
Object.keys(this.data.members).length === 0 ||
|
||||||
|
Object.values(context.members).some(x =>
|
||||||
|
context.usesDamage ? !x.damageValues || x.damageValues.length === 0 : !x.roll
|
||||||
|
);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSource(update) {
|
||||||
|
await this.data.updateSource(update);
|
||||||
|
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, this.data.toObject());
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.GMUpdate,
|
||||||
|
data: {
|
||||||
|
action: GMUpdateEvent.UpdateSetting,
|
||||||
|
uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll,
|
||||||
|
update: this.data.toObject(),
|
||||||
|
refresh: { refreshType: RefreshType.TagTeamRoll }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async updateData(_event, _element, formData) {
|
||||||
|
const { selectedAddMember, initiator } = foundry.utils.expandObject(formData.object);
|
||||||
|
const update = { initiator: initiator };
|
||||||
|
if (selectedAddMember) {
|
||||||
|
const member = await foundry.utils.fromUuid(selectedAddMember);
|
||||||
|
update[`members.${member.id}`] = { messageId: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateSource(update);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #removeMember(_, button) {
|
||||||
|
const update = { [`members.-=${button.dataset.characterId}`]: null };
|
||||||
|
if (this.data.initiator.id === button.dataset.characterId) {
|
||||||
|
update.iniator = { id: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateSource(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #unlinkMessage(_, button) {
|
||||||
|
await this.updateSource({ [`members.${button.id}.messageId`]: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #selectMessage(_, button) {
|
||||||
|
const member = this.data.members[button.id];
|
||||||
|
const currentSelected = Object.keys(this.data.members).find(key => this.data.members[key].selected);
|
||||||
|
const curretSelectedUpdate =
|
||||||
|
currentSelected && currentSelected !== button.id ? { [`${currentSelected}`]: { selected: false } } : {};
|
||||||
|
await this.updateSource({
|
||||||
|
members: {
|
||||||
|
[`${button.id}`]: { selected: !member.selected },
|
||||||
|
...curretSelectedUpdate
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #createTagTeam() {
|
||||||
|
const mainRollId = Object.keys(this.data.members).find(key => this.data.members[key].selected);
|
||||||
|
const mainRoll = game.messages.get(this.data.members[mainRollId].messageId);
|
||||||
|
|
||||||
|
if (this.data.initiator.cost) {
|
||||||
|
const initiator = this.party.find(x => x.id === this.data.initiator.id);
|
||||||
|
if (initiator.system.resources.hope.value < this.data.initiator.cost) {
|
||||||
|
return ui.notifications.warn(
|
||||||
|
game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.insufficientHope')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const secondaryRolls = Object.keys(this.data.members)
|
||||||
|
.filter(key => key !== mainRollId)
|
||||||
|
.map(key => game.messages.get(this.data.members[key].messageId));
|
||||||
|
|
||||||
|
const systemData = foundry.utils.deepClone(mainRoll).system.toObject();
|
||||||
|
for (let roll of secondaryRolls) {
|
||||||
|
if (roll.system.hasDamage) {
|
||||||
|
for (let key in roll.system.damage) {
|
||||||
|
var damage = roll.system.damage[key];
|
||||||
|
if (systemData.damage[key]) {
|
||||||
|
systemData.damage[key].total += damage.total;
|
||||||
|
systemData.damage[key].parts = [...systemData.damage[key].parts, ...damage.parts];
|
||||||
|
} else {
|
||||||
|
systemData.damage[key] = damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
systemData.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle');
|
||||||
|
|
||||||
|
const cls = getDocumentClass('ChatMessage'),
|
||||||
|
msgData = {
|
||||||
|
type: 'dualityRoll',
|
||||||
|
user: game.user.id,
|
||||||
|
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'),
|
||||||
|
speaker: cls.getSpeaker({ actor: this.party.find(x => x.id === mainRollId) }),
|
||||||
|
system: systemData,
|
||||||
|
rolls: mainRoll.rolls,
|
||||||
|
sound: null,
|
||||||
|
flags: { core: { RollTable: true } }
|
||||||
|
};
|
||||||
|
|
||||||
|
await cls.create(msgData);
|
||||||
|
|
||||||
|
const fearUpdate = { key: 'fear', value: null, total: null, enabled: true };
|
||||||
|
for (let memberId of Object.keys(this.data.members)) {
|
||||||
|
const resourceUpdates = [];
|
||||||
|
if (systemData.roll.isCritical || systemData.roll.result.duality === 1) {
|
||||||
|
const value =
|
||||||
|
memberId !== this.data.initiator.id
|
||||||
|
? 1
|
||||||
|
: this.data.initiator.cost
|
||||||
|
? 1 - this.data.initiator.cost
|
||||||
|
: 1;
|
||||||
|
resourceUpdates.push({ key: 'hope', value: value, total: -value, enabled: true });
|
||||||
|
}
|
||||||
|
if (systemData.roll.isCritical) resourceUpdates.push({ key: 'stress', value: -1, total: 1, enabled: true });
|
||||||
|
if (systemData.roll.result.duality === -1) {
|
||||||
|
fearUpdate.value = fearUpdate.value === null ? 1 : fearUpdate.value + 1;
|
||||||
|
fearUpdate.total = fearUpdate.total === null ? -1 : fearUpdate.total - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.party.find(x => x.id === memberId).modifyResource(resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fearUpdate.value) {
|
||||||
|
this.party.find(x => x.id === mainRollId).modifyResource([fearUpdate]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve by fetching default from schema */
|
||||||
|
const update = { members: [], initiator: { id: null, cost: 3 } };
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, update);
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.GMUpdate,
|
||||||
|
data: {
|
||||||
|
action: GMUpdateEvent.UpdateSetting,
|
||||||
|
uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll,
|
||||||
|
update: update,
|
||||||
|
refresh: { refreshType: RefreshType.TagTeamRoll }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async assignRoll(char, message) {
|
||||||
|
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
const character = settings.members[char.id];
|
||||||
|
if (!character) return;
|
||||||
|
|
||||||
|
await settings.updateSource({ [`members.${char.id}.messageId`]: message.id });
|
||||||
|
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, settings);
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.GMUpdate,
|
||||||
|
data: {
|
||||||
|
action: GMUpdateEvent.UpdateSetting,
|
||||||
|
uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll,
|
||||||
|
update: settings,
|
||||||
|
refresh: { refreshType: RefreshType.TagTeamRoll }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(options = {}) {
|
||||||
|
Hooks.off(socketEvent.Refresh, this.setupHooks);
|
||||||
|
await super.close(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
import { shuffleArray } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
|
export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
classes: ['daggerheart'],
|
classes: ['daggerheart'],
|
||||||
actions: {
|
actions: {
|
||||||
combat: DHTokenHUD.#onToggleCombat
|
combat: DHTokenHUD.#onToggleCombat,
|
||||||
|
togglePartyTokens: DHTokenHUD.#togglePartyTokens
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -19,6 +22,12 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
|
|
||||||
|
context.partyOnCanvas =
|
||||||
|
this.actor.type === 'party' &&
|
||||||
|
this.actor.system.partyMembers.some(member => member.getActiveTokens().length > 0);
|
||||||
|
context.icons.toggleParty = 'systems/daggerheart/assets/icons/arrow-dunk.png';
|
||||||
|
context.actorType = this.actor.type;
|
||||||
|
context.usesEffects = this.actor.type !== 'party';
|
||||||
context.canToggleCombat = DHTokenHUD.#nonCombatTypes.includes(this.actor.type)
|
context.canToggleCombat = DHTokenHUD.#nonCombatTypes.includes(this.actor.type)
|
||||||
? false
|
? false
|
||||||
: context.canToggleCombat;
|
: context.canToggleCombat;
|
||||||
|
|
@ -59,6 +68,105 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #togglePartyTokens(_, button) {
|
||||||
|
const icon = button.querySelector('img');
|
||||||
|
icon.classList.toggle('flipped');
|
||||||
|
button.dataset.tooltip = game.i18n.localize(
|
||||||
|
icon.classList.contains('flipped')
|
||||||
|
? 'DAGGERHEART.APPLICATIONS.HUD.tokenHUD.retrievePartyTokens'
|
||||||
|
: 'DAGGERHEART.APPLICATIONS.HUD.tokenHUD.depositPartyTokens'
|
||||||
|
);
|
||||||
|
|
||||||
|
const animationDuration = 500;
|
||||||
|
const activeTokens = this.actor.system.partyMembers.flatMap(member => member.getActiveTokens());
|
||||||
|
const { x: actorX, y: actorY } = this.document;
|
||||||
|
if (activeTokens.length > 0) {
|
||||||
|
for (let token of activeTokens) {
|
||||||
|
await token.document.update(
|
||||||
|
{ x: actorX, y: actorY, alpha: 0 },
|
||||||
|
{ animation: { duration: animationDuration } }
|
||||||
|
);
|
||||||
|
setTimeout(() => token.document.delete(), animationDuration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const activeScene = game.scenes.find(x => x.active);
|
||||||
|
const partyTokenData = [];
|
||||||
|
for (let member of this.actor.system.partyMembers) {
|
||||||
|
const data = await member.getTokenDocument();
|
||||||
|
partyTokenData.push(data.toObject());
|
||||||
|
}
|
||||||
|
const newTokens = await activeScene.createEmbeddedDocuments(
|
||||||
|
'Token',
|
||||||
|
partyTokenData.map(tokenData => ({
|
||||||
|
...tokenData,
|
||||||
|
alpha: 0,
|
||||||
|
x: actorX,
|
||||||
|
y: actorY
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
const { sizeX, sizeY } = activeScene.grid;
|
||||||
|
const nrRandomPositions = Math.ceil(newTokens.length / 8) * 8;
|
||||||
|
/* This is an overcomplicated mess, but I'm stupid */
|
||||||
|
const positions = shuffleArray(
|
||||||
|
[...Array(nrRandomPositions).keys()].map((_, index) => {
|
||||||
|
const nonZeroIndex = index + 1;
|
||||||
|
const indexFloor = Math.floor(index / 8);
|
||||||
|
const distanceCoefficient = indexFloor + 1;
|
||||||
|
const side = 3 + indexFloor * 2;
|
||||||
|
const sideMiddle = Math.ceil(side / 2);
|
||||||
|
const inbetween = 1 + indexFloor * 2;
|
||||||
|
const inbetweenMiddle = Math.ceil(inbetween / 2);
|
||||||
|
|
||||||
|
if (index < side) {
|
||||||
|
const distance =
|
||||||
|
nonZeroIndex === sideMiddle
|
||||||
|
? 0
|
||||||
|
: nonZeroIndex < sideMiddle
|
||||||
|
? -nonZeroIndex
|
||||||
|
: nonZeroIndex - sideMiddle;
|
||||||
|
return { x: actorX - sizeX * distance, y: actorY - sizeY * distanceCoefficient };
|
||||||
|
} else if (index < side + inbetween) {
|
||||||
|
const inbetweenIndex = nonZeroIndex - side;
|
||||||
|
const distance =
|
||||||
|
inbetweenIndex === inbetweenMiddle
|
||||||
|
? 0
|
||||||
|
: inbetweenIndex < inbetweenMiddle
|
||||||
|
? -inbetweenIndex
|
||||||
|
: inbetweenIndex - inbetweenMiddle;
|
||||||
|
return { x: actorX + sizeX * distanceCoefficient, y: actorY + sizeY * distance };
|
||||||
|
} else if (index < 2 * side + inbetween) {
|
||||||
|
const sideIndex = nonZeroIndex - side - inbetween;
|
||||||
|
const distance =
|
||||||
|
sideIndex === sideMiddle
|
||||||
|
? 0
|
||||||
|
: sideIndex < sideMiddle
|
||||||
|
? sideIndex
|
||||||
|
: -(sideIndex - sideMiddle);
|
||||||
|
return { x: actorX + sizeX * distance, y: actorY + sizeY * distanceCoefficient };
|
||||||
|
} else {
|
||||||
|
const inbetweenIndex = nonZeroIndex - 2 * side - inbetween;
|
||||||
|
const distance =
|
||||||
|
inbetweenIndex === inbetweenMiddle
|
||||||
|
? 0
|
||||||
|
: inbetweenIndex < inbetweenMiddle
|
||||||
|
? inbetweenIndex
|
||||||
|
: -(inbetweenIndex - inbetweenMiddle);
|
||||||
|
return { x: actorX - sizeX * distanceCoefficient, y: actorY + sizeY * distance };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let token of newTokens) {
|
||||||
|
const position = positions.pop();
|
||||||
|
token.update(
|
||||||
|
{ x: position.x, y: position.y, alpha: 1 },
|
||||||
|
{ animation: { duration: animationDuration } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_getStatusEffectChoices() {
|
_getStatusEffectChoices() {
|
||||||
// Include all HUD-enabled status effects
|
// Include all HUD-enabled status effects
|
||||||
const choices = {};
|
const choices = {};
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ export { default as Adversary } from './adversary.mjs';
|
||||||
export { default as Character } from './character.mjs';
|
export { default as Character } from './character.mjs';
|
||||||
export { default as Companion } from './companion.mjs';
|
export { default as Companion } from './companion.mjs';
|
||||||
export { default as Environment } from './environment.mjs';
|
export { default as Environment } from './environment.mjs';
|
||||||
|
export { default as Party } from './party.mjs';
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
||||||
position: { width: 660, height: 766 },
|
position: { width: 660, height: 766 },
|
||||||
window: { resizable: true },
|
window: { resizable: true },
|
||||||
actions: {
|
actions: {
|
||||||
|
toggleHitPoints: AdversarySheet.#toggleHitPoints,
|
||||||
|
toggleStress: AdversarySheet.#toggleStress,
|
||||||
reactionRoll: AdversarySheet.#reactionRoll,
|
reactionRoll: AdversarySheet.#reactionRoll,
|
||||||
toggleResourceDice: AdversarySheet.#toggleResourceDice,
|
toggleResourceDice: AdversarySheet.#toggleResourceDice,
|
||||||
handleResourceDice: AdversarySheet.#handleResourceDice
|
handleResourceDice: AdversarySheet.#handleResourceDice
|
||||||
|
|
@ -75,6 +77,16 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
||||||
|
|
||||||
|
context.resources = Object.keys(this.document.system.resources).reduce((acc, key) => {
|
||||||
|
acc[key] = this.document.system.resources[key];
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
const maxResource = Math.max(context.resources.hitPoints.max, context.resources.stress.max);
|
||||||
|
context.resources.hitPoints.emptyPips =
|
||||||
|
context.resources.hitPoints.max < maxResource ? maxResource - context.resources.hitPoints.max : 0;
|
||||||
|
context.resources.stress.emptyPips =
|
||||||
|
context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +167,27 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles hitpoint resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleHitPoints(_, button) {
|
||||||
|
const hitPointsValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue =
|
||||||
|
this.document.system.resources.hitPoints.value >= hitPointsValue ? hitPointsValue - 1 : hitPointsValue;
|
||||||
|
await this.document.update({ 'system.resources.hitPoints.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles stress resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleStress(_, button) {
|
||||||
|
const StressValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue = this.document.system.resources.stress.value >= StressValue ? StressValue - 1 : StressValue;
|
||||||
|
await this.document.update({ 'system.resources.stress.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a reaction roll for an Adversary.
|
* Performs a reaction roll for an Adversary.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
actions: {
|
actions: {
|
||||||
toggleVault: CharacterSheet.#toggleVault,
|
toggleVault: CharacterSheet.#toggleVault,
|
||||||
rollAttribute: CharacterSheet.#rollAttribute,
|
rollAttribute: CharacterSheet.#rollAttribute,
|
||||||
|
toggleHitPoints: CharacterSheet.#toggleHitPoints,
|
||||||
|
toggleStress: CharacterSheet.#toggleStress,
|
||||||
|
toggleArmor: CharacterSheet.#toggleArmor,
|
||||||
toggleHope: CharacterSheet.#toggleHope,
|
toggleHope: CharacterSheet.#toggleHope,
|
||||||
toggleLoadoutView: CharacterSheet.#toggleLoadoutView,
|
toggleLoadoutView: CharacterSheet.#toggleLoadoutView,
|
||||||
openPack: CharacterSheet.#openPack,
|
openPack: CharacterSheet.#openPack,
|
||||||
|
|
@ -196,6 +199,16 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
context.resources = Object.keys(this.document.system.resources).reduce((acc, key) => {
|
||||||
|
acc[key] = this.document.system.resources[key];
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
const maxResource = Math.max(context.resources.hitPoints.max, context.resources.stress.max);
|
||||||
|
context.resources.hitPoints.emptyPips =
|
||||||
|
context.resources.hitPoints.max < maxResource ? maxResource - context.resources.hitPoints.max : 0;
|
||||||
|
context.resources.stress.emptyPips =
|
||||||
|
context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0;
|
||||||
|
|
||||||
context.inventory = {
|
context.inventory = {
|
||||||
currency: {
|
currency: {
|
||||||
title: game.i18n.localize('DAGGERHEART.CONFIG.Gold.title'),
|
title: game.i18n.localize('DAGGERHEART.CONFIG.Gold.title'),
|
||||||
|
|
@ -746,6 +759,37 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles hitpoint resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleHitPoints(_, button) {
|
||||||
|
const hitPointsValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue =
|
||||||
|
this.document.system.resources.hitPoints.value >= hitPointsValue ? hitPointsValue - 1 : hitPointsValue;
|
||||||
|
await this.document.update({ 'system.resources.hitPoints.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles stress resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleStress(_, button) {
|
||||||
|
const StressValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue = this.document.system.resources.stress.value >= StressValue ? StressValue - 1 : StressValue;
|
||||||
|
await this.document.update({ 'system.resources.stress.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles ArmorScore resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleArmor(_, button, element) {
|
||||||
|
const ArmorValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue = this.document.system.armor.system.marks.value >= ArmorValue ? ArmorValue - 1 : ArmorValue;
|
||||||
|
await this.document.system.armor.update({ 'system.marks.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles a hope resource value.
|
* Toggles a hope resource value.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
|
||||||
classes: ['actor', 'companion'],
|
classes: ['actor', 'companion'],
|
||||||
position: { width: 340 },
|
position: { width: 340 },
|
||||||
actions: {
|
actions: {
|
||||||
|
toggleStress: DhCompanionSheet.#toggleStress,
|
||||||
actionRoll: DhCompanionSheet.#actionRoll,
|
actionRoll: DhCompanionSheet.#actionRoll,
|
||||||
levelManagement: DhCompanionSheet.#levelManagement
|
levelManagement: DhCompanionSheet.#levelManagement
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +51,16 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles stress resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleStress(_, button) {
|
||||||
|
const StressValue = Number.parseInt(button.dataset.value);
|
||||||
|
const newValue = this.document.system.resources.stress.value >= StressValue ? StressValue - 1 : StressValue;
|
||||||
|
await this.document.update({ 'system.resources.stress.value': newValue });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,6 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the used state of a resource dice.
|
* Toggle the used state of a resource dice.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
@ -177,5 +176,4 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
||||||
}, {})
|
}, {})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
512
module/applications/sheets/actors/party.mjs
Normal file
512
module/applications/sheets/actors/party.mjs
Normal file
|
|
@ -0,0 +1,512 @@
|
||||||
|
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||||
|
import { getDocFromElement } from '../../../helpers/utils.mjs';
|
||||||
|
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';
|
||||||
|
import DhpActor from '../../../documents/actor.mjs';
|
||||||
|
import DHItem from '../../../documents/item.mjs';
|
||||||
|
|
||||||
|
export default class Party extends DHBaseActorSheet {
|
||||||
|
constructor(options) {
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
this.refreshSelections = DaggerheartMenu.defaultRefreshSelections();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ['party'],
|
||||||
|
position: {
|
||||||
|
width: 550
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
deletePartyMember: Party.#deletePartyMember,
|
||||||
|
deleteItem: Party.#deleteItem,
|
||||||
|
toggleHope: Party.#toggleHope,
|
||||||
|
toggleHitPoints: Party.#toggleHitPoints,
|
||||||
|
toggleStress: Party.#toggleStress,
|
||||||
|
toggleArmorSlot: Party.#toggleArmorSlot,
|
||||||
|
tempBrowser: Party.#tempBrowser,
|
||||||
|
refeshActions: Party.#refeshActions,
|
||||||
|
triggerRest: Party.#triggerRest,
|
||||||
|
tagTeamRoll: Party.#tagTeamRoll,
|
||||||
|
groupRoll: Party.#groupRoll,
|
||||||
|
selectRefreshable: DaggerheartMenu.selectRefreshable,
|
||||||
|
refreshActors: DaggerheartMenu.refreshActors
|
||||||
|
},
|
||||||
|
dragDrop: [{ dragSelector: '.actors-section .inventory-item', dropSelector: null }]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@override */
|
||||||
|
static PARTS = {
|
||||||
|
header: { template: 'systems/daggerheart/templates/sheets/actors/party/header.hbs' },
|
||||||
|
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||||
|
partyMembers: { template: 'systems/daggerheart/templates/sheets/actors/party/party-members.hbs' },
|
||||||
|
resources: {
|
||||||
|
template: 'systems/daggerheart/templates/sheets/actors/party/resources.hbs',
|
||||||
|
scrollable: ['']
|
||||||
|
},
|
||||||
|
/* NOT YET IMPLEMENTED */
|
||||||
|
// projects: {
|
||||||
|
// template: 'systems/daggerheart/templates/sheets/actors/party/projects.hbs',
|
||||||
|
// scrollable: ['']
|
||||||
|
// },
|
||||||
|
inventory: {
|
||||||
|
template: 'systems/daggerheart/templates/sheets/actors/party/inventory.hbs',
|
||||||
|
scrollable: ['.tab.inventory .items-section']
|
||||||
|
},
|
||||||
|
notes: { template: 'systems/daggerheart/templates/sheets/actors/party/notes.hbs' }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
static TABS = {
|
||||||
|
primary: {
|
||||||
|
tabs: [
|
||||||
|
{ id: 'partyMembers' },
|
||||||
|
{ id: 'resources' },
|
||||||
|
/* NOT YET IMPLEMENTED */
|
||||||
|
// { id: 'projects' },
|
||||||
|
{ id: 'inventory' },
|
||||||
|
{ id: 'notes' }
|
||||||
|
],
|
||||||
|
initial: 'partyMembers',
|
||||||
|
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async _onRender(context, options) {
|
||||||
|
await super._onRender(context, options);
|
||||||
|
this._createFilterMenus();
|
||||||
|
this._createSearchFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Prepare Context */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
|
||||||
|
context.inventory = {
|
||||||
|
currency: {
|
||||||
|
title: game.i18n.localize('DAGGERHEART.CONFIG.Gold.title'),
|
||||||
|
coins: game.i18n.localize('DAGGERHEART.CONFIG.Gold.coins'),
|
||||||
|
handfuls: game.i18n.localize('DAGGERHEART.CONFIG.Gold.handfuls'),
|
||||||
|
bags: game.i18n.localize('DAGGERHEART.CONFIG.Gold.bags'),
|
||||||
|
chests: game.i18n.localize('DAGGERHEART.CONFIG.Gold.chests')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const homebrewCurrency = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).currency;
|
||||||
|
if (homebrewCurrency.enabled) {
|
||||||
|
context.inventory.currency = homebrewCurrency;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.inventory.length === 0) {
|
||||||
|
context.inventory = Array(1).fill(Array(5).fill([]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _preparePartContext(partId, context, options) {
|
||||||
|
context = await super._preparePartContext(partId, context, options);
|
||||||
|
switch (partId) {
|
||||||
|
case 'header':
|
||||||
|
await this._prepareHeaderContext(context, options);
|
||||||
|
break;
|
||||||
|
case 'notes':
|
||||||
|
await this._prepareNotesContext(context, options);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare render context for the Header part.
|
||||||
|
* @param {ApplicationRenderContext} context
|
||||||
|
* @param {ApplicationRenderOptions} options
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _prepareHeaderContext(context, _options) {
|
||||||
|
const { system } = this.document;
|
||||||
|
const { TextEditor } = foundry.applications.ux;
|
||||||
|
|
||||||
|
context.description = await TextEditor.implementation.enrichHTML(system.description, {
|
||||||
|
secrets: this.document.isOwner,
|
||||||
|
relativeTo: this.document
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare render context for the Biography part.
|
||||||
|
* @param {ApplicationRenderContext} context
|
||||||
|
* @param {ApplicationRenderOptions} options
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _prepareNotesContext(context, _options) {
|
||||||
|
const { system } = this.document;
|
||||||
|
const { TextEditor } = foundry.applications.ux;
|
||||||
|
|
||||||
|
const paths = {
|
||||||
|
notes: 'notes'
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [key, path] of Object.entries(paths)) {
|
||||||
|
const value = foundry.utils.getProperty(system, path);
|
||||||
|
context[key] = {
|
||||||
|
field: system.schema.getField(path),
|
||||||
|
value,
|
||||||
|
enriched: await TextEditor.implementation.enrichHTML(value, {
|
||||||
|
secrets: this.document.isOwner,
|
||||||
|
relativeTo: this.document
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles a hope resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleHope(_, target) {
|
||||||
|
const hopeValue = Number.parseInt(target.dataset.value);
|
||||||
|
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||||
|
const newValue = actor.system.resources.hope.value >= hopeValue ? hopeValue - 1 : hopeValue;
|
||||||
|
await actor.update({ 'system.resources.hope.value': newValue });
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles a hp resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleHitPoints(_, target) {
|
||||||
|
const hitPointsValue = Number.parseInt(target.dataset.value);
|
||||||
|
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||||
|
const newValue = actor.system.resources.hitPoints.value >= hitPointsValue ? hitPointsValue - 1 : hitPointsValue;
|
||||||
|
await actor.update({ 'system.resources.hitPoints.value': newValue });
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles a stress resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleStress(_, target) {
|
||||||
|
const stressValue = Number.parseInt(target.dataset.value);
|
||||||
|
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||||
|
const newValue = actor.system.resources.stress.value >= stressValue ? stressValue - 1 : stressValue;
|
||||||
|
await actor.update({ 'system.resources.stress.value': newValue });
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles a armor slot resource value.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleArmorSlot(_, target, element) {
|
||||||
|
const armorItem = await foundry.utils.fromUuid(target.dataset.itemUuid);
|
||||||
|
const armorValue = Number.parseInt(target.dataset.value);
|
||||||
|
const newValue = armorItem.system.marks.value >= armorValue ? armorValue - 1 : armorValue;
|
||||||
|
await armorItem.update({ 'system.marks.value': newValue });
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens Compedium Browser
|
||||||
|
*/
|
||||||
|
static async #tempBrowser(_, target) {
|
||||||
|
new ItemBrowser().render({ force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #refeshActions() {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: 'New Section',
|
||||||
|
icon: 'fa-solid fa-campground'
|
||||||
|
},
|
||||||
|
content: await foundry.applications.handlebars.renderTemplate(
|
||||||
|
'systems/daggerheart/templates/sidebar/daggerheart-menu/main.hbs',
|
||||||
|
{
|
||||||
|
refreshables: DaggerheartMenu.defaultRefreshSelections()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
classes: ['daggerheart', 'dialog', 'dh-style', 'tab', 'sidebar-tab', 'daggerheartMenu-sidebar']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #triggerRest(_, button) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize(`DAGGERHEART.APPLICATIONS.Downtime.${button.dataset.type}.title`),
|
||||||
|
icon: button.dataset.type === 'shortRest' ? 'fa-solid fa-utensils' : 'fa-solid fa-bed'
|
||||||
|
},
|
||||||
|
content: 'This will trigger a dialog to players make their downtime moves, are you sure?',
|
||||||
|
classes: ['daggerheart', 'dialog', 'dh-style']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
this.document.system.partyMembers.forEach(actor => {
|
||||||
|
game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.DowntimeTrigger,
|
||||||
|
data: {
|
||||||
|
actorId: actor.uuid,
|
||||||
|
downtimeType: button.dataset.type
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async downtimeMoveQuery({ actorId, downtimeType }) {
|
||||||
|
const actor = await foundry.utils.fromUuid(actorId);
|
||||||
|
if (!actor || !actor?.isOwner) reject();
|
||||||
|
new game.system.api.applications.dialogs.Downtime(actor, downtimeType === 'shortRest').render({
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #tagTeamRoll() {
|
||||||
|
new game.system.api.applications.dialogs.TagTeamDialog(this.document.system.partyMembers).render({
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
* @this {CharacterSheet}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
static #getItemContextOptions() {
|
||||||
|
return this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true });
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Filter Tracking */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active search filter.
|
||||||
|
* @type {foundry.applications.ux.SearchFilter}
|
||||||
|
*/
|
||||||
|
#search = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active search filter.
|
||||||
|
* @type {FilterMenu}
|
||||||
|
*/
|
||||||
|
#menu = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks which item IDs are currently displayed, organized by filter type and section.
|
||||||
|
* @type {{
|
||||||
|
* inventory: {
|
||||||
|
* search: Set<string>,
|
||||||
|
* menu: Set<string>
|
||||||
|
* },
|
||||||
|
* loadout: {
|
||||||
|
* search: Set<string>,
|
||||||
|
* menu: Set<string>
|
||||||
|
* },
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
#filteredItems = {
|
||||||
|
inventory: {
|
||||||
|
search: new Set(),
|
||||||
|
menu: new Set()
|
||||||
|
},
|
||||||
|
loadout: {
|
||||||
|
search: new Set(),
|
||||||
|
menu: new Set()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Search Inputs */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and initialize search filter instances for the inventory and loadout sections.
|
||||||
|
*
|
||||||
|
* Sets up two {@link foundry.applications.ux.SearchFilter} instances:
|
||||||
|
* - One for the inventory, which filters items in the inventory grid.
|
||||||
|
* - One for the loadout, which filters items in the loadout/card grid.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createSearchFilter() {
|
||||||
|
//Filters could be a application option if needed
|
||||||
|
const filters = [
|
||||||
|
{
|
||||||
|
key: 'inventory',
|
||||||
|
input: 'input[type="search"].search-inventory',
|
||||||
|
content: '[data-application-part="inventory"] .items-section',
|
||||||
|
callback: this._onSearchFilterInventory.bind(this)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { key, input, content, callback } of filters) {
|
||||||
|
const filter = new foundry.applications.ux.SearchFilter({
|
||||||
|
inputSelector: input,
|
||||||
|
contentSelector: content,
|
||||||
|
callback
|
||||||
|
});
|
||||||
|
filter.bind(this.element);
|
||||||
|
this.#search[key] = filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle invetory items search and filtering.
|
||||||
|
* @param {KeyboardEvent} event The keyboard input event.
|
||||||
|
* @param {string} query The input search string.
|
||||||
|
* @param {RegExp} rgx The regular expression query that should be matched against.
|
||||||
|
* @param {HTMLElement} html The container to filter items from.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _onSearchFilterInventory(_event, query, rgx, html) {
|
||||||
|
this.#filteredItems.inventory.search.clear();
|
||||||
|
|
||||||
|
for (const li of html.querySelectorAll('.inventory-item')) {
|
||||||
|
const item = await getDocFromElement(li);
|
||||||
|
const matchesSearch = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name);
|
||||||
|
if (matchesSearch) this.#filteredItems.inventory.search.add(item.id);
|
||||||
|
const { menu } = this.#filteredItems.inventory;
|
||||||
|
li.hidden = !(menu.has(item.id) && matchesSearch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Filter Menus */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
_createFilterMenus() {
|
||||||
|
//Menus could be a application option if needed
|
||||||
|
const menus = [
|
||||||
|
{
|
||||||
|
key: 'inventory',
|
||||||
|
container: '[data-application-part="inventory"]',
|
||||||
|
content: '.items-section',
|
||||||
|
callback: this._onMenuFilterInventory.bind(this),
|
||||||
|
target: '.filter-button',
|
||||||
|
filters: FilterMenu.invetoryFilters
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
menus.forEach(m => {
|
||||||
|
const container = this.element.querySelector(m.container);
|
||||||
|
this.#menu[m.key] = new FilterMenu(container, m.target, m.filters, m.callback, {
|
||||||
|
contentSelector: m.content
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when filters change
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} html
|
||||||
|
* @param {import('../ux/filter-menu.mjs').FilterItem[]} filters
|
||||||
|
*/
|
||||||
|
async _onMenuFilterInventory(_event, html, filters) {
|
||||||
|
this.#filteredItems.inventory.menu.clear();
|
||||||
|
|
||||||
|
for (const li of html.querySelectorAll('.inventory-item')) {
|
||||||
|
const item = await getDocFromElement(li);
|
||||||
|
|
||||||
|
const matchesMenu =
|
||||||
|
filters.length === 0 || filters.some(f => foundry.applications.ux.SearchFilter.evaluateFilter(item, f));
|
||||||
|
if (matchesMenu) this.#filteredItems.inventory.menu.add(item.id);
|
||||||
|
|
||||||
|
const { search } = this.#filteredItems.inventory;
|
||||||
|
li.hidden = !(search.has(item.id) && matchesMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
async _onDragStart(event) {
|
||||||
|
const item = event.currentTarget.closest('.inventory-item');
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
const adversaryData = { type: 'Actor', uuid: item.dataset.itemUuid };
|
||||||
|
event.dataTransfer.setData('text/plain', JSON.stringify(adversaryData));
|
||||||
|
event.dataTransfer.setDragImage(item, 60, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onDrop(event) {
|
||||||
|
// Prevent event bubbling to avoid duplicate handling
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||||
|
const item = await foundry.utils.fromUuid(data.uuid);
|
||||||
|
|
||||||
|
if (item instanceof DhpActor) {
|
||||||
|
const currentMembers = this.document.system.partyMembers.map(x => x.uuid);
|
||||||
|
if (currentMembers.includes(data.uuid)) {
|
||||||
|
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.duplicateCharacter'));
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.document.update({ 'system.partyMembers': [...currentMembers, item.uuid] });
|
||||||
|
} else if (item instanceof DHItem) {
|
||||||
|
this.document.createEmbeddedDocuments('Item', [item.toObject()]);
|
||||||
|
} else {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.onlyCharactersInPartySheet'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #deletePartyMember(event, target) {
|
||||||
|
const doc = await getDocFromElement(target.closest('.inventory-item'));
|
||||||
|
|
||||||
|
if (!event.shiftKey) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||||
|
type: game.i18n.localize('TYPES.Actor.adversary'),
|
||||||
|
name: doc.name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: doc.name })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentMembers = this.document.system.partyMembers.map(x => x.uuid);
|
||||||
|
const newMemberdList = currentMembers.filter(uuid => uuid !== doc.uuid);
|
||||||
|
await this.document.update({ 'system.partyMembers': newMemberdList });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #deleteItem(event, target) {
|
||||||
|
const doc = await getDocFromElement(target.closest('.inventory-item'));
|
||||||
|
if (!event.shiftKey) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||||
|
type: game.i18n.localize('TYPES.Actor.party'),
|
||||||
|
name: doc.name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: doc.name })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.document.deleteEmbeddedDocuments('Item', [doc.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -61,6 +61,10 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.isNPC = this.document.isNPC;
|
context.isNPC = this.document.isNPC;
|
||||||
|
context.useResourcePips = game.settings.get(
|
||||||
|
CONFIG.DH.id,
|
||||||
|
CONFIG.DH.SETTINGS.gameSettings.appearance
|
||||||
|
).useResourcePips;
|
||||||
context.showAttribution = !game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
context.showAttribution = !game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||||
.hideAttribution;
|
.hideAttribution;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
||||||
this.refreshSelections = DaggerheartMenu.#defaultRefreshSelections();
|
this.refreshSelections = DaggerheartMenu.defaultRefreshSelections();
|
||||||
}
|
}
|
||||||
|
|
||||||
static #defaultRefreshSelections() {
|
static defaultRefreshSelections() {
|
||||||
return {
|
return {
|
||||||
session: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.session') },
|
session: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.session') },
|
||||||
scene: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.scene') },
|
scene: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.scene') },
|
||||||
|
|
@ -138,7 +138,7 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract
|
||||||
types: `[${types}]`
|
types: `[${types}]`
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.refreshSelections = DaggerheartMenu.#defaultRefreshSelections();
|
this.refreshSelections = DaggerheartMenu.defaultRefreshSelections();
|
||||||
|
|
||||||
const cls = getDocumentClass('ChatMessage');
|
const cls = getDocumentClass('ChatMessage');
|
||||||
const msg = {
|
const msg = {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
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 {
|
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
@ -35,7 +38,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: 'Reroll Damage',
|
name: game.i18n.localize('DAGGERHEART.UI.ChatLog.rerollDamage'),
|
||||||
icon: '<i class="fa-solid fa-dice"></i>',
|
icon: '<i class="fa-solid fa-dice"></i>',
|
||||||
condition: li => {
|
condition: li => {
|
||||||
const message = game.messages.get(li.dataset.messageId);
|
const message = game.messages.get(li.dataset.messageId);
|
||||||
|
|
@ -65,6 +68,18 @@ 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, data.message))
|
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() {
|
setupHooks() {
|
||||||
|
|
@ -164,6 +179,169 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
'system.roll': newRoll,
|
'system.roll': newRoll,
|
||||||
'rolls': [parsedRoll]
|
'rolls': [parsedRoll]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,16 +93,17 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
if (lite === true) {
|
if (lite === true) {
|
||||||
this.compendiumBrowserTypeKey = 'compendiumBrowserLite';
|
this.compendiumBrowserTypeKey = 'compendiumBrowserLite';
|
||||||
}
|
}
|
||||||
const userPresetPosition = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.compendiumBrowserTypeKey}`].position) ;
|
const userPresetPosition = game.user.getFlag(
|
||||||
|
CONFIG.DH.id,
|
||||||
|
CONFIG.DH.FLAGS[`${this.compendiumBrowserTypeKey}`].position
|
||||||
|
);
|
||||||
|
|
||||||
options.position = userPresetPosition ?? ItemBrowser.DEFAULT_OPTIONS.position;
|
options.position = userPresetPosition ?? ItemBrowser.DEFAULT_OPTIONS.position;
|
||||||
|
|
||||||
if (!userPresetPosition) {
|
if (!userPresetPosition) {
|
||||||
const width = noFolder === true || lite === true ? 600 : 850;
|
const width = noFolder === true || lite === true ? 600 : 850;
|
||||||
if (this.rendered)
|
if (this.rendered) this.setPosition({ width });
|
||||||
this.setPosition({ width });
|
else options.position.width = width;
|
||||||
else
|
|
||||||
options.position.width = width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await super._preRender(context, options);
|
await super._preRender(context, options);
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ export const defeatedConditions = () => {
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const defeatedConditionChoices = {
|
export const defeatedConditionChoices = {
|
||||||
defeated: {
|
defeated: {
|
||||||
id: 'defeated',
|
id: 'defeated',
|
||||||
name: 'DAGGERHEART.CONFIG.Condition.defeated.name'
|
name: 'DAGGERHEART.CONFIG.Condition.defeated.name'
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ export const gameSettings = {
|
||||||
},
|
},
|
||||||
LevelTiers: 'LevelTiers',
|
LevelTiers: 'LevelTiers',
|
||||||
Countdowns: 'Countdowns',
|
Countdowns: 'Countdowns',
|
||||||
LastMigrationVersion: 'LastMigrationVersion'
|
LastMigrationVersion: 'LastMigrationVersion',
|
||||||
|
TagTeamRoll: 'TagTeamRoll'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actionAutomationChoices = {
|
export const actionAutomationChoices = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
export { default as DhCombat } from './combat.mjs';
|
export { default as DhCombat } from './combat.mjs';
|
||||||
export { default as DhCombatant } from './combatant.mjs';
|
export { default as DhCombatant } from './combatant.mjs';
|
||||||
|
export { default as DhTagTeamRoll } from './tagTeamRoll.mjs';
|
||||||
|
|
||||||
export * as actions from './action/_module.mjs';
|
export * as actions from './action/_module.mjs';
|
||||||
export * as activeEffects from './activeEffect/_module.mjs';
|
export * as activeEffects from './activeEffect/_module.mjs';
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ import DhCharacter from './character.mjs';
|
||||||
import DhCompanion from './companion.mjs';
|
import DhCompanion from './companion.mjs';
|
||||||
import DhAdversary from './adversary.mjs';
|
import DhAdversary from './adversary.mjs';
|
||||||
import DhEnvironment from './environment.mjs';
|
import DhEnvironment from './environment.mjs';
|
||||||
|
import DhParty from './party.mjs';
|
||||||
|
|
||||||
export { DhCharacter, DhCompanion, DhAdversary, DhEnvironment };
|
export { DhCharacter, DhCompanion, DhAdversary, DhEnvironment, DhParty };
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
character: DhCharacter,
|
character: DhCharacter,
|
||||||
companion: DhCompanion,
|
companion: DhCompanion,
|
||||||
adversary: DhAdversary,
|
adversary: DhAdversary,
|
||||||
environment: DhEnvironment
|
environment: DhEnvironment,
|
||||||
|
party: DhParty
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -170,4 +170,13 @@ export default class DhpAdversary extends BaseDataActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getTags() {
|
||||||
|
const tags = [
|
||||||
|
game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${this.tier}`),
|
||||||
|
`${game.i18n.localize(`DAGGERHEART.CONFIG.AdversaryType.${this.type}.label`)}`,
|
||||||
|
`${game.i18n.localize('DAGGERHEART.GENERAL.difficulty')}: ${this.difficulty}`
|
||||||
|
];
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -673,4 +673,8 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
this.companion.updateLevel(1);
|
this.companion.updateLevel(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getTags() {
|
||||||
|
return [this.class.value?.name, this.class.subclass?.name, this.community?.name, this.ancestry?.name].filter((t) => !!t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
module/data/actor/party.mjs
Normal file
48
module/data/actor/party.mjs
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import BaseDataActor from './base.mjs';
|
||||||
|
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
||||||
|
|
||||||
|
export default class DhParty extends BaseDataActor {
|
||||||
|
/**@inheritdoc */
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
...super.defineSchema(),
|
||||||
|
partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }),
|
||||||
|
notes: new fields.HTMLField(),
|
||||||
|
gold: new fields.SchemaField({
|
||||||
|
coins: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
|
handfuls: new fields.NumberField({ initial: 1, integer: true }),
|
||||||
|
bags: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
|
chests: new fields.NumberField({ initial: 0, integer: true })
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
static DEFAULT_ICON = 'systems/daggerheart/assets/icons/documents/actors/dark-squad.svg';
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
prepareBaseData() {
|
||||||
|
super.prepareBaseData();
|
||||||
|
this.partyMembers = this.partyMembers.filter(p => !!p);
|
||||||
|
|
||||||
|
// Register this party to all members
|
||||||
|
if (game.actors.get(this.parent.id) === this.parent) {
|
||||||
|
for (const member of this.partyMembers) {
|
||||||
|
member.parties?.add(this.parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDelete(options, userId) {
|
||||||
|
super._onDelete(options, userId);
|
||||||
|
|
||||||
|
// Clear this party from all members that aren't deleted
|
||||||
|
for (const member of this.partyMembers) {
|
||||||
|
member.parties?.delete(this.parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
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 = {
|
||||||
|
|
@ -7,5 +8,6 @@ export const config = {
|
||||||
adversaryRoll: DHActorRoll,
|
adversaryRoll: DHActorRoll,
|
||||||
damageRoll: DHActorRoll,
|
damageRoll: DHActorRoll,
|
||||||
dualityRoll: DHActorRoll,
|
dualityRoll: DHActorRoll,
|
||||||
|
groupRoll: DHGroupRoll,
|
||||||
systemMessage: DHSystemMessage
|
systemMessage: DHSystemMessage
|
||||||
};
|
};
|
||||||
|
|
|
||||||
39
module/data/chat-message/groupRoll.mjs
Normal file
39
module/data/chat-message/groupRoll.mjs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -131,6 +131,12 @@ export default class DHArmor extends AttachableItem {
|
||||||
|
|
||||||
_onUpdate(a, b, c) {
|
_onUpdate(a, b, c) {
|
||||||
super._onUpdate(a, b, c);
|
super._onUpdate(a, b, c);
|
||||||
|
|
||||||
|
if (this.actor?.type === 'character') {
|
||||||
|
for (const party of this.actor.parties) {
|
||||||
|
party.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
useResourcePips: new BooleanField({ initial: false }),
|
||||||
displayFear: new StringField({
|
displayFear: new StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.fearDisplay,
|
choices: CONFIG.DH.GENERAL.fearDisplay,
|
||||||
|
|
|
||||||
|
|
@ -69,19 +69,19 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
||||||
characterDefault: new fields.StringField({
|
characterDefault: new fields.StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
||||||
initial: 'unconscious',
|
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.unconscious.id,
|
||||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
|
||||||
}),
|
}),
|
||||||
adversaryDefault: new fields.StringField({
|
adversaryDefault: new fields.StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
||||||
initial: 'defeated',
|
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.dead.id,
|
||||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.adversaryDefault.label'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.adversaryDefault.label'
|
||||||
}),
|
}),
|
||||||
companionDefault: new fields.StringField({
|
companionDefault: new fields.StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
||||||
initial: 'defeated',
|
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.defeated.id,
|
||||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
|
||||||
}),
|
}),
|
||||||
deadIcon: new fields.FilePathField({
|
deadIcon: new fields.FilePathField({
|
||||||
|
|
|
||||||
20
module/data/tagTeamRoll.mjs
Normal file
20
module/data/tagTeamRoll.mjs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { DhCharacter } from './actor/_module.mjs';
|
||||||
|
|
||||||
|
export default class DhTagTeamRoll extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
return {
|
||||||
|
initiator: new fields.SchemaField({
|
||||||
|
id: new fields.StringField({ nullable: true, initial: null }),
|
||||||
|
cost: new fields.NumberField({ integer: true, min: 0, initial: 3 })
|
||||||
|
}),
|
||||||
|
members: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
messageId: new fields.StringField({ required: true, nullable: true, initial: null }),
|
||||||
|
selected: new fields.BooleanField({ required: true, initial: false })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import DamageDialog from '../applications/dialogs/damageDialog.mjs';
|
import DamageDialog from '../applications/dialogs/damageDialog.mjs';
|
||||||
|
import { RefreshType, socketEvent } from '../systemRegistration/socket.mjs';
|
||||||
import DHRoll from './dhRoll.mjs';
|
import DHRoll from './dhRoll.mjs';
|
||||||
|
|
||||||
export default class DamageRoll extends DHRoll {
|
export default class DamageRoll extends DHRoll {
|
||||||
|
|
@ -338,5 +339,13 @@ export default class DamageRoll extends DHRoll {
|
||||||
parts: damageParts
|
parts: damageParts
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ export default class DHRoll extends Roll {
|
||||||
config.hooks = [...this.getHooks(), ''];
|
config.hooks = [...this.getHooks(), ''];
|
||||||
config.dialog ??= {};
|
config.dialog ??= {};
|
||||||
|
|
||||||
|
const actorIdSplit = config.source.actor.split('.');
|
||||||
|
const tagTeamSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
config.tagTeamSelected = tagTeamSettings.members[actorIdSplit[actorIdSplit.length - 1]];
|
||||||
|
|
||||||
for (const hook of config.hooks) {
|
for (const hook of config.hooks) {
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null;
|
if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null;
|
||||||
}
|
}
|
||||||
|
|
@ -66,8 +70,13 @@ export default class DHRoll extends Roll {
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.postRoll${hook.capitalize()}`, config, message) === false) return null;
|
if (Hooks.call(`${CONFIG.DH.id}.postRoll${hook.capitalize()}`, config, message) === false) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Chat Message
|
if (config.skips?.createMessage) {
|
||||||
if (!config.source?.message) config.message = await this.toMessage(roll, config);
|
if (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 = {}) {
|
static postEvaluate(roll, config = {}) {
|
||||||
|
|
@ -100,6 +109,10 @@ export default class DHRoll extends Roll {
|
||||||
if (roll._evaluated) {
|
if (roll._evaluated) {
|
||||||
const message = await cls.create(msgData, { rollMode: config.selectedRollMode });
|
const message = await cls.create(msgData, { rollMode: config.selectedRollMode });
|
||||||
|
|
||||||
|
if (config.tagTeamSelected) {
|
||||||
|
game.system.api.applications.dialogs.TagTeamDialog.assignRoll(message.speakerActor, message);
|
||||||
|
}
|
||||||
|
|
||||||
if (game.modules.get('dice-so-nice')?.active) {
|
if (game.modules.get('dice-so-nice')?.active) {
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(message.id);
|
await game.dice3d.waitFor3DAnimationByMessageID(message.id);
|
||||||
}
|
}
|
||||||
|
|
@ -228,10 +241,11 @@ export const registerRollDiceHooks = () => {
|
||||||
if (
|
if (
|
||||||
!config.source?.actor ||
|
!config.source?.actor ||
|
||||||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
|
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
|
||||||
config.actionType === 'reaction'
|
config.actionType === 'reaction' ||
|
||||||
|
config.tagTeamSelected ||
|
||||||
|
config.skips?.resources
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const actor = await fromUuid(config.source.actor);
|
const actor = await fromUuid(config.source.actor);
|
||||||
let updates = [];
|
let updates = [];
|
||||||
if (!actor) return;
|
if (!actor) return;
|
||||||
|
|
|
||||||
|
|
@ -256,9 +256,11 @@ export default class DualityRoll extends D20Roll {
|
||||||
});
|
});
|
||||||
newRoll.extra = newRoll.extra.slice(2);
|
newRoll.extra = newRoll.extra.slice(2);
|
||||||
|
|
||||||
|
const tagTeamSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
Hooks.call(`${CONFIG.DH.id}.postRollDuality`, {
|
Hooks.call(`${CONFIG.DH.id}.postRollDuality`, {
|
||||||
source: { actor: message.system.source.actor ?? '' },
|
source: { actor: message.system.source.actor ?? '' },
|
||||||
targets: message.system.targets,
|
targets: message.system.targets,
|
||||||
|
tagTeamSelected: Object.values(tagTeamSettings.members).some(x => x.messageId === message._id),
|
||||||
roll: newRoll,
|
roll: newRoll,
|
||||||
rerolledRoll:
|
rerolledRoll:
|
||||||
newRoll.result.duality !== message.system.roll.result.duality ? message.system.roll : undefined
|
newRoll.result.duality !== message.system.roll.result.duality ? message.system.roll : undefined
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import { createScrollText, damageKeyToNumber } from '../helpers/utils.mjs';
|
||||||
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
||||||
|
|
||||||
export default class DhpActor extends Actor {
|
export default class DhpActor extends Actor {
|
||||||
|
parties = new Set();
|
||||||
|
|
||||||
#scrollTextQueue = [];
|
#scrollTextQueue = [];
|
||||||
#scrollTextInterval;
|
#scrollTextInterval;
|
||||||
|
|
||||||
|
|
@ -74,7 +76,7 @@ export default class DhpActor extends Actor {
|
||||||
|
|
||||||
// Configure prototype token settings
|
// Configure prototype token settings
|
||||||
const prototypeToken = {};
|
const prototypeToken = {};
|
||||||
if (['character', 'companion'].includes(this.type))
|
if (['character', 'companion', 'party'].includes(this.type))
|
||||||
Object.assign(prototypeToken, {
|
Object.assign(prototypeToken, {
|
||||||
sight: { enabled: true },
|
sight: { enabled: true },
|
||||||
actorLink: true,
|
actorLink: true,
|
||||||
|
|
@ -83,6 +85,20 @@ export default class DhpActor extends Actor {
|
||||||
this.updateSource({ prototypeToken });
|
this.updateSource({ prototypeToken });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onUpdate(changes, options, userId) {
|
||||||
|
super._onUpdate(changes, options, userId);
|
||||||
|
for (const party of this.parties) {
|
||||||
|
party.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDelete(options, userId) {
|
||||||
|
super._onDelete(options, userId);
|
||||||
|
for (const party of this.parties) {
|
||||||
|
party.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async updateLevel(newLevel) {
|
async updateLevel(newLevel) {
|
||||||
if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return;
|
if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return;
|
||||||
|
|
||||||
|
|
@ -808,4 +824,14 @@ export default class DhpActor extends Actor {
|
||||||
|
|
||||||
return await super.importFromJSON(json);
|
return await super.importFromJSON(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an array of localized tag.
|
||||||
|
* @returns {string[]} An array of localized tag strings.
|
||||||
|
*/
|
||||||
|
_getTags() {
|
||||||
|
const tags = [];
|
||||||
|
if (this.system._getTags) tags.push(...this.system._getTags());
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../systemRegistration/socket.mjs';
|
||||||
|
|
||||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
targetHook = null;
|
targetHook = null;
|
||||||
|
|
@ -16,7 +16,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
const html = await super.renderHTML({ actor: actorData, author: this.author });
|
const html = await super.renderHTML({ actor: actorData, author: this.author });
|
||||||
|
|
||||||
if (this.flags.core?.RollTable) {
|
if (this.flags.core?.RollTable) {
|
||||||
html.querySelector('.roll-buttons.apply-buttons').remove();
|
html.querySelector('.roll-buttons.apply-buttons')?.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enrichChatMessage(html);
|
this.enrichChatMessage(html);
|
||||||
|
|
@ -155,7 +155,15 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const config = foundry.utils.deepClone(this.system);
|
const config = foundry.utils.deepClone(this.system);
|
||||||
config.event = event;
|
config.event = event;
|
||||||
this.system.action?.workflow.get('damage')?.execute(config, this._id, true);
|
await this.system.action?.workflow.get('damage')?.execute(config, this._id, true);
|
||||||
|
|
||||||
|
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll });
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.TagTeamRoll
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onApplyDamage(event) {
|
async onApplyDamage(event) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { parseInlineParams } from './parser.mjs';
|
import { parseInlineParams } from './parser.mjs';
|
||||||
|
|
||||||
export default function DhLookupEnricher(match, { rollData }) {
|
export default function DhLookupEnricher(match, { rollData }) {
|
||||||
const results = parseInlineParams(match[1], { first: 'formula'});
|
const results = parseInlineParams(match[1], { first: 'formula' });
|
||||||
const element = document.createElement('span');
|
const element = document.createElement('span');
|
||||||
element.textContent = Roll.replaceFormulaData(String(results.formula), rollData);
|
element.textContent = Roll.replaceFormulaData(String(results.formula), rollData);
|
||||||
return element;
|
return element;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* @param {string} paramString The parameter inside the brackets of something like @Template[] to parse
|
* @param {string} paramString The parameter inside the brackets of something like @Template[] to parse
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {string} options.first If set, the first parameter is treated as a value with this as its key
|
* @param {string} options.first If set, the first parameter is treated as a value with this as its key
|
||||||
* @returns {Record<string, string | undefined> | null}
|
* @returns {Record<string, string | undefined> | null}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ export default class RegisterHandlebarsHelpers {
|
||||||
setVar: this.setVar,
|
setVar: this.setVar,
|
||||||
empty: this.empty,
|
empty: this.empty,
|
||||||
pluralize: this.pluralize,
|
pluralize: this.pluralize,
|
||||||
positive: this.positive
|
positive: this.positive,
|
||||||
|
isNullish: this.isNullish
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static add(a, b) {
|
static add(a, b) {
|
||||||
|
|
@ -94,4 +95,8 @@ export default class RegisterHandlebarsHelpers {
|
||||||
static positive(a) {
|
static positive(a) {
|
||||||
return Math.abs(Number(a));
|
return Math.abs(Number(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isNullish(a) {
|
||||||
|
return a === null || a === undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -418,3 +418,15 @@ export async function createEmbeddedItemsWithEffects(actor, baseData) {
|
||||||
export const slugify = name => {
|
export const slugify = name => {
|
||||||
return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', '');
|
return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function shuffleArray(array) {
|
||||||
|
let currentIndex = array.length;
|
||||||
|
while (currentIndex != 0) {
|
||||||
|
let randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
|
||||||
|
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'systems/daggerheart/templates/sheets/global/partials/domain-card-item.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/domain-card-item.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/item-resource.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/item-resource.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/resource-section.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/resource-section.hbs',
|
||||||
|
'systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs',
|
||||||
'systems/daggerheart/templates/components/card-preview.hbs',
|
'systems/daggerheart/templates/components/card-preview.hbs',
|
||||||
'systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs',
|
'systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
DhHomebrewSettings,
|
DhHomebrewSettings,
|
||||||
DhVariantRuleSettings
|
DhVariantRuleSettings
|
||||||
} from '../applications/settings/_module.mjs';
|
} from '../applications/settings/_module.mjs';
|
||||||
|
import { DhTagTeamRoll } from '../data/_module.mjs';
|
||||||
|
|
||||||
export const registerDHSettings = () => {
|
export const registerDHSettings = () => {
|
||||||
registerMenuSettings();
|
registerMenuSettings();
|
||||||
|
|
@ -122,4 +123,10 @@ const registerNonConfigSettings = () => {
|
||||||
config: false,
|
config: false,
|
||||||
type: DhCountdowns
|
type: DhCountdowns
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, {
|
||||||
|
scope: 'world',
|
||||||
|
config: false,
|
||||||
|
type: DhTagTeamRoll
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import DamageReductionDialog from '../applications/dialogs/damageReductionDialog.mjs';
|
import DamageReductionDialog from '../applications/dialogs/damageReductionDialog.mjs';
|
||||||
|
import Party from '../applications/sheets/actors/party.mjs';
|
||||||
|
|
||||||
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
|
@ -11,13 +12,17 @@ export function handleSocketEvent({ action = null, data = {} } = {}) {
|
||||||
case socketEvent.Refresh:
|
case socketEvent.Refresh:
|
||||||
Hooks.call(socketEvent.Refresh, data);
|
Hooks.call(socketEvent.Refresh, data);
|
||||||
break;
|
break;
|
||||||
|
case socketEvent.DowntimeTrigger:
|
||||||
|
Party.downtimeMoveQuery(data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketEvent = {
|
export const socketEvent = {
|
||||||
GMUpdate: 'DhGMUpdate',
|
GMUpdate: 'DhGMUpdate',
|
||||||
Refresh: 'DhRefresh',
|
Refresh: 'DhRefresh',
|
||||||
DhpFearUpdate: 'DhFearUpdate'
|
DhpFearUpdate: 'DhFearUpdate',
|
||||||
|
DowntimeTrigger: 'DowntimeTrigger'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GMUpdateEvent = {
|
export const GMUpdateEvent = {
|
||||||
|
|
@ -30,7 +35,8 @@ export const GMUpdateEvent = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RefreshType = {
|
export const RefreshType = {
|
||||||
Countdown: 'DhCoundownRefresh'
|
Countdown: 'DhCoundownRefresh',
|
||||||
|
TagTeamRoll: 'DhTagTeamRollRefresh'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registerSocketHooks = () => {
|
export const registerSocketHooks = () => {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,14 @@
|
||||||
.application.daggerheart.dialog.dh-style.views.roll-selection {
|
.application.daggerheart.dialog.dh-style.views.roll-selection {
|
||||||
.dialog-header {
|
.dialog-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.dialog-header-inner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
@ -37,6 +44,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-team-controller {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: fit-content;
|
||||||
|
gap: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background: light-dark(@dark-blue-40, @golden-40);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.roll-dialog-container {
|
.roll-dialog-container {
|
||||||
|
|
|
||||||
50
styles/less/dialog/group-roll/group-roll.less
Normal file
50
styles/less/dialog/group-roll/group-roll.less
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tooltip-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,4 +31,7 @@
|
||||||
|
|
||||||
@import './reroll-dialog/sheet.less';
|
@import './reroll-dialog/sheet.less';
|
||||||
|
|
||||||
|
@import './group-roll/group-roll.less';
|
||||||
|
@import './tag-team-dialog/sheet.less';
|
||||||
|
|
||||||
@import './image-select/sheet.less';
|
@import './image-select/sheet.less';
|
||||||
|
|
|
||||||
178
styles/less/dialog/tag-team-dialog/sheet.less
Normal file
178
styles/less/dialog/tag-team-dialog/sheet.less
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
.daggerheart.dialog.dh-style.views.tag-team-dialog {
|
||||||
|
.tag-team-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.tag-team-data-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
flex: 0;
|
||||||
|
|
||||||
|
label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flex-group {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.participants-container {
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.participant-outer-container {
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&.selected,
|
||||||
|
&:hover {
|
||||||
|
background-color: light-dark(@golden-40, @golden-40);
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.participant-inner-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 48px;
|
||||||
|
width: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-labels {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
.participant-label-title {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-label-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.participant-label-info-part {
|
||||||
|
border: 1px solid light-dark(white, white);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
background-color: light-dark(@beige-80, @soft-white-shadow);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-empty-roll-container {
|
||||||
|
border: 1px dashed white;
|
||||||
|
padding: 8px 2px;
|
||||||
|
text-align: center;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-roll-outer-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
text-align: center;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-roll-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.participant-roll-text-container {
|
||||||
|
padding: 0 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.damage-values-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.damage-container {
|
||||||
|
border: 1px solid light-dark(white, white);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px;
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.result-damages-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.result-damage-container {
|
||||||
|
border: 1px solid light-dark(white, white);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-leader-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,4 @@
|
||||||
@import './filter-menu.less';
|
@import './filter-menu.less';
|
||||||
@import './tab-attachments.less';
|
@import './tab-attachments.less';
|
||||||
@import './dice.less';
|
@import './dice.less';
|
||||||
|
@import './resource-bar.less';
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
flex: 0 0 40px;
|
flex: 0 0 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
position: relative;
|
position: relative;
|
||||||
&:has(.roll-img) {
|
&:has(.roll-img) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,6 +87,7 @@
|
||||||
|
|
||||||
&.actor-img {
|
&.actor-img {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
object-position: top center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +123,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
|
&.padded {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.item-label {
|
.item-label {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
|
@ -248,9 +253,9 @@
|
||||||
|
|
||||||
&.inventory-item-compact {
|
&.inventory-item-compact {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template:
|
grid-template:
|
||||||
"img name controls" auto
|
'img name controls' auto
|
||||||
"img labels labels" 1fr
|
'img labels labels' 1fr
|
||||||
/ 40px 1fr min-content;
|
/ 40px 1fr min-content;
|
||||||
column-gap: 8px;
|
column-gap: 8px;
|
||||||
|
|
||||||
|
|
|
||||||
178
styles/less/global/resource-bar.less
Normal file
178
styles/less/global/resource-bar.less
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
// Theme sidebar backgrounds
|
||||||
|
.appTheme({
|
||||||
|
.slot-value .slot-bar {
|
||||||
|
background: @dark-blue;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
.slot-value .slot-bar {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
width: 120px;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
position: relative;
|
||||||
|
top: 40px;
|
||||||
|
height: 22px;
|
||||||
|
width: 79px;
|
||||||
|
clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z');
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 18px;
|
||||||
|
color: light-dark(@beige, @dark-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slot-value {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
width: 140px;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 2;
|
||||||
|
color: @beige;
|
||||||
|
|
||||||
|
.slot-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
z-index: 1;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.slot {
|
||||||
|
width: 15px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.filled {
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-slot {
|
||||||
|
width: 15px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slot-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: light-dark(@beige, @dark-blue);
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 0 5px;
|
||||||
|
width: fit-content;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 0px 0px 5px 5px;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
padding-left: 6px;
|
||||||
|
border-left: 1px solid light-dark(@beige, @dark-golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
width: 140px;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 2;
|
||||||
|
color: @beige;
|
||||||
|
|
||||||
|
input[type='number'] {
|
||||||
|
background: transparent;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 40px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
border: none;
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
color: @beige;
|
||||||
|
|
||||||
|
&.bar-input {
|
||||||
|
padding: 0;
|
||||||
|
color: @beige;
|
||||||
|
backdrop-filter: none;
|
||||||
|
background: transparent;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: @semi-transparent-dark-blue;
|
||||||
|
backdrop-filter: blur(9.5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-label {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.progress-bar {
|
||||||
|
position: absolute;
|
||||||
|
appearance: none;
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
z-index: 1;
|
||||||
|
background: @dark-blue;
|
||||||
|
|
||||||
|
&::-webkit-progress-bar {
|
||||||
|
border: none;
|
||||||
|
background: @dark-blue;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
&::-webkit-progress-value {
|
||||||
|
background: @gradient-hp;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
&.stress-color::-webkit-progress-value {
|
||||||
|
background: @gradient-stress;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
&::-moz-progress-bar {
|
||||||
|
background: @gradient-hp;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
&.stress-color::-moz-progress-bar {
|
||||||
|
background: @gradient-stress;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,11 @@ body.game:is(.performance-low, .noblur) {
|
||||||
.themed.theme-dark .application.daggerheart.sheet.dh-style,
|
.themed.theme-dark .application.daggerheart.sheet.dh-style,
|
||||||
.themed.theme-dark.application.daggerheart.sheet.dh-style,
|
.themed.theme-dark.application.daggerheart.sheet.dh-style,
|
||||||
&.theme-dark .application.daggerheart {
|
&.theme-dark .application.daggerheart {
|
||||||
background: @dark-blue;
|
&.adversary,
|
||||||
|
&.character,
|
||||||
|
&.item {
|
||||||
|
background: @dark-blue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
@import '../utils/colors.less';
|
@import '../utils/colors.less';
|
||||||
@import '../utils/fonts.less';
|
@import '../utils/fonts.less';
|
||||||
|
|
||||||
.daggerheart.dh-style {
|
.daggerheart.dh-style {
|
||||||
.tab.active.description {
|
.tab.active.description {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: -webkit-fill-available !important;
|
height: -webkit-fill-available !important;
|
||||||
overflow-y: hidden !important;
|
overflow-y: hidden !important;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
|
||||||
prose-mirror.active + .artist-attribution {
|
prose-mirror.active + .artist-attribution {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,13 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clown-car img {
|
||||||
|
transition: 0.5s;
|
||||||
|
|
||||||
|
&.flipped {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,14 @@
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-bottom: -10px;
|
margin-bottom: -10px;
|
||||||
|
|
||||||
|
&.pip-display {
|
||||||
|
top: -15px;
|
||||||
|
|
||||||
|
.resources-section {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.resources-section {
|
.resources-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,16 @@
|
||||||
.appTheme({
|
.appTheme({
|
||||||
.character-sidebar-sheet {
|
.character-sidebar-sheet {
|
||||||
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
|
||||||
.experience-value {
|
.experience-value {
|
||||||
background: url(../assets/svg/experience-shield.svg) no-repeat;
|
background: url(../assets/svg/experience-shield.svg) no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-section .status-section .status-bar.armor-slots {
|
||||||
|
.slot-value .slot-bar {
|
||||||
|
background: @dark-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
&.sheet.actor.dh-style.character .character-sidebar-sheet {
|
&.sheet.actor.dh-style.character .character-sidebar-sheet {
|
||||||
|
|
@ -21,6 +28,12 @@
|
||||||
.portrait.death-roll .death-roll-btn {
|
.portrait.death-roll .death-roll-btn {
|
||||||
filter: brightness(0) drop-shadow(0 0 3px @dark-blue);
|
filter: brightness(0) drop-shadow(0 0 3px @dark-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-section .status-section .status-bar.armor-slots {
|
||||||
|
.slot-value .slot-bar {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -127,6 +140,15 @@
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-bottom: -16px;
|
margin-bottom: -16px;
|
||||||
|
|
||||||
|
&.pip-display {
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
.resources-section {
|
||||||
|
justify-content: space-around;
|
||||||
|
margin: 8px 2px 8px 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.resources-section {
|
.resources-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|
@ -136,7 +158,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100px;
|
width: 120px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
||||||
.status-label {
|
.status-label {
|
||||||
|
|
@ -154,13 +176,14 @@
|
||||||
color: light-dark(@beige, @dark-blue);
|
color: light-dark(@beige, @dark-blue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-value {
|
.status-value {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0 6px;
|
padding: 0 5px;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100px;
|
width: 140px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -237,6 +260,28 @@
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
&.pip-display {
|
||||||
|
align-items: end;
|
||||||
|
|
||||||
|
.status-bar.armor-slots {
|
||||||
|
width: 100px;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
.slot-value {
|
||||||
|
position: relative;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
.slot-bar {
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.status-bar.armor-slots {
|
.status-bar.armor-slots {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -252,6 +297,7 @@
|
||||||
width: 95px;
|
width: 95px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background: light-dark(@dark-blue, @golden);
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
clip-path: none;
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
@ -261,6 +307,66 @@
|
||||||
font-size: var(--font-size-12);
|
font-size: var(--font-size-12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.slot-value {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
align-items: center;
|
||||||
|
width: 80px;
|
||||||
|
height: 30px;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 2;
|
||||||
|
color: light-dark(@dark-blue, @beige);
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.slot-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
z-index: 1;
|
||||||
|
background: @dark-blue;
|
||||||
|
justify-content: center;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
.armor-slot {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
|
||||||
|
.fa-shield-halved {
|
||||||
|
color: light-dark(@dark-blue-40, @golden-40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slot-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: light-dark(@beige, @dark-blue);
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 0 5px;
|
||||||
|
width: 120%;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding-right: 1px;
|
||||||
|
border-bottom: 1px solid @dark-golden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
padding-left: 6px;
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.status-value {
|
.status-value {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -292,8 +398,6 @@
|
||||||
color: light-dark(@dark-blue, @beige);
|
color: light-dark(@dark-blue, @beige);
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
background: @semi-transparent-dark-blue;
|
background: @semi-transparent-dark-blue;
|
||||||
|
|
@ -306,7 +410,6 @@
|
||||||
width: 30px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
|
@ -318,7 +421,6 @@
|
||||||
background: light-dark(transparent, @dark-blue);
|
background: light-dark(transparent, @dark-blue);
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: 6px 6px 0 0;
|
||||||
|
|
||||||
&::-webkit-progress-bar {
|
&::-webkit-progress-bar {
|
||||||
border: none;
|
border: none;
|
||||||
background: light-dark(transparent, @dark-blue);
|
background: light-dark(transparent, @dark-blue);
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-section {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.status-section {
|
.status-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
&.pip-display {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
.status-number {
|
.status-number {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -84,103 +95,103 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-bar {
|
// .status-bar {
|
||||||
display: flex;
|
// display: flex;
|
||||||
justify-content: center;
|
// justify-content: center;
|
||||||
position: relative;
|
// position: relative;
|
||||||
width: 100px;
|
// width: 100px;
|
||||||
height: 40px;
|
// height: 40px;
|
||||||
|
|
||||||
.status-label {
|
// .status-label {
|
||||||
position: relative;
|
// position: relative;
|
||||||
top: 40px;
|
// top: 40px;
|
||||||
height: 22px;
|
// height: 22px;
|
||||||
width: 79px;
|
// width: 79px;
|
||||||
clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z');
|
// clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z');
|
||||||
background: light-dark(@dark-blue, @golden);
|
// background: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
h4 {
|
// h4 {
|
||||||
font-weight: bold;
|
// font-weight: bold;
|
||||||
text-align: center;
|
// text-align: center;
|
||||||
line-height: 18px;
|
// line-height: 18px;
|
||||||
color: light-dark(@beige, @dark-blue);
|
// color: light-dark(@beige, @dark-blue);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
.status-value {
|
// .status-value {
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
display: flex;
|
// display: flex;
|
||||||
padding: 0 6px;
|
// padding: 0 6px;
|
||||||
font-size: 1.5rem;
|
// font-size: 1.5rem;
|
||||||
align-items: center;
|
// align-items: center;
|
||||||
width: 100px;
|
// width: 100px;
|
||||||
height: 40px;
|
// height: 40px;
|
||||||
justify-content: center;
|
// justify-content: center;
|
||||||
text-align: center;
|
// text-align: center;
|
||||||
z-index: 2;
|
// z-index: 2;
|
||||||
color: @beige;
|
// color: @beige;
|
||||||
|
|
||||||
input[type='number'] {
|
// input[type='number'] {
|
||||||
background: transparent;
|
// background: transparent;
|
||||||
font-size: 1.5rem;
|
// font-size: 1.5rem;
|
||||||
width: 40px;
|
// width: 40px;
|
||||||
height: 30px;
|
// height: 30px;
|
||||||
text-align: center;
|
// text-align: center;
|
||||||
border: none;
|
// border: none;
|
||||||
outline: 2px solid transparent;
|
// outline: 2px solid transparent;
|
||||||
color: @beige;
|
// color: @beige;
|
||||||
|
|
||||||
&.bar-input {
|
// &.bar-input {
|
||||||
padding: 0;
|
// padding: 0;
|
||||||
color: @beige;
|
// color: @beige;
|
||||||
backdrop-filter: none;
|
// backdrop-filter: none;
|
||||||
background: transparent;
|
// background: transparent;
|
||||||
transition: all 0.3s ease;
|
// transition: all 0.3s ease;
|
||||||
|
|
||||||
&:hover,
|
// &:hover,
|
||||||
&:focus {
|
// &:focus {
|
||||||
background: @semi-transparent-dark-blue;
|
// background: @semi-transparent-dark-blue;
|
||||||
backdrop-filter: blur(9.5px);
|
// backdrop-filter: blur(9.5px);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
.bar-label {
|
// .bar-label {
|
||||||
width: 40px;
|
// width: 40px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
.progress-bar {
|
// .progress-bar {
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
appearance: none;
|
// appearance: none;
|
||||||
width: 100px;
|
// width: 100px;
|
||||||
height: 40px;
|
// height: 40px;
|
||||||
border: 1px solid light-dark(@dark-blue, @golden);
|
// border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
z-index: 1;
|
// z-index: 1;
|
||||||
background: @dark-blue;
|
// background: @dark-blue;
|
||||||
|
|
||||||
&::-webkit-progress-bar {
|
// &::-webkit-progress-bar {
|
||||||
border: none;
|
// border: none;
|
||||||
background: @dark-blue;
|
// background: @dark-blue;
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
}
|
// }
|
||||||
&::-webkit-progress-value {
|
// &::-webkit-progress-value {
|
||||||
background: @gradient-hp;
|
// background: @gradient-hp;
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
}
|
// }
|
||||||
&.stress-color::-webkit-progress-value {
|
// &.stress-color::-webkit-progress-value {
|
||||||
background: @gradient-stress;
|
// background: @gradient-stress;
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
}
|
// }
|
||||||
&::-moz-progress-bar {
|
// &::-moz-progress-bar {
|
||||||
background: @gradient-hp;
|
// background: @gradient-hp;
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
}
|
// }
|
||||||
&.stress-color::-moz-progress-bar {
|
// &.stress-color::-moz-progress-bar {
|
||||||
background: @gradient-stress;
|
// background: @gradient-stress;
|
||||||
border-radius: 6px;
|
// border-radius: 6px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
.level-div {
|
.level-div {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
||||||
42
styles/less/sheets/actors/party/header.less
Normal file
42
styles/less/sheets/actors/party/header.less
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
@import '../../../utils/colors.less';
|
||||||
|
@import '../../../utils/fonts.less';
|
||||||
|
|
||||||
|
.party-header-sheet {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: start;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
height: 235px;
|
||||||
|
mask-image: linear-gradient(0deg, transparent 0%, black 10%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-container {
|
||||||
|
.item-name {
|
||||||
|
padding: 0 20px;
|
||||||
|
input[type='text'] {
|
||||||
|
font-size: 32px;
|
||||||
|
height: 42px;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover[type='text'],
|
||||||
|
&:focus[type='text'] {
|
||||||
|
box-shadow: none;
|
||||||
|
outline: 2px solid light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
styles/less/sheets/actors/party/inventory.less
Normal file
73
styles/less/sheets/actors/party/inventory.less
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
@import '../../../utils/colors.less';
|
||||||
|
@import '../../../utils/fonts.less';
|
||||||
|
|
||||||
|
.application.sheet.daggerheart.actor.dh-style.party {
|
||||||
|
.tab.inventory {
|
||||||
|
.search-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
position: relative;
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 5px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-radius: 50px;
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
border: none;
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
outline: 2px solid light-dark(@dark, @golden);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:placeholder {
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-search-cancel-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
align-content: center;
|
||||||
|
height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
overflow-y: auto;
|
||||||
|
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||||
|
padding: 20px 0;
|
||||||
|
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 10px 0;
|
||||||
|
|
||||||
|
input {
|
||||||
|
color: light-dark(@dark, @beige);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
styles/less/sheets/actors/party/party-members.less
Normal file
28
styles/less/sheets/actors/party/party-members.less
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
@import '../../../utils/colors.less';
|
||||||
|
@import '../../../utils/fonts.less';
|
||||||
|
|
||||||
|
.application.sheet.daggerheart.actor.dh-style.party {
|
||||||
|
.tab.partyMembers {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.actors-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.actors-dragger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px dashed light-dark(@dark-blue-50, @beige-50);
|
||||||
|
border-radius: 3px;
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
196
styles/less/sheets/actors/party/resources.less
Normal file
196
styles/less/sheets/actors/party/resources.less
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
@import '../../../utils/colors.less';
|
||||||
|
@import '../../../utils/fonts.less';
|
||||||
|
@import '../../../utils/mixin.less';
|
||||||
|
|
||||||
|
body.game:is(.performance-low, .noblur) {
|
||||||
|
.application.sheet.daggerheart.actor.dh-style.party .tab.resources .actors-list .actor-resources {
|
||||||
|
background: light-dark(@dark-blue, @dark-golden);
|
||||||
|
|
||||||
|
.actor-name {
|
||||||
|
background: light-dark(@dark-blue, @dark-golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.application.sheet.daggerheart.actor.dh-style.party {
|
||||||
|
.tab.resources {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.actors-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.actor-resources {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
background: light-dark(@dark-blue-40, @dark-golden-40);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
max-width: 230px;
|
||||||
|
height: -webkit-fill-available;
|
||||||
|
|
||||||
|
.actor-name {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
background: light-dark(@dark-blue-90, @dark-golden-80);
|
||||||
|
backdrop-filter: blur(6.5px);
|
||||||
|
border-radius: 6px 6px 0px 0px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
color: light-dark(@beige, @golden);
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-img {
|
||||||
|
height: 150px;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: top center;
|
||||||
|
border-radius: 6px 6px 0px 0px;
|
||||||
|
mask-image: linear-gradient(180deg, black 88%, transparent 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resources {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
.slot-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.slot-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
width: 239px;
|
||||||
|
|
||||||
|
background-color: light-dark(@dark-blue-10, @dark-blue);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.armor-slot {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
|
||||||
|
.fa-shield-halved {
|
||||||
|
color: light-dark(@dark-blue-40, @golden-40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot {
|
||||||
|
width: 20px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.filled {
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slot-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: light-dark(@beige, @dark-blue);
|
||||||
|
background: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 0 5px;
|
||||||
|
width: fit-content;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 0px 0px 5px 5px;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
padding-left: 6px;
|
||||||
|
border-left: 1px solid light-dark(@beige, @dark-golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hope-section {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: light-dark(transparent, @dark-blue);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 3px;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hope-value {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.threshold-section {
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: light-dark(transparent, @dark-blue);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 3px;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
&.threshold-value {
|
||||||
|
color: light-dark(@dark, @beige);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.actors-dragger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px dashed light-dark(@dark-blue-50, @beige-50);
|
||||||
|
border-radius: 3px;
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
styles/less/sheets/actors/party/sheet.less
Normal file
45
styles/less/sheets/actors/party/sheet.less
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
@import '../../../utils/colors.less';
|
||||||
|
@import '../../../utils/fonts.less';
|
||||||
|
@import '../../../utils/mixin.less';
|
||||||
|
|
||||||
|
.appTheme({
|
||||||
|
&.party {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
&.party {
|
||||||
|
background: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
.application.sheet.daggerheart.actor.dh-style.party {
|
||||||
|
.tab {
|
||||||
|
height: -webkit-fill-available;
|
||||||
|
max-height: 514px;
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
gap: 20px;
|
||||||
|
background-color: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
|
||||||
|
button {
|
||||||
|
span {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,12 @@
|
||||||
@import './actors/environment/potentialAdversaries.less';
|
@import './actors/environment/potentialAdversaries.less';
|
||||||
@import './actors/environment/sheet.less';
|
@import './actors/environment/sheet.less';
|
||||||
|
|
||||||
|
@import './actors/party/header.less';
|
||||||
|
@import './actors/party/party-members.less';
|
||||||
|
@import './actors/party/sheet.less';
|
||||||
|
@import './actors/party/inventory.less';
|
||||||
|
@import './actors/party/resources.less';
|
||||||
|
|
||||||
@import './items/beastform.less';
|
@import './items/beastform.less';
|
||||||
@import './items/class.less';
|
@import './items/class.less';
|
||||||
@import './items/domain-card.less';
|
@import './items/domain-card.less';
|
||||||
|
|
|
||||||
210
styles/less/ui/chat/group-roll.less
Normal file
210
styles/less/ui/chat/group-roll.less
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
.chat-message .message-content .group-roll {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
.group-roll-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.group-roll-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&.first {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-header-expand-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: auto;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.closed {
|
||||||
|
height: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.finished {
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-main-roll {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-roll-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
.main-value {
|
||||||
|
font-size: var(--font-size-24);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-text {
|
||||||
|
font-size: var(--font-size-16);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-member {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.group-roll-data {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-label-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.group-roll-label-inner-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-modifier {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border: 1px solid light-dark(@green, @green);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: light-dark(@green, @green);
|
||||||
|
background: light-dark(@green-40, @green-40);
|
||||||
|
|
||||||
|
&.failure {
|
||||||
|
border-color: light-dark(@red, @red);
|
||||||
|
color: light-dark(@red, @red);
|
||||||
|
background: light-dark(@red-40, @red-40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-trait {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border: 1px solid light-dark(white, white);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: light-dark(white, white);
|
||||||
|
background: light-dark(@beige-80, @beige-80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-rolling {
|
||||||
|
img {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: drop-shadow(0 0 8px light-dark(@dark-blue, @golden));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-results {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: fit-content;
|
||||||
|
gap: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
&.finished {
|
||||||
|
background-color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reroll-result-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success,
|
||||||
|
.success i {
|
||||||
|
color: @green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.failure,
|
||||||
|
.failure i {
|
||||||
|
color: @red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-roll-reroll {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.dice-icon {
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reroll-icon {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 14px;
|
||||||
|
color: black;
|
||||||
|
filter: drop-shadow(0 0 3px black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
|
|
||||||
&.tiny {
|
&.tiny {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
input {
|
input {
|
||||||
min-width: 2.5rem;
|
min-width: 2.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
@import './chat/damage-summary.less';
|
@import './chat/damage-summary.less';
|
||||||
@import './chat/downtime.less';
|
@import './chat/downtime.less';
|
||||||
@import './chat/effect-summary.less';
|
@import './chat/effect-summary.less';
|
||||||
|
@import './chat/group-roll.less';
|
||||||
@import './chat/refresh-message.less';
|
@import './chat/refresh-message.less';
|
||||||
@import './chat/sheet.less';
|
@import './chat/sheet.less';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
img {
|
img {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
|
filter: @beige-filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
@golden: #f3c267;
|
@golden: #f3c267;
|
||||||
@golden-10: #f3c26710;
|
@golden-10: #f3c26710;
|
||||||
@golden-40: #f3c26740;
|
@golden-40: #f3c26740;
|
||||||
|
@golden-90: #f3c26790;
|
||||||
@golden-bg: #f3c2671a;
|
@golden-bg: #f3c2671a;
|
||||||
@golden-secondary: #eaaf42;
|
@golden-secondary: #eaaf42;
|
||||||
@golden-filter: brightness(0) saturate(100%) invert(89%) sepia(13%) saturate(2008%) hue-rotate(332deg) brightness(99%)
|
@golden-filter: brightness(0) saturate(100%) invert(89%) sepia(13%) saturate(2008%) hue-rotate(332deg) brightness(99%)
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
@medium-red-40: #d0474740;
|
@medium-red-40: #d0474740;
|
||||||
|
|
||||||
@dark-golden: #2b1d03;
|
@dark-golden: #2b1d03;
|
||||||
|
@dark-golden-40: #2b1d0340;
|
||||||
@dark-golden-80: #2b1d0380;
|
@dark-golden-80: #2b1d0380;
|
||||||
|
|
||||||
@red: #e54e4e;
|
@red: #e54e4e;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13.347",
|
"verified": "13.350",
|
||||||
"maximum": "13"
|
"maximum": "13"
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
@ -220,6 +220,9 @@
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"htmlFields": ["notes", "description"]
|
"htmlFields": ["notes", "description"]
|
||||||
|
},
|
||||||
|
"party": {
|
||||||
|
"htmlFields": ["notes"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Item": {
|
"Item": {
|
||||||
|
|
@ -267,6 +270,8 @@
|
||||||
"adversaryRoll": {},
|
"adversaryRoll": {},
|
||||||
"damageRoll": {},
|
"damageRoll": {},
|
||||||
"abilityUse": {},
|
"abilityUse": {},
|
||||||
|
"tagTeam": {},
|
||||||
|
"groupRoll": {},
|
||||||
"systemMessage": {}
|
"systemMessage": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,22 @@
|
||||||
<header class="dialog-header">
|
<header class="dialog-header">
|
||||||
<h1>
|
<div class="dialog-header-inner">
|
||||||
{{#if reactionOverride}}
|
<h1>
|
||||||
{{localize "DAGGERHEART.CONFIG.ActionType.reaction"}}
|
{{#if reactionOverride}}
|
||||||
{{else}}
|
{{localize "DAGGERHEART.CONFIG.ActionType.reaction"}}
|
||||||
{{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}}
|
{{else}}
|
||||||
{{/if}}
|
{{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}}
|
||||||
{{#if showReaction}}
|
{{/if}}
|
||||||
<button class="reaction-roll-controller {{#if reactionOverride}}active{{/if}}" data-action="toggleReaction" data-tooltip-text="{{localize "DAGGERHEART.GENERAL.reactionRoll"}}">
|
{{#if showReaction}}
|
||||||
<i class="fa-solid fa-reply"></i>
|
<button class="reaction-roll-controller {{#if reactionOverride}}active{{/if}}" data-action="toggleReaction" data-tooltip-text="{{localize "DAGGERHEART.GENERAL.reactionRoll"}}">
|
||||||
</button>
|
<i class="fa-solid fa-reply"></i>
|
||||||
{{/if}}
|
</button>
|
||||||
</h1>
|
{{/if}}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
{{#if (and @root.hasRoll @root.activeTagTeamRoll)}}
|
||||||
|
<div class="tag-team-controller {{#if @root.tagTeamSelected}}selected{{/if}}" data-action="toggleTagTeamRoll">
|
||||||
|
<span><i class="{{ifThen @root.tagTeamSelected "fa-solid" "fa-regular"}} fa-circle"></i></span>
|
||||||
|
<span class="label">{{localize "Tag Team Roll"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</header>
|
</header>
|
||||||
84
templates/dialogs/group-roll/group-roll.hbs
Normal file
84
templates/dialogs/group-roll/group-roll.hbs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
<div class="group-roll">
|
||||||
|
<header class="dialog-header">
|
||||||
|
<h1>{{localize "DAGGERHEART.UI.Chat.groupRoll.title"}}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<fieldset class="one-column">
|
||||||
|
<legend>{{localize "DAGGERHEART.UI.Chat.groupRoll.leader"}}</legend>
|
||||||
|
{{#unless leader.actor}}
|
||||||
|
<input type="text" class="leader-change-input" />
|
||||||
|
<div class="drag-area">
|
||||||
|
<span>{{localize "DAGGERHEART.UI.Chat.groupRoll.selectLeader"}}</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="actorLeader.trait">
|
||||||
|
{{selectOptions traitList selected=leader.trait labelAttr="label" valueAttr="id" localize=true }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{!-- Not used yet --}}
|
||||||
|
{{!-- <div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.difficulty"}}</label>
|
||||||
|
<input type="number" name="actorLeader.difficulty" value="{{leader.difficulty}}" data-dtype="Number">
|
||||||
|
</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>{{localize "DAGGERHEART.UI.Chat.groupRoll.partyTeam"}}</legend>
|
||||||
|
<span class="tooltip-container" {{#if allSelected}}data-tooltip="{{localize "The whole party is selected"}}"{{/if}}>
|
||||||
|
<input type="text" class="team-push-input" {{disabled @root.allSelected}}/>
|
||||||
|
</span>
|
||||||
|
{{#if (gt this.members.length 0)}}
|
||||||
|
{{#each members as |member index|}}
|
||||||
|
<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="{{concat "actorsMembers." index ".trait"}}">
|
||||||
|
{{selectOptions @root.traitList selected=member.trait labelAttr="label" valueAttr="id" localize=true }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{!-- Not used yet --}}
|
||||||
|
{{!-- <div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.GENERAL.difficulty"}}</label>
|
||||||
|
<input type="number" name="{{concat "actorsMembers." index ".difficulty"}}" value="{{member.difficulty}}" data-dtype="Number">
|
||||||
|
</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}}
|
||||||
|
{{#unless allSelected}}
|
||||||
|
<div class="drag-area">
|
||||||
|
<span>{{localize "DAGGERHEART.UI.Chat.groupRoll.selectMember"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</fieldset>
|
||||||
|
<button class="submit-btn" data-action="roll" {{disabled @root.rollDisabled}}>
|
||||||
|
<i class="fa-solid fa-dice"></i>
|
||||||
|
<span>{{localize "DAGGERHEART.GENERAL.roll"}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
110
templates/dialogs/tagTeamDialog.hbs
Normal file
110
templates/dialogs/tagTeamDialog.hbs
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
<div>
|
||||||
|
<div class="tag-team-container">
|
||||||
|
<fieldset>
|
||||||
|
<legend>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.partyTeam"}}</legend>
|
||||||
|
|
||||||
|
<div class="form-group flex-group">
|
||||||
|
<label>{{localize "TYPES.Actor.character"}}</label>
|
||||||
|
|
||||||
|
<div class="form-fields">
|
||||||
|
<select name="selectedAddMember">
|
||||||
|
{{selectOptions memberOptions labelAttr="name" valueAttr="uuid" blank=""}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="participants-container">
|
||||||
|
{{#each members as |member|}}
|
||||||
|
<div class="participant-outer-container {{#if member.selected}}selected{{/if}}" data-action="selectMessage" id="{{member.character.id}}">
|
||||||
|
<div class="participant-container">
|
||||||
|
<div class="participant-inner-container">
|
||||||
|
<img src="{{member.character.img}}" />
|
||||||
|
<div class="participant-labels">
|
||||||
|
<div class="participant-label-title">{{member.character.name}}</div>
|
||||||
|
<div class="participant-label-info">
|
||||||
|
{{#if member.character.system.class.value}}
|
||||||
|
<div class="participant-label-info-part">{{member.character.system.class.value.name}}</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if member.system.multiclass.value}}
|
||||||
|
<div class="participant-label-info-part">{{member.character.system.multiclass.value.name}}</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a data-action="removeMember" data-character-id="{{member.character.id}}"><i class="fa-solid fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
|
{{#if member.roll}}
|
||||||
|
<div class="participant-roll-outer-container">
|
||||||
|
<div class="participant-roll-container">
|
||||||
|
<h4>
|
||||||
|
<a data-action="unlinkMessage" id="{{member.character.id}}"><i class="fa-solid fa-link"></i></a>
|
||||||
|
{{member.roll.system.title}}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="participant-roll-container">
|
||||||
|
<side-line-div class="invert"></side-line-div>
|
||||||
|
<div class="participant-roll-text-container">
|
||||||
|
{{member.roll.system.roll.total}}
|
||||||
|
{{localize "DAGGERHEART.GENERAL.withThing" thing=member.roll.system.roll.result.label}}
|
||||||
|
</div>
|
||||||
|
<side-line-div></side-line-div>
|
||||||
|
</div>
|
||||||
|
{{#if member.roll.system.hasDamage}}
|
||||||
|
<h4>{{localize "DAGGERHEART.GENERAL.damage"}}</h4>
|
||||||
|
<div class="damage-values-container">
|
||||||
|
{{#if member.damageValues}}
|
||||||
|
{{#each member.damageValues as |damage|}}
|
||||||
|
<div class="damage-container">
|
||||||
|
<div>{{damage.name}}</div>
|
||||||
|
<div>{{damage.total}}</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{else}}
|
||||||
|
{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.damageNotRolled"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="participant-empty-roll-container">
|
||||||
|
{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.linkMessageHint"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="roll-leader-container">
|
||||||
|
<h4>
|
||||||
|
<strong>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.initiatingCharacter"}}</strong>
|
||||||
|
<select name="initiator.id">
|
||||||
|
{{selectOptions selectedCharacterOptions selected=initiator.character.id labelAttr="name" valueAttr="id" blank=""}}
|
||||||
|
</select>
|
||||||
|
</h4>
|
||||||
|
<h4>
|
||||||
|
<strong>{{localize "DAGGERHEART.GENERAL.Cost.single"}}</strong>
|
||||||
|
<input type="text" data-dtype="Number" min="0" name="initiator.cost" value="{{initiator.cost}}" />
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
{{#if showResult}}
|
||||||
|
{{#if selectedData.result}}
|
||||||
|
<div class="result-container">
|
||||||
|
<h4><strong>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.title"}}:</strong> {{selectedData.result}}</h4>
|
||||||
|
{{#if usesDamage}}
|
||||||
|
<div class="result-damages-container">
|
||||||
|
<label><strong>{{localize "DAGGERHEART.GENERAL.damage"}}:</strong></label>
|
||||||
|
{{#each selectedData.damageValues as |damage|}}
|
||||||
|
<div class="result-damage-container">
|
||||||
|
{{damage.name}}
|
||||||
|
{{damage.total}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<button data-action="createTagTeam" {{disabled createDisabled}}>{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.createTagTeam"}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -40,6 +40,7 @@
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if usesEffects}}
|
||||||
<button type="button" class="control-icon" data-action="togglePalette" data-palette="effects" data-tooltip="HUD.AssignStatusEffects">
|
<button type="button" class="control-icon" data-action="togglePalette" data-palette="effects" data-tooltip="HUD.AssignStatusEffects">
|
||||||
<img src="{{icons.effects}}">
|
<img src="{{icons.effects}}">
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -54,6 +55,13 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if (eq actorType 'party')}}
|
||||||
|
<button type="button" class="control-icon clown-car" data-action="togglePartyTokens" data-tooltip="{{#if partyOnCanvas}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.retrievePartyTokens"}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.HUD.tokenHUD.depositPartyTokens"}}{{/if}}">
|
||||||
|
<img {{#if partyOnCanvas}}class="flipped"{{/if}} src="{{icons.toggleParty}}">
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<button type="button" class="control-icon" data-action="togglePalette" data-palette="movementActions"
|
<button type="button" class="control-icon" data-action="togglePalette" data-palette="movementActions"
|
||||||
aria-label="{{ localize "HUD.SelectMovementAction" }}" data-tooltip>
|
aria-label="{{ localize "HUD.SelectMovementAction" }}" data-tooltip>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
<section class="tab {{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
<section class="tab {{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
||||||
|
{{formGroup
|
||||||
|
fields.useResourcePips
|
||||||
|
value=setting.useResourcePips
|
||||||
|
localize=true}}
|
||||||
{{formGroup
|
{{formGroup
|
||||||
fields.displayFear
|
fields.displayFear
|
||||||
value=setting.displayFear
|
value=setting.displayFear
|
||||||
|
|
|
||||||
|
|
@ -4,35 +4,10 @@
|
||||||
<a class="death-roll-btn"><i class="fa-solid fa-skull death-save"></i></a>
|
<a class="death-roll-btn"><i class="fa-solid fa-skull death-save"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-section">
|
<div class="info-section {{#if useResourcePips}}pip-display{{/if}}">
|
||||||
<div class="resources-section">
|
<div class="resources-section">
|
||||||
<div class="status-bar">
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=resources.hitPoints label="DAGGERHEART.GENERAL.HitPoints.short" key="system.resources.hitPoints.value" action="toggleHitPoints" }}
|
||||||
<div class='status-value'>
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=resources.stress label="DAGGERHEART.GENERAL.stress" key="system.resources.stress.value" action="toggleStress" }}
|
||||||
<input class="bar-input" name="system.resources.hitPoints.value" min="0" max='{{source.system.resources.hitPoints.max}}'
|
|
||||||
value="{{source.system.resources.hitPoints.value}}" type="number">
|
|
||||||
<span>/</span>
|
|
||||||
<span class="bar-label">{{source.system.resources.hitPoints.max}}</span>
|
|
||||||
</div>
|
|
||||||
<progress class='progress-bar' value='{{source.system.resources.hitPoints.value}}'
|
|
||||||
max='{{source.system.resources.hitPoints.max}}'></progress>
|
|
||||||
<div class="status-label">
|
|
||||||
<h4>{{localize 'DAGGERHEART.GENERAL.HitPoints.short'}}</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="status-bar">
|
|
||||||
<div class='status-value'>
|
|
||||||
<input class="bar-input" name="system.resources.stress.value" min="0" max='{{source.system.resources.stress.max}}'
|
|
||||||
value="{{source.system.resources.stress.value}}" type="number">
|
|
||||||
<span>/</span>
|
|
||||||
<span class="bar-label">{{source.system.resources.stress.max}}</span>
|
|
||||||
</div>
|
|
||||||
<progress class='progress-bar stress-color' value='{{source.system.resources.stress.value}}'
|
|
||||||
max='{{source.system.resources.stress.max}}'></progress>
|
|
||||||
<div class="status-label">
|
|
||||||
<h4>{{localize 'DAGGERHEART.GENERAL.stress'}}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="status-section">
|
<div class="status-section">
|
||||||
<div class="status-number">
|
<div class="status-number">
|
||||||
|
|
|
||||||
|
|
@ -15,44 +15,12 @@
|
||||||
<a class="death-roll-btn" data-tooltip="DAGGERHEART.UI.Tooltip.makeDeathMove" {{#if
|
<a class="death-roll-btn" data-tooltip="DAGGERHEART.UI.Tooltip.makeDeathMove" {{#if
|
||||||
isDeath}}data-action="makeDeathMove" {{/if}}><i class="fa-solid fa-skull death-save"></i></a>
|
isDeath}}data-action="makeDeathMove" {{/if}}><i class="fa-solid fa-skull death-save"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-section">
|
<div class="info-section {{#if useResourcePips}}pip-display{{/if}}">
|
||||||
<div class="resources-section">
|
<div class="resources-section">
|
||||||
<div class="status-bar">
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=resources.hitPoints label="DAGGERHEART.GENERAL.HitPoints.short" key="system.resources.hitPoints.value" action="toggleHitPoints" }}
|
||||||
<div class='status-value'>
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=resources.stress label="DAGGERHEART.GENERAL.stress" key="system.resources.stress.value" action="toggleStress" }}
|
||||||
<input class="bar-input" name="system.resources.hitPoints.value" min="0" max='{{document.system.resources.hitPoints.max}}'
|
|
||||||
value="{{document.system.resources.hitPoints.value}}" type="number">
|
|
||||||
<span>/</span>
|
|
||||||
<span class="bar-label">{{document.system.resources.hitPoints.max}}</span>
|
|
||||||
</div>
|
|
||||||
<progress
|
|
||||||
class='progress-bar'
|
|
||||||
max='{{document.system.resources.hitPoints.max}}'
|
|
||||||
value='{{document.system.resources.hitPoints.value}}'
|
|
||||||
></progress>
|
|
||||||
<div class="status-label">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.HitPoints.short"}}</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="status-bar">
|
|
||||||
<div class='status-value'>
|
|
||||||
<input class="bar-input" name="system.resources.stress.value" min="0" max='{{document.system.resources.stress.max}}'
|
|
||||||
value="{{document.system.resources.stress.value}}" type="number">
|
|
||||||
<span>/</span>
|
|
||||||
<span class="bar-label">{{document.system.resources.stress.max}}</span>
|
|
||||||
</div>
|
|
||||||
<progress
|
|
||||||
class='progress-bar stress-color'
|
|
||||||
value='{{document.system.resources.stress.value}}'
|
|
||||||
min="0"
|
|
||||||
max='{{document.system.resources.stress.max}}'
|
|
||||||
></progress>
|
|
||||||
<div class="status-label">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.stress"}}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="status-section">
|
<div class="status-section {{#if useResourcePips}}pip-display{{/if}}">
|
||||||
<div class="status-number">
|
<div class="status-number">
|
||||||
<div class='status-value'>
|
<div class='status-value'>
|
||||||
<p>{{document.system.evasion}}</p>
|
<p>{{document.system.evasion}}</p>
|
||||||
|
|
@ -64,10 +32,29 @@
|
||||||
|
|
||||||
{{#if document.system.armor.system.marks}}
|
{{#if document.system.armor.system.marks}}
|
||||||
<div class="status-bar armor-slots">
|
<div class="status-bar armor-slots">
|
||||||
|
{{#if useResourcePips}}
|
||||||
|
<div class='slot-value'>
|
||||||
|
<div class="slot-bar">
|
||||||
|
{{#times document.system.armorScore}}
|
||||||
|
<a class='armor-slot' data-action='toggleArmor' data-value="{{add this 1}}">
|
||||||
|
{{#if (gte ../document.system.armor.system.marks.value (add this 1))}}
|
||||||
|
<i class="fa-solid fa-shield"></i>
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-shield-halved"></i>
|
||||||
|
{{/if}}
|
||||||
|
</a>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="slot-label">
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.armorSlots"}}</span>
|
||||||
|
<span class="value">{{document.system.armor.system.marks.value}} / {{document.system.armorScore}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
<div class='status-value'>
|
<div class='status-value'>
|
||||||
<p><input class="bar-input armor-marks-input" value="{{document.system.armor.system.marks.value}}" type="number"></p>
|
<input class="bar-input armor-marks-input" value="{{document.system.armor.system.marks.value}}" type="number">
|
||||||
<p>/</p>
|
<span>/</span>
|
||||||
<p class="bar-label">{{document.system.armorScore}}</p>
|
<span class="bar-label">{{document.system.armorScore}}</span>
|
||||||
</div>
|
</div>
|
||||||
<progress
|
<progress
|
||||||
class='progress-bar stress-color'
|
class='progress-bar stress-color'
|
||||||
|
|
@ -77,6 +64,7 @@
|
||||||
<div class="status-label">
|
<div class="status-label">
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.armorSlots"}}</h4>
|
<h4>{{localize "DAGGERHEART.GENERAL.armorSlots"}}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="status-number armor-slots">
|
<div class="status-number armor-slots">
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,12 @@
|
||||||
placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}'
|
placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}'
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="status-section">
|
{{#if useResourcePips}}
|
||||||
|
<div class="resource-section">
|
||||||
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=document.system.resources.stress label="DAGGERHEART.GENERAL.stress" key="system.resources.stress.value" action="toggleStress" largePips=true }}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
<div class="status-section {{#if useResourcePips}}pip-display{{/if}}">
|
||||||
<div class="status-number">
|
<div class="status-number">
|
||||||
<div class='status-value'>
|
<div class='status-value'>
|
||||||
<p>{{document.system.evasion}}</p>
|
<p>{{document.system.evasion}}</p>
|
||||||
|
|
@ -17,21 +22,11 @@
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.evasion"}}</h4>
|
<h4>{{localize "DAGGERHEART.GENERAL.evasion"}}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-bar">
|
{{#unless useResourcePips}}
|
||||||
<div class='status-value'>
|
<div class="resource-section">
|
||||||
<input class="bar-input" name="system.resources.stress.value" value="{{document.system.resources.stress.value}}" min="0" max='{{document.system.resources.stress.max}}' type="number">
|
{{> "systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs" resource=document.system.resources.stress label="DAGGERHEART.GENERAL.stress" key="system.resources.stress.value" action="toggleStress" }}
|
||||||
<span>/</span>
|
|
||||||
<span class="bar-label">{{document.system.resources.stress.max}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<progress
|
{{/unless}}
|
||||||
class='progress-bar stress-color'
|
|
||||||
value='{{document.system.resources.stress.value}}'
|
|
||||||
max='{{document.system.resources.stress.max}}'
|
|
||||||
></progress>
|
|
||||||
<div class="status-label">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.stress"}}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='level-div'>
|
<div class='level-div'>
|
||||||
<h3 class='label'>
|
<h3 class='label'>
|
||||||
{{localize 'DAGGERHEART.GENERAL.level'}}
|
{{localize 'DAGGERHEART.GENERAL.level'}}
|
||||||
|
|
|
||||||
9
templates/sheets/actors/party/header.hbs
Normal file
9
templates/sheets/actors/party/header.hbs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<header class='party-header-sheet'>
|
||||||
|
<img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' />
|
||||||
|
<div class='item-container'>
|
||||||
|
<div class="item-info">
|
||||||
|
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
|
||||||
|
<h2 class="label">Party</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
82
templates/sheets/actors/party/inventory.hbs
Normal file
82
templates/sheets/actors/party/inventory.hbs
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
<section class='tab {{tabs.inventory.cssClass}} {{tabs.inventory.id}}' data-tab='{{tabs.inventory.id}}'
|
||||||
|
data-group='{{tabs.inventory.group}}'>
|
||||||
|
<div class="search-section">
|
||||||
|
<div class="search-bar">
|
||||||
|
<div class="icon">
|
||||||
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
|
</div>
|
||||||
|
<input type="search" name="search" class="search-inventory" placeholder="Search...">
|
||||||
|
</div>
|
||||||
|
<a class="filter-button">
|
||||||
|
<i class="fa-solid fa-filter"></i>
|
||||||
|
</a>
|
||||||
|
<a data-tooltip="{{localize 'DAGGERHEART.UI.Tooltip.compendiumBrowser'}}" data-action="tempBrowser">
|
||||||
|
<i class="fa-solid fa-book-atlas"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="currency-section">
|
||||||
|
<div class="input">
|
||||||
|
<span>{{localize this.inventory.currency.coins}}</span>
|
||||||
|
{{formInput systemFields.gold.fields.coins value=source.system.gold.coins enriched=source.system.gold.coins
|
||||||
|
localize=true toggled=true}}
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<span>{{localize this.inventory.currency.handfuls}}</span>
|
||||||
|
{{formInput systemFields.gold.fields.handfuls value=source.system.gold.handfuls
|
||||||
|
enriched=source.system.gold.handfuls localize=true toggled=true}}
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<span>{{localize this.inventory.currency.bags}}</span>
|
||||||
|
{{formInput systemFields.gold.fields.bags value=source.system.gold.bags enriched=source.system.gold.bags
|
||||||
|
localize=true toggled=true}}
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<span>{{localize this.inventory.currency.chests}}</span>
|
||||||
|
{{formInput systemFields.gold.fields.chests value=source.system.gold.chests
|
||||||
|
enriched=source.system.gold.chests localize=true toggled=true}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="items-section">
|
||||||
|
{{> 'daggerheart.inventory-items'
|
||||||
|
title='TYPES.Item.weapon'
|
||||||
|
type='weapon'
|
||||||
|
actorType='party'
|
||||||
|
collection=document.itemTypes.weapon
|
||||||
|
isGlassy=true
|
||||||
|
canCreate=true
|
||||||
|
hideResources=true
|
||||||
|
hideContextMenu=true
|
||||||
|
}}
|
||||||
|
{{> 'daggerheart.inventory-items'
|
||||||
|
title='TYPES.Item.armor'
|
||||||
|
type='armor'
|
||||||
|
actorType='party'
|
||||||
|
collection=document.itemTypes.armor
|
||||||
|
isGlassy=true
|
||||||
|
canCreate=true
|
||||||
|
hideResources=true
|
||||||
|
hideContextMenu=true
|
||||||
|
}}
|
||||||
|
{{> 'daggerheart.inventory-items'
|
||||||
|
title='TYPES.Item.consumable'
|
||||||
|
type='consumable'
|
||||||
|
actorType='party'
|
||||||
|
collection=document.itemTypes.consumable
|
||||||
|
isGlassy=true
|
||||||
|
canCreate=true
|
||||||
|
hideContextMenu=true
|
||||||
|
}}
|
||||||
|
{{> 'daggerheart.inventory-items'
|
||||||
|
title='TYPES.Item.loot'
|
||||||
|
type='loot'
|
||||||
|
actorType='party'
|
||||||
|
collection=document.itemTypes.loot
|
||||||
|
isGlassy=true
|
||||||
|
canCreate=true
|
||||||
|
hideContextMenu=true
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
10
templates/sheets/actors/party/notes.hbs
Normal file
10
templates/sheets/actors/party/notes.hbs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<section
|
||||||
|
class='tab {{tabs.notes.cssClass}} {{tabs.notes.id}}'
|
||||||
|
data-tab='{{tabs.notes.id}}'
|
||||||
|
data-group='{{tabs.notes.group}}'
|
||||||
|
>
|
||||||
|
<fieldset class="fit-height">
|
||||||
|
<legend>{{localize tabs.notes.label}}</legend>
|
||||||
|
{{formInput notes.field value=notes.value enriched=notes.value toggled=true}}
|
||||||
|
</fieldset>
|
||||||
|
</section>
|
||||||
40
templates/sheets/actors/party/party-members.hbs
Normal file
40
templates/sheets/actors/party/party-members.hbs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<section
|
||||||
|
class='tab {{tabs.partyMembers.cssClass}} {{tabs.partyMembers.id}}'
|
||||||
|
data-tab='{{tabs.partyMembers.id}}'
|
||||||
|
data-group='{{tabs.partyMembers.group}}'
|
||||||
|
>
|
||||||
|
|
||||||
|
<div class="actions-section">
|
||||||
|
<button data-action="tagTeamRoll">
|
||||||
|
<i class="fa-solid fa-user-group"></i>
|
||||||
|
<span>Tag Team Roll</span>
|
||||||
|
</button>
|
||||||
|
<button data-action="groupRoll">
|
||||||
|
<i class="fa-solid fa-users"></i>
|
||||||
|
<span>Group Roll</span>
|
||||||
|
</button>
|
||||||
|
{{!-- NOT YET IMPLEMENTED --}}
|
||||||
|
{{!-- <button>
|
||||||
|
<i class="fa-solid fa-handshake-angle"></i>
|
||||||
|
<span>Help Action</span>
|
||||||
|
</button> --}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="actors-section glassy">
|
||||||
|
<legend>{{localize tabs.partyMembers.label}}</legend>
|
||||||
|
<ul class="actors-list">
|
||||||
|
{{#each document.system.partyMembers as |actor id|}}
|
||||||
|
{{> 'daggerheart.inventory-item'
|
||||||
|
item=actor
|
||||||
|
type='character'
|
||||||
|
isActor=true
|
||||||
|
}}
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
{{#unless document.system.partyMembers.length}}
|
||||||
|
<div class="actors-dragger">
|
||||||
|
<span>{{localize "DAGGERHEART.GENERAL.dropActorsHere"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</fieldset>
|
||||||
|
</section>
|
||||||
4
templates/sheets/actors/party/projects.hbs
Normal file
4
templates/sheets/actors/party/projects.hbs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<section class='tab {{tabs.projects.cssClass}} {{tabs.projects.id}}' data-tab='{{tabs.projects.id}}'
|
||||||
|
data-group='{{tabs.projects.group}}'>
|
||||||
|
<h2>Soon tm</h2>
|
||||||
|
</section>
|
||||||
99
templates/sheets/actors/party/resources.hbs
Normal file
99
templates/sheets/actors/party/resources.hbs
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
<section
|
||||||
|
class='tab {{tabs.resources.cssClass}} {{tabs.resources.id}}'
|
||||||
|
data-tab='{{tabs.resources.id}}'
|
||||||
|
data-group='{{tabs.resources.group}}'
|
||||||
|
>
|
||||||
|
<div data-action="triggerRest" data-type="longRest" class="actions-section">
|
||||||
|
<button data-type="longRest">
|
||||||
|
<i class="fa-solid fa-bed"></i>
|
||||||
|
<span>{{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}}</span>
|
||||||
|
</button>
|
||||||
|
<button data-action="triggerRest" data-type="shortRest">
|
||||||
|
<i class="fa-solid fa-utensils"></i>
|
||||||
|
<span>{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="resource-section glassy">
|
||||||
|
<legend>{{localize tabs.resources.label}}</legend>
|
||||||
|
<ul class="actors-list">
|
||||||
|
{{#each document.system.partyMembers as |actor id|}}
|
||||||
|
<li class="actor-resources">
|
||||||
|
<h2 class="actor-name">{{actor.name}}</h2>
|
||||||
|
<img class="actor-img" src="{{actor.img}}">
|
||||||
|
<div class="resources">
|
||||||
|
<div class="slot-section">
|
||||||
|
<div class="slot-bar">
|
||||||
|
{{#times actor.system.resources.hitPoints.max}}
|
||||||
|
<span class='slot {{#if (gte actor.system.resources.hitPoints.value (add this 1))}}filled{{/if}}'
|
||||||
|
data-action='toggleHitPoints' data-actor-id="{{actor.uuid}}" data-value="{{add this 1}}">
|
||||||
|
</span>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="slot-label">
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.HitPoints.short"}}</span>
|
||||||
|
<span class="value">{{actor.system.resources.hitPoints.value}} / {{actor.system.resources.hitPoints.max}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="slot-section">
|
||||||
|
<div class="slot-bar">
|
||||||
|
{{#times actor.system.resources.stress.max}}
|
||||||
|
<span class='slot {{#if (gte actor.system.resources.stress.value (add this 1))}}filled{{/if}}'
|
||||||
|
data-action='toggleStress' data-actor-id="{{actor.uuid}}" data-value="{{add this 1}}">
|
||||||
|
</span>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="slot-label">
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.stress"}}</span>
|
||||||
|
<span class="value">{{actor.system.resources.stress.value}} / {{actor.system.resources.stress.max}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if actor.system.armor.system.marks}}
|
||||||
|
<div class="slot-section">
|
||||||
|
<div class="slot-bar">
|
||||||
|
{{#times actor.system.armorScore}}
|
||||||
|
<a class='armor-slot'
|
||||||
|
data-action='toggleArmorSlot' data-actor-id="{{actor.uuid}}" data-item-uuid="{{actor.system.armor.uuid}}" data-value="{{add this 1}}">
|
||||||
|
{{#if (gte actor.system.armor.system.marks.value (add this 1))}}
|
||||||
|
<i class="fa-solid fa-shield"></i>
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-shield-halved"></i>
|
||||||
|
{{/if}}
|
||||||
|
</a>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="slot-label">
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.armorSlots"}}</span>
|
||||||
|
<span class="value">{{actor.system.armor.system.marks.value}} / {{actor.system.armorScore}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="hope-section">
|
||||||
|
<h4>{{localize "DAGGERHEART.GENERAL.hope"}}</h4>
|
||||||
|
{{#times actor.system.resources.hope.max}}
|
||||||
|
<span class='hope-value' data-action='toggleHope' data-actor-id="{{actor.uuid}}" data-value="{{add this 1}}">
|
||||||
|
{{#if (gte actor.system.resources.hope.value (add this 1))}}
|
||||||
|
<i class='fa-solid fa-diamond'></i>
|
||||||
|
{{else}}
|
||||||
|
<i class='fa-regular fa-circle'></i>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="threshold-section">
|
||||||
|
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}</h4>
|
||||||
|
<h4 class="threshold-value">{{actor.system.damageThresholds.major}}</h4>
|
||||||
|
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}</h4>
|
||||||
|
<h4 class="threshold-value">{{actor.system.damageThresholds.severe}}</h4>
|
||||||
|
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
</section>
|
||||||
|
|
@ -10,6 +10,7 @@ Parameters:
|
||||||
- isGlassy {boolean} : If true, applies the 'glassy' class to the fieldset.
|
- isGlassy {boolean} : If true, applies the 'glassy' class to the fieldset.
|
||||||
- cardView {boolean} : If true and type is 'domainCard', renders using domain card layout.
|
- cardView {boolean} : If true and type is 'domainCard', renders using domain card layout.
|
||||||
- isActor {boolean} : Passed through to inventory-item partials.
|
- isActor {boolean} : Passed through to inventory-item partials.
|
||||||
|
- actorType {boolean} : The actor type of the parent actor
|
||||||
- canCreate {boolean} : If true, show createDoc anchor on legend
|
- canCreate {boolean} : If true, show createDoc anchor on legend
|
||||||
- inVault {boolean} : If true, the domainCard is created with inVault=true
|
- inVault {boolean} : If true, the domainCard is created with inVault=true
|
||||||
- disabled {boolean}: If true, the ActiveEffect is created with disabled=true;
|
- disabled {boolean}: If true, the ActiveEffect is created with disabled=true;
|
||||||
|
|
@ -54,6 +55,7 @@ Parameters:
|
||||||
{{> 'daggerheart.inventory-item'
|
{{> 'daggerheart.inventory-item'
|
||||||
item=item
|
item=item
|
||||||
type=../type
|
type=../type
|
||||||
|
actorType=../actorType
|
||||||
hideControls=../hideControls
|
hideControls=../hideControls
|
||||||
hideContextMenu=../hideContextMenu
|
hideContextMenu=../hideContextMenu
|
||||||
isActor=../isActor
|
isActor=../isActor
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
Parameters:
|
Parameters:
|
||||||
- type {string} : The type of items in the list
|
- type {string} : The type of items in the list
|
||||||
- isActor {boolean} : Passed through to inventory-item partials.
|
- isActor {boolean} : Passed through to inventory-item partials.
|
||||||
|
- actorType {boolean} : The actor type of the parent actor
|
||||||
- categoryAdversary {string} : Category adversary id.
|
- categoryAdversary {string} : Category adversary id.
|
||||||
- noExtensible {boolean} : If true, the inventory-item-content would be collapsable/extendible else it always be showed
|
- noExtensible {boolean} : If true, the inventory-item-content would be collapsable/extendible else it always be showed
|
||||||
- hideLabels {boolean} : If true, hide label-tags else show label-tags.
|
- hideLabels {boolean} : If true, hide label-tags else show label-tags.
|
||||||
|
|
@ -17,7 +18,7 @@ Parameters:
|
||||||
|
|
||||||
<li class="inventory-item" data-item-id="{{item.id}}" {{#if (or (eq type 'action' ) (eq type 'attack' ))}}
|
<li class="inventory-item" data-item-id="{{item.id}}" {{#if (or (eq type 'action' ) (eq type 'attack' ))}}
|
||||||
data-action-id="{{item.id}}" {{/if}} data-item-uuid="{{item.uuid}}" data-type="{{type}}" data-no-compendium-edit="{{noCompendiumEdit}}" draggable="true">
|
data-action-id="{{item.id}}" {{/if}} data-item-uuid="{{item.uuid}}" data-type="{{type}}" data-no-compendium-edit="{{noCompendiumEdit}}" draggable="true">
|
||||||
<div class="inventory-item-header" {{#unless noExtensible}}data-action="toggleExtended" {{/unless}}>
|
<div class="inventory-item-header {{#if (eq actorType 'party')}}padded{{/if}}" {{#unless noExtensible}}data-action="toggleExtended" {{/unless}}>
|
||||||
{{!-- Image --}}
|
{{!-- Image --}}
|
||||||
<div class="img-portait" data-action='{{ifThen (or (hasProperty item "use") (eq type "attack")) "useItem" (ifThen
|
<div class="img-portait" data-action='{{ifThen (or (hasProperty item "use") (eq type "attack")) "useItem" (ifThen
|
||||||
(hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}}
|
(hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}}
|
||||||
|
|
@ -36,7 +37,7 @@ Parameters:
|
||||||
<div class="item-label">
|
<div class="item-label">
|
||||||
|
|
||||||
{{!-- Item Name --}}
|
{{!-- Item Name --}}
|
||||||
<span class="item-name">{{localize item.name}} {{#unless noExtensible}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span>
|
<span class="item-name">{{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span>
|
||||||
|
|
||||||
{{!-- Tags Start --}}
|
{{!-- Tags Start --}}
|
||||||
{{#with item}}
|
{{#with item}}
|
||||||
|
|
@ -75,18 +76,30 @@ Parameters:
|
||||||
<i class='fas fa-trash'></i>
|
<i class='fas fa-trash'></i>
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if (eq type 'character')}}
|
||||||
|
<a data-action='deletePartyMember' data-tooltip="CONTROLS.CommonDelete">
|
||||||
|
<i class='fas fa-trash'></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if (eq type 'weapon')}}
|
{{#unless (eq actorType 'party')}}
|
||||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
{{#if (eq type 'weapon')}}
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||||
<i class="fa-solid fa-hands"></i>
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||||
</a>
|
<i class="fa-solid fa-hands"></i>
|
||||||
{{else if (eq type 'armor')}}
|
</a>
|
||||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
{{else if (eq type 'armor')}}
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||||
<i class="fa-solid fa-shield"></i>
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||||
</a>
|
<i class="fa-solid fa-shield"></i>
|
||||||
{{else if (eq type 'domainCard')}}
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
<a data-action="deleteItem" data-tooltip="DAGGERHEART.UI.Tooltip.deleteItem">
|
||||||
|
<i class="fa-solid fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
{{/unless}}
|
||||||
|
{{#if (eq type 'domainCard')}}
|
||||||
<a data-action="toggleVault"
|
<a data-action="toggleVault"
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
||||||
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
||||||
|
|
@ -97,7 +110,7 @@ Parameters:
|
||||||
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}"></i>
|
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}"></i>
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (hasProperty item "toChat")}}
|
{{#if (and (hasProperty item "toChat") (not (eq actorType 'party')))}}
|
||||||
<a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat">
|
<a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat">
|
||||||
<i class="fa-regular fa-message"></i>
|
<i class="fa-regular fa-message"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
35
templates/sheets/global/partials/resource-bar.hbs
Normal file
35
templates/sheets/global/partials/resource-bar.hbs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<div class="status-bar">
|
||||||
|
{{#if useResourcePips}}
|
||||||
|
<div class='slot-value'>
|
||||||
|
<div class="slot-bar">
|
||||||
|
{{#times resource.max}}
|
||||||
|
<span class='slot {{#if (gte ../resource.value (add this 1))}}filled{{/if}} {{#if ../largePips}}large{{/if}}' data-action="{{../action}}" data-value="{{add this 1}}">
|
||||||
|
</span>
|
||||||
|
{{/times}}
|
||||||
|
|
||||||
|
{{#times resource.emptyPips}}
|
||||||
|
<span class="empty-slot"></span>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
<div class="slot-label">
|
||||||
|
<span class="label">{{localize label}}</span>
|
||||||
|
<span class="value">{{resource.value}} / {{resource.max}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class='status-value'>
|
||||||
|
<input class="bar-input" name="{{key}}" min="0" max='{{resource.max}}'
|
||||||
|
value="{{resource.value}}" type="number">
|
||||||
|
<span>/</span>
|
||||||
|
<span class="bar-label">{{resource.max}}</span>
|
||||||
|
</div>
|
||||||
|
<progress
|
||||||
|
class='progress-bar'
|
||||||
|
max='{{resource.max}}'
|
||||||
|
value='{{resource.value}}'
|
||||||
|
></progress>
|
||||||
|
<div class="status-label">
|
||||||
|
<h4>{{localize label}}</h4>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
124
templates/ui/chat/groupRoll.hbs
Normal file
124
templates/ui/chat/groupRoll.hbs
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
<div class="group-roll">
|
||||||
|
<div class="group-roll-section">
|
||||||
|
<h4 class="divider group-roll-header first">
|
||||||
|
<label>{{localize "DAGGERHEART.UI.Chat.groupRoll.leader"}}</label>
|
||||||
|
</h4>
|
||||||
|
<div class="group-roll-content {{#if system.leader.result}}finished{{/if}}">
|
||||||
|
<div class="group-roll-member">
|
||||||
|
<div class="group-roll-data">
|
||||||
|
<img src="{{system.leader.actor.img}}" />
|
||||||
|
<div class="group-roll-label-container">
|
||||||
|
<div>{{system.leader.actor.name}}</div>
|
||||||
|
<div class="group-roll-label-inner-container">
|
||||||
|
{{#unless (isNullish system.leader.manualSuccess)}}
|
||||||
|
<label class="group-roll-modifier {{#unless system.leader.manualSuccess}}failure{{/unless}}">{{#if system.leader.manualSuccess}}{{localize "DAGGERHEART.GENERAL.hit.single"}}{{else}}{{localize "DAGGERHEART.GENERAL.miss.single"}}{{/if}}</label>
|
||||||
|
{{/unless}}
|
||||||
|
<div class="group-roll-trait">{{localize (concat "DAGGERHEART.CONFIG.Traits." system.leader.trait ".name")}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{#unless system.leader.result}}
|
||||||
|
<div class="group-roll-rolling">
|
||||||
|
<a class="group-roll-button" data-path="leader"><img class="dice-icon normal" src="{{concat 'systems/daggerheart/assets/icons/dice/default/d20.svg'}}" alt=""></a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="roll-results {{#if system.leader.result}}finished{{/if}}">
|
||||||
|
{{#if (isNullish system.leader.manualSuccess)}}
|
||||||
|
<div class="reroll-result-container">
|
||||||
|
<a class="group-roll-success success" data-success="true" data-path="leader"><i class="fa-solid fa-check"></i></a>
|
||||||
|
<a class="group-roll-success failure" data-path="leader"><i class="fa-solid fa-xmark"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="group-roll-reroll" data-path="leader" data-tooltip="{{localize "DAGGERHEART.UI.Chat.groupRoll.rerollTooltip"}}">
|
||||||
|
<img class="dice-icon normal" src="{{concat 'systems/daggerheart/assets/icons/dice/default/d20.svg'}}" alt=""></img>
|
||||||
|
<i class="fa-solid fa-arrow-rotate-left reroll-icon"></i>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<div class="reroll-result-container">
|
||||||
|
{{#if system.leader.manualSuccess}}
|
||||||
|
<i class="fa-solid fa-check success"></i>
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-xmark failure"></i>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
{{#if system.leader.result}}
|
||||||
|
<div class="group-roll-main-roll">
|
||||||
|
<h4 class="divider">
|
||||||
|
{{localize "DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle" ability=(localize (concat "DAGGERHEART.CONFIG.Traits." system.leader.trait ".name"))}}
|
||||||
|
</h4>
|
||||||
|
<span class="main-roll-content">
|
||||||
|
<span class="main-value">
|
||||||
|
{{system.leader.result.total}}
|
||||||
|
{{#unless (isNullish system.totalModifier)}}
|
||||||
|
{{#if (gte system.totalModifier 0)}}+{{else}}-{{/if}}
|
||||||
|
{{positive system.totalModifier}} = {{add system.leader.result.total system.totalModifier}}
|
||||||
|
{{/unless}}
|
||||||
|
</span>
|
||||||
|
<span class="main-text">{{localize "DAGGERHEART.GENERAL.withThing" thing=system.leader.result.result.label}}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="group-roll-section">
|
||||||
|
<h4 class="divider group-roll-header">
|
||||||
|
<a class="group-roll-header-expand-section">
|
||||||
|
<i class="fa-solid fa-angle-down"></i>
|
||||||
|
<label>{{localize "DAGGERHEART.UI.Chat.groupRoll.team"}}</label>
|
||||||
|
<i class="fa-solid fa-angle-down"></i>
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
<div class="group-roll-content">
|
||||||
|
{{#each system.members as |member index|}}
|
||||||
|
<div class="group-roll-member">
|
||||||
|
<div class="group-roll-data">
|
||||||
|
<img src="{{member.actor.img}}" />
|
||||||
|
<div class="group-roll-label-container">
|
||||||
|
<div>{{member.actor.name}}</div>
|
||||||
|
<div class="group-roll-label-inner-container">
|
||||||
|
{{#unless (isNullish member.manualSuccess)}}
|
||||||
|
<label class="group-roll-modifier {{#unless member.manualSuccess}}failure{{/unless}}">{{#if member.manualSuccess}}+1{{else}}-1{{/if}}</label>
|
||||||
|
{{/unless}}
|
||||||
|
<div class="group-roll-trait">{{localize (concat "DAGGERHEART.CONFIG.Traits." member.trait ".name")}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{#unless member.result}}
|
||||||
|
<div class="group-roll-rolling">
|
||||||
|
<a class="group-roll-button" data-path="{{concat "members." index}}"><img class="dice-icon normal" src="{{concat 'systems/daggerheart/assets/icons/dice/default/d20.svg'}}" alt=""></a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="roll-results">
|
||||||
|
{{#if (isNullish member.manualSuccess)}}
|
||||||
|
<div class="reroll-result-container">
|
||||||
|
<span class="label">{{member.result.total}}</span>
|
||||||
|
|
||||||
|
<a class="group-roll-success success" data-success="true" data-path="{{concat "members." index}}"><i class="fa-solid fa-check"></i></a>
|
||||||
|
<a class="group-roll-success failure" data-path="{{concat "members." index}}"><i class="fa-solid fa-xmark"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="group-roll-reroll" data-path="{{concat "members." index}}" data-tooltip="{{localize "DAGGERHEART.UI.Chat.groupRoll.rerollTooltip"}}">
|
||||||
|
<img class="dice-icon normal" src="{{concat 'systems/daggerheart/assets/icons/dice/default/d20.svg'}}" alt=""></img>
|
||||||
|
<i class="fa-solid fa-arrow-rotate-left reroll-icon"></i>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<div class="reroll-result-container">
|
||||||
|
<span class="label">{{member.result.total}}</span>
|
||||||
|
{{#if member.manualSuccess}}
|
||||||
|
<i class="fa-solid fa-check success"></i>
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-xmark failure"></i>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue