235 lines
8.5 KiB
JavaScript
235 lines
8.5 KiB
JavaScript
/* ============================================================
|
|
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;
|