const SCALE = 0.5 const SPACE = 100 * SCALE; const RADIUS = 30 * SCALE; const WIDTH = 450; const HEIGHT = 450; const state = { app: {}, camera: {}, map_layer: {}, puppets_layer: {}, puppets: {}, map: {}, main: null, playing: false, history: [], p_history: [], turn: [], control: {}, } function selectMap(event) { ws.send(window.location.hash.substr(1)); } function listenWS_selectMap(event) { const { opcode, message } = JSON.parse(event.data); switch (opcode) { case 'INCORRECT_MAP': console.log('Wrong URL'); break; case 'CORRECT_MAP': console.log("We are in!") setupGame(); break; default: console.log('Anomaly happened') } } function setupGame() { state.app = new PIXI.Application({ width: WIDTH, height: HEIGHT, antialias: true, resolution: 1, }); state.camera = new PIXI.Container(); state.map_layer = new PIXI.Container(); state.puppets_layer = new PIXI.Container(); state.app.stage.addChild(state.camera); state.camera.addChild(state.map_layer); state.camera.addChild(state.puppets_layer); document.getElementById('scene').appendChild(state.app.view); document.getElementById('move_left').onclick = () => { let x = state.puppets[state.main].position.x / SPACE - 1, y = state.puppets[state.main].position.y / SPACE; askMoveTo(x, y); newSelectedControl('move_left'); }; document.getElementById('move_right').onclick = () => { let x = state.puppets[state.main].position.x / SPACE + 1, y = state.puppets[state.main].position.y / SPACE; askMoveTo(x, y); newSelectedControl('move_right'); }; document.getElementById('move_up').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE - 1; askMoveTo(x, y); newSelectedControl('move_up'); }; document.getElementById('move_down').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE + 1; askMoveTo(x, y); newSelectedControl('move_down'); }; document.getElementById('attack_left').onclick = () => { let x = state.puppets[state.main].position.x / SPACE - 1, y = state.puppets[state.main].position.y / SPACE; askAttackTo(x, y); newSelectedControl('attack_left'); }; document.getElementById('attack_right').onclick = () => { let x = state.puppets[state.main].position.x / SPACE + 1, y = state.puppets[state.main].position.y / SPACE; askAttackTo(x, y); newSelectedControl('attack_right'); }; document.getElementById('attack_up').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE - 1; askAttackTo(x, y); newSelectedControl('attack_up'); }; document.getElementById('attack_down').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE + 1; askAttackTo(x, y); newSelectedControl('attack_down'); }; document.getElementById('defend_left').onclick = () => { let x = state.puppets[state.main].position.x / SPACE - 1, y = state.puppets[state.main].position.y / SPACE; askDefendTo(x, y); newSelectedControl('defend_left'); }; document.getElementById('defend_right').onclick = () => { let x = state.puppets[state.main].position.x / SPACE + 1, y = state.puppets[state.main].position.y / SPACE; askDefendTo(x, y); newSelectedControl('defend_right'); }; document.getElementById('defend_up').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE - 1; askDefendTo(x, y); newSelectedControl('defend_up'); }; document.getElementById('defend_down').onclick = () => { let x = state.puppets[state.main].position.x / SPACE, y = state.puppets[state.main].position.y / SPACE + 1; askDefendTo(x, y); newSelectedControl('defend_down'); }; document.getElementById('surrender').onclick = () => { ws.send(JSON.stringify({ opcode: 'SURRENDER', arguments: {} })); newSelectedControl('surrender'); }; document.getElementById('wait').onclick = () => { ws.send(JSON.stringify({ opcode: 'WAIT', arguments: {} })); newSelectedControl('wait'); }; ws.onmessage = listenWS_playGame; ws.send('ready to go, boss'); } function askMoveTo(x, y) { if (0 <= x && 0 <= y && x < state.map.width && y < state.map.height) { ws.send(JSON.stringify({ opcode: "MOVE", arguments: { x: x, y: y } })); } } function askAttackTo(x, y) { ws.send(JSON.stringify({ opcode: "ATTACK", arguments: { x: x, y: y } })); } function askDefendTo(x, y) { ws.send(JSON.stringify({ opcode: "DEFEND", arguments: { x: x, y: y } })); } function drawArena(lines, rows) { for (i = 0; i < lines; i++) { const line = new PIXI.Graphics(); let color = 0xcc6600; if (i % 2) { color = 0xbb7711; } line.position.set(0, i * SPACE); line.lineStyle(RADIUS, color) .moveTo(0, 0) .lineTo(SPACE * (rows - 1), 0); state.map_layer.addChild(line); } for (i = 0; i < rows; i++) { const line = new PIXI.Graphics(); let color = 0xcc6600; if (i % 2) { color = 0xbb7711; } line.position.set(i * SPACE, 0); line.lineStyle(RADIUS, color) .moveTo(0, 0) .lineTo(0, SPACE * (lines - 1)); state.map_layer.addChild(line); } } function addNewPuppet(pk, puppet) { if (puppet.plays) { const puppet_layer = new PIXI.Graphics(); puppet_layer.position.set(puppet.x * SPACE, puppet.y * SPACE); puppet_layer.puppet_name = puppet.name; puppet_layer.puppet_color = puppet.color; puppet_layer.puppet_stamina = puppet.stamina; puppet_layer.puppet_anger = puppet.anger; state.puppets[pk] = puppet_layer; state.puppets_layer.addChild(puppet_layer); drawPuppet(pk, puppet.color); if (state.main == pk) { updateCamera(); updateHUD(); } listPuppets(); } } function drawPuppet(pk, color) { const layer = state.puppets[pk]; layer.beginFill(0xcecece); layer.drawCircle(0, 0, RADIUS + 2); layer.endFill(); layer.beginFill(color); layer.drawCircle(0, 0, RADIUS); layer.endFill(); } function listPuppets() { const elem = document.getElementById('players'); let txt = '', cpt = 0; Object.keys(state.puppets).filter(Boolean).forEach((pk) => { if (state.puppets[pk]) { cpt += 1; txt += '
  • ' + puppetName(pk) + '
  • '; } }); elem.innerHTML = '
  • ' + cpt + ' joueurs
  • ' + txt } function movePuppet(cmd) { let pk = cmd.puppet, x = cmd.x, y = cmd.y; if (state.puppets[pk]) { state.puppets[pk].position.set(x * SPACE, y * SPACE); if (state.main == pk) { updateCamera(); } } } function removePuppet(pk) { state.puppets_layer.removeChild(state.puppets[pk]); state.puppets[pk] = null; listPuppets(); } function updateHUD(duration) { const main = state.puppets[state.main]; if (main) { document.getElementById('stamina').style.width = main.puppet_stamina + '%'; document.getElementById('anger').style.width = main.puppet_anger + '%'; } if (duration) { document.getElementById('time').style.transition = '0s'; document.getElementById('time').style.width = '2%'; setTimeout(() => { document.getElementById('time').style.transition = 'width ' + (duration - 50) + 'ms'; document.getElementById('time').style.width = '100%'; }, 50); } } function updateCamera() { if (state.main) { const main = state.puppets[state.main]; let x = main.position.x, y = main.position.y; state.camera.position.set((WIDTH / 2) - x, (HEIGHT / 2) - y); } } function listenWS_playGame(event) { const { opcode, message } = JSON.parse(event.data); console.log(opcode); switch (opcode) { case 'BEGIN_TURN': state.history.push([]); break; case 'SELECT_PHASE': if (state.playing) { document.getElementById('lobby').style.display = 'none'; document.getElementById('control').style.display = 'block'; } updateHUD(message.duration); updateHistory(); break; case 'PUPPET_CHOICES': if (state.main == message.puppet) { enableControl(message.up, message.right, message.down, message.left); } break; case 'RESOLVE_PHASE': disableControl(); document.getElementById('p_history').innerHTML = ''; break; case 'INSTANCE_DIGEST': let s = message.map.digest.space, l = (message.map.digest.lines - 1) * s + 1, r = (message.map.digest.rows - 1) * s + 1; state.map.width = r; state.map.height = l; drawArena(l, r); Object.keys(message.puppets).filter(Boolean).forEach((pk) => { addNewPuppet(pk, message.puppets[pk]); }); break; case 'PUPPET_ENTERS': addNewPuppet(message.puppet_key, message.digest); if (message.puppet_key == state.main) { document.getElementById('lobby').style.display = 'block'; const color_input = document.getElementById('color'); const name_input = document.getElementById('name'); color_input.value = '#' + message.digest.color.toString(16); name_input.value = message.digest.name; color_input.oninput = () => { const new_color = parseColor(color_input.value); ws.send(JSON.stringify({ opcode: "CHANGE_COLOR", arguments: { new_color: new_color } })); }; name_input.oninput = () => { const new_name = name_input.value; ws.send(JSON.stringify({ opcode: "CHANGE_NAME", arguments: { new_name: new_name } })); }; } break; case 'PUPPET_LEAVES': removePuppet(message.puppet_key); break; case 'END_OF_GAME': if (state.playing) { addPersoEvent("Vous faites parti des gagnants") document.getElementById('control').style.display = 'none'; document.getElementById('summary').style.display = 'none'; document.getElementById('history').style.display = 'block'; } break; case 'PUPPET_FALLS': addEvent(puppetName(message.winner) + ' a fait tomber ' + puppetName(message.looser)); if (message.winner == state.main) { addPersoEvent('Vous avez fait tomber ' + puppetName(message.looser)); } else if (message.looser == state.main) { addPersoEvent(puppetName(message.winner) + ' vous a fait tomber'); document.getElementById('control').style.display = 'none'; document.getElementById('summary').style.display = 'none'; document.getElementById('history').style.display = 'block'; state.playing = false; } removePuppet(message.looser); break; case 'PUPPET_DISGRACE': addEvent('Le public a réclamé la défaite de ' + puppetName(message.puppet)); if (message.puppet == state.main) { addPersoEvent('Le public a réclamé votre défaite'); state.playing = false; } removePuppet(message.puppet); break; case 'PUPPET_SURRENDERS': addEvent(puppetName(message.looser) + ' a abandonné'); if (message.looser == state.main) { document.getElementById('control').style.display = 'none'; document.getElementById('summary').style.display = 'none'; document.getElementById('history').style.display = 'block'; addPersoEvent('Vous avez abandonné'); state.playing = false; } removePuppet(message.looser); break; case 'PUPPET_NAME': state.puppets[message.puppet].puppet_name = message.name; listPuppets(); break; case 'PUPPET_COLOR': state.puppets[message.puppet].puppet_color = message.color; listPuppets(); drawPuppet(message.puppet, message.color); break; case 'ATTRIBUTE_PUPPET': state.main = message.puppet_key; state.playing = true; break; case 'PUPPET_WAITS': break; case 'PUPPET_MISS': addEvent(puppetName(message.attacker) + ' a manqué sa cible'); if (message.attacker == state.main) { addPersoEvent('Vous avez manqué votre cible'); } break; case 'PUPPET_ATTACKS': let comp = ''; if (message.success) { comp = ' et l’a blessé' } else { comp = ', sans succès' } addEvent(puppetName(message.attacker) + ' a attaqué ' + puppetName(message.target) + comp); if (message.attacker == state.main && message.success) { addPersoEvent('Vous avez attaqué ' + puppetName(message.target) + ' et êtes parvenu à le blesser'); } else if (message.attacker == state.main) { addPersoEvent('Vous avez attaqué ' + puppetName(message.target) + ', sans succès'); } else if (message.target == state.main) { addPersoEvent(puppetName(message.attacker) + ' vous a attaqué'); } break; case 'PUPPET_STAMINA': state.puppets[message.puppet].puppet_stamina = message.stamina; if (message.puppet == state.main) { updateHUD(); } break; case 'PUPPET_ANGER': state.puppets[message.puppet].puppet_anger = message.anger; if (message.puppet == state.main) { updateHUD(); } break; case 'PUPPET_MOVES': /* addEvent(puppetName(message.puppet) + ' s’est déplacé en ' + puppetPos(message.x, message.y)); if (message.puppet == state.main) { addPersoEvent('Vous vous êtes déplacé en ' + puppetPos(message.x, message.y)); } */ movePuppet(message); break; default: console.log("not yet implemented:"); console.log(opcode); console.log(message); } } ws = new WebSocket('ws://localhost:10000'); ws.onmessage = listenWS_selectMap; ws.onopen = selectMap; function parseColor(str) { str = str.substr(1); return parseInt("0x" + str, 16); } function puppetName(pk) { if (state.puppets[pk]) { return '' + state.puppets[pk].puppet_name + ''; } else { return '???'; } } function puppetPos(x, y) { return '(' + x + ', ' + y + ')'; } function addEvent(str) { if (state.history[state.history.length - 1]) { state.history[state.history.length - 1].push(str); } } function addPersoEvent(str) { state.p_history.push(str); } function updateHistory() { const hist = document.getElementById('history'); let txt = ''; state.history.forEach((turn_hist, turn) => { if (0 < turn_hist.length) { txt += '

    Tour ' + (turn + 1).toString() + '

    '; } }); hist.innerHTML = txt; txt = ''; document.getElementById('p_history').innerHTML = txt; if (state.playing) { state.p_history = []; } } function disableControl() { disable('move_left'); disable('move_right'); disable('move_up'); disable('move_down'); disable('attack_left'); disable('attack_right'); disable('attack_up'); disable('attack_down'); disable('wait'); disable('surrender'); } function enableControl(up, right, down, left) { document.getElementById('wait').disabled = false; document.getElementById('surrender').disabled = false; if (up == 1) { document.getElementById('move_up').disabled = false; } else if (up == 2) { document.getElementById('attack_up').disabled = false; document.getElementById('defend_up').disabled = false; } if (right == 1) { document.getElementById('move_right').disabled = false; } else if (right == 2) { document.getElementById('attack_right').disabled = false; document.getElementById('defend_right').disabled = false; } if (left == 1) { document.getElementById('move_left').disabled = false; } else if (left == 2) { document.getElementById('attack_left').disabled = false; document.getElementById('defend_left').disabled = false; } if (down == 1) { document.getElementById('move_down').disabled = false; } else if (down == 2) { document.getElementById('attack_down').disabled = false; document.getElementById('defend_down').disabled = false; } } disableControl() function newSelectedControl(cls) { if (state.control) { state.control.style.color = ''; state.control.style.fontWeight = ''; state.control.disabled = false; } state.control = document.getElementById(cls); state.control.style.color = 'goldenrod'; state.control.disabled = true; state.control.style.fontWeight = 'bold'; } function disable(cls) { let elem = document.getElementById(cls); elem.style.fontWeight = ''; elem.style.color = ''; elem.disabled = true; }