Actor sheet, WIP

This commit is contained in:
2026-03-07 22:47:29 +01:00
parent c6f7a9e966
commit 8f7f0169e4
27 changed files with 835 additions and 381 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

BIN
assets/icons/icon_oath.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

View File

@@ -11,8 +11,8 @@
--oh-font-secondary: "BlueDragon", "Palatino Linotype", serif; --oh-font-secondary: "BlueDragon", "Palatino Linotype", serif;
--oh-font-body: "Calibri", "Segoe UI", sans-serif; --oh-font-body: "Calibri", "Segoe UI", sans-serif;
--oh-font-size: 0.82rem; --oh-font-size: 0.82rem;
--oh-color-blue: #1a4a7a; --oh-color-blue: #084a74;
--oh-color-olive: #5a5a2a; --oh-color-olive: #535128;
--oh-color-gold: #c8a84b; --oh-color-gold: #c8a84b;
--oh-color-dark: #2a1a0a; --oh-color-dark: #2a1a0a;
--oh-color-paper: #f5ead0; --oh-color-paper: #f5ead0;
@@ -20,7 +20,7 @@
--oh-logo: url("../assets/logos/official_logo_01.webp"); --oh-logo: url("../assets/logos/official_logo_01.webp");
} }
.application.dialog.oathhammer { .application.dialog.oathhammer {
font-family: "Sherwood", "Palatino Linotype", serif; font-family: "Calibri", "Segoe UI", sans-serif;
font-size: 0.82rem; font-size: 0.82rem;
background-image: var(--oh-background-image); background-image: var(--oh-background-image);
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -28,21 +28,22 @@
} }
.oathhammer .character-content, .oathhammer .character-content,
.oathhammer .npc-content { .oathhammer .npc-content {
font-family: "Sherwood", "Palatino Linotype", serif; font-family: "Calibri", "Segoe UI", sans-serif;
font-size: 0.82rem; font-size: 0.82rem;
color: var(--color-dark-1); color: var(--color-dark-1);
background-image: var(--oh-background-image); background-image: var(--oh-background-image);
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
overflow: auto; overflow: auto;
padding: 10px 20px;
} }
.oathhammer .character-content nav.tabs [data-tab], .oathhammer .character-content nav.tabs [data-tab],
.oathhammer .npc-content nav.tabs [data-tab] { .oathhammer .npc-content nav.tabs [data-tab] {
color: #5a5a2a; color: #535128;
} }
.oathhammer .character-content nav.tabs [data-tab].active, .oathhammer .character-content nav.tabs [data-tab].active,
.oathhammer .npc-content nav.tabs [data-tab].active { .oathhammer .npc-content nav.tabs [data-tab].active {
color: #1a4a7a; color: #084a74;
} }
.oathhammer .character-content input:disabled, .oathhammer .character-content input:disabled,
.oathhammer .npc-content input:disabled, .oathhammer .npc-content input:disabled,
@@ -58,24 +59,24 @@
.oathhammer .npc-content select { .oathhammer .npc-content select {
height: 1.5rem; height: 1.5rem;
background-color: rgba(255, 255, 255, 0.3); background-color: rgba(255, 255, 255, 0.3);
border-color: #1a4a7a; border-color: #084a74;
color: #2a1a0a; color: #2a1a0a;
} }
.oathhammer .character-content input[name="name"], .oathhammer .character-content input[name="name"],
.oathhammer .npc-content input[name="name"] { .oathhammer .npc-content input[name="name"] {
height: 2.5rem; height: 2.5rem;
font-family: "BlueDragon", "Palatino Linotype", serif; font-family: "Sherwood", "Palatino Linotype", serif;
font-size: calc(0.82rem * 1.2); font-size: calc(0.82rem * 1.2);
font-weight: bold; font-weight: bold;
border: none; border: none;
border-bottom: 2px solid #1a4a7a; border-bottom: 2px solid #084a74;
background: transparent; background: transparent;
} }
.oathhammer .character-content fieldset, .oathhammer .character-content fieldset,
.oathhammer .npc-content fieldset { .oathhammer .npc-content fieldset {
margin-bottom: 4px; margin-bottom: 4px;
border-radius: 4px; border-radius: 4px;
border-color: #5a5a2a; border-color: #535128;
} }
.oathhammer .character-content legend, .oathhammer .character-content legend,
.oathhammer .npc-content legend { .oathhammer .npc-content legend {
@@ -83,7 +84,7 @@
font-size: calc(0.82rem * 1.1); font-size: calc(0.82rem * 1.1);
font-weight: bold; font-weight: bold;
letter-spacing: 1px; letter-spacing: 1px;
color: #1a4a7a; color: #084a74;
} }
.oathhammer .character-content label, .oathhammer .character-content label,
.oathhammer .npc-content label { .oathhammer .npc-content label {
@@ -94,10 +95,53 @@
.oathhammer .tab { .oathhammer .tab {
padding: 4px; padding: 4px;
} }
.oathhammer .skills-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.oathhammer .skills-container .skills-group {
margin: 0;
}
.oathhammer .skills-container .skills-group legend .attr-rank {
font-family: "Calibri", "Segoe UI", sans-serif;
font-size: calc(0.82rem * 0.85);
color: #535128;
}
.oathhammer .skills-container .skills-header,
.oathhammer .skills-container .skill-row {
display: grid;
grid-template-columns: 1fr 3rem 3rem;
align-items: center;
gap: 4px;
}
.oathhammer .skills-container .skills-header {
font-family: "BlueDragon", "Palatino Linotype", serif;
font-size: calc(0.82rem * 0.85);
font-weight: bold;
color: #084a74;
border-bottom: 1px solid #535128;
margin-bottom: 2px;
padding-bottom: 2px;
}
.oathhammer .skills-container .skill-row {
margin-bottom: 2px;
}
.oathhammer .skills-container .skill-row label.skill-name-col {
font-size: calc(0.82rem * 0.85);
}
.oathhammer .skills-container .skill-row .skill-rank-col input {
text-align: center;
}
.oathhammer .skills-container .skill-row .skill-total {
text-align: center;
font-weight: bold;
color: #084a74;
}
.oathhammer .actor-img { .oathhammer .actor-img {
height: 150px; height: 150px;
width: auto; width: auto;
border: 2px solid #1a4a7a; border: 2px solid #084a74;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
-o-object-fit: cover; -o-object-fit: cover;
@@ -128,9 +172,13 @@
.oathhammer .character-main .character-resource { .oathhammer .character-main .character-resource {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: nowrap;
gap: 4px; gap: 4px;
margin-bottom: 2px; margin-bottom: 2px;
} }
.oathhammer .character-main .character-resource div.form-group {
display: contents;
}
.oathhammer .character-main .character-resource input { .oathhammer .character-main .character-resource input {
min-width: 2.5rem; min-width: 2.5rem;
max-width: 2.5rem; max-width: 2.5rem;
@@ -226,15 +274,15 @@
align-items: center; align-items: center;
gap: 6px; gap: 6px;
padding: 3px 4px; padding: 3px 4px;
border-bottom: 1px solid rgba(90, 90, 42, 0.2); border-bottom: 1px solid rgba(83, 81, 40, 0.2);
} }
.oathhammer .item-entry:hover { .oathhammer .item-entry:hover {
background-color: rgba(26, 74, 122, 0.08); background-color: rgba(8, 74, 116, 0.08);
} }
.oathhammer .item-entry .item-img { .oathhammer .item-entry .item-img {
height: 24px; height: 24px;
width: 24px; width: 24px;
border: 1px solid #5a5a2a; border: 1px solid #535128;
border-radius: 2px; border-radius: 2px;
-o-object-fit: cover; -o-object-fit: cover;
object-fit: cover; object-fit: cover;
@@ -246,13 +294,13 @@
} }
.oathhammer .item-entry .item-detail { .oathhammer .item-entry .item-detail {
font-size: calc(0.82rem * 0.9); font-size: calc(0.82rem * 0.9);
color: #5a5a2a; color: #535128;
min-width: 4rem; min-width: 4rem;
text-align: center; text-align: center;
} }
.oathhammer .item-entry .item-type { .oathhammer .item-entry .item-type {
font-size: calc(0.82rem * 0.85); font-size: calc(0.82rem * 0.85);
color: #1a4a7a; color: #084a74;
min-width: 6rem; min-width: 6rem;
} }
.oathhammer .item-entry a { .oathhammer .item-entry a {
@@ -263,7 +311,7 @@
opacity: 1; opacity: 1;
} }
.oathhammer .item-entry a:hover { .oathhammer .item-entry a:hover {
color: #1a4a7a; color: #084a74;
} }
.oathhammer .no-items { .oathhammer .no-items {
color: var(--color-dark-5); color: var(--color-dark-5);
@@ -273,7 +321,7 @@
} }
.oathhammer .create-btn { .oathhammer .create-btn {
margin-left: 6px; margin-left: 6px;
color: #1a4a7a; color: #084a74;
opacity: 0.6; opacity: 0.6;
transition: opacity 0.2s; transition: opacity 0.2s;
} }
@@ -282,7 +330,8 @@
} }
.oathhammer .item-sheet-common { .oathhammer .item-sheet-common {
overflow: auto; overflow: auto;
font-family: "Sherwood", "Palatino Linotype", serif; padding: 10px 20px;
font-family: "Calibri", "Segoe UI", sans-serif;
font-size: 0.82rem; font-size: 0.82rem;
background-image: var(--oh-background-image); background-image: var(--oh-background-image);
background-repeat: no-repeat; background-repeat: no-repeat;
@@ -294,53 +343,86 @@
gap: 8px; gap: 8px;
margin-bottom: 8px; margin-bottom: 8px;
padding-bottom: 4px; padding-bottom: 4px;
border-bottom: 2px solid #1a4a7a; border-bottom: 2px solid #084a74;
}
.oathhammer .item-sheet-common .header input[name="name"] {
font-family: "Sherwood", "Palatino Linotype", serif;
} }
.oathhammer .item-sheet-common .item-img { .oathhammer .item-sheet-common .item-img {
height: 52px; height: 52px;
width: 52px; width: 52px;
border: 2px solid #5a5a2a; border: 2px solid #535128;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
-o-object-fit: cover; -o-object-fit: cover;
object-fit: cover; object-fit: cover;
} }
.oathhammer .item-sheet-common .form-group { .oathhammer .item-sheet-common input:not([type="checkbox"]),
display: flex; .oathhammer .item-sheet-common select {
flex: 1; height: 1.5rem;
flex-direction: row; background-color: rgba(255, 255, 255, 0.3);
align-items: center; border-color: #084a74;
gap: 4px; color: #2a1a0a;
margin-bottom: 2px;
} }
.oathhammer .item-sheet-common .form-group label { .oathhammer .item-sheet-common input[type="checkbox"] {
width: auto;
height: auto;
background-color: transparent;
border-color: #084a74;
}
.oathhammer .item-sheet-common input[name="name"] {
height: 2.5rem;
font-family: "Sherwood", "Palatino Linotype", serif;
font-size: calc(0.82rem * 1.2);
font-weight: bold;
border: none;
border-bottom: 2px solid #084a74;
background: transparent;
}
.oathhammer .item-sheet-common label {
font-family: "BlueDragon", "Palatino Linotype", serif; font-family: "BlueDragon", "Palatino Linotype", serif;
font-size: 0.82rem; font-size: 0.82rem;
min-width: 9rem; color: #2a1a0a;
max-width: 9rem;
} }
.oathhammer .item-sheet-common .form-group select, .oathhammer .item-sheet-common .form-group {
.oathhammer .item-sheet-common .form-group input { display: flex;
text-align: left; flex-direction: row;
min-width: 10rem; align-items: center;
max-width: 12rem; gap: 6px;
margin-bottom: 4px;
}
.oathhammer .item-sheet-common .form-group > label {
flex: 0 0 8rem;
font-family: "BlueDragon", "Palatino Linotype", serif;
font-size: 0.82rem;
color: #2a1a0a;
}
.oathhammer .item-sheet-common .form-group .form-fields {
flex: 1;
min-width: 0;
}
.oathhammer .item-sheet-common .form-group .form-fields input:not([type="checkbox"]),
.oathhammer .item-sheet-common .form-group .form-fields select {
width: 100%;
box-sizing: border-box;
} }
.oathhammer .item-sheet-common .align-top { .oathhammer .item-sheet-common .align-top {
flex: 1;
min-width: 0;
align-self: flex-start; align-self: flex-start;
padding: 0.2rem; padding: 0 0.3rem;
min-width: 260px;
} }
.oathhammer .item-sheet-common .shift-right { .oathhammer .item-sheet-common .shift-right {
margin-left: 2rem; margin-left: 2rem;
} }
.oathhammer .item-sheet-common fieldset { .oathhammer .item-sheet-common fieldset {
margin-top: 6px; margin-top: 6px;
border-color: #5a5a2a; border-color: #535128;
border-radius: 4px; border-radius: 4px;
} }
.oathhammer .item-sheet-common legend { .oathhammer .item-sheet-common legend {
font-family: "BlueDragon", "Palatino Linotype", serif; font-family: "BlueDragon", "Palatino Linotype", serif;
font-size: calc(0.82rem * 1.1); font-size: calc(0.82rem * 1.1);
font-weight: bold; font-weight: bold;
color: #1a4a7a; color: #084a74;
} }

View File

@@ -16,6 +16,7 @@
}, },
"Tab": { "Tab": {
"Identity": "Identity", "Identity": "Identity",
"Skills": "Skills",
"Combat": "Combat", "Combat": "Combat",
"Magic": "Magic", "Magic": "Magic",
"Equipment": "Equipment", "Equipment": "Equipment",
@@ -29,6 +30,34 @@
"Intelligence": "Intelligence", "Intelligence": "Intelligence",
"Fate": "Fate" "Fate": "Fate"
}, },
"Skill": {
"Academics": "Academics",
"Acrobatics": "Acrobatics",
"AnimalHandling": "Animal Handling",
"Athletics": "Athletics",
"Brewing": "Brewing",
"Carpentry": "Carpentry",
"Defense": "Defense",
"Dexterity": "Dexterity",
"Diplomacy": "Diplomacy",
"Discipline": "Discipline",
"Fighting": "Fighting",
"Folklore": "Folklore",
"Fortune": "Fortune",
"Heal": "Heal",
"Leadership": "Leadership",
"Magic": "Magic",
"Masonry": "Masonry",
"Orientation": "Orientation",
"Perception": "Perception",
"Resilience": "Resilience",
"Ride": "Ride",
"Shooting": "Shooting",
"Smithing": "Smithing",
"Stealth": "Stealth",
"Survival": "Survival",
"Tracking": "Tracking"
},
"Lineage": { "Lineage": {
"Dwarf": "Dwarf", "Dwarf": "Dwarf",
"Firbolg": "Firbolg", "Firbolg": "Firbolg",
@@ -180,7 +209,10 @@
"Enchantment": "Enchantment", "Enchantment": "Enchantment",
"Tenet": "Tenet", "Tenet": "Tenet",
"Boon": "Boon", "Boon": "Boon",
"Bane": "Bane" "Bane": "Bane",
"Skill": "Skill",
"SkillRank": "Rank",
"TotalDice": "Total Dice"
}, },
"NewItem": { "NewItem": {
"Weapon": "New Weapon", "Weapon": "New Weapon",
@@ -190,6 +222,7 @@
}, },
"ToggleSheet": "Toggle Edit/Play Mode", "ToggleSheet": "Toggle Edit/Play Mode",
"Character": { "Character": {
"FIELDS": {
"attributes": { "attributes": {
"label": "Attributes" "label": "Attributes"
}, },
@@ -197,7 +230,11 @@
"label": "Grit" "label": "Grit"
}, },
"luck": { "luck": {
"label": "Luck" "label": "Luck",
"fields": {
"value": { "label": "Luck" },
"max": { "label": "Luck Max" }
}
}, },
"arcaneStress": { "arcaneStress": {
"label": "Arcane Stress" "label": "Arcane Stress"
@@ -252,9 +289,20 @@
"copper": { "copper": {
"label": "Copper" "label": "Copper"
} }
},
"description": {
"label": "Description"
},
"notes": {
"label": "Notes"
},
"skills": {
"label": "Skills"
}
} }
}, },
"NPC": { "NPC": {
"FIELDS": {
"attributes": { "attributes": {
"label": "Attributes" "label": "Attributes"
}, },
@@ -275,23 +323,59 @@
}, },
"challengeRating": { "challengeRating": {
"label": "Challenge Rating" "label": "Challenge Rating"
},
"description": {
"label": "Description"
},
"notes": {
"label": "Notes"
}
} }
}, },
"Weapon": { "Weapon": {
"proficiencyGroup": "Proficiency Group", "FIELDS": {
"usesMight": "Uses Might", "proficiencyGroup": {
"damageMod": "Damage Modifier", "label": "Proficiency Group"
"ap": "Armor Penetration (AP)", },
"reach": "Reach (ft)", "usesMight": {
"shortRange": "Short Range (ft)", "label": "Uses Might"
"longRange": "Long Range (ft)", },
"traits": "Traits", "damageMod": {
"slots": "Item Slots", "label": "Damage Modifier"
"rarity": "Rarity", },
"equipped": "Equipped", "ap": {
"cost": "Cost", "label": "Armor Penetration (AP)"
"currency": "Currency", },
"description": "Description", "reach": {
"label": "Reach (ft)"
},
"shortRange": {
"label": "Short Range (ft)"
},
"longRange": {
"label": "Long Range (ft)"
},
"traits": {
"label": "Traits"
},
"slots": {
"label": "Item Slots"
},
"rarity": {
"label": "Rarity"
},
"equipped": {
"label": "Equipped"
},
"cost": {
"label": "Cost"
},
"currency": {
"label": "Currency"
},
"description": {
"label": "Description"
},
"isMagic": { "isMagic": {
"label": "Magic Item" "label": "Magic Item"
}, },
@@ -307,8 +391,10 @@
"classRestriction": { "classRestriction": {
"label": "Restriction" "label": "Restriction"
} }
}
}, },
"Armor": { "Armor": {
"FIELDS": {
"armorType": { "armorType": {
"label": "Armor Type" "label": "Armor Type"
}, },
@@ -351,8 +437,10 @@
"classRestriction": { "classRestriction": {
"label": "Restriction" "label": "Restriction"
} }
}
}, },
"Ammunition": { "Ammunition": {
"FIELDS": {
"ammoType": { "ammoType": {
"label": "Ammunition Type" "label": "Ammunition Type"
}, },
@@ -368,8 +456,10 @@
"currency": { "currency": {
"label": "Currency" "label": "Currency"
} }
}
}, },
"Equipment": { "Equipment": {
"FIELDS": {
"itemType": { "itemType": {
"label": "Category" "label": "Category"
}, },
@@ -391,8 +481,10 @@
"currency": { "currency": {
"label": "Currency" "label": "Currency"
} }
}
}, },
"Spell": { "Spell": {
"FIELDS": {
"tradition": { "tradition": {
"label": "Tradition" "label": "Tradition"
}, },
@@ -422,9 +514,14 @@
}, },
"isExalted": { "isExalted": {
"label": "Exalted" "label": "Exalted"
},
"effect": {
"label": "Effect"
}
} }
}, },
"Miracle": { "Miracle": {
"FIELDS": {
"divineTradition": { "divineTradition": {
"label": "Divine Tradition" "label": "Divine Tradition"
}, },
@@ -442,9 +539,14 @@
}, },
"spellSave": { "spellSave": {
"label": "Spell Save" "label": "Spell Save"
},
"effect": {
"label": "Effect"
}
} }
}, },
"MagicItem": { "MagicItem": {
"FIELDS": {
"itemType": { "itemType": {
"label": "Type" "label": "Type"
}, },
@@ -471,9 +573,14 @@
}, },
"equipped": { "equipped": {
"label": "Equipped" "label": "Equipped"
},
"effect": {
"label": "Effect"
}
} }
}, },
"Ability": { "Ability": {
"FIELDS": {
"abilityType": { "abilityType": {
"label": "Type" "label": "Type"
}, },
@@ -485,6 +592,10 @@
}, },
"maxUses": { "maxUses": {
"label": "Max Uses" "label": "Max Uses"
},
"description": {
"label": "Description"
}
} }
}, },
"WeaponGroup": { "WeaponGroup": {
@@ -574,6 +685,43 @@
"violated": { "violated": {
"label": "Violated" "label": "Violated"
} }
},
"Oath": {
"FIELDS": {
"oathType": {
"label": "Oath"
},
"tenet": {
"label": "Tenet"
},
"boon": {
"label": "Boon"
},
"bane": {
"label": "Bane"
},
"violated": {
"label": "Violated"
}
}
}
},
"TYPES": {
"Item": {
"weapon": "Weapon",
"armor": "Armor",
"ammunition": "Ammunition",
"equipment": "Equipment",
"spell": "Spell",
"miracle": "Miracle",
"magic_item": "Magic Item",
"magic-item": "Magic Item",
"ability": "Ability",
"oath": "Oath"
},
"Actor": {
"character": "Character",
"npc": "NPC"
} }
} }
} }

