Skip to content

Commit

Permalink
Move skill data to CONFIG.PF2E.skills (foundryvtt#15292)
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlosFdez committed Jun 29, 2024
1 parent c4ea68a commit f9e6c69
Show file tree
Hide file tree
Showing 37 changed files with 118 additions and 167 deletions.
8 changes: 3 additions & 5 deletions src/module/actor/actions/single-check.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";

Expand All @@ -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
);
}

Expand Down
22 changes: 7 additions & 15 deletions src/module/actor/character/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -407,9 +407,8 @@ class CharacterPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
attributes.classhp = 0;

// Skills
system.skills = R.mapToObj([...SKILL_SLUGS], (key) => {
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) }];
});

Expand Down Expand Up @@ -741,7 +740,7 @@ class CharacterPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
rollOptionsAll[`attribute:${key}:mod:${mod}`] = true;
}

for (const key of SKILL_SLUGS) {
for (const key of R.keys.strict(CONFIG.PF2E.skills)) {
const rank = this.system.skills[key].rank;
rollOptionsAll[`skill:${key}:rank:${rank}`] = true;
}
Expand Down Expand Up @@ -885,17 +884,10 @@ class CharacterPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
private prepareSkills() {
const { synthetics, system, wornArmor } = this;

this.skills = R.mapToObj([...SKILL_SLUGS], (skillSlug) => {
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) {
Expand Down Expand Up @@ -932,7 +924,7 @@ class CharacterPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
slug: skillSlug,
label,
rank: skill.rank,
attribute: skill.attribute,
attribute,
domains,
modifiers,
lore: false,
Expand Down
13 changes: 5 additions & 8 deletions src/module/actor/familiar/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ActorSizePF2e } from "@actor/data/size.ts";
import { createEncounterRollOptions, setHitPointsRollOptions } from "@actor/helpers.ts";
import { ModifierPF2e, applyStackingRules } from "@actor/modifiers.ts";
import { SaveType } from "@actor/types.ts";
import { SAVE_TYPES, SKILL_EXPANDED, SKILL_SLUGS } from "@actor/values.ts";
import { SAVE_TYPES } from "@actor/values.ts";
import type { ItemType } from "@item/base/data/index.ts";
import type { CombatantPF2e, EncounterPF2e } from "@module/encounter/index.ts";
import type { RuleElementPF2e } from "@module/rules/index.ts";
Expand Down Expand Up @@ -223,16 +223,13 @@ class FamiliarPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
system.perception = fu.mergeObject(this.perception.getTraceData(), { attribute: "wis" as const });

// Skills
this.skills = [...SKILL_SLUGS].reduce((builtSkills: Record<string, Statistic<this>>, 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,
Expand All @@ -243,11 +240,11 @@ class FamiliarPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e
check: { type: "skill-check" },
});

builtSkills[skill] = statistic;
// Create trace data in system data
this.system.skills[skill] = fu.mergeObject(statistic.getTraceData(), { attribute });

return builtSkills;
}, {});
return [skill, statistic];
});
}

