From a281592541f646613fa76472090a86ba628fd79f Mon Sep 17 00:00:00 2001 From: Falk Graepel Date: Sat, 16 May 2026 18:58:05 +0200 Subject: [PATCH] refine abilities and stuff --- src/lib/characters/default.ts | 6 +- src/lib/rules/abilities.ts | 99 +++++++++++++++ src/lib/rules/advantages.ts | 45 +++++++ src/lib/rules/disadvantages.ts | 26 ++++ src/lib/schema/character.ts | 14 +- src/routes/characters/[id]/sheet/+page.svelte | 120 +++++++++++++++--- 6 files changed, 283 insertions(+), 27 deletions(-) create mode 100644 src/lib/rules/abilities.ts create mode 100644 src/lib/rules/advantages.ts create mode 100644 src/lib/rules/disadvantages.ts diff --git a/src/lib/characters/default.ts b/src/lib/characters/default.ts index a035b56..8196926 100644 --- a/src/lib/characters/default.ts +++ b/src/lib/characters/default.ts @@ -34,9 +34,9 @@ export function newCharacter(partial?: { name?: string; id?: string }): Characte aup: { mod: 0 }, mr: { mod: 0 } }, - vorteile: [], - nachteile: [], - sonderfertigkeiten: [], + advantages: [], + disadvantages: [], + abilities: [], talente: [], kampftalente: [], inventar: [], diff --git a/src/lib/rules/abilities.ts b/src/lib/rules/abilities.ts new file mode 100644 index 0000000..61a58b4 --- /dev/null +++ b/src/lib/rules/abilities.ts @@ -0,0 +1,99 @@ +/** Abilities (Sonderfertigkeiten, extensible); modifiers for melee and ranged combat */ +export type AbilityDef = { + id: string; + name: string; + at_mod: number; + pa_mod: number; + fk_mod: number; +}; + +export const ABILITIES: AbilityDef[] = [ + { + id: 'evade_1', + name: 'Ausweichen I', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'evade_2', + name: 'Ausweichen II', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'evade_3', + name: 'Ausweichen III', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'sniper', + name: 'Scharfschütze', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'marksman', + name: 'Meisterschütze', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'fast_reload', + name: 'Schnellladen', + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'specialize_elven_bow', + name: 'Talentspezialisierung Bogen (Elfenbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'specialize_composite_bow', + name: 'Talentspezialisierung Bogen (Kompositbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'specialize_warbow', + name: 'Talentspezialisierung Bogen (Kriegsbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'specialize_shortbow', + name: 'Talentspezialisierung Bogen (Kurzbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'specialize_longbow', + name: 'Talentspezialisierung Bogen (Langbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'specialize_orc_bow', + name: 'Talentspezialisierung Bogen (Ork. Reiterbogen)', + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + } +]; + +export function getAbility(id: string): AbilityDef | undefined { + return ABILITIES.find((s) => s.id === id); +} diff --git a/src/lib/rules/advantages.ts b/src/lib/rules/advantages.ts new file mode 100644 index 0000000..a6a0f90 --- /dev/null +++ b/src/lib/rules/advantages.ts @@ -0,0 +1,45 @@ +/** Advantage definitions (extensible); modifiers for melee and ranged combat */ +export type AdvantageDef = { + id: string; + name: string; + has_levels: boolean; + /** z. B. [1, 2, 3], wenn has_levels – sonst leer */ + levels: number[]; + at_mod: number; + pa_mod: number; + fk_mod: number; +}; + +export const ADVANTAGES: AdvantageDef[] = [ + { + id: 'entfernungssinn', + name: 'Entfernungssinn', + has_levels: false, + levels: [], + at_mod: 0, + pa_mod: 0, + fk_mod: 2 + }, + { + id: 'innerer_kompass', + name: 'Innerer Kompass', + has_levels: false, + levels: [], + at_mod: 0, + pa_mod: 0, + fk_mod: 0 + }, + { + id: 'kampfreflexe', + name: 'Kampfreflexe', + has_levels: true, + levels: [1, 2, 3], + at_mod: 1, + pa_mod: 0, + fk_mod: 0 + } +]; + +export function getAdvantage(id: string): AdvantageDef | undefined { + return ADVANTAGES.find((v) => v.id === id); +} diff --git a/src/lib/rules/disadvantages.ts b/src/lib/rules/disadvantages.ts new file mode 100644 index 0000000..b2db85a --- /dev/null +++ b/src/lib/rules/disadvantages.ts @@ -0,0 +1,26 @@ +/** Disadvantage definitions (extensible); modifiers for melee and ranged combat */ +export type DisadvantageDef = { + id: string; + name: string; + has_levels: boolean; + levels: number[]; + at_mod: number; + pa_mod: number; + fk_mod: number; +}; + +export const DISADVANTAGES: DisadvantageDef[] = [ + { + id: 'einaeuig', + name: 'Einäugig', + has_levels: false, + levels: [], + at_mod: 0, + pa_mod: 0, + fk_mod: -2 + } +]; + +export function getDisadvantage(id: string): DisadvantageDef | undefined { + return DISADVANTAGES.find((n) => n.id === id); +} diff --git a/src/lib/schema/character.ts b/src/lib/schema/character.ts index e11e42c..62ec64c 100644 --- a/src/lib/schema/character.ts +++ b/src/lib/schema/character.ts @@ -14,13 +14,17 @@ const energySchema = z.object({ const traitSchema = z.object({ id: z.string(), - name: z.string(), + /** Referenz auf Eintrag in rules (advantage/disadvantage) */ + defId: z.string().default(''), + name: z.string().optional(), + stufe: z.number().int().optional(), note: z.string().optional() }); const sfSchema = z.object({ id: z.string(), - name: z.string(), + defId: z.string().default(''), + name: z.string().optional(), note: z.string().optional() }); @@ -108,9 +112,9 @@ export const characterSchema = z.object({ aup: energySchema, mr: energySchema }), - vorteile: z.array(traitSchema).default([]), - nachteile: z.array(traitSchema).default([]), - sonderfertigkeiten: z.array(sfSchema).default([]), + advantages: z.array(traitSchema).default([]), + disadvantages: z.array(traitSchema).default([]), + abilities: z.array(sfSchema).default([]), talente: z.array(talentEntrySchema).default([]), kampftalente: z.array(combatTalentSchema).default([]), zauber: z.array(spellEntrySchema).optional(), diff --git a/src/routes/characters/[id]/sheet/+page.svelte b/src/routes/characters/[id]/sheet/+page.svelte index ec72f68..aaece99 100644 --- a/src/routes/characters/[id]/sheet/+page.svelte +++ b/src/routes/characters/[id]/sheet/+page.svelte @@ -5,7 +5,10 @@ import { ATTRIBUTE_KEYS, ATTRIBUTE_LABELS } from '$lib/rules/attributes'; import { getCharacter, saveCharacter } from '$lib/storage/repo'; import { RACES } from '$lib/rules/races'; + import { DISADVANTAGES, getDisadvantage } from '$lib/rules/disadvantages'; + import { ABILITIES } from '$lib/rules/abilities'; import { TALENTS } from '$lib/rules/talents'; + import { ADVANTAGES, getAdvantage } from '$lib/rules/advantages'; import { computeDerived } from '$lib/engine/derived'; import { atBasis, paBasis } from '$lib/engine/derived'; @@ -55,21 +58,59 @@ char = char; } - function addVorteil() { + function addAdvantage() { if (!char) return; - char.vorteile = [...char.vorteile, { id: crypto.randomUUID(), name: '' }]; + const first = ADVANTAGES[0]; + char.advantages = [ + ...char.advantages, + { + id: crypto.randomUUID(), + defId: first?.id ?? '', + stufe: first?.has_levels && first.levels[0] !== undefined ? first.levels[0] : undefined + } + ]; char = char; } - function addNachteil() { + function addDisadvantage() { if (!char) return; - char.nachteile = [...char.nachteile, { id: crypto.randomUUID(), name: '' }]; + const first = DISADVANTAGES[0]; + char.disadvantages = [ + ...char.disadvantages, + { + id: crypto.randomUUID(), + defId: first?.id ?? '', + stufe: first?.has_levels && first.levels[0] !== undefined ? first.levels[0] : undefined + } + ]; char = char; } - function addSF() { + function addAbility() { if (!char) return; - char.sonderfertigkeiten = [...char.sonderfertigkeiten, { id: crypto.randomUUID(), name: '' }]; + const first = ABILITIES[0]; + char.abilities = [ + ...char.abilities, + { id: crypto.randomUUID(), defId: first?.id ?? '' } + ]; + char = char; + } + + function onAdvantageDefChange(v: Character['advantages'][number], defId: string) { + if (!char) return; + v.defId = defId; + const d = getAdvantage(defId); + if (d?.has_levels && d.levels.length) v.stufe = d.levels[0]; + else v.stufe = undefined; + char = char; + } + + function onDisadvantageDefChange(v: Character['disadvantages'][number], defId: string) { + if (!char) return; + v.defId = defId; + const d = getDisadvantage(defId); + if (d?.has_levels && d.levels.length) v.stufe = d.levels[0]; + else v.stufe = undefined; char = char; } @@ -232,7 +273,7 @@ {#each char.talente as tal, i}
@@ -252,56 +293,97 @@

Vorteile

- {#each char.vorteile as v, i} + {#each char.advantages as v, i} + {@const vd = getAdvantage(v.defId)}
- + + {#if vd?.has_levels && vd.levels.length} + + + {/if}
{/each} - +

Nachteile

- {#each char.nachteile as v, i} + {#each char.disadvantages as v, i} + {@const nd = getDisadvantage(v.defId)}
- + + {#if nd?.has_levels && nd.levels.length} + + + {/if}
{/each} - +

Sonderfertigkeiten

- {#each char.sonderfertigkeiten as s, i} + {#each char.abilities as s, i}
- +
{/each} - +