diff --git a/src/module/actor/actions/single-check.ts b/src/module/actor/actions/single-check.ts index f4b958de49a..f29b12c26cf 100644 --- a/src/module/actor/actions/single-check.ts +++ b/src/module/actor/actions/single-check.ts @@ -1,7 +1,7 @@ import { ActorPF2e } from "@actor"; import { ModifierPF2e, RawModifier, StatisticModifier } from "@actor/modifiers.ts"; import { DCSlug } from "@actor/types.ts"; -import { SAVE_TYPES, SKILL_SLUGS } from "@actor/values.ts"; +import { SAVE_TYPES } from "@actor/values.ts"; import type { ItemPF2e } from "@item"; import { TokenPF2e } from "@module/canvas/index.ts"; import { RollNotePF2e, RollNoteSource } from "@module/notes.ts"; @@ -14,7 +14,7 @@ import { CheckResultCallback, } from "@system/action-macros/types.ts"; import { CheckDC } from "@system/degree-of-success.ts"; -import { getActionGlyph, isObject, setHasElement, tupleHasValue } from "@util"; +import { getActionGlyph, isObject, tupleHasValue } from "@util"; import { BaseAction, BaseActionData, BaseActionVariant, BaseActionVariantData } from "./base.ts"; import { ActionUseOptions } from "./types.ts"; @@ -31,9 +31,7 @@ function isValidDifficultyClass(dc: unknown): dc is CheckDC | DCSlug { const slug = String(dc); return ( - ["ac", "armor", "perception"].includes(slug) || - tupleHasValue(SAVE_TYPES, slug) || - setHasElement(SKILL_SLUGS, slug) + ["ac", "armor", "perception"].includes(slug) || tupleHasValue(SAVE_TYPES, slug) || slug in CONFIG.PF2E.skills ); } diff --git a/src/module/actor/character/document.ts b/src/module/actor/character/document.ts index 721a2ba1ed2..a42ac67c321 100644 --- a/src/module/actor/character/document.ts +++ b/src/module/actor/character/document.ts @@ -25,7 +25,7 @@ import { import { CheckContext } from "@actor/roll-context/check.ts"; import { DamageContext } from "@actor/roll-context/damage.ts"; import { AttributeString, MovementType, SkillSlug } from "@actor/types.ts"; -import { ATTRIBUTE_ABBREVIATIONS, SAVE_TYPES, SKILL_EXPANDED, SKILL_SLUGS } from "@actor/values.ts"; +import { ATTRIBUTE_ABBREVIATIONS, SAVE_TYPES } from "@actor/values.ts"; import type { AncestryPF2e, BackgroundPF2e, @@ -407,9 +407,8 @@ class CharacterPF2e { + system.skills = R.mapToObj(R.entries.strict(CONFIG.PF2E.skills), ([key, { attribute }]) => { const rank = Math.clamp(this._source.system.skills[key]?.rank || 0, 0, 4) as ZeroToFour; - const attribute = SKILL_EXPANDED[key].attribute; return [key, { rank, attribute, armor: ["dex", "str"].includes(attribute) }]; }); @@ -741,7 +740,7 @@ class CharacterPF2e { + this.skills = R.mapToObj(R.entries.strict(CONFIG.PF2E.skills), ([skillSlug, { label, attribute }]) => { const skill = system.skills[skillSlug]; - const label = CONFIG.PF2E.skillList[skillSlug] ?? skillSlug; - - const domains = [ - skillSlug, - `${skill.attribute}-based`, - "skill-check", - `${skill.attribute}-skill-check`, - "all", - ]; + + const domains = [skillSlug, `${attribute}-based`, "skill-check", `${attribute}-skill-check`, "all"]; const modifiers: ModifierPF2e[] = []; if (skill.armor && typeof wornArmor?.strength === "number" && wornArmor.checkPenalty < 0) { @@ -932,7 +924,7 @@ class CharacterPF2e>, skill) => { + this.skills = R.mapToObj(R.entries.strict(CONFIG.PF2E.skills), ([skill, { label, attribute }]) => { const modifiers = [new ModifierPF2e("PF2E.MasterLevel", masterLevel, "untyped")]; if (["acrobatics", "stealth"].includes(skill)) { modifiers.push(attributeModifier); } - const attribute = SKILL_EXPANDED[skill].attribute; const domains = [skill, `${attribute}-based`, "skill-check", "all"]; - - const label = CONFIG.PF2E.skillList[skill] ?? skill; const statistic = new Statistic(this, { slug: skill, label, @@ -243,11 +240,11 @@ class FamiliarPF2e { + this.skills = R.mapToObj(R.entries.strict(CONFIG.PF2E.skills), ([skillSlug, { attribute, label }]) => { const skill = this._source.system.skills[skillSlug]; - const attribute = SKILL_EXPANDED[skillSlug].attribute; - const label = CONFIG.PF2E.skillList[skillSlug] ?? skillSlug; const domains = [skillSlug, `${attribute}-based`, "skill-check", `${attribute}-skill-check`, "all"]; // Get predicated variants as modifiers that trigger when the predicate is met diff --git a/src/module/actor/npc/sheet.ts b/src/module/actor/npc/sheet.ts index d3d44aa789b..c3922142fc5 100644 --- a/src/module/actor/npc/sheet.ts +++ b/src/module/actor/npc/sheet.ts @@ -201,7 +201,7 @@ class NPCSheetPF2e extends AbstractNPCSheet { const data = this.actor.identificationDCs; const skills = data.skills.length > 0 - ? localizeList(data.skills.map((s) => game.i18n.localize(CONFIG.PF2E.skillList[s]))) + ? localizeList(data.skills.map((s) => game.i18n.localize(CONFIG.PF2E.skills[s].label))) : null; return { standard: skills diff --git a/src/module/actor/npc/skills-editor.ts b/src/module/actor/npc/skills-editor.ts index f971ed9acfa..9ed01d125d4 100644 --- a/src/module/actor/npc/skills-editor.ts +++ b/src/module/actor/npc/skills-editor.ts @@ -1,8 +1,7 @@ import type { NPCPF2e } from "@actor"; import { NPCSkillData, NPCSource } from "@actor/npc/data.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; import { LoreSource } from "@item/base/data/index.ts"; -import { htmlClosest, htmlQuery, htmlQueryAll, setHasElement } from "@util"; +import { htmlClosest, htmlQuery, htmlQueryAll, objectHasKey } from "@util"; /** Specialized form to setup skills for an NPC character. */ export class NPCSkillsEditor extends DocumentSheet { @@ -49,7 +48,7 @@ export class NPCSkillsEditor extends DocumentSheet { htmlQuery(html, "button[data-action=add-skill]")?.addEventListener("click", async (event) => { const slug = htmlQuery(htmlClosest(event.currentTarget, ".skill-selector"), "select")?.value; - if (setHasElement(SKILL_SLUGS, slug)) { + if (slug && slug in CONFIG.PF2E.skills) { await this.actor.update({ [`system.skills.${slug}`]: { base: 0 } }); } }); @@ -69,7 +68,7 @@ export class NPCSkillsEditor extends DocumentSheet { for (const button of htmlQueryAll(html, "a[data-action=add-special-skill]")) { button.addEventListener("click", (event): void => { const skill = htmlClosest(event.target, "[data-skill]")?.dataset.skill; - if (!setHasElement(SKILL_SLUGS, skill)) return; + if (!objectHasKey(CONFIG.PF2E.skills, skill)) return; const special = fu.duplicate(this.actor._source.system.skills[skill]?.special ?? []); special.push({ label: "", base: 0 }); @@ -80,7 +79,7 @@ export class NPCSkillsEditor extends DocumentSheet { for (const button of htmlQueryAll(html, "a[data-action=remove-special-skill]")) { button.addEventListener("click", (event): void => { const skill = htmlClosest(event.target, "[data-skill]")?.dataset.skill; - if (!setHasElement(SKILL_SLUGS, skill) || !(event.currentTarget instanceof HTMLElement)) return; + if (!objectHasKey(CONFIG.PF2E.skills, skill) || !(event.currentTarget instanceof HTMLElement)) return; const index = Number(event.currentTarget.dataset.specialSkillIndex); const special = diff --git a/src/module/actor/party/sheet.ts b/src/module/actor/party/sheet.ts index 4444ba7a60a..eaae69d131f 100644 --- a/src/module/actor/party/sheet.ts +++ b/src/module/actor/party/sheet.ts @@ -6,7 +6,6 @@ import { ActorSheetPF2e } from "@actor/sheet/base.ts"; import { ActorSheetDataPF2e, ActorSheetRenderOptionsPF2e } from "@actor/sheet/data-types.ts"; import { condenseSenses } from "@actor/sheet/helpers.ts"; import { DistributeCoinsPopup } from "@actor/sheet/popups/distribute-coins-popup.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; import { ItemPF2e } from "@item"; import { ItemSourcePF2e } from "@item/base/data/index.ts"; import { Bulk } from "@item/physical/index.ts"; @@ -234,9 +233,8 @@ class PartySheetPF2e extends ActorSheetPF2e { (l) => l.label, ), skills: R.sortBy( - Array.from(SKILL_SLUGS).map((slug): SkillData => { + Object.entries(CONFIG.PF2E.skills).map(([slug, { label }]): SkillData => { const best = getBestSkill(slug); - const label = game.i18n.localize(CONFIG.PF2E.skillList[slug]); return best ?? { mod: 0, label, slug, rank: 0 }; }), (s) => s.label, diff --git a/src/module/actor/sheet/popups/recall-knowledge-popup.ts b/src/module/actor/sheet/popups/recall-knowledge-popup.ts index abd572c49c9..809d69e5824 100644 --- a/src/module/actor/sheet/popups/recall-knowledge-popup.ts +++ b/src/module/actor/sheet/popups/recall-knowledge-popup.ts @@ -25,7 +25,9 @@ export class RecallKnowledgePopup extends Application { return { standard: { - label: localizeList(identificationData.skills.map((s) => game.i18n.localize(CONFIG.PF2E.skillList[s]))), + label: localizeList( + identificationData.skills.map((s) => game.i18n.localize(CONFIG.PF2E.skills[s].label)), + ), attempts: this.#padAttempts(identificationData.standard.progression), }, loreEasy: this.#padAttempts(identificationData.lore[0].progression), diff --git a/src/module/actor/types.ts b/src/module/actor/types.ts index dffa9ea89f5..2b2c4d9b279 100644 --- a/src/module/actor/types.ts +++ b/src/module/actor/types.ts @@ -13,9 +13,9 @@ import type { Predicate } from "@system/predication.ts"; import type { ACTOR_TYPES, ATTRIBUTE_ABBREVIATIONS, + CORE_SKILL_SLUGS, MOVEMENT_TYPES, SAVE_TYPES, - SKILL_SLUGS, UNAFFECTED_TYPES, } from "./values.ts"; @@ -45,7 +45,7 @@ interface ActorDimensions { height: number; } -type SkillSlug = SetElement; +type SkillSlug = SetElement; type ActorAlliance = "party" | "opposition" | null; diff --git a/src/module/actor/values.ts b/src/module/actor/values.ts index aac0e8037f1..c358c834213 100644 --- a/src/module/actor/values.ts +++ b/src/module/actor/values.ts @@ -1,4 +1,4 @@ -import { AttributeString, ImmunityType, ResistanceType, SkillSlug, WeaknessType } from "@actor/types.ts"; +import type { ImmunityType, ResistanceType, WeaknessType } from "@actor/types.ts"; import { immunityTypes, resistanceTypes, weaknessTypes } from "@scripts/config/iwr.ts"; const ATTRIBUTE_ABBREVIATIONS = new Set(["str", "dex", "con", "int", "wis", "cha"] as const); @@ -17,7 +17,8 @@ const RESISTANCE_TYPES = new Set(Object.keys(resistanceTypes)) as Set = { - acrobatics: { attribute: "dex" }, - arcana: { attribute: "int" }, - athletics: { attribute: "str" }, - crafting: { attribute: "int" }, - deception: { attribute: "cha" }, - diplomacy: { attribute: "cha" }, - intimidation: { attribute: "cha" }, - medicine: { attribute: "wis" }, - nature: { attribute: "wis" }, - occultism: { attribute: "int" }, - performance: { attribute: "cha" }, - religion: { attribute: "wis" }, - society: { attribute: "int" }, - stealth: { attribute: "dex" }, - survival: { attribute: "wis" }, - thievery: { attribute: "dex" }, -}; - const MOVEMENT_TYPES = ["land", "burrow", "climb", "fly", "swim"] as const; /** Actor types that are valid for token size linking */ @@ -67,14 +45,13 @@ const SIZE_LINKABLE_ACTOR_TYPES = new Set([...CREATURE_ACTOR_TYPES, "vehicle"]); export { ACTOR_TYPES, ATTRIBUTE_ABBREVIATIONS, + CORE_SKILL_SLUGS, CREATURE_ACTOR_TYPES, IMMUNITY_TYPES, MOVEMENT_TYPES, RESISTANCE_TYPES, SAVE_TYPES, SIZE_LINKABLE_ACTOR_TYPES, - SKILL_EXPANDED, - SKILL_SLUGS, UNAFFECTED_TYPES, WEAKNESS_TYPES, }; diff --git a/src/module/apps/compendium-browser/tabs/base.ts b/src/module/apps/compendium-browser/tabs/base.ts index d9be45c0afc..4f0bca28eb0 100644 --- a/src/module/apps/compendium-browser/tabs/base.ts +++ b/src/module/apps/compendium-browser/tabs/base.ts @@ -1,6 +1,7 @@ import { CompendiumDirectoryPF2e } from "@module/apps/sidebar/compendium-directory.ts"; import { ErrorPF2e, htmlQuery, sluggify } from "@util"; import MiniSearch from "minisearch"; +import * as R from "remeda"; import type { TableResultSource } from "types/foundry/common/documents/table-result.d.ts"; import { BrowserTabs, ContentTabName } from "../data.ts"; import { CompendiumBrowser } from "../index.ts"; @@ -222,16 +223,12 @@ export abstract class CompendiumBrowserTab { } /** Generates a localized and sorted CheckBoxOptions object from config data */ - protected generateCheckboxOptions(configData: Record, sort = true): CheckboxOptions { - // Localize labels for sorting - const localized = Object.entries(configData).reduce( - (result: Record, [key, label]) => ({ - ...result, - [key]: game.i18n.localize(label), - }), - {}, - ); - // Return localized and sorted CheckBoxOptions + protected generateCheckboxOptions( + configData: Record, + sort = true, + ): CheckboxOptions { + // Localize labels for sorting. Return localized and sorted CheckBoxOptions + const localized = R.mapValues(configData, (v) => game.i18n.localize(R.isObjectType(v) ? v.label : v)); return Object.entries(sort ? this.sortedConfig(localized) : localized).reduce( (result: CheckboxOptions, [key, label]) => ({ ...result, diff --git a/src/module/apps/compendium-browser/tabs/feat.ts b/src/module/apps/compendium-browser/tabs/feat.ts index 17146d1eaf4..29ce8015280 100644 --- a/src/module/apps/compendium-browser/tabs/feat.ts +++ b/src/module/apps/compendium-browser/tabs/feat.ts @@ -39,17 +39,6 @@ export class CompendiumBrowserFeatTab extends CompendiumBrowserTab { "system.source", ]; - const translatedSkills = Object.entries(CONFIG.PF2E.skillList).reduce( - (result: Record, [key, value]) => { - return { - ...result, - [key]: game.i18n.localize(value).toLocaleLowerCase(game.i18n.lang), - }; - }, - {}, - ); - const skillList = Object.entries(translatedSkills); - for await (const { pack, index } of this.browser.packLoader.loadPacks( "Item", this.browser.loadedPacks("feat"), @@ -87,9 +76,10 @@ export class CompendiumBrowserFeatTab extends CompendiumBrowserTab { ); const skills: Set = new Set(); for (const prereq of prerequisitesArr) { - for (const [key, value] of skillList) { + for (const [key, value] of Object.entries(CONFIG.PF2E.skills)) { // Check the string for the english translation key or a translated skill name - if (prereq.includes(key) || prereq.includes(value)) { + const translated = game.i18n.localize(value.label).toLocaleLowerCase(game.i18n.lang); + if (prereq.includes(key) || prereq.includes(translated)) { // Alawys record the translation key to enable filtering skills.add(key); } @@ -124,7 +114,7 @@ export class CompendiumBrowserFeatTab extends CompendiumBrowserTab { // Filters this.filterData.checkboxes.category.options = this.generateCheckboxOptions(CONFIG.PF2E.featCategories); - this.filterData.checkboxes.skills.options = this.generateCheckboxOptions(CONFIG.PF2E.skillList); + this.filterData.checkboxes.skills.options = this.generateCheckboxOptions(CONFIG.PF2E.skills); this.filterData.checkboxes.rarity.options = this.generateCheckboxOptions(CONFIG.PF2E.rarityTraits); this.filterData.checkboxes.source.options = this.generateSourceCheckboxOptions(publications); this.filterData.multiselects.traits.options = this.generateMultiselectOptions(CONFIG.PF2E.featTraits); diff --git a/src/module/encounter/document.ts b/src/module/encounter/document.ts index c53d0314bb6..98a598219a3 100644 --- a/src/module/encounter/document.ts +++ b/src/module/encounter/document.ts @@ -4,11 +4,9 @@ import { RollInitiativeOptionsPF2e } from "@actor/data/index.ts"; import { isReallyPC, resetActors } from "@actor/helpers.ts"; import { InitiativeRollResult } from "@actor/initiative.ts"; import { SkillSlug } from "@actor/types.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; import type { ScenePF2e, TokenDocumentPF2e } from "@scene/index.ts"; import { calculateXP } from "@scripts/macros/index.ts"; import { ThreatRating } from "@scripts/macros/xp/index.ts"; -import { setHasElement } from "@util"; import * as R from "remeda"; import type { CombatantFlags, CombatantPF2e, RolledCombatant } from "./combatant.ts"; @@ -179,7 +177,7 @@ class EncounterPF2e extends Combat { value: result.roll.total, statistic: result.roll.options.domains?.find( - (s): s is SkillSlug | "perception" => setHasElement(SKILL_SLUGS, s) || s === "perception", + (s): s is SkillSlug | "perception" => s in CONFIG.PF2E.skills || s === "perception", ) ?? null, } : [], diff --git a/src/module/item/ability/sheet.ts b/src/module/item/ability/sheet.ts index f2e778d62ad..f6482d3b6d8 100644 --- a/src/module/item/ability/sheet.ts +++ b/src/module/item/ability/sheet.ts @@ -42,7 +42,6 @@ class AbilitySheetPF2e extends ItemSheetPF2e { actionsNumber: CONFIG.PF2E.actionsNumber, actionTraits: CONFIG.PF2E.actionTraits, frequencies: CONFIG.PF2E.frequencies, - skills: CONFIG.PF2E.skillList, proficiencies: CONFIG.PF2E.proficiencyLevels, selfEffect: createSelfEffectSheetData(sheetData.data.selfEffect), }; @@ -71,7 +70,6 @@ interface ActionSheetData extends ItemSheetDataPF2e { actionsNumber: ConfigPF2e["PF2E"]["actionsNumber"]; actionTraits: ConfigPF2e["PF2E"]["actionTraits"]; frequencies: ConfigPF2e["PF2E"]["frequencies"]; - skills: ConfigPF2e["PF2E"]["skillList"]; proficiencies: ConfigPF2e["PF2E"]["proficiencyLevels"]; selfEffect: SelfEffectReference | null; } diff --git a/src/module/item/background/sheet.ts b/src/module/item/background/sheet.ts index 94fd78accd0..012c0725517 100644 --- a/src/module/item/background/sheet.ts +++ b/src/module/item/background/sheet.ts @@ -1,9 +1,9 @@ import { ItemSheetOptions } from "@item/base/sheet/sheet.ts"; import { SheetOptions, createSheetOptions } from "@module/sheet/helpers.ts"; +import { htmlQuery, htmlQueryAll } from "@util"; import { ABCSheetData, ABCSheetPF2e } from "../abc/sheet.ts"; -import type { BackgroundPF2e } from "./document.ts"; import { BackgroundSource } from "./data.ts"; -import { htmlQuery, htmlQueryAll } from "@util"; +import type { BackgroundPF2e } from "./document.ts"; export class BackgroundSheetPF2e extends ABCSheetPF2e { override async getData(options?: Partial): Promise { @@ -12,7 +12,7 @@ export class BackgroundSheetPF2e extends ABCSheetPF2e { return { ...data, - trainedSkills: createSheetOptions(CONFIG.PF2E.skillList, itemData.system.trainedSkills), + trainedSkills: createSheetOptions(CONFIG.PF2E.skills, itemData.system.trainedSkills), selectedBoosts: Object.fromEntries( Object.entries(itemData.system.boosts).map(([k, b]) => [k, this.getLocalizedAbilities(b)]), ), diff --git a/src/module/item/class/document.ts b/src/module/item/class/document.ts index 77bda5eb003..ee4bbd39893 100644 --- a/src/module/item/class/document.ts +++ b/src/module/item/class/document.ts @@ -2,13 +2,13 @@ import type { ActorPF2e, CharacterPF2e } from "@actor"; import { ClassDCData } from "@actor/character/data.ts"; import { FeatSlotCreationData } from "@actor/character/feats.ts"; import { SaveType } from "@actor/types.ts"; -import { SAVE_TYPES, SKILL_SLUGS } from "@actor/values.ts"; +import { SAVE_TYPES } from "@actor/values.ts"; import { ABCItemPF2e, FeatPF2e } from "@item"; import { ArmorCategory } from "@item/armor/index.ts"; import { ARMOR_CATEGORIES } from "@item/armor/values.ts"; import { WEAPON_CATEGORIES } from "@item/weapon/values.ts"; import { ZeroToFour } from "@module/data.ts"; -import { sluggify } from "@util"; +import { objectHasKey, sluggify } from "@util"; import * as R from "remeda"; import { ClassAttackProficiencies, ClassDefenseProficiencies, ClassSource, ClassSystemData } from "./data.ts"; import { ClassTrait } from "./types.ts"; @@ -134,7 +134,7 @@ class ClassPF2e extends ABC } for (const trainedSkill of this.system.trainedSkills.value) { - if (SKILL_SLUGS.has(trainedSkill)) { + if (objectHasKey(skills, trainedSkill)) { skills[trainedSkill].rank = Math.max(skills[trainedSkill].rank, 1) as ZeroToFour; } } diff --git a/src/module/item/class/sheet.ts b/src/module/item/class/sheet.ts index 4ca0c5736d5..a22e8bf2c20 100644 --- a/src/module/item/class/sheet.ts +++ b/src/module/item/class/sheet.ts @@ -12,7 +12,7 @@ export class ClassSheetPF2e extends ABCSheetPF2e { ...sheetData, proficiencyChoices: CONFIG.PF2E.proficiencyLevels, selectedKeyAbility: this.getLocalizedAbilities(itemData.system.keyAbility), - trainedSkills: createSheetTags(CONFIG.PF2E.skillList, itemData.system.trainedSkills), + trainedSkills: createSheetTags(CONFIG.PF2E.skills, itemData.system.trainedSkills), ancestryFeatLevels: createSheetTags(CONFIG.PF2E.levels, itemData.system.ancestryFeatLevels), classFeatLevels: createSheetTags(CONFIG.PF2E.levels, itemData.system.classFeatLevels), generalFeatLevels: createSheetTags(CONFIG.PF2E.levels, itemData.system.generalFeatLevels), diff --git a/src/module/item/deity/sheet.ts b/src/module/item/deity/sheet.ts index abc17ca0f9a..c945d619ae7 100644 --- a/src/module/item/deity/sheet.ts +++ b/src/module/item/deity/sheet.ts @@ -48,7 +48,7 @@ export class DeitySheetPF2e extends ItemSheetPF2e { { value: "philosophy", label: "PF2E.Item.Deity.Category.Philosophy" }, ], sanctifications, - skills: CONFIG.PF2E.skillList, + skills: R.mapValues(CONFIG.PF2E.skills, (s) => s.label), divineFonts: createSheetOptions( { harm: "PF2E.Item.Deity.DivineFont.Harm", heal: "PF2E.Item.Deity.DivineFont.Heal" }, sheetData.data.font, @@ -71,7 +71,7 @@ export class DeitySheetPF2e extends ItemSheetPF2e { tagify(getInput("system.attribute"), { whitelist: CONFIG.PF2E.abilities, maxTags: 2 }); - tagify(getInput("system.skill"), { whitelist: CONFIG.PF2E.skillList, maxTags: 2 }); + tagify(getInput("system.skill"), { whitelist: CONFIG.PF2E.skills, maxTags: 2 }); // Everything past this point requires a deity or pantheon if (this.item.category === "philosophy") return; diff --git a/src/module/migration/migrations/749-assurance-res.ts b/src/module/migration/migrations/749-assurance-res.ts index e8938f3c7fd..09069856f3b 100644 --- a/src/module/migration/migrations/749-assurance-res.ts +++ b/src/module/migration/migrations/749-assurance-res.ts @@ -1,5 +1,5 @@ import { SkillSlug } from "@actor/types.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; +import { CORE_SKILL_SLUGS } from "@actor/values.ts"; import { ItemSourcePF2e } from "@item/base/data/index.ts"; import { RuleElementSource } from "@module/rules/index.ts"; import { ChoiceSetSource } from "@module/rules/rule-element/choice-set/data.ts"; @@ -49,7 +49,7 @@ export class Migration749AssuranceREs extends MigrationBase { rules.push(...this.#newRules("choice")); } else if (rules.length === 0) { const skill = /^assurance-([a-z]+)$/.exec(slug)?.at(1); - if (setHasElement(SKILL_SLUGS, skill)) { + if (setHasElement(CORE_SKILL_SLUGS, skill)) { rules.push(...this.#newRules(skill)); } } diff --git a/src/module/migration/migrations/914-move-perception-senses.ts b/src/module/migration/migrations/914-move-perception-senses.ts index e80cd0ad01d..c22f8f9ff60 100644 --- a/src/module/migration/migrations/914-move-perception-senses.ts +++ b/src/module/migration/migrations/914-move-perception-senses.ts @@ -3,7 +3,7 @@ import { SenseAcuity } from "@actor/creature/index.ts"; import { SENSES_WITH_MANDATORY_ACUITIES, SENSES_WITH_UNLIMITED_RANGE, SENSE_TYPES } from "@actor/creature/values.ts"; import { ActorSourcePF2e, CharacterSource } from "@actor/data/index.ts"; import { NPCPerceptionSource } from "@actor/npc/data.ts"; -import { SAVE_TYPES, SKILL_SLUGS } from "@actor/values.ts"; +import { CORE_SKILL_SLUGS, SAVE_TYPES } from "@actor/values.ts"; import { ARMOR_CATEGORIES } from "@item/armor/values.ts"; import { AncestrySource, FeatSource, ItemSourcePF2e } from "@item/base/data/index.ts"; import { HeritageSource } from "@item/heritage/data.ts"; @@ -24,7 +24,7 @@ export class Migration914MovePerceptionSenses extends MigrationBase { if ( R.isPlainObject(attributes.initiative) && "statistic" in attributes.initiative && - setHasElement(SKILL_SLUGS, attributes.initiative.statistic) + setHasElement(CORE_SKILL_SLUGS, attributes.initiative.statistic) ) { source.system.initiative.statistic = attributes.initiative.statistic; } diff --git a/src/module/migration/migrations/929-remove-skill-abbreviations.ts b/src/module/migration/migrations/929-remove-skill-abbreviations.ts index c133a56d74f..4da5644bf5d 100644 --- a/src/module/migration/migrations/929-remove-skill-abbreviations.ts +++ b/src/module/migration/migrations/929-remove-skill-abbreviations.ts @@ -1,5 +1,5 @@ import { SkillSlug } from "@actor/types.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; +import { CORE_SKILL_SLUGS } from "@actor/values.ts"; import { ItemSourcePF2e } from "@item/base/data/index.ts"; import { SIZES } from "@module/data.ts"; import { AELikeSource } from "@module/rules/rule-element/ae-like.ts"; @@ -16,7 +16,7 @@ export class Migration929RemoveSkillAbbreviations extends MigrationBase { static override version = 0.929; #SKILL_LOCALIZATION = ((): RegExp => { - const skillSlugs = [...SKILL_SLUGS, ...SKILL_ABBREVIATIONS].map(capitalize).join("|"); + const skillSlugs = [...CORE_SKILL_SLUGS, ...SKILL_ABBREVIATIONS].map(capitalize).join("|"); return new RegExp(String.raw`PF2E.Skill(${skillSlugs})\b`, "g"); })(); diff --git a/src/module/migration/migrations/932-npc-system-skills.ts b/src/module/migration/migrations/932-npc-system-skills.ts index 3a68c28609a..692bd092bb9 100644 --- a/src/module/migration/migrations/932-npc-system-skills.ts +++ b/src/module/migration/migrations/932-npc-system-skills.ts @@ -1,7 +1,7 @@ import { ActorSourcePF2e } from "@actor/data/index.ts"; import { NPCSkillSource, NPCSpecialSkillSource } from "@actor/npc/data.ts"; import { SkillSlug } from "@actor/types.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; +import { CORE_SKILL_SLUGS } from "@actor/values.ts"; import { LoreSource } from "@item/lore.ts"; import { FlatModifierSource } from "@module/rules/rule-element/flat-modifier.ts"; import { RollOptionRuleElement } from "@module/rules/rule-element/roll-option/rule-element.ts"; @@ -18,7 +18,7 @@ export class Migration932NPCSystemSkills extends MigrationBase { // Pull all lores that should be in actor system data. If none, exit const skillLores = source.items.filter( - (i): i is LoreSource => i.type === "lore" && setHasElement(SKILL_SLUGS, sluggify(i.name)), + (i): i is LoreSource => i.type === "lore" && setHasElement(CORE_SKILL_SLUGS, sluggify(i.name)), ); if (skillLores.length === 0) return; diff --git a/src/module/rules/rule-element/battle-form/rule-element.ts b/src/module/rules/rule-element/battle-form/rule-element.ts index 0b626404474..7d706026462 100644 --- a/src/module/rules/rule-element/battle-form/rule-element.ts +++ b/src/module/rules/rule-element/battle-form/rule-element.ts @@ -3,12 +3,12 @@ import { CharacterStrike } from "@actor/character/data.ts"; import { SENSE_TYPES } from "@actor/creature/values.ts"; import { ActorInitiative } from "@actor/initiative.ts"; import { DamageDicePF2e, ModifierPF2e, StatisticModifier } from "@actor/modifiers.ts"; -import { MOVEMENT_TYPES, SKILL_SLUGS } from "@actor/values.ts"; +import { MOVEMENT_TYPES } from "@actor/values.ts"; import { WeaponPF2e } from "@item"; import { RollNotePF2e } from "@module/notes.ts"; import { Predicate } from "@system/predication.ts"; import { RecordField } from "@system/schema-data-fields.ts"; -import { ErrorPF2e, isObject, setHasElement, sluggify, tupleHasValue } from "@util"; +import { ErrorPF2e, isObject, objectHasKey, setHasElement, sluggify, tupleHasValue } from "@util"; import * as R from "remeda"; import { RuleElementOptions, RuleElementPF2e } from "../base.ts"; import { CreatureSizeRuleElement } from "../creature-size.ts"; @@ -255,8 +255,9 @@ class BattleFormRuleElement extends RuleElementPF2e { // Inform predicates that this battle form grants a skill modifier for (const key of Object.keys(this.overrides.skills)) { - if (!setHasElement(SKILL_SLUGS, key)) continue; - rollOptions.all[`battle-form:${key}`] = true; + if (key in CONFIG.PF2E.skills) { + rollOptions.all[`battle-form:${key}`] = true; + } } // Reestablish hands free @@ -341,7 +342,7 @@ class BattleFormRuleElement extends RuleElementPF2e { #prepareSkills(): void { const actor = this.actor; for (const [key, newSkill] of Object.entries(this.overrides.skills)) { - if (!setHasElement(SKILL_SLUGS, key)) { + if (!objectHasKey(actor.skills, key)) { return this.failValidation(`Unrecognized skill: ${key}`); } newSkill.ownIfHigher ??= true; diff --git a/src/module/rules/rule-element/special-statistic.ts b/src/module/rules/rule-element/special-statistic.ts index 6bd1365e7c6..2bd3a05483f 100644 --- a/src/module/rules/rule-element/special-statistic.ts +++ b/src/module/rules/rule-element/special-statistic.ts @@ -1,13 +1,13 @@ import type { CreaturePF2e } from "@actor"; import { ModifierPF2e } from "@actor/modifiers.ts"; import { AttributeString } from "@actor/types.ts"; -import { ATTRIBUTE_ABBREVIATIONS, SAVE_TYPES, SKILL_SLUGS } from "@actor/values.ts"; +import { ATTRIBUTE_ABBREVIATIONS, SAVE_TYPES } from "@actor/values.ts"; import { MagicTradition } from "@item/spell/types.ts"; import { ItemSpellcasting } from "@item/spellcasting-entry/item-spellcasting.ts"; import { Predicate, RawPredicate } from "@system/predication.ts"; import { PredicateField, SlugField } from "@system/schema-data-fields.ts"; import { Statistic, StatisticData } from "@system/statistic/index.ts"; -import { setHasElement, tupleHasValue } from "@util"; +import { tupleHasValue } from "@util"; import * as R from "remeda"; import type { NumberField, SchemaField, StringField } from "types/foundry/common/data/fields.d.ts"; import { RuleElementPF2e } from "../index.ts"; @@ -31,7 +31,7 @@ class SpecialStatisticRuleElement extends RuleElementPF2e, + options: Record, selections: SheetSelections = [], { selected = false } = {}, ): SheetOptions { - const sheetOptions = Object.entries(options).reduce((compiledOptions: SheetOptions, [stringKey, label]) => { + const sheetOptions = Object.entries(options).reduce((compiledOptions: SheetOptions, [stringKey, value]) => { const selectionList = Array.isArray(selections) ? selections : selections.value; const key = typeof selectionList[0] === "number" ? Number(stringKey) : stringKey; const isSelected = selectionList.includes(key); if (isSelected || !selected) { compiledOptions[key] = { - label: game.i18n.localize(label), + label: game.i18n.localize(R.isObjectType(value) ? value.label : value), value: stringKey, selected: isSelected, }; @@ -24,7 +25,10 @@ function createSheetOptions( return sortLabeledRecord(sheetOptions); } -function createSheetTags(options: Record, selections: SheetSelections): SheetOptions { +function createSheetTags( + options: Record, + selections: SheetSelections, +): SheetOptions { return createSheetOptions(options, selections, { selected: true }); } diff --git a/src/module/system/action-macros/general/recall-knowledge.ts b/src/module/system/action-macros/general/recall-knowledge.ts index 4b84c8ccfa9..2bbcd9180be 100644 --- a/src/module/system/action-macros/general/recall-knowledge.ts +++ b/src/module/system/action-macros/general/recall-knowledge.ts @@ -5,11 +5,10 @@ import { SingleCheckActionVariant, SingleCheckActionVariantData, } from "@actor/actions/index.ts"; -import { SKILL_SLUGS } from "@actor/values.ts"; import { TokenPF2e } from "@module/canvas/index.ts"; import { ActionMacroHelpers } from "@system/action-macros/index.ts"; import { CheckResultCallback } from "@system/action-macros/types.ts"; -import { setHasElement } from "@util/misc.ts"; +import { objectHasKey } from "@util/misc.ts"; const PREFIX = "PF2E.Actions.RecallKnowledge"; @@ -37,7 +36,7 @@ class RecallKnowledgeActionVariant extends SingleCheckActionVariant { : options.target instanceof TokenPF2e ? options.target.actor : ActionMacroHelpers.target()?.actor; - if (target instanceof NPCPF2e && setHasElement(SKILL_SLUGS, options.statistic)) { + if (target instanceof NPCPF2e && objectHasKey(CONFIG.PF2E.skills, options.statistic)) { const identification = target.identificationDCs; if (identification.skills.includes(options.statistic)) { options.difficultyClass = { diff --git a/src/module/system/action-macros/helpers.ts b/src/module/system/action-macros/helpers.ts index edd592d7d4e..116dfce3c25 100644 --- a/src/module/system/action-macros/helpers.ts +++ b/src/module/system/action-macros/helpers.ts @@ -333,10 +333,12 @@ class ActionMacroHelpers { return game.i18n.localize("PF2E.PerceptionLabel"); case "unarmed": return game.i18n.localize("PF2E.TraitUnarmed"); + case "lore": + return game.i18n.localize("PF2E.SkillLore"); default: { const saves: Record = CONFIG.PF2E.saves; - const skills: Record = CONFIG.PF2E.skillList; - const label = saves[slug] ?? skills[slug]; + const skills: Record = CONFIG.PF2E.skills; + const label = saves[slug] ?? skills[slug]?.label; return label ? game.i18n.localize(label) : null; } } diff --git a/src/module/system/settings/homebrew/helpers.ts b/src/module/system/settings/homebrew/helpers.ts index a3fcd254e41..d8db07f98f4 100644 --- a/src/module/system/settings/homebrew/helpers.ts +++ b/src/module/system/settings/homebrew/helpers.ts @@ -45,7 +45,7 @@ function prepareReservedTerms(): ReservedTermsRecord { ...Object.keys(CONFIG.PF2E.immunityTypes), ...Object.keys(CONFIG.PF2E.resistanceTypes), ...Object.keys(CONFIG.PF2E.saves), - ...Object.keys(CONFIG.PF2E.skillList), + ...Object.keys(CONFIG.PF2E.skills), ...Object.keys(CONFIG.PF2E.weaknessTypes), ...Object.keys(CONFIG.PF2E.environmentTypes), "damage", diff --git a/src/module/system/tag-selector/base.ts b/src/module/system/tag-selector/base.ts index bd1833fd28b..73e7518d787 100644 --- a/src/module/system/tag-selector/base.ts +++ b/src/module/system/tag-selector/base.ts @@ -1,6 +1,7 @@ import type { ActorPF2e } from "@actor"; import type { ItemPF2e } from "@item"; import { htmlQueryAll, sortStringRecord } from "@util"; +import * as R from "remeda"; import type { SelectableTagField } from "./index.ts"; abstract class BaseTagSelector extends DocumentSheet< @@ -63,10 +64,11 @@ abstract class BaseTagSelector extends D * @returns An object of all key and translated value pairs sorted by key */ #getChoices(): Record { - const choices = this.configTypes.reduce( - (types: Record, key) => fu.mergeObject(types, CONFIG.PF2E[key]), - {}, - ); + const choices = this.configTypes.reduce((types: Record, key) => { + const config: Record = CONFIG.PF2E[key]; + const configLabels = R.mapValues(config, (c) => (R.isObjectType(c) ? c.label : c)); + return fu.mergeObject(types, configLabels); + }, {}); return sortStringRecord(choices); } } diff --git a/src/module/system/tag-selector/index.ts b/src/module/system/tag-selector/index.ts index d5b9960cb33..1897944770e 100644 --- a/src/module/system/tag-selector/index.ts +++ b/src/module/system/tag-selector/index.ts @@ -14,7 +14,7 @@ const SELECTABLE_TAG_FIELDS = [ "otherConsumableTags", "otherWeaponTags", "senses", - "skillList", + "skills", "speedTypes", "vehicleTraits", "weaponTraits", diff --git a/src/scripts/config/index.ts b/src/scripts/config/index.ts index a706074daba..790bf8373b8 100644 --- a/src/scripts/config/index.ts +++ b/src/scripts/config/index.ts @@ -1,7 +1,7 @@ import { ArmyPF2e, CharacterPF2e, FamiliarPF2e, HazardPF2e, LootPF2e, NPCPF2e, PartyPF2e, VehiclePF2e } from "@actor"; import { SenseAcuity } from "@actor/creature/types.ts"; import { LANGUAGES, SENSE_TYPES } from "@actor/creature/values.ts"; -import { ActorType, AttributeString } from "@actor/types.ts"; +import type { ActorType, AttributeString, SkillSlug } from "@actor/types.ts"; import { MOVEMENT_TYPES } from "@actor/values.ts"; import { AbilityItemPF2e, @@ -654,25 +654,24 @@ export const PF2ECONFIG = { helpful: "PF2E.Attitudes.Helpful", }, - skillList: { - acrobatics: "PF2E.Skill.Acrobatics", - arcana: "PF2E.Skill.Arcana", - athletics: "PF2E.Skill.Athletics", - crafting: "PF2E.Skill.Crafting", - deception: "PF2E.Skill.Deception", - diplomacy: "PF2E.Skill.Diplomacy", - intimidation: "PF2E.Skill.Intimidation", - medicine: "PF2E.Skill.Medicine", - nature: "PF2E.Skill.Nature", - occultism: "PF2E.Skill.Occultism", - performance: "PF2E.Skill.Performance", - religion: "PF2E.Skill.Religion", - society: "PF2E.Skill.Society", - stealth: "PF2E.Skill.Stealth", - survival: "PF2E.Skill.Survival", - thievery: "PF2E.Skill.Thievery", - lore: "PF2E.SkillLore", - }, + skills: Object.freeze({ + acrobatics: { label: "PF2E.Skill.Acrobatics", attribute: "dex" }, + arcana: { label: "PF2E.Skill.Arcana", attribute: "int" }, + athletics: { label: "PF2E.Skill.Athletics", attribute: "str" }, + crafting: { label: "PF2E.Skill.Crafting", attribute: "int" }, + deception: { label: "PF2E.Skill.Deception", attribute: "cha" }, + diplomacy: { label: "PF2E.Skill.Diplomacy", attribute: "cha" }, + intimidation: { label: "PF2E.Skill.Intimidation", attribute: "cha" }, + medicine: { label: "PF2E.Skill.Medicine", attribute: "wis" }, + nature: { label: "PF2E.Skill.Nature", attribute: "wis" }, + occultism: { label: "PF2E.Skill.Occultism", attribute: "int" }, + performance: { label: "PF2E.Skill.Performance", attribute: "cha" }, + religion: { label: "PF2E.Skill.Religion", attribute: "wis" }, + society: { label: "PF2E.Skill.Society", attribute: "int" }, + stealth: { label: "PF2E.Skill.Stealth", attribute: "dex" }, + survival: { label: "PF2E.Skill.Survival", attribute: "wis" }, + thievery: { label: "PF2E.Skill.Thievery", attribute: "dex" }, + }) satisfies Record, featCategories, diff --git a/src/scripts/macros/check-prompt/prompt.ts b/src/scripts/macros/check-prompt/prompt.ts index 3f3617a3efc..7b831e45602 100644 --- a/src/scripts/macros/check-prompt/prompt.ts +++ b/src/scripts/macros/check-prompt/prompt.ts @@ -84,7 +84,7 @@ class CheckPromptDialog extends Application { const skillEl = html.querySelector("input#check-prompt-skills"); const skills = { - ...R.omit(CONFIG.PF2E.skillList, ["lore"]), + ...R.mapValues(CONFIG.PF2E.skills, (s) => s.label), perception: "PF2E.PerceptionLabel", }; tagify(skillEl, { whitelist: skills }); diff --git a/src/scripts/macros/treat-wounds.ts b/src/scripts/macros/treat-wounds.ts index 3ad204dda53..bdc6f2bc346 100644 --- a/src/scripts/macros/treat-wounds.ts +++ b/src/scripts/macros/treat-wounds.ts @@ -122,8 +122,8 @@ async function treat( const skillSlug = String($html.find(`#skill-${domIdAppend}`).val()) || "medicine"; const skill = actor.skills[skillSlug]; if (!skill?.proficient) { - const skillName = objectHasKey(CONFIG.PF2E.skillList, skillSlug) - ? game.i18n.localize(CONFIG.PF2E.skillList[skillSlug]) + const skillName = objectHasKey(CONFIG.PF2E.skills, skillSlug) + ? game.i18n.localize(CONFIG.PF2E.skills[skillSlug].label) : skillSlug; ui.notifications.warn(game.i18n.format("PF2E.Actions.TreatWounds.Error", { name, skill: skillName })); return; diff --git a/static/templates/actors/party/regions/overview.hbs b/static/templates/actors/party/regions/overview.hbs index 24928c3a666..f9a66d38ade 100644 --- a/static/templates/actors/party/regions/overview.hbs +++ b/static/templates/actors/party/regions/overview.hbs @@ -149,6 +149,6 @@ {{#*inline "skillTag"}} - {{skill.label}} {{numberFormat skill.mod sign=true}} + {{localize skill.label}} {{numberFormat skill.mod sign=true}} {{/inline}} diff --git a/static/templates/items/background-details.hbs b/static/templates/items/background-details.hbs index ad07efc566a..2e317905033 100644 --- a/static/templates/items/background-details.hbs +++ b/static/templates/items/background-details.hbs @@ -23,7 +23,7 @@
    diff --git a/static/templates/items/class-details.hbs b/static/templates/items/class-details.hbs index b423acca2a9..e974a8060fd 100644 --- a/static/templates/items/class-details.hbs +++ b/static/templates/items/class-details.hbs @@ -146,7 +146,7 @@