diff --git a/src/main.ts b/src/main.ts index 6156ded2..dc7c9e53 100644 --- a/src/main.ts +++ b/src/main.ts @@ -47,6 +47,7 @@ export const schema = new Schema( Types.BandageOrRemedy, Types.Bannzeichen, Types.Beutelzauber, + Types.Biome, Types.BlessedTradition, Types.Blessing, Types.Book, @@ -97,6 +98,7 @@ export const schema = new Schema( Types.Guideline, Types.HairColor, Types.Haubenzauber, + Types.HerbalAid, Types.HomunculusType, Types.IlluminationLightSource, Types.IlluminationRefillOrSupply, @@ -133,6 +135,7 @@ export const schema = new Schema( Types.PatronCategory, Types.PersonalityTrait, Types.PlayerType, + Types.Plant, Types.Poison, Types.Profession, Types.Property, diff --git a/src/types/_AlternativeNames.ts b/src/types/_AlternativeNames.ts index 490da90f..03c365e9 100644 --- a/src/types/_AlternativeNames.ts +++ b/src/types/_AlternativeNames.ts @@ -1,4 +1,5 @@ import * as DB from "tsondb/schema/dsl" +import { LanguageIdentifier } from "./_Identifier.js" export const AlternativeName = DB.TypeAlias(import.meta.url, { name: "AlternativeName", @@ -12,5 +13,9 @@ export const AlternativeName = DB.TypeAlias(import.meta.url, { comment: "The region where this alternative name is used.", type: DB.String({ minLength: 1 }), }), + language: DB.Optional({ + comment: "The language of that alternative name if any.", + type: LanguageIdentifier(), + }), }), }) diff --git a/src/types/_Identifier.ts b/src/types/_Identifier.ts index 57c37090..db15652d 100644 --- a/src/types/_Identifier.ts +++ b/src/types/_Identifier.ts @@ -15,7 +15,7 @@ import { CloseCombatTechnique, RangedCombatTechnique } from "./CombatTechnique.j import { Condition } from "./Condition.js" import { Continent } from "./Continent.js" import { Culture } from "./Culture.js" -import { DerivedCharacteristic } from "./DerivedCharacteristic.ts" +import { DerivedCharacteristic } from "./DerivedCharacteristic.js" import { Disadvantage } from "./Disadvantage.js" import { Disease } from "./Disease.js" import { Element } from "./Element.js" @@ -32,6 +32,7 @@ import { Container } from "./equipment/item/Container.js" import { Elixir } from "./equipment/item/Elixir.js" import { EquipmentOfBlessedOnes } from "./equipment/item/EquipmentOfBlessedOnes.js" import { GemOrPreciousStone } from "./equipment/item/GemOrPreciousStone.js" +import { HerbalAid } from "./equipment/item/HerbalAid.js" import { IlluminationLightSource } from "./equipment/item/IlluminationLightSource.js" import { IlluminationRefillOrSupply } from "./equipment/item/IlluminationRefillOrSupply.js" import { Jewelry } from "./equipment/item/Jewelry.js" @@ -42,10 +43,12 @@ import { MagicalArtifact } from "./equipment/item/MagicalArtifact.js" import { MusicalInstrument } from "./equipment/item/MusicalInstrument.js" import { Newspaper } from "./equipment/item/Newspaper.js" import { OrienteeringAid } from "./equipment/item/OrienteeringAid.js" +import { Plant } from "./equipment/item/Plant.js" import { Poison } from "./equipment/item/Poison.js" import { RopeOrChain } from "./equipment/item/RopeOrChain.js" import { Stationery } from "./equipment/item/Stationery.js" import { ArmorType } from "./equipment/item/sub/ArmorType.js" +import { Biome } from "./equipment/item/sub/Biome.js" import { Reach } from "./equipment/item/sub/Reach.js" import { ThievesTool } from "./equipment/item/ThievesTool.js" import { ToolOfTheTrade } from "./equipment/item/ToolOfTheTrade.js" @@ -53,11 +56,11 @@ import { TravelGearOrTool } from "./equipment/item/TravelGearOrTool.js" import { Vehicle } from "./equipment/item/Vehicle.js" import { Weapon } from "./equipment/item/Weapon.js" import { WeaponAccessory } from "./equipment/item/WeaponAccessory.js" -import { WorkingSupernaturalCreature } from "./equipment/item/WorkingSupernaturalCreature.ts" +import { WorkingSupernaturalCreature } from "./equipment/item/WorkingSupernaturalCreature.js" import { ExperienceLevel } from "./ExperienceLevel.js" import { EyeColor } from "./EyeColor.js" import { HairColor } from "./HairColor.js" -import { Influence } from "./Influence.ts" +import { Influence } from "./Influence.js" import { Curriculum, Guideline, LessonPackage } from "./Lessons.js" import { LiturgicalChant } from "./LiturgicalChant.js" import { AnimistPower } from "./magicalActions/AnimistPower.js" @@ -187,6 +190,7 @@ export const AttributeIdentifier: () => R = () => R(Attribute) export const BandageOrRemedyIdentifier: () => R = () => R(BandageOrRemedy) export const BannzeichenIdentifier: () => R = () => R(Bannzeichen) export const BeutelzauberIdentifier: () => R = () => R(Beutelzauber) +export const BiomeIdentifier: () => R = () => R(Biome) export const BlessedTraditionIdentifier: () => R = () => R(BlessedTradition) export const BlessingIdentifier: () => R = () => R(Blessing) export const BookIdentifier: () => R = () => R(Book) @@ -238,6 +242,7 @@ export const GoblinRitualIdentifier: () => R = () => R(GoblinRitual) export const GuidelineIdentifier: () => R = () => R(Guideline) export const HairColorIdentifier: () => R = () => R(HairColor) export const HaubenzauberIdentifier: () => R = () => R(Haubenzauber) +export const HerbalAidIdentifier: () => R = () => R(HerbalAid) export const IlluminationLightSourceIdentifier: () => R = () => R(IlluminationLightSource) export const IlluminationRefillOrSupplyIdentifier: () => R = () => R(IlluminationRefillOrSupply) export const InfluenceIdentifier: () => R = () => R(Influence) @@ -278,6 +283,7 @@ export const PactTypeIdentifier: () => R = () => R(PactType) export const PatronCategoryIdentifier: () => R = () => R(PatronCategory) export const PatronIdentifier: () => R = () => R(Patron) export const PersonalityTraitIdentifier: () => R = () => R(PersonalityTrait) +export const PlantIdentifier: () => R = () => R(Plant) export const PlayerTypeIdentifier: () => R = () => R(PlayerType) export const PoisonIdentifier: () => R = () => R(Poison) export const ProfessionIdentifier: () => R = () => R(Profession) diff --git a/src/types/equipment/item/HerbalAid.ts b/src/types/equipment/item/HerbalAid.ts new file mode 100644 index 00000000..791089b3 --- /dev/null +++ b/src/types/equipment/item/HerbalAid.ts @@ -0,0 +1,63 @@ +import * as DB from "tsondb/schema/dsl" +import { src } from "../../source/_PublicationRef.js" +import { NestedTranslationMap } from "../../Locale.js" +import { WeaponIdentifier, ArmorIdentifier } from "../../_Identifier.js" +import { EffectType } from "./_Herbary.js" + +export const HerbalAid = DB.Entity(import.meta.url, { + name: "HerbalAid", + namePlural: "HerbalAids", + type: () => + DB.Object({ + types: DB.Required({ + comment: "The plant types this aid belongs to.", + type: DB.Array(DB.IncludeIdentifier(EffectType), { minItems: 1, uniqueItems: true }), + }), + crafting_difficulty: DB.Required({ + comment: "The difficulty for this aid to craft.", + type: DB.Integer(), + }), + combatUse: DB.Optional({ + comment: "The armor or weapon this herbal aid represents.", + type: DB.IncludeIdentifier(HerbalAidCombatUse), + }), + src, + translations: NestedTranslationMap( + DB.Required, + "HerbalAid", + DB.Object({ + name: DB.Required({ + comment: "The herbal aid's name.", + type: DB.String({ minLength: 1 }), + }), + description: DB.Required({ + comment: "The herbal aid's description.", + type: DB.String({ minLength: 1, markdown: "block" }), + }), + ingredients: DB.Required({ + comment: "The ingredients used to craft this herbal aid.", + type: DB.Array(DB.String({ minLength: 1, markdown: "inline" }), { minItems: 1 }), + }), + typical_tools: DB.Optional({ + comment: "The typical tools used to craft this.", + type: DB.Array(DB.String({ minLength: 1, markdown: "inline" }), { minItems: 1 }), + }), + }), + ), + }), + instanceDisplayName: {}, + uniqueConstraints: [ + { + entityMapKeyPath: "translations", + keyPathInEntityMap: "name", + }, + ], +}) + +const HerbalAidCombatUse = DB.Enum(import.meta.url, { + name: "HerbalAidCombatUse", + values: () => ({ + Weapon: DB.EnumCase({ type: WeaponIdentifier() }), + Armor: DB.EnumCase({ type: ArmorIdentifier() }), + }), +}) diff --git a/src/types/equipment/item/Plant.ts b/src/types/equipment/item/Plant.ts new file mode 100644 index 00000000..33a0439d --- /dev/null +++ b/src/types/equipment/item/Plant.ts @@ -0,0 +1,281 @@ +import * as DB from "tsondb/schema/dsl" +import { src } from "../../source/_PublicationRef.js" +import { NestedTranslationMap } from "../../Locale.js" +import { AlternativeName } from "../../_AlternativeNames.js" +import { + BiomeIdentifier, + HerbalAidIdentifier, + ElixirIdentifier, + PoisonIdentifier, +} from "../../_Identifier.js" +import { ResponsiveTextOptional, ResponsiveTextReplace } from "../../_ResponsiveText.js" +import { EffectType, PlantRarity } from "./_Herbary.js" + +export const Plant = DB.Entity(import.meta.url, { + name: "Plant", + namePlural: "Plants", + type: () => + DB.Object({ + types: DB.Required({ + comment: "The plant types of this plant.", + type: DB.Array(DB.IncludeIdentifier(EffectType), { minItems: 1, uniqueItems: true }), + }), + occurences: DB.Required({ + comment: "The biomes this plant occurs in and its rarity in those biomes.", + type: DB.IncludeIdentifier(PlantOccurences), + }), + search_difficulty: DB.Required({ + comment: "The search difficulty for this plant.", + type: DB.Integer(), + }), + identification_difficulty: DB.Required({ + comment: "The identification difficulty for this plant.", + type: DB.Integer(), + }), + applications: DB.Required({ + comment: "The applications of this plant per quality level.", + type: DB.Array(DB.Integer(), { minItems: 6, maxItems: 6 }), + }), + touch: DB.Optional({ + comment: "The plant's touch effect.", + type: DB.IncludeIdentifier(PlantEffect), + }), + inhalation: DB.Optional({ + comment: "The plant's inhalation effect.", + type: DB.IncludeIdentifier(PlantEffect), + }), + ingestion: DB.Optional({ + comment: "The plant's ingestion effect.", + type: DB.IncludeIdentifier(PlantEffect), + }), + price: DB.Required({ + comment: "The price of the plant.", + type: DB.IncludeIdentifier(PlantPrice), + }), + recipes: DB.Optional({ + comment: "The herbal aids and elixirs that can be crafted with this plant.", + type: DB.Array(DB.IncludeIdentifier(PlantRecipe), { minItems: 1 }), + }), + src, + translations: NestedTranslationMap( + DB.Required, + "Plant", + DB.Object({ + name: DB.Required({ + comment: "The plant's name.", + type: DB.String({ minLength: 1 }), + }), + alternative_names: DB.Optional({ + comment: "A list of alternative names.", + type: DB.Array(DB.IncludeIdentifier(AlternativeName), { minItems: 1 }), + }), + remedies_and_traditions: DB.Required({ + comment: "How this plant is used as a household remedy and in folk traditions.", + type: DB.String({ minLength: 1, markdown: "block" }), + }), + knowledge: DB.Required({ + comment: + "What one knows about this plant for each quality level. The first element represents QL 1, the second element QL 2, and so on.", + type: DB.Array(DB.String({ minLength: 1, markdown: "block" }), { + minItems: 3, + maxItems: 6, + }), + }), + }), + ), + }), + instanceDisplayName: {}, + uniqueConstraints: [ + { + entityMapKeyPath: "translations", + keyPathInEntityMap: "name", + }, + ], +}) + +const PlantOccurences = DB.TypeAlias(import.meta.url, { + name: "PlantOccurences", + type: () => + DB.Object( + { + items: DB.Optional({ + comment: "The biomes this plant occurs in and its rarity in those biomes.", + type: DB.Array(DB.IncludeIdentifier(PlantOccurrence), { minItems: 1 }), + }), + translation: NestedTranslationMap( + DB.Optional, + "PlantOccurrences", + DB.Object({ + note: DB.Required({ + comment: "A note to all occurences of this plant", + type: DB.String({ minLength: 1, markdown: "block" }), + }), + }), + ), + }, + { + minProperties: 1, + }, + ), +}) + +const PlantOccurrence = DB.TypeAlias(import.meta.url, { + name: "PlantOccurrence", + type: () => + DB.Object({ + biome: DB.Required({ + comment: "The biome this plant occurs in.", + type: BiomeIdentifier(), + }), + rarity: DB.Required({ + comment: "The rarity of this plant in the biome.", + type: DB.IncludeIdentifier(PlantRarity), + }), + translation: NestedTranslationMap( + DB.Optional, + "PlantOccurrence", + DB.Object({ + note: DB.Required({ + comment: "A note added to this occurrence", + type: DB.String({ minLength: 1, markdown: "inline" }), + }), + }), + ), + }), +}) + +const PlantEffect = DB.TypeAlias(import.meta.url, { + name: "PlantEffect", + type: () => + DB.Object({ + types: DB.Optional({ + comment: "The effect type of this plant effect.", + type: DB.Array(DB.IncludeIdentifier(EffectType), { minItems: 1, uniqueItems: true }), + }), + translations: NestedTranslationMap( + DB.Required, + "PlantEffectTranslation", + DB.Object({ + description: DB.Required({ + comment: "The effect of the plant.", + type: DB.String({ minLength: 1, markdown: "block" }), + }), + }), + ), + }), +}) + +const PlantPrice = DB.Enum(import.meta.url, { + name: "PlantPrice", + values: () => ({ + Constant: DB.EnumCase({ + type: DB.Object({ + value: DB.Required({ + comment: "The value of the plant in silver coins.", + type: DB.Float({ minimum: 0 }), + }), + cost: DB.Required({ + comment: "The cost of the plant in silver coins.", + type: DB.Float({ minimum: 0 }), + }), + }), + }), + Indefinite: DB.EnumCase({ type: DB.IncludeIdentifier(IndefinitePlantPrice) }), + }), +}) + +const IndefinitePlantPrice = DB.TypeAlias(import.meta.url, { + name: "IndefinitePlantPrice", + type: () => + DB.Object({ + translations: NestedTranslationMap( + DB.Required, + "IndefinitePlantPrice", + DB.Object({ + description: DB.Required({ + comment: "A description of the price.", + type: DB.String({ minLength: 1, markdown: "block" }), + }), + }), + ), + }), +}) + +const PlantRecipe = DB.Enum(import.meta.url, { + name: "PlantRecipe", + values: () => ({ + HerbalAid: DB.EnumCase({ type: DB.IncludeIdentifier(HerbalAidRecipe) }), + Elixir: DB.EnumCase({ type: DB.IncludeIdentifier(ElixirRecipe) }), + Poison: DB.EnumCase({ type: DB.IncludeIdentifier(PoisonRecipe) }), + Indefinite: DB.EnumCase({ type: DB.IncludeIdentifier(IndefiniteRecipe) }), + }), +}) + +const PlantProductTranslation = DB.Object( + { + note: DB.Optional({ + comment: + "A note, appended to the generated string in parenthesis. If the generated is modified using `replacement`, the note is appended to the modifier string.", + type: DB.IncludeIdentifier(ResponsiveTextOptional), + }), + replacement: DB.Optional({ + comment: + "A replacement string. If `note` is provided, it is appended to the replaced string.", + type: DB.IncludeIdentifier(ResponsiveTextReplace), + }), + }, + { minProperties: 1 }, +) + +const HerbalAidRecipe = DB.TypeAlias(import.meta.url, { + name: "HerbalAidRecipe", + type: () => + DB.Object({ + herbal_aid: DB.Required({ + comment: "The herbal aid this recipe results in.", + type: HerbalAidIdentifier(), + }), + translation: NestedTranslationMap(DB.Optional, "HerbalAidRecipe", PlantProductTranslation), + }), +}) + +const ElixirRecipe = DB.TypeAlias(import.meta.url, { + name: "ElixirRecipe", + type: () => + DB.Object({ + elixir: DB.Required({ + comment: "The elixir this recipe results in.", + type: ElixirIdentifier(), + }), + translation: NestedTranslationMap(DB.Optional, "ElixirRecipe", PlantProductTranslation), + }), +}) + +const PoisonRecipe = DB.TypeAlias(import.meta.url, { + name: "PoisonRecipe", + type: () => + DB.Object({ + poison: DB.Required({ + comment: "The poison this recipe results in.", + type: PoisonIdentifier(), + }), + translation: NestedTranslationMap(DB.Optional, "PoisonRecipe", PlantProductTranslation), + }), +}) + +const IndefiniteRecipe = DB.TypeAlias(import.meta.url, { + name: "IndefiniteRecipe", + type: () => + DB.Object({ + translations: NestedTranslationMap( + DB.Required, + "IndefiniteRecipe", + DB.Object({ + description: DB.Required({ + comment: "A description of the recipe.", + type: DB.String({ minLength: 1, markdown: "inline" }), + }), + }), + ), + }), +}) diff --git a/src/types/equipment/item/_Herbary.ts b/src/types/equipment/item/_Herbary.ts index 610574a6..3bfbec6b 100644 --- a/src/types/equipment/item/_Herbary.ts +++ b/src/types/equipment/item/_Herbary.ts @@ -19,6 +19,18 @@ export const EffectType = DB.Enum(import.meta.url, { }), }) +export const PlantRarity = DB.Enum(import.meta.url, { + name: "PlantRarity", + comment: "The rarity of a plant in a biome.", + values: () => ({ + Common: DB.EnumCase({ type: null }), + Occasional: DB.EnumCase({ type: null }), + RatherRare: DB.EnumCase({ type: null }), + Rare: DB.EnumCase({ type: null }), + VeryRare: DB.EnumCase({ type: null }), + }), +}) + export const LaboratoryLevel = DB.Enum(import.meta.url, { name: "LaboratoryLevel", values: () => ({ diff --git a/src/types/equipment/item/sub/Biome.ts b/src/types/equipment/item/sub/Biome.ts new file mode 100644 index 00000000..23b228af --- /dev/null +++ b/src/types/equipment/item/sub/Biome.ts @@ -0,0 +1,27 @@ +import * as DB from "tsondb/schema/dsl" +import { NestedTranslationMap } from "../../../Locale.js" + +export const Biome = DB.Entity(import.meta.url, { + name: "Biome", + namePlural: "Biome", + type: () => + DB.Object({ + translations: NestedTranslationMap( + DB.Required, + "Biome", + DB.Object({ + name: DB.Required({ + comment: "The biome's name.", + type: DB.String({ minLength: 1 }), + }), + }), + ), + }), + instanceDisplayName: {}, + uniqueConstraints: [ + { + entityMapKeyPath: "translations", + keyPathInEntityMap: "name", + }, + ], +}) diff --git a/src/types/index.ts b/src/types/index.ts index c38ece4e..1e735191 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -30,6 +30,7 @@ export { Container } from "./equipment/item/Container.js" export { Elixir } from "./equipment/item/Elixir.js" export { EquipmentOfBlessedOnes } from "./equipment/item/EquipmentOfBlessedOnes.js" export { GemOrPreciousStone } from "./equipment/item/GemOrPreciousStone.js" +export { HerbalAid } from "./equipment/item/HerbalAid.js" export { IlluminationLightSource } from "./equipment/item/IlluminationLightSource.js" export { IlluminationRefillOrSupply } from "./equipment/item/IlluminationRefillOrSupply.js" export { Jewelry } from "./equipment/item/Jewelry.js" @@ -40,10 +41,12 @@ export { MagicalArtifact } from "./equipment/item/MagicalArtifact.js" export { MusicalInstrument } from "./equipment/item/MusicalInstrument.js" export { Newspaper } from "./equipment/item/Newspaper.js" export { OrienteeringAid } from "./equipment/item/OrienteeringAid.js" +export { Plant } from "./equipment/item/Plant.js" export { Poison } from "./equipment/item/Poison.js" export { RopeOrChain } from "./equipment/item/RopeOrChain.js" export { Stationery } from "./equipment/item/Stationery.js" export { ArmorType } from "./equipment/item/sub/ArmorType.js" +export { Biome } from "./equipment/item/sub/Biome.js" export { Reach } from "./equipment/item/sub/Reach.js" export { ThievesTool } from "./equipment/item/ThievesTool.js" export { ToolOfTheTrade } from "./equipment/item/ToolOfTheTrade.js" @@ -51,7 +54,7 @@ export { TravelGearOrTool } from "./equipment/item/TravelGearOrTool.js" export { Vehicle } from "./equipment/item/Vehicle.js" export { Weapon } from "./equipment/item/Weapon.js" export { WeaponAccessory } from "./equipment/item/WeaponAccessory.js" -export { WorkingSupernaturalCreature } from "./equipment/item/WorkingSupernaturalCreature.ts" +export { WorkingSupernaturalCreature } from "./equipment/item/WorkingSupernaturalCreature.js" export { ExperienceLevel } from "./ExperienceLevel.js" export { EyeColor } from "./EyeColor.js" export { FamiliarsTrick } from "./FamiliarsTrick.js"