Ziel
@@ -216,7 +203,7 @@
diff --git a/tests/engine/derived.test.ts b/tests/engine/derived.test.ts
index ab364f8..64ae6b5 100644
--- a/tests/engine/derived.test.ts
+++ b/tests/engine/derived.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
-import { atBasis, fkBasis, lepMax, paBasis, computeDerived } from '$lib/engine/derived';
+import { aspMax, atBasis, aupMax, fkBasis, lepMax, paBasis, computeDerived } from '$lib/engine/derived';
import { newCharacter } from '$lib/characters/default';
describe('derived', () => {
@@ -7,7 +7,7 @@ describe('derived', () => {
const c = newCharacter({ name: 'Test', id: '00000000-0000-4000-8000-000000000001' });
expect(atBasis(c)).toBe(Math.round((11 + 11 + 11) / 5));
expect(paBasis(c)).toBe(Math.round((11 + 11 + 11) / 5));
- expect(fkBasis(c)).toBe(Math.round((11 + 11 + 11) / 4));
+ expect(fkBasis(c)).toBe(Math.round((11 + 11 + 11) / 5));
});
it('includes race LeP bonus for human', () => {
@@ -17,10 +17,30 @@ describe('derived', () => {
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);
+ const base = Math.round((2 * ko + kk) / 2);
expect(lepMax(c)).toBe(base + 10 + c.energien.lep.mod);
});
+ it('computes aspMax as round((MU+IN+CH)/2) plus race and mod', () => {
+ const c = newCharacter({ id: '00000000-0000-4000-8000-000000000004' });
+ c.energien.asp = { mod: 0 };
+ c.eigenschaften.MU = { startwert: 12, mod: 0 };
+ c.eigenschaften.IN = { startwert: 14, mod: 0 };
+ c.eigenschaften.CH = { startwert: 10, mod: 0 };
+ const base = Math.round((12 + 14 + 10) / 2);
+ expect(aspMax(c)).toBe(base + c.energien.asp.mod);
+ });
+
+ it('computes aupMax as round((MU+KO+GE)/2) plus race and mod', () => {
+ const c = newCharacter({ id: '00000000-0000-4000-8000-000000000005' });
+ c.meta.rasse = 'mensch01';
+ c.eigenschaften.MU = { startwert: 13, mod: 0 };
+ c.eigenschaften.KO = { startwert: 12, mod: 0 };
+ c.eigenschaften.GE = { startwert: 11, mod: 0 };
+ const base = Math.round((13 + 12 + 11) / 2);
+ expect(aupMax(c)).toBe(base + 10 + c.energien.aup.mod);
+ });
+
it('computeDerived returns all keys', () => {
const c = newCharacter({ id: '00000000-0000-4000-8000-000000000003' });
const d = computeDerived(c);
diff --git a/tests/engine/ranged.test.ts b/tests/engine/ranged.test.ts
index d0149ff..81cf777 100644
--- a/tests/engine/ranged.test.ts
+++ b/tests/engine/ranged.test.ts
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest';
import { computeRangedTarget } from '$lib/engine/ranged';
+import { fkBasis } from '$lib/engine/derived';
import { newCharacter } from '$lib/characters/default';
import type { ExtraModifierId } from '$lib/rules/modifiers-ranged';
@@ -26,8 +27,8 @@ const baseSel = {
describe('ranged', () => {
it('computes FK target with zero modifiers', () => {
const c = charWithBogen(4);
- const fkBase = Math.round((11 + 11 + 11) / 4);
- const r = computeRangedTarget(c, 'shortbow', { ...baseSel, reloadState: undefined }, 'none');
+ const fkBase = fkBasis(c);
+ const r = computeRangedTarget(c, 'shortbow', { ...baseSel, reloadState: undefined });
expect(r.fkBase).toBe(fkBase);
expect(r.baseTarget).toBe(fkBase + 4);
expect(r.finalTarget).toBe(fkBase + 4);
@@ -38,8 +39,7 @@ describe('ranged', () => {
const r = computeRangedTarget(
c,
'shortbow',
- { ...baseSel, range: 'medium', reloadState: 'regular_shot' },
- 'none'
+ { ...baseSel, range: 'medium', reloadState: 'regular_shot' }
);
// +4 Entfernung, +1 normaler Schuss, +0 Zielgröße „groß“
expect(r.totalModifier).toBe(5);
@@ -51,10 +51,39 @@ describe('ranged', () => {
const r = computeRangedTarget(
c,
'shortbow',
- { ...baseSel, reloadState: 'aimed_shot' },
- 'none'
+ { ...baseSel, reloadState: 'aimed_shot' }
);
expect(r.effectiveTaW).toBe(5);
expect(r.baseTarget).toBe(r.fkBase + 5);
});
+
+ it('applies matching weapon specialization (+2 FK)', () => {
+ const c = charWithBogen(0);
+ c.abilities = [{ id: 'sf1', defId: 'specialize_shortbow' }];
+ const base = computeRangedTarget(c, 'shortbow', baseSel);
+ const plain = computeRangedTarget(charWithBogen(0), 'shortbow', baseSel);
+ expect(base.finalTarget).toBe(plain.finalTarget + 2);
+ });
+
+ it('ignores specialization for a different weapon', () => {
+ const c = charWithBogen(0);
+ c.abilities = [{ id: 'sf1', defId: 'specialize_longbow' }];
+ const r = computeRangedTarget(c, 'shortbow', baseSel);
+ const plain = computeRangedTarget(charWithBogen(0), 'shortbow', baseSel);
+ expect(r.finalTarget).toBe(plain.finalTarget);
+ });
+
+ it('derives expert from Scharfschütze ability (TaW/2 -2 for aimed shot)', () => {
+ const c = charWithBogen(10);
+ c.abilities = [{ id: 'sf1', defId: 'sniper' }];
+ const r = computeRangedTarget(c, 'shortbow', { ...baseSel, reloadState: 'aimed_shot' });
+ expect(r.effectiveTaW).toBe(3);
+ });
+
+ it('derives master from Meisterschütze ability (full TaW for aimed shot)', () => {
+ const c = charWithBogen(10);
+ c.abilities = [{ id: 'sf1', defId: 'marksman' }];
+ const r = computeRangedTarget(c, 'shortbow', { ...baseSel, reloadState: 'aimed_shot' });
+ expect(r.effectiveTaW).toBe(10);
+ });
});