From b9970ccdf842e735c1f712afc74c21a21c0254c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Pons?= Date: Wed, 22 Oct 2025 17:57:19 +0200 Subject: [PATCH] Add inventory management in character sheet. --- db.sqlite | Bin 761856 -> 761856 bytes db.sqlite-shm | Bin 32768 -> 0 bytes db.sqlite-wal | 0 shared/character-config.json | 10991 +-------------------------------- shared/character.util.ts | 219 +- shared/components.util.ts | 2 +- shared/feature.util.ts | 14 +- types/character.d.ts | 4 +- 8 files changed, 195 insertions(+), 11035 deletions(-) delete mode 100644 db.sqlite-shm delete mode 100644 db.sqlite-wal diff --git a/db.sqlite b/db.sqlite index a82d5370ad78f8e7e18ba5031b7f0c5326b23601..9cdef3f89af015adb5e6071e987fe073e4106b3c 100644 GIT binary patch delta 714 zcmb7?O>5Lp6oxbDL^}?#*|=zj7QI&7q@84(L^3FJ<*rLXszdWJH(!&RJCjK!&GloV zi?l^hQ7~&kTq^}#+Fwxg-?&kXHR!YyN|)z6hv&Q;PP)IE?yr7)w^{q~>mI*Qy<4lk z`GlAE4mO*YXNuOdG)pU4N@wZJ=d@b+R;MV6t~aQ9W3IO+azAIeZJ%YS`PzEr1zTCv z8dSctLSN6{Z!lN6=TA!XcI7Dg&h3s%^m_3qy29-)mFN{Zj&|;p=;iJI=u5F{fu1}B zP7icIq>C}$8cLED7)XL<4Beri_aj5bFqV@5@IXU2@emDZ1`&}Ls zbzs4w5FhiUQm_V|h}uvvY|Gm+T`ZG;U^$F$V%;Q(b*P;Db&4lB;V^Or16af}HE#s} ziS@P|h_)*ZP>Y29NFZX2WJ_||H|)fVi8Gb;RPSV3j4ZEj;?PwP?kRqsw2-DLvQL5p z$)ix2KEkQuX|Fv-lJA;B+a<|3v|O3QN<=JOkDax|5C}R;;y>cz;0XIL0UaU#`hdAL zH-C|(E)~!8be&?^;+Y;b>1%nj%LvTjT)xp|TA9jZ>bXokpQ*E%TFcZ6AJqEVZ{hFZ AGynhq delta 208 zcmZoTpx1CfZ^OcP&hM*=bfj29Iawxe%vafbE?!@O87S1$(AL1%*1*)(z`U)2h4BJ6 zZw~_#S1torF3+#ch60IP+^t-^ybO|@zKk8N)AJ%(|87@~VfAEWjGe9-&uYWP&&SIk z3Y2WLoSq-g8a4f;4wIT_K~ZK|Vo53k15*i9C!?(X^ukEiUl7eQv9(OW`N^4yNja%5 rhgX)Q7MG+d CompiledCharacter = (c aspect: "", notes: Object.assign({ public: '', private: '' }, character.notes), }); - export const mainStatTexts: Record = { "strength": "Force", "dexterity": "Dextérité", @@ -153,7 +152,6 @@ export const mainStatShortTexts: Record = { "charisma": "CHA", "psyche": "PSY", }; - export const elementTexts: Record = { fire: { class: 'text-light-red dark:text-dark-red border-light-red dark:border-dark-red bg-light-red dark:bg-dark-red', text: 'Feu' }, ice: { class: 'text-light-blue dark:text-dark-blue border-light-blue dark:border-dark-blue bg-light-blue dark:bg-dark-blue', text: 'Glace' }, @@ -169,7 +167,6 @@ export const elementDom = (element: SpellElement) => dom("span", { class: [`border !border-opacity-50 rounded-full !bg-opacity-20 px-2 py-px`, elementTexts[element].class], text: elementTexts[element].text }); - export const alignmentTexts: Record = { 'loyal_good': 'Loyal bon', 'neutral_good': 'Neutre bon', @@ -182,7 +179,6 @@ export const alignmentTexts: Record = { 'chaotic_evil': 'Chaotique mauvais', }; export const spellTypeTexts: Record = { "instinct": "Instinct", "knowledge": "Savoir", "precision": "Précision", "arts": "Oeuvres" }; - export const abilityTexts: Record = { "athletics": "Athlétisme", "acrobatics": "Acrobatique", @@ -202,7 +198,6 @@ export const abilityTexts: Record = { "animalhandling": "Dressage", "deception": "Mensonge" }; - export const resistanceTexts: Record = { 'stun': 'Hébètement', 'bleed': 'Saignement', @@ -224,23 +219,19 @@ export const damageTypeTexts: Record = { 'slashing': 'Tranchant', 'thunder': 'Foudre', }; -export const weaponTypeTexts: Record = { - "light": "Arme légère", - "shield": "Bouclier", - "heavy": "Arme lourde", - "classic": "Arme", - "throw": "Arme de jet", - "natural": "Arme naturelle", - "twohanded": "Deux mains", - "finesse": "Arme maniable", - "reach": "Arme longue", - "projectile": "Arme à projectile", -}; export const CharacterNotesValidation = z.object({ public: z.string().optional(), private: z.string().optional(), }); +export const ItemStateValidation = z.object({ + id: z.string(), + amount: z.number().min(1), + enchantments: z.array(z.string()).optional(), + charges: z.number().optional(), + equipped: z.boolean().optional(), + state: z.any().optional(), +}) export const CharacterVariablesValidation = z.object({ health: z.number(), mana: z.number(), @@ -255,7 +246,9 @@ export const CharacterVariablesValidation = z.object({ state: z.number().min(1).max(7).or(z.literal(true)), })), spells: z.array(z.string()), - items: z.array(z.string()), + items: z.array(ItemStateValidation), + + money: z.number(), }); export const CharacterValidation = z.object({ id: z.number(), @@ -1229,6 +1222,65 @@ class AspectPicker extends BuilderTab } } +type Category = ItemConfig['category']; +type Rarity = ItemConfig['rarity']; +export const colorByRarity: Record = { + 'common': 'text-light-100 dark:text-dark-100', + 'uncommon': 'text-light-cyan dark:text-dark-cyan', + 'rare': 'text-light-purple dark:text-dark-purple', + 'legendary': 'text-light-orange dark:text-dark-orange' +} +export const weaponTypeTexts: Record = { + "light": 'légère', + "shield": 'bouclier', + "heavy": 'lourde', + "classic": 'arme', + "throw": 'de jet', + "natural": 'naturelle', + "twohanded": 'à deux mains', + "finesse": 'maniable', + "reach": 'longue', + "projectile": 'à projectile', +} +export const armorTypeTexts: Record = { + 'heavy': 'Armure lourde', + 'light': 'Armure légère', + 'medium': 'Armure', +} +export const categoryText: Record = { + 'mundane': 'Objet', + 'armor': 'Armure', + 'weapon': 'Arme', + 'wondrous': 'Objet magique' +}; +export const rarityText: Record = { + 'common': 'Commun', + 'uncommon': 'Atypique', + 'rare': 'Rare', + 'legendary': 'Légendaire' +}; +const subnameFactory = (item: ItemConfig, state?: ItemState): string[] => { + let result = []; + switch(item.category) + { + case 'armor': + result = [armorTypeTexts[(item as ArmorConfig).type]]; + break; + case 'weapon': + result = ['Arme', ...(item as WeaponConfig).type.filter(e => e !== 'classic').map(e => weaponTypeTexts[e])]; + break; + case 'mundane': + result = ['Objet']; + break; + case 'wondrous': + result = ['Objet magique']; + break; + } + if(state && state.enchantments !== undefined && state.enchantments.length > 0) result.push('Enchanté'); + if(item.consummable) result.push('Consommable'); + + return result; +} export class CharacterSheet { user: ComputedRef; @@ -1290,9 +1342,7 @@ export class CharacterSheet { id: 'spells', title: [ text('Sorts') ], content: () => this.spellTab(character) }, - { id: 'inventory', title: [ text('Inventaire') ], content: () => [ - - ] }, + { id: 'inventory', title: [ text('Inventaire') ], content: () => this.itemsTab(character) }, { id: 'notes', title: [ text('Notes') ], content: () => [ div('flex flex-col gap-2', [ @@ -1488,7 +1538,7 @@ export class CharacterSheet div('flex flex-col gap-8', [ div('flex flex-col gap-2', [ div("flex flex-row items-center justify-center gap-4", [ - div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 12, height: 12, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Actions', class: 'h-4' }) ]), + div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Actions', class: 'h-4' }) ]), div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"), div('flex flex-row items-center gap-2', [ ...Array(character.action).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ round' }) ]), ]), @@ -1503,7 +1553,7 @@ export class CharacterSheet ]), div('flex flex-col gap-2', [ div("flex flex-row items-center justify-center gap-4", [ - div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Réactions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 12, height: 12, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Réaction', class: 'h-4' }) ]), + div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Réactions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Réaction', class: 'h-4' }) ]), div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"), div('flex flex-row items-center gap-2', [ ...Array(character.reaction).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ round' }) ]), ]), @@ -1518,7 +1568,7 @@ export class CharacterSheet ]), div('flex flex-col gap-2', [ div("flex flex-row items-center justify-center gap-4", [ - div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions libres" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 12, height: 12, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Action libre', class: 'h-4' }) ]), + div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions libres" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Action libre', class: 'h-4' }) ]), div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"), ]), @@ -1576,14 +1626,14 @@ export class CharacterSheet ]), div('flex flex-row gap-2 items-center', [ dom('span', { class: ['italic text-sm', { 'text-light-red dark:text-dark-red': character.variables.spells.length !== character.spellslots }], text: `${character.variables.spells.length}/${character.spellslots} sort${character.variables.spells.length > 1 ? 's' : ''} maitrisé${character.variables.spells.length > 1 ? 's' : ''}` }), - button(text('Modifier'), () => this.spellPanel(character, spells), 'py-1 px-4'), + button(text('Modifier'), () => this.spellPanel(character), 'py-1 px-4'), ]) ]), div('flex flex-col gap-2', spells.map(e => e.dom)) ]) ] } - spellPanel(character: CompiledCharacter, spelllist: Array<{ id: string, spell?: SpellConfig, source: string }>) + spellPanel(character: CompiledCharacter) { const availableSpells = Object.values(config.spells).filter(spell => { if (spell.rank === 4) return false; @@ -1650,4 +1700,113 @@ export class CharacterSheet const blocker = fullblocker([ container ], { closeWhenOutside: true, onClose: () => this.character?.saveVariables() }); setTimeout(() => container.setAttribute('data-state', 'active'), 1); } + itemsTab(character: CompiledCharacter) + { + let debounceId: NodeJS.Timeout | undefined; + //TODO: Recompile values on "equip" checkbox change + const items = (character.variables.items.map(e => ({ ...e, item: config.items[e.id] })).filter(e => !!e.item) as Array).map(e => div('flex flex-row justify-between', [ + div('flex flex-row items-center gap-4', [ + div('flex flex-col gap-1', [ e.item.equippable ? checkbox({ defaultValue: e.equipped, change: v => { + e.equipped = v; + + this.character!.variable('items', this.character!.character.variables.items); + + debounceId && clearTimeout(debounceId); + debounceId = setTimeout(() => this.character?.saveVariables(), 2000); + + this.tabs?.refresh(); + }, class: { container: '!w-5 !h-5' } }) : checkbox({ disabled: true, class: { container: '!w-5 !h-5' } }), button(icon('radix-icons:trash', { width: 16, height: 17 }), () => { + const idx = this.character!.character.variables.items.findIndex(_e => _e.id === e.id); + if(idx === -1) return; + + this.character!.character.variables.items[idx]!.amount--; + if(this.character!.character.variables.items[idx]!.amount >= 0) this.character!.character.variables.items.splice(idx, 1); + + this.character!.variable('items', this.character!.character.variables.items); + + debounceId && clearTimeout(debounceId); + debounceId = setTimeout(() => this.character?.saveVariables(), 2000); + + this.tabs?.refresh(); + }, 'p-px') ]), + div('flex flex-col gap-1', [ span([colorByRarity[e.item.rarity], 'text-lg'], e.item.name), div('flex flex-row gap-4 text-light-60 dark:text-dark-60 text-sm italic', subnameFactory(e.item, e).map(text)) ]), + ]), + div('grid grid-cols-2 row-gap-2 col-gap-8', [ + div('flex flex-row w-16 gap-2 justify-between items-center', [ icon('game-icons:bolt-drop', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('flex-1', (e.item.powercost || (e.enchantments && e.enchantments.length > 0)) && e.item.capacity ? `${(e.item?.powercost ?? 0) + (e.enchantments?.reduce((p, v) => (config.enchantments[v]?.power ?? 0) + p, 0) ?? 0)}/${e.item.capacity}` : '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center', [ icon('mdi:weight', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('flex-1', e.item.weight?.toString() ?? '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center', [ icon('game-icons:battery-pack', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('flex-1', e.charges && e.item.charge ? `${e.charges}/${e.item.charge}` : '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center', [ icon('radix-icons:cross-2', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('flex-1', e.amount?.toString() ?? '-') ]) + ]) + ])); + + const power = character.variables.items.filter(e => config.items[e.id]?.equippable && e.equipped).reduce((p, v) => p + (config.items[v.id]?.powercost ?? 0) + (v.enchantments?.reduce((_p, _v) => (config.enchantments[_v]?.power ?? 0) + _p, 0) ?? 0), 0); + const weight = character.variables.items.reduce((p, v) => p + (config.items[v.id]?.weight ?? 0), 0); + + return [ + div('flex flex-col gap-2', [ + div('flex flex-row justify-end items-center gap-8', [ + dom('span', { class: ['italic text-sm', { 'text-light-red dark:text-dark-red': weight > character.itempower }], text: `Poids total: ${weight}/${character.itempower}` }), + dom('span', { class: ['italic text-sm', { 'text-light-red dark:text-dark-red': power > (character.capacity === false ? 0 : character.capacity) }], text: `Puissance magique: ${power}/${character.capacity}` }), + button(text('Modifier'), () => this.itemsPanel(character), 'py-1 px-4'), + ]), + div('grid grid-cols-2 flex-1 gap-4', items) + ]) + ] + } + itemsPanel(character: CompiledCharacter) + { + const items = Object.values(config.items).map(item => ({ item, dom: foldable(() => [ markdown(getText(item.description)) ], [div('flex flex-row justify-between', [ + div('flex flex-row items-center gap-4', [ + div('flex flex-row items-center gap-4', [ span([colorByRarity[item.rarity], 'text-lg'], item.name), div('flex flex-row gap-2 text-light-60 dark:text-dark-60 text-sm italic', subnameFactory(item).map(e => span('', e))) ]), + ]), + div('flex flex-row items-center divide-x divide-light-50 dark:divide-dark-50 divide-dashed px-2', [ + div('flex flex-row w-16 gap-2 justify-between items-center px-2', [ icon('game-icons:bolt-drop', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('', item.powercost || item.capacity ? `${item.powercost ?? 0}/${item.capacity ?? 0}` : '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center px-2', [ icon('mdi:weight', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('', item.weight?.toString() ?? '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center px-2', [ icon('game-icons:battery-pack', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('', item.charge ? `${item.charge}` : '-') ]), + div('flex flex-row w-16 gap-2 justify-between items-center px-2', [ icon('ph:coin', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }), span('', item.price ? `${item.price}` : '-') ]), + button(icon('radix-icons:plus', { width: 16, height: 16 }), () => { + const list = [...this.character!.character.variables.items]; + if(item.equippable) list.push({ id: item.id, amount: 1, charges: item.charge, enchantments: [], equipped: false }); + else if(list.find(e => e.id === item.id)) this.character!.character.variables.items.find(e => e.id === item.id)!.amount++; + else list.push({ id: item.id, amount: 1, charges: item.charge, enchantments: [] }); + this.character!.variable('items', list); //TO REWORK + this.tabs?.refresh(); + }, 'p-1 !border-solid !border-r'), + ]), + ])], { open: false, class: { icon: 'px-2', container: 'border border-light-35 dark:border-dark-35 p-1 gap-2', content: 'px-2 pb-1' } }) })); + + const filters: { category: Category[], rarity: Rarity[], name: string, power: { min: number, max: number } } = { + category: [], + rarity: [], + name: '', + power: { min: 0, max: Infinity }, + }; + const applyFilters = () => { + content.replaceChildren(...items.filter(e => + (filters.category.length === 0 || filters.category.includes(e.item.category)) && + (filters.rarity.length === 0 || filters.rarity.includes(e.item.rarity)) && + (filters.name === '' || e.item.name.toLowerCase().includes(filters.name.toLowerCase())) + ).map(e => e.dom)); + } + + const content = div('grid grid-cols-1 -my-2 overflow-y-auto gap-1'); + const container = div("border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10 border-l absolute top-0 bottom-0 right-0 w-[10%] data-[state=active]:w-1/2 flex flex-col gap-4 text-light-100 dark:text-dark-100 p-8 transition-[width] transition-delay-[150ms]", [ + div("flex flex-row justify-between items-center mb-4", [ + dom("h2", { class: "text-xl font-bold", text: "Gestion de l'inventaire" }), + div('flex flex-row gap-4 items-center', [ tooltip(button(icon("radix-icons:cross-1", { width: 20, height: 20 }), () => { + setTimeout(blocker.close, 150); + container.setAttribute('data-state', 'inactive'); + }, "p-1"), "Fermer", "left") ]) + ]), + div('flex flex-row items-center gap-4', [ + div('flex flex-row gap-2 items-center', [ text('Catégorie'), multiselect(Object.keys(categoryText).map(e => ({ text: categoryText[e as Category], value: e as Category })), { defaultValue: filters.category, change: v => { filters.category = v; applyFilters(); }, class: { container: 'w-40' } }) ]), + div('flex flex-row gap-2 items-center', [ text('Rareté'), multiselect(Object.keys(rarityText).map(e => ({ text: rarityText[e as Rarity], value: e as Rarity })), { defaultValue: filters.rarity, change: v => { filters.rarity = v; applyFilters(); }, class: { container: 'w-40' } }) ]), + div('flex flex-row gap-2 items-center', [ text('Nom'), input('text', { defaultValue: filters.name, input: v => { filters.name = v; applyFilters(); }, class: 'w-64' }) ]), + ]), + content, + ]); + applyFilters(); + const blocker = fullblocker([ container ], { closeWhenOutside: true, onClose: () => this.character?.saveVariables() }); + setTimeout(() => container.setAttribute('data-state', 'active'), 1); + } } \ No newline at end of file diff --git a/shared/components.util.ts b/shared/components.util.ts index 00e12b3..c0e60e3 100644 --- a/shared/components.util.ts +++ b/shared/components.util.ts @@ -481,7 +481,7 @@ export function checkbox(settings?: { defaultValue?: boolean, change?: (this: HT let state = settings?.defaultValue ?? false; const element = dom("div", { class: [`group w-6 h-6 box-content flex items-center justify-center border border-light-50 dark:border-dark-50 bg-light-20 dark:bg-dark-20 cursor-pointer hover:bg-light-30 dark:hover:bg-dark-30 hover:border-light-60 dark:hover:border-dark-60 - data-[disabled]:cursor-default data-[disabled]:border-dashed data-[disabled]:border-light-40 dark:data-[disabled]:border-dark-40 data-[disabled]:bg-0 dark:data-[disabled]:bg-0`, settings?.class?.container], attributes: { "data-state": state ? "checked" : "unchecked", "data-disabled": settings?.disabled }, listeners: { + data-[disabled]:cursor-default data-[disabled]:border-dashed data-[disabled]:border-light-40 dark:data-[disabled]:border-dark-40 data-[disabled]:bg-0 dark:data-[disabled]:bg-0 hover:data-[disabled]:bg-0 dark:hover:data-[disabled]:bg-0`, settings?.class?.container], attributes: { "data-state": state ? "checked" : "unchecked", "data-disabled": settings?.disabled }, listeners: { click: function(e: Event) { if(this.hasAttribute('data-disabled')) return; diff --git a/shared/feature.util.ts b/shared/feature.util.ts index 836b289..c5031f6 100644 --- a/shared/feature.util.ts +++ b/shared/feature.util.ts @@ -4,7 +4,7 @@ import { MarkdownEditor } from "#shared/editor.util"; import { preview } from "#shared/proses"; import { button, checkbox, combobox, foldable, input, multiselect, numberpicker, optionmenu, select, tabgroup, table, toggle, type Option } from "#shared/components.util"; import { confirm, contextmenu, fullblocker, tooltip } from "#shared/floating.util"; -import { ABILITIES, abilityTexts, ALIGNMENTS, alignmentTexts, damageTypeTexts, elementTexts, LEVELS, MAIN_STATS, mainStatShortTexts, mainStatTexts, RESISTANCES, resistanceTexts, SPELL_ELEMENTS, SPELL_TYPES, spellTypeTexts, weaponTypeTexts } from "#shared/character.util"; +import { ABILITIES, abilityTexts, ALIGNMENTS, alignmentTexts, categoryText, damageTypeTexts, elementTexts, LEVELS, MAIN_STATS, mainStatShortTexts, mainStatTexts, rarityText, RESISTANCES, resistanceTexts, SPELL_ELEMENTS, SPELL_TYPES, spellTypeTexts, weaponTypeTexts } from "#shared/character.util"; import characterConfig from "#shared/character-config.json"; import { getID } from "#shared/general.util"; import markdown, { markdownReference, renderMDAsText } from "#shared/markdown.util"; @@ -13,18 +13,6 @@ import { getText } from "#shared/i18n"; type Category = ItemConfig['category']; type Rarity = ItemConfig['rarity']; -const categoryText: Record = { - 'mundane': 'Objet inerte', - 'armor': 'Armure', - 'weapon': 'Arme', - 'wondrous': 'Objet magique' -}; -const rarityText: Record = { - 'common': 'Commun', - 'uncommon': 'Peu commun', - 'rare': 'Rare', - 'legendary': 'Légendaire' -}; const config = characterConfig as CharacterConfig; export class HomebrewBuilder diff --git a/types/character.d.ts b/types/character.d.ts index cec951d..61a34f7 100644 --- a/types/character.d.ts +++ b/types/character.d.ts @@ -52,11 +52,13 @@ export type CharacterVariables = { poisons: Array<{ id: string, state: number | true }>; spells: string[]; //Spell ID items: ItemState[]; + + money: number; }; type ItemState = { id: string; amount: number; - enchantments?: []; + enchantments?: string[]; charges?: number; equipped?: boolean; state?: any;