Cangaceiros — Matchmaker Completo

Cangaceiros Matchmaker

Balanceamento & Partidas

Balancear Times

Como Usar

1. Preencha os nicks dos 10 jogadores

2. As lanes e elos serão carregados automaticamente

3. Clique em "Balancear Times"

4. Os times serão formados automaticamente

* Apenas administradores podem iniciar e salvar partidas

* Os elos são calculados automaticamente com base nas vitórias/derrotas

Ranking

Veja os melhores do servidor — filtro rápido e visual moderno

Tabela de Elos

Sistema detalhado de elos, divisões e PDLS por lane - Ordenado do maior para o menor elo

Carregando tabela de elos...

Histórico

Últimas partidas realizadas
`); win.document.close(); }/* ====== ESTATÍSTICAS ====== */async function updateStats() { try { const playersSnap = await getDocs(collection(db, "players")); const matchesSnap = await getDocs(collection(db, "matches")); const players = []; playersSnap.forEach(d => players.push(d.data())); const matches = []; matchesSnap.forEach(d => matches.push(d.data())); window.allMatches = matches; if (typeof calculatePlayerLaneStats === 'function') { calculatePlayerLaneStats(matches, players); } else { console.error("calculatePlayerLaneStats não está definida"); } const totalPlayers = players.length; const totalMatches = matches.length; const totalPoints = players.reduce((sum, p) => sum + (p.pontos || 0), 0); const avgPoints = totalPlayers > 0 ? (totalPoints / totalPlayers).toFixed(1) : 0; const topPlayer = players.length > 0 ? players.reduce((max, p) => (p.pontos || 0) > (max.pontos || 0) ? p : max) : null; const azulWins = matches.filter(m => m.vencedor === 'azul').length; const vermelhoWins = matches.filter(m => m.vencedor === 'vermelho').length; if (typeof calculatePlayerLaneStats === 'function') { calculatePlayerLaneStats(matches, players); } else { console.error("calculatePlayerLaneStats não está definida"); } const statsContent = document.getElementById("statsContent"); if (statsContent) { statsContent.innerHTML = `

Total de Jogadores

${totalPlayers}

Total de Partidas

${totalMatches}

Média de Pontos

${avgPoints}

Vitórias Azul

${azulWins}

Vitórias Vermelho

