diff --git a/assets/icons/icon_ability.webp b/assets/icons/icon_ability.webp new file mode 100644 index 0000000..52bf674 Binary files /dev/null and b/assets/icons/icon_ability.webp differ diff --git a/assets/icons/icon_ammunition.webp b/assets/icons/icon_ammunition.webp new file mode 100644 index 0000000..408df55 Binary files /dev/null and b/assets/icons/icon_ammunition.webp differ diff --git a/assets/icons/icon_armor.webp b/assets/icons/icon_armor.webp new file mode 100644 index 0000000..6b14549 Binary files /dev/null and b/assets/icons/icon_armor.webp differ diff --git a/assets/icons/icon_equipment.webp b/assets/icons/icon_equipment.webp new file mode 100644 index 0000000..7be2a2d Binary files /dev/null and b/assets/icons/icon_equipment.webp differ diff --git a/assets/icons/icon_magic_item.webp b/assets/icons/icon_magic_item.webp new file mode 100644 index 0000000..7eae212 Binary files /dev/null and b/assets/icons/icon_magic_item.webp differ diff --git a/assets/icons/icon_miracle.webp b/assets/icons/icon_miracle.webp new file mode 100644 index 0000000..4f63da8 Binary files /dev/null and b/assets/icons/icon_miracle.webp differ diff --git a/assets/icons/icon_oath.webp b/assets/icons/icon_oath.webp new file mode 100644 index 0000000..40c6098 Binary files /dev/null and b/assets/icons/icon_oath.webp differ diff --git a/assets/icons/icon_spell.webp b/assets/icons/icon_spell.webp new file mode 100644 index 0000000..6c631b2 Binary files /dev/null and b/assets/icons/icon_spell.webp differ diff --git a/assets/icons/icon_weapon.webp b/assets/icons/icon_weapon.webp new file mode 100644 index 0000000..7b5a985 Binary files /dev/null and b/assets/icons/icon_weapon.webp differ diff --git a/css/fvtt-oath-hammer.css b/css/fvtt-oath-hammer.css index 37bccd6..991892a 100644 --- a/css/fvtt-oath-hammer.css +++ b/css/fvtt-oath-hammer.css @@ -11,8 +11,8 @@ --oh-font-secondary: "BlueDragon", "Palatino Linotype", serif; --oh-font-body: "Calibri", "Segoe UI", sans-serif; --oh-font-size: 0.82rem; - --oh-color-blue: #1a4a7a; - --oh-color-olive: #5a5a2a; + --oh-color-blue: #084a74; + --oh-color-olive: #535128; --oh-color-gold: #c8a84b; --oh-color-dark: #2a1a0a; --oh-color-paper: #f5ead0; @@ -20,7 +20,7 @@ --oh-logo: url("../assets/logos/official_logo_01.webp"); } .application.dialog.oathhammer { - font-family: "Sherwood", "Palatino Linotype", serif; + font-family: "Calibri", "Segoe UI", sans-serif; font-size: 0.82rem; background-image: var(--oh-background-image); background-repeat: no-repeat; @@ -28,21 +28,22 @@ } .oathhammer .character-content, .oathhammer .npc-content { - font-family: "Sherwood", "Palatino Linotype", serif; + font-family: "Calibri", "Segoe UI", sans-serif; font-size: 0.82rem; color: var(--color-dark-1); background-image: var(--oh-background-image); background-repeat: no-repeat; background-size: 100% 100%; overflow: auto; + padding: 10px 20px; } .oathhammer .character-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 .npc-content nav.tabs [data-tab].active { - color: #1a4a7a; + color: #084a74; } .oathhammer .character-content input:disabled, .oathhammer .npc-content input:disabled, @@ -58,24 +59,24 @@ .oathhammer .npc-content select { height: 1.5rem; background-color: rgba(255, 255, 255, 0.3); - border-color: #1a4a7a; + border-color: #084a74; color: #2a1a0a; } .oathhammer .character-content input[name="name"], .oathhammer .npc-content input[name="name"] { height: 2.5rem; - font-family: "BlueDragon", "Palatino Linotype", serif; + font-family: "Sherwood", "Palatino Linotype", serif; font-size: calc(0.82rem * 1.2); font-weight: bold; border: none; - border-bottom: 2px solid #1a4a7a; + border-bottom: 2px solid #084a74; background: transparent; } .oathhammer .character-content fieldset, .oathhammer .npc-content fieldset { margin-bottom: 4px; border-radius: 4px; - border-color: #5a5a2a; + border-color: #535128; } .oathhammer .character-content legend, .oathhammer .npc-content legend { @@ -83,7 +84,7 @@ font-size: calc(0.82rem * 1.1); font-weight: bold; letter-spacing: 1px; - color: #1a4a7a; + color: #084a74; } .oathhammer .character-content label, .oathhammer .npc-content label { @@ -94,10 +95,53 @@ .oathhammer .tab { 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 { height: 150px; width: auto; - border: 2px solid #1a4a7a; + border: 2px solid #084a74; border-radius: 4px; cursor: pointer; -o-object-fit: cover; @@ -128,9 +172,13 @@ .oathhammer .character-main .character-resource { display: flex; align-items: center; + flex-wrap: nowrap; gap: 4px; margin-bottom: 2px; } +.oathhammer .character-main .character-resource div.form-group { + display: contents; +} .oathhammer .character-main .character-resource input { min-width: 2.5rem; max-width: 2.5rem; @@ -226,15 +274,15 @@ align-items: center; gap: 6px; 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 { - background-color: rgba(26, 74, 122, 0.08); + background-color: rgba(8, 74, 116, 0.08); } .oathhammer .item-entry .item-img { height: 24px; width: 24px; - border: 1px solid #5a5a2a; + border: 1px solid #535128; border-radius: 2px; -o-object-fit: cover; object-fit: cover; @@ -246,13 +294,13 @@ } .oathhammer .item-entry .item-detail { font-size: calc(0.82rem * 0.9); - color: #5a5a2a; + color: #535128; min-width: 4rem; text-align: center; } .oathhammer .item-entry .item-type { font-size: calc(0.82rem * 0.85); - color: #1a4a7a; + color: #084a74; min-width: 6rem; } .oathhammer .item-entry a { @@ -263,7 +311,7 @@ opacity: 1; } .oathhammer .item-entry a:hover { - color: #1a4a7a; + color: #084a74; } .oathhammer .no-items { color: var(--color-dark-5); @@ -273,7 +321,7 @@ } .oathhammer .create-btn { margin-left: 6px; - color: #1a4a7a; + color: #084a74; opacity: 0.6; transition: opacity 0.2s; } @@ -282,7 +330,8 @@ } .oathhammer .item-sheet-common { overflow: auto; - font-family: "Sherwood", "Palatino Linotype", serif; + padding: 10px 20px; + font-family: "Calibri", "Segoe UI", sans-serif; font-size: 0.82rem; background-image: var(--oh-background-image); background-repeat: no-repeat; @@ -294,53 +343,86 @@ gap: 8px; margin-bottom: 8px; 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 { height: 52px; width: 52px; - border: 2px solid #5a5a2a; + border: 2px solid #535128; border-radius: 4px; cursor: pointer; -o-object-fit: cover; object-fit: cover; } -.oathhammer .item-sheet-common .form-group { - display: flex; - flex: 1; - flex-direction: row; - align-items: center; - gap: 4px; - margin-bottom: 2px; +.oathhammer .item-sheet-common input:not([type="checkbox"]), +.oathhammer .item-sheet-common select { + height: 1.5rem; + background-color: rgba(255, 255, 255, 0.3); + border-color: #084a74; + color: #2a1a0a; } -.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-size: 0.82rem; - min-width: 9rem; - max-width: 9rem; + color: #2a1a0a; } -.oathhammer .item-sheet-common .form-group select, -.oathhammer .item-sheet-common .form-group input { - text-align: left; - min-width: 10rem; - max-width: 12rem; +.oathhammer .item-sheet-common .form-group { + display: flex; + flex-direction: row; + align-items: center; + 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 { + flex: 1; + min-width: 0; align-self: flex-start; - padding: 0.2rem; - min-width: 260px; + padding: 0 0.3rem; } .oathhammer .item-sheet-common .shift-right { margin-left: 2rem; } .oathhammer .item-sheet-common fieldset { margin-top: 6px; - border-color: #5a5a2a; + border-color: #535128; border-radius: 4px; } .oathhammer .item-sheet-common legend { font-family: "BlueDragon", "Palatino Linotype", serif; font-size: calc(0.82rem * 1.1); font-weight: bold; - color: #1a4a7a; + color: #084a74; } diff --git a/lang/en.json b/lang/en.json index 857ce6f..9cb5d3b 100644 --- a/lang/en.json +++ b/lang/en.json @@ -16,6 +16,7 @@ }, "Tab": { "Identity": "Identity", + "Skills": "Skills", "Combat": "Combat", "Magic": "Magic", "Equipment": "Equipment", @@ -29,6 +30,34 @@ "Intelligence": "Intelligence", "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": { "Dwarf": "Dwarf", "Firbolg": "Firbolg", @@ -180,7 +209,10 @@ "Enchantment": "Enchantment", "Tenet": "Tenet", "Boon": "Boon", - "Bane": "Bane" + "Bane": "Bane", + "Skill": "Skill", + "SkillRank": "Rank", + "TotalDice": "Total Dice" }, "NewItem": { "Weapon": "New Weapon", @@ -190,301 +222,380 @@ }, "ToggleSheet": "Toggle Edit/Play Mode", "Character": { - "attributes": { - "label": "Attributes" - }, - "grit": { - "label": "Grit" - }, - "luck": { - "label": "Luck" - }, - "arcaneStress": { - "label": "Arcane Stress" - }, - "movement": { - "label": "Movement" - }, - "defense": { - "label": "Defense" - }, - "experience": { - "label": "Experience" - }, - "biodata": { - "label": "Background", - "lineage": { - "label": "Lineage" + "FIELDS": { + "attributes": { + "label": "Attributes" }, - "class": { - "label": "Class" + "grit": { + "label": "Grit" }, - "age": { - "label": "Age" + "luck": { + "label": "Luck", + "fields": { + "value": { "label": "Luck" }, + "max": { "label": "Luck Max" } + } }, - "gender": { - "label": "Gender" + "arcaneStress": { + "label": "Arcane Stress" }, - "height": { - "label": "Height" + "movement": { + "label": "Movement" }, - "weight": { - "label": "Weight" + "defense": { + "label": "Defense" }, - "eyes": { - "label": "Eye Color" + "experience": { + "label": "Experience" }, - "hair": { - "label": "Hair Color" + "biodata": { + "label": "Background", + "lineage": { + "label": "Lineage" + }, + "class": { + "label": "Class" + }, + "age": { + "label": "Age" + }, + "gender": { + "label": "Gender" + }, + "height": { + "label": "Height" + }, + "weight": { + "label": "Weight" + }, + "eyes": { + "label": "Eye Color" + }, + "hair": { + "label": "Hair Color" + }, + "alignment": { + "label": "Alignment" + } }, - "alignment": { - "label": "Alignment" - } - }, - "currency": { - "label": "Currency", - "gold": { - "label": "Gold" + "currency": { + "label": "Currency", + "gold": { + "label": "Gold" + }, + "silver": { + "label": "Silver" + }, + "copper": { + "label": "Copper" + } }, - "silver": { - "label": "Silver" + "description": { + "label": "Description" }, - "copper": { - "label": "Copper" + "notes": { + "label": "Notes" + }, + "skills": { + "label": "Skills" } } }, "NPC": { - "attributes": { - "label": "Attributes" - }, - "grit": { - "label": "Grit" - }, - "defense": { - "label": "Defense" - }, - "movement": { - "label": "Movement" - }, - "attackBonus": { - "label": "Attack Bonus" - }, - "damageBonus": { - "label": "Damage Bonus" - }, - "challengeRating": { - "label": "Challenge Rating" + "FIELDS": { + "attributes": { + "label": "Attributes" + }, + "grit": { + "label": "Grit" + }, + "defense": { + "label": "Defense" + }, + "movement": { + "label": "Movement" + }, + "attackBonus": { + "label": "Attack Bonus" + }, + "damageBonus": { + "label": "Damage Bonus" + }, + "challengeRating": { + "label": "Challenge Rating" + }, + "description": { + "label": "Description" + }, + "notes": { + "label": "Notes" + } } }, "Weapon": { - "proficiencyGroup": "Proficiency Group", - "usesMight": "Uses Might", - "damageMod": "Damage Modifier", - "ap": "Armor Penetration (AP)", - "reach": "Reach (ft)", - "shortRange": "Short Range (ft)", - "longRange": "Long Range (ft)", - "traits": "Traits", - "slots": "Item Slots", - "rarity": "Rarity", - "equipped": "Equipped", - "cost": "Cost", - "currency": "Currency", - "description": "Description", - "isMagic": { - "label": "Magic Item" - }, - "magicQuality": { - "label": "Quality" - }, - "isCursed": { - "label": "Cursed" - }, - "magicEffect": { - "label": "Enchantment" - }, - "classRestriction": { - "label": "Restriction" + "FIELDS": { + "proficiencyGroup": { + "label": "Proficiency Group" + }, + "usesMight": { + "label": "Uses Might" + }, + "damageMod": { + "label": "Damage Modifier" + }, + "ap": { + "label": "Armor Penetration (AP)" + }, + "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": { + "label": "Magic Item" + }, + "magicQuality": { + "label": "Quality" + }, + "isCursed": { + "label": "Cursed" + }, + "magicEffect": { + "label": "Enchantment" + }, + "classRestriction": { + "label": "Restriction" + } } }, "Armor": { - "armorType": { - "label": "Armor Type" - }, - "armorValue": { - "label": "Armor Value (AV)" - }, - "penalty": { - "label": "Penalty" - }, - "slots": { - "label": "Slots" - }, - "traits": { - "label": "Traits" - }, - "rarity": { - "label": "Rarity" - }, - "equipped": { - "label": "Equipped" - }, - "cost": { - "label": "Cost" - }, - "currency": { - "label": "Currency" - }, - "isMagic": { - "label": "Magic Item" - }, - "magicQuality": { - "label": "Quality" - }, - "isCursed": { - "label": "Cursed" - }, - "magicEffect": { - "label": "Enchantment" - }, - "classRestriction": { - "label": "Restriction" + "FIELDS": { + "armorType": { + "label": "Armor Type" + }, + "armorValue": { + "label": "Armor Value (AV)" + }, + "penalty": { + "label": "Penalty" + }, + "slots": { + "label": "Slots" + }, + "traits": { + "label": "Traits" + }, + "rarity": { + "label": "Rarity" + }, + "equipped": { + "label": "Equipped" + }, + "cost": { + "label": "Cost" + }, + "currency": { + "label": "Currency" + }, + "isMagic": { + "label": "Magic Item" + }, + "magicQuality": { + "label": "Quality" + }, + "isCursed": { + "label": "Cursed" + }, + "magicEffect": { + "label": "Enchantment" + }, + "classRestriction": { + "label": "Restriction" + } } }, "Ammunition": { - "ammoType": { - "label": "Ammunition Type" - }, - "quantity": { - "label": "Quantity" - }, - "rarity": { - "label": "Rarity" - }, - "cost": { - "label": "Cost" - }, - "currency": { - "label": "Currency" + "FIELDS": { + "ammoType": { + "label": "Ammunition Type" + }, + "quantity": { + "label": "Quantity" + }, + "rarity": { + "label": "Rarity" + }, + "cost": { + "label": "Cost" + }, + "currency": { + "label": "Currency" + } } }, "Equipment": { - "itemType": { - "label": "Category" - }, - "quantity": { - "label": "Quantity" - }, - "slots": { - "label": "Slots" - }, - "rarity": { - "label": "Rarity" - }, - "lightRadius": { - "label": "Light Radius (ft)" - }, - "cost": { - "label": "Cost" - }, - "currency": { - "label": "Currency" + "FIELDS": { + "itemType": { + "label": "Category" + }, + "quantity": { + "label": "Quantity" + }, + "slots": { + "label": "Slots" + }, + "rarity": { + "label": "Rarity" + }, + "lightRadius": { + "label": "Light Radius (ft)" + }, + "cost": { + "label": "Cost" + }, + "currency": { + "label": "Currency" + } } }, "Spell": { - "tradition": { - "label": "Tradition" - }, - "difficultyValue": { - "label": "Difficulty Value (DV)" - }, - "isRitual": { - "label": "Ritual" - }, - "isMagicMissile": { - "label": "Magic Missile" - }, - "range": { - "label": "Range" - }, - "duration": { - "label": "Duration" - }, - "spellSave": { - "label": "Spell Save" - }, - "element": { - "label": "Element" - }, - "runeType": { - "label": "Rune Type" - }, - "isExalted": { - "label": "Exalted" + "FIELDS": { + "tradition": { + "label": "Tradition" + }, + "difficultyValue": { + "label": "Difficulty Value (DV)" + }, + "isRitual": { + "label": "Ritual" + }, + "isMagicMissile": { + "label": "Magic Missile" + }, + "range": { + "label": "Range" + }, + "duration": { + "label": "Duration" + }, + "spellSave": { + "label": "Spell Save" + }, + "element": { + "label": "Element" + }, + "runeType": { + "label": "Rune Type" + }, + "isExalted": { + "label": "Exalted" + }, + "effect": { + "label": "Effect" + } } }, "Miracle": { - "divineTradition": { - "label": "Divine Tradition" - }, - "difficultyValue": { - "label": "Difficulty Value (DV)" - }, - "isRitual": { - "label": "Ritual" - }, - "range": { - "label": "Range" - }, - "duration": { - "label": "Duration" - }, - "spellSave": { - "label": "Spell Save" + "FIELDS": { + "divineTradition": { + "label": "Divine Tradition" + }, + "difficultyValue": { + "label": "Difficulty Value (DV)" + }, + "isRitual": { + "label": "Ritual" + }, + "range": { + "label": "Range" + }, + "duration": { + "label": "Duration" + }, + "spellSave": { + "label": "Spell Save" + }, + "effect": { + "label": "Effect" + } } }, "MagicItem": { - "itemType": { - "label": "Type" - }, - "quality": { - "label": "Quality" - }, - "isCursed": { - "label": "Cursed" - }, - "isBonded": { - "label": "Bonded" - }, - "classRestriction": { - "label": "Restriction" - }, - "usagePeriod": { - "label": "Usage Period" - }, - "maxUses": { - "label": "Max Uses" - }, - "slots": { - "label": "Slots" - }, - "equipped": { - "label": "Equipped" + "FIELDS": { + "itemType": { + "label": "Type" + }, + "quality": { + "label": "Quality" + }, + "isCursed": { + "label": "Cursed" + }, + "isBonded": { + "label": "Bonded" + }, + "classRestriction": { + "label": "Restriction" + }, + "usagePeriod": { + "label": "Usage Period" + }, + "maxUses": { + "label": "Max Uses" + }, + "slots": { + "label": "Slots" + }, + "equipped": { + "label": "Equipped" + }, + "effect": { + "label": "Effect" + } } }, "Ability": { - "abilityType": { - "label": "Type" - }, - "source": { - "label": "Source (Class / Lineage)" - }, - "usagePeriod": { - "label": "Usage Period" - }, - "maxUses": { - "label": "Max Uses" + "FIELDS": { + "abilityType": { + "label": "Type" + }, + "source": { + "label": "Source (Class / Lineage)" + }, + "usagePeriod": { + "label": "Usage Period" + }, + "maxUses": { + "label": "Max Uses" + }, + "description": { + "label": "Description" + } } }, "WeaponGroup": { @@ -574,6 +685,43 @@ "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" } } -} +} \ No newline at end of file diff --git a/less/actor-sheet.less b/less/actor-sheet.less index 89c9a52..5fcbe4d 100644 --- a/less/actor-sheet.less +++ b/less/actor-sheet.less @@ -41,9 +41,15 @@ .character-resource { display: flex; align-items: center; + flex-wrap: nowrap; gap: 4px; margin-bottom: 2px; + // formInput renders a
— flatten it so it doesn't break flex row + div.form-group { + display: contents; + } + input { min-width: 2.5rem; max-width: 2.5rem; diff --git a/less/base.less b/less/base.less index 4ac0c63..f17193d 100644 --- a/less/base.less +++ b/less/base.less @@ -29,7 +29,7 @@ // Global dialog styling .application.dialog.oathhammer { - font-family: @font-primary; + font-family: @font-body; font-size: @font-size-base; .sheet-background(); } @@ -37,11 +37,12 @@ // Shared actor content base .oathhammer .character-content, .oathhammer .npc-content { - font-family: @font-primary; + font-family: @font-body; // Calibri — standard text per design_rules.md font-size: @font-size-base; color: var(--color-dark-1); .sheet-background(); overflow: auto; + padding: 10px 20px; // Inner margin so content clears the parchment border nav.tabs [data-tab] { color: @color-olive; @@ -63,9 +64,10 @@ color: @color-dark; } + // Character/NPC name — decorative title font input[name="name"] { height: 2.5rem; - font-family: @font-secondary; + font-family: @font-primary; // Sherwood — decorative title font-size: @font-size-xl; font-weight: bold; border: none; @@ -80,7 +82,7 @@ } legend { - font-family: @font-secondary; + font-family: @font-secondary; // BlueDragon — section headers font-size: @font-size-lg; font-weight: bold; letter-spacing: 1px; @@ -88,7 +90,7 @@ } label { - font-family: @font-secondary; + font-family: @font-secondary; // BlueDragon — UI labels font-size: @font-size-base; color: @color-dark; } @@ -98,3 +100,58 @@ .oathhammer .tab { 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; + } + } +} diff --git a/less/item-sheets.less b/less/item-sheets.less index 3c0d543..8538a89 100644 --- a/less/item-sheets.less +++ b/less/item-sheets.less @@ -4,7 +4,8 @@ .oathhammer .item-sheet-common { 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; .sheet-background(); @@ -15,6 +16,11 @@ margin-bottom: 8px; padding-bottom: 4px; border-bottom: 2px solid @color-blue; + + // Item name input — decorative title font + input[name="name"] { + font-family: @font-primary; // Sherwood — decorative title + } } .item-img { @@ -26,33 +32,70 @@ object-fit: cover; } + // Override Foundry dark-theme input/select backgrounds for parchment look + input:not([type="checkbox"]), + select { + height: 1.5rem; + background-color: @color-input-bg; + border-color: @color-blue; + 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 { + font-family: @font-secondary; + font-size: @font-size-base; + color: @color-dark; + } + .form-group { display: flex; - flex: 1; flex-direction: row; align-items: center; - gap: 4px; - margin-bottom: 2px; + gap: 6px; + margin-bottom: 4px; - label { + & > label { + flex: 0 0 8rem; // Fixed label width, no grow/shrink font-family: @font-secondary; font-size: @font-size-base; - min-width: @label-min-width; - max-width: @label-min-width; + color: @color-dark; } - select, - input { - text-align: left; - min-width: @input-min-width; - max-width: @input-max-width; + .form-fields { + flex: 1; + min-width: 0; + + input:not([type="checkbox"]), + select { + width: 100%; + box-sizing: border-box; + } } } .align-top { + flex: 1; + min-width: 0; align-self: flex-start; - padding: 0.2rem; - min-width: 260px; + padding: 0 0.3rem; } .shift-right { diff --git a/less/variables.less b/less/variables.less index 8232027..76670ec 100644 --- a/less/variables.less +++ b/less/variables.less @@ -8,16 +8,18 @@ @font-body: "Calibri", "Segoe UI", sans-serif; @font-size-base: 0.82rem; -// Colors -@color-blue: #1a4a7a; -@color-olive: #5a5a2a; +// Colors — from design_rules.md (CMYK converted to RGB) +// Blue: CMYK(94, 42, 9, 50) → rgb(8, 74, 116) +// Olive: CMYK(26, 28, 64, 56) → rgb(83, 81, 40) +@color-blue: #084a74; +@color-olive: #535128; @color-gold: #c8a84b; @color-dark: #2a1a0a; @color-paper: #f5ead0; -// Derived -@color-olive-faint: rgba(90, 90, 42, 0.2); -@color-blue-hover: rgba(26, 74, 122, 0.08); +// Derived — using LESS fade() to keep colors in sync with variables +@color-olive-faint: fade(@color-olive, 20%); +@color-blue-hover: fade(@color-blue, 8%); @color-input-bg: rgba(255, 255, 255, 0.3); @color-disabled-bg: rgba(0, 0, 0, 0.08); diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 663bcb1..287fa5b 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -1,4 +1,5 @@ import OathHammerActorSheet from "./base-actor-sheet.mjs" +import { SYSTEM } from "../../config/system.mjs" export default class OathHammerCharacterSheet extends OathHammerActorSheet { /** @override */ @@ -21,27 +22,14 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet { /** @override */ static PARTS = { - main: { - 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", - }, - 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", - }, + main: { 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" }, + skills: { template: "systems/fvtt-oath-hammer/templates/actor/character-skills.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 */ @@ -51,11 +39,12 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet { #getTabs() { const tabs = { - identity: { id: "identity", group: "sheet", icon: "fa-solid fa-person", label: "OATHHAMMER.Tab.Identity" }, - 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" }, - equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-backpack", label: "OATHHAMMER.Tab.Equipment" }, - notes: { id: "notes", group: "sheet", icon: "fa-solid fa-book", label: "OATHHAMMER.Tab.Notes" }, + 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" }, + 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" }, + notes: { id: "notes", group: "sheet", icon: "fa-solid fa-book", label: "OATHHAMMER.Tab.Notes" }, } for (const v of Object.values(tabs)) { v.active = this.tabGroups[v.group] === v.id @@ -82,6 +71,33 @@ export default class OathHammerCharacterSheet extends OathHammerActorSheet { context.abilities = doc.itemTypes.ability context.oaths = doc.itemTypes.oath 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": context.tab = context.tabs.combat context.weapons = doc.itemTypes.weapon diff --git a/module/config/system.mjs b/module/config/system.mjs index 1b2da71..6bd51b8 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -279,6 +279,46 @@ export const STATUS_EFFECTS = [ 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 = ` ················································· : ___ _ _ _ _ : @@ -293,6 +333,8 @@ export const ASCII = ` export const SYSTEM = { id: SYSTEM_ID, ATTRIBUTES, + SKILLS, + SKILLS_BY_ATTRIBUTE, LINEAGE_CHOICES, CLASS_CHOICES, OATH_TYPES, diff --git a/module/models/character.mjs b/module/models/character.mjs index 6fef1e1..de1bc75 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -21,13 +21,48 @@ export default class OathHammerCharacter extends foundry.abstract.TypeDataModel fate: attributeField() }) + // Skills: 26 skills each with a rank (0–4). 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({ value: 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({ - 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({ @@ -77,7 +112,11 @@ export default class OathHammerCharacter extends foundry.abstract.TypeDataModel 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 } } diff --git a/templates/actor/character-combat.hbs b/templates/actor/character-combat.hbs index d4a5bef..8b1d674 100644 --- a/templates/actor/character-combat.hbs +++ b/templates/actor/character-combat.hbs @@ -1,4 +1,4 @@ -
+
{{localize "OATHHAMMER.Label.Defense"}}
diff --git a/templates/actor/character-equipment.hbs b/templates/actor/character-equipment.hbs index 8ede981..0d96421 100644 --- a/templates/actor/character-equipment.hbs +++ b/templates/actor/character-equipment.hbs @@ -1,4 +1,4 @@ -
+
{{localize "OATHHAMMER.Label.Equipment"}} {{#unless isPlayMode}}{{/unless}} diff --git a/templates/actor/character-identity.hbs b/templates/actor/character-identity.hbs index 96b5580..58ce2e7 100644 --- a/templates/actor/character-identity.hbs +++ b/templates/actor/character-identity.hbs @@ -1,4 +1,4 @@ -
+
{{localize "OATHHAMMER.Label.Biodata"}}
diff --git a/templates/actor/character-magic.hbs b/templates/actor/character-magic.hbs index 546e5d3..1727f53 100644 --- a/templates/actor/character-magic.hbs +++ b/templates/actor/character-magic.hbs @@ -1,4 +1,4 @@ -
+
{{localize "OATHHAMMER.Label.ArcaneStress"}}
diff --git a/templates/actor/character-notes.hbs b/templates/actor/character-notes.hbs index 4852ca4..f792826 100644 --- a/templates/actor/character-notes.hbs +++ b/templates/actor/character-notes.hbs @@ -1,4 +1,4 @@ -
+
{{localize "OATHHAMMER.Label.Description"}} {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} diff --git a/templates/actor/character-sheet.hbs b/templates/actor/character-sheet.hbs index 393178d..72d6c72 100644 --- a/templates/actor/character-sheet.hbs +++ b/templates/actor/character-sheet.hbs @@ -16,6 +16,8 @@
{{localize "OATHHAMMER.Label.Luck"}} {{formInput systemFields.luck.fields.value value=system.luck.value name="system.luck.value" disabled=isPlayMode}} + / + {{formInput systemFields.luck.fields.max value=system.luck.max name="system.luck.max" disabled=isPlayMode}}
{{localize "OATHHAMMER.Label.Defense"}} @@ -40,7 +42,7 @@ {{#each system.attributes as |attr key|}}
- {{formInput (lookup ../systemFields.attributes.fields key).fields.rank value=attr.rank name=(concat "system.attributes." key ".rank") disabled=../isPlayMode}} +
{{/each}}
diff --git a/templates/actor/character-skills.hbs b/templates/actor/character-skills.hbs new file mode 100644 index 0000000..aad1c88 --- /dev/null +++ b/templates/actor/character-skills.hbs @@ -0,0 +1,28 @@ +
+
+ {{#each skillGroups as |group|}} +
+ + {{localize group.label}} + ({{group.attrRank}}) + +
+
+ {{localize "OATHHAMMER.Label.Skill"}} + {{localize "OATHHAMMER.Label.SkillRank"}} + {{localize "OATHHAMMER.Label.TotalDice"}} +
+ {{#each group.skillData as |skill|}} +
+ +
+ {{formInput skill.field value=skill.rank name=skill.name disabled=../../isPlayMode}} +
+ {{skill.total}} +
+ {{/each}} +
+
+ {{/each}} +
+
diff --git a/templates/item/miracle-sheet.hbs b/templates/item/miracle-sheet.hbs index 933d541..4a34245 100644 --- a/templates/item/miracle-sheet.hbs +++ b/templates/item/miracle-sheet.hbs @@ -5,20 +5,14 @@
- {{formField systemFields.piety value=system.piety name="system.piety"}} - {{formField systemFields.castingTime value=system.castingTime name="system.castingTime"}} + {{formField systemFields.divineTradition value=system.divineTradition name="system.divineTradition" localize=true}} + {{formField systemFields.difficultyValue value=system.difficultyValue name="system.difficultyValue"}} {{formField systemFields.range value=system.range name="system.range"}} {{formField systemFields.duration value=system.duration name="system.duration"}} + {{formField systemFields.spellSave value=system.spellSave name="system.spellSave"}}
- -
- {{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"}} -
- {{formField systemFields.materialComponent value=system.materialComponent name="system.materialComponent"}} - {{formField systemFields.savingThrow value=system.savingThrow name="system.savingThrow"}} + {{formField systemFields.isRitual value=system.isRitual name="system.isRitual"}}
diff --git a/templates/item/spell-sheet.hbs b/templates/item/spell-sheet.hbs index 38074fe..ce8de5d 100644 --- a/templates/item/spell-sheet.hbs +++ b/templates/item/spell-sheet.hbs @@ -6,22 +6,17 @@
{{formField systemFields.tradition value=system.tradition name="system.tradition" localize=true}} - {{formField systemFields.level value=system.level name="system.level"}} - {{formField systemFields.arcaneStress value=system.arcaneStress name="system.arcaneStress"}} - {{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.duration value=system.duration name="system.duration"}} + {{formField systemFields.spellSave value=system.spellSave name="system.spellSave"}}
- -
- {{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"}} -
- {{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"}} + {{formField systemFields.isRitual value=system.isRitual name="system.isRitual"}} + {{formField systemFields.isMagicMissile value=system.isMagicMissile name="system.isMagicMissile"}} + {{formField systemFields.isExalted value=system.isExalted name="system.isExalted"}} + {{formField systemFields.element value=system.element name="system.element" localize=true}} + {{formField systemFields.runeType value=system.runeType name="system.runeType" localize=true}}