|
|
|
@@ -24,7 +24,7 @@ let playerTimerRemaining=0,playerTimerInterval=null;
|
|
|
|
const saveMod=(id,s)=>localStorage.setItem('mod',JSON.stringify({id,s}));
|
|
|
|
const saveMod=(id,s)=>localStorage.setItem('mod',JSON.stringify({id,s}));
|
|
|
|
const loadMod=()=>{try{return JSON.parse(localStorage.getItem('mod')||'null');}catch{return null;}};
|
|
|
|
const loadMod=()=>{try{return JSON.parse(localStorage.getItem('mod')||'null');}catch{return null;}};
|
|
|
|
const clearMod=()=>{localStorage.removeItem('mod');document.getElementById('rejoin-bar').style.display='none';};
|
|
|
|
const clearMod=()=>{localStorage.removeItem('mod');document.getElementById('rejoin-bar').style.display='none';};
|
|
|
|
const savePlay=(rid,pid,name)=>localStorage.setItem('play',JSON.stringify({rid,pid,name}));
|
|
|
|
const savePlay=(rid,pid)=>localStorage.setItem('play',JSON.stringify({rid,pid}));
|
|
|
|
const loadPlay=()=>{try{return JSON.parse(localStorage.getItem('play')||'null');}catch{return null;}};
|
|
|
|
const loadPlay=()=>{try{return JSON.parse(localStorage.getItem('play')||'null');}catch{return null;}};
|
|
|
|
|
|
|
|
|
|
|
|
// ══════════════════════════════════════════════════════
|
|
|
|
// ══════════════════════════════════════════════════════
|
|
|
|
@@ -45,7 +45,7 @@ function schedReconn(){
|
|
|
|
const d=Math.min(8000,500*Math.pow(1.5,reconnAttempts++));
|
|
|
|
const d=Math.min(8000,500*Math.pow(1.5,reconnAttempts++));
|
|
|
|
reconnTimer=setTimeout(()=>{
|
|
|
|
reconnTimer=setTimeout(()=>{
|
|
|
|
if(role==='mod'){const m=loadMod();if(m)connect(()=>ws_send({type:'mod_rejoin',roomId:m.id,modSecret:m.s}));}
|
|
|
|
if(role==='mod'){const m=loadMod();if(m)connect(()=>ws_send({type:'mod_rejoin',roomId:m.id,modSecret:m.s}));}
|
|
|
|
else if(role==='player'&&myId){const p=loadPlay();if(p)connect(()=>ws_send({type:'join_room',roomId:p.rid,playerName:p.name,playerId:p.pid}));}
|
|
|
|
else if(role==='player'&&myId){const p=loadPlay();if(p)connect(()=>ws_send({type:'join_room',roomId:p.rid,playerId:p.pid}));}
|
|
|
|
else connect(null);
|
|
|
|
else connect(null);
|
|
|
|
},d);
|
|
|
|
},d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -68,7 +68,7 @@ function handle(msg){
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'joined':
|
|
|
|
case 'joined':
|
|
|
|
myId=msg.playerId;room=msg.room;role='player';
|
|
|
|
myId=msg.playerId;room=msg.room;role='player';
|
|
|
|
savePlay(room.id,myId,document.getElementById('ji-name').value||loadPlay()?.name||'');
|
|
|
|
savePlay(room.id,myId);
|
|
|
|
showScr('s-player');renderPlayer();
|
|
|
|
showScr('s-player');renderPlayer();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'room_update':
|
|
|
|
case 'room_update':
|
|
|
|
@@ -171,10 +171,9 @@ function setConn(on){
|
|
|
|
function goSetup(){renderSetupTeamNames();showScr('s-setup');}
|
|
|
|
function goSetup(){renderSetupTeamNames();showScr('s-setup');}
|
|
|
|
function joinRoom(){
|
|
|
|
function joinRoom(){
|
|
|
|
const code=document.getElementById('ji-code').value.trim().toUpperCase();
|
|
|
|
const code=document.getElementById('ji-code').value.trim().toUpperCase();
|
|
|
|
const name=document.getElementById('ji-name').value.trim();
|
|
|
|
|
|
|
|
if(!code){toast('Enter room code','err');return;}
|
|
|
|
if(!code){toast('Enter room code','err');return;}
|
|
|
|
if(!name){toast('Enter your name','err');return;}
|
|
|
|
const autoId=Math.floor(Math.random()*99999999)+1;
|
|
|
|
connect(()=>ws_send({type:'join_room',roomId:code,playerName:name}));
|
|
|
|
connect(()=>ws_send({type:'join_room',roomId:code,playerId:autoId}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function openRejoin(){
|
|
|
|
function openRejoin(){
|
|
|
|
const m=loadMod();if(!m)return;
|
|
|
|
const m=loadMod();if(!m)return;
|
|
|
|
@@ -411,7 +410,7 @@ function renderModPlayerList(){
|
|
|
|
row.className='pl-row'+(p.isConnected?'':' offline');
|
|
|
|
row.className='pl-row'+(p.isConnected?'':' offline');
|
|
|
|
row.innerHTML=`
|
|
|
|
row.innerHTML=`
|
|
|
|
<div class="pl-info" style="flex:1;min-width:0;">
|
|
|
|
<div class="pl-info" style="flex:1;min-width:0;">
|
|
|
|
<div class="pl-name">${esc(p.name)} ${p.isConnected?'':`<span class="tag tag-red" style="font-size:9px;padding:2px 6px;">OFFLINE</span>`}</div>
|
|
|
|
<div class="pl-name">${esc(p.name)} <span class="tag tag-y" style="font-size:12px;padding:3px 8px;background:rgba(249,226,175,0.15);color:var(--yellow);border:none;">#${p.playerId}</span> ${p.isConnected?'':`<span class="tag tag-red" style="font-size:9px;padding:2px 6px;">OFFLINE</span>`}</div>
|
|
|
|
${teamName?`<div class="pl-meta" style="color:${color}">${esc(teamName)}</div>`:'<div class="pl-meta">No team</div>'}
|
|
|
|
${teamName?`<div class="pl-meta" style="color:${color}">${esc(teamName)}</div>`:'<div class="pl-meta">No team</div>'}
|
|
|
|
${teamSel}
|
|
|
|
${teamSel}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@@ -437,7 +436,7 @@ function renderModTeams(){
|
|
|
|
card.innerHTML=`
|
|
|
|
card.innerHTML=`
|
|
|
|
<div class="tc-n" style="color:${color}">${esc(name)}</div>
|
|
|
|
<div class="tc-n" style="color:${color}">${esc(name)}</div>
|
|
|
|
<div class="tc-c" style="color:${color}">${members.length}</div>
|
|
|
|
<div class="tc-c" style="color:${color}">${members.length}</div>
|
|
|
|
<div class="tc-m">${members.map(p=>esc(p.name)).join('<br>')||'—'}</div>
|
|
|
|
<div class="tc-m">${members.map(p=>`#${p.playerId}`).join('<br>')||'—'}</div>
|
|
|
|
`;
|
|
|
|
`;
|
|
|
|
grid.appendChild(card);
|
|
|
|
grid.appendChild(card);
|
|
|
|
if(typeof gsap!=='undefined'){
|
|
|
|
if(typeof gsap!=='undefined'){
|
|
|
|
@@ -527,7 +526,7 @@ function renderPlayer(){
|
|
|
|
if(!room)return;
|
|
|
|
if(!room)return;
|
|
|
|
document.getElementById('p-code').textContent=room.id;
|
|
|
|
document.getElementById('p-code').textContent=room.id;
|
|
|
|
const me=room.players.find(p=>p.id===myId);
|
|
|
|
const me=room.players.find(p=>p.id===myId);
|
|
|
|
document.getElementById('p-namelbl').textContent=me?.name??'';
|
|
|
|
document.getElementById('p-namelbl').textContent=`#${me?.playerId||'?'}`;
|
|
|
|
renderTeamPicker();
|
|
|
|
renderTeamPicker();
|
|
|
|
renderPlayerBuzzer();
|
|
|
|
renderPlayerBuzzer();
|
|
|
|
renderRoster();
|
|
|
|
renderRoster();
|
|
|
|
@@ -626,7 +625,7 @@ function renderRoster(){
|
|
|
|
row.className='roster-row'+(isMe?' roster-me':'');
|
|
|
|
row.className='roster-row'+(isMe?' roster-me':'');
|
|
|
|
row.innerHTML=`
|
|
|
|
row.innerHTML=`
|
|
|
|
<div class="roster-dot" style="background:${p.isConnected?(isMe?'var(--g)':color):'var(--border2)'}"></div>
|
|
|
|
<div class="roster-dot" style="background:${p.isConnected?(isMe?'var(--g)':color):'var(--border2)'}"></div>
|
|
|
|
<div style="flex:1">${esc(p.name)}${isMe?' <span style="font-size:11px;color:var(--dim);letter-spacing:1px;">(YOU)</span>':''}</div>
|
|
|
|
<div style="flex:1">${esc(p.name)} ${isMe?`<span style="font-size:11px;color:var(--dim);letter-spacing:1px;">(#${p.playerId}) (YOU)</span>`:''}</div>
|
|
|
|
${teamName?`<div style="font-size:12px;color:${color};letter-spacing:0.5px;">${esc(teamName)}</div>`:''}
|
|
|
|
${teamName?`<div style="font-size:12px;color:${color};letter-spacing:0.5px;">${esc(teamName)}</div>`:''}
|
|
|
|
`;
|
|
|
|
`;
|
|
|
|
el.appendChild(row);
|
|
|
|
el.appendChild(row);
|
|
|
|
@@ -638,10 +637,11 @@ function addFeed(evt){
|
|
|
|
const isFirst=evt.buzzOrder?.[0]===evt.playerId;
|
|
|
|
const isFirst=evt.buzzOrder?.[0]===evt.playerId;
|
|
|
|
const color=evt.teamIndex!==null?teamColor(evt.teamIndex):'var(--g)';
|
|
|
|
const color=evt.teamIndex!==null?teamColor(evt.teamIndex):'var(--g)';
|
|
|
|
const teamStr=(room?.settings.mode==='teams'&&evt.teamIndex!==null)?` [${esc(room.settings.teamNames[evt.teamIndex]??'')}]`:'';
|
|
|
|
const teamStr=(room?.settings.mode==='teams'&&evt.teamIndex!==null)?` [${esc(room.settings.teamNames[evt.teamIndex]??'')}]`:'';
|
|
|
|
|
|
|
|
const playerStr=`#${evt.playerId}`;
|
|
|
|
const div=document.createElement('div');
|
|
|
|
const div=document.createElement('div');
|
|
|
|
div.className='feed-entry'+(isFirst?' first':'');
|
|
|
|
div.className='feed-entry'+(isFirst?' first':'');
|
|
|
|
div.style.borderLeftColor=isFirst?'var(--yellow)':color;
|
|
|
|
div.style.borderLeftColor=isFirst?'var(--yellow)':color;
|
|
|
|
div.innerHTML=`<strong>${esc(evt.playerName)}</strong>${teamStr} buzzed${isFirst?' <span style="color:var(--yellow);font-weight:700;"> — FIRST!</span>':''}`;
|
|
|
|
div.innerHTML=`<strong>${playerStr}</strong>${teamStr} buzzed${isFirst?' <span style="color:var(--yellow);font-weight:700;"> — FIRST!</span>':''}`;
|
|
|
|
feed.prepend(div);
|
|
|
|
feed.prepend(div);
|
|
|
|
if(typeof gsap!=='undefined'){
|
|
|
|
if(typeof gsap!=='undefined'){
|
|
|
|
gsap.fromTo(div,
|
|
|
|
gsap.fromTo(div,
|
|
|
|
|