mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Merge branch 'main' into 157-feature-simplify-and-refactor-item-sheets
This commit is contained in:
commit
175ae7dd23
38 changed files with 2378 additions and 808 deletions
7
.github/workflows/deploy.yml
vendored
7
.github/workflows/deploy.yml
vendored
|
|
@ -16,6 +16,9 @@ jobs:
|
||||||
- name: Build Packs
|
- name: Build Packs
|
||||||
run: npm run pullYMLtoLDB
|
run: npm run pullYMLtoLDB
|
||||||
|
|
||||||
|
- name: Build daggerheart.js
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
# get part of the tag after the `v`
|
# get part of the tag after the `v`
|
||||||
- name: Extract tag version number
|
- name: Extract tag version number
|
||||||
id: get_version
|
id: get_version
|
||||||
|
|
@ -34,7 +37,7 @@ jobs:
|
||||||
download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/system.zip
|
download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/system.zip
|
||||||
|
|
||||||
# Create a zip file with all files required by the module to add to the release
|
# Create a zip file with all files required by the module to add to the release
|
||||||
- run: zip -r ./system.zip system.json README.md LICENSE daggerheart.mjs templates/ styles/daggerheart.css packs/ lang/
|
- run: zip -r ./system.zip system.json README.md LICENSE build/daggerheart.js assets/ templates/ styles/daggerheart.css packs/ lang/
|
||||||
|
|
||||||
# Create a release for this specific version
|
# Create a release for this specific version
|
||||||
- name: Update Release with Files
|
- name: Update Release with Files
|
||||||
|
|
@ -46,6 +49,6 @@ jobs:
|
||||||
draft: ${{ github.event.release.unpublished }}
|
draft: ${{ github.event.release.unpublished }}
|
||||||
prerelease: ${{ github.event.release.prerelease }}
|
prerelease: ${{ github.event.release.prerelease }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
artifacts: './module.json, ./module.zip'
|
artifacts: './system.json, ./system.zip'
|
||||||
tag: ${{ github.event.release.tag_name }}
|
tag: ${{ github.event.release.tag_name }}
|
||||||
body: ${{ github.event.release.body }}
|
body: ${{ github.event.release.body }}
|
||||||
|
|
@ -4,7 +4,7 @@ import * as models from './module/data/_module.mjs';
|
||||||
import * as documents from './module/documents/_module.mjs';
|
import * as documents from './module/documents/_module.mjs';
|
||||||
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
||||||
import DhCombatTracker from './module/ui/combatTracker.mjs';
|
import DhCombatTracker from './module/ui/combatTracker.mjs';
|
||||||
import { GMUpdateEvent, handleSocketEvent, socketEvent } from './module/helpers/socket.mjs';
|
import { handleSocketEvent, registerSocketHooks } from './module/helpers/socket.mjs';
|
||||||
import { registerDHSettings } from './module/applications/settings.mjs';
|
import { registerDHSettings } from './module/applications/settings.mjs';
|
||||||
import DhpChatLog from './module/ui/chatLog.mjs';
|
import DhpChatLog from './module/ui/chatLog.mjs';
|
||||||
import DhpRuler from './module/ui/ruler.mjs';
|
import DhpRuler from './module/ui/ruler.mjs';
|
||||||
|
|
@ -13,11 +13,13 @@ import { DhDualityRollEnricher, DhTemplateEnricher } from './module/enrichers/_m
|
||||||
import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs';
|
import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs';
|
||||||
import { abilities } from './module/config/actorConfig.mjs';
|
import { abilities } from './module/config/actorConfig.mjs';
|
||||||
import Resources from './module/applications/resources.mjs';
|
import Resources from './module/applications/resources.mjs';
|
||||||
|
import { NarrativeCountdowns, registerCountdownApplicationHooks } from './module/applications/countdowns.mjs';
|
||||||
import DHDualityRoll from './module/data/chat-message/dualityRoll.mjs';
|
import DHDualityRoll from './module/data/chat-message/dualityRoll.mjs';
|
||||||
import { DualityRollColor } from './module/data/settings/Appearance.mjs';
|
import { DualityRollColor } from './module/data/settings/Appearance.mjs';
|
||||||
import { DhMeasuredTemplate } from './module/placeables/_module.mjs';
|
import { DhMeasuredTemplate } from './module/placeables/_module.mjs';
|
||||||
import { renderDualityButton } from './module/enrichers/DualityRollEnricher.mjs';
|
import { renderDualityButton } from './module/enrichers/DualityRollEnricher.mjs';
|
||||||
import { renderMeasuredTemplate } from './module/enrichers/TemplateEnricher.mjs';
|
import { renderMeasuredTemplate } from './module/enrichers/TemplateEnricher.mjs';
|
||||||
|
import { registerCountdownHooks } from './module/data/countdowns.mjs';
|
||||||
|
|
||||||
globalThis.SYSTEM = SYSTEM;
|
globalThis.SYSTEM = SYSTEM;
|
||||||
|
|
||||||
|
|
@ -126,39 +128,20 @@ Hooks.on('ready', () => {
|
||||||
ui.resources = new CONFIG.ui.resources();
|
ui.resources = new CONFIG.ui.resources();
|
||||||
if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear !== 'hide')
|
if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear !== 'hide')
|
||||||
ui.resources.render({ force: true });
|
ui.resources.render({ force: true });
|
||||||
|
|
||||||
document.body.classList.toggle(
|
document.body.classList.toggle(
|
||||||
'theme-colorful',
|
'theme-colorful',
|
||||||
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
|
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
|
||||||
DualityRollColor.colorful.value
|
DualityRollColor.colorful.value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
registerCountdownHooks();
|
||||||
|
registerSocketHooks();
|
||||||
|
registerCountdownApplicationHooks();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.once('dicesoniceready', () => {});
|
Hooks.once('dicesoniceready', () => {});
|
||||||
|
|
||||||
Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
|
|
||||||
if (game.user.isGM) {
|
|
||||||
const document = uuid ? await fromUuid(uuid) : null;
|
|
||||||
switch (action) {
|
|
||||||
case GMUpdateEvent.UpdateDocument:
|
|
||||||
if (document && update) {
|
|
||||||
await document.update(update);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GMUpdateEvent.UpdateFear:
|
|
||||||
if (game.user.isGM) {
|
|
||||||
await game.settings.set(
|
|
||||||
SYSTEM.id,
|
|
||||||
SYSTEM.SETTINGS.gameSettings.Resources.Fear,
|
|
||||||
Math.max(Math.min(update, 6), 0)
|
|
||||||
);
|
|
||||||
Hooks.callAll(socketEvent.DhpFearUpdate);
|
|
||||||
await game.socket.emit(`system.${SYSTEM.id}`, { action: socketEvent.DhpFearUpdate });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Hooks.on('renderChatMessageHTML', (_, element) => {
|
Hooks.on('renderChatMessageHTML', (_, element) => {
|
||||||
element
|
element
|
||||||
.querySelectorAll('.duality-roll-button')
|
.querySelectorAll('.duality-roll-button')
|
||||||
|
|
@ -264,6 +247,29 @@ Hooks.on('chatMessage', (_, message) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderJournalDirectory', async (tab, html, _, options) => {
|
||||||
|
if (tab.id === 'journal') {
|
||||||
|
if (options.parts && !options.parts.includes('footer')) return;
|
||||||
|
|
||||||
|
const buttons = tab.element.querySelector('.directory-footer.action-buttons');
|
||||||
|
const title = game.i18n.format('DAGGERHEART.Countdown.Title', {
|
||||||
|
type: game.i18n.localize('DAGGERHEART.Countdown.Types.narrative')
|
||||||
|
});
|
||||||
|
buttons.insertAdjacentHTML(
|
||||||
|
'afterbegin',
|
||||||
|
`
|
||||||
|
<button id="narrative-countdown-button">
|
||||||
|
<i class="fa-solid fa-stopwatch"></i>
|
||||||
|
<span style="font-weight: 400; font-family: var(--font-sans);">${title}</span>
|
||||||
|
</button>`
|
||||||
|
);
|
||||||
|
|
||||||
|
buttons.querySelector('#narrative-countdown-button').onclick = async () => {
|
||||||
|
new NarrativeCountdowns().open();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const preloadHandlebarsTemplates = async function () {
|
const preloadHandlebarsTemplates = async function () {
|
||||||
return foundry.applications.handlebars.loadTemplates([
|
return foundry.applications.handlebars.loadTemplates([
|
||||||
'systems/daggerheart/templates/sheets/parts/attributes.hbs',
|
'systems/daggerheart/templates/sheets/parts/attributes.hbs',
|
||||||
|
|
|
||||||
43
lang/en.json
43
lang/en.json
|
|
@ -83,6 +83,10 @@
|
||||||
"actionPoints": {
|
"actionPoints": {
|
||||||
"label": "Action Points",
|
"label": "Action Points",
|
||||||
"hint": "Automatically give and take Action Points as combatants take their turns."
|
"hint": "Automatically give and take Action Points as combatants take their turns."
|
||||||
|
},
|
||||||
|
"countdowns": {
|
||||||
|
"label": "Countdowns",
|
||||||
|
"hint": "Automatically progress non-custom countdowns"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1027,6 +1031,45 @@
|
||||||
"Title": "Downtime"
|
"Title": "Downtime"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Countdown": {
|
||||||
|
"FIELDS": {
|
||||||
|
"countdowns": {
|
||||||
|
"element": {
|
||||||
|
"name": { "label": "Name" },
|
||||||
|
"progress": {
|
||||||
|
"current": { "label": "Current" },
|
||||||
|
"max": { "label": "Max" },
|
||||||
|
"type": {
|
||||||
|
"value": { "label": "Value" },
|
||||||
|
"label": { "label": "Label", "hint": "Used for custom" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type": {
|
||||||
|
"Spotlight": "Spotlight",
|
||||||
|
"Custom": "Custom",
|
||||||
|
"CharacterAttack": "Character Attack"
|
||||||
|
},
|
||||||
|
"NewCountdown": "New Countdown",
|
||||||
|
"AddCountdown": "Add Countdown",
|
||||||
|
"RemoveCountdownTitle": "Remove Countdown",
|
||||||
|
"RemoveCountdownText": "Are you sure you want to remove the countdown: {name}?",
|
||||||
|
"OpenOwnership": "Edit Player Ownership",
|
||||||
|
"Title": "{type} Countdowns",
|
||||||
|
"Types": {
|
||||||
|
"narrative": "Narrative",
|
||||||
|
"encounter": "Encounter"
|
||||||
|
},
|
||||||
|
"Notifications": {
|
||||||
|
"LimitedOwnershipMaximise": "You don't have permission to enter edit view"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OwnershipSelection": {
|
||||||
|
"Title": "Ownership Selection - {name}",
|
||||||
|
"Default": "Default Ownership"
|
||||||
|
},
|
||||||
"Sheets": {
|
"Sheets": {
|
||||||
"TABS": {
|
"TABS": {
|
||||||
"features": "Features",
|
"features": "Features",
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@ export { default as DhpChatMessage } from './chatMessage.mjs';
|
||||||
export { default as DhpEnvironment } from './sheets/environment.mjs';
|
export { default as DhpEnvironment } from './sheets/environment.mjs';
|
||||||
export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs';
|
export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs';
|
||||||
|
|
||||||
export * as api from './sheets/api/_modules.mjs';
|
export * as api from './sheets/api/_modules.mjs';
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,9 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
return {
|
return {
|
||||||
armor: characterGuide.suggestedArmor ?? null,
|
armor: characterGuide.suggestedArmor ?? null,
|
||||||
primaryWeapon: characterGuide.suggestedPrimaryWeapon ?? null,
|
primaryWeapon: characterGuide.suggestedPrimaryWeapon ?? null,
|
||||||
secondaryWeapon:
|
secondaryWeapon: characterGuide.suggestedSecondaryWeapon
|
||||||
{ ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid } ??
|
? { ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid }
|
||||||
null,
|
: null,
|
||||||
inventory: {
|
inventory: {
|
||||||
take: inventory.take ?? [],
|
take: inventory.take ?? [],
|
||||||
choiceA:
|
choiceA:
|
||||||
|
|
@ -399,11 +399,19 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
const data = TextEditor.getDragEventData(event);
|
const data = TextEditor.getDragEventData(event);
|
||||||
const item = await foundry.utils.fromUuid(data.uuid);
|
const item = await foundry.utils.fromUuid(data.uuid);
|
||||||
if (item.type === 'ancestry' && event.target.closest('.ancestry-card')) {
|
if (item.type === 'ancestry' && event.target.closest('.ancestry-card')) {
|
||||||
this.setup.ancestry = { ...item, uuid: item.uuid };
|
this.setup.ancestry = {
|
||||||
|
...item,
|
||||||
|
effects: Array.from(item.effects).map(x => x.toObject()),
|
||||||
|
uuid: item.uuid
|
||||||
|
};
|
||||||
} else if (item.type === 'community' && event.target.closest('.community-card')) {
|
} else if (item.type === 'community' && event.target.closest('.community-card')) {
|
||||||
this.setup.community = { ...item, uuid: item.uuid };
|
this.setup.community = {
|
||||||
|
...item,
|
||||||
|
effects: Array.from(item.effects).map(x => x.toObject()),
|
||||||
|
uuid: item.uuid
|
||||||
|
};
|
||||||
} else if (item.type === 'class' && event.target.closest('.class-card')) {
|
} else if (item.type === 'class' && event.target.closest('.class-card')) {
|
||||||
this.setup.class = { ...item, uuid: item.uuid };
|
this.setup.class = { ...item, effects: Array.from(item.effects).map(x => x.toObject()), uuid: item.uuid };
|
||||||
this.setup.subclass = {};
|
this.setup.subclass = {};
|
||||||
this.setup.domainCards = {
|
this.setup.domainCards = {
|
||||||
[foundry.utils.randomID()]: {},
|
[foundry.utils.randomID()]: {},
|
||||||
|
|
@ -417,7 +425,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setup.subclass = { ...item, uuid: item.uuid };
|
this.setup.subclass = {
|
||||||
|
...item,
|
||||||
|
effects: Array.from(item.effects).map(x => x.toObject()),
|
||||||
|
uuid: item.uuid
|
||||||
|
};
|
||||||
} else if (item.type === 'domainCard' && event.target.closest('.domain-card')) {
|
} else if (item.type === 'domainCard' && event.target.closest('.domain-card')) {
|
||||||
if (!this.setup.class.uuid) {
|
if (!this.setup.class.uuid) {
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.CharacterCreation.Notifications.MissingClass'));
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.CharacterCreation.Notifications.MissingClass'));
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
|
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
|
||||||
const html = await super.renderHTML();
|
const html = await super.renderHTML();
|
||||||
|
|
||||||
if (
|
if (this.type === 'dualityRoll') {
|
||||||
this.type === 'dualityRoll'
|
|
||||||
) {
|
|
||||||
html.classList.add('duality');
|
html.classList.add('duality');
|
||||||
const dualityResult = this.system.dualityResult;
|
const dualityResult = this.system.dualityResult;
|
||||||
if (dualityResult === DHDualityRoll.dualityResult.hope) html.classList.add('hope');
|
if (dualityResult === DHDualityRoll.dualityResult.hope) html.classList.add('hope');
|
||||||
|
|
|
||||||
339
module/applications/countdowns.mjs
Normal file
339
module/applications/countdowns.mjs
Normal file
|
|
@ -0,0 +1,339 @@
|
||||||
|
import { countdownTypes } from '../config/generalConfig.mjs';
|
||||||
|
import { GMUpdateEvent, RefreshType, socketEvent } from '../helpers/socket.mjs';
|
||||||
|
import OwnershipSelection from './ownershipSelection.mjs';
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(basePath) {
|
||||||
|
super({});
|
||||||
|
|
||||||
|
this.basePath = basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.format('DAGGERHEART.Countdown.Title', {
|
||||||
|
type: game.i18n.localize(`DAGGERHEART.Countdown.Types.${this.basePath}`)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ['daggerheart', 'dh-style', 'countdown'],
|
||||||
|
tag: 'form',
|
||||||
|
position: { width: 740, height: 700 },
|
||||||
|
window: {
|
||||||
|
frame: true,
|
||||||
|
title: 'Countdowns',
|
||||||
|
resizable: true,
|
||||||
|
minimizable: true
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
addCountdown: this.addCountdown,
|
||||||
|
removeCountdown: this.removeCountdown,
|
||||||
|
editImage: this.onEditImage,
|
||||||
|
openOwnership: this.openOwnership,
|
||||||
|
openCountdownOwnership: this.openCountdownOwnership
|
||||||
|
},
|
||||||
|
form: { handler: this.updateData, submitOnChange: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
countdowns: {
|
||||||
|
template: 'systems/daggerheart/templates/views/countdowns.hbs',
|
||||||
|
scrollable: ['.expanded-view']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
htmlElement.querySelectorAll('.mini-countdown-container').forEach(element => {
|
||||||
|
element.addEventListener('click', event => this.updateCountdownValue.bind(this)(event, true));
|
||||||
|
element.addEventListener('contextmenu', event => this.updateCountdownValue.bind(this)(event, false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onFirstRender(context, options) {
|
||||||
|
super._onFirstRender(context, options);
|
||||||
|
|
||||||
|
this.element.querySelector('.expanded-view').classList.toggle('hidden');
|
||||||
|
this.element.querySelector('.minimized-view').classList.toggle('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
const countdownData = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
||||||
|
|
||||||
|
context.isGM = game.user.isGM;
|
||||||
|
context.base = this.basePath;
|
||||||
|
|
||||||
|
context.canCreate = countdownData.playerOwnership[game.user.id].value === CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER;
|
||||||
|
context.source = {
|
||||||
|
...countdownData,
|
||||||
|
countdowns: Object.keys(countdownData.countdowns).reduce((acc, key) => {
|
||||||
|
const countdown = countdownData.countdowns[key];
|
||||||
|
|
||||||
|
const ownershipValue = countdown.playerOwnership[game.user.id].value;
|
||||||
|
if (ownershipValue > CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE) {
|
||||||
|
acc[key] = { ...countdown, canEdit: ownershipValue === CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER };
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
};
|
||||||
|
context.systemFields = countdownData.schema.fields;
|
||||||
|
context.countdownFields = context.systemFields.countdowns.element.fields;
|
||||||
|
context.minimized = this.minimized || _options.isFirstRender;
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async updateData(event, _, formData) {
|
||||||
|
const data = foundry.utils.expandObject(formData.object);
|
||||||
|
const newSetting = foundry.utils.mergeObject(
|
||||||
|
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns).toObject(),
|
||||||
|
data
|
||||||
|
);
|
||||||
|
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, newSetting);
|
||||||
|
this.render();
|
||||||
|
} else {
|
||||||
|
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
action: socketEvent.GMUpdate,
|
||||||
|
data: {
|
||||||
|
action: GMUpdateEvent.UpdateSetting,
|
||||||
|
uuid: SYSTEM.SETTINGS.gameSettings.Countdowns,
|
||||||
|
update: newSetting
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async minimize() {
|
||||||
|
await super.minimize();
|
||||||
|
|
||||||
|
this.element.querySelector('.expanded-view').classList.toggle('hidden');
|
||||||
|
this.element.querySelector('.minimized-view').classList.toggle('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
async maximize() {
|
||||||
|
if (this.minimized) {
|
||||||
|
const settings = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
||||||
|
if (settings.playerOwnership[game.user.id].value <= CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED) {
|
||||||
|
ui.notifications.info(game.i18n.localize('DAGGERHEART.Countdown.Notifications.LimitedOwnership'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.querySelector('.expanded-view').classList.toggle('hidden');
|
||||||
|
this.element.querySelector('.minimized-view').classList.toggle('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
await super.maximize();
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSetting(update) {
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, update);
|
||||||
|
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.Countdown,
|
||||||
|
application: `${this.basePath}-countdowns`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
} else {
|
||||||
|
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
action: socketEvent.GMUpdate,
|
||||||
|
data: {
|
||||||
|
action: GMUpdateEvent.UpdateSetting,
|
||||||
|
uuid: SYSTEM.SETTINGS.gameSettings.Countdowns,
|
||||||
|
update: update,
|
||||||
|
refresh: { refreshType: RefreshType.Countdown, application: `${this.basePath}-countdowns` }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static onEditImage(_, target) {
|
||||||
|
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
||||||
|
const current = setting.countdowns[target.dataset.countdown].img;
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current,
|
||||||
|
type: 'image',
|
||||||
|
callback: async path => this.updateImage.bind(this)(path, target.dataset.countdown),
|
||||||
|
top: this.position.top + 40,
|
||||||
|
left: this.position.left + 10
|
||||||
|
});
|
||||||
|
return fp.browse();
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateImage(path, countdown) {
|
||||||
|
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
await setting.updateSource({
|
||||||
|
[`${this.basePath}.countdowns.${countdown}.img`]: path
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.updateSetting(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
static openOwnership(_, target) {
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
||||||
|
const ownership = { default: setting.ownership.default, players: setting.playerOwnership };
|
||||||
|
new OwnershipSelection(resolve, reject, this.title, ownership).render(true);
|
||||||
|
}).then(async ownership => {
|
||||||
|
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
await setting.updateSource({
|
||||||
|
[`${this.basePath}.ownership`]: ownership
|
||||||
|
});
|
||||||
|
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, setting.toObject());
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static openCountdownOwnership(_, target) {
|
||||||
|
const countdownId = target.dataset.countdown;
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const countdown = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath]
|
||||||
|
.countdowns[countdownId];
|
||||||
|
const ownership = { default: countdown.ownership.default, players: countdown.playerOwnership };
|
||||||
|
new OwnershipSelection(resolve, reject, countdown.name, ownership).render(true);
|
||||||
|
}).then(async ownership => {
|
||||||
|
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
await setting.updateSource({
|
||||||
|
[`${this.basePath}.countdowns.${countdownId}.ownership`]: ownership
|
||||||
|
});
|
||||||
|
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, setting);
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateCountdownValue(event, increase) {
|
||||||
|
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
const countdown = countdownSetting[this.basePath].countdowns[event.currentTarget.dataset.countdown];
|
||||||
|
|
||||||
|
if (countdown.playerOwnership[game.user.id] < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentValue = countdown.progress.current;
|
||||||
|
|
||||||
|
if (increase && currentValue === countdown.progress.max) return;
|
||||||
|
if (!increase && currentValue === 0) return;
|
||||||
|
|
||||||
|
await countdownSetting.updateSource({
|
||||||
|
[`${this.basePath}.countdowns.${event.currentTarget.dataset.countdown}.progress.current`]: increase
|
||||||
|
? currentValue + 1
|
||||||
|
: currentValue - 1
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.updateSetting(countdownSetting.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
static async addCountdown() {
|
||||||
|
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
await countdownSetting.updateSource({
|
||||||
|
[`${this.basePath}.countdowns.${foundry.utils.randomID()}`]: {
|
||||||
|
name: game.i18n.localize('DAGGERHEART.Countdown.NewCountdown'),
|
||||||
|
ownership: game.user.isGM
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
players: {
|
||||||
|
[game.user.id]: { type: CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.updateSetting(countdownSetting.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
static async removeCountdown(_, target) {
|
||||||
|
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
const countdownName = countdownSetting[this.basePath].countdowns[target.dataset.countdown].name;
|
||||||
|
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize('DAGGERHEART.Countdown.RemoveCountdownTitle')
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.Countdown.RemoveCountdownText', { name: countdownName })
|
||||||
|
});
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
await countdownSetting.updateSource({ [`${this.basePath}.countdowns.-=${target.dataset.countdown}`]: null });
|
||||||
|
|
||||||
|
await this.updateSetting(countdownSetting.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.render(true);
|
||||||
|
if (
|
||||||
|
Object.keys(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath].countdowns)
|
||||||
|
.length > 0
|
||||||
|
) {
|
||||||
|
this.minimize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NarrativeCountdowns extends Countdowns {
|
||||||
|
constructor() {
|
||||||
|
super('narrative');
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: 'narrative-countdowns'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EncounterCountdowns extends Countdowns {
|
||||||
|
constructor() {
|
||||||
|
super('encounter');
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: 'encounter-countdowns'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const registerCountdownApplicationHooks = () => {
|
||||||
|
const updateCountdowns = async shouldProgress => {
|
||||||
|
if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).countdowns) {
|
||||||
|
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
|
||||||
|
for (let countdownCategoryKey in countdownSetting) {
|
||||||
|
const countdownCategory = countdownSetting[countdownCategoryKey];
|
||||||
|
for (let countdownKey in countdownCategory.countdowns) {
|
||||||
|
const countdown = countdownCategory.countdowns[countdownKey];
|
||||||
|
|
||||||
|
if (shouldProgress(countdown)) {
|
||||||
|
await countdownSetting.updateSource({
|
||||||
|
[`${countdownCategoryKey}.countdowns.${countdownKey}.progress.current`]:
|
||||||
|
countdown.progress.current - 1
|
||||||
|
});
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, countdownSetting);
|
||||||
|
foundry.applications.instances.get(`${countdownCategoryKey}-countdowns`)?.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Hooks.on(SYSTEM.HOOKS.characterAttack, async () => {
|
||||||
|
updateCountdowns(countdown => {
|
||||||
|
return (
|
||||||
|
countdown.progress.type.value === countdownTypes.characterAttack.id && countdown.progress.current > 0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on(SYSTEM.HOOKS.spotlight, async () => {
|
||||||
|
updateCountdowns(countdown => {
|
||||||
|
return countdown.progress.type.value === countdownTypes.spotlight.id && countdown.progress.current > 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
72
module/applications/ownershipSelection.mjs
Normal file
72
module/applications/ownershipSelection.mjs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class OwnershipSelection extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(resolve, reject, name, ownership) {
|
||||||
|
super({});
|
||||||
|
|
||||||
|
this.resolve = resolve;
|
||||||
|
this.reject = reject;
|
||||||
|
this.name = name;
|
||||||
|
this.ownership = ownership;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'form',
|
||||||
|
classes: ['daggerheart', 'views', 'ownership-selection'],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
height: 'auto'
|
||||||
|
},
|
||||||
|
form: { handler: this.updateData }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
selection: {
|
||||||
|
template: 'systems/daggerheart/templates/views/ownershipSelection.hbs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.format('DAGGERHEART.OwnershipSelection.Title', { name: this.name });
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
context.ownershipOptions = Object.keys(CONST.DOCUMENT_OWNERSHIP_LEVELS).map(level => ({
|
||||||
|
value: CONST.DOCUMENT_OWNERSHIP_LEVELS[level],
|
||||||
|
label: game.i18n.localize(`OWNERSHIP.${level}`)
|
||||||
|
}));
|
||||||
|
context.ownership = {
|
||||||
|
default: this.ownership.default,
|
||||||
|
players: Object.keys(this.ownership.players).reduce((acc, x) => {
|
||||||
|
const user = game.users.get(x);
|
||||||
|
if (!user.isGM) {
|
||||||
|
acc[x] = {
|
||||||
|
img: user.character?.img ?? 'icons/svg/cowled.svg',
|
||||||
|
name: user.name,
|
||||||
|
ownership: this.ownership.players[x].value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async updateData(event, _, formData) {
|
||||||
|
const { ownership } = foundry.utils.expandObject(formData.object);
|
||||||
|
|
||||||
|
this.resolve(ownership);
|
||||||
|
this.close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(fromSave) {
|
||||||
|
if (!fromSave) {
|
||||||
|
this.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
await super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
|
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
|
||||||
|
import DhCountdowns from '../data/countdowns.mjs';
|
||||||
import {
|
import {
|
||||||
DhAppearance,
|
DhAppearance,
|
||||||
DhAutomation,
|
DhAutomation,
|
||||||
|
|
@ -130,4 +131,10 @@ const registerNonConfigSettings = () => {
|
||||||
ui.combat.render({ force: true });
|
ui.combat.render({ force: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, {
|
||||||
|
scope: 'world',
|
||||||
|
config: false,
|
||||||
|
type: DhCountdowns
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,11 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||||
static async attackRoll(event, button) {
|
static async attackRoll(event, button) {
|
||||||
const weapon = await fromUuid(button.dataset.weapon);
|
const weapon = await fromUuid(button.dataset.weapon);
|
||||||
if (!weapon) return;
|
if (!weapon) return;
|
||||||
weapon.use(event);
|
|
||||||
|
const wasUsed = await weapon.use(event);
|
||||||
|
if (wasUsed) {
|
||||||
|
Hooks.callAll(SYSTEM.HOOKS.characterAttack, {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static openLevelUp() {
|
static openLevelUp() {
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,20 @@ export const abilityCosts = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const countdownTypes = {
|
||||||
|
spotlight: {
|
||||||
|
id: 'spotlight',
|
||||||
|
label: 'DAGGERHEART.Countdown.Type.Spotlight'
|
||||||
|
},
|
||||||
|
characterAttack: {
|
||||||
|
id: 'characterAttack',
|
||||||
|
label: 'DAGGERHEART.Countdown.Type.CharacterAttack'
|
||||||
|
},
|
||||||
|
custom: {
|
||||||
|
id: 'custom',
|
||||||
|
label: 'DAGGERHEART.Countdown.Type.Custom'
|
||||||
|
}
|
||||||
|
};
|
||||||
export const rollTypes = {
|
export const rollTypes = {
|
||||||
weapon: {
|
weapon: {
|
||||||
id: 'weapon',
|
id: 'weapon',
|
||||||
|
|
|
||||||
4
module/config/hooksConfig.mjs
Normal file
4
module/config/hooksConfig.mjs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export const hooks = {
|
||||||
|
characterAttack: 'characterAttackHook',
|
||||||
|
spotlight: 'spotlightHook'
|
||||||
|
};
|
||||||
|
|
@ -26,7 +26,8 @@ export const gameSettings = {
|
||||||
Resources: {
|
Resources: {
|
||||||
Fear: 'ResourcesFear'
|
Fear: 'ResourcesFear'
|
||||||
},
|
},
|
||||||
LevelTiers: 'LevelTiers'
|
LevelTiers: 'LevelTiers',
|
||||||
|
Countdowns: 'Countdowns'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DualityRollColor = {
|
export const DualityRollColor = {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import * as DOMAIN from './domainConfig.mjs';
|
||||||
import * as ACTOR from './actorConfig.mjs';
|
import * as ACTOR from './actorConfig.mjs';
|
||||||
import * as ITEM from './itemConfig.mjs';
|
import * as ITEM from './itemConfig.mjs';
|
||||||
import * as SETTINGS from './settingsConfig.mjs';
|
import * as SETTINGS from './settingsConfig.mjs';
|
||||||
|
import { hooks as HOOKS } from './hooksConfig.mjs';
|
||||||
import * as EFFECTS from './effectConfig.mjs';
|
import * as EFFECTS from './effectConfig.mjs';
|
||||||
import * as ACTIONS from './actionConfig.mjs';
|
import * as ACTIONS from './actionConfig.mjs';
|
||||||
|
|
||||||
|
|
@ -15,6 +16,7 @@ export const SYSTEM = {
|
||||||
ACTOR,
|
ACTOR,
|
||||||
ITEM,
|
ITEM,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
HOOKS,
|
||||||
EFFECTS,
|
EFFECTS,
|
||||||
ACTIONS,
|
ACTIONS
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
import DHAbilityUse from "./abilityUse.mjs";
|
import DHAbilityUse from './abilityUse.mjs';
|
||||||
import DHAdversaryRoll from "./adversaryRoll.mjs";
|
import DHAdversaryRoll from './adversaryRoll.mjs';
|
||||||
import DHDamageRoll from "./damageRoll.mjs";
|
import DHDamageRoll from './damageRoll.mjs';
|
||||||
import DHDualityRoll from "./dualityRoll.mjs";
|
import DHDualityRoll from './dualityRoll.mjs';
|
||||||
|
|
||||||
export {
|
export { DHAbilityUse, DHAdversaryRoll, DHDamageRoll, DHDualityRoll };
|
||||||
DHAbilityUse,
|
|
||||||
DHAdversaryRoll,
|
|
||||||
DHDamageRoll,
|
|
||||||
DHDualityRoll,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
abilityUse: DHAbilityUse,
|
abilityUse: DHAbilityUse,
|
||||||
adversaryRoll: DHAdversaryRoll,
|
adversaryRoll: DHAdversaryRoll,
|
||||||
damageRoll: DHDamageRoll,
|
damageRoll: DHDamageRoll,
|
||||||
dualityRoll: DHDualityRoll,
|
dualityRoll: DHDualityRoll
|
||||||
};
|
};
|
||||||
|
|
|
||||||
139
module/data/countdowns.mjs
Normal file
139
module/data/countdowns.mjs
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
import { countdownTypes } from '../config/generalConfig.mjs';
|
||||||
|
import { RefreshType, socketEvent } from '../helpers/socket.mjs';
|
||||||
|
|
||||||
|
export default class DhCountdowns extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
return {
|
||||||
|
narrative: new fields.EmbeddedDataField(DhCountdownData),
|
||||||
|
encounter: new fields.EmbeddedDataField(DhCountdownData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CountdownCategories = { narrative: 'narrative', combat: 'combat' };
|
||||||
|
}
|
||||||
|
|
||||||
|
class DhCountdownData extends foundry.abstract.DataModel {
|
||||||
|
static LOCALIZATION_PREFIXES = ['DAGGERHEART.Countdown']; // Nots ure why this won't work. Setting labels manually for now
|
||||||
|
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhCountdown)),
|
||||||
|
ownership: new fields.SchemaField({
|
||||||
|
default: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS),
|
||||||
|
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE
|
||||||
|
}),
|
||||||
|
players: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
type: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS),
|
||||||
|
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get playerOwnership() {
|
||||||
|
return Array.from(game.users).reduce((acc, user) => {
|
||||||
|
acc[user.id] = {
|
||||||
|
value: user.isGM
|
||||||
|
? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER
|
||||||
|
: this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1
|
||||||
|
? this.ownership.players[user.id].type
|
||||||
|
: this.ownership.default,
|
||||||
|
isGM: user.isGM
|
||||||
|
};
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DhCountdown extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
name: new fields.StringField({
|
||||||
|
required: true,
|
||||||
|
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.name.label'
|
||||||
|
}),
|
||||||
|
img: new fields.FilePathField({
|
||||||
|
categories: ['IMAGE'],
|
||||||
|
base64: false,
|
||||||
|
initial: 'icons/magic/time/hourglass-yellow-green.webp'
|
||||||
|
}),
|
||||||
|
ownership: new fields.SchemaField({
|
||||||
|
default: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS),
|
||||||
|
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE
|
||||||
|
}),
|
||||||
|
players: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
type: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS),
|
||||||
|
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
progress: new fields.SchemaField({
|
||||||
|
current: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
integer: true,
|
||||||
|
initial: 1,
|
||||||
|
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.current.label'
|
||||||
|
}),
|
||||||
|
max: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
integer: true,
|
||||||
|
initial: 1,
|
||||||
|
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.max.label'
|
||||||
|
}),
|
||||||
|
type: new fields.SchemaField({
|
||||||
|
value: new fields.StringField({
|
||||||
|
required: true,
|
||||||
|
choices: countdownTypes,
|
||||||
|
initial: countdownTypes.spotlight.id,
|
||||||
|
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.type.value.label'
|
||||||
|
}),
|
||||||
|
label: new fields.StringField({
|
||||||
|
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.type.label.label'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get playerOwnership() {
|
||||||
|
return Array.from(game.users).reduce((acc, user) => {
|
||||||
|
acc[user.id] = {
|
||||||
|
value: user.isGM
|
||||||
|
? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER
|
||||||
|
: this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1
|
||||||
|
? this.ownership.players[user.id].type
|
||||||
|
: this.ownership.default,
|
||||||
|
isGM: user.isGM
|
||||||
|
};
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const registerCountdownHooks = () => {
|
||||||
|
Hooks.on(socketEvent.Refresh, ({ refreshType, application }) => {
|
||||||
|
if (refreshType === RefreshType.Countdown) {
|
||||||
|
foundry.applications.instances.get(application)?.render();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -10,45 +10,44 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
/** @returns {ItemDataModelMetadata}*/
|
/** @returns {ItemDataModelMetadata}*/
|
||||||
static get metadata() {
|
static get metadata() {
|
||||||
return {
|
return {
|
||||||
label: "Base Item",
|
label: 'Base Item',
|
||||||
type: "base",
|
type: 'base',
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
isQuantifiable: false,
|
isQuantifiable: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const schema = {};
|
const schema = {};
|
||||||
|
|
||||||
if (this.metadata.hasDescription)
|
if (this.metadata.hasDescription) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||||
schema.description = new fields.HTMLField({ required: true, nullable: true });
|
|
||||||
|
|
||||||
if (this.metadata.isQuantifiable)
|
if (this.metadata.isQuantifiable)
|
||||||
schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true });
|
schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true });
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenient access to the item's actor, if it exists.
|
* Convenient access to the item's actor, if it exists.
|
||||||
* @returns {foundry.documents.Actor | null}
|
* @returns {foundry.documents.Actor | null}
|
||||||
*/
|
*/
|
||||||
get actor() {
|
get actor() {
|
||||||
return this.parent.actor;
|
return this.parent.actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a data object used to evaluate any dice rolls associated with this Item Type
|
* Obtain a data object used to evaluate any dice rolls associated with this Item Type
|
||||||
* @param {object} [options] - Options which modify the getRollData method.
|
* @param {object} [options] - Options which modify the getRollData method.
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
getRollData(options = {}) {
|
getRollData(options = {}) {
|
||||||
const actorRollData = this.actor?.getRollData() ?? {};
|
const actorRollData = this.actor?.getRollData() ?? {};
|
||||||
const data = { ...actorRollData, item: { ...this } };
|
const data = { ...actorRollData, item: { ...this } };
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,16 @@ export default class DHClass extends BaseDataItem {
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
|
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
|
||||||
classItems: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
|
|
||||||
evasion: new fields.NumberField({ initial: 0, integer: true }),
|
evasion: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
hopeFeatures: new foundry.data.fields.ArrayField(new ActionField()),
|
hopeFeatures: new foundry.data.fields.ArrayField(new ActionField()),
|
||||||
classFeatures: new foundry.data.fields.ArrayField(new ActionField()),
|
classFeatures: new foundry.data.fields.ArrayField(new ActionField()),
|
||||||
subclasses: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
inventory: new fields.SchemaField({
|
inventory: new fields.SchemaField({
|
||||||
take: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
choiceA: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
choiceA: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
choiceB: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
choiceB: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false })
|
||||||
}),
|
}),
|
||||||
characterGuide: new fields.SchemaField({
|
characterGuide: new fields.SchemaField({
|
||||||
suggestedTraits: new fields.SchemaField({
|
suggestedTraits: new fields.SchemaField({
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import BaseDataItem from "./base.mjs";
|
import BaseDataItem from './base.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import ActionField from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHConsumable extends BaseDataItem {
|
export default class DHConsumable extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static get metadata() {
|
static get metadata() {
|
||||||
return foundry.utils.mergeObject(super.metadata, {
|
return foundry.utils.mergeObject(super.metadata, {
|
||||||
label: "TYPES.Item.consumable",
|
label: 'TYPES.Item.consumable',
|
||||||
type: "consumable",
|
type: 'consumable',
|
||||||
hasDescription: true,
|
hasDescription: true,
|
||||||
isQuantifiable: true,
|
isQuantifiable: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ export default class DHMiscellaneous extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static get metadata() {
|
static get metadata() {
|
||||||
return foundry.utils.mergeObject(super.metadata, {
|
return foundry.utils.mergeObject(super.metadata, {
|
||||||
label: "TYPES.Item.miscellaneous",
|
label: 'TYPES.Item.miscellaneous',
|
||||||
type: "miscellaneous",
|
type: 'miscellaneous',
|
||||||
hasDescription: true,
|
hasDescription: true,
|
||||||
isQuantifiable: true,
|
isQuantifiable: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import BaseDataItem from './base.mjs';
|
||||||
const featureSchema = () => {
|
const featureSchema = () => {
|
||||||
return new foundry.data.fields.SchemaField({
|
return new foundry.data.fields.SchemaField({
|
||||||
name: new foundry.data.fields.StringField({ required: true }),
|
name: new foundry.data.fields.StringField({ required: true }),
|
||||||
effects: new ForeignDocumentUUIDArrayField({type: 'Item', required: false}),
|
effects: new ForeignDocumentUUIDArrayField({ type: 'ActiveEffect', required: false }),
|
||||||
actions: new foundry.data.fields.ArrayField(new ActionField())
|
actions: new foundry.data.fields.ArrayField(new ActionField())
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -64,7 +64,7 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
} else if (subclassData) {
|
} else if (subclassData) {
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassAlreadySelected'));
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassAlreadySelected'));
|
||||||
return false;
|
return false;
|
||||||
} else if (classData.system.subclasses.every(x => x.uuid !== data.uuid ?? `Item.${data._id}`)) {
|
} else if (classData.system.subclasses.every(x => x.uuid !== (data.uuid ?? `Item.${data._id}`))) {
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassNotInClass'));
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Item.Errors.SubclassNotInClass'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
hope: new fields.BooleanField({ required: true, initial: false }),
|
hope: new fields.BooleanField({ required: true, initial: false }),
|
||||||
actionPoints: new fields.BooleanField({ required: true, initial: false })
|
actionPoints: new fields.BooleanField({ required: true, initial: false }),
|
||||||
|
countdowns: new fields.BooleanField({ requireD: true, initial: false })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ export default class DhpActor extends Actor {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.type === 'character') {
|
if (this.type === 'character') {
|
||||||
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
|
const automateHope = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope;
|
||||||
|
|
||||||
if (automateHope && result.hopeUsed) {
|
if (automateHope && result.hopeUsed) {
|
||||||
await this.update({
|
await this.update({
|
||||||
|
|
@ -330,7 +330,7 @@ export default class DhpActor extends Actor {
|
||||||
hope = roll.dice[0].results[0].result;
|
hope = roll.dice[0].results[0].result;
|
||||||
fear = roll.dice[1].results[0].result;
|
fear = roll.dice[1].results[0].result;
|
||||||
if (
|
if (
|
||||||
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope) &&
|
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope &&
|
||||||
config.roll.type === 'action'
|
config.roll.type === 'action'
|
||||||
) {
|
) {
|
||||||
if (hope > fear) {
|
if (hope > fear) {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,68 @@
|
||||||
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case socketEvent.GMUpdate:
|
case socketEvent.GMUpdate:
|
||||||
Hooks.callAll(socketEvent.GMUpdate, data.action, data.uuid, data.update);
|
Hooks.callAll(socketEvent.GMUpdate, data);
|
||||||
break;
|
break;
|
||||||
case socketEvent.DhpFearUpdate:
|
case socketEvent.DhpFearUpdate:
|
||||||
Hooks.callAll(socketEvent.DhpFearUpdate);
|
Hooks.callAll(socketEvent.DhpFearUpdate);
|
||||||
break;
|
break;
|
||||||
|
case socketEvent.Refresh:
|
||||||
|
Hooks.call(socketEvent.Refresh, data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketEvent = {
|
export const socketEvent = {
|
||||||
GMUpdate: 'DhpGMUpdate',
|
GMUpdate: 'DhGMUpdate',
|
||||||
DhpFearUpdate: 'DhpFearUpdate'
|
Refresh: 'DhRefresh',
|
||||||
|
DhpFearUpdate: 'DhFearUpdate'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GMUpdateEvent = {
|
export const GMUpdateEvent = {
|
||||||
UpdateDocument: 'DhpGMUpdateDocument',
|
UpdateDocument: 'DhGMUpdateDocument',
|
||||||
UpdateFear: 'DhpUpdateFear'
|
UpdateSetting: 'DhGMUpdateSetting',
|
||||||
|
UpdateFear: 'DhGMUpdateFear'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RefreshType = {
|
||||||
|
Countdown: 'DhCoundownRefresh'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerSocketHooks = () => {
|
||||||
|
Hooks.on(socketEvent.GMUpdate, async data => {
|
||||||
|
if (game.user.isGM) {
|
||||||
|
const document = data.uuid ? await fromUuid(data.uuid) : null;
|
||||||
|
switch (data.action) {
|
||||||
|
case GMUpdateEvent.UpdateDocument:
|
||||||
|
if (document && data.update) {
|
||||||
|
await document.update(data.update);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GMUpdateEvent.UpdateSetting:
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(SYSTEM.id, data.uuid, data.update);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GMUpdateEvent.UpdateFear:
|
||||||
|
if (game.user.isGM) {
|
||||||
|
await game.settings.set(
|
||||||
|
SYSTEM.id,
|
||||||
|
SYSTEM.SETTINGS.gameSettings.Resources.Fear,
|
||||||
|
Math.max(Math.min(data.update, 6), 0)
|
||||||
|
);
|
||||||
|
Hooks.callAll(socketEvent.DhpFearUpdate);
|
||||||
|
await game.socket.emit(`system.${SYSTEM.id}`, { action: socketEvent.DhpFearUpdate });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.refresh) {
|
||||||
|
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: data.refresh
|
||||||
|
});
|
||||||
|
Hooks.call(socketEvent.Refresh, data.refresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
import { EncounterCountdowns } from '../applications/countdowns.mjs';
|
||||||
|
|
||||||
export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
actions: {
|
actions: {
|
||||||
requestSpotlight: this.requestSpotlight,
|
requestSpotlight: this.requestSpotlight,
|
||||||
toggleSpotlight: this.toggleSpotlight,
|
toggleSpotlight: this.toggleSpotlight,
|
||||||
setActionTokens: this.setActionTokens
|
setActionTokens: this.setActionTokens,
|
||||||
|
openCountdowns: this.openCountdowns
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -83,6 +86,8 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
||||||
.map(x => x.id)
|
.map(x => x.id)
|
||||||
.indexOf(combatantId);
|
.indexOf(combatantId);
|
||||||
|
|
||||||
|
if (this.viewed.turn !== toggleTurn) Hooks.callAll(SYSTEM.HOOKS.spotlight, {});
|
||||||
|
|
||||||
await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn });
|
await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn });
|
||||||
await combatant.update({ 'system.spotlight.requesting': false });
|
await combatant.update({ 'system.spotlight.requesting': false });
|
||||||
}
|
}
|
||||||
|
|
@ -97,4 +102,8 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
||||||
await combatant.update({ 'system.actionTokens': newIndex });
|
await combatant.update({ 'system.actionTokens': newIndex });
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static openCountdowns() {
|
||||||
|
new EncounterCountdowns().open();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1718
package-lock.json
generated
1718
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -8,6 +8,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"",
|
"start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"",
|
||||||
"start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp",
|
"start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp",
|
||||||
|
"build": "npm run rollup && npm run gulp",
|
||||||
|
"rollup": "rollup -c",
|
||||||
|
"gulp": "gulp less",
|
||||||
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
|
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
|
||||||
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
|
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
|
||||||
"createSymlink": "node ./tools/create-symlink.mjs"
|
"createSymlink": "node ./tools/create-symlink.mjs"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,17 @@
|
||||||
|
.theme-light .daggerheart.dh-style.dialog.character-creation {
|
||||||
|
.tab-navigation nav a .descriptor {
|
||||||
|
background: red;
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
.main-selections-container {
|
||||||
|
.traits-container .suggested-traits-container .suggested-trait-container,
|
||||||
|
.creation-action-footer .footer-section nav a .descriptor,
|
||||||
|
.equipment-selection .simple-equipment-container .simple-equipment label {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.daggerheart.dh-style.dialog.character-creation {
|
.daggerheart.dh-style.dialog.character-creation {
|
||||||
.window-content {
|
.window-content {
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
@ -114,12 +128,12 @@
|
||||||
width: 110px;
|
width: 110px;
|
||||||
min-height: unset;
|
min-height: unset;
|
||||||
border: 1px solid light-dark(@dark-blue, @golden);
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
color: light-dark(@dark, @beige);
|
color: light-dark(@beige, @beige);
|
||||||
background-color: var(--color-warm-3);
|
background-color: light-dark(var(--color-warm-3), var(--color-warm-3));
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-warm-2);
|
background-color: light-dark(var(--color-warm-2), var(--color-warm-2));
|
||||||
filter: drop-shadow(0 0 3px var(--color-warm-2));
|
filter: drop-shadow(0 0 3px light-dark(var(--color-warm-2), var(--color-warm-2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
.chat-message {
|
.chat-message {
|
||||||
.duality-modifiers, .duality-result, .dice-title {
|
.duality-modifiers,
|
||||||
|
.duality-result,
|
||||||
|
.dice-title {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +69,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
&.hope, &.fear {
|
&.hope,
|
||||||
|
&.fear {
|
||||||
.dice-wrapper {
|
.dice-wrapper {
|
||||||
clip-path: polygon(
|
clip-path: polygon(
|
||||||
50% 0%,
|
50% 0%,
|
||||||
|
|
@ -335,8 +338,10 @@
|
||||||
> * {
|
> * {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
.message-content {
|
.message-content {
|
||||||
.duality-modifiers, .duality-result, .dice-title {
|
.duality-modifiers,
|
||||||
|
.duality-result,
|
||||||
|
.dice-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.duality-modifiers {
|
.duality-modifiers {
|
||||||
|
|
@ -364,7 +369,7 @@
|
||||||
}
|
}
|
||||||
.dice-result {
|
.dice-result {
|
||||||
.duality-modifiers {
|
.duality-modifiers {
|
||||||
display: flex; // Default => display: none;
|
display: flex; // Default => display: none;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
.duality-modifier {
|
.duality-modifier {
|
||||||
|
|
@ -375,7 +380,9 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dice-formula, > .dice-total, .part-header {
|
.dice-formula,
|
||||||
|
> .dice-total,
|
||||||
|
.part-header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.dice-tooltip {
|
.dice-tooltip {
|
||||||
|
|
@ -384,7 +391,7 @@
|
||||||
.tooltip-part {
|
.tooltip-part {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
gap: .25rem;
|
gap: 0.25rem;
|
||||||
.dice {
|
.dice {
|
||||||
.dice-rolls {
|
.dice-rolls {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
||||||
154
styles/countdown.less
Normal file
154
styles/countdown.less
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
.theme-light {
|
||||||
|
.daggerheart.dh-style.countdown {
|
||||||
|
&.minimized .minimized-view .mini-countdown-container {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.daggerheart.dh-style.countdown {
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 5px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
legend {
|
||||||
|
font-family: @font-body;
|
||||||
|
font-weight: bold;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.minimized {
|
||||||
|
height: auto !important;
|
||||||
|
max-height: unset !important;
|
||||||
|
max-width: 740px !important;
|
||||||
|
width: auto !important;
|
||||||
|
|
||||||
|
.window-content {
|
||||||
|
display: flex;
|
||||||
|
padding: 4px 8px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minimized-view {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.mini-countdown-container {
|
||||||
|
width: fit-content;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
border: 2px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
color: light-dark(@beige, @dark);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-countdown-name {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-countdown-value {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-content {
|
||||||
|
> div {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.expanded-view {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.countdowns-menu {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdowns-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
|
||||||
|
.countdown-fieldset {
|
||||||
|
width: 340px;
|
||||||
|
height: min-content;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.ownership-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-inner-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.countdown-value-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
/* Background */
|
/* Background */
|
||||||
/* Duality */
|
/* Duality */
|
||||||
/* Fear */
|
/* Fear */
|
||||||
@import '../node_modules/@yaireo/tagify/dist/tagify.css';
|
|
||||||
.daggerheart.sheet.class .editor {
|
.daggerheart.sheet.class .editor {
|
||||||
height: 500px;
|
height: 500px;
|
||||||
}
|
}
|
||||||
|
|
@ -1297,25 +1296,38 @@
|
||||||
.combat-sidebar .encounter-controls.combat {
|
.combat-sidebar .encounter-controls.combat {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.combat-sidebar .encounter-controls.combat .encounter-control-fear-container {
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-fear-dice-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-fear-dice-container .encounter-control-fear-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
.combat-sidebar .encounter-controls.combat .encounter-control-fear-container .dice {
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-fear-dice-container .encounter-control-fear-container .dice {
|
||||||
height: 24px;
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
}
|
}
|
||||||
.combat-sidebar .encounter-controls.combat .encounter-control-fear-container .encounter-control-fear {
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-fear-dice-container .encounter-control-fear-container .encounter-control-fear {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
.combat-sidebar .encounter-controls.combat .encounter-control-fear-container .encounter-control-counter {
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-fear-dice-container .encounter-control-fear-container .encounter-control-counter {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -10px;
|
right: -10px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
.combat-sidebar .encounter-controls.combat .encounter-fear-controls .encounter-countdowns {
|
||||||
|
color: var(--content-link-icon-color);
|
||||||
|
}
|
||||||
.combat-sidebar .encounter-controls.combat .control-buttons {
|
.combat-sidebar .encounter-controls.combat .control-buttons {
|
||||||
width: min-content;
|
width: min-content;
|
||||||
}
|
}
|
||||||
|
|
@ -2512,6 +2524,15 @@ div.daggerheart.views.multiclass {
|
||||||
.item-button .item-icon.checked {
|
.item-button .item-icon.checked {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
.theme-light .daggerheart.dh-style.dialog.character-creation .tab-navigation nav a .descriptor {
|
||||||
|
background: red;
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
.theme-light .daggerheart.dh-style.dialog.character-creation .main-selections-container .traits-container .suggested-traits-container .suggested-trait-container,
|
||||||
|
.theme-light .daggerheart.dh-style.dialog.character-creation .main-selections-container .creation-action-footer .footer-section nav a .descriptor,
|
||||||
|
.theme-light .daggerheart.dh-style.dialog.character-creation .main-selections-container .equipment-selection .simple-equipment-container .simple-equipment label {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
.daggerheart.dh-style.dialog.character-creation .window-content {
|
.daggerheart.dh-style.dialog.character-creation .window-content {
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
@ -2612,12 +2633,12 @@ div.daggerheart.views.multiclass {
|
||||||
width: 110px;
|
width: 110px;
|
||||||
min-height: unset;
|
min-height: unset;
|
||||||
border: 1px solid light-dark(#18162e, #f3c267);
|
border: 1px solid light-dark(#18162e, #f3c267);
|
||||||
color: light-dark(#222, #efe6d8);
|
color: light-dark(#efe6d8, #efe6d8);
|
||||||
background-color: var(--color-warm-3);
|
background-color: light-dark(var(--color-warm-3), var(--color-warm-3));
|
||||||
}
|
}
|
||||||
.daggerheart.dh-style.dialog.character-creation .main-selections-container .section-container .section-inner-container .action-button:hover {
|
.daggerheart.dh-style.dialog.character-creation .main-selections-container .section-container .section-inner-container .action-button:hover {
|
||||||
background-color: var(--color-warm-2);
|
background-color: light-dark(var(--color-warm-2), var(--color-warm-2));
|
||||||
filter: drop-shadow(0 0 3px var(--color-warm-2));
|
filter: drop-shadow(0 0 3px light-dark(var(--color-warm-2), var(--color-warm-2)));
|
||||||
}
|
}
|
||||||
.daggerheart.dh-style.dialog.character-creation .main-selections-container .traits-container {
|
.daggerheart.dh-style.dialog.character-creation .main-selections-container .traits-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -3064,6 +3085,27 @@ div.daggerheart.views.multiclass {
|
||||||
.daggerheart.levelup .levelup-footer {
|
.daggerheart.levelup .levelup-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
.daggerheart.views.ownership-selection .ownership-outer-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.daggerheart.views.ownership-selection .ownership-outer-container .ownership-container {
|
||||||
|
display: flex;
|
||||||
|
border: 2px solid light-dark(#18162e, #f3c267);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.daggerheart.views.ownership-selection .ownership-outer-container .ownership-container img {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
}
|
||||||
|
.daggerheart.views.ownership-selection .ownership-outer-container .ownership-container select {
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
:root {
|
:root {
|
||||||
--shadow-text-stroke: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
--shadow-text-stroke: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||||
--fear-animation: background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
|
--fear-animation: background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
|
||||||
|
|
@ -3178,6 +3220,126 @@ div.daggerheart.views.multiclass {
|
||||||
#resources:has(.fear-bar) {
|
#resources:has(.fear-bar) {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
.theme-light .daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown fieldset {
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 5px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-color: light-dark(#18162e, #f3c267);
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown fieldset legend {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
color: light-dark(#18162e, #f3c267);
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown fieldset legend a {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized {
|
||||||
|
height: auto !important;
|
||||||
|
max-height: unset !important;
|
||||||
|
max-width: 740px !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .window-content {
|
||||||
|
display: flex;
|
||||||
|
padding: 4px 8px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .minimized-view {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container {
|
||||||
|
width: fit-content;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
border: 2px solid light-dark(#18162e, #f3c267);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
color: light-dark(#efe6d8, #222);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container.disabled {
|
||||||
|
cursor: initial;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container .mini-countdown-name {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-menu {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-menu .flex {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset {
|
||||||
|
width: 340px;
|
||||||
|
height: min-content;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .ownership-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container img {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container img.disabled {
|
||||||
|
cursor: initial;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container .countdown-inner-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container .countdown-inner-container .countdown-value-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.daggerheart.dh-style.countdown .window-content > div .expanded-view .countdowns-container .countdown-fieldset .countdown-container .countdown-inner-container .countdown-value-container input {
|
||||||
|
max-width: 80px;
|
||||||
|
}
|
||||||
.daggerheart.dh-style.setting fieldset {
|
.daggerheart.dh-style.setting fieldset {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@
|
||||||
@import './dialog.less';
|
@import './dialog.less';
|
||||||
@import './characterCreation.less';
|
@import './characterCreation.less';
|
||||||
@import './levelup.less';
|
@import './levelup.less';
|
||||||
@import '../node_modules/@yaireo/tagify/dist/tagify.css';
|
@import './ownershipSelection.less';
|
||||||
@import './resources.less';
|
@import './resources.less';
|
||||||
|
@import './countdown.less';
|
||||||
@import './settings.less';
|
@import './settings.less';
|
||||||
|
|
||||||
// new styles imports
|
// new styles imports
|
||||||
|
|
|
||||||
26
styles/ownershipSelection.less
Normal file
26
styles/ownershipSelection.less
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
.daggerheart.views.ownership-selection {
|
||||||
|
.ownership-outer-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.ownership-container {
|
||||||
|
display: flex;
|
||||||
|
border: 2px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,26 +2,42 @@
|
||||||
.encounter-controls.combat {
|
.encounter-controls.combat {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.encounter-control-fear-container {
|
.encounter-fear-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
gap: 8px;
|
||||||
color: black;
|
|
||||||
|
|
||||||
.dice {
|
.encounter-fear-dice-container {
|
||||||
height: 24px;
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
.encounter-control-fear-container {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: black;
|
||||||
|
|
||||||
|
.dice {
|
||||||
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.encounter-control-fear {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.encounter-control-counter {
|
||||||
|
position: absolute;
|
||||||
|
right: -10px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.encounter-control-fear {
|
.encounter-countdowns {
|
||||||
position: absolute;
|
color: var(--content-link-icon-color);
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.encounter-control-counter {
|
|
||||||
position: absolute;
|
|
||||||
right: -10px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,12 @@
|
||||||
{{formInput settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints }}
|
{{formInput settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "DAGGERHEART.Settings.Automation.FIELDS.countdowns.label"}}</label>
|
||||||
|
<div class="form-fields">
|
||||||
|
{{formInput settingFields.schema.fields.countdowns value=settingFields._source.countdowns }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<footer class="form-footer">
|
<footer class="form-footer">
|
||||||
<button data-action="reset">
|
<button data-action="reset">
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,15 @@
|
||||||
|
|
||||||
<div class="encounter-controls {{#if hasCombat}}combat{{/if}}">
|
<div class="encounter-controls {{#if hasCombat}}combat{{/if}}">
|
||||||
{{#if hasCombat}}
|
{{#if hasCombat}}
|
||||||
<div class="encounter-control-fear-container">
|
<div class="encounter-fear-controls">
|
||||||
<img class="dice " src="../icons/svg/d12-grey.svg"/>
|
<div class="encounter-fear-dice-container">
|
||||||
<i class="fas fa-skull encounter-control-fear"></i>
|
<div class="encounter-control-fear-container">
|
||||||
<div class="encounter-control-counter">{{fear}}</div>
|
<img class="dice " src="../icons/svg/d12-grey.svg"/>
|
||||||
|
<i class="fas fa-skull encounter-control-fear"></i>
|
||||||
|
</div>
|
||||||
|
<div>{{fear}}</div>
|
||||||
|
</div>
|
||||||
|
<a class="encounter-countdowns" data-tooltip="{{localize "DAGGERHEART.Countdown.Title" type=(localize "DAGGERHEART.Countdown.Types.combat")}}" data-action="openCountdowns"><i class="fa-solid fa-stopwatch"></i></a>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
|
||||||
42
templates/views/countdowns.hbs
Normal file
42
templates/views/countdowns.hbs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<div>
|
||||||
|
<div class="expanded-view {{#if minimized}}hidden{{/if}}">
|
||||||
|
<div class="countdowns-menu">
|
||||||
|
{{#if canCreate}}<button class="flex" data-action="addCountdown">{{localize "DAGGERHEART.Countdown.AddCountdown"}}</button>{{/if}}
|
||||||
|
{{#if isGM}}<button data-action="openOwnership" data-tooltip="{{localize "DAGGERHEART.Countdown.OpenOwnership"}}"><i class="fa-solid fa-users"></i></button>{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="countdowns-container">
|
||||||
|
{{#each source.countdowns}}
|
||||||
|
<fieldset class="countdown-fieldset">
|
||||||
|
<legend>
|
||||||
|
{{this.name}}
|
||||||
|
{{#if this.canEdit}}<a><i class="fa-solid fa-trash icon-button" data-action="removeCountdown" data-countdown="{{@key}}"></i></a>{{/if}}
|
||||||
|
{{#if @root.isGM}}<a><i class="fa-solid fa-users icon-button" data-action="openCountdownOwnership" data-countdown="{{@key}}" data-tooltip="{{localize "DAGGERHEART.Countdown.OpenOwnership"}}"></i></a>{{/if}}
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="countdown-container">
|
||||||
|
<img src="{{this.img}}" {{#if this.canEdit}}data-action='editImage'{{else}}class="disabled"{{/if}} data-countdown="{{@key}}" />
|
||||||
|
<div class="countdown-inner-container">
|
||||||
|
{{formGroup @root.countdownFields.name name=(concat @root.base ".countdowns." @key ".name") value=this.name localize=true disabled=(not this.canEdit)}}
|
||||||
|
<div class="countdown-value-container">
|
||||||
|
{{formGroup @root.countdownFields.progress.fields.current name=(concat @root.base ".countdowns." @key ".progress.current") value=this.progress.current localize=true disabled=(not this.canEdit)}}
|
||||||
|
{{formGroup @root.countdownFields.progress.fields.max name=(concat @root.base ".countdowns." @key ".progress.max") value=this.progress.max localize=true disabled=(not this.canEdit)}}
|
||||||
|
</div>
|
||||||
|
{{formGroup @root.countdownFields.progress.fields.type.fields.value name=(concat @root.base ".countdowns." @key ".progress.type.value") value=this.progress.type.value localize=true localize=true disabled=(not this.canEdit)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="minimized-view {{#if (not minimized)}}hidden{{/if}}">
|
||||||
|
{{#each source.countdowns}}
|
||||||
|
<a class="mini-countdown-container {{#if (not this.canEdit)}}disabled{{/if}}" data-countdown="{{@key}}">
|
||||||
|
<img src="{{this.img}}" />
|
||||||
|
<div class="mini-countdown-name">{{this.name}}</div>
|
||||||
|
<div class="mini-countdown-value">{{this.progress.current}}/{{this.progress.max}}</div>
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
22
templates/views/ownershipSelection.hbs
Normal file
22
templates/views/ownershipSelection.hbs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="ownership-outer-container">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.OwnershipSelection.Default"}}</label>
|
||||||
|
<select name="ownership.default" data-dtype="Number">
|
||||||
|
{{selectOptions @root.ownershipOptions selected=ownership.default labelAttr="label" valueAttr="value" }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{#each ownership.players as |player id|}}
|
||||||
|
<div class="ownership-container">
|
||||||
|
<img src="{{player.img}}" />
|
||||||
|
<div>{{player.name}}</div>
|
||||||
|
<select name="{{concat "ownership.players." id ".type"}}" data-dtype="Number">
|
||||||
|
{{selectOptions @root.ownershipOptions selected=player.ownership labelAttr="label" valueAttr="value" }}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<footer class="flexrow">
|
||||||
|
<button type="submit">{{localize "Save"}}</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue