/* ============================================================ routes/points.route.js Punkte-Vergabe nach Arena-Matches Jeder Spieler meldet sein eigenes Ergebnis: POST /api/points/match → Punkte für diesen Spieler vergeben GET /api/points/me → Aktueller Stand + Level-Fortschritt ============================================================ */ const express = require("express"); const router = express.Router(); const db = require("../database/database"); /* ── Punkte-Konfiguration ───────────────────────────────── */ const POINTS = { "1v1": { win: 15, lose: 5 }, "2v2": { win: 12, lose: 2 }, "4v4": { win: 10, lose: 2 }, }; const DAILY_LIMIT = 500; const SURRENDER_MIN_SEC = 60; // Aufgabe unter 60s → 0 Punkte /* ── Auth-Guard ─────────────────────────────────────────── */ function requireLogin(req, res, next) { if (!req.session?.user) return res.status(401).json({ error: "Nicht eingeloggt" }); next(); } /* ═══════════════════════════════════════════════════════════ HELPER: Punkte vergeben - accounts.arena_points += amount (NIE abgezogen → Level) - user_buildings.points += amount (für Gebäude-Upgrades) - Tages-Limit 500 prüfen ═══════════════════════════════════════════════════════════ */ async function awardPoints(accountId, amount) { if (amount <= 0) return { awarded: 0, level_up: false }; const today = new Date().toISOString().slice(0, 10); const [[acc]] = await db.query( "SELECT arena_points, arena_points_today, arena_points_reset, level FROM accounts WHERE id = ?", [accountId] ); if (!acc) return { awarded: 0, level_up: false }; /* Tages-Reset */ const lastReset = acc.arena_points_reset ? new Date(acc.arena_points_reset).toISOString().slice(0, 10) : null; const pointsToday = lastReset === today ? acc.arena_points_today : 0; /* Tages-Limit anwenden */ const remaining = Math.max(0, DAILY_LIMIT - pointsToday); const actual = Math.min(amount, remaining); if (actual === 0) { return { awarded: 0, level_up: false, daily_limit_reached: true }; } /* accounts: arena_points erhöhen (NIE abziehen) */ await db.query( `UPDATE accounts SET arena_points = arena_points + ?, arena_points_today = ? + ?, arena_points_reset = ? WHERE id = ?`, [actual, pointsToday, actual, today, accountId] ); /* Alle Gebäude des Spielers ebenfalls gutschreiben */ await db.query( "UPDATE user_buildings SET points = points + ? WHERE user_id = ?", [actual, accountId] ); /* Level-Up prüfen */ const newTotal = acc.arena_points + actual; const [[levelRow]] = await db.query( `SELECT MAX(level) AS level FROM character_levels WHERE points_cumulative <= ?`, [newTotal] ); const newLevel = levelRow?.level || 1; const levelUp = newLevel > acc.level; if (levelUp) { await db.query( "UPDATE accounts SET level = ? WHERE id = ?", [newLevel, accountId] ); console.log(`[Points] Level-Up! Spieler ${accountId}: ${acc.level} → ${newLevel}`); } return { awarded: actual, new_total: newTotal, new_level: newLevel, level_up: levelUp, daily_limit_reached: actual < amount, }; } /* ═══════════════════════════════════════════════════════════ POST /api/points/match Jeder Spieler ruft dies für sich selbst auf wenn das Match endet (Sieg, Niederlage oder Aufgabe). Body: { match_id: "match_1234_abc", -- eindeutige Match-ID mode: "1v1"|"2v2"|"4v4", result: "win"|"lose", surrender: false, -- true wenn aufgegeben duration_seconds: 240 -- Spieldauer in Sekunden } ═══════════════════════════════════════════════════════════ */ router.post("/match", requireLogin, async (req, res) => { const { match_id, mode, result, surrender, duration_seconds } = req.body; const accountId = req.session.user.id; if (!match_id || !mode || !POINTS[mode] || !["win", "lose"].includes(result)) { return res.status(400).json({ error: "Ungültige Parameter" }); } try { /* Doppelte Vergabe für diesen Spieler verhindern */ const [[existing]] = await db.query( "SELECT id FROM arena_match_players WHERE match_id = ? AND account_id = ?", [match_id, accountId] ); if (existing) { return res.json({ success: true, already_processed: true }); } /* Punkte berechnen */ const pts = POINTS[mode]; const isWin = result === "win"; const isSurr = !!surrender; const shortMatch = duration_seconds && duration_seconds < SURRENDER_MIN_SEC; let pointsToAward = 0; if (shortMatch) { pointsToAward = 0; // Zu kurz → keine Punkte } else if (isWin) { pointsToAward = pts.win; } else if (isSurr) { pointsToAward = 0; // Aufgegeben → keine Punkte } else { pointsToAward = pts.lose; } /* Punkte vergeben */ const awarded = await awardPoints(accountId, pointsToAward); /* Match-Log: Eintrag für diesen Spieler */ await db.query( `INSERT IGNORE INTO arena_matches (match_id, mode, surrender, duration_seconds) VALUES (?, ?, ?, ?)`, [match_id, mode, isSurr ? 1 : 0, duration_seconds || null] ); await db.query( `INSERT INTO arena_match_players (match_id, account_id, team, won, points) VALUES (?, ?, 1, ?, ?)`, [match_id, accountId, isWin ? 1 : 0, awarded.awarded] ); console.log( `[Points] ${mode} | Spieler ${accountId} | ${result} | +${awarded.awarded} Pts` + (awarded.level_up ? ` | LEVEL UP → ${awarded.new_level}!` : "") ); res.json({ success: true, points_awarded: awarded.awarded, total_arena_points: awarded.new_total, level: awarded.new_level, level_up: awarded.level_up, daily_limit_reached: awarded.daily_limit_reached || false, }); } catch (err) { console.error("[Points] Fehler:", err); res.status(500).json({ error: "Datenbankfehler" }); } }); /* ═══════════════════════════════════════════════════════════ GET /api/points/me Aktueller Punktestand + Level-Fortschritt für HUD ═══════════════════════════════════════════════════════════ */ router.get("/me", requireLogin, async (req, res) => { const userId = req.session.user.id; try { const [[acc]] = await db.query( "SELECT arena_points, level FROM accounts WHERE id = ?", [userId] ); if (!acc) return res.status(404).json({ error: "Spieler nicht gefunden" }); const [[curLevel]] = await db.query( `SELECT level, points_cumulative FROM character_levels WHERE points_cumulative <= ? ORDER BY level DESC LIMIT 1`, [acc.arena_points] ); const [[nextLevel]] = await db.query( `SELECT level, points_cumulative FROM character_levels WHERE points_cumulative > ? ORDER BY level ASC LIMIT 1`, [acc.arena_points] ); const curThreshold = curLevel?.points_cumulative || 0; const nextThreshold = nextLevel?.points_cumulative || null; const progress = nextThreshold ? Math.round((acc.arena_points - curThreshold) * 100 / (nextThreshold - curThreshold)) : 100; res.json({ arena_points: acc.arena_points, level: acc.level, points_this_level: acc.arena_points - curThreshold, points_for_next: nextThreshold ? nextThreshold - curThreshold : 0, progress_percent: progress, is_max_level: !nextLevel, }); } catch (err) { console.error("[Points] /me Fehler:", err); res.status(500).json({ error: "Datenbankfehler" }); } }); router.awardPoints = awardPoints; module.exports = router;