Migrate files from @elyukai/optolith-client
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { mapNullable } from "@optolith/helpers/nullable"
|
||||
import { CloseCombatTechnique } from "optolith-database-schema/types/CombatTechnique_Close"
|
||||
import { RangedCombatTechnique } from "optolith-database-schema/types/CombatTechnique_Ranged"
|
||||
import { GetById } from "../helpers/getTypes.js"
|
||||
import { createLibraryEntryCreator } from "../libraryEntry.js"
|
||||
import { createImprovementCost } from "./partial/rated/improvementCost.js"
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a close combat technique.
|
||||
*/
|
||||
export const getCloseCombatTechniqueLibraryEntry = createLibraryEntryCreator<
|
||||
CloseCombatTechnique,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
}
|
||||
>((entry, { getAttributeById }) => ({ translate, translateMap }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "combat-technique close-combat-technique",
|
||||
content: [
|
||||
mapNullable(translation.special, (value) => ({
|
||||
label: translate("Special"),
|
||||
value,
|
||||
})),
|
||||
{
|
||||
label: translate("Primary Attribute"),
|
||||
value: entry.primary_attribute
|
||||
.map(
|
||||
(attr) =>
|
||||
translateMap(getAttributeById(attr.id.attribute)?.translations)
|
||||
?.name
|
||||
)
|
||||
.join("/"),
|
||||
},
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a ranged combat technique.
|
||||
*/
|
||||
export const getRangedCombatTechniqueLibraryEntry = createLibraryEntryCreator<
|
||||
RangedCombatTechnique,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
}
|
||||
>((entry, { getAttributeById }) => ({ translate, translateMap }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "combat-technique ranged-combat-technique",
|
||||
content: [
|
||||
mapNullable(translation.special, (value) => ({
|
||||
label: translate("Special"),
|
||||
value,
|
||||
})),
|
||||
{
|
||||
label: translate("Primary Attribute"),
|
||||
value: entry.primary_attribute
|
||||
.map(
|
||||
(attr) =>
|
||||
translateMap(getAttributeById(attr.id.attribute)?.translations)
|
||||
?.name
|
||||
)
|
||||
.join("/"),
|
||||
},
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,52 @@
|
||||
import { ExperienceLevel } from "optolith-database-schema/types/ExperienceLevel"
|
||||
import { createLibraryEntryCreator } from "../libraryEntry.js"
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for an experience level.
|
||||
*/
|
||||
export const getExperienceLevelLibraryEntry =
|
||||
createLibraryEntryCreator<ExperienceLevel>(
|
||||
(entry) =>
|
||||
({ translate, translateMap }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "experience-level",
|
||||
content: [
|
||||
{
|
||||
label: translate("Adventure Points"),
|
||||
value: entry.adventure_points,
|
||||
},
|
||||
{
|
||||
label: translate("Maximum Attribute Value"),
|
||||
value: entry.max_attribute_value,
|
||||
},
|
||||
{
|
||||
label: translate("Maximum Skill Value"),
|
||||
value: entry.max_skill_rating,
|
||||
},
|
||||
{
|
||||
label: translate("Maximum Combat Technique"),
|
||||
value: entry.max_combat_technique_rating,
|
||||
},
|
||||
{
|
||||
label: translate("Maximum Attribute Total"),
|
||||
value: entry.max_attribute_total,
|
||||
},
|
||||
{
|
||||
label: translate("Number of Spells/Liturgical Chants"),
|
||||
value: entry.max_number_of_spells_liturgical_chants,
|
||||
},
|
||||
{
|
||||
label: translate("Number from other Traditions"),
|
||||
value: entry.max_number_of_unfamiliar_spells,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,409 @@
|
||||
import { Compare } from "@optolith/helpers/compare"
|
||||
import { isNotNullish } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { Blessing } from "optolith-database-schema/types/Blessing"
|
||||
import { Ceremony } from "optolith-database-schema/types/Ceremony"
|
||||
import { DerivedCharacteristic } from "optolith-database-schema/types/DerivedCharacteristic"
|
||||
import { LiturgicalChant } from "optolith-database-schema/types/LiturgicalChant"
|
||||
import { SkillTradition } from "optolith-database-schema/types/_Blessed"
|
||||
import { AspectReference } from "optolith-database-schema/types/_SimpleReferences"
|
||||
import { GetById } from "../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../helpers/translate.js"
|
||||
import {
|
||||
createLibraryEntryCreator,
|
||||
LibraryEntryContent,
|
||||
} from "../libraryEntry.js"
|
||||
import { getTextForBlessingDuration } from "./partial/rated/activatable/duration.js"
|
||||
import { getTextForEffect } from "./partial/rated/activatable/effect.js"
|
||||
import { Entity } from "./partial/rated/activatable/entity.js"
|
||||
import {
|
||||
getTextForFastOneTimePerformanceParameters,
|
||||
getTextForFastSustainedPerformanceParameters,
|
||||
getTextForSlowOneTimePerformanceParameters,
|
||||
getTextForSlowSustainedPerformanceParameters,
|
||||
} from "./partial/rated/activatable/index.js"
|
||||
import { getTextForBlessingRange } from "./partial/rated/activatable/range.js"
|
||||
import { getTextForTargetCategory } from "./partial/rated/activatable/targetCategory.js"
|
||||
import { createImprovementCost } from "./partial/rated/improvementCost.js"
|
||||
import { getTextForCheck } from "./partial/rated/skillCheck.js"
|
||||
import { ResponsiveTextSize } from "./partial/responsiveText.js"
|
||||
|
||||
const getTextForTraditions = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
localeCompare: Compare<string>
|
||||
getBlessedTraditionById: GetById.Static.BlessedTradition
|
||||
getAspectById: GetById.Static.Aspect
|
||||
},
|
||||
values: SkillTradition[]
|
||||
): LibraryEntryContent => {
|
||||
const getAspectName = (ref: AspectReference) =>
|
||||
deps.translateMap(deps.getAspectById(ref.id.aspect)?.translations)?.name
|
||||
|
||||
const text = values
|
||||
.map((trad) => {
|
||||
switch (trad.tag) {
|
||||
case "GeneralAspect":
|
||||
return getAspectName(trad.general_aspect)
|
||||
case "Tradition": {
|
||||
const traditionTranslation = deps.translateMap(
|
||||
deps.getBlessedTraditionById(
|
||||
trad.tradition.tradition.id.blessed_tradition
|
||||
)?.translations
|
||||
)
|
||||
const name =
|
||||
traditionTranslation?.name_compressed ?? traditionTranslation?.name
|
||||
|
||||
if (name === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const aspects =
|
||||
trad.tradition.aspects
|
||||
?.map(getAspectName)
|
||||
.filter(isNotNullish)
|
||||
.sort(deps.localeCompare) ?? []
|
||||
|
||||
if (aspects.length === 0) {
|
||||
return name
|
||||
}
|
||||
|
||||
return `${name} (${aspects.join(" and ")})`
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(trad)
|
||||
}
|
||||
})
|
||||
.filter(isNotNullish)
|
||||
.join(", ")
|
||||
|
||||
return {
|
||||
label: deps.translate("Traditions"),
|
||||
value: text,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a blessing.
|
||||
*/
|
||||
export const getBlessingLibraryEntry = createLibraryEntryCreator<
|
||||
Blessing,
|
||||
{
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
}
|
||||
>((entry, { getTargetCategoryById }) => ({ translate, translateMap }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const range = getTextForBlessingRange({ translate }, entry.parameters.range, {
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
})
|
||||
|
||||
const duration = getTextForBlessingDuration(
|
||||
{ translate, translateMap },
|
||||
entry.parameters.duration,
|
||||
{
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "blessing",
|
||||
content: [
|
||||
{
|
||||
label: translate("Effect"),
|
||||
value: translation.effect,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range
|
||||
? `***${range}*** (${translation.range})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration
|
||||
? `***${duration}*** (${translation.duration})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a liturgical chant.
|
||||
*/
|
||||
export const getLiturgicalChantLibraryEntry = createLibraryEntryCreator<
|
||||
LiturgicalChant,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
getSpirit: () => DerivedCharacteristic | undefined
|
||||
getToughness: () => DerivedCharacteristic | undefined
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
getBlessedTraditionById: GetById.Static.BlessedTradition
|
||||
getAspectById: GetById.Static.Aspect
|
||||
}
|
||||
>(
|
||||
(
|
||||
entry,
|
||||
{
|
||||
getAttributeById,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
getSkillModificationLevelById,
|
||||
getTargetCategoryById,
|
||||
getBlessedTraditionById,
|
||||
getAspectById,
|
||||
}
|
||||
) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { castingTime, cost, range, duration } = (() => {
|
||||
switch (entry.parameters.tag) {
|
||||
case "OneTime":
|
||||
return getTextForFastOneTimePerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.one_time,
|
||||
{
|
||||
entity: Entity.LiturgicalChant,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
case "Sustained":
|
||||
return getTextForFastSustainedPerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.sustained,
|
||||
{
|
||||
entity: Entity.LiturgicalChant,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
default:
|
||||
return assertExhaustive(entry.parameters)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "liturgical-chant",
|
||||
content: [
|
||||
getTextForCheck(
|
||||
{ translate, translateMap, getAttributeById },
|
||||
entry.check,
|
||||
{
|
||||
value: entry.check_penalty,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
}
|
||||
),
|
||||
...getTextForEffect(translation.effect, translate),
|
||||
{
|
||||
label: translate("Liturgical Time"),
|
||||
value:
|
||||
castingTime !== translation.casting_time.full
|
||||
? `***${castingTime}*** (${translation.casting_time.full})`
|
||||
: castingTime,
|
||||
},
|
||||
{
|
||||
label: translate("KP Cost"),
|
||||
value:
|
||||
cost !== translation.cost.full
|
||||
? `***${cost}*** (${translation.cost.full})`
|
||||
: cost,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range.full
|
||||
? `***${range}*** (${translation.range.full})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration.full
|
||||
? `***${duration}*** (${translation.duration.full})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
getTextForTraditions(
|
||||
{
|
||||
translate,
|
||||
translateMap,
|
||||
localeCompare,
|
||||
getBlessedTraditionById,
|
||||
getAspectById,
|
||||
},
|
||||
entry.traditions
|
||||
),
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a ceremony.
|
||||
*/
|
||||
export const getCeremonyLibraryEntry = createLibraryEntryCreator<
|
||||
Ceremony,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
getSpirit: () => DerivedCharacteristic | undefined
|
||||
getToughness: () => DerivedCharacteristic | undefined
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
getBlessedTraditionById: GetById.Static.BlessedTradition
|
||||
getAspectById: GetById.Static.Aspect
|
||||
}
|
||||
>(
|
||||
(
|
||||
entry,
|
||||
{
|
||||
getAttributeById,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
getSkillModificationLevelById,
|
||||
getTargetCategoryById,
|
||||
getBlessedTraditionById,
|
||||
getAspectById,
|
||||
}
|
||||
) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { castingTime, cost, range, duration } = (() => {
|
||||
switch (entry.parameters.tag) {
|
||||
case "OneTime":
|
||||
return getTextForSlowOneTimePerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.one_time,
|
||||
{
|
||||
entity: Entity.Ceremony,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
case "Sustained":
|
||||
return getTextForSlowSustainedPerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.sustained,
|
||||
{
|
||||
entity: Entity.Ceremony,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
default:
|
||||
return assertExhaustive(entry.parameters)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "ceremony",
|
||||
content: [
|
||||
getTextForCheck(
|
||||
{ translate, translateMap, getAttributeById },
|
||||
entry.check,
|
||||
{
|
||||
value: entry.check_penalty,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
}
|
||||
),
|
||||
...getTextForEffect(translation.effect, translate),
|
||||
{
|
||||
label: translate("Ceremonial Time"),
|
||||
value:
|
||||
castingTime !== translation.casting_time.full
|
||||
? `***${castingTime}*** (${translation.casting_time.full})`
|
||||
: castingTime,
|
||||
},
|
||||
{
|
||||
label: translate("KP Cost"),
|
||||
value:
|
||||
cost !== translation.cost.full
|
||||
? `***${cost}*** (${translation.cost.full})`
|
||||
: cost,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range.full
|
||||
? `***${range}*** (${translation.range.full})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration.full
|
||||
? `***${duration}*** (${translation.duration.full})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
getTextForTraditions(
|
||||
{
|
||||
translate,
|
||||
translateMap,
|
||||
localeCompare,
|
||||
getBlessedTraditionById,
|
||||
getAspectById,
|
||||
},
|
||||
entry.traditions
|
||||
),
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,197 @@
|
||||
import { isNotNullish, mapNullable } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
CastingTime,
|
||||
CastingTimeDuringLovemaking,
|
||||
FastCastingTime,
|
||||
FastSkillNonModifiableCastingTime,
|
||||
ModifiableCastingTime,
|
||||
SlowCastingTime,
|
||||
SlowSkillNonModifiableCastingTime,
|
||||
} from "optolith-database-schema/types/_ActivatableSkillCastingTime"
|
||||
import { GetById } from "../../../../helpers/getTypes.js"
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
import { ResponsiveTextSize } from "../../responsiveText.js"
|
||||
import { MISSING_VALUE } from "../../unknown.js"
|
||||
import { Entity } from "./entity.js"
|
||||
import { ModifiableParameter } from "./modifiableParameter.js"
|
||||
import { getTextForNonModifiableSuffix } from "./nonModifiable.js"
|
||||
import { Speed } from "./speed.js"
|
||||
import { formatTimeSpan } from "./units.js"
|
||||
|
||||
const getTextForModifiableCastingTime = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
},
|
||||
value: ModifiableCastingTime,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
mapNullable(
|
||||
deps.getSkillModificationLevelById(value.initial_modification_level),
|
||||
({
|
||||
fast: { casting_time: fastTime },
|
||||
slow: { casting_time: slowTime },
|
||||
}) => {
|
||||
switch (env.speed) {
|
||||
case Speed.Fast:
|
||||
return formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
"Actions",
|
||||
fastTime
|
||||
)
|
||||
case Speed.Slow:
|
||||
return formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
slowTime.unit,
|
||||
slowTime.value
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(env.speed)
|
||||
}
|
||||
}
|
||||
) ?? MISSING_VALUE
|
||||
|
||||
const getTextForFastSkillNonModifiableCastingTime = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
},
|
||||
value: FastSkillNonModifiableCastingTime,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
formatTimeSpan(deps.translate, env.responsiveText, "Actions", value.actions) +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.CastingTime,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
const getTextForSlowSkillNonModifiableCastingTime = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
},
|
||||
value: SlowSkillNonModifiableCastingTime,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
formatTimeSpan(deps.translate, env.responsiveText, value.unit, value.value) +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.CastingTime,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
const getTextForCastingTime = <NonModifiable extends object>(
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
},
|
||||
value: CastingTime<NonModifiable>,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
},
|
||||
getTextForNonModifiableCastingTime: (value: NonModifiable) => string
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Modifiable":
|
||||
return getTextForModifiableCastingTime(deps, value.modifiable, env)
|
||||
case "NonModifiable":
|
||||
return getTextForNonModifiableCastingTime(value.non_modifiable)
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
const getTextForCastingTimeDuringLovemaking = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
},
|
||||
value: CastingTimeDuringLovemaking,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
formatTimeSpan(deps.translate, env.responsiveText, value.unit, value.value)
|
||||
|
||||
/**
|
||||
* Get the text for the casting time of a fast activatable skill.
|
||||
*/
|
||||
export const getTextForFastCastingTime = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
},
|
||||
value: FastCastingTime,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
[
|
||||
mapNullable(value.default, (def) =>
|
||||
getTextForCastingTime(
|
||||
deps,
|
||||
def,
|
||||
{ ...env, speed: Speed.Fast },
|
||||
(nonModifiableValue) =>
|
||||
getTextForFastSkillNonModifiableCastingTime(
|
||||
deps,
|
||||
nonModifiableValue,
|
||||
env
|
||||
)
|
||||
)
|
||||
),
|
||||
mapNullable(value.during_lovemaking, (duringLovemaking) =>
|
||||
getTextForCastingTimeDuringLovemaking(deps, duringLovemaking, env)
|
||||
),
|
||||
]
|
||||
.filter(isNotNullish)
|
||||
.join(" / ")
|
||||
|
||||
/**
|
||||
* Get the text for the casting time of a slow activatable skill.
|
||||
*/
|
||||
export const getTextForSlowCastingTime = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
},
|
||||
value: SlowCastingTime,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
[
|
||||
mapNullable(value.default, (def) =>
|
||||
getTextForCastingTime(
|
||||
deps,
|
||||
def,
|
||||
{ ...env, speed: Speed.Slow },
|
||||
(nonModifiableValue) =>
|
||||
getTextForSlowSkillNonModifiableCastingTime(
|
||||
deps,
|
||||
nonModifiableValue,
|
||||
env
|
||||
)
|
||||
)
|
||||
),
|
||||
mapNullable(value.during_lovemaking, (duringLovemaking) =>
|
||||
getTextForCastingTimeDuringLovemaking(deps, duringLovemaking, env)
|
||||
),
|
||||
]
|
||||
.filter(isNotNullish)
|
||||
.join(" / ")
|
||||
@@ -0,0 +1,31 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { describe, it } from "node:test"
|
||||
import { translateMock } from "../../../../helpers/translate.js"
|
||||
import { getTextForCheckResultBased } from "./checkResultBased.js"
|
||||
|
||||
describe("getTextForCheckResultBased", () => {
|
||||
it("should return the value text for a check-result-based parameter of an activatable skill", () => {
|
||||
assert.equal(
|
||||
getTextForCheckResultBased({ base: "QualityLevels" }, translateMock),
|
||||
"QL"
|
||||
)
|
||||
assert.equal(
|
||||
getTextForCheckResultBased({ base: "SkillPoints" }, translateMock),
|
||||
"SP"
|
||||
)
|
||||
assert.equal(
|
||||
getTextForCheckResultBased(
|
||||
{ base: "QualityLevels", modifier: { arithmetic: "Divide", value: 2 } },
|
||||
translateMock
|
||||
),
|
||||
"QL / 2"
|
||||
)
|
||||
assert.equal(
|
||||
getTextForCheckResultBased(
|
||||
{ base: "SkillPoints", modifier: { arithmetic: "Multiply", value: 3 } },
|
||||
translateMock
|
||||
),
|
||||
"SP × 3"
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,48 @@
|
||||
import { mapNullableDefault } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
CheckResultArithmetic,
|
||||
CheckResultBased,
|
||||
CheckResultValue,
|
||||
} from "optolith-database-schema/types/_ActivatableSkillCheckResultBased"
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
|
||||
const getCheckResultBaseValue = (
|
||||
baseValue: CheckResultValue,
|
||||
translate: Translate
|
||||
) => {
|
||||
switch (baseValue) {
|
||||
case "QualityLevels":
|
||||
return translate("QL")
|
||||
case "SkillPoints":
|
||||
return translate("SP")
|
||||
default:
|
||||
return assertExhaustive(baseValue)
|
||||
}
|
||||
}
|
||||
|
||||
const getArithmeticSymbol = (arithmetic: CheckResultArithmetic) => {
|
||||
switch (arithmetic) {
|
||||
case "Divide":
|
||||
return ` / `
|
||||
case "Multiply":
|
||||
return ` × `
|
||||
default:
|
||||
return assertExhaustive(arithmetic)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value text for a check-result-based parameter of an activatable
|
||||
* skill.
|
||||
*/
|
||||
export const getTextForCheckResultBased = (
|
||||
value: CheckResultBased,
|
||||
translate: Translate
|
||||
): string =>
|
||||
getCheckResultBaseValue(value.base, translate) +
|
||||
mapNullableDefault(
|
||||
value.modifier,
|
||||
(modifier) => getArithmeticSymbol(modifier.arithmetic) + modifier.value,
|
||||
""
|
||||
)
|
||||
@@ -0,0 +1,490 @@
|
||||
import { mapNullable, mapNullableDefault } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
CostMap,
|
||||
IndefiniteOneTimeCost,
|
||||
ModifiableOneTimeCost,
|
||||
MultipleOneTimeCosts,
|
||||
NonModifiableOneTimeCost,
|
||||
NonModifiableOneTimeCostPerCountable,
|
||||
OneTimeCost,
|
||||
SingleOneTimeCost,
|
||||
SustainedCost,
|
||||
} from "optolith-database-schema/types/_ActivatableSkillCost"
|
||||
import { GetById } from "../../../../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
|
||||
import {
|
||||
getResponsiveText,
|
||||
getResponsiveTextOptional,
|
||||
replaceTextIfRequested,
|
||||
responsive,
|
||||
ResponsiveTextSize,
|
||||
} from "../../responsiveText.js"
|
||||
import { MISSING_VALUE } from "../../unknown.js"
|
||||
import { Entity } from "./entity.js"
|
||||
import { ModifiableParameter } from "./modifiableParameter.js"
|
||||
import { getTextForNonModifiableSuffix } from "./nonModifiable.js"
|
||||
import { getModifiableBySpeed, Speed } from "./speed.js"
|
||||
import { formatCost, formatTimeSpan } from "./units.js"
|
||||
|
||||
const getTextForModifiableOneTimeCost = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: ModifiableOneTimeCost,
|
||||
env: {
|
||||
speed: Speed
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
mapNullable(
|
||||
deps.getSkillModificationLevelById(value.initial_modification_level),
|
||||
(modificationLevel) => {
|
||||
const cost = getModifiableBySpeed(
|
||||
modificationLevel,
|
||||
env.speed,
|
||||
(config) => config.cost,
|
||||
(config) => config.cost
|
||||
)
|
||||
|
||||
return replaceTextIfRequested(
|
||||
value.translations,
|
||||
formatCost(deps.translate, env.entity, cost),
|
||||
deps.translateMap,
|
||||
env.responsiveText
|
||||
)
|
||||
}
|
||||
) ?? MISSING_VALUE
|
||||
|
||||
const getMinimumText = (
|
||||
isMinimum: boolean | undefined,
|
||||
translate: Translate,
|
||||
responsiveText: ResponsiveTextSize
|
||||
) =>
|
||||
isMinimum !== true
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
() => translate("at least "),
|
||||
() => translate("min. ")
|
||||
)
|
||||
|
||||
const getTextForNonModifiableOneTimeCostPerCountable = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
formatCost: (x: number | string) => string
|
||||
},
|
||||
value: NonModifiableOneTimeCostPerCountable | undefined,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
) =>
|
||||
mapNullable(value, (perCountable) => {
|
||||
const countableText = responsive(
|
||||
env.responsiveText,
|
||||
(entity) => deps.translate(" per {0}", entity),
|
||||
(entity) => deps.translate("/{0}", entity),
|
||||
getResponsiveText(
|
||||
deps.translateMap(perCountable.translations)?.countable,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
|
||||
const minimumTotalText =
|
||||
mapNullable(perCountable.minimum_total, (minimumTotal) =>
|
||||
deps.translate(", minimum of {0}", deps.formatCost(minimumTotal))
|
||||
) ?? ""
|
||||
|
||||
return countableText + minimumTotalText
|
||||
}) ?? ""
|
||||
|
||||
const getTextForPermanentValue = (
|
||||
value: number | undefined,
|
||||
responsiveText: ResponsiveTextSize,
|
||||
translate: Translate
|
||||
) =>
|
||||
value === undefined
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
(perm) => translate(", {0} of which are permanent", perm),
|
||||
(perm) => translate(" ({0} perm.)", perm),
|
||||
value
|
||||
)
|
||||
|
||||
const getTextForNonModifiableOneTimeCost = (
|
||||
deps: { translate: Translate; translateMap: TranslateMap },
|
||||
value: NonModifiableOneTimeCost,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
const isMinimum = getMinimumText(
|
||||
value.is_minimum,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
const formatCostP = formatCost.bind(this, deps.translate, env.entity)
|
||||
const per = getTextForNonModifiableOneTimeCostPerCountable(
|
||||
{ ...deps, formatCost: formatCostP },
|
||||
value.per,
|
||||
env
|
||||
)
|
||||
const permanent = getTextForPermanentValue(
|
||||
value.permanent_value,
|
||||
env.responsiveText,
|
||||
deps.translate
|
||||
)
|
||||
const translation = deps.translateMap(value.translations)
|
||||
const note = mapNullableDefault(
|
||||
translation === undefined || translation.note === undefined
|
||||
? undefined
|
||||
: getResponsiveTextOptional(translation.note, env.responsiveText),
|
||||
(noteIfPresent) => ` (${noteIfPresent})`,
|
||||
""
|
||||
)
|
||||
|
||||
const cannotModify = getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Cost,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
return (
|
||||
isMinimum + formatCostP(value.value) + per + permanent + note + cannotModify
|
||||
)
|
||||
}
|
||||
|
||||
const getTextForIndefiniteOneTimeCost = (
|
||||
deps: { translate: Translate; translateMap: TranslateMap },
|
||||
value: IndefiniteOneTimeCost,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string =>
|
||||
(getResponsiveText(
|
||||
deps.translateMap(value.translations)?.description,
|
||||
env.responsiveText
|
||||
) ?? "") +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Cost,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
const getTextForSingleOneTimeCost = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: SingleOneTimeCost,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Modifiable":
|
||||
return getTextForModifiableOneTimeCost(deps, value.modifiable, env)
|
||||
case "NonModifiable":
|
||||
return getTextForNonModifiableOneTimeCost(deps, value.non_modifiable, env)
|
||||
case "Indefinite":
|
||||
return getTextForIndefiniteOneTimeCost(deps, value.indefinite, env)
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
const getTextForMultipleOneTimeCosts = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: MultipleOneTimeCosts,
|
||||
type: "conjunction" | "disjunction",
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
const modifiable = !value.every((part) => part.tag === "Modifiable")
|
||||
? getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Cost,
|
||||
env.responsiveText
|
||||
)
|
||||
: ""
|
||||
|
||||
return (
|
||||
value
|
||||
.map((part) => getTextForSingleOneTimeCost(deps, part, env))
|
||||
.join(
|
||||
(() => {
|
||||
switch (type) {
|
||||
case "conjunction":
|
||||
return responsive(
|
||||
env.responsiveText,
|
||||
() => deps.translate(" and "),
|
||||
() => deps.translate(" + ")
|
||||
)
|
||||
case "disjunction":
|
||||
return responsive(
|
||||
env.responsiveText,
|
||||
() => deps.translate(" or "),
|
||||
() => deps.translate(" / ")
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(type)
|
||||
}
|
||||
})()
|
||||
) + modifiable
|
||||
)
|
||||
}
|
||||
|
||||
const getTextForCostMap = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: CostMap,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
const translation = deps.translateMap(value.translations)
|
||||
|
||||
if (value.translations !== undefined && translation === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
if (translation?.replacement !== undefined) {
|
||||
return translation.replacement
|
||||
}
|
||||
|
||||
const costs = value.options.map((option) => option.value).join("/")
|
||||
const labels = value.options
|
||||
.map(
|
||||
(option) => deps.translateMap(option.translations)?.label ?? MISSING_VALUE
|
||||
)
|
||||
.join("/")
|
||||
const permanentCosts = value.options.every(
|
||||
(option) => option.permanent_value !== undefined
|
||||
)
|
||||
? value.options.map((option) => option.permanent_value!).join("/")
|
||||
: undefined
|
||||
|
||||
const formatCostP = formatCost.bind(this, deps.translate, env.entity)
|
||||
const notModifiable = getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Cost,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
return (
|
||||
formatCostP(costs) +
|
||||
deps.translate(" for ") +
|
||||
mapNullableDefault(
|
||||
translation?.list_prepend,
|
||||
(listPrepend) => `${listPrepend} `,
|
||||
""
|
||||
) +
|
||||
labels +
|
||||
(translation?.list_append ?? "") +
|
||||
(permanentCosts !== undefined
|
||||
? deps.translate(
|
||||
", {0} of which are permanent",
|
||||
formatCostP(permanentCosts)
|
||||
)
|
||||
: "") +
|
||||
notModifiable
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the cost of a one-time activatable skill.
|
||||
*/
|
||||
export const getTextForOneTimeCost = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: OneTimeCost,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Single":
|
||||
return getTextForSingleOneTimeCost(deps, value.single, env)
|
||||
case "Conjunction":
|
||||
return getTextForMultipleOneTimeCosts(
|
||||
deps,
|
||||
value.conjunction,
|
||||
"conjunction",
|
||||
env
|
||||
)
|
||||
case "Disjunction":
|
||||
return getTextForMultipleOneTimeCosts(
|
||||
deps,
|
||||
value.disjunction,
|
||||
"disjunction",
|
||||
env
|
||||
)
|
||||
case "Map":
|
||||
return getTextForCostMap(deps, value.map, env)
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the cost of a sustained activatable skill.
|
||||
*/
|
||||
export const getTextForSustainedCost = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: SustainedCost,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Modifiable": {
|
||||
const modificationLevel = deps.getSkillModificationLevelById(
|
||||
value.modifiable.initial_modification_level
|
||||
)
|
||||
|
||||
if (modificationLevel === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
const cost = (() => {
|
||||
switch (env.speed) {
|
||||
case Speed.Fast:
|
||||
return modificationLevel.fast.cost
|
||||
case Speed.Slow:
|
||||
return modificationLevel.slow.cost
|
||||
default:
|
||||
return assertExhaustive(env.speed)
|
||||
}
|
||||
})()
|
||||
|
||||
const formatCostP = formatCost.bind(this, deps.translate, env.entity)
|
||||
const interval = formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
value.modifiable.interval.unit,
|
||||
value.modifiable.interval.value
|
||||
)
|
||||
|
||||
return responsive(
|
||||
env.responsiveText,
|
||||
() =>
|
||||
`${formatCostP(cost) + deps.translate(" (casting)")} + ${
|
||||
formatCostP(cost / 2) + deps.translate(" per {0}", interval)
|
||||
}`,
|
||||
() =>
|
||||
`${formatCostP(cost)} + ${
|
||||
formatCostP(cost / 2) + deps.translate("/{0}", interval)
|
||||
}`
|
||||
)
|
||||
}
|
||||
case "NonModifiable": {
|
||||
const isMinimum = getMinimumText(
|
||||
value.non_modifiable.is_minimum,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
const cost = value.non_modifiable.value
|
||||
const formatCostP = formatCost.bind(this, deps.translate, env.entity)
|
||||
|
||||
const per = (() => {
|
||||
if (value.non_modifiable.per === undefined) {
|
||||
return { countable: "", minimumTotal: "" }
|
||||
}
|
||||
|
||||
const countable = responsive(
|
||||
env.responsiveText,
|
||||
(entity) => deps.translate(" per {0}", entity),
|
||||
(entity) => deps.translate("/{0}", entity),
|
||||
getResponsiveText(
|
||||
deps.translateMap(value.non_modifiable.per.translations)?.countable,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
|
||||
const minimumTotal =
|
||||
value.non_modifiable.per.minimum_total !== undefined
|
||||
? deps.translate(
|
||||
", minimum of {0}",
|
||||
formatCostP(value.non_modifiable.per.minimum_total)
|
||||
)
|
||||
: ""
|
||||
|
||||
return { countable, minimumTotal }
|
||||
})()
|
||||
|
||||
const interval = formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
value.non_modifiable.interval.unit,
|
||||
value.non_modifiable.interval.value
|
||||
)
|
||||
|
||||
return (
|
||||
isMinimum +
|
||||
responsive(
|
||||
env.responsiveText,
|
||||
() =>
|
||||
`${formatCostP(cost) + deps.translate(" (casting)")} + ${
|
||||
(value.non_modifiable.is_minimum === true
|
||||
? deps.translate("half of the activation cost")
|
||||
: formatCostP(cost / 2)) +
|
||||
per.countable +
|
||||
deps.translate(" per {0}", interval)
|
||||
}`,
|
||||
() =>
|
||||
`${formatCostP(cost)} + ${
|
||||
(value.non_modifiable.is_minimum === true
|
||||
? "50%"
|
||||
: formatCostP(cost / 2)) +
|
||||
per.countable +
|
||||
deps.translate("/{0}", interval)
|
||||
}`
|
||||
) +
|
||||
per.minimumTotal +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Cost,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
import { mapNullableDefault } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
CheckResultBasedDuration,
|
||||
DurationForOneTime,
|
||||
DurationForSustained,
|
||||
FixedDuration,
|
||||
Immediate,
|
||||
PermanentDuration,
|
||||
} from "optolith-database-schema/types/_ActivatableSkillDuration"
|
||||
import { BlessingDuration } from "optolith-database-schema/types/Blessing"
|
||||
import { CantripDuration } from "optolith-database-schema/types/Cantrip"
|
||||
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
|
||||
import {
|
||||
getResponsiveText,
|
||||
replaceTextIfRequested,
|
||||
responsive,
|
||||
ResponsiveTextSize,
|
||||
} from "../../responsiveText.js"
|
||||
import { getTextForCheckResultBased } from "./checkResultBased.js"
|
||||
import { getTextForIsMaximum } from "./isMaximum.js"
|
||||
import { formatTimeSpan } from "./units.js"
|
||||
|
||||
const getTextForImmediateDuration = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: Immediate,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
const text =
|
||||
deps.translate("Immediate") +
|
||||
mapNullableDefault(
|
||||
value.maximum,
|
||||
(max) => {
|
||||
const maxText = formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
max.unit,
|
||||
max.value
|
||||
)
|
||||
|
||||
return responsive(
|
||||
env.responsiveText,
|
||||
() => deps.translate(" (no more than {0})", maxText),
|
||||
() => deps.translate(" (max. {0})", maxText)
|
||||
)
|
||||
},
|
||||
""
|
||||
)
|
||||
|
||||
return replaceTextIfRequested(
|
||||
value.translations,
|
||||
text,
|
||||
deps.translateMap,
|
||||
env.responsiveText
|
||||
)
|
||||
}
|
||||
|
||||
const getTextForPermanentDuration = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: PermanentDuration,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
const translation = deps.translateMap(value.translations)
|
||||
const text = deps.translate("Permanent")
|
||||
|
||||
if (translation?.replacement !== undefined) {
|
||||
return getResponsiveText(
|
||||
translation.replacement,
|
||||
env.responsiveText
|
||||
).replace("$1", text)
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
const getTextForFixedDuration = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: FixedDuration,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
const isMaximum = getTextForIsMaximum(
|
||||
value.is_maximum,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
const unitValue = formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
value.unit,
|
||||
value.value
|
||||
)
|
||||
const text = isMaximum + unitValue
|
||||
const translation = deps.translateMap(value.translations)
|
||||
|
||||
if (translation?.replacement !== undefined) {
|
||||
return getResponsiveText(
|
||||
translation.replacement,
|
||||
env.responsiveText
|
||||
).replace("$1", text)
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
const getTextForCheckResultBasedDuration = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: CheckResultBasedDuration,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
const isMaximum = getTextForIsMaximum(
|
||||
value.is_maximum,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
return formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
value.unit,
|
||||
isMaximum + getTextForCheckResultBased(value, deps.translate)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the duration of a one-time activatable skill.
|
||||
*/
|
||||
export const getTextForDurationForOneTime = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: DurationForOneTime,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Immediate":
|
||||
return getTextForImmediateDuration(deps, value.immediate, env)
|
||||
case "Permanent":
|
||||
return getTextForPermanentDuration(deps, value.permanent, env)
|
||||
case "Fixed":
|
||||
return getTextForFixedDuration(deps, value.fixed, env)
|
||||
case "CheckResultBased":
|
||||
return getTextForCheckResultBasedDuration(
|
||||
deps,
|
||||
value.check_result_based,
|
||||
env
|
||||
)
|
||||
case "Indefinite":
|
||||
return getResponsiveText(
|
||||
deps.translateMap(value.indefinite.translations)?.description,
|
||||
env.responsiveText
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the duration of a sustained activatable skill.
|
||||
*/
|
||||
export const getTextForDurationForSustained = (
|
||||
deps: { translate: Translate },
|
||||
value: DurationForSustained | undefined,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string =>
|
||||
value === undefined
|
||||
? responsive(
|
||||
env.responsiveText,
|
||||
() => deps.translate("Sustained"),
|
||||
() => deps.translate("(S)")
|
||||
)
|
||||
: responsive(
|
||||
env.responsiveText,
|
||||
() => deps.translate("no more than "),
|
||||
() => deps.translate("max. ")
|
||||
) +
|
||||
formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
value.maximum.unit,
|
||||
value.maximum.value
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns the text for the duration of a cantrip.
|
||||
*/
|
||||
export const getTextForCantripDuration = (
|
||||
deps: { translate: Translate; translateMap: TranslateMap },
|
||||
value: CantripDuration,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Immediate":
|
||||
return getTextForImmediateDuration(deps, value.immediate, env)
|
||||
case "Fixed":
|
||||
return getTextForFixedDuration(deps, value.fixed, env)
|
||||
case "Indefinite":
|
||||
return getResponsiveText(
|
||||
deps.translateMap(value.indefinite.translations)?.description,
|
||||
env.responsiveText
|
||||
)
|
||||
case "DuringLovemaking": {
|
||||
const { value: lovemakingValue, unit: lovemakingUnit } =
|
||||
value.during_lovemaking
|
||||
return formatTimeSpan(
|
||||
deps.translate,
|
||||
env.responsiveText,
|
||||
lovemakingUnit,
|
||||
lovemakingValue
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the duration of a blessing.
|
||||
*/
|
||||
export const getTextForBlessingDuration = (
|
||||
deps: { translate: Translate; translateMap: TranslateMap },
|
||||
value: BlessingDuration,
|
||||
env: {
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Immediate":
|
||||
return getTextForImmediateDuration(deps, value.immediate, env)
|
||||
case "Fixed":
|
||||
return getTextForFixedDuration(deps, value.fixed, env)
|
||||
case "Indefinite":
|
||||
return getResponsiveText(
|
||||
deps.translateMap(value.indefinite.translations)?.description,
|
||||
env.responsiveText
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { filterNonNullable } from "@optolith/helpers/array"
|
||||
import { mapNullable } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { Effect } from "optolith-database-schema/types/_ActivatableSkillEffect"
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
import { LibraryEntryContent } from "../../../../libraryEntry.js"
|
||||
|
||||
const getContentPartsForQualityLevels = (
|
||||
source: {
|
||||
text_before: string
|
||||
quality_levels: string[]
|
||||
text_after?: string
|
||||
},
|
||||
getQualityLevelString: (index: number) => string | number,
|
||||
translate: Translate
|
||||
): LibraryEntryContent[] =>
|
||||
filterNonNullable([
|
||||
{
|
||||
label: translate("Effect"),
|
||||
value: source.text_before,
|
||||
},
|
||||
...source.quality_levels.map((text, index) => ({
|
||||
value: text,
|
||||
label: translate("QL {0}", getQualityLevelString(index)),
|
||||
})),
|
||||
mapNullable(source.text_after, (textAfter) => ({
|
||||
value: textAfter,
|
||||
className: "effect-after",
|
||||
})),
|
||||
])
|
||||
|
||||
/**
|
||||
* Gets the text for the effect of an activatable skill.
|
||||
*/
|
||||
export const getTextForEffect = (
|
||||
effect: Effect,
|
||||
translate: Translate
|
||||
): LibraryEntryContent[] => {
|
||||
switch (effect.tag) {
|
||||
case "Plain":
|
||||
return [
|
||||
{
|
||||
label: translate("Effect"),
|
||||
value: effect.plain.text,
|
||||
},
|
||||
]
|
||||
case "ForEachQualityLevel":
|
||||
return getContentPartsForQualityLevels(
|
||||
effect.for_each_quality_level,
|
||||
(index) => index + 1,
|
||||
translate
|
||||
)
|
||||
case "ForEachTwoQualityLevels":
|
||||
return getContentPartsForQualityLevels(
|
||||
effect.for_each_two_quality_levels,
|
||||
(index) => `${index * 2 + 1}–${index * 2 + 2}`,
|
||||
translate
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(effect)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* The entity type of an activatable skill.
|
||||
*/
|
||||
export enum Entity {
|
||||
Cantrip,
|
||||
Spell,
|
||||
Ritual,
|
||||
Blessing,
|
||||
LiturgicalChant,
|
||||
Ceremony,
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import {
|
||||
FastOneTimePerformanceParameters,
|
||||
FastSustainedPerformanceParameters,
|
||||
SlowOneTimePerformanceParameters,
|
||||
SlowSustainedPerformanceParameters,
|
||||
} from "optolith-database-schema/types/_ActivatableSkill"
|
||||
import { GetById } from "../../../../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
|
||||
import { ResponsiveTextSize } from "../../responsiveText.js"
|
||||
import {
|
||||
getTextForFastCastingTime,
|
||||
getTextForSlowCastingTime,
|
||||
} from "./castingTime.js"
|
||||
import { getTextForOneTimeCost, getTextForSustainedCost } from "./cost.js"
|
||||
import {
|
||||
getTextForDurationForOneTime,
|
||||
getTextForDurationForSustained,
|
||||
} from "./duration.js"
|
||||
import { Entity } from "./entity.js"
|
||||
import { getTextForActivatableSkillRange } from "./range.js"
|
||||
import { Speed } from "./speed.js"
|
||||
|
||||
/**
|
||||
* Get the texts for all fast one-time performance parameters.
|
||||
*/
|
||||
export const getTextForFastOneTimePerformanceParameters = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: FastOneTimePerformanceParameters,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): {
|
||||
castingTime: string
|
||||
cost: string
|
||||
range: string
|
||||
duration: string
|
||||
} => ({
|
||||
castingTime: getTextForFastCastingTime(deps, value.casting_time, env),
|
||||
cost: getTextForOneTimeCost(deps, value.cost, { speed: Speed.Fast, ...env }),
|
||||
range: getTextForActivatableSkillRange(deps, value.range, {
|
||||
speed: Speed.Fast,
|
||||
...env,
|
||||
}),
|
||||
duration: getTextForDurationForOneTime(deps, value.duration, env),
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the texts for all fast sustained performance parameters.
|
||||
*/
|
||||
export const getTextForFastSustainedPerformanceParameters = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: FastSustainedPerformanceParameters,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): {
|
||||
castingTime: string
|
||||
cost: string
|
||||
range: string
|
||||
duration: string
|
||||
} => ({
|
||||
castingTime: getTextForFastCastingTime(deps, value.casting_time, env),
|
||||
cost: getTextForSustainedCost(deps, value.cost, {
|
||||
speed: Speed.Fast,
|
||||
...env,
|
||||
}),
|
||||
range: getTextForActivatableSkillRange(deps, value.range, {
|
||||
speed: Speed.Fast,
|
||||
...env,
|
||||
}),
|
||||
duration: getTextForDurationForSustained(deps, value.duration, env),
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the texts for all slow one-time performance parameters.
|
||||
*/
|
||||
export const getTextForSlowOneTimePerformanceParameters = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: SlowOneTimePerformanceParameters,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): {
|
||||
castingTime: string
|
||||
cost: string
|
||||
range: string
|
||||
duration: string
|
||||
} => ({
|
||||
castingTime: getTextForSlowCastingTime(deps, value.casting_time, env),
|
||||
cost: getTextForOneTimeCost(deps, value.cost, { speed: Speed.Slow, ...env }),
|
||||
range: getTextForActivatableSkillRange(deps, value.range, {
|
||||
speed: Speed.Slow,
|
||||
...env,
|
||||
}),
|
||||
duration: getTextForDurationForOneTime(deps, value.duration, env),
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the texts for all slow sustained performance parameters.
|
||||
*/
|
||||
export const getTextForSlowSustainedPerformanceParameters = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: SlowSustainedPerformanceParameters,
|
||||
env: {
|
||||
entity: Entity
|
||||
responsiveText: ResponsiveTextSize
|
||||
}
|
||||
): {
|
||||
castingTime: string
|
||||
cost: string
|
||||
range: string
|
||||
duration: string
|
||||
} => ({
|
||||
castingTime: getTextForSlowCastingTime(deps, value.casting_time, env),
|
||||
cost: getTextForSustainedCost(deps, value.cost, {
|
||||
speed: Speed.Slow,
|
||||
...env,
|
||||
}),
|
||||
range: getTextForActivatableSkillRange(deps, value.range, {
|
||||
speed: Speed.Slow,
|
||||
...env,
|
||||
}),
|
||||
duration: getTextForDurationForSustained(deps, value.duration, env),
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
import { responsive, ResponsiveTextSize } from "../../responsiveText.js"
|
||||
|
||||
/**
|
||||
* Returns the text to prepend for the `is_maximum` property.
|
||||
*/
|
||||
export const getTextForIsMaximum = (
|
||||
is_maximum: boolean | undefined,
|
||||
translate: Translate,
|
||||
responsiveText: ResponsiveTextSize
|
||||
): string => {
|
||||
if (is_maximum !== true) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => translate("no more than "),
|
||||
() => translate("max. ")
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* A parameter that is designed to be modifiable.
|
||||
*/
|
||||
export enum ModifiableParameter {
|
||||
CastingTime,
|
||||
Cost,
|
||||
Range,
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
import { ResponsiveTextSize } from "../../responsiveText.js"
|
||||
import { Entity } from "./entity.js"
|
||||
import { ModifiableParameter } from "./modifiableParameter.js"
|
||||
|
||||
/**
|
||||
* Returns the suffix for the text of a non-modifiable parameter that indicates
|
||||
* that the parameter cannot be modified.
|
||||
*/
|
||||
export const getTextForNonModifiableSuffix = (
|
||||
translate: Translate,
|
||||
entity: Entity,
|
||||
param: ModifiableParameter,
|
||||
responsiveText: ResponsiveTextSize
|
||||
): string => {
|
||||
if (responsiveText === ResponsiveTextSize.Compressed) {
|
||||
switch (entity) {
|
||||
case Entity.Spell:
|
||||
case Entity.Ritual:
|
||||
case Entity.LiturgicalChant:
|
||||
case Entity.Ceremony:
|
||||
return translate(" (cannot modify)")
|
||||
case Entity.Cantrip:
|
||||
case Entity.Blessing:
|
||||
return ""
|
||||
default:
|
||||
return assertExhaustive(entity)
|
||||
}
|
||||
}
|
||||
|
||||
switch (entity) {
|
||||
case Entity.Spell:
|
||||
switch (param) {
|
||||
case ModifiableParameter.CastingTime:
|
||||
return translate(
|
||||
" (you cannot use a modification on this spell’s casting time)"
|
||||
)
|
||||
case ModifiableParameter.Cost:
|
||||
return translate(
|
||||
" (you cannot use a modification on this spell’s cost)"
|
||||
)
|
||||
case ModifiableParameter.Range:
|
||||
return translate(
|
||||
" (you cannot use a modification on this spell’s range)"
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(param)
|
||||
}
|
||||
case Entity.Ritual:
|
||||
switch (param) {
|
||||
case ModifiableParameter.CastingTime:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ritual’s ritual time)"
|
||||
)
|
||||
case ModifiableParameter.Cost:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ritual’s cost)"
|
||||
)
|
||||
case ModifiableParameter.Range:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ritual’s range)"
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(param)
|
||||
}
|
||||
case Entity.LiturgicalChant:
|
||||
switch (param) {
|
||||
case ModifiableParameter.CastingTime:
|
||||
return translate(
|
||||
" (you cannot use a modification on this chant’s liturgical time)"
|
||||
)
|
||||
case ModifiableParameter.Cost:
|
||||
return translate(
|
||||
" (you cannot use a modification on this chant’s cost)"
|
||||
)
|
||||
case ModifiableParameter.Range:
|
||||
return translate(
|
||||
" (you cannot use a modification on this chant’s range)"
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(param)
|
||||
}
|
||||
case Entity.Ceremony:
|
||||
switch (param) {
|
||||
case ModifiableParameter.CastingTime:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ceremony’s ceremonial time)"
|
||||
)
|
||||
case ModifiableParameter.Cost:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ceremony’s cost)"
|
||||
)
|
||||
case ModifiableParameter.Range:
|
||||
return translate(
|
||||
" (you cannot use a modification on this ceremony’s range)"
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(param)
|
||||
}
|
||||
case Entity.Cantrip:
|
||||
case Entity.Blessing:
|
||||
return ""
|
||||
default:
|
||||
return assertExhaustive(entity)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Wraps a string in parentheses with a leading space if it is not empty or
|
||||
* `undefined`.
|
||||
*/
|
||||
export const parensIf = (text: string | undefined): string =>
|
||||
text === undefined || text === "" ? "" : ` (${text})`
|
||||
|
||||
/**
|
||||
* Appends a string in parentheses with a leading space if it is not empty or
|
||||
* `undefined`.
|
||||
*/
|
||||
export const appendInParens = (
|
||||
text: string,
|
||||
append: string | undefined
|
||||
): string =>
|
||||
append === undefined || append === "" ? text : `${text} (${append})`
|
||||
@@ -0,0 +1,242 @@
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
Range,
|
||||
RangeUnit,
|
||||
} from "optolith-database-schema/types/_ActivatableSkillRange"
|
||||
import { BlessingRange } from "optolith-database-schema/types/Blessing"
|
||||
import { CantripRange } from "optolith-database-schema/types/Cantrip"
|
||||
import { GetById } from "../../../../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
|
||||
import {
|
||||
getResponsiveText,
|
||||
getResponsiveTextOptional,
|
||||
responsive,
|
||||
ResponsiveTextSize,
|
||||
} from "../../responsiveText.js"
|
||||
import { MISSING_VALUE } from "../../unknown.js"
|
||||
import { getTextForCheckResultBased } from "./checkResultBased.js"
|
||||
import { Entity } from "./entity.js"
|
||||
import { getTextForIsMaximum } from "./isMaximum.js"
|
||||
import { ModifiableParameter } from "./modifiableParameter.js"
|
||||
import { getTextForNonModifiableSuffix } from "./nonModifiable.js"
|
||||
import { Speed } from "./speed.js"
|
||||
|
||||
const toRangeUnit = (
|
||||
unit: RangeUnit,
|
||||
value: number | string,
|
||||
translate: Translate,
|
||||
responsiveText: ResponsiveTextSize
|
||||
) => {
|
||||
switch (unit) {
|
||||
case "Steps":
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => translate("{0} yards", value),
|
||||
() => translate("{0} yd", value)
|
||||
)
|
||||
case "Miles":
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => translate("{0} miles", value),
|
||||
() => translate("{0} mi.", value)
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(unit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the range of an activatable skill.
|
||||
*/
|
||||
export const getTextForActivatableSkillRange = (
|
||||
deps: {
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
},
|
||||
value: Range,
|
||||
env: {
|
||||
speed: Speed
|
||||
responsiveText: ResponsiveTextSize
|
||||
entity: Entity
|
||||
}
|
||||
): string => {
|
||||
const translation = deps.translateMap(value.translations)
|
||||
|
||||
if (value.translations !== undefined && translation === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
const rangeValue = (() => {
|
||||
switch (value.value.tag) {
|
||||
case "Modifiable": {
|
||||
const modificationLevel = deps.getSkillModificationLevelById(
|
||||
value.value.modifiable.initial_modification_level
|
||||
)
|
||||
|
||||
if (modificationLevel === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
const range = (() => {
|
||||
switch (env.speed) {
|
||||
case Speed.Fast:
|
||||
return modificationLevel.fast.range
|
||||
case Speed.Slow:
|
||||
return modificationLevel.slow.range
|
||||
default:
|
||||
return assertExhaustive(env.speed)
|
||||
}
|
||||
})()
|
||||
|
||||
if (range === 1) {
|
||||
return deps.translate("Touch")
|
||||
}
|
||||
|
||||
return toRangeUnit("Steps", range, deps.translate, env.responsiveText)
|
||||
}
|
||||
case "Sight":
|
||||
return deps.translate("Sight")
|
||||
case "Self":
|
||||
return deps.translate("Self")
|
||||
case "Global":
|
||||
return deps.translate("Global")
|
||||
case "Touch":
|
||||
return (
|
||||
deps.translate("Touch") +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Range,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
case "Fixed": {
|
||||
return (
|
||||
toRangeUnit(
|
||||
value.value.fixed.unit,
|
||||
value.value.fixed.value,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
) +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Range,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
}
|
||||
case "CheckResultBased": {
|
||||
const isMaximum = getTextForIsMaximum(
|
||||
value.value.check_result_based.is_maximum,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
|
||||
const isRadius =
|
||||
value.value.check_result_based.is_radius === true
|
||||
? ` ${deps.translate("Radius")}`
|
||||
: ""
|
||||
|
||||
return (
|
||||
isMaximum +
|
||||
toRangeUnit(
|
||||
value.value.check_result_based.unit,
|
||||
getTextForCheckResultBased(
|
||||
value.value.check_result_based,
|
||||
deps.translate
|
||||
),
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
) +
|
||||
isRadius +
|
||||
getTextForNonModifiableSuffix(
|
||||
deps.translate,
|
||||
env.entity,
|
||||
ModifiableParameter.Range,
|
||||
env.responsiveText
|
||||
)
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(value.value)
|
||||
}
|
||||
})()
|
||||
|
||||
const withReplacement =
|
||||
translation?.replacement !== undefined
|
||||
? getResponsiveText(translation.replacement, env.responsiveText).replace(
|
||||
"$1",
|
||||
rangeValue
|
||||
)
|
||||
: rangeValue
|
||||
|
||||
const withNote = (() => {
|
||||
if (translation?.note === undefined) {
|
||||
return withReplacement
|
||||
}
|
||||
|
||||
const note = getResponsiveTextOptional(translation.note, env.responsiveText)
|
||||
|
||||
if (note === undefined) {
|
||||
return withReplacement
|
||||
}
|
||||
|
||||
return `${withReplacement} (${note})`
|
||||
})()
|
||||
|
||||
return withNote
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the range of a cantrip.
|
||||
*/
|
||||
export const getTextForCantripRange = (
|
||||
deps: { translate: Translate },
|
||||
value: CantripRange,
|
||||
env: { responsiveText: ResponsiveTextSize }
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Self":
|
||||
return deps.translate("Self")
|
||||
case "Touch":
|
||||
return deps.translate("Touch")
|
||||
case "Fixed": {
|
||||
return toRangeUnit(
|
||||
value.fixed.unit,
|
||||
value.fixed.value,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for the range of a blessing.
|
||||
*/
|
||||
export const getTextForBlessingRange = (
|
||||
deps: { translate: Translate },
|
||||
value: BlessingRange,
|
||||
env: { responsiveText: ResponsiveTextSize }
|
||||
): string => {
|
||||
switch (value.tag) {
|
||||
case "Self":
|
||||
return deps.translate("Self")
|
||||
case "Touch":
|
||||
return deps.translate("Touch")
|
||||
case "Fixed": {
|
||||
return toRangeUnit(
|
||||
value.fixed.unit,
|
||||
value.fixed.value,
|
||||
deps.translate,
|
||||
env.responsiveText
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
FastSkillModificationLevelConfig,
|
||||
SkillModificationLevel,
|
||||
SlowSkillModificationLevelConfig,
|
||||
} from "optolith-database-schema/types/SkillModificationLevel"
|
||||
|
||||
/**
|
||||
* The speed of an activatable skill.
|
||||
*/
|
||||
export enum Speed {
|
||||
Fast,
|
||||
Slow,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a common value for a skill modification level depending on the speed.
|
||||
*/
|
||||
export const getModifiableBySpeed = <T>(
|
||||
level: SkillModificationLevel,
|
||||
speed: Speed,
|
||||
fast: (config: FastSkillModificationLevelConfig) => T,
|
||||
slow: (config: SlowSkillModificationLevelConfig) => T
|
||||
): T => {
|
||||
switch (speed) {
|
||||
case Speed.Fast:
|
||||
return fast(level.fast)
|
||||
case Speed.Slow:
|
||||
return slow(level.slow)
|
||||
default:
|
||||
return assertExhaustive(speed)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { mapNullable } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { TargetCategory } from "optolith-database-schema/types/_ActivatableSkillTargetCategory"
|
||||
import { GetById } from "../../../../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
|
||||
import { LibraryEntryContent } from "../../../../libraryEntry.js"
|
||||
import { MISSING_VALUE } from "../../unknown.js"
|
||||
import { appendInParens } from "./parensIf.js"
|
||||
|
||||
/**
|
||||
* Get the text for the target category.
|
||||
*/
|
||||
export const getTextForTargetCategory = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
},
|
||||
values: TargetCategory
|
||||
): LibraryEntryContent => ({
|
||||
label: deps.translate("Target Category"),
|
||||
value:
|
||||
values.length === 0
|
||||
? deps.translate("all")
|
||||
: values
|
||||
.map(({ id, translations }) => {
|
||||
const mainName = (() => {
|
||||
switch (id.tag) {
|
||||
case "Self":
|
||||
return deps.translate("Self")
|
||||
case "Zone":
|
||||
return deps.translate("Zone")
|
||||
case "LiturgicalChantsAndCeremonies":
|
||||
return deps.translate("Liturgical Chants and Ceremonies")
|
||||
case "Cantrips":
|
||||
return deps.translate("Cantrips")
|
||||
case "Predefined": {
|
||||
const numericId = id.predefined.id.target_category
|
||||
const specificTargetCategory =
|
||||
deps.getTargetCategoryById(numericId)
|
||||
return (
|
||||
mapNullable(
|
||||
deps.translateMap(specificTargetCategory?.translations),
|
||||
(translation) => translation.name
|
||||
) ?? MISSING_VALUE
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(id)
|
||||
}
|
||||
})()
|
||||
|
||||
return appendInParens(
|
||||
mainName,
|
||||
deps.translateMap(translations)?.note
|
||||
)
|
||||
})
|
||||
.join(", "),
|
||||
})
|
||||
@@ -0,0 +1,127 @@
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { Translate } from "../../../../helpers/translate.js"
|
||||
import { responsive, ResponsiveTextSize } from "../../responsiveText.js"
|
||||
import { Entity } from "./entity.js"
|
||||
|
||||
type TimeSpanUnit =
|
||||
| "Seconds"
|
||||
| "Minutes"
|
||||
| "Hours"
|
||||
| "Days"
|
||||
| "Weeks"
|
||||
| "Months"
|
||||
| "Years"
|
||||
| "Centuries"
|
||||
| "Actions"
|
||||
| "CombatRounds"
|
||||
| "SeductionActions"
|
||||
| "Rounds"
|
||||
|
||||
/**
|
||||
* Returns the text for a time span unit.
|
||||
*/
|
||||
export const formatTimeSpan = (
|
||||
translate: Translate,
|
||||
responsiveTextSize: ResponsiveTextSize,
|
||||
unit: TimeSpanUnit,
|
||||
value: number | string
|
||||
): string => {
|
||||
switch (unit) {
|
||||
case "Seconds":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} seconds", value),
|
||||
() => translate("{0} s", value)
|
||||
)
|
||||
case "Minutes":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} minutes", value),
|
||||
() => translate("{0} min", value)
|
||||
)
|
||||
case "Hours":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} hours", value),
|
||||
() => translate("{0} h", value)
|
||||
)
|
||||
case "Days":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} days", value),
|
||||
() => translate("{0} d", value)
|
||||
)
|
||||
case "Weeks":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} weeks", value),
|
||||
() => translate("{0} wks.", value)
|
||||
)
|
||||
case "Months":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} months", value),
|
||||
() => translate("{0} mos.", value)
|
||||
)
|
||||
case "Years":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} years", value),
|
||||
() => translate("{0} yrs.", value)
|
||||
)
|
||||
case "Centuries":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} centuries", value),
|
||||
() => translate("{0} cent.", value)
|
||||
)
|
||||
case "Actions":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} actions", value),
|
||||
() => translate("{0} act", value)
|
||||
)
|
||||
case "CombatRounds":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} combat rounds", value),
|
||||
() => translate("{0} CR", value)
|
||||
)
|
||||
case "SeductionActions":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} seduction actions", value),
|
||||
() => translate("{0} SA", value)
|
||||
)
|
||||
case "Rounds":
|
||||
return responsive(
|
||||
responsiveTextSize,
|
||||
() => translate("{0} rounds", value),
|
||||
() => translate("{0} rnds", value)
|
||||
)
|
||||
default:
|
||||
return assertExhaustive(unit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text for a cost unit that is based on the entity type.
|
||||
*/
|
||||
export const formatCost = (
|
||||
translate: Translate,
|
||||
entity: Entity,
|
||||
value: number | string
|
||||
) => {
|
||||
switch (entity) {
|
||||
case Entity.Cantrip:
|
||||
case Entity.Spell:
|
||||
case Entity.Ritual:
|
||||
return translate("{0} AE", value)
|
||||
case Entity.Blessing:
|
||||
case Entity.LiturgicalChant:
|
||||
case Entity.Ceremony:
|
||||
return translate("{0} KP", value)
|
||||
default:
|
||||
return assertExhaustive(entity)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ImprovementCost as RawImprovementCost } from "optolith-database-schema/types/_ImprovementCost"
|
||||
import { Translate } from "../../../helpers/translate.js"
|
||||
import { LibraryEntryContent } from "../../../libraryEntry.js"
|
||||
|
||||
/**
|
||||
* Returns the improvement cost as an inline library property.
|
||||
*/
|
||||
export const createImprovementCost = (
|
||||
translate: Translate,
|
||||
improvementCost: RawImprovementCost
|
||||
): LibraryEntryContent => ({
|
||||
label: translate("Improvement Cost"),
|
||||
value: improvementCost,
|
||||
})
|
||||
@@ -0,0 +1,134 @@
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import {
|
||||
SkillCheck,
|
||||
SkillCheckPenalty,
|
||||
} from "optolith-database-schema/types/_SkillCheck"
|
||||
import { DerivedCharacteristic } from "optolith-database-schema/types/DerivedCharacteristic"
|
||||
import { GetById } from "../../../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../../../helpers/translate.js"
|
||||
import { LibraryEntryContent } from "../../../libraryEntry.js"
|
||||
import { responsive, ResponsiveTextSize } from "../responsiveText.js"
|
||||
|
||||
/**
|
||||
* Returns the skill check as an inline library property.
|
||||
*/
|
||||
export const getTextForCheck = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
},
|
||||
check: SkillCheck,
|
||||
checkPenalty?: {
|
||||
value: SkillCheckPenalty | undefined
|
||||
responsiveText: ResponsiveTextSize
|
||||
getSpirit: () => DerivedCharacteristic | undefined
|
||||
getToughness: () => DerivedCharacteristic | undefined
|
||||
}
|
||||
): LibraryEntryContent => ({
|
||||
label: deps.translate("Check"),
|
||||
value:
|
||||
check
|
||||
.map(
|
||||
({ id: { attribute: id } }) =>
|
||||
deps.translateMap(deps.getAttributeById(id)?.translations)
|
||||
?.abbreviation ?? "??"
|
||||
)
|
||||
.join("/") +
|
||||
(() => {
|
||||
if (checkPenalty?.value === undefined) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const { responsiveText } = checkPenalty
|
||||
|
||||
const getDerivedCharacteristicTranslation = (
|
||||
getDerivedCharacteristic: () => DerivedCharacteristic | undefined
|
||||
) => deps.translateMap(getDerivedCharacteristic()?.translations)
|
||||
|
||||
const getSpiritTranslation = () =>
|
||||
getDerivedCharacteristicTranslation(checkPenalty.getSpirit)
|
||||
|
||||
const getToughnessTranslation = () =>
|
||||
getDerivedCharacteristicTranslation(checkPenalty.getToughness)
|
||||
|
||||
const penalty = (() => {
|
||||
switch (checkPenalty.value) {
|
||||
case "Spirit": {
|
||||
const translation = getSpiritTranslation()
|
||||
return translation === undefined
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
() => translation.name,
|
||||
() => translation.abbreviation
|
||||
)
|
||||
}
|
||||
|
||||
case "HalfOfSpirit": {
|
||||
const translation = getSpiritTranslation()
|
||||
return translation === undefined
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
() => `${translation.name}/2`,
|
||||
() => `${translation.abbreviation}/2`
|
||||
)
|
||||
}
|
||||
|
||||
case "Toughness": {
|
||||
const translation = getToughnessTranslation()
|
||||
return translation === undefined
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
() => `${translation.name}/2`,
|
||||
() => `${translation.abbreviation}/2`
|
||||
)
|
||||
}
|
||||
|
||||
case "HigherOfSpiritAndToughness": {
|
||||
const spiritTranslation = getSpiritTranslation()
|
||||
const toughnessTranslation = getToughnessTranslation()
|
||||
return spiritTranslation === undefined ||
|
||||
toughnessTranslation === undefined
|
||||
? ""
|
||||
: responsive(
|
||||
responsiveText,
|
||||
() =>
|
||||
deps.translate(
|
||||
"{0} or {1}, depending on which value is higher",
|
||||
spiritTranslation.abbreviation,
|
||||
toughnessTranslation.abbreviation
|
||||
),
|
||||
() =>
|
||||
`${spiritTranslation.abbreviation}/${toughnessTranslation.abbreviation}`
|
||||
)
|
||||
}
|
||||
|
||||
case "SummoningDifficulty":
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => deps.translate("Invocation Difficulty"),
|
||||
() => deps.translate("ID")
|
||||
)
|
||||
|
||||
case "CreationDifficulty":
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => deps.translate("Creation Difficulty"),
|
||||
() => deps.translate("CD")
|
||||
)
|
||||
|
||||
default:
|
||||
return assertExhaustive(checkPenalty.value)
|
||||
}
|
||||
})()
|
||||
|
||||
return responsive(
|
||||
responsiveText,
|
||||
() => deps.translate(" (modified by {0})", penalty),
|
||||
() => deps.translate(" (− {0})", penalty)
|
||||
)
|
||||
})(),
|
||||
})
|
||||
@@ -0,0 +1,89 @@
|
||||
import { mapNullable } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { LocaleMap } from "optolith-database-schema/types/_LocaleMap"
|
||||
import {
|
||||
ResponsiveText,
|
||||
ResponsiveTextOptional,
|
||||
ResponsiveTextReplace,
|
||||
} from "optolith-database-schema/types/_ResponsiveText"
|
||||
import { TranslateMap } from "../../helpers/translate.js"
|
||||
import { MISSING_VALUE } from "./unknown.js"
|
||||
|
||||
/**
|
||||
* Whether the entry is displayed in a normal or compressed setting. Normal/full
|
||||
* usually means a full library entry display, whether compressed usually means
|
||||
* the character sheet.
|
||||
*/
|
||||
export enum ResponsiveTextSize {
|
||||
Compressed,
|
||||
Full,
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes one of two functions depending on the responsive text size.
|
||||
*/
|
||||
export const responsive = <T, A extends unknown[]>(
|
||||
size: ResponsiveTextSize,
|
||||
full: (...args: A) => T,
|
||||
compressed: (...args: A) => T,
|
||||
...args: A
|
||||
): T => {
|
||||
switch (size) {
|
||||
case ResponsiveTextSize.Compressed:
|
||||
return compressed(...args)
|
||||
case ResponsiveTextSize.Full:
|
||||
return full(...args)
|
||||
default:
|
||||
return assertExhaustive(size)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the responsive text for a given size.
|
||||
*/
|
||||
export const getResponsiveText = (
|
||||
value: ResponsiveText | undefined,
|
||||
size: ResponsiveTextSize
|
||||
): string => {
|
||||
if (value === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
return responsive(
|
||||
size,
|
||||
() => value.full,
|
||||
() => value.compressed
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the responsive text for a given size if it is defined.
|
||||
*/
|
||||
export const getResponsiveTextOptional = (
|
||||
value: ResponsiveTextOptional | undefined,
|
||||
size: ResponsiveTextSize
|
||||
): string | undefined => {
|
||||
if (value === undefined) {
|
||||
return MISSING_VALUE
|
||||
}
|
||||
|
||||
return responsive(
|
||||
size,
|
||||
() => value.full,
|
||||
() => value.compressed
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a text with a given value if a replacement is requested, otherwise
|
||||
* just return the .
|
||||
*/
|
||||
export const replaceTextIfRequested = (
|
||||
translation: LocaleMap<{ replacement?: ResponsiveTextReplace }> | undefined,
|
||||
valueToReplace: string,
|
||||
translateMap: TranslateMap,
|
||||
responsiveText: ResponsiveTextSize
|
||||
) =>
|
||||
mapNullable(translateMap(translation)?.replacement, (replacement) =>
|
||||
getResponsiveText(replacement, responsiveText).replace("$1", valueToReplace)
|
||||
) ?? valueToReplace
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* String to display when a translation that should be present is missing.
|
||||
*/
|
||||
export const MISSING_VALUE = "???"
|
||||
@@ -0,0 +1,136 @@
|
||||
import { isNotNullish } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { NewApplicationsAndUsesCache } from "optolith-database-schema/cache/newApplicationsAndUses"
|
||||
import { Skill } from "optolith-database-schema/types/Skill"
|
||||
import { All, GetById } from "../helpers/getTypes.js"
|
||||
import { createLibraryEntryCreator } from "../libraryEntry.js"
|
||||
import { createImprovementCost } from "./partial/rated/improvementCost.js"
|
||||
import { getTextForCheck } from "./partial/rated/skillCheck.js"
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a skill.
|
||||
*/
|
||||
export const getSkillLibraryEntry = createLibraryEntryCreator<
|
||||
Skill,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
blessedTraditions: All.Static.BlessedTraditions
|
||||
diseases: All.Static.Diseases
|
||||
regions: All.Static.Regions
|
||||
cache: NewApplicationsAndUsesCache
|
||||
}
|
||||
>(
|
||||
(entry, { getAttributeById, blessedTraditions, diseases, regions, cache }) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const newApplications = (
|
||||
entry === undefined ? [] : cache.newApplications[entry.id] ?? []
|
||||
)
|
||||
.map((x) => translateMap(x.data.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
|
||||
const uses = (entry === undefined ? [] : cache.uses[entry.id] ?? [])
|
||||
.map((x) => translateMap(x.data.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
|
||||
const applications = (() => {
|
||||
switch (entry.applications.tag) {
|
||||
case "Derived":
|
||||
return (() => {
|
||||
switch (entry.applications.derived) {
|
||||
case "BlessedTraditions":
|
||||
return Object.values(blessedTraditions)
|
||||
.map((x) => translateMap(x.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
case "Diseases":
|
||||
return Object.values(diseases)
|
||||
.map((x) => translateMap(x.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
case "Regions":
|
||||
return Object.values(regions)
|
||||
.map((x) => translateMap(x.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
default:
|
||||
return assertExhaustive(entry.applications.derived)
|
||||
}
|
||||
})()
|
||||
case "Explicit":
|
||||
return entry.applications.explicit
|
||||
.map((x) => translateMap(x.translations)?.name)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
default:
|
||||
return assertExhaustive(entry.applications)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "skill",
|
||||
content: [
|
||||
newApplications.length === 0
|
||||
? undefined
|
||||
: {
|
||||
label: translate("New Applications"),
|
||||
value: newApplications.join(", "),
|
||||
},
|
||||
uses.length === 0
|
||||
? undefined
|
||||
: {
|
||||
label: translate("Uses"),
|
||||
value: uses.join(", "),
|
||||
},
|
||||
getTextForCheck(
|
||||
{ translate, translateMap, getAttributeById },
|
||||
entry.check
|
||||
),
|
||||
{
|
||||
label: translate("Applications"),
|
||||
value: applications.join(", "),
|
||||
},
|
||||
{
|
||||
label: translate("Encumbrance"),
|
||||
value:
|
||||
entry.encumbrance === "True"
|
||||
? translate("Yes")
|
||||
: entry.encumbrance === "False"
|
||||
? translate("No")
|
||||
: translation.encumbrance_description ?? translate("Maybe"),
|
||||
},
|
||||
translation?.tools === undefined
|
||||
? undefined
|
||||
: {
|
||||
label: translate("Tools"),
|
||||
value: translation.tools,
|
||||
},
|
||||
{
|
||||
label: translate("Quality"),
|
||||
value: translation.quality,
|
||||
},
|
||||
{
|
||||
label: translate("Failed Check"),
|
||||
value: translation.failed,
|
||||
},
|
||||
{
|
||||
label: translate("Critical Success"),
|
||||
value: translation.critical,
|
||||
},
|
||||
{
|
||||
label: translate("Botch"),
|
||||
value: translation.botch,
|
||||
},
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,502 @@
|
||||
import { Compare } from "@optolith/helpers/compare"
|
||||
import { isNotNullish, mapNullable } from "@optolith/helpers/nullable"
|
||||
import { assertExhaustive } from "@optolith/helpers/typeSafety"
|
||||
import { Cantrip } from "optolith-database-schema/types/Cantrip"
|
||||
import { DerivedCharacteristic } from "optolith-database-schema/types/DerivedCharacteristic"
|
||||
import { Ritual } from "optolith-database-schema/types/Ritual"
|
||||
import { Spell } from "optolith-database-schema/types/Spell"
|
||||
import {
|
||||
MagicalTraditionReference,
|
||||
PropertyReference,
|
||||
} from "optolith-database-schema/types/_SimpleReferences"
|
||||
import { Traditions } from "optolith-database-schema/types/_Spellwork"
|
||||
import { GetById } from "../helpers/getTypes.js"
|
||||
import { Translate, TranslateMap } from "../helpers/translate.js"
|
||||
import {
|
||||
createLibraryEntryCreator,
|
||||
LibraryEntryContent,
|
||||
} from "../libraryEntry.js"
|
||||
import { getTextForCantripDuration } from "./partial/rated/activatable/duration.js"
|
||||
import { getTextForEffect } from "./partial/rated/activatable/effect.js"
|
||||
import { Entity } from "./partial/rated/activatable/entity.js"
|
||||
import {
|
||||
getTextForFastOneTimePerformanceParameters,
|
||||
getTextForFastSustainedPerformanceParameters,
|
||||
getTextForSlowOneTimePerformanceParameters,
|
||||
getTextForSlowSustainedPerformanceParameters,
|
||||
} from "./partial/rated/activatable/index.js"
|
||||
import { parensIf } from "./partial/rated/activatable/parensIf.js"
|
||||
import { getTextForCantripRange } from "./partial/rated/activatable/range.js"
|
||||
import { getTextForTargetCategory } from "./partial/rated/activatable/targetCategory.js"
|
||||
import { createImprovementCost } from "./partial/rated/improvementCost.js"
|
||||
import { getTextForCheck } from "./partial/rated/skillCheck.js"
|
||||
import { ResponsiveTextSize } from "./partial/responsiveText.js"
|
||||
|
||||
const getTextForProperty = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
getPropertyById: GetById.Static.Property
|
||||
},
|
||||
value: PropertyReference
|
||||
): LibraryEntryContent => {
|
||||
const text = (() => {
|
||||
const staticEntry = deps.getPropertyById(value.id.property)
|
||||
const staticEntryTranslation = deps.translateMap(staticEntry?.translations)
|
||||
|
||||
if (staticEntryTranslation === undefined) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return staticEntryTranslation.name
|
||||
})()
|
||||
|
||||
return {
|
||||
label: deps.translate("Property"),
|
||||
value: text,
|
||||
}
|
||||
}
|
||||
|
||||
const getTextForTraditions = (
|
||||
deps: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
localeCompare: Compare<string>
|
||||
getMagicalTraditionById: GetById.Static.MagicalTradition
|
||||
},
|
||||
value: Traditions
|
||||
): LibraryEntryContent => {
|
||||
const text = (() => {
|
||||
switch (value.tag) {
|
||||
case "General":
|
||||
return deps.translate("General")
|
||||
case "Specific":
|
||||
return value.specific
|
||||
.map((trad) =>
|
||||
deps.translateMap(
|
||||
deps.getMagicalTraditionById(trad.magical_tradition)?.translations
|
||||
)
|
||||
)
|
||||
.filter(isNotNullish)
|
||||
.map((trad) => trad.name_for_arcane_spellworks ?? trad.name)
|
||||
.sort(deps.localeCompare)
|
||||
.join(", ")
|
||||
default:
|
||||
return assertExhaustive(value)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
label: deps.translate("Traditions"),
|
||||
value: text,
|
||||
}
|
||||
}
|
||||
|
||||
const getTraditionNameForArcaneSpellworksById = (
|
||||
ref: MagicalTraditionReference,
|
||||
getMagicalTraditionById: GetById.Static.MagicalTradition,
|
||||
translateMap: TranslateMap
|
||||
) => {
|
||||
const translation = translateMap(
|
||||
getMagicalTraditionById(ref.id.magical_tradition)?.translations
|
||||
)
|
||||
return translation?.name_for_arcane_spellworks ?? translation?.name
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a cantrip.
|
||||
*/
|
||||
export const getCantripLibraryEntry = createLibraryEntryCreator<
|
||||
Cantrip,
|
||||
{
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
getPropertyById: GetById.Static.Property
|
||||
getMagicalTraditionById: GetById.Static.MagicalTradition
|
||||
getCurriculumById: GetById.Static.Curriculum
|
||||
}
|
||||
>(
|
||||
(
|
||||
entry,
|
||||
{
|
||||
getTargetCategoryById,
|
||||
getPropertyById,
|
||||
getMagicalTraditionById,
|
||||
getCurriculumById,
|
||||
}
|
||||
) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const range = getTextForCantripRange(
|
||||
{ translate },
|
||||
entry.parameters.range,
|
||||
{
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
const duration = getTextForCantripDuration(
|
||||
{ translate, translateMap },
|
||||
entry.parameters.duration,
|
||||
{
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "cantrip",
|
||||
content: [
|
||||
{
|
||||
label: translate("Effect"),
|
||||
value: translation.effect,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range
|
||||
? `***${range}*** (${translation.range})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration
|
||||
? `***${duration}*** (${translation.duration})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
getTextForProperty(
|
||||
{ translate, translateMap, getPropertyById },
|
||||
entry.property
|
||||
),
|
||||
mapNullable(entry.note, (note) => ({
|
||||
label: translate("Note"),
|
||||
value: (() => {
|
||||
switch (note.tag) {
|
||||
case "Common":
|
||||
return note.common.list
|
||||
.map((academyOrTradition) => {
|
||||
switch (academyOrTradition.tag) {
|
||||
case "Academy":
|
||||
return translateMap(
|
||||
getCurriculumById(
|
||||
academyOrTradition.academy.id.curriculum
|
||||
)?.translations
|
||||
)?.name
|
||||
case "Tradition": {
|
||||
return mapNullable(
|
||||
getTraditionNameForArcaneSpellworksById(
|
||||
academyOrTradition.tradition,
|
||||
getMagicalTraditionById,
|
||||
translateMap
|
||||
),
|
||||
(name) =>
|
||||
name +
|
||||
parensIf(
|
||||
translateMap(
|
||||
academyOrTradition.tradition.translations
|
||||
)?.note
|
||||
)
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertExhaustive(academyOrTradition)
|
||||
}
|
||||
})
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
.join(", ")
|
||||
|
||||
case "Exclusive":
|
||||
return note.exclusive.traditions
|
||||
.map((tradition) =>
|
||||
getTraditionNameForArcaneSpellworksById(
|
||||
tradition,
|
||||
getMagicalTraditionById,
|
||||
translateMap
|
||||
)
|
||||
)
|
||||
.filter(isNotNullish)
|
||||
.sort(localeCompare)
|
||||
.join(", ")
|
||||
|
||||
default:
|
||||
return assertExhaustive(note)
|
||||
}
|
||||
})(),
|
||||
})),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a skill.
|
||||
*/
|
||||
export const getSpellLibraryEntry = createLibraryEntryCreator<
|
||||
Spell,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
getSpirit: () => DerivedCharacteristic | undefined
|
||||
getToughness: () => DerivedCharacteristic | undefined
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
getPropertyById: GetById.Static.Property
|
||||
getMagicalTraditionById: GetById.Static.MagicalTradition
|
||||
}
|
||||
>(
|
||||
(
|
||||
entry,
|
||||
{
|
||||
getAttributeById,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
getSkillModificationLevelById,
|
||||
getTargetCategoryById,
|
||||
getPropertyById,
|
||||
getMagicalTraditionById,
|
||||
}
|
||||
) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { castingTime, cost, range, duration } = (() => {
|
||||
switch (entry.parameters.tag) {
|
||||
case "OneTime":
|
||||
return getTextForFastOneTimePerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.one_time,
|
||||
{
|
||||
entity: Entity.Spell,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
case "Sustained":
|
||||
return getTextForFastSustainedPerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.sustained,
|
||||
{
|
||||
entity: Entity.Spell,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
default:
|
||||
return assertExhaustive(entry.parameters)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "spell",
|
||||
content: [
|
||||
getTextForCheck(
|
||||
{ translate, translateMap, getAttributeById },
|
||||
entry.check,
|
||||
{
|
||||
value: entry.check_penalty,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
}
|
||||
),
|
||||
...getTextForEffect(translation.effect, translate),
|
||||
{
|
||||
label: translate("Casting Time"),
|
||||
value:
|
||||
castingTime !== translation.casting_time.full
|
||||
? `***${castingTime}*** (${translation.casting_time.full})`
|
||||
: castingTime,
|
||||
},
|
||||
{
|
||||
label: translate("AE Cost"),
|
||||
value:
|
||||
cost !== translation.cost.full
|
||||
? `***${cost}*** (${translation.cost.full})`
|
||||
: cost,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range.full
|
||||
? `***${range}*** (${translation.range.full})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration.full
|
||||
? `***${duration}*** (${translation.duration.full})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
getTextForProperty(
|
||||
{ translate, translateMap, getPropertyById },
|
||||
entry.property
|
||||
),
|
||||
getTextForTraditions(
|
||||
{ translate, translateMap, localeCompare, getMagicalTraditionById },
|
||||
entry.traditions
|
||||
),
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Get a JSON representation of the rules text for a ritual.
|
||||
*/
|
||||
export const getRitualLibraryEntry = createLibraryEntryCreator<
|
||||
Ritual,
|
||||
{
|
||||
getAttributeById: GetById.Static.Attribute
|
||||
getSpirit: () => DerivedCharacteristic | undefined
|
||||
getToughness: () => DerivedCharacteristic | undefined
|
||||
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
|
||||
getTargetCategoryById: GetById.Static.TargetCategory
|
||||
getPropertyById: GetById.Static.Property
|
||||
getMagicalTraditionById: GetById.Static.MagicalTradition
|
||||
}
|
||||
>(
|
||||
(
|
||||
entry,
|
||||
{
|
||||
getAttributeById,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
getSkillModificationLevelById,
|
||||
getTargetCategoryById,
|
||||
getPropertyById,
|
||||
getMagicalTraditionById,
|
||||
}
|
||||
) =>
|
||||
({ translate, translateMap, localeCompare }) => {
|
||||
const translation = translateMap(entry.translations)
|
||||
|
||||
if (translation === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { castingTime, cost, range, duration } = (() => {
|
||||
switch (entry.parameters.tag) {
|
||||
case "OneTime":
|
||||
return getTextForSlowOneTimePerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.one_time,
|
||||
{
|
||||
entity: Entity.Ritual,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
case "Sustained":
|
||||
return getTextForSlowSustainedPerformanceParameters(
|
||||
{
|
||||
getSkillModificationLevelById,
|
||||
translate,
|
||||
translateMap,
|
||||
},
|
||||
entry.parameters.sustained,
|
||||
{
|
||||
entity: Entity.Ritual,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
}
|
||||
)
|
||||
|
||||
default:
|
||||
return assertExhaustive(entry.parameters)
|
||||
}
|
||||
})()
|
||||
|
||||
return {
|
||||
title: translation.name,
|
||||
className: "ritual",
|
||||
content: [
|
||||
getTextForCheck(
|
||||
{ translate, translateMap, getAttributeById },
|
||||
entry.check,
|
||||
{
|
||||
value: entry.check_penalty,
|
||||
responsiveText: ResponsiveTextSize.Full,
|
||||
getSpirit,
|
||||
getToughness,
|
||||
}
|
||||
),
|
||||
...getTextForEffect(translation.effect, translate),
|
||||
{
|
||||
label: translate("Ritual Time"),
|
||||
value:
|
||||
castingTime !== translation.casting_time.full
|
||||
? `***${castingTime}*** (${translation.casting_time.full})`
|
||||
: castingTime,
|
||||
},
|
||||
{
|
||||
label: translate("AE Cost"),
|
||||
value:
|
||||
cost !== translation.cost.full
|
||||
? `***${cost}*** (${translation.cost.full})`
|
||||
: cost,
|
||||
},
|
||||
{
|
||||
label: translate("Range"),
|
||||
value:
|
||||
range !== translation.range.full
|
||||
? `***${range}*** (${translation.range.full})`
|
||||
: range,
|
||||
},
|
||||
{
|
||||
label: translate("Duration"),
|
||||
value:
|
||||
duration !== translation.duration.full
|
||||
? `***${duration}*** (${translation.duration.full})`
|
||||
: duration,
|
||||
},
|
||||
getTextForTargetCategory(
|
||||
{ translate, translateMap, getTargetCategoryById },
|
||||
entry.target
|
||||
),
|
||||
getTextForProperty(
|
||||
{ translate, translateMap, getPropertyById },
|
||||
entry.property
|
||||
),
|
||||
getTextForTraditions(
|
||||
{ translate, translateMap, localeCompare, getMagicalTraditionById },
|
||||
entry.traditions
|
||||
),
|
||||
createImprovementCost(translate, entry.improvement_cost),
|
||||
],
|
||||
src: entry.src,
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,497 @@
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
import { config as advantageConfig } from "optolith-database-schema/types/Advantage"
|
||||
import { config as animalDiseaseConfig } from "optolith-database-schema/types/AnimalDisease"
|
||||
import { config as animalTypeConfig } from "optolith-database-schema/types/AnimalType"
|
||||
import { config as arcaneBardTraditionConfig } from "optolith-database-schema/types/ArcaneBardTradition"
|
||||
import { config as arcaneDancerTraditionConfig } from "optolith-database-schema/types/ArcaneDancerTradition"
|
||||
import { config as aspectConfig } from "optolith-database-schema/types/Aspect"
|
||||
import { config as attributeConfig } from "optolith-database-schema/types/Attribute"
|
||||
import { config as blessingConfig } from "optolith-database-schema/types/Blessing"
|
||||
import { config as cantripConfig } from "optolith-database-schema/types/Cantrip"
|
||||
import { config as ceremonyConfig } from "optolith-database-schema/types/Ceremony"
|
||||
import { config as closeCombatTechniqueConfig } from "optolith-database-schema/types/CombatTechnique_Close"
|
||||
import { config as rangedCombatTechniqueConfig } from "optolith-database-schema/types/CombatTechnique_Ranged"
|
||||
import { config as conditionConfig } from "optolith-database-schema/types/Condition"
|
||||
import { config as continentConfig } from "optolith-database-schema/types/Continent"
|
||||
import { config as cultureConfig } from "optolith-database-schema/types/Culture"
|
||||
import { config as derivedCharacteristicConfig } from "optolith-database-schema/types/DerivedCharacteristic"
|
||||
import { config as disadvantageConfig } from "optolith-database-schema/types/Disadvantage"
|
||||
import { config as diseaseConfig } from "optolith-database-schema/types/Disease"
|
||||
import { config as elementConfig } from "optolith-database-schema/types/Element"
|
||||
import { config as experienceLevelConfig } from "optolith-database-schema/types/ExperienceLevel"
|
||||
import { config as eyeColorConfig } from "optolith-database-schema/types/EyeColor"
|
||||
import { config as familiarsTrickConfig } from "optolith-database-schema/types/FamiliarsTrick"
|
||||
import { config as hairColorConfig } from "optolith-database-schema/types/HairColor"
|
||||
import { config as kirchenpraegungConfig } from "optolith-database-schema/types/Kirchenpraegung"
|
||||
import { config as curriculumConfig } from "optolith-database-schema/types/Lessons_Curriculum"
|
||||
import { config as guidelineConfig } from "optolith-database-schema/types/Lessons_Guideline"
|
||||
import { config as liturgicalChantConfig } from "optolith-database-schema/types/LiturgicalChant"
|
||||
import { config as localeConfig } from "optolith-database-schema/types/Locale"
|
||||
import { config as metaConditionConfig } from "optolith-database-schema/types/MetaCondition"
|
||||
import { config as pactCategoryConfig } from "optolith-database-schema/types/PactCategory"
|
||||
import { config as patronConfig } from "optolith-database-schema/types/Patron"
|
||||
import { config as patronCategoryConfig } from "optolith-database-schema/types/PatronCategory"
|
||||
import { config as personalityTraitConfig } from "optolith-database-schema/types/PersonalityTrait"
|
||||
import { config as professionConfig } from "optolith-database-schema/types/Profession"
|
||||
import { config as propertyConfig } from "optolith-database-schema/types/Property"
|
||||
import { config as raceConfig } from "optolith-database-schema/types/Race"
|
||||
import { config as regionConfig } from "optolith-database-schema/types/Region"
|
||||
import { config as ritualConfig } from "optolith-database-schema/types/Ritual"
|
||||
import { config as serviceConfig } from "optolith-database-schema/types/Service"
|
||||
import { config as sexPracticeConfig } from "optolith-database-schema/types/SexPractice"
|
||||
import { config as skillConfig } from "optolith-database-schema/types/Skill"
|
||||
import { config as skillGroupConfig } from "optolith-database-schema/types/SkillGroup"
|
||||
import { config as skillModificationLevelConfig } from "optolith-database-schema/types/SkillModificationLevel"
|
||||
import { config as socialStatusConfig } from "optolith-database-schema/types/SocialStatus"
|
||||
import { config as spellConfig } from "optolith-database-schema/types/Spell"
|
||||
import { config as stateConfig } from "optolith-database-schema/types/State"
|
||||
import { config as talismanConfig } from "optolith-database-schema/types/Talisman"
|
||||
import { config as targetCategoryConfig } from "optolith-database-schema/types/TargetCategory"
|
||||
import { config as uIConfig } from "optolith-database-schema/types/UI"
|
||||
import { config as equipmentPackageConfig } from "optolith-database-schema/types/equipment/EquipmentPackage"
|
||||
import { config as ammunitionConfig } from "optolith-database-schema/types/equipment/item/Ammunition"
|
||||
import { config as animalConfig } from "optolith-database-schema/types/equipment/item/Animal"
|
||||
import { config as animalCareConfig } from "optolith-database-schema/types/equipment/item/AnimalCare"
|
||||
import { config as armorConfig } from "optolith-database-schema/types/equipment/item/Armor"
|
||||
import { config as bandageOrRemedyConfig } from "optolith-database-schema/types/equipment/item/BandageOrRemedy"
|
||||
import { config as bookConfig } from "optolith-database-schema/types/equipment/item/Book"
|
||||
import { config as ceremonialItemConfig } from "optolith-database-schema/types/equipment/item/CeremonialItem"
|
||||
import { config as clothesConfig } from "optolith-database-schema/types/equipment/item/Clothes"
|
||||
import { config as containerConfig } from "optolith-database-schema/types/equipment/item/Container"
|
||||
import { config as elixirConfig } from "optolith-database-schema/types/equipment/item/Elixir"
|
||||
import { config as equipmentOfBlessedOnesConfig } from "optolith-database-schema/types/equipment/item/EquipmentOfBlessedOnes"
|
||||
import { config as gemOrPreciousStoneConfig } from "optolith-database-schema/types/equipment/item/GemOrPreciousStone"
|
||||
import { config as illuminationLightSourceConfig } from "optolith-database-schema/types/equipment/item/IlluminationLightSource"
|
||||
import { config as illuminationRefillsOrSuppliesConfig } from "optolith-database-schema/types/equipment/item/IlluminationRefillsOrSupplies"
|
||||
import { config as jewelryConfig } from "optolith-database-schema/types/equipment/item/Jewelry"
|
||||
import { config as liebesspielzeugConfig } from "optolith-database-schema/types/equipment/item/Liebesspielzeug"
|
||||
import { config as luxuryGoodConfig } from "optolith-database-schema/types/equipment/item/LuxuryGood"
|
||||
import { config as magicalArtifactConfig } from "optolith-database-schema/types/equipment/item/MagicalArtifact"
|
||||
import { config as musicalInstrumentConfig } from "optolith-database-schema/types/equipment/item/MusicalInstrument"
|
||||
import { config as orienteeringAidConfig } from "optolith-database-schema/types/equipment/item/OrienteeringAid"
|
||||
import { config as poisonConfig } from "optolith-database-schema/types/equipment/item/Poison"
|
||||
import { config as ropeOrChainConfig } from "optolith-database-schema/types/equipment/item/RopeOrChain"
|
||||
import { config as stationaryConfig } from "optolith-database-schema/types/equipment/item/Stationary"
|
||||
import { config as thievesToolConfig } from "optolith-database-schema/types/equipment/item/ThievesTool"
|
||||
import { config as toolOfTheTradeConfig } from "optolith-database-schema/types/equipment/item/ToolOfTheTrade"
|
||||
import { config as travelGearOrToolConfig } from "optolith-database-schema/types/equipment/item/TravelGearOrTool"
|
||||
import { config as vehicleConfig } from "optolith-database-schema/types/equipment/item/Vehicle"
|
||||
import { config as weaponConfig } from "optolith-database-schema/types/equipment/item/Weapon"
|
||||
import { config as weaponAccessoryConfig } from "optolith-database-schema/types/equipment/item/WeaponAccessory"
|
||||
import { config as armorTypeConfig } from "optolith-database-schema/types/equipment/item/sub/ArmorType"
|
||||
import { config as reachConfig } from "optolith-database-schema/types/equipment/item/sub/Reach"
|
||||
import { config as animistPowerConfig } from "optolith-database-schema/types/magicalActions/AnimistPower"
|
||||
import { config as tribeConfig } from "optolith-database-schema/types/magicalActions/AnimistPower_Tribe"
|
||||
import { config as curseConfig } from "optolith-database-schema/types/magicalActions/Curse"
|
||||
import { config as dominationRitualConfig } from "optolith-database-schema/types/magicalActions/DominationRitual"
|
||||
import { config as elvenMagicalSongConfig } from "optolith-database-schema/types/magicalActions/ElvenMagicalSong"
|
||||
import { config as geodeRitualConfig } from "optolith-database-schema/types/magicalActions/GeodeRitual"
|
||||
import { config as jesterTrickConfig } from "optolith-database-schema/types/magicalActions/JesterTrick"
|
||||
import { config as magicalDanceConfig } from "optolith-database-schema/types/magicalActions/MagicalDance"
|
||||
import { config as magicalMelodyConfig } from "optolith-database-schema/types/magicalActions/MagicalMelody"
|
||||
import { config as magicalRuneConfig } from "optolith-database-schema/types/magicalActions/MagicalRune"
|
||||
import { config as zibiljaRitualConfig } from "optolith-database-schema/types/magicalActions/ZibiljaRitual"
|
||||
import { config as coreRuleConfig } from "optolith-database-schema/types/rule/CoreRule"
|
||||
import { config as focusRuleConfig } from "optolith-database-schema/types/rule/FocusRule"
|
||||
import { config as subjectConfig } from "optolith-database-schema/types/rule/FocusRule_Subject"
|
||||
import { config as optionalRuleConfig } from "optolith-database-schema/types/rule/OptionalRule"
|
||||
import { config as publicationConfig } from "optolith-database-schema/types/source/Publication"
|
||||
import { config as advancedCombatSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/AdvancedCombatSpecialAbility"
|
||||
import { config as advancedKarmaSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/AdvancedKarmaSpecialAbility"
|
||||
import { config as advancedMagicalSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/AdvancedMagicalSpecialAbility"
|
||||
import { config as advancedSkillSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/AdvancedSkillSpecialAbility"
|
||||
import { config as ancestorGlyphConfig } from "optolith-database-schema/types/specialAbility/AncestorGlyph"
|
||||
import { config as blessedTraditionConfig } from "optolith-database-schema/types/specialAbility/BlessedTradition"
|
||||
import { config as brawlingSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/BrawlingSpecialAbility"
|
||||
import { config as ceremonialItemSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/CeremonialItemSpecialAbility"
|
||||
import { config as combatSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/CombatSpecialAbility"
|
||||
import { config as combatStyleSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/CombatStyleSpecialAbility"
|
||||
import { config as commandSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/CommandSpecialAbility"
|
||||
import { config as familiarSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/FamiliarSpecialAbility"
|
||||
import { config as fatePointSexSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/FatePointSexSpecialAbility"
|
||||
import { config as fatePointSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/FatePointSpecialAbility"
|
||||
import { config as generalSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/GeneralSpecialAbility"
|
||||
import { config as karmaSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/KarmaSpecialAbility"
|
||||
import { config as liturgicalStyleSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/LiturgicalStyleSpecialAbility"
|
||||
import { config as lycantropicGiftConfig } from "optolith-database-schema/types/specialAbility/LycantropicGift"
|
||||
import { config as magicStyleSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/MagicStyleSpecialAbility"
|
||||
import { config as magicalSignConfig } from "optolith-database-schema/types/specialAbility/MagicalSign"
|
||||
import { config as magicalSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/MagicalSpecialAbility"
|
||||
import { config as magicalTraditionConfig } from "optolith-database-schema/types/specialAbility/MagicalTradition"
|
||||
import { config as pactGiftConfig } from "optolith-database-schema/types/specialAbility/PactGift"
|
||||
import { config as protectiveWardingCircleSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/ProtectiveWardingCircleSpecialAbility"
|
||||
import { config as sermonConfig } from "optolith-database-schema/types/specialAbility/Sermon"
|
||||
import { config as sexSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/SexSpecialAbility"
|
||||
import { config as sikaryanDrainSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/SikaryanDrainSpecialAbility"
|
||||
import { config as skillStyleSpecialAbilityConfig } from "optolith-database-schema/types/specialAbility/SkillStyleSpecialAbility"
|
||||
import { config as vampiricGiftConfig } from "optolith-database-schema/types/specialAbility/VampiricGift"
|
||||
import { config as visionConfig } from "optolith-database-schema/types/specialAbility/Vision"
|
||||
import { config as languageConfig } from "optolith-database-schema/types/specialAbility/sub/Language"
|
||||
import { config as scriptConfig } from "optolith-database-schema/types/specialAbility/sub/Script"
|
||||
import { config as tradeSecretConfig } from "optolith-database-schema/types/specialAbility/sub/TradeSecret"
|
||||
import { config as arcaneOrbEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/ArcaneOrbEnchantment"
|
||||
import { config as attireEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/AttireEnchantment"
|
||||
import { config as bowlEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/BowlEnchantment"
|
||||
import { config as cauldronEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/CauldronEnchantment"
|
||||
import { config as chronicleEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/ChronicleEnchantment"
|
||||
import { config as daggerRitualConfig } from "optolith-database-schema/types/traditionArtifacts/DaggerRitual"
|
||||
import { config as foolsHatEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/FoolsHatEnchantment"
|
||||
import { config as instrumentEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/InstrumentEnchantment"
|
||||
import { config as krallenkettenzauberConfig } from "optolith-database-schema/types/traditionArtifacts/Krallenkettenzauber"
|
||||
import { config as orbEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/OrbEnchantment"
|
||||
import { config as ringEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/RingEnchantment"
|
||||
import { config as sickleRitualConfig } from "optolith-database-schema/types/traditionArtifacts/SickleRitual"
|
||||
import { config as spellSwordEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/SpellSwordEnchantment"
|
||||
import { config as staffEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/StaffEnchantment"
|
||||
import { config as toyEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/ToyEnchantment"
|
||||
import { config as trinkhornzauberConfig } from "optolith-database-schema/types/traditionArtifacts/Trinkhornzauber"
|
||||
import { config as wandEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/WandEnchantment"
|
||||
import { config as weaponEnchantmentConfig } from "optolith-database-schema/types/traditionArtifacts/WeaponEnchantment"
|
||||
import { config as animalShapeConfig } from "optolith-database-schema/types/traditionArtifacts/sub/AnimalShape"
|
||||
import { config as animalShapePathConfig } from "optolith-database-schema/types/traditionArtifacts/sub/AnimalShapePath"
|
||||
import { config as animalShapeSizeConfig } from "optolith-database-schema/types/traditionArtifacts/sub/AnimalShapeSize"
|
||||
import { config as brewConfig } from "optolith-database-schema/types/traditionArtifacts/sub/Brew"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type IdFromConfig<
|
||||
Config extends { id: (data: any, filePath: string) => string | number }
|
||||
> = ReturnType<Config["id"]>
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type TypeFromConfig<
|
||||
Config extends { id: (data: any, filePath: string) => string | number }
|
||||
> = Parameters<Config["id"]>[0]
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type GetByIdFromConfig<
|
||||
Config extends { id: (data: any, filePath: string) => string | number }
|
||||
> = (id: IdFromConfig<Config>) => TypeFromConfig<Config> | undefined
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type AllFromConfig<
|
||||
Config extends { id: (data: any, filePath: string) => string | number }
|
||||
> = TypeFromConfig<Config>[]
|
||||
|
||||
// prettier-ignore
|
||||
export namespace GetById {
|
||||
export namespace Static {
|
||||
export type AdvancedCombatSpecialAbility = GetByIdFromConfig<typeof advancedCombatSpecialAbilityConfig>
|
||||
export type AdvancedKarmaSpecialAbility = GetByIdFromConfig<typeof advancedKarmaSpecialAbilityConfig>
|
||||
export type AdvancedMagicalSpecialAbility = GetByIdFromConfig<typeof advancedMagicalSpecialAbilityConfig>
|
||||
export type AdvancedSkillSpecialAbility = GetByIdFromConfig<typeof advancedSkillSpecialAbilityConfig>
|
||||
export type Advantage = GetByIdFromConfig<typeof advantageConfig>
|
||||
export type Ammunition = GetByIdFromConfig<typeof ammunitionConfig>
|
||||
export type AncestorGlyph = GetByIdFromConfig<typeof ancestorGlyphConfig>
|
||||
export type AnimalCare = GetByIdFromConfig<typeof animalCareConfig>
|
||||
export type AnimalDisease = GetByIdFromConfig<typeof animalDiseaseConfig>
|
||||
export type Animal = GetByIdFromConfig<typeof animalConfig>
|
||||
export type AnimalShapePath = GetByIdFromConfig<typeof animalShapePathConfig>
|
||||
export type AnimalShape = GetByIdFromConfig<typeof animalShapeConfig>
|
||||
export type AnimalShapeSize = GetByIdFromConfig<typeof animalShapeSizeConfig>
|
||||
export type AnimalType = GetByIdFromConfig<typeof animalTypeConfig>
|
||||
export type AnimistPower = GetByIdFromConfig<typeof animistPowerConfig>
|
||||
export type Tribe = GetByIdFromConfig<typeof tribeConfig>
|
||||
export type ArcaneBardTradition = GetByIdFromConfig<typeof arcaneBardTraditionConfig>
|
||||
export type ArcaneDancerTradition = GetByIdFromConfig<typeof arcaneDancerTraditionConfig>
|
||||
export type ArcaneOrbEnchantment = GetByIdFromConfig<typeof arcaneOrbEnchantmentConfig>
|
||||
export type Armor = GetByIdFromConfig<typeof armorConfig>
|
||||
export type ArmorType = GetByIdFromConfig<typeof armorTypeConfig>
|
||||
export type Aspect = GetByIdFromConfig<typeof aspectConfig>
|
||||
export type AttireEnchantment = GetByIdFromConfig<typeof attireEnchantmentConfig>
|
||||
export type Attribute = GetByIdFromConfig<typeof attributeConfig>
|
||||
export type BandageOrRemedy = GetByIdFromConfig<typeof bandageOrRemedyConfig>
|
||||
export type BlessedTradition = GetByIdFromConfig<typeof blessedTraditionConfig>
|
||||
export type Blessing = GetByIdFromConfig<typeof blessingConfig>
|
||||
export type Book = GetByIdFromConfig<typeof bookConfig>
|
||||
export type BowlEnchantment = GetByIdFromConfig<typeof bowlEnchantmentConfig>
|
||||
export type BrawlingSpecialAbility = GetByIdFromConfig<typeof brawlingSpecialAbilityConfig>
|
||||
export type Brew = GetByIdFromConfig<typeof brewConfig>
|
||||
export type Cantrip = GetByIdFromConfig<typeof cantripConfig>
|
||||
export type CauldronEnchantment = GetByIdFromConfig<typeof cauldronEnchantmentConfig>
|
||||
export type CeremonialItem = GetByIdFromConfig<typeof ceremonialItemConfig>
|
||||
export type CeremonialItemSpecialAbility = GetByIdFromConfig<typeof ceremonialItemSpecialAbilityConfig>
|
||||
export type Ceremony = GetByIdFromConfig<typeof ceremonyConfig>
|
||||
export type ChronicleEnchantment = GetByIdFromConfig<typeof chronicleEnchantmentConfig>
|
||||
export type CloseCombatTechnique = GetByIdFromConfig<typeof closeCombatTechniqueConfig>
|
||||
export type Clothes = GetByIdFromConfig<typeof clothesConfig>
|
||||
export type CombatSpecialAbility = GetByIdFromConfig<typeof combatSpecialAbilityConfig>
|
||||
export type CombatStyleSpecialAbility = GetByIdFromConfig<typeof combatStyleSpecialAbilityConfig>
|
||||
export type CommandSpecialAbility = GetByIdFromConfig<typeof commandSpecialAbilityConfig>
|
||||
export type Condition = GetByIdFromConfig<typeof conditionConfig>
|
||||
export type Container = GetByIdFromConfig<typeof containerConfig>
|
||||
export type Continent = GetByIdFromConfig<typeof continentConfig>
|
||||
export type CoreRule = GetByIdFromConfig<typeof coreRuleConfig>
|
||||
export type Culture = GetByIdFromConfig<typeof cultureConfig>
|
||||
export type Curse = GetByIdFromConfig<typeof curseConfig>
|
||||
export type DaggerRitual = GetByIdFromConfig<typeof daggerRitualConfig>
|
||||
export type DerivedCharacteristic = GetByIdFromConfig<typeof derivedCharacteristicConfig>
|
||||
export type Disadvantage = GetByIdFromConfig<typeof disadvantageConfig>
|
||||
export type Disease = GetByIdFromConfig<typeof diseaseConfig>
|
||||
export type DominationRitual = GetByIdFromConfig<typeof dominationRitualConfig>
|
||||
export type Element = GetByIdFromConfig<typeof elementConfig>
|
||||
export type Elixir = GetByIdFromConfig<typeof elixirConfig>
|
||||
export type ElvenMagicalSong = GetByIdFromConfig<typeof elvenMagicalSongConfig>
|
||||
export type EquipmentOfBlessedOnes = GetByIdFromConfig<typeof equipmentOfBlessedOnesConfig>
|
||||
export type EquipmentPackage = GetByIdFromConfig<typeof equipmentPackageConfig>
|
||||
export type ExperienceLevel = GetByIdFromConfig<typeof experienceLevelConfig>
|
||||
export type EyeColor = GetByIdFromConfig<typeof eyeColorConfig>
|
||||
export type FamiliarSpecialAbility = GetByIdFromConfig<typeof familiarSpecialAbilityConfig>
|
||||
export type FamiliarsTrick = GetByIdFromConfig<typeof familiarsTrickConfig>
|
||||
export type FatePointSexSpecialAbility = GetByIdFromConfig<typeof fatePointSexSpecialAbilityConfig>
|
||||
export type FatePointSpecialAbility = GetByIdFromConfig<typeof fatePointSpecialAbilityConfig>
|
||||
export type FocusRule = GetByIdFromConfig<typeof focusRuleConfig>
|
||||
export type Subject = GetByIdFromConfig<typeof subjectConfig>
|
||||
export type FoolsHatEnchantment = GetByIdFromConfig<typeof foolsHatEnchantmentConfig>
|
||||
export type GemOrPreciousStone = GetByIdFromConfig<typeof gemOrPreciousStoneConfig>
|
||||
export type GeneralSpecialAbility = GetByIdFromConfig<typeof generalSpecialAbilityConfig>
|
||||
export type GeodeRitual = GetByIdFromConfig<typeof geodeRitualConfig>
|
||||
export type HairColor = GetByIdFromConfig<typeof hairColorConfig>
|
||||
export type IlluminationLightSource = GetByIdFromConfig<typeof illuminationLightSourceConfig>
|
||||
export type IlluminationRefillsOrSupplies = GetByIdFromConfig<typeof illuminationRefillsOrSuppliesConfig>
|
||||
export type InstrumentEnchantment = GetByIdFromConfig<typeof instrumentEnchantmentConfig>
|
||||
export type JesterTrick = GetByIdFromConfig<typeof jesterTrickConfig>
|
||||
export type Jewelry = GetByIdFromConfig<typeof jewelryConfig>
|
||||
export type KarmaSpecialAbility = GetByIdFromConfig<typeof karmaSpecialAbilityConfig>
|
||||
export type Kirchenpraegung = GetByIdFromConfig<typeof kirchenpraegungConfig>
|
||||
export type Krallenkettenzauber = GetByIdFromConfig<typeof krallenkettenzauberConfig>
|
||||
export type Language = GetByIdFromConfig<typeof languageConfig>
|
||||
export type Curriculum = GetByIdFromConfig<typeof curriculumConfig>
|
||||
export type Guideline = GetByIdFromConfig<typeof guidelineConfig>
|
||||
export type Liebesspielzeug = GetByIdFromConfig<typeof liebesspielzeugConfig>
|
||||
export type LiturgicalChant = GetByIdFromConfig<typeof liturgicalChantConfig>
|
||||
export type LiturgicalStyleSpecialAbility = GetByIdFromConfig<typeof liturgicalStyleSpecialAbilityConfig>
|
||||
export type Locale = GetByIdFromConfig<typeof localeConfig>
|
||||
export type LuxuryGood = GetByIdFromConfig<typeof luxuryGoodConfig>
|
||||
export type LycantropicGift = GetByIdFromConfig<typeof lycantropicGiftConfig>
|
||||
export type MagicalArtifact = GetByIdFromConfig<typeof magicalArtifactConfig>
|
||||
export type MagicalDance = GetByIdFromConfig<typeof magicalDanceConfig>
|
||||
export type MagicalMelody = GetByIdFromConfig<typeof magicalMelodyConfig>
|
||||
export type MagicalRune = GetByIdFromConfig<typeof magicalRuneConfig>
|
||||
export type MagicalSign = GetByIdFromConfig<typeof magicalSignConfig>
|
||||
export type MagicalSpecialAbility = GetByIdFromConfig<typeof magicalSpecialAbilityConfig>
|
||||
export type MagicalTradition = GetByIdFromConfig<typeof magicalTraditionConfig>
|
||||
export type MagicStyleSpecialAbility = GetByIdFromConfig<typeof magicStyleSpecialAbilityConfig>
|
||||
export type MetaCondition = GetByIdFromConfig<typeof metaConditionConfig>
|
||||
export type MusicalInstrument = GetByIdFromConfig<typeof musicalInstrumentConfig>
|
||||
export type OptionalRule = GetByIdFromConfig<typeof optionalRuleConfig>
|
||||
export type OrbEnchantment = GetByIdFromConfig<typeof orbEnchantmentConfig>
|
||||
export type OrienteeringAid = GetByIdFromConfig<typeof orienteeringAidConfig>
|
||||
export type PactCategory = GetByIdFromConfig<typeof pactCategoryConfig>
|
||||
export type PactGift = GetByIdFromConfig<typeof pactGiftConfig>
|
||||
export type PatronCategory = GetByIdFromConfig<typeof patronCategoryConfig>
|
||||
export type Patron = GetByIdFromConfig<typeof patronConfig>
|
||||
export type PersonalityTrait = GetByIdFromConfig<typeof personalityTraitConfig>
|
||||
export type Poison = GetByIdFromConfig<typeof poisonConfig>
|
||||
export type Profession = GetByIdFromConfig<typeof professionConfig>
|
||||
export type Property = GetByIdFromConfig<typeof propertyConfig>
|
||||
export type ProtectiveWardingCircleSpecialAbility = GetByIdFromConfig<typeof protectiveWardingCircleSpecialAbilityConfig>
|
||||
export type Publication = GetByIdFromConfig<typeof publicationConfig>
|
||||
export type Race = GetByIdFromConfig<typeof raceConfig>
|
||||
export type RangedCombatTechnique = GetByIdFromConfig<typeof rangedCombatTechniqueConfig>
|
||||
export type Reach = GetByIdFromConfig<typeof reachConfig>
|
||||
export type Region = GetByIdFromConfig<typeof regionConfig>
|
||||
export type RingEnchantment = GetByIdFromConfig<typeof ringEnchantmentConfig>
|
||||
export type Ritual = GetByIdFromConfig<typeof ritualConfig>
|
||||
export type RopeOrChain = GetByIdFromConfig<typeof ropeOrChainConfig>
|
||||
export type Script = GetByIdFromConfig<typeof scriptConfig>
|
||||
export type Sermon = GetByIdFromConfig<typeof sermonConfig>
|
||||
export type Service = GetByIdFromConfig<typeof serviceConfig>
|
||||
export type SexPractice = GetByIdFromConfig<typeof sexPracticeConfig>
|
||||
export type SexSpecialAbility = GetByIdFromConfig<typeof sexSpecialAbilityConfig>
|
||||
export type SickleRitual = GetByIdFromConfig<typeof sickleRitualConfig>
|
||||
export type SikaryanDrainSpecialAbility = GetByIdFromConfig<typeof sikaryanDrainSpecialAbilityConfig>
|
||||
export type SkillGroup = GetByIdFromConfig<typeof skillGroupConfig>
|
||||
export type SkillModificationLevel = GetByIdFromConfig<typeof skillModificationLevelConfig>
|
||||
export type Skill = GetByIdFromConfig<typeof skillConfig>
|
||||
export type SkillStyleSpecialAbility = GetByIdFromConfig<typeof skillStyleSpecialAbilityConfig>
|
||||
export type SocialStatus = GetByIdFromConfig<typeof socialStatusConfig>
|
||||
export type Spell = GetByIdFromConfig<typeof spellConfig>
|
||||
export type SpellSwordEnchantment = GetByIdFromConfig<typeof spellSwordEnchantmentConfig>
|
||||
export type StaffEnchantment = GetByIdFromConfig<typeof staffEnchantmentConfig>
|
||||
export type State = GetByIdFromConfig<typeof stateConfig>
|
||||
export type Stationary = GetByIdFromConfig<typeof stationaryConfig>
|
||||
export type Talisman = GetByIdFromConfig<typeof talismanConfig>
|
||||
export type TargetCategory = GetByIdFromConfig<typeof targetCategoryConfig>
|
||||
export type ThievesTool = GetByIdFromConfig<typeof thievesToolConfig>
|
||||
export type ToolOfTheTrade = GetByIdFromConfig<typeof toolOfTheTradeConfig>
|
||||
export type ToyEnchantment = GetByIdFromConfig<typeof toyEnchantmentConfig>
|
||||
export type TradeSecret = GetByIdFromConfig<typeof tradeSecretConfig>
|
||||
export type TravelGearOrTool = GetByIdFromConfig<typeof travelGearOrToolConfig>
|
||||
export type Trinkhornzauber = GetByIdFromConfig<typeof trinkhornzauberConfig>
|
||||
export type UI = GetByIdFromConfig<typeof uIConfig>
|
||||
export type VampiricGift = GetByIdFromConfig<typeof vampiricGiftConfig>
|
||||
export type Vehicle = GetByIdFromConfig<typeof vehicleConfig>
|
||||
export type Vision = GetByIdFromConfig<typeof visionConfig>
|
||||
export type WandEnchantment = GetByIdFromConfig<typeof wandEnchantmentConfig>
|
||||
export type WeaponAccessory = GetByIdFromConfig<typeof weaponAccessoryConfig>
|
||||
export type WeaponEnchantment = GetByIdFromConfig<typeof weaponEnchantmentConfig>
|
||||
export type Weapon = GetByIdFromConfig<typeof weaponConfig>
|
||||
export type ZibiljaRitual = GetByIdFromConfig<typeof zibiljaRitualConfig>
|
||||
}
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export namespace Singleton {
|
||||
export namespace Static {
|
||||
export type ExperienceLevel = TypeFromConfig<typeof experienceLevelConfig> | undefined
|
||||
}
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export namespace All {
|
||||
export namespace Static {
|
||||
export type AdvancedCombatSpecialAbilities = AllFromConfig<typeof advancedCombatSpecialAbilityConfig>
|
||||
export type AdvancedKarmaSpecialAbilities = AllFromConfig<typeof advancedKarmaSpecialAbilityConfig>
|
||||
export type AdvancedMagicalSpecialAbilities = AllFromConfig<typeof advancedMagicalSpecialAbilityConfig>
|
||||
export type AdvancedSkillSpecialAbilities = AllFromConfig<typeof advancedSkillSpecialAbilityConfig>
|
||||
export type Advantages = AllFromConfig<typeof advantageConfig>
|
||||
export type Ammunition = AllFromConfig<typeof ammunitionConfig>
|
||||
export type AncestorGlyphs = AllFromConfig<typeof ancestorGlyphConfig>
|
||||
export type AnimalCare = AllFromConfig<typeof animalCareConfig>
|
||||
export type AnimalDiseases = AllFromConfig<typeof animalDiseaseConfig>
|
||||
export type Animals = AllFromConfig<typeof animalConfig>
|
||||
export type AnimalShapePaths = AllFromConfig<typeof animalShapePathConfig>
|
||||
export type AnimalShapes = AllFromConfig<typeof animalShapeConfig>
|
||||
export type AnimalShapeSizes = AllFromConfig<typeof animalShapeSizeConfig>
|
||||
export type AnimalTypes = AllFromConfig<typeof animalTypeConfig>
|
||||
export type AnimistPowers = AllFromConfig<typeof animistPowerConfig>
|
||||
export type AnimistPowerTribes = AllFromConfig<typeof tribeConfig>
|
||||
export type ArcaneBardTraditions = AllFromConfig<typeof arcaneBardTraditionConfig>
|
||||
export type ArcaneDancerTraditions = AllFromConfig<typeof arcaneDancerTraditionConfig>
|
||||
export type ArcaneOrbEnchantments = AllFromConfig<typeof arcaneOrbEnchantmentConfig>
|
||||
export type Armors = AllFromConfig<typeof armorConfig>
|
||||
export type ArmorTypes = AllFromConfig<typeof armorTypeConfig>
|
||||
export type Aspects = AllFromConfig<typeof aspectConfig>
|
||||
export type AttireEnchantments = AllFromConfig<typeof attireEnchantmentConfig>
|
||||
export type Attributes = AllFromConfig<typeof attributeConfig>
|
||||
export type BandagesAndRemedies = AllFromConfig<typeof bandageOrRemedyConfig>
|
||||
export type BlessedTraditions = AllFromConfig<typeof blessedTraditionConfig>
|
||||
export type Blessings = AllFromConfig<typeof blessingConfig>
|
||||
export type Books = AllFromConfig<typeof bookConfig>
|
||||
export type BowlEnchantments = AllFromConfig<typeof bowlEnchantmentConfig>
|
||||
export type BrawlingSpecialAbilities = AllFromConfig<typeof brawlingSpecialAbilityConfig>
|
||||
export type Brews = AllFromConfig<typeof brewConfig>
|
||||
export type Cantrips = AllFromConfig<typeof cantripConfig>
|
||||
export type CauldronEnchantments = AllFromConfig<typeof cauldronEnchantmentConfig>
|
||||
export type CeremonialItems = AllFromConfig<typeof ceremonialItemConfig>
|
||||
export type CeremonialItemSpecialAbilities = AllFromConfig<typeof ceremonialItemSpecialAbilityConfig>
|
||||
export type Ceremonies = AllFromConfig<typeof ceremonyConfig>
|
||||
export type ChronicleEnchantments = AllFromConfig<typeof chronicleEnchantmentConfig>
|
||||
export type CloseCombatTechniques = AllFromConfig<typeof closeCombatTechniqueConfig>
|
||||
export type Clothes = AllFromConfig<typeof clothesConfig>
|
||||
export type CombatSpecialAbilities = AllFromConfig<typeof combatSpecialAbilityConfig>
|
||||
export type CombatStyleSpecialAbilities = AllFromConfig<typeof combatStyleSpecialAbilityConfig>
|
||||
export type CommandSpecialAbilities = AllFromConfig<typeof commandSpecialAbilityConfig>
|
||||
export type Conditions = AllFromConfig<typeof conditionConfig>
|
||||
export type Containers = AllFromConfig<typeof containerConfig>
|
||||
export type Continents = AllFromConfig<typeof continentConfig>
|
||||
export type CoreRules = AllFromConfig<typeof coreRuleConfig>
|
||||
export type Cultures = AllFromConfig<typeof cultureConfig>
|
||||
export type Curses = AllFromConfig<typeof curseConfig>
|
||||
export type DaggerRituals = AllFromConfig<typeof daggerRitualConfig>
|
||||
export type DerivedCharacteristics = AllFromConfig<typeof derivedCharacteristicConfig>
|
||||
export type Disadvantages = AllFromConfig<typeof disadvantageConfig>
|
||||
export type Diseases = AllFromConfig<typeof diseaseConfig>
|
||||
export type DominationRituals = AllFromConfig<typeof dominationRitualConfig>
|
||||
export type Elements = AllFromConfig<typeof elementConfig>
|
||||
export type Elixirs = AllFromConfig<typeof elixirConfig>
|
||||
export type ElvenMagicalSongs = AllFromConfig<typeof elvenMagicalSongConfig>
|
||||
export type EquipmentOfBlessedOnes = AllFromConfig<typeof equipmentOfBlessedOnesConfig>
|
||||
export type EquipmentPackages = AllFromConfig<typeof equipmentPackageConfig>
|
||||
export type ExperienceLevels = AllFromConfig<typeof experienceLevelConfig>
|
||||
export type EyeColors = AllFromConfig<typeof eyeColorConfig>
|
||||
export type FamiliarSpecialAbilities = AllFromConfig<typeof familiarSpecialAbilityConfig>
|
||||
export type FamiliarsTricks = AllFromConfig<typeof familiarsTrickConfig>
|
||||
export type FatePointSexSpecialAbilities = AllFromConfig<typeof fatePointSexSpecialAbilityConfig>
|
||||
export type FatePointSpecialAbilities = AllFromConfig<typeof fatePointSpecialAbilityConfig>
|
||||
export type FocusRules = AllFromConfig<typeof focusRuleConfig>
|
||||
export type FocusRuleSubjects = AllFromConfig<typeof subjectConfig>
|
||||
export type FoolsHatEnchantments = AllFromConfig<typeof foolsHatEnchantmentConfig>
|
||||
export type GemsAndPreciousStones = AllFromConfig<typeof gemOrPreciousStoneConfig>
|
||||
export type GeneralSpecialAbilities = AllFromConfig<typeof generalSpecialAbilityConfig>
|
||||
export type GeodeRituals = AllFromConfig<typeof geodeRitualConfig>
|
||||
export type HairColors = AllFromConfig<typeof hairColorConfig>
|
||||
export type IlluminationLightSources = AllFromConfig<typeof illuminationLightSourceConfig>
|
||||
export type IlluminationRefillsAndSupplies = AllFromConfig<typeof illuminationRefillsOrSuppliesConfig>
|
||||
export type InstrumentEnchantments = AllFromConfig<typeof instrumentEnchantmentConfig>
|
||||
export type JesterTricks = AllFromConfig<typeof jesterTrickConfig>
|
||||
export type Jewelry = AllFromConfig<typeof jewelryConfig>
|
||||
export type KarmaSpecialAbilities = AllFromConfig<typeof karmaSpecialAbilityConfig>
|
||||
export type Kirchenpraegungen = AllFromConfig<typeof kirchenpraegungConfig>
|
||||
export type Krallenkettenzauber = AllFromConfig<typeof krallenkettenzauberConfig>
|
||||
export type Languages = AllFromConfig<typeof languageConfig>
|
||||
export type LessonsCurricula = AllFromConfig<typeof curriculumConfig>
|
||||
export type LessonsGuidelines = AllFromConfig<typeof guidelineConfig>
|
||||
export type Liebesspielzeug = AllFromConfig<typeof liebesspielzeugConfig>
|
||||
export type LiturgicalChants = AllFromConfig<typeof liturgicalChantConfig>
|
||||
export type LiturgicalStyleSpecialAbilities = AllFromConfig<typeof liturgicalStyleSpecialAbilityConfig>
|
||||
export type Locales = AllFromConfig<typeof localeConfig>
|
||||
export type LuxuryGoods = AllFromConfig<typeof luxuryGoodConfig>
|
||||
export type LycantropicGifts = AllFromConfig<typeof lycantropicGiftConfig>
|
||||
export type MagicalArtifacts = AllFromConfig<typeof magicalArtifactConfig>
|
||||
export type MagicalDances = AllFromConfig<typeof magicalDanceConfig>
|
||||
export type MagicalMelodies = AllFromConfig<typeof magicalMelodyConfig>
|
||||
export type MagicalRunes = AllFromConfig<typeof magicalRuneConfig>
|
||||
export type MagicalSigns = AllFromConfig<typeof magicalSignConfig>
|
||||
export type MagicalSpecialAbilities = AllFromConfig<typeof magicalSpecialAbilityConfig>
|
||||
export type MagicalTraditions = AllFromConfig<typeof magicalTraditionConfig>
|
||||
export type MagicStyleSpecialAbilities = AllFromConfig<typeof magicStyleSpecialAbilityConfig>
|
||||
export type MetaConditions = AllFromConfig<typeof metaConditionConfig>
|
||||
export type MusicalInstruments = AllFromConfig<typeof musicalInstrumentConfig>
|
||||
export type OptionalRules = AllFromConfig<typeof optionalRuleConfig>
|
||||
export type OrbEnchantments = AllFromConfig<typeof orbEnchantmentConfig>
|
||||
export type OrienteeringAids = AllFromConfig<typeof orienteeringAidConfig>
|
||||
export type PactCategories = AllFromConfig<typeof pactCategoryConfig>
|
||||
export type PactGifts = AllFromConfig<typeof pactGiftConfig>
|
||||
export type PatronCategories = AllFromConfig<typeof patronCategoryConfig>
|
||||
export type Patrons = AllFromConfig<typeof patronConfig>
|
||||
export type PersonalityTraits = AllFromConfig<typeof personalityTraitConfig>
|
||||
export type Poisons = AllFromConfig<typeof poisonConfig>
|
||||
export type Professions = AllFromConfig<typeof professionConfig>
|
||||
export type Properties = AllFromConfig<typeof propertyConfig>
|
||||
export type ProtectiveWardingCircleSpecialAbilities = AllFromConfig<typeof protectiveWardingCircleSpecialAbilityConfig>
|
||||
export type Publications = AllFromConfig<typeof publicationConfig>
|
||||
export type Races = AllFromConfig<typeof raceConfig>
|
||||
export type RangedCombatTechniques = AllFromConfig<typeof rangedCombatTechniqueConfig>
|
||||
export type Reaches = AllFromConfig<typeof reachConfig>
|
||||
export type Regions = AllFromConfig<typeof regionConfig>
|
||||
export type RingEnchantments = AllFromConfig<typeof ringEnchantmentConfig>
|
||||
export type Rituals = AllFromConfig<typeof ritualConfig>
|
||||
export type RopesAndChains = AllFromConfig<typeof ropeOrChainConfig>
|
||||
export type Scripts = AllFromConfig<typeof scriptConfig>
|
||||
export type Sermons = AllFromConfig<typeof sermonConfig>
|
||||
export type Services = AllFromConfig<typeof serviceConfig>
|
||||
export type SexPractices = AllFromConfig<typeof sexPracticeConfig>
|
||||
export type SexSpecialAbilities = AllFromConfig<typeof sexSpecialAbilityConfig>
|
||||
export type SickleRituals = AllFromConfig<typeof sickleRitualConfig>
|
||||
export type SikaryanDrainSpecialAbilities = AllFromConfig<typeof sikaryanDrainSpecialAbilityConfig>
|
||||
export type SkillGroups = AllFromConfig<typeof skillGroupConfig>
|
||||
export type SkillModificationLevels = AllFromConfig<typeof skillModificationLevelConfig>
|
||||
export type Skills = AllFromConfig<typeof skillConfig>
|
||||
export type SkillStyleSpecialAbilities = AllFromConfig<typeof skillStyleSpecialAbilityConfig>
|
||||
export type SocialStatuses = AllFromConfig<typeof socialStatusConfig>
|
||||
export type Spells = AllFromConfig<typeof spellConfig>
|
||||
export type SpellSwordEnchantments = AllFromConfig<typeof spellSwordEnchantmentConfig>
|
||||
export type StaffEnchantments = AllFromConfig<typeof staffEnchantmentConfig>
|
||||
export type States = AllFromConfig<typeof stateConfig>
|
||||
export type Stationary = AllFromConfig<typeof stationaryConfig>
|
||||
export type Talismans = AllFromConfig<typeof talismanConfig>
|
||||
export type TargetCategories = AllFromConfig<typeof targetCategoryConfig>
|
||||
export type ThievesTools = AllFromConfig<typeof thievesToolConfig>
|
||||
export type ToolsOfTheTrade = AllFromConfig<typeof toolOfTheTradeConfig>
|
||||
export type ToyEnchantments = AllFromConfig<typeof toyEnchantmentConfig>
|
||||
export type TradeSecrets = AllFromConfig<typeof tradeSecretConfig>
|
||||
export type TravelGearAndTools = AllFromConfig<typeof travelGearOrToolConfig>
|
||||
export type Trinkhornzauber = AllFromConfig<typeof trinkhornzauberConfig>
|
||||
export type UI = AllFromConfig<typeof uIConfig>
|
||||
export type VampiricGifts = AllFromConfig<typeof vampiricGiftConfig>
|
||||
export type Vehicles = AllFromConfig<typeof vehicleConfig>
|
||||
export type Visions = AllFromConfig<typeof visionConfig>
|
||||
export type WandEnchantments = AllFromConfig<typeof wandEnchantmentConfig>
|
||||
export type WeaponAccessories = AllFromConfig<typeof weaponAccessoryConfig>
|
||||
export type WeaponEnchantments = AllFromConfig<typeof weaponEnchantmentConfig>
|
||||
export type Weapons = AllFromConfig<typeof weaponConfig>
|
||||
export type ZibiljaRituals = AllFromConfig<typeof zibiljaRitualConfig>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { UI } from "optolith-database-schema/types/UI"
|
||||
import { LocaleMap } from "optolith-database-schema/types/_LocaleMap"
|
||||
|
||||
/**
|
||||
* Translates a given key into a string, optionally with parameters.
|
||||
*/
|
||||
export type Translate = <K extends keyof UI>(
|
||||
key: K,
|
||||
...params: (string | number)[]
|
||||
) => string
|
||||
|
||||
const insertParams = (str: string, params: (string | number)[]): string =>
|
||||
str.replace(
|
||||
/\{(?<index>\d+)\}/gu,
|
||||
(_match, _p1, _offset, _s, { index: rawIndex }) => {
|
||||
const index = Number.parseInt(rawIndex, 10)
|
||||
return params[index]?.toString() ?? `{${rawIndex}}`
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* A mocked translate function.
|
||||
*/
|
||||
export const translateMock: Translate = <K extends keyof UI>(
|
||||
key: K,
|
||||
...options: (string | number)[]
|
||||
) => insertParams(key, options)
|
||||
|
||||
/**
|
||||
* Selects a value from a locale dictionary based on the selected locale.
|
||||
*/
|
||||
export type TranslateMap = <T>(map: LocaleMap<T> | undefined) => T | undefined
|
||||
@@ -0,0 +1,80 @@
|
||||
import { filterNonNullable } from "@optolith/helpers/array"
|
||||
import { Compare } from "@optolith/helpers/compare"
|
||||
import { PublicationRefs } from "optolith-database-schema/types/source/_PublicationRef"
|
||||
import { Translate, TranslateMap } from "./helpers/translate.js"
|
||||
|
||||
/**
|
||||
* Creates a function that creates the JSON representation of the rules text for
|
||||
* a library entry.
|
||||
*/
|
||||
export const createLibraryEntryCreator =
|
||||
<T, A = undefined>(
|
||||
fn: LibraryEntryCreator<T, A, RawLibraryEntry>
|
||||
): LibraryEntryCreator<T | undefined, A> =>
|
||||
(entry, ...args) => {
|
||||
if (entry === undefined) {
|
||||
return () => undefined
|
||||
}
|
||||
|
||||
return (params) => {
|
||||
const rawEntry = fn(entry, ...args)(params)
|
||||
|
||||
if (rawEntry === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return { ...rawEntry, content: filterNonNullable(rawEntry.content) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that creates the JSON representation of the rules text for a
|
||||
* library entry if given further params to the returned function.
|
||||
*/
|
||||
export type LibraryEntryCreator<T, A = undefined, R = LibraryEntry> = (
|
||||
entry: T,
|
||||
...args: A extends undefined ? [] : [A]
|
||||
) => LibraryEntryConfiguredCreator<R>
|
||||
|
||||
/**
|
||||
* A function that is already configures for a specific entity and returns the
|
||||
* JSON representation of the rules text for a ibrary entry.
|
||||
*/
|
||||
export type LibraryEntryConfiguredCreator<R = LibraryEntry> = (params: {
|
||||
translate: Translate
|
||||
translateMap: TranslateMap
|
||||
localeCompare: Compare<string>
|
||||
}) => R | undefined
|
||||
|
||||
/**
|
||||
* A JSON representation of the rules text for a library entry.
|
||||
*/
|
||||
export type LibraryEntry = {
|
||||
title: string
|
||||
subtitle?: string
|
||||
className: string
|
||||
content: LibraryEntryContent[]
|
||||
src?: PublicationRefs
|
||||
}
|
||||
|
||||
/**
|
||||
* A JSON representation of the rules text for a library entry that has not been
|
||||
* cleaned up.
|
||||
*/
|
||||
export type RawLibraryEntry = {
|
||||
title: string
|
||||
subtitle?: string
|
||||
className: string
|
||||
content: (LibraryEntryContent | undefined)[]
|
||||
src?: PublicationRefs
|
||||
}
|
||||
|
||||
/**
|
||||
* A slice of the content of a library entry text.
|
||||
*/
|
||||
export type LibraryEntryContent = {
|
||||
label?: string
|
||||
value: string | number
|
||||
noIndent?: boolean
|
||||
className?: string
|
||||
}
|
||||
Reference in New Issue
Block a user