almost working for new version
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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										31
									
								
								grid.js
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								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) | ||||||
| @ -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(); | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								index.html
									
									
									
									
									
								
							| @ -8,23 +8,17 @@ | |||||||
| 		<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> |  | ||||||
|             <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); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								infocontainer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								infocontainer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | 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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     hide() | ||||||
|  |     { | ||||||
|  |         this.container.style.display = "none"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     show() | ||||||
|  |     { | ||||||
|  |         this.container.style.display = "inline-block"; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								local_match_manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								local_match_manager.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | 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_change_listener("" + grid.get_won_player().get_name() + " has won.", "Game Over") | ||||||
|  |             this.end_game(); | ||||||
|  |         } | ||||||
|  |         else if (grid.is_complete()) | ||||||
|  |         { | ||||||
|  |             this.status_change_listener("Draw. Everybody looses!", "Game Over"); | ||||||
|  |             this.end_game(); | ||||||
|  |         } | ||||||
|  |         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() | ||||||
|  |     { | ||||||
|  |         this.status_label.innerHTML = "Game Over. Game Closed"; | ||||||
|  |         this.grid.block_all(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |      | ||||||
|  | } | ||||||
							
								
								
									
										225
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								main.js
									
									
									
									
									
								
							| @ -3,16 +3,225 @@ 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("Register or 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"); | ||||||
|  |  | ||||||
|  | // logout: | ||||||
|  | logout_container = sub_menu.create_infocontainer(); | ||||||
|  | l_username = logout_container.create_label("logged in as: "); | ||||||
|  | b_logout = logout_container.create_button("logout"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // match control | ||||||
|  | match_control = sub_menu.create_infocontainer(); | ||||||
|  | b_end_game = match_control.create_button("End Game"); | ||||||
|  |  | ||||||
|  | // fill subcontainer: | ||||||
|  | match_slot_container = sub_menu.create_infocontainer(); | ||||||
|  | match_slot_container.create_label("online matches"); | ||||||
|  |  | ||||||
|  | // search match: | ||||||
|  | search_match_container = main_menu.create_infocontainer(); | ||||||
|  | search_match_container.create_label("Create Online Match"); | ||||||
|  | b_match_search = search_match_container.create_button("random match"); | ||||||
|  | search_match_container.create_label("<p> </p>"); | ||||||
|  |  | ||||||
|  | l_match_op = search_match_container.create_input("player name"); | ||||||
|  | b_match_invite = search_match_container.create_button("invite player"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //status: | ||||||
|  | status_container = main_menu.create_infocontainer(); | ||||||
|  | l_status_head = status_container.create_label("status:"); | ||||||
|  | l_status = status_container.create_label("..."); | ||||||
|  |  | ||||||
|  | // global vars: | ||||||
|  |  | ||||||
|  | game_manager = null; | ||||||
|  |  | ||||||
|  | logged_in = false; | ||||||
|  |  | ||||||
|  | // connection stuff: | ||||||
|  |  | ||||||
|  | var connection = null; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // 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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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(); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | login = function(){ | ||||||
|  |  | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |         connection.close(); | ||||||
|  |     } | ||||||
|  |     connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, login_callback); | ||||||
|  |     connection.connect(i_register_username.value, i_register_pw.value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | logout = function() | ||||||
|  | { | ||||||
|  |     logged_in = false; | ||||||
|  |     if (connection != null) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         connection.close(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     connection = null; | ||||||
|  |     grid.unblock_all(); | ||||||
|  |     grid.deactivate_all(); | ||||||
|  |     grid.block_all(); | ||||||
|  |     end_local_game(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | var websocket_connection = new WebsocketConnection('127.0.0.1', 5556); | ||||||
|  | websocket_connection.connect(); | ||||||
|  | */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // 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"); | ||||||
|  | |||||||
							
								
								
									
										199
									
								
								online_match_manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								online_match_manager.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,199 @@ | |||||||
|  | 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 | ||||||
|  |         this.match_button = matches_container.create_button("" + this.online_opponent.get_name()); | ||||||
|  |         this.match_button.addEventListener("click", () => this.open_match()); | ||||||
|  |         this.match_button.style.background = "rbg(0,255,0)"; | ||||||
|  |  | ||||||
|  |         this.match_button.className = "infobar-button-active"; | ||||||
|  |  | ||||||
|  |         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); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.matches_container.container.removeChild(this.match_button); | ||||||
|  |         this.status_label.innerHTML = "match is closed"; | ||||||
|  |         this.control_container.hide(); | ||||||
|  |         this.is_closed = true; | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     remove_match() | ||||||
|  |     { | ||||||
|  |         if (!this.is_closed) | ||||||
|  |         { | ||||||
|  |             this.matches_container.container.removeChild(this.match_button); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update_match_state(match_state) | ||||||
|  |     { | ||||||
|  |         this.match_state = match_state; | ||||||
|  |         this.match_button.className = "infobar-button-active"; | ||||||
|  |  | ||||||
|  |         if (this.match_state.current_player != this.current_player_name) | ||||||
|  |         { | ||||||
|  |             this.game_server_connection.notify("" + this.online_opponent.get_name() + " moved"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     open_match() | ||||||
|  |     { | ||||||
|  |         this.grid.register_click_callback(null); | ||||||
|  |  | ||||||
|  |         this.grid.deactivate_all(); | ||||||
|  |         this.grid.unblock_all(); | ||||||
|  |  | ||||||
|  |         this.match_button.className = "infobar-button"; | ||||||
|  |  | ||||||
|  |         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) | ||||||
|  |         { | ||||||
|  |             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,2 +1,2 @@ | |||||||
| var server_url = "the-cake-is-a-lie.net"; | var server_url = "the-cake-is-a-lie.net"; | ||||||
| var server_port = "5555"; | var server_port = "5556"; | ||||||
							
								
								
									
										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>"; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
							
								
								
									
										147
									
								
								style.css
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								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: calc(50vh - 0.5 * var(--board-size) - var(--sidebar-height) - 2 * var(--button-margin)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -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,15 @@ 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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .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); | ||||||
| @ -178,7 +164,7 @@ a:visited { | |||||||
|     white-space: normal; |     white-space: normal; | ||||||
| } | } | ||||||
|  |  | ||||||
| .sidebar-label { | .infobar-label { | ||||||
|     color: white; |     color: white; | ||||||
|     display: flex; |     display: flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| @ -187,14 +173,14 @@ a:visited { | |||||||
|     text-align: left; |     text-align: left; | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 1/1) { | ||||||
|     .sidebar-label |     .infobar-label | ||||||
|     { |     { | ||||||
|         width: calc(var(--sidebar-width) * 0.3); |         width: calc(var(--sidebar-width) * 0.25); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| .sidebar-button { | .infobar-button { | ||||||
|     border-radius: var(--border-radius); |     border-radius: var(--border-radius); | ||||||
|     margin: var(--border-radius); |     margin: var(--border-radius); | ||||||
|     border: none; |     border: none; | ||||||
| @ -202,7 +188,7 @@ a:visited { | |||||||
|     transition-duration: 0.3s; |     transition-duration: 0.3s; | ||||||
|     background: rgba(0, 0, 0, 0.5); |     background: rgba(0, 0, 0, 0.5); | ||||||
|     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; |     vertical-align: middle; | ||||||
| @ -210,30 +196,59 @@ a:visited { | |||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (orientation: portrait) { | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|     .sidebar-button{ |     .infobar-button{ | ||||||
|         width: calc(0.25 * var(--sidebar-width)); |         width: calc(0.25 * var(--sidebar-width)); | ||||||
|         height: calc(0.3 * var(--sidebar-height)); |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .infobar-button-active { | ||||||
| .sidebar-button:hover { |  | ||||||
|     background: rgba(255, 255, 255, 0.2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebar-button:active { |  | ||||||
|     background: rgba(255, 255, 255, 0.4); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebar-input { |  | ||||||
|     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(0, 255, 0, 0.5); | ||||||
|  |     color: rgb(255, 255, 255); | ||||||
|  |     font-size: calc(2.8 * var(--border-radius)); | ||||||
|  |     height: calc(4 * var(--border-radius)); | ||||||
|  |     width: calc(var(--sidebar-width) - 4 * var(--border-radius)); | ||||||
|  |     vertical-align: middle; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-aspect-ratio: 1/1) { | ||||||
|  |  | ||||||
|  |     .infobar-button-active{ | ||||||
|  |         width: calc(0.25 * var(--sidebar-width)); | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .infobar-button:hover { | ||||||
|  |     background: rgba(255, 255, 255, 0.2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .infobar-button:active { | ||||||
|  |     background: rgba(255, 255, 255, 0.4); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .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(0, 0, 0, 0.2); | ||||||
|     color: rgb(255, 255, 255); |     color: rgb(255, 255, 255); | ||||||
|     font-size: calc(3 * var(--border-radius)); |     font-size: calc(3 * var(--border-radius)); | ||||||
|     height: calc(4 * var(--border-radius)); |     height: calc(4 * var(--border-radius)); | ||||||
| @ -244,10 +259,14 @@ a:visited { | |||||||
|     text-align: center; |     text-align: center; | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (orientation: portrait) { | .infobar-input::placeholder { | ||||||
|  |     color: rgba(255,255,255,0.3); | ||||||
|  | } | ||||||
|  |  | ||||||
|     .sidebar-input{ | @media (max-aspect-ratio: 1/1) { | ||||||
|         height: calc(0.3 * var(--sidebar-height)); |  | ||||||
|  |     .infobar-input{ | ||||||
|  |         height: calc(0.18 * var(--sidebar-height)); | ||||||
|         width: calc(0.25 * var(--sidebar-width)); |         width: calc(0.25 * var(--sidebar-width)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										303
									
								
								websocket_connection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								websocket_connection.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,303 @@ | |||||||
|  | class WebsocketConnection | ||||||
|  | { | ||||||
|  |     constructor(ip, port, grid, status_label, matches_container, control_container, login_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.active_match = null; | ||||||
|  |  | ||||||
|  |         this.connected = false; | ||||||
|  |  | ||||||
|  |         this.current_end_button = null; | ||||||
|  |  | ||||||
|  |         this.login_callback_func = login_callback_func; | ||||||
|  |  | ||||||
|  |         this.openmatches = {}; | ||||||
|  |  | ||||||
|  |         this. | ||||||
|  |  | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_open(username, pw) | ||||||
|  |     { | ||||||
|  |         this.connected = true; | ||||||
|  |         this.login(username, pw) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_close() | ||||||
|  |     { | ||||||
|  |         this.registered = false; | ||||||
|  |         this.connected = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     on_error() | ||||||
|  |     { | ||||||
|  |         console.log("error in websocket connection"); | ||||||
|  |         this.registered = false; | ||||||
|  |         this.connected = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     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 "temp_session_response": | ||||||
|  |                 console.log(json_msg) | ||||||
|  |                 this.on_temp_session_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; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set_active_match(id) | ||||||
|  |     { | ||||||
|  |         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(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     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) | ||||||
|  |                 console.log("update!!!"); | ||||||
|  |                 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()); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     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_temp_session_response(data) | ||||||
|  |     { | ||||||
|  |         console.log("not supported yet"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     connect(username, pw) | ||||||
|  |     { | ||||||
|  |         this.socket = new WebSocket("wss://" + 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()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send_disconnect() | ||||||
|  |     { | ||||||
|  |         if (!this.is_connected) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         var msg_object = { | ||||||
|  |             type: "end_game", | ||||||
|  |             data: { | ||||||
|  |                 msg: "" | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         this.socket.send(JSON.stringify(msg_object)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     close() | ||||||
|  |     { | ||||||
|  |         for (var key in this.openmatches) | ||||||
|  |         { | ||||||
|  |             this.openmatches[key].remove_match(); | ||||||
|  |         } | ||||||
|  |         this.socket.close(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     notify(text) { | ||||||
|  |          | ||||||
|  |         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