403Webshell
Server IP : 202.61.199.114  /  Your IP : 216.73.217.139
Web Server : nginx/1.22.1
System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64
User : web20 ( 1018)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /tmp/rrpkg/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /tmp/rrpkg/check.js
/* Reel Royale – Stadt Land Fluss (Link-Multiplayer). */
import { $, toast } from '../util.js';
import { validate, isCovered } from './validator.js';

const boot = window.SLF_BOOT || {};
const DEFAULT_CATS = ['Stadt', 'Land', 'Fluss', 'Name', 'Tier', 'Beruf'];
const getCats = () => (R.state && R.state.cats && R.state.cats.length ? R.state.cats : DEFAULT_CATS);
const LETTERS = 'ABCDEFGHIKLMNOPRSTUW'.split('');
const R = { code: null, token: null, myId: null, version: -1, state: null, players: [], status: null, poll: null, renderedPhase: null, saveT: null };
const app = () => $('slfApp');

async function api(body) {
  const r = await fetch('api/room.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
  return r.json();
}
const promptName = () => (window.prompt('Dein Name:', boot.username || 'Spieler') || 'Spieler').slice(0, 30);
const esc = (s) => { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; };
const isHost = () => R.myId === 0;
const pickLetter = (used) => { const a = LETTERS.filter((l) => !(used || []).includes(l)); const p = a.length ? a : LETTERS; return p[(Math.random() * p.length) | 0]; };
const initialState = () => ({ phase: 'lobby', round: 0, letter: '', cats: DEFAULT_CATS.slice(), answers: {}, done: {}, scores: {}, used: [], history: [], readyRound: {} });
const shareLink = () => location.origin + location.pathname + '?room=' + R.code;

function setRoom(d) { R.code = d.code; R.token = d.token; R.myId = d.your_id != null ? d.your_id : (d.you && d.you.id); R.version = d.version; R.state = d.state; R.players = d.players; R.status = d.status; }
function applyServer(d) { if (d.version === R.version) { R.players = d.players; return false; } R.version = d.version; R.state = d.state; R.players = d.players; R.status = d.status; return true; }
function startPoll() { stopPoll(); R.poll = setInterval(poll, 1500); }
function stopPoll() { if (R.poll) { clearInterval(R.poll); R.poll = null; } }
async function poll() { if (!R.code) return; let d; try { d = await api({ action: 'state', code: R.code, token: R.token }); } catch { return; } if (!d.ok) return; if (applyServer(d)) render(); else if (R.state && R.state.phase === 'writing') updateWritingStatus(); maybeStartWriting(); }

// ---------- Aktionen ----------
async function createRoom() {
  const name = boot.username || promptName();
  const d = await api({ action: 'create', game: 'slf', name, maxp: 8, state: initialState(), status: 'lobby' });
  if (!d.ok) return toast('SLF', d.message, 'error');
  setRoom(d); localStorage.setItem('slf_' + d.code, d.token); startPoll(); render();
}
async function joinRoom(code) {
  const stored = localStorage.getItem('slf_' + code);
  const d = stored ? await api({ action: 'join', code, token: stored }) : await api({ action: 'join', code, name: boot.username || promptName() });
  if (!d.ok) { toast('SLF', d.message, 'error'); showMenu(); return; }
  setRoom(d); localStorage.setItem('slf_' + code, d.token); startPoll(); render();
}
async function replaceState(partial, status) {
  const st = Object.assign({}, R.state, partial);
  const d = await api({ action: 'replace', code: R.code, token: R.token, state: st, status: status || R.status });
  if (d.ok) applyServer(d), render();
}
async function startGame() {
  let cats = getCats();
  const box = document.getElementById('catBox');
  if (box) { const p = box.value.split(/[\n,]+/).map((x) => x.trim()).filter(Boolean); if (p.length) cats = [...new Set(p)].slice(0, 12); }
  // Spielstart → Bereit-Phase (sperrt neue Beitritte: status playing)
  await replaceState({ phase: 'ready', round: 1, cats, scores: {}, used: [], history: [], answers: {}, done: {}, votes: {}, readyRound: {} }, 'playing');
}
async function nextRound() {
  const s = R.state; const used = [...(s.used || []), s.letter];
  await replaceState({ phase: 'ready', round: s.round + 1, scores: commitScores(), used, history: pushHistory(s), answers: {}, done: {}, votes: {}, readyRound: {} }, 'playing');
}
async function endGame() { await replaceState({ phase: 'done', scores: commitScores(), history: pushHistory(R.state) }, 'done'); }

// Bereit-Phase: alle bestätigen → Gastgeber startet das Schreiben
async function confirmReady() {
  await api({ action: 'merge', code: R.code, token: R.token, patch: { readyRound: { [R.myId]: 1 } } });
  const d = await api({ action: 'state', code: R.code, token: R.token });
  if (applyServer(d)) render();
  maybeStartWriting();
}
function allReady() { const rr = R.state.readyRound || {}; return R.players.length >= 1 && R.players.every((p) => rr[p.id]); }
function maybeStartWriting() { if (isHost() && R.state && R.state.phase === 'ready' && allReady()) startWritingPhase(); }
async function startWritingPhase() {
  const s = R.state; const used = s.used || [];
  await replaceState({ phase: 'writing', letter: pickLetter(used), answers: {}, done: {}, votes: {} }, 'playing');
}

async function saveMy() {
  const ans = {};
  getCats().forEach((c, i) => { const el = document.getElementById('slf_in_' + i); if (el) ans[c] = el.value.trim(); });
  await api({ action: 'merge', code: R.code, token: R.token, patch: { answers: { [R.myId]: ans }, done: { [R.myId]: true } } });
}
async function stopRound() {
  await saveMy();
  const d = await api({ action: 'state', code: R.code, token: R.token }); applyServer(d);
  await replaceState({ phase: 'reveal', votes: {} }, 'reveal');
}

// Antwort gilt als angezweifelt, wenn mind. die Hälfte der Spieler dagegen ist.
function rejected(s, cat, id) {
  const v = (s.votes || {})[cat + '|' + id] || {};
  const n = Object.keys(v).filter((k) => v[k]).length;
  return n > 0 && n * 2 >= R.players.length;
}

// Detaillierte Rundenpunkte je Kategorie (berücksichtigt Anzweiflungen).
function computeDetail(s) {
  const ids = R.players.map((p) => p.id);
  const letter = (s.letter || '').toUpperCase();
  const cats = s.cats && s.cats.length ? s.cats : DEFAULT_CATS;
  const totals = {}; const perCat = {};
  ids.forEach((id) => { totals[id] = 0; perCat[id] = {}; });
  const valid = (id, cat) => {
    const a = (((s.answers[id] || {})[cat]) || '').trim();
    return a && a[0].toUpperCase() === letter && !rejected(s, cat, id) ? a : null;
  };
  cats.forEach((cat) => {
    const counts = {}; const ok = [];
    ids.forEach((id) => { const a = valid(id, cat); if (a) { ok.push(id); const k = a.toLowerCase(); counts[k] = (counts[k] || 0) + 1; } });
    ids.forEach((id) => {
      const a = valid(id, cat); let pts = 0;
      if (a) { const k = a.toLowerCase(); pts = ok.length === 1 ? 20 : (counts[k] > 1 ? 5 : 10); }
      perCat[id][cat] = pts; totals[id] += pts;
    });
  });
  return { totals, perCat };
}
function computeRound(s) { return computeDetail(s).totals; }
function pushHistory(s) {
  const d = computeDetail(s);
  const entry = { round: s.round, letter: s.letter, cats: (s.cats && s.cats.length ? s.cats : DEFAULT_CATS).slice(), answers: JSON.parse(JSON.stringify(s.answers || {})), perCat: d.perCat, totals: d.totals, names: R.players.map((p) => ({ id: p.id, name: p.name })) };
  return [...(s.history || []), entry];
}

async function vote(cat, id) {
  const key = cat + '|' + id;
  const cur = ((R.state.votes || {})[key] || {})[R.myId];
  await api({ action: 'merge', code: R.code, token: R.token, patch: { votes: { [key]: { [R.myId]: cur ? 0 : 1 } } } });
  const d = await api({ action: 'state', code: R.code, token: R.token });
  if (applyServer(d)) render();
}

function commitScores() {
  const round = computeRound(R.state);
  const scores = Object.assign({}, R.state.scores || {});
  R.players.forEach((p) => (scores[p.id] = (scores[p.id] || 0) + (round[p.id] || 0)));
  return scores;
}

// ---------- Rendering ----------
function nameOf(id) { const p = R.players.find((x) => x.id === id); return p ? p.name : ('Spieler ' + (id + 1)); }

function render() {
  const s = R.state;
  if (!s) { app().innerHTML = '<p style="text-align:center">Lade …</p>'; return; }
  // Beim Tippen/Editieren nicht neu aufbauen, nur dynamische Teile aktualisieren
  if (s.phase === 'lobby' && R.renderedPhase === 'lobby') { updateLobbyDynamic(); return; }
  if (s.phase === 'writing' && R.renderedPhase === 'writing') { updateWritingStatus(); return; }
  R.renderedPhase = s.phase;
  if (s.phase === 'lobby') return renderLobby();
  if (s.phase === 'ready') return renderReady();
  if (s.phase === 'writing') return renderWriting();
  if (s.phase === 'reveal') return renderReveal();
  if (s.phase === 'done') return renderDone();
}

function renderReady() {
  const s = R.state; const rr = s.readyRound || {}; const iReady = !!rr[R.myId];
  const cnt = R.players.filter((p) => rr[p.id]).length;
  app().innerHTML = `
    <div class="rr-room-card">
      <h2 class="rr-room-title">Runde ${s.round}</h2>
      <p class="rr-room-sub">Bereitmachen – es startet, sobald alle bereit sind (${cnt}/${R.players.length})</p>
      <div class="rr-room-players">${R.players.map((p) => `<span class="rr-pill">${esc(p.name)}${p.id === 0 ? ' 👑' : ''} ${rr[p.id] ? '✅' : '⏳'}</span>`).join('')}</div>
      ${iReady ? '<div class="rr-room-hint">✅ Du bist bereit – warte auf die anderen …</div>' : '<button class="rr-btn rr-btn-gold rr-btn-block" id="readyBtn">Ich bin bereit</button>'}
      ${histBtnHTML()}
      <a class="rr-btn rr-btn-ghost rr-btn-block" href="index.php">‹ Lobby</a>
    </div>`;
  if (!iReady) $('readyBtn').onclick = confirmReady;
  bindHistBtn();
}

// ---------- Historie ----------
function histBtnHTML() { return (R.state.history && R.state.history.length) ? '<button class="rr-btn rr-btn-ghost rr-btn-block" id="histBtn">📜 Historie</button>' : ''; }
function bindHistBtn() { const b = $('histBtn'); if (b) b.onclick = showHistory; }
function showHistory() {
  const h = R.state.history || [];
  const body = h.length ? h.slice().reverse().map((e) => {
    const names = e.names || R.players.map((p) => ({ id: p.id, name: p.name }));
    const ids = names.map((n) => n.id);
    const nm = (id) => { const n = names.find((x) => x.id === id); return n ? n.name : ('#' + id); };
    return `<div class="rr-hist-round"><h4>Runde ${e.round} · Buchstabe ${esc(e.letter)}</h4>
      <div class="rr-slf-table-wrap"><table class="rr-slf-table">
        <thead><tr><th>Kategorie</th>${ids.map((id) => `<th>${esc(nm(id))}</th>`).join('')}</tr></thead><tbody>
        ${e.cats.map((c) => `<tr><td class="rr-slf-cat">${esc(c)}</td>${ids.map((id) => { const a = ((e.answers[id] || {})[c] || '').trim(); const p = (e.perCat[id] || {})[c] || 0; return `<td>${a ? esc(a) : '–'} <b class="hist-pts">${p}</b></td>`; }).join('')}</tr>`).join('')}
        <tr class="rr-slf-sum"><td>Runde gesamt</td>${ids.map((id) => `<td>+${e.totals[id] || 0}</td>`).join('')}</tr>
      </tbody></table></div></div>`;
  }).join('') : '<p class="rr-room-hint">Noch keine Runden gespielt.</p>';
  const ov = document.createElement('div'); ov.className = 'rr-modal';
  ov.innerHTML = `<div class="rr-modal-card"><div class="rr-modal-head"><h3>📜 Historie</h3><button class="rr-icon-btn" id="histClose">✕</button></div><div class="rr-hist-body">${body}</div></div>`;
  document.body.appendChild(ov);
  ov.addEventListener('click', (ev) => { if (ev.target === ov) ov.remove(); });
  ov.querySelector('#histClose').onclick = () => ov.remove();
}

function updateLobbyDynamic() {
  const pc = document.getElementById('lobbyPlayers');
  if (pc) pc.innerHTML = R.players.map((p) => `<span class="rr-pill">${esc(p.name)}${p.id === 0 ? ' 👑' : ''}</span>`).join('');
  const sb = document.getElementById('startBtn');
  if (sb) sb.disabled = R.players.length < 2;
  const sub = document.getElementById('lobbySub');
  if (sub) sub.textContent = `Lade Freunde per Link ein – ${R.players.length} dabei`;
}

function renderLobby() {
  app().innerHTML = `
    <div class="rr-room-card">
      <h1 class="rr-room-title">Stadt Land Fluss</h1>
      <p class="rr-room-sub" id="lobbySub">Lade Freunde per Link ein – ${R.players.length} dabei</p>
      <div class="rr-room-players" id="lobbyPlayers">${R.players.map((p) => `<span class="rr-pill">${esc(p.name)}${p.id === 0 ? ' 👑' : ''}</span>`).join('')}</div>
      <div class="rr-share"><input id="shareLink" readonly value="${shareLink()}"><button class="rr-btn rr-btn-gold" id="copyLink">Kopieren</button></div>
      ${isHost()
        ? `<div class="rr-slf-cats"><label>Kategorien (frei wählbar – eine pro Zeile, z. B. Automarke):</label><textarea id="catBox" rows="6">${esc(getCats().join('\n'))}</textarea></div>
           <button class="rr-btn rr-btn-gold rr-btn-block" id="startBtn" ${R.players.length < 2 ? 'disabled' : ''}>Spiel starten</button>${R.players.length < 2 ? '<p class="rr-room-hint">Mindestens 2 Spieler nötig.</p>' : ''}`
        : '<p class="rr-room-hint">Warte, bis der Gastgeber startet …</p>'}
      <a class="rr-btn rr-btn-ghost rr-btn-block" href="index.php">‹ Lobby</a>
    </div>`;
  bindShare();
  if (isHost()) $('startBtn') && ($('startBtn').onclick = startGame);
}

function renderWriting() {
  const s = R.state; const mine = s.answers[R.myId] || {};
  const iDone = !!s.done[R.myId];
  app().innerHTML = `
    <div class="rr-room-card">
      <div class="rr-slf-letterbar"><span>Runde ${s.round}</span><div class="rr-slf-letter">${esc(s.letter)}</div><span id="doneCount"></span></div>
      <div class="rr-slf-form">
        ${getCats().map((c, i) => `<label class="rr-slf-field"><span>${esc(c)}</span><input id="slf_in_${i}" value="${esc(mine[c] || '')}" autocomplete="off" ${iDone ? 'disabled' : ''}></label>`).join('')}
      </div>
      ${iDone
        ? '<div class="rr-room-hint">✅ Abgegeben – warte auf die anderen …</div>'
        : '<button class="rr-btn rr-btn-gold rr-btn-block" id="stopBtn">STOPP – Runde beenden</button>'}
    </div>`;
  if (!iDone) {
    $('stopBtn').onclick = stopRound;
    getCats().forEach((c, i) => { const el = $('slf_in_' + i); el.addEventListener('input', () => { clearTimeout(R.saveT); R.saveT = setTimeout(saveMy, 700); }); });
  }
  updateWritingStatus();
}
function updateWritingStatus() {
  const s = R.state; if (!s || s.phase !== 'writing') return;
  const done = R.players.filter((p) => (s.done || {})[p.id]).length;
  const dc = $('doneCount'); if (dc) dc.textContent = `${done}/${R.players.length} fertig`;
}

function renderReveal() {
  const s = R.state; const ids = R.players.map((p) => p.id);
  const cats = s.cats && s.cats.length ? s.cats : DEFAULT_CATS;
  const live = computeRound(s);
  const proj = (id) => (s.scores[id] || 0) + (live[id] || 0);
  const standings = [...ids].sort((a, b) => proj(b) - proj(a));
  const cell = (id, c, ci) => {
    const a = ((s.answers[id] || {})[c] || '').trim();
    if (!a) return '<td>–</td>';
    const isRej = rejected(s, c, id);
    const v = (s.votes || {})[c + '|' + id] || {};
    const n = Object.keys(v).filter((k) => v[k]).length;
    const mine = !!v[R.myId];
    let badge = '';
    const val = validate(c, a);
    if (val === 'ok') badge = '<span class="slf-ok" title="bekannt – gültig">✓</span>';
    else if (val === 'unknown') badge = '<span class="slf-warn" title="nicht in der Liste – bitte prüfen">⚠</span>';
    return `<td class="${isRej ? 'slf-rej' : ''}"><div class="slf-cell"><span>${esc(a)} ${badge}</span>
      <button class="slf-vote${mine ? ' on' : ''}" data-ci="${ci}" data-id="${id}" title="Antwort anzweifeln">👎${n || ''}</button></div></td>`;
  };
  app().innerHTML = `
    <div class="rr-room-card">
      <h2 class="rr-room-title">Runde ${s.round} · Buchstabe ${esc(s.letter)}</h2>
      <p class="rr-room-hint">✓ = bekannt gültig · ⚠ = nicht in Liste (prüfen) · 👎 = anzweifeln (ab der Hälfte der Spieler → 0 Punkte)</p>
      <div class="rr-slf-table-wrap"><table class="rr-slf-table">
        <thead><tr><th>Kategorie</th>${R.players.map((p) => `<th>${esc(p.name)}</th>`).join('')}</tr></thead>
        <tbody>
          ${cats.map((c, ci) => `<tr><td class="rr-slf-cat">${esc(c)}</td>${ids.map((id) => cell(id, c, ci)).join('')}</tr>`).join('')}
          <tr class="rr-slf-sum"><td>Punkte</td>${ids.map((id) => `<td>+${live[id] || 0}</td>`).join('')}</tr>
        </tbody>
      </table></div>
      <div class="rr-slf-scores">${standings.map((id, i) => `<div class="rr-score-row${i === 0 ? ' lead' : ''}"><span>${i + 1}. ${esc(nameOf(id))}</span><b>${proj(id)}</b></div>`).join('')}</div>
      ${isHost() ? '<div class="rr-room-actions"><button class="rr-btn rr-btn-gold" id="nextBtn">Nächste Runde</button><button class="rr-btn rr-btn-ghost" id="endBtn">Spiel beenden</button></div>' : '<p class="rr-room-hint">Warte auf die nächste Runde …</p>'}
      ${histBtnHTML()}
    </div>`;
  document.querySelectorAll('.slf-vote').forEach((b) => { b.onclick = () => vote(cats[+b.dataset.ci], +b.dataset.id); });
  bindHistBtn();
  if (isHost()) { $('nextBtn').onclick = nextRound; $('endBtn').onclick = endGame; }
}

function renderDone() {
  const s = R.state; const ids = R.players.map((p) => p.id).sort((a, b) => (s.scores[b] || 0) - (s.scores[a] || 0));
  app().innerHTML = `
    <div class="rr-room-card">
      <h1 class="rr-room-title">🏆 Endstand</h1>
      <div class="rr-slf-scores">${ids.map((id, i) => `<div class="rr-score-row${i === 0 ? ' lead' : ''}"><span>${['🥇','🥈','🥉'][i] || (i + 1 + '.')} ${esc(nameOf(id))}</span><b>${s.scores[id] || 0}</b></div>`).join('')}</div>
      ${histBtnHTML()}
      ${isHost() ? '<button class="rr-btn rr-btn-gold rr-btn-block" id="againBtn">Neue Partie</button>' : ''}
      <a class="rr-btn rr-btn-ghost rr-btn-block" href="index.php">‹ Lobby</a>
    </div>`;
  bindHistBtn();
  if (isHost()) $('againBtn').onclick = () => replaceState({ phase: 'lobby', round: 0, scores: {}, used: [], answers: {}, done: {}, votes: {}, readyRound: {} }, 'lobby');
}

function bindShare() {
  const c = $('copyLink'); if (!c) return;
  c.onclick = () => { const i = $('shareLink'); i.select(); navigator.clipboard?.writeText(i.value).then(() => toast('SLF', 'Link kopiert!', 'win')).catch(() => {}); };
}

function stopMenuPoll() { if (R.menuPoll) { clearInterval(R.menuPoll); R.menuPoll = null; } }
function showMenu() {
  stopPoll(); R.renderedPhase = null;
  app().innerHTML = `
    <div class="rr-room-card">
      <h1 class="rr-room-title">Stadt Land Fluss</h1>
      <p class="rr-room-sub">Eigene Runde erstellen oder einem offenen Raum beitreten</p>
      <button class="rr-btn rr-btn-gold rr-btn-block" id="newBtn">➕ Neue Runde erstellen</button>
      <div class="rr-roomlist-head"><span>Offene Räume</span><button class="rr-mini" id="refreshRooms" title="Aktualisieren">↻</button></div>
      <div id="roomList" class="rr-roomlist"><p class="rr-room-hint">Lade …</p></div>
      <a class="rr-btn rr-btn-ghost rr-btn-block" href="index.php">‹ Zurück zur Lobby</a>
    </div>`;
  $('newBtn').onclick = () => { stopMenuPoll(); createRoom(); };
  $('refreshRooms').onclick = refreshMenuRooms;
  refreshMenuRooms();
  stopMenuPoll(); R.menuPoll = setInterval(refreshMenuRooms, 3000);
}
async function refreshMenuRooms() {
  let rooms = [];
  try { const d = await api({ action: 'list', game: 'slf' }); if (d.ok) rooms = d.rooms; } catch {}
  const el = $('roomList'); if (!el) return;
  if (!rooms.length) { el.innerHTML = '<p class="rr-room-hint">Keine offenen Räume – erstelle einen neuen.</p>'; return; }
  el.innerHTML = '';
  rooms.forEach((r) => {
    const row = document.createElement('div'); row.className = 'rr-roomrow';
    row.innerHTML = `<div class="rr-roomrow-info"><b>${esc(r.host)}s Runde</b><span>${r.count}/${r.maxp} Spieler</span></div>`;
    const b = document.createElement('button'); b.className = 'rr-btn rr-btn-gold'; b.textContent = 'Beitreten';
    b.onclick = () => { stopMenuPoll(); joinRoom(r.code); };
    row.appendChild(b); el.appendChild(row);
  });
}

if (boot.codeParam) joinRoom(boot.codeParam);
else showMenu();

Youez - 2016 - github.com/yon3zu
LinuXploit