View File

@@ -41,9 +41,15 @@
.character-resource { .character-resource {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: nowrap;
gap: 4px; gap: 4px;
margin-bottom: 2px; margin-bottom: 2px;
// formInput renders a <div class="form-group"> — flatten it so it doesn't break flex row
div.form-group {
display: contents;
}
input { input {
min-width: 2.5rem; min-width: 2.5rem;
max-width: 2.5rem; max-width: 2.5rem;

View File

@@ -29,7 +29,7 @@
// Global dialog styling // Global dialog styling
.application.dialog.oathhammer { .application.dialog.oathhammer {
font-family: @font-primary; font-family: @font-body;
font-size: @font-size-base; font-size: @font-size-base;
.sheet-background(); .sheet-background();
} }
@@ -37,11 +37,12 @@
// Shared actor content base // Shared actor content base
.oathhammer .character-content, .oathhammer .character-content,
.oathhammer .npc-content { .oathhammer .npc-content {
font-family: @font-primary; font-family: @font-body; // Calibri — standard text per design_rules.md
font-size: @font-size-base; font-size: @font-size-base;
color: var(--color-dark-1); color: var(--color-dark-1);
.sheet-background(); .sheet-background();
overflow: auto; overflow: auto;
padding: 10px 20px; // Inner margin so content clears the parchment border
nav.tabs [data-tab] { nav.tabs [data-tab] {
color: @color-olive; color: @color-olive;
@@ -63,9 +64,10 @@
color: @color-dark; color: @color-dark;
} }
// Character/NPC name — decorative title font
input[name="name"] { input[name="name"] {
height: 2.5rem; height: 2.5rem;
font-family: @font-secondary; font-family: @font-primary; // Sherwood — decorative title
font-size: @font-size-xl; font-size: @font-size-xl;
font-weight: bold; font-weight: bold;
border: none; border: none;
@@ -80,7 +82,7 @@
} }
legend { legend {
font-family: @font-secondary; font-family: @font-secondary; // BlueDragon — section headers
font-size: @font-size-lg; font-size: @font-size-lg;
font-weight: bold; font-weight: bold;
letter-spacing: 1px; letter-spacing: 1px;
@@ -88,7 +90,7 @@
} }
label { label {
font-family: @font-secondary; font-family: @font-secondary; // BlueDragon — UI labels
font-size: @font-size-base; font-size: @font-size-base;
color: @color-dark; color: @color-dark;
} }
@@ -98,3 +100,58 @@
.oathhammer .tab { .oathhammer .tab {
padding: 4px; padding: 4px;
} }
// ============================================================
// SKILLS TAB
// ============================================================
.oathhammer .skills-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
.skills-group {
margin: 0;
legend .attr-rank {
font-family: @font-body;
font-size: @font-size-sm;
color: @color-olive;
}
}
.skills-header,
.skill-row {
display: grid;
grid-template-columns: 1fr 3rem 3rem;
align-items: center;
gap: 4px;
}
.skills-header {
font-family: @font-secondary;
font-size: @font-size-sm;
font-weight: bold;
color: @color-blue;
border-bottom: 1px solid @color-olive;
margin-bottom: 2px;
padding-bottom: 2px;
}
.skill-row {
margin-bottom: 2px;
label.skill-name-col {
font-size: @font-size-sm;
}
.skill-rank-col input {
text-align: center;
}
.skill-total {
text-align: center;
font-weight: bold;
color: @color-blue;
}
}
}

View File

@@ -4,7 +4,8 @@
.oathhammer .item-sheet-common { .oathhammer .item-sheet-common {
overflow: auto; overflow: auto;
font-family: @font-primary; padding: 10px 20px; // Inner margin so content clears the parchment border
font-family: @font-body; // Calibri — standard text per design_rules.md
font-size: @font-size-base; font-size: @font-size-base;
.sheet-background(); .sheet-background();
@@ -15,6 +16,11 @@
margin-bottom: 8px; margin-bottom: 8px;
padding-bottom: 4px; padding-bottom: 4px;
border-bottom: 2px solid @color-blue; border-bottom: 2px solid @color-blue;
// Item name input — decorative title font
input[name="name"] {
font-family: @font-primary; // Sherwood — decorative title
}
} }
.item-img { .item-img {
@@ -26,33 +32,70 @@
object-fit: cover; object-fit: cover;
} }
.form-group { // Override Foundry dark-theme input/select backgrounds for parchment look
display: flex; input:not([type="checkbox"]),
flex: 1; select {
flex-direction: row; height: 1.5rem;
align-items: center; background-color: @color-input-bg;
gap: 4px; border-color: @color-blue;
margin-bottom: 2px; color: @color-dark;
}
// Checkboxes: natural size, no custom background
input[type="checkbox"] {
width: auto;
height: auto;
background-color: transparent;
border-color: @color-blue;
}
input[name="name"] {
height: 2.5rem;
font-family: @font-primary;
font-size: @font-size-xl;
font-weight: bold;
border: none;
border-bottom: 2px solid @color-blue;
background: transparent;
}
label { label {
font-family: @font-secondary; font-family: @font-secondary;
font-size: @font-size-base; font-size: @font-size-base;
min-width: @label-min-width; color: @color-dark;
max-width: @label-min-width;
} }
select, .form-group {
input { display: flex;
text-align: left; flex-direction: row;
min-width: @input-min-width; align-items: center;
max-width: @input-max-width; gap: 6px;
margin-bottom: 4px;
& > label {
flex: 0 0 8rem; // Fixed label width, no grow/shrink
font-family: @font-secondary;
font-size: @font-size-base;
color: @color-dark;
}
.form-fields {
flex: 1;
min-width: 0;
input:not([type="checkbox"]),
select {
width: 100%;
box-sizing: border-box;
}
} }
} }
.align-top { .align-top {
flex: 1;
min-width: 0;
align-self: flex-start; align-self: flex-start;
padding: 0.2rem; padding: 0 0.3rem;
min-width: 260px;
} }
.shift-right { .shift-right {

View File

@@ -8,16 +8,18 @@
@font-body: "Calibri", "Segoe UI", sans-serif; @font-body: "Calibri", "Segoe UI", sans-serif;
@font-size-base: 0.82rem; @font-size-base: 0.82rem;
// Colors // Colors — from design_rules.md (CMYK converted to RGB)
@color-blue: #1a4a7a; // Blue: CMYK(94, 42, 9, 50) → rgb(8, 74, 116)
@color-olive: #5a5a2a; // Olive: CMYK(26, 28, 64, 56) → rgb(83, 81, 40)
@color-blue: #084a74;
@color-olive: #535128;
@color-gold: #c8a84b; @color-gold: #c8a84b;
@color-dark: #2a1a0a; @color-dark: #2a1a0a;
@color-paper: #f5ead0; @color-paper: #f5ead0;
// Derived // Derived — using LESS fade() to keep colors in sync with variables
@color-olive-faint: rgba(90, 90, 42, 0.2); @color-olive-faint: fade(@color-olive, 20%);
@color-blue-hover: rgba(26, 74, 122, 0.08); @color-blue-hover: fade(@color-blue, 8%);
@color-input-bg: rgba(255, 255, 255, 0.3); @color-input-bg: rgba(255, 255, 255, 0.3);
@color-disabled-bg: rgba(0, 0, 0, 0.08); @color-disabled-bg: rgba(0, 0, 0, 0.08);

View File

@@ -1,4 +1,5 @@
import OathHammerActorSheet from "./base-actor-sheet.mjs" import OathHammerActorSheet from "./base-actor-sheet.mjs"
import { SYSTEM } from "../../config/system.mjs"
export default class OathHammerCharacterSheet extends OathHammerActorSheet { export default class OathHammerCharacterSheet extends OathHammerActorSheet {
/** @override */ /** @override */
@@ -21,27 +22,14 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet {
/** @override */ /** @override */
static PARTS = { static PARTS = {
main: { main: { template: "systems/fvtt-oath-hammer/templates/actor/character-sheet.hbs" },
template: "systems/fvtt-oath-hammer/templates/actor/character-sheet.hbs", tabs: { template: "templates/generic/tab-navigation.hbs" },
}, identity: { template: "systems/fvtt-oath-hammer/templates/actor/character-identity.hbs" },
tabs: { skills: { template: "systems/fvtt-oath-hammer/templates/actor/character-skills.hbs" },
template: "templates/generic/tab-navigation.hbs", combat: { template: "systems/fvtt-oath-hammer/templates/actor/character-combat.hbs" },
}, magic: { template: "systems/fvtt-oath-hammer/templates/actor/character-magic.hbs" },
identity: { equipment: { template: "systems/fvtt-oath-hammer/templates/actor/character-equipment.hbs" },
template: "systems/fvtt-oath-hammer/templates/actor/character-identity.hbs", notes: { template: "systems/fvtt-oath-hammer/templates/actor/character-notes.hbs" },
},
combat: {
template: "systems/fvtt-oath-hammer/templates/actor/character-combat.hbs",
},
magic: {
template: "systems/fvtt-oath-hammer/templates/actor/character-magic.hbs",
},
equipment: {
template: "systems/fvtt-oath-hammer/templates/actor/character-equipment.hbs",
},
notes: {
template: "systems/fvtt-oath-hammer/templates/actor/character-notes.hbs",
},
} }
/** @override */ /** @override */
@@ -52,6 +40,7 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet {
#getTabs() { #getTabs() {
const tabs = { const tabs = {
identity: { id: "identity", group: "sheet", icon: "fa-solid fa-person", label: "OATHHAMMER.Tab.Identity" }, identity: { id: "identity", group: "sheet", icon: "fa-solid fa-person", label: "OATHHAMMER.Tab.Identity" },
skills: { id: "skills", group: "sheet", icon: "fa-solid fa-scroll", label: "OATHHAMMER.Tab.Skills" },
combat: { id: "combat", group: "sheet", icon: "fa-solid fa-swords", label: "OATHHAMMER.Tab.Combat" }, combat: { id: "combat", group: "sheet", icon: "fa-solid fa-swords", label: "OATHHAMMER.Tab.Combat" },
magic: { id: "magic", group: "sheet", icon: "fa-solid fa-wand-magic-sparkles", label: "OATHHAMMER.Tab.Magic" }, magic: { id: "magic", group: "sheet", icon: "fa-solid fa-wand-magic-sparkles", label: "OATHHAMMER.Tab.Magic" },
equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-backpack", label: "OATHHAMMER.Tab.Equipment" }, equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-backpack", label: "OATHHAMMER.Tab.Equipment" },
@@ -82,6 +71,33 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet {
context.abilities = doc.itemTypes.ability context.abilities = doc.itemTypes.ability
context.oaths = doc.itemTypes.oath context.oaths = doc.itemTypes.oath
break break
case "skills": {
context.tab = context.tabs.skills
const sys = doc.system
const skillSchemaFields = doc.system.schema.fields.skills.fields
const attrRanks = {
might: sys.attributes.might.rank,
toughness: sys.attributes.toughness.rank,
agility: sys.attributes.agility.rank,
willpower: sys.attributes.willpower.rank,
intelligence: sys.attributes.intelligence.rank,
fate: sys.attributes.fate.rank,
}
context.skillGroups = Object.entries(SYSTEM.SKILLS_BY_ATTRIBUTE).map(([attr, skillKeys]) => ({
attribute: attr,
label: `OATHHAMMER.Attribute.${attr.charAt(0).toUpperCase()}${attr.slice(1)}`,
attrRank: attrRanks[attr],
skillData: skillKeys.map(skillKey => ({
key: skillKey,
label: SYSTEM.SKILLS[skillKey].label,
rank: sys.skills[skillKey].rank,
name: `system.skills.${skillKey}.rank`,
total: attrRanks[attr] + sys.skills[skillKey].rank,
field: skillSchemaFields[skillKey].fields.rank,
}))
}))
break
}
case "combat": case "combat":
context.tab = context.tabs.combat context.tab = context.tabs.combat
context.weapons = doc.itemTypes.weapon context.weapons = doc.itemTypes.weapon

View File

@@ -279,6 +279,46 @@ export const STATUS_EFFECTS = [
export const ATTRIBUTE_RANK_CHOICES = { 1: "1", 2: "2", 3: "3", 4: "4" } export const ATTRIBUTE_RANK_CHOICES = { 1: "1", 2: "2", 3: "3", 4: "4" }
// 26 skills: each mapped to its primary attribute. "magic" is dual (WP=miracles, INT=spells).
export const SKILLS = {
academics: { id: "academics", attribute: "intelligence", label: "OATHHAMMER.Skill.Academics" },
acrobatics: { id: "acrobatics", attribute: "agility", label: "OATHHAMMER.Skill.Acrobatics" },
animalHandling:{ id: "animalHandling", attribute: "willpower", label: "OATHHAMMER.Skill.AnimalHandling" },
athletics: { id: "athletics", attribute: "might", label: "OATHHAMMER.Skill.Athletics" },
brewing: { id: "brewing", attribute: "intelligence", label: "OATHHAMMER.Skill.Brewing" },
carpentry: { id: "carpentry", attribute: "agility", label: "OATHHAMMER.Skill.Carpentry" },
defense: { id: "defense", attribute: "agility", label: "OATHHAMMER.Skill.Defense" },
dexterity: { id: "dexterity", attribute: "agility", label: "OATHHAMMER.Skill.Dexterity" },
diplomacy: { id: "diplomacy", attribute: "willpower", label: "OATHHAMMER.Skill.Diplomacy" },
discipline: { id: "discipline", attribute: "willpower", label: "OATHHAMMER.Skill.Discipline" },
fighting: { id: "fighting", attribute: "might", label: "OATHHAMMER.Skill.Fighting" },
folklore: { id: "folklore", attribute: "fate", label: "OATHHAMMER.Skill.Folklore" },
fortune: { id: "fortune", attribute: "fate", label: "OATHHAMMER.Skill.Fortune" },
heal: { id: "heal", attribute: "intelligence", label: "OATHHAMMER.Skill.Heal" },
leadership: { id: "leadership", attribute: "willpower", label: "OATHHAMMER.Skill.Leadership" },
magic: { id: "magic", attribute: "willpower", label: "OATHHAMMER.Skill.Magic" },
masonry: { id: "masonry", attribute: "might", label: "OATHHAMMER.Skill.Masonry" },
orientation: { id: "orientation", attribute: "intelligence", label: "OATHHAMMER.Skill.Orientation" },
perception: { id: "perception", attribute: "willpower", label: "OATHHAMMER.Skill.Perception" },
resilience: { id: "resilience", attribute: "toughness", label: "OATHHAMMER.Skill.Resilience" },
ride: { id: "ride", attribute: "agility", label: "OATHHAMMER.Skill.Ride" },
shooting: { id: "shooting", attribute: "agility", label: "OATHHAMMER.Skill.Shooting" },
smithing: { id: "smithing", attribute: "might", label: "OATHHAMMER.Skill.Smithing" },
stealth: { id: "stealth", attribute: "agility", label: "OATHHAMMER.Skill.Stealth" },
survival: { id: "survival", attribute: "willpower", label: "OATHHAMMER.Skill.Survival" },
tracking: { id: "tracking", attribute: "intelligence", label: "OATHHAMMER.Skill.Tracking" },
}
// Skills grouped by primary attribute (for sheet display)
export const SKILLS_BY_ATTRIBUTE = {
might: ["athletics", "fighting", "masonry", "smithing"],
toughness: ["resilience"],
agility: ["acrobatics", "carpentry", "defense", "dexterity", "ride", "shooting", "stealth"],
willpower: ["animalHandling", "diplomacy", "discipline", "leadership", "magic", "perception", "survival"],
intelligence: ["academics", "brewing", "heal", "orientation", "tracking"],
fate: ["folklore", "fortune"],
}
export const ASCII = ` export const ASCII = `
················································· ·················································
: ___ _ _ _ _ : : ___ _ _ _ _ :
@@ -293,6 +333,8 @@ export const ASCII = `
export const SYSTEM = { export const SYSTEM = {
id: SYSTEM_ID, id: SYSTEM_ID,
ATTRIBUTES, ATTRIBUTES,
SKILLS,
SKILLS_BY_ATTRIBUTE,
LINEAGE_CHOICES, LINEAGE_CHOICES,
CLASS_CHOICES, CLASS_CHOICES,
OATH_TYPES, OATH_TYPES,

View File

@@ -21,13 +21,48 @@ export default class OathHammerCharacter extends foundry.abstract.TypeDataModel
fate: attributeField() fate: attributeField()
}) })
// Skills: 26 skills each with a rank (04). Grit.max = resilience.rank + toughness.rank.
const skillField = () => new fields.SchemaField({
rank: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 4 })
})
schema.skills = new fields.SchemaField({
academics: skillField(),
acrobatics: skillField(),
animalHandling:skillField(),
athletics: skillField(),
brewing: skillField(),
carpentry: skillField(),
defense: skillField(),
dexterity: skillField(),
diplomacy: skillField(),
discipline: skillField(),
fighting: skillField(),
folklore: skillField(),
fortune: skillField(),
heal: skillField(),
leadership: skillField(),
magic: skillField(),
masonry: skillField(),
orientation: skillField(),
perception: skillField(),
resilience: skillField(),
ride: skillField(),
shooting: skillField(),
smithing: skillField(),
stealth: skillField(),
survival: skillField(),
tracking: skillField(),
})
schema.grit = new fields.SchemaField({ schema.grit = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 2, min: 0 }), value: new fields.NumberField({ ...requiredInteger, initial: 2, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 2, min: 0 }) max: new fields.NumberField({ ...requiredInteger, initial: 2, min: 0 })
}) })
// Luck.max is derived from fate.rank; resets at session start.
schema.luck = new fields.SchemaField({ schema.luck = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }) value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
}) })
schema.arcaneStress = new fields.SchemaField({ schema.arcaneStress = new fields.SchemaField({
@@ -77,7 +112,11 @@ export default class OathHammerCharacter extends foundry.abstract.TypeDataModel
prepareDerivedData() { prepareDerivedData() {
super.prepareDerivedData() super.prepareDerivedData()
this.grit.max = this.attributes.might.rank + this.attributes.toughness.rank // Grit max = Resilience skill rank + Toughness attribute rank (rulebook p.5)
this.grit.max = this.skills.resilience.rank + this.attributes.toughness.rank
// Luck max = Fate rank; restores at session start
this.luck.max = this.attributes.fate.rank
// Defense score = 10 + Agility + Armor Rating + bonus
this.defense.value = 10 + this.attributes.agility.rank + this.defense.armorRating + this.defense.bonus this.defense.value = 10 + this.attributes.agility.rank + this.defense.armorRating + this.defense.bonus
} }
} }

View File

@@ -1,4 +1,4 @@
<section data-tab="combat" class="tab"> <section data-tab="combat" class="tab {{tab.cssClass}}">
<fieldset> <fieldset>
<legend>{{localize "OATHHAMMER.Label.Defense"}}</legend> <legend>{{localize "OATHHAMMER.Label.Defense"}}</legend>
<div class="flexrow"> <div class="flexrow">

View File

@@ -1,4 +1,4 @@
<section data-tab="equipment" class="tab"> <section data-tab="equipment" class="tab {{tab.cssClass}}">
<fieldset> <fieldset>
<legend>{{localize "OATHHAMMER.Label.Equipment"}} <legend>{{localize "OATHHAMMER.Label.Equipment"}}
{{#unless isPlayMode}}<a data-action="createEquipment" class="create-btn"><i class="fa-solid fa-plus"></i></a>{{/unless}} {{#unless isPlayMode}}<a data-action="createEquipment" class="create-btn"><i class="fa-solid fa-plus"></i></a>{{/unless}}

View File

@@ -1,4 +1,4 @@
<section data-tab="identity" class="tab"> <section data-tab="identity" class="tab {{tab.cssClass}}">
<fieldset> <fieldset>
<legend>{{localize "OATHHAMMER.Label.Biodata"}}</legend> <legend>{{localize "OATHHAMMER.Label.Biodata"}}</legend>
<div class="flexrow"> <div class="flexrow">

View File

@@ -1,4 +1,4 @@
<section data-tab="magic" class="tab"> <section data-tab="magic" class="tab {{tab.cssClass}}">
<fieldset> <fieldset>
<legend>{{localize "OATHHAMMER.Label.ArcaneStress"}}</legend> <legend>{{localize "OATHHAMMER.Label.ArcaneStress"}}</legend>
<div class="flexrow"> <div class="flexrow">

View File

@@ -1,4 +1,4 @@
<section data-tab="notes" class="tab"> <section data-tab="notes" class="tab {{tab.cssClass}}">
<fieldset> <fieldset>
<legend>{{localize "OATHHAMMER.Label.Description"}}</legend> <legend>{{localize "OATHHAMMER.Label.Description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}

View File

@@ -16,6 +16,8 @@
<div class="flexrow character-resource"> <div class="flexrow character-resource">
<span class="resource-label">{{localize "OATHHAMMER.Label.Luck"}}</span> <span class="resource-label">{{localize "OATHHAMMER.Label.Luck"}}</span>
{{formInput systemFields.luck.fields.value value=system.luck.value name="system.luck.value" disabled=isPlayMode}} {{formInput systemFields.luck.fields.value value=system.luck.value name="system.luck.value" disabled=isPlayMode}}
<span>/</span>
{{formInput systemFields.luck.fields.max value=system.luck.max name="system.luck.max" disabled=isPlayMode}}
</div> </div>
<div class="flexrow character-resource"> <div class="flexrow character-resource">
<span class="resource-label">{{localize "OATHHAMMER.Label.Defense"}}</span> <span class="resource-label">{{localize "OATHHAMMER.Label.Defense"}}</span>
@@ -40,7 +42,7 @@
{{#each system.attributes as |attr key|}} {{#each system.attributes as |attr key|}}
<div class="attribute-box"> <div class="attribute-box">
<label>{{localize (concat "OATHHAMMER.Attribute." (capitalize key))}}</label> <label>{{localize (concat "OATHHAMMER.Attribute." (capitalize key))}}</label>
{{formInput (lookup ../systemFields.attributes.fields key).fields.rank value=attr.rank name=(concat "system.attributes." key ".rank") disabled=../isPlayMode}} <input type="number" name="system.attributes.{{key}}.rank" value="{{attr.rank}}" min="1" max="4" {{#if ../isPlayMode}}disabled{{/if}}>
</div> </div>
{{/each}} {{/each}}
</div> </div>

View File

@@ -0,0 +1,28 @@
<section data-tab="skills" class="tab {{tab.cssClass}}">
<div class="skills-container">
{{#each skillGroups as |group|}}
<fieldset class="skills-group">
<legend>
{{localize group.label}}
<span class="attr-rank">({{group.attrRank}})</span>
</legend>
<div class="skills-list">
<div class="skills-header">
<span class="skill-name-col">{{localize "OATHHAMMER.Label.Skill"}}</span>
<span class="skill-rank-col">{{localize "OATHHAMMER.Label.SkillRank"}}</span>
<span class="skill-total-col">{{localize "OATHHAMMER.Label.TotalDice"}}</span>
</div>
{{#each group.skillData as |skill|}}
<div class="skill-row">
<label class="skill-name-col">{{localize skill.label}}</label>
<div class="skill-rank-col">
{{formInput skill.field value=skill.rank name=skill.name disabled=../../isPlayMode}}
</div>
<span class="skill-total-col skill-total">{{skill.total}}</span>
</div>
{{/each}}
</div>
</fieldset>
{{/each}}
</div>
</section>

View File

@@ -5,20 +5,14 @@
</div> </div>
<div class="flexrow"> <div class="flexrow">
<div class="align-top"> <div class="align-top">
{{formField systemFields.piety value=system.piety name="system.piety"}} {{formField systemFields.divineTradition value=system.divineTradition name="system.divineTradition" localize=true}}
{{formField systemFields.castingTime value=system.castingTime name="system.castingTime"}} {{formField systemFields.difficultyValue value=system.difficultyValue name="system.difficultyValue"}}
{{formField systemFields.range value=system.range name="system.range"}} {{formField systemFields.range value=system.range name="system.range"}}
{{formField systemFields.duration value=system.duration name="system.duration"}} {{formField systemFields.duration value=system.duration name="system.duration"}}
{{formField systemFields.spellSave value=system.spellSave name="system.spellSave"}}
</div> </div>
<div class="align-top"> <div class="align-top">
<label>{{localize "OATHHAMMER.Label.Components"}}</label> {{formField systemFields.isRitual value=system.isRitual name="system.isRitual"}}
<div class="shift-right">
{{formField systemFields.components.fields.verbal value=system.components.verbal name="system.components.verbal"}}
{{formField systemFields.components.fields.somatic value=system.components.somatic name="system.components.somatic"}}
{{formField systemFields.components.fields.material value=system.components.material name="system.components.material"}}
</div>
{{formField systemFields.materialComponent value=system.materialComponent name="system.materialComponent"}}
{{formField systemFields.savingThrow value=system.savingThrow name="system.savingThrow"}}
</div> </div>
</div> </div>
<fieldset> <fieldset>

View File

@@ -6,22 +6,17 @@
<div class="flexrow"> <div class="flexrow">
<div class="align-top"> <div class="align-top">
{{formField systemFields.tradition value=system.tradition name="system.tradition" localize=true}} {{formField systemFields.tradition value=system.tradition name="system.tradition" localize=true}}
{{formField systemFields.level value=system.level name="system.level"}} {{formField systemFields.difficultyValue value=system.difficultyValue name="system.difficultyValue"}}
{{formField systemFields.arcaneStress value=system.arcaneStress name="system.arcaneStress"}}
{{formField systemFields.castingTime value=system.castingTime name="system.castingTime"}}
{{formField systemFields.range value=system.range name="system.range"}} {{formField systemFields.range value=system.range name="system.range"}}
{{formField systemFields.duration value=system.duration name="system.duration"}} {{formField systemFields.duration value=system.duration name="system.duration"}}
{{formField systemFields.spellSave value=system.spellSave name="system.spellSave"}}
</div> </div>
<div class="align-top"> <div class="align-top">
<label>{{localize "OATHHAMMER.Label.Components"}}</label> {{formField systemFields.isRitual value=system.isRitual name="system.isRitual"}}
<div class="shift-right"> {{formField systemFields.isMagicMissile value=system.isMagicMissile name="system.isMagicMissile"}}
{{formField systemFields.components.fields.verbal value=system.components.verbal name="system.components.verbal"}} {{formField systemFields.isExalted value=system.isExalted name="system.isExalted"}}
{{formField systemFields.components.fields.somatic value=system.components.somatic name="system.components.somatic"}} {{formField systemFields.element value=system.element name="system.element" localize=true}}
{{formField systemFields.components.fields.material value=system.components.material name="system.components.material"}} {{formField systemFields.runeType value=system.runeType name="system.runeType" localize=true}}
</div>
{{formField systemFields.materialComponent value=system.materialComponent name="system.materialComponent"}}
{{formField systemFields.savingThrow value=system.savingThrow name="system.savingThrow"}}
{{formField systemFields.enhancement value=system.enhancement name="system.enhancement"}}
</div> </div>
</div> </div>
<fieldset> <fieldset>