const express = require('express'); const Database = require('better-sqlite3'); const path = require('path'); const app = express(); app.use(express.json()); app.use(express.static(path.join(__dirname, '../'))); const DB_PATH = path.join(__dirname, 'data.db'); function getDb() { const db = new Database(DB_PATH); db.pragma('journal_mode = WAL'); db.exec(` CREATE TABLE IF NOT EXISTS state ( key TEXT PRIMARY KEY, value TEXT ); CREATE TABLE IF NOT EXISTS spieler ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, rolle TEXT, quest_id INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, body TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS drinks_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, amount INTEGER, note TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); `); return db; } let db = getDb(); function initState() { const row = db.prepare("SELECT value FROM state WHERE key = 'game'").get(); if (!row) { const s = { gameName: '', gameStarted: false, drinks: 0, items: [false,false,false,false,false,false,false,false], quests: [false,false,false,false,false,false,false,false], timestamp: Date.now() }; db.prepare('INSERT OR REPLACE INTO state (key,value) VALUES (?,?)').run('game', JSON.stringify(s)); } } initState(); // GET state app.get('/api/game', (req, res) => { initState(); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); res.json({ state: JSON.parse(sv.value), spieler: db.prepare('SELECT * FROM spieler ORDER BY id').all(), notes: db.prepare('SELECT * FROM notes ORDER BY created_at DESC').all(), stats: db.prepare('SELECT SUM(amount) as total, COUNT(*) as entries FROM drinks_log').get() || {total:0,entries:0} }); }); // Start app.post('/api/game/start', (req, res) => { initState(); const {name} = req.body; const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.gameName = name || 'Der letzte Auftrag'; s.gameStarted = true; s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); res.json({success:true, state:s}); }); // Drink app.post('/api/game/drink', (req, res) => { initState(); const amt = req.body.amount || 1; const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.drinks = Math.max(0, s.drinks + amt); s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); db.prepare('INSERT INTO drinks_log (amount) VALUES (?)').run(amt); res.json({success:true, drinks:s.drinks}); }); // Reset drink app.post('/api/game/drink/reset', (req, res) => { initState(); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.drinks = 0; s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); res.json({success:true, drinks:0}); }); // Toggle item app.post('/api/game/toggle-item', (req, res) => { initState(); const idx = parseInt(req.body.index); if (idx<0||idx>7) return res.status(400).json({error:'Index 0-7'}); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.items[idx] = !s.items[idx]; s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); res.json({success:true, state:s, collected:s.items.filter(Boolean).length}); }); // Toggle quest app.post('/api/game/toggle-quest', (req, res) => { initState(); const idx = parseInt(req.body.index); if (idx<0||idx>7) return res.status(400).json({error:'Index 0-7'}); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.quests[idx] = !s.quests[idx]; s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); res.json({success:true, state:s}); }); // Save full state app.post('/api/game/save-state', (req, res) => { initState(); const s = req.body; s.timestamp = Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); res.json({success:true, state:s}); }); // Reset all app.post('/api/game/reset', (req, res) => { initState(); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); s.drinks=0; s.items=[false,false,false,false,false,false,false,false]; s.quests=[false,false,false,false,false,false,false,false]; s.gameStarted=false; s.gameName=''; s.timestamp=Date.now(); db.prepare("UPDATE state SET value=? WHERE key='game'").run(JSON.stringify(s)); db.prepare('DELETE FROM notes').run(); db.prepare('DELETE FROM drinks_log').run(); res.json({success:true, state:s}); }); // Spieler CRUD app.get('/api/spieler', (req, res) => res.json(db.prepare('SELECT * FROM spieler ORDER BY id').all())); app.post('/api/spieler', (req, res) => { const {name, rolle, quest_id} = req.body; const r = db.prepare('INSERT INTO spieler (name,rolle,quest_id) VALUES (?,?,?)').run(name, rolle, quest_id||null); res.json({success:true, spieler:db.prepare('SELECT * FROM spieler WHERE id=?').get(r.lastInsertRowid)}); }); app.put('/api/spieler/:id', (req, res) => { const {name, rolle, quest_id} = req.body; db.prepare('UPDATE spieler SET name=COALESCE(?,name),rolle=COALESCE(?,rolle),quest_id=COALESCE(?,quest_id) WHERE id=?') .run(name||null, rolle||null, quest_id||null, req.params.id); res.json({success:true, spieler:db.prepare('SELECT * FROM spieler WHERE id=?').get(req.params.id)}); }); app.delete('/api/spieler/:id', (req, res) => { db.prepare('DELETE FROM spieler WHERE id=?').run(req.params.id); res.json({success:true}); }); // Notes app.post('/api/notes', (req, res) => { const {body} = req.body; const r = db.prepare('INSERT INTO notes (body) VALUES (?)').run(body); res.json({success:true, note:db.prepare('SELECT * FROM notes WHERE id=?').get(r.lastInsertRowid)}); }); // Stats app.get('/api/game/stats', (req, res) => { initState(); const sv = db.prepare("SELECT value FROM state WHERE key='game'").get(); const s = JSON.parse(sv.value); res.json({ collected: s.items.filter(Boolean).length, total:8, questsDone: s.quests.filter(Boolean).length, questsTotal:8, drinks: s.drinks, gameName: s.gameName, spielerCount: db.prepare('SELECT COUNT(*) as c FROM spieler').get().c, spieler: db.prepare('SELECT * FROM spieler').all() }); }); const PORT = process.env.PORT || 8082; app.listen(PORT, '0.0.0.0', () => { console.log(`🏰 Der letzte Auftrag server on port ${PORT}`); });