From 99fd56d0fe885ab9630c6fe3dafddf5f27da7b90 Mon Sep 17 00:00:00 2001 From: Lector Date: Sun, 24 May 2026 10:52:30 +0200 Subject: [PATCH 1/6] Added rendering for goblin rituals and bannzeichen --- src/entities/spell.ts | 321 ++++++++++++++++++++++++++++++++++++++---- src/index.ts | 4 + 2 files changed, 299 insertions(+), 26 deletions(-) diff --git a/src/entities/spell.ts b/src/entities/spell.ts index 7963da4..cd41621 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -16,7 +16,13 @@ import { type ArcaneDancerTraditionReference, type FamiliarsTrickPerformanceParameters, type FamiliarsTrickProperty, + type BannzeichenCost, + type BannzeichenCraftingTime, + type BannzeichenDuration, + type BannzeichenImprovementCost, + type BannzeichenOption, type MagicalRuneCost, + type SingleBannzeichenCost, type MagicalRuneCraftingTime, type MagicalRuneDuration, type MagicalRuneImprovementCost, @@ -51,6 +57,7 @@ import { renderMagicalActionCost, renderModifiableOneTimeCost, renderNonModifiableOneTimeCost, + renderNonModifiableSustainedCost, } from "./partial/rated/activatable/cost.js" import { renderCheckResultBasedDuration, @@ -67,7 +74,7 @@ import { } from "./partial/rated/activatable/index.js" import { ModifiableParameter } from "./partial/rated/activatable/nonModifiableSuffix.js" import { parensIf } from "./partial/rated/activatable/parensIf.js" -import { renderNonModifiableRange } from "./partial/rated/activatable/range.js" +import { renderNonModifiableRange, renderRange } from "./partial/rated/activatable/range.js" import { Speed } from "./partial/rated/activatable/speed.js" import { renderTargetCategory } from "./partial/rated/activatable/targetCategory.js" import { @@ -1330,6 +1337,112 @@ export const getJesterTrickEntityDescription = createEntityDescriptionCreator< } }) +/** + * Get a JSON representation of the rules text for a goblin ritual. + */ +export const getGoblinRitualEntityDescription = createEntityDescriptionCreator< + "GoblinRitual", + { + getInstanceById: GetInstanceById< + | "Publication" + | "Attribute" + | "SkillModificationLevel" + | "TargetCategory" + | "Property" + | "MagicalTradition" + | "DerivedCharacteristic" + > + idMap: IdMap + } +>(({ getInstanceById, idMap }, locale, { content: entry }) => { + const { translate, translateMap } = locale + const translation = translateMap(entry.translations) + + if (translation === undefined) { + return undefined + } + + const env = { + translate, + translateMap, + getInstanceById, + localeJoin: locale.join, + speed: Speed.Slow, + energyUnit: "ArcaneEnergy", + responsiveTextSize: ResponsiveTextSize.Full, + } satisfies Partial + + const { castingTime, cost, range, duration } = (() => { + switch (entry.parameters.kind) { + case "OneTime": { + const parameters = entry.parameters.OneTime + const { value, unit } = parameters.casting_time + const renderedCastingTime = + unit.kind === "Actions" + ? renderFastSkillNonModifiableCastingTime({ actions: value }).run(env) + : renderSlowSkillNonModifiableCastingTime({ value, unit }).run(env) + + return { + castingTime: renderedCastingTime, + cost: renderNonModifiableOneTimeCost(parameters.cost, false).run(env), + range: renderRange(parameters.range).run(env), + duration: renderOneTimeDuration(parameters.duration).run(env), + } + } + case "Sustained": { + const parameters = entry.parameters.Sustained + const { value, unit } = parameters.casting_time + const renderedCastingTime = + unit.kind === "Actions" + ? renderFastSkillNonModifiableCastingTime({ actions: value }).run(env) + : renderSlowSkillNonModifiableCastingTime({ value, unit }).run(env) + + return { + castingTime: renderedCastingTime, + cost: renderNonModifiableSustainedCost(parameters.cost).run(env), + range: renderRange(parameters.range).run(env), + duration: undefined, + } + } + default: + return assertExhaustive(entry.parameters) + } + })() + + return { + title: translation.name, + className: "goblin-ritual", + body: [ + { + type: "definitionList", + items: [ + renderSkillCheckWithPenalty(entry.check, entry.check_penalty, idMap).run(env), + renderEffect(translation.effect).run(env), + combineGeneratedTextWithStaticTranslation( + translate("Ritual Time"), + castingTime, + translation.casting_time, + ), + combineGeneratedTextWithStaticTranslation(translate("AE Cost"), cost, translation.cost), + combineGeneratedTextWithStaticTranslation(translate("Range"), range, translation.range), + duration === undefined + ? undefined + : combineGeneratedTextWithStaticTranslation( + translate("Duration"), + duration, + translation.duration, + ), + renderTargetCategory(entry.target).run(env), + renderProperty(entry.property).run(env), + renderImprovementCost(entry.improvement_cost).run(env), + ], + }, + ], + errata: translation.errata, + references: entry.src, + } +}) + /** * Get a JSON representation of the rules text for a Zibilja ritual. */ @@ -1405,9 +1518,9 @@ export const getZibiljaRitualEntityDescription = createEntityDescriptionCreator< } }) -const deriveValueGroupsFromMagicalRuneOptions = ( - options: Lazy, - grouper: (option: MagicalRuneOption) => T, +const deriveValueGroupsFromNamedOptions = }>( + options: Lazy, + grouper: (option: O) => T, comparator: Compare, printValue: (value: T) => string, ): StdReader => @@ -1429,32 +1542,195 @@ const deriveValueGroupsFromMagicalRuneOptions = ( ), ).then(formattedOptions => localeJoinR(formattedOptions, "disjunction")) +const deriveValueGroupsFromMagicalRuneOptions = ( + options: Lazy, + grouper: (option: MagicalRuneOption) => T, + comparator: Compare, + printValue: (value: T) => string, +): StdReader => + deriveValueGroupsFromNamedOptions(options, grouper, comparator, printValue) + +const renderSingleEnergyCost = (cost: Pick) => + formatEnergyR(cost.value).thenW(text => appendNoteIfNeeded(cost.translations, text)) + +const renderOptionDerivedEnergyCost = ; cost?: { value: number } }>( + options: Lazy, + grouper: (option: O) => number | undefined, +): StdReader => + deriveValueGroupsFromNamedOptions( + options, + grouper, + compareNullish(numAsc), + num => num?.toFixed() ?? MISSING_VALUE, + ).thenW(formatEnergyR) + const renderMagicalRuneCost = (options: Lazy, cost: MagicalRuneCost) => { switch (cost.kind) { case "Single": - return formatEnergyR(cost.Single.value).thenW(text => - appendNoteIfNeeded(cost.Single.translations, text), + return renderSingleEnergyCost(cost.Single) + case "Disjunction": + return Reader.sequence(cost.Disjunction.list.map(renderSingleEnergyCost)).thenW(text => + localeJoinR(text, "disjunction"), ) + case "DerivedFromOption": + return renderOptionDerivedEnergyCost(options, option => option.cost?.value) + default: + return assertExhaustive(cost) + } +} + +const renderBannzeichenCost = (options: Lazy, cost: BannzeichenCost) => { + switch (cost.kind) { + case "Single": + return renderSingleEnergyCost(cost.Single) case "Disjunction": - return Reader.sequence( - cost.Disjunction.list.map(costItem => - formatEnergyR(costItem.value).thenW(text => - appendNoteIfNeeded(costItem.translations, text), - ), - ), - ).thenW(text => localeJoinR(text, "disjunction")) + return Reader.sequence(cost.Disjunction.list.map(renderSingleEnergyCost)).thenW(text => + localeJoinR(text, "disjunction"), + ) case "DerivedFromOption": - return deriveValueGroupsFromMagicalRuneOptions( - options, - option => option.cost?.value, - compareNullish(numAsc), - num => num?.toFixed() ?? MISSING_VALUE, - ).thenW(formatEnergyR) + return renderOptionDerivedEnergyCost(options, option => option.cost?.value) default: return assertExhaustive(cost) } } + +const renderBannzeichenCraftingTimePart = ( + craftingTime: BannzeichenCraftingTime, + unit: TimeSpanUnit, +) => + formatTimeSpanR(unit, craftingTime.value).thenW(text => { + if (craftingTime.per === undefined) { + return Reader.of(text) + } + + const { translations } = craftingTime.per + + return translateMapR(translations).thenW(translation => { + if (translation === undefined) { + return Reader.of(text) + } + + return responsiveTextR(translation.countable).thenW(countable => + responsiveTranslateR("{$cost} per {$countable}", "{$cost}/{$countable}", { + cost: text, + countable, + }), + ) + }) + }) + +const renderBannzeichenCraftingTime = (craftingTime: BannzeichenCraftingTime): StdReader => + renderBannzeichenCraftingTimePart(craftingTime, "Actions").map2( + renderBannzeichenCraftingTimePart(craftingTime, "Days"), + (fast, slow) => `${slow} / ${fast}`, + ) + +const renderSlowFastCheckResultBasedDuration = (duration: BannzeichenDuration | MagicalRuneDuration) => + renderCheckResultBasedDuration(duration.fast).map2( + renderCheckResultBasedDuration(duration.slow), + (fast, slow) => `${slow} / ${fast}`, + ) + +const renderMagicalRuneDuration = (duration: MagicalRuneDuration) => + renderSlowFastCheckResultBasedDuration(duration) + + + +const renderBannzeichenImprovementCost = ( + options: Lazy, + improvementCost: BannzeichenImprovementCost, +): StdReader => { + switch (improvementCost.kind) { + case "Constant": + return renderImprovementCost(improvementCost.Constant) + case "DerivedFromOption": + return deriveValueGroupsFromNamedOptions( + options, + option => + option.improvement_cost === undefined + ? undefined + : renderImprovementCostValue(option.improvement_cost), + compareNullish((a, b) => a.localeCompare(b)), + selectedImprovementCost => selectedImprovementCost ?? MISSING_VALUE, + ) + .then(value => translateR("Improvement Cost").map(label => ({ label, value }))) + default: + return assertExhaustive(improvementCost) + } +} + +/** + * Get a JSON representation of the rules text for a Bannzeichen. + */ +export const getBannzeichenEntityDescription = createEntityDescriptionCreator< + "Bannzeichen", + { + getInstanceById: GetInstanceById< + "Publication" | "Attribute" | "Property" | "DerivedCharacteristic" + > + getChildInstancesForInstanceId: GetAllChildInstancesForParent<"BannzeichenOption"> + } +>(({ getInstanceById, getChildInstancesForInstanceId }, locale, { id, content: entry }) => { + const { translate, translateMap } = locale + const translation = translateMap(entry.translations) + + if (translation === undefined) { + return undefined + } + + const env = { + translate, + translateMap, + getInstanceById, + localeCompare: locale.compare, + localeJoin: locale.join, + energyUnit: "ArcaneEnergy", + responsiveTextSize: ResponsiveTextSize.Full, + } satisfies Partial + + const options = Lazy.of(() => + getChildInstancesForInstanceId("BannzeichenOption", id).map(item => item.content), + ) + + const cost = renderBannzeichenCost(options, entry.parameters.cost).run(env) + const craftingTime = renderBannzeichenCraftingTime(entry.parameters.crafting_time).run(env) + const duration = renderSlowFastCheckResultBasedDuration(entry.parameters.duration).run(env) + + return { + title: (translation.name_in_library ?? translation.name) + parensIf(translation.native_name), + className: "bannzeichen", + body: [ + { + type: "definitionList", + items: [ + renderSkillCheck(entry.check).run(env), + renderEffect(translation.effect).run(env), + combineGeneratedTextWithStaticTranslation(translate("AE Cost"), cost, translation.cost), + combineGeneratedTextWithStaticTranslation( + translate("Crafting Time (slow / fast)"), + craftingTime, + translation.crafting_time === undefined + ? undefined + : typeof (translation.crafting_time as any) === "string" + ? (translation.crafting_time as any) + : renderSplitMagicalRuneParameterTranslation(translation.crafting_time as any).run(env), + ), + combineGeneratedTextWithStaticTranslation( + translate("Duration (slow / fast)"), + duration, + translation.duration, + ), + renderProperty(entry.property).run(env), + renderBannzeichenImprovementCost(options, entry.improvement_cost).run(env), + ], + }, + ], + errata: translation.errata, + references: entry.src, + } +}) + const renderSplitMagicalRuneParameterTranslation = ( parameter: OldParameterBySpeed, ): StdReader => @@ -1500,12 +1776,6 @@ const renderMagicalRuneCraftingTime = (craftingTime: MagicalRuneCraftingTime) => (fast, slow) => `${slow} / ${fast}`, ) -const renderMagicalRuneDuration = (duration: MagicalRuneDuration) => - renderCheckResultBasedDuration(duration.fast).map2( - renderCheckResultBasedDuration(duration.slow), - (fast, slow) => `${slow} / ${fast}`, - ) - const renderMagicalRuneImprovementCost = ( options: Lazy, improvementCost: MagicalRuneImprovementCost, @@ -1523,7 +1793,6 @@ const renderMagicalRuneImprovementCost = ( compareNullish((a, b) => a.localeCompare(b)), selectedImprovementCost => selectedImprovementCost ?? MISSING_VALUE, ) - .thenW(formatEnergyR) .then(value => translateR("Improvement Cost").map(label => ({ label, value }))) default: return assertExhaustive(improvementCost) diff --git a/src/index.ts b/src/index.ts index 6e00ba7..ae98158 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,12 +48,14 @@ import { getSexPracticeEntityDescription } from "./entities/sexPractice.js" import { getSkillEntityDescription } from "./entities/skill.js" import { getAnimistPowerEntityDescription, + getBannzeichenEntityDescription, getCantripEntityDescription, getCurseEntityDescription, getDominationRitualEntityDescription, getElvenMagicalSongEntityDescription, getFamiliarsTrickEntityDescription, getGeodeRitualEntityDescription, + getGoblinRitualEntityDescription, getJesterTrickEntityDescription, getMagicalDanceEntityDescription, getMagicalMelodyEntityDescription, @@ -281,6 +283,7 @@ const registeredEntityDescriptionCreators = { DominationRitual: getDominationRitualEntityDescription, ElvenMagicalSong: getElvenMagicalSongEntityDescription, GeodeRitual: getGeodeRitualEntityDescription, + GoblinRitual: getGoblinRitualEntityDescription, JesterTrick: getJesterTrickEntityDescription, MagicalDance: getMagicalDanceEntityDescription, MagicalMelody: getMagicalMelodyEntityDescription, @@ -301,6 +304,7 @@ const registeredEntityDescriptionCreators = { AncestorGlyph: getActivatableEntityDescription, ArcaneOrbEnchantment: getActivatableEntityDescription, AttireEnchantment: getActivatableEntityDescription, + Bannzeichen: getBannzeichenEntityDescription, Beutelzauber: getActivatableEntityDescription, BlessedTradition: getActivatableEntityDescription, BowlEnchantment: getActivatableEntityDescription, From 7ba5f361dd1bb0840c3dfb3c50708bfc1fdc6873 Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sun, 21 Jun 2026 15:37:16 +0200 Subject: [PATCH 2/6] fix merge error --- src/entities/spell.ts | 53 +++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/entities/spell.ts b/src/entities/spell.ts index 07ae720..ac291a0 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -11,15 +11,14 @@ import { type AnimistPowerPerformanceParameters, type ArcaneBardTraditionReference, type ArcaneDancerTraditionReference, - type FamiliarsTrickPerformanceParameters, - type FamiliarsTrickProperty, type BannzeichenCost, type BannzeichenCraftingTime, type BannzeichenDuration, type BannzeichenImprovementCost, type BannzeichenOption, + type FamiliarsTrickPerformanceParameters, + type FamiliarsTrickProperty, type MagicalRuneCost, - type SingleBannzeichenCost, type MagicalRuneCraftingTime, type MagicalRuneDuration, type MagicalRuneImprovementCost, @@ -28,6 +27,7 @@ import { type OldParameterBySpeed, type Property_ID, type RatedIdentifier, + type SingleBannzeichenCost, type SpellworkTraditions, type Tribe_ID, } from "@optolith/database-schema/gen" @@ -1524,7 +1524,10 @@ export const getZibiljaRitualEntityDescription = createEntityDescriptionCreator< } }) -const deriveValueGroupsFromNamedOptions = }>( +const deriveValueGroupsFromNamedOptions = < + T, + O extends { translations?: Record }, +>( options: Lazy, grouper: (option: O) => T, comparator: Compare, @@ -1559,7 +1562,12 @@ const deriveValueGroupsFromMagicalRuneOptions = ( const renderSingleEnergyCost = (cost: Pick) => formatEnergyR(cost.value).thenW(text => appendNoteIfNeeded(cost.translations, text)) -const renderOptionDerivedEnergyCost = ; cost?: { value: number } }>( +const renderOptionDerivedEnergyCost = < + O extends { + translations?: Record + cost?: { value: number } + }, +>( options: Lazy, grouper: (option: O) => number | undefined, ): StdReader => @@ -1600,7 +1608,6 @@ const renderBannzeichenCost = (options: Lazy, cost: Bannzei } } - const renderBannzeichenCraftingTimePart = ( craftingTime: BannzeichenCraftingTime, unit: TimeSpanUnit, @@ -1626,23 +1633,22 @@ const renderBannzeichenCraftingTimePart = ( }) }) -const renderBannzeichenCraftingTime = (craftingTime: BannzeichenCraftingTime): StdReader => +const renderBannzeichenCraftingTime = ( + craftingTime: BannzeichenCraftingTime, +): StdReader => renderBannzeichenCraftingTimePart(craftingTime, "Actions").map2( renderBannzeichenCraftingTimePart(craftingTime, "Days"), (fast, slow) => `${slow} / ${fast}`, ) -const renderSlowFastCheckResultBasedDuration = (duration: BannzeichenDuration | MagicalRuneDuration) => - renderCheckResultBasedDuration(duration.fast).map2( - renderCheckResultBasedDuration(duration.slow), +const renderSlowFastCheckResultBasedDuration = ( + duration: BannzeichenDuration | MagicalRuneDuration, +) => + renderExpressionBasedDuration(duration.fast).map2( + renderExpressionBasedDuration(duration.slow), (fast, slow) => `${slow} / ${fast}`, ) -const renderMagicalRuneDuration = (duration: MagicalRuneDuration) => - renderSlowFastCheckResultBasedDuration(duration) - - - const renderBannzeichenImprovementCost = ( options: Lazy, improvementCost: BannzeichenImprovementCost, @@ -1659,8 +1665,7 @@ const renderBannzeichenImprovementCost = ( : renderImprovementCostValue(option.improvement_cost), compareNullish((a, b) => a.localeCompare(b)), selectedImprovementCost => selectedImprovementCost ?? MISSING_VALUE, - ) - .then(value => translateR("Improvement Cost").map(label => ({ label, value }))) + ).then(value => translateR("Improvement Cost").map(label => ({ label, value }))) default: return assertExhaustive(improvementCost) } @@ -1719,8 +1724,10 @@ export const getBannzeichenEntityDescription = createEntityDescriptionCreator< translation.crafting_time === undefined ? undefined : typeof (translation.crafting_time as any) === "string" - ? (translation.crafting_time as any) - : renderSplitMagicalRuneParameterTranslation(translation.crafting_time as any).run(env), + ? (translation.crafting_time as any) + : renderSplitMagicalRuneParameterTranslation(translation.crafting_time as any).run( + env, + ), ), combineGeneratedTextWithStaticTranslation( translate("Duration (slow / fast)"), @@ -1783,10 +1790,7 @@ const renderMagicalRuneCraftingTime = (craftingTime: MagicalRuneCraftingTime) => ) const renderMagicalRuneDuration = (duration: MagicalRuneDuration) => - renderExpressionBasedDuration(duration.fast).map2( - renderExpressionBasedDuration(duration.slow), - (fast, slow) => `${slow} / ${fast}`, - ) + renderSlowFastCheckResultBasedDuration(duration) const renderMagicalRuneImprovementCost = ( options: Lazy, @@ -1804,8 +1808,7 @@ const renderMagicalRuneImprovementCost = ( : renderImprovementCostValue(option.improvement_cost), compareNullish((a, b) => a.localeCompare(b)), selectedImprovementCost => selectedImprovementCost ?? MISSING_VALUE, - ) - .then(value => translateR("Improvement Cost").map(label => ({ label, value }))) + ).then(value => translateR("Improvement Cost").map(label => ({ label, value }))) default: return assertExhaustive(improvementCost) } From 32dabdf90d4b05d09a39058b34c1aebf0a1a4cd7 Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sun, 21 Jun 2026 17:11:14 +0200 Subject: [PATCH 3/6] fix eslint error --- src/entities/spell.ts | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/entities/spell.ts b/src/entities/spell.ts index ac291a0..f0010df 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -1407,7 +1407,7 @@ export const getGoblinRitualEntityDescription = createEntityDescriptionCreator< castingTime: renderedCastingTime, cost: renderNonModifiableSustainedCost(parameters.cost).run(env), range: renderRange(parameters.range).run(env), - duration: undefined, + duration: renderSustainedDuration(undefined).run(env), } } default: @@ -1671,6 +1671,20 @@ const renderBannzeichenImprovementCost = ( } } +const renderSplitMagicalRuneParameterTranslation = ( + parameter: OldParameterBySpeed, +): StdReader => + responsiveR( + () => parameter.fast.full, + () => parameter.fast.abbr, + ).map2( + responsiveR( + () => parameter.slow.full, + () => parameter.slow.abbr, + ), + (fast, slow) => `${slow} / ${fast}`, + ) + /** * Get a JSON representation of the rules text for a Bannzeichen. */ @@ -1723,11 +1737,9 @@ export const getBannzeichenEntityDescription = createEntityDescriptionCreator< craftingTime, translation.crafting_time === undefined ? undefined - : typeof (translation.crafting_time as any) === "string" - ? (translation.crafting_time as any) - : renderSplitMagicalRuneParameterTranslation(translation.crafting_time as any).run( - env, - ), + : typeof translation.crafting_time === "string" + ? translation.crafting_time + : renderSplitMagicalRuneParameterTranslation(translation.crafting_time).run(env), ), combineGeneratedTextWithStaticTranslation( translate("Duration (slow / fast)"), @@ -1744,20 +1756,6 @@ export const getBannzeichenEntityDescription = createEntityDescriptionCreator< } }) -const renderSplitMagicalRuneParameterTranslation = ( - parameter: OldParameterBySpeed, -): StdReader => - responsiveR( - () => parameter.fast.full, - () => parameter.fast.abbr, - ).map2( - responsiveR( - () => parameter.slow.full, - () => parameter.slow.abbr, - ), - (fast, slow) => `${slow} / ${fast}`, - ) - const renderMagicalRuneCraftingTimePart = ( craftingTime: MagicalRuneCraftingTime, unit: TimeSpanUnit, From e5ef7c2d8fb4d81e685e4d03b116d5724f370574 Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sun, 21 Jun 2026 17:13:47 +0200 Subject: [PATCH 4/6] goblin ritual duration is always present --- src/entities/spell.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/entities/spell.ts b/src/entities/spell.ts index f0010df..5dad964 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -1431,13 +1431,11 @@ export const getGoblinRitualEntityDescription = createEntityDescriptionCreator< ), combineGeneratedTextWithStaticTranslation(translate("AE Cost"), cost, translation.cost), combineGeneratedTextWithStaticTranslation(translate("Range"), range, translation.range), - duration === undefined - ? undefined - : combineGeneratedTextWithStaticTranslation( - translate("Duration"), - duration, - translation.duration, - ), + combineGeneratedTextWithStaticTranslation( + translate("Duration"), + duration, + translation.duration, + ), renderTargetCategory(entry.target).run(env), renderProperty(entry.property).run(env), renderImprovementCost(entry.improvement_cost).run(env), From 481182ae0d1aaa7ce6678f684536b4a792a3ba2a Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sun, 21 Jun 2026 22:18:13 +0200 Subject: [PATCH 5/6] remove unnecessary conditionals --- src/entities/spell.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/entities/spell.ts b/src/entities/spell.ts index 5dad964..749c73c 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -1733,11 +1733,7 @@ export const getBannzeichenEntityDescription = createEntityDescriptionCreator< combineGeneratedTextWithStaticTranslation( translate("Crafting Time (slow / fast)"), craftingTime, - translation.crafting_time === undefined - ? undefined - : typeof translation.crafting_time === "string" - ? translation.crafting_time - : renderSplitMagicalRuneParameterTranslation(translation.crafting_time).run(env), + translation.crafting_time, ), combineGeneratedTextWithStaticTranslation( translate("Duration (slow / fast)"), From 74b7201c520c5081cf9f0ed4b0ec8cf04d97cf06 Mon Sep 17 00:00:00 2001 From: Lukas Obermann Date: Sun, 21 Jun 2026 22:18:38 +0200 Subject: [PATCH 6/6] add cost map --- package-lock.json | 16 ++++++++-------- package.json | 2 +- src/entities/spell.ts | 3 +++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index d668d8e..aec2096 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@optolith/database-schema": "^0.52.1", + "@optolith/database-schema": "^0.53.0", "@types/node": "^25.9.1", "commit-and-tag-version": "^12.7.3", "eslint-config-prettier": "^10.1.8", @@ -83,9 +83,9 @@ } }, "node_modules/@elyukai/utils": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@elyukai/utils/-/utils-0.3.4.tgz", - "integrity": "sha512-zqBF3Nz7Pd5e35E2mZuImeAvCSRlAneIWb/gZKtaa9yX1oPTW/4uVKrK5k7QE9pR7xMPo7FTUs2jZ5ZDaZ75PA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@elyukai/utils/-/utils-0.3.6.tgz", + "integrity": "sha512-SFij3T0baqFu+G5NGjlHPVpLtKEeVRKg59jiMr7wQwAYM7LLpgoArBLeM/UL98FM0ntmvaRDDEBCfyMcCnsxdA==", "license": "MPL-2.0" }, "node_modules/@es-joy/jsdoccomment": { @@ -842,13 +842,13 @@ "license": "MPL-2.0" }, "node_modules/@optolith/database-schema": { - "version": "0.52.1", - "resolved": "https://registry.npmjs.org/@optolith/database-schema/-/database-schema-0.52.1.tgz", - "integrity": "sha512-XOSbSfJIGYo7+ud+RKziJPsnf7QsS43Zbgf3yv9FPIUNCgq6n/TlK1va4V9mLXvhayxTEdoEr4YTNkl/04VruQ==", + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@optolith/database-schema/-/database-schema-0.53.0.tgz", + "integrity": "sha512-T41UV2G0l30iIMWBvw8pABNHcWkrR5iE88MvRYm/4GfXwacSkzOAiuXtqn/gVj9Wq3HIbI1cMizgU2y1QtB+dw==", "dev": true, "license": "MPL-2.0", "dependencies": { - "@elyukai/utils": "^0.3.4", + "@elyukai/utils": "^0.3.6", "tsondb": "^0.20.3", "yaml": "^2.9.0" } diff --git a/package.json b/package.json index 5be7f78..6b9439e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@optolith/database-schema": "^0.52.1", + "@optolith/database-schema": "^0.53.0", "@types/node": "^25.9.1", "commit-and-tag-version": "^12.7.3", "eslint-config-prettier": "^10.1.8", diff --git a/src/entities/spell.ts b/src/entities/spell.ts index 749c73c..f0c7597 100644 --- a/src/entities/spell.ts +++ b/src/entities/spell.ts @@ -58,6 +58,7 @@ import { renderModifiableOneTimeCost, renderNonModifiableOneTimeCost, renderNonModifiableSustainedCost, + renderOneTimeCostMap, } from "./partial/rated/activatable/cost.js" import { renderExpressionBasedDuration, @@ -1599,6 +1600,8 @@ const renderBannzeichenCost = (options: Lazy, cost: Bannzei return Reader.sequence(cost.Disjunction.list.map(renderSingleEnergyCost)).thenW(text => localeJoinR(text, "disjunction"), ) + case "Map": + return renderOneTimeCostMap(cost.Map) case "DerivedFromOption": return renderOptionDerivedEnergyCost(options, option => option.cost?.value) default: