1696 lines
59 KiB
HTML
1696 lines
59 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light only">
|
||
<meta name="supported-color-schemes" content="light">
|
||
<title>Der letzte Auftrag – JGA Abenteuer</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=MedievalSharp&family=Cinzel+Decorative:wght@700&family=Cinzel:wght@400;600&family=Crimson+Pro:ital,wght@0,400;0,600;1,400&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root {
|
||
--parchment: #f4e8c1;
|
||
--parchment-dark: #e8d5a0;
|
||
--ink: #1a0f00;
|
||
--ink-light: #3d2200;
|
||
--red: #8b1a1a;
|
||
--gold: #c9a227;
|
||
--gold-light: #f0c94a;
|
||
--green: #1a4a1a;
|
||
--blue: #1a2a5a;
|
||
--purple: #4a1a6a;
|
||
--shadow: rgba(0,0,0,0.4);
|
||
}
|
||
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
/* Force light mode – verhindert iOS/Koder Dark Mode Override */
|
||
:root { color-scheme: light only; }
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
body { background: #0d0800 !important; }
|
||
.parchment { background: #f4e8c1 !important; }
|
||
.parchment p, .parchment li, .parchment div { color: #3d2200 !important; }
|
||
.quest-card { background: #e8d5a0 !important; }
|
||
.rules-box { background: rgba(138,101,32,0.15) !important; }
|
||
input, textarea { background: #f4e8c1 !important; color: #1a0f00 !important; }
|
||
}
|
||
|
||
body {
|
||
background: #0d0800;
|
||
font-family: 'Crimson Pro', Georgia, serif;
|
||
color: #1a0f00;
|
||
min-height: 100vh;
|
||
background-image:
|
||
radial-gradient(ellipse at 50% 0%, #2a1500 0%, #0d0800 60%);
|
||
}
|
||
|
||
/* ── COVER ─────────────────────────────────── */
|
||
#cover {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-align: center;
|
||
padding: 2rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#cover::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse at 50% 40%, rgba(201,162,39,0.15) 0%, transparent 70%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.stars {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
.star {
|
||
position: absolute;
|
||
width: 2px; height: 2px;
|
||
background: #fff;
|
||
border-radius: 50%;
|
||
animation: twinkle var(--d, 3s) ease-in-out infinite var(--delay, 0s);
|
||
opacity: 0;
|
||
}
|
||
@keyframes twinkle {
|
||
0%,100% { opacity: 0; }
|
||
50% { opacity: var(--bright, 0.8); }
|
||
}
|
||
|
||
.cover-emblem {
|
||
font-size: 5rem;
|
||
margin-bottom: 1rem;
|
||
filter: drop-shadow(0 0 20px rgba(201,162,39,0.6));
|
||
animation: float 4s ease-in-out infinite;
|
||
}
|
||
@keyframes float {
|
||
0%,100% { transform: translateY(0); }
|
||
50% { transform: translateY(-10px); }
|
||
}
|
||
|
||
.cover-subtitle {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.9rem;
|
||
letter-spacing: 0.4em;
|
||
color: var(--gold);
|
||
text-transform: uppercase;
|
||
margin-bottom: 0.8rem;
|
||
}
|
||
|
||
.cover-title {
|
||
font-family: 'Cinzel Decorative', serif;
|
||
font-size: clamp(2rem, 6vw, 4.5rem);
|
||
color: var(--gold-light);
|
||
text-shadow:
|
||
0 0 30px rgba(201,162,39,0.8),
|
||
2px 2px 0 #5a3a00,
|
||
4px 4px 0 #3a2000;
|
||
line-height: 1.15;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.cover-divider {
|
||
width: 300px;
|
||
height: 2px;
|
||
background: linear-gradient(90deg, transparent, var(--gold), transparent);
|
||
margin: 1.5rem auto;
|
||
position: relative;
|
||
}
|
||
.cover-divider::before, .cover-divider::after {
|
||
content: '◆';
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: var(--gold);
|
||
font-size: 1rem;
|
||
}
|
||
.cover-divider::before { left: -10px; }
|
||
.cover-divider::after { right: -10px; }
|
||
|
||
.cover-desc {
|
||
color: #c8a86a;
|
||
font-size: 1.15rem;
|
||
font-style: italic;
|
||
max-width: 500px;
|
||
line-height: 1.7;
|
||
margin-bottom: 2.5rem;
|
||
}
|
||
|
||
.btn-primary {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 1rem;
|
||
letter-spacing: 0.15em;
|
||
color: var(--ink);
|
||
background: linear-gradient(135deg, var(--gold-light), var(--gold));
|
||
border: none;
|
||
padding: 0.9rem 2.5rem;
|
||
cursor: pointer;
|
||
clip-path: polygon(8px 0%, 100% 0%, calc(100% - 8px) 100%, 0% 100%);
|
||
transition: all 0.2s;
|
||
font-weight: 600;
|
||
box-shadow: 0 4px 15px rgba(201,162,39,0.4);
|
||
}
|
||
.btn-primary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 25px rgba(201,162,39,0.6);
|
||
background: linear-gradient(135deg, #ffe070, var(--gold-light));
|
||
}
|
||
|
||
/* ── MAIN APP ───────────────────────────────── */
|
||
#app { display: none; }
|
||
|
||
.page-wrap {
|
||
max-width: 900px;
|
||
margin: 0 auto;
|
||
padding: 2rem 1rem 4rem;
|
||
background: #f0e4b8;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* ── NAV ───────────────────────────────────── */
|
||
.top-nav {
|
||
background: linear-gradient(90deg, #1a0800, #2d1500, #1a0800);
|
||
border-bottom: 2px solid var(--gold);
|
||
padding: 0.8rem 1.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
}
|
||
.nav-title {
|
||
font-family: 'Cinzel', serif;
|
||
color: var(--gold);
|
||
font-size: 1rem;
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.nav-tabs {
|
||
display: flex;
|
||
gap: 0.3rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
.nav-tab {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.75rem;
|
||
letter-spacing: 0.08em;
|
||
color: #a07840;
|
||
background: transparent;
|
||
border: 1px solid #4a2800;
|
||
padding: 0.35rem 0.8rem;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.nav-tab:hover, .nav-tab.active {
|
||
color: var(--gold-light);
|
||
border-color: var(--gold);
|
||
background: rgba(201,162,39,0.1);
|
||
}
|
||
|
||
/* ── PARCHMENT SECTIONS ────────────────────── */
|
||
.parchment {
|
||
background: #f4e8c1 !important;
|
||
border: 3px solid #8a6520;
|
||
border-radius: 4px;
|
||
padding: 2rem;
|
||
margin-bottom: 2rem;
|
||
box-shadow:
|
||
0 0 0 1px #c9a227,
|
||
0 8px 30px rgba(0,0,0,0.5),
|
||
inset 0 1px 0 rgba(255,255,255,0.3);
|
||
position: relative;
|
||
}
|
||
|
||
.parchment::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 6px;
|
||
border: 1px solid rgba(138,101,32,0.3);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.section-title {
|
||
font-family: 'Cinzel Decorative', serif;
|
||
font-size: 1.4rem;
|
||
color: var(--red);
|
||
text-align: center;
|
||
margin-bottom: 0.5rem;
|
||
text-shadow: 1px 1px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.2em;
|
||
color: #8a6520;
|
||
text-align: center;
|
||
text-transform: uppercase;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.ornament {
|
||
text-align: center;
|
||
color: var(--gold);
|
||
font-size: 1.2rem;
|
||
letter-spacing: 0.5em;
|
||
margin: 1rem 0;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
p {
|
||
font-size: 1.05rem;
|
||
line-height: 1.8;
|
||
margin-bottom: 0.8rem;
|
||
color: var(--ink-light);
|
||
}
|
||
|
||
.flavor-text {
|
||
font-style: italic;
|
||
background: rgba(138,101,32,0.08);
|
||
border-left: 3px solid var(--gold);
|
||
padding: 0.8rem 1rem;
|
||
margin: 1rem 0;
|
||
border-radius: 0 4px 4px 0;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
/* ── QUEST CARDS ───────────────────────────── */
|
||
.quest-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||
gap: 1.2rem;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
.quest-card {
|
||
background: #e8d5a0;
|
||
border: 2px solid #8a6520;
|
||
border-radius: 4px;
|
||
padding: 1.2rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition: transform 0.2s, box-shadow 0.2s;
|
||
cursor: pointer;
|
||
}
|
||
.quest-card:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
|
||
}
|
||
.quest-card.done {
|
||
opacity: 0.6;
|
||
filter: saturate(0.4);
|
||
}
|
||
.quest-card.done::after {
|
||
content: '✓ ERLEDIGT';
|
||
position: absolute;
|
||
top: 50%; left: 50%;
|
||
transform: translate(-50%,-50%) rotate(-15deg);
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 1.5rem;
|
||
color: var(--green);
|
||
border: 3px solid var(--green);
|
||
padding: 0.3rem 0.8rem;
|
||
opacity: 0.8;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.quest-badge {
|
||
display: inline-block;
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.65rem;
|
||
letter-spacing: 0.1em;
|
||
padding: 0.2rem 0.6rem;
|
||
border-radius: 2px;
|
||
margin-bottom: 0.5rem;
|
||
font-weight: 600;
|
||
}
|
||
.badge-easy { background: #2a5a1a; color: #a8ff80; }
|
||
.badge-medium { background: #5a4a00; color: #ffd060; }
|
||
.badge-hard { background: #5a1a00; color: #ff8060; }
|
||
.badge-tabletop { background: #2a1a5a; color: #a080ff; }
|
||
|
||
.quest-name {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 1rem;
|
||
color: var(--red);
|
||
margin-bottom: 0.4rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.quest-holder {
|
||
font-size: 0.85rem;
|
||
color: #5a3a10;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.quest-holder strong { color: var(--ink); }
|
||
|
||
.quest-desc {
|
||
font-size: 0.9rem;
|
||
line-height: 1.5;
|
||
color: var(--ink-light);
|
||
margin-bottom: 0.8rem;
|
||
}
|
||
|
||
.quest-rewards {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 0.8rem;
|
||
border-top: 1px solid #c9a22760;
|
||
padding-top: 0.6rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.reward-success {
|
||
color: var(--green);
|
||
font-weight: 600;
|
||
}
|
||
.reward-fail {
|
||
color: var(--red);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.quest-expand {
|
||
display: none;
|
||
margin-top: 0.8rem;
|
||
padding-top: 0.8rem;
|
||
border-top: 1px dashed #c9a22780;
|
||
font-size: 0.9rem;
|
||
line-height: 1.6;
|
||
color: var(--ink);
|
||
}
|
||
.quest-card.expanded .quest-expand { display: block; }
|
||
|
||
.expand-hint {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.7rem;
|
||
color: #8a6520;
|
||
text-align: right;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
/* ── INVENTORY TRACKER ─────────────────────── */
|
||
.inventory-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||
gap: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.item-slot {
|
||
border: 2px dashed #8a6520;
|
||
border-radius: 4px;
|
||
padding: 1rem;
|
||
text-align: center;
|
||
min-height: 100px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.4rem;
|
||
transition: all 0.3s;
|
||
cursor: pointer;
|
||
position: relative;
|
||
background: rgba(138,101,32,0.05);
|
||
}
|
||
.item-slot.collected {
|
||
border: 2px solid var(--gold);
|
||
background: rgba(201,162,39,0.1);
|
||
box-shadow: 0 0 10px rgba(201,162,39,0.3);
|
||
}
|
||
|
||
.item-emoji { font-size: 2.5rem; }
|
||
.item-name {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.75rem;
|
||
color: var(--ink-light);
|
||
line-height: 1.3;
|
||
}
|
||
.item-slot.collected .item-name { color: var(--gold); }
|
||
.item-check {
|
||
position: absolute;
|
||
top: 5px; right: 8px;
|
||
font-size: 1rem;
|
||
color: var(--gold-light);
|
||
opacity: 0;
|
||
transition: opacity 0.3s;
|
||
}
|
||
.item-slot.collected .item-check { opacity: 1; }
|
||
|
||
/* ── DRINKS TRACKER ────────────────────────── */
|
||
.drink-tracker {
|
||
text-align: center;
|
||
padding: 1rem;
|
||
}
|
||
.drink-count {
|
||
font-family: 'Cinzel Decorative', serif;
|
||
font-size: 4rem;
|
||
color: var(--red);
|
||
text-shadow: 2px 2px 0 rgba(0,0,0,0.2);
|
||
line-height: 1;
|
||
}
|
||
.drink-label {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.3em;
|
||
color: #8a6520;
|
||
margin-top: 0.3rem;
|
||
text-transform: uppercase;
|
||
}
|
||
.drink-btns {
|
||
display: flex;
|
||
gap: 1rem;
|
||
justify-content: center;
|
||
margin-top: 1.2rem;
|
||
}
|
||
.btn-drink {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 1.1rem;
|
||
border: 2px solid;
|
||
padding: 0.5rem 1.5rem;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
background: transparent;
|
||
border-radius: 3px;
|
||
}
|
||
.btn-drink.add { border-color: var(--red); color: var(--red); }
|
||
.btn-drink.add:hover { background: var(--red); color: #fff; }
|
||
.btn-drink.sub { border-color: #8a6520; color: #8a6520; }
|
||
.btn-drink.sub:hover { background: #8a6520; color: #fff; }
|
||
|
||
/* ── TABLETOP SECTION ──────────────────────── */
|
||
.encounter-box {
|
||
background: #0d0500;
|
||
border: 2px solid var(--gold);
|
||
border-radius: 4px;
|
||
padding: 1.5rem;
|
||
margin: 1rem 0;
|
||
color: #e8d5a0;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.encounter-box::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: radial-gradient(ellipse at 50% 0%, rgba(201,162,39,0.08), transparent 60%);
|
||
pointer-events: none;
|
||
}
|
||
.encounter-title {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 1.1rem;
|
||
color: var(--gold-light);
|
||
margin-bottom: 0.8rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
.encounter-box p { color: #c8a86a; }
|
||
.encounter-box .flavor-text {
|
||
border-left-color: var(--gold);
|
||
background: rgba(201,162,39,0.05);
|
||
color: #e8d5a0;
|
||
}
|
||
|
||
.stat-block {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 0.5rem;
|
||
margin: 1rem 0;
|
||
background: #1a0800;
|
||
border: 1px solid #4a2800;
|
||
padding: 0.8rem;
|
||
border-radius: 4px;
|
||
}
|
||
.stat-item {
|
||
text-align: center;
|
||
font-family: 'Cinzel', serif;
|
||
}
|
||
.stat-val {
|
||
font-size: 1.4rem;
|
||
color: var(--gold-light);
|
||
}
|
||
.stat-name {
|
||
font-size: 0.6rem;
|
||
letter-spacing: 0.15em;
|
||
color: #8a6520;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
/* ── DICE ROLLER ───────────────────────────── */
|
||
.dice-roller {
|
||
background: #1a0800;
|
||
border: 1px solid #4a2800;
|
||
border-radius: 4px;
|
||
padding: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
.dice-roller-title {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.2em;
|
||
color: var(--gold);
|
||
text-transform: uppercase;
|
||
margin-bottom: 0.8rem;
|
||
}
|
||
.dice-btns {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
margin-bottom: 0.8rem;
|
||
}
|
||
.dice-btn {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.85rem;
|
||
color: #c8a86a;
|
||
background: #2a1000;
|
||
border: 1px solid #4a2800;
|
||
padding: 0.4rem 0.8rem;
|
||
cursor: pointer;
|
||
border-radius: 3px;
|
||
transition: all 0.2s;
|
||
}
|
||
.dice-btn:hover {
|
||
border-color: var(--gold);
|
||
color: var(--gold-light);
|
||
background: #3a1800;
|
||
}
|
||
.dice-result {
|
||
font-family: 'Cinzel Decorative', serif;
|
||
font-size: 2.5rem;
|
||
color: var(--gold-light);
|
||
text-align: center;
|
||
min-height: 3rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-shadow: 0 0 15px rgba(201,162,39,0.5);
|
||
transition: all 0.3s;
|
||
}
|
||
.dice-result.rolling {
|
||
animation: diceRoll 0.4s ease-out;
|
||
}
|
||
@keyframes diceRoll {
|
||
0%,20%,40%,60%,80% { transform: rotate(-5deg) scale(1.1); }
|
||
10%,30%,50%,70%,90% { transform: rotate(5deg) scale(1.1); }
|
||
100% { transform: none; }
|
||
}
|
||
.dice-log {
|
||
font-size: 0.8rem;
|
||
color: #5a3a10;
|
||
min-height: 1.2rem;
|
||
text-align: center;
|
||
font-style: italic;
|
||
}
|
||
|
||
/* ── TIMELINE ──────────────────────────────── */
|
||
.timeline {
|
||
position: relative;
|
||
padding-left: 2rem;
|
||
margin-top: 1rem;
|
||
}
|
||
.timeline::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0.5rem;
|
||
top: 0; bottom: 0;
|
||
width: 2px;
|
||
background: linear-gradient(180deg, var(--gold), var(--gold) 80%, transparent);
|
||
}
|
||
.timeline-item {
|
||
position: relative;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.timeline-item::before {
|
||
content: '◆';
|
||
position: absolute;
|
||
left: -1.7rem;
|
||
color: var(--gold);
|
||
font-size: 0.8rem;
|
||
top: 0.1rem;
|
||
}
|
||
.timeline-time {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.7rem;
|
||
letter-spacing: 0.15em;
|
||
color: var(--gold);
|
||
text-transform: uppercase;
|
||
margin-bottom: 0.2rem;
|
||
}
|
||
.timeline-event {
|
||
font-size: 1rem;
|
||
color: var(--ink-light);
|
||
font-weight: 600;
|
||
}
|
||
.timeline-note {
|
||
font-size: 0.9rem;
|
||
color: #5a3a10;
|
||
font-style: italic;
|
||
}
|
||
|
||
/* ── RULES BOX ─────────────────────────────── */
|
||
.rules-box {
|
||
background: rgba(138,101,32,0.08);
|
||
border: 1px solid #c9a22740;
|
||
border-radius: 4px;
|
||
padding: 1rem 1.2rem;
|
||
margin: 0.8rem 0;
|
||
}
|
||
.rules-title {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.15em;
|
||
color: var(--red);
|
||
text-transform: uppercase;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.rules-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
.rules-list li {
|
||
font-size: 0.95rem;
|
||
padding: 0.25rem 0 0.25rem 1.2rem;
|
||
position: relative;
|
||
color: var(--ink-light);
|
||
}
|
||
.rules-list li::before {
|
||
content: '⚔';
|
||
position: absolute;
|
||
left: 0;
|
||
font-size: 0.75rem;
|
||
color: var(--gold);
|
||
top: 0.35rem;
|
||
}
|
||
|
||
/* ── TABS ──────────────────────────────────── */
|
||
.tab-content { display: none; }
|
||
.tab-content.active { display: block; }
|
||
|
||
/* ── SPIELER ───────────────────────────────── */
|
||
.spieler-add-row {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 1.2rem;
|
||
}
|
||
.spieler-input {
|
||
font-family: 'Crimson Pro', serif;
|
||
font-size: 1rem;
|
||
background: #fdf5dc;
|
||
border: 1px solid #8a6520;
|
||
border-radius: 3px;
|
||
padding: 0.5rem 0.8rem;
|
||
color: #1a0f00;
|
||
outline: none;
|
||
flex: 1;
|
||
min-width: 120px;
|
||
}
|
||
.spieler-input:focus { border-color: #c9a227; box-shadow: 0 0 0 2px rgba(201,162,39,0.2); }
|
||
.spieler-select {
|
||
font-family: 'Crimson Pro', serif;
|
||
font-size: 0.95rem;
|
||
background: #fdf5dc;
|
||
border: 1px solid #8a6520;
|
||
border-radius: 3px;
|
||
padding: 0.5rem 0.6rem;
|
||
color: #1a0f00;
|
||
cursor: pointer;
|
||
outline: none;
|
||
}
|
||
.btn-add {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.8rem;
|
||
letter-spacing: 0.1em;
|
||
background: #2a5a1a;
|
||
color: #a8ff80;
|
||
border: none;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 3px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
white-space: nowrap;
|
||
}
|
||
.btn-add:hover { background: #1a4a0a; }
|
||
|
||
.spieler-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.6rem;
|
||
}
|
||
.spieler-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.7rem;
|
||
background: #fdf5dc;
|
||
border: 1px solid #c9a22760;
|
||
border-radius: 4px;
|
||
padding: 0.7rem 1rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
.spieler-avatar {
|
||
width: 38px; height: 38px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #8a6520, #c9a227);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 1.1rem;
|
||
flex-shrink: 0;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
font-family: 'Cinzel', serif;
|
||
}
|
||
.spieler-info { flex: 1; min-width: 100px; }
|
||
.spieler-name-display {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.95rem;
|
||
color: #1a0f00;
|
||
font-weight: 600;
|
||
}
|
||
.spieler-rolle-display {
|
||
font-size: 0.8rem;
|
||
color: #5a3a10;
|
||
margin-top: 0.1rem;
|
||
font-style: italic;
|
||
}
|
||
.spieler-rolle-badge {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.65rem;
|
||
letter-spacing: 0.08em;
|
||
padding: 0.15rem 0.5rem;
|
||
border-radius: 2px;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
.rolle-held { background: #5a3a00; color: #ffd060; }
|
||
.rolle-hüter { background: #2a1a5a; color: #a080ff; }
|
||
.rolle-ratsmitglied { background: #4a1a1a; color: #ff9060; }
|
||
.rolle-einsteiger { background: #1a4a1a; color: #a8ff80; }
|
||
.rolle-spielleiter { background: #1a1a4a; color: #80c0ff; }
|
||
.rolle-gast { background: #3a3a1a; color: #e0e080; }
|
||
|
||
.spieler-quest-sel {
|
||
font-family: 'Crimson Pro', serif;
|
||
font-size: 0.8rem;
|
||
background: #f4e8c1;
|
||
border: 1px solid #8a652060;
|
||
border-radius: 3px;
|
||
padding: 0.25rem 0.4rem;
|
||
color: #3d2200;
|
||
cursor: pointer;
|
||
max-width: 160px;
|
||
}
|
||
.btn-del {
|
||
background: transparent;
|
||
border: 1px solid #8b1a1a60;
|
||
color: #8b1a1a;
|
||
border-radius: 3px;
|
||
padding: 0.25rem 0.6rem;
|
||
cursor: pointer;
|
||
font-size: 0.85rem;
|
||
transition: all 0.2s;
|
||
flex-shrink: 0;
|
||
}
|
||
.btn-del:hover { background: #8b1a1a; color: #fff; }
|
||
|
||
.spieler-empty {
|
||
text-align: center;
|
||
font-style: italic;
|
||
color: #8a6520;
|
||
padding: 2rem;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.spieler-summary {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
flex-wrap: wrap;
|
||
margin-top: 1rem;
|
||
padding-top: 1rem;
|
||
border-top: 1px solid #c9a22740;
|
||
}
|
||
.summary-chip {
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.7rem;
|
||
letter-spacing: 0.08em;
|
||
padding: 0.2rem 0.6rem;
|
||
border-radius: 20px;
|
||
border: 1px solid #c9a22760;
|
||
color: #5a3a10;
|
||
}
|
||
|
||
/* ── PRINT HINT ────────────────────────────── */
|
||
.print-hint {
|
||
text-align: center;
|
||
font-family: 'Cinzel', serif;
|
||
font-size: 0.75rem;
|
||
letter-spacing: 0.15em;
|
||
color: #5a3a10;
|
||
padding: 1rem;
|
||
}
|
||
|
||
/* ── RESPONSIVE ────────────────────────────── */
|
||
@media (max-width: 600px) {
|
||
.cover-title { font-size: 1.8rem; }
|
||
.parchment { padding: 1.2rem; }
|
||
.quest-grid { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ══════════════════ COVER ══════════════════ -->
|
||
<div id="cover">
|
||
<div class="stars" id="stars"></div>
|
||
<div class="cover-emblem">⚔️</div>
|
||
<div class="cover-subtitle">Ein Junggesellenabschied der Legenden</div>
|
||
<div class="cover-title">Der letzte<br>Auftrag</div>
|
||
<div class="cover-divider"></div>
|
||
<div class="cover-desc">
|
||
Eine Heldengeschichte, Trinkspiele & tabletop Quests –<br>
|
||
für den tapfersten Krieger, der je eine Braut zu retten wagte.
|
||
</div>
|
||
<button class="btn-primary" onclick="startApp()">📜 Abenteuer beginnen</button>
|
||
</div>
|
||
|
||
<!-- ══════════════════ APP ══════════════════ -->
|
||
<div id="app">
|
||
<nav class="top-nav">
|
||
<span class="nav-title">⚔ Der letzte Auftrag</span>
|
||
<div class="nav-tabs">
|
||
<button class="nav-tab active" onclick="showTab('intro')">Intro</button>
|
||
<button class="nav-tab" onclick="showTab('quests')">Quests</button>
|
||
<button class="nav-tab" onclick="showTab('tabletop')">Tabletop</button>
|
||
<button class="nav-tab" onclick="showTab('tracker')">Tracker</button>
|
||
<button class="nav-tab" onclick="showTab('spieler')">Spieler</button>
|
||
<button class="nav-tab" onclick="showTab('ablauf')">Ablauf</button>
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="page-wrap">
|
||
|
||
<!-- ═══ INTRO ═══ -->
|
||
<div id="tab-intro" class="tab-content active">
|
||
<div class="parchment">
|
||
<div class="section-title">Das Abenteuer</div>
|
||
<div class="section-subtitle">Für Spielleiter & Organisatoren</div>
|
||
<div class="ornament">✦ ✦ ✦</div>
|
||
|
||
<div class="flavor-text">
|
||
„Höre mich an, tapferer Held. Deine zukünftige Gemahlin wurde von den mächtigen Hütern ihrer Habseligkeiten gefangen gehalten. Acht Gegenstände von unschätzbarem Wert trägt sie bei sich – oder vielmehr: tragen sie ANDERE für sie. Nur wer alle acht erbeuten kann, verdient es, sie zum Traualtar zu führen."
|
||
</div>
|
||
|
||
<p>Das Konzept ist simpel: <strong>Der Bräutigam ist der Held.</strong> Jeder Gast (oder eine Gruppe) hütet ein Besitztum der Braut. Durch Quests und Aufgaben erkämpft er sich die Gegenstände – oder trinkt bei Misserfolg.</p>
|
||
|
||
<div class="rules-box">
|
||
<div class="rules-title">Grundregeln</div>
|
||
<ul class="rules-list">
|
||
<li>Der Held löst Aufgaben bei den verschiedenen Gästen (= Hüter).</li>
|
||
<li>Erfolg → Hüter übergibt seinen Gegenstand (oder einen Hinweis-Zettel).</li>
|
||
<li>Misserfolg → Der Held trinkt. Der Gegenstand bleibt beim Hüter.</li>
|
||
<li>Er kann es später nochmal versuchen – mit erhöhtem Schwierigkeitsgrad.</li>
|
||
<li>Hat er am Ende ALLE 8 Gegenstände, darf er die Braut symbolisch freikaufen.</li>
|
||
<li>Fehlt noch etwas? Er trinkt für jeden fehlenden Gegenstand nochmal.</li>
|
||
<li>Einsteiger-Quests brauchen keine Vorkenntnisse. Der Tabletop-Block ist optional für RPG-Enthusiasten.</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="rules-box">
|
||
<div class="rules-title">Was braucht ihr?</div>
|
||
<ul class="rules-list">
|
||
<li>8 physische Gegenstände (Fotos, kleine Dinge oder Zettel mit Clue-Beschreibungen)</li>
|
||
<li>Diese App / Ausgedrucktes für den Spielleiter</li>
|
||
<li>Getränke in ausreichender Menge 🍺</li>
|
||
<li>Gute Laune & keine Scham</li>
|
||
<li>Für den Tabletop-Block: W6, W10 oder diese App als Würfel</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ornament">✦ ✦ ✦</div>
|
||
<p style="text-align:center; font-style:italic; color: #5a3a10;">Der Held weiß am Anfang NUR, dass er Quests lösen muss.<br>Die Hüter kennen ihre Aufgabe, er nicht.</p>
|
||
</div>
|
||
|
||
<div class="parchment">
|
||
<div class="section-title">Die 8 Besitztümer</div>
|
||
<div class="section-subtitle">Für die Braut vorbereiten</div>
|
||
<p>Bereite diese 8 Gegenstände (oder Zettel mit ihrer Beschreibung) vor. Die Hüter bekommen sie vorab zugewiesen:</p>
|
||
<div class="inventory-grid">
|
||
<div class="item-slot" id="inv-0" onclick="toggleItem(0)">
|
||
<span class="item-emoji">💍</span>
|
||
<span class="item-name">Der Ring der Verbindung</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-1" onclick="toggleItem(1)">
|
||
<span class="item-emoji">👠</span>
|
||
<span class="item-name">Der Schuh der Flucht</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-2" onclick="toggleItem(2)">
|
||
<span class="item-emoji">💌</span>
|
||
<span class="item-name">Der Brief des ersten Dates</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-3" onclick="toggleItem(3)">
|
||
<span class="item-emoji">🌹</span>
|
||
<span class="item-name">Die Blume der Ewigkeit</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-4" onclick="toggleItem(4)">
|
||
<span class="item-emoji">🔑</span>
|
||
<span class="item-name">Der Schlüssel zur Zukunft</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-5" onclick="toggleItem(5)">
|
||
<span class="item-emoji">📸</span>
|
||
<span class="item-name">Das Foto der gemeinsamen Zeit</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-6" onclick="toggleItem(6)">
|
||
<span class="item-emoji">🧸</span>
|
||
<span class="item-name">Das Maskottchen des Heils</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
<div class="item-slot" id="inv-7" onclick="toggleItem(7)">
|
||
<span class="item-emoji">🏆</span>
|
||
<span class="item-name">Die Urkunde der Heldentaten</span>
|
||
<span class="item-check">✦</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ QUESTS ═══ -->
|
||
<div id="tab-quests" class="tab-content">
|
||
<div class="parchment">
|
||
<div class="section-title">Die Quests</div>
|
||
<div class="section-subtitle">Aufgaben der Hüter — Klicken zum Aufklappen</div>
|
||
|
||
<div class="rules-box">
|
||
<div class="rules-title">Farbcode</div>
|
||
<ul class="rules-list" style="columns:2; gap:1rem;">
|
||
<li><span class="quest-badge badge-easy">EINSTEIGER</span> Keine Vorkenntnisse</li>
|
||
<li><span class="quest-badge badge-medium">MITTEL</span> Etwas Geschick</li>
|
||
<li><span class="quest-badge badge-hard">HERAUSFORDERUNG</span> Echte Prüfung</li>
|
||
<li><span class="quest-badge badge-tabletop">TABLETOP</span> RPG-Erfahrene</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="quest-grid" id="questGrid"></div>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ TABLETOP ═══ -->
|
||
<div id="tab-tabletop" class="tab-content">
|
||
<div class="parchment">
|
||
<div class="section-title">Tabletop-Block</div>
|
||
<div class="section-subtitle">Für erfahrene Rollenspieler · W6/W10-System</div>
|
||
|
||
<div class="flavor-text">
|
||
Dieser Block ist für den Moment gedacht, wenn die erfahrenen Rollenspieler in der Runde zusammenkommen. Eine kurze Kampf- und Entscheidungsszene, vollständig vorbereitet. Dauer: ca. 30–60 Minuten.
|
||
</div>
|
||
|
||
<div class="encounter-box">
|
||
<div class="encounter-title">🐉 Szene I – Der Wächter des Tores</div>
|
||
<div class="flavor-text">
|
||
„Der Held steht vor dem letzten Tor zur Festung der Braut. Der Wächter – ein alter Vertrauter – versperrt den Weg. Er verlangt den Beweis, dass der Held seiner Gemahlin würdig ist."
|
||
</div>
|
||
<p>Der Wächter stellt <strong>3 Fragen</strong> – echte Fragen über die Beziehung (Spielleiter vorbereiten!). Für jede richtige Antwort: kein Würfelwurf nötig. Für jede falsche: Würfelduell.</p>
|
||
<div class="stat-block">
|
||
<div class="stat-item">
|
||
<div class="stat-val">W10</div>
|
||
<div class="stat-name">System</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-val">7+</div>
|
||
<div class="stat-name">Erfolg</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-val">3</div>
|
||
<div class="stat-name">Fragen</div>
|
||
</div>
|
||
</div>
|
||
<p style="font-size:0.9rem;"><strong>Beispielfragen:</strong> Wann hatten sie ihr erstes Date? Was ist ihr Lieblingsessen? Was war ihr erster gemeinsamer Urlaub?</p>
|
||
</div>
|
||
|
||
<div class="encounter-box">
|
||
<div class="encounter-title">⚔ Szene II – Die Prüfung des Mutes</div>
|
||
<div class="flavor-text">
|
||
„Der Rat der Weisen (= die erfahrenen Rollenspieler) sitzt im Kreis. Jeder hat eine Herausforderung für den Held: einen Skill-Check, eine moralische Entscheidung oder eine Improvisation."
|
||
</div>
|
||
<p>Jeder RPG-erfahrene Spieler ist ein <strong>Ratsmitglied</strong> und beschreibt eine kurze Szene. Der Held muss reagieren (Roleplay + Würfelwurf). Das Ratsmitglied entscheidet, ob der Wurf ausreicht.</p>
|
||
<div class="rules-box" style="background: rgba(201,162,39,0.05); border-color: #4a2800;">
|
||
<div class="rules-title" style="color: var(--gold);">Beispiel-Szenen für Ratsmitglieder</div>
|
||
<ul class="rules-list">
|
||
<li>„Du stehst vor einem Drachen, der dich nach ihrem schlimmsten Eigenschaft fragt. Antworte weise." (Charisma-Check)</li>
|
||
<li>„Ein alter Rivale erscheint. Er behauptet, ihr erster Kuss war mit ihm." (Einschüchterungs-Check)</li>
|
||
<li>„Du musst in 30 Sekunden 3 Dinge nennen, die du an ihr liebst – ohne zu stocken." (Wisdom-Check)</li>
|
||
<li>„Der Magier bietet dir: ENTWEDER ihre Schuhe ODER ein ewiges Leben ohne sie. Was wählst du?" (Roleplay – kein Würfelwurf)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="encounter-box">
|
||
<div class="encounter-title">🎲 Szene III – Der finale Würfelkampf</div>
|
||
<div class="flavor-text">
|
||
„Ein letztes Tor. Dahinter wartet der Wächter der Wächter – der härteste Gegner des Abends. Er fordert den Held zum entscheidenden Duell."
|
||
</div>
|
||
<p>Klassischer Würfelkampf: Beide würfeln W10. Wer höher würfelt, gewinnt die Runde. Beste 3 von 5 Runden. Bei Unentschieden: Stechershot trinkt der Verlierer.</p>
|
||
<div class="stat-block">
|
||
<div class="stat-item">
|
||
<div class="stat-val">W10</div>
|
||
<div class="stat-name">Würfel</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-val">3/5</div>
|
||
<div class="stat-name">Best-of</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-val">🍺</div>
|
||
<div class="stat-name">Einsatz</div>
|
||
</div>
|
||
</div>
|
||
<p style="font-size:0.9rem;">Jede verlorene Runde = ein Schluck. Wer das Duell verliert, ERZÄHLT außerdem einer Anekdote über die Braut.</p>
|
||
</div>
|
||
|
||
<div class="dice-roller">
|
||
<div class="dice-roller-title">🎲 Würfel-Assistent</div>
|
||
<div class="dice-btns" id="diceBtns"></div>
|
||
<div class="dice-result" id="diceResult">–</div>
|
||
<div class="dice-log" id="diceLog"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ TRACKER ═══ -->
|
||
<div id="tab-tracker" class="tab-content">
|
||
<div class="parchment">
|
||
<div class="section-title">Helden-Tracker</div>
|
||
<div class="section-subtitle">Live-Übersicht während des Abends</div>
|
||
|
||
<div style="display:grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom:1.5rem;">
|
||
<div class="drink-tracker">
|
||
<div class="drink-count" id="drinkCount">0</div>
|
||
<div class="drink-label">Getrunken 🍺</div>
|
||
<div class="drink-btns">
|
||
<button class="btn-drink add" onclick="changeDrinks(1)">+1</button>
|
||
<button class="btn-drink sub" onclick="changeDrinks(-1)">–1</button>
|
||
</div>
|
||
</div>
|
||
<div class="drink-tracker">
|
||
<div class="drink-count" id="questCount" style="color: var(--green);">0/8</div>
|
||
<div class="drink-label">Besitztümer ⚔</div>
|
||
<div style="margin-top:1rem; font-family: 'Cinzel', serif; font-size:0.75rem; color:#8a6520; letter-spacing:0.1em;">
|
||
Im Intro-Tab verwalten
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="rules-box">
|
||
<div class="rules-title">Quest-Status</div>
|
||
<div id="questStatusList" style="display:flex; flex-direction:column; gap:0.4rem; margin-top:0.5rem;"></div>
|
||
</div>
|
||
|
||
<div class="rules-box" style="margin-top:1rem;">
|
||
<div class="rules-title">Notizen</div>
|
||
<textarea id="notes" placeholder="Hier Notizen eingeben..."
|
||
style="width:100%; background:rgba(138,101,32,0.05); border:1px solid #c9a22740; border-radius:4px; padding:0.6rem; font-family:'Crimson Pro',serif; font-size:0.95rem; color:var(--ink-light); resize:vertical; min-height:80px; outline:none;"
|
||
oninput="saveNotes()"></textarea>
|
||
</div>
|
||
|
||
<div style="text-align:center; margin-top:1.5rem;">
|
||
<button class="btn-primary" onclick="resetAll()">↺ Neustart</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ SPIELER ═══ -->
|
||
<div id="tab-spieler" class="tab-content">
|
||
<div class="parchment">
|
||
<div class="section-title">Die Gefährten</div>
|
||
<div class="section-subtitle">Spieler, Rollen & Hüter-Zuteilung</div>
|
||
|
||
<div class="flavor-text">
|
||
Trage hier alle Teilnehmer des Abends ein und weise ihnen ihre Rolle zu. So behältst du den Überblick, wer welche Quest hütet.
|
||
</div>
|
||
|
||
<!-- Hinzufügen -->
|
||
<div class="rules-box">
|
||
<div class="rules-title">Spieler hinzufügen</div>
|
||
<div class="spieler-add-row" style="margin-top:0.8rem;">
|
||
<input class="spieler-input" id="sName" placeholder="Name..." maxlength="30" onkeydown="if(event.key==='Enter')addSpieler()">
|
||
<select class="spieler-select" id="sRolle">
|
||
<option value="held">⚔ Held (Bräutigam)</option>
|
||
<option value="spielleiter">📜 Spielleiter</option>
|
||
<option value="hüter" selected>🔒 Hüter</option>
|
||
<option value="ratsmitglied">🧙 Ratsmitglied</option>
|
||
<option value="einsteiger">🌱 Einsteiger</option>
|
||
<option value="gast">🍺 Gast</option>
|
||
</select>
|
||
<select class="spieler-select" id="sQuest">
|
||
<option value="">– Quest zuweisen –</option>
|
||
</select>
|
||
<button class="btn-add" onclick="addSpieler()">+ Hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Liste -->
|
||
<div id="spielerList" class="spieler-list">
|
||
<div class="spieler-empty">Keine Teilnehmer eingetragen.</div>
|
||
</div>
|
||
|
||
<!-- Zusammenfassung -->
|
||
<div class="spieler-summary" id="spielerSummary" style="display:none;">
|
||
<span class="summary-chip" id="sumTotal">0 Teilnehmer</span>
|
||
<span class="summary-chip" id="sumHüter">0 Hüter</span>
|
||
<span class="summary-chip" id="sumRat">0 Ratsmitglieder</span>
|
||
<span class="summary-chip" id="sumEinsteiger">0 Einsteiger</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Rollen-Legende -->
|
||
<div class="parchment">
|
||
<div class="section-title" style="font-size:1.1rem;">Rollen-Übersicht</div>
|
||
<div class="ornament">✦ ✦ ✦</div>
|
||
<div class="rules-box">
|
||
<ul class="rules-list">
|
||
<li><span class="spieler-rolle-badge rolle-held">⚔ HELD</span> Der Bräutigam – löst alle Quests.</li>
|
||
<li><span class="spieler-rolle-badge rolle-spielleiter">📜 SPIELLEITER</span> Organisator – kennt alle Aufgaben, leitet den Abend.</li>
|
||
<li><span class="spieler-rolle-badge rolle-hüter">🔒 HÜTER</span> Bewacht ein Besitztum & stellt die zugewiesene Quest.</li>
|
||
<li><span class="spieler-rolle-badge rolle-ratsmitglied">🧙 RATSMITGLIED</span> Erfahrener RPG-Spieler – nimmt am Tabletop-Block teil.</li>
|
||
<li><span class="spieler-rolle-badge rolle-einsteiger">🌱 EINSTEIGER</span> Tabletop-Neuling – bekommt einfache Quests.</li>
|
||
<li><span class="spieler-rolle-badge rolle-gast">🍺 GAST</span> Schaut zu, feuert an und trinkt mit.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ ABLAUF ═══ -->
|
||
<div id="tab-ablauf" class="tab-content">
|
||
<div class="parchment">
|
||
<div class="section-title">Ablaufplan</div>
|
||
<div class="section-subtitle">Empfohlener Zeitplan für den Abend</div>
|
||
|
||
<div class="timeline">
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Beginn · Ankunft</div>
|
||
<div class="timeline-event">Versammlung & Einstimmung</div>
|
||
<div class="timeline-note">Alle Hüter bekommen ihren Gegenstand & ihre Aufgabe erklärt. Der Held weiß noch nichts.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">~30 Min. nach Beginn</div>
|
||
<div class="timeline-event">Die Verkündigung 📜</div>
|
||
<div class="timeline-note">Der Spielleiter liest dem Held feierlich die Quest vor (Intro-Text). Dann beginnt das Abenteuer.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Phase 1 · 45-60 Min.</div>
|
||
<div class="timeline-event">Einsteiger-Quests (1–5)</div>
|
||
<div class="timeline-note">Der Held absolviert die ersten Aufgaben und erbeutet die ersten Besitztümer.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Pause · ~Mitte des Abends</div>
|
||
<div class="timeline-event">Inventur & Halftime-Ritual</div>
|
||
<div class="timeline-note">Für jeden fehlenden Gegenstand trinkt der Held einen kleinen Schluck. Dann gehts weiter.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Phase 2 · 45-60 Min.</div>
|
||
<div class="timeline-event">Herausforderungs-Quests (6–8)</div>
|
||
<div class="timeline-note">Anspruchsvollere Aufgaben mit höherem Einsatz.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Optional · nach Phase 2</div>
|
||
<div class="timeline-event">⚔ Tabletop-Block</div>
|
||
<div class="timeline-note">Die RPG-erfahrenen Spieler ziehen sich für 30-60 Min. in die Ratssitzung zurück. Andere trinken weiter.</div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="timeline-time">Finale · Abend-Ende</div>
|
||
<div class="timeline-event">Die Befreiung der Braut 🏆</div>
|
||
<div class="timeline-note">Der Held präsentiert alle Besitztümer. Für jeden fehlenden: Straftrunk. Dann: Feier ohne Quests!</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="rules-box" style="margin-top:1.5rem;">
|
||
<div class="rules-title">Hinweise für den Spielleiter</div>
|
||
<ul class="rules-list">
|
||
<li>Hüter vorab briefen! Aufgabe kennen, Gegenstand bereit haben.</li>
|
||
<li>Zweite Chance immer erlauben – aber mit Extratrinken.</li>
|
||
<li>Atmosphäre hat Vorrang vor strikter Regelauslegung.</li>
|
||
<li>Wasser & Snacks bereitstellen, wenn es länger geht.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /page-wrap -->
|
||
</div><!-- /app -->
|
||
|
||
<script>
|
||
// ══════════════════════════════════════════
|
||
// DATA
|
||
// ══════════════════════════════════════════
|
||
const quests = [
|
||
{
|
||
id: 0,
|
||
badge: 'easy',
|
||
badgeLabel: 'EINSTEIGER',
|
||
name: 'Das Lied der Liebe',
|
||
holder: 'Hüter des <strong>Briefes</strong>',
|
||
item: '💌 Brief des ersten Dates',
|
||
desc: 'Der Held muss der Runde einen Liebesfilm-Titel nennen und ihn pantomimisch darstellen – die anderen raten.',
|
||
success: '✓ Brief bekommt er',
|
||
fail: '✗ Ein Schluck',
|
||
details: `<strong>Ablauf:</strong> Der Hüter flüstert dem Held einen Filmtitel ins Ohr (z.B. Titanic, Die Schöne und das Biest, Notting Hill). Der Held darf nicht sprechen und muss den Titel pantomimisch darstellen. Zeitlimit: 60 Sekunden.`,
|
||
},
|
||
{
|
||
id: 1,
|
||
badge: 'easy',
|
||
badgeLabel: 'EINSTEIGER',
|
||
name: 'Der Wissenstest',
|
||
holder: 'Hüter des <strong>Rings</strong>',
|
||
item: '💍 Ring der Verbindung',
|
||
desc: 'Der Hüter stellt 5 Fragen über die Braut. Der Held muss mindestens 3 richtig beantworten.',
|
||
success: '✓ Ring bekommt er',
|
||
fail: '✗ Pro Falschantwort ein Schluck',
|
||
details: `<strong>Fragen vorbereiten (Hüter):</strong> Wähle 5 aus diesen Kategorien:<br>
|
||
• Lieblingsessen? • Lieblingsfilm? • Wo wollte sie immer hinreisen?<br>
|
||
• Was ist ihr größter Tick? • Wie heißt ihre beste Freundin?<br>
|
||
• Was war ihr erstes Haustier? • Was mag sie am Bräutigam am meisten?<br><br>
|
||
<strong>Hinweis:</strong> Fragen vorab mit der Braut abstimmen.`,
|
||
},
|
||
{
|
||
id: 2,
|
||
badge: 'easy',
|
||
badgeLabel: 'EINSTEIGER',
|
||
name: 'Das Duell der Münzen',
|
||
holder: 'Hüter des <strong>Schlüssels</strong>',
|
||
item: '🔑 Schlüssel zur Zukunft',
|
||
desc: 'Münze oder Kronkorken werfen: Wer 3 von 5 Würfen in einen Becher trifft, gewinnt.',
|
||
success: '✓ Schlüssel bekommt er',
|
||
fail: '✗ Ein ordentlicher Schluck',
|
||
details: `<strong>Setup:</strong> Einen Becher auf den Tisch stellen, ca. 1–2 Meter Abstand. Jeder wirft abwechselnd (Held vs. Hüter). Bester aus 5 Versuchen gewinnt.<br><br>
|
||
<strong>Regelung bei Gleichstand:</strong> Plötzlicher Tod – wer als nächstes trifft, gewinnt.`,
|
||
},
|
||
{
|
||
id: 3,
|
||
badge: 'easy',
|
||
badgeLabel: 'EINSTEIGER',
|
||
name: 'Der Schwur der tausend Worte',
|
||
holder: 'Hüter der <strong>Blume</strong>',
|
||
item: '🌹 Blume der Ewigkeit',
|
||
desc: 'Der Held muss in 90 Sekunden einen Heiratsantrag improvisieren – vor allen Gästen.',
|
||
success: '✓ Blume bekommt er',
|
||
fail: '✗ Kein Applaus = trinken',
|
||
details: `<strong>Ablauf:</strong> Der Held hat 90 Sekunden Zeit für einen improvisierten Heiratsantrag an die (nicht anwesende) Braut. Die Gäste klatschen am Ende.<br><br>
|
||
<strong>Bewertung:</strong> Lautester Applaus = Erfolg. Stille oder Widerspruch = Misserfolg. Der Hüter entscheidet im Zweifelsfall.`,
|
||
},
|
||
{
|
||
id: 4,
|
||
badge: 'medium',
|
||
badgeLabel: 'MITTEL',
|
||
name: 'Die Chronik der Scham',
|
||
holder: 'Hüter des <strong>Fotos</strong>',
|
||
item: '📸 Foto der gemeinsamen Zeit',
|
||
desc: 'Der Hüter erzählt eine peinliche Geschichte des Helden. Wer davon die meisten Details wusste, gewinnt.',
|
||
success: '✓ Foto und eine Geschichte über die Braut zurück',
|
||
fail: '✗ Der Held trinkt und erzählt selbst die Geschichte',
|
||
details: `<strong>Ablauf:</strong> Der Hüter hat vorab eine peinliche Geschichte über den Helden vorbereitet. Er liest sie vor und stellt danach 3 Detailfragen. Kann der Held 2 von 3 beantworten? → Erfolg.<br><br>
|
||
<strong>Empfehlung:</strong> Eine Person, die den Helden gut kennt, übernimmt diese Rolle.`,
|
||
},
|
||
{
|
||
id: 5,
|
||
badge: 'medium',
|
||
badgeLabel: 'MITTEL',
|
||
name: 'Das Blindverkostung',
|
||
holder: 'Hüter des <strong>Schuhs</strong>',
|
||
item: '👠 Schuh der Flucht',
|
||
desc: '5 Getränke blind verkosten und benennen. Mindestens 3 richtig.',
|
||
success: '✓ Schuh bekommt er',
|
||
fail: '✗ Alle falsch erkannten Getränke austrinken',
|
||
details: `<strong>Vorbereitung:</strong> 5 Getränke in nummerierten Bechern vorbereiten (Mischung aus Alkohol und Softdrinks). Augenbinde aufsetzen.<br><br>
|
||
<strong>Regeln:</strong> Riechen ist erlaubt. Geraten werden darf nur auf Basis der Verkostung.`,
|
||
},
|
||
{
|
||
id: 6,
|
||
badge: 'hard',
|
||
badgeLabel: 'HERAUSFORDERUNG',
|
||
name: 'Der Zweikampf der Weisheit',
|
||
holder: 'Hüter des <strong>Maskottchens</strong>',
|
||
item: '🧸 Maskottchen des Heils',
|
||
desc: 'Ein Trivia-Duell: Pop-Kultur, Warhammer & DnD-Fragen. Wer 3 von 5 beantwortet, gewinnt.',
|
||
success: '✓ Maskottchen und ein Ehrentitel',
|
||
fail: '✗ Zwei große Schlucke',
|
||
details: `<strong>Beispielfragen:</strong><br>
|
||
• RPG: „Wie viele Seiten hat ein W20?" (20)<br>
|
||
• Warhammer: „Welche Fraktion trägt Schädelornamente als Zeichen der Loyalität?" (Space Marines / diverse)<br>
|
||
• DnD: „Was ist ein nat. 20?" (Kritischer Erfolg)<br>
|
||
• Allgemein: „Wer schrieb 'Der Herr der Ringe'?" (Tolkien)<br>
|
||
• Persönlich: Eine Frage über das Paar.<br><br>
|
||
<strong>Hinweis:</strong> Schwierigkeitsgrad der Fragen an die Gruppe anpassen.`,
|
||
},
|
||
{
|
||
id: 7,
|
||
badge: 'hard',
|
||
badgeLabel: 'HERAUSFORDERUNG',
|
||
name: 'Die letzte Prüfung',
|
||
holder: 'Hüter der <strong>Urkunde</strong>',
|
||
item: '🏆 Urkunde der Heldentaten',
|
||
desc: 'Der Held muss einen Abend-Rückblick halten: Die 5 peinlichsten Momente des Abends, dramatisch vorgetragen.',
|
||
success: '✓ Urkunde + Applaus der Legende',
|
||
fail: '✗ Nochmal von vorne – lauter!',
|
||
details: `<strong>Ablauf:</strong> Diese Quest steht am Ende des Abends. Der Held fasst in einer Rede (2–3 Min.) die Ereignisse des Abends zusammen – pointiert und feierlich vorgetragen.<br><br>
|
||
<strong>Bewertung:</strong> Stehende Ovationen = Erfolg. Unzureichende Darbietung = Neuversuch.<br><br>
|
||
<strong>Abschluss:</strong> Nach bestandener Quest wird die Urkunde feierlich überreicht.`,
|
||
},
|
||
];
|
||
|
||
const itemCollected = new Array(8).fill(false);
|
||
let drinks = 0;
|
||
const questDone = new Array(quests.length).fill(false);
|
||
|
||
// ══════════════════════════════════════════
|
||
// STARS
|
||
// ══════════════════════════════════════════
|
||
(function createStars() {
|
||
const c = document.getElementById('stars');
|
||
for (let i = 0; i < 120; i++) {
|
||
const s = document.createElement('div');
|
||
s.className = 'star';
|
||
s.style.cssText = `
|
||
left:${Math.random()*100}%;
|
||
top:${Math.random()*100}%;
|
||
--d:${2+Math.random()*4}s;
|
||
--delay:${Math.random()*5}s;
|
||
--bright:${0.4+Math.random()*0.6};
|
||
width:${Math.random()<0.3?3:2}px;
|
||
height:${Math.random()<0.3?3:2}px;
|
||
`;
|
||
c.appendChild(s);
|
||
}
|
||
})();
|
||
|
||
// ══════════════════════════════════════════
|
||
// START
|
||
// ══════════════════════════════════════════
|
||
function startApp() {
|
||
document.getElementById('cover').style.display = 'none';
|
||
document.getElementById('app').style.display = 'block';
|
||
buildQuests();
|
||
buildDice();
|
||
loadState();
|
||
loadSpieler();
|
||
updateQuestStatus();
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// TABS
|
||
// ══════════════════════════════════════════
|
||
function showTab(id) {
|
||
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
|
||
document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
|
||
document.getElementById('tab-' + id).classList.add('active');
|
||
event.target.classList.add('active');
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// QUESTS
|
||
// ══════════════════════════════════════════
|
||
function buildQuests() {
|
||
const grid = document.getElementById('questGrid');
|
||
grid.innerHTML = '';
|
||
quests.forEach((q, i) => {
|
||
const card = document.createElement('div');
|
||
card.className = 'quest-card' + (questDone[i] ? ' done' : '');
|
||
card.id = 'qcard-' + i;
|
||
card.innerHTML = `
|
||
<span class="quest-badge badge-${q.badge}">${q.badgeLabel}</span>
|
||
<div class="quest-name">${q.name}</div>
|
||
<div class="quest-holder">Hüter: ${q.holder}</div>
|
||
<div class="quest-desc">${q.desc}</div>
|
||
<div class="quest-rewards">
|
||
<span class="reward-success">${q.success}</span>
|
||
<span class="reward-fail">${q.fail}</span>
|
||
</div>
|
||
<div class="quest-expand">${q.details}<br><br>
|
||
<button onclick="event.stopPropagation(); toggleDone(${i})"
|
||
style="font-family:'Cinzel',serif; font-size:0.75rem; background:transparent; border:1px solid #8a6520; padding:0.3rem 0.8rem; cursor:pointer; color:#8a6520; border-radius:3px;">
|
||
${questDone[i] ? '↩ Als offen markieren' : '✓ Als erledigt markieren'}
|
||
</button>
|
||
</div>
|
||
<div class="expand-hint">▼ Aufklappen für Details</div>
|
||
`;
|
||
card.addEventListener('click', () => toggleExpand(i));
|
||
grid.appendChild(card);
|
||
});
|
||
}
|
||
|
||
function toggleExpand(i) {
|
||
const card = document.getElementById('qcard-' + i);
|
||
card.classList.toggle('expanded');
|
||
}
|
||
|
||
function toggleDone(i) {
|
||
questDone[i] = !questDone[i];
|
||
saveState();
|
||
buildQuests();
|
||
updateQuestStatus();
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// INVENTORY
|
||
// ══════════════════════════════════════════
|
||
function toggleItem(i) {
|
||
itemCollected[i] = !itemCollected[i];
|
||
const slot = document.getElementById('inv-' + i);
|
||
slot.classList.toggle('collected', itemCollected[i]);
|
||
saveState();
|
||
updateQuestStatus();
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// DRINKS
|
||
// ══════════════════════════════════════════
|
||
function changeDrinks(n) {
|
||
drinks = Math.max(0, drinks + n);
|
||
document.getElementById('drinkCount').textContent = drinks;
|
||
saveState();
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// STATUS
|
||
// ══════════════════════════════════════════
|
||
function updateQuestStatus() {
|
||
const count = itemCollected.filter(Boolean).length;
|
||
document.getElementById('questCount').textContent = count + '/8';
|
||
|
||
const list = document.getElementById('questStatusList');
|
||
if (!list) return;
|
||
list.innerHTML = quests.map((q, i) => `
|
||
<div style="display:flex; align-items:center; gap:0.5rem; font-size:0.9rem; color:${questDone[i]?'#2a5a1a':'#5a3a10'};">
|
||
<span>${questDone[i] ? '✓' : '○'}</span>
|
||
<span>${q.name}</span>
|
||
<span style="margin-left:auto; font-size:0.8rem; opacity:0.7">${q.item}</span>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// DICE
|
||
// ══════════════════════════════════════════
|
||
function buildDice() {
|
||
const btn = document.getElementById('diceBtns');
|
||
if (!btn) return;
|
||
[4,6,8,10,12,20,100].forEach(d => {
|
||
const b = document.createElement('button');
|
||
b.className = 'dice-btn';
|
||
b.textContent = 'W' + d;
|
||
b.onclick = () => rollDice(d);
|
||
btn.appendChild(b);
|
||
});
|
||
}
|
||
|
||
function rollDice(sides) {
|
||
const result = Math.floor(Math.random() * sides) + 1;
|
||
const el = document.getElementById('diceResult');
|
||
const log = document.getElementById('diceLog');
|
||
el.classList.remove('rolling');
|
||
void el.offsetWidth;
|
||
el.classList.add('rolling');
|
||
el.textContent = result;
|
||
const reactions = result === sides ? '⭐ KRITISCH! Legendär!' :
|
||
result === 1 ? '💀 Kritischer Fehlschlag! Trinken!' :
|
||
result >= Math.ceil(sides * 0.7) ? '✓ Starkes Ergebnis!' :
|
||
result >= Math.ceil(sides * 0.4) ? '~ Mittelmaß...' : '✗ Schwach. Trinken?';
|
||
log.textContent = `W${sides} → ${result} · ${reactions}`;
|
||
}
|
||
|
||
// ══════════════════════════════════════════
|
||
// SPIELER
|
||
// ══════════════════════════════════════════
|
||
let spieler = [];
|
||
|
||
const rolleLabels = {
|
||
held: '⚔ Held',
|
||
spielleiter: '📜 Spielleiter',
|
||
hüter: '🔒 Hüter',
|
||
ratsmitglied: '🧙 Ratsmitglied',
|
||
einsteiger: '🌱 Einsteiger',
|
||
gast: '🍺 Gast',
|
||
};
|
||
|
||
function populateQuestSelect() {
|
||
const sel = document.getElementById('sQuest');
|
||
if (!sel) return;
|
||
const current = sel.value;
|
||
sel.innerHTML = '<option value="">– Quest zuweisen –</option>';
|
||
quests.forEach((q, i) => {
|
||
const opt = document.createElement('option');
|
||
opt.value = i;
|
||
opt.textContent = q.name;
|
||
sel.appendChild(opt);
|
||
});
|
||
sel.value = current;
|
||
}
|
||
|
||
function addSpieler() {
|
||
const nameEl = document.getElementById('sName');
|
||
const rolleEl = document.getElementById('sRolle');
|
||
const questEl = document.getElementById('sQuest');
|
||
const name = nameEl.value.trim();
|
||
if (!name) { nameEl.focus(); return; }
|
||
const rolle = rolleEl.value;
|
||
const questIdx = questEl.value !== '' ? parseInt(questEl.value) : null;
|
||
spieler.push({ id: Date.now(), name, rolle, questIdx });
|
||
nameEl.value = '';
|
||
questEl.value = '';
|
||
saveSpieler();
|
||
renderSpieler();
|
||
}
|
||
|
||
function deleteSpieler(id) {
|
||
spieler = spieler.filter(s => s.id !== id);
|
||
saveSpieler();
|
||
renderSpieler();
|
||
}
|
||
|
||
function changeRolle(id, rolle) {
|
||
const s = spieler.find(s => s.id === id);
|
||
if (s) { s.rolle = rolle; saveSpieler(); renderSpieler(); }
|
||
}
|
||
|
||
function changeQuest(id, val) {
|
||
const s = spieler.find(s => s.id === id);
|
||
if (s) { s.questIdx = val !== '' ? parseInt(val) : null; saveSpieler(); renderSpieler(); }
|
||
}
|
||
|
||
function getInitial(name) {
|
||
return name.charAt(0).toUpperCase();
|
||
}
|
||
|
||
function renderSpieler() {
|
||
const list = document.getElementById('spielerList');
|
||
if (!list) return;
|
||
if (spieler.length === 0) {
|
||
list.innerHTML = '<div class="spieler-empty">Keine Teilnehmer eingetragen.</div>';
|
||
} else {
|
||
list.innerHTML = spieler.map(s => {
|
||
const questName = s.questIdx !== null ? quests[s.questIdx]?.name : null;
|
||
return `
|
||
<div class="spieler-item">
|
||
<div class="spieler-avatar">${getInitial(s.name)}</div>
|
||
<div class="spieler-info">
|
||
<div class="spieler-name-display">${s.name}</div>
|
||
<div class="spieler-rolle-display">${questName ? '🔒 ' + questName : rolleLabels[s.rolle]}</div>
|
||
</div>
|
||
<span class="spieler-rolle-badge rolle-${s.rolle}">${rolleLabels[s.rolle]}</span>
|
||
<select class="spieler-quest-sel" onchange="changeQuest(${s.id}, this.value)">
|
||
<option value="">– Keine Quest –</option>
|
||
${quests.map((q,i) => `<option value="${i}" ${s.questIdx===i?'selected':''}>${q.name}</option>`).join('')}
|
||
</select>
|
||
<select class="spieler-select" style="font-size:0.8rem; padding:0.25rem 0.4rem;" onchange="changeRolle(${s.id}, this.value)">
|
||
${Object.entries(rolleLabels).map(([k,v]) => `<option value="${k}" ${s.rolle===k?'selected':''}>${v}</option>`).join('')}
|
||
</select>
|
||
<button class="btn-del" onclick="deleteSpieler(${s.id})">✕</button>
|
||
</div>`;
|
||
}).join('');
|
||
}
|
||
|
||
// Summary
|
||
const summary = document.getElementById('spielerSummary');
|
||
if (summary) {
|
||
summary.style.display = spieler.length ? 'flex' : 'none';
|
||
document.getElementById('sumTotal').textContent = spieler.length + ' Teilnehmer';
|
||
document.getElementById('sumHüter').textContent = spieler.filter(s=>s.rolle==='hüter'||s.questIdx!==null).length + ' Hüter';
|
||
document.getElementById('sumRat').textContent = spieler.filter(s=>s.rolle==='ratsmitglied').length + ' Ratsmitglieder';
|
||
document.getElementById('sumEinsteiger').textContent = spieler.filter(s=>s.rolle==='einsteiger').length + ' Einsteiger';
|
||
}
|
||
}
|
||
|
||
function saveSpieler() {
|
||
try { localStorage.setItem('jga_spieler', JSON.stringify(spieler)); } catch(e) {}
|
||
}
|
||
|
||
function loadSpieler() {
|
||
try {
|
||
const s = JSON.parse(localStorage.getItem('jga_spieler') || 'null');
|
||
if (s) spieler = s;
|
||
} catch(e) {}
|
||
populateQuestSelect();
|
||
renderSpieler();
|
||
}
|
||
|
||
function saveState() {
|
||
try {
|
||
localStorage.setItem('jga_state', JSON.stringify({ itemCollected, drinks, questDone }));
|
||
} catch(e) {}
|
||
}
|
||
|
||
function loadState() {
|
||
try {
|
||
const s = JSON.parse(localStorage.getItem('jga_state') || 'null');
|
||
if (!s) return;
|
||
s.itemCollected?.forEach((v, i) => {
|
||
itemCollected[i] = v;
|
||
const slot = document.getElementById('inv-' + i);
|
||
if (slot && v) slot.classList.add('collected');
|
||
});
|
||
drinks = s.drinks || 0;
|
||
document.getElementById('drinkCount').textContent = drinks;
|
||
s.questDone?.forEach((v, i) => { questDone[i] = v; });
|
||
const notes = localStorage.getItem('jga_notes');
|
||
if (notes) document.getElementById('notes').value = notes;
|
||
} catch(e) {}
|
||
}
|
||
|
||
function saveNotes() {
|
||
try { localStorage.setItem('jga_notes', document.getElementById('notes').value); } catch(e) {}
|
||
}
|
||
|
||
function resetAll() {
|
||
if (!confirm('Wirklich alles zurücksetzen?')) return;
|
||
itemCollected.fill(false);
|
||
questDone.fill(false);
|
||
drinks = 0;
|
||
document.querySelectorAll('.item-slot').forEach(s => s.classList.remove('collected'));
|
||
document.getElementById('drinkCount').textContent = 0;
|
||
document.getElementById('notes').value = '';
|
||
spieler = [];
|
||
renderSpieler();
|
||
try { localStorage.clear(); } catch(e) {}
|
||
buildQuests();
|
||
updateQuestStatus();
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|