// init - game view (map) const GRID_SIZE = 200; // Grid size in pixels var mapScale = 1.0; var mapOffsetX = 0.0; var mapOffsetY = 0.0; var draggedToken = { token: null, offX: 0, offY: 0 }; var draggedDiv = { div: null, offX: 0, offY: 0 }; function init() { let view = document.getElementById('game-view'); view.onwheel = onGameViewScroll; view.onmousemove = onGameMouseMove; view.onmouseup = onGameMouseUp; view.oncontextmenu = () => false; // allow sending chat message using enter (and shift-enter for new line) document.getElementById('newmsg-content').onkeypress = (e) => { if(e.key == "Enter" && !e.shiftKey) { sendChatMessage(); return false; } } document.getElementById('login-username').onkeypress = (e) => { if(e.key == 'Enter') { document.getElementById('login-pass').focus(); return false; } } document.getElementById('login-pass').onkeypress = (e) => { if(e.key == 'Enter') { onLoginClick(); return false; } } // focus on the username field for the sake of just pressing enter multiple times document.getElementById('login-username').focus(); document.body.onclick = (e) => { document.getElementById('msg-context-menu').style.display = 'none'; } document.body.onmousemove = onMoveableDivDrag; document.body.onmouseup = onMoveableDivMouseUp; // TODO: Remove when done dev-ing tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' }); } tavern.onlogin = (s) => { if(s) { let login = document.getElementById('login-screen'); let game = document.getElementById('game'); login.style.display = 'none'; game.style.display = 'flex'; // get last 50 msgs (i think that is enough for now) when we get in tavern.get_last_msgs(50); tavern.get_tokens(); } else { alert("Invalid username or password!"); } } tavern.onmessage = (m) => { console.log(m); let msg = document.createElement('div'); msg.className = 'chat-message'; // #abusing_style_order_as_both_id_variable_and_forcing_chronological_order msg.style.order = m.id; msg.innerHTML = `

${m.character ?? ''} (${m.source})


