From ad8904ecc8fccd0ce52225d86e48c5f767b16daa Mon Sep 17 00:00:00 2001 From: Christian Heller <c.heller@plomlompom.de> Date: Mon, 26 Oct 2020 23:00:36 +0100 Subject: [PATCH] Add monochrome no canvas chat client. --- new2/rogue_chat_nocanvas_monochrome.html | 269 +++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 new2/rogue_chat_nocanvas_monochrome.html diff --git a/new2/rogue_chat_nocanvas_monochrome.html b/new2/rogue_chat_nocanvas_monochrome.html new file mode 100644 index 0000000..0ca95ed --- /dev/null +++ b/new2/rogue_chat_nocanvas_monochrome.html @@ -0,0 +1,269 @@ +<!DOCTYPE html> +<html><head> +<style> +</style> +</head><body> +<pre id="terminal" style="display: inline-block; color: white; background-color: black;"></pre> +<script> +"use strict"; +let websocket_location = "ws://localhost:8000"; + +let terminal = { + rows: 24, + cols: 80, + initialize: function() { + this.pre_el = document.getElementById("terminal"); + this.content = []; + let line = [] + for (let y = 0, x = 0; y <= this.rows; x++) { + if (x == this.cols) { + x = 0; + y += 1; + this.content.push(line); + line = []; + if (y == this.rows) { + break; + } + } + line.push(' '); + } + console.log(this.content); + }, + refresh: function() { + let pre_string = ''; + for (let y = 0; y < this.rows; y++) { + let line = this.content[y].join(''); + pre_string += line + '\n'; + } + this.pre_el.textContent = pre_string; + }, + write: function(start_y, start_x, msg) { + for (let x = start_x, i = 0; x < this.cols, i < msg.length; x++, i++) { + this.content[start_y][x] = msg[i]; + } + }, + drawBox: function(start_y, start_x, height, width) { + let end_y = start_y + height; + let end_x = start_x + width; + for (let y = start_y, x = start_x; y < end_y; x++) { + this.content[y][x] = ' '; + if (x == end_x) { + x = start_x - 1; + y += 1; + } + } + }, +} + +let parser = { + tokenize: function(str) { + let tokens = []; + let token = '' + let quoted = false; + let escaped = false; + for (let i = 0; i < str.length; i++) { + let c = str[i]; + if (quoted) { + if (escaped) { + token += c; + escaped = false; + } else if (c == '\\') { + escaped = true; + } else if (c == '"') { + quoted = false + } else { + token += c; + } + } else if (c == '"') { + quoted = true + } else if (c === ' ') { + if (token.length > 0) { + tokens.push(token); + token = ''; + } + } else { + token += c; + } + } + if (token.length > 0) { + tokens.push(token); + } + return tokens; + }, + parse_yx(position_string) { + let coordinate_strings = position_string.split(',') + let position = [0, 0]; + position[0] = parseInt(coordinate_strings[0].slice(2)); + position[1] = parseInt(coordinate_strings[1].slice(2)); + return position; + } +} + +let tui = { + draw_history: function() { + terminal.drawBox(1, terminal.cols / 2, terminal.rows - 2, terminal.cols / 2); + let i = 0; + for (let line of chat.history) { + terminal.write(terminal.rows - 2 - i, terminal.cols / 2, line); + i += 1; + } + }, + draw_map: function() { + let map_lines = []; + let line = ''; + for (let i = 0, j = 0; i < game.map.length; i++, j++) { + if (j == game.map_size[1]) { + map_lines.push(line); + line = ''; + j = 0; + }; + line += game.map[i]; + }; + map_lines.push(line); + for (let y = 0; y < game.map_size[0]; y++) { + terminal.write(y, 0, map_lines[y]); + } + for (const t in game.things) { + terminal.write(game.things[t][0], game.things[t][1], '@'); + } + }, + draw_turn_line: function(n) { + terminal.drawBox(0, terminal.cols / 2, 1, terminal.cols / 2); + terminal.write(0, terminal.cols / 2, 'turn: ' + game.turn); + }, + draw_input_line: function() { + terminal.drawBox(terminal.rows - 1, terminal.cols / 2, 1, terminal.cols / 2); + terminal.write(terminal.rows - 1, terminal.cols / 2, chat.input_line); + }, + log_msg: function(msg, indent=0) { + let line_length = (terminal.cols / 2) - indent; + let chunk = ""; + for (let i = 0, x = 0; i < msg.length; i++, x++) { + if (x >= line_length) { + chat.history.unshift(' '.repeat(indent) + chunk); + chunk = ""; + x = 0; + }; + chunk += msg[i]; + } + chat.history.unshift(' '.repeat(indent) + chunk); + while (chat.history.length > terminal.rows - 2) { + chat.history.pop(); + }; + this.draw_history(); + }, + refresh: function() { + terminal.refresh(); + } +} + +let game = { + things: {}, + turn: 0, + map: "", + map_size: [0,0] +} + +let chat = { + input_line: "", + history: [] +} + +terminal.initialize(); + +tui.draw_map(); +tui.draw_turn_line(); +tui.draw_history(); +tui.draw_input_line(); +tui.refresh(); + +tui.log_msg("basic commands:", 1); +tui.log_msg("LOGIN USER - register as USER", 3); +tui.log_msg("ALL TEXT - send TEXT to all users", 3); +tui.log_msg("QUERY USER TEXT - send TEXT to USER", 3); +tui.log_msg(""); +tui.log_msg("Use arrow keys to move your avatar. You can only move over \".\" map cells.", 1); +tui.log_msg(""); +tui.log_msg("Use double quotes for strings that contain whitespace, escape them with \\.", 1); +tui.log_msg(""); +tui.log_msg("To change the map cell you are standing on, type the desired ASCII character into the prompt and hit Return.", 1); +tui.log_msg(""); +tui.log_msg("more commands:", 1); +tui.log_msg("FLATTEN - transform surrounding map cells to \".\" ones", 3); +tui.log_msg(""); + +let websocket = new WebSocket(websocket_location); +websocket.onmessage = function (event) { + let tokens = parser.tokenize(event.data); + if (tokens[0] === 'TURN') { + game.things = {} + game.turn = parseInt(tokens[1]); + } else if (tokens[0] === 'THING_POS') { + game.things[tokens[1]] = parser.parse_yx(tokens[2]); + } else if (tokens[0] === 'MAP') { + game.map_size = parser.parse_yx(tokens[1]); + game.map = tokens[2] + } else if (tokens[0] === 'GAME_STATE_COMPLETE') { + tui.draw_turn_line(); + tui.draw_map(); + tui.refresh(); + } else if (tokens[0] === 'LOG') { + tui.log_msg(tokens[1], 1); + tui.refresh(); + } else if (tokens[0] === 'META') { + tui.log_msg(tokens[1]); + tui.refresh(); + } else if (tokens[0] === 'UNHANDLED_INPUT') { + tui.log_msg('unknown command'); + tui.refresh(); + } else if (tokens[0] === 'ARGUMENT_ERROR') { + tui.log_msg('syntax error: ' + tokens[1]); + tui.refresh(); + } else if (tokens[0] === 'GAME_ERROR') { + tui.log_msg('game error: ' + tokens[1]); + tui.refresh(); + } else if (tokens[0] === 'PONG') { + console.log('PONG'); + } else { + tui.log_msg('unhandled input: ' + event.data); + tui.refresh(); + } +} + +document.addEventListener('keydown', (event) => { + if (chat.input_line === '') { + tui.draw_input_line(); + tui.refresh(); + } + if (event.key && event.key.length === 1) { + chat.input_line += event.key; + tui.draw_input_line(); + tui.refresh(); + } else if (event.key === 'Backspace') { + chat.input_line = chat.input_line.slice(0, -1); + tui.draw_input_line(); + tui.refresh(); + } else if (event.key === 'Enter') { + if (chat.input_line.length === 1) { + websocket.send("TASK:WRITE " + chat.input_line); + } else if (chat.input_line.trimEnd() === 'FLATTEN') { + websocket.send("TASK:FLATTEN_SURROUNDINGS"); + } else { + websocket.send(chat.input_line); + } + chat.input_line = ''; + tui.draw_input_line(); + } else if (event.key === 'ArrowLeft') { + websocket.send('TASK:MOVE LEFT'); + } else if (event.key === 'ArrowRight') { + websocket.send('TASK:MOVE RIGHT'); + } else if (event.key === 'ArrowUp') { + websocket.send('TASK:MOVE UP'); + } else if (event.key === 'ArrowDown') { + websocket.send('TASK:MOVE DOWN'); + }; +}, false); + +window.setInterval(function() { websocket.send('PING') }, 30000); +</script> +</body></html> -- 2.30.2