refactor: restructure activatable skill partial helpers

This commit is contained in:
Lukas Obermann
2024-10-06 20:44:48 +02:00
parent f5917f9195
commit ed9d0a2297
31 changed files with 1632 additions and 1456 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
"build": "tsc -b",
"watch": "tsc -b -w",
"release": "commit-and-tag-version",
"test": "glob -c \"node --import tsx --test\" \"./src/**/*.test.ts\""
"test": "glob -c \"node --import tsx --test\" \"./test/**/*.ts\""
},
"repository": {
"type": "git",
+54 -72
View File
@@ -13,17 +13,17 @@ import {
createLibraryEntryCreator,
LibraryEntryContent,
} from "../libraryEntry.js"
import { getTextForBlessingDuration } from "./partial/rated/activatable/duration.js"
import { getDurationTranslationForBlessing } 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,
getFastOneTimePerformanceParametersTranslations,
getFastSustainedPerformanceParametersTranslations,
getSlowOneTimePerformanceParametersTranslations,
getSlowSustainedPerformanceParametersTranslations,
} from "./partial/rated/activatable/index.js"
import { getTextForBlessingRange } from "./partial/rated/activatable/range.js"
import { getTextForTargetCategory } from "./partial/rated/activatable/targetCategory.js"
import { getTargetCategoryTranslation } 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"
@@ -92,23 +92,24 @@ export const getBlessingLibraryEntry = createLibraryEntryCreator<
{
getTargetCategoryById: GetById.Static.TargetCategory
}
>((entry, { getTargetCategoryById }) => ({ translate, translateMap }) => {
>((entry, { getTargetCategoryById }) => (locale) => {
const { translate, translateMap } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
return undefined
}
const range = getTextForBlessingRange({ translate }, entry.parameters.range, {
responsiveText: ResponsiveTextSize.Full,
})
const range = getTextForBlessingRange(
locale,
ResponsiveTextSize.Full,
entry.parameters.range
)
const duration = getTextForBlessingDuration(
{ translate, translateMap },
entry.parameters.duration,
{
responsiveText: ResponsiveTextSize.Full,
}
const duration = getDurationTranslationForBlessing(
locale,
ResponsiveTextSize.Full,
entry.parameters.duration
)
return {
@@ -133,10 +134,7 @@ export const getBlessingLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
entry.target
),
getTargetCategoryTranslation(getTargetCategoryById, locale, entry.target),
],
src: entry.src,
}
@@ -169,7 +167,8 @@ export const getLiturgicalChantLibraryEntry = createLibraryEntryCreator<
getAspectById,
}
) =>
({ translate, translateMap, localeCompare }) => {
(locale) => {
const { translate, translateMap, compare: localeCompare } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
@@ -179,31 +178,21 @@ export const getLiturgicalChantLibraryEntry = createLibraryEntryCreator<
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,
}
return getFastOneTimePerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.LiturgicalChant,
ResponsiveTextSize.Full,
entry.parameters.one_time
)
case "Sustained":
return getTextForFastSustainedPerformanceParameters(
{
getSkillModificationLevelById,
translate,
translateMap,
},
entry.parameters.sustained,
{
entity: Entity.LiturgicalChant,
responsiveText: ResponsiveTextSize.Full,
}
return getFastSustainedPerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.LiturgicalChant,
ResponsiveTextSize.Full,
entry.parameters.sustained
)
default:
@@ -225,7 +214,7 @@ export const getLiturgicalChantLibraryEntry = createLibraryEntryCreator<
getToughness,
}
),
...getTextForEffect(translation.effect, translate),
...getTextForEffect(locale, translation.effect),
{
label: translate("Liturgical Time"),
value:
@@ -254,8 +243,9 @@ export const getLiturgicalChantLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration.full})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
getTargetCategoryTranslation(
getTargetCategoryById,
locale,
entry.target
),
getTextForTraditions(
@@ -302,7 +292,8 @@ export const getCeremonyLibraryEntry = createLibraryEntryCreator<
getAspectById,
}
) =>
({ translate, translateMap, localeCompare }) => {
(locale) => {
const { translate, translateMap, compare: localeCompare } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
@@ -312,31 +303,21 @@ export const getCeremonyLibraryEntry = createLibraryEntryCreator<
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,
}
return getSlowOneTimePerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Ritual,
ResponsiveTextSize.Full,
entry.parameters.one_time
)
case "Sustained":
return getTextForSlowSustainedPerformanceParameters(
{
getSkillModificationLevelById,
translate,
translateMap,
},
entry.parameters.sustained,
{
entity: Entity.Ceremony,
responsiveText: ResponsiveTextSize.Full,
}
return getSlowSustainedPerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Ceremony,
ResponsiveTextSize.Full,
entry.parameters.sustained
)
default:
@@ -358,7 +339,7 @@ export const getCeremonyLibraryEntry = createLibraryEntryCreator<
getToughness,
}
),
...getTextForEffect(translation.effect, translate),
...getTextForEffect(locale, translation.effect),
{
label: translate("Ceremonial Time"),
value:
@@ -387,8 +368,9 @@ export const getCeremonyLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration.full})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
getTargetCategoryTranslation(
getTargetCategoryById,
locale,
entry.target
),
getTextForTraditions(
@@ -3,6 +3,7 @@ import { assertExhaustive } from "@optolith/helpers/typeSafety"
import {
CastingTime,
CastingTimeDuringLovemaking,
CastingTimeIncludingLovemaking,
FastCastingTime,
FastSkillNonModifiableCastingTime,
ModifiableCastingTime,
@@ -10,188 +11,179 @@ import {
SlowSkillNonModifiableCastingTime,
} from "optolith-database-schema/types/_ActivatableSkillCastingTime"
import { GetById } from "../../../../helpers/getTypes.js"
import { Translate } from "../../../../helpers/translate.js"
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import { ResponsiveTextSize } from "../../responsiveText.js"
import { formatTimeSpan } from "../../units/timeSpan.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"
import {
getNonModifiableSuffixTranslation,
ModifiableParameter,
} from "./nonModifiableSuffix.js"
import { getModifiableBySpeed, Speed } from "./speed.js"
const getTextForModifiableCastingTime = (
deps: {
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
translate: Translate
},
value: ModifiableCastingTime,
env: {
speed: Speed
responsiveText: ResponsiveTextSize
}
const getModifiableCastingTimeTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
responsiveTextSize: ResponsiveTextSize,
value: ModifiableCastingTime
): 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,
getSkillModificationLevelById(value.initial_modification_level),
(modificationLevel) =>
getModifiableBySpeed(
(config) =>
formatTimeSpan(
locale,
responsiveTextSize,
"Actions",
fastTime
)
case Speed.Slow:
return formatTimeSpan(
deps.translate,
env.responsiveText,
slowTime.unit,
slowTime.value
)
default:
return assertExhaustive(env.speed)
}
}
config.casting_time
),
(config) =>
formatTimeSpan(
locale,
responsiveTextSize,
config.casting_time.unit,
config.casting_time.value
),
speed,
modificationLevel
)
) ?? MISSING_VALUE
const getTextForFastSkillNonModifiableCastingTime = (
deps: {
translate: Translate
},
value: FastSkillNonModifiableCastingTime,
env: {
entity: Entity
responsiveText: ResponsiveTextSize
}
const getFastSkillNonModifiableCastingTimeTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: FastSkillNonModifiableCastingTime
): string =>
formatTimeSpan(deps.translate, env.responsiveText, "Actions", value.actions) +
getTextForNonModifiableSuffix(
deps.translate,
env.entity,
ModifiableParameter.CastingTime,
env.responsiveText
)
formatTimeSpan(locale, responsiveTextSize, "Actions", value.actions)
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 getSlowSkillNonModifiableCastingTimeTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: SlowSkillNonModifiableCastingTime
): string => formatTimeSpan(locale, responsiveTextSize, value.unit, value.value)
const getTextForCastingTime = <NonModifiable extends object>(
deps: {
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
translate: Translate
},
value: CastingTime<NonModifiable>,
env: {
speed: Speed
responsiveText: ResponsiveTextSize
},
getTextForNonModifiableCastingTime: (value: NonModifiable) => string
const getCastingTimeTranslation = <NonModifiable extends object>(
getNonModifiableCastingTimeTranslation: (value: NonModifiable) => string,
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: CastingTime<NonModifiable>
): string => {
switch (value.tag) {
case "Modifiable":
return getTextForModifiableCastingTime(deps, value.modifiable, env)
return getModifiableCastingTimeTranslation(
getSkillModificationLevelById,
locale,
speed,
responsiveTextSize,
value.modifiable
)
case "NonModifiable":
return getTextForNonModifiableCastingTime(value.non_modifiable)
return (
getNonModifiableCastingTimeTranslation(value.non_modifiable) +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.CastingTime,
responsiveTextSize
)
)
default:
return assertExhaustive(value)
}
}
const getTextForCastingTimeDuringLovemaking = (
deps: {
translate: Translate
},
value: CastingTimeDuringLovemaking,
env: {
responsiveText: ResponsiveTextSize
}
): string =>
formatTimeSpan(deps.translate, env.responsiveText, value.unit, value.value)
const getCastingTimeDuringLovemakingTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: CastingTimeDuringLovemaking
): string => formatTimeSpan(locale, responsiveTextSize, value.unit, value.value)
const getCastingTimeIncludingLovemakingTranslation = <
NonModifiable extends object
>(
getNonModifiableCastingTimeTranslation: (value: NonModifiable) => string,
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: CastingTimeIncludingLovemaking<NonModifiable>
) =>
[
mapNullable(value.default, (def) =>
getCastingTimeTranslation(
getNonModifiableCastingTimeTranslation,
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
def
)
),
mapNullable(value.during_lovemaking, (duringLovemaking) =>
getCastingTimeDuringLovemakingTranslation(
locale,
responsiveTextSize,
duringLovemaking
)
),
]
.filter(isNotNullish)
.join(" / ")
/**
* 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
}
export const getFastCastingTimeTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: FastCastingTime
): 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(" / ")
getCastingTimeIncludingLovemakingTranslation(
(nonModifiableValue) =>
getFastSkillNonModifiableCastingTimeTranslation(
locale,
responsiveTextSize,
nonModifiableValue
),
getSkillModificationLevelById,
locale,
Speed.Fast,
entity,
responsiveTextSize,
value
)
/**
* 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
}
export const getSlowCastingTimeTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: SlowCastingTime
): 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(" / ")
getCastingTimeIncludingLovemakingTranslation(
(nonModifiableValue) =>
getSlowSkillNonModifiableCastingTimeTranslation(
locale,
responsiveTextSize,
nonModifiableValue
),
getSkillModificationLevelById,
locale,
Speed.Slow,
entity,
responsiveTextSize,
value
)
@@ -1,31 +0,0 @@
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"
)
})
})
@@ -7,9 +7,9 @@ import {
} from "optolith-database-schema/types/_ActivatableSkillCheckResultBased"
import { Translate } from "../../../../helpers/translate.js"
const getCheckResultBaseValue = (
baseValue: CheckResultValue,
translate: Translate
const getCheckResultBaseValueTranslation = (
translate: Translate,
baseValue: CheckResultValue
) => {
switch (baseValue) {
case "QualityLevels":
@@ -36,11 +36,11 @@ const getArithmeticSymbol = (arithmetic: CheckResultArithmetic) => {
* Returns the value text for a check-result-based parameter of an activatable
* skill.
*/
export const getTextForCheckResultBased = (
value: CheckResultBased,
translate: Translate
export const getCheckResultBasedValueTranslation = (
translate: Translate,
value: CheckResultBased
): string =>
getCheckResultBaseValue(value.base, translate) +
getCheckResultBaseValueTranslation(translate, value.base) +
mapNullableDefault(
value.modifier,
(modifier) => getArithmeticSymbol(modifier.arithmetic) + modifier.value,
+346 -317
View File
@@ -4,247 +4,246 @@ import {
CostMap,
IndefiniteOneTimeCost,
ModifiableOneTimeCost,
ModifiableSustainedCost,
MultipleOneTimeCosts,
NonModifiableOneTimeCost,
NonModifiableOneTimeCostPerCountable,
NonModifiableSustainedCost,
OneTimeCost,
SingleOneTimeCost,
SustainedCost,
} from "optolith-database-schema/types/_ActivatableSkillCost"
import { GetById } from "../../../../helpers/getTypes.js"
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import {
appendNoteIfRequested,
getResponsiveText,
getResponsiveTextOptional,
replaceTextIfRequested,
responsive,
ResponsiveTextSize,
} from "../../responsiveText.js"
import { formatEnergyByEntity } from "../../units/energy.js"
import { formatTimeSpan } from "../../units/timeSpan.js"
import { MISSING_VALUE } from "../../unknown.js"
import { Entity } from "./entity.js"
import { ModifiableParameter } from "./modifiableParameter.js"
import { getTextForNonModifiableSuffix } from "./nonModifiable.js"
import { wrapIfMinimum } from "./isMinimumMaximum.js"
import {
getNonModifiableSuffixTranslation,
ModifiableParameter,
} from "./nonModifiableSuffix.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
}
const getModifiableOneTimeCostTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
entity: Entity,
speed: Speed,
value: ModifiableOneTimeCost
): string =>
mapNullable(
deps.getSkillModificationLevelById(value.initial_modification_level),
getSkillModificationLevelById(value.initial_modification_level),
(modificationLevel) => {
const cost = getModifiableBySpeed(
modificationLevel,
env.speed,
(config) => config.cost,
(config) => config.cost
(config) => config.cost,
speed,
modificationLevel
)
return replaceTextIfRequested(
"replacement",
value.translations,
formatCost(deps.translate, env.entity, cost),
deps.translateMap,
env.responsiveText
locale.translateMap,
responsiveTextSize,
formatEnergyByEntity(locale, entity, cost)
)
}
) ?? 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
}
const getNonModifiableOneTimeCostPerCountableTranslation = (
formatCost: (x: number | string) => string,
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: NonModifiableOneTimeCostPerCountable | undefined
) =>
mapNullable(value, (perCountable) => {
const entity = getResponsiveText(
locale.translateMap(perCountable.translations)?.countable,
responsiveTextSize
)
const countableText = responsive(
env.responsiveText,
(entity) => deps.translate(" per {0}", entity),
(entity) => deps.translate("/{0}", entity),
getResponsiveText(
deps.translateMap(perCountable.translations)?.countable,
env.responsiveText
)
responsiveTextSize,
() => locale.translate(" per {0}", entity),
() => locale.translate("/{0}", entity)
)
const minimumTotalText =
mapNullable(perCountable.minimum_total, (minimumTotal) =>
deps.translate(", minimum of {0}", deps.formatCost(minimumTotal))
locale.translate(", minimum of {0}", formatCost(minimumTotal))
) ?? ""
return countableText + minimumTotalText
}) ?? ""
const getTextForPermanentValue = (
value: number | undefined,
responsiveText: ResponsiveTextSize,
translate: Translate
const getPermanentValueTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
permanentValue: number | undefined
) =>
value === undefined
permanentValue === undefined
? ""
: responsive(
responsiveText,
(perm) => translate(", {0} of which are permanent", perm),
(perm) => translate(" ({0} perm.)", perm),
value
responsiveTextSize,
() => locale.translate(", {0} of which are permanent", permanentValue),
() => locale.translate(" ({0} perm.)", permanentValue)
)
const getTextForNonModifiableOneTimeCost = (
deps: { translate: Translate; translateMap: TranslateMap },
value: NonModifiableOneTimeCost,
env: {
responsiveText: ResponsiveTextSize
entity: Entity
}
const getNonModifiableOneTimeCostTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: NonModifiableOneTimeCost
): string => {
const isMinimum = getMinimumText(
const formatCostP = formatEnergyByEntity.bind(this, locale, entity)
const perCountable = getNonModifiableOneTimeCostPerCountableTranslation(
formatCostP,
locale,
responsiveTextSize,
value.per
)
const permanentValue = getPermanentValueTranslation(
locale,
responsiveTextSize,
value.permanent_value
)
const costWrappedIfMinimum = wrapIfMinimum(
locale,
responsiveTextSize,
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})`,
""
formatCostP(value.value) + perCountable + permanentValue
)
const cannotModify = getTextForNonModifiableSuffix(
deps.translate,
env.entity,
const withNote = appendNoteIfRequested(
"note",
value.translations,
locale.translateMap,
responsiveTextSize,
costWrappedIfMinimum
)
const cannotModify = getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Cost,
env.responsiveText
responsiveTextSize
)
return (
isMinimum + formatCostP(value.value) + per + permanent + note + cannotModify
)
return withNote + cannotModify
}
const getTextForIndefiniteOneTimeCost = (
deps: { translate: Translate; translateMap: TranslateMap },
value: IndefiniteOneTimeCost,
env: {
responsiveText: ResponsiveTextSize
entity: Entity
}
const getIndefiniteOneTimeCostTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: IndefiniteOneTimeCost
): string =>
(getResponsiveText(
deps.translateMap(value.translations)?.description,
env.responsiveText
) ?? "") +
getTextForNonModifiableSuffix(
deps.translate,
env.entity,
getResponsiveText(
locale.translateMap(value.translations)?.description,
responsiveTextSize
) +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Cost,
env.responsiveText
responsiveTextSize
)
const getTextForSingleOneTimeCost = (
deps: {
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
translate: Translate
translateMap: TranslateMap
},
value: SingleOneTimeCost,
env: {
speed: Speed
responsiveText: ResponsiveTextSize
entity: Entity
}
const getSingleOneTimeCostTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: SingleOneTimeCost
): string => {
switch (value.tag) {
case "Modifiable":
return getTextForModifiableOneTimeCost(deps, value.modifiable, env)
return getModifiableOneTimeCostTranslation(
getSkillModificationLevelById,
locale,
responsiveTextSize,
entity,
speed,
value.modifiable
)
case "NonModifiable":
return getTextForNonModifiableOneTimeCost(deps, value.non_modifiable, env)
return getNonModifiableOneTimeCostTranslation(
locale,
entity,
responsiveTextSize,
value.non_modifiable
)
case "Indefinite":
return getTextForIndefiniteOneTimeCost(deps, value.indefinite, env)
return getIndefiniteOneTimeCostTranslation(
locale,
entity,
responsiveTextSize,
value.indefinite
)
default:
return assertExhaustive(value)
}
}
const getTextForMultipleOneTimeCosts = (
deps: {
getSkillModificationLevelById: GetById.Static.SkillModificationLevel
translate: Translate
translateMap: TranslateMap
},
value: MultipleOneTimeCosts,
const getMultipleOneTimeCostsTranslation = (
type: "conjunction" | "disjunction",
env: {
speed: Speed
responsiveText: ResponsiveTextSize
entity: Entity
}
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: MultipleOneTimeCosts
): string => {
const modifiable = !value.every((part) => part.tag === "Modifiable")
? getTextForNonModifiableSuffix(
deps.translate,
env.entity,
? getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Cost,
env.responsiveText
responsiveTextSize
)
: ""
return (
value
.map((part) => getTextForSingleOneTimeCost(deps, part, env))
.map((part) =>
getSingleOneTimeCostTranslation(
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
part
)
)
.join(
(() => {
switch (type) {
case "conjunction":
return responsive(
env.responsiveText,
() => deps.translate(" and "),
() => deps.translate(" + ")
responsiveTextSize,
() => locale.translate(" and "),
() => locale.translate(" + ")
)
case "disjunction":
return responsive(
env.responsiveText,
() => deps.translate(" or "),
() => deps.translate(" / ")
responsiveTextSize,
() => locale.translate(" or "),
() => locale.translate(" / ")
)
default:
return assertExhaustive(type)
@@ -254,18 +253,13 @@ const getTextForMultipleOneTimeCosts = (
)
}
const getTextForCostMap = (
deps: {
translate: Translate
translateMap: TranslateMap
},
value: CostMap,
env: {
responsiveText: ResponsiveTextSize
entity: Entity
}
const getCostMapTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: CostMap
): string => {
const translation = deps.translateMap(value.translations)
const translation = locale.translateMap(value.translations)
if (value.translations !== undefined && translation === undefined) {
return MISSING_VALUE
@@ -275,29 +269,33 @@ const getTextForCostMap = (
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
(option) =>
locale.translateMap(option.translations)?.label ?? MISSING_VALUE
)
.join("/")
const costs = value.options.map((option) => option.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,
const formatCostP = formatEnergyByEntity.bind(this, locale, entity)
const notModifiable = getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Cost,
env.responsiveText
responsiveTextSize
)
return (
formatCostP(costs) +
deps.translate(" for ") +
locale.translate(" for ") +
mapNullableDefault(
translation?.list_prepend,
(listPrepend) => `${listPrepend} `,
@@ -306,7 +304,7 @@ const getTextForCostMap = (
labels +
(translation?.list_append ?? "") +
(permanentCosts !== undefined
? deps.translate(
? locale.translate(
", {0} of which are permanent",
formatCostP(permanentCosts)
)
@@ -318,172 +316,203 @@ const getTextForCostMap = (
/**
* 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
}
export const getOneTimeCostTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: OneTimeCost
): string => {
switch (value.tag) {
case "Single":
return getTextForSingleOneTimeCost(deps, value.single, env)
return getSingleOneTimeCostTranslation(
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
value.single
)
case "Conjunction":
return getTextForMultipleOneTimeCosts(
deps,
value.conjunction,
return getMultipleOneTimeCostsTranslation(
"conjunction",
env
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
value.conjunction
)
case "Disjunction":
return getTextForMultipleOneTimeCosts(
deps,
value.disjunction,
return getMultipleOneTimeCostsTranslation(
"disjunction",
env
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
value.disjunction
)
case "Map":
return getTextForCostMap(deps, value.map, env)
return getCostMapTranslation(
locale,
entity,
responsiveTextSize,
value.map
)
default:
return assertExhaustive(value)
}
}
const getModifiableSustainedCostTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: ModifiableSustainedCost
) =>
mapNullable(
getSkillModificationLevelById(value.initial_modification_level),
(modificationLevel) => {
const cost = getModifiableBySpeed(
(config) => config.cost,
(config) => config.cost,
speed,
modificationLevel
)
const formatCostP = formatEnergyByEntity.bind(this, locale, entity)
const interval = formatTimeSpan(
locale,
responsiveTextSize,
value.interval.unit,
value.interval.value
)
return responsive(
responsiveTextSize,
() =>
`${formatCostP(cost) + locale.translate(" (casting)")} + ${
formatCostP(cost / 2) + locale.translate(" per {0}", interval)
}`,
() =>
`${formatCostP(cost)} + ${
formatCostP(cost / 2) + locale.translate("/{0}", interval)
}`
)
}
) ?? MISSING_VALUE
const getNonModifiableSustainedCostTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: NonModifiableSustainedCost
) => {
const formatCostP = formatEnergyByEntity.bind(this, locale, entity)
const per = (() => {
if (value.per === undefined) {
return { countable: "", minimumTotal: "" }
}
const countable = responsive(
responsiveTextSize,
(entity) => locale.translate(" per {0}", entity),
(entity) => locale.translate("/{0}", entity),
getResponsiveText(
locale.translateMap(value.per.translations)?.countable,
responsiveTextSize
)
)
const minimumTotal =
value.per.minimum_total !== undefined
? locale.translate(
", minimum of {0}",
formatCostP(value.per.minimum_total)
)
: ""
return { countable, minimumTotal }
})()
const interval = formatTimeSpan(
locale,
responsiveTextSize,
value.interval.unit,
value.interval.value
)
const cost =
responsive(
responsiveTextSize,
() =>
`${formatCostP(value.value) + locale.translate(" (casting)")} + ${
(value.is_minimum === true
? locale.translate("half of the activation cost")
: formatCostP(value.value / 2)) +
per.countable +
locale.translate(" per {0}", interval)
}`,
() =>
`${formatCostP(value.value)} + ${
(value.is_minimum === true ? "50%" : formatCostP(value.value / 2)) +
per.countable +
locale.translate("/{0}", interval)
}`
) + per.minimumTotal
const costWrappedIfMinimum = wrapIfMinimum(
locale,
responsiveTextSize,
value.is_minimum,
cost
)
return (
costWrappedIfMinimum +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Cost,
responsiveTextSize
)
)
}
/**
* 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
}
export const getSustainedCostTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: SustainedCost
): string => {
switch (value.tag) {
case "Modifiable": {
const modificationLevel = deps.getSkillModificationLevelById(
value.modifiable.initial_modification_level
case "Modifiable":
return getModifiableSustainedCostTranslation(
getSkillModificationLevelById,
locale,
speed,
entity,
responsiveTextSize,
value.modifiable
)
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
case "NonModifiable":
return getNonModifiableSustainedCostTranslation(
locale,
entity,
responsiveTextSize,
value.non_modifiable
)
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)
}
+176 -174
View File
@@ -1,176 +1,165 @@
import { mapNullableDefault } from "@optolith/helpers/nullable"
import { mapNullable } from "@optolith/helpers/nullable"
import { assertExhaustive } from "@optolith/helpers/typeSafety"
import { CastingTimeDuringLovemaking } from "optolith-database-schema/types/_ActivatableSkillCastingTime"
import {
CheckResultBasedDuration,
DurationForOneTime,
DurationForSustained,
FixedDuration,
Immediate,
IndefiniteDuration,
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 { LocaleEnvironment } from "../../../../helpers/locale.js"
import {
getResponsiveText,
replaceTextIfRequested,
responsive,
ResponsiveTextSize,
} from "../../responsiveText.js"
import { getTextForCheckResultBased } from "./checkResultBased.js"
import { getTextForIsMaximum } from "./isMaximum.js"
import { formatTimeSpan } from "./units.js"
import { formatTimeSpan } from "../../units/timeSpan.js"
import { getCheckResultBasedValueTranslation } from "./checkResultBased.js"
import { wrapAsMaximum, wrapIfMaximum } from "./isMinimumMaximum.js"
import { appendInParensIfNotEmpty } from "./parensIf.js"
const getTextForImmediateDuration = (
deps: {
translate: Translate
translateMap: TranslateMap
},
value: Immediate,
env: {
responsiveText: ResponsiveTextSize
}
const getImmediateDurationTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: Immediate
): string => {
const text =
deps.translate("Immediate") +
mapNullableDefault(
value.maximum,
(max) => {
const maxText = formatTimeSpan(
deps.translate,
env.responsiveText,
max.unit,
max.value
)
const text = appendInParensIfNotEmpty(
mapNullable(value.maximum, (max) => {
const maxText = formatTimeSpan(
locale,
responsiveTextSize,
max.unit,
max.value
)
return responsive(
env.responsiveText,
() => deps.translate(" (no more than {0})", maxText),
() => deps.translate(" (max. {0})", maxText)
)
},
""
)
return responsive(
responsiveTextSize,
() => locale.translate("no more than {0}", maxText),
() => locale.translate("max. {0}", maxText)
)
}),
locale.translate("Immediate")
)
return replaceTextIfRequested(
"replacement",
value.translations,
text,
deps.translateMap,
env.responsiveText
locale.translateMap,
responsiveTextSize,
text
)
}
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 getPermanentDurationTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: PermanentDuration
): string =>
replaceTextIfRequested(
"replacement",
value.translations,
locale.translateMap,
responsiveTextSize,
locale.translate("Permanent")
)
const unitValue = formatTimeSpan(
deps.translate,
env.responsiveText,
const getFixedDurationTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: FixedDuration
): string => {
const duration = formatTimeSpan(
locale,
responsiveTextSize,
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(
const durationWrappedIfMaximum = wrapIfMaximum(
locale,
responsiveTextSize,
value.is_maximum,
deps.translate,
env.responsiveText
duration
)
return formatTimeSpan(
deps.translate,
env.responsiveText,
value.unit,
isMaximum + getTextForCheckResultBased(value, deps.translate)
return replaceTextIfRequested(
"replacement",
value.translations,
locale.translateMap,
responsiveTextSize,
durationWrappedIfMaximum
)
}
const getCheckResultBasedDurationTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: CheckResultBasedDuration
): string => {
const duration = formatTimeSpan(
locale,
responsiveTextSize,
value.unit,
getCheckResultBasedValueTranslation(locale.translate, value)
)
return wrapIfMaximum(locale, responsiveTextSize, value.is_maximum, duration)
}
const getIndefiniteDurationTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: IndefiniteDuration
) =>
getResponsiveText(
locale.translateMap(value.translations)?.description,
responsiveTextSize
)
/**
* 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
}
export const getDurationForOneTimeTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: DurationForOneTime
): string => {
switch (value.tag) {
case "Immediate":
return getTextForImmediateDuration(deps, value.immediate, env)
return getImmediateDurationTranslation(
locale,
responsiveTextSize,
value.immediate
)
case "Permanent":
return getTextForPermanentDuration(deps, value.permanent, env)
return getPermanentDurationTranslation(
locale,
responsiveTextSize,
value.permanent
)
case "Fixed":
return getTextForFixedDuration(deps, value.fixed, env)
return getFixedDurationTranslation(
locale,
responsiveTextSize,
value.fixed
)
case "CheckResultBased":
return getTextForCheckResultBasedDuration(
deps,
value.check_result_based,
env
return getCheckResultBasedDurationTranslation(
locale,
responsiveTextSize,
value.check_result_based
)
case "Indefinite":
return getResponsiveText(
deps.translateMap(value.indefinite.translations)?.description,
env.responsiveText
return getIndefiniteDurationTranslation(
locale,
responsiveTextSize,
value.indefinite
)
default:
return assertExhaustive(value)
@@ -180,61 +169,67 @@ export const getTextForDurationForOneTime = (
/**
* Returns the text for the duration of a sustained activatable skill.
*/
export const getTextForDurationForSustained = (
deps: { translate: Translate },
value: DurationForSustained | undefined,
env: {
responsiveText: ResponsiveTextSize
}
export const getDurationForSustainedTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: DurationForSustained | undefined
): string =>
value === undefined
? responsive(
env.responsiveText,
() => deps.translate("Sustained"),
() => deps.translate("(S)")
responsiveTextSize,
() => locale.translate("Sustained"),
() => locale.translate("(S)")
)
: responsive(
env.responsiveText,
() => deps.translate("no more than "),
() => deps.translate("max. ")
) +
formatTimeSpan(
deps.translate,
env.responsiveText,
value.maximum.unit,
value.maximum.value
: wrapAsMaximum(
locale,
responsiveTextSize,
formatTimeSpan(
locale,
responsiveTextSize,
value.maximum.unit,
value.maximum.value
)
)
const getDurationDuringLovemakingTranslation = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: CastingTimeDuringLovemaking
): string => formatTimeSpan(locale, responsiveTextSize, value.unit, value.value)
/**
* Returns the text for the duration of a cantrip.
*/
export const getTextForCantripDuration = (
deps: { translate: Translate; translateMap: TranslateMap },
value: CantripDuration,
env: {
responsiveText: ResponsiveTextSize
}
export const getDurationTranslationForCantrip = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: CantripDuration
): string => {
switch (value.tag) {
case "Immediate":
return getTextForImmediateDuration(deps, value.immediate, env)
return getImmediateDurationTranslation(
locale,
responsiveTextSize,
value.immediate
)
case "Fixed":
return getTextForFixedDuration(deps, value.fixed, env)
return getFixedDurationTranslation(
locale,
responsiveTextSize,
value.fixed
)
case "Indefinite":
return getResponsiveText(
deps.translateMap(value.indefinite.translations)?.description,
env.responsiveText
return getIndefiniteDurationTranslation(
locale,
responsiveTextSize,
value.indefinite
)
case "DuringLovemaking": {
const { value: lovemakingValue, unit: lovemakingUnit } =
case "DuringLovemaking":
return getDurationDuringLovemakingTranslation(
locale,
responsiveTextSize,
value.during_lovemaking
return formatTimeSpan(
deps.translate,
env.responsiveText,
lovemakingUnit,
lovemakingValue
)
}
default:
return assertExhaustive(value)
}
@@ -243,22 +238,29 @@ export const getTextForCantripDuration = (
/**
* Returns the text for the duration of a blessing.
*/
export const getTextForBlessingDuration = (
deps: { translate: Translate; translateMap: TranslateMap },
value: BlessingDuration,
env: {
responsiveText: ResponsiveTextSize
}
export const getDurationTranslationForBlessing = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: BlessingDuration
): string => {
switch (value.tag) {
case "Immediate":
return getTextForImmediateDuration(deps, value.immediate, env)
return getImmediateDurationTranslation(
locale,
responsiveTextSize,
value.immediate
)
case "Fixed":
return getTextForFixedDuration(deps, value.fixed, env)
return getFixedDurationTranslation(
locale,
responsiveTextSize,
value.fixed
)
case "Indefinite":
return getResponsiveText(
deps.translateMap(value.indefinite.translations)?.description,
env.responsiveText
return getIndefiniteDurationTranslation(
locale,
responsiveTextSize,
value.indefinite
)
default:
return assertExhaustive(value)
@@ -2,26 +2,26 @@ 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 { LocaleEnvironment } from "../../../../helpers/locale.js"
import { LibraryEntryContent } from "../../../../libraryEntry.js"
const getContentPartsForQualityLevels = (
getQualityLevelString: (index: number) => string | number,
locale: LocaleEnvironment,
source: {
text_before: string
quality_levels: string[]
text_after?: string
},
getQualityLevelString: (index: number) => string | number,
translate: Translate
}
): LibraryEntryContent[] =>
filterNonNullable([
{
label: translate("Effect"),
label: locale.translate("Effect"),
value: source.text_before,
},
...source.quality_levels.map((text, index) => ({
value: text,
label: translate("QL {0}", getQualityLevelString(index)),
label: locale.translate("QL {0}", getQualityLevelString(index)),
})),
mapNullable(source.text_after, (textAfter) => ({
value: textAfter,
@@ -33,28 +33,28 @@ const getContentPartsForQualityLevels = (
* Gets the text for the effect of an activatable skill.
*/
export const getTextForEffect = (
effect: Effect,
translate: Translate
locale: LocaleEnvironment,
effect: Effect
): LibraryEntryContent[] => {
switch (effect.tag) {
case "Plain":
return [
{
label: translate("Effect"),
label: locale.translate("Effect"),
value: effect.plain.text,
},
]
case "ForEachQualityLevel":
return getContentPartsForQualityLevels(
effect.for_each_quality_level,
(index) => index + 1,
translate
locale,
effect.for_each_quality_level
)
case "ForEachTwoQualityLevels":
return getContentPartsForQualityLevels(
effect.for_each_two_quality_levels,
(index) => `${index * 2 + 1}${index * 2 + 2}`,
translate
locale,
effect.for_each_two_quality_levels
)
default:
return assertExhaustive(effect)
+145 -84
View File
@@ -5,16 +5,19 @@ import {
SlowSustainedPerformanceParameters,
} from "optolith-database-schema/types/_ActivatableSkill"
import { GetById } from "../../../../helpers/getTypes.js"
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import { ResponsiveTextSize } from "../../responsiveText.js"
import {
getTextForFastCastingTime,
getTextForSlowCastingTime,
getFastCastingTimeTranslation,
getSlowCastingTimeTranslation,
} from "./castingTime.js"
import { getTextForOneTimeCost, getTextForSustainedCost } from "./cost.js"
import {
getTextForDurationForOneTime,
getTextForDurationForSustained,
getOneTimeCostTranslation,
getSustainedCostTranslation,
} from "./cost.js"
import {
getDurationForOneTimeTranslation,
getDurationForSustainedTranslation,
} from "./duration.js"
import { Entity } from "./entity.js"
import { getTextForActivatableSkillRange } from "./range.js"
@@ -23,121 +26,179 @@ 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
}
export const getFastOneTimePerformanceParametersTranslations = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: FastOneTimePerformanceParameters
): {
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),
castingTime: getFastCastingTimeTranslation(
getSkillModificationLevelById,
locale,
entity,
responsiveTextSize,
value.casting_time
),
cost: getOneTimeCostTranslation(
getSkillModificationLevelById,
locale,
Speed.Fast,
entity,
responsiveTextSize,
value.cost
),
range: getTextForActivatableSkillRange(
getSkillModificationLevelById,
locale,
Speed.Fast,
responsiveTextSize,
entity,
value.range
),
duration: getDurationForOneTimeTranslation(
locale,
responsiveTextSize,
value.duration
),
})
/**
* 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
}
export const getFastSustainedPerformanceParametersTranslations = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: FastSustainedPerformanceParameters
): {
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),
castingTime: getFastCastingTimeTranslation(
getSkillModificationLevelById,
locale,
entity,
responsiveTextSize,
value.casting_time
),
cost: getSustainedCostTranslation(
getSkillModificationLevelById,
locale,
Speed.Fast,
entity,
responsiveTextSize,
value.cost
),
range: getTextForActivatableSkillRange(
getSkillModificationLevelById,
locale,
Speed.Fast,
responsiveTextSize,
entity,
value.range
),
duration: getDurationForSustainedTranslation(
locale,
responsiveTextSize,
value.duration
),
})
/**
* 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
}
export const getSlowOneTimePerformanceParametersTranslations = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: SlowOneTimePerformanceParameters
): {
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),
castingTime: getSlowCastingTimeTranslation(
getSkillModificationLevelById,
locale,
entity,
responsiveTextSize,
value.casting_time
),
cost: getOneTimeCostTranslation(
getSkillModificationLevelById,
locale,
Speed.Slow,
entity,
responsiveTextSize,
value.cost
),
range: getTextForActivatableSkillRange(
getSkillModificationLevelById,
locale,
Speed.Slow,
responsiveTextSize,
entity,
value.range
),
duration: getDurationForOneTimeTranslation(
locale,
responsiveTextSize,
value.duration
),
})
/**
* 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
}
export const getSlowSustainedPerformanceParametersTranslations = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: SlowSustainedPerformanceParameters
): {
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),
castingTime: getSlowCastingTimeTranslation(
getSkillModificationLevelById,
locale,
entity,
responsiveTextSize,
value.casting_time
),
cost: getSustainedCostTranslation(
getSkillModificationLevelById,
locale,
Speed.Slow,
entity,
responsiveTextSize,
value.cost
),
range: getTextForActivatableSkillRange(
getSkillModificationLevelById,
locale,
Speed.Slow,
responsiveTextSize,
entity,
value.range
),
duration: getDurationForSustainedTranslation(
locale,
responsiveTextSize,
value.duration
),
})
@@ -1,21 +0,0 @@
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,54 @@
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import { responsive, ResponsiveTextSize } from "../../responsiveText.js"
/**
* Wraps the text in a translation that indicates its a minimum value.
*/
export const wrapAsMinimum = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
text: string
): string =>
responsive(
responsiveTextSize,
() => locale.translate("at least {0}", text),
() => locale.translate("min. {0}", text)
)
/**
* Wraps the text in a translation that indicates its a minimum value if the
* `is_minimum` property says its a minimum value.
*/
export const wrapIfMinimum = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
is_minimum: boolean | undefined,
text: string
) =>
is_minimum === true ? wrapAsMinimum(locale, responsiveTextSize, text) : ""
/**
* Wraps the text in a translation that indicates its a maximum value.
*/
export const wrapAsMaximum = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
text: string
): string =>
responsive(
responsiveTextSize,
() => locale.translate("no more than {0}", text),
() => locale.translate("max. {0}", text)
)
/**
* Wraps the text in a translation that indicates its a maximum value if the
* `is_maximum` property says its a maximum value.
*/
export const wrapIfMaximum = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
is_maximum: boolean | undefined,
text: string
): string =>
is_maximum === true ? wrapAsMaximum(locale, responsiveTextSize, text) : ""
@@ -1,8 +0,0 @@
/**
* A parameter that is designed to be modifiable.
*/
export enum ModifiableParameter {
CastingTime,
Cost,
Range,
}
@@ -1,107 +0,0 @@
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 spells casting time)"
)
case ModifiableParameter.Cost:
return translate(
" (you cannot use a modification on this spells cost)"
)
case ModifiableParameter.Range:
return translate(
" (you cannot use a modification on this spells range)"
)
default:
return assertExhaustive(param)
}
case Entity.Ritual:
switch (param) {
case ModifiableParameter.CastingTime:
return translate(
" (you cannot use a modification on this rituals ritual time)"
)
case ModifiableParameter.Cost:
return translate(
" (you cannot use a modification on this rituals cost)"
)
case ModifiableParameter.Range:
return translate(
" (you cannot use a modification on this rituals range)"
)
default:
return assertExhaustive(param)
}
case Entity.LiturgicalChant:
switch (param) {
case ModifiableParameter.CastingTime:
return translate(
" (you cannot use a modification on this chants liturgical time)"
)
case ModifiableParameter.Cost:
return translate(
" (you cannot use a modification on this chants cost)"
)
case ModifiableParameter.Range:
return translate(
" (you cannot use a modification on this chants range)"
)
default:
return assertExhaustive(param)
}
case Entity.Ceremony:
switch (param) {
case ModifiableParameter.CastingTime:
return translate(
" (you cannot use a modification on this ceremonys ceremonial time)"
)
case ModifiableParameter.Cost:
return translate(
" (you cannot use a modification on this ceremonys cost)"
)
case ModifiableParameter.Range:
return translate(
" (you cannot use a modification on this ceremonys range)"
)
default:
return assertExhaustive(param)
}
case Entity.Cantrip:
case Entity.Blessing:
return ""
default:
return assertExhaustive(entity)
}
}
@@ -0,0 +1,91 @@
import { mapNullable } from "@optolith/helpers/nullable"
import { assertExhaustive } from "@optolith/helpers/typeSafety"
import { UI } from "optolith-database-schema/types/UI"
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import { responsive, ResponsiveTextSize } from "../../responsiveText.js"
import { Entity } from "./entity.js"
/**
* A parameter that is designed to be modifiable.
*/
export enum ModifiableParameter {
CastingTime,
Cost,
Range,
}
const translationKeyForNonModifiableSuffix: {
[key in Entity]:
| {
[key in ModifiableParameter]: keyof UI
}
| undefined
} = {
[Entity.Spell]: {
[ModifiableParameter.CastingTime]:
" (you cannot use a modification on this spells casting time)",
[ModifiableParameter.Cost]:
" (you cannot use a modification on this spells cost)",
[ModifiableParameter.Range]:
" (you cannot use a modification on this spells range)",
},
[Entity.Ritual]: {
[ModifiableParameter.CastingTime]:
" (you cannot use a modification on this rituals ritual time)",
[ModifiableParameter.Cost]:
" (you cannot use a modification on this rituals cost)",
[ModifiableParameter.Range]:
" (you cannot use a modification on this rituals range)",
},
[Entity.LiturgicalChant]: {
[ModifiableParameter.CastingTime]:
" (you cannot use a modification on this chants liturgical time)",
[ModifiableParameter.Cost]:
" (you cannot use a modification on this chants cost)",
[ModifiableParameter.Range]:
" (you cannot use a modification on this chants range)",
},
[Entity.Ceremony]: {
[ModifiableParameter.CastingTime]:
" (you cannot use a modification on this ceremonys ceremonial time)",
[ModifiableParameter.Cost]:
" (you cannot use a modification on this ceremonys cost)",
[ModifiableParameter.Range]:
" (you cannot use a modification on this ceremonys range)",
},
[Entity.Cantrip]: undefined,
[Entity.Blessing]: undefined,
}
/**
* Returns the suffix for the text of a non-modifiable parameter that indicates
* that the parameter cannot be modified.
*/
export const getNonModifiableSuffixTranslation = (
locale: LocaleEnvironment,
entity: Entity,
param: ModifiableParameter,
responsiveTextSize: ResponsiveTextSize
): string =>
responsive(
responsiveTextSize,
() =>
mapNullable(
translationKeyForNonModifiableSuffix[entity]?.[param],
(key) => locale.translate(key)
) ?? "",
() => {
switch (entity) {
case Entity.Spell:
case Entity.Ritual:
case Entity.LiturgicalChant:
case Entity.Ceremony:
return locale.translate(" (cannot modify)")
case Entity.Cantrip:
case Entity.Blessing:
return ""
default:
return assertExhaustive(entity)
}
}
)
@@ -9,8 +9,10 @@ export const parensIf = (text: string | undefined): string =>
* Appends a string in parentheses with a leading space if it is not empty or
* `undefined`.
*/
export const appendInParens = (
text: string,
append: string | undefined
export const appendInParensIfNotEmpty = (
textToAppend: string | undefined,
text: string
): string =>
append === undefined || append === "" ? text : `${text} (${append})`
textToAppend === undefined || textToAppend === ""
? text
: `${text} (${textToAppend})`
+226 -205
View File
@@ -1,47 +1,174 @@
import { mapNullable } from "@optolith/helpers/nullable"
import { assertExhaustive } from "@optolith/helpers/typeSafety"
import {
CheckResultBasedRange,
FixedRange,
ModifiableRange,
Range,
RangeUnit,
RangeValue,
} 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 { LocaleEnvironment } from "../../../../helpers/locale.js"
import {
getResponsiveText,
getResponsiveTextOptional,
responsive,
appendNoteIfRequested,
replaceTextIfRequested,
ResponsiveTextSize,
} from "../../responsiveText.js"
import { formatLength } from "../../units/length.js"
import { MISSING_VALUE } from "../../unknown.js"
import { getTextForCheckResultBased } from "./checkResultBased.js"
import { getCheckResultBasedValueTranslation } 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"
import { wrapIfMaximum } from "./isMinimumMaximum.js"
import {
getNonModifiableSuffixTranslation,
ModifiableParameter,
} from "./nonModifiableSuffix.js"
import { getModifiableBySpeed, 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)
const getModifiableRangeTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
responsiveTextSize: ResponsiveTextSize,
value: ModifiableRange
) =>
mapNullable(
getSkillModificationLevelById(value.initial_modification_level),
(modificationLevel) => {
const range = getModifiableBySpeed(
(config) => config.range,
(config) => config.range,
speed,
modificationLevel
)
case "Miles":
return responsive(
responsiveText,
() => translate("{0} miles", value),
() => translate("{0} mi.", value)
if (range === 1) {
return locale.translate("Touch")
}
return formatLength(locale, responsiveTextSize, "Steps", range)
}
) ?? MISSING_VALUE
const getSightTranslation = (locale: LocaleEnvironment) =>
locale.translate("Sight")
const getSelfTranslation = (locale: LocaleEnvironment) =>
locale.translate("Self")
const getGlobalTranslation = (locale: LocaleEnvironment) =>
locale.translate("Global")
const getTouchTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize
) =>
locale.translate("Touch") +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Range,
responsiveTextSize
)
const getFixedRangeTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: FixedRange
) =>
formatLength(locale, responsiveTextSize, value.unit, value.value) +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Range,
responsiveTextSize
)
const wrapIfRadius = (
locale: LocaleEnvironment,
is_radius: boolean | undefined,
text: string
) => (is_radius === true ? `${text} ${locale.translate("Radius")}` : text)
const getCheckResultBasedRangeTranslation = (
locale: LocaleEnvironment,
entity: Entity,
responsiveTextSize: ResponsiveTextSize,
value: CheckResultBasedRange
) => {
const range = formatLength(
locale,
responsiveTextSize,
value.unit,
getCheckResultBasedValueTranslation(locale.translate, value)
)
const rangeWrappedIfRadius = wrapIfRadius(locale, value.is_radius, range)
const rangeWrappedIfRadiusAndIfMaximum = wrapIfMaximum(
locale,
responsiveTextSize,
value.is_maximum,
rangeWrappedIfRadius
)
return (
rangeWrappedIfRadiusAndIfMaximum +
getNonModifiableSuffixTranslation(
locale,
entity,
ModifiableParameter.Range,
responsiveTextSize
)
)
}
const getRangeValueTranslation = (
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
responsiveTextSize: ResponsiveTextSize,
entity: Entity,
value: RangeValue
) => {
switch (value.tag) {
case "Modifiable":
return getModifiableRangeTranslation(
getSkillModificationLevelById,
locale,
speed,
responsiveTextSize,
value.modifiable
)
case "Sight":
return getSightTranslation(locale)
case "Self":
return getSelfTranslation(locale)
case "Global":
return getGlobalTranslation(locale)
case "Touch":
return getTouchTranslation(locale, entity, responsiveTextSize)
case "Fixed": {
return getFixedRangeTranslation(
locale,
entity,
responsiveTextSize,
value.fixed
)
}
case "CheckResultBased":
return getCheckResultBasedRangeTranslation(
locale,
entity,
responsiveTextSize,
value.check_result_based
)
default:
return assertExhaustive(unit)
return assertExhaustive(value)
}
}
@@ -49,194 +176,88 @@ const toRangeUnit = (
* 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
}
getSkillModificationLevelById: GetById.Static.SkillModificationLevel,
locale: LocaleEnvironment,
speed: Speed,
responsiveTextSize: ResponsiveTextSize,
entity: Entity,
value: Range
): string => {
const translation = deps.translateMap(value.translations)
const rangeValue = getRangeValueTranslation(
getSkillModificationLevelById,
locale,
speed,
responsiveTextSize,
entity,
value.value
)
if (value.translations !== undefined && translation === undefined) {
return MISSING_VALUE
const withReplacement = replaceTextIfRequested(
"replacement",
value.translations,
locale.translateMap,
responsiveTextSize,
rangeValue
)
return appendNoteIfRequested(
"note",
value.translations,
locale.translateMap,
responsiveTextSize,
withReplacement
)
}
const getTextForTinyAcitvatableRange = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
entity: Entity,
value: CantripRange | BlessingRange
): string => {
switch (value.tag) {
case "Self":
return getSelfTranslation(locale)
case "Touch":
return getTouchTranslation(locale, entity, responsiveTextSize)
case "Fixed":
return getFixedRangeTranslation(
locale,
entity,
responsiveTextSize,
value.fixed
)
default:
return assertExhaustive(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)
}
}
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: CantripRange
): string =>
getTextForTinyAcitvatableRange(
locale,
responsiveTextSize,
Entity.Cantrip,
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)
}
}
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
value: BlessingRange
): string =>
getTextForTinyAcitvatableRange(
locale,
responsiveTextSize,
Entity.Blessing,
value
)
@@ -17,10 +17,10 @@ export enum Speed {
* 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
slow: (config: SlowSkillModificationLevelConfig) => T,
speed: Speed,
level: SkillModificationLevel
): T => {
switch (speed) {
case Speed.Fast:
@@ -1,59 +1,92 @@
import { mapNullable } from "@optolith/helpers/nullable"
import { assertExhaustive } from "@optolith/helpers/typeSafety"
import { TargetCategory } from "optolith-database-schema/types/_ActivatableSkillTargetCategory"
import {
TargetCategory,
TargetCategoryIdentifier,
} from "optolith-database-schema/types/_ActivatableSkillTargetCategory"
import { TargetCategoryReference } from "optolith-database-schema/types/_SimpleReferences"
import { GetById } from "../../../../helpers/getTypes.js"
import { Translate, TranslateMap } from "../../../../helpers/translate.js"
import { LocaleEnvironment } from "../../../../helpers/locale.js"
import { LibraryEntryContent } from "../../../../libraryEntry.js"
import { MISSING_VALUE } from "../../unknown.js"
import { appendInParens } from "./parensIf.js"
import { appendInParensIfNotEmpty } from "./parensIf.js"
const getSelfTranslation = (locale: LocaleEnvironment) =>
locale.translate("Self")
const getZoneTranslation = (locale: LocaleEnvironment) =>
locale.translate("Zone")
const getLiturgicalChantsAndCeremoniesTranslation = (
locale: LocaleEnvironment
) => locale.translate("Liturgical Chants and Ceremonies")
const getCantripsTranslation = (locale: LocaleEnvironment) =>
locale.translate("Cantrips")
const getPredefinedTranslation = (
getTargetCategoryById: GetById.Static.TargetCategory,
locale: LocaleEnvironment,
value: TargetCategoryReference
) => {
const numericId = value.id.target_category
const specificTargetCategory = getTargetCategoryById(numericId)
return (
mapNullable(
locale.translateMap(specificTargetCategory?.translations),
(translation) => translation.name
) ?? MISSING_VALUE
)
}
const getTargetCategoryTranslationByType = (
getTargetCategoryById: GetById.Static.TargetCategory,
locale: LocaleEnvironment,
id: TargetCategoryIdentifier
) => {
switch (id.tag) {
case "Self":
return getSelfTranslation(locale)
case "Zone":
return getZoneTranslation(locale)
case "LiturgicalChantsAndCeremonies":
return getLiturgicalChantsAndCeremoniesTranslation(locale)
case "Cantrips":
return getCantripsTranslation(locale)
case "Predefined":
return getPredefinedTranslation(
getTargetCategoryById,
locale,
id.predefined
)
default:
return assertExhaustive(id)
}
}
/**
* Get the text for the target category.
*/
export const getTextForTargetCategory = (
deps: {
translate: Translate
translateMap: TranslateMap
getTargetCategoryById: GetById.Static.TargetCategory
},
export const getTargetCategoryTranslation = (
getTargetCategoryById: GetById.Static.TargetCategory,
locale: LocaleEnvironment,
values: TargetCategory
): LibraryEntryContent => ({
label: deps.translate("Target Category"),
label: locale.translate("Target Category"),
value:
values.length === 0
? deps.translate("all")
? locale.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
.map(({ id, translations }) =>
appendInParensIfNotEmpty(
locale.translateMap(translations)?.note,
getTargetCategoryTranslationByType(
getTargetCategoryById,
locale,
id
)
)
})
)
.join(", "),
})
@@ -1,127 +0,0 @@
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)
}
}
+26 -6
View File
@@ -7,6 +7,7 @@ import {
ResponsiveTextReplace,
} from "optolith-database-schema/types/_ResponsiveText"
import { TranslateMap } from "../../helpers/translate.js"
import { appendInParensIfNotEmpty } from "./rated/activatable/parensIf.js"
import { MISSING_VALUE } from "./unknown.js"
/**
@@ -76,14 +77,33 @@ export const getResponsiveTextOptional = (
/**
* Replaces a text with a given value if a replacement is requested, otherwise
* just return the .
* just return the given value.
*/
export const replaceTextIfRequested = (
translation: LocaleMap<{ replacement?: ResponsiveTextReplace }> | undefined,
valueToReplace: string,
export const replaceTextIfRequested = <Key extends string>(
key: Key,
translation: LocaleMap<{ [K in Key]?: ResponsiveTextReplace }> | undefined,
translateMap: TranslateMap,
responsiveText: ResponsiveTextSize
responsiveText: ResponsiveTextSize,
valueToReplace: string
) =>
mapNullable(translateMap(translation)?.replacement, (replacement) =>
mapNullable(translateMap(translation)?.[key], (replacement) =>
getResponsiveText(replacement, responsiveText).replace("$1", valueToReplace)
) ?? valueToReplace
/**
* Appends a note to a given value if a note is requested, otherwise just return
* the given value.
*/
export const appendNoteIfRequested = <Key extends string>(
key: Key,
translation: LocaleMap<{ [K in Key]?: ResponsiveTextOptional }> | undefined,
translateMap: TranslateMap,
responsiveText: ResponsiveTextSize,
valueToAppendTo: string
) =>
mapNullable(translateMap(translation)?.[key], (note) =>
appendInParensIfNotEmpty(
getResponsiveTextOptional(note, responsiveText),
valueToAppendTo
)
) ?? valueToAppendTo
+48
View File
@@ -0,0 +1,48 @@
import { assertExhaustive } from "@optolith/helpers/typeSafety"
import { UI } from "optolith-database-schema/types/UI"
import { LocaleEnvironment } from "../../../helpers/locale.js"
import { Entity } from "../rated/activatable/entity.js"
type EnergyUnit = "ArcaneEnergy" | "KarmaPoints"
const lengthUnitTranslationKeys: {
[key in EnergyUnit]: keyof UI
} = {
ArcaneEnergy: "{0} AE",
KarmaPoints: "{0} KP",
}
/**
* Returns the text for an energy unit.
*/
export const formatEnergy = (
locale: LocaleEnvironment,
unit: EnergyUnit,
value: number | string
): string => {
const key = lengthUnitTranslationKeys[unit]
return locale.translate(key, value)
}
/**
* Returns the text for an energy unit that is based on the entity type.
*/
export const formatEnergyByEntity = (
locale: LocaleEnvironment,
entity: Entity,
value: number | string
) => {
switch (entity) {
case Entity.Cantrip:
case Entity.Spell:
case Entity.Ritual:
return formatEnergy(locale, "ArcaneEnergy", value)
case Entity.Blessing:
case Entity.LiturgicalChant:
case Entity.Ceremony:
return formatEnergy(locale, "KarmaPoints", value)
default:
return assertExhaustive(entity)
}
}
+30
View File
@@ -0,0 +1,30 @@
import { UI } from "optolith-database-schema/types/UI"
import { LocaleEnvironment } from "../../../helpers/locale.js"
import { responsive, ResponsiveTextSize } from "../responsiveText.js"
type LengthUnit = "Steps" | "Miles"
const lengthUnitTranslationKeys: {
[key in LengthUnit]: [full: keyof UI, compressed: keyof UI]
} = {
Steps: ["{0} yards", "{0} yd"],
Miles: ["{0} miles", "{0} mi."],
}
/**
* Returns the text for a length unit.
*/
export const formatLength = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
unit: LengthUnit,
value: number | string
) => {
const [fullKey, compressedKey] = lengthUnitTranslationKeys[unit]
return responsive(
responsiveTextSize,
() => locale.translate(fullKey, value),
() => locale.translate(compressedKey, value)
)
}
+52
View File
@@ -0,0 +1,52 @@
import { UI } from "optolith-database-schema/types/UI"
import { LocaleEnvironment } from "../../../helpers/locale.js"
import { ResponsiveTextSize, responsive } from "../responsiveText.js"
type TimeSpanUnit =
| "Seconds"
| "Minutes"
| "Hours"
| "Days"
| "Weeks"
| "Months"
| "Years"
| "Centuries"
| "Actions"
| "CombatRounds"
| "SeductionActions"
| "Rounds"
const timeSpanUnitTranslationKeys: {
[key in TimeSpanUnit]: [full: keyof UI, compressed: keyof UI]
} = {
Seconds: ["{0} seconds", "{0} s"],
Minutes: ["{0} minutes", "{0} min"],
Hours: ["{0} hours", "{0} h"],
Days: ["{0} days", "{0} d"],
Weeks: ["{0} weeks", "{0} wks."],
Months: ["{0} months", "{0} mos."],
Years: ["{0} years", "{0} yrs."],
Centuries: ["{0} centuries", "{0} cent."],
Actions: ["{0} actions", "{0} act"],
CombatRounds: ["{0} combat rounds", "{0} CR"],
SeductionActions: ["{0} seduction actions", "{0} SA"],
Rounds: ["{0} rounds", "{0} rnds"],
}
/**
* Returns the text for a time span unit.
*/
export const formatTimeSpan = (
locale: LocaleEnvironment,
responsiveTextSize: ResponsiveTextSize,
unit: TimeSpanUnit,
value: number | string
): string => {
const [fullKey, compressedKey] = timeSpanUnitTranslationKeys[unit]
return responsive(
responsiveTextSize,
() => locale.translate(fullKey, value),
() => locale.translate(compressedKey, value)
)
}
+1 -1
View File
@@ -21,7 +21,7 @@ export const getSkillLibraryEntry = createLibraryEntryCreator<
}
>(
(entry, { getAttributeById, blessedTraditions, diseases, regions, cache }) =>
({ translate, translateMap, localeCompare }) => {
({ translate, translateMap, compare: localeCompare }) => {
const translation = translateMap(entry.translations)
if (translation === undefined) {
+54 -72
View File
@@ -16,18 +16,18 @@ import {
createLibraryEntryCreator,
LibraryEntryContent,
} from "../libraryEntry.js"
import { getTextForCantripDuration } from "./partial/rated/activatable/duration.js"
import { getDurationTranslationForCantrip } 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,
getFastOneTimePerformanceParametersTranslations,
getFastSustainedPerformanceParametersTranslations,
getSlowOneTimePerformanceParametersTranslations,
getSlowSustainedPerformanceParametersTranslations,
} 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 { getTargetCategoryTranslation } 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"
@@ -124,7 +124,8 @@ export const getCantripLibraryEntry = createLibraryEntryCreator<
getCurriculumById,
}
) =>
({ translate, translateMap, localeCompare }) => {
(locale) => {
const { translate, translateMap, compare: localeCompare } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
@@ -132,19 +133,15 @@ export const getCantripLibraryEntry = createLibraryEntryCreator<
}
const range = getTextForCantripRange(
{ translate },
entry.parameters.range,
{
responsiveText: ResponsiveTextSize.Full,
}
locale,
ResponsiveTextSize.Full,
entry.parameters.range
)
const duration = getTextForCantripDuration(
{ translate, translateMap },
entry.parameters.duration,
{
responsiveText: ResponsiveTextSize.Full,
}
const duration = getDurationTranslationForCantrip(
locale,
ResponsiveTextSize.Full,
entry.parameters.duration
)
return {
@@ -169,8 +166,9 @@ export const getCantripLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
getTargetCategoryTranslation(
getTargetCategoryById,
locale,
entry.target
),
getTextForProperty(
@@ -266,7 +264,8 @@ export const getSpellLibraryEntry = createLibraryEntryCreator<
getMagicalTraditionById,
}
) =>
({ translate, translateMap, localeCompare }) => {
(locale) => {
const { translate, translateMap, compare: localeCompare } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
@@ -276,31 +275,21 @@ export const getSpellLibraryEntry = createLibraryEntryCreator<
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,
}
return getFastOneTimePerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Spell,
ResponsiveTextSize.Full,
entry.parameters.one_time
)
case "Sustained":
return getTextForFastSustainedPerformanceParameters(
{
getSkillModificationLevelById,
translate,
translateMap,
},
entry.parameters.sustained,
{
entity: Entity.Spell,
responsiveText: ResponsiveTextSize.Full,
}
return getFastSustainedPerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Spell,
ResponsiveTextSize.Full,
entry.parameters.sustained
)
default:
@@ -322,7 +311,7 @@ export const getSpellLibraryEntry = createLibraryEntryCreator<
getToughness,
}
),
...getTextForEffect(translation.effect, translate),
...getTextForEffect(locale, translation.effect),
{
label: translate("Casting Time"),
value:
@@ -351,8 +340,9 @@ export const getSpellLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration.full})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
getTargetCategoryTranslation(
getTargetCategoryById,
locale,
entry.target
),
getTextForProperty(
@@ -397,7 +387,8 @@ export const getRitualLibraryEntry = createLibraryEntryCreator<
getMagicalTraditionById,
}
) =>
({ translate, translateMap, localeCompare }) => {
(locale) => {
const { translate, translateMap, compare: localeCompare } = locale
const translation = translateMap(entry.translations)
if (translation === undefined) {
@@ -407,31 +398,21 @@ export const getRitualLibraryEntry = createLibraryEntryCreator<
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,
}
return getSlowOneTimePerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Ritual,
ResponsiveTextSize.Full,
entry.parameters.one_time
)
case "Sustained":
return getTextForSlowSustainedPerformanceParameters(
{
getSkillModificationLevelById,
translate,
translateMap,
},
entry.parameters.sustained,
{
entity: Entity.Ritual,
responsiveText: ResponsiveTextSize.Full,
}
return getSlowSustainedPerformanceParametersTranslations(
getSkillModificationLevelById,
locale,
Entity.Ritual,
ResponsiveTextSize.Full,
entry.parameters.sustained
)
default:
@@ -453,7 +434,7 @@ export const getRitualLibraryEntry = createLibraryEntryCreator<
getToughness,
}
),
...getTextForEffect(translation.effect, translate),
...getTextForEffect(locale, translation.effect),
{
label: translate("Ritual Time"),
value:
@@ -482,8 +463,9 @@ export const getRitualLibraryEntry = createLibraryEntryCreator<
? `***${duration}*** (${translation.duration.full})`
: duration,
},
getTextForTargetCategory(
{ translate, translateMap, getTargetCategoryById },
getTargetCategoryTranslation(
getTargetCategoryById,
locale,
entry.target
),
getTextForProperty(
+9
View File
@@ -0,0 +1,9 @@
import { Compare } from "@optolith/helpers/compare"
import { Translate, TranslateMap } from "./translate.js"
export type LocaleEnvironment = {
id: string
translate: Translate
translateMap: TranslateMap
compare: Compare<string>
}
+4 -7
View File
@@ -1,7 +1,6 @@
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"
import { LocaleEnvironment } from "./helpers/locale.js"
/**
* Creates a function that creates the JSON representation of the rules text for
@@ -40,11 +39,9 @@ export type LibraryEntryCreator<T, A = undefined, R = LibraryEntry> = (
* 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
export type LibraryEntryConfiguredCreator<R = LibraryEntry> = (
locale: LocaleEnvironment
) => R | undefined
/**
* A JSON representation of the rules text for a library entry.
+1
View File
@@ -14,6 +14,7 @@
"noImplicitThis": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUncheckedSideEffectImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "../lib",
@@ -0,0 +1,35 @@
import assert from "node:assert/strict"
import { describe, it } from "node:test"
import { getCheckResultBasedValueTranslation } from "../../../../../src/entities/partial/rated/activatable/checkResultBased.js"
import { translateMock } from "../../../../../src/helpers/translate.js"
describe("getTextForCheckResultBased", () => {
it("should return the value text for a check-result-based parameter of an activatable skill", () => {
assert.equal(
getCheckResultBasedValueTranslation(translateMock, {
base: "QualityLevels",
}),
"QL"
)
assert.equal(
getCheckResultBasedValueTranslation(translateMock, {
base: "SkillPoints",
}),
"SP"
)
assert.equal(
getCheckResultBasedValueTranslation(translateMock, {
base: "QualityLevels",
modifier: { arithmetic: "Divide", value: 2 },
}),
"QL / 2"
)
assert.equal(
getCheckResultBasedValueTranslation(translateMock, {
base: "SkillPoints",
modifier: { arithmetic: "Multiply", value: 3 },
}),
"SP × 3"
)
})
})
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"composite": true,
"declaration": true,
"forceConsistentCasingInFileNames": true,
"lib": ["esnext"],
"module": "NodeNext",
"noEmit": true,
"noEmitHelpers": true,
"noErrorTruncation": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUncheckedSideEffectImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true,
"target": "ESNext",
"useUnknownInCatchVariables": true,
},
"references": [
{ "path": "../src" },
]
}
+1
View File
@@ -2,5 +2,6 @@
"files": [],
"references": [
{ "path": "src" },
{ "path": "test" },
],
}