${m.text.replace('\n', '\n
\n')}

` msg.oncontextmenu = (e) => { if(e.shiftKey) { return true; } let cm = document.getElementById('msg-context-menu'); cm.style.display = 'flex'; cm.style.top = `${e.pageY}px`; cm.style.left = `${e.pageX}px`; return false; } if(m.actions) { let holder = document.createElement('div'); holder.style.display = 'flex'; holder.style.flexWrap = 'wrap'; msg.appendChild(holder); for (const act of m.actions) { let button = document.createElement('button'); button.innerText = act.display_name ?? act.name; button.action = act; button.onclick = () => console.log(button.action); button.style.margin = '2px'; button.onclick = () => openRollsPopup(act); holder.appendChild(button); } } let history = document.getElementById('chat-history'); // this is to force update everytime we get a duplicate msg to allow msg editing (yay) let exists = Array.from(history.children).filter(e => e.style.order == m.id)[0]; if(exists) { history.removeChild(exists); } history.appendChild(msg); msg.scrollIntoView(); } tavern.onspawntoken = (t) => { console.log(t); let map = document.getElementById('map'); let token = document.createElement('div'); token.className = 'token token-transition'; token.style.top = `${t.y * GRID_SIZE}px`; token.style.left = `${t.x * GRID_SIZE}px`; token.token_id = t.token_id; token.innerHTML = ` ` token.onmousedown = (e) => { token.classList.remove('token-transition'); draggedToken.token = token; draggedToken.offX = ((e.clientX - mapOffsetX) / mapScale) - parseInt(token.style.left); draggedToken.offY = ((e.clientY - mapOffsetY) / mapScale) - parseInt(token.style.top); token.children[0].style.cursor = 'grabbing'; } map.appendChild(token); } tavern.onmovetoken = (m) => { let token = Array.from(document.getElementsByClassName('token')).filter(t => t.token_id == m.token_id)[0] if(token) { token.style.top = `${m.y * GRID_SIZE}px`; token.style.left = `${m.x * GRID_SIZE}px`; } } function onLoginClick() { let username = document.getElementById('login-username').value; let pass = document.getElementById('login-pass').value; if(username == 'test') { // TODO: Remove this for when im done dev-ing with this file tavern.onlogin(true); } tavern.login(username, pass); } function onGameViewScroll(event) { let map = document.getElementById('map'); mapScale += (event.wheelDelta / 1800.0); if(mapScale < 0.1) { mapScale = 0.1; } map.style.transform = `scale(${mapScale})`; } function onGameMouseMove(event) { if(event.buttons == 2) { // right click let map = document.getElementById('map'); let mult = event.ctrlKey ? 2.0 : 1.0; mapOffsetX += event.movementX * mult; mapOffsetY += event.movementY * mult; map.style.left = `${mapOffsetX}px`; map.style.top = `${mapOffsetY}px`; } else if(draggedToken.token != null && event.buttons == 1) { let top = (event.clientY - mapOffsetY) / mapScale - draggedToken.offY; let left = (event.clientX - mapOffsetX) / mapScale - draggedToken.offX; draggedToken.token.style.top = `${top}px`; draggedToken.token.style.left = `${left}px`; } } function onGameMouseUp() { if(draggedToken.token != null) { let t = draggedToken.token; let x = Math.floor(0.5 + parseInt(t.style.left) / GRID_SIZE); let y = Math.floor(0.5 + parseInt(t.style.top) / GRID_SIZE); let id = t.token_id; t.classList.add('token-transition'); t.children[0].style.cursor = ''; tavern.move_token(id, x, y); draggedToken.token = null; } } function sendChatMessage() { let tb = document.getElementById('newmsg-content'); // get the msg and reset the textarea let text = tb.value; tb.value = ''; tavern.simple_msg(text); } function openRollsPopup(action) { let holder = document.getElementById('dice-roll-holder'); holder.innerHTML = ''; // remove all holder children holder.action = action; if(action.rolls != undefined && Array.isArray(action.rolls)) { for (const r of action.rolls) { // name (extra) (dice_amount)d(dice_type) + constant | enabled console.log(r); let row = document.createElement('div'); row.style.display = 'flex'; row.roll = r; row.innerHTML = `

${r.name} ${r.extra != null ? '(' + r.extra + ')' : ''}

${r.dice_amount}d${r.dice_type} + ${r.constant}

`; holder.appendChild(row); } } document.getElementById('dice-roll-title').innerText = action.display_name ?? action.name; document.getElementById('dice-roll-popup').style.display = 'flex'; } function rollPopup() { // TODO: Maybe let the server roll the dice? // first - hide the popup document.getElementById('dice-roll-popup').style.display = 'none'; // get the holder and start rolling dice let rolls = []; let holder = document.getElementById('dice-roll-holder'); for(const h of holder.children) { if(h.roll && h.children[2].checked) { let roll = { name: h.roll.name, extra: h.roll.extra }; let msg = ''; let sum = 0; for (let i = 0; i < h.roll.dice_amount; i++) { // Math.random gives a value in [0, 1), so we need to add 1 at the end let roll = Math.floor(Math.random() * h.roll.dice_type) + 1; sum += roll; msg += `${roll}`; if(i != h.roll.dice_amount - 1 || h.roll.constant != 0) { msg += ' + '; } } if(h.roll.constant != 0) { sum += h.roll.constant; msg += `${h.roll.constant}`; } roll.result = sum; roll.result_text = msg; rolls.push(roll); } } console.log(rolls); tavern.action_result(holder.action.name, 'Louise', [], rolls); } function onMoveableDivMouseDown(e, id) { if(e.buttons == 1) { let div = document.getElementById(id); let rect = div.getBoundingClientRect(); draggedDiv.div = div; draggedDiv.offX = e.clientX - rect.x; draggedDiv.offY = e.clientY - rect.y; } } function onMoveableDivDrag(e) { if(draggedDiv.div) { draggedDiv.div.style.right = ''; draggedDiv.div.style.top = `${e.clientY - draggedDiv.offY}px`; draggedDiv.div.style.left = `${e.clientX - draggedDiv.offX}px`; } } function onMoveableDivMouseUp(e, id) { draggedDiv.div = null; } function showHideDiv(id) { let div = document.getElementById(id); div.style.display = div.style.display == 'none' ? 'flex' : 'none'; }