version 0.0.1

This commit is contained in:
2026-05-11 22:07:17 +02:00
parent fd160cc13b
commit 5869b87336
53 changed files with 11810 additions and 80 deletions
@@ -0,0 +1,154 @@
<script lang="ts">
import { onMount } from 'svelte';
import { page } from '$app/stores';
import type { Character } from '$lib/schema/character';
import { getCharacter } from '$lib/storage/repo';
import { computeMeleeTargets } from '$lib/engine/melee';
import { TALENTS } from '$lib/rules/talents';
let char: Character | undefined;
let err = '';
const id = $page.params.id ?? '';
let talentId = 'dolche';
let weaponIndex = 0;
let situation = '0';
let atExtra = 0;
let paExtra = 0;
let ansage = 0;
onMount(async () => {
if (!id) {
err = 'Ungültige URL.';
return;
}
char = await getCharacter(id);
if (!char) err = 'Held nicht gefunden.';
else if (char.waffen.nahkampf.length) {
talentId = char.waffen.nahkampf[0].talentId;
}
});
$: wIdx = Number(weaponIndex);
$: weapon = char?.waffen.nahkampf[wIdx];
$: result =
char &&
weapon &&
computeMeleeTargets(
char,
talentId,
weapon.atMod,
weapon.paMod,
{
situationModifiers: situation
.split(/[,;]+/)
.map((s) => parseInt(s.trim(), 10))
.filter((n) => Number.isFinite(n)),
atExtra,
paExtra,
ansageAtAnteil: ansage
}
);
</script>
{#if err}
<p class="err">{err}</p>
{:else if !char}
<p>Lade …</p>
{:else}
<h1>Nahkampf · {char.meta.name}</h1>
<p class="muted">
Wähle Waffe und Erschwernisse (Zahlen). Manöver-Details am Tisch hier nur Summen.
</p>
<section class="card stack">
<h2>Waffe</h2>
{#if char.waffen.nahkampf.length === 0}
<p>Keine Nahkampfwaffe im Bogen. Unter „Bogen“ anlegen.</p>
{:else}
<select bind:value={weaponIndex}>
{#each char.waffen.nahkampf as w, i}
<option value={i}>{w.name}</option>
{/each}
</select>
<div class="field">
<label>Kampftalent für diese Attacke</label>
<select bind:value={talentId}>
{#each TALENTS.filter((t) => t.category === 'kampf') as t}
<option value={t.id}>{t.name}</option>
{/each}
</select>
</div>
{/if}
</section>
<section class="card stack">
<h2>Situation</h2>
<div class="field">
<label>Zusätzliche Erschwernisse (Komma-getrennt, z.B. 3,2)</label>
<input bind:value={situation} placeholder="0" />
</div>
<div class="grid-2">
<div class="field">
<label>AT-Zusatz</label>
<input type="number" bind:value={atExtra} />
</div>
<div class="field">
<label>PA-Zusatz</label>
<input type="number" bind:value={paExtra} />
</div>
</div>
<div class="field">
<label>Ansage (AT-Anteil, vereinfacht)</label>
<input type="number" min="0" bind:value={ansage} />
</div>
</section>
{#if result}
<section class="card stack highlight">
<h2>Zielzahlen</h2>
<div class="grid-2">
<div>
<p class="muted">Attacke</p>
<p class="big-number">{result.atTarget}</p>
</div>
<div>
<p class="muted">Parade</p>
<p class="big-number">{result.paTarget}</p>
</div>
</div>
<ul class="kv">
<li><span>AT (inkl. Waffe)</span><strong>{result.at}</strong></li>
<li><span>PA (inkl. Waffe)</span><strong>{result.pa}</strong></li>
<li><span>Summe Modifikatoren</span><strong>{result.modifierSum}</strong></li>
</ul>
{#each result.notes as n}
<p class="muted">{n}</p>
{/each}
</section>
{/if}
<p><a href="/characters/{char.id}">Zurück</a></p>
{/if}
<style>
.highlight {
border-color: var(--accent-dim);
}
.kv {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.kv li {
display: flex;
justify-content: space-between;
gap: 1rem;
}
.err {
color: var(--danger);
}
</style>