From b0a4bd554eddfa13ec3dc0ea3a43f62bf80848ae Mon Sep 17 00:00:00 2001 From: Falk Graepel Date: Sat, 16 May 2026 18:35:55 +0200 Subject: [PATCH] rework races --- src/lib/characters/default.ts | 2 +- src/lib/engine/derived.ts | 15 ++-- src/lib/rules/races.ts | 68 ++++++++++++------- src/routes/characters/[id]/sheet/+page.svelte | 8 ++- tests/engine/derived.test.ts | 4 +- 5 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/lib/characters/default.ts b/src/lib/characters/default.ts index ea4900d..a035b56 100644 --- a/src/lib/characters/default.ts +++ b/src/lib/characters/default.ts @@ -24,7 +24,7 @@ export function newCharacter(partial?: { name?: string; id?: string }): Characte schemaVersion: CURRENT_SCHEMA_VERSION, meta: { name, - rasse: 'Mensch', + rasse: 'mensch01', kultur: '', profession: '' }, diff --git a/src/lib/engine/derived.ts b/src/lib/engine/derived.ts index f62ffb2..0b67f5c 100644 --- a/src/lib/engine/derived.ts +++ b/src/lib/engine/derived.ts @@ -1,6 +1,6 @@ import type { AttributeKey } from '$lib/rules/attributes'; import type { Character } from '$lib/schema/character'; -import { RACE_ASP_MOD, RACE_LEP_MOD } from '$lib/rules/races'; +import { getRaceDef } from '$lib/rules/races'; export function effectiveAttr(char: Character, key: AttributeKey): number { const a = char.eigenschaften[key]; @@ -36,11 +36,13 @@ export function iniBasis(char: Character): number { return Math.round(v); } -/** MR-Basis = (MU + KL + KO) / 5 + MR-Mod aus Energien */ +/** MR-Basis = (MU + KL + KO) / 5 + MR-Mod aus Energien + Rassen-MR */ export function mrBasis(char: Character): number { + const race = getRaceDef(char.meta.rasse); const v = (effectiveAttr(char, 'MU') + effectiveAttr(char, 'KL') + effectiveAttr(char, 'KO')) / 5 + - char.energien.mr.mod; + char.energien.mr.mod + + (race?.mr_mod ?? 0); return Math.round(v); } @@ -49,20 +51,21 @@ export function lepMax(char: Character): number { const ko = effectiveAttr(char, 'KO'); const kk = effectiveAttr(char, 'KK'); const base = Math.floor((2 * ko + kk) / 2); - const race = RACE_LEP_MOD[char.meta.rasse] ?? 0; + const race = getRaceDef(char.meta.rasse)?.lep_mod ?? 0; return base + race + char.energien.lep.mod; } export function aspMax(char: Character): number { if (!char.energien.asp) return 0; - const race = RACE_ASP_MOD[char.meta.rasse] ?? 0; + const race = getRaceDef(char.meta.rasse)?.asp_mod ?? 0; const base = effectiveAttr(char, 'IN') + effectiveAttr(char, 'IN') + effectiveAttr(char, 'CH'); return Math.max(0, base + race + char.energien.asp.mod); } export function aupMax(char: Character): number { + const race = getRaceDef(char.meta.rasse)?.aup_mod ?? 0; const base = effectiveAttr(char, 'MU') + effectiveAttr(char, 'MU') + effectiveAttr(char, 'IN'); - return Math.max(0, base + char.energien.aup.mod); + return Math.max(0, base + race + char.energien.aup.mod); } export type DerivedSheet = { diff --git a/src/lib/rules/races.ts b/src/lib/rules/races.ts index dbda099..32230cd 100644 --- a/src/lib/rules/races.ts +++ b/src/lib/rules/races.ts @@ -1,26 +1,46 @@ -/** LeP-Modifikator je Rasse (typische Werte DSA 4.1, vereinfacht) */ -export const RACE_LEP_MOD: Record = { - Mensch: 5, - Elf: 2, - Halbelf: 4, - Zwerg: 8, - Halbling: 0, - Gnom: -4, - Halbork: 6, - Ork: 8, - Goblin: -5, - '': 0 +/** Rassen mit LeP-/AuP-/AsP-/MR-Modifikatoren (typische Werte DSA 4.1, vereinfacht) */ +export type RaceDef = { + id: string; + name: string; + lep_mod: number; + aup_mod: number; + asp_mod: number; + mr_mod: number; }; -export const RACE_ASP_MOD: Record = { - Mensch: 0, - Elf: 12, - Halbelf: 6, - Zwerg: 0, - Halbling: 0, - Gnom: 0, - Halbork: 0, - Ork: 0, - Goblin: 0, - '': 0 -}; +export const RACES: RaceDef[] = [ + { id: 'mensch01', name: 'Mittelländer', lep_mod: 10, aup_mod: 10, asp_mod: 0, mr_mod: -4 }, + { id: 'mensch02', name: 'Tulamide', lep_mod: 10, aup_mod: 10, asp_mod: 0, mr_mod: -4 }, + { id: 'mensch03', name: 'Thorwaler', lep_mod: 11, aup_mod: 10, asp_mod: 0, mr_mod: -5 }, + { id: 'mensch04', name: 'Nivese', lep_mod: 9, aup_mod: 12, asp_mod: 0, mr_mod: -5 }, + { id: 'mensch05', name: 'Norbarde', lep_mod: 11, aup_mod: 10, asp_mod: 0, mr_mod: -4 }, + { id: 'mensch06', name: 'Trollzacker', lep_mod: 11, aup_mod: 18, asp_mod: 0, mr_mod: -5 }, + { id: 'mensch07', name: 'Rochshaz', lep_mod: 12, aup_mod: 20, asp_mod: 0, mr_mod: -5 }, + { id: 'mensch08', name: 'Waldmensch', lep_mod: 8, aup_mod: 12, asp_mod: 0, mr_mod: -6 }, + { id: 'mensch09', name: 'Tocamuyac', lep_mod: 8, aup_mod: 12, asp_mod: 0, mr_mod: -6 }, + { id: 'mensch10', name: 'Utulu', lep_mod: 11, aup_mod: 12, asp_mod: 0, mr_mod: -6 }, + { id: 'plainelf', name: 'Auelf', lep_mod: 6, aup_mod: 12, asp_mod: 12, mr_mod: -2 }, + { id: 'woodelf', name: 'Waldelf', lep_mod: 6, aup_mod: 10, asp_mod: 12, mr_mod: -2 }, + { id: 'firnelf', name: 'Firnelf', lep_mod: 7, aup_mod: 15, asp_mod: 12, mr_mod: -1 }, + { id: 'halbelf', name: 'Halbelf', lep_mod: 8, aup_mod: 10, asp_mod: -6, mr_mod: -4 }, + { id: 'zwerg01', name: 'Zwerg', lep_mod: 11, aup_mod: 15, asp_mod: 0, mr_mod: -4 }, + { id: 'zwerg02', name: 'Brilliantzwerg', lep_mod: 10, aup_mod: 18, asp_mod: 0, mr_mod: -4 }, + { id: 'zwerg03', name: 'Ambosszwerg', lep_mod: 12, aup_mod: 18, asp_mod: 0, mr_mod: -4 }, + { id: 'ork01', name: 'Ork', lep_mod: 12, aup_mod: 18, asp_mod: 0, mr_mod: -7 }, + { id: 'ork02', name: 'Orkfrau', lep_mod: 10, aup_mod: 15, asp_mod: 0, mr_mod: -7 }, + { id: 'halbork', name: 'Halbork', lep_mod: 11, aup_mod: 15, asp_mod: 0, mr_mod: -6 }, + { id: 'goblin', name: 'Goblin', lep_mod: 4, aup_mod: 12, asp_mod: 0, mr_mod: -5 }, + { id: 'achaz01', name: 'Achaz', lep_mod: 8, aup_mod: 7, asp_mod: 0, mr_mod: -2 }, + { id: 'achaz02', name: 'Orkland-Achaz', lep_mod: 15, aup_mod: 7, asp_mod: 0, mr_mod: -2 }, + { id: 'achaz03', name: 'Maraskan-Achaz', lep_mod: 15, aup_mod: 7, asp_mod: 0, mr_mod: -2 } +]; + +export function getRaceDef(rasse: string): RaceDef | undefined { + if (!rasse) return undefined; + const byId = RACES.find((r) => r.id === rasse); + if (byId) return byId; + const lower = rasse.toLowerCase(); + const byIdLower = RACES.find((r) => r.id === lower); + if (byIdLower) return byIdLower; + return RACES.find((r) => r.name === rasse); +} diff --git a/src/routes/characters/[id]/sheet/+page.svelte b/src/routes/characters/[id]/sheet/+page.svelte index 2659db8..ec72f68 100644 --- a/src/routes/characters/[id]/sheet/+page.svelte +++ b/src/routes/characters/[id]/sheet/+page.svelte @@ -4,6 +4,7 @@ import type { Character } from '$lib/schema/character'; import { ATTRIBUTE_KEYS, ATTRIBUTE_LABELS } from '$lib/rules/attributes'; import { getCharacter, saveCharacter } from '$lib/storage/repo'; + import { RACES } from '$lib/rules/races'; import { TALENTS } from '$lib/rules/talents'; import { computeDerived } from '$lib/engine/derived'; import { atBasis, paBasis } from '$lib/engine/derived'; @@ -116,7 +117,12 @@
- +
diff --git a/tests/engine/derived.test.ts b/tests/engine/derived.test.ts index 0cdbcd2..ab364f8 100644 --- a/tests/engine/derived.test.ts +++ b/tests/engine/derived.test.ts @@ -12,13 +12,13 @@ describe('derived', () => { it('includes race LeP bonus for human', () => { const c = newCharacter({ name: 'H', id: '00000000-0000-4000-8000-000000000002' }); - c.meta.rasse = 'Mensch'; + c.meta.rasse = 'Mittelländer'; const ko = 12; const kk = 13; c.eigenschaften.KO = { startwert: ko, mod: 0 }; c.eigenschaften.KK = { startwert: kk, mod: 0 }; const base = Math.floor((2 * ko + kk) / 2); - expect(lepMax(c)).toBe(base + 5 + c.energien.lep.mod); + expect(lepMax(c)).toBe(base + 10 + c.energien.lep.mod); }); it('computeDerived returns all keys', () => {