+45
-10
@@ -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<string>,
|
||||
const matchesSpecificSkillishIdList = <Ref>(
|
||||
config: SpecificFromSkillSelectOptionCategoryCategory<Ref>,
|
||||
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 = <E extends SkillishEntityName>(
|
||||
const { specific } = category
|
||||
return specific === undefined
|
||||
? undefined
|
||||
: ({ id }) => matchesSpecificSkillishIdList(id, specific)
|
||||
: ({ id }) => matchesSpecificSkillishIdList(specific, required => required === id)
|
||||
}
|
||||
|
||||
const getDerivedSkillishSelectOptions = <E extends SkillishEntityName>(
|
||||
const getSpellworkFilter = <E extends "Spell" | "Ritual">(
|
||||
category: GenericSkillsSelectOptionCategoryCategory<
|
||||
Case<"Single", Spell_ID | Ritual_ID> | Case<"Property", Property_ID>
|
||||
>,
|
||||
): ((instance: { id: string; content: Entity<TSONDBTypes, E> }) => 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 = <E extends SkillishEntityName, ID>(
|
||||
database: TSONDB<TSONDBTypes>,
|
||||
entryId: ActivatableIdentifier,
|
||||
entity: E,
|
||||
category: GenericSkillsSelectOptionCategoryCategory<string> & {
|
||||
category: GenericSkillsSelectOptionCategoryCategory<ID> & {
|
||||
skill_applications?: SkillApplicationOrUse[] | undefined
|
||||
skill_uses?: SkillApplicationOrUse[] | undefined
|
||||
},
|
||||
@@ -248,7 +274,7 @@ const getDerivedSkillishSelectOptions = <E extends SkillishEntityName>(
|
||||
bindingCost?: SelectOptionsBindingCostValue<SkillishIdentifier | CombatTechniqueIdentifier>
|
||||
ap_value?: SelectOptionsAdventurePointsValue<SkillishIdentifier | CombatTechniqueIdentifier>
|
||||
},
|
||||
filter = getDefaultSkillishFilter<E>(category),
|
||||
filter: ((instance: { id: string; content: Entity<TSONDBTypes, E> }) => 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)
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
SkillIdentifier,
|
||||
SpellIdentifier,
|
||||
TargetCategoryIdentifier,
|
||||
PropertyIdentifier,
|
||||
} from "./_Identifier.js"
|
||||
import {
|
||||
ActivatableIdentifier,
|
||||
@@ -211,16 +212,34 @@ const SkillsSelectOptionCategory = DB.TypeAlias(import.meta.url, {
|
||||
}),
|
||||
})
|
||||
|
||||
const SpellFilter = DB.Enum(import.meta.url, {
|
||||
name: "SpellFilter",
|
||||
values: () => ({
|
||||
Single: DB.EnumCase({ type: SpellIdentifier() }),
|
||||
Property: DB.EnumCase({ type: PropertyIdentifier() }),
|
||||
}),
|
||||
})
|
||||
|
||||
const RitualFilter = DB.Enum(import.meta.url, {
|
||||
name: "RitualFilter",
|
||||
values: () => ({
|
||||
Single: 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({
|
||||
|
||||
@@ -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),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user