From 7828d6bf90b138e11939a4aa7a2874c03321f956 Mon Sep 17 00:00:00 2001 From: Lector Date: Wed, 24 Jun 2026 14:20:19 +0200 Subject: [PATCH 1/7] Added Property-Parameter to SkillSelectOptionCategoryPrerequisite --- src/types/_ActivatableSelectOptionCategory.ts | 4 ++++ .../single/PropertyPrerequisite.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/types/prerequisites/single/PropertyPrerequisite.ts diff --git a/src/types/_ActivatableSelectOptionCategory.ts b/src/types/_ActivatableSelectOptionCategory.ts index 85edbcb7..9f40a67b 100644 --- a/src/types/_ActivatableSelectOptionCategory.ts +++ b/src/types/_ActivatableSelectOptionCategory.ts @@ -17,6 +17,9 @@ import { CombatTechniqueIdentifier, SkillishIdentifier, } from "./_IdentifierGroup.js" +import { + PropertyPrerequisite +} from "./prerequisites/single/PropertyPrerequisite.js" export const SelectOptionCategory = DB.Enum(import.meta.url, { name: "SelectOptionCategory", @@ -386,6 +389,7 @@ const SkillSelectOptionCategoryPrerequisite = DB.Enum(import.meta.url, { values: () => ({ Self: DB.EnumCase({ type: DB.IncludeIdentifier(SelfPrerequisite) }), SelectOption: DB.EnumCase({ type: DB.IncludeIdentifier(OptionPrerequisite) }), + Property: DB.EnumCase({ type: DB.IncludeIdentifier(PropertyPrerequisite) }), }), }) diff --git a/src/types/prerequisites/single/PropertyPrerequisite.ts b/src/types/prerequisites/single/PropertyPrerequisite.ts new file mode 100644 index 00000000..8260791f --- /dev/null +++ b/src/types/prerequisites/single/PropertyPrerequisite.ts @@ -0,0 +1,18 @@ +import * as DB from "tsondb/schema/dsl" +import { PropertyIdentifier } from "../../_Identifier.js" +import { DisplayOption } from "../DisplayOption.js" + +export const PropertyPrerequisite = DB.TypeAlias(import.meta.url, { + name: "PropertyPrerequisite", + comment: "Requires a specific property or one of a specific set of properties.", + type: () => + DB.Object({ + id: DB.Required({ + comment: "The property’s identifier.", + type: PropertyIdentifier(), + }), + display_option: DB.Optional({ + type: DB.IncludeIdentifier(DisplayOption), + }), + }), +}) From 25c6ff403e7d2bb444f7721c17790494fcd3a06c Mon Sep 17 00:00:00 2001 From: Lector Date: Thu, 25 Jun 2026 13:54:47 +0200 Subject: [PATCH 2/7] Property filter in spellwork select options is now an enum as a parameter with specific identifiers or a property --- src/types/_ActivatableSelectOptionCategory.ts | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/types/_ActivatableSelectOptionCategory.ts b/src/types/_ActivatableSelectOptionCategory.ts index 9f40a67b..87120a2c 100644 --- a/src/types/_ActivatableSelectOptionCategory.ts +++ b/src/types/_ActivatableSelectOptionCategory.ts @@ -11,15 +11,14 @@ import { SkillIdentifier, SpellIdentifier, TargetCategoryIdentifier, + PropertyIdentifier, } from "./_Identifier.js" import { ActivatableIdentifier, CombatTechniqueIdentifier, SkillishIdentifier, } from "./_IdentifierGroup.js" -import { - PropertyPrerequisite -} from "./prerequisites/single/PropertyPrerequisite.js" +import { PropertyPrerequisite } from "./prerequisites/single/PropertyPrerequisite.js" export const SelectOptionCategory = DB.Enum(import.meta.url, { name: "SelectOptionCategory", @@ -214,16 +213,34 @@ const SkillsSelectOptionCategory = DB.TypeAlias(import.meta.url, { }), }) +const SpellFilter = DB.Enum(import.meta.url, { + name: "SpellFilter", + values: () => ({ + Identifier: DB.EnumCase({ type: SpellIdentifier() }), + Property: DB.EnumCase({ type: PropertyIdentifier() }), + }), +}) + +const RitualFilter = DB.Enum(import.meta.url, { + name: "RitualFilter", + values: () => ({ + Identifier: DB.EnumCase({ type: RitualIdentifier() }), + Property: DB.EnumCase({ type: PropertyIdentifier() }), + }), +}) + const SkillsSelectOptionCategoryCategory = DB.Enum(import.meta.url, { name: "SkillsSelectOptionCategoryCategory", values: () => ({ Skills: DB.EnumCase({ type: DB.IncludeIdentifier(SkillSelectOptionCategoryCategory) }), Spells: DB.EnumCase({ - type: DB.GenIncludeIdentifier(GenericSkillsSelectOptionCategoryCategory, [SpellIdentifier()]), + type: DB.GenIncludeIdentifier(GenericSkillsSelectOptionCategoryCategory, [ + DB.IncludeIdentifierType(SpellFilter()), + ]), }), Rituals: DB.EnumCase({ type: DB.GenIncludeIdentifier(GenericSkillsSelectOptionCategoryCategory, [ - RitualIdentifier(), + DB.IncludeIdentifierType(RitualFilter()), ]), }), LiturgicalChants: DB.EnumCase({ @@ -389,7 +406,6 @@ const SkillSelectOptionCategoryPrerequisite = DB.Enum(import.meta.url, { values: () => ({ Self: DB.EnumCase({ type: DB.IncludeIdentifier(SelfPrerequisite) }), SelectOption: DB.EnumCase({ type: DB.IncludeIdentifier(OptionPrerequisite) }), - Property: DB.EnumCase({ type: DB.IncludeIdentifier(PropertyPrerequisite) }), }), }) From 6a2ce4a2b437770174cd4508c09aea848fa7938f Mon Sep 17 00:00:00 2001 From: Lector Date: Thu, 25 Jun 2026 13:57:02 +0200 Subject: [PATCH 3/7] correction --- src/types/_ActivatableSelectOptionCategory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/_ActivatableSelectOptionCategory.ts b/src/types/_ActivatableSelectOptionCategory.ts index 87120a2c..572a0e50 100644 --- a/src/types/_ActivatableSelectOptionCategory.ts +++ b/src/types/_ActivatableSelectOptionCategory.ts @@ -235,12 +235,12 @@ const SkillsSelectOptionCategoryCategory = DB.Enum(import.meta.url, { Skills: DB.EnumCase({ type: DB.IncludeIdentifier(SkillSelectOptionCategoryCategory) }), Spells: DB.EnumCase({ type: DB.GenIncludeIdentifier(GenericSkillsSelectOptionCategoryCategory, [ - DB.IncludeIdentifierType(SpellFilter()), + DB.IncludeIdentifierType(SpellFilter), ]), }), Rituals: DB.EnumCase({ type: DB.GenIncludeIdentifier(GenericSkillsSelectOptionCategoryCategory, [ - DB.IncludeIdentifierType(RitualFilter()), + DB.IncludeIdentifierType(RitualFilter), ]), }), LiturgicalChants: DB.EnumCase({ From 0ee19d81f5504cf804449630406a597fce2c779d Mon Sep 17 00:00:00 2001 From: Lector Date: Thu, 25 Jun 2026 13:59:25 +0200 Subject: [PATCH 4/7] removed unnessesarc import --- src/types/_ActivatableSelectOptionCategory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/_ActivatableSelectOptionCategory.ts b/src/types/_ActivatableSelectOptionCategory.ts index 572a0e50..d9ccc9c7 100644 --- a/src/types/_ActivatableSelectOptionCategory.ts +++ b/src/types/_ActivatableSelectOptionCategory.ts @@ -18,7 +18,6 @@ import { CombatTechniqueIdentifier, SkillishIdentifier, } from "./_IdentifierGroup.js" -import { PropertyPrerequisite } from "./prerequisites/single/PropertyPrerequisite.js" export const SelectOptionCategory = DB.Enum(import.meta.url, { name: "SelectOptionCategory", From 8644905f6a2f66ded2fcbf3555d6d234ea6db60d Mon Sep 17 00:00:00 2001 From: Lector Date: Sat, 27 Jun 2026 14:04:22 +0200 Subject: [PATCH 5/7] Rename --- src/types/_ActivatableSelectOptionCategory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/_ActivatableSelectOptionCategory.ts b/src/types/_ActivatableSelectOptionCategory.ts index d9ccc9c7..525715d8 100644 --- a/src/types/_ActivatableSelectOptionCategory.ts +++ b/src/types/_ActivatableSelectOptionCategory.ts @@ -215,7 +215,7 @@ const SkillsSelectOptionCategory = DB.TypeAlias(import.meta.url, { const SpellFilter = DB.Enum(import.meta.url, { name: "SpellFilter", values: () => ({ - Identifier: DB.EnumCase({ type: SpellIdentifier() }), + Single: DB.EnumCase({ type: SpellIdentifier() }), Property: DB.EnumCase({ type: PropertyIdentifier() }), }), }) @@ -223,7 +223,7 @@ const SpellFilter = DB.Enum(import.meta.url, { const RitualFilter = DB.Enum(import.meta.url, { name: "RitualFilter", values: () => ({ - Identifier: DB.EnumCase({ type: RitualIdentifier() }), + Single: DB.EnumCase({ type: RitualIdentifier() }), Property: DB.EnumCase({ type: PropertyIdentifier() }), }), }) From 8c5f5fdaa9a1e5a2dbd881d66417d740b3fe54ee Mon Sep 17 00:00:00 2001 From: Lector Date: Sat, 27 Jun 2026 14:24:36 +0200 Subject: [PATCH 6/7] prettier --- .../single/PropertyPrerequisite.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/types/prerequisites/single/PropertyPrerequisite.ts b/src/types/prerequisites/single/PropertyPrerequisite.ts index 8260791f..5f0318b3 100644 --- a/src/types/prerequisites/single/PropertyPrerequisite.ts +++ b/src/types/prerequisites/single/PropertyPrerequisite.ts @@ -3,16 +3,16 @@ import { PropertyIdentifier } from "../../_Identifier.js" import { DisplayOption } from "../DisplayOption.js" export const PropertyPrerequisite = DB.TypeAlias(import.meta.url, { - name: "PropertyPrerequisite", - comment: "Requires a specific property or one of a specific set of properties.", - type: () => - DB.Object({ - id: DB.Required({ - comment: "The property’s identifier.", - type: PropertyIdentifier(), - }), - display_option: DB.Optional({ - type: DB.IncludeIdentifier(DisplayOption), - }), - }), + name: "PropertyPrerequisite", + comment: "Requires a specific property or one of a specific set of properties.", + type: () => + DB.Object({ + id: DB.Required({ + comment: "The property�s identifier.", + type: PropertyIdentifier(), + }), + display_option: DB.Optional({ + type: DB.IncludeIdentifier(DisplayOption), + }), + }), }) From 03001a37b1a6d0ce285d6be965d920f13b19c1d0 Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sat, 27 Jun 2026 14:34:26 +0200 Subject: [PATCH 7/7] fix cache --- src/cache/activatableSelectOptions.ts | 55 ++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/cache/activatableSelectOptions.ts b/src/cache/activatableSelectOptions.ts index 63247b15..89a3c4bb 100644 --- a/src/cache/activatableSelectOptions.ts +++ b/src/cache/activatableSelectOptions.ts @@ -17,7 +17,9 @@ import type { ImprovementCost, Poison, PrerequisiteForLevel, + Property_ID, RequirableSelectOptionIdentifier, + Ritual_ID, SelectOptionCategory, SelectOptions, SelectOptionsAdventurePointsValue, @@ -28,6 +30,7 @@ import type { SkillSelectOptionCategoryPrerequisite, SpecificFromSkillSelectOptionCategoryCategory, SpecificTargetCategory, + Spell_ID, TargetCategory, TradeSecretAdventurePointsValue, } from "../../gen/types.js" @@ -67,15 +70,17 @@ const wrapPlainApValue = ( ): TradeSecretAdventurePointsValue | undefined => apValue === undefined ? undefined : Case("Fixed", apValue) -const matchesSpecificSkillishIdList = ( - id: string, - config: SpecificFromSkillSelectOptionCategoryCategory, +const matchesSpecificSkillishIdList = ( + config: SpecificFromSkillSelectOptionCategoryCategory, + matches: (required: Ref) => boolean, ): boolean => { + const isInList = config.list.some(matches) + switch (config.operation.kind) { case "Intersection": - return config.list.includes(id) + return isInList case "Difference": - return !config.list.includes(id) + return !isInList default: return assertExhaustive(config.operation) } @@ -233,14 +238,35 @@ const getDefaultSkillishFilter = ( const { specific } = category return specific === undefined ? undefined - : ({ id }) => matchesSpecificSkillishIdList(id, specific) + : ({ id }) => matchesSpecificSkillishIdList(specific, required => required === id) +} + +const getSpellworkFilter = ( + category: GenericSkillsSelectOptionCategoryCategory< + Case<"Single", Spell_ID | Ritual_ID> | Case<"Property", Property_ID> + >, +): ((instance: { id: string; content: Entity }) => boolean) | undefined => { + const { specific } = category + return specific === undefined + ? undefined + : ({ id, content: { property } }) => + matchesSpecificSkillishIdList(specific, required => { + switch (required.kind) { + case "Single": + return required.Single === id + case "Property": + return property === required.Property + default: + return assertExhaustive(required) + } + }) } -const getDerivedSkillishSelectOptions = ( +const getDerivedSkillishSelectOptions = ( database: TSONDB, entryId: ActivatableIdentifier, entity: E, - category: GenericSkillsSelectOptionCategoryCategory & { + category: GenericSkillsSelectOptionCategoryCategory & { skill_applications?: SkillApplicationOrUse[] | undefined skill_uses?: SkillApplicationOrUse[] | undefined }, @@ -248,7 +274,7 @@ const getDerivedSkillishSelectOptions = ( bindingCost?: SelectOptionsBindingCostValue ap_value?: SelectOptionsAdventurePointsValue }, - filter = getDefaultSkillishFilter(category), + filter: ((instance: { id: string; content: Entity }) => boolean) | undefined, ) => { const { prerequisites } = category const { bindingCost, ap_value } = options @@ -928,7 +954,10 @@ const getDerivedSelectOptions = ( const matchesIdRequirement = category.Skills.specific === undefined || - matchesSpecificSkillishIdList(id, category.Skills.specific) + matchesSpecificSkillishIdList( + category.Skills.specific, + required => required === id, + ) return matchesGroupRequirement && matchesIdRequirement }, @@ -940,6 +969,7 @@ const getDerivedSelectOptions = ( "Spell", category.Spells, selectOptionCategory.Skills, + getSpellworkFilter(category.Spells), ) case "Rituals": return getDerivedSkillishSelectOptions( @@ -948,6 +978,7 @@ const getDerivedSelectOptions = ( "Ritual", category.Rituals, selectOptionCategory.Skills, + getSpellworkFilter(category.Rituals), ) case "LiturgicalChants": return getDerivedSkillishSelectOptions( @@ -956,6 +987,7 @@ const getDerivedSelectOptions = ( "LiturgicalChant", category.LiturgicalChants, selectOptionCategory.Skills, + getDefaultSkillishFilter(category.LiturgicalChants), ) case "Ceremonies": return getDerivedSkillishSelectOptions( @@ -964,6 +996,7 @@ const getDerivedSelectOptions = ( "Ceremony", category.Ceremonies, selectOptionCategory.Skills, + getDefaultSkillishFilter(category.Ceremonies), ) default: return assertExhaustive(category) @@ -980,6 +1013,7 @@ const getDerivedSelectOptions = ( "CloseCombatTechnique", category.CloseCombatTechniques, selectOptionCategory.CombatTechniques, + getDefaultSkillishFilter(category.CloseCombatTechniques), ) case "RangedCombatTechniques": return getDerivedSkillishSelectOptions( @@ -988,6 +1022,7 @@ const getDerivedSelectOptions = ( "RangedCombatTechnique", category.RangedCombatTechniques, selectOptionCategory.CombatTechniques, + getDefaultSkillishFilter(category.RangedCombatTechniques), ) default: return assertExhaustive(category)