diff --git a/module/Apps/ActorSheets/CombinedHeroSheet.mjs b/module/Apps/ActorSheets/CombinedHeroSheet.mjs index 8ca46db..974269b 100644 --- a/module/Apps/ActorSheets/CombinedHeroSheet.mjs +++ b/module/Apps/ActorSheets/CombinedHeroSheet.mjs @@ -80,6 +80,7 @@ export class CombinedHeroSheet extends GenericAppMixin(HandlebarsApplicationMixi ctx = await HeroSkillsCardV1.prepareGear(ctx); ctx = await HeroSkillsCardV1.prepareAmmo(ctx); + ctx = await HeroSkillsCardV1.prepareSkills(ctx); Logger.debug(`Context:`, ctx); return ctx; diff --git a/module/Apps/ActorSheets/HeroSkillsCardV1.mjs b/module/Apps/ActorSheets/HeroSkillsCardV1.mjs index 9d406bc..608d921 100644 --- a/module/Apps/ActorSheets/HeroSkillsCardV1.mjs +++ b/module/Apps/ActorSheets/HeroSkillsCardV1.mjs @@ -1,5 +1,5 @@ import { deleteItemFromElement, editItemFromElement } from "../utils.mjs"; -import { filePath } from "../../consts.mjs"; +import { documentSorter, filePath } from "../../consts.mjs"; import { gameTerms } from "../../gameTerms.mjs"; import { GenericAppMixin } from "../GenericApp.mjs"; import { localizer } from "../../utils/Localizer.mjs"; @@ -52,7 +52,7 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin } = options; new ContextMenu( element, - `[data-ctx-menu="gear"]`, + `[data-ctx-menu="gear"],[data-ctx-menu="skill"]`, [ { name: localizer(`RipCrypt.common.edit`), @@ -81,6 +81,7 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin ctx = await HeroSkillsCardV1.prepareGear(ctx); ctx = await HeroSkillsCardV1.prepareAmmo(ctx); + ctx = await HeroSkillsCardV1.prepareSkills(ctx); Logger.debug(`Context:`, ctx); return ctx; @@ -122,6 +123,48 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin ctx.ammo = 0; return ctx; }; + + static async prepareSkills(ctx) { + ctx.skills = {}; + const abilities = Object.values(gameTerms.Abilities); + const heroRank = ctx.actor.system.level.rank; + const embeddedSkills = ctx.actor.itemTypes.skill.sort(documentSorter); + + for (let ability of abilities) { + const skills = []; + for (const skill of embeddedSkills) { + if (skill.system.ability !== ability) { continue }; + skills.push({ + uuid: skill.uuid, + name: skill.name, + use: skill.system.advances[heroRank], + }); + }; + + // Thin Glim is grouped with full glim. + if (ability === gameTerms.Abilities.THINGLIM) { + ability = gameTerms.Abilities.GLIM; + }; + + ctx.skills[ability] ??= []; + ctx.skills[ability].push(...skills); + }; + + const limit = ctx.actor.system.limit.skills; + for (const ability of abilities) { + if (ctx.skills[ability] == null) { continue }; + + const length = ctx.skills[ability].length; + if (length >= limit) { + ctx.skills[ability] = ctx.skills[ability].slice(0, limit); + } else { + ctx.skills[ability] = ctx.skills[ability] + .concat(Array(limit - length).fill(null)) + .slice(0, limit); + }; + } + return ctx; + }; // #endregion // #region Actions diff --git a/module/api.mjs b/module/api.mjs index 97af86f..99719b5 100644 --- a/module/api.mjs +++ b/module/api.mjs @@ -1,8 +1,12 @@ +// App imports import { CombinedHeroSheet } from "./Apps/ActorSheets/CombinedHeroSheet.mjs"; import { DicePool } from "./Apps/DicePool.mjs"; import { HeroSkillsCardV1 } from "./Apps/ActorSheets/HeroSkillsCardV1.mjs"; import { HeroSummaryCardV1 } from "./Apps/ActorSheets/HeroSummaryCardV1.mjs"; +// Util imports +import { documentSorter } from "./consts.mjs"; + const { deepFreeze } = foundry.utils; Object.defineProperty( @@ -16,6 +20,9 @@ Object.defineProperty( HeroSummaryCardV1, HeroSkillsCardV1, }, + utils: { + documentSorter, + }, }), writable: false, }, diff --git a/module/consts.mjs b/module/consts.mjs index dc5d000..a3242a2 100644 --- a/module/consts.mjs +++ b/module/consts.mjs @@ -5,3 +5,13 @@ export function filePath(path) { }; return `systems/ripcrypt/${path}`; }; + +// MARK: documentSorter +export function documentSorter(a, b) { + const sortDelta = b.sort - a.sort; + if (sortDelta !== 0) { + return sortDelta; + }; + // TODO alphabetical sort + return 0; +}; diff --git a/module/data/Actor/Hero.mjs b/module/data/Actor/Hero.mjs index da9a775..6f2e3ed 100644 --- a/module/data/Actor/Hero.mjs +++ b/module/data/Actor/Hero.mjs @@ -132,6 +132,7 @@ export class HeroData extends foundry.abstract.TypeDataModel { this.limit = { weapons: 4, equipment: 12, + skills: 4, }; }; diff --git a/module/data/Item/Skill.mjs b/module/data/Item/Skill.mjs index c02351a..49df190 100644 --- a/module/data/Item/Skill.mjs +++ b/module/data/Item/Skill.mjs @@ -2,19 +2,17 @@ import { gameTerms } from "../../gameTerms.mjs"; const { fields } = foundry.data; -const abilityPaths = [`grit`, `gait`, `grip`, `glim`, `thin-glim`]; - export class SkillData extends foundry.abstract.TypeDataModel { // MARK: Schema static defineSchema() { const schema = { ability: new fields.StringField({ - initial: abilityPaths[0], + initial: gameTerms.Abilities.GRIT, blank: true, trim: true, nullable: false, required: true, - choices: () => abilityPaths, + choices: () => Object.values(gameTerms.Abilities), }), }; @@ -53,7 +51,7 @@ export class SkillData extends foundry.abstract.TypeDataModel { label: `RipCrypt.common.ability`, path: `system.ability`, value: this.ability, - options: abilityPaths.map(ability => ({ + options: Object.values(gameTerms.Abilities).map(ability => ({ label: `RipCrypt.common.abilities.${ability}`, value: ability, })), diff --git a/module/gameTerms.mjs b/module/gameTerms.mjs index 3406baf..eccaa94 100644 --- a/module/gameTerms.mjs +++ b/module/gameTerms.mjs @@ -1,4 +1,11 @@ export const gameTerms = Object.preventExtensions({ + Abilities: Object.freeze({ + GRIT: `grit`, + GRIP: `grip`, + GAIT: `gait`, + GLIM: `glim`, + THINGLIM: `thin-glim`, + }), FatePath: [ `North`, `East`, diff --git a/templates/Apps/HeroSkillsCardV1/content.hbs b/templates/Apps/HeroSkillsCardV1/content.hbs index 62b3c5b..8a6a829 100644 --- a/templates/Apps/HeroSkillsCardV1/content.hbs +++ b/templates/Apps/HeroSkillsCardV1/content.hbs @@ -4,10 +4,22 @@ {{ rc-i18n "RipCrypt.common.rank" }}
    -
  1. -
  2. -
  3. -
  4. + {{#each skills.grit as | skill |}} + {{#if skill}} +
  5. + {{ skill.name }} + +
  6. + {{else}} +
  7. + {{/if}} + {{/each}}
@@ -15,10 +27,22 @@ {{ rc-i18n "RipCrypt.common.rank" }}
    -
  1. -
  2. -
  3. -
  4. + {{#each skills.gait as | skill |}} + {{#if skill}} +
  5. + {{ skill.name }} + +
  6. + {{else}} +
  7. + {{/if}} + {{/each}}
@@ -26,10 +50,22 @@ {{ rc-i18n "RipCrypt.common.rank" }}
    -
  1. -
  2. -
  3. -
  4. + {{#each skills.grip as | skill |}} + {{#if skill}} +
  5. + {{ skill.name }} + +
  6. + {{else}} +
  7. + {{/if}} + {{/each}}
@@ -37,10 +73,22 @@ {{ rc-i18n "RipCrypt.common.rank" }}
    -
  1. -
  2. -
  3. -
  4. + {{#each skills.glim as | skill |}} + {{#if skill}} +
  5. + {{ skill.name }} + +
  6. + {{else}} +
  7. + {{/if}} + {{/each}}
diff --git a/templates/Apps/HeroSkillsCardV1/style.css b/templates/Apps/HeroSkillsCardV1/style.css index c9a28bc..9c092ca 100644 --- a/templates/Apps/HeroSkillsCardV1/style.css +++ b/templates/Apps/HeroSkillsCardV1/style.css @@ -41,7 +41,10 @@ grid-template-rows: subgrid; & > li { - padding-left: 4px; + padding: 0 4px; + .name { + flex-grow: 1; + } } &.even > :nth-child(even),