// DEMO: erzeugt einen zufälligen Matchverlauf als CS2-Logzeilen. // Die Zeilen laufen durch denselben Parser wie echte Serverlogs, so lässt sich die // Live-Anzeige ohne CS2-Server testen. Ergebnisse sind frei erfunden. const REASONS = { CT: ['CTs_Win', 'Bomb_Defused', 'Target_Saved'], T: ['Terrorists_Win', 'Target_Bombed'], }; const stamp = () => { const d = new Date(); const p = (n, l = 2) => String(n).padStart(l, '0'); return `${p(d.getMonth() + 1)}/${p(d.getDate())}/${d.getFullYear()} - ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)} - `; }; export class DemoMatchSimulator { constructor({ random = Math.random } = {}) { this.runs = new Map(); this.random = random; } start(matchId, { map, teamNames, ctTeam, maxRounds, roundMs, onLines }) { this.stop(matchId); const other = (t) => (t === 'A' ? 'B' : 'A'); const run = { sides: { CT: ctTeam, T: other(ctTeam) }, score: { A: 0, B: 0 }, played: 0 }; const toWin = maxRounds / 2 + 1; // Leichte Stärke-Unterschiede, damit nicht jedes Demo-Match gleich aussieht const strengthA = 0.4 + this.random() * 0.2; const teamLines = () => [ `${stamp()}MatchStatus: Team playing "CT": ${teamNames[run.sides.CT]}`, `${stamp()}MatchStatus: Team playing "TERRORIST": ${teamNames[run.sides.T]}`, ]; onLines([...teamLines(), `${stamp()}World triggered "Match_Start" on "${map}"`]); run.timer = setInterval(() => { const winner = this.random() < strengthA ? 'A' : 'B'; const side = run.sides.CT === winner ? 'CT' : 'T'; run.score[winner] += 1; run.played += 1; const notice = REASONS[side][Math.floor(this.random() * REASONS[side].length)]; // Reihenfolge wie bei einem echten CS2-Server: Rundenende, Seitenzuordnung der gespielten Runde, Round_End const lines = [ `${stamp()}Team "${side === 'CT' ? 'CT' : 'TERRORIST'}" triggered "SFUI_Notice_${notice}" (CT "${run.score[run.sides.CT]}") (T "${run.score[run.sides.T]}")`, ...teamLines(), `${stamp()}World triggered "Round_End"`, ]; if (run.score[winner] >= toWin) { lines.push(`${stamp()}Game Over: competitive mg_active ${map} score ${run.score[run.sides.CT]}:${run.score[run.sides.T]} after 1 min`); onLines(lines); this.stop(matchId); return; } // Halbzeit: Seiten wechseln, die nächsten Zeilen nennen die neue Zuordnung if (run.played === maxRounds / 2) run.sides = { CT: run.sides.T, T: run.sides.CT }; onLines(lines); }, roundMs); this.runs.set(matchId, run); } stop(matchId) { const run = this.runs.get(matchId); if (run) clearInterval(run.timer); this.runs.delete(matchId); } stopAll() { for (const id of [...this.runs.keys()]) this.stop(id); } }