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

View File

@@ -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

View File

@@ -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,

View File

@@ -21,13 +21,48 @@ export default class OathHammerCharacter extends foundry.abstract.TypeDataModel
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({
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
}
}