diff --git a/lang/en.json b/lang/en.json index 7867265d..d466b0fc 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1312,7 +1312,8 @@ } }, "Experiences": "Experiences", - "Level": "Level" + "Level": "Level", + "noPartner": "No Partner selected" }, "Adversary": { "FIELDS": { diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index 1ee7f37a..c5eb45d9 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -1,6 +1,6 @@ export { default as DhCharacterSheet } from './sheets/actors/character.mjs'; export { default as DhpAdversarySheet } from './sheets/actors/adversary.mjs'; -export { default as DhCompanionSheet } from './sheets/companion.mjs'; +export { default as DhCompanionSheet } from './sheets/actors/companion.mjs'; export { default as DhpClassSheet } from './sheets/items/class.mjs'; export { default as DhpSubclass } from './sheets/items/subclass.mjs'; export { default as DhpFeatureSheet } from './sheets/items/feature.mjs'; diff --git a/module/applications/sheets/actors/companion.mjs b/module/applications/sheets/actors/companion.mjs new file mode 100644 index 00000000..89939e9a --- /dev/null +++ b/module/applications/sheets/actors/companion.mjs @@ -0,0 +1,108 @@ +import DaggerheartSheet from '../daggerheart-sheet.mjs'; +import DHCompanionSettings from '../applications/companion-settings.mjs'; + +const { ActorSheetV2 } = foundry.applications.sheets; +export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'], + position: { width: 300 }, + actions: { + viewActor: this.viewActor, + openSettings: this.openSettings, + useItem: this.useItem, + toChat: this.toChat + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false + } + }; + + static PARTS = { + header: { template: 'systems/daggerheart/templates/sheets/actors/companion/header.hbs' }, + details: { template: 'systems/daggerheart/templates/sheets/actors/companion/details.hbs' }, + effects: { template: 'systems/daggerheart/templates/sheets/actors/companion/effects.hbs' } + }; + + static TABS = { + details: { + active: true, + cssClass: '', + group: 'primary', + id: 'details', + icon: null, + label: 'DAGGERHEART.General.tabs.details' + }, + effects: { + active: false, + cssClass: '', + group: 'primary', + id: 'effects', + icon: null, + label: 'DAGGERHEART.Sheets.PC.Tabs.effects' + } + }; + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.tabs = super._getTabs(this.constructor.TABS); + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object); + this.render(); + } + + static async viewActor(_, button) { + const target = button.closest('[data-item-uuid]'); + const actor = await foundry.utils.fromUuid(target.dataset.itemUuid); + if (!actor) return; + + actor.sheet.render(true); + } + + getAction(element) { + const itemId = (element.target ?? element).closest('[data-item-id]').dataset.itemId, + item = this.document.system.actions.find(x => x.id === itemId); + return item; + } + + static async useItem(event) { + const action = this.getAction(event) ?? this.actor.system.attack; + action.use(event); + } + + static async toChat(event, button) { + if (button?.dataset?.type === 'experience') { + const experience = this.document.system.experiences[button.dataset.uuid]; + const cls = getDocumentClass('ChatMessage'); + const systemData = { + name: game.i18n.localize('DAGGERHEART.General.Experience.Single'), + description: `${experience.name} ${experience.total < 0 ? experience.total : `+${experience.total}`}` + }; + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + system: systemData, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/chat/ability-use.hbs', + systemData + ) + }); + + cls.create(msg.toObject()); + } else { + const item = this.getAction(event) ?? this.document.system.attack; + item.toChat(this.document.id); + } + } + + static async openSettings() { + await new DHCompanionSettings(this.document).render(true); + } +} diff --git a/module/applications/sheets/applications/companion-settings.mjs b/module/applications/sheets/applications/companion-settings.mjs new file mode 100644 index 00000000..89d20a07 --- /dev/null +++ b/module/applications/sheets/applications/companion-settings.mjs @@ -0,0 +1,160 @@ +import { GMUpdateEvent, socketEvent } from '../../../helpers/socket.mjs'; +import DhCompanionlevelUp from '../../levelup/companionLevelup.mjs'; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export default class DHCompanionSettings extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actor) { + super({}); + + this.actor = actor; + } + + get title() { + return `${game.i18n.localize('DAGGERHEART.Sheets.TABS.settings')}`; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'dh-style', 'dialog', 'companion-settings'], + window: { + icon: 'fa-solid fa-wrench', + resizable: false + }, + position: { width: 455, height: 'auto' }, + actions: { + levelUp: this.levelUp + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false + } + }; + + static PARTS = { + header: { + id: 'header', + template: 'systems/daggerheart/templates/sheets/applications/companion-settings/header.hbs' + }, + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + details: { + id: 'details', + template: 'systems/daggerheart/templates/sheets/applications/companion-settings/details.hbs' + }, + experiences: { + id: 'experiences', + template: 'systems/daggerheart/templates/sheets/applications/companion-settings/experiences.hbs' + }, + attack: { + id: 'attack', + template: 'systems/daggerheart/templates/sheets/applications/companion-settings/attack.hbs' + } + }; + + static TABS = { + details: { + active: true, + cssClass: '', + group: 'primary', + id: 'details', + icon: null, + label: 'DAGGERHEART.General.tabs.details' + }, + experiences: { + active: false, + cssClass: '', + group: 'primary', + id: 'experiences', + icon: null, + label: 'DAGGERHEART.General.tabs.experiences' + }, + attack: { + active: false, + cssClass: '', + group: 'primary', + id: 'attack', + icon: null, + label: 'DAGGERHEART.General.tabs.attack' + } + }; + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement.querySelector('.partner-value')?.addEventListener('change', this.onPartnerChange.bind(this)); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.actor; + context.tabs = this._getTabs(this.constructor.TABS); + context.systemFields = this.actor.system.schema.fields; + context.systemFields.attack.fields = this.actor.system.attack.schema.fields; + context.isNPC = true; + context.playerCharacters = game.actors + .filter( + x => + x.type === 'character' && + (x.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) || + this.document.system.partner?.uuid === x.uuid) + ) + .map(x => ({ key: x.uuid, name: x.name })); + + return context; + } + + _getTabs(tabs) { + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? 'active' : ''; + } + + return tabs; + } + + async onPartnerChange(event) { + const partnerDocument = event.target.value + ? await foundry.utils.fromUuid(event.target.value) + : this.actor.system.partner; + const partnerUpdate = { 'system.companion': event.target.value ? this.actor.uuid : null }; + + if (!partnerDocument.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) { + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateDocument, + uuid: partnerDocument.uuid, + update: update + } + }); + } else { + await partnerDocument.update(partnerUpdate); + } + + await this.actor.update({ 'system.partner': event.target.value }); + + if (!event.target.value) { + await this.actor.updateLevel(1); + } + + this.render(); + } + + async viewActor(_, button) { + const target = button.closest('[data-item-uuid]'); + const actor = await foundry.utils.fromUuid(target.dataset.itemUuid); + if (!actor) return; + + actor.sheet.render(true); + } + + static async levelUp() { + new DhCompanionlevelUp(this.actor).render(true); + } + + static async updateForm(event, _, formData) { + await this.actor.update(formData.object); + this.render(); + } +} diff --git a/module/applications/sheets/companion.mjs b/module/applications/sheets/companion.mjs deleted file mode 100644 index 46080814..00000000 --- a/module/applications/sheets/companion.mjs +++ /dev/null @@ -1,86 +0,0 @@ -import { GMUpdateEvent, socketEvent } from '../../helpers/socket.mjs'; -import DhCompanionlevelUp from '../levelup/companionLevelup.mjs'; -import DaggerheartSheet from './daggerheart-sheet.mjs'; - -const { ActorSheetV2 } = foundry.applications.sheets; -export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) { - static DEFAULT_OPTIONS = { - tag: 'form', - classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'], - position: { width: 700, height: 1000 }, - actions: { - attackRoll: this.attackRoll, - levelUp: this.levelUp - }, - form: { - handler: this.updateForm, - submitOnChange: true, - closeOnSubmit: false - } - }; - - static PARTS = { - sidebar: { template: 'systems/daggerheart/templates/sheets/actors/companion/tempMain.hbs' } - }; - - _attachPartListeners(partId, htmlElement, options) { - super._attachPartListeners(partId, htmlElement, options); - - htmlElement.querySelector('.partner-value')?.addEventListener('change', this.onPartnerChange.bind(this)); - } - - async _prepareContext(_options) { - const context = await super._prepareContext(_options); - context.document = this.document; - context.playerCharacters = game.actors - .filter( - x => - x.type === 'character' && - (x.ownership.default === 3 || - x.ownership[game.user.id] === 3 || - this.document.system.partner?.uuid === x.uuid) - ) - .map(x => ({ key: x.uuid, name: x.name })); - - return context; - } - - static async updateForm(event, _, formData) { - await this.document.update(formData.object); - this.render(); - } - - async onPartnerChange(event) { - const partnerDocument = event.target.value - ? await foundry.utils.fromUuid(event.target.value) - : this.document.system.partner; - const partnerUpdate = { 'system.companion': event.target.value ? this.document.uuid : null }; - - if (!partnerDocument.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) { - await game.socket.emit(`system.${SYSTEM.id}`, { - action: socketEvent.GMUpdate, - data: { - action: GMUpdateEvent.UpdateDocument, - uuid: partnerDocument.uuid, - update: update - } - }); - } else { - await partnerDocument.update(partnerUpdate); - } - - await this.document.update({ 'system.partner': event.target.value }); - - if (!event.target.value) { - await this.document.updateLevel(1); - } - } - - static async attackRoll(event) { - this.actor.system.attack.use(event); - } - - static async levelUp() { - new DhCompanionlevelUp(this.document).render(true); - } -} diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index abc38e93..b1254f87 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -47,6 +47,7 @@ export default class DhCompanion extends BaseDataActor { attack: new ActionField({ initial: { name: 'Attack', + img: 'icons/creatures/claws/claw-bear-paw-swipe-brown.webp', _id: foundry.utils.randomID(), systemPath: 'attack', type: 'attack', @@ -57,7 +58,8 @@ export default class DhCompanion extends BaseDataActor { }, roll: { type: 'weapon', - bonus: 0 + bonus: 0, + trait: 'instinct' }, damage: { parts: [ @@ -77,8 +79,10 @@ export default class DhCompanion extends BaseDataActor { }; } - get attackBonus() { - return this.attack.roll.bonus ?? 0; + get traits() { + return { + instinct: { total: this.attack.roll.bonus } + }; } prepareBaseData() { diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 541b76d0..2bb4084f 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -126,6 +126,7 @@ export default class DhpActor extends Actor { } } }); + this.sheet.render(); if (this.system.companion) { this.system.companion.updateLevel(newLevel); @@ -307,6 +308,7 @@ export default class DhpActor extends Actor { } } }); + this.sheet.render(); if (this.system.companion) { this.system.companion.updateLevel(this.system.levelData.level.changed); @@ -338,7 +340,7 @@ export default class DhpActor extends Actor { } get rollClass() { - return CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll']; + return CONFIG.Dice.daggerheart[['character', 'companion'].includes(this.type) ? 'DualityRoll' : 'D20Roll']; } getRollData() { diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 763b7e7d..cc6854ca 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -4989,13 +4989,248 @@ div.daggerheart.views.multiclass { color: light-dark(#18162e50, #efe6d850); font-family: 'Montserrat', sans-serif; } -.application.sheet.daggerheart.actor.dh-style.companion .profile { - height: 80px; - width: 80px; +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; } -.application.sheet.daggerheart.actor.dh-style.companion .temp-container { +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .profile { + height: 235px; + width: 100%; + object-fit: cover; + cursor: pointer; + mask-image: linear-gradient(0deg, transparent 0%, black 10%); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .actor-name { + display: flex; + align-items: center; position: relative; - top: 32px; + top: -30px; + gap: 20px; + padding: 0 20px; + margin-bottom: -30px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .actor-name input[type='text'] { + font-size: 24px; + height: 32px; + text-align: center; + border: 1px solid transparent; + outline: 2px solid transparent; + transition: all 0.3s ease; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .actor-name input[type='text']:hover { + outline: 2px solid light-dark(#222, #f3c267); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section { + display: flex; + gap: 5px; + justify-content: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-number { + justify-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-number .status-value { + position: relative; + display: flex; + width: 50px; + height: 40px; + border: 1px solid light-dark(#18162e, #f3c267); + border-bottom: none; + border-radius: 6px 6px 0 0; + padding: 0 6px; + font-size: 1.5rem; + align-items: center; + justify-content: center; + background: light-dark(transparent, #18162e); + z-index: 2; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-number .status-value.armor-slots { + width: 80px; + height: 30px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-number .status-label { + padding: 2px 10px; + width: 100%; + border-radius: 3px; + background: light-dark(#18162e, #f3c267); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-number .status-label h4 { + font-weight: bold; + text-align: center; + line-height: 18px; + font-size: 12px; + color: light-dark(#efe6d8, #18162e); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar { + position: relative; + width: 100px; + height: 40px; + justify-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-label { + position: relative; + top: 40px; + height: 22px; + width: 79px; + clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z'); + background: light-dark(#18162e, #f3c267); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-label h4 { + font-weight: bold; + text-align: center; + line-height: 18px; + color: light-dark(#efe6d8, #18162e); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value { + position: absolute; + display: flex; + padding: 0 6px; + font-size: 1.5rem; + align-items: center; + width: 100px; + height: 40px; + justify-content: center; + text-align: center; + z-index: 2; + color: #efe6d8; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value input[type='number'] { + background: transparent; + font-size: 1.5rem; + width: 40px; + height: 30px; + text-align: center; + border: none; + outline: 2px solid transparent; + color: #efe6d8; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value input[type='number'].bar-input { + padding: 0; + color: #efe6d8; + backdrop-filter: none; + background: transparent; + transition: all 0.3s ease; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value input[type='number'].bar-input:hover, +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value input[type='number'].bar-input:focus { + background: rgba(24, 22, 46, 0.33); + backdrop-filter: blur(9.5px); +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .status-value .bar-label { + width: 40px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar { + position: absolute; + appearance: none; + width: 100px; + height: 40px; + border: 1px solid light-dark(#18162e, #f3c267); + border-radius: 6px; + z-index: 1; + background: #18162e; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar::-webkit-progress-bar { + border: none; + background: #18162e; + border-radius: 6px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar::-webkit-progress-value { + background: linear-gradient(15deg, #46140a 0%, #be0000 42%, #fcb045 100%); + border-radius: 6px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar.stress-color::-webkit-progress-value { + background: linear-gradient(15deg, #823b01 0%, #fc8e45 65%, #be0000 100%); + border-radius: 6px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar::-moz-progress-bar { + background: linear-gradient(15deg, #46140a 0%, #be0000 42%, #fcb045 100%); + border-radius: 6px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .status-bar .progress-bar.stress-color::-moz-progress-bar { + background: linear-gradient(15deg, #823b01 0%, #fc8e45 65%, #be0000 100%); + border-radius: 6px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .status-section .level-up-label { + font-size: 24px; + padding-top: 8px; +} +.application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet .companion-navigation { + display: flex; + gap: 8px; + align-items: center; + width: 100%; +} +.application.sheet.daggerheart.actor.dh-style.companion .partner-section, +.application.sheet.daggerheart.actor.dh-style.companion .attack-section { + display: flex; + flex-direction: column; + align-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .partner-section .title, +.application.sheet.daggerheart.actor.dh-style.companion .attack-section .title { + display: flex; + gap: 15px; + align-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .partner-section .title h3, +.application.sheet.daggerheart.actor.dh-style.companion .attack-section .title h3 { + font-size: 20px; +} +.application.sheet.daggerheart.actor.dh-style.companion .partner-section .items-list, +.application.sheet.daggerheart.actor.dh-style.companion .attack-section .items-list { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .partner-placeholder { + display: flex; + opacity: 0.6; + text-align: center; + font-style: italic; + justify-content: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .experience-list { + display: flex; + flex-direction: column; + gap: 5px; + width: 100%; + margin-top: 10px; + align-items: center; +} +.application.sheet.daggerheart.actor.dh-style.companion .experience-list .experience-row { + display: flex; + gap: 5px; + width: 250px; + align-items: center; + justify-content: space-between; +} +.application.sheet.daggerheart.actor.dh-style.companion .experience-list .experience-row .experience-name { + width: 180px; + text-align: start; + font-size: 14px; + font-family: 'Montserrat', sans-serif; + color: light-dark(#222, #efe6d8); +} +.application.sheet.daggerheart.actor.dh-style.companion .experience-list .experience-value { + height: 25px; + width: 35px; + font-size: 14px; + font-family: 'Montserrat', sans-serif; + color: light-dark(#222, #efe6d8); + align-content: center; + text-align: center; + background: url(../assets/svg/experience-shield.svg) no-repeat; +} +.theme-light .application.sheet.daggerheart.actor.dh-style.companion .experience-list .experience-value { + background: url('../assets/svg/experience-shield-light.svg') no-repeat; +} +.theme-light .application.sheet.daggerheart.actor.dh-style.companion { + background: url('../assets/parchments/dh-parchment-light.png'); +} +.theme-dark .application.sheet.daggerheart.actor.dh-style.companion { + background-image: url('../assets/parchments/dh-parchment-dark.png'); } .application.sheet.daggerheart.actor.dh-style.adversary .window-content { overflow: auto; @@ -5290,6 +5525,19 @@ div.daggerheart.views.multiclass { box-shadow: none; outline: 2px solid light-dark(#222, #efe6d8); } +.application.dh-style input[type='text']:disabled[type='text'], +.application.dh-style input[type='number']:disabled[type='text'], +.application.dh-style input[type='text']:disabled[type='number'], +.application.dh-style input[type='number']:disabled[type='number'] { + outline: 2px solid transparent; + cursor: not-allowed; +} +.application.dh-style input[type='text']:disabled[type='text']:hover, +.application.dh-style input[type='number']:disabled[type='text']:hover, +.application.dh-style input[type='text']:disabled[type='number']:hover, +.application.dh-style input[type='number']:disabled[type='number']:hover { + background: transparent; +} .application.dh-style input[type='checkbox']:checked::after { color: light-dark(#222, #f3c267); } @@ -5313,6 +5561,16 @@ div.daggerheart.views.multiclass { .application.dh-style button.glow { animation: glow 0.75s infinite alternate; } +.application.dh-style button:disabled { + background: light-dark(transparent, #f3c267); + color: light-dark(#18162e, #18162e); + opacity: 0.6; + cursor: not-allowed; +} +.application.dh-style button:disabled:hover { + background: light-dark(transparent, #f3c267); + color: light-dark(#18162e, #18162e); +} .application.dh-style select { background: light-dark(transparent, transparent); color: light-dark(#222, #efe6d8); diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 8903dcf0..49c66916 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -40,6 +40,8 @@ @import './less/applications/environment-settings/actions.less'; @import './less/applications/environment-settings/adversaries.less'; +@import './less/actors/companion/header.less'; +@import './less/actors/companion/details.less'; @import './less/actors/companion/sheet.less'; @import './less/actors/adversary.less'; diff --git a/styles/less/actors/companion/details.less b/styles/less/actors/companion/details.less new file mode 100644 index 00000000..4da8d126 --- /dev/null +++ b/styles/less/actors/companion/details.less @@ -0,0 +1,75 @@ +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + +.application.sheet.daggerheart.actor.dh-style.companion { + .partner-section, + .attack-section { + display: flex; + flex-direction: column; + align-items: center; + + .title { + display: flex; + gap: 15px; + align-items: center; + + h3 { + font-size: 20px; + } + } + .items-list { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + } + } + + .partner-placeholder { + display: flex; + opacity: 0.6; + text-align: center; + font-style: italic; + justify-content: center; + } + + .experience-list { + display: flex; + flex-direction: column; + gap: 5px; + width: 100%; + margin-top: 10px; + align-items: center; + + .experience-row { + display: flex; + gap: 5px; + width: 250px; + align-items: center; + justify-content: space-between; + + .experience-name { + width: 180px; + text-align: start; + font-size: 14px; + font-family: @font-body; + color: light-dark(@dark, @beige); + } + } + + .experience-value { + height: 25px; + width: 35px; + font-size: 14px; + font-family: @font-body; + color: light-dark(@dark, @beige); + align-content: center; + text-align: center; + background: url(../assets/svg/experience-shield.svg) no-repeat; + + .theme-light & { + background: url('../assets/svg/experience-shield-light.svg') no-repeat; + } + } + } +} diff --git a/styles/less/actors/companion/header.less b/styles/less/actors/companion/header.less new file mode 100644 index 00000000..df68747b --- /dev/null +++ b/styles/less/actors/companion/header.less @@ -0,0 +1,197 @@ +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + +.application.sheet.daggerheart.actor.dh-style.companion { + .companion-header-sheet { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + + .profile { + height: 235px; + width: 100%; + object-fit: cover; + cursor: pointer; + mask-image: linear-gradient(0deg, transparent 0%, black 10%); + } + + .actor-name { + display: flex; + align-items: center; + position: relative; + top: -30px; + gap: 20px; + padding: 0 20px; + margin-bottom: -30px; + + input[type='text'] { + font-size: 24px; + height: 32px; + text-align: center; + border: 1px solid transparent; + outline: 2px solid transparent; + transition: all 0.3s ease; + + &:hover { + outline: 2px solid light-dark(@dark, @golden); + } + } + } + + .status-section { + display: flex; + gap: 5px; + justify-content: center; + + .status-number { + justify-items: center; + + .status-value { + position: relative; + display: flex; + width: 50px; + height: 40px; + border: 1px solid light-dark(@dark-blue, @golden); + border-bottom: none; + border-radius: 6px 6px 0 0; + padding: 0 6px; + font-size: 1.5rem; + align-items: center; + justify-content: center; + background: light-dark(transparent, @dark-blue); + z-index: 2; + + &.armor-slots { + width: 80px; + height: 30px; + } + } + + .status-label { + padding: 2px 10px; + width: 100%; + border-radius: 3px; + background: light-dark(@dark-blue, @golden); + + h4 { + font-weight: bold; + text-align: center; + line-height: 18px; + font-size: 12px; + color: light-dark(@beige, @dark-blue); + } + } + } + + .status-bar { + position: relative; + width: 100px; + height: 40px; + justify-items: center; + + .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); + } + } + .status-value { + position: absolute; + display: flex; + padding: 0 6px; + font-size: 1.5rem; + align-items: center; + width: 100px; + 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; + } + } + } + + .level-up-label { + font-size: 24px; + padding-top: 8px; + } + } + + .companion-navigation { + display: flex; + gap: 8px; + align-items: center; + width: 100%; + } + } +} diff --git a/styles/less/actors/companion/sheet.less b/styles/less/actors/companion/sheet.less index 1beb28a7..db221597 100644 --- a/styles/less/actors/companion/sheet.less +++ b/styles/less/actors/companion/sheet.less @@ -1,11 +1,18 @@ .application.sheet.daggerheart.actor.dh-style.companion { - .profile { - height: 80px; - width: 80px; + .theme-light & { + background: url('../assets/parchments/dh-parchment-light.png'); + } + .theme-dark & { + background-image: url('../assets/parchments/dh-parchment-dark.png'); } - .temp-container { - position: relative; - top: 32px; - } + // .profile { + // height: 80px; + // width: 80px; + // } + + // .temp-container { + // position: relative; + // top: 32px; + // } } diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 1f6e5988..fcf9d353 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -23,6 +23,16 @@ box-shadow: none; outline: 2px solid light-dark(@dark, @beige); } + + &:disabled[type='text'], + &:disabled[type='number'] { + outline: 2px solid transparent; + cursor: not-allowed; + + &:hover { + background: transparent; + } + } } input[type='checkbox'] { @@ -52,6 +62,18 @@ &.glow { animation: glow 0.75s infinite alternate; } + + &:disabled { + background: light-dark(transparent, @golden); + color: light-dark(@dark-blue, @dark-blue); + opacity: 0.6; + cursor: not-allowed; + + &:hover { + background: light-dark(transparent, @golden); + color: light-dark(@dark-blue, @dark-blue); + } + } } select { diff --git a/templates/sheets/actors/companion/details.hbs b/templates/sheets/actors/companion/details.hbs new file mode 100644 index 00000000..f337d009 --- /dev/null +++ b/templates/sheets/actors/companion/details.hbs @@ -0,0 +1,43 @@ +
+
+
+ +

Partner

+ +
+ {{#if document.system.partner}} + + {{else}} + {{localize "DAGGERHEART.Sheets.Companion.noPartner"}} + {{/if}} +
+
+
+ +

Attack

+ +
+ +
+
+ {{#each source.system.experiences as |experience id|}} +
+
+ +{{experience.value}} +
+ {{experience.name}} +
+ +
+
+ {{/each}} +
+
\ No newline at end of file diff --git a/templates/sheets/actors/companion/effects.hbs b/templates/sheets/actors/companion/effects.hbs new file mode 100644 index 00000000..9046fff8 --- /dev/null +++ b/templates/sheets/actors/companion/effects.hbs @@ -0,0 +1,8 @@ +
+ {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.Global.activeEffects') type='effect'}} + {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.Global.inativeEffects') type='effect'}} +
\ No newline at end of file diff --git a/templates/sheets/actors/companion/header.hbs b/templates/sheets/actors/companion/header.hbs new file mode 100644 index 00000000..e7b43900 --- /dev/null +++ b/templates/sheets/actors/companion/header.hbs @@ -0,0 +1,46 @@ +
+ {{document.name}} +

+ +

+
+
+
+

{{document.system.evasion.total}}

+
+
+

Evasion

+
+
+
+
+

+

/

+

{{document.system.resources.stress.maxTotal}}

+
+ +
+

Stress

+
+
+

+ {{localize "DAGGERHEART.Sheets.Companion.Level"}} + {{source.system.levelData.level.changed}} +

+
+
+ {{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} + +
+
\ No newline at end of file diff --git a/templates/sheets/applications/companion-settings/attack.hbs b/templates/sheets/applications/companion-settings/attack.hbs new file mode 100644 index 00000000..f0a26769 --- /dev/null +++ b/templates/sheets/applications/companion-settings/attack.hbs @@ -0,0 +1,21 @@ +
+
+ {{localize "DAGGERHEART.General.basics"}} + {{formGroup systemFields.attack.fields.img value=document.system.attack.img label="Image Path" name="system.attack.img"}} + {{formGroup systemFields.attack.fields.name value=document.system.attack.name label="Attack Name" name="system.attack.name"}} +
+
+ {{localize "DAGGERHEART.Sheets.Adversary.Attack"}} + {{formField systemFields.attack.fields.range value=document.system.attack.range label="Range" name="system.attack.range" localize=true}} + {{#if systemFields.attack.fields.target.fields}} + {{ formField systemFields.attack.fields.target.fields.type value=document.system.attack.target.type label="Target" name="system.attack.target.type" localize=true }} + {{#if (and document.system.attack.target.type (not (eq document.system.attack.target.type 'self')))}} + {{ formField systemFields.attack.fields.target.fields.amount value=document.system.attack.target.amount label="Amount" name="system.attack.target.amount" }} + {{/if}} + {{/if}} +
+
\ No newline at end of file diff --git a/templates/sheets/applications/companion-settings/details.hbs b/templates/sheets/applications/companion-settings/details.hbs new file mode 100644 index 00000000..d047752c --- /dev/null +++ b/templates/sheets/applications/companion-settings/details.hbs @@ -0,0 +1,23 @@ +
+
+ {{localize 'DAGGERHEART.General.basics'}} +
+ {{formGroup systemFields.evasion.fields.value value=document.system.evasion.value localize=true}} + {{formGroup systemFields.resources.fields.stress.fields.value value=document.system.resources.stress.value label='Current Stress'}} + {{formGroup systemFields.resources.fields.stress.fields.max value=document.system.resources.stress.max label='Max Stress'}} +
+
+
+ + +
+
+
+ +
\ No newline at end of file diff --git a/templates/sheets/applications/companion-settings/experiences.hbs b/templates/sheets/applications/companion-settings/experiences.hbs new file mode 100644 index 00000000..124a1a86 --- /dev/null +++ b/templates/sheets/applications/companion-settings/experiences.hbs @@ -0,0 +1,18 @@ +
+
+ {{localize tabs.experiences.label}} + +
+ +
\ No newline at end of file diff --git a/templates/sheets/applications/companion-settings/header.hbs b/templates/sheets/applications/companion-settings/header.hbs new file mode 100644 index 00000000..0978f2c3 --- /dev/null +++ b/templates/sheets/applications/companion-settings/header.hbs @@ -0,0 +1,3 @@ +
+

{{document.name}}

+
\ No newline at end of file diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index b69f1a2d..9b1c392b 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,7 +1,11 @@ -
  • +
  • -
    {{item.name}}
    + {{#if isCompanion}} + {{item.name}} + {{else}} +
    {{item.name}}
    + {{/if}} {{#if (eq type 'weapon')}}
    {{#if isSidebar}} @@ -114,6 +118,11 @@ {{#unless hideControls}} {{#if isActor}}
    + {{#if (eq type 'actor')}} + + + + {{/if}} {{#if (eq type 'adversary')}}