diff options
author | tomsmeding <hallo@tomsmeding.nl> | 2015-12-05 20:40:32 +0100 |
---|---|---|
committer | tomsmeding <hallo@tomsmeding.nl> | 2015-12-05 20:40:32 +0100 |
commit | 1954ed67ef61c509560418a9d2da58083b822996 (patch) | |
tree | 870237504df86fcdd6cfaab2948e73e7211cf95d /index.html |
Initial enzo
Diffstat (limited to 'index.html')
-rw-r--r-- | index.html | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..dcf0b9b --- /dev/null +++ b/index.html @@ -0,0 +1,545 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Multichain</title> +<script src="/socket.io/socket.io.js"></script> +<script src="/common.js"></script> +<script> +"use strict"; + +var COLOURS=["#00F","#F00","#0CC"]; + +var socket=io(),me=[-1,""],userlist=[],rooms={},visibleroomuidiv=null; +socket.on("disconnect",function(){ + location.href=location.href; +}); +socket.on("message",function(msg){ + alert("Message:\n\n"+msg); +}); +socket.on("me",updateme); +socket.on("userlist",updateuserlist); +socket.on("room",joinroom); +socket.on("roomdestroy",roomdestroy); +socket.on("roominvite",roominvite); +socket.on("roomjoin",roomadduser); +socket.on("roomchat",roomchat); +socket.on("roomgameturn",roomgameturn); + +if(location.hostname=="localhost"&&Math.random()<.25)localStorage.setItem("nickname","aaa"); + +if(localStorage.getItem("nickname"))socket.emit("setnick",localStorage.getItem("nickname")); +else socket.emit("me",updateme); +socket.emit("userlist",updateuserlist); + +function updateme(_me){ + me=_me; + document.getElementById("nickname").innerHTML=me[1]; + localStorage.setItem("nickname",me[1]); +} + +function updateuserlist(_ul){ + userlist=_ul; + var elem=document.getElementById("userlist"),l=elem.children; + var i,div; + for(i=l.length-1;i>=0;i--)elem.removeChild(l[i]); + var input=document.getElementById("roomuserinput"),selectedlist=input.value.trim().split(/\s+/g); + for(i=0;i<userlist.length;i++){ + if(userlist[i][1]==me[1]){ + userlist.splice(i,1); + i--; + continue; + } + div=document.createElement("div"); + div.setAttribute("userid",userlist[i][0]); + div.setAttribute("username",userlist[i][1]); + div.innerHTML=userlist[i][1]; + div.addEventListener("click",function(ev){ + var usernameattr=ev.target.getAttribute("username"); + if(ev.target.classList.contains("selected")){ + ev.target.classList.remove("selected"); + input.value=input.value.trim().split(/\s+/g).filter(function(n){return n!=usernameattr;}).join(" "); + } else { + ev.target.classList.add("selected"); + input.value=(input.value.trim()+" "+usernameattr).trim(); + } + }); + if(selectedlist.indexOf(userlist[i][1])!=-1)div.classList.add("selected"); + elem.appendChild(div); + } + input.value=selectedlist.filter(function(n){ + var i; + for(i=0;i<userlist.length;i++)if(userlist[i][1]==n)return true; + return false; + }).join(" "); +} + +function joinroom(roomid,users){ + rooms[roomid]=new Room(roomid); + users.forEach(function(user){ + rooms[roomid].join(user); + }); +} + +function roomadduser(roomid,user){ + rooms[roomid].join(user); +} + +function Room(_roomid){ + if(!(this instanceof Room))return new Room(_roomid) + this.id=_roomid; + this.userlist=[]; + this.bd=emptyboard(); + this.onturn=0; + this.cellsz=40; + + this.canplace=false; + + this.listdiv=document.createElement("div"); + this.listdiv.classList.add("room"); + this.listdiv.innerHTML="<div style='float:right;cursor:default' onclick='dodestroyroom(\""+this.id+"\")'>X</div><b>Room:</b>"; + this.listdiv.addEventListener("click",function(ev){ + if(ev.target!=this.listdiv)return; + if(visibleroomuidiv)visibleroomuidiv.classList.add("invisible"); + else document.getElementById("roomuisplash").classList.remove("invisible"); + visibleroomuidiv=this.uidiv; + this.uidiv.classList.remove("invisible"); + }.bind(this)); + document.getElementById("roomlistcontainer").appendChild(this.listdiv); + + var e,table,tbody,input; + this.uidiv=document.createElement("div"); + this.uidiv.classList.add("roomui"); + this.uidiv.classList.add("invisible"); + + e=document.createElement("div"); + e.setAttribute("style","float:right;margin:5px;cursor:pointer"); + e.innerHTML="x"; + e.addEventListener("click",function(){ + this.uidiv.classList.add("invisible"); + visibleroomuidiv=null; + document.getElementById("roomuisplash").classList.add("invisible"); + }.bind(this)); + this.uidiv.appendChild(e); + + e=document.createElement("div"); + e.classList.add("chatdiv"); + table=document.createElement("table"); + table.classList.add("chatlogtable"); + tbody=document.createElement("tbody"); + tbody.classList.add("chatlogtbody"); + table.appendChild(tbody); + e.appendChild(table); + input=document.createElement("input"); + input.type="text"; + input.classList.add("chatinput"); + input.setAttribute("placeholder","Type something..."); + input.addEventListener("keypress",function(ev){ + if(ev.keyCode!=13&&ev.which!=13)return; + var msg=ev.target.value; + ev.target.value=""; + if(msg.length==0)return; + socket.emit("roomchat",this.id,msg); + }.bind(this)); + e.appendChild(input); + this.uidiv.appendChild(e); + + e=document.createElement("div"); + e.classList.add("gamediv"); + this.cvs=document.createElement("canvas"); + this.ctx=this.cvs.getContext("2d"); + this.cvs.classList.add("gamecvs"); + this.cvs.width=this.cellsz*W+1; + this.cvs.height=this.cellsz*H+1; + this.cvs.addEventListener("click",function(ev){ + if(ev.target!=this.cvs)return; + var x=ev.clientX/this.cellsz,y=ev.clientY/this.cellsz,idx=W*y+x; + if(x<0||y<0||x>=W||y>=H)return; + if(this.bd[idx]place(idx,this.onturn); + }.bind(this)); + drawboard(this.ctx,this.cellsz,this.bd,0); + e.appendChild(this.cvs); + this.uidiv.appendChild(e); + + this.statusdiv=document.createElement("div"); + this.statusdiv.classList.add("gamestatusdiv"); + this.uidiv.appendChild(this.statusdiv); + + document.body.appendChild(this.uidiv); +} +Room.prototype.join=function(user){ + this.listdiv.innerHTML+=" "+user[1]; + this.userlist.push(user.slice()); +}; +Room.prototype.destroy=function(){ + if(visibleroomuidiv==this.uidiv){ + visibleroomuidiv=null; + document.getElementById("roomuisplash").classList.add("invisible"); + } + this.uidiv.parentElement.removeChild(this.uidiv); + this.listdiv.parentElement.removeChild(this.listdiv); +}; +Room.prototype.chat=function(by,msg){ + var tr,td,div; + tr=document.createElement("tr"); + td=document.createElement("td"); + div=document.createElement("div"); + div.classList.add("chatitem"); + div.innerHTML="<i>"+by[1]+"</i>: "+msg; + td.appendChild(div); + tr.appendChild(td); + this.uidiv.getElementsByClassName("chatlogtbody")[0].appendChild(tr); + tr.scrollIntoView(); +}; +Room.prototype.place=function(pos,pidx){ + queueapplymove(this.id,this.ctx,this.cellsz,pos,pidx); + queueapplymove(this.id,function(){ + //WINCHECK? + this.onturn=(this.onturn+1)%this.userlist.length; + drawboard(this.ctx,this.cellsz,this.bd,this.onturn); + }.bind(this)); +}; +Room.prototype.myturn=function(ot){ + this.canplace=true; + this.onturn=ot; + this.statusdiv.innerHTML="Your turn!"; +}; + +function roominvite(roomid,by){ + if(!confirm("User '"+by[1]+"' sent you an invite to join their room. Accept?"))return; + socket.emit("inviteaccept",roomid); +} + +function roomdestroy(roomid){ + rooms[roomid].destroy(); + delete rooms[roomid]; +} + +function roomchat(roomid,by,msg){ + rooms[roomid].chat(by,msg); +} + +function roomgameturn(roomid,ot){ + rooms[roomid].myturn(ot); +} + + +function changenick(){ + var newnick=prompt("New nickname?"); + if(!newnick)return; + if(!validatenick(newnick)){ + alert("That's an invalid nick! (regex [a-zA-Z0-9_-]{3,})"); + return; + } + socket.emit("setnick",newnick); +} + +function createroom(){ + var users=document.getElementById("roomuserinput").value.trim().split(/\s+/g).map(function(n){ + var i; + for(i=0;i<userlist.length;i++)if(userlist[i][1]==n)return userlist[i][0]; + return -1; + }).filter(function(id){return id!=-1;}); + socket.emit("createroom",users); +} + +function dodestroyroom(roomid){ + socket.emit("roomdestroy",roomid); +} + +function drawboard(ctx,cellsz,bd,clr){ + var x,y,i,angle,radius; + ctx.clearRect(0,0,W*cellsz+1,H*cellsz+1); + ctx.strokeStyle=COLOURS[+clr]; + ctx.beginPath(); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + ctx.moveTo(x*cellsz+.5,y*cellsz+.5); + ctx.lineTo((x+1)*cellsz+.5,y*cellsz+.5); + ctx.lineTo((x+1)*cellsz+.5,(y+1)*cellsz+.5); + ctx.lineTo(x*cellsz+.5,(y+1)*cellsz+.5); + ctx.lineTo(x*cellsz+.5,y*cellsz+.5); + } + } + ctx.stroke(); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + ctx.fillStyle=COLOURS[bd[y][x].c]; + angle=1/bd[y][x].n*2*Math.PI; + radius=bd[y][x].n==1?0:.15; + for(i=0;i<bd[y][x].n;i++){ + ctx.beginPath(); + ctx.arc( + (x+.5+radius*Math.cos(angle*i))*cellsz, + (y+.5+radius*Math.sin(angle*i))*cellsz, + cellsz*.2,0,2*Math.PI,1); + ctx.fill(); + } + } + } +} + +function stabiliseanims(bd){ + var anims=[],stage; + var newbd; + var x,y,nnei,quo; + do { + stage=[]; + newbd=bdcopy(bd); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + nnei=(y>0)+(x>0)+(y<H-1)+(x<W-1); + if(bd[y][x].n>=nnei){ + quo=~~(bd[y][x].n/nnei); + newbd[y][x].n-=quo*nnei; + if(y>0) { + newbd[y-1][x].n+=quo; newbd[y-1][x].c=bd[y][x].c; + stage.push([W*y+x,W*(y-1)+x]); + } + if(x>0) { + newbd[y][x-1].n+=quo; newbd[y][x-1].c=bd[y][x].c; + stage.push([W*y+x,W*y+x-1]); + } + if(y<H-1){ + newbd[y+1][x].n+=quo; newbd[y+1][x].c=bd[y][x].c; + stage.push([W*y+x,W*(y+1)+x]); + } + if(x<W-1){ + newbd[y][x+1].n+=quo; newbd[y][x+1].c=bd[y][x].c; + stage.push([W*y+x,W*y+x+1]); + } + } + } + } + bd=newbd; + anims.push([stage,bdcopy(bd)]); + if(checkwin(bd)!=-1)break; + } while(stage.length); + return anims; +} + +var applymove_queue={}; //objects of room ids +var applymove_busy={}; + +function applymove(ctx,cellsz,idx,c,aqid){ + var bd=rooms[aqid].bd,onturn=rooms[aqid].onturn; + applymove_busy[aqid]=true; + bd[~~(idx/W)][idx%W].n++; + bd[~~(idx/W)][idx%W].c=c; + drawboard(ctx,cellsz,bd,onturn); + var anims=stabiliseanims(bd); + anims.forEach(function(pair,i){ + var stage=pair[0],newbd=pair[1]; + var finalstage=i==anims.length-1; + setTimeout(function(){ + var time=0; + var interval=setInterval(function(){ + var i,fx,fy,tx,ty; + for(i=0;i<stage.length;i++){ + fx=stage[i][0]%W; fy=~~(stage[i][0]/W); + bd[fy][fx].n--; + } + drawboard(ctx,cellsz,bd,onturn); + for(i=0;i<stage.length;i++){ + fx=stage[i][0]%W; fy=~~(stage[i][0]/W); + tx=stage[i][1]%W; ty=~~(stage[i][1]/W); + ctx.fillStyle=COLOURS[bd[fy][fx].c]; + ctx.beginPath(); + ctx.arc( + (fx*(1-time/10)+tx*time/10+.5)*cellsz, + (fy*(1-time/10)+ty*time/10+.5)*cellsz, + cellsz*.2,0,2*Math.PI,1); + ctx.fill(); + } + if(time==10){ + clearInterval(interval); + bd=rooms[aqid].bd=newbd; + drawboard(ctx,cellsz,bd,onturn); + if(finalstage){ + applymove_busy[aqid]=false; + while(applymove_queue[aqid].length&&typeof applymove_queue[aqid][0]=="function"){ + applymove_queue[aqid][0](); + applymove_queue[aqid].shift(); + } + if(applymove_queue[aqid].length){ + setTimeout(function(){ + applymove.apply(null,applymove_queue[aqid][0]); + applymove_queue[aqid].shift(); + },50); + } + } + } + time++; + },20); + },350*i+1); + }); +} + +function queueapplymove(id,ctx,cellsz,idx,c){ + if(!applymove_queue[id])applymove_queue[id]=[]; + if(!applymove_busy[id])applymove_busy[id]=false; + if(applymove_busy[id]){ + if(typeof ctx=="function")applymove_queue[id].push(ctx); + else applymove_queue[id].push([ctx,cellsz,idx,c,id]); + } else { + if(typeof ctx=="function")ctx(); + else applymove(ctx,cellsz,idx,c,id); + } +} +</script> +<style> +body{ + background-color:#fff; + margin:0; + font-family:Monaco,Menlo,"Courier New",Monospace; + font-size:14px; +} +header{ + background-color:#fee; +} +header h1{ + margin-top:0; + margin-bottom:0; + padding:10px; + padding-left:20px; + width:350px; +} +div#headerbottom{ + height:10px; + background: #fee; + background: -moz-linear-gradient(top, #fee 0%, #fff 100%); + background: -webkit-gradient(left top, left bottom, color-stop(0%, #fee), color-stop(100%, #fff)); + background: -webkit-linear-gradient(top, #fee 0%, #fff 100%); + background: -o-linear-gradient(top, #fee 0%, #fff 100%); + background: -ms-linear-gradient(top, #fee 0%, #fff 100%); + background: linear-gradient(to bottom, #fee 0%, #fff 100%); +} + +div#nickbar{ + float:right; + margin-top:15px; + font-size:10px; +} +span#nickname{ + font-weight:bold; +} + + +div#body{ + margin:5px; +} + +div#userlistcontainer{ + width:190px; +} +div#userlist{ + width:150px; + height:200px; + border:1px #eee solid; + overflow-y:scroll; + -moz-user-select:none; + -webkit-user-select:none; + -ms-user-select:none; +} +div#userlist > div{ + cursor:pointer; + padding:1px; +} +div#userlist > div:hover{ + background-color:#edd; +} +div#userlist > div.selected{ + background-color:#dcc; + border:1px #abb solid; + padding:0; +} + +input#roomuserinput{ + width:180px; +} + + +div.room{ + background-color:#edd; + -webkit-box-shadow:0px 0px 2px 3px #edd; + -moz-box-shadow:0px 0px 2px 3px #edd; + box-shadow:0px 0px 2px 3px #edd; + padding:10px; + margin:10px; + width:300px; + cursor:pointer; +} + +div.roomui{ + position:absolute; + top:50%; + margin-top:-300px; + left:50%; + margin-left:-350px; + width:700px; + height:600px; + padding:10px; + background-color:#edd; + border-radius:5px; +} + +div.chatdiv{ + float:right; + width:200px; + height:200px; +} +table.chatlogtable{ + display:block; + width:100%; + height:160px; + border:1px black solid; + overflow-y:scroll; +} +div.chatitem{ + width:200px; + word-wrap:break-word; +} +input.chatinput{ + width:200px; +} + +div.gamestatusdiv{ + font-style:italic; + font-weight:bold; + font-size:12px; +} + + +.invisible{ + display:none; +} + + +div#roomuisplash{ + position:absolute; + left:0; + top:0; + width:100%; + height:100%; + background-color:rgba(0,0,0,0.4); +} +</style> +</head> +<body> +<div id="roomuisplash" class="invisible" onclick="visibleroomuidiv.classList.add('invisible');visibleroomuidiv=null;event.target.classList.add('invisible')"></div> +<header> + <div id="nickbar">Nickname: <span id="nickname"></span> <input type="button" onclick="changenick()" value="Change"></div> + <h1>Multichain</h1> + <div id="headerbottom"></div> +</header> +<div id="body"> + <div id="createroomcontainer" style="float:right"> + <b>Online users:</b> + <div id="userlist"></div> + <input type="text" id="roomuserinput" disabled> <br> + <input type="button" onclick="createroom()" value="Create room"> + </div> + <div id="roomlistcontainer"></div> +</div> +</body> +</html> |