/* -------------------------------------------- */
Expand Down
2 changes: 1 addition & 1 deletion src/module/actor/hazard/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class HazardPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e |
this.skills = {
stealth: new Statistic(this, {
slug: "stealth",
label: CONFIG.PF2E.skillList.stealth,
label: CONFIG.PF2E.skills.stealth.label,
domains: ["stealth", `dex-based`, "skill-check", `dex-skill-check`, "all"],
modifiers: [
new ModifierPF2e({
Expand Down
6 changes: 2 additions & 4 deletions src/module/actor/npc/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { setHitPointsRollOptions, strikeFromMeleeItem } from "@actor/helpers.ts"
import { ActorInitiative } from "@actor/initiative.ts";
import { ModifierPF2e, StatisticModifier } from "@actor/modifiers.ts";
import type { SaveType } from "@actor/types.ts";
import { SAVE_TYPES, SKILL_EXPANDED, SKILL_SLUGS } from "@actor/values.ts";
import { SAVE_TYPES } from "@actor/values.ts";
import type { ItemPF2e, LorePF2e, MeleePF2e } from "@item";
import type { ItemType } from "@item/base/data/index.ts";
import { calculateDC } from "@module/dc.ts";
Expand Down Expand Up @@ -307,10 +307,8 @@ class NPCPF2e<TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e | nul
private prepareSkills() {
const modifierAdjustments = this.synthetics.modifierAdjustments;

this.skills = R.mapToObj([...SKILL_SLUGS], (skillSlug) => {
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
Expand Down
2 changes: 1 addition & 1 deletion src/module/actor/npc/sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions src/module/actor/npc/skills-editor.ts
Original file line number Diff line number Diff line change
@@ -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<NPCPF2e> {
Expand Down Expand Up @@ -49,7 +48,7 @@ export class NPCSkillsEditor extends DocumentSheet<NPCPF2e> {

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 } });
}
});
Expand All @@ -69,7 +68,7 @@ export class NPCSkillsEditor extends DocumentSheet<NPCPF2e> {
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 });
Expand All @@ -80,7 +79,7 @@ export class NPCSkillsEditor extends DocumentSheet<NPCPF2e> {
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 =
Expand Down
4 changes: 1 addition & 3 deletions src/module/actor/party/sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -234,9 +233,8 @@ class PartySheetPF2e extends ActorSheetPF2e<PartyPF2e> {
(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,
Expand Down
4 changes: 3 additions & 1 deletion src/module/actor/sheet/popups/recall-knowledge-popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions src/module/actor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -45,7 +45,7 @@ interface ActorDimensions {
height: number;
}

type SkillSlug = SetElement<typeof SKILL_SLUGS>;
type SkillSlug = SetElement<typeof CORE_SKILL_SLUGS>;

type ActorAlliance = "party" | "opposition" | null;

Expand Down
31 changes: 4 additions & 27 deletions src/module/actor/values.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -17,7 +17,8 @@ const RESISTANCE_TYPES = new Set(Object.keys(resistanceTypes)) as Set<Resistance

const UNAFFECTED_TYPES = new Set(["bleed", "good", "evil", "lawful", "chaotic", "spirit", "vitality", "void"] as const);

const SKILL_SLUGS = new Set([
/** All skill slugs that are part of the core system. Used for validation. */
const CORE_SKILL_SLUGS = new Set([
"acrobatics",
"arcana",
"athletics",
Expand All @@ -36,29 +37,6 @@ const SKILL_SLUGS = new Set([
"thievery",
] as const);

interface SkillExpanded {
attribute: AttributeString;
}

const SKILL_EXPANDED: Record<SkillSlug, SkillExpanded> = {
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 */
Expand All @@ -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,
};
17 changes: 7 additions & 10 deletions src/module/apps/compendium-browser/tabs/base.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -222,16 +223,12 @@ export abstract class CompendiumBrowserTab {
}

/** Generates a localized and sorted CheckBoxOptions object from config data */
protected generateCheckboxOptions(configData: Record<string, string>, sort = true): CheckboxOptions {
// Localize labels for sorting
const localized = Object.entries(configData).reduce(
(result: Record<string, string>, [key, label]) => ({
...result,
[key]: game.i18n.localize(label),
}),
{},
);
// Return localized and sorted CheckBoxOptions
protected generateCheckboxOptions(
configData: Record<string, string | { label: string }>,
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,
Expand Down
18 changes: 4 additions & 14 deletions src/module/apps/compendium-browser/tabs/feat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,6 @@ export class CompendiumBrowserFeatTab extends CompendiumBrowserTab {
"system.source",
];

const translatedSkills = Object.entries(CONFIG.PF2E.skillList).reduce(
(result: Record<string, string>, [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"),
Expand Down Expand Up @@ -87,9 +76,10 @@ export class CompendiumBrowserFeatTab extends CompendiumBrowserTab {
);
const skills: Set<string> = 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);
}
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit f9e6c69

Please sign in to comment.