Implements inventory system, wip

This commit is contained in:
2026-05-19 22:23:31 +02:00
parent 68e3d35af1
commit 4ff46865c2
29 changed files with 1317 additions and 35 deletions
+240 -7
View File
@@ -681,6 +681,96 @@ i.prismrpg {
.prismrpg .tab.character-equipment .main-div .equipments .name {
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 .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 {
background-image: url("../assets/ui/prism_rpg_background.webp");
background-size: cover;
@@ -951,6 +1041,27 @@ i.prismrpg {
.prismrpg .tab.character-miracles .main-div prose-mirror.active {
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 {
font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1);
@@ -1052,17 +1163,21 @@ i.prismrpg {
align-items: start;
}
.prismrpg .character-main-v2 .character-left-column {
display: flex;
flex-direction: row;
gap: 12px;
align-items: flex-start;
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto auto;
column-gap: 12px;
row-gap: 8px;
align-items: start;
min-width: 0;
}
.prismrpg .character-main-v2 .character-left-column .portrait-hp-column {
display: flex;
flex-direction: column;
gap: 12px;
width: 200px;
flex-shrink: 0;
grid-column: 1;
grid-row: 1 / 3;
}
.prismrpg .character-main-v2 .character-left-column .character-portrait {
width: 200px;
@@ -1134,9 +1249,9 @@ i.prismrpg {
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
grid-column: 2;
grid-row: 1;
min-width: 0;
max-width: 280px;
}
.prismrpg .character-main-v2 .character-left-column .character-attributes .attribute-shield {
position: relative;
@@ -1408,6 +1523,103 @@ i.prismrpg {
line-height: 1.6;
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 {
padding: 1rem;
}
@@ -3563,6 +3775,27 @@ i.prismrpg {
.prismrpg .character-path-content input[type="checkbox"]:checked::after {
color: rgba(0, 0, 0, 0.1);
}
.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 {
padding: 0.5rem;
}
+122 -3
View File
@@ -244,6 +244,17 @@
},
"wis": {
"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": {
"label": "Money unit"
},
"equipped": {
"label": "Equipped"
},
"isKit": {
"label": "Is Kit?"
},
@@ -523,6 +537,17 @@
"Challenges": "Challenges",
"HP": "HP",
"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",
"Saves": "Saves",
"app": "APP",
@@ -898,13 +923,41 @@
"skill": "Skills list",
"skills": "Skills - Your character's skills and abilities",
"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"
},
"RollSavingThrow": "Roll Saving Throw",
"Dialog": {
"useConsumable": "Use Consumable",
"useConsumableContent": "Use one charge of <strong>{name}</strong>? ({uses} remaining)"
},
"Message": {
"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",
"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"
},
"Miracle": {
"FIELDS": {
@@ -1381,6 +1434,69 @@
"subraceAbilityDescription": {
"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": {
"label": "Notes"
}
@@ -1507,7 +1623,10 @@
"weapon": "Weapon",
"race": "Race",
"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 PrismRPGClassSheet } from "./sheets/class-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"
+95 -3
View File
@@ -29,6 +29,9 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
hpTempPlus: PrismRPGCharacterSheet.#onHpTempPlus,
hpTempMinus: PrismRPGCharacterSheet.#onHpTempMinus,
postItemToChat: PrismRPGCharacterSheet.#onPostItemToChat,
useConsumable: PrismRPGCharacterSheet.#onUseConsumable,
toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped,
toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped,
},
}
@@ -109,13 +112,39 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
classes[1] || 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
case "skills":
context.tab = context.tabs.skills
context.skills = doc.itemTypes.skill
context.racialAbilities = doc.itemTypes["racial-ability"]
context.abilities = doc.itemTypes["ability"]
context.vulnerabilities = doc.itemTypes.vulnerability
context.abilities = doc.itemTypes.ability
context.vulnerabilities = doc.itemTypes.vulnerability ?? []
break
case "subattributes":
context.tab = context.tabs.subattributes
@@ -133,7 +162,25 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
break
case "equipment":
context.tab = context.tabs.equipment
context.equipments = doc.itemTypes.equipment
context.weapons = doc.itemTypes.weapon
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield]
context.consumables = doc.itemTypes.consumable
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit)
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit)
context.loots = doc.itemTypes.loot
context.containers = doc.itemTypes.container
context.packBurdenMax = doc.itemTypes.container
.filter(c => c.system.equipped)
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
context.packBurdenUsed = [
...doc.itemTypes.equipment,
...doc.itemTypes.consumable,
...doc.itemTypes.loot,
...doc.itemTypes.container,
...doc.itemTypes.weapon,
...doc.itemTypes.armor,
...doc.itemTypes.shield,
].reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
break
case "biography":
context.tab = context.tabs.biography
@@ -237,6 +284,51 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
}
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 #onPostItemToChat(event, target) {
@@ -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
}
}
+3
View File
@@ -11,3 +11,6 @@ export { default as PrismRPGEquipment } from "./equipment.mjs"
export { default as PrismRPGRace } from "./race.mjs"
export { default as PrismRPGClass } from "./class.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"
+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
}
+19
View File
@@ -0,0 +1,19 @@
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 })
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"]
}
+1
View File
@@ -12,6 +12,7 @@ export default class PrismRPGEquipment extends foundry.abstract.TypeDataModel {
schema.encLoad = new fields.NumberField({ 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.equipped = new fields.BooleanField({ required: true, initial: false })
// Kit properties
schema.isKit = new fields.BooleanField({
+17
View File
@@ -0,0 +1,17 @@
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 })
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"
})
schema.baseBurden = new fields.NumberField({
required: true,
nullable: false,
integer: true,
initial: 0,
min: 0,
label: "Base Burden"
})
// Racial Passive
schema.racialPassive = new fields.StringField({
required: true,
+6
View File
@@ -62,6 +62,9 @@ Hooks.once("init", function () {
race: models.PrismRPGRace,
class: models.PrismRPGClass,
"character-path": models.PrismRPGCharacterPath,
container: models.PrismRPGContainer,
consumable: models.PrismRPGConsumable,
loot: models.PrismRPGLoot,
}
// 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.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.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
CONFIG.statusEffects = [
+118 -7
View File
@@ -58,17 +58,21 @@
// Left Column - Portrait, Attributes, HP
.character-left-column {
display: flex;
flex-direction: row;
gap: 12px;
align-items: flex-start;
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto auto;
column-gap: 12px;
row-gap: 8px;
align-items: start;
min-width: 0;
.portrait-hp-column {
display: flex;
flex-direction: column;
gap: 12px;
width: 200px;
flex-shrink: 0;
grid-column: 1;
grid-row: 1 / 3;
}
.character-portrait {
@@ -158,9 +162,9 @@
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
grid-column: 2;
grid-row: 1;
min-width: 0;
max-width: 280px;
.attribute-shield {
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; }
}
}
}
}
+102
View File
@@ -619,6 +619,79 @@
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;
}
}
.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 {
@@ -911,3 +984,32 @@
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;
}
}
+9
View File
@@ -0,0 +1,9 @@
.container-content {
.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 "class.less";
@import "character-path.less";
@import "container.less";
@import "consumable.less";
@import "loot.less";
@import "effects.less";
@import "weapon-types-config.less";
}
+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;
}
}
+4 -1
View File
@@ -42,7 +42,10 @@
"equipment": { "htmlFields": ["description"] },
"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"] },
"character-path": { "htmlFields": ["description"] }
"character-path": { "htmlFields": ["description"] },
"container": { "htmlFields": ["description", "notes"] },
"consumable": { "htmlFields": ["description", "notes"] },
"loot": { "htmlFields": ["description", "notes"] }
}
},
"grid": {
+175 -12
View File
@@ -1,6 +1,16 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<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>
<legend>{{localize "PRISMRPG.Label.money"}}</legend>
<div class="moneys">
@@ -12,23 +22,176 @@
</div>
</fieldset>
<fieldset>
<legend>{{localize "PRISMRPG.Label.equipment"}}</legend>
<div class="equipments">
{{#each equipments as |item|}}
<div class="equipment" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{! Weapons }}
<fieldset class="inv-section">
<legend>
{{localize "PRISMRPG.Label.weapons"}}
<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" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<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.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>
<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 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.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.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.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.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.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 containers as |item|}}
<div class="inv-item inv-container" 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-capacity" data-tooltip="{{localize 'PRISMRPG.Tooltip.packBurden'}}">{{item.system.packBurden}}</div>
<div class="inv-enc" data-tooltip="{{localize 'PRISMRPG.Label.encLoad'}}">{{item.system.encLoad}}</div>
<div class="controls">
<a data-tooltip="{{localize 'PRISMRPG.Tooltip.toggleEquipped'}}" data-action="toggleContainerEquipped" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
{{#if item.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="{{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 containers.length}}<p class="inv-empty">{{localize "PRISMRPG.Message.noContainers"}}</p>{{/unless}}
</div>
</fieldset>
+57
View File
@@ -293,6 +293,63 @@
</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>
{{! Right Column - Race, Classes }}
+2
View File
@@ -42,6 +42,7 @@
<fieldset>
<legend data-tooltip="{{localize 'PRISMRPG.Tooltip.racialAbilities'}}" data-tooltip-direction="UP">
{{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>
<div class="racial-abilities">
{{#each racialAbilities as |item|}}
@@ -64,6 +65,7 @@
<fieldset>
<legend data-tooltip="{{localize 'PRISMRPG.Tooltip.abilities'}}" data-tooltip-direction="UP">
{{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>
<div class="racial-abilities">
{{#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.baseBurden value=system.baseBurden}}
</div>
<div class="align-top">