From 2e64850314260e66034c9a1e19e394cd42aa5a44 Mon Sep 17 00:00:00 2001 From: cay Date: Thu, 9 Apr 2026 13:23:08 +0100 Subject: [PATCH] qegQ --- app.js | 2 + routes/points.route.js | 233 ++++++++++++++++++++++ views/1v1-battlefield.ejs | 394 +++++++++++++++++++------------------- 3 files changed, 428 insertions(+), 201 deletions(-) create mode 100644 routes/points.route.js diff --git a/app.js b/app.js index b35de62..395af81 100644 --- a/app.js +++ b/app.js @@ -27,6 +27,7 @@ const arenaRoutes = require("./routes/arena.route"); const { registerArenaHandlers } = require("./sockets/arena"); const { registerChatHandlers } = require("./sockets/chat"); const boosterRoutes = require("./routes/booster.route"); +const pointsRoutes = require("./routes/points.route"); const compression = require("compression"); @@ -386,6 +387,7 @@ app.use("/api", carddeckRoutes); app.use("/arena", arenaRoutes); app.use("/api", boosterRoutes); app.use("/api", require("./routes/daily.route")); +app.use("/api/points", pointsRoutes); /* ======================== 404 Handler diff --git a/routes/points.route.js b/routes/points.route.js new file mode 100644 index 0000000..b9d3243 --- /dev/null +++ b/routes/points.route.js @@ -0,0 +1,233 @@ +/* ============================================================ + 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: 3 }, + "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" }); + } +}); + +module.exports = router; diff --git a/views/1v1-battlefield.ejs b/views/1v1-battlefield.ejs index fbc29d4..5f7ee0c 100644 --- a/views/1v1-battlefield.ejs +++ b/views/1v1-battlefield.ejs @@ -4,18 +4,45 @@ <%= title || "Spielfeld" %> - - - + + - -
Warte auf Gegner…
@@ -23,29 +50,26 @@
-
<%= title || "Spielfeld" %>
-
-
-
🗺
-
📖
-
🏆
+
🗺
+
📖
🏆
-
-
Bereit machen
- + + + +
30
Beide Spieler müssen BEREIT klicken
@@ -57,90 +81,45 @@
-
- - + - -
-
-
- +
<%= player1 || "Spieler 1" %>
-
-
- - <%= player1hp || 20 %> -
- -
- 💧 - <%= player1mana || 3 %> -
+
<%= player1hp || 20 %>
+
💧<%= player1mana || 3 %>
-
<%= player1hp || 15 %>
-
- - + - -
-
🛡
-
- -
<%= player2 || "Spieler 2" %>
- +
🛡
+
<%= player2 || "Gegner" %>
-
- - <%= player2hp || 20 %> -
- -
- 💧 - <%= player2mana || 3 %> -
+
<%= player2hp || 20 %>
+
💧<%= player2mana || 3 %>
-
<%= player2hp || 15 %>
-
Reihe 1
-
Reihe 2
-
-
- -
🛡
-
💊
🃏
@@ -150,51 +129,45 @@
- + +
+
+
+ + + +
+ -