feat: plants entity

Refs: #142
Closes #3
Reviewed-by: Lukas Obermann <lukas.obermann@icloud.com>
This commit is contained in:
Lector
2026-06-04 13:45:30 +02:00
committed by GitHub
parent 2be0fb3c50
commit ae45659ff9
8 changed files with 404 additions and 4 deletions
+3
View File
@@ -47,6 +47,7 @@ export const schema = new Schema<TSONDBTypes>(
Types.BandageOrRemedy,
Types.Bannzeichen,
Types.Beutelzauber,
Types.Biome,
Types.BlessedTradition,
Types.Blessing,
Types.Book,
@@ -97,6 +98,7 @@ export const schema = new Schema<TSONDBTypes>(
Types.Guideline,
Types.HairColor,
Types.Haubenzauber,
Types.HerbalAid,
Types.HomunculusType,
Types.IlluminationLightSource,
Types.IlluminationRefillOrSupply,
@@ -133,6 +135,7 @@ export const schema = new Schema<TSONDBTypes>(
Types.PatronCategory,
Types.PersonalityTrait,
Types.PlayerType,
Types.Plant,
Types.Poison,
Types.Profession,
Types.Property,
+5
View File
@@ -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(),
}),
}),
})
+9 -3
View File
@@ -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)
+63
View File
@@ -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() }),
}),
})
+281
View File
@@ -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" }),
}),
}),
),
}),
})
+12
View File
@@ -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: () => ({
+27
View File
@@ -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",
},
],
})
+4 -1
View File
@@ -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"