From 122621a57ad1dd0cb05b7ec2901e2758573a0393 Mon Sep 17 00:00:00 2001 From: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:26:03 -0300 Subject: [PATCH 1/3] FEAT: add appTheme mixin on less files (#256) Co-authored-by: Joaquin Pereyra --- styles/daggerheart.css | 215 +++++----- styles/less/actors/character/header.less | 17 +- styles/less/actors/character/sidebar.less | 501 +++++++++++----------- styles/less/actors/companion/sheet.less | 17 +- styles/less/actors/environment/sheet.less | 14 +- styles/less/global/dialog.less | 20 +- styles/less/global/sheet.less | 119 +++-- styles/less/utils/mixin.less | 18 + 8 files changed, 472 insertions(+), 449 deletions(-) create mode 100644 styles/less/utils/mixin.less diff --git a/styles/daggerheart.css b/styles/daggerheart.css index cc6854ca..803cd9eb 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -3685,6 +3685,14 @@ div.daggerheart.views.multiclass { .daggerheart.dh-style.setting .trait-array-container .trait-array-item input { text-align: center; } +.themed.theme-dark .application.sheet.dh-style .character-header-sheet .trait, +.themed.theme-dark.application.sheet.dh-style .character-header-sheet .trait { + background: url(../assets/svg/trait-shield.svg) no-repeat; +} +.themed.theme-light .application.sheet.dh-style .character-header-sheet .trait, +.themed.theme-light.application.sheet.dh-style .character-header-sheet .trait { + background: url('../assets/svg/trait-shield-light.svg') no-repeat; +} .application.sheet.daggerheart.actor.dh-style.character .character-header-sheet { padding: 0 15px; padding-top: 36px; @@ -3822,12 +3830,8 @@ div.daggerheart.views.multiclass { .application.sheet.daggerheart.actor.dh-style.character .character-header-sheet .character-traits .trait { height: 60px; width: 60px; - background: url(../assets/svg/trait-shield.svg) no-repeat; cursor: pointer; } -.theme-light .application.sheet.daggerheart.actor.dh-style.character .character-header-sheet .character-traits .trait { - background: url('../assets/svg/trait-shield-light.svg') no-repeat; -} .application.sheet.daggerheart.actor.dh-style.character .character-header-sheet .character-traits .trait .trait-name { display: flex; padding-top: 5px; @@ -3849,32 +3853,44 @@ div.daggerheart.views.multiclass { font-size: 20px; text-align: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet { +.themed.theme-dark .application.sheet.dh-style .character-sidebar-sheet, +.themed.theme-dark.application.sheet.dh-style .character-sidebar-sheet { + background-image: url('../assets/parchments/dh-parchment-dark.png'); +} +.themed.theme-dark .application.sheet.dh-style .character-sidebar-sheet .experience-value, +.themed.theme-dark.application.sheet.dh-style .character-sidebar-sheet .experience-value { + background: url(../assets/svg/experience-shield.svg) no-repeat; +} +.themed.theme-light .application.sheet.dh-style .character-sidebar-sheet, +.themed.theme-light.application.sheet.dh-style .character-sidebar-sheet { + background: transparent; +} +.themed.theme-light .application.sheet.dh-style .character-sidebar-sheet .experience-value, +.themed.theme-light.application.sheet.dh-style .character-sidebar-sheet .experience-value { + background: url('../assets/svg/experience-shield-light.svg') no-repeat; +} +.application.sheet.dh-style .character-sidebar-sheet { width: 275px; min-width: 275px; border-right: 1px solid light-dark(#18162e, #f3c267); - background-image: url('../assets/parchments/dh-parchment-dark.png'); } -.theme-light .application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet { - background: transparent; -} -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait { +.application.sheet.dh-style .character-sidebar-sheet .portrait { position: relative; border-bottom: 1px solid light-dark(#18162e, #f3c267); cursor: pointer; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait img { +.application.sheet.dh-style .character-sidebar-sheet .portrait img { height: 235px; width: 275px; object-fit: cover; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait .death-roll-btn { +.application.sheet.dh-style .character-sidebar-sheet .portrait .death-roll-btn { display: none; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll { +.application.sheet.dh-style .character-sidebar-sheet .portrait.death-roll { filter: grayscale(1); } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll .death-roll-btn { +.application.sheet.dh-style .character-sidebar-sheet .portrait.death-roll .death-roll-btn { display: flex; position: absolute; top: 30%; @@ -3882,10 +3898,10 @@ div.daggerheart.views.multiclass { font-size: 6rem; color: #efe6d8; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll .death-roll-btn:hover { +.application.sheet.dh-style .character-sidebar-sheet .portrait.death-roll .death-roll-btn:hover { text-shadow: 0 0 8px #efe6d8; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section { +.application.sheet.dh-style .character-sidebar-sheet .info-section { position: relative; display: flex; flex-direction: column; @@ -3893,17 +3909,17 @@ div.daggerheart.views.multiclass { gap: 30px; margin-bottom: -10px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section { display: flex; justify-content: space-evenly; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar { position: relative; width: 100px; height: 40px; justify-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-label { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .status-label { position: relative; top: 40px; height: 22px; @@ -3911,13 +3927,13 @@ div.daggerheart.views.multiclass { clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z'); background: light-dark(#18162e, #f3c267); } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-label h4 { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .status-value { position: absolute; display: flex; padding: 0 6px; @@ -3930,7 +3946,7 @@ div.daggerheart.views.multiclass { z-index: 2; color: #efe6d8; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'] { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'] { background: transparent; font-size: 1.5rem; width: 40px; @@ -3940,22 +3956,22 @@ div.daggerheart.views.multiclass { outline: 2px solid transparent; color: #efe6d8; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'].bar-input { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'].bar-input:hover, -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'].bar-input:focus { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .status-value input[type='number'].bar-input:hover, +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .status-value .bar-label { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .status-value .bar-label { width: 40px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar { position: absolute; appearance: none; width: 100px; @@ -3965,37 +3981,37 @@ div.daggerheart.views.multiclass { z-index: 1; background: #18162e; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar::-webkit-progress-bar { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar::-webkit-progress-bar { border: none; background: #18162e; border-radius: 6px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar::-webkit-progress-value { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar.stress-color::-webkit-progress-value { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar::-moz-progress-bar { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .resources-section .status-bar .progress-bar.stress-color::-moz-progress-bar { +.application.sheet.dh-style .character-sidebar-sheet .info-section .resources-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.character .character-sidebar-sheet .info-section .status-section { +.application.sheet.dh-style .character-sidebar-sheet .info-section .status-section { display: flex; flex-wrap: wrap; gap: 5px; justify-content: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .status-section .status-number { +.application.sheet.dh-style .character-sidebar-sheet .info-section .status-section .status-number { justify-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .status-section .status-number .status-value { +.application.sheet.dh-style .character-sidebar-sheet .info-section .status-section .status-number .status-value { position: relative; display: flex; width: 50px; @@ -4010,62 +4026,62 @@ div.daggerheart.views.multiclass { background: light-dark(transparent, #18162e); z-index: 2; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .status-section .status-number .status-value.armor-slots { +.application.sheet.dh-style .character-sidebar-sheet .info-section .status-section .status-number .status-value.armor-slots { width: 80px; height: 30px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section .status-section .status-number .status-label { +.application.sheet.dh-style .character-sidebar-sheet .info-section .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.character .character-sidebar-sheet .info-section .status-section .status-number .status-label h4 { +.application.sheet.dh-style .character-sidebar-sheet .info-section .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.character .character-sidebar-sheet .items-sidebar-list { +.application.sheet.dh-style .character-sidebar-sheet .items-sidebar-list { display: flex; flex-direction: column; gap: 5px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .items-sidebar-list .inventory-item { +.application.sheet.dh-style .character-sidebar-sheet .items-sidebar-list .inventory-item { padding: 0 10px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .equipment-section .title { +.application.sheet.dh-style .character-sidebar-sheet .equipment-section .title { display: flex; gap: 15px; align-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .equipment-section .title h3 { +.application.sheet.dh-style .character-sidebar-sheet .equipment-section .title h3 { font-size: 20px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .equipment-section .items-list { +.application.sheet.dh-style .character-sidebar-sheet .equipment-section .items-list { display: flex; flex-direction: column; gap: 10px; align-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .loadout-section .title { +.application.sheet.dh-style .character-sidebar-sheet .loadout-section .title { display: flex; gap: 15px; align-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .loadout-section .title h3 { +.application.sheet.dh-style .character-sidebar-sheet .loadout-section .title h3 { font-size: 20px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .title { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .title { display: flex; gap: 15px; align-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .title h3 { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .title h3 { font-size: 20px; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .experience-list { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .experience-list { display: flex; flex-direction: column; gap: 5px; @@ -4073,14 +4089,14 @@ div.daggerheart.views.multiclass { margin-top: 10px; align-items: center; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .experience-list .experience-row { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .experience-list .experience-row { display: flex; gap: 5px; width: 250px; align-items: center; justify-content: space-between; } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .experience-list .experience-row input[type='text'] { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .experience-list .experience-row input[type='text'] { height: 32px; width: 180px; border: 1px solid transparent; @@ -4090,10 +4106,10 @@ div.daggerheart.views.multiclass { transition: all 0.3s ease; color: light-dark(#222, #efe6d8); } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .experience-list .experience-row input[type='text']:hover { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .experience-list .experience-row input[type='text']:hover { outline: 2px solid light-dark(#222, #efe6d8); } -.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .experience-section .experience-list .experience-value { +.application.sheet.dh-style .character-sidebar-sheet .experience-section .experience-list .experience-value { height: 25px; width: 35px; font-size: 14px; @@ -4101,10 +4117,6 @@ div.daggerheart.views.multiclass { 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.character .character-sidebar-sheet .experience-section .experience-list .experience-value { - background: url('../assets/svg/experience-shield-light.svg') no-repeat; } .application.sheet.daggerheart.actor.dh-style.character .window-content { display: grid; @@ -4778,12 +4790,14 @@ div.daggerheart.views.multiclass { align-items: center; padding: 0 20px; } -.theme-light .application.sheet.daggerheart.actor.dh-style.environment { - background: url('../assets/parchments/dh-parchment-light.png'); -} -.theme-dark .application.sheet.daggerheart.actor.dh-style.environment { +.themed.theme-dark .application.sheet.dh-style.environment, +.themed.theme-dark.application.sheet.dh-style.environment { background-image: url('../assets/parchments/dh-parchment-dark.png'); } +.themed.theme-light .application.sheet.dh-style.environment, +.themed.theme-light.application.sheet.dh-style.environment { + background: url('../assets/parchments/dh-parchment-light.png'); +} .application.sheet.daggerheart.actor.dh-style.environment .tab { max-height: 300px; overflow-y: auto; @@ -5226,12 +5240,14 @@ div.daggerheart.views.multiclass { .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 { +.themed.theme-dark .application.sheet.dh-style.companion, +.themed.theme-dark.application.sheet.dh-style.companion { background-image: url('../assets/parchments/dh-parchment-dark.png'); } +.themed.theme-light .application.sheet.dh-style.companion, +.themed.theme-light.application.sheet.dh-style.companion { + background: url('../assets/parchments/dh-parchment-light.png'); +} .application.sheet.daggerheart.actor.dh-style.adversary .window-content { overflow: auto; } @@ -5402,6 +5418,9 @@ div.daggerheart.views.multiclass { font-family: 'Montserrat', sans-serif; opacity: 0.8; } +.application.sheet.dh-style { + border-radius: 10px; +} .application.sheet.dh-style .window-header { background: transparent; border-bottom: none; @@ -5418,65 +5437,53 @@ div.daggerheart.views.multiclass { padding: 0; } .application.sheet.dh-style .window-header button:hover { - border: 1px solid light-dark(#18162e, #f3c267); + border-color: light-dark(#18162e, #f3c267); color: light-dark(#18162e, #f3c267); } +.application.sheet.dh-style .window-content { + padding: 0; + position: relative; + top: -36px; + min-height: -webkit-fill-available; + transition: opacity 0.3s ease; +} +.application.sheet.dh-style .window-content .tab { + padding: 0 10px; +} +.application.sheet.dh-style.minimized .window-content { + opacity: 0; + transition-duration: 0.1s; +} .application.sheet.dh-style:not(.minimized) .window-title, .application.sheet.dh-style:not(.minimized) .window-icon { display: none; opacity: 0; transition: opacity 0.3s ease; } -.application.sheet.dh-style.minimized .window-content { - opacity: 0; - transition: opacity 0.1s ease; -} .application.sheet.dh-style:not(.minimized) .window-content { opacity: 1; - transition: opacity 0.3s ease; } -.theme-dark .application.sheet.dh-style { +.themed.theme-dark .application.sheet.dh-style, +.themed.theme-dark.application.sheet.dh-style { background: rgba(24, 22, 46, 0.33); backdrop-filter: blur(9px); } -.theme-light .application.sheet.dh-style { - background-image: url('../assets/parchments/dh-parchment-light.png'); - background-repeat: no-repeat; - background-position: center; +.themed.theme-light .application.sheet.dh-style, +.themed.theme-light.application.sheet.dh-style { + background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; } -.application.sheet.daggerheart.dh-style { - border-radius: 10px; -} -.application.sheet.daggerheart.dh-style .window-content { - padding: 0; - position: relative; - top: -36px; - min-height: -webkit-fill-available; -} -.application.sheet.daggerheart.dh-style .window-content .tab { - padding: 0 10px; -} -.application.sheet.daggerheart.character.dh-style { - border-radius: 10px; -} -.application.sheet.daggerheart.character.dh-style .window-content { - position: absolute; - top: 0; -} -.application.sheet.daggerheart.character.dh-style .window-content .tab { - padding: 0 15px; - overflow-y: hidden; -} -.theme-light .application.dialog.dh-style { - background-image: url('../assets/parchments/dh-parchment-light.png'); - background-repeat: no-repeat; - background-position: center; -} -.theme-dark .application.dialog.dh-style { +.themed.theme-dark .application.sheet.dh-style.dialog, +.themed.theme-dark.application.sheet.dh-style.dialog { background-image: url('../assets/parchments/dh-parchment-dark.png'); background-repeat: no-repeat; background-position: center; } +.themed.theme-light .application.sheet.dh-style.dialog, +.themed.theme-light.application.sheet.dh-style.dialog { + background-image: url('../assets/parchments/dh-parchment-light.png'); + background-repeat: no-repeat; + background-position: center; +} .application.dialog.dh-style { border: none; } diff --git a/styles/less/actors/character/header.less b/styles/less/actors/character/header.less index 4a2c1cec..300314da 100644 --- a/styles/less/actors/character/header.less +++ b/styles/less/actors/character/header.less @@ -1,6 +1,17 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; +// Theme header backgrounds +.appTheme({ + .character-header-sheet .trait { + background: url(../assets/svg/trait-shield.svg) no-repeat; + } +}, { + .character-header-sheet .trait { + background: url('../assets/svg/trait-shield-light.svg') no-repeat; + } +}); + .application.sheet.daggerheart.actor.dh-style.character { .character-header-sheet { padding: 0 15px; @@ -153,14 +164,8 @@ .trait { height: 60px; width: 60px; - background: url(../assets/svg/trait-shield.svg) no-repeat; - cursor: pointer; - .theme-light & { - background: url('../assets/svg/trait-shield-light.svg') no-repeat; - } - .trait-name { display: flex; align-items: center; diff --git a/styles/less/actors/character/sidebar.less b/styles/less/actors/character/sidebar.less index e5783cbb..4c637839 100644 --- a/styles/less/actors/character/sidebar.less +++ b/styles/less/actors/character/sidebar.less @@ -1,305 +1,310 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; -.application.sheet.daggerheart.actor.dh-style.character { +// Theme sidebar backgrounds +.appTheme({ .character-sidebar-sheet { - width: 275px; - min-width: 275px; - border-right: 1px solid light-dark(@dark-blue, @golden); background-image: url('../assets/parchments/dh-parchment-dark.png'); + .experience-value { + background: url(../assets/svg/experience-shield.svg) no-repeat; + } + } +}, { + .character-sidebar-sheet { + background: transparent; + .experience-value { + background: url('../assets/svg/experience-shield-light.svg') no-repeat; + } + } +}); - .theme-light & { - background: transparent; +.application.sheet.dh-style .character-sidebar-sheet { + width: 275px; + min-width: 275px; + border-right: 1px solid light-dark(@dark-blue, @golden); + + .portrait { + position: relative; + border-bottom: 1px solid light-dark(@dark-blue, @golden); + cursor: pointer; + + img { + height: 235px; + width: 275px; + object-fit: cover; } - .portrait { - position: relative; - border-bottom: 1px solid light-dark(@dark-blue, @golden); - cursor: pointer; + .death-roll-btn { + display: none; + } - img { - height: 235px; - width: 275px; - object-fit: cover; - } + &.death-roll { + filter: grayscale(1); .death-roll-btn { - display: none; - } + display: flex; + position: absolute; + top: 30%; + right: 30%; + font-size: 6rem; + color: @beige; - &.death-roll { - filter: grayscale(1); - - .death-roll-btn { - display: flex; - position: absolute; - top: 30%; - right: 30%; - font-size: 6rem; - color: @beige; - - &:hover { - text-shadow: 0 0 8px @beige; - } + &:hover { + text-shadow: 0 0 8px @beige; } } } + } - .info-section { - position: relative; + .info-section { + position: relative; + display: flex; + flex-direction: column; + top: -20px; + gap: 30px; + margin-bottom: -10px; + + .resources-section { display: flex; - flex-direction: column; - top: -20px; - gap: 30px; - margin-bottom: -10px; + justify-content: space-evenly; - .resources-section { - display: flex; - justify-content: space-evenly; + .status-bar { + position: relative; + width: 100px; + height: 40px; + justify-items: center; - .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(@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-items: center; + justify-content: center; + text-align: center; + z-index: 2; + color: @beige; - .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; + input[type='number'] { + background: transparent; font-size: 1.5rem; - align-items: center; - width: 100px; - height: 40px; - justify-content: center; + width: 40px; + height: 30px; text-align: center; - z-index: 2; + border: none; + outline: 2px solid transparent; color: @beige; - input[type='number'] { - background: transparent; - font-size: 1.5rem; - width: 40px; - height: 30px; - text-align: center; - border: none; - outline: 2px solid transparent; + &.bar-input { + padding: 0; color: @beige; + backdrop-filter: none; + background: transparent; + transition: all 0.3s ease; - &.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); - } + &: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; + + .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; - - &::-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; - } + border-radius: 6px; } - } - } - - .status-section { - display: flex; - flex-wrap: wrap; - gap: 5px; - justify-content: center; - - .status-number { - justify-items: center; - - .status-value { - position: relative; - display: flex; - width: 50px; - height: 30px; - border: 1px solid light-dark(@dark-blue, @golden); - border-bottom: none; - border-radius: 6px 6px 0 0; - padding: 0 6px; - font-size: 1.2rem; - align-items: center; - justify-content: center; - background: light-dark(transparent, @dark-blue); - z-index: 2; - - &.armor-slots { - width: 80px; - height: 30px; - } + &::-webkit-progress-value { + background: @gradient-hp; + border-radius: 6px; } - - .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); - } + &.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; } } } } - .items-sidebar-list { + .status-section { display: flex; - flex-direction: column; + flex-wrap: wrap; gap: 5px; + justify-content: center; - .inventory-item { - padding: 0 10px; - } - } + .status-number { + justify-items: center; - .equipment-section { - .title { - display: flex; - gap: 15px; - align-items: center; - - h3 { - font-size: 20px; - } - } - .items-list { - display: flex; - flex-direction: column; - gap: 10px; - align-items: center; - } - } - - .loadout-section { - .title { - display: flex; - gap: 15px; - align-items: center; - - h3 { - font-size: 20px; - } - } - } - - .experience-section { - .title { - display: flex; - gap: 15px; - align-items: center; - - h3 { - font-size: 20px; - } - } - - .experience-list { - display: flex; - flex-direction: column; - gap: 5px; - width: 100%; - margin-top: 10px; - align-items: center; - - .experience-row { + .status-value { + position: relative; display: flex; - gap: 5px; - width: 250px; + width: 50px; + height: 30px; + border: 1px solid light-dark(@dark-blue, @golden); + border-bottom: none; + border-radius: 6px 6px 0 0; + padding: 0 6px; + font-size: 1.2rem; align-items: center; - justify-content: space-between; + justify-content: center; + background: light-dark(transparent, @dark-blue); + z-index: 2; - input[type='text'] { - height: 32px; - width: 180px; - border: 1px solid transparent; - outline: 2px solid transparent; - font-size: 14px; - font-family: @font-body; - transition: all 0.3s ease; - color: light-dark(@dark, @beige); - - &:hover { - outline: 2px solid light-dark(@dark, @beige); - } + &.armor-slots { + width: 80px; + height: 30px; } } - .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; + .status-label { + padding: 2px 10px; + width: 100%; + border-radius: 3px; + background: light-dark(@dark-blue, @golden); - .theme-light & { - background: url('../assets/svg/experience-shield-light.svg') no-repeat; + h4 { + font-weight: bold; + text-align: center; + line-height: 18px; + font-size: 12px; + color: light-dark(@beige, @dark-blue); } } } } } + + .items-sidebar-list { + display: flex; + flex-direction: column; + gap: 5px; + + .inventory-item { + padding: 0 10px; + } + } + + .equipment-section { + .title { + display: flex; + gap: 15px; + align-items: center; + + h3 { + font-size: 20px; + } + } + .items-list { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + } + } + + .loadout-section { + .title { + display: flex; + gap: 15px; + align-items: center; + + h3 { + font-size: 20px; + } + } + } + + .experience-section { + .title { + display: flex; + gap: 15px; + align-items: center; + + h3 { + font-size: 20px; + } + } + + .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; + + input[type='text'] { + height: 32px; + width: 180px; + border: 1px solid transparent; + outline: 2px solid transparent; + font-size: 14px; + font-family: @font-body; + transition: all 0.3s ease; + color: light-dark(@dark, @beige); + + &:hover { + outline: 2px solid 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; + } + } + } } diff --git a/styles/less/actors/companion/sheet.less b/styles/less/actors/companion/sheet.less index db221597..f245ea2a 100644 --- a/styles/less/actors/companion/sheet.less +++ b/styles/less/actors/companion/sheet.less @@ -1,10 +1,17 @@ -.application.sheet.daggerheart.actor.dh-style.companion { - .theme-light & { - background: url('../assets/parchments/dh-parchment-light.png'); - } - .theme-dark & { + +// Theme header backgrounds + +.appTheme({ + &.companion { background-image: url('../assets/parchments/dh-parchment-dark.png'); } +}, { + &.companion { + background: url('../assets/parchments/dh-parchment-light.png'); + } +}); + +.application.sheet.daggerheart.actor.dh-style.companion { // .profile { // height: 80px; diff --git a/styles/less/actors/environment/sheet.less b/styles/less/actors/environment/sheet.less index 5e604188..c04b3dc3 100644 --- a/styles/less/actors/environment/sheet.less +++ b/styles/less/actors/environment/sheet.less @@ -1,13 +1,17 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; -.application.sheet.daggerheart.actor.dh-style.environment { - .theme-light & { - background: url('../assets/parchments/dh-parchment-light.png'); - } - .theme-dark & { +.appTheme({ + &.environment { background-image: url('../assets/parchments/dh-parchment-dark.png'); } +}, { + &.environment { + background: url('../assets/parchments/dh-parchment-light.png'); + } +}); + +.application.sheet.daggerheart.actor.dh-style.environment { .tab { max-height: 300px; diff --git a/styles/less/global/dialog.less b/styles/less/global/dialog.less index 5db641b2..bd12d73f 100644 --- a/styles/less/global/dialog.less +++ b/styles/less/global/dialog.less @@ -1,21 +1,19 @@ @import '../utils/colors.less'; @import '../utils/fonts.less'; -.theme-light { - .application.dialog.dh-style { - background-image: url('../assets/parchments/dh-parchment-light.png'); - background-repeat: no-repeat; - background-position: center; - } -} - -.theme-dark { - .application.dialog.dh-style { +.appTheme({ + &.dialog { background-image: url('../assets/parchments/dh-parchment-dark.png'); background-repeat: no-repeat; background-position: center; } -} +}, { + &.dialog { + background-image: url('../assets/parchments/dh-parchment-light.png'); + background-repeat: no-repeat; + background-position: center; + } +}); .application.dialog.dh-style { border: none; diff --git a/styles/less/global/sheet.less b/styles/less/global/sheet.less index 669b00ec..1e44d7a0 100755 --- a/styles/less/global/sheet.less +++ b/styles/less/global/sheet.less @@ -1,91 +1,70 @@ @import '../utils/colors.less'; @import '../utils/fonts.less'; +@import '../utils/mixin.less'; -.application.sheet.dh-style .window-header { - background: transparent; - border-bottom: none; - justify-content: end; +// Theme handling +.appTheme({ + background: @semi-transparent-dark-blue; + backdrop-filter: blur(9px); +}, { + background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; +}); - h1 { - color: light-dark(@dark-blue, @beige); - font-family: @font-body; - } - - button { - background: light-dark(transparent, @deep-black); - color: light-dark(@dark-blue, @beige); - border: 1px solid light-dark(@dark-blue, transparent); - padding: 0; - - &:hover { - border: 1px solid light-dark(@dark-blue, @golden); - color: light-dark(@dark-blue, @golden); - } - } -} - -.application.sheet.dh-style:not(.minimized) { - .window-title, - .window-icon { - display: none; - opacity: 0; - transition: opacity 0.3s ease; - } -} - -.application.sheet.dh-style.minimized { - .window-content { - opacity: 0; - transition: opacity 0.1s ease; - } -} - -.application.sheet.dh-style:not(.minimized) { - .window-content { - opacity: 1; - transition: opacity 0.3s ease; - } -} - -.theme-dark { - .application.sheet.dh-style { - background: @semi-transparent-dark-blue; - backdrop-filter: blur(9px); - } -} - -.theme-light { - .application.sheet.dh-style { - background-image: url('../assets/parchments/dh-parchment-light.png'); - background-repeat: no-repeat; - background-position: center; - } -} - -.application.sheet.daggerheart.dh-style { +.application.sheet.dh-style { border-radius: 10px; + // Window header styles + .window-header { + background: transparent; + border-bottom: none; + justify-content: end; + + h1 { + color: light-dark(@dark-blue, @beige); + font-family: @font-body; + } + + button { + background: light-dark(transparent, @deep-black); + color: light-dark(@dark-blue, @beige); + border: 1px solid light-dark(@dark-blue, transparent); + padding: 0; + + &:hover { + border-color: light-dark(@dark-blue, @golden); + color: light-dark(@dark-blue, @golden); + } + } + } + + // Window content transitions .window-content { padding: 0; position: relative; top: -36px; min-height: -webkit-fill-available; + transition: opacity 0.3s ease; .tab { padding: 0 10px; } } -} -.application.sheet.daggerheart.character.dh-style { - border-radius: 10px; + // Minimized states + &.minimized .window-content { + opacity: 0; + transition-duration: 0.1s; + } - .window-content { - position: absolute; - top: 0; - .tab { - padding: 0 15px; - overflow-y: hidden; + &:not(.minimized) { + .window-title, + .window-icon { + display: none; + opacity: 0; + transition: opacity 0.3s ease; + } + .window-content { + opacity: 1; } } } diff --git a/styles/less/utils/mixin.less b/styles/less/utils/mixin.less new file mode 100644 index 00000000..c9f9f968 --- /dev/null +++ b/styles/less/utils/mixin.less @@ -0,0 +1,18 @@ +/** + * Applies theme-specific styles. + * @param {Rules} @darkRules - Styles to apply when `.theme-dark` is present + * @param {Rules} @lightRules - Styles to apply when `.theme-light` is present + */ +.appTheme(@darkRules, @lightRules) { + .themed { + &.theme-dark .application.sheet.dh-style, + &.theme-dark.application.sheet.dh-style { + @darkRules(); + } + + &.theme-light .application.sheet.dh-style, + &.theme-light.application.sheet.dh-style { + @lightRules(); + } + } +} From c4448226e055b207576db54122d8abb8558278bb Mon Sep 17 00:00:00 2001 From: IrkTheImp <41175833+IrkTheImp@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:02:44 -0500 Subject: [PATCH 2/3] 219-fix weapon action damage and display of calculation. (#250) * fix weapon action damage and display of calculation. * modify weapon data to split formula. * remove unused field --- lang/en.json | 3 ++- module/applications/config/Action.mjs | 7 +++--- module/applications/roll.mjs | 25 +++++++++++-------- .../applications/adversary-settings.mjs | 1 - module/data/action/action.mjs | 4 +-- module/data/item/weapon.mjs | 3 ++- module/dialogs/d20RollDialog.mjs | 8 +++--- templates/chat/duality-roll.hbs | 2 +- templates/chat/parts/damage-chat.hbs | 3 ++- templates/sheets/items/weapon/header.hbs | 3 ++- templates/sheets/items/weapon/settings.hbs | 6 +++-- 11 files changed, 36 insertions(+), 29 deletions(-) diff --git a/lang/en.json b/lang/en.json index d466b0fc..61498321 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1546,7 +1546,8 @@ "Range": "Range", "Damage": { "Title": "Damage", - "Value": "Value", + "Die": "Die", + "Bonus": "Bonus", "Type": "Type" }, "Burden": "Burden", diff --git a/module/applications/config/Action.mjs b/module/applications/config/Action.mjs index 6b5f7b41..7e14bb33 100644 --- a/module/applications/config/Action.mjs +++ b/module/applications/config/Action.mjs @@ -38,7 +38,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { } }; - static CLEAN_ARRAYS = ["damage.parts", "cost", "effects"]; + static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects']; _getTabs() { const tabs = { @@ -69,7 +69,6 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { context.disableOption = this.disableOption.bind(this); context.isNPC = this.action.actor && this.action.actor.type !== 'character'; context.hasRoll = this.action.hasRoll; - console.log(context) return context; } @@ -97,9 +96,9 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { _prepareSubmitData(event, formData) { const submitData = foundry.utils.expandObject(formData.object); - for ( const keyPath of this.constructor.CLEAN_ARRAYS ) { + for (const keyPath of this.constructor.CLEAN_ARRAYS) { const data = foundry.utils.getProperty(submitData, keyPath); - if ( data ) foundry.utils.setProperty(submitData, keyPath, Object.values(data)); + if (data) foundry.utils.setProperty(submitData, keyPath, Object.values(data)); } return submitData; } diff --git a/module/applications/roll.mjs b/module/applications/roll.mjs index 321ead6f..36188ad8 100644 --- a/module/applications/roll.mjs +++ b/module/applications/roll.mjs @@ -39,7 +39,6 @@ export class DHRoll extends Roll { if (config.dialog.configure !== false) { // Open Roll Dialog const DialogClass = config.dialog?.class ?? this.DefaultDialog; - console.log(roll, config); const configDialog = await DialogClass.configure(roll, config, message); if (!configDialog) return; } @@ -124,6 +123,18 @@ export class DHRoll extends Roll { } return (this._formula = this.constructor.getFormula(this.terms)); } + + static calculateTotalModifiers(roll, config) { + config.roll.modifierTotal = 0; + for (let i = 0; i < roll.terms.length; i++) { + if ( + roll.terms[i] instanceof foundry.dice.terms.NumericTerm && + !!roll.terms[i - 1] && + roll.terms[i - 1] instanceof foundry.dice.terms.OperatorTerm + ) + config.roll.modifierTotal += Number(`${roll.terms[i - 1].operator}${roll.terms[i].total}`); + } + } } export class DualityDie extends foundry.dice.terms.Die { @@ -299,15 +310,8 @@ export class D20Roll extends DHRoll { value: d.total }; }); - config.roll.modifierTotal = 0; - for (let i = 0; i < roll.terms.length; i++) { - if ( - roll.terms[i] instanceof foundry.dice.terms.NumericTerm && - !!roll.terms[i - 1] && - roll.terms[i - 1] instanceof foundry.dice.terms.OperatorTerm - ) - config.roll.modifierTotal += Number(`${roll.terms[i - 1].operator}${roll.terms[i].total}`); - } + + this.calculateTotalModifiers(roll, config); } resetFormula() { @@ -468,6 +472,7 @@ export class DamageRoll extends DHRoll { static async postEvaluate(roll, config = {}) { super.postEvaluate(roll, config); config.roll.type = config.type; + this.calculateTotalModifiers(roll, config); if (config.source?.message) { const chatMessage = ui.chat.collection.get(config.source.message); chatMessage.update({ 'system.damage': config }); diff --git a/module/applications/sheets/applications/adversary-settings.mjs b/module/applications/sheets/applications/adversary-settings.mjs index cc18d7f6..2ecdcb60 100644 --- a/module/applications/sheets/applications/adversary-settings.mjs +++ b/module/applications/sheets/applications/adversary-settings.mjs @@ -103,7 +103,6 @@ export default class DHAdversarySettings extends HandlebarsApplicationMixin(Appl context.systemFields = this.actor.system.schema.fields; context.systemFields.attack.fields = this.actor.system.attack.schema.fields; context.isNPC = true; - console.log(context) return context; } diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index 7bda6089..ddf4fb5c 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -231,6 +231,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { } if (this.hasRoll) { + console.log(config); const rollConfig = this.prepareRoll(config); config.roll = rollConfig; config = await this.actor.diceRoll(config); @@ -242,7 +243,6 @@ export class DHBaseAction extends foundry.abstract.DataModel { if(t.hit) { const target = game.canvas.tokens.get(t.id), actor = target?.actor; - console.log(actor) if(!actor) return; actor.saveRoll({ event, @@ -629,7 +629,7 @@ export class DHAttackAction extends DHDamageAction { return { value: { multiplier: 'prof', - dice: this.item?.system?.damage.value, + dice: this.item?.system?.damage.dice, bonus: this.item?.system?.damage.bonus ?? 0 }, type: this.item?.system?.damage.type, diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 9154eb31..ee59a7f7 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -32,7 +32,8 @@ export default class DHWeapon extends BaseDataItem { burden: new fields.StringField({ required: true, choices: SYSTEM.GENERAL.burden, initial: 'oneHanded' }), //DAMAGE damage: new fields.SchemaField({ - value: new FormulaField({ initial: 'd6' }), + dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6' }), + bonus: new fields.NumberField({ nullable: true, initial: null }), type: new fields.StringField({ required: true, choices: SYSTEM.GENERAL.damageTypes, diff --git a/module/dialogs/d20RollDialog.mjs b/module/dialogs/d20RollDialog.mjs index b21e79df..26efaf7d 100644 --- a/module/dialogs/d20RollDialog.mjs +++ b/module/dialogs/d20RollDialog.mjs @@ -9,7 +9,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.experiences = []; if (config.source?.action) { - console.log(config) this.item = config.data.parent.items.get(config.source.item) ?? config.data.parent; this.action = config.data.attack?._id == config.source.action @@ -51,7 +50,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio }; async _prepareContext(_options) { - console.log(this.config, this.roll) const context = await super._prepareContext(_options); context.hasRoll = !!this.config.roll; context.roll = this.roll; @@ -77,7 +75,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio } context.extraFormula = this.config.extraFormula; context.formula = this.roll.constructFormula(this.config); - + return context; } @@ -87,10 +85,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); } if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses); - if(rest.roll?.dice) { + if (rest.roll?.dice) { Object.entries(rest.roll.dice).forEach(([key, value]) => { this.roll[key] = value; - }) + }); } this.config.extraFormula = rest.extraFormula; this.render(); diff --git a/templates/chat/duality-roll.hbs b/templates/chat/duality-roll.hbs index ff1e9894..9a530649 100644 --- a/templates/chat/duality-roll.hbs +++ b/templates/chat/duality-roll.hbs @@ -123,7 +123,7 @@
- {{!-- {{> 'systems/daggerheart/templates/chat/parts/damage-chat.hbs' damage=damage noTitle=true}} --}} + {{> 'systems/daggerheart/templates/chat/parts/damage-chat.hbs' damage=damage noTitle=true}}
diff --git a/templates/chat/parts/damage-chat.hbs b/templates/chat/parts/damage-chat.hbs index 096f09dc..f8d7cfed 100644 --- a/templates/chat/parts/damage-chat.hbs +++ b/templates/chat/parts/damage-chat.hbs @@ -17,7 +17,8 @@ {{/each}} - {{/each}} + {{/each}} + {{#if damage.roll.modifierTotal}}
{{#if (gt damage.roll.modifierTotal 0)}}+{{/if}}{{damage.roll.modifierTotal}}
{{/if}}
Total: {{damage.roll.total}}
diff --git a/templates/sheets/items/weapon/header.hbs b/templates/sheets/items/weapon/header.hbs index 5d33c6ae..7a10bcc1 100644 --- a/templates/sheets/items/weapon/header.hbs +++ b/templates/sheets/items/weapon/header.hbs @@ -14,7 +14,8 @@ - {{localize (concat 'DAGGERHEART.Range.' source.system.range '.name')}} - - {{source.system.damage.value}} + {{log this}} + {{source.system.damage.dice}} + {{source.system.damage.bonus}} ({{localize (concat 'DAGGERHEART.DamageType.' source.system.damage.type '.abbreviation')}}) - {{localize (concat 'DAGGERHEART.Burden.' source.system.burden)}} diff --git a/templates/sheets/items/weapon/settings.hbs b/templates/sheets/items/weapon/settings.hbs index aaa5192b..b431f1dd 100644 --- a/templates/sheets/items/weapon/settings.hbs +++ b/templates/sheets/items/weapon/settings.hbs @@ -19,8 +19,10 @@
{{localize "DAGGERHEART.Sheets.Weapon.Damage.Title"}} - {{localize "DAGGERHEART.Sheets.Weapon.Damage.Value"}} - {{formGroup systemFields.damage.fields.value value=source.system.damage.value}} + {{localize "DAGGERHEART.Sheets.Weapon.Damage.Die"}} + {{formGroup systemFields.damage.fields.dice value=source.system.damage.dice}} + {{localize "DAGGERHEART.Sheets.Weapon.Damage.Bonus"}} + {{formGroup systemFields.damage.fields.bonus value=source.system.damage.bonus}} {{localize "DAGGERHEART.Sheets.Weapon.Damage.Type"}} {{formGroup systemFields.damage.fields.type value=source.system.damage.type localize=true}}
From d071fadf7dbd9f134d24d05b2fb118422dbe4f90 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 4 Jul 2025 02:02:14 +0200 Subject: [PATCH 3/3] Feature/200 beastform (#255) * Temp * Dialog setup * Fixed basic beastform * Reworked beastform to hold it's data entirely in the beastformEffect * UpdateActorTokens fix * Removed hardcoded tierlimit on beastform * PR fixes --- daggerheart.mjs | 4 + lang/en.json | 36 +- module/applications/_module.mjs | 3 +- module/applications/config/Action.mjs | 7 + module/applications/rollSelectionDialog.mjs | 6 +- .../applications/sheets/actors/character.mjs | 25 +- .../applications/sheets/items/beastform.mjs | 65 +++ module/config/actionConfig.mjs | 7 +- module/config/generalConfig.mjs | 12 +- module/data/_module.mjs | 1 + module/data/action/_module.mjs | 4 +- module/data/action/action.mjs | 53 +++ module/data/activeEffect/_module.mjs | 7 + module/data/activeEffect/beastformEffect.mjs | 40 ++ module/data/item/_module.mjs | 7 +- module/data/item/beastform.mjs | 98 +++++ module/dialogs/beastformDialog.mjs | 86 ++++ module/dialogs/damageDialog.mjs | 2 +- module/documents/activeEffect.mjs | 23 + module/documents/item.mjs | 6 +- module/helpers/utils.mjs | 12 + styles/application.less | 31 +- styles/daggerheart.css | 131 +++++- styles/daggerheart.less | 5 +- styles/less/actors/companion/header.less | 394 +++++++++--------- styles/less/actors/companion/sheet.less | 2 - styles/less/actors/environment/sheet.less | 1 - styles/less/applications/beastform.less | 59 +++ styles/less/global/dialog.less | 86 ++-- styles/less/global/tab-features.less | 50 +++ styles/less/utils/mixin.less | 18 +- system.json | 8 +- .../partials/inventory-fieldset-items.hbs | 5 - .../sheets/global/partials/inventory-item.hbs | 2 +- templates/sheets/global/tabs/tab-features.hbs | 23 + templates/sheets/items/beastform/header.hbs | 10 + templates/sheets/items/beastform/settings.hbs | 27 ++ templates/tooltip/beastform.hbs | 6 + templates/views/action.hbs | 3 +- templates/views/actionTypes/beastform.hbs | 17 + templates/views/beastformDialog.hbs | 18 + 41 files changed, 1102 insertions(+), 298 deletions(-) create mode 100644 module/applications/sheets/items/beastform.mjs create mode 100644 module/data/activeEffect/_module.mjs create mode 100644 module/data/activeEffect/beastformEffect.mjs create mode 100644 module/data/item/beastform.mjs create mode 100644 module/dialogs/beastformDialog.mjs create mode 100644 styles/less/applications/beastform.less create mode 100644 styles/less/global/tab-features.less create mode 100644 templates/sheets/global/tabs/tab-features.hbs create mode 100644 templates/sheets/items/beastform/header.hbs create mode 100644 templates/sheets/items/beastform/settings.hbs create mode 100644 templates/tooltip/beastform.hbs create mode 100644 templates/views/actionTypes/beastform.hbs create mode 100644 templates/views/beastformDialog.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index ac444c44..1b7be686 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -79,6 +79,7 @@ Hooks.once('init', () => { Items.registerSheet(SYSTEM.id, applications.DhpConsumable, { types: ['consumable'], makeDefault: true }); Items.registerSheet(SYSTEM.id, applications.DhpWeapon, { types: ['weapon'], makeDefault: true }); Items.registerSheet(SYSTEM.id, applications.DhpArmor, { types: ['armor'], makeDefault: true }); + Items.registerSheet(SYSTEM.id, applications.DhBeastform, { types: ['beastform'], makeDefault: true }); CONFIG.Actor.documentClass = documents.DhpActor; CONFIG.Actor.dataModels = models.actors.config; @@ -90,6 +91,8 @@ Hooks.once('init', () => { Actors.registerSheet(SYSTEM.id, applications.DhpEnvironment, { types: ['environment'], makeDefault: true }); CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect; + CONFIG.ActiveEffect.dataModels = models.activeEffects.config; + foundry.applications.apps.DocumentSheetConfig.unregisterSheet( CONFIG.ActiveEffect.documentClass, 'core', @@ -300,6 +303,7 @@ const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/views/actionTypes/cost.hbs', 'systems/daggerheart/templates/views/actionTypes/range-target.hbs', 'systems/daggerheart/templates/views/actionTypes/effect.hbs', + 'systems/daggerheart/templates/views/actionTypes/beastform.hbs', 'systems/daggerheart/templates/settings/components/settings-item-line.hbs', 'systems/daggerheart/templates/chat/parts/damage-chat.hbs', 'systems/daggerheart/templates/chat/parts/target-chat.hbs' diff --git a/lang/en.json b/lang/en.json index 61498321..4c374458 100755 --- a/lang/en.json +++ b/lang/en.json @@ -10,7 +10,8 @@ "consumable": "Consumable", "miscellaneous": "Miscellaneous", "weapon": "Weapon", - "armor": "Armor" + "armor": "Armor", + "beastform": "Beastform" }, "Actor": { "character": "Character", @@ -22,7 +23,9 @@ "DAGGERHEART": { "UI": { "notifications": { - "adversaryMissing": "The linked adversary doesn't exist in the world." + "adversaryMissing": "The linked adversary doesn't exist in the world.", + "beastformInapplicable": "A beastform can only be applied to a Character.", + "beastformAlreadyApplied": "The character already has a beastform applied!" } }, "Settings": { @@ -1186,6 +1189,7 @@ "LevelUp": "You can level up", "Features": "Features", "CompanionFeatures": "Companion Features", + "beastformFeatures": "Beastform Features", "Tabs": { "Features": "Features", "Inventory": "Inventory", @@ -1472,8 +1476,26 @@ } } }, + "Beastform": { + "FIELDS": { + "tier": { "label": "Tier" }, + "examples": { "label": "Examples" }, + "advantageOn": { "label": "Gain Advantage On" }, + "tokenImg": { "label": "Token Image" }, + "tokenSize": { + "placeholder": "Using character dimensions", + "height": { "label": "Height" }, + "width": { "label": "Width" } + } + }, + "dialogTitle": "Beastform Selection", + "tokenTitle": "Beastform Token", + "transform": "Transform", + "beastformEffect": "Beastform Transformation" + }, "Global": { "Actions": "Actions", + "Features": "Features", "Effects": "Effects", "activeEffects": "Active Effects", "inativeEffects": "Inative Effects" @@ -1632,12 +1654,22 @@ }, "macro": { "name": "Macro" + }, + "beastform": { + "name": "Beastform" } }, "Settings": { "ResultBased": { "label": "Formula based on Hope/Fear result." } + }, + "Config": { + "Beastform": { + "label": "Beastform", + "exact": "Beastform Max Tier", + "exactHint": "The Character's Tier is used if empty" + } } }, "RollTypes": { diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index c5eb45d9..a1574a33 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -15,7 +15,8 @@ export { default as DhpChatMessage } from './chatMessage.mjs'; export { default as DhpEnvironment } from './sheets/actors/environment.mjs'; export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs'; export { default as DhContextMenu } from './contextMenu.mjs'; +export { default as DhBeastform } from './sheets/items/beastform.mjs'; export { default as DhTooltipManager } from './tooltipManager.mjs'; export * as api from './sheets/api/_modules.mjs'; -export * as ux from "./ux/_module.mjs"; +export * as ux from './ux/_module.mjs'; diff --git a/module/applications/config/Action.mjs b/module/applications/config/Action.mjs index 7e14bb33..803f22fe 100644 --- a/module/applications/config/Action.mjs +++ b/module/applications/config/Action.mjs @@ -69,6 +69,13 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { context.disableOption = this.disableOption.bind(this); context.isNPC = this.action.actor && this.action.actor.type !== 'character'; context.hasRoll = this.action.hasRoll; + + const settingsTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers).tiers; + context.tierOptions = [ + { key: 1, label: game.i18n.localize('DAGGERHEART.Tiers.tier1') }, + ...Object.values(settingsTiers).map(x => ({ key: x.tier, label: x.name })) + ]; + return context; } diff --git a/module/applications/rollSelectionDialog.mjs b/module/applications/rollSelectionDialog.mjs index fbc77d2b..543fa6c5 100644 --- a/module/applications/rollSelectionDialog.mjs +++ b/module/applications/rollSelectionDialog.mjs @@ -5,7 +5,7 @@ const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { constructor(experiences, costs, action, resolve) { super({}, {}); - + this.experiences = experiences; this.costs = costs; this.action = action; @@ -67,9 +67,9 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl context.fear = this.data.fear; context.advantage = this.data.advantage; context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] })); - if(this.costs?.length) { + if (this.costs?.length) { const updatedCosts = this.action.calcCosts(this.costs); - context.costs = updatedCosts + context.costs = updatedCosts; context.canRoll = this.action.getRealCosts(updatedCosts)?.hasCost; } else context.canRoll = true; diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 1a6fec84..10791435 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -7,6 +7,8 @@ import { abilities } from '../../../config/actorConfig.mjs'; import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs'; import DhCharacterCreation from '../../characterCreation.mjs'; import FilterMenu from '../../ux/filter-menu.mjs'; +import { DhBeastformAction } from '../../../data/action/action.mjs'; +import DHActionConfig from '../../config/Action.mjs'; const { ActorSheetV2 } = foundry.applications.sheets; const { TextEditor } = foundry.applications.ux; @@ -306,11 +308,14 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { getItem(element) { const listElement = (element.target ?? element).closest('[data-item-id]'); - const document = listElement.dataset.companion ? this.document.system.companion : this.document; - - const itemId = listElement.dataset.itemId, - item = document.items.get(itemId); - return item; + const itemId = listElement.dataset.itemId; + if (listElement.dataset.type === 'effect') { + return this.document.effects.get(itemId); + } else if (['armor', 'weapon', 'feature', 'consumable', 'miscellaneous'].includes(listElement.dataset.type)) { + return this.document.items.get(itemId); + } else { + return this.document.system[listElement.dataset.type].system.actions.find(x => x.id === itemId); + } } static triggerContextMenu(event, button) { @@ -733,7 +738,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { // Should dandle its actions. Or maybe they'll be separate buttons as per an Issue on the board if (item.type === 'feature') { - item.toChat(); + item.use(event); + } else if (item instanceof ActiveEffect) { + item.toChat(this); } else { const wasUsed = await item.use(event); if (wasUsed && item.type === 'weapon') { @@ -746,7 +753,11 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { const item = this.getItem(event); if (!item) return; - item.sheet.render(true); + if (item.sheet) { + item.sheet.render(true); + } else { + await new DHActionConfig(item).render(true); + } } editItem(event) { diff --git a/module/applications/sheets/items/beastform.mjs b/module/applications/sheets/items/beastform.mjs new file mode 100644 index 00000000..b04671ec --- /dev/null +++ b/module/applications/sheets/items/beastform.mjs @@ -0,0 +1,65 @@ +import DHBaseItemSheet from '../api/base-item.mjs'; + +export default class BeastformSheet extends DHBaseItemSheet { + /**@inheritdoc */ + static DEFAULT_OPTIONS = { + classes: ['beastform'], + dragDrop: [{ dragSelector: null, dropSelector: '.drop-section' }], + actions: { + editFeature: this.editFeature, + removeFeature: this.removeFeature + } + }; + + /**@override */ + static PARTS = { + header: { template: 'systems/daggerheart/templates/sheets/items/beastform/header.hbs' }, + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + settings: { template: 'systems/daggerheart/templates/sheets/items/beastform/settings.hbs' }, + features: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-features.hbs', + scrollable: ['.features'] + }, + effects: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-effects.hbs', + scrollable: ['.effects'] + } + }; + + static TABS = { + primary: { + tabs: [{ id: 'settings' }, { id: 'features' }, { id: 'effects' }], + initial: 'settings', + labelPrefix: 'DAGGERHEART.Sheets.TABS' + } + }; + + /**@inheritdoc */ + async _preparePartContext(partId, context) { + await super._preparePartContext(partId, context); + + return context; + } + + static editFeature(event) { + const target = event.target.closest('[data-action="editFeature"]'); + const feature = this.document.system.features[target.dataset.index]; + feature.sheet.render({ force: true }); + } + + static async removeFeature(_, target) { + const current = this.document.system.features.map(x => x.uuid); + await this.document.update({ + 'system.features': current.filter((_, index) => index !== Number(target.dataset.index)) + }); + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + if (item.type === 'feature') { + const current = this.document.system.features.map(x => x.uuid); + await this.document.update({ 'system.features': [...current, item.uuid] }); + } + } +} diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index e83040f5..4dc65fd7 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -38,6 +38,11 @@ export const actionTypes = { id: 'macro', name: 'DAGGERHEART.Actions.Types.macro.name', icon: 'fa-scroll' + }, + beastform: { + id: 'beastform', + name: 'DAGGERHEART.Actions.Types.beastform.name', + icon: 'fa-paw' } }; @@ -119,4 +124,4 @@ export const advandtageState = { label: 'DAGGERHEART.General.Advantage.Full', value: 1 } -} +}; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 6710d3ed..06c75fce 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -245,19 +245,23 @@ export const deathMoves = { export const tiers = { tier1: { id: 'tier1', - label: 'DAGGERHEART.Tiers.tier1' + label: 'DAGGERHEART.Tiers.tier1', + value: 1 }, tier2: { id: 'tier2', - label: 'DAGGERHEART.Tiers.tier2' + label: 'DAGGERHEART.Tiers.tier2', + value: 2 }, tier3: { id: 'tier3', - label: 'DAGGERHEART.Tiers.tier3' + label: 'DAGGERHEART.Tiers.tier3', + value: 3 }, tier4: { id: 'tier4', - label: 'DAGGERHEART.Tiers.tier4' + label: 'DAGGERHEART.Tiers.tier4', + value: 4 } }; diff --git a/module/data/_module.mjs b/module/data/_module.mjs index 4284bc41..45a1d558 100644 --- a/module/data/_module.mjs +++ b/module/data/_module.mjs @@ -6,3 +6,4 @@ export * as items from './item/_module.mjs'; export { actionsTypes } from './action/_module.mjs'; export * as messages from './chat-message/_modules.mjs'; export * as fields from './fields/_module.mjs'; +export * as activeEffects from './activeEffect/_module.mjs'; diff --git a/module/data/action/_module.mjs b/module/data/action/_module.mjs index 23d4e3c1..09c027d1 100644 --- a/module/data/action/_module.mjs +++ b/module/data/action/_module.mjs @@ -1,6 +1,7 @@ import { DHAttackAction, DHBaseAction, + DhBeastformAction, DHDamageAction, DHEffectAction, DHHealingAction, @@ -19,5 +20,6 @@ export const actionsTypes = { healing: DHHealingAction, summon: DHSummonAction, effect: DHEffectAction, - macro: DHMacroAction + macro: DHMacroAction, + beastform: DhBeastformAction }; diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index ddf4fb5c..979a6e65 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -1,6 +1,7 @@ import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField } from './actionDice.mjs'; import DhpActor from '../../documents/actor.mjs'; import D20RollDialog from '../../dialogs/d20RollDialog.mjs'; +import BeastformDialog from '../../dialogs/beastformDialog.mjs'; const fields = foundry.data.fields; @@ -106,6 +107,11 @@ export class DHBaseAction extends foundry.abstract.DataModel { }), value: new fields.EmbeddedDataField(DHActionDiceData), valueAlt: new fields.EmbeddedDataField(DHActionDiceData) + }), + beastform: new fields.SchemaField({ + tierAccess: new fields.SchemaField({ + exact: new fields.NumberField({ integer: true, nullable: true, initial: null }) + }) }) }, extraSchemas = {}; @@ -757,3 +763,50 @@ export class DHMacroAction extends DHBaseAction { } } } + +export class DhBeastformAction extends DHBaseAction { + static extraSchemas = ['beastform']; + + async use(event, ...args) { + const beastformConfig = this.prepareBeastformConfig(); + + const abort = await this.handleActiveTransformations(); + if (abort) return; + + const beastformUuid = await BeastformDialog.configure(beastformConfig); + if (!beastformUuid) return; + + await this.transform(beastformUuid); + } + + prepareBeastformConfig(config) { + const settingsTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers).tiers; + const actorLevel = this.actor.system.levelData.level.current; + const actorTier = + Object.values(settingsTiers).find( + tier => actorLevel >= tier.levels.start && actorLevel <= tier.levels.end + ) ?? 1; + + return { + tierLimit: this.beastform.tierAccess.exact ?? actorTier + }; + } + + async transform(beastformUuid) { + const beastform = await foundry.utils.fromUuid(beastformUuid); + this.actor.createEmbeddedDocuments('Item', [beastform.toObject()]); + } + + async handleActiveTransformations() { + const beastformEffects = this.actor.effects.filter(x => x.type === 'beastform'); + if (beastformEffects.length > 0) { + for (let effect of beastformEffects) { + await effect.delete(); + } + + return true; + } + + return false; + } +} diff --git a/module/data/activeEffect/_module.mjs b/module/data/activeEffect/_module.mjs new file mode 100644 index 00000000..f4627f0c --- /dev/null +++ b/module/data/activeEffect/_module.mjs @@ -0,0 +1,7 @@ +import beastformEffect from './beastformEffect.mjs'; + +export { beastformEffect }; + +export const config = { + beastform: beastformEffect +}; diff --git a/module/data/activeEffect/beastformEffect.mjs b/module/data/activeEffect/beastformEffect.mjs new file mode 100644 index 00000000..3aa25bef --- /dev/null +++ b/module/data/activeEffect/beastformEffect.mjs @@ -0,0 +1,40 @@ +import { updateActorTokens } from '../../helpers/utils.mjs'; + +export default class BeastformEffect extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + characterTokenData: new fields.SchemaField({ + tokenImg: new fields.FilePathField({ + categories: ['IMAGE'], + base64: false, + nullable: true + }), + tokenSize: new fields.SchemaField({ + height: new fields.NumberField({ integer: true, nullable: true }), + width: new fields.NumberField({ integer: true, nullable: true }) + }) + }), + advantageOn: new fields.ArrayField(new fields.StringField()), + featureIds: new fields.ArrayField(new fields.StringField()), + effectIds: new fields.ArrayField(new fields.StringField()) + }; + } + + async _preDelete() { + if (this.parent.parent.type === 'character') { + const update = { + height: this.characterTokenData.tokenSize.height, + width: this.characterTokenData.tokenSize.width, + texture: { + src: this.characterTokenData.tokenImg + } + }; + + await updateActorTokens(this.parent.parent, update); + + await this.parent.parent.deleteEmbeddedDocuments('Item', this.featureIds); + await this.parent.parent.deleteEmbeddedDocuments('ActiveEffect', this.effectIds); + } + } +} diff --git a/module/data/item/_module.mjs b/module/data/item/_module.mjs index da3bf2d4..a29d1595 100644 --- a/module/data/item/_module.mjs +++ b/module/data/item/_module.mjs @@ -8,6 +8,7 @@ import DHFeature from './feature.mjs'; import DHMiscellaneous from './miscellaneous.mjs'; import DHSubclass from './subclass.mjs'; import DHWeapon from './weapon.mjs'; +import DHBeastform from './beastform.mjs'; export { DHAncestry, @@ -19,7 +20,8 @@ export { DHFeature, DHMiscellaneous, DHSubclass, - DHWeapon + DHWeapon, + DHBeastform }; export const config = { @@ -32,5 +34,6 @@ export const config = { feature: DHFeature, miscellaneous: DHMiscellaneous, subclass: DHSubclass, - weapon: DHWeapon + weapon: DHWeapon, + beastform: DHBeastform }; diff --git a/module/data/item/beastform.mjs b/module/data/item/beastform.mjs new file mode 100644 index 00000000..e90af930 --- /dev/null +++ b/module/data/item/beastform.mjs @@ -0,0 +1,98 @@ +import { updateActorTokens } from '../../helpers/utils.mjs'; +import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; +import BaseDataItem from './base.mjs'; + +export default class DHBeastform extends BaseDataItem { + static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Beastform']; + + /** @inheritDoc */ + static get metadata() { + return foundry.utils.mergeObject(super.metadata, { + label: 'TYPES.Item.beastform', + type: 'beastform', + hasDescription: false + }); + } + + /** @inheritDoc */ + static defineSchema() { + const fields = foundry.data.fields; + return { + ...super.defineSchema(), + tier: new fields.StringField({ + required: true, + choices: SYSTEM.GENERAL.tiers, + initial: SYSTEM.GENERAL.tiers.tier1.id + }), + tokenImg: new fields.FilePathField({ + initial: 'icons/svg/mystery-man.svg', + categories: ['IMAGE'], + base64: false + }), + tokenSize: new fields.SchemaField({ + height: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }), + width: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }) + }), + examples: new fields.StringField(), + advantageOn: new fields.ArrayField(new fields.StringField()), + features: new ForeignDocumentUUIDArrayField({ type: 'Item' }) + }; + } + + async _preCreate(data, options, user) { + const allowed = await super._preCreate(data, options, user); + if (allowed === false) return; + + if (!this.actor) return; + + if (this.actor.type !== 'character') { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.notifications.beastformInapplicable')); + return false; + } + + if (this.actor.items.find(x => x.type === 'beastform')) { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.notifications.beastformAlreadyApplied')); + return false; + } + + const features = await this.parent.parent.createEmbeddedDocuments( + 'Item', + this.features.map(x => x.toObject()) + ); + const effects = await this.parent.parent.createEmbeddedDocuments( + 'ActiveEffect', + this.parent.effects.map(x => x.toObject()) + ); + + await this.parent.parent.createEmbeddedDocuments('ActiveEffect', [ + { + type: 'beastform', + name: game.i18n.localize('DAGGERHEART.Sheets.Beastform.beastformEffect'), + img: 'icons/creatures/abilities/paw-print-pair-purple.webp', + system: { + isBeastform: true, + characterTokenData: { + tokenImg: this.parent.parent.prototypeToken.texture.src, + tokenSize: { + height: this.parent.parent.prototypeToken.height, + width: this.parent.parent.prototypeToken.width + } + }, + advantageOn: this.advantageOn, + featureIds: features.map(x => x.id), + effectIds: effects.map(x => x.id) + } + } + ]); + + await updateActorTokens(this.parent.parent, { + height: this.tokenSize.height, + width: this.tokenSize.width, + texture: { + src: this.tokenImg + } + }); + + return false; + } +} diff --git a/module/dialogs/beastformDialog.mjs b/module/dialogs/beastformDialog.mjs new file mode 100644 index 00000000..34b71c24 --- /dev/null +++ b/module/dialogs/beastformDialog.mjs @@ -0,0 +1,86 @@ +import { tiers } from '../config/generalConfig.mjs'; + +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class BeastformDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(configData) { + super(); + + this.configData = configData; + this.selected = null; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'views', 'dh-style', 'beastform-selection'], + position: { + width: 600, + height: 'auto' + }, + actions: { + selectBeastform: this.selectBeastform, + submitBeastform: this.submitBeastform + }, + form: { + handler: this.updateBeastform, + submitOnChange: true, + submitOnClose: false + } + }; + + get title() { + return game.i18n.localize('DAGGERHEART.Sheets.Beastform.dialogTitle'); + } + + /** @override */ + static PARTS = { + beastform: { + template: 'systems/daggerheart/templates/views/beastformDialog.hbs' + } + }; + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + + context.beastformTiers = game.items.reduce((acc, x) => { + const tier = tiers[x.system.tier]; + if (x.type !== 'beastform' || tier.value > this.configData.tierLimit) return acc; + + if (!acc[tier.value]) acc[tier.value] = { label: game.i18n.localize(tier.label), values: {} }; + acc[tier.value].values[x.uuid] = { selected: this.selected == x.uuid, value: x }; + + return acc; + }, {}); // Also get from compendium when added + context.canSubmit = this.selected; + + return context; + } + + static updateBeastform(event, _, formData) { + this.selected = foundry.utils.mergeObject(this.selected, formData.object); + + this.render(); + } + + static selectBeastform(_, target) { + this.selected = this.selected === target.dataset.uuid ? null : target.dataset.uuid; + this.render(); + } + + static async submitBeastform() { + await this.close({ submitted: true }); + } + + /** @override */ + _onClose(options = {}) { + if (!options.submitted) this.config = false; + } + + static async configure(configData) { + return new Promise(resolve => { + const app = new this(configData); + app.addEventListener('close', () => resolve(app.selected), { once: true }); + app.render({ force: true }); + }); + } +} diff --git a/module/dialogs/damageDialog.mjs b/module/dialogs/damageDialog.mjs index 4882475d..afec593b 100644 --- a/module/dialogs/damageDialog.mjs +++ b/module/dialogs/damageDialog.mjs @@ -38,7 +38,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application const context = await super._prepareContext(_options); context.title = this.config.title; context.extraFormula = this.config.extraFormula; - context.formula = this.roll.constructFormula(this.config);; + context.formula = this.roll.constructFormula(this.config); return context; } diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index ce73441b..2a2aa33e 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -28,4 +28,27 @@ export default class DhActiveEffect extends ActiveEffect { change.value = Roll.safeEval(Roll.replaceFormulaData(change.value, change.effect.parent)); super.applyField(model, change, field); } + + async toChat(origin) { + const cls = getDocumentClass('ChatMessage'); + const systemData = { + title: game.i18n.localize('DAGGERHEART.ActionType.action'), + origin: origin, + img: this.img, + name: this.name, + description: this.description, + actions: [] + }; + 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()); + } } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 0671e7e3..79e065fd 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -97,16 +97,16 @@ export default class DHItem extends foundry.documents.Item { async use(event) { const actions = this.system.actions; - let response; if (actions?.length) { let action = actions[0]; if (actions.length > 1 && !event?.shiftKey) { // Actions Choice Dialog action = await this.selectActionDialog(); } - if (action) response = action.use(event); + if (action) return action.use(event); } - return response; + + return this.toChat(); } async toChat(origin) { diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 62248af6..3dd4abc2 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -294,3 +294,15 @@ export const adjustRange = (rangeVal, decrease) => { const newIndex = decrease ? Math.max(index - 1, 0) : Math.min(index + 1, rangeKeys.length - 1); return range[rangeKeys[newIndex]]; }; + +export const updateActorTokens = async (actor, update) => { + await actor.prototypeToken.update(update); + + /* Update the tokens in all scenes belonging to Actor */ + for (let token of actor.getDependentTokens()) { + const tokenActor = token.baseActor ?? token.actor; + if (tokenActor?.id === actor.id) { + await token.update(update); + } + } +}; diff --git a/styles/application.less b/styles/application.less index 66735594..24b6a7d4 100644 --- a/styles/application.less +++ b/styles/application.less @@ -227,7 +227,7 @@ div.daggerheart.views.multiclass { filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%); } } - + #roll-selection-costSelection footer { display: none; } @@ -372,7 +372,6 @@ div.daggerheart.views.multiclass { } } - .roll-dialog-experience-container { display: flex; align-items: flex-start; @@ -509,6 +508,34 @@ div.daggerheart.views.multiclass { } } + .hint-group { + display: flex; + flex-direction: column; + align-items: end; + + .form-fields { + width: 100%; + display: flex; + align-items: center; + + label { + flex: 1; + } + + input, + select { + flex: 3; + } + } + + .hint { + margin: 4px 0 0 0; + font-size: 12px; + font-style: italic; + opacity: 0.6; + } + } + .data-form-array { border: 1px solid var(--color-fieldset-border); padding: 0.5rem; diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 803cd9eb..6b2b28d6 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -2329,6 +2329,29 @@ div.daggerheart.views.multiclass { width: 1.5rem; height: 1.5rem; } +.daggerheart.views.action .action-category .action-category-data .hint-group { + display: flex; + flex-direction: column; + align-items: end; +} +.daggerheart.views.action .action-category .action-category-data .hint-group .form-fields { + width: 100%; + display: flex; + align-items: center; +} +.daggerheart.views.action .action-category .action-category-data .hint-group .form-fields label { + flex: 1; +} +.daggerheart.views.action .action-category .action-category-data .hint-group .form-fields input, +.daggerheart.views.action .action-category .action-category-data .hint-group .form-fields select { + flex: 3; +} +.daggerheart.views.action .action-category .action-category-data .hint-group .hint { + margin: 4px 0 0 0; + font-size: 12px; + font-style: italic; + opacity: 0.6; +} .daggerheart.views.action .action-category .action-category-data .data-form-array { border: 1px solid var(--color-fieldset-border); padding: 0.5rem; @@ -5003,6 +5026,53 @@ div.daggerheart.views.multiclass { color: light-dark(#18162e50, #efe6d850); font-family: 'Montserrat', sans-serif; } +.theme-light .application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier .beastform-container .beastform-title { + background-image: url('../assets/parchments/dh-parchment-dark.png'); +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container { + display: flex; + flex-direction: column; + gap: 4px; +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 4px; +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier .beastform-container { + position: relative; + display: flex; + justify-content: center; + border: 1px solid light-dark(#18162e, #f3c267); + border-radius: 6px; + cursor: pointer; +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier .beastform-container.inactive { + opacity: 0.4; +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier .beastform-container img { + width: 100%; + border-radius: 6px; +} +.application.daggerheart.dh-style.views.beastform-selection .beastforms-container .beastforms-tier .beastform-container .beastform-title { + position: absolute; + top: 4px; + display: flex; + flex-wrap: wrap; + font-size: 16px; + margin: 0 4px; + border: 1px solid light-dark(#18162e, #f3c267); + border-radius: 6px; + color: light-dark(#efe6d8, #222); + background-image: url('../assets/parchments/dh-parchment-light.png'); +} +.application.daggerheart.dh-style.views.beastform-selection footer { + margin-top: 8px; + display: flex; +} +.application.daggerheart.dh-style.views.beastform-selection footer button { + flex: 1; +} .application.sheet.daggerheart.actor.dh-style.companion .companion-header-sheet { display: flex; flex-direction: column; @@ -5418,6 +5488,20 @@ div.daggerheart.views.multiclass { font-family: 'Montserrat', sans-serif; opacity: 0.8; } +/** + * Applies theme-specific styles. + * @param {Rules} @darkRules - Styles to apply when `.theme-dark` is present + * @param {Rules} @lightRules - Styles to apply when `.theme-light` is present + */ +.themed.theme-dark .application.sheet.dh-style, +.themed.theme-dark.application.sheet.dh-style { + background: rgba(24, 22, 46, 0.33); + backdrop-filter: blur(9px); +} +.themed.theme-light .application.sheet.dh-style, +.themed.theme-light.application.sheet.dh-style { + background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; +} .application.sheet.dh-style { border-radius: 10px; } @@ -5463,15 +5547,6 @@ div.daggerheart.views.multiclass { .application.sheet.dh-style:not(.minimized) .window-content { opacity: 1; } -.themed.theme-dark .application.sheet.dh-style, -.themed.theme-dark.application.sheet.dh-style { - background: rgba(24, 22, 46, 0.33); - backdrop-filter: blur(9px); -} -.themed.theme-light .application.sheet.dh-style, -.themed.theme-light.application.sheet.dh-style { - background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; -} .themed.theme-dark .application.sheet.dh-style.dialog, .themed.theme-dark.application.sheet.dh-style.dialog { background-image: url('../assets/parchments/dh-parchment-dark.png'); @@ -5973,6 +6048,44 @@ div.daggerheart.views.multiclass { justify-content: center; gap: 10px; } +.sheet.daggerheart.dh-style .tab.features .features-list { + display: flex; + flex-direction: column; + list-style: none; + padding: 0; + margin: 0; + width: 100%; + gap: 5px; +} +.sheet.daggerheart.dh-style .tab.features .features-list .feature-item { + display: grid; + align-items: center; + grid-template-columns: 1fr 4fr 1fr; + cursor: pointer; +} +.sheet.daggerheart.dh-style .tab.features .features-list .feature-item img { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 3px; +} +.sheet.daggerheart.dh-style .tab.features .features-list .feature-item h4 { + font-family: 'Montserrat', sans-serif; + font-weight: lighter; + color: #efe6d8; +} +.sheet.daggerheart.dh-style .tab.features .features-list .feature-item .image { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 6px; + border: none; +} +.sheet.daggerheart.dh-style .tab.features .features-list .feature-item .controls { + display: flex; + justify-content: center; + gap: 10px; +} .sheet.daggerheart.dh-style .tab.effects .effects-list { display: flex; flex-direction: column; diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 49c66916..38654759 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/applications//beastform.less'; + @import './less/actors/companion/header.less'; @import './less/actors/companion/details.less'; @import './less/actors/companion/sheet.less'; @@ -60,13 +62,14 @@ @import './less/global/tab-navigation.less'; @import './less/global/tab-form-footer.less'; @import './less/global/tab-actions.less'; +@import './less/global/tab-features.less'; @import './less/global/tab-effects.less'; @import './less/global/item-header.less'; @import './less/global/feature-section.less'; @import './less/global/inventory-item.less'; @import './less/global/inventory-fieldset-items.less'; @import './less/global/prose-mirror.less'; -@import "./less/global/filter-menu.less"; +@import './less/global/filter-menu.less'; @import '../node_modules/@yaireo/tagify/dist/tagify.css'; diff --git a/styles/less/actors/companion/header.less b/styles/less/actors/companion/header.less index df68747b..daa20e93 100644 --- a/styles/less/actors/companion/header.less +++ b/styles/less/actors/companion/header.less @@ -1,197 +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%; - } - } -} +@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 f245ea2a..8c071978 100644 --- a/styles/less/actors/companion/sheet.less +++ b/styles/less/actors/companion/sheet.less @@ -1,4 +1,3 @@ - // Theme header backgrounds .appTheme({ @@ -12,7 +11,6 @@ }); .application.sheet.daggerheart.actor.dh-style.companion { - // .profile { // height: 80px; // width: 80px; diff --git a/styles/less/actors/environment/sheet.less b/styles/less/actors/environment/sheet.less index c04b3dc3..733f105e 100644 --- a/styles/less/actors/environment/sheet.less +++ b/styles/less/actors/environment/sheet.less @@ -12,7 +12,6 @@ }); .application.sheet.daggerheart.actor.dh-style.environment { - .tab { max-height: 300px; overflow-y: auto; diff --git a/styles/less/applications/beastform.less b/styles/less/applications/beastform.less new file mode 100644 index 00000000..37069bdb --- /dev/null +++ b/styles/less/applications/beastform.less @@ -0,0 +1,59 @@ +.theme-light .application.daggerheart.dh-style.views.beastform-selection { + .beastforms-container .beastforms-tier .beastform-container .beastform-title { + background-image: url('../assets/parchments/dh-parchment-dark.png'); + } +} + +.application.daggerheart.dh-style.views.beastform-selection { + .beastforms-container { + display: flex; + flex-direction: column; + gap: 4px; + + .beastforms-tier { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 4px; + + .beastform-container { + position: relative; + display: flex; + justify-content: center; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + cursor: pointer; + + &.inactive { + opacity: 0.4; + } + + img { + width: 100%; + border-radius: 6px; + } + + .beastform-title { + position: absolute; + top: 4px; + display: flex; + flex-wrap: wrap; + font-size: 16px; + margin: 0 4px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + color: light-dark(@beige, @dark); + background-image: url('../assets/parchments/dh-parchment-light.png'); + } + } + } + } + + footer { + margin-top: 8px; + display: flex; + + button { + flex: 1; + } + } +} diff --git a/styles/less/global/dialog.less b/styles/less/global/dialog.less index bd12d73f..3856facb 100644 --- a/styles/less/global/dialog.less +++ b/styles/less/global/dialog.less @@ -1,43 +1,43 @@ -@import '../utils/colors.less'; -@import '../utils/fonts.less'; - -.appTheme({ - &.dialog { - background-image: url('../assets/parchments/dh-parchment-dark.png'); - background-repeat: no-repeat; - background-position: center; - } -}, { - &.dialog { - background-image: url('../assets/parchments/dh-parchment-light.png'); - background-repeat: no-repeat; - background-position: center; - } -}); - -.application.dialog.dh-style { - border: none; - - .window-header { - background: transparent; - border-bottom: none; - color: light-dark(@dark-blue, @beige); - - h1 { - color: light-dark(@dark-blue, @beige); - font-family: @font-body; - } - - button { - color: light-dark(@dark-blue, @beige); - background: light-dark(transparent, @deep-black); - border: 1px solid light-dark(@dark-blue, transparent); - padding: 0; - - &:hover { - border: 1px solid light-dark(@dark-blue, @golden); - color: light-dark(@dark-blue, @golden); - } - } - } -} +@import '../utils/colors.less'; +@import '../utils/fonts.less'; + +.appTheme({ + &.dialog { + background-image: url('../assets/parchments/dh-parchment-dark.png'); + background-repeat: no-repeat; + background-position: center; + } +}, { + &.dialog { + background-image: url('../assets/parchments/dh-parchment-light.png'); + background-repeat: no-repeat; + background-position: center; + } +}); + +.application.dialog.dh-style { + border: none; + + .window-header { + background: transparent; + border-bottom: none; + color: light-dark(@dark-blue, @beige); + + h1 { + color: light-dark(@dark-blue, @beige); + font-family: @font-body; + } + + button { + color: light-dark(@dark-blue, @beige); + background: light-dark(transparent, @deep-black); + border: 1px solid light-dark(@dark-blue, transparent); + padding: 0; + + &:hover { + border: 1px solid light-dark(@dark-blue, @golden); + color: light-dark(@dark-blue, @golden); + } + } + } +} diff --git a/styles/less/global/tab-features.less b/styles/less/global/tab-features.less new file mode 100644 index 00000000..91335fd5 --- /dev/null +++ b/styles/less/global/tab-features.less @@ -0,0 +1,50 @@ +@import '../utils/colors.less'; +@import '../utils/fonts.less'; + +.sheet.daggerheart.dh-style { + .tab.features { + .features-list { + display: flex; + flex-direction: column; + list-style: none; + padding: 0; + margin: 0; + width: 100%; + gap: 5px; + + .feature-item { + display: grid; + align-items: center; + grid-template-columns: 1fr 4fr 1fr; + cursor: pointer; + + img { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 3px; + } + + h4 { + font-family: @font-body; + font-weight: lighter; + color: @beige; + } + + .image { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 6px; + border: none; + } + + .controls { + display: flex; + justify-content: center; + gap: 10px; + } + } + } + } +} diff --git a/styles/less/utils/mixin.less b/styles/less/utils/mixin.less index c9f9f968..8b2dfedb 100644 --- a/styles/less/utils/mixin.less +++ b/styles/less/utils/mixin.less @@ -4,15 +4,15 @@ * @param {Rules} @lightRules - Styles to apply when `.theme-light` is present */ .appTheme(@darkRules, @lightRules) { - .themed { - &.theme-dark .application.sheet.dh-style, - &.theme-dark.application.sheet.dh-style { - @darkRules(); - } + .themed { + &.theme-dark .application.sheet.dh-style, + &.theme-dark.application.sheet.dh-style { + @darkRules(); + } - &.theme-light .application.sheet.dh-style, - &.theme-light.application.sheet.dh-style { - @lightRules(); + &.theme-light .application.sheet.dh-style, + &.theme-light.application.sheet.dh-style { + @lightRules(); + } } - } } diff --git a/system.json b/system.json index c1a5c501..99bdd747 100644 --- a/system.json +++ b/system.json @@ -5,7 +5,7 @@ "version": "0.0.1", "compatibility": { "minimum": "13", - "verified": "13.345", + "verified": "13.346", "maximum": "13" }, "authors": [ @@ -247,7 +247,11 @@ }, "armor": { "htmlFields": ["description"] - } + }, + "beastform": {} + }, + "ActiveEffect": { + "beastform": {} }, "Combat": { "combat": {} diff --git a/templates/sheets/global/partials/inventory-fieldset-items.hbs b/templates/sheets/global/partials/inventory-fieldset-items.hbs index 0051d6df..cd99fe17 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items.hbs @@ -14,11 +14,6 @@ {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=action type=../type}} {{/if}} {{/each}} - {{#each document.system.ancestry.system.actions as |action|}} - {{#if (or (eq ../type 'ancestry'))}} - {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=action type=../type}} - {{/if}} - {{/each}} {{#each document.system.class.value.system.classFeatures as |classFeature|}} {{#if (or (eq ../type 'class'))}} {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=classFeature type=../type}} diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 9b1c392b..a774b332 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,4 +1,4 @@ -
  • +
  • {{#if isCompanion}} diff --git a/templates/sheets/global/tabs/tab-features.hbs b/templates/sheets/global/tabs/tab-features.hbs new file mode 100644 index 00000000..59a43655 --- /dev/null +++ b/templates/sheets/global/tabs/tab-features.hbs @@ -0,0 +1,23 @@ +
    +
    + {{localize "DAGGERHEART.Sheets.Global.Features"}} +
    + {{#each document.system.features as |feature index|}} +
    + + {{feature.name}} +
    + +
    +
    + {{/each}} +
    +
    +
    \ No newline at end of file diff --git a/templates/sheets/items/beastform/header.hbs b/templates/sheets/items/beastform/header.hbs new file mode 100644 index 00000000..9c116c13 --- /dev/null +++ b/templates/sheets/items/beastform/header.hbs @@ -0,0 +1,10 @@ +
    + +
    + +

    +
    +

    {{localize 'TYPES.Item.beastform'}}

    +
    +
    +
    \ No newline at end of file diff --git a/templates/sheets/items/beastform/settings.hbs b/templates/sheets/items/beastform/settings.hbs new file mode 100644 index 00000000..a9052122 --- /dev/null +++ b/templates/sheets/items/beastform/settings.hbs @@ -0,0 +1,27 @@ +
    +
    + {{formGroup systemFields.tier value=source.system.tier localize=true}} + {{formGroup systemFields.examples value=source.system.examples localize=true}} +
    + +
    + {{localize "DAGGERHEART.Sheets.Beastform.FIELDS.advantageOn.label"}} + + {{!-- {{formGroup systemFields.examples value=source.system.examples localize=true}} --}} +
    + +
    + {{localize "DAGGERHEART.Sheets.Beastform.tokenTitle"}} + +
    + {{formGroup systemFields.tokenImg value=source.system.tokenImg localize=true}} +
    + + {{formGroup systemFields.tokenSize.fields.height value=source.system.tokenSize.height localize=true placeholder=(localize "DAGGERHEART.Sheets.Beastform.FIELDS.tokenSize.placeholder") }} + {{formGroup systemFields.tokenSize.fields.width value=source.system.tokenSize.width localize=true placeholder=(localize "DAGGERHEART.Sheets.Beastform.FIELDS.tokenSize.placeholder")}} +
    +
    \ No newline at end of file diff --git a/templates/tooltip/beastform.hbs b/templates/tooltip/beastform.hbs new file mode 100644 index 00000000..3af49969 --- /dev/null +++ b/templates/tooltip/beastform.hbs @@ -0,0 +1,6 @@ +
    +
    {{name}}
    + +
    {{{system.examples}}}
    +
    {{system.advantageOn}}
    +
    \ No newline at end of file diff --git a/templates/views/action.hbs b/templates/views/action.hbs index 9a3a25b4..711094a5 100644 --- a/templates/views/action.hbs +++ b/templates/views/action.hbs @@ -44,7 +44,8 @@ {{#if fields.healing}}{{> 'systems/daggerheart/templates/views/actionTypes/healing.hbs' fields=fields.healing.fields source=source.healing}}{{/if}} {{#if fields.resource}}{{> 'systems/daggerheart/templates/views/actionTypes/resource.hbs' fields=fields.resource.fields source=source.resource}}{{/if}} {{#if fields.documentUUID}}{{> 'systems/daggerheart/templates/views/actionTypes/uuid.hbs' fields=fields.documentUUID source=source.documentUUID}}{{/if}} - {{#if fields.effects}}{{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs' fields=fields.effects.element.fields source=source.effects}}{{/if}} + {{#if fields.effects}}{{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs' fields=fields.effects.element.fields source=source.effects}}{{/if}} + {{#if fields.beastform}}{{> 'systems/daggerheart/templates/views/actionTypes/beastform.hbs' fields=fields.effects.element.fields source=source.beastform}}{{/if}}
    \ No newline at end of file diff --git a/templates/views/actionTypes/beastform.hbs b/templates/views/actionTypes/beastform.hbs new file mode 100644 index 00000000..3ff4b0f1 --- /dev/null +++ b/templates/views/actionTypes/beastform.hbs @@ -0,0 +1,17 @@ +
    + +
    {{localize "DAGGERHEART.Actions.Config.Beastform.label"}}
    +
    + +
    +
    +
    + + +
    +

    {{localize "DAGGERHEART.Actions.Config.Beastform.exactHint"}}

    +
    +
    +
    \ No newline at end of file diff --git a/templates/views/beastformDialog.hbs b/templates/views/beastformDialog.hbs new file mode 100644 index 00000000..a9a0f757 --- /dev/null +++ b/templates/views/beastformDialog.hbs @@ -0,0 +1,18 @@ +
    +
    + {{#each beastformTiers as |tier tierKey|}} +
    + {{tier.label}} + {{#each tier.values as |form uuid|}} +
    + +
    {{form.value.name}}
    +
    + {{/each}} +
    + {{/each}} +
    + +
    \ No newline at end of file