let match_active = false; let prompt_disable = false; let match_state, user_rem, boat_rem; let oi_timeout; let delay_ms = 1000; const POINT_CLASSES = [180, 140, 100, 60, 40, 20, 1, 0]; function stcall(f, ret_type, arg_types, args) { return Module.ccall(f, ret_type, arg_types ? ['number'].concat(arg_types) : ['number'], args ? [match_state].concat(args) : [match_state]); } function initMatch() { stcall('free_match'); updateDelay(delay_ms); match_state = stcall('start_match', 'number'); match_active = true; document.getElementById('user-rem').className = 'active'; document.getElementById('match').textContent = ''; promptSuggStr(""); stcall('draw_match'); } function oi() { document.getElementById('oi').textContent = 'oi!'; oi_timeout = setTimeout(function() { oi_timeout = null; clearOi() }, 3000); } function clearOi() { document.getElementById('oi').textContent = ''; if (oi_timeout) { clearTimeout(oi_timeout); oi_timeout = null; } } function updateUserRem(rem) { user_rem = document.getElementById('user-rem').textContent = rem; } function updateBoatRem(rem) { boat_rem = document.getElementById('boat-rem').textContent = rem; } function promptMsg(p) { document.getElementById('prompt-msg').textContent = UTF8ToString(p); } function promptMsgStr(str) { document.getElementById('prompt-msg').textContent = str; } function promptSugg(p) { document.getElementById('prompt-sugg').textContent = UTF8ToString(p); } function promptSuggStr(str) { document.getElementById('prompt-sugg').textContent = str; } function promptUpdateRem() { let elem = document.getElementById('user-rem'); let pts = document.getElementById('prompt').textContent; if (pts) { let nrem = user_rem - pts; let nrem_str = nrem < 0 || nrem == 1 ? "BUST" : nrem; elem.textContent = `${user_rem} » ${nrem_str}`; } else { elem.textContent = user_rem; } } function boatTempRem(pts, str) { let elem = document.getElementById('boat-rem'); let nrem = boat_rem - pts; let nrem_str = nrem < 0 || nrem == 1 ? "BUST" : nrem; elem.textContent = `${nrem_str} « ${boat_rem}`; document.getElementById('prompt').textContent = pts; promptSuggStr(str); } function promptAppend(val) { if (!match_active || prompt_disable) return; clearOi(); let elem = document.getElementById('prompt'); if (elem.textContent.length < 3) { elem.textContent += val; promptUpdateRem(); } } function promptClear() { if (!match_active || prompt_disable) return; clearOi(); document.getElementById('prompt').textContent = ''; promptUpdateRem(); } function promptBackspace() { if (!match_active || prompt_disable) return; clearOi(); let elem = document.getElementById('prompt'); elem.textContent = elem.textContent.slice(0, -1); promptUpdateRem(); } function setBoatActive() { document.getElementById('user-rem').className = ''; document.getElementById('boat-rem').className = 'active'; promptMsgStr("Bot is throwing…"); prompt_disable = true; } function setUserActive() { document.getElementById('user-rem').className = 'active'; document.getElementById('boat-rem').className = ''; prompt_disable = false; } function promptSubmit() { clearOi(); if (prompt_disable) return; if (!match_active) { initMatch(); return; } let elem = document.getElementById('prompt'); let p_user = elem.textContent; if (!p_user) return; promptClear(); if (!stcall('user_visit', 'number', ['number'], [p_user])) { oi(); return; } elem = document.getElementById('match'); elem.textContent = ''; stcall('draw_match'); if (!stcall('is_match_over', 'number')) { setBoatActive(); stcall('boat_visit', 'number'); } } function boatVisitRes(rem, n, p1, p2, p3, ptr1, ptr2, ptr3) { // cannot convert in timeout func because strings are freed in c func let s1 = UTF8ToString(ptr1); let s2 = UTF8ToString(ptr2); let s3 = UTF8ToString(ptr3); if (delay_ms == 0) { updateBoatRem(rem); document.getElementById('match').textContent = ''; stcall('draw_match'); setUserActive(); } else { // backup to restore after bot is done let user_sugg = document.getElementById('prompt-sugg').textContent; promptSuggStr(''); setTimeout(function() { boatTempRem(p1, s1); }, delay_ms); if (n > 1) { setTimeout(function() { boatTempRem(p1 + p2, `${s1}-${s2}`); }, delay_ms * 2); } if (n > 2) { setTimeout(function() { boatTempRem(p1 + p2 + p3, `${s1}-${s2}-${s3}`); }, delay_ms * 3); } setTimeout(function() { updateBoatRem(rem); document.getElementById('prompt').textContent = ''; document.getElementById('match').textContent = ''; promptSuggStr(user_sugg); stcall('draw_match'); setUserActive(); }, delay_ms * (n + 1)); } } function matchOver() { match_active = false; promptSuggStr("Press OK to play again."); document.getElementById('user-rem').className = ''; } function drawVisitNames(n1, n2) { let elem = document.getElementById('match'); for (let [k, v] of Object.entries({ 'user-name': n1, 'boat-name': n2 })) { let div = document.createElement('div'); div.className = k; div.textContent = UTF8ToString(v); elem.append(div); } } function drawVisit(visit_no, u_pts, u_rem, b_pts, b_rem, b_darts) { let elem = document.getElementById('match'); for (let [i, v] of [visit_no, u_pts, u_rem, b_rem, b_pts, b_darts].entries()) { let div = document.createElement('div'); let vv = div.textContent = UTF8ToString(v); if (i == 0) { div.className = 'visit-no'; } else if (i == 1 || i == 4) { div.className = `p${POINT_CLASSES.find(x => x <= vv)}`; } else if (i == 5) { div.className = 'darts'; } elem.append(div); } elem.scrollTop = elem.scrollHeight; } function stdevChanged(val) { Module.ccall('change_stdev', null, ['number', 'number'], [val, val]); } function updateStdev(val) { document.getElementById('stdev').value = val; } function updateDelay(val) { document.getElementById('delay').value = val; } function delayChanged(val) { delay_ms = val; } function processKey(data) { if (data.altKey || data.ctrlKey || data.metaKey || data.target.type == 'text') return; let key = data.key; if (isFinite(key)) promptAppend(key); else if (key == 'Enter') promptSubmit(); else if (key == 'Backspace') promptBackspace(); } function modal(id) { document.getElementById(id).style.display = 'block'; } window.onclick = function(e) { if (e.target.classList.contains('modal')) e.target.style.display = 'none'; } document.addEventListener('keydown', processKey);