merged feature/user_management into master
This commit is contained in:
		| @ -1,199 +0,0 @@ | |||||||
| class GameServerConnection |  | ||||||
| { |  | ||||||
|     constructor(ip, port) |  | ||||||
|     { |  | ||||||
|         this.ip = ip; |  | ||||||
|         this.port = port; |  | ||||||
|         this.player = null; |  | ||||||
|         this.socket = null; |  | ||||||
|         this.registered = false; |  | ||||||
|  |  | ||||||
|         this.game_manager = null; |  | ||||||
|         this.connected = false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     set_player(p) |  | ||||||
|     { |  | ||||||
|         this.player = p; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     set_game_manager(gm) |  | ||||||
|     { |  | ||||||
|         this.game_manager = gm; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     is_registered() |  | ||||||
|     { |  | ||||||
|         return this.registered; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     is_connected() |  | ||||||
|     { |  | ||||||
|         return this.connected; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_open(callback_func) |  | ||||||
|     { |  | ||||||
|         // TODO |  | ||||||
|         console.log("connected to " + this.ip + ":" + this.port); |  | ||||||
|         this.connected = true; |  | ||||||
|         callback_func(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_close() |  | ||||||
|     { |  | ||||||
|         this.game_manager.end_game_listener() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_error() |  | ||||||
|     { |  | ||||||
|         console.log("error in websocket connection"); |  | ||||||
|         this.game_manager.connection_error_listener(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_message(event) |  | ||||||
|     { |  | ||||||
|         var json_msg = event.data; |  | ||||||
|         var msg = JSON.parse(json_msg); |  | ||||||
|  |  | ||||||
|         if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data")) |  | ||||||
|         { |  | ||||||
|             console.log("received wrong formatted message"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         switch(msg.type) |  | ||||||
|         { |  | ||||||
|             case "register_response": |  | ||||||
|                 this.on_register_response(msg.data); |  | ||||||
|                 break; |  | ||||||
|              |  | ||||||
|             case "game_starts": |  | ||||||
|                 this.on_game_starts(msg.data); |  | ||||||
|                 break; |  | ||||||
|              |  | ||||||
|             case "move": |  | ||||||
|                 this.on_move(msg.data); |  | ||||||
|                 break; |  | ||||||
|              |  | ||||||
|             case "move_response": |  | ||||||
|                 this.on_move_response(msg.data); |  | ||||||
|                 break; |  | ||||||
|              |  | ||||||
|             case "end_game": |  | ||||||
|                 this.on_end_game(msg.data); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_register_response(data) |  | ||||||
|     { |  | ||||||
|         var success = data.success; |  | ||||||
|         this.game_manager.register_response_listener(success); |  | ||||||
|  |  | ||||||
|         if (!success) |  | ||||||
|         { |  | ||||||
|             this.socket.close(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_game_starts(data) |  | ||||||
|     { |  | ||||||
|         var op_name = data.opponent_name; |  | ||||||
|         var is_first_move = data.is_first_move; |  | ||||||
|  |  | ||||||
|         this.game_manager.start_game_listener(op_name, is_first_move); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_move(data) |  | ||||||
|     { |  | ||||||
|         var sub_x = data.sub_x; |  | ||||||
|         var sub_y = data.sub_y; |  | ||||||
|         var x = data.x; |  | ||||||
|         var y = data.y; |  | ||||||
|  |  | ||||||
|         this.game_manager.move_listener(sub_x, sub_y, x, y); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_move_response(data) |  | ||||||
|     { |  | ||||||
|         if (data.success) |  | ||||||
|         { |  | ||||||
|             console.log("move accepted"); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             console.error("move not accepted"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     on_end_game(data) |  | ||||||
|     { |  | ||||||
|         this.game_manager.end_game_listener(); |  | ||||||
|         this.close(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     connect(callback_func) |  | ||||||
|     { |  | ||||||
|         this.socket = new WebSocket("wss://" + this.ip + ":" + this.port); |  | ||||||
|         this.socket.onmessage = (e => this.on_message(e)); |  | ||||||
|         this.socket.onopen = (() => this.on_open(callback_func)); |  | ||||||
|         this.socket.onerror = (() => this.on_error()); |  | ||||||
|         this.socket.onclose = (() => this.on_close()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     send_move(sub_x, sub_y, x, y) |  | ||||||
|     { |  | ||||||
|         var msg_object = { |  | ||||||
|             type: "move", |  | ||||||
|             data: { |  | ||||||
|                 sub_x: "" + sub_x, |  | ||||||
|                 sub_y: "" + sub_y, |  | ||||||
|                 x: "" + x, |  | ||||||
|                 y: "" + y |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         this.socket.send(JSON.stringify(msg_object)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     register() |  | ||||||
|     { |  | ||||||
|         // register for game queue |  | ||||||
|         var msg_object = { |  | ||||||
|             type: "register", |  | ||||||
|             data: { |  | ||||||
|                 id: this.player.get_id(), |  | ||||||
|                 name: this.player.get_name() |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         this.socket.send(JSON.stringify(msg_object)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     send_disconnect() |  | ||||||
|     { |  | ||||||
|         if (!this.is_connected) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         var msg_object = { |  | ||||||
|             type: "end_game", |  | ||||||
|             data: { |  | ||||||
|                 msg: "" |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         this.socket.send(JSON.stringify(msg_object)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     close() |  | ||||||
|     { |  | ||||||
|         if (this.is_connected) |  | ||||||
|         { |  | ||||||
|             this.is_connected = false; |  | ||||||
|             this.socket.close(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										33
									
								
								grid.js
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								grid.js
									
									
									
									
									
								
							| @ -1,9 +1,9 @@ | |||||||
| class Grid | class Grid | ||||||
| { | { | ||||||
|     constructor(n, grid_container_div, tile_width, tile_height, ground_color) |     constructor(n, parent, tile_width, tile_height, ground_color) | ||||||
|     { |     { | ||||||
|         this.n = n; |         this.n = n; | ||||||
|         this.grid_container_div = grid_container_div; |         this.grid_container_div = null; | ||||||
|         this.tile_width = tile_width; |         this.tile_width = tile_width; | ||||||
|         this.tile_height = tile_height; |         this.tile_height = tile_height; | ||||||
|         this.ground_color = ground_color; |         this.ground_color = ground_color; | ||||||
| @ -11,6 +11,8 @@ class Grid | |||||||
|         this.won_player = null; |         this.won_player = null; | ||||||
|         this.n_complete_subgrids = 0; |         this.n_complete_subgrids = 0; | ||||||
|  |  | ||||||
|  |         this.parent = parent; | ||||||
|  |  | ||||||
|         this.subgrids = [] |         this.subgrids = [] | ||||||
|  |  | ||||||
|         console.log("create grid of size " + this.n); |         console.log("create grid of size " + this.n); | ||||||
| @ -20,6 +22,10 @@ class Grid | |||||||
|  |  | ||||||
|     create() |     create() | ||||||
|     { |     { | ||||||
|  |         this.grid_container_div = document.createElement("div"); | ||||||
|  |         this.grid_container_div.className = "grid-container"; | ||||||
|  |         this.parent.appendChild(this.grid_container_div); | ||||||
|  |  | ||||||
|         var x,y; |         var x,y; | ||||||
|         for (y = 0; y < this.n; y++) |         for (y = 0; y < this.n; y++) | ||||||
|         { |         { | ||||||
| @ -49,7 +55,10 @@ class Grid | |||||||
|     { |     { | ||||||
|         this.check_win(sub_x, sub_y, x, y); |         this.check_win(sub_x, sub_y, x, y); | ||||||
|         this.check_complete(sub_x, sub_y, x, y); |         this.check_complete(sub_x, sub_y, x, y); | ||||||
|         this.click_callback(sub_x, sub_y, x, y);  |         if (this.click_callback != null) | ||||||
|  |         { | ||||||
|  |             this.click_callback(sub_x, sub_y, x, y); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     player_change_listener(player) |     player_change_listener(player) | ||||||
| @ -81,7 +90,7 @@ class Grid | |||||||
|  |  | ||||||
|     check_complete(sub_x, sub_y, x, y) |     check_complete(sub_x, sub_y, x, y) | ||||||
|     { |     { | ||||||
|         if (this.subgrids[sub_x][sub_y].is_won() || this.subgrids[sub_x][sub_y].is_draw()) |         if (this.subgrids[sub_y][sub_x].is_won() || this.subgrids[sub_y][sub_x].is_draw()) | ||||||
|         { |         { | ||||||
|             this.n_complete_subgrids++; |             this.n_complete_subgrids++; | ||||||
|         } |         } | ||||||
| @ -211,6 +220,22 @@ class Grid | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     unblock_all_non_completed() | ||||||
|  |     { | ||||||
|  |         var x,y; | ||||||
|  |         for (y = 0; y < this.n; y++) | ||||||
|  |         { | ||||||
|  |             for (x = 0; x < this.n; x++) | ||||||
|  |             { | ||||||
|  |                 if (this.subgrids[y][x].is_won() || this.subgrids[y][x].is_draw()) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 this.subgrids[y][x].unblock(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     block(x,y) |     block(x,y) | ||||||
|     { |     { | ||||||
|         this.subgrids[y][x].block(); |         this.subgrids[y][x].block(); | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								icon.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								icon.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 19 KiB | 
							
								
								
									
										20
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								index.html
									
									
									
									
									
								
							| @ -2,29 +2,25 @@ | |||||||
|     <link rel="stylesheet" type="text/css" href="style.css"> |     <link rel="stylesheet" type="text/css" href="style.css"> | ||||||
| 	<head> | 	<head> | ||||||
|         <meta name="viewport" content="width=device-width, user-scalable=no" /> |         <meta name="viewport" content="width=device-width, user-scalable=no" /> | ||||||
|  |         <meta name="theme-color" content="#7e57c2" /> | ||||||
|         <link rel="manifest" href="./manifest.json" /> |         <link rel="manifest" href="./manifest.json" /> | ||||||
|         <link rel="icon" href="icon.png" type="image/png"/> |         <link rel="icon" href="icon.png" type="image/png"/> | ||||||
|         <script defer src="site.js"></script> |         <script defer src="site.js"></script> | ||||||
| 		<title>ultimate tictactoe</title> | 		<title>ultimate tictactoe</title> | ||||||
| 	</head> | 	</head> | ||||||
| 	<body> | 	<body> | ||||||
|         <div id="main-container" class="main-container"> |         <div id="main-container" class="main-container"></div> | ||||||
|             <div id="grid-container" class="grid-container"></div> |         <script src="tools.js"></script> | ||||||
|             <div id="sidebar-container" class="sidebar-container"> |  | ||||||
|                 <div id="create-game-container" class="create-game-container"></div> |  | ||||||
|                 <div id="setting-container" class="setting-container"></div> |  | ||||||
|                 <div id="control-container" class="control-container"></div> |  | ||||||
|                 <div id="info-container" class="info-container"></div> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|         <script src="settings.js"></script> |         <script src="settings.js"></script> | ||||||
|         <script src="player.js"></script> |         <script src="player.js"></script> | ||||||
|         <script src="tile.js"></script> |         <script src="tile.js"></script> | ||||||
|         <script src="grid.js"></script> |         <script src="grid.js"></script> | ||||||
|         <script src="subgrid.js"></script> |         <script src="subgrid.js"></script> | ||||||
|         <script src="game_manager.js"></script> |         <script src="local_match_manager.js"></script> | ||||||
|         <script src="game_server_connection.js"></script> |         <script src="online_match_manager.js"></script> | ||||||
|         <script src="sidebar.js"></script> |         <script src="websocket_connection.js"></script> | ||||||
|  |         <script src="infobar.js"></script> | ||||||
|  |         <script src="infocontainer.js"></script> | ||||||
|         <script src="main.js"></script> |         <script src="main.js"></script> | ||||||
|          |          | ||||||
| 	</body> | 	</body> | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								infobar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								infobar.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | class Infobar | ||||||
|  | { | ||||||
|  |     constructor(parent) | ||||||
|  |     { | ||||||
|  |         this.parent = parent; | ||||||
|  |         this.container = document.createElement("div"); | ||||||
|  |         this.container.className = "infobar-container"; | ||||||
|  |         this.parent.appendChild(this.container); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     create_infocontainer() | ||||||
|  |     { | ||||||
|  |         return new Infocontainer(this.container); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								infocontainer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								infocontainer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | |||||||
|  | class Infocontainer | ||||||
|  | { | ||||||
|  |     constructor(parent) | ||||||
|  |     { | ||||||
|  |         this.parent = parent; | ||||||
|  |         this.container = document.createElement("div"); | ||||||
|  |         this.container.className = "info-container"; | ||||||
|  |         this.parent.appendChild(this.container); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     create_button(text) | ||||||
|  |     { | ||||||
|  |         var b = document.createElement("button"); | ||||||
|  |         b.className = "infobar-button"; | ||||||
|  |         b.appendChild(document.createTextNode(text)); | ||||||
|  |         this.container.appendChild(b) | ||||||
|  |         return b; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     create_input(placeholder, pw=false) | ||||||
|  |     { | ||||||
|  |         var i = document.createElement("input"); | ||||||
|  |         i.className = "infobar-input"; | ||||||
|  |         i.placeholder = placeholder; | ||||||
|  |         i.type = pw ? "password" : "text";  | ||||||
|  |  | ||||||
|  |         this.container.appendChild(i); | ||||||
|  |         return i; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     create_label(text) | ||||||
|  |     { | ||||||
|  |         var l = document.createElement("label"); | ||||||
|  |         l.className = "infobar-label"; | ||||||
|  |         l.innerHTML = text; | ||||||
|  |         this.container.appendChild(l); | ||||||
|  |         return l; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     create_double_button(text, option) | ||||||
|  |     { | ||||||
|  |         var div = document.createElement("div"); | ||||||
|  |         div.className = "option-button-container"; | ||||||
|  |         var b1 = document.createElement("button"); | ||||||
|  |         var b2 = document.createElement("button"); | ||||||
|  |  | ||||||
|  |         b1.style.width = "10%"; | ||||||
|  |  | ||||||
|  |         b1.className = "infobar-button"; | ||||||
|  |         b2.className = "infobar-button"; | ||||||
|  |  | ||||||
|  |         b1.style.width = "80%"; | ||||||
|  |         b2.style.width = "20%"; | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         b1.appendChild(document.createTextNode(text)); | ||||||
|  |         b2.appendChild(document.createTextNode(option)); | ||||||
|  |  | ||||||
|  |         div.appendChild(b1); | ||||||
|  |         div.appendChild(b2); | ||||||
|  |  | ||||||
|  |         this.container.appendChild(div); | ||||||
|  |  | ||||||
|  |         return [div, b1,b2]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     hide() | ||||||
|  |     { | ||||||
|  |         this.container.style.display = "none"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     show() | ||||||
|  |     { | ||||||
|  |         this.container.style.display = "inline-block"; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								local_match_manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								local_match_manager.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | class LocalMatchManager | ||||||
|  | { | ||||||
|  |     constructor(grid, status_label, control_container) | ||||||
|  |     { | ||||||
|  |         this.grid = grid; | ||||||
|  |         this.status_label = status_label; | ||||||
|  |  | ||||||
|  |         this.control_container = control_container; | ||||||
|  |  | ||||||
|  |         this.control_container.show(); | ||||||
|  |  | ||||||
|  |         this.local_player_a = new Player("red player", 255,0,0); | ||||||
|  |         this.local_player_b = new Player("green player", 0,255,0); | ||||||
|  |         this.is_local_player_a = false; | ||||||
|  |  | ||||||
|  |         this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l)); | ||||||
|  |  | ||||||
|  |         this.grid.deactivate_all(); | ||||||
|  |         this.grid.unblock_all(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         this.toggle_local_player(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     click_listener(sub_x, sub_y, x,y) | ||||||
|  |     { | ||||||
|  |         // check whether the game is over: | ||||||
|  |         if (grid.is_won()) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "" + grid.get_won_player().get_name() + " has won."; | ||||||
|  |             this.end_game(); | ||||||
|  |         } | ||||||
|  |         else if (grid.is_complete()) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "Draw. Everybody looses!"; | ||||||
|  |             this.end_game(false); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.toggle_local_player(); | ||||||
|  |             this.grid.block_all() | ||||||
|  |             if (this.grid.subgrids[y][x].is_draw() || this.grid.subgrids[y][x].is_won()) | ||||||
|  |             { | ||||||
|  |                 this.grid.unblock_all_non_completed(); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 this.grid.subgrids[y][x].unblock(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     toggle_local_player() | ||||||
|  |     { | ||||||
|  |         this.is_local_player_a = !this.is_local_player_a; | ||||||
|  |         var next_player = this.is_local_player_a ? this.local_player_a : this.local_player_b; | ||||||
|  |          | ||||||
|  |         this.status_label.innerHTML = "" + "it's " + next_player.get_name() + "'s turn..."; | ||||||
|  |         this.grid.player_change_listener(next_player); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     end_game(closed_by_player = true) | ||||||
|  |     { | ||||||
|  |         if (closed_by_player) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "Game Over. Game Closed"; | ||||||
|  |         } | ||||||
|  |         this.grid.block_all(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |      | ||||||
|  | } | ||||||
							
								
								
									
										304
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										304
									
								
								main.js
									
									
									
									
									
								
							| @ -3,18 +3,304 @@ var n = style.getPropertyValue("--tictactoe_n"); | |||||||
| var tilesize = style.getPropertyValue("--tile-size"); | var tilesize = style.getPropertyValue("--tile-size"); | ||||||
| var default_opacity = style.getPropertyValue("--opacity"); | var default_opacity = style.getPropertyValue("--opacity"); | ||||||
| var ground_color = style.getPropertyValue("--ground-color"); | var ground_color = style.getPropertyValue("--ground-color"); | ||||||
|  | var main_container = document.getElementById("main-container"); | ||||||
|  |  | ||||||
| var create_game_container = document.getElementById("create-game-container"); |  | ||||||
| var setting_container = document.getElementById("setting-container"); |  | ||||||
| var control_container = document.getElementById("control-container"); |  | ||||||
| var info_container = document.getElementById("info-container"); |  | ||||||
|  |  | ||||||
| var grid = new Grid(n, document.getElementById("grid-container"), tilesize, tilesize, ground_color); | var main_menu = new Infobar(main_container); | ||||||
| var server_connection = new GameServerConnection(server_url, server_port); | var grid = new Grid(n, main_container, tilesize, tilesize, ground_color); | ||||||
| var game_manager = new GameManager(grid, server_connection); | var sub_menu = new Infobar(main_container); | ||||||
| var sidebar = new Sidebar(create_game_container, setting_container, control_container, info_container, game_manager); |  | ||||||
|  |  | ||||||
|  | // fill containers with buttons and containers: | ||||||
|  |  | ||||||
|  | // empty dummy container on top (to force other containers to be at the bottom) | ||||||
|  | dummy_main = main_menu.create_infocontainer(); | ||||||
|  | dummy_sub = sub_menu.create_infocontainer(); | ||||||
|  |  | ||||||
|  | // start container: | ||||||
|  | create_game_container = main_menu.create_infocontainer(); | ||||||
|  | create_game_container.create_label("Start Local Game"); | ||||||
|  | b_local_game = create_game_container.create_button("Local Game"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // register container: | ||||||
|  | register_container = main_menu.create_infocontainer(); | ||||||
|  | register_container.create_label("Login to play online"); | ||||||
|  | i_register_username = register_container.create_input("username"); | ||||||
|  | i_register_pw = register_container.create_input("password", true); | ||||||
|  | b_register = register_container.create_button("register/login"); | ||||||
|  | //register_container.create_label("(creates new account for a new username)"); | ||||||
|  |  | ||||||
|  | // logout: | ||||||
|  | logout_container = main_menu.create_infocontainer(); | ||||||
|  | l_username = logout_container.create_label("logged in as: "); | ||||||
|  | b_logout = logout_container.create_button("logout"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // fill subcontainer: | ||||||
|  | match_slot_container = sub_menu.create_infocontainer(); | ||||||
|  | match_slot_container.create_label("Running Matches<br>(click to open)"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // local match control: | ||||||
|  | match_control = sub_menu.create_infocontainer(); | ||||||
|  | b_end_game = match_control.create_button("Close Match"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // search match: | ||||||
|  | search_match_container = sub_menu.create_infocontainer(); | ||||||
|  | search_match_container.create_label("Create Online Match"); | ||||||
|  | b_match_search = search_match_container.create_button("random match"); | ||||||
|  |  | ||||||
|  | l_match_op = search_match_container.create_input("player name"); | ||||||
|  | b_match_invite = search_match_container.create_button("invite player"); | ||||||
|  |  | ||||||
|  | search_match_container.create_label("Invite friends:") | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //status: | ||||||
|  | status_container = main_menu.create_infocontainer(); | ||||||
|  | l_status_head = status_container.create_label("Status:"); | ||||||
|  | l_status = status_container.create_label("select gamemode. click <br> <a href=https://en.wikipedia.org/wiki/Ultimate_tic-tac-toe#Rules>[here]</a> for the rules!"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // global vars: | ||||||
|  |  | ||||||
|  | game_manager = null; | ||||||
|  |  | ||||||
|  | logged_in = false; | ||||||
|  |  | ||||||
|  | // connection stuff: | ||||||
|  |  | ||||||
|  | var connection = null; | ||||||
|  | var session_id = null; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // cookies: | ||||||
|  | function get_cookie(cname) { | ||||||
|  |     var name = cname + "="; | ||||||
|  |     var ca = document.cookie.split(';'); | ||||||
|  |     for(var i = 0; i < ca.length; i++) { | ||||||
|  |         var c = ca[i]; | ||||||
|  |         while (c.charAt(0) == ' ') { | ||||||
|  |             c = c.substring(1); | ||||||
|  |         } | ||||||
|  |         if (c.indexOf(name) == 0) { | ||||||
|  |             return c.substring(name.length, c.length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function set_cookie(cname, cvalue, exdays) { | ||||||
|  |     var d = new Date(); | ||||||
|  |     d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); | ||||||
|  |     var expires = "expires="+d.toUTCString(); | ||||||
|  |     document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function check_cookie(cname) { | ||||||
|  |     var tmp = get_cookie(cname); | ||||||
|  |     if (tmp != "") { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // global funcs: | ||||||
|  |  | ||||||
|  | disable_all_containers = function() | ||||||
|  | { | ||||||
|  |     create_game_container.hide(); | ||||||
|  |     register_container.hide(); | ||||||
|  |     logout_container.hide(); | ||||||
|  |     match_slot_container.hide(); | ||||||
|  |     search_match_container.hide(); | ||||||
|  |     match_control.hide(); | ||||||
|  |     status_container.hide(); | ||||||
|  |  | ||||||
|  |     dummy_main.hide(); | ||||||
|  |     dummy_sub.hide(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | end_local_game = function() | ||||||
|  | { | ||||||
|  |     disable_all_containers(); | ||||||
|  |     create_game_container.show(); | ||||||
|  |     status_container.show(); | ||||||
|  |     if (logged_in) | ||||||
|  |     { | ||||||
|  |         logout_container.show(); | ||||||
|  |         search_match_container.show(); | ||||||
|  |         match_slot_container.show(); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         register_container.show(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     game_manager = null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | on_close_click = function() { | ||||||
|  |     if (game_manager != null) | ||||||
|  |     { | ||||||
|  |         game_manager.end_game(); | ||||||
|  |         end_local_game(); | ||||||
|  |     } | ||||||
|  |     else if (connection != null) | ||||||
|  |     { | ||||||
|  |         connection.on_close_click(); | ||||||
|  |         match_control.hide(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | start_local_game = function() | ||||||
|  | { | ||||||
|  |     console.log("clicked"); | ||||||
|  |     disable_all_containers(); | ||||||
|  |     match_control.show(); | ||||||
|  |     dummy_main.show(); | ||||||
|  |     dummy_sub.show(); | ||||||
|  |  | ||||||
|  |     status_container.show(); | ||||||
|  |  | ||||||
|  |     game_manager = new LocalMatchManager(grid, l_status, match_control, end_local_game); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // connection stuff: | ||||||
|  |  | ||||||
|  | login_callback = function() | ||||||
|  | { | ||||||
|  |     logged_in = true; | ||||||
|  |     if (game_manager != null) | ||||||
|  |     { | ||||||
|  |         game_manager.end_game(); | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |     end_local_game(); | ||||||
|  |     l_username.innerHTML = "logged in as: " + connection.player.get_name(); | ||||||
|  |  | ||||||
|  |     set_cookie("sessionid", connection.session_id, 30); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | logout = function() | ||||||
|  | { | ||||||
|  |     logged_in = false; | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         connection.close(); | ||||||
|  |         if (check_cookie("sessionid")) | ||||||
|  |         { | ||||||
|  |             // delete session: | ||||||
|  |             session_id = get_cookie("sessionid"); | ||||||
|  |             set_cookie("sessionid", session_id, -100); | ||||||
|  |             session_id = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     connection = null; | ||||||
|  |     grid.unblock_all(); | ||||||
|  |     grid.deactivate_all(); | ||||||
|  |     grid.block_all(); | ||||||
|  |     end_local_game(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | reconnect = function() | ||||||
|  | { | ||||||
|  |     if (check_cookie("sessionid")) | ||||||
|  |     { | ||||||
|  |         session_id = get_cookie("sessionid"); | ||||||
|  |         if (connection != null) | ||||||
|  |         { | ||||||
|  |             connection.close(); | ||||||
|  |         } | ||||||
|  |         connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, search_match_container, login_callback, on_connection_error); | ||||||
|  |         connection.reconnect(session_id); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | on_connection_error = function() | ||||||
|  | { | ||||||
|  |     connection = null; | ||||||
|  |     logout(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | login = function(){ | ||||||
|  |  | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |         connection.close(); | ||||||
|  |     } | ||||||
|  |     connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, search_match_container, login_callback, on_connection_error); | ||||||
|  |     connection.connect(i_register_username.value.toLowerCase(), i_register_pw.value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | search_match = function() | ||||||
|  | { | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |         connection.send_match_request(null); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | invite_player = function() | ||||||
|  | { | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |         if (l_match_op.value == "") | ||||||
|  |         { | ||||||
|  |             l_status.innerHTML = "choose your opponent first!"; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             connection.send_match_request(l_match_op.value); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // initiate stuff and connect events: | ||||||
|  |  | ||||||
|  | end_local_game(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | b_local_game.addEventListener("click", start_local_game); | ||||||
|  | b_end_game.addEventListener("click", on_close_click); | ||||||
|  | b_register.addEventListener("click", login); | ||||||
|  | b_logout.addEventListener("click", logout); | ||||||
|  |  | ||||||
|  | b_match_search.addEventListener("click", search_match); | ||||||
|  | b_match_invite.addEventListener("click", invite_player); | ||||||
|  |  | ||||||
|  | reconnect(); | ||||||
|  |  | ||||||
|  | // register resize event: | ||||||
|  |  | ||||||
| window.addEventListener("resize", function() { | window.addEventListener("resize", function() { | ||||||
|     var tilesize = getComputedStyle(document.body).getPropertyValue("--tile-size"); |     var tilesize = getComputedStyle(document.body).getPropertyValue("--tile-size"); | ||||||
|     grid.on_screen_orientation_change(tilesize, tilesize); |     grid.on_screen_orientation_change(tilesize, tilesize); | ||||||
| }) | }); | ||||||
|  |  | ||||||
|  | window.onload = function() {  | ||||||
|  |     window.onfocus = function() { | ||||||
|  |         if (session_id != null && connection == null) | ||||||
|  |         { | ||||||
|  |             reconnect(); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ | |||||||
|     "display": "standalone", |     "display": "standalone", | ||||||
|     "start_url": "/website/ultimate_tictactoe/", |     "start_url": "/website/ultimate_tictactoe/", | ||||||
|     "scope": "/website/ultimate_tictactoe/", |     "scope": "/website/ultimate_tictactoe/", | ||||||
|     "theme_color": "#4650e2", |     "theme_color": "#7e57c2", | ||||||
|     "background_color": "#1e2477", |     "background_color": "#31364A", | ||||||
|     "icons": [ |     "icons": [ | ||||||
|       { |       { | ||||||
|         "src": "icon.png", |         "src": "icon.png", | ||||||
|  | |||||||
							
								
								
									
										257
									
								
								online_match_manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								online_match_manager.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,257 @@ | |||||||
|  | class OnlineMatchManager | ||||||
|  | { | ||||||
|  |     constructor(grid, status_label, matches_container, control_container, game_server_connection, match_id, match_state, player_name) | ||||||
|  |     { | ||||||
|  |         this.grid = grid; | ||||||
|  |         this.status_label = status_label; | ||||||
|  |  | ||||||
|  |         this.match_id = match_id; | ||||||
|  |  | ||||||
|  |         this.game_server_connection = game_server_connection; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         this.match_state = match_state; | ||||||
|  |         this.player_name = player_name | ||||||
|  |  | ||||||
|  |         var player_a = this.match_state.player_a; | ||||||
|  |         var player_b = this.match_state.player_b; | ||||||
|  |  | ||||||
|  |         this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0); | ||||||
|  |         this.local_player = new Player(this.player_name, 0,255,0); | ||||||
|  |  | ||||||
|  |         // create match button in match list: | ||||||
|  |         this.control_container = control_container; | ||||||
|  |         this.matches_container = matches_container; | ||||||
|  |  | ||||||
|  |         var tmp = matches_container.create_double_button("" + this.online_opponent.get_name(), "+") | ||||||
|  |  | ||||||
|  |         this.match_button = tmp[1]; | ||||||
|  |         this.match_button_div = tmp[0]; | ||||||
|  |         this.match_button_option = tmp[2]; | ||||||
|  |  | ||||||
|  |         if (this.game_server_connection.is_friend(this.online_opponent.get_name())) | ||||||
|  |         { | ||||||
|  |             this.match_button_option.disabled = true; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.match_button_option.addEventListener("click", () => { | ||||||
|  |                 this.game_server_connection.send_friend_request(this.online_opponent.get_name()); | ||||||
|  |                 this.match_button_option.disabled = true; | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.match_button.addEventListener("click", () => this.open_match()); | ||||||
|  |  | ||||||
|  |         if (this.online_opponent.get_name() == this.match_state.active_player) | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-red"; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-green" | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.is_closed = false; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     click_listener(sub_x, sub_y, x,y) | ||||||
|  |     { | ||||||
|  |         this.grid.block_all(); | ||||||
|  |  | ||||||
|  |         this.game_server_connection.send_move(sub_x, sub_y, x, y, this.match_id); | ||||||
|  |  | ||||||
|  |         this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_user_close() | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         // send end match message: | ||||||
|  |         if (!this.match_state.game_over) | ||||||
|  |         { | ||||||
|  |             this.game_server_connection.send_end_match(this.match_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.match_button_div != null) | ||||||
|  |         { | ||||||
|  |             clearInner(this.match_button_div) | ||||||
|  |             this.matches_container.container.removeChild(this.match_button_div); | ||||||
|  |             this.match_button_div = null; | ||||||
|  |         } | ||||||
|  |         this.status_label.innerHTML = "match is closed"; | ||||||
|  |         this.control_container.hide(); | ||||||
|  |         this.is_closed = true; | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     remove_match() | ||||||
|  |     { | ||||||
|  |         if (this.match_button_div != null) | ||||||
|  |         { | ||||||
|  |             clearInner(this.match_button_div); | ||||||
|  |             this.matches_container.container.removeChild(this.match_button_div); | ||||||
|  |             this.match_button_div = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update_match_state(match_state) | ||||||
|  |     { | ||||||
|  |         this.match_state = match_state; | ||||||
|  |          | ||||||
|  |         if (this.online_opponent.get_name() == this.match_state.active_player) | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-red"; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-green" | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.match_state.active_player == this.local_player.get_name()) | ||||||
|  |         { | ||||||
|  |             this.game_server_connection.notify("your turn against " + this.online_opponent.get_name()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_focus_loose() | ||||||
|  |     { | ||||||
|  |         if (this.online_opponent.get_name() == this.match_state.active_player) | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-red"; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.match_button.className = "infobar-button-green" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     open_match() | ||||||
|  |     { | ||||||
|  |         this.grid.register_click_callback(null); | ||||||
|  |  | ||||||
|  |         this.grid.deactivate_all(); | ||||||
|  |         this.grid.unblock_all(); | ||||||
|  |  | ||||||
|  |         this.match_button.className = "infobar-button-active"; | ||||||
|  |  | ||||||
|  |         this.game_server_connection.set_active_match(this.match_id); | ||||||
|  |  | ||||||
|  |         this.control_container.show(); | ||||||
|  |  | ||||||
|  |         var complete_field = this.match_state.complete_field; | ||||||
|  |         var global_field = this.match_state.global_field; | ||||||
|  |  | ||||||
|  |         var sub_x = null; | ||||||
|  |         var sub_y = null; | ||||||
|  |         var x = null; | ||||||
|  |         var y = null;         | ||||||
|  |  | ||||||
|  |         if (this.match_state.last_move != null) | ||||||
|  |         { | ||||||
|  |             sub_x = this.match_state.last_move.sub_x; | ||||||
|  |             sub_y = this.match_state.last_move.sub_y; | ||||||
|  |             x = this.match_state.last_move.x; | ||||||
|  |             y = this.match_state.last_move.y; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         var game_over = this.match_state.game_over; | ||||||
|  |         var player_won = this.match_state.player_won; | ||||||
|  |         var current_player_name = this.match_state.active_player; | ||||||
|  |  | ||||||
|  |         var player_a = this.match_state.player_a; | ||||||
|  |         var player_b = this.match_state.player_b; | ||||||
|  |  | ||||||
|  |         console.log(game_over); | ||||||
|  |         console.log(current_player); | ||||||
|  |  | ||||||
|  |         var FIELD_EMPTY = 0 | ||||||
|  |         var FIELD_USER = player_a == this.player_name ? 1 : 2; | ||||||
|  |         var FIELD_OPPONENT = player_a == this.player_name ? 2 : 1; | ||||||
|  |         var FIELD_DRAW = 3 | ||||||
|  |  | ||||||
|  |         this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0); | ||||||
|  |         this.local_player = new Player(this.player_name, 0,255,0); | ||||||
|  |  | ||||||
|  |         var i,j; | ||||||
|  |         for(j = 0; j < 9; j++) | ||||||
|  |         { | ||||||
|  |             for(i = 0; i < 9; i++) | ||||||
|  |             { | ||||||
|  |                 var si = Math.floor(i / 3); | ||||||
|  |                 var sj = Math.floor(j / 3); | ||||||
|  |                 if (complete_field[j][i] == FIELD_USER) | ||||||
|  |                 { | ||||||
|  |                     this.grid.subgrids[sj][si].player_change_listener(this.local_player); | ||||||
|  |                     this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click(); | ||||||
|  |                 } | ||||||
|  |                 if (complete_field[j][i] == FIELD_OPPONENT) | ||||||
|  |                 { | ||||||
|  |                     this.grid.subgrids[sj][si].player_change_listener(this.online_opponent); | ||||||
|  |                     this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.grid.block_all(); | ||||||
|  |         this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l)); | ||||||
|  |  | ||||||
|  |         if (game_over && player_won != null) | ||||||
|  |         { | ||||||
|  |             if (player_won == this.player_name) | ||||||
|  |             { | ||||||
|  |                 this.status_label.innerHTML = "Congratulation, you won!"; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 this.status_label.innerHTML = "Game over, you lost!"; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         else if(game_over) | ||||||
|  |         { | ||||||
|  |             if (this.grid.is_complete()) | ||||||
|  |             { | ||||||
|  |                 this.status_label.innerHTML = "Draw. Everyone looses!"; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 this.status_label.innerHTML = "Game was closed by server or opponent"; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         var current_player = this.player_name == current_player_name ? this.local_player : this.online_opponent; | ||||||
|  |         this.grid.player_change_listener(current_player); | ||||||
|  |  | ||||||
|  |          | ||||||
|  |         if (this.player_name == current_player_name) | ||||||
|  |         { | ||||||
|  |              | ||||||
|  |             if (this.match_state.last_move != null) | ||||||
|  |             { | ||||||
|  |                 if (this.grid.subgrids[y][x].is_won() || this.grid.subgrids[y][x].is_draw()) | ||||||
|  |                 { | ||||||
|  |                     this.grid.unblock_all_non_completed(); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     this.grid.unblock(x,y); | ||||||
|  |                 } | ||||||
|  |                 this.status_label.innerHTML = "It's your turn!"; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 this.grid.unblock_all(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |          | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,4 +1,6 @@ | |||||||
|  | var server_protocol = "ws://" | ||||||
|  | var server_url = "127.0.0.1"; | ||||||
|  | var server_port = "5556"; | ||||||
|  |  | ||||||
| var home = "https://the-cake-is-a-lie.net/website/ultimate_tictactoe/"; | var home = "https://the-cake-is-a-lie.net/website/ultimate_tictactoe/"; | ||||||
| var rel_home = "/website/ultimate_tictactoe"; | var rel_home = "/website/ultimate_tictactoe"; | ||||||
| var server_url = "the-cake-is-a-lie.net"; |  | ||||||
| var server_port = "5555"; |  | ||||||
							
								
								
									
										184
									
								
								sidebar.js
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								sidebar.js
									
									
									
									
									
								
							| @ -1,184 +0,0 @@ | |||||||
| class Sidebar |  | ||||||
| { |  | ||||||
|     constructor(create_game_container, setting_container, control_container, info_container, game_manager) |  | ||||||
|     { |  | ||||||
|         this.create_game_container = create_game_container; |  | ||||||
|         this.setting_container = setting_container; |  | ||||||
|         this.control_container = control_container; |  | ||||||
|         this.info_container = info_container; |  | ||||||
|  |  | ||||||
|         this.game_manager = game_manager; |  | ||||||
|  |  | ||||||
|         this.fill_containers(); |  | ||||||
|         this.bind_events(); |  | ||||||
|  |  | ||||||
|         this.activate_create_game(); |  | ||||||
|         this.activate_setting(); |  | ||||||
|         this.activate_info(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     create_button(text) |  | ||||||
|     { |  | ||||||
|         var b = document.createElement("button"); |  | ||||||
|         b.className = "sidebar-button"; |  | ||||||
|         b.appendChild(document.createTextNode(text)); |  | ||||||
|         return b; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     create_input(text) |  | ||||||
|     { |  | ||||||
|         var i = document.createElement("input"); |  | ||||||
|         i.className = "sidebar-input"; |  | ||||||
|         i.type = "text"; |  | ||||||
|         i.value = text; |  | ||||||
|         return i; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     create_label(text) |  | ||||||
|     { |  | ||||||
|         var l = document.createElement("label"); |  | ||||||
|         l.className = "sidebar-label"; |  | ||||||
|         l.innerHTML = text; |  | ||||||
|         return l; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fill_containers() |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         // create new game area: |  | ||||||
|         this.create_game_container.appendChild(this.create_label("Choose game type")); |  | ||||||
|         this.b_local = this.create_button("local game") |  | ||||||
|         this.create_game_container.appendChild(this.b_local); |  | ||||||
|  |  | ||||||
|         this.b_remote = this.create_button("remote game"); |  | ||||||
|         this.create_game_container.appendChild(this.b_remote); |  | ||||||
|  |  | ||||||
|         this.create_game_container.style.display = "none"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         // settings area |  | ||||||
|         this.setting_container.appendChild(this.create_label("select online name:")); |  | ||||||
|  |  | ||||||
|         this.i_player_name = this.create_input(""); |  | ||||||
|         this.setting_container.appendChild(this.i_player_name); |  | ||||||
|  |  | ||||||
|         this.setting_container.style.display = "none"; |  | ||||||
|  |  | ||||||
|         // control area: |  | ||||||
|  |  | ||||||
|         this.b_end_game = this.create_button("end game"); |  | ||||||
|         this.control_container.appendChild(this.b_end_game); |  | ||||||
|  |  | ||||||
|         this.control_container.style.display = "none"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         // status area: |  | ||||||
|         this.status_title = this.create_label(""); |  | ||||||
|         this.info_container.appendChild(this.status_title); |  | ||||||
|  |  | ||||||
|         this.status_text = this.create_label("select gamemode. <br> <a href=https://en.wikipedia.org/wiki/Ultimate_tic-tac-toe#Rules>here are the rules </a>"); |  | ||||||
|         this.info_container.appendChild(this.status_text); |  | ||||||
|  |  | ||||||
|         this.info_container.style.display = "none"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bind_events() |  | ||||||
|     { |  | ||||||
|         // TODO |  | ||||||
|         this.game_manager.register_game_mode_change_listener((c) => this.game_mode_change_listener(c)); |  | ||||||
|         this.game_manager.register_status_change_listener((c,t=null) => this.status_change_listener(c, t)); |  | ||||||
|  |  | ||||||
|         this.b_local.addEventListener("click", () => this.game_manager.start_local_game()); |  | ||||||
|         this.b_end_game.addEventListener("click", () => this.game_manager.end_game(true)); |  | ||||||
|         this.b_remote.addEventListener("click", () => this.game_manager.register_remote_game(this.get_player_name())); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     set_status(text) |  | ||||||
|     { |  | ||||||
|         this.status_text.innerHTML = text; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     get_player_name() |  | ||||||
|     { |  | ||||||
|         return this.i_player_name.value; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     activate_create_game() |  | ||||||
|     { |  | ||||||
|         this.create_game_container.style.display = "inline-block"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     activate_setting() |  | ||||||
|     { |  | ||||||
|         this.setting_container.style.display = "inline-block"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     activate_control() |  | ||||||
|     { |  | ||||||
|         this.control_container.style.display = "inline-block"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     activate_info() |  | ||||||
|     { |  | ||||||
|         this.info_container.style.display = "inline-block"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     deactivate_create_game() |  | ||||||
|     { |  | ||||||
|         this.create_game_container.style.display = "none"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     deactivate_setting() |  | ||||||
|     { |  | ||||||
|         this.setting_container.style.display = "none"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     deactivate_control() |  | ||||||
|     { |  | ||||||
|         this.control_container.style.display = "none"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     deactivate_info() |  | ||||||
|     { |  | ||||||
|         this.info_container.style.display = "none"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     game_mode_change_listener(gamemode) |  | ||||||
|     { |  | ||||||
|         if (gamemode == "none") |  | ||||||
|         { |  | ||||||
|             this.activate_create_game(); |  | ||||||
|             this.activate_setting(); |  | ||||||
|             this.deactivate_control(); |  | ||||||
|             this.activate_info(); |  | ||||||
|             return |  | ||||||
|         } |  | ||||||
|         if (gamemode == "local") |  | ||||||
|         { |  | ||||||
|             this.deactivate_create_game(); |  | ||||||
|             this.deactivate_setting(); |  | ||||||
|             this.activate_control(); |  | ||||||
|             this.activate_info(); |  | ||||||
|         } |  | ||||||
|         if (gamemode == "remote") |  | ||||||
|         { |  | ||||||
|             this.deactivate_create_game(); |  | ||||||
|             this.deactivate_setting(); |  | ||||||
|             this.activate_control(); |  | ||||||
|             this.activate_info(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     status_change_listener(statustext, title=null) |  | ||||||
|     { |  | ||||||
|         this.status_text.innerHTML = statustext; |  | ||||||
|         if (title != null) |  | ||||||
|         { |  | ||||||
|             this.status_title.innerHTML = "<p>" + title + "</p>"; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
							
								
								
									
										271
									
								
								style.css
									
									
									
									
									
								
							
							
						
						
									
										271
									
								
								style.css
									
									
									
									
									
								
							| @ -4,7 +4,7 @@ html, body { | |||||||
|  |  | ||||||
| body {  | body {  | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     background: rgb(30, 36, 119) ; |     background: rgb(49, 54, 74) ; | ||||||
|     outline: 0; |     outline: 0; | ||||||
|     position: relative; |     position: relative; | ||||||
| } | } | ||||||
| @ -15,21 +15,36 @@ body { | |||||||
|     --tile-size: calc((100vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)); |     --tile-size: calc((100vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)); | ||||||
|     --opacity: 1; |     --opacity: 1; | ||||||
|     --border-radius: 1vh; |     --border-radius: 1vh; | ||||||
|     --sidebar-width: 25vh; |     --sidebar-width: 26vh; | ||||||
|     --ground-color: rgb(30, 36, 119) ; |     --ground-color: rgb(41, 45, 62) ; | ||||||
|     --board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) ); |     --board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) ); | ||||||
|     --sidebar-height: calc(var(--board-size) - 2 * var(--border-radius)); |     --sidebar-height: calc(var(--board-size) - 2 * var(--border-radius)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* override settings on portrait mode: */ | /* override settings on portrait mode: */ | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 16/10) { | ||||||
|  |  | ||||||
|  |     :root{ | ||||||
|  |         --button-margin: 0.35vh; | ||||||
|  |         --tile-size: calc(((70vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin))); | ||||||
|  |         --border-radius: 0.7vh; | ||||||
|  |         --sidebar-width: 18.2vh; | ||||||
|  |         --board-size: calc((var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin))); | ||||||
|  |         --sidebar-height: calc(var(--board-size) - 2 * var(--border-radius)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* override settings on portrait mode: */ | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|     :root{ |     :root{ | ||||||
|         --button-margin: 0.5vw; |         --button-margin: 0.5vw; | ||||||
|         --tile-size: calc((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)); |         --tile-size: calc(((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin))); | ||||||
|         --border-radius: 1vw; |         --border-radius: 1vw; | ||||||
|  |         --board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) ); | ||||||
|         --sidebar-width: calc(var(--board-size) - 2 * var(--border-radius)); |         --sidebar-width: calc(var(--board-size) - 2 * var(--border-radius)); | ||||||
|         --sidebar-height: 15vw; |         --sidebar-height: 25vw; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -51,11 +66,11 @@ a:visited { | |||||||
| } | } | ||||||
|  |  | ||||||
| /* override settings on portrait mode: */ | /* override settings on portrait mode: */ | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|     .main-container { |     .main-container { | ||||||
|         white-space: normal; |         white-space: normal; | ||||||
|         padding-top: calc(50vh - 0.5 * var(--board-size)); |         padding-top: 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -114,11 +129,11 @@ a:visited { | |||||||
|     transition-duration: 0.5s; |     transition-duration: 0.5s; | ||||||
| } | } | ||||||
|  |  | ||||||
| .sidebar-container { | .infobar-container { | ||||||
|     border-radius: var(--border-radius); |     border-radius: var(--border-radius); | ||||||
|     padding: var(--border-radius); |     padding: var(--border-radius); | ||||||
|     vertical-align: top; |     vertical-align: top; | ||||||
|     background: rgba(255, 255, 255, 0.05); |     background: none; | ||||||
|     display: inline-flex; |     display: inline-flex; | ||||||
|     justify-content: space-between; |     justify-content: space-between; | ||||||
|     flex-direction:column; |     flex-direction:column; | ||||||
| @ -129,44 +144,17 @@ a:visited { | |||||||
| } | } | ||||||
|  |  | ||||||
| /* override settings on portrait mode: */ | /* override settings on portrait mode: */ | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|     .sidebar-container { |     .infobar-container { | ||||||
|         flex-direction:row; |         flex-direction:row; | ||||||
|         padding: none; |         padding: none; | ||||||
|  |         min-height: var(--sidebar-height); | ||||||
|  |         height: calc((100vh - var(--board-size)) * 0.5 - 2* var(--border-radius)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .create-game-container { |  | ||||||
|     border-radius: var(--border-radius); |  | ||||||
|     padding: var(--border-radius); |  | ||||||
|     top: 0; |  | ||||||
|     background: none; |  | ||||||
|     display: inline-block; |  | ||||||
|     vertical-align: middle; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| .control-container { |  | ||||||
|     border-radius: var(--border-radius); |  | ||||||
|     padding: var(--border-radius); |  | ||||||
|     top: 0; |  | ||||||
|     background: none; |  | ||||||
|     display: inline-block; |  | ||||||
|     vertical-align: middle; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| .setting-container { |  | ||||||
|     border-radius: var(--border-radius); |  | ||||||
|     padding: var(--border-radius); |  | ||||||
|     top: 0; |  | ||||||
|     background: none; |  | ||||||
|     display: inline-block; |  | ||||||
|     vertical-align: middle; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .info-container { | .info-container { | ||||||
|     border-radius: var(--border-radius); |     border-radius: var(--border-radius); | ||||||
|     padding: var(--border-radius); |     padding: var(--border-radius); | ||||||
| @ -176,78 +164,183 @@ a:visited { | |||||||
|     text-align: center; |     text-align: center; | ||||||
|     background: none; |     background: none; | ||||||
|     white-space: normal; |     white-space: normal; | ||||||
|  |     overflow-y: scroll; | ||||||
| } | } | ||||||
|  |  | ||||||
| .sidebar-label { | @media (max-aspect-ratio: 1/1) { | ||||||
|     color: white; |  | ||||||
|     display: flex; |     .info-container{ | ||||||
|     flex-direction: column; |         width: calc(0.3 * var(--sidebar-width)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-label { | ||||||
|  |     color: rgba(224, 217, 235, 0.8); | ||||||
|     font-size: calc(2 * var(--border-radius)); |     font-size: calc(2 * var(--border-radius)); | ||||||
|     width: calc(var(--sidebar-width) - 4 * var(--border-radius)); |     margin-left: 0; | ||||||
|     text-align: left; |     margin-right: 0; | ||||||
| } |     width: 100%; | ||||||
|  |  | ||||||
| @media (orientation: portrait) { |  | ||||||
|     .sidebar-label |  | ||||||
|     { |  | ||||||
|         width: calc(var(--sidebar-width) * 0.3); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebar-button { |  | ||||||
|     border-radius: var(--border-radius); |  | ||||||
|     margin: var(--border-radius); |  | ||||||
|     border: none; |  | ||||||
|     outline: 0; |  | ||||||
|     transition-duration: 0.3s; |  | ||||||
|     background: rgba(0, 0, 0, 0.5); |  | ||||||
|     color: rgb(255, 255, 255); |  | ||||||
|     font-size: calc(3 * var(--border-radius)); |  | ||||||
|     height: calc(4 * var(--border-radius)); |  | ||||||
|     width: calc(var(--sidebar-width) - 4 * var(--border-radius)); |  | ||||||
|     vertical-align: middle; |  | ||||||
|     display: flex; |     display: flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
|  |     text-align: center; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (orientation: portrait) { | .option-button-container | ||||||
|  | { | ||||||
|     .sidebar-button{ |     border-radius: 0%; | ||||||
|         width: calc(0.25 * var(--sidebar-width)); |     margin: 0%; | ||||||
|         height: calc(0.3 * var(--sidebar-height)); |     top: 0%; | ||||||
|     } |     display: flex; | ||||||
|  |     flex-direction:row; | ||||||
|  |     padding: none; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| .sidebar-button:hover { |  | ||||||
|     background: rgba(255, 255, 255, 0.2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebar-button:active { |  | ||||||
|     background: rgba(255, 255, 255, 0.4); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebar-input { | .infobar-button { | ||||||
|     border-radius: var(--border-radius); |     border-radius: var(--border-radius); | ||||||
|     margin: var(--border-radius); |     margin: var(--border-radius); | ||||||
|     border: none; |     border: none; | ||||||
|     outline: 0; |     outline: 0; | ||||||
|     transition-duration: 0.3s; |     transition-duration: 0.3s; | ||||||
|     background: rgba(0, 0, 0, 0.5); |     background: rgba(126,87,194, 0.2) ; | ||||||
|     color: rgb(255, 255, 255); |     color: rgb(255, 255, 255); | ||||||
|     font-size: calc(3 * var(--border-radius)); |     font-size: calc(2.8 * var(--border-radius)); | ||||||
|     height: calc(4 * var(--border-radius)); |     height: calc(4 * var(--border-radius)); | ||||||
|     width: calc(var(--sidebar-width) - 4 * var(--border-radius)); |     /* width: calc(var(--sidebar-width) - 4 * var(--border-radius)); */ | ||||||
|     vertical-align: middle; |     margin-left: 0; | ||||||
|  |     margin-right: 0; | ||||||
|  |     width: 100%; | ||||||
|     display: flex; |     display: flex; | ||||||
|  |     vertical-align: middle; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
|     text-align: center; |     text-align: center; | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|     .sidebar-input{ |     .infobar-button{ | ||||||
|         height: calc(0.3 * var(--sidebar-height)); |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|         width: calc(0.25 * var(--sidebar-width)); |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button-green { | ||||||
|  |     border-radius: var(--border-radius); | ||||||
|  |     margin: var(--border-radius); | ||||||
|  |     border: none; | ||||||
|  |     outline: 0; | ||||||
|  |     transition-duration: 0.3s; | ||||||
|  |     background: rgba(0, 255, 0, 0.2); | ||||||
|  |     color: rgb(255, 255, 255); | ||||||
|  |     font-size: calc(2.8 * var(--border-radius)); | ||||||
|  |     height: calc(4 * var(--border-radius)); | ||||||
|  |     margin-left: 0; | ||||||
|  |     margin-right: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     display: flex; | ||||||
|  |     vertical-align: middle; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|  |     .infobar-button-green{ | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button-red { | ||||||
|  |     border-radius: var(--border-radius); | ||||||
|  |     margin: var(--border-radius); | ||||||
|  |     border: none; | ||||||
|  |     outline: 0; | ||||||
|  |     transition-duration: 0.3s; | ||||||
|  |     background: rgba(255, 0, 0, 0.2); | ||||||
|  |     color: rgb(255, 255, 255); | ||||||
|  |     font-size: calc(2.8 * var(--border-radius)); | ||||||
|  |     height: calc(4 * var(--border-radius)); | ||||||
|  |     margin-left: 0; | ||||||
|  |     margin-right: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     display: flex; | ||||||
|  |     vertical-align: middle; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|  |     .infobar-button-red{ | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button-active { | ||||||
|  |     border-radius: var(--border-radius); | ||||||
|  |     margin: var(--border-radius); | ||||||
|  |     border: none; | ||||||
|  |     outline: 0; | ||||||
|  |     transition-duration: 0.3s; | ||||||
|  |     background: rgba(126,87,194, 0.8) ; | ||||||
|  |     color: rgb(255, 255, 255); | ||||||
|  |     font-size: calc(2.8 * var(--border-radius)); | ||||||
|  |     height: calc(4 * var(--border-radius)); | ||||||
|  |     margin-left: 0; | ||||||
|  |     margin-right: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     display: flex; | ||||||
|  |     vertical-align: middle; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|  |     .infobar-button-active{ | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .infobar-button:hover { | ||||||
|  |     background: rgba(126,87,194, 0.5); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button:active { | ||||||
|  |     background: rgba(126,87,194, 0.8); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button:disabled { | ||||||
|  |     background: rgba(0, 0, 0, 0.1); | ||||||
|  |     color: rgb(64,64,64); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-input { | ||||||
|  |     border-radius: var(--border-radius); | ||||||
|  |     margin: var(--border-radius); | ||||||
|  |     border: none; | ||||||
|  |     outline: 0; | ||||||
|  |     transition-duration: 0.3s; | ||||||
|  |     background: rgba(126,87,194, 0.2); | ||||||
|  |     color: rgb(255, 255, 255); | ||||||
|  |     font-size: calc(3 * var(--border-radius)); | ||||||
|  |     height: calc(4 * var(--border-radius)); | ||||||
|  |     margin-left: 0; | ||||||
|  |     margin-right: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     display: flex; | ||||||
|  |     vertical-align: middle; | ||||||
|  |     flex-direction: column; | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-input::placeholder { | ||||||
|  |     color: rgba(255,255,255,0.3); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|  |     .infobar-input{ | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										73
									
								
								sw.js
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								sw.js
									
									
									
									
									
								
							| @ -1,37 +1,44 @@ | |||||||
|  |  | ||||||
| self.addEventListener('install', function(e) { | var home = "https://the-cake-is-a-lie.net/website/ultimate_tictactoe/"; | ||||||
|     e.waitUntil( | var rel_home = "/website/ultimate_tictactoe"; | ||||||
|       caches.open('your-magic-cache').then(function(cache) { |  | ||||||
|         return cache.addAll([ | self.addEventListener('install', function (e) { | ||||||
|           '/website/ultimate_tictactoe/', |   e.waitUntil( | ||||||
|           '/website/ultimate_tictactoe/index.html', |     caches.open('your-magic-cache').then(function (cache) { | ||||||
|           '/website/ultimate_tictactoe/manifest.json', |       return cache.addAll([ | ||||||
|           '/website/ultimate_tictactoe/icon.png', |         '/website/ultimate_tictactoe/', | ||||||
|           '/website/ultimate_tictactoe/LICENSE', |         '/website/ultimate_tictactoe/tools.js', | ||||||
|           '/website/ultimate_tictactoe/main.js', |         '/website/ultimate_tictactoe/index.html', | ||||||
|           '/website/ultimate_tictactoe/grid.js', |         '/website/ultimate_tictactoe/manifest.json', | ||||||
|           '/website/ultimate_tictactoe/game_manager.js', |         '/website/ultimate_tictactoe/icon.png', | ||||||
|           '/website/ultimate_tictactoe/game_server_connection.js', |         '/website/ultimate_tictactoe/LICENSE', | ||||||
|           '/website/ultimate_tictactoe/sidebar.js', |         '/website/ultimate_tictactoe/main.js', | ||||||
|           '/website/ultimate_tictactoe/settings.js', |         '/website/ultimate_tictactoe/grid.js', | ||||||
|           '/website/ultimate_tictactoe/subgrid.js', |         '/website/ultimate_tictactoe/local_match_manager.js', | ||||||
|           '/website/ultimate_tictactoe/tile.js', |         '/website/ultimate_tictactoe/online_match_manager.js', | ||||||
|           '/website/ultimate_tictactoe/README.md', |         '/website/ultimate_tictactoe/websocket_connection.js', | ||||||
|           '/website/ultimate_tictactoe/site.js', |         '/website/ultimate_tictactoe/infobar.js', | ||||||
|           '/website/ultimate_tictactoe/style.css', |         '/website/ultimate_tictactoe/infocontainer.js', | ||||||
|         ]); |         '/website/ultimate_tictactoe/settings.js', | ||||||
|       }) |         '/website/ultimate_tictactoe/subgrid.js', | ||||||
|     ); |         '/website/ultimate_tictactoe/tile.js', | ||||||
|   }); |         '/website/ultimate_tictactoe/README.md', | ||||||
|    |         '/website/ultimate_tictactoe/site.js', | ||||||
|   self.addEventListener('fetch', function(event) { |         '/website/ultimate_tictactoe/style.css', | ||||||
|     event.respondWith( |       ]); | ||||||
|       caches.match(event.request).then(function(response) { |     }) | ||||||
|         return response || fetch(event.request); |   ); | ||||||
|       }) | }); | ||||||
|     ); |  | ||||||
|  | self.addEventListener('fetch', function (event) { | ||||||
|  |   event.respondWith( | ||||||
|  |     caches.match(event.request).then(function (response) { | ||||||
|  |       return response || fetch(event.request); | ||||||
|  |     }) | ||||||
|  |   ); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| self.addEventListener('notificationclick', function (event) { | self.addEventListener('notificationclick', function (event) { | ||||||
|     console.log ("push message clicked"); |   event.notification.close(); | ||||||
| }); |   clients.openWindow(home); | ||||||
|  | }); | ||||||
							
								
								
									
										13
									
								
								tools.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tools.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  |    | ||||||
|  | function clear(node) { | ||||||
|  |     while (node.hasChildNodes()) { | ||||||
|  |         clear(node.firstChild); | ||||||
|  |     } | ||||||
|  |     node.parentNode.removeChild(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function clearInner(node) { | ||||||
|  |     while (node.hasChildNodes()) { | ||||||
|  |         clear(node.firstChild); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										519
									
								
								websocket_connection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										519
									
								
								websocket_connection.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,519 @@ | |||||||
|  | class WebsocketConnection | ||||||
|  | { | ||||||
|  |     constructor(ip, port, grid, status_label, matches_container, control_container, search_container, login_callback_func, error_callback_func) | ||||||
|  |     { | ||||||
|  |         this.ip = ip; | ||||||
|  |         this.port = port; | ||||||
|  |         this.session_id = null; | ||||||
|  |         this.player = new Player("player", 128, 0,0); | ||||||
|  |         this.socket = null; | ||||||
|  |         this.registered = false; | ||||||
|  |  | ||||||
|  |         this.grid = grid; | ||||||
|  |         this.status_label = status_label; | ||||||
|  |         this.matches_container = matches_container; | ||||||
|  |         this.control_container = control_container; | ||||||
|  |         this.search_container  = search_container; | ||||||
|  |  | ||||||
|  |         this.active_match = null; | ||||||
|  |  | ||||||
|  |         this.connected = false; | ||||||
|  |  | ||||||
|  |         this.current_end_button = null; | ||||||
|  |  | ||||||
|  |         this.login_callback_func = login_callback_func; | ||||||
|  |  | ||||||
|  |         this.openmatches = {}; | ||||||
|  |         this.error_callback_func = error_callback_func; | ||||||
|  |  | ||||||
|  |         this.closed_by_user = false; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         this.friends = []; | ||||||
|  |  | ||||||
|  |         this.friend_name_divs = []; | ||||||
|  |  | ||||||
|  |         matches_container.hide(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set_player(p) | ||||||
|  |     { | ||||||
|  |         this.player = p; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set_game_manager(gm) | ||||||
|  |     { | ||||||
|  |         this.game_manager = gm; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is_registered() | ||||||
|  |     { | ||||||
|  |         return this.registered; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is_connected() | ||||||
|  |     { | ||||||
|  |         return this.connected; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is_friend(friend) | ||||||
|  |     { | ||||||
|  |         return this.friends.includes(friend); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_open(username, pw) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         this.connected = true; | ||||||
|  |         this.login(username, pw) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_reopen(session_id) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         this.connected = true; | ||||||
|  |         this.relogin(session_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_close(login_failed=false) | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             this.openmatches[key].remove_match(); | ||||||
|  |         } | ||||||
|  |         this.openmatches = {}; | ||||||
|  |          | ||||||
|  |         // remove complete friend list: | ||||||
|  |         var n = this.friend_name_divs.length; | ||||||
|  |  | ||||||
|  |         var i; | ||||||
|  |  | ||||||
|  |         for (i = 0; i < n; i++) | ||||||
|  |         { | ||||||
|  |             clearInner(this.friend_name_divs[i]); | ||||||
|  |             this.search_container.container.removeChild(this.friend_name_divs[i]); | ||||||
|  |             this.friend_name_divs[i] = null; | ||||||
|  |         } | ||||||
|  |         this.friend_name_divs = []; | ||||||
|  |         this.friends = []; | ||||||
|  |  | ||||||
|  |         var login_failed = !this.registered; | ||||||
|  |         this.registered = false; | ||||||
|  |         this.connected = false; | ||||||
|  |         if (!this.closed_by_user && !login_failed) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "connection to server closed"; | ||||||
|  |             this.error_callback_func(); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_error() | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             this.openmatches[key].remove_match(); | ||||||
|  |         } | ||||||
|  |         this.openmatches = {}; | ||||||
|  |  | ||||||
|  |         // remove complete friend list: | ||||||
|  |         var n = this.friend_name_divs.length; | ||||||
|  |  | ||||||
|  |         var i; | ||||||
|  |  | ||||||
|  |         for (i = 0; i < n; i++) | ||||||
|  |         { | ||||||
|  |             clearInner(this.friend_name_divs[i]); | ||||||
|  |             this.search_container.container.removeChild(this.friend_name_divs[i]); | ||||||
|  |             this.friend_name_divs[i] = null; | ||||||
|  |         } | ||||||
|  |         this.friend_name_divs = []; | ||||||
|  |         this.friends = []; | ||||||
|  |  | ||||||
|  |         console.log("error in websocket connection"); | ||||||
|  |         this.registered = false; | ||||||
|  |         this.connected = false; | ||||||
|  |         if (!this.closed_by_user) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "connection to server lost"; | ||||||
|  |             this.error_callback_func(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     on_message(event) | ||||||
|  |     { | ||||||
|  |         var json_msg = event.data; | ||||||
|  |         var msg = JSON.parse(json_msg); | ||||||
|  |  | ||||||
|  |         if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data")) | ||||||
|  |         { | ||||||
|  |             console.log("received wrong formatted message"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         console.log("raw_msg: " + json_msg); | ||||||
|  |  | ||||||
|  |         switch(msg.type) | ||||||
|  |         { | ||||||
|  |             case "login_response": | ||||||
|  |                 this.on_register_response(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "reconnect_response": | ||||||
|  |                 this.on_reconnect_response(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "match_update": | ||||||
|  |                 this.on_match_update(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "match_request_response": | ||||||
|  |                 this.on_match_request_response(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "friend_request_response": | ||||||
|  |                 this.on_friend_request_response(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "unfriend_request_response": | ||||||
|  |                 this.on_unfriend_request_response(msg.data); | ||||||
|  |                 break; | ||||||
|  |              | ||||||
|  |             case "friends_update": | ||||||
|  |                 this.on_friends_update(msg.data); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set_active_match(id) | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             if (key == id) | ||||||
|  |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             this.openmatches[key].on_focus_loose(); | ||||||
|  |         } | ||||||
|  |         this.active_match = id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_close_click() | ||||||
|  |     { | ||||||
|  |         if (this.active_match != null && (this.active_match in this.openmatches)) | ||||||
|  |         { | ||||||
|  |             this.openmatches[this.active_match].on_user_close(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.current_end_button != null) | ||||||
|  |         { | ||||||
|  |             this.control_container.container.deleteChild(this.current_end_button); | ||||||
|  |             this.current_end_button = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     on_match_update(data) | ||||||
|  |     { | ||||||
|  |         var id = data.id | ||||||
|  |         var match_state = data.match_state; | ||||||
|  |  | ||||||
|  |         if (match_state == null) | ||||||
|  |         { | ||||||
|  |             // checking whether we can delete our dict object | ||||||
|  |             if (id in this.openmatches) | ||||||
|  |             { | ||||||
|  |                 delete this.openmatches[id]; | ||||||
|  |                 if (this.active_match == id) | ||||||
|  |                 { | ||||||
|  |                     if (this.current_end_button != null) | ||||||
|  |                     { | ||||||
|  |                         this.control_container.container.deleteChild(this.current_end_button); | ||||||
|  |                         this.current_end_button = null; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             if (id in this.openmatches) | ||||||
|  |             { | ||||||
|  |                 this.openmatches[id].update_match_state(match_state) | ||||||
|  |                 if (this.active_match == id) | ||||||
|  |                 { | ||||||
|  |                     this.openmatches[id].open_match(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 if (!match_state.game_over) | ||||||
|  |                 { | ||||||
|  |                     this.openmatches[id] = new OnlineMatchManager(this.grid, this.status_label, this.matches_container, this.control_container, this, id, match_state, this.player.get_name()); | ||||||
|  |                     if (match_state.last_move == null) | ||||||
|  |                     { | ||||||
|  |                         this.notify("new Game against " + this.openmatches[id].online_opponent.get_name()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     on_register_response(data) | ||||||
|  |     { | ||||||
|  |         if (data.success) | ||||||
|  |         { | ||||||
|  |             this.registered = true; | ||||||
|  |             this.session_id = data.id; | ||||||
|  |             this.login_callback_func(); | ||||||
|  |         } | ||||||
|  |         this.status_label.innerHTML = data.msg; | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_reconnect_response(data) | ||||||
|  |     { | ||||||
|  |         if (data.success) | ||||||
|  |         { | ||||||
|  |             this.registered = true; | ||||||
|  |             this.session_id = data.id; | ||||||
|  |             this.player.set_name(data.user); | ||||||
|  |             this.login_callback_func(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.status_label.innerHTML = data.msg; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_match_request_response(data) | ||||||
|  |     { | ||||||
|  |         if (data.success) | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "match request sent"; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             this.status_label.innerHTML = "could not send request: " + data.msg; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_friend_request_response(data) | ||||||
|  |     { | ||||||
|  |         this.status_label.innerHTML = data.msg; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_unfriend_request_response(data) | ||||||
|  |     { | ||||||
|  |         this.status_label.innerHTML = data.msg; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_friends_update(data) | ||||||
|  |     { | ||||||
|  |         this.friends = data.friends; | ||||||
|  |  | ||||||
|  |         // remove complete friend list: | ||||||
|  |         var n = this.friend_name_divs.length; | ||||||
|  |  | ||||||
|  |         var i; | ||||||
|  |  | ||||||
|  |         for (i = 0; i < n; i++) | ||||||
|  |         { | ||||||
|  |             clearInner(this.friend_name_divs[i]); | ||||||
|  |             this.search_container.container.removeChild(this.friend_name_divs[i]); | ||||||
|  |             this.friend_name_divs[i] = null; | ||||||
|  |         } | ||||||
|  |         this.friend_name_divs = []; | ||||||
|  |         // rebuild friend list: | ||||||
|  |         n = this.friends.length; | ||||||
|  |          | ||||||
|  |         for (i = 0; i < n; i++) | ||||||
|  |         { | ||||||
|  |             var tmp = this.search_container.create_double_button("" + this.friends[i], "-"); | ||||||
|  |  | ||||||
|  |             tmp[1].name = this.friends[i]; | ||||||
|  |             tmp[2].name = this.friends[i]; | ||||||
|  |             tmp[1].connection = this; | ||||||
|  |             tmp[2].connection = this; | ||||||
|  |              | ||||||
|  |              | ||||||
|  |             tmp[1].addEventListener("click", function() { | ||||||
|  |                 this.connection.send_match_request(this.name); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             tmp[2].addEventListener("click", function (){ | ||||||
|  |                 this.connection.send_unfriend_request(this.name); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             this.friend_name_divs.push(tmp[0]) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     connect(username, pw) | ||||||
|  |     { | ||||||
|  |         this.socket = new WebSocket(server_protocol + this.ip + ":" + this.port); | ||||||
|  |         this.socket.onmessage = (e => this.on_message(e)); | ||||||
|  |         this.socket.onopen = (() => this.on_open(username, pw)); | ||||||
|  |         this.socket.onerror = (() => this.on_error()); | ||||||
|  |         this.socket.onclose = (() => this.on_close()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     reconnect(session_id) | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             this.openmatches[key].remove_match(); | ||||||
|  |         } | ||||||
|  |         this.openmatches = {}; | ||||||
|  |         this.socket = new WebSocket(server_protocol + this.ip + ":" + this.port); | ||||||
|  |         this.socket.onmessage = (e => this.on_message(e)); | ||||||
|  |         this.socket.onopen = (() => this.on_reopen(session_id)); | ||||||
|  |         this.socket.onerror = (() => this.on_error()); | ||||||
|  |         this.socket.onclose = (() => this.on_close()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_move(sub_x, sub_y, x, y, match_id) | ||||||
|  |     { | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "move", | ||||||
|  |             data: { | ||||||
|  |                 id: match_id, | ||||||
|  |                 sub_x: "" + sub_x, | ||||||
|  |                 sub_y: "" + sub_y, | ||||||
|  |                 x: "" + x, | ||||||
|  |                 y: "" + y | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_end_match(match_id) | ||||||
|  |     { | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "end_match", | ||||||
|  |             data: { | ||||||
|  |                 id: match_id, | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_match_request(player_name) | ||||||
|  |     { | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "match_request", | ||||||
|  |             data: { | ||||||
|  |                 player: player_name | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_friend_request(friend_name) | ||||||
|  |     { | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "friend_request", | ||||||
|  |             data: { | ||||||
|  |                 user: friend_name | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_unfriend_request(friend_name) | ||||||
|  |     { | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "unfriend_request", | ||||||
|  |             data: { | ||||||
|  |                 user: friend_name | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     login(username, pw) | ||||||
|  |     { | ||||||
|  |         this.player.set_name(username); | ||||||
|  |         // register for game queue | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "login", | ||||||
|  |             data: { | ||||||
|  |                 name: this.player.get_name(), | ||||||
|  |                 pw: pw | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     relogin(session_id) | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             this.openmatches[key].remove_match(); | ||||||
|  |         } | ||||||
|  |         // register for game queue | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "reconnect", | ||||||
|  |             data: { | ||||||
|  |                 id: session_id | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_disconnect() | ||||||
|  |     { | ||||||
|  |         if (!this.is_connected) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "end_game", | ||||||
|  |             data: { | ||||||
|  |                 msg: "" | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     close() | ||||||
|  |     { | ||||||
|  |         this.status_label.innerHTML = "logged out"; | ||||||
|  |         this.closed_by_user = true; | ||||||
|  |         this.socket.close(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     notify(text) { | ||||||
|  |  | ||||||
|  |         if (document.hasFocus()) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         Notification.requestPermission(function(result) { | ||||||
|  |             if (result === 'granted') { | ||||||
|  |                 navigator.serviceWorker.ready.then(function(registration) { | ||||||
|  |                 registration.showNotification(text, { | ||||||
|  |                         icon: './icon.png', | ||||||
|  |                         vibrate: [200, 200], | ||||||
|  |                         tag: "tictactoe-notification" | ||||||
|  |                     }); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |        | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user