${vermelhoWins}
${topPlayer ? `

Top Player

${topPlayer.nickname}
${topPlayer.pontos || 0} pontos
` : ''} `; } } catch (error) { console.error("Erro ao carregar estatísticas:", error); } }/* ====== RANKING INICIAL ====== */async function loadInitialRanking() { try { // Verificar se db está definido if (typeof db === 'undefined' || !db) { console.error("Firebase não está inicializado!"); return; } console.log("Carregando ranking inicial..."); const snap = await getDocs(collection(db, "players")); const arr = []; snap.forEach(d => arr.push(d.data())); arr.forEach(p => { p.pontos = p.pontos || 0; p.vitorias = p.vitorias || 0; p.derrotas = p.derrotas || 0; p.mvp = p.mvp || 0; p.ace = p.ace || 0; p.bagre = p.bagre || 0; }); window.rankingData = arr; const matchesSnap = await getDocs(collection(db, "matches")); const matches = []; matchesSnap.forEach(d => matches.push(d.data())); window.allMatches = matches; if (typeof calculatePlayerLaneStats === 'function') { calculatePlayerLaneStats(matches, arr); } else { console.error("calculatePlayerLaneStats não está definida"); } if (typeof renderRanking === 'function') { renderRanking(); } // Carregar tabela de elos inicial if (typeof calcularEloCompleto === 'function') { const elosCalculados = arr.map(player => calcularEloCompleto(player)); elosCalculados.sort((a, b) => { const nivelA = ELOS[a.elo]?.nivel || 0; const nivelB = ELOS[b.elo]?.nivel || 0; if (nivelB !== nivelA) return nivelB - nivelA; if (a.divisao !== b.divisao) return a.divisao - b.divisao; return (b.pdls || 0) - (a.pdls || 0); }); if (typeof loadEloTable === 'function') { loadEloTable(elosCalculados, 'all'); } else { console.error("loadEloTable não está definida"); } } else { console.error("calcularEloCompleto não está definida"); } } catch (error) { console.error("Erro ao carregar ranking:", error); } }/* ====== PROCESSAR PARÂMETROS DE URL ====== */function processUrlParams() { const urlParams = new URLSearchParams(window.location.search); const voteType = urlParams.get('vote'); const matchId = urlParams.get('match'); if (voteType && matchId) { createVotePage(matchId, voteType); window.history.replaceState({}, document.title, window.location.pathname); } }/* ====== INICIALIZAÇÃO FINAL ====== */// Aguardar DOM estar completamente pronto function startApp() { // Carregar imagens dos elos PRIMEIRO (do localStorage) if (typeof loadEloImages === 'function') { loadEloImages(); } // Aguardar um pouco mais para garantir que todos os elementos estejam no DOM setTimeout(() => { // Inicializar UI if (typeof updateUIForUserType === 'function') { updateUIForUserType(); }// Carregar dados iniciais if (typeof loadInitialRanking === 'function') { loadInitialRanking(); } }, 100); }// Inicializar quando DOM estiver pronto if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startApp); } else { // DOM já está pronto startApp(); }// Listener em tempo real para players (atualiza ranking e tabela de elos automaticamente) // Verificar se db está definido antes de criar o listener function setupPlayersListener() { if (typeof db !== 'undefined' && db) { onSnapshot(collection(db, "players"), async (snap) => { try { const arr = []; snap.forEach(d => arr.push(d.data())); arr.forEach(p => { p.pontos = p.pontos || 0; p.vitorias = p.vitorias || 0; p.derrotas = p.derrotas || 0; p.mvp = p.mvp || 0; p.ace = p.ace || 0; p.bagre = p.bagre || 0; }); window.rankingData = arr; // Carregar matches para calcular estatísticas de lanes const matchesSnap = await getDocs(collection(db, "matches")); const matches = []; matchesSnap.forEach(d => matches.push(d.data())); window.allMatches = matches; if (typeof calculatePlayerLaneStats === 'function') { calculatePlayerLaneStats(matches, arr); } else { console.error("calculatePlayerLaneStats não está definida"); } if (typeof renderRanking === 'function') { renderRanking(); } // Atualizar tabela de elos // Primeiro calcular elos sem filtro para determinar lane principal if (typeof calcularEloCompleto === 'function') { const elosCalculados = arr.map(player => calcularEloCompleto(player)); elosCalculados.sort((a, b) => { const nivelA = ELOS[a.elo]?.nivel || 0; const nivelB = ELOS[b.elo]?.nivel || 0; if (nivelB !== nivelA) return nivelB - nivelA; if (a.divisao !== b.divisao) return a.divisao - b.divisao; return (b.pdls || 0) - (a.pdls || 0); }); // Armazenar dados dos players para uso no filtro window.rankingData = arr; const eloFilter = document.getElementById('eloFilter'); if (typeof loadEloTable === 'function') { loadEloTable(elosCalculados, eloFilter?.value || 'all'); } else { console.error("loadEloTable não está definida"); } } else { console.error("calcularEloCompleto não está definida"); // Armazenar dados dos players mesmo se não conseguir calcular elos window.rankingData = arr; } } catch (error) { console.error("Erro no listener de players:", error); } }, (error) => { console.error("Erro ao configurar listener de players:", error); }); } else { // Firebase não está pronto ainda, tentar novamente setTimeout(setupPlayersListener, 500); } }// Configurar listener quando Firebase estiver pronto setupPlayersListener();// Verificar parâmetros de URL window.addEventListener('load', processUrlParams);// Atualizar estatísticas periodicamente setInterval(updateStats, 30000);// Fechar modais ao clicar fora const voteModal = document.getElementById('voteModal'); if (voteModal) { voteModal.addEventListener('click', (e) => { if (e.target.id === 'voteModal') { e.target.classList.remove('show'); } }); }/* ====== SISTEMA DE UPLOAD DE AVATAR DO RANKING ====== */// Event listener para clicar no avatar document.addEventListener('click', (e) => { const avatarEl = e.target.closest('.rank-avatar[data-nick]'); if (avatarEl && isAdmin) { const nickname = avatarEl.dataset.nick; if (nickname) { openAvatarUploadModal(nickname); } } });function openAvatarUploadModal(nickname) { const modal = document.getElementById('avatarUploadModal'); const playerNameEl = document.getElementById('avatarPlayerName'); const previewEl = document.getElementById('avatarPreview'); const letterEl = document.getElementById('avatarLetter'); const fileInput = document.getElementById('avatarFileInput'); const saveBtn = document.getElementById('saveAvatarBtn'); if (!modal) return; // Buscar dados do jogador const player = window.rankingData?.find(p => p.nickname === nickname); playerNameEl.textContent = nickname; letterEl.textContent = nickname.charAt(0).toUpperCase(); // Mostrar avatar atual se existir if (player?.avatarUrl) { previewEl.innerHTML = ``; } else { previewEl.innerHTML = `${nickname.charAt(0).toUpperCase()}`; } // Resetar file input fileInput.value = ''; saveBtn.disabled = true; // Preview da nova imagem fileInput.onchange = (e) => { const file = e.target.files[0]; if (file) { if (!file.type.startsWith('image/')) { showToast('Por favor, selecione um arquivo de imagem!', 'error'); return; } const reader = new FileReader(); reader.onload = (e) => { previewEl.innerHTML = ``; saveBtn.disabled = false; }; reader.readAsDataURL(file); } }; // Mostrar modal modal.style.display = 'flex'; // Configurar botões document.getElementById('cancelAvatarBtn').onclick = () => { modal.style.display = 'none'; }; document.getElementById('removeAvatarBtn').onclick = async () => { if (!confirm(`Remover avatar de ${nickname}?`)) return; try { const playerRef = doc(db, "players", nickname); await updateDoc(playerRef, { avatarUrl: null }); showToast('Avatar removido com sucesso!', 'success'); modal.style.display = 'none'; // Recarregar ranking if (typeof loadInitialRanking === 'function') { loadInitialRanking(); } } catch (error) { console.error('Erro ao remover avatar:', error); showToast('Erro ao remover avatar!', 'error'); } }; document.getElementById('saveAvatarBtn').onclick = async () => { const file = fileInput.files[0]; if (!file) { showToast('Selecione uma imagem!', 'error'); return; } saveBtn.disabled = true; saveBtn.textContent = 'Salvando...'; try { // Converter para base64 const reader = new FileReader(); reader.onload = async (e) => { const base64Image = e.target.result; // Salvar no Firebase const playerRef = doc(db, "players", nickname); await updateDoc(playerRef, { avatarUrl: base64Image }); showToast('Avatar atualizado com sucesso!', 'success'); modal.style.display = 'none'; // Recarregar ranking if (typeof loadInitialRanking === 'function') { loadInitialRanking(); } }; reader.readAsDataURL(file); } catch (error) { console.error('Erro ao salvar avatar:', error); showToast('Erro ao salvar avatar!', 'error'); saveBtn.disabled = false; saveBtn.textContent = 'Salvar Avatar'; } }; }// Fechar modal ao clicar fora document.getElementById('avatarUploadModal')?.addEventListener('click', (e) => { if (e.target.id === 'avatarUploadModal') { e.target.style.display = 'none'; } });// Limpar monitoramento ao fechar window.addEventListener('beforeunload', () => { stopLiveVotingUpdates(); });// Atualizar variáveis globais (já inicializadas acima) window.duos = duos; window.isAdmin = isAdmin;// Log function function log(message) { const logElement = document.getElementById('log'); if (logElement) { logElement.textContent = message + '\n' + logElement.textContent; } }