10 Commits

Author SHA1 Message Date
uberwald 0d3cc5bbe0 Enable auto-release
Release Creation / build (release) Successful in 1m28s
2026-05-22 15:07:34 +02:00
uberwald ae65c93026 Enable auto-release
Release Creation / build (release) Successful in 1m52s
2026-05-22 15:01:26 +02:00
uberwald de2175f31c Enable auto-release
Release Creation / build (release) Failing after 53s
2026-05-22 14:56:06 +02:00
uberwald 220891c93f Enable auto-release
Release Creation / build (release) Failing after 47s
2026-05-22 14:51:16 +02:00
uberwald e7bb7b4456 Enable auto-release
Release Creation / build (release) Failing after 1m40s
2026-05-22 14:45:26 +02:00
uberwald 984dfcf507 Enable auto-release 2026-05-22 14:06:58 +02:00
uberwald 7947ceaff1 Enable auto-release 2026-05-22 14:05:25 +02:00
uberwald 9717bc7b77 Enable auto-release 2026-05-22 14:02:28 +02:00
uberwald dd3fe0e38e Implements inventory system, wip 2026-05-22 11:03:17 +02:00
uberwald 4ff46865c2 Implements inventory system, wip 2026-05-19 22:23:31 +02:00
36 changed files with 1792 additions and 48 deletions
+71
View File
@@ -0,0 +1,71 @@
name: Release Creation
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "💡 The ${{ gitea.repository }} repository will be cloned to the runner."
- uses: RouxAntoine/checkout@v3.5.4
# Extrait la version depuis le tag (ex: v1.2.3 → 1.2.3)
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
# Met à jour version, manifest et download dans system.json
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
with:
files: "system.json"
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-prism-rpg-${{github.event.release.tag_name}}.zip
# Compile le CSS depuis les sources LESS (gitignored)
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: "22"
- name: Build CSS
run: npm install && npx gulp css
# Crée le zip de release avec tous les fichiers nécessaires au système
- run: |
apt update -y
apt install -y zip
- run: zip -r ./fvtt-prism-rpg-${{github.event.release.tag_name}}.zip system.json prism-rpg.mjs assets/ css/ lang/ module/ styles/ templates/
- name: setup go
uses: https://github.com/actions/setup-go@v4
with:
go-version: ">=1.20.1"
- name: Use Go Action
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./fvtt-prism-rpg-${{github.event.release.tag_name}}.zip
system.json
api_key: "${{secrets.RELEASE_PRISM }}"
#- name: Publish to Foundry server
# uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
# with:
# token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
# id: "fvtt-prism-rpg"
# version: ${{github.event.release.tag_name}}
# manifest: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/latest/system.json"
# notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-prism-rpg-${{github.event.release.tag_name}}.zip"
# compatibility-minimum: "14"
# compatibility-verified: "14"
+424 -15
View File
@@ -54,6 +54,13 @@ i.prismrpg {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); font-size: calc(var(--font-size-standard) * 1);
background-image: var(--background-image-base); background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.application.dialog.prismrpg .window-content {
background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
} }
.application.dialog.prismrpg button:hover { .application.dialog.prismrpg button:hover {
background: var(--color-dark-6); background: var(--color-dark-6);
@@ -681,6 +688,166 @@ i.prismrpg {
.prismrpg .tab.character-equipment .main-div .equipments .name { .prismrpg .tab.character-equipment .main-div .equipments .name {
min-width: 12rem; min-width: 12rem;
} }
.prismrpg .tab.character-equipment .main-div .inv-section {
margin-bottom: 6px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-items {
display: flex;
flex-direction: column;
gap: 3px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(255, 255, 255, 0.15);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item:hover {
background: rgba(255, 255, 255, 0.25);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .item-img {
width: 24px;
height: 24px;
cursor: pointer;
flex-shrink: 0;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-name {
flex: 1;
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-enc,
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-uses,
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-capacity {
font-size: 11px;
color: #555;
min-width: 30px;
text-align: center;
white-space: nowrap;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .controls {
display: flex;
gap: 4px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .controls a {
font-size: 12px;
cursor: pointer;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-empty {
font-style: italic;
color: rgba(0, 0, 0, 0.4);
text-align: center;
font-size: 11px;
padding: 4px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id] {
border: 1px dashed transparent;
transition: border-color 0.15s, background 0.15s;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id].drag-over {
border-color: rgba(100, 150, 255, 0.7);
background: rgba(100, 150, 255, 0.12);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-items {
margin: 2px 0 6px 28px;
display: flex;
flex-direction: column;
gap: 2px;
border-left: 2px solid rgba(0, 0, 0, 0.15);
padding-left: 8px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(0, 0, 0, 0.06);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item:hover {
background: rgba(0, 0, 0, 0.12);
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .item-img {
width: 20px;
height: 20px;
cursor: pointer;
flex-shrink: 0;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-name {
flex: 1;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-enc {
font-size: 10px;
color: #555;
min-width: 24px;
text-align: center;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-container-type-badge {
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: rgba(0, 0, 0, 0.45);
background: rgba(0, 0, 0, 0.07);
border-radius: 3px;
padding: 1px 4px;
flex-shrink: 0;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls {
display: flex;
gap: 4px;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls a {
font-size: 11px;
cursor: pointer;
}
.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-empty {
margin: 2px 0 4px 36px;
font-size: 10px;
font-style: italic;
color: rgba(0, 0, 0, 0.35);
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
font-size: 13px;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-label {
font-weight: bold;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value {
font-weight: bold;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-used {
color: #e6a817;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-sep {
color: rgba(0, 0, 0, 0.4);
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-max {
color: rgba(0, 0, 0, 0.7);
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-used {
color: #e6a817;
font-weight: bold;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-sep {
color: rgba(0, 0, 0, 0.4);
margin: 0 2px;
}
.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-max {
color: rgba(0, 0, 0, 0.7);
font-weight: bold;
}
.prismrpg .tab.character-combat .main-div { .prismrpg .tab.character-combat .main-div {
background-image: url("../assets/ui/prism_rpg_background.webp"); background-image: url("../assets/ui/prism_rpg_background.webp");
background-size: cover; background-size: cover;
@@ -951,6 +1118,27 @@ i.prismrpg {
.prismrpg .tab.character-miracles .main-div prose-mirror.active { .prismrpg .tab.character-miracles .main-div prose-mirror.active {
min-height: 150px; min-height: 150px;
} }
.prismrpg .inv-item.is-equipped {
background: rgba(100, 180, 100, 0.12);
border-left: 2px solid rgba(80, 160, 80, 0.6);
}
.prismrpg .inv-item .equipped-icon {
color: #5a9e6a;
}
.prismrpg .inv-item .unequipped-icon {
color: rgba(0, 0, 0, 0.25);
}
.prismrpg .burden-excess {
font-size: 0.75em;
color: #ff5c5c;
margin-left: 4px;
white-space: nowrap;
}
.prismrpg .controls a.disabled {
opacity: 0.35;
pointer-events: none;
cursor: default;
}
.prismrpg .character-main-v2 { .prismrpg .character-main-v2 {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); font-size: calc(var(--font-size-standard) * 1);
@@ -1052,17 +1240,21 @@ i.prismrpg {
align-items: start; align-items: start;
} }
.prismrpg .character-main-v2 .character-left-column { .prismrpg .character-main-v2 .character-left-column {
display: flex; display: grid;
flex-direction: row; grid-template-columns: 200px 1fr;
gap: 12px; grid-template-rows: auto auto;
align-items: flex-start; column-gap: 12px;
row-gap: 8px;
align-items: start;
min-width: 0;
} }
.prismrpg .character-main-v2 .character-left-column .portrait-hp-column { .prismrpg .character-main-v2 .character-left-column .portrait-hp-column {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
width: 200px; width: 200px;
flex-shrink: 0; grid-column: 1;
grid-row: 1 / 3;
} }
.prismrpg .character-main-v2 .character-left-column .character-portrait { .prismrpg .character-main-v2 .character-left-column .character-portrait {
width: 200px; width: 200px;
@@ -1134,9 +1326,9 @@ i.prismrpg {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
flex: 1; grid-column: 2;
grid-row: 1;
min-width: 0; min-width: 0;
max-width: 280px;
} }
.prismrpg .character-main-v2 .character-left-column .character-attributes .attribute-shield { .prismrpg .character-main-v2 .character-left-column .character-attributes .attribute-shield {
position: relative; position: relative;
@@ -1408,6 +1600,103 @@ i.prismrpg {
line-height: 1.6; line-height: 1.6;
resize: vertical; resize: vertical;
} }
.prismrpg .burden-mr-section {
display: flex;
flex-direction: row;
gap: 16px;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.35);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 4px;
grid-column: 2;
grid-row: 2;
}
.prismrpg .burden-mr-section .burden-mr-item {
display: flex;
flex-direction: column;
gap: 3px;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-display-row {
display: flex;
align-items: center;
gap: 8px;
min-height: 22px;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-edit-row {
display: flex;
align-items: center;
gap: 3px;
flex-wrap: wrap;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-label {
font-weight: bold;
font-size: 11px;
letter-spacing: 0.05em;
min-width: 52px;
color: #fff;
cursor: default;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-group {
display: contents;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-group label {
display: none;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-fields {
display: contents;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr select {
font-size: 11px;
padding: 1px 2px;
height: 22px;
max-width: 80px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-op {
font-size: 11px;
color: rgba(255, 255, 255, 0.9);
flex-shrink: 0;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-other input[type="number"] {
width: 32px;
text-align: center;
font-size: 11px;
height: 22px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-total {
font-size: 18px;
font-weight: bold;
color: #ffe566;
min-width: 24px;
text-align: center;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-used-max {
display: flex;
align-items: center;
gap: 2px;
font-size: 14px;
font-weight: bold;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-used {
color: #ffe566;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-separator {
color: rgba(255, 255, 255, 0.8);
}
.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-max {
color: #e0e0e0;
}
.prismrpg .burden-mr-section .burden-mr-item .burden-used-max.burden-overloaded .burden-used {
color: #ff5c5c;
font-weight: bold;
}
.prismrpg .character-subattributes.tab .subattributes-content { .prismrpg .character-subattributes.tab .subattributes-content {
padding: 1rem; padding: 1rem;
} }
@@ -3563,6 +3852,126 @@ i.prismrpg {
.prismrpg .character-path-content input[type="checkbox"]:checked::after { .prismrpg .character-path-content input[type="checkbox"]:checked::after {
color: rgba(0, 0, 0, 0.1); color: rgba(0, 0, 0, 0.1);
} }
.prismrpg .container-content {
font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1);
color: var(--color-dark-1);
background-image: var(--background-image-base);
background-repeat: no-repeat;
background-size: 100% 100%;
overflow: auto;
}
.prismrpg .container-content nav.tabs [data-tab] {
color: #636060;
}
.prismrpg .container-content nav.tabs [data-tab].active {
color: #252424;
}
.prismrpg .container-content input:disabled,
.prismrpg .container-content select:disabled {
background-color: rgba(0, 0, 0, 0.2);
border-color: transparent;
color: var(--color-dark-3);
}
.prismrpg .container-content input,
.prismrpg .container-content select {
height: 1.5rem;
background-color: rgba(0, 0, 0, 0.1);
border-color: var(--color-dark-6);
color: var(--color-dark-2);
}
.prismrpg .container-content input[name="name"] {
height: 2.5rem;
margin-right: 4px;
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.2);
font-weight: bold;
border: none;
}
.prismrpg .container-content fieldset {
margin-bottom: 4px;
border-radius: 4px;
}
.prismrpg .container-content .form-fields input,
.prismrpg .container-content .form-fields select {
text-align: center;
font-size: calc(var(--font-size-standard) * 1);
}
.prismrpg .container-content .form-fields select {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1);
}
.prismrpg .container-content legend {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.2);
font-weight: bold;
letter-spacing: 1px;
}
.prismrpg .container-content .form-fields {
padding-top: 4px;
}
.prismrpg .container-content .form-group {
display: flex;
flex: 1;
flex-direction: row;
}
.prismrpg .container-content .form-group label {
align-content: center;
min-width: 10rem;
max-width: 10rem;
}
.prismrpg .container-content .form-group select,
.prismrpg .container-content .form-group input {
text-align: left;
min-width: 12rem;
max-width: 12rem;
}
.prismrpg .container-content .form-group input[type="checkbox"] {
min-width: 1.2rem;
max-width: 1.2rem;
margin-right: 0.5rem;
}
.prismrpg .container-content label {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1);
flex: 50%;
}
.prismrpg .container-content .align-top {
align-self: flex-start;
padding: 0.1rem;
margin-right: 0.2rem;
}
.prismrpg .container-content .shift-right {
margin-left: 2rem;
}
.prismrpg .container-content .header {
display: flex;
}
.prismrpg .container-content .header img {
width: 50px;
height: 50px;
}
.prismrpg .container-content .item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
.prismrpg .consumable-content .item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
.prismrpg .loot-content .item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
.prismrpg .effects-container { .prismrpg .effects-container {
padding: 0.5rem; padding: 0.5rem;
} }
@@ -4914,15 +5323,15 @@ i.prismrpg {
.prismrpg-roll-dialog-modern .checkbox-group .checkbox-label input[type="checkbox"]:checked ~ .checkbox-text i { .prismrpg-roll-dialog-modern .checkbox-group .checkbox-label input[type="checkbox"]:checked ~ .checkbox-text i {
color: #d4af37; color: #d4af37;
} }
.application.dialog.prismrpg .window-content { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .window-content {
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
padding: 8px; padding: 8px;
} }
.application.dialog.prismrpg .dialog-buttons { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons {
padding: 6px 8px; padding: 6px 8px;
gap: 6px; gap: 6px;
} }
.application.dialog.prismrpg .dialog-buttons button { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button {
background: linear-gradient(135deg, #4a4a4a 0%, #6a6a6a 100%); background: linear-gradient(135deg, #4a4a4a 0%, #6a6a6a 100%);
border: 1px solid #3a3a3a; border: 1px solid #3a3a3a;
color: white; color: white;
@@ -4931,19 +5340,19 @@ i.prismrpg {
border-radius: 4px; border-radius: 4px;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.application.dialog.prismrpg .dialog-buttons button:hover { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button:hover {
background: linear-gradient(135deg, #5a5a5a 0%, #7a7a7a 100%); background: linear-gradient(135deg, #5a5a5a 0%, #7a7a7a 100%);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transform: translateY(-1px); transform: translateY(-1px);
} }
.application.dialog.prismrpg .dialog-buttons button.default, .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default,
.application.dialog.prismrpg .dialog-buttons button[data-button="roll"] { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"] {
background: linear-gradient(135deg, #d4af37 0%, #f4cf67 100%); background: linear-gradient(135deg, #d4af37 0%, #f4cf67 100%);
border-color: #b49030; border-color: #b49030;
color: #2a2a2a; color: #2a2a2a;
} }
.application.dialog.prismrpg .dialog-buttons button.default:hover, .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default:hover,
.application.dialog.prismrpg .dialog-buttons button[data-button="roll"]:hover { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"]:hover {
background: linear-gradient(135deg, #e4bf47 0%, #ffdf77 100%); background: linear-gradient(135deg, #e4bf47 0%, #ffdf77 100%);
} }
#token-hud .hp-loss-wrap { #token-hud .hp-loss-wrap {
+127 -3
View File
@@ -244,6 +244,17 @@
}, },
"wis": { "wis": {
"label": "Wisdom" "label": "Wisdom"
},
"movementRating": {
"label": "Movement Rating",
"subAttribute": { "label": "Sub-Attribute" },
"other": { "label": "Other" },
"reduction": { "label": "Reduction" }
},
"burden": {
"label": "Burden",
"subAttribute": { "label": "Sub-Attribute" },
"other": { "label": "Other" }
} }
} }
}, },
@@ -361,6 +372,9 @@
"money": { "money": {
"label": "Money unit" "label": "Money unit"
}, },
"equipped": {
"label": "Equipped"
},
"isKit": { "isKit": {
"label": "Is Kit?" "label": "Is Kit?"
}, },
@@ -523,6 +537,17 @@
"Challenges": "Challenges", "Challenges": "Challenges",
"HP": "HP", "HP": "HP",
"HPTemp": "Temporary Hit Points", "HPTemp": "Temporary Hit Points",
"movementRating": "Movement Rating",
"burdenCharacter": "Burden",
"packBurden": "Pack Burden",
"container": "Container",
"containers": "Containers",
"consumables": "Consumables",
"loot": "Loot",
"kits": "Kits",
"weapons": "Weapons",
"encLoad": "Enc. Load",
"reduction": "Reduction",
"Movement": "Movement", "Movement": "Movement",
"Saves": "Saves", "Saves": "Saves",
"app": "APP", "app": "APP",
@@ -898,13 +923,46 @@
"skill": "Skills list", "skill": "Skills list",
"skills": "Skills - Your character's skills and abilities", "skills": "Skills - Your character's skills and abilities",
"racialAbilities": "Racial Abilities from your character's race and sub-race", "racialAbilities": "Racial Abilities from your character's race and sub-race",
"abilities": "Abilities acquired through class, paths, or other sources" "abilities": "Abilities acquired through class, paths, or other sources",
"movementRating": "Movement Rating (MR): 3 + Sub-Attribute + Other - Reduction",
"burdenCharacter": "Burden: Base Burden + Sub-Attribute + Other (max); Used = sum of equipped item load",
"packBurden": "Pack Burden capacity of this container",
"uses": "Remaining uses / Max uses",
"useConsumable": "Use this consumable",
"toggleEquipped": "Toggle equipped (affects Pack Burden)",
"addWeapon": "Add weapon",
"addArmor": "Add armor",
"addShield": "Add shield",
"addConsumable": "Add consumable",
"addKit": "Add kit",
"addEquipment": "Add equipment",
"addLoot": "Add loot",
"addContainer": "Add container",
"addRacialAbility": "Add racial ability",
"addAbility": "Add ability",
"excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating",
"assignToContainer": "Assign to container",
"removeFromContainer": "Remove from container",
"packBurden": "Pack Burden"
}, },
"RollSavingThrow": "Roll Saving Throw", "RollSavingThrow": "Roll Saving Throw",
"Dialog": {
"useConsumable": "Use Consumable",
"useConsumableContent": "Use one charge of <strong>{name}</strong>? ({uses} remaining)",
"assignToContainer": "Assign to Container"
},
"Message": { "Message": {
"selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.", "selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.",
"dropRace": "Drag and drop a Race item here", "dropRace": "Drag and drop a Race item here",
"dropClass": "Drag and drop a Class item here" "dropClass": "Drag and drop a Class item here",
"noContainers": "No containers in inventory",
"noConsumables": "No consumables in inventory",
"noLoot": "No loot in inventory",
"noWeapons": "No weapons",
"noArmor": "No armor or shields",
"noKits": "No kits",
"noEquipment": "No equipment",
"noStoredItems": "Nothing stored"
}, },
"Miracle": { "Miracle": {
"FIELDS": { "FIELDS": {
@@ -1381,6 +1439,69 @@
"subraceAbilityDescription": { "subraceAbilityDescription": {
"label": "Sub-race Ability Description" "label": "Sub-race Ability Description"
}, },
"notes": {
"label": "Notes"
},
"baseBurden": {
"label": "Base Burden"
}
}
},
"Container": {
"FIELDS": {
"packBurden": {
"label": "Pack Burden (Capacity)"
},
"encLoad": {
"label": "Enc. Load"
},
"cost": {
"label": "Cost"
},
"equipped": {
"label": "Equipped"
},
"description": {
"label": "Description"
},
"notes": {
"label": "Notes"
}
}
},
"Consumable": {
"FIELDS": {
"description": {
"label": "Description"
},
"usesMax": {
"label": "Max Uses"
},
"uses": {
"label": "Uses"
},
"encLoad": {
"label": "Enc. Load"
},
"cost": {
"label": "Cost"
},
"notes": {
"label": "Notes"
}
}
},
"Loot": {
"FIELDS": {
"description": {
"label": "Description"
},
"encLoad": {
"label": "Enc. Load"
},
"cost": {
"label": "Cost"
},
"notes": { "notes": {
"label": "Notes" "label": "Notes"
} }
@@ -1507,7 +1628,10 @@
"weapon": "Weapon", "weapon": "Weapon",
"race": "Race", "race": "Race",
"class": "Class", "class": "Class",
"character-path": "Character Path" "character-path": "Character Path",
"container": "Container",
"consumable": "Consumable",
"loot": "Loot"
} }
} }
} }
+3
View File
@@ -13,4 +13,7 @@ export { default as PrismRPGMiracleSheet } from "./sheets/miracle-sheet.mjs"
export { default as PrismRPGRaceSheet } from "./sheets/race-sheet.mjs" export { default as PrismRPGRaceSheet } from "./sheets/race-sheet.mjs"
export { default as PrismRPGClassSheet } from "./sheets/class-sheet.mjs" export { default as PrismRPGClassSheet } from "./sheets/class-sheet.mjs"
export { default as PrismRPGCharacterPathSheet } from "./sheets/character-path-sheet.mjs" export { default as PrismRPGCharacterPathSheet } from "./sheets/character-path-sheet.mjs"
export { default as PrismRPGContainerSheet } from "./sheets/container-sheet.mjs"
export { default as PrismRPGConsumableSheet } from "./sheets/consumable-sheet.mjs"
export { default as PrismRPGLootSheet } from "./sheets/loot-sheet.mjs"
export { WeaponTypesConfig } from "./weapon-types-config.mjs" export { WeaponTypesConfig } from "./weapon-types-config.mjs"
+182 -3
View File
@@ -29,6 +29,11 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
hpTempPlus: PrismRPGCharacterSheet.#onHpTempPlus, hpTempPlus: PrismRPGCharacterSheet.#onHpTempPlus,
hpTempMinus: PrismRPGCharacterSheet.#onHpTempMinus, hpTempMinus: PrismRPGCharacterSheet.#onHpTempMinus,
postItemToChat: PrismRPGCharacterSheet.#onPostItemToChat, postItemToChat: PrismRPGCharacterSheet.#onPostItemToChat,
useConsumable: PrismRPGCharacterSheet.#onUseConsumable,
toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped,
toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped,
assignToContainer: PrismRPGCharacterSheet.#onAssignToContainer,
removeFromContainer: PrismRPGCharacterSheet.#onRemoveFromContainer,
}, },
} }
@@ -109,13 +114,39 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
classes[1] || null, classes[1] || null,
classes[2] || null classes[2] || null
] ]
// Burden computed values
const bSubAttr = doc.system.burden.subAttribute
const bSubVal = doc.system.subAttributes[bSubAttr]?.value ?? 0
const baseBurden = doc.itemTypes.race?.[0]?.system.baseBurden ?? 0
context.burdenMax = Math.max(0, baseBurden + bSubVal + doc.system.burden.other)
// Equipped burden: only items with equipped=true count toward burden
const equippableTypes = [
...doc.itemTypes.weapon,
...doc.itemTypes.armor,
...doc.itemTypes.shield,
...doc.itemTypes.equipment,
...doc.itemTypes.container,
]
const burdenEquipped = equippableTypes
.filter(i => i.system.equipped)
.reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
context.burdenUsed = burdenEquipped
// Excess equipped burden reduces Movement Rating
const excessBurden = Math.max(0, burdenEquipped - context.burdenMax)
// Movement Rating computed value (excess burden adds to reduction)
const mrSubAttr = doc.system.movementRating.subAttribute
const mrSubVal = doc.system.subAttributes[mrSubAttr]?.value ?? 0
context.movementRatingValue = Math.max(0,
3 + mrSubVal + doc.system.movementRating.other - doc.system.movementRating.reduction - excessBurden
)
context.excessBurden = excessBurden
break break
case "skills": case "skills":
context.tab = context.tabs.skills context.tab = context.tabs.skills
context.skills = doc.itemTypes.skill context.skills = doc.itemTypes.skill
context.racialAbilities = doc.itemTypes["racial-ability"] context.racialAbilities = doc.itemTypes["racial-ability"]
context.abilities = doc.itemTypes["ability"] context.abilities = doc.itemTypes.ability
context.vulnerabilities = doc.itemTypes.vulnerability context.vulnerabilities = doc.itemTypes.vulnerability ?? []
break break
case "subattributes": case "subattributes":
context.tab = context.tabs.subattributes context.tab = context.tabs.subattributes
@@ -133,7 +164,45 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
break break
case "equipment": case "equipment":
context.tab = context.tabs.equipment context.tab = context.tabs.equipment
context.equipments = doc.itemTypes.equipment // All items that can be stored in containers
const allStorable = [
...doc.itemTypes.weapon,
...doc.itemTypes.armor,
...doc.itemTypes.shield,
...doc.itemTypes.equipment,
...doc.itemTypes.consumable,
...doc.itemTypes.loot,
]
// Build a map: containerId → items[]
const containerGroups = {}
for (const container of doc.itemTypes.container) {
containerGroups[container.id] = { container, items: [] }
}
for (const item of allStorable) {
const cid = item.system.containerId
if (cid && containerGroups[cid]) {
containerGroups[cid].items.push(item)
}
}
context.containerGroups = Object.values(containerGroups)
// Items are "uncontained" if they have no containerId, or if their container was deleted
const isUncontained = i => !i.system.containerId || !containerGroups[i.system.containerId]
context.weapons = doc.itemTypes.weapon.filter(isUncontained)
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield].filter(isUncontained)
context.consumables = doc.itemTypes.consumable.filter(isUncontained)
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit && isUncontained(i))
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit && isUncontained(i))
context.loots = doc.itemTypes.loot.filter(isUncontained)
context.containers = doc.itemTypes.container
context.packBurdenMax = doc.itemTypes.container
.filter(c => c.system.equipped)
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
// Pack burden = items stored in an existing container
context.packBurdenUsed = allStorable
.filter(i => i.system.containerId && containerGroups[i.system.containerId])
.reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
break break
case "biography": case "biography":
context.tab = context.tabs.biography context.tab = context.tabs.biography
@@ -158,6 +227,18 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
// Handle different data types // Handle different data types
if (data.type === "Item") { if (data.type === "Item") {
const item = await fromUuid(data.uuid) const item = await fromUuid(data.uuid)
// Check if dropped onto a container row
const containerEl = event.target.closest("[data-container-id]")
if (containerEl && item?.parent === this.document) {
const containerId = containerEl.dataset.containerId
// Don't store containers inside containers
if (item.type !== "container") {
await item.update({ "system.containerId": containerId })
return
}
}
return this._onDropItem(item) return this._onDropItem(item)
} }
} }
@@ -237,6 +318,93 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
} }
static async #onCreateEquipment(event, target) { static async #onCreateEquipment(event, target) {
const itemType = target.dataset.itemType ?? "equipment"
const isKit = target.dataset.itemKit === "true"
const typeLabel = game.i18n.localize(`TYPES.Item.${itemType}`) || itemType
const itemData = {
name: game.i18n.format("DOCUMENT.New", { type: typeLabel }),
type: itemType,
}
if (isKit) itemData["system.isKit"] = true
await this.document.createEmbeddedDocuments("Item", [itemData])
}
static async #onUseConsumable(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item) return
if (item.system.uses <= 0) return
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: { title: game.i18n.localize("PRISMRPG.Dialog.useConsumable") },
content: `<p>${game.i18n.format("PRISMRPG.Dialog.useConsumableContent", { name: item.name, uses: item.system.uses })}</p>`,
})
if (!confirmed) return
if (item.system.uses <= 1) {
await item.delete()
} else {
await item.update({ "system.uses": item.system.uses - 1 })
}
}
static async #onToggleContainerEquipped(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item) return
await item.update({ "system.equipped": !item.system.equipped })
}
static async #onToggleEquipped(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item) return
await item.update({ "system.equipped": !item.system.equipped })
}
static async #onAssignToContainer(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item || item.type === "container") return
const containers = this.document.itemTypes.container
if (!containers.length) {
ui.notifications.warn(game.i18n.localize("PRISMRPG.Message.noContainers"))
return
}
const options = containers.map(c => {
const escapedName = foundry.utils.escapeHTML(c.name)
return `<option value="${c.id}">${escapedName}</option>`
}).join("")
const content = `<div class="form-group">
<label>${game.i18n.localize("PRISMRPG.Label.container")}</label>
<div class="form-fields">
<select name="containerId">${options}</select>
</div>
</div>`
const containerId = await foundry.applications.api.DialogV2.prompt({
window: { title: game.i18n.localize("PRISMRPG.Dialog.assignToContainer") },
classes: ["prismrpg"],
content,
ok: {
callback: (event, button) => button.form.elements.containerId.value,
},
})
if (containerId) await item.update({ "system.containerId": containerId })
}
static async #onRemoveFromContainer(event, target) {
const itemElement = target.closest("[data-item-id]")
if (!itemElement) return
const item = this.document.items.get(itemElement.dataset.itemId)
if (!item) return
await item.update({ "system.containerId": "" })
} }
static async #onPostItemToChat(event, target) { static async #onPostItemToChat(event, target) {
@@ -403,6 +571,17 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
this.actor.update({ "system.hp.wounds": tab }); this.actor.update({ "system.hp.wounds": tab });
}) })
} }
// Container drag-over highlight
this.element.querySelectorAll("[data-container-id]").forEach(el => {
el.addEventListener("dragover", (e) => {
e.preventDefault()
el.classList.add("drag-over")
})
el.addEventListener("dragleave", () => el.classList.remove("drag-over"))
el.addEventListener("drop", () => el.classList.remove("drag-over"))
})
super._onRender(); super._onRender();
} }
@@ -0,0 +1,44 @@
import PrismRPGItemSheet from "./base-item-sheet.mjs"
export default class PrismRPGConsumableSheet extends PrismRPGItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["consumable"],
position: { width: 550 },
window: { contentClasses: ["consumable-content"] },
}
/** @override */
static PARTS = {
main: { template: "systems/fvtt-prism-rpg/templates/consumable.hbs" },
}
/** @override */
tabGroups = { primary: "details" }
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" },
description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" },
effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" },
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.description, { async: true }
)
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.notes, { async: true }
)
return context
}
}
@@ -0,0 +1,52 @@
import PrismRPGItemSheet from "./base-item-sheet.mjs"
export default class PrismRPGContainerSheet extends PrismRPGItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["container"],
position: {
width: 600,
},
window: {
contentClasses: ["container-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-prism-rpg/templates/container.hbs",
},
}
/** @override */
tabGroups = {
primary: "details",
}
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" },
description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" },
effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" },
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.description, { async: true }
)
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.notes, { async: true }
)
return context
}
}
+44
View File
@@ -0,0 +1,44 @@
import PrismRPGItemSheet from "./base-item-sheet.mjs"
export default class PrismRPGLootSheet extends PrismRPGItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["loot"],
position: { width: 500 },
window: { contentClasses: ["loot-content"] },
}
/** @override */
static PARTS = {
main: { template: "systems/fvtt-prism-rpg/templates/loot.hbs" },
}
/** @override */
tabGroups = { primary: "details" }
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" },
description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" },
effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" },
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.description, { async: true }
)
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.notes, { async: true }
)
return context
}
}
+1
View File
@@ -9,6 +9,7 @@ export const defaultItemImg = {
race: "systems/fvtt-prism-rpg/assets/icons/icon_race.webp", race: "systems/fvtt-prism-rpg/assets/icons/icon_race.webp",
class: "systems/fvtt-prism-rpg/assets/icons/icon_class.webp", class: "systems/fvtt-prism-rpg/assets/icons/icon_class.webp",
"character-path": "systems/fvtt-prism-rpg/assets/icons/icon_character_path.webp", "character-path": "systems/fvtt-prism-rpg/assets/icons/icon_character_path.webp",
container: "icons/containers/bags/pack-leather-brown.webp",
} }
export default class PrismRPGItem extends Item { export default class PrismRPGItem extends Item {
+3
View File
@@ -11,3 +11,6 @@ export { default as PrismRPGEquipment } from "./equipment.mjs"
export { default as PrismRPGRace } from "./race.mjs" export { default as PrismRPGRace } from "./race.mjs"
export { default as PrismRPGClass } from "./class.mjs" export { default as PrismRPGClass } from "./class.mjs"
export { default as PrismRPGCharacterPath } from "./character-path.mjs" export { default as PrismRPGCharacterPath } from "./character-path.mjs"
export { default as PrismRPGContainer } from "./container.mjs"
export { default as PrismRPGConsumable } from "./consumable.mjs"
export { default as PrismRPGLoot } from "./loot.mjs"
+1
View File
@@ -25,6 +25,7 @@ export default class PrismRPGArmor extends foundry.abstract.TypeDataModel {
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+15
View File
@@ -136,6 +136,21 @@ export default class PrismRPGCharacter extends foundry.abstract.TypeDataModel {
}, {}), }, {}),
) )
// Sub-attribute choices for movement rating and burden selectors
const subAttributeChoices = () =>
Object.values(SYSTEM.SUB_ATTRIBUTES).reduce((obj, s) => { obj[s.id] = s.label; return obj }, {})
schema.movementRating = new fields.SchemaField({
subAttribute: new fields.StringField({ required: true, initial: "stamina", choices: subAttributeChoices }),
other: new fields.NumberField({ ...requiredInteger, initial: 0 }),
reduction: new fields.NumberField({ ...requiredInteger, initial: 0 })
})
schema.burden = new fields.SchemaField({
subAttribute: new fields.StringField({ required: true, initial: "vigor", choices: subAttributeChoices }),
other: new fields.NumberField({ ...requiredInteger, initial: 0 })
})
return schema return schema
} }
+20
View File
@@ -0,0 +1,20 @@
export default class PrismRPGConsumable extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.usesMax = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 })
schema.uses = new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.notes = new fields.HTMLField({ required: true })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["PRISMRPG.Consumable"]
}
+19
View File
@@ -0,0 +1,19 @@
export default class PrismRPGContainer extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.packBurden = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.notes = new fields.HTMLField({ required: true })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["PRISMRPG.Container"]
}
+2
View File
@@ -12,6 +12,8 @@ export default class PrismRPGEquipment extends foundry.abstract.TypeDataModel {
schema.encLoad = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.encLoad = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
// Kit properties // Kit properties
schema.isKit = new fields.BooleanField({ schema.isKit = new fields.BooleanField({
+18
View File
@@ -0,0 +1,18 @@
export default class PrismRPGLoot extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.notes = new fields.HTMLField({ required: true })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["PRISMRPG.Loot"]
}
+9
View File
@@ -46,6 +46,15 @@ export default class PrismRPGRace extends foundry.abstract.TypeDataModel {
label: "Language" label: "Language"
}) })
schema.baseBurden = new fields.NumberField({
required: true,
nullable: false,
integer: true,
initial: 0,
min: 0,
label: "Base Burden"
})
// Racial Passive // Racial Passive
schema.racialPassive = new fields.StringField({ schema.racialPassive = new fields.StringField({
required: true, required: true,
+1
View File
@@ -63,6 +63,7 @@ export default class PrismRPGShield extends foundry.abstract.TypeDataModel {
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+1
View File
@@ -127,6 +127,7 @@ export default class PrismRPGWeapon extends foundry.abstract.TypeDataModel {
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY }) schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
schema.equipped = new fields.BooleanField({ required: true, initial: false }) schema.equipped = new fields.BooleanField({ required: true, initial: false })
schema.isImplement = new fields.BooleanField({ required: true, initial: false }) schema.isImplement = new fields.BooleanField({ required: true, initial: false })
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
return schema return schema
} }
+6
View File
@@ -62,6 +62,9 @@ Hooks.once("init", function () {
race: models.PrismRPGRace, race: models.PrismRPGRace,
class: models.PrismRPGClass, class: models.PrismRPGClass,
"character-path": models.PrismRPGCharacterPath, "character-path": models.PrismRPGCharacterPath,
container: models.PrismRPGContainer,
consumable: models.PrismRPGConsumable,
loot: models.PrismRPGLoot,
} }
// Register sheet application classes // Register sheet application classes
@@ -81,6 +84,9 @@ Hooks.once("init", function () {
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGRaceSheet, { types: ["race"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGRaceSheet, { types: ["race"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGClassSheet, { types: ["class"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGClassSheet, { types: ["class"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGCharacterPathSheet, { types: ["character-path"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGCharacterPathSheet, { types: ["character-path"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGContainerSheet, { types: ["container"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGConsumableSheet, { types: ["consumable"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGLootSheet, { types: ["loot"], makeDefault: true })
// Status Effects — Afflictions & Imbuements // Status Effects — Afflictions & Imbuements
CONFIG.statusEffects = [ CONFIG.statusEffects = [
+118 -7
View File
@@ -58,17 +58,21 @@
// Left Column - Portrait, Attributes, HP // Left Column - Portrait, Attributes, HP
.character-left-column { .character-left-column {
display: flex; display: grid;
flex-direction: row; grid-template-columns: 200px 1fr;
gap: 12px; grid-template-rows: auto auto;
align-items: flex-start; column-gap: 12px;
row-gap: 8px;
align-items: start;
min-width: 0;
.portrait-hp-column { .portrait-hp-column {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
width: 200px; width: 200px;
flex-shrink: 0; grid-column: 1;
grid-row: 1 / 3;
} }
.character-portrait { .character-portrait {
@@ -158,9 +162,9 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
flex: 1; grid-column: 2;
grid-row: 1;
min-width: 0; min-width: 0;
max-width: 280px;
.attribute-shield { .attribute-shield {
position: relative; position: relative;
@@ -484,3 +488,110 @@
} }
} }
} }
// Movement Rating + Burden section
.burden-mr-section {
display: flex;
flex-direction: row;
gap: 16px;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.35);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 4px;
grid-column: 2;
grid-row: 2;
.burden-mr-item {
display: flex;
flex-direction: column;
gap: 3px;
.burden-display-row {
display: flex;
align-items: center;
gap: 8px;
min-height: 22px;
}
.burden-edit-row {
display: flex;
align-items: center;
gap: 3px;
flex-wrap: wrap;
}
.burden-label {
font-weight: bold;
font-size: 11px;
letter-spacing: 0.05em;
min-width: 52px;
color: #fff;
cursor: default;
}
.burden-sub-attr {
// formField helper renders a .form-group with label stacked above select.
// Flatten it so the select sits inline in the flex row.
.form-group {
display: contents;
label { display: none; }
}
.form-fields {
display: contents;
}
select {
font-size: 11px;
padding: 1px 2px;
height: 22px;
max-width: 80px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
}
}
.burden-op {
font-size: 11px;
color: rgba(255, 255, 255, 0.9);
flex-shrink: 0;
}
.burden-other {
input[type="number"] {
width: 32px;
text-align: center;
font-size: 11px;
height: 22px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
}
}
.burden-total {
font-size: 18px;
font-weight: bold;
color: #ffe566;
min-width: 24px;
text-align: center;
}
.burden-used-max {
display: flex;
align-items: center;
gap: 2px;
font-size: 14px;
font-weight: bold;
.burden-used { color: #ffe566; }
.burden-separator { color: rgba(255, 255, 255, 0.8); }
.burden-max { color: #e0e0e0; }
&.burden-overloaded {
.burden-used { color: #ff5c5c; font-weight: bold; }
}
}
}
}
+173
View File
@@ -619,6 +619,150 @@
min-width: 12rem; min-width: 12rem;
} }
} }
.inv-section {
margin-bottom: 6px;
.inv-items {
display: flex;
flex-direction: column;
gap: 3px;
}
.inv-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(255,255,255,0.15);
&:hover { background: rgba(255,255,255,0.25); }
.item-img {
width: 24px;
height: 24px;
cursor: pointer;
flex-shrink: 0;
}
.inv-name {
flex: 1;
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.inv-enc, .inv-uses, .inv-capacity {
font-size: 11px;
color: #555;
min-width: 30px;
text-align: center;
white-space: nowrap;
}
.controls {
display: flex;
gap: 4px;
a { font-size: 12px; cursor: pointer; }
}
}
.inv-empty {
font-style: italic;
color: rgba(0,0,0,0.4);
text-align: center;
font-size: 11px;
padding: 4px;
}
// Container drag-drop highlight
.inv-container[data-container-id] {
border: 1px dashed transparent;
transition: border-color 0.15s, background 0.15s;
&.drag-over {
border-color: rgba(100, 150, 255, 0.7);
background: rgba(100, 150, 255, 0.12);
}
}
// Items nested inside a container
.inv-container-items {
margin: 2px 0 6px 28px;
display: flex;
flex-direction: column;
gap: 2px;
border-left: 2px solid rgba(0,0,0,0.15);
padding-left: 8px;
}
.inv-container-item {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 4px;
border-radius: 3px;
background: rgba(0,0,0,0.06);
&:hover { background: rgba(0,0,0,0.12); }
.item-img {
width: 20px;
height: 20px;
cursor: pointer;
flex-shrink: 0;
}
.inv-name {
flex: 1;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.inv-enc {
font-size: 10px;
color: #555;
min-width: 24px;
text-align: center;
}
.inv-container-type-badge {
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: rgba(0,0,0,0.45);
background: rgba(0,0,0,0.07);
border-radius: 3px;
padding: 1px 4px;
flex-shrink: 0;
}
.controls {
display: flex;
gap: 4px;
a { font-size: 11px; cursor: pointer; }
}
}
.inv-container-empty {
margin: 2px 0 4px 36px;
font-size: 10px;
font-style: italic;
color: rgba(0,0,0,0.35);
}
}
.pack-burden-fieldset {
.pack-burden-display {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
font-size: 13px;
.pack-burden-label {
font-weight: bold;
}
.pack-burden-value {
font-weight: bold;
.pack-burden-used { color: #e6a817; }
.pack-burden-sep { color: rgba(0,0,0,0.4); }
.pack-burden-max { color: rgba(0,0,0,0.7); }
}
}
.pack-burden-used { color: #e6a817; font-weight: bold; }
.pack-burden-sep { color: rgba(0,0,0,0.4); margin: 0 2px; }
.pack-burden-max { color: rgba(0,0,0,0.7); font-weight: bold; }
}
} }
.tab.character-combat .main-div { .tab.character-combat .main-div {
@@ -911,3 +1055,32 @@
min-height: 150px; min-height: 150px;
} }
} }
// Equipped item visual feedback
.inv-item {
&.is-equipped {
background: rgba(100, 180, 100, 0.12);
border-left: 2px solid rgba(80, 160, 80, 0.6);
}
.equipped-icon {
color: #5a9e6a;
}
.unequipped-icon {
color: rgba(0, 0, 0, 0.25);
}
}
// Burden overload warning
.burden-excess {
font-size: 0.75em;
color: #ff5c5c;
margin-left: 4px;
white-space: nowrap;
}
// Depleted consumable button
.controls a.disabled {
opacity: 0.35;
pointer-events: none;
cursor: default;
}
+9
View File
@@ -0,0 +1,9 @@
.consumable-content {
.item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
}
+20
View File
@@ -0,0 +1,20 @@
.container-content {
.sheet-common();
.item-sheet-common();
.header {
display: flex;
img {
width: 50px;
height: 50px;
}
}
.item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
}
+3
View File
@@ -20,6 +20,9 @@
@import "race.less"; @import "race.less";
@import "class.less"; @import "class.less";
@import "character-path.less"; @import "character-path.less";
@import "container.less";
@import "consumable.less";
@import "loot.less";
@import "effects.less"; @import "effects.less";
@import "weapon-types-config.less"; @import "weapon-types-config.less";
} }
+9
View File
@@ -53,6 +53,15 @@ i.prismrpg {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); font-size: calc(var(--font-size-standard) * 1);
background-image: var(--background-image-base); background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
.window-content {
background-image: var(--background-image-base);
background-size: 100% 100%;
background-repeat: no-repeat;
}
button:hover { button:hover {
background: var(--color-dark-6); background: var(--color-dark-6);
} }
+9
View File
@@ -0,0 +1,9 @@
.loot-content {
.item-img {
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid var(--color-border-light-tertiary);
border-radius: 4px;
}
}
+2 -2
View File
@@ -263,8 +263,8 @@
} }
} }
// Dialog application styling // Dialog application styling — only apply grey gradient when roll dialog content is present
.application.dialog.prismrpg { .application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) {
.window-content { .window-content {
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
padding: 8px; padding: 8px;
+7 -4
View File
@@ -6,7 +6,7 @@
"download": "#{DOWNLOAD}#", "download": "#{DOWNLOAD}#",
"url": "#{URL}#", "url": "#{URL}#",
"license": "LICENSE", "license": "LICENSE",
"version": "13.0.1", "version": "14.0.0",
"authors": [ "authors": [
{ {
"name": "Uberwald", "name": "Uberwald",
@@ -14,8 +14,8 @@
} }
], ],
"compatibility": { "compatibility": {
"minimum": "13", "minimum": "14",
"verified": "13" "verified": "14"
}, },
"esmodules": ["prism-rpg.mjs"], "esmodules": ["prism-rpg.mjs"],
"styles": ["css/fvtt-prism-rpg.css"], "styles": ["css/fvtt-prism-rpg.css"],
@@ -42,7 +42,10 @@
"equipment": { "htmlFields": ["description"] }, "equipment": { "htmlFields": ["description"] },
"race": { "htmlFields": ["description", "racialPassiveDescription", "subraceAbilityDescription", "notes"] }, "race": { "htmlFields": ["description", "racialPassiveDescription", "subraceAbilityDescription", "notes"] },
"class": { "htmlFields": ["description", "attributeBonuses", "notes", "features.level1", "features.level2", "features.level3", "features.level4", "features.level5", "features.level6", "features.level7", "features.level8", "features.level9", "features.level10"] }, "class": { "htmlFields": ["description", "attributeBonuses", "notes", "features.level1", "features.level2", "features.level3", "features.level4", "features.level5", "features.level6", "features.level7", "features.level8", "features.level9", "features.level10"] },
"character-path": { "htmlFields": ["description"] } "character-path": { "htmlFields": ["description"] },
"container": { "htmlFields": ["description", "notes"] },
"consumable": { "htmlFields": ["description", "notes"] },
"loot": { "htmlFields": ["description", "notes"] }
} }
}, },
"grid": { "grid": {
+200 -12
View File
@@ -1,6 +1,16 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}"> <section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div"> <div class="main-div">
{{! Pack Burden Summary }}
<fieldset class="pack-burden-fieldset">
<legend>{{localize "PRISMRPG.Label.packBurden"}}</legend>
<div class="pack-burden-display">
<span class="pack-burden-used">{{packBurdenUsed}}</span>
<span class="pack-burden-sep">/</span>
<span class="pack-burden-max">{{packBurdenMax}}</span>
</div>
</fieldset>
{{! Money }}
<fieldset> <fieldset>
<legend>{{localize "PRISMRPG.Label.money"}}</legend> <legend>{{localize "PRISMRPG.Label.money"}}</legend>
<div class="moneys"> <div class="moneys">
@@ -12,23 +22,201 @@
</div> </div>
</fieldset> </fieldset>
<fieldset> {{! Weapons }}
<legend>{{localize "PRISMRPG.Label.equipment"}}</legend> <fieldset class="inv-section">
<div class="equipments"> <legend>
{{#each equipments as |item|}} {{localize "PRISMRPG.Label.weapons"}}
<div class="equipment" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> <a data-action="createEquipment" data-item-type="weapon" data-tooltip="{{localize 'PRISMRPG.Tooltip.addWeapon'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each weapons as |item|}}
<div class="inv-item {{#if item.system.equipped}}is-equipped{{/if}}" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" /> <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="name" data-tooltip="{{{item.system.description}}}"> <div class="inv-name">{{item.name}}</div>
{{item.name}} <div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
</div>
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" <a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> <a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" {{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> </a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div> </div>
</div> </div>
{{/each}} {{/each}}
{{#unless weapons.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noWeapons"}}</p>{{/unless}}
</div>
</fieldset>
{{! Armor & Shields }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.armors"}}
<a data-action="createEquipment" data-item-type="armor" data-tooltip="{{localize 'PRISMRPG.Tooltip.addArmor'}}"><i class="fas fa-plus"></i></a>
<a data-action="createEquipment" data-item-type="shield" data-tooltip="{{localize 'PRISMRPG.Tooltip.addShield'}}"><i class="fas fa-shield-halved"></i></a>
</legend>
<div class="inv-items">
{{#each armors as |item|}}
<div class="inv-item {{#if item.system.equipped}}is-equipped{{/if}}" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{#unless armors.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noArmor"}}</p>{{/unless}}
</div>
</fieldset>
{{! Consumables }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.consumables"}}
<a data-action="createEquipment" data-item-type="consumable" data-tooltip="{{localize 'PRISMRPG.Tooltip.addConsumable'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each consumables as |item|}}
<div class="inv-item inv-consumable" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div>
<div class="inv-uses" data-tooltip="{{localize 'PRISMRPG.Tooltip.uses'}}">{{item.system.uses}}/{{item.system.usesMax}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.useConsumable'}}" data-action="useConsumable" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" {{#unless item.system.uses}}aria-disabled="true" class="disabled"{{/unless}}><i class="fas fa-flask"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{#unless consumables.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noConsumables"}}</p>{{/unless}}
</div>
</fieldset>
{{! Kits }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.kits"}}
<a data-action="createEquipment" data-item-type="equipment" data-item-kit="true" data-tooltip="{{localize 'PRISMRPG.Tooltip.addKit'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each kits as |item|}}
<div class="inv-item {{#if item.system.equipped}}is-equipped{{/if}}" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{#unless kits.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noKits"}}</p>{{/unless}}
</div>
</fieldset>
{{! General Equipment (non-kit) }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.equipment"}}
<a data-action="createEquipment" data-item-type="equipment" data-tooltip="{{localize 'PRISMRPG.Tooltip.addEquipment'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each equipmentItems as |item|}}
<div class="inv-item {{#if item.system.equipped}}is-equipped{{/if}}" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name" data-tooltip="{{{item.system.description}}}">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.system.equipped}}<i class="fas fa-shield-check equipped-icon"></i>{{else}}<i class="far fa-circle unequipped-icon"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{#unless equipmentItems.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noEquipment"}}</p>{{/unless}}
</div>
</fieldset>
{{! Loot }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.loot"}}
<a data-action="createEquipment" data-item-type="loot" data-tooltip="{{localize 'PRISMRPG.Tooltip.addLoot'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each loots as |item|}}
<div class="inv-item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.assignToContainer'}}" data-action="assignToContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-bag-shopping"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{#unless loots.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noLoot"}}</p>{{/unless}}
</div>
</fieldset>
{{! Containers }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.containers"}}
<a data-action="createEquipment" data-item-type="container" data-tooltip="{{localize 'PRISMRPG.Tooltip.addContainer'}}"><i class="fas fa-plus"></i></a>
</legend>
<div class="inv-items">
{{#each containerGroups as |group|}}
<div class="inv-item inv-container" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}" data-container-id="{{group.container.id}}">
<img class="item-img" src="{{group.container.img}}" data-tooltip="{{group.container.name}}" data-action="postItemToChat" />
<div class="inv-name">{{group.container.name}}</div>
<div class="inv-capacity" data-tooltip="{{localize 'PRISMRPG.Tooltip.packBurden'}}">{{group.container.system.packBurden}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{group.container.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleContainerEquipped" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}">
{{#if group.container.system.equipped}}<i class="fas fa-backpack"></i>{{else}}<i class="fas fa-box"></i>{{/if}}
</a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{group.container.id}}" data-item-uuid="{{group.container.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{#if group.items.length}}
<div class="inv-container-items">
{{#each group.items as |item|}}
<div class="inv-item inv-container-item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<span class="inv-container-type-badge">{{item.type}}</span>
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" data-action="postItemToChat" />
<div class="inv-name">{{item.name}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.removeFromContainer'}}" data-action="removeFromContainer" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-arrow-up-from-bracket"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'PRISMRPG.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{else}}
<div class="inv-container-empty">{{localize "PRISMRPG.Message.noStoredItems"}}</div>
{{/if}}
{{/each}}
{{#unless containerGroups.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noContainers"}}</p>{{/unless}}
</div> </div>
</fieldset> </fieldset>
+57
View File
@@ -293,6 +293,63 @@
</div> </div>
</div> </div>
</div> </div>
{{! Movement Rating + Burden Section - below attributes }}
<div class="burden-mr-section">
<div class="burden-mr-item">
<div class="burden-display-row">
<div class="burden-label" data-tooltip="{{localize 'PRISMRPG.Tooltip.movementRating'}}">MR</div>
<div class="burden-total">{{movementRatingValue}}</div>
</div>
{{#if isEditMode}}
<div class="burden-edit-row">
<div class="burden-sub-attr">
{{formField
systemFields.movementRating.fields.subAttribute
value=system.movementRating.subAttribute
localize=true
}}
</div>
<span class="burden-op">+</span>
<div class="burden-other">
{{formInput systemFields.movementRating.fields.other value=system.movementRating.other}}
</div>
<span class="burden-op">-</span>
<div class="burden-other">
{{formInput systemFields.movementRating.fields.reduction value=system.movementRating.reduction}}
</div>
</div>
{{/if}}
</div>
<div class="burden-mr-item">
<div class="burden-display-row">
<div class="burden-label" data-tooltip="{{localize 'PRISMRPG.Tooltip.burdenCharacter'}}">BURDEN</div>
<div class="burden-used-max {{#if excessBurden}}burden-overloaded{{/if}}">
<span class="burden-used">{{burdenUsed}}</span>
<span class="burden-separator">/</span>
<span class="burden-max">{{burdenMax}}</span>
{{#if excessBurden}}
<span class="burden-excess" data-tooltip="{{localize 'PRISMRPG.Tooltip.excessBurden'}}">(-{{excessBurden}} MR)</span>
{{/if}}
</div>
</div>
{{#if isEditMode}}
<div class="burden-edit-row">
<div class="burden-sub-attr">
{{formField
systemFields.burden.fields.subAttribute
value=system.burden.subAttribute
localize=true
}}
</div>
<span class="burden-op">+</span>
<div class="burden-other">
{{formInput systemFields.burden.fields.other value=system.burden.other}}
</div>
</div>
{{/if}}
</div>
</div>
</div> </div>
{{! Right Column - Race, Classes }} {{! Right Column - Race, Classes }}
+2
View File
@@ -42,6 +42,7 @@
<fieldset> <fieldset>
<legend data-tooltip="{{localize 'PRISMRPG.Tooltip.racialAbilities'}}" data-tooltip-direction="UP"> <legend data-tooltip="{{localize 'PRISMRPG.Tooltip.racialAbilities'}}" data-tooltip-direction="UP">
{{localize "PRISMRPG.Label.racialAbilities"}} {{localize "PRISMRPG.Label.racialAbilities"}}
<a data-action="createEquipment" data-item-type="racial-ability" data-tooltip="{{localize 'PRISMRPG.Tooltip.addRacialAbility'}}"><i class="fas fa-plus"></i></a>
</legend> </legend>
<div class="racial-abilities"> <div class="racial-abilities">
{{#each racialAbilities as |item|}} {{#each racialAbilities as |item|}}
@@ -64,6 +65,7 @@
<fieldset> <fieldset>
<legend data-tooltip="{{localize 'PRISMRPG.Tooltip.abilities'}}" data-tooltip-direction="UP"> <legend data-tooltip="{{localize 'PRISMRPG.Tooltip.abilities'}}" data-tooltip-direction="UP">
{{localize "PRISMRPG.Label.abilities"}} {{localize "PRISMRPG.Label.abilities"}}
<a data-action="createEquipment" data-item-type="ability" data-tooltip="{{localize 'PRISMRPG.Tooltip.addAbility'}}"><i class="fas fa-plus"></i></a>
</legend> </legend>
<div class="racial-abilities"> <div class="racial-abilities">
{{#each abilities as |item|}} {{#each abilities as |item|}}
+40
View File
@@ -0,0 +1,40 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item {{tabs.details.cssClass}}" data-tab="details">{{localize "PRISMRPG.Label.details"}}</a>
<a class="item {{tabs.description.cssClass}}" data-tab="description">{{localize "PRISMRPG.Label.description"}}</a>
<a class="item {{tabs.effects.cssClass}}" data-tab="effects">{{localize "PRISMRPG.Label.effects"}}</a>
</nav>
{{! Details Tab }}
<div class="tab {{tabs.details.cssClass}}" data-group="primary" data-tab="details">
<fieldset>
<legend>{{localize "PRISMRPG.Label.consumable"}}</legend>
{{formField systemFields.usesMax value=system.usesMax localize=true}}
{{formField systemFields.uses value=system.uses localize=true}}
{{formField systemFields.encLoad value=system.encLoad localize=true}}
{{formField systemFields.cost value=system.cost localize=true}}
</fieldset>
</div>
{{! Description Tab }}
<div class="tab {{tabs.description.cssClass}}" data-group="primary" data-tab="description">
<fieldset>
<legend>{{localize "PRISMRPG.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "PRISMRPG.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</div>
{{! Effects Tab }}
<div class="tab {{tabs.effects.cssClass}}" data-group="primary" data-tab="effects">
{{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}}
</div>
</section>
+58
View File
@@ -0,0 +1,58 @@
<section>
<div class="header">
<img
class="item-img"
src="{{item.img}}"
data-edit="img"
data-action="editImage"
data-tooltip="{{item.name}}"
/>
{{formInput fields.name value=source.name}}
</div>
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item {{tabs.details.cssClass}}" data-tab="details">{{localize "PRISMRPG.Label.details"}}</a>
<a class="item {{tabs.description.cssClass}}" data-tab="description">{{localize "PRISMRPG.Label.description"}}</a>
<a class="item {{tabs.effects.cssClass}}" data-tab="effects">{{localize "PRISMRPG.Label.effects"}}</a>
</nav>
{{! Details Tab }}
<div class="tab {{tabs.details.cssClass}}" data-group="primary" data-tab="details">
<fieldset>
<legend>{{localize "PRISMRPG.Label.container"}}</legend>
{{formField systemFields.packBurden value=system.packBurden localize=true}}
{{formField systemFields.encLoad value=system.encLoad localize=true}}
{{formField systemFields.cost value=system.cost localize=true}}
</fieldset>
</div>
{{! Description Tab }}
<div class="tab {{tabs.description.cssClass}}" data-group="primary" data-tab="description">
<fieldset>
<legend>{{localize "PRISMRPG.Label.description"}}</legend>
{{formInput
systemFields.description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled=true
}}
</fieldset>
<fieldset>
<legend>{{localize "PRISMRPG.Label.notes"}}</legend>
{{formInput
systemFields.notes
enriched=enrichedNotes
value=system.notes
name="system.notes"
toggled=true
}}
</fieldset>
</div>
{{! Effects Tab }}
<div class="tab {{tabs.effects.cssClass}}" data-group="primary" data-tab="effects">
{{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}}
</div>
</section>
+38
View File
@@ -0,0 +1,38 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item {{tabs.details.cssClass}}" data-tab="details">{{localize "PRISMRPG.Label.details"}}</a>
<a class="item {{tabs.description.cssClass}}" data-tab="description">{{localize "PRISMRPG.Label.description"}}</a>
<a class="item {{tabs.effects.cssClass}}" data-tab="effects">{{localize "PRISMRPG.Label.effects"}}</a>
</nav>
{{! Details Tab }}
<div class="tab {{tabs.details.cssClass}}" data-group="primary" data-tab="details">
<fieldset>
<legend>{{localize "PRISMRPG.Label.loot"}}</legend>
{{formField systemFields.encLoad value=system.encLoad localize=true}}
{{formField systemFields.cost value=system.cost localize=true}}
</fieldset>
</div>
{{! Description Tab }}
<div class="tab {{tabs.description.cssClass}}" data-group="primary" data-tab="description">
<fieldset>
<legend>{{localize "PRISMRPG.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "PRISMRPG.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</div>
{{! Effects Tab }}
<div class="tab {{tabs.effects.cssClass}}" data-group="primary" data-tab="effects">
{{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}}
</div>
</section>
+2
View File
@@ -43,6 +43,8 @@
{{formField systemFields.language value=system.language}} {{formField systemFields.language value=system.language}}
{{formField systemFields.baseBurden value=system.baseBurden}}
</div> </div>
<div class="align-top"> <div class="